---
name: vjcad
description: Use when building browser-based 2D CAD editor/viewer applications with vjcad (唯杰 WebCAD, npm package vjcad) — MainView/initCadContainer/onLoad init, Engine (pcanvas/currentDoc/currentSpace/eventManager/undoManager/editor/contextMenu), creating entities (LineEnt/CircleEnt/ArcEnt/PolylineEnt/TextEnt/MTextEnt/HatchEnt/DimensionEnt/InsertEnt), custom commands and user input (getPoint/getSelections/InputStatusEnum), editing (move/copy/rotate/mirror/erase), layers/properties/linetypes/selection sets, geometry tools, views, DWG open/save (DrawingManagerService.openDrawing/openDbDoc/SAVESERVER/EXPORTDWG/EXPORTPNG), events and undo, reactors, SVG/symbols/bitmap-vectorize, table extraction, tile editing, version branches, plugins and UI customization (Ribbon/dialogs/themes), CAD-over-web-map overlays, read-only viewer mode, parametric auto-drawing. Keywords vjcad WebCAD MainView Engine CAD编辑器 实体 图层 选择集 撤销 插件 Ribbon 自动成图 DWG. Excludes vjmap/vjmapext/vjmap3d (use those skills).
metadata:
  product: vjcad
  package: vjcad
  packageVersion: "1.0.16"
  docsMcp: https://vjmap.com/server/aimcp/mcp?products=vjcad
---

# vjcad — 唯杰 WebCAD 编辑器 SDK 二次开发

```yaml
pkg: vjcad@1.0.16          # npm 已发布；UMD 全局对象 vjcad
docsMcp: https://vjmap.com/server/aimcp/mcp?products=vjcad
```

本 skill 的 `references/` 基于官方文档整理改编（合并实体专页、增补 quickref/autodraw 等自撰章节）。仍需更深细节时按下列来源查证，**冲突时以 npm 包 `dist/types.d.ts` 与 playground 示例为准**：

| 来源 | 入口 |
|---|---|
| 官方文档/示例 MCP | `https://vjmap.com/server/aimcp/mcp?products=vjcad`（`list_docs` / `search_docs` / `get_doc_content`）。路径前缀：`vjcad/doc/...`（官方文档）、`vjcad/example/...`（playground 示例）。references 正文、「MCP 参考」行与「参考（官方文档 MCP）」小节里的这类路径，都可直接用 `get_doc_content` 读取原文 |
| npm 包类型定义 | `npm i vjcad` 后看 `node_modules/vjcad/dist/types.d.ts` |
| 离线参考 | 本目录 `references/`（速查表 [references/quickref/](references/quickref/README.md) 21 篇） |

服务地址与 token 换为你自己的（公有云 `https://vjmap.com/server/api/v1`，私有化 `http://<ip>:27660/api/v1`，见 vjmap-service skill）。wasm / 字体默认由 `serviceUrl` 所指服务提供（`<serviceRoot>_webcad/wasm`），**不要**另设 `wasmServiceUrl`。**不要把 token 写进提交的代码**。

## 安装与模板

```bash
npm i vjcad
```

- **vite 模板** → `templates/vite-app/`（[README](templates/vite-app/README.md)）
- **纯 HTML / CDN 模板** → `templates/cdn/`（`<script src>` UMD，全局对象 `vjcad`）

```js
// npm / ESM
import { MainView, initCadContainer } from "vjcad";

// CDN / UMD
const { MainView, initCadContainer, message } = vjcad;
```

## 心智模型

```
                              [DWG / WebCAD JSON / 互联网底图]
                                            |
                                            v
   +-----------------------+     await      +------------------------+
   |  new MainView({...})  | ---> onLoad -> |       Engine            |  <-- 运行时上下文唯一入口
   +-----------------------+     PixiJS/    +-----------+------------+
              |                  WASM/                  |
   initCadContainer(id, view)    Fonts/                 v
              |                  Plugins/         +-----------------+
              v                  URL params      |  pcanvas         |  (画布、regen/redraw/zoomExtents)
        DOM 容器挂载                              +-----------------+
                                                  |  currentDoc       |  (CadDocument，含 layers/blocks/...)
                                                  |    └ currentSpace |  (ModelSpace/PaperSpace，items/addEntities/erase)
                                                  |  editor           |  (executerWithOp / 命令调度 / contextMenu 右键菜单)
                                                  |  eventManager     |  (on/off/once/suspendEvents/resumeEvents + CadEvents)
                                                  |  undoManager      |  (undo/redo/start/end/UndoDescriptor)
                                                  |  trans            |  (CanvasToWcs / WcsToCanvas / WcsToUcs)
                                                  +-----------------+
```

