bus-entity
本文回答:
mapcadLayer.eventBus实体事件 ——entity:added / deleted / modified / click / dblclick / mouseenter / mouseleave。
一、事件列表
const { VjmapextEvents } = vjmapext;
| 常量 | 字符串 | payload |
|---|---|---|
EntityAdded |
entity:added |
{ entity } |
EntityDeleted |
entity:deleted |
{ entity } |
EntityModified |
entity:modified |
{ entityId, styleOnly? } ⚠️ 是 entityId 不是 entity |
EntityClick |
entity:click |
{ entityId, entity, cadPoint, originalEvent } |
EntityDblClick |
entity:dblclick |
{ entityId, entity, cadPoint, originalEvent } |
EntityMouseEnter |
entity:mouseenter |
{ entityId, entity, originalEvent } |
EntityMouseLeave |
entity:mouseleave |
{ entityId, entity } |
二、生命周期:增删改
const bus = mapcadLayer.eventBus;
bus.on(VjmapextEvents.EntityAdded, ({ entity }) => {
console.log('new:', entity.id, entity.type);
});
bus.on(VjmapextEvents.EntityDeleted, ({ entity }) => {
console.log('del:', entity.id);
});
bus.on(VjmapextEvents.EntityModified, ({ entityId, styleOnly }) => {
const entity = mapcadLayer.store.get(entityId);
if (styleOnly) {
// 只动了颜色 / 线宽 / 可见;不必重算空间索引
} else {
// 几何变化;重算你自己的索引
}
});
styleOnly 标志
entity.styleChanged() 触发 modified 且 styleOnly=true;entity.changed() 触发 modified 且不带 styleOnly 字段(即 undefined,不是 false)。
三、实体鼠标事件
bus.on(VjmapextEvents.EntityClick, ({ entity, originalEvent }) => {
console.log('click:', entity.id, entity.type);
});
bus.on(VjmapextEvents.EntityDblClick, ({ entity }) => {
if (entity.type === 'TEXT' || entity.type === 'MTEXT') {
mapcadLayer.executeCommand('TEXTEDIT');
}
});
bus.on(VjmapextEvents.EntityMouseEnter, ({ entity }) => {
entity.setCustomProperty('__prevColor', entity.color);
entity.color = 0xff0000;
entity.styleChanged();
});
bus.on(VjmapextEvents.EntityMouseLeave, ({ entity }) => {
entity.color = entity.getCustomProperty('__prevColor')?.value ?? entity.color; // 返回 {type,value}
entity.styleChanged();
});
四、结合修饰键
entity:click 在内置选中逻辑之前同步发出,handler 返回后内置逻辑会再执行(普通单击 setSelection([id]) 替换选集、Shift+单击 toggle)——handler 里直接 setSelection 会被立刻覆盖。内置的多选键是 Shift;非要 Ctrl 多选,得等内置逻辑跑完再改:
bus.on(VjmapextEvents.EntityClick, ({ entity, originalEvent }) => {
if (!originalEvent.ctrlKey || originalEvent.shiftKey) return; // 其余交给内置逻辑
const ids = mapcadLayer.store.getSelectedIds(); // 内置逻辑执行前的选集(副本)
const i = ids.indexOf(entity.id);
if (i >= 0) ids.splice(i, 1);
else ids.push(entity.id);
queueMicrotask(() => mapcadLayer.store.setSelection(ids)); // 在内置 setSelection([id]) 之后再覆盖
});
五、实体批量统计
let count = 0;
bus.on(VjmapextEvents.EntityAdded, () => { count++; refresh(); });
bus.on(VjmapextEvents.EntityDeleted, () => { count--; refresh(); });
六、性能提示
- 上万 entity 同时 add 会触发上万次
entity:added→ handler 里不要做昂贵操作,或合并到command:ended统一处理(store:changed在 1.0.1 从未发射,不能用作聚合出口,见 bus-render-store)。 entity:mouseenter / leave只在悬停对象切换时 fire(同一实体上移动不重复发),且只在空闲态(非命令输入/拖拽中)检测;悬停到夹点上也会先发 leave。handler 本身不必节流,但别做重活。
七、事件级联防死循环
bus.on(VjmapextEvents.EntityModified, ({ entityId }) => {
const entity = mapcadLayer.store.get(entityId);
// 错误示例:这里再次改 entity → 又触发 modified → 无限
entity.color = 0xff0000;
entity.styleChanged();
});
正确做法:
const processed = new WeakSet();
bus.on(VjmapextEvents.EntityModified, ({ entityId, styleOnly }) => {
if (styleOnly) return; // 样式变化不再二次改
const entity = mapcadLayer.store.get(entityId);
if (processed.has(entity)) return;
processed.add(entity);
entity.color = 0xff0000;
entity.styleChanged();
});
八、在命令期间捕获新增
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, '条');
}
});
bus.on(VjmapextEvents.EntityAdded, ({ entity }) => {
if (capturing) captured.push(entity);
});
九、off / once
const handler = ({ entity }) => { ... };
bus.on(VjmapextEvents.EntityAdded, handler);
bus.off(VjmapextEvents.EntityAdded, handler);
bus.once(VjmapextEvents.EntityAdded, handler); // 只触发一次
十、常见坑
- mouseenter 每次进离重复绑样式:用
_prevColor缓存,避免连续 enter 导致绿色反转。 entity:added在store.add之后:不要在 handler 里再store.add同一个实体。- 命令中 fire
entity:click? 命令执行期间默认 fire 的是 input 事件,实体 click 可能被屏蔽。 - selection 和 click 顺序:实体 click → 自动 selection:changed;监听任一都可以得到选中。
- 匿名函数无 off → 清理困难。
相关
- 选集事件 → bus-selection
- 命令事件 → bus-command-mode
- 实体生命周期 → entity/lifecycle