唯杰地图 logo唯杰地图
VJMAP
EN

符号系统

vjcad/references/quickref/symbol-system.md 12.3 KB443 行
原文

符号库的创建、管理、插入完整指南。支持本地存储和服务端存储两种方式。

概览

存储方式 服务 特点
本地存储 getLocalStorageService() IndexedDB 存储,离线可用
服务端存储 Engine.service 云端存储,需要网络和权限

创建符号

本地符号

const { 
    LineEnt, CircleEnt, Engine, 
    getLocalStorageService, 
    buildSymbolVcadData, 
    generateThumbnailFromEntities 
} = vjcad;

// 1. 创建实体作为符号内容
const line1 = new LineEnt([-10, 0], [10, 0]);
const line2 = new LineEnt([0, -10], [0, 10]);
const circle = new CircleEnt([0, 0], 8);

line1.setDefaults();
line2.setDefaults();
circle.setDefaults();

// 2. 获取本地存储服务
const localService = getLocalStorageService();

// 3. 创建或获取分类
let categories = await localService.getLocalSymbolCategories();
let category = categories.find(c => c.name === "我的符号");

if (!category) {
    category = await localService.createLocalSymbolCategory("我的符号");
}

// 4. 构建符号数据
const entities = [line1, line2, circle];
const vcadData = await buildSymbolVcadData(entities, false);

// 5. 生成缩略图
const thumbnail = await generateThumbnailFromEntities(entities, 128, 128);

// 6. 保存符号
const symbol = await localService.saveLocalSymbol({
    categoryId: category.id,
    name: "十字圆符号",
    basePoint: [0, 0],      // 符号基点(插入时的参考点)
    thumbnail: thumbnail,
    vcadData: vcadData
});

console.log("符号已保存,ID:", symbol.id);

服务端符号

const { 
    LineEnt, Engine,
    buildSymbolVcadData,
    compressSymbolData,
    uint8ArrayToBase64,
    generateThumbnailFromEntities
} = vjcad;

// 1. 创建实体
const line1 = new LineEnt([0, 0], [20, 0]);
const line2 = new LineEnt([20, 0], [15, 3]);
const line3 = new LineEnt([20, 0], [15, -3]);

line1.setDefaults();
line2.setDefaults();
line3.setDefaults();

// 2. 获取服务
const service = Engine.service;

// 3. 获取或创建分类
const categories = await service.getSymbolCategories();
let category = categories.find(c => c.name === "用户自定义");

if (!category) {
    category = await service.createSymbolCategory("用户自定义");
}

// 4. 构建符号数据
const entities = [line1, line2, line3];
const vcadData = await buildSymbolVcadData(entities, false);

// 5. 压缩数据(服务端存储需要压缩)
const compressedData = await compressSymbolData(vcadData, 6);
const base64Data = uint8ArrayToBase64(compressedData);

// 6. 生成缩略图
const thumbnail = await generateThumbnailFromEntities(entities, 128, 128);

// 7. 保存符号
const symbol = await service.createSymbol({
    categoryId: category.id,
    name: "箭头符号",
    basePoint: [0, 0],
    thumbnail: thumbnail,
    data: base64Data
});

console.log("符号已保存,ID:", symbol.id);

插入符号

指定参数插入

const { 
    Point2D, Engine,
    getLocalStorageService,
    parseSymbolVcadData,
    mergeSymbolToDocument,
    regen
} = vjcad;

// 1. 获取符号数据
const localService = getLocalStorageService();
const categories = await localService.getLocalSymbolCategories();
const symbols = await localService.getLocalSymbolList(categories[0].id);
const symbolData = await localService.getLocalSymbol(symbols[0].id);

// 2. 解析符号数据
const symbolDoc = await parseSymbolVcadData(symbolData.vcadData);

// 3. 插入参数
const insertPoint = new Point2D(50, 50);  // 插入点
const basePoint = symbolData.record.basePoint;   // 符号基点(getLocalSymbol 返回 {record, vcadData},basePoint 在 record 上)
const scale = 1.5;                         // 缩放比例
const rotation = 45;                       // 旋转角度(度)

