唯杰地图 logo唯杰地图
VJMAP
EN

style-only-fast-path

vjmapext/references/perf/style-only-fast-path.md 6.2 KB144 行
原文

本文回答:entity.styleChanged() —— 只改 color / lineWidth / effect_* 时的快路径,比 changed() 快 5~20 倍(visible/fill/lineType 不在快路径)。

一、两种 API 对比

方法 内部路径 代价
entity.changed() 进 _changedIds → 从桶摘除 → 重跑 toGeoJSON() + CAD→经纬度变换 → 重插桶 重编码 + 所在桶 setData 整体重传
entity.styleChanged() 进 _styleOnlyIds → renderCache.updateStyleProps(e) → 对缓存的每个 feature 调 e.updateFeatureStyleProps(feature) 原地 patch 属性 不重编码;所在桶照样 setData 重传

省的是重编码 + 坐标变换,不是 GPU 上传——桶的 GeoJSON 两种路径都要重传。实体越少动,差距越大。

二、何时必须 changed()

改了什么 必须用 changed()
起点 / 终点 / center / radius / points ✅
rotation / transform ✅
insertionPoint / scale ✅
text 内容(文字尺寸不变情况可能 style 够用,但保守用 changed) ✅

三、何时可以 styleChanged()

覆盖范围只有 3 组属性(EntityBase.updateFeatureStyleProps 唯一定义处,且无子类重写):

改了什么 styleChanged() 生效? 原因
color ✅ feature properties.color 被原地 patch
lineWidth ✅(文本实体除外;改回 0 除外) patch line_width;_role 为 text_fill/text_stroke 的 feature 被跳过。只在 lineWidth > 0 时写、从不删——改回 0 后旧值残留,须 changed()
effectColor / effectWidth / effectOpacity / effectBlur ✅ patch effect_* 四个属性(effectColor=-1 时改为删除)
fillColor / fillOpacity / borderOpacity ❌ 用 changed() 不在 patch 清单内,缓存 feature 保留旧值
lineType / ltScale ❌ 用 changed() 虚线是** tessellate 进几何坐标**的(tessellateWithLinetype),不是样式属性
visible ❌ 用 changed() 可见性在桶重建时过滤,styleOnly 路径不重查
layerId ❌ 用 changed() 图层归属不在 patch 清单
minDisplayLevel / maxDisplayLevel ❌ 用 changed() display-level 过滤在重建时做

opacity 字段不存在于 EntityBase(有的是 fillOpacity/borderOpacity/effectOpacity)。

四、对比示例

// 慢:1 万实体每条 changed()
const t0 = performance.now();
for (const e of mapcadLayer.getEntities()) {
  e.color = 0xff0000;
  e.changed();                // ← 全量
}
console.log(performance.now() - t0);   // 比如 2500ms

// 快:1 万实体每条 styleChanged()
const t1 = performance.now();
for (const e of mapcadLayer.getEntities()) {
  e.color = 0xff0000;
  e.styleChanged();           // ← 快路径
}
console.log(performance.now() - t1);   // 比如 180ms

五、批量修改

for (const e of entities) {
  e.color = 0xff0000;
  e.styleChanged();
}
// 标脏后所在桶在下一帧合并 setData 一次(RAF 调度,无需手动 bulk)

六、bus 事件差异

bus.on(VjmapextEvents.EntityModified, ({ entityId, styleOnly }) => {
  // payload 是 { entityId, styleOnly } —— 是 id 不是实体对象
  if (styleOnly) {
    // 来自 styleChanged()
  } else {
    // 来自 changed()
  }
});

下游可根据 styleOnly 决定是否重建自己的索引。

七、feature-state(vjmap 底座版)

对 GeoJSON 图层,底座有类似的快路径 —— feature-state:

map.setFeatureState({ source: 'src', id: 123 }, { hover: true });

map.addLineLayer('lyr', 'src', {
  lineColor: ['case',
    ['boolean', ['feature-state', 'hover'], false], '#f00', '#888'
  ]
});

不需要 setData,只改 state → 自动重绘(毫秒级)。配合表达式覆盖大范围 hover。

八、自定义实体支持快路径

没有 encode/encodeStyle/encodeGeometry 这套 API——快路径的真实挂钩是 updateFeatureStyleProps(feature):基类实现只 patch color / line_width / effect_*。自定义实体若在 toGeoJSON() 里往 properties 塞了额外的样式字段(如 fill_color、自定义角色 _role),想享受快路径就重写它:

class StarEnt extends vjmapext.EntityBase {
  updateFeatureStyleProps(feature) {
    super.updateFeatureStyleProps(feature);      // color / line_width / effect_*
    const p = feature.properties;
    if (p) p.fill_color = '#' + this.fillColor.toString(16).padStart(6, '0');
  }
}

不重写也能用——只是 fillColor 等自定义样式字段必须走 changed() 全量。

九、批量换色最佳实践

function setBatchColor(ents, color) {
  for (const e of ents) {
    if (e.color === color) continue;        // 跳过无变化
    e.color = color;
    e.styleChanged();
  }
}
  • 同一帧内多次 styleChanged() 合并成一次桶 setData(rAF 调度)
  • 跳过无变化避免无谓标脏与上传

十、常见坑

  1. 改了几何还调 styleChanged:画面没变;用 changed()。
  2. 改了 fillColor / lineType / visible / layerId 用 styleChanged:同样不生效——这些不在 updateFeatureStyleProps 的 patch 清单里,必须 changed()。
  3. 自定义实体 styleChanged 不生效:自有样式字段需重写 updateFeatureStyleProps(见 §八)。
  4. 循环里每条 changed + styleChanged:changed 已包含 style,别再 styleChanged——而且先 changed() 后 styleChanged() 会吞掉几何更新:styleChanged 把 id 重新放回 styleOnlyIds,本帧只原地 patch 旧缓存的样式并清掉 isDirty,新几何不会重算。只有反过来(先 styleChanged 后 changed,changed 会把 id 从 styleOnlyIds 摘除)才走全量。
  5. map 的 feature-state 不生效:source 没设 generateId: true 或 promoteId,feature 没 id。
  6. styleChanged 后事件里又 changed:变成全量;监听 styleOnly 再决定。

相关