> **本文回答**：`entity.dynamic = true` —— 为什么需要、何时用、性能差别。

## 一、问题：静态实体频繁改，画面不更新 / 非常卡

```js
const line = new vjmapext.LineEnt(p1, p2);
mapcadLayer.addEntity(line);

setInterval(() => {
  line.endPoint.x += 1;   // 原地改字段，保持 Point2D 实例（别赋 {x,y} 字面量，getGripPoints/clone 路径会崩）
  line.changed();
}, 16);
```

现象：

- 画面每帧都更新（正确）
- 但每帧都会对 **cold 桶整条 GeoJSON source `setData`**——上万实体的 features 重新序列化上传一次
- 导致 10 FPS

## 二、解法：`entity.dynamic = true`

```js
const line = new vjmapext.LineEnt(p1, p2);
line.dynamic = true;           // ← 关键
mapcadLayer.addEntity(line);
```

此后 `line.changed()` 只会让 **dyn 桶那条 GeoJSON source** 重 `setData`，不再牵连几万条的 cold source。

## 三、语义

`dynamic = true` 告诉渲染管线把该实体的 features 放进独立的 `dyn` 桶。渲染管线内部是**三条 GeoJSON source**（`hot`/`cold`/`dyn`，不是 GL buffer）：

- 实体进 **dyn 桶**（独立 FeatureCollection source）
- `changed()` → 增量更新只重算该实体的 features，再对 **dyn source** 调 `setData`（几十/几百条），cold source（几万条）不动
- `styleChanged()` 走 styleOnly 快路径：直接回写缓存 feature 属性，连重算都省（见 [style-only-fast-path](style-only-fast-path.md)）
- 没设 dynamic 时，`changed()` 会让整条 cold source `setData` —— 实体越多这一下越贵

## 四、什么时候一定要设 dynamic

| 场景 | 必须 dynamic |
|---|---|
| 实体每帧改位置（路径跟随、平移动画） | ✅ |
| 实体每帧改颜色 / alpha（闪烁、脉冲） | ✅ |
| 用 [动画/特效系统](fx-overview.md) 驱动 | ✅ |
| 跟随鼠标 / 橡皮筋 | ✅（或走 PreviewManager） |

## 五、什么时候不要设 dynamic

| 场景 | 保持 cold |
|---|---|
| 从 DWG 加载几万静态实体 | ❌（全用 dynamic 反而慢） |
| 用户偶尔点一下改颜色 | ❌（hot 桶会自动处理） |
| 一次画完不再动 | ❌ |

规则：**默认不动**；只给真正高频变化的实体单独开。

## 六、dynamic + 动画

```js
const circle = new vjmapext.CircleEnt([0, 0], 10);
circle.dynamic = true;
mapcadLayer.addEntity(circle);

let t = 0;
function tick() {
  t += 0.016;
  circle.radius = 10 + 5 * Math.sin(t);
  circle.color = 0xff0000 + Math.floor(127 * Math.sin(t));
  circle.changed();
  requestAnimationFrame(tick);
}
tick();
```

不设 dynamic 的话，每帧都会让 cold 桶一起重建，整张图都卡。

## 七、dynamic 实体怎么迁回 cold

场景：动画结束后想变回"静态"。

```js
circle.dynamic = false;
circle.changed();           // 触发重分桶
```

内部：实体从 dynamic 桶移出，进 cold 桶（下一次批次 rebuild 时合并）。

**但一般不用管**：dynamic 桶空间充足，留着也没事。

## 八、dynamic + bulk

```js
for (const e of loadedEntities) {
  e.dynamic = true;
  mapcadLayer.addEntity(e);
}
```

允许但**不推荐**：dynamic 桶一次塞 1 万条也会慢。对于一次性加载的大量数据，走 cold 实体更快（重绘由 RAF 自动合并，不需要手动 bulk）。

## 九、查看 dynamic 实体数

```js
const dynCount = mapcadLayer.getEntities().filter(e => e.dynamic).length;
console.log('dynamic 实体:', dynCount);
```

正常业务 dynamic < 100；超过 1000 说明过度使用。

## 十、和动画系统的关系

vjmapext 的 `AnimationManager`（顶层导出，另有 `KeyframeAnimator` / `PathAnimator` / `SpringAnimator`，四类均可 `new`）只是一个 **rAF 回调调度器**：它**不会**替你设 `dynamic`，也不替你标脏——不管用它还是手写 `setInterval`，高频改动的实体都要自己 `ent.dynamic = true`，并在回调里 `changed()`/`styleChanged()`。

```js
const am = mapcadLayer.animationManager;
circle.dynamic = true;                       // 自己设
am.add('blink', (dt, now) => {             // dt=距上次回调毫秒数，now=rAF 时间戳（不是累计时长）
  circle.radius = 50 + 10 * Math.sin(now / 300);
  circle.changed();
}, { maxFps: 60 });                          // 默认每个回调限 30fps；maxFps:0 = 每帧
am.remove('blink');
// 另有 am.addTween(id, tweenOptions, { maxFps }) 与
// am.addPathAnimation(id, pathOptions, (pos, angle, t) => {...}, { maxFps }) → 返回 PathAnimator
```

## 十一、常见坑

1. **忘设 dynamic**：每帧都触发 cold 桶 rebuild → 明显卡顿。
2. **所有实体都设 dynamic**：dynamic 桶膨胀，总体 FPS 反而下降。
3. **dynamic 实体 changed 不触发画面刷新**：确认确实调了 `changed()`/`styleChanged()`；没调就只改了字段、没标脏。
4. **一批实体一半 dynamic 一半 cold**：两桶都要 rebuild；全 dynamic 或全 cold 更干净。
5. **dynamic = true 后样式变了**：换桶会重新走 `toGeoJSON` 序列化；自定义实体若 `toFeatureStyleProps`/`updateFeatureStyleProps` 漏写字段 → 视觉异常。

## 相关

- 渲染桶 → [render-buckets](render-buckets.md)
- 批量 → [batch-rendering](batch-rendering.md)
- 动画性能 → [event-throttling](../../../vjmap/references/perf/event-throttling.md)