// 4. 合并到当前文档
const addedEntities = mergeSymbolToDocument(
    symbolDoc,
    insertPoint,
    basePoint,
    scale,
    rotation,
    false  // 不清空来源图信息
);

console.log("已插入实体数:", addedEntities.length);

// 5. 刷新视图
regen();
Engine.zoomExtents();

服务端符号插入

const { 
    Point2D, Engine,
    decompressSymbolData,
    parseSymbolVcadData,
    mergeSymbolToDocument
} = vjcad;

const service = Engine.service;

// 1. 获取符号列表
const categories = await service.getSymbolCategories();
const category = categories.find(c => c.name === "用户自定义");
const result = await service.getSymbolList(category.id);

// 2. 获取符号详情
const fullSymbol = await service.getSymbol(result.list[0].id);

// 3. 解压数据
const vcadData = await decompressSymbolData(fullSymbol.data);

// 4. 解析并插入
const symbolDoc = await parseSymbolVcadData(vcadData);
const insertPoint = new Point2D(100, 100);

const addedEntities = mergeSymbolToDocument(
    symbolDoc,
    insertPoint,
    fullSymbol.basePoint,
    1,    // 缩放
    0,    // 旋转
    false
);

交互式插入

const { 
    Engine, 
    getLocalStorageService,
    insertSymbolInteractive,
    CommandRegistry, CommandDefinition, CommandOptions
} = vjcad;

class InsertSymbolCommand {
    async main() {
        // 1. 获取符号数据
        const localService = getLocalStorageService();
        const categories = await localService.getLocalSymbolCategories();
        const symbols = await localService.getLocalSymbolList(categories[0].id);
        const symbolData = await localService.getLocalSymbol(symbols[0].id);

        // 2. 交互式插入
        // 会依次提示用户指定:插入点、缩放比例、旋转角度
        const entities = await insertSymbolInteractive(
            symbolData.vcadData,
            symbolData.record.basePoint,   // 不是 symbolData.basePoint(undefined → 内部 basePoint[0] 抛错)
            {
                allowScale: true,      // 允许指定缩放
                allowRotation: true,   // 允许指定旋转
                clearSourceInfo: false
            }
        );

        if (entities) {
            console.log("符号插入成功,实体数量:", entities.length);
            Engine.zoomExtents();
        } else {
            console.log("符号插入已取消");
        }
    }
}

// 注册命令
const cmdDef = new CommandDefinition('MYINSERTSYMBOL', '交互式插入符号', InsertSymbolCommand);
CommandRegistry.regist(cmdDef);

// 执行命令
await Engine.editor.executerWithOp('MYINSERTSYMBOL');

分类管理

本地分类

const localService = getLocalStorageService();

// 获取所有分类
const categories = await localService.getLocalSymbolCategories();

// 创建分类
const newCategory = await localService.createLocalSymbolCategory("新分类");

// 更新分类名称
await localService.updateLocalSymbolCategory(newCategory.id, "新名称");

// 删除分类
await localService.deleteLocalSymbolCategory(newCategory.id);

服务端分类

const service = Engine.service;

// 获取所有分类
const categories = await service.getSymbolCategories();

// 创建分类(需要权限)
const newCategory = await service.createSymbolCategory("新分类");

// 更新分类名称
await service.updateSymbolCategory(newCategory.id, "新名称");

// 删除分类
await service.deleteSymbolCategory(newCategory.id);

符号管理

本地符号管理

const localService = getLocalStorageService();

// 获取符号列表
const symbols = await localService.getLocalSymbolList(categoryId);

// 获取符号详情:返回 { record, vcadData } | null(basePoint/name 等元数据在 detail.record 上)
const detail = await localService.getLocalSymbol(symbolId);

// 删除符号
await localService.deleteLocalSymbol(symbolId);

