唯杰地图 logo唯杰地图
VJMAP
EN

bus-command-mode

vjmapext/references/event/bus-command-mode.md 5.9 KB148 行
原文

本文回答:命令 / 模式 / 输入事件 —— command:started / ended / mode:changed / input:started / ended。

一、事件列表

常量 字符串 payload
CommandStarted command:started { name }
CommandEnded command:ended { name }
ModeChanged mode:changed { mode }(mode 是新值,无 from/to)
InputStarted input:started { type, message?, keywords?, keywordTips?, defaultValue?, multiple? }(type ∈ point/entity/selection/string/real/integer/keyword;字段面按 type 裁剪——point 只有 type/message/keywords/keywordTips,entity 多 multiple,selection 只有 type/message;defaultValue 在 string/real/integer/keyword 型发射——注意 keyword 型读的是 options 的 defaultKeyword,但 payload 字段名仍是 defaultValue,getKeyword({defaultKeyword:'Y'}) → {defaultValue:'Y'})
InputEnded input:ended { type }

二、命令生命周期

const { VjmapextEvents } = vjmapext;
const bus = mapcadLayer.eventBus;

bus.on(VjmapextEvents.CommandStarted, ({ name }) => {
  statusBar.textContent = `执行中:${name}`;
});

bus.on(VjmapextEvents.CommandEnded, ({ name }) => {
  statusBar.textContent = '就绪';
});

command:ended 不区分成功 / 取消:用户 Esc 取消也会 fire。

三、命令统计 / 日志

const stats = {};
bus.on(VjmapextEvents.CommandEnded, ({ name }) => {
  stats[name] = (stats[name] || 0) + 1;
});

四、input:started / input:ended

每次 inputManager.getPoint / getSelections / ... 开始 / 结束都 fire。用途:

  • UI 里显示 / 隐藏命令行输入框
  • 暂停地图的其他 hover 逻辑
bus.on(VjmapextEvents.InputStarted, () => cmdLine.style.display = 'block');
bus.on(VjmapextEvents.InputEnded,   () => cmdLine.style.display = 'none');

五、mode:changed

bus.on(VjmapextEvents.ModeChanged, ({ mode }) => {
  myToolbar.applyMode(mode);   // 你自己的工具栏 UI
});

详见 drawing/mode。

六、命令 + 实体:捕获命令生成的实体

let capturing = false;
const captured = [];

bus.on(VjmapextEvents.CommandStarted, ({ name }) => {
  if (name === 'LINE') { capturing = true; captured.length = 0; }
});
bus.on(VjmapextEvents.CommandEnded, ({ name }) => {
  if (name === 'LINE') {
    capturing = false;
    console.log('LINE 生成了', captured.length, '个实体:', captured.map(e => e.id));
  }
});
bus.on(VjmapextEvents.EntityAdded, ({ entity }) => {
  if (capturing) captured.push(entity);
});

七、拦截 / 取消命令

eventBus 是单向广播,没法"拒绝"命令启动。要拦截命令:

// 包装 executeCommand
const orig = mapcadLayer.executeCommand.bind(mapcadLayer);
mapcadLayer.executeCommand = (name, opts) => {
  if (!canExecute(name)) {
    alert('无权限:' + name);
    return Promise.resolve();
  }
  return orig(name, opts);
};

或通过 mode 限制(见 drawing/mode)。

八、命令嵌套

vjmapext 不支持嵌套命令:新命令启动会先取消旧命令。

bus.on(VjmapextEvents.CommandStarted, ({ name }) => {
  if (name !== prevCmd) {
    console.log('自动取消了', prevCmd);
  }
  prevCmd = name;
});

九、InputStarted/Ended 的粒度

一条 LINE 命令内部可能多次调用 getPoint → 每次都 fire 一对 input:started / input:ended。用于:

  • 显示 / 隐藏"请指定点"的提示条
  • 命令行输入框的 focus / blur

十、枚举外附加事件(runtime 实发,不在 VjmapextEvents)

UMD 里还有两个字符串事件,订阅时用字面量:

事件 载荷 用途
command:prompt { message } 命令阶段提示文本(已 i18n 处理)。⚠️ 不是通用"输入提示"事件——只有命令体里显式 eventBus.emit('command:prompt',…) 的少数命令才发(如 STRETCH 起手发 cmd.stretch.promptCrossing);LINE 等常规命令的"指定第一点"走 input:started 的 message 字段,不发 command:prompt。自建命令行 UI 应以 input:started 为准
command:message { text } 命令产生的普通消息(如"已生成 N 个填充")

compact({ preset, result },FX 闲置槽位整理)不在 eventBus 上——它由 FX 层自己的 emitter 发出,订阅要 mapcadLayer.fx.on('compact', ({ preset, result }) => …)(见 perf/fx-quality);eventBus.on('compact', …) 永远收不到。

bus.on('command:prompt', ({ message }) => cmdLine.textContent = message);
bus.on('command:message', ({ text }) => log(text));

十一、常见坑

  1. command:ended 里立即执行新命令 → 可能和上条命令清理冲突;加 requestAnimationFrame。
  2. 没 off:组件卸载时保存 handler 引用逐个 eventBus.off(event, handler)(on() 不返回退订函数)。不要用 eventBus.clear()——它清掉全部监听,连内部的也一起删(显示级别过滤、DimReactor 标注联动、FX 实体绑定、工具栏/命令行 UI),之后这些功能静默失效;整层卸载用 map.removeControl(cad)(onRemove 内部已 clear)。
  3. 统计代码命中 undo/redo:undo / redo 不走 CommandStarted(它们是内置 action 而非命令);但有独立的非枚举事件 undo:performed / redo:performed(UndoManager 直发,用字面量订阅)。不要挂 StoreChanged——1.0.1 从未发射。
  4. 等 command:ended 拿返回值:命令没返回值;通过 entity:added 或业务自定义事件拿到"生成了什么"。
  5. input:started 对应非命令输入:自定义命令内部的 inputManager 也算;不是只命令才 fire。

相关