cesium-multi-target-framework 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +474 -0
- package/dist/assets/renderWorker-118e8f3b.js +1 -0
- package/dist/cesium-multi-target-framework.js +4605 -0
- package/dist/cesium-multi-target-framework.umd.cjs +101 -0
- package/dist/cluster/QuadCluster.d.ts +66 -0
- package/dist/cluster/clusterClient.d.ts +44 -0
- package/dist/cluster/clusterWorker.d.ts +1 -0
- package/dist/config/types.d.ts +266 -0
- package/dist/core/EventEmitter.d.ts +9 -0
- package/dist/core/MultiTargetFramework.d.ts +184 -0
- package/dist/core/MultiTargetScene.d.ts +224 -0
- package/dist/data/types.d.ts +67 -0
- package/dist/events/bus.d.ts +336 -0
- package/dist/index.d.ts +22 -0
- package/dist/render/AirGroundReferenceRenderer.d.ts +20 -0
- package/dist/render/InstancedGltfBatch.d.ts +37 -0
- package/dist/render/InstancedSymbolRenderer.d.ts +65 -0
- package/dist/render/LowModelInstancedRenderer.d.ts +39 -0
- package/dist/render/ModelPoolRenderer.d.ts +43 -0
- package/dist/render/PointCloudRenderer.d.ts +135 -0
- package/dist/render/SelectionOverlayRenderer.d.ts +37 -0
- package/dist/render/targetVisualMetrics.d.ts +9 -0
- package/dist/site/SiteLayer.d.ts +43 -0
- package/dist/site/SiteLowModelRenderer.d.ts +12 -0
- package/dist/site/SiteSpatialIndex.d.ts +10 -0
- package/dist/site/types.d.ts +72 -0
- package/dist/track/TrackHoverPicker.d.ts +26 -0
- package/dist/track/TrackManager.d.ts +42 -0
- package/dist/track/TrackRenderer.d.ts +29 -0
- package/dist/track/types.d.ts +27 -0
- package/dist/worker/protocol.d.ts +182 -0
- package/dist/worker/renderWorker.d.ts +1 -0
- package/doc//345/244/232/347/233/256/346/240/207/344/274/230/345/214/226/344/270/216/351/242/204/346/265/213/346/270/262/346/237/223/350/257/264/346/230/216.md +186 -0
- package/doc//345/244/232/347/273/204/344/273/266/344/272/213/344/273/266/346/226/271/346/241/210.md +410 -0
- package/doc//345/257/271/345/244/226/346/216/245/345/217/243/350/257/264/346/230/216.md +519 -0
- package/doc//345/267/245/344/275/234/350/256/241/345/210/222.md +59 -0
- package/doc//346/270/262/346/237/223/344/270/232/345/212/241/351/200/273/350/276/221.md +202 -0
- package/doc//347/253/231/347/202/271/346/270/262/346/237/223/344/270/216/345/217/263/351/224/256/350/217/234/345/215/225/345/256/236/347/216/260/350/257/264/346/230/216.md +49 -0
- package/doc//350/247/206/345/217/243/351/251/261/345/212/250/346/225/260/346/215/256/346/265/201/347/250/213/344/277/256/346/224/271/350/256/241/345/210/222.md +69 -0
- package/doc//351/241/271/347/233/256/350/257/264/346/230/216/344/271/246.md +729 -0
- package/package.json +51 -0
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
# cesium-multi-target-framework
|
|
2
|
+
|
|
3
|
+
高性能 Cesium 多目标渲染框架。传入一个 Cesium `Viewer`,返回一个**包装过的高性能实例**:它拥有原 Viewer 的全部能力,并叠加海量目标的对象池、均匀网格空间索引、分帧调度、运动预测与三级 LOD 渲染。
|
|
4
|
+
|
|
5
|
+
- 兼容 Cesium 1.107.2 ~ 1.128.0(版本敏感 API 由适配层统一封装,当前依赖锁定 1.107.2)
|
|
6
|
+
- 数据 → 节点逻辑态 → 渲染协议 → 三级渲染后端,单向数据流
|
|
7
|
+
- 逻辑位(权威)与渲染位(插值)分离,支撑预测与平滑
|
|
8
|
+
- 完整对外接口、事件、配置见本文下方「对外接口说明」
|
|
9
|
+
|
|
10
|
+
## 安装与构建
|
|
11
|
+
|
|
12
|
+
> 运行环境:Node.js 16.x(已通过 `engines` 与 `.nvmrc` 限定;工具链使用 Vite 4 以兼容 node16)。
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install
|
|
16
|
+
npm run dev # 启动 demo(http://localhost:5173)
|
|
17
|
+
npm run build # 构建库,产出 dist/ 下 ESM + UMD + .d.ts
|
|
18
|
+
npm run typecheck # 仅类型检查
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 快速使用
|
|
22
|
+
|
|
23
|
+
推荐新接入使用 `MultiTargetFramework` / `createMultiTargetFramework`。本包会转导 Cesium 能力,因此使用方可以像使用 `cesium` 包一样从这里导入 `Viewer`、`Cartesian3` 等对象;多目标能力由独立实例管理,不会往原始 `Viewer` 上挂字段。
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { Viewer, MultiTargetFramework } from "cesium-multi-target-framework";
|
|
27
|
+
|
|
28
|
+
const viewer = new Viewer("cesiumContainer", {
|
|
29
|
+
animation: false,
|
|
30
|
+
timeline: false,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const multiTarget = new MultiTargetFramework(viewer, {
|
|
34
|
+
targetTypes: [
|
|
35
|
+
{
|
|
36
|
+
type: "ship",
|
|
37
|
+
name: "船舶",
|
|
38
|
+
iconPath: "/icons/target-ship-mask.png",
|
|
39
|
+
defaultColor: "#25e65c",
|
|
40
|
+
smoothMove: true,
|
|
41
|
+
smoothMoveMinCameraHeight: 25000,
|
|
42
|
+
predict: false,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: "uav",
|
|
46
|
+
name: "无人机",
|
|
47
|
+
iconPath: "/icons/target-uav-mask.png",
|
|
48
|
+
defaultColor: "#22d2f2",
|
|
49
|
+
smoothMove: true,
|
|
50
|
+
predict: true,
|
|
51
|
+
predictMinCameraHeight: 25000,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
scene: {
|
|
55
|
+
data: { commitIntervalMs: 2000, leading: true, worker: true },
|
|
56
|
+
merge: { enabled: true, maxVisible: 30000, byType: true },
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
multiTarget.setTargetData([
|
|
61
|
+
{
|
|
62
|
+
id: "ship-001",
|
|
63
|
+
type: "ship",
|
|
64
|
+
lon: 121.5,
|
|
65
|
+
lat: 31.2,
|
|
66
|
+
height: 0,
|
|
67
|
+
speedH: 8,
|
|
68
|
+
speedV: 0,
|
|
69
|
+
heading: 45,
|
|
70
|
+
renderColor: "#f81282",
|
|
71
|
+
openAnimate: true,
|
|
72
|
+
animateType: "发光",
|
|
73
|
+
animateColor: "#f81282",
|
|
74
|
+
},
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
viewer.camera.flyHome(0); // 原 Cesium Viewer 正常使用
|
|
78
|
+
const added = multiTarget.addTarget({
|
|
79
|
+
id: "manual-001",
|
|
80
|
+
type: "ship",
|
|
81
|
+
lon: 121.5,
|
|
82
|
+
lat: 31.2,
|
|
83
|
+
height: 0,
|
|
84
|
+
speedH: 0,
|
|
85
|
+
speedV: 0,
|
|
86
|
+
heading: 0,
|
|
87
|
+
});
|
|
88
|
+
multiTarget.setTargetColor(added.id, "#f81282");
|
|
89
|
+
multiTarget.setTargetGlow(added.id, true, "#f81282");
|
|
90
|
+
multiTarget.updateTarget({ ...added, heading: 45 });
|
|
91
|
+
void multiTarget.locateTarget(added.id);
|
|
92
|
+
multiTarget.upsertTargetData(nextTargets); // 多目标框架能力走实例
|
|
93
|
+
multiTarget.removeTargetData(["ship-001"]);
|
|
94
|
+
multiTarget.scene.on("perf", console.log);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 初始化就绪(作为依赖底座)
|
|
98
|
+
|
|
99
|
+
框架内部会启动一个 Web Worker,`new` 同步返回时引擎尚未就绪。若本框架是其它组件的依赖底座,需要「等它就绪再加载后续组件」,用 `ready` 或异步工厂:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
// 同步 new:可立即挂事件,需要就绪时再 await
|
|
103
|
+
const multiTarget = new MultiTargetFramework(viewer, options);
|
|
104
|
+
await multiTarget.ready; // 引擎(Worker 握手)就绪
|
|
105
|
+
loadOtherComponents(multiTarget);
|
|
106
|
+
|
|
107
|
+
// 或异步工厂:拿到的实例已就绪
|
|
108
|
+
const multiTarget2 = await MultiTargetFramework.create(viewer, options);
|
|
109
|
+
// createMultiTargetFramework(viewer, options) 同样返回 Promise<实例>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
> `ready` 只等引擎就绪;glTF 模型按需懒加载,不纳入就绪范围。
|
|
113
|
+
|
|
114
|
+
## 数据标准(统一口径)
|
|
115
|
+
|
|
116
|
+
所有进入框架的数据先满足 `TargetData`:速度单位 m/s,角度单位度,坐标 WGS84 经纬度 + 椭球高。
|
|
117
|
+
|
|
118
|
+
| 字段 | 含义 |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `id` | 唯一标识 |
|
|
121
|
+
| `type` | 目标类型,对应某个 `NodeTypeConfig.type` |
|
|
122
|
+
| `lon` / `lat` / `height` | 经度 / 纬度 / 高度 |
|
|
123
|
+
| `speedH` / `speedV` | 水平速度 / 垂直速度(向上为正) |
|
|
124
|
+
| `heading` | 航向(正北 0,顺时针) |
|
|
125
|
+
| `renderColor` | 单目标渲染颜色,`#RRGGBB` 或 `#RRGGBBAA`(可选) |
|
|
126
|
+
| `openAnimate` | 是否打开目标动画(可选) |
|
|
127
|
+
| `animateType` | 动画类型,当前内置支持 `glow` / `发光`(可选) |
|
|
128
|
+
| `animateColor` | 动画颜色,不传时沿用 `renderColor` 或类型默认色(可选) |
|
|
129
|
+
| `track` | 轨迹点数组(每项含位置 / 时间 / 当时航向,可选) |
|
|
130
|
+
| `secrecy` | 密级(可选,预留字段:当前仅随数据透传,未参与合并逻辑) |
|
|
131
|
+
|
|
132
|
+
更多字段和 packed 数据入口见本文下方「对外接口说明」。
|
|
133
|
+
|
|
134
|
+
## 节点类型配置 `NodeTypeConfig`
|
|
135
|
+
|
|
136
|
+
`name`、`type`、`highModelUrl`、`lowModelUrl`、`pointIcon`、`scale`、`modelHeadingOffset`、`lod`(高/中/低切换高度)、`smoothMove`(是否平滑)、`predictMove`(是否按预测移动)。
|
|
137
|
+
|
|
138
|
+
## 架构
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
业务数据 ── setData/upsert/applyIncremental ─→ MultiTargetScene
|
|
142
|
+
│ 归一化 + 口径统一 + 差分(data.worker 开启时在 Web Worker,renderWorker.ts)
|
|
143
|
+
│ + 全局聚合树分级建簇 + 相机分级 + 预测协调
|
|
144
|
+
▼
|
|
145
|
+
渲染分发(按相机离地高度 LOD / renderKind)
|
|
146
|
+
├─ PointCloudRenderer 点模式(BillboardCollection,三角贴图按 heading 旋转)
|
|
147
|
+
├─ LowModelInstancedRenderer 低模合批(按模型 URL 分组的 GPU 实例化 glTF,静态网格)
|
|
148
|
+
├─ ModelPoolRenderer 高模动画(Cesium Model 对象池,播放动画)
|
|
149
|
+
└─ InstancedSymbolRenderer 有向符号(自定义 DrawCommand GPU 实例化)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 三级 LOD(相机离地高度驱动)
|
|
153
|
+
|
|
154
|
+
- 高于 `pointAbove`:点模式
|
|
155
|
+
- 介于两者之间:低模合批
|
|
156
|
+
- 低于 `animatedBelow`:高模动画(受动画池容量约束,按距相机最近 + 选中/悬停优先取 topN)
|
|
157
|
+
|
|
158
|
+
### 运动预测与平滑
|
|
159
|
+
|
|
160
|
+
- 预测在 worker 内按目标 id 维护状态,只对 buffered viewport 内、低模 LOD 高度下、`predictMove: true` 的单目标启用。
|
|
161
|
+
- 默认 `predictSeconds: 10`、`predictFitSeconds: 2`:新数据到达时先从当前渲染位置 2 秒拟合到新航线,之后沿最新速度、航向、垂直速度持续外推。
|
|
162
|
+
- 聚合簇不参与预测;`predictMove: false` 的目标只保留原有平滑对齐权威位置行为。
|
|
163
|
+
|
|
164
|
+
### 贴近稳定性(姓名版/高模抖动治理)
|
|
165
|
+
|
|
166
|
+
相机贴近单目标(跟随、低空)时姓名版与高模会出现抖动,远处不可见、越近越明显。根因分三层,已逐层修复:
|
|
167
|
+
|
|
168
|
+
1. **高模运动判定失效(阶梯抖动)**:`ModelPoolRenderer` 判断目标是否移动时误用 `Cartesian3.equalsEpsilon(a, b, 0.001)`——第三参是**相对** epsilon,对 ~6.3×10⁶ 量级的 ECEF 坐标会放大成公里级容差,使任何正常位移都被判为"没动",高模逐帧 lerp 分支从不触发、直接逐包吸附成阶梯。改用绝对比较 `Cartesian3.distanceSquared(a, b) > 1e-4`(1cm 阈值)。
|
|
169
|
+
2. **姓名版锚点与相机不同源**:相机跟随走 `getRenderedTargetFrame`(model ?? point ?? symbol),而姓名版曾锚定 point billboard。`groundSymbols` 开启时船是贴地符号渲染、point 被隐藏,两条位置源分叉 → 姓名版相对相机漂移。改为姓名版经 `setAnchorPositionResolver` 锚到与相机**完全相同**的渲染位置源。
|
|
170
|
+
3. **billboard 大坐标 Float32 投影量化(RTC 治理)**:即便位置数值一致,billboard 走 GPU 路径用 Float32 投影 ~6.3×10⁶ 的绝对 ECEF 坐标,量化误差 ≈ 0.3~0.7m,贴近时(1px≈0.13m)放大成数像素抖动。`labelCollection` 改用 **RTC(相对相机中心)**:每帧把 `modelMatrix` 设为"相机位置丸到 100m 网格"的平移,billboard `position` 只存"锚点 − 参考点"的米级小偏移,GPU 不再对大坐标做 Float32 投影。参考点网格丸避免相机微动引入新抖源;绝对位置缓存(`labelPositionsById`)不变,其它逻辑仍按绝对坐标工作。
|
|
171
|
+
|
|
172
|
+
> 验证手段:`demo/jitter-lab.html` 对照页用同一条匀速轨迹喂 6 种渲染方式(Billboard / Label / Entity / DOM 取整 / DOM 不取整 / Billboard+RTC),贴近肉眼对比即可定位抖动来源——DOM(CPU·Float64 投影)与 Billboard+RTC 不抖,普通 GPU 图元抖。
|
|
173
|
+
|
|
174
|
+
### 交互拾取
|
|
175
|
+
|
|
176
|
+
拾取用**屏幕像素均匀网格**(把可见目标投影到屏幕、按网格分桶,命中半径内取像素距离最近者)替代 Cesium 原生左键 `scene.pick`(海量目标下原生拾取很卡,框架会移除原生左键查找)。选中/悬停目标会被强制升级为高模并在动画池中优先占位。
|
|
177
|
+
|
|
178
|
+
### 自适应递进合并
|
|
179
|
+
|
|
180
|
+
当**视野内目标数超过 `merge.maxVisible`(缺省取对象池容量 `pool.size`)**时启用合并:沿半径阶梯 `merge.radii`(缺省 100m→200m→500m→1km→2km→3km→…→10km)**从小到大逐级试探**,对每个可见目标按 `floor(ECEF坐标 / 半径)` 落入均匀网格、**同网格 + 同类型**合成一簇,数出合并后簇数;第一个能把簇数压到 `maxVisible` 以内的半径即采用(都不达标则用最大半径尽力压缩)。每格第一个为簇心,其余 `mergedHidden=true` 不渲染,簇心 `node.mergedCount` 记录簇大小。
|
|
181
|
+
|
|
182
|
+
逐级试探每级一遍 O(可见目标数) 网格哈希、不做逐点范围查询,并复用相机移动/最大间隔帧的降频重算,避免每帧抖动。场景内部 `lastMergeRadius` 暴露本次采用的半径(0 表示未触发)。
|
|
183
|
+
|
|
184
|
+
> 网格法按格归并,相邻格子边界两侧即使物理很近也不并簇(固有近似),但对降低渲染总数足够,是海量点聚类的最快路径;目标拾取与站点范围查询另用屏幕像素 / 经纬度均匀网格索引完成。
|
|
185
|
+
|
|
186
|
+
## 关键调参
|
|
187
|
+
|
|
188
|
+
| 配置 | 默认 | 含义 |
|
|
189
|
+
| --- | --- | --- |
|
|
190
|
+
| `lod.pointAbove` | 150000 | 高于此高度走点模式(米) |
|
|
191
|
+
| `lod.animatedBelow` | 12000 | 低于此高度走高模动画(米) |
|
|
192
|
+
| `pool.size` | 30000 | 通用对象池容量 |
|
|
193
|
+
| `animatedPool.size` | 64 | 高模动画同时并发上限 |
|
|
194
|
+
| `updateFps` | 30 | 帧循环频率 |
|
|
195
|
+
| `data.commitIntervalMs` | 2000 | 数据入口合并提交周期;设为 0 表示每次写入立即提交 |
|
|
196
|
+
| `data.leading` | true | 第一批数据是否立即提交 |
|
|
197
|
+
| `data.worker` | true | 周期性总数据归一化与 diff 是否放到 Web Worker |
|
|
198
|
+
| `merge.mode` | `"global"` | 合并策略;全局层级树,低空也会结合视口查询 |
|
|
199
|
+
| `merge.globalRootLimit` | 500 | global 模式下顶层根聚合点数量上限 |
|
|
200
|
+
| `merge.globalRebuildIntervalMs` | 300000 | global 模式下全局树最短重建间隔 |
|
|
201
|
+
| `frame.maxLowModelRenderItems` | 3000 | 同时进入低模后端的目标上限;超过则整批回退点云 |
|
|
202
|
+
| `frame.maxModelRenderItems` | 2000 | 旧配置兼容项,建议改用 `frame.maxLowModelRenderItems` |
|
|
203
|
+
| `predictSeconds` | 10 | 预测窗口秒数;无新数据时超过窗口仍沿最新航线持续外推 |
|
|
204
|
+
| `predictFitSeconds` | 2 | 新权威数据到达后的航线拟合秒数 |
|
|
205
|
+
| `masterHideHeight` | 150000 | 高于此高度隐藏所有模型(点保留) |
|
|
206
|
+
| `pick.pixelThreshold` | 20 | 拾取命中像素阈值 |
|
|
207
|
+
| `cull.viewportBufferMinMeters` | 500 | 视口裁剪缓冲的绝对下限(米)。相机贴近时视野矩形极小,单纯按 `viewportBufferRatio` 的相对缓冲不足以覆盖近处快速目标在一帧节流窗口内的位移,会被裁掉造成闪烁;实际缓冲取 `max(相对缓冲, 该下限)`,高空时相对缓冲远大于此值故不受影响 |
|
|
208
|
+
|
|
209
|
+
完整 API、事件、站点层、轨迹、聚类工具和配置默认值见本文下方「对外接口说明」;设计原理详见 `doc/多目标优化与预测渲染说明.md`,实施记录见 `doc/工作计划.md`。
|
|
210
|
+
|
|
211
|
+
## 对外接口说明
|
|
212
|
+
|
|
213
|
+
本文档按 `src/index.ts` 的包根入口整理当前对外能力,适用于从 `cesium-multi-target-framework` 接入的业务方。
|
|
214
|
+
|
|
215
|
+
### 一、包根导出
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import {
|
|
219
|
+
Viewer,
|
|
220
|
+
MultiTargetFramework,
|
|
221
|
+
createMultiTargetFramework,
|
|
222
|
+
SiteLayer,
|
|
223
|
+
TrackManager,
|
|
224
|
+
createQuadClusterer,
|
|
225
|
+
clusterProgressive,
|
|
226
|
+
lonLatToLocalPlane,
|
|
227
|
+
createClusterWorkerClient,
|
|
228
|
+
bindFrameworkEventBus,
|
|
229
|
+
bindSiteLayerEventBus,
|
|
230
|
+
getFrameworkEventBus,
|
|
231
|
+
} from "cesium-multi-target-framework";
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
包根导出分为七类:
|
|
235
|
+
|
|
236
|
+
| 类别 | 导出 |
|
|
237
|
+
| --- | --- |
|
|
238
|
+
| Cesium | `export * from "cesium"`,可直接导入 `Viewer`、`Cartesian3` 等 Cesium API |
|
|
239
|
+
| 高层目标框架 | `MultiTargetFramework`、`createMultiTargetFramework` |
|
|
240
|
+
| 底层目标场景 | `MultiTargetScene` |
|
|
241
|
+
| 轨迹和站点 | `TrackManager`、`SiteLayer` |
|
|
242
|
+
| Web Event Bus | `bindFrameworkEventBus`、`bindSiteLayerEventBus`、`getFrameworkEventBus`、`tryGetFrameworkEventBus`、`createFrameworkEventBus` |
|
|
243
|
+
| 聚类工具 | `createQuadClusterer`、`clusterProgressive`、`lonLatToLocalPlane`、`createClusterWorkerClient` |
|
|
244
|
+
| 常量 | `VERSION`、`DEFAULT_LOD`、`DEFAULT_POOL`、`DEFAULT_ANIMATED_POOL`、`DEFAULT_SCENE`、`TARGET_DOMAINS` |
|
|
245
|
+
|
|
246
|
+
常用类型包括:`TargetData`、`StandardTargetData`、`TrackPoint`、`IncrementalPayload`、`PackedTargetData`、`SceneConfig`、`MultiTargetFrameworkOptions`、`MultiTargetTypeConfig`、`TargetSnapshot`、`ContextMenuContext`、`SiteData`、`SiteLayerOptions`、`TrackRecord`、`ClusterWorkerClient`、`FrameworkEventBus`、`FrameworkBusActionMap`、`FrameworkBusEventMap` 等。
|
|
247
|
+
|
|
248
|
+
### 二、高层入口 `MultiTargetFramework`
|
|
249
|
+
|
|
250
|
+
推荐业务优先使用该入口。它不改写原始 `Viewer`,而是在内部持有 `scene`、`viewer`、`tracks`。
|
|
251
|
+
|
|
252
|
+
#### 创建
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
const framework = new MultiTargetFramework(viewer, {
|
|
256
|
+
targetTypes: [
|
|
257
|
+
{
|
|
258
|
+
type: "ship",
|
|
259
|
+
name: "船舶",
|
|
260
|
+
iconPath: "/icons/target-ship-mask.png",
|
|
261
|
+
defaultColor: "#25e65c",
|
|
262
|
+
smoothMove: true,
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
scene: {
|
|
266
|
+
data: { commitIntervalMs: 2000, leading: true, worker: true },
|
|
267
|
+
merge: { enabled: true, maxVisible: 30000 },
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// 等价工厂(异步:等引擎就绪后 resolve)
|
|
272
|
+
const framework2 = await createMultiTargetFramework(viewer, options);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`MultiTargetFramework` 内部会启动一个 Web Worker,构造函数同步返回时引擎尚未就绪。需要「初始化完成后再加载依赖底座的其它组件」时,有两种等价写法:
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
// 写法一:同步 new,可立即挂事件/调方法,需要就绪时再 await
|
|
279
|
+
const framework = new MultiTargetFramework(viewer, options);
|
|
280
|
+
framework.scene.on("perf", console.log);
|
|
281
|
+
await framework.ready; // 引擎(Worker 握手)就绪
|
|
282
|
+
loadOtherComponents(framework);
|
|
283
|
+
|
|
284
|
+
// 写法二:异步工厂,拿到的实例已就绪
|
|
285
|
+
const framework3 = await MultiTargetFramework.create(viewer, options);
|
|
286
|
+
loadOtherComponents(framework3);
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
> `ready` 只等引擎就绪(Worker init 握手完成);glTF 模型按需懒加载,不纳入就绪范围。
|
|
290
|
+
|
|
291
|
+
`MultiTargetFrameworkOptions`:
|
|
292
|
+
|
|
293
|
+
| 字段 | 说明 |
|
|
294
|
+
| --- | --- |
|
|
295
|
+
| `targetTypes` | 必填,目标类型数组 |
|
|
296
|
+
| `scene` | 可选,除 `nodeTypes` 之外的 `SceneConfig` |
|
|
297
|
+
|
|
298
|
+
`MultiTargetTypeConfig` 重点字段:`type`、`name`、`targetDomain`、`iconPath`、`defaultColor`、`highModel`、`lowModel`、`highModelUrl`、`lowModelUrl`、`scale`、`modelHeadingOffset`、`modelPitchOffset`、`modelRollOffset`、`smoothMove`、`smoothMoveMinCameraHeight`、`smoothMoveDurationMs`、`predict`、`predictMove`、`predictMinCameraHeight`、`predictSeconds`、`predictFitSeconds`。
|
|
299
|
+
|
|
300
|
+
#### 数据方法
|
|
301
|
+
|
|
302
|
+
| 方法 | 说明 |
|
|
303
|
+
| --- | --- |
|
|
304
|
+
| `setData(targets)` | `setTargetData` 的别名,全量替换目标数据 |
|
|
305
|
+
| `upsert(targets)` | `upsertTargetData` 的别名,增量新增或更新 |
|
|
306
|
+
| `remove(ids)` | `removeTargetData` 的别名,按 id 删除 |
|
|
307
|
+
| `addTarget(target)` | 校验并实时 upsert 单目标,返回校验后的目标 |
|
|
308
|
+
| `updateTarget(target)` | 校验并实时 upsert 单目标,返回校验后的目标 |
|
|
309
|
+
| `setTargetData(targets)` | 全量替换目标数据 |
|
|
310
|
+
| `upsertTargetData(targets)` | 增量新增或更新目标数据 |
|
|
311
|
+
| `removeTargetData(ids)` | 实时删除目标 |
|
|
312
|
+
| `applyTargetIncremental(payload)` | 应用 `{ upserts, removes }` 增量包 |
|
|
313
|
+
|
|
314
|
+
`MultiTargetFramework` 会校验目标字段,只允许 `id`、`type`、`lon`、`lat`、`height`、`speedH`、`speedV`、`heading`、`renderColor`、`openAnimate`、`animateType`、`animateColor`、`nationality`、`customInfo`、`track`、`secrecy`、`extra`。
|
|
315
|
+
|
|
316
|
+
#### 样式和显示
|
|
317
|
+
|
|
318
|
+
| 方法 | 说明 |
|
|
319
|
+
| --- | --- |
|
|
320
|
+
| `setTargetColor(id, color, options?)` | 设置单个或多个目标颜色,颜色格式 `#RRGGBB` 或 `#RRGGBBAA` |
|
|
321
|
+
| `setTargetGlow(id, enabled, color?, options?)` | 开关发光动画 |
|
|
322
|
+
| `hideTarget(id, options?)` | 隐藏目标 |
|
|
323
|
+
| `showTarget(id, options?)` | 显示目标 |
|
|
324
|
+
| `disappearTarget(id, options?)` | `hideTarget` 别名 |
|
|
325
|
+
| `appearTarget(id, options?)` | `showTarget` 别名 |
|
|
326
|
+
| `setNameplateConfig(config)` | 动态更新名称牌/标签配置 |
|
|
327
|
+
|
|
328
|
+
`id` 可传字符串或字符串数组。`TargetStyleOptions.clearBefore` 默认 `true`,表示本次样式补丁会先清理旧同类样式;`clearBefor` 为兼容旧拼写。
|
|
329
|
+
|
|
330
|
+
#### 选择、框选和定位
|
|
331
|
+
|
|
332
|
+
| 方法 | 说明 |
|
|
333
|
+
| --- | --- |
|
|
334
|
+
| `selectTarget(id, options?)` | 选中目标,返回 `TargetSnapshot | null` |
|
|
335
|
+
| `selectTargets(ids, options?)` | 批量选中目标,返回存在的快照数组 |
|
|
336
|
+
| `unselectTarget(id)` | 取消单目标选中 |
|
|
337
|
+
| `clearSelection()` | 清空选中和框选状态 |
|
|
338
|
+
| `boxTarget(id, enabled?, options?)` | 设置黄色框选覆盖层,`enabled` 默认 `true` |
|
|
339
|
+
| `unboxTarget(id, options?)` | 取消框选 |
|
|
340
|
+
| `locateTarget(id, options?)` | 飞行定位目标,返回目标快照 |
|
|
341
|
+
|
|
342
|
+
`LocateTargetOptions`:
|
|
343
|
+
|
|
344
|
+
| 字段 | 默认 | 说明 |
|
|
345
|
+
| --- | --- | --- |
|
|
346
|
+
| `range` | `18000` | 相机离目标距离,单位米 |
|
|
347
|
+
| `height` | - | 兼容旧字段,低优先级 |
|
|
348
|
+
| `duration` | `0.8` | 飞行时间,秒 |
|
|
349
|
+
| `pitch` | `-65` | 俯仰角,度 |
|
|
350
|
+
| `heading` | `0` | 航向角,度 |
|
|
351
|
+
|
|
352
|
+
#### 右键菜单
|
|
353
|
+
|
|
354
|
+
| 方法 | 说明 |
|
|
355
|
+
| --- | --- |
|
|
356
|
+
| `registerContextMenuItem(item)` | 注册菜单项,返回注销函数 |
|
|
357
|
+
| `showContextMenu(ctx)` | 使用统一菜单 DOM 展示上下文 |
|
|
358
|
+
| `closeContextMenu()` | 关闭菜单 |
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
const dispose = framework.registerContextMenuItem({
|
|
362
|
+
key: "locate",
|
|
363
|
+
label: "定位",
|
|
364
|
+
targetKinds: ["target", "site"],
|
|
365
|
+
order: 10,
|
|
366
|
+
visible: (ctx) => ctx.target.kind !== "ground",
|
|
367
|
+
onClick: async (ctx) => {
|
|
368
|
+
if (ctx.target.kind === "target") await ctx.framework.locateTarget(ctx.target.id);
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
`ContextMenuContext.target.kind` 支持:
|
|
374
|
+
|
|
375
|
+
| kind | 数据 |
|
|
376
|
+
| --- | --- |
|
|
377
|
+
| `"target"` | `id`、`type`、`data: TargetSnapshot` |
|
|
378
|
+
| `"ground"` | `lon`、`lat`、`height` |
|
|
379
|
+
| `"site"` | `id`、`siteType`、`data?` |
|
|
380
|
+
|
|
381
|
+
#### 生命周期
|
|
382
|
+
|
|
383
|
+
| 方法 | 说明 |
|
|
384
|
+
| --- | --- |
|
|
385
|
+
| `destroy()` | 销毁菜单 DOM、事件监听、底层场景和 worker |
|
|
386
|
+
| `MultiTargetFramework.create(viewer, options)` | 静态异步工厂,构造后等 `ready` 就绪再 resolve,返回 `Promise<MultiTargetFramework>` |
|
|
387
|
+
|
|
388
|
+
### 三、底层入口 `MultiTargetScene`
|
|
389
|
+
|
|
390
|
+
`MultiTargetScene` 更接近渲染引擎本体,适合需要 packed 数据、底层事件或自定义封装的场景。高层 `MultiTargetFramework.scene` 即为此实例。
|
|
391
|
+
|
|
392
|
+
#### 属性
|
|
393
|
+
|
|
394
|
+
| 属性 | 说明 |
|
|
395
|
+
| --- | --- |
|
|
396
|
+
| `config` | 解析后的 `ResolvedConfig` |
|
|
397
|
+
| `render` | 点云/图标渲染器 |
|
|
398
|
+
| `models` | 低模/高模模型池渲染器 |
|
|
399
|
+
| `symbols` | 可选,地表实例化有向符号渲染器 |
|
|
400
|
+
| `selection` | 选中覆盖层渲染器 |
|
|
401
|
+
| `tracks` | `TrackManager` |
|
|
402
|
+
| `nodes` | `SceneNodeStats` 渲染统计 |
|
|
403
|
+
| `quality` | 当前质量档,当前固定为 `{ tier: "high" }` |
|
|
404
|
+
| `targetCount` | 当前 worker 内目标总数 |
|
|
405
|
+
|
|
406
|
+
#### 数据和渲染方法
|
|
407
|
+
|
|
408
|
+
| 方法 | 说明 |
|
|
409
|
+
| --- | --- |
|
|
410
|
+
| `setData(targets)` | 全量目标数据 |
|
|
411
|
+
| `applyIncremental(payload)` | 增量目标数据 |
|
|
412
|
+
| `applyRealtimeUpsert(targets)` | 实时 upsert,不走周期提交等待 |
|
|
413
|
+
| `applyRealtimeRemove(ids)` | 实时删除 |
|
|
414
|
+
| `applyPacked(payload)` | 提交 typed array packed 数据,适合大批量高频输入 |
|
|
415
|
+
| `applyTargetStyle(patches)` | 底层样式补丁 |
|
|
416
|
+
| `setBoxedTargetIds(ids)` | 设置框选 id 集合 |
|
|
417
|
+
| `setLabelConfig(config)` | 更新标签配置 |
|
|
418
|
+
| `flushNow()` | 立即提交当前 staged 数据 |
|
|
419
|
+
| `pause()` | 暂停提交和视口刷新 |
|
|
420
|
+
| `resume()` | 恢复并刷新视口 |
|
|
421
|
+
| `destroy()` | 销毁 worker、渲染器、事件和选择状态 |
|
|
422
|
+
|
|
423
|
+
#### 查询和交互方法
|
|
424
|
+
|
|
425
|
+
| 方法 | 说明 |
|
|
426
|
+
| --- | --- |
|
|
427
|
+
| `selectTarget(id, clearBefore?)` | 选中目标,返回 `PickedNodeLike | null` |
|
|
428
|
+
| `selectTargets(ids, clearBefore?)` | 批量选中,返回命中的目标数组 |
|
|
429
|
+
| `unselectTarget(id)` | 取消选中 |
|
|
430
|
+
| `clearSelection(emit?)` | 清空选择,`emit` 默认 `true` |
|
|
431
|
+
| `getTargetSnapshot(id)` | 从 worker 查询目标逻辑快照 |
|
|
432
|
+
| `getRenderedTargetFrame(id, result?)` | 查询当前实际渲染帧位置和航向 |
|
|
433
|
+
| `getRenderedTargetPosition(id, result?)` | 查询当前 render packet 中的渲染坐标 |
|
|
434
|
+
|
|
435
|
+
#### 事件
|
|
436
|
+
|
|
437
|
+
`MultiTargetScene` 继承 `EventEmitter`,使用 `scene.on(event, handler)` 监听,返回取消监听函数。
|
|
438
|
+
|
|
439
|
+
| 事件 | 载荷 |
|
|
440
|
+
| --- | --- |
|
|
441
|
+
| `perf` | 输入、worker、渲染慢帧等性能事件 |
|
|
442
|
+
| `dirty` | `{ added, updated, removed }` 普通 diff |
|
|
443
|
+
| `packedDirty` | packed diff |
|
|
444
|
+
| `pick` | `PickedNodeLike | null` |
|
|
445
|
+
| `hover` | `PickedNodeLike | null` |
|
|
446
|
+
| `selection` | `PickedNodeLike[]` |
|
|
447
|
+
| `contextmenu` | 目标或空地右键上下文 |
|
|
448
|
+
|
|
449
|
+
### 四、目标数据类型
|
|
450
|
+
|
|
451
|
+
`TargetData` / `StandardTargetData`:
|
|
452
|
+
|
|
453
|
+
| 字段 | 必填 | 说明 |
|
|
454
|
+
| --- | --- | --- |
|
|
455
|
+
| `id` | 是 | 唯一 id |
|
|
456
|
+
| `type` | 是 | 目标类型,必须命中配置 |
|
|
457
|
+
| `lon` / `lat` / `height` | 是 | WGS84 经纬度和高度 |
|
|
458
|
+
| `speedH` / `speedV` | 是 | 水平/垂直速度,m/s |
|
|
459
|
+
| `heading` | 是 | 航向角,度,正北 0 顺时针 |
|
|
460
|
+
| `renderColor` | 否 | `#RRGGBB` 或 `#RRGGBBAA` |
|
|
461
|
+
| `openAnimate` | 否 | 是否开启动画 |
|
|
462
|
+
| `animateType` | 否 | 当前内置支持 `glow` / `发光` |
|
|
463
|
+
| `animateColor` | 否 | 动画颜色 |
|
|
464
|
+
| `nationality` | 否 | 国籍/归属字符串 |
|
|
465
|
+
| `customInfo` | 否 | 自定义信息对象,可用于名称牌字段 |
|
|
466
|
+
| `track` | 否 | `TrackPoint[]` |
|
|
467
|
+
| `secrecy` | 否 | 密级(预留字段,当前仅透传,未参与聚合/合并逻辑) |
|
|
468
|
+
| `extra` | 否 | 额外内部/业务状态 |
|
|
469
|
+
|
|
470
|
+
`PackedTargetData` 用 typed array 表示大批量数据:`lon`、`lat` 必填;`ids`、`types`、`height`、`speedH`、`speedV`、`heading`、`secrecy`、`renderColor`、`animate`、`animateColor`、`removes` 可选。
|
|
471
|
+
|
|
472
|
+
### 五、配置速查
|
|
473
|
+
|
|
474
|
+
| 配置 | 当前默认 | 说明 |
|
|
475
|
+
| --- | --- | --- |
|
|
476
|
+
| `lod.pointAbove` | `150000` | 高于此高度走点模式 |
|
|
477
|
+
| `lod.animatedBelow` | `10000` | 低于此高度允许高模动画 |
|
|
478
|
+
| `pool.size` | `30000` | 通用目标池容量 |
|
|
479
|
+
| `animatedPool.size` | `64` | 高模动画容量 |
|
|
480
|
+
| `updateFps` | `30` | 渲染/刷新频率 |
|
|
481
|
+
| `predictSeconds` | `10` | 预测窗口秒数 |
|
|
482
|
+
| `predictFitSeconds` | `2` | 新权威数据到达后的拟合秒数 |
|
|
483
|
+
| `fadeMs` | `350` | 显隐淡入淡出时间 |
|
|
484
|
+
| `masterHideHeight` | `150000` | 高于此高度隐藏模型内容 |
|
|
485
|
+
| `merge.mode` | `"global"` | 聚合模式 |
|
|
486
|
+
| `merge.maxVisible` | `pool.size` | 最大渲染目标数 |
|
|
487
|
+
| `merge.globalRootLimit` | `500` | global 顶层根聚合数量上限 |
|
|
488
|
+
| `merge.globalMaxLevels` | `64` | global 最大层级 |
|
|
489
|
+
| `merge.globalRebuildIntervalMs` | `300000` | global 缓存重建间隔 |
|
|
490
|
+
| `merge.globalViewportHeight` | `450000` | 高于此高度按全球视口处理 |
|
|
491
|
+
| `merge.cameraMergeBaseHeight` | `100000` | 低于/等于该高度不随相机增加合并半径 |
|
|
492
|
+
| `merge.cameraMergeStepHeight` | `10000` | 相机高度每增一档的高度 |
|
|
493
|
+
| `merge.cameraMergeStepRadius` | `100` | 每档半径增量 |
|
|
494
|
+
| `pick.enabled` | `true` | 是否启用点击拾取 |
|
|
495
|
+
| `pick.pixelThreshold` | `20` | 拾取像素阈值 |
|
|
496
|
+
| `pick.hover` | `true` | 是否启用 hover |
|
|
497
|
+
| `cull.viewportBufferRatio` | `0.15` | 视口缓冲比例 |
|
|
498
|
+
| `label.enabled` | `true` | 是否显示名称牌 |
|
|
499
|
+
| `label.maxCount` | `200` | 名称牌最多显示数量 |
|
|
500
|
+
| `label.maxCameraHeight` | `5000` | 名称牌最大相机高度 |
|
|
501
|
+
| `frame.maxLowModelRenderItems` | `3000` | 低模后端数量上限 |
|
|
502
|
+
| `frame.maxModelRenderItems` | `2000` | 旧兼容项 |
|
|
503
|
+
| `data.commitIntervalMs` | `2000` | 数据提交周期 |
|
|
504
|
+
| `data.leading` | `true` | 首批数据是否立即提交 |
|
|
505
|
+
| `data.worker` | `true` | 数据处理是否使用 worker |
|
|
506
|
+
| `groundSymbols` | `false` | 点档单目标是否用地表实例化有向符号 |
|
|
507
|
+
| `groundSymbolPixelSize` | `30` | 地表符号像素大小 |
|
|
508
|
+
|
|
509
|
+
### 六、轨迹 `TrackManager`
|
|
510
|
+
|
|
511
|
+
可通过 `framework.tracks` 或 `scene.tracks` 使用。
|
|
512
|
+
|
|
513
|
+
| 方法 | 说明 |
|
|
514
|
+
| --- | --- |
|
|
515
|
+
| `on("hover", handler)` | 监听轨迹点 hover,载荷为 `TrackHoverInfo | null` |
|
|
516
|
+
| `setTracks(tracks)` | 新增或更新轨迹 |
|
|
517
|
+
| `getTracks(targetIds?)` | 查询轨迹,返回拷贝 |
|
|
518
|
+
| `showTracks(targetIds)` | 显示轨迹 |
|
|
519
|
+
| `hideTracks(targetIds)` | 隐藏轨迹 |
|
|
520
|
+
| `removeTracks(targetIds)` | 删除指定轨迹 |
|
|
521
|
+
| `clearTracks()` | 清空轨迹 |
|
|
522
|
+
|
|
523
|
+
`TrackRecord` 支持 `pointList` 或 `trackLine`。`trackLine` 格式为 `LINESTRING (...)` 或 `LINESTRING Z (...)`。
|
|
524
|
+
|
|
525
|
+
### 七、站点层 `SiteLayer`
|
|
526
|
+
|
|
527
|
+
站点层独立于目标系统,用于光电、雷达、AIS 等固定站点图标/低模展示。
|
|
528
|
+
|
|
529
|
+
```ts
|
|
530
|
+
const siteLayer = new SiteLayer(viewer, {
|
|
531
|
+
modelSwitchHeight: 8000,
|
|
532
|
+
siteTypes: [
|
|
533
|
+
{
|
|
534
|
+
type: "radar",
|
|
535
|
+
category: "radar",
|
|
536
|
+
iconPath: "/icons/radar.png",
|
|
537
|
+
lowModel: { url: "/model/radar.glb" },
|
|
538
|
+
},
|
|
539
|
+
],
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
siteLayer.setData([{ id: "radar-1", type: "radar", lon: 121, lat: 31, height: 0 }]);
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
#### 属性和方法
|
|
546
|
+
|
|
547
|
+
| 方法/属性 | 说明 |
|
|
548
|
+
| --- | --- |
|
|
549
|
+
| `options` | 解析后的站点配置 |
|
|
550
|
+
| `stats` | `{ total, inView, iconCount, lowModelCount, lowModelEligibleCount, mode }` |
|
|
551
|
+
| `setData(sites)` | 全量设置站点 |
|
|
552
|
+
| `pickAt(position, thresholdPx?)` | 按屏幕坐标拾取最近站点 |
|
|
553
|
+
| `clear()` | 清空站点 |
|
|
554
|
+
| `destroy()` | 销毁图标、低模和事件 |
|
|
555
|
+
|
|
556
|
+
事件:
|
|
557
|
+
|
|
558
|
+
| 事件 | 载荷 |
|
|
559
|
+
| --- | --- |
|
|
560
|
+
| `contextmenu` | `{ site, screenX, screenY, cartesian? }` |
|
|
561
|
+
| `pick` | `SiteData | null` |
|
|
562
|
+
|
|
563
|
+
`SiteLayer` 右键站点后可调用 `framework.showContextMenu(...)` 接入统一菜单。
|
|
564
|
+
|
|
565
|
+
### 八、聚类工具
|
|
566
|
+
|
|
567
|
+
#### 同步聚类
|
|
568
|
+
|
|
569
|
+
| 方法 | 说明 |
|
|
570
|
+
| --- | --- |
|
|
571
|
+
| `lonLatToLocalPlane(lons, lats, count, lon0?, lat0?)` | 经纬度投影到本地平面米坐标 |
|
|
572
|
+
| `clusterProgressive(xs, ys, count, options?)` | 一次性递进聚类,返回独立数组,适合低频 |
|
|
573
|
+
| `createQuadClusterer(initialCapacity?)` | 创建复用缓冲的高频聚类器 |
|
|
574
|
+
|
|
575
|
+
`ProgressiveClusterOptions`:`baseCellMeters` 默认 `200`、`maxClusters` 默认 `30000`、`maxLevels` 默认 `20`。
|
|
576
|
+
|
|
577
|
+
#### Worker 聚类
|
|
578
|
+
|
|
579
|
+
```ts
|
|
580
|
+
const client = createClusterWorkerClient();
|
|
581
|
+
const result = await client.run(lons, lats, count, { baseCellMeters: 200, maxClusters: 30000 });
|
|
582
|
+
client.terminate();
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
`ClusterWorkerClient`:
|
|
586
|
+
|
|
587
|
+
| 方法 | 说明 |
|
|
588
|
+
| --- | --- |
|
|
589
|
+
| `run(lons, lats, count, options?)` | 拷贝输入并在 worker 中聚类;忙时 last-wins,旧排队任务返回 `null` |
|
|
590
|
+
| `inputBuffers(count)` | 借出内部输入缓冲 |
|
|
591
|
+
| `runReusing(count, options?)` | 零拷贝提交内部输入缓冲 |
|
|
592
|
+
| `terminate()` | 结束 worker |
|
|
593
|
+
|
|
594
|
+
### 九、Web Event Bus 自动对外暴露能力
|
|
595
|
+
|
|
596
|
+
本包集成 `web-event-bus`,用于把框架实例的对外方法和事件自动暴露到全局 bus。创建 `MultiTargetFramework` 后会自动注册 framework/tracks 相关 action 并桥接 scene/tracks 事件;创建 `SiteLayer` 后会自动注册 site 相关 action 并桥接站点事件。该能力不会修改 `scene.on(...)`、`siteLayer.on(...)`、`tracks.on(...)` 的原行为,实例 `destroy()` 时会自动解绑本实例注册的 action 和事件桥接。
|
|
597
|
+
|
|
598
|
+
默认使用固定 action 名;如果页面上同时存在多个 `MultiTargetFramework` 或多个 `SiteLayer`,最后创建的同类实例会接管对应 action。旧实例销毁时不会注销已被新实例接管的 action。
|
|
599
|
+
|
|
600
|
+
#### 使用方式
|
|
601
|
+
|
|
602
|
+
```ts
|
|
603
|
+
import {
|
|
604
|
+
getFrameworkEventBus,
|
|
605
|
+
} from "cesium-multi-target-framework";
|
|
606
|
+
|
|
607
|
+
const framework = new MultiTargetFramework(viewer, options);
|
|
608
|
+
const siteLayer = new SiteLayer(viewer, siteOptions);
|
|
609
|
+
const bus = getFrameworkEventBus();
|
|
610
|
+
|
|
611
|
+
bus.on("mtf.scene.hover", (payload) => {
|
|
612
|
+
console.log("scene hover", payload);
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
await bus.invoke("mtf.framework.locateTarget", {
|
|
616
|
+
id: "ship-001",
|
|
617
|
+
});
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
| 工具 | 说明 |
|
|
621
|
+
| --- | --- |
|
|
622
|
+
| `getFrameworkEventBus()` | 获取 `web-event-bus` 的浏览器全局 bus;非浏览器环境会抛错 |
|
|
623
|
+
| `tryGetFrameworkEventBus()` | 获取全局 bus;不可用时返回 `null` |
|
|
624
|
+
| `createFrameworkEventBus()` | 创建独立 bus 实例,不挂到全局 |
|
|
625
|
+
| `bindFrameworkEventBus(framework, options?)` | 高级用法:手动把指定 `MultiTargetFramework` 绑定到自定义 bus 或自定义 owner |
|
|
626
|
+
| `bindSiteLayerEventBus(siteLayer, options?)` | 高级用法:手动把指定 `SiteLayer` 绑定到自定义 bus 或自定义 owner |
|
|
627
|
+
|
|
628
|
+
自动绑定内部也使用 `FrameworkBusBinding` 管理生命周期。手动调用 `bindFrameworkEventBus` / `bindSiteLayerEventBus` 时会返回该对象:
|
|
629
|
+
|
|
630
|
+
| 字段/方法 | 说明 |
|
|
631
|
+
| --- | --- |
|
|
632
|
+
| `active` | 是否成功绑定;非浏览器环境且未传入自定义 bus 时为 `false` |
|
|
633
|
+
| `owner` | 注册到 bus 的 owner 名 |
|
|
634
|
+
| `dispose()` | 注销本次注册的 action,并取消事件桥接监听 |
|
|
635
|
+
|
|
636
|
+
绑定选项:
|
|
637
|
+
|
|
638
|
+
| 字段 | 默认 | 说明 |
|
|
639
|
+
| --- | --- | --- |
|
|
640
|
+
| `bus` | 全局 bus | 指定使用的 `FrameworkEventBus` |
|
|
641
|
+
| `owner` | `"cesium-multi-target-framework"` | 注册 action 时写入的 owner |
|
|
642
|
+
| `registerActions` | `true` | 是否注册方法 action |
|
|
643
|
+
| `bridgeEvents` | `true` | 是否桥接框架事件到 bus |
|
|
644
|
+
| `replaceExisting` | `false` | action 已存在时是否先 unregister 再注册 |
|
|
645
|
+
|
|
646
|
+
#### 自动暴露的事件
|
|
647
|
+
|
|
648
|
+
事件会在对应实例创建后自动桥接到 bus。bus listener 抛错由 `web-event-bus` 隔离,不影响原本 `.on()` 监听。
|
|
649
|
+
|
|
650
|
+
| event 字符串 | 载荷 |
|
|
651
|
+
| --- | --- |
|
|
652
|
+
| `mtf.scene.perf` | `SceneEvents["perf"]` |
|
|
653
|
+
| `mtf.scene.dirty` | `SceneEvents["dirty"]` |
|
|
654
|
+
| `mtf.scene.packedDirty` | `SceneEvents["packedDirty"]` |
|
|
655
|
+
| `mtf.scene.pick` | `PickedNodeLike \| null` |
|
|
656
|
+
| `mtf.scene.hover` | `PickedNodeLike \| null` |
|
|
657
|
+
| `mtf.scene.selection` | `PickedNodeLike[]` |
|
|
658
|
+
| `mtf.scene.contextmenu` | `SceneContextMenuPayload \| null` |
|
|
659
|
+
| `mtf.track.hover` | `TrackHoverInfo \| null` |
|
|
660
|
+
| `mtf.site.contextmenu` | `SiteContextMenuPayload` |
|
|
661
|
+
| `mtf.site.pick` | `SiteData \| null` |
|
|
662
|
+
| `mtf.site.hover` | `SiteData \| null` |
|
|
663
|
+
|
|
664
|
+
#### 自动暴露的方法 action
|
|
665
|
+
|
|
666
|
+
创建 `MultiTargetFramework` 后自动注册 `framework` 和 `framework.tracks` 的对外方法:
|
|
667
|
+
|
|
668
|
+
| action 字符串 | params | result |
|
|
669
|
+
| --- | --- | --- |
|
|
670
|
+
| `mtf.framework.addTarget` | `{ target }` | `StandardTargetData` |
|
|
671
|
+
| `mtf.framework.updateTarget` | `{ target }` | `StandardTargetData` |
|
|
672
|
+
| `mtf.framework.setTargetData` | `{ targets }` | `void` |
|
|
673
|
+
| `mtf.framework.upsertTargetData` | `{ targets }` | `void` |
|
|
674
|
+
| `mtf.framework.removeTargetData` | `{ ids }` | `void` |
|
|
675
|
+
| `mtf.framework.applyTargetIncremental` | `{ payload }` | `void` |
|
|
676
|
+
| `mtf.framework.setTargetColor` | `{ id, color, options? }` | `void` |
|
|
677
|
+
| `mtf.framework.setTargetGlow` | `{ id, enabled, color?, options? }` | `void` |
|
|
678
|
+
| `mtf.framework.hideTarget` | `{ id, options? }` | `void` |
|
|
679
|
+
| `mtf.framework.showTarget` | `{ id, options? }` | `void` |
|
|
680
|
+
| `mtf.framework.disappearTarget` | `{ id, options? }` | `void` |
|
|
681
|
+
| `mtf.framework.appearTarget` | `{ id, options? }` | `void` |
|
|
682
|
+
| `mtf.framework.setNameplateConfig` | `{ config }` | `void` |
|
|
683
|
+
| `mtf.framework.selectTarget` | `{ id, options? }` | `TargetSnapshot \| null` |
|
|
684
|
+
| `mtf.framework.selectTargets` | `{ ids, options? }` | `TargetSnapshot[]` |
|
|
685
|
+
| `mtf.framework.unselectTarget` | `{ id }` | `void` |
|
|
686
|
+
| `mtf.framework.clearSelection` | `undefined` | `void` |
|
|
687
|
+
| `mtf.framework.boxTarget` | `{ id, enabled?, options? }` | `void` |
|
|
688
|
+
| `mtf.framework.unboxTarget` | `{ id, options? }` | `void` |
|
|
689
|
+
| `mtf.framework.locateTarget` | `{ id, options? }` | `TargetSnapshot \| null` |
|
|
690
|
+
| `mtf.framework.registerContextMenuItem` | `{ item }` | `() => void` |
|
|
691
|
+
| `mtf.framework.showContextMenu` | `{ context }` | `void` |
|
|
692
|
+
| `mtf.framework.closeContextMenu` | `undefined` | `void` |
|
|
693
|
+
| `mtf.framework.destroy` | `undefined` | `void` |
|
|
694
|
+
| `mtf.tracks.setTracks` | `{ tracks }` | `void` |
|
|
695
|
+
| `mtf.tracks.getTracks` | `{ targetIds? } \| undefined` | `TrackRecord[]` |
|
|
696
|
+
| `mtf.tracks.showTracks` | `{ targetIds }` | `void` |
|
|
697
|
+
| `mtf.tracks.hideTracks` | `{ targetIds }` | `void` |
|
|
698
|
+
| `mtf.tracks.removeTracks` | `{ targetIds }` | `void` |
|
|
699
|
+
| `mtf.tracks.clearTracks` | `undefined` | `void` |
|
|
700
|
+
|
|
701
|
+
创建 `SiteLayer` 后自动注册站点层方法:
|
|
702
|
+
|
|
703
|
+
| action 字符串 | params | result |
|
|
704
|
+
| --- | --- | --- |
|
|
705
|
+
| `mtf.site.setData` | `{ sites }` | `void` |
|
|
706
|
+
| `mtf.site.clear` | `undefined` | `void` |
|
|
707
|
+
| `mtf.site.pickAt` | `{ position, thresholdPx? }` | `SiteData \| null` |
|
|
708
|
+
| `mtf.site.destroy` | `undefined` | `void` |
|
|
709
|
+
|
|
710
|
+
#### TypeScript 类型
|
|
711
|
+
|
|
712
|
+
| 类型 | 说明 |
|
|
713
|
+
| --- | --- |
|
|
714
|
+
| `FrameworkEventBus` | 带框架事件/action 类型提示的 bus |
|
|
715
|
+
| `FrameworkBusEventMap` | event name 到 payload 的映射 |
|
|
716
|
+
| `FrameworkBusActionMap` | action name 到 params/result 的映射 |
|
|
717
|
+
| `FrameworkEventName` / `FrameworkEventPayload` | 事件名和载荷辅助类型 |
|
|
718
|
+
| `FrameworkBusActionName` / `FrameworkBusActionParams` / `FrameworkBusActionResult` | action 名、参数、结果辅助类型 |
|
|
719
|
+
|
|
720
|
+
### 十、事件工具 `EventEmitter`
|
|
721
|
+
|
|
722
|
+
`EventEmitter<EventMap>` 是一个轻量事件类,`MultiTargetScene`、`TrackManager`、`SiteLayer` 都继承它。
|
|
723
|
+
|
|
724
|
+
| 方法 | 说明 |
|
|
725
|
+
| --- | --- |
|
|
726
|
+
| `on(event, handler)` | 注册监听,返回取消函数 |
|
|
727
|
+
| `off(event, handler)` | 取消监听 |
|
|
728
|
+
| `emit(event, payload)` | 触发事件,通常内部使用 |
|
|
729
|
+
| `clear()` | 清空所有监听 |
|