文件操作
大约 10 分钟
文件操作
WebCAD 提供完整的图纸文件管理功能,包括服务端存储、本地缓存、DWG 导入导出等。
概述
文件操作分为以下几类:
| 类别 | 命令 | 说明 |
|---|---|---|
| 服务端操作 | OPENFROMSERVER / SAVESERVER | 从服务器打开/保存图纸 |
| 本地缓存 | OPENFROMLOCAL / SAVELOCAL | 从 IndexedDB 打开/保存图纸 |
| 本地文件 | QSAVE / SAVEAS | 下载 .webcad 文件 |
| DWG 转换 | IMPORTDWG / EXPORTDWG | 导入/导出 DWG 格式 |
| 图片导出 | EXPORTPNG | 导出当前视图为 PNG 图片 |
| 模板成图 | NEWFROMTEMPLATE / CLONEFROMTEMPLATE | 从模板新建图纸 / 克隆模板实体 |
核心服务
DrawingManagerService
DrawingManagerService 是图纸管理的核心服务,封装了与服务端交互的所有操作。
import { DrawingManagerService } from 'vjcad';
const drawingManager = new DrawingManagerService();LocalStorageService
LocalStorageService 管理本地 IndexedDB 存储,支持离线编辑。
import { getLocalStorageService } from 'vjcad';
const localService = getLocalStorageService();从服务端打开图纸
命令方式
// 执行 OPENFROMSERVER 命令,打开图纸浏览器对话框
await Engine.editor.executerWithOp('OPENFROMSERVER');API 方式
import { DrawingManagerService, Engine } from 'vjcad';
const drawingManager = new DrawingManagerService();
// 打开图纸
const openResult = await drawingManager.openDrawing({
type: 'imports', // 类型:'imports' | 'designs'
mapid: 'example_map', // 图纸ID
version: 'v1', // 版本号
branch: 'main', // 分支名称
patchId: 'base', // Patch ID(可选,不传则使用最新)
readOnly: false // 是否只读模式
});
if (openResult.success) {
// 加载到编辑器
const virtualFile = new File(
[openResult.webcadJson],
'drawing.webcad',
{ type: 'application/json' }
);
await Engine.view.openDbDoc(virtualFile, openResult.webcadData);
// 保存来源信息(用于后续保存)
Engine.currentDoc.serverSource = {
type: 'imports',
mapid: 'example_map',
version: 'v1',
branchName: 'main',
lastPatchId: openResult.latestPatchId || 'base'
};
// 保存原始数据(用于增量保存时的diff计算)
await Engine.currentDoc.setOriginalJson(openResult.webcadJson);
}打开参数 IOpenDrawingParams
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
type | 'imports' | 'designs' | 是 | 图纸类型 |
mapid | string | imports必填 | 图纸ID |
version | string | imports必填 | 版本号 |
designPath | string | designs必填 | 设计图路径 |
branch | string | 否 | 分支名称,默认 "main" |
patchId | string | 否 | 指定 patch 版本,为空则获取最新 |
readOnly | boolean | 否 | 是否只读模式 |
clipbounds | [number, number, number, number] | 否 | 裁剪范围,只返回范围内的实体 |
editAreas | Array<{minX, minY, maxX, maxY}> | 否 | 多个编辑区域(瓦片模式) |
editLayers | string[] | 否 | 编辑图层名称列表 |
打开结果 IOpenDrawingResult
| 属性 | 类型 | 说明 |
|---|---|---|
success | boolean | 是否成功 |
error | string | 错误信息 |
webcadJson | string | 解压后的 webcad JSON 数据 |
webcadData | any | 解析后的对象 |
latestPatchId | string | 最新的 Patch ID |
isReadOnly | boolean | 是否只读模式 |
保存到服务端
命令方式
await Engine.editor.executerWithOp('SAVESERVER');API 方式
const currentDoc = Engine.currentDoc;
const currentJson = JSON.stringify(currentDoc.toDb());
const originalJson = await currentDoc.getOriginalJson();
const serverSource = currentDoc.serverSource;
const saveResult = await drawingManager.saveDrawing({
type: serverSource.type,
mapid: serverSource.mapid,
version: serverSource.version,
branchName: serverSource.branchName,
originalJson: originalJson, // 原始数据(用于计算diff)
currentJson: currentJson, // 当前数据
parentId: serverSource.lastPatchId,
drawingName: '我的图纸',
author: '作者',
remark: '修改说明'
});
if (saveResult.status) {
// 更新原始数据和 patchId
await currentDoc.setOriginalJson(currentJson);
currentDoc.serverSource.lastPatchId = saveResult.patchId;
}保存参数 ISaveDrawingParams
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
type | 'imports' | 'designs' | 是 | 图纸类型 |
mapid | string | imports必填 | 图纸ID |
version | string | imports必填 | 版本号 |
designPath | string | designs可选 | 设计图路径,空表示新建 |
branchName | string | 否 | 分支名称,默认 "main" |
originalJson | string | 否 | 原始 webcad JSON(用于计算diff) |
currentJson | string | 是 | 当前 webcad JSON |
parentId | string | 否 | 父级 Patch ID(用于冲突检测) |
drawingName | string | 否 | 图纸名称 |
author | string | 否 | 作者 |
remark | string | 否 | 备注 |
增量保存特点
- 只保存修改的部分:计算 diff,节省存储空间和网络带宽
- 支持版本历史回溯:每次保存生成新的 patch
- 支持多人协作冲突检测:通过 parentId 检测并发修改
本地缓存操作
本地缓存使用 IndexedDB 存储,支持离线编辑。
保存到本地
import { getLocalStorageService, Engine } from 'vjcad';
const localService = getLocalStorageService();
const currentDoc = Engine.currentDoc;
const currentJson = JSON.stringify(currentDoc.toDb());
const result = await localService.saveDrawing({
serverSource: currentDoc.serverSource,
webcadJson: currentJson,
serviceUrl: 'https://api.example.com',
drawingName: '我的图纸'
});
if (result.success) {
console.log(`保存成功! ID: ${result.id}`);
}从本地打开
// 获取所有本地图纸列表
const drawings = await localService.listDrawings();
// 根据 ID 加载图纸
const loadResult = await localService.loadDrawingById(drawingId);
if (loadResult.success) {
const virtualFile = new File(
[loadResult.webcadJson],
'local.webcad',
{ type: 'application/json' }
);
await Engine.view.openDbDoc(virtualFile);
// 恢复服务器来源信息
Engine.currentDoc.serverSource = {
type: loadResult.record.type,
mapid: loadResult.record.mapid,
version: loadResult.record.version,
branchName: loadResult.record.branchName,
lastPatchId: loadResult.record.lastPatchId
};
}LocalStorageService API
| 方法 | 说明 |
|---|---|
saveDrawing(params) | 保存图纸到本地 |
loadDrawing(key) | 根据 key 加载图纸 |
loadDrawingById(id) | 根据 ID 加载图纸 |
listDrawings(type?) | 列出所有本地图纸 |
deleteDrawing(key) | 删除图纸 |
deleteDrawingById(id) | 根据 ID 删除图纸 |
clearAll() | 清空所有本地缓存 |
getStats() | 获取缓存统计信息 |
exists(key) | 检查图纸是否存在 |
本地缓存特点
- 使用 IndexedDB 存储:容量大,支持存储大型图纸
- 支持离线访问:无网络时也可编辑
- 保存服务器来源信息:支持后续同步到服务器
- 自动压缩存储:使用 vcad 格式压缩,节省空间
下载 .webcad 文件
QSAVE - 快速保存
直接使用当前文件名下载。
// 命令方式
await Engine.editor.executerWithOp('QSAVE');
// API 方式
const currentDoc = Engine.currentDoc;
const data = currentDoc.toDb();
const jsonString = JSON.stringify(data, null, 2);
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = (currentDoc.name || 'untitled') + '.webcad';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);SAVEAS - 另存为
弹出对话框,可自定义文件名。
await Engine.editor.executerWithOp('SAVEAS');.webcad 文件格式
- JSON 格式:易于解析和调试
- 包含完整的图纸数据:实体、图层、样式等
- 可通过 OPEN 命令打开:或拖拽到编辑器打开
导入 DWG
命令方式
await Engine.editor.executerWithOp('IMPORTDWG');API 方式
import { DrawingManagerService, Service, MapOpenWay, openMapDarkStyle } from 'vjcad';
const drawingManager = new DrawingManagerService();
const service = drawingManager.getService();
// 1. 上传文件
const uploadResult = await service.uploadMap(file);
if (uploadResult.error) {
throw new Error('上传失败: ' + uploadResult.error);
}
// 2. 解析 DWG
const mapid = file.name.replace(/\.(dwg|dxf)$/i, '') + '_' + Date.now();
const openResult = await service.openMap({
mapid: mapid,
fileid: uploadResult.fileid,
uploadname: file.name,
mapopenway: MapOpenWay.Memory,
style: openMapDarkStyle()
}, true);
if (openResult.error) {
throw new Error('解析失败: ' + openResult.error);
}
// 3. 获取 webcad 数据并加载
const drawingResult = await drawingManager.openDrawing({
type: 'imports',
mapid: openResult.mapid,
version: openResult.version,
branch: 'main'
});
if (drawingResult.success) {
const virtualFile = new File(
[drawingResult.webcadJson],
'drawing.webcad',
{ type: 'application/json' }
);
await Engine.view.openDbDoc(virtualFile, drawingResult.webcadData);
Engine.currentDoc.serverSource = {
type: 'imports',
mapid: openResult.mapid,
version: openResult.version,
branchName: 'main',
lastPatchId: drawingResult.latestPatchId || 'base'
};
await Engine.currentDoc.setOriginalJson(drawingResult.webcadJson);
}支持的文件格式
- DWG:AutoCAD 图纸格式(2000-2018 版本)
- DXF:图形交换格式
导出 DWG
命令方式
await Engine.editor.executerWithOp('EXPORTDWG');API 方式
const currentDoc = Engine.currentDoc;
const currentJson = JSON.stringify(currentDoc.toDb());
const serverSource = currentDoc.serverSource;
const result = await drawingManager.exportToDwg({
type: serverSource.type,
webcadJson: currentJson,
mapid: serverSource.mapid,
version: serverSource.version,
branch: serverSource.branchName,
cadVersion: '', // CAD版本,空为自动
isZoomExtents: false, // 是否缩放到全图
useCache: true, // 是否使用缓存
unGroup: false, // 是否解散组
exportDimAsNative: false // 是否导出原生标注
});
if (result.status && result.downloadUrl) {
window.open(result.downloadUrl, '_blank');
}导出参数 IExportToDwgParams
| 参数 | 类型 | 说明 |
|---|---|---|
type | 'imports' | 'designs' | 图纸类型 |
webcadJson | string | 当前的 webcad JSON 数据 |
mapid | string | 图纸 ID(imports 类型) |
version | string | 版本号(imports 类型) |
designPath | string | 设计图路径(designs 类型) |
branch | string | 分支名称 |
cadVersion | string | CAD 版本号(2000-2018) |
isZoomExtents | boolean | 导出时是否缩放至全图 |
useCache | boolean | 是否使用缓存 |
unGroup | boolean | 是否解散组 |
exportDimAsNative | boolean | 是否将标注导出为原生CAD标注 |
导出说明
- imports 类型:基于原 DWG 增量导出,保留原始格式
- designs 类型:全新导出,不依赖原始文件
- 原生标注:可选择将 WebCAD 标注转换为 AutoCAD 原生标注
导出 PNG 图片
将当前图纸渲染为 PNG/JPEG 图片并直接下载。直接复用内存中已有的实体进行离屏渲染(支持所有实体类型:块引用、文字、填充、标注等),无需服务端参与。
命令方式
// 弹出导出对话框(可选择实体、主题色、尺寸等)
await Engine.editor.executerWithOp('EXPORTPNG');API 方式
import { exportEntitiesToImageAndDownload, exportEntitiesToImage } from 'vjcad';
// 导出全部实体(默认透明背景 PNG)
await exportEntitiesToImageAndDownload({
width: 2048,
fileName: 'my-drawing.png'
});
// 导出白色背景(关闭透明)
await exportEntitiesToImageAndDownload({
width: 2048,
transparent: false,
theme: 'light',
fileName: 'my-drawing-white.png'
});
// 导出指定实体(透明背景)
await exportEntitiesToImageAndDownload({
entities: [line1, circle1],
width: 1280,
fileName: 'partial-export.png'
});
// 导出为 JPEG(JPEG 不支持透明,自动使用主题色背景)
await exportEntitiesToImageAndDownload({
width: 1920,
theme: 'dark',
mimeType: 'image/jpeg',
quality: 0.9,
fileName: 'my-drawing.jpg'
});
// 获取 Blob 做自定义处理(如上传到服务器)
const result = await exportEntitiesToImage({
entities: myEntities,
width: 1920
});
if (result.success && result.blob) {
const formData = new FormData();
formData.append('file', result.blob, 'screenshot.png');
// await fetch('/upload', { method: 'POST', body: formData });
}导出参数 IExportImageOptions
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
entities | EntityBase[] | 当前空间全部实体 | 要导出的实体数组 |
width | number | 1000 | 图片宽度(像素),渲染画布上限 4096px |
height | number | 自动计算 | 图片高度(省略时根据实体范围宽高比自动计算) |
theme | 'dark' | 'light' | 'light' | 主题色,透明时仅影响 colorIndex 7 反色逻辑 |
transparent | boolean | true | 透明背景(仅 PNG 有效,JPEG 自动忽略) |
mimeType | 'image/png' | 'image/jpeg' | 'image/png' | 图片格式 |
quality | number | 0.92 | JPEG 质量(0-1),仅 JPEG 有效 |
fileName | string | 'export.png' | 下载的文件名 |
说明
- 默认导出透明背景 PNG,可直接用于文档、PPT 等场景
- 设置
transparent: false可切换为不透明背景,背景色由theme控制 light主题:白色背景,colorIndex 7(白色)自动反色为黑色dark主题:黑色背景,colorIndex 7 保持白色- 透明背景时
theme仅影响 colorIndex 7 的颜色:light时为黑色,dark时为白色 - JPEG 不支持透明通道,
transparent会自动忽略 - 高度根据实体包围盒的宽高比自动计算
- 渲染画布上限 4096px,超出时自动缩放后输出到目标尺寸
- 纯前端实现,直接下载,无需服务端参与
URL 参数自动打开图纸
WebCAD 支持通过 URL 参数控制页面加载后的行为,包括自动打开指定图纸和激活侧边栏面板。
支持的 URL 参数
所有 URL 参数以 vcad_ 为前缀:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
vcad_mapid | string | 是 | - | 图纸 ID |
vcad_version | string | 否 | 最新版本 | 版本号 |
vcad_branch | string | 否 | main | 分支名称 |
vcad_patch | string | 否 | base | Patch ID |
vcad_readonly | boolean | 否 | false | 是否只读打开 |
vcad_tile | boolean | 否 | false | 是否以瓦片方式打开 |
vcad_panel | string | 否 | - | 初始化后要激活的侧边栏面板名称 |
使用示例
// 自动打开指定图纸
https://your-domain.com/?vcad_mapid=building_plan
// 打开指定版本,只读模式
https://your-domain.com/?vcad_mapid=building_plan&vcad_version=v2&vcad_readonly=true
// 以瓦片方式打开大图纸
https://your-domain.com/?vcad_mapid=city_map&vcad_tile=true
// 打开图纸并激活 AI 助手面板
https://your-domain.com/?vcad_mapid=building_plan&vcad_panel=ai-assistant
// 仅激活侧边栏面板(不打开图纸)
https://your-domain.com/?vcad_panel=ai-assistant处理流程
- 页面加载完成后,解析 URL 中的
vcad_参数 - 如果有
vcad_panel,激活指定的侧边栏面板 - 如果有
vcad_mapid,按以下流程打开图纸:- 检查服务端是否有已转换完成的图(imports 列表)
- 如果有,直接打开
- 如果没有,检查后台原图是否存在(serverMaps)
- 如果原图存在,则进行导入打开(后端会自动转换)
- 如果
vcad_tile=true,则以瓦片方式打开
代码中访问 URL 参数常量
import { MainView } from 'vjcad';
// 所有 URL 参数名称定义在 MainView.URL_PARAMS 中
console.log(MainView.URL_PARAMS.MAPID); // 'vcad_mapid'
console.log(MainView.URL_PARAMS.VERSION); // 'vcad_version'
console.log(MainView.URL_PARAMS.BRANCH); // 'vcad_branch'
console.log(MainView.URL_PARAMS.PATCH); // 'vcad_patch'
console.log(MainView.URL_PARAMS.READONLY); // 'vcad_readonly'
console.log(MainView.URL_PARAMS.TILE); // 'vcad_tile'
console.log(MainView.URL_PARAMS.PANEL); // 'vcad_panel'图纸列表查询
获取所有图纸列表
const allDrawings = await drawingManager.listAllDrawings();
// 后台 DWG 图纸
console.log('后台图纸:', allDrawings.serverMaps);
// 已导入的图纸(imports)
console.log('已导入图纸:', allDrawings.imports);
// 用户设计图(designs)
console.log('设计图:', allDrawings.designs);获取 WebCAD 图纸列表
const webcadDraws = await drawingManager.listWebcadDraws({
mapid: 'example_map', // 可选,按 mapid 过滤
version: 'v1' // 可选,按版本过滤
});分支管理
详细的分支管理操作请参考 版本机制。
// 创建分支
await drawingManager.createBranch({
type: 'imports',
mapid: 'example_map',
version: 'v1',
sourceBranch: 'main',
newBranch: 'feature-1',
author: '作者'
});
// 获取分支列表
const branches = await drawingManager.listBranches({
type: 'imports',
mapid: 'example_map',
version: 'v1'
});
// 合并分支
await drawingManager.mergeBranch({
type: 'imports',
mapid: 'example_map',
version: 'v1',
sourceBranch: 'feature-1',
targetBranch: 'main'
});命令快捷键
| 快捷键 | 功能 |
|---|---|
Ctrl + O | 打开文件 |
Ctrl + S | 快速保存 |
Ctrl + Shift + S | 另存为 |