唯杰地图 logo唯杰地图
VJMAP
EN

execute-command

vjmapext/references/drawing/execute-command.md 5.4 KB117 行
原文

本文回答:mapcadLayer.executeCommand / commandRegistry.repeatLast / lastCommandName —— 启动 / 重复 / 取消命令。

一、基本调用

mapcadLayer.executeCommand('LINE');                  // 启动
mapcadLayer.executeCommand('DRAWORDER', { action: 'back' }); // 带选项(内置命令仅 TEXTEDIT/INSERT/DRAWORDER 读 opts)

返回 Promise<void>。命令启动后异步等待用户输入;不需要 await,也可以 await 等结束。

二、带选项

选项被 main(ctx, opts) 的第二个参数接收:

mapcadLayer.executeCommand('TEXTEDIT', { entity: someTextEnt });   // 跳过"选择实体"步骤
mapcadLayer.executeCommand('INSERT', { blockName: '灯具' });
mapcadLayer.executeCommand('DRAWORDER', { action: 'front' });

⚠️ 绝大多数内置命令不读 opts——v1.0.1 中只有 TEXTEDIT(opts.entity)、INSERT(opts.blockName)、DRAWORDER(opts.action)三个消费它;executeCommand('TEXT', { text, height }) 这类写法会被静默忽略。opts 主要给自定义命令用。

三、重复上一条

mapcadLayer.commandRegistry.repeatLast();
const last = mapcadLayer.commandRegistry.lastCommandName;
// → 'LINE'

键盘:repeatCommand 快捷键默认是 null(未绑定)——回车默认是 confirm 动作不是 repeat。要回车重复上一条:mapcadLayer.setShortcuts({ repeatCommand: 'enter' })(会顶掉 confirm 的回车)。

四、取消命令

mapcadLayer.inputManager.cancelCurrentInput();

对应的 getPoint / getSelections / ... Promise 会以 status: 'cancel' resolve,main 函数自然流程结束。

按 Esc 默认触发 cancel。右键行为分输入类型(右键只处理点输入与实体输入两种状态):getPoint 等待中右键 = cancel;getEntity({ multiple: true })(MOVE/COPY/ERASE 等内置编辑命令的选集步骤)等待中右键 = 确认当前选择(返回 OK + 已选实体,等同回车),单选 getEntity 右键 = cancel;getSelections 等待中右键无反应——用回车/空格,或单击空白处结束选择。

五、错误处理

await mapcadLayer.executeCommand('UNKNOWN_CMD');
// 不抛异常:console 输出警告 `[vjmapext] Unknown command: UNKNOWN_CMD`,直接 return

注意:命令名不存在不会 throw(warn + return,Promise 正常 resolve)。想兜底:

const names = mapcadLayer.commandRegistry.getAll().map(c => c.name);
if (!names.includes('MYCMD')) console.error('命令未注册');
  • main 抛异常 → 也被吞掉:console.error('[vjmapext] Command XXX error:', err),Promise 照样 resolve;finally 里会 endTransaction + 清理 _activeCommand,command:ended 照发(实采)。command:ended 的 payload 只有 { name },成功/取消/异常一律在 finally 里发出,无法据此判断结果;要结果请在 main 里自行 try/catch、eventBus.emit 业务事件,或配合 entity:added 统计产出。
  • 失败的命令不进历史(实采):lastCommandName 只在 main 正常结束时更新;main 抛错后 repeatLast() 重放的是上一条成功的命令。
  • browse 模式静默空转(实采):setMode('browse') 下 executeCommand/repeatLastCommand 直接 resolve()——不执行、不报错、不发 command:started。批量脚本里若误留 browse 态,命令全部静默跳过。

六、查看所有已注册命令

// 低级 API
for (const cmd of mapcadLayer.commandRegistry.getAll()) {
  console.log(cmd.name, cmd.description);
}

或结合 getShortcuts()(返回动作→键位映射,见 shortcuts):

const shortcuts = mapcadLayer.getShortcuts();
// { undo: 'ctrl+z', cancel: 'escape', ... }

七、命令互斥

同一时刻只能有一条命令在执行。启动新命令会:

  1. 取消旧命令(cancelCurrentInput);
  2. 清除旧命令残留的预览 / 高亮;
  3. 启动新命令。

这是特性不是 bug:工具栏切换时不必手动清理。

八、延迟 / 定时启动

setTimeout(() => mapcadLayer.executeCommand('LINE'), 100);

常见用途:UI 面板弹出后再启动对应绘图命令,避免 UI 动画吃掉第一次 click。

九、组合调用

await mapcadLayer.executeCommand('LINE');        // 等画完一条线
await mapcadLayer.executeCommand('CIRCLE');      // 再画圆
// 注意:中间用户有可能取消;上面 await 只是等 command 的流程结束,并不等价于"成功"

十、常见坑

  1. await 里等不到用户输入:命令内部有用户交互,executeCommand 不返回"用户确定";command:ended(payload 只有 { name })也只说明"结束了",成功与否要靠 entity:added 或命令自己 emit 的业务事件判断。
  2. 不能并发:两次 executeCommand 并发时,第二次会取消第一次。
  3. 空闲按回车没触发:需要 mapcadLayer.getMapContainer()?.focus() 聚焦容器。
  4. 右键菜单多次执行 LINE:注意菜单回调里的 executeCommand 会重复启动命令,取消当前再启动新的。

相关