关键认知：

1. **入口三段式**：`new MainView({...})` → `initCadContainer(elementId, cadView)` → `await cadView.onLoad()`。**`onLoad()` 之前禁止使用 `Engine`**。
2. **实体三段式**：`new XxxEnt(位置参数…)`（如 `new LineEnt([0,0],[100,0])`、`new CircleEnt([0,0],50)`，构造函数不收选项对象）→ `setDefaults()` → `Engine.addEntities([ent])`（自动记录撤销）；若用 `Engine.pcanvas.addEntity` 需自行 `added_undoMark`。
3. **命令三段式**：`class { async main() {...} }` + `CommandDefinition` + `CommandRegistry.regist(cmdDef)` → `Engine.editor.executerWithOp('CMDNAME')` 触发；`main` 内 `getPoint / getSelections / getEntity / Engine.getString` 交互，逐步检查 `InputStatusEnum.OK/Cancel`（getPoint 空回车/空格返回 `None`，`EnterOrSpace` 仅 getEntity）。
4. **服务端图纸**：`drawingManager.openDrawing({...})` → `new File([jsonString], docName)` → `await Engine.view.openDbDoc(virtualFile, webcadData)`，并在 `Engine.currentDoc.serverSource` 记录 `type/mapid/version/branchName/lastPatchId`（openDbDoc 不会设置；须在 `setOriginalJson` 之前赋值，否则后者直接返回 false）。
5. **事件清理**：监听必须有对应 `off(event, handler)`；**勿用 `offAll`**（会连内核自己的监听一起移除，关联标注/Ribbon 刷新失效）；交互式命令（PLINE/SPLINE）的 `EntityAdded` 拿到中间态，命令结束（`CommandEnded`）后再读最终点位。

## 最小可运行模板

```ts
import { MainView, initCadContainer, Engine } from "vjcad";

const cadView = new MainView({
  appname: "我的CAD应用",
  version: "v1.0.0",
  serviceUrl,      // 你的服务地址（wasm/字体也从这里加载）
  accessToken,     // 你的 token
});
initCadContainer("cad-app", cadView);   // 容器需有非零宽高
await cadView.onLoad();

// onLoad 之后才可用 Engine；Engine 是全局单例绑最近活跃视图，多实例先 Engine.bindViewCache(cadView)
// 或直接用视图实例成员 cadView.editor / cadView.pcanvas（cadView.Engine 不存在）
Engine.editor.executerWithOp("LINE");
```

**只读 Viewer**：`MainView` 配置加 `viewMode: "viewer"`（是 `viewMode` 不是 `viewerMode`），可叠加 `showUcsIcon:false / showAxis:false / enableContextMenu:false / showGrips:false`。

## 按场景速查

