命令系统
大约 3 分钟
命令系统
自定义命令的创建、注册和执行。
基础命令定义
const {
CommandDefinition,
CommandRegistry,
CommandOptions,
writeMessage,
Engine
} = vjcad;
// 定义命令类
class HelloCommand {
async main() {
writeMessage("<br/>Hello WebCAD!");
Engine.zoomExtents();
}
}
// 创建命令定义
const options = new CommandOptions();
options.useAutoComplete = true; // 启用自动补全
const cmdDef = new CommandDefinition(
'HELLO', // 命令名(大写)
'简单示例命令', // 描述
HelloCommand, // 命令类
options // 选项(可选)
);
// 注册命令
CommandRegistry.regist(cmdDef);
// 执行命令
await Engine.editor.executerWithOp('HELLO');带用户输入的命令
const {
CommandDefinition, CommandRegistry,
PointInputOptions, InputStatusEnum,
getPoint, writeMessage,
LineEnt, Engine
} = vjcad;
class DrawLineCommand {
async main() {
// 开始撤销组
Engine.undoManager.start_undoMark();
try {
// 获取起点
const opt1 = new PointInputOptions("指定起点:");
const result1 = await getPoint(opt1);
if (result1.status !== InputStatusEnum.OK) return;
// 获取终点(带橡皮筋线)
const opt2 = new PointInputOptions("指定终点:");
opt2.useBasePoint = true;
opt2.basePoint = result1.value;
const result2 = await getPoint(opt2);
if (result2.status !== InputStatusEnum.OK) return;
// 创建直线
const line = new LineEnt(result1.value, result2.value);
line.setDefaults();
Engine.addEntities(line);
writeMessage("<br/>直线已创建");
} finally {
Engine.undoManager.end_undoMark();
}
}
}
const cmdDef = new CommandDefinition("DRAWLINE", "绘制直线", DrawLineCommand);
CommandRegistry.regist(cmdDef);预览绘制
使用 callback 实现鼠标移动时的实时预览。
const {
PointInputOptions, InputStatusEnum,
getPoint, CircleEnt, Engine
} = vjcad;
class DrawCircleWithPreviewCommand {
constructor() {
this.center = null;
}
async main() {
Engine.undoManager.start_undoMark();
try {
// 获取圆心
const opt1 = new PointInputOptions("指定圆心:");
const result1 = await getPoint(opt1);
if (result1.status !== InputStatusEnum.OK) return;
this.center = result1.value;
// 获取半径(带预览)
await this.getRadiusWithPreview();
} finally {
Engine.undoManager.end_undoMark();
Engine.clearPreview(); // 清除预览
}
}
async getRadiusWithPreview() {
const options = new PointInputOptions("指定半径:");
options.useBasePoint = true;
options.basePoint = this.center;
// 预览回调
options.callback = (canvasPoint) => {
const worldPoint = Engine.CanvasToWcs(canvasPoint);
const radius = Math.sqrt(
Math.pow(worldPoint.x - this.center.x, 2) +
Math.pow(worldPoint.y - this.center.y, 2)
);
if (radius > 0) {
const previewCircle = new CircleEnt(
[this.center.x, this.center.y],
radius
);
previewCircle.setDefaults();
Engine.clearPreview();
Engine.drawPreviewEntity(previewCircle);
}
};
const result = await getPoint(options);
Engine.clearPreview();
if (result.status === InputStatusEnum.OK) {
const endPoint = result.value;
const radius = Math.sqrt(
Math.pow(endPoint.x - this.center.x, 2) +
Math.pow(endPoint.y - this.center.y, 2)
);
const circle = new CircleEnt([this.center.x, this.center.y], radius);
circle.setDefaults();
Engine.addEntities(circle);
}
}
}预览相关 API:
Engine.CanvasToWcs(canvasPoint)- 画布坐标转世界坐标Engine.clearPreview()- 清除预览Engine.drawPreviewEntity(entity)- 绘制单个预览实体Engine.drawPreviewEntities(entities)- 绘制多个预览实体
状态机命令模式
处理复杂的多步骤命令。
const {
PointInputOptions, InputStatusEnum,
getPoint, PolylineEnt, Engine, writeMessage
} = vjcad;
class DrawPolylineCommand {
constructor() {
this.step = 1; // 当前状态
this.points = []; // 顶点集合
this.isClosed = false;
}
async main() {
Engine.undoManager.start_undoMark();
try {
// 状态机循环
while (this.step > 0) {
switch (this.step) {
case 1:
await this.step1_getFirstPoint();
break;
case 2:
await this.step2_getNextPoints();
break;
case 3:
this.step3_finish();
break;
}
}
} finally {
Engine.undoManager.end_undoMark();
Engine.clearPreview();
}
}
async step1_getFirstPoint() {
const options = new PointInputOptions("指定起点:");
const result = await getPoint(options);
if (result.status === InputStatusEnum.OK) {
this.points.push(result.value);
this.step = 2;
} else {
this.step = 0; // 退出
}
}
async step2_getNextPoints() {
const options = new PointInputOptions(
"指定下一点 [闭合(C)/撤销(U)] <完成>:"
);
options.keywords = ["C", "U"]; // 支持关键字
if (this.points.length > 0) {
options.useBasePoint = true;
options.basePoint = this.points[this.points.length - 1];
}
const result = await getPoint(options);
if (result.status === InputStatusEnum.OK) {
// 用户点击了一个点
this.points.push(result.value);
} else if (result.status === InputStatusEnum.Keyword) {
// 用户输入了关键字
const keyword = result.stringResult.toUpperCase();
if (keyword === "C") {
this.isClosed = true;
this.step = 3;
} else if (keyword === "U") {
if (this.points.length > 1) {
this.points.pop();
writeMessage("<br/>已撤销上一点");
}
}
} else if (result.status === InputStatusEnum.EnterOrSpace) {
// 用户按回车/空格,完成
this.step = 3;
} else {
// 取消
this.step = 0;
}
}
step3_finish() {
if (this.points.length >= 2) {
const pline = new PolylineEnt();
pline.setPoints(this.points.map(p => [p.x, p.y]));
pline.isClosed = this.isClosed;
pline.setDefaults();
Engine.addEntities(pline);
writeMessage(`<br/>多段线已创建,${this.points.length} 个顶点`);
}
this.step = 0; // 结束
}
}状态机要点:
step > 0继续循环,step = 0退出InputStatusEnum.Keyword处理关键字输入result.stringResult获取关键字字符串InputStatusEnum.EnterOrSpace处理回车/空格
命令注册与管理
// 批量注册命令
const commands = [
{ name: 'CMD1', desc: '命令1', cls: Cmd1Class },
{ name: 'CMD2', desc: '命令2', cls: Cmd2Class },
];
commands.forEach(cmd => {
const options = new CommandOptions();
options.useAutoComplete = true;
CommandRegistry.regist(
new CommandDefinition(cmd.name, cmd.desc, cmd.cls, options)
);
});
// 查询已注册的命令
const cmdInfo = CommandRegistry.item('CMD1');
if (cmdInfo) {
console.log("命令名:", cmdInfo.name);
console.log("描述:", cmdInfo.description);
}
// 注销命令
CommandRegistry.unregist('CMD1');命令类标准模板
class MyCommand {
constructor() {
// 初始化状态
}
async main() {
// 开始撤销组
Engine.undoManager.start_undoMark();
try {
// 命令逻辑
await this.doWork();
} catch (error) {
writeMessage(`<br/>错误: ${error.message}`);
} finally {
// 结束撤销组
Engine.undoManager.end_undoMark();
// 清除预览
Engine.clearPreview();
}
}
async doWork() {
// 实际命令逻辑
}
}