// 获取统计信息
const stats = await localService.getLocalSymbolStats();
console.log("分类数:", stats.categoryCount);
console.log("符号数:", stats.symbolCount);
console.log("总大小:", stats.totalSize);

服务端符号管理

const service = Engine.service;

// 获取符号列表(支持分页和搜索)
const result = await service.getSymbolList(categoryId, {
    page: 1,
    pageSize: 10,
    keyword: "箭头"  // 可选:关键字搜索
});

console.log("总数:", result.total);
console.log("当前页:", result.page);
console.log("列表:", result.list);

// 获取符号详情(包含压缩的 data)
const fullSymbol = await service.getSymbol(symbolId);

// 删除符号(需要权限)
await service.deleteSymbol(symbolId);

工具函数

函数 说明
buildSymbolVcadData(entities, clearSourceInfo) 将实体数组转换为符号数据
generateThumbnailFromEntities(entities, width, height) 生成缩略图
parseSymbolVcadData(vcadData) 解析符号数据为 CadDocument
mergeSymbolToDocument(doc, insertPt, basePt, scale, rotation, clearInfo) 合并符号到当前文档
insertSymbolInteractive(vcadData, basePoint, options) 交互式插入符号
compressSymbolData(data, level) 压缩符号数据(服务端存储用)
decompressSymbolData(base64Data) 解压符号数据
uint8ArrayToBase64(uint8Array) Uint8Array 转 Base64

符号数据格式

字段 说明
id 符号 ID
name 符号名称
categoryId 所属分类 ID
basePoint 符号基点 [x, y]
thumbnail 缩略图(Base64 或 Data URL)
vcadData / data 符号数据(本地为原始数据,服务端为压缩后的 Base64)
createTime 创建时间

完整示例:符号库命令

const { 
    Engine, CommandRegistry, CommandDefinition, CommandOptions,
    getLocalStorageService, insertSymbolInteractive,
    showSelectDialog, message
} = vjcad;

class SymbolLibraryCommand {
    async main() {
        const localService = getLocalStorageService();
        
        // 1. 获取所有分类
        const categories = await localService.getLocalSymbolCategories();
        
        if (categories.length === 0) {
            message.error("没有符号分类");
            return;
        }
        
        // 2. 选择分类(showSelectDialog 的 value 必须是字符串:未改选时内部会对默认值 .trim(),数字会抛错;
        //    结果 value 也总是字符串,而本地库的 id/categoryId 是数字,需转回 Number)
        const categoryResult = await showSelectDialog({
            title: "选择符号分类",
            label: "请选择分类:",
            options: categories.map(c => ({ value: String(c.id), label: c.name }))
        });
        
        if (!categoryResult.confirmed) return;
        
        // 3. 获取符号列表
        const symbols = await localService.getLocalSymbolList(Number(categoryResult.value));
        
        if (symbols.length === 0) {
            message.error("该分类下没有符号");
            return;
        }
        
        // 4. 选择符号
        const symbolResult = await showSelectDialog({
            title: "选择符号",
            label: "请选择要插入的符号:",
            options: symbols.map(s => ({ value: String(s.id), label: s.name }))
        });
        
        if (!symbolResult.confirmed) return;
        
        // 5. 获取符号详情
        const symbolId = Number(symbolResult.value);
        const symbolData = await localService.getLocalSymbol(symbolId);
        const symbolMeta = symbols.find(s => s.id === symbolId);
        
        // 6. 交互式插入
        const entities = await insertSymbolInteractive(
            symbolData.vcadData,
            symbolMeta.basePoint,
            { allowScale: true, allowRotation: true }
        );
        
        if (entities) {
            message.info(`已插入符号: ${symbolMeta.name}`);
            Engine.zoomExtents();
        }
    }
}

// 注册命令
CommandRegistry.regist(new CommandDefinition(
    'MYSYMBOLLIBRARY', 
    '符号库', 
    SymbolLibraryCommand
));