| 要做什么 | 去读 |
|---|---|
| 初始化 / onLoad 生命周期 / 安装与环境 | [setup/overview](references/setup/overview.md) · [setup/mainview-init](references/setup/mainview-init.md) · [setup/onload-lifecycle](references/setup/onload-lifecycle.md) · [setup/install-and-mcp](references/setup/install-and-mcp.md) |
| 字体（woff/ttf/shx）/ 中英文切换 | [setup/fonts](references/setup/fonts.md) · [setup/locale-i18n](references/setup/locale-i18n.md) |
| 只读查看 / MainView 全量配置 | [setup/viewer-mode](references/setup/viewer-mode.md) · [setup/mainview-config](references/setup/mainview-config.md) |
| Engine / pcanvas / currentDoc+currentSpace / 坐标 / 公开 API 清单 | [core/](references/core/overview.md)（engine · pcanvas · document-space · coordinate · public-api） |
| 自定义命令 / CommandOptions / 预览 / 状态机 / 脚本命令链 | [command/](references/command/overview.md)（custom-command · options · preview · state-machine · execute-script） |
| 取点 / 选实体 / 选集 / 取字符串数字关键字 / 基点 | [input/](references/input/overview.md)（get-point · get-selections · get-entity · get-string-number · base-point） |
| 实体：Line/Arc/Circle · Polyline/DLine · Text/MText · 块 · Hatch/Solid · 标注引线 · Spline/Ellipse · 图像 · 自定义实体 | [entity/](references/entity/overview.md) + [common-entities](references/entity/common-entities.md) |
| 编辑：移动复制 / 旋转缩放 / 镜像 / 删除 / 绘序 / 组 / 高亮 | [edit/](references/edit/overview.md) |
| 选择集 API | [selection/](references/selection/overview.md)（selection-api） |
| 颜色线型线宽 / 透明度可见性 / setDefaults / XData | [property/](references/property/overview.md) |
| 图层：创建切换 / 可见冻结锁定 / 列举 / 状态保存 | [layer/](references/layer/overview.md) |
| 几何：点包围盒 / 距离角度 / 求交 / Offset-Trim-Extend / 打断变换 / 空间索引 / 智能工具 | [geometry/](references/geometry/overview.md) |
| 视图：缩放 / 平移重绘 / 坐标显示 / 背景 / 屏幕范围 / UCS / PLAN | [view/](references/view/overview.md) |
| 文件：服务端图纸 / 本地 IndexedDB / DWG 导入导出 / PNG / Diff / URL 参数 | [file/](references/file/overview.md) |
| 事件：监听 / 命令事件 / 实体事件 / PLINE 时序 / 文档事件 | [event/](references/event/overview.md) |
| 撤销：基本 / 标记 / 分组 / 描述历史 | [undo/](references/undo/overview.md) |
| 反应器：IEntityReactor / 标注关联 / 事件式 / 约束 | [reactor/](references/reactor/overview.md) |
| 插入：SVG / 符号创建管理插入 / 位图矢量化 | [insert/](references/insert/overview.md) |
| 表格识别 | [recognition/](references/recognition/overview.md)（table-extract） |
| 瓦片：打开模式 / 区域图层编辑 / 透明度 / 叠互联网底图 | [tile/](references/tile/overview.md) |
| 版本：分支 / 补丁 / 合并 / 历史 / 认证 | [version/](references/version/overview.md) |
| 插件：生命周期 / PluginContext / Ribbon 菜单 / 内置清单 | [plugin/](references/plugin/overview.md) |
| UI：对话框 / 右键菜单 / 主题状态栏 / 侧边栏 / 浮动工具栏 / 图标 / 选择器 / 控件 / PreviewView / 地图叠加 | [ui/](references/ui/overview.md) |
| CAD 叠 vjmap / CAD 上叠高德天地图 / 坐标对齐 EPSG | [map-integration/](references/map-integration/overview.md) |
| 综合大示例（剖切） | [comprehensive/section](references/comprehensive/section.md) |
| 参数化自动成图（思路 + 板/阀/三视图示例） | [autodraw/](references/autodraw/README.md)（入口索引）+ [overview](references/autodraw/overview.md) + [examples/](references/autodraw/examples/plate-and-cat.md) |
| 常见坑：初始化黑屏 / 事件泄漏 / PLINE 时序 / 命名不一致 | [trouble/](references/trouble/overview.md) |

## 约定与红旗

### 命名

- `cadView` = `MainView` 实例；`Engine` = vjcad 导出的全局单例（`onLoad` 后才可用，`cadView.Engine` 不存在）。
- `doc` = `Engine.currentDoc`；`space` = `Engine.currentSpace`；`pcanvas` = `Engine.pcanvas`；`editor` = `Engine.editor`；`eventManager` = `Engine.eventManager`；`undoManager` = `Engine.undoManager`。
- `cmdDef` = `CommandDefinition`；`drawingManager` = `DrawingManagerService` 实例。

### Top 红旗

1. **`cadView.onLoad()` 之前** 用 `Engine` / `Engine.currentDoc` / `Engine.eventManager` → `undefined`。
2. 把 vjmap 的 `new vjmap.Service()` / `new vjmap.Map()` 套到 vjcad → vjcad 只走 `MainView` + `initCadContainer`。
3. 忽略 `InputStatusEnum.Cancel`，用户 Esc 后还继续建实体。
4. 监听事件不 `off` → 泄漏；用 `offAll()` 清理 → 误删内核内部监听。
5. `EntityAdded` 里读 PLINE/SPLINE 完整点位 → 中间态；命令结束后再读。
6. `viewMode:"viewer"` 下调编辑命令。
7. 编造未在文档/示例出现的 API（见 [trouble/source-conflicts](references/trouble/source-conflicts.md)：命名不一致时以能跑的示例为准）。
8. 容器 `<div>` 无宽高 → 黑屏。
9. `Engine.pcanvas.addEntity(ent)` 后忘 `added_undoMark` 或 `regen`/`redraw`。
10. 循环里逐个 `addEntities` 且每次 `regen`/`zoomExtents` → 卡顿；批量加完再统一 `regen`。
