唯杰地图 logo唯杰地图
VJMAP
EN

bulk-style-update

vjmapext/references/batch/bulk-style-update.md 4.9 KB114 行
原文

本文回答:大量实体只改样式(color / lineWidth / effect_*)时用 styleChanged 快路径,避免几何重算;visible / fill / lineType 不在快路径。

一、为什么要分快慢两路径

实体每次 dirty 会触发:

信号 空间索引重建 顶点缓冲重构 样式缓冲刷新
changed() ✅ ✅ ✅
styleChanged() ❌ ❌ ✅

只改颜色 / 线宽等样式 → 用 styleChanged() 省掉前两步,差几倍性能。

二、基础用法

mapcadLayer.getEntities()
  .filter(e => e.layerId === '标注')
  .forEach(e => {
    e.color = 0xff0000;
    e.styleChanged();           // ← 不是 changed
  });

无需手动包批处理:styleChanged 只标脏,重绘由 requestAnimationFrame 自动合并到下一帧。

三、只修改样式的属性白名单

styleChanged() 快路径走 renderCache.updateStyleProps → 实体 updateFeatureStyleProps(feature),只回写以下 feature props:

  • color(→ t.color)
  • lineWidth(→ t.line_width,跳过 TEXT_FILL/TEXT_STROKE 角色)——⚠️ 只在 lineWidth > 0 时写入、从不删除:把线宽改回 0 时缓存里的旧 line_width 留着,须用 changed()
  • effectColor / effectWidth / effectOpacity / effectBlur(→ t.effect_*;effectColor===-1 时删除这些 props)

以下属性 styleChanged() 不会生效,必须用 changed():

  • fillColor / fillOpacity / borderOpacity / opacity —— fill/透明度 props 不在回写清单,改了画面不变
  • visible —— 可见性只在全量重建时过滤(!d.visible → continue),styleChanged 后实体仍在渲染桶里
  • layerId —— 图层隐藏检查 hiddenLayerChecker 只在全量路径执行
  • lineType / ltScale / ltOffset —— 线型改变 tessellation 几何(虚线展开),必须重建
  • 任何几何(point / center / radius / angle / text ...)、rotation(影响包围盒)
  • setCustomProperty —— 不影响渲染(也不用 dirty,业务属性随便改)

四、大量实体瞬切主题

function applyTheme(theme) {
  mapcadLayer.getEntities().forEach(e => {
    e.color = theme[e.layerId] || theme.default;
    e.styleChanged();
  });
}

applyTheme({ wall: 0x888888, door: 0xff4444, window: 0x44ff44, default: 0xcccccc });

五、按条件批量染色

mapcadLayer.getEntities().forEach(e => {
  const temp = e.getCustomProperty('temp')?.value ?? 0;   // 返回 {type,value} 包装,取 .value
  if (temp > 100)      e.color = 0xff0000;
  else if (temp > 60)  e.color = 0xffaa00;
  else if (temp > 30)  e.color = 0x00aaff;
  else                 e.color = 0x00ff00;
  e.styleChanged();
});

六、事务包装 Undo

改属性/styleChanged() 不会自动记 undo(只有 store.add/store.delete 自动入栈),空事务也不入栈——光把 applyTheme 包进事务,Ctrl+Z 什么都不撤。要可撤销,改之前逐个 recordModify 快照:

const um = mapcadLayer.undoManager;
um.beginTransaction();
mapcadLayer.getEntities().forEach(e => {
  um.recordModify(e);                                // 改之前快照
  e.color = darkTheme[e.layerId] || darkTheme.default;
  e.styleChanged();
});
um.endTransaction();

这样一次 Ctrl+Z 撤销整批样式修改(撤销是按快照删旧实体再加回,见 drawing/undo-redo)。

七、批量显隐

visible 不在 styleChanged 快路径(见 §3),要用 changed():

mapcadLayer.getEntities()
  .filter(e => e.layerId === '辅助')
  .forEach(e => { e.visible = false; e.changed(); });

八、特例:批量 deleteEntity

删除要重建空间索引,没快路径;直接循环 deleteEntity 即可(重绘按帧合并),需要一步撤销就包 beginTransaction/endTransaction。

九、常见坑

  1. 用 changed() 改样式 → 慢数倍,几何并没变。
  2. 改完几何又改颜色:changed() 已含样式刷新,一次即可——千万别在 changed() 之后同帧再 styleChanged():后者把 id 重新标成 style-only,本帧只 patch 缓存 feature 的样式,几何更新被吞(且 isDirty 被清,之后也不会补)。顺序反过来(先 styleChanged 后 changed)则无害。
  3. styleChanged 后 bounding box 不变:正确;只有 changed 才会刷新空间索引。
  4. visible/fill 不属于样式快路径:visible、fillColor、fillOpacity 等改了要用 changed();styleChanged() 只会更新缓存 feature 的 color/line_width/effect_*,其余属性画面不变。
  5. 实体图层字段是 layerId:不是 layer。

相关