Jig(动态预览)系统
AutoCAD 依赖 AcEdJig 框架在获取用户输入时提供实时视觉反馈。该系统虽然强大,但将提示、预览渲染和输入采样分散在多个重写方法中——常常把逻辑分散到不同的函数和生命周期阶段。MLightCAD 面向 Web 重新构想了这一概念,引入了统一的、由 TypeScript 驱动的 jig 机制,并与提示输入无缝集成。开发者无需管理拖拽循环或采样器状态码,只需将 jig 直接附加到提示选项上,即可将动态预览逻辑、用户输入和最终实体创建保持在一个可读的工作流中。
概览
MLightCAD 中的 Jig 系统支持交互式预览和动态实体创建,提供与 AutoCAD 的 AcEdJig(ObjectARX)类似的工作流。jig 管理一个临时预览实体,该实体会根据光标移动或增量用户输入持续更新。
使用场景包括:
- 交互式几何创建(点、圆、多段线等)
- 实时距离或角度测量
- 现有实体的实时修改
不过,MLightCAD 引入了更简单、更内聚、对 TypeScript 更友好的设计,减少了 AutoCAD jig 中常见的结构复杂性。
关键架构差异
Jig 被传入提示选项
在 AutoCAD 中,提示和 jig 是分离的机制。执行 jig 需要重写 sampler()、worldDraw() 并调用 drag()。
在 MLightCAD 中,提示可以直接携带 jig 实例:
const opts = new AcEdPromptDistanceOptions('Specify radius:')
opts.jig = new CircleJig(view, center)
const radius = await editor.getDistance(opts)这种设计:
- 自动将用户输入与实时预览关联起来
- 消除了手动管理拖拽循环的需要
➡️ 结果:更少的样板代码,更高的一致性。
完整的动态输入逻辑保持在一起
正如你在 AutoCAD AcEdJig 示例代码中所见,AutoCAD 将创建一个椭圆的输入逻辑分散到多个地方。
createEllipse()— 获取椭圆中心点sampler()— 获取长轴端点以及从椭圆中心到短轴端点的距离
在 MLightCAD 中,整个动态输入工作流按顺序表达如下。
const center = await editor.getPoint(pointOpts)
radiusOpts.jig = new CircleJig(view, center)
const radius = await editor.getDistance(radiusOpts)➡️ 用户输入、jig 预览和最终几何体都在同一段代码中管理。
核心概念
通用 Jig(AcEdPreviewJig<T>)
AcEdPreviewJig<T> 是一个基于 TypeScript 的类,用于管理临时预览实体:
| AutoCAD AcEdJig | Web CAD Jig(AcEdPreviewJig) |
|---|---|
sampler() | update(value: T) |
startJig() | setEntity() |
drag() | 通过 JS 事件在外部控制 |
特性:
- 使用泛型
T处理多种输入类型(点、距离、角度等) - 与
AcEdBaseView集成以渲染临时实体 - 支持实现
onJigUpdate(value: T)的预览实体,以便动态更新几何体 - 允许使用
end()干净地终止 jig
核心方法
update(value: T): void
根据用户输入更新预览实体。这相当于 AutoCAD 的 sampler()。
render(): void
在关联的视图中渲染预览实体,类似于 AutoCAD 的 worldDraw()。
end(): void
清除临时实体并结束 jig 会话。
entity: AcDbEntity | null
当前预览实体的 getter。
使用 Jig
步骤 1:创建 Jig 类
你需要为特定实体创建一个继承 AcEdPreviewJig<T> 的类。例如,创建一个 圆 jig:
import { AcDbCircle, AcGePoint3dLike } from '@mlightcad/data-model'
import { AcEdPreviewJig, AcEdBaseView } from '@mlightcad/cad-simple-viewer'
export class AcApCircleJig extends AcEdPreviewJig<number> {
private _circle: AcDbCircle
constructor(view: AcEdBaseView, center: AcGePoint3dLike) {
super(view)
this._circle = new AcDbCircle(center, 0)
}
get entity(): AcDbCircle {
return this._circle
}
update(radius: number) {
this._circle.radius = radius
}
}说明:
- jig 管理一个临时的
AcDbCircle。 update方法根据用户输入动态更改半径。
步骤 2:在命令中使用 Jig
你可以在命令中集成 jig,以交互方式创建实体:
import { AcEdCommand, AcApDocManager, AcEdPromptPointOptions, AcEdPromptDistanceOptions } from '@mlightcad/cad-simple-viewer'
import { AcApCircleJig } from './AcApCircleJig'
export class AcApCircleCmd extends AcEdCommand {
async execute(context) {
// Step 2a: Acquire center point
const centerPrompt = new AcEdPromptPointOptions('Specify center of circle:')
const center = await AcApDocManager.instance.editor.getPoint(centerPrompt)
// Step 2b: Acquire radius using Jig
const radiusPrompt = new AcEdPromptDistanceOptions('Specify radius of circle:')
radiusPrompt.jig = new AcApCircleJig(context.view, center)
const radius = await AcApDocManager.instance.editor.getDistance(radiusPrompt)
// Step 2c: Add circle to database
const circle = new AcDbCircle(center, radius)
context.doc.database.tables.blockTable.modelSpace.appendEntity(circle)
}
}工作流:
- 提示用户输入圆的圆心。
- 创建一个附加到圆心的圆 jig。
- 提示用户输入半径,并提供交互式预览。
- 将最终确定的圆提交到数据库。
用户输入
关于 AcEditor 输入 API、提示选项、关键字规则和提示结果处理的完整且最新的指南,请参阅: