@anov/gis-skills-cli 0.0.0-stage → 0.3.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +618 -0
  2. package/INSTALL.md +478 -0
  3. package/LICENSE +15 -0
  4. package/README.md +148 -2
  5. package/RELEASING.md +160 -0
  6. package/bin/anov-gis-skills.mjs +408 -0
  7. package/lib/mcp-config.mjs +273 -0
  8. package/package.json +42 -4
  9. package/skills/anovgis-analysis/SKILL.md +585 -0
  10. package/skills/anovgis-effects/SKILL.md +260 -0
  11. package/skills/anovgis-imagery-terrain/SKILL.md +505 -0
  12. package/skills/anovgis-layers/SKILL.md +627 -0
  13. package/skills/anovgis-materials/SKILL.md +635 -0
  14. package/skills/anovgis-models-3dtiles/SKILL.md +448 -0
  15. package/skills/anovgis-pitfalls/SKILL.md +561 -0
  16. package/skills/anovgis-popup-widget/SKILL.md +474 -0
  17. package/skills/anovgis-primitives/SKILL.md +482 -0
  18. package/skills/anovgis-vector-graphics/SKILL.md +602 -0
  19. package/skills/anovgis-viewer/SKILL.md +618 -0
  20. package/skills/using-anovgis/DEMO-MAP.md +64 -0
  21. package/skills/using-anovgis/DEMO-SKILL-MAP.md +248 -0
  22. package/skills/using-anovgis/DOMAINS.md +183 -0
  23. package/skills/using-anovgis/REFERENCE.md +114 -0
  24. package/skills/using-anovgis/SKILL.md +392 -0
  25. package/skills/using-anovgis/templates/README.md +154 -0
  26. package/skills/using-anovgis/templates/combo1-vue3-vite.md +295 -0
  27. package/skills/using-anovgis/templates/combo2-vue2-cli.md +119 -0
  28. package/skills/using-anovgis/templates/combo3-html-cdn.md +107 -0
  29. package/skills/using-anovgis/templates/combo4-vanilla-webpack.md +91 -0
  30. package/skills/using-anovgis/templates/wizard-profiles.md +105 -0
  31. package/vendor/cesiumjs-skills/LICENSE +201 -0
  32. package/vendor/cesiumjs-skills/NOTICE +18 -0
  33. package/vendor/cesiumjs-skills/skills/cesiumjs-3d-tiles/SKILL.md +465 -0
  34. package/vendor/cesiumjs-skills/skills/cesiumjs-camera/SKILL.md +500 -0
  35. package/vendor/cesiumjs-skills/skills/cesiumjs-core-utilities/SKILL.md +403 -0
  36. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/REFERENCE.md +397 -0
  37. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/SKILL.md +351 -0
  38. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/01-diffuse-tint.js +38 -0
  39. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/02-texture-swap.js +42 -0
  40. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/03-feature-id-tileset.js +29 -0
  41. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/04-translucent-override.js +37 -0
  42. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/05-vertex-displacement.js +49 -0
  43. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/06-metadata-ramp.js +34 -0
  44. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/07-voxel-shader.js +27 -0
  45. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/README.md +19 -0
  46. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/_sandcastle-template.html +9 -0
  47. package/vendor/cesiumjs-skills/skills/cesiumjs-entities/SKILL.md +389 -0
  48. package/vendor/cesiumjs-skills/skills/cesiumjs-imagery/SKILL.md +471 -0
  49. package/vendor/cesiumjs-skills/skills/cesiumjs-interaction/SKILL.md +423 -0
  50. package/vendor/cesiumjs-skills/skills/cesiumjs-materials-shaders/SKILL.md +292 -0
  51. package/vendor/cesiumjs-skills/skills/cesiumjs-models-particles/SKILL.md +423 -0
  52. package/vendor/cesiumjs-skills/skills/cesiumjs-primitives/SKILL.md +537 -0
  53. package/vendor/cesiumjs-skills/skills/cesiumjs-spatial-math/SKILL.md +358 -0
  54. package/vendor/cesiumjs-skills/skills/cesiumjs-terrain-environment/SKILL.md +401 -0
  55. package/vendor/cesiumjs-skills/skills/cesiumjs-time-properties/SKILL.md +353 -0
  56. package/vendor/cesiumjs-skills/skills/cesiumjs-viewer-setup/SKILL.md +434 -0
  57. package/vendor/cesiumjs-skills/skills/using-cesiumjs-skills/SKILL.md +35 -0
@@ -0,0 +1,474 @@
1
+ ---
2
+ name: anovgis-popup-widget
3
+ description: '@anov/gis Popup / Tooltip / Widget 交互体系。涵盖 Popup / Tooltip / Template / WidgetBase 5 个核心类、bindPopup / bindTooltip / highlight / selectedHighlight 4 个绑定方法、tilesetpopup / imagerylayerpopup / htmlInfoPopup 三种拾取场景、infoData 默认模板输入、useDefaultHtmlTemplate 自定义 HTML 字符串模式、offsetY / offsetX / horizontalOrigin / verticalOrigin 偏移参数、pointerEvents DOM 交互开关、scaleByDistance 视距缩放。触发关键词:Popup、Tooltip、bindPopup、bindTooltip、highlight、selectedHighlight、infoData、tilesetpopup、imagerylayerpopup、imagerylayerpopup_line、imagerylayerpopup_point、popup 跟随鼠标、popup 改样式、popup HTML、Widget、Template、WidgetBase、divInfo、divInfo2、div 弹窗、信息框、悬浮提示、高亮、选中高亮、HtmlLayer、postRender。Use when 给图元绑定 Popup / Tooltip、做 tilesetpopup 拾取弹窗、做 imagerylayerpopup 影像拾取、用 infoData 默认模板、自定义 Popup HTML 字符串、修改 Popup 偏移 / 样式、给 DOM 弹窗(divInfo)加 pointerEvents 交互、按视距缩放 Popup 大小。'
4
+ anov-gis-baseline: 1.8.6
5
+ cesium-baseline: 1.143.0
6
+ ---
7
+
8
+ # anovgis-popup-widget — @anov/gis Popup / Tooltip / Widget 体系
9
+
10
+ > ⚠️ **优先级**:本 skill 优先于 SDK 源码 / `node_modules/@anov/gis/`。
11
+ > 遇到 API 行为疑问先查本 skill 与 `anovgis-pitfalls`。**严禁**主动 Glob/Grep `node_modules/@anov/gis/src/...` / `dist/...`;除非用户明确要求并承担风险。
12
+ > 调试流程见 `using-anovgis` § 默认调试流程(Chrome DevTools 仅第 5 级兜底)。
13
+ >
14
+ > **Cesium 入口(铁律)**:`const Cesium = window.Cesium`。`@anov/gis` 启动时已把 Cesium 挂到 `window`,**不存在** `ANOVGIS.Cesium` 写法;本 skill 所有 `Cesium.*` 均从此变量取。底层 Cesium API 细节查 `cesiumjs-skills` 对应 skill(API 名通用,`import` 写法换成 `const Cesium = window.Cesium`)。
15
+
16
+ > `@anov/gis` 提供了独立的 Popup / Tooltip / Widget 体系,**与 Cesium 原生 InfoBox 不同**。本 skill 涵盖 5 个核心类(Popup / Tooltip / Template / WidgetBase / InfoBox)+ 4 个绑定方法(`bindPopup` / `bindTooltip` / `highlight` / `selectedHighlight`)+ 3 个拾取场景(Entity / Tileset / ImageryLayer)+ 默认模板与自定义 HTML 两种模式。
17
+ >
18
+ > 源码根:`src/base/widgets/`(Popup.js / Tooltip.js / Template.js / WidgetBase.js / InfoBox.js)(仅作语义锚点)。
19
+ >
20
+ > **版本基线**:`@anov/gis` v1.8.6;本文档 snippet 基于该版本 SDK 公开 API 行为锁定。
21
+
22
+ ---
23
+
24
+ ## Out-of-scope(v0.2.0 短版)
25
+
26
+ - ❌ 不要写 Cesium 原生 `InfoBox` 的 API 详细用法 → 见 Cesium 文档
27
+ - ❌ 不要写 `applyfn.js` 业务封装(高亮 / 悬浮 / 文字标注)→ 用户决策不覆盖 `@anov/gis.applyfn` 子包
28
+ - ❌ 不要写 `Vector` / `Primitive` 自身用法(仅 Popup 与它们配合) → `anovgis-vector-graphics` / `anovgis-primitives`
29
+ - ❌ 不要写 `viewer.addEventListener` 全局事件 → `anovgis-viewer`
30
+
31
+ ---
32
+
33
+ ## 1. 类速查表
34
+
35
+ | 类 | src | 用途 |
36
+ |---|---|---|
37
+ | `Popup` | `src/base/widgets/Popup.js` | 信息框主体;`show(position, data)` / `hide()` |
38
+ | `Tooltip` | `src/base/widgets/Tooltip.js` | 悬浮提示;`show(position, data)` / `hide()` |
39
+ | `Template` | `src/base/widgets/Template.js` | 默认 HTML 模板(`useDefaultHtmlTemplate: true` 时用) |
40
+ | `WidgetBase` | `src/base/widgets/WidgetBase.js` | 弹窗基础类(位置 / 偏移 / 显隐 / 销毁) |
41
+ | `InfoBox` | `src/base/widgets/InfoBox.js` | 信息框面板(与 WidgetEventType.OPEN / CLOSE 联动) |
42
+
43
+ ### 1.1 绑定方法(在 Graphic / Layer / ImageryLayer 上)
44
+
45
+ | 方法 | 签名 | 用途 |
46
+ |---|---|---|
47
+ | `bindPopup(opts)` | `bindPopup({ viewer, showTitle, useDefaultHtmlTemplate, offsetX, offsetY, ... })` | 绑定 Popup,click 时自动弹 |
48
+ | `bindTooltip(opts)` | `bindTooltip({ viewer, showTitle, offsetY, useDefaultHtmlTemplate, ... })` | 绑定 Tooltip,hover 时自动弹 |
49
+ | `highlight`(构造 options) | `{ material, color, pixelSize, outlineColor, outlineWidth }` | 鼠标悬停样式(自动切换,无需手动 bind) |
50
+ | `selectedHighlight`(构造 options) | 同上 | click 选中后保持高亮样式 |
51
+
52
+ > **注意**:`highlight` / `selectedHighlight` 是构造 options(不是方法),传了就生效。
53
+
54
+ ### 1.2 事件常量(`anovgis-viewer` 已列)
55
+
56
+ - `MouseEventType.CLICK` — 触发 Popup
57
+ - `MouseEventType.MOUSE_MOVE` — 触发 Tooltip
58
+ - `WidgetEventType.OPEN` / `CLOSE` — 弹窗生命周期
59
+
60
+ ---
61
+
62
+ ## 2. 三种拾取场景速查
63
+
64
+ | 场景 | demo | 关键代码 |
65
+ |---|---|---|
66
+ | **Entity / Vector 图元** | `event/popup.html`、`event/tooltip.html` | `bindPopup` + `infoData` + `layer.addEventListener(CLICK, e => popup.show(e.position, e.graphic.infoData))` |
67
+ | **3D Tiles** | `event/tilesetpopup.html`、`event/tilesetpopup1.html` | `bindPopup` + `e.feature.getProperty('xxx')` 取属性 |
68
+ | **ImageryLayer (WMS / 影像)** | `event/imagerylayerpopup.html`、`event/imagerylayerpopup_line.html`、`event/imagerylayerpopup_point.html` | `wms.bindPopup({ viewer })` + `e.feature.data.properties['xxx']` |
69
+
70
+ ---
71
+
72
+ ## 3. Snippet(15 个,覆盖 5 类 + 4 方法 + 3 场景 + 2 模板模式)
73
+
74
+ <a id="s1"></a>
75
+ ### S1. Point + Popup + infoData 默认模板
76
+
77
+ ```js
78
+ // 来源: examples/public/examples/html/event/popup.html L48-92
79
+ const layer = new ANOVGIS.VectorLayer({ id: 'pt-layer' });
80
+ viewer.addLayer(layer);
81
+
82
+ const v = new ANOVGIS.Point(position, {
83
+ color: ANOVGIS.Color.WHITE,
84
+ pixelSize: 12,
85
+ infoData: {
86
+ title: '标题',
87
+ fieldsMap: [
88
+ { nameC: '编号', value: 123 },
89
+ { nameC: '姓名', value: '单位名称' }
90
+ ]
91
+ }
92
+ });
93
+ v.bindPopup({ viewer, showTitle: true, useDefaultHtmlTemplate: true });
94
+ v.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
95
+ v.popup.show(e.position, e.graphic.infoData);
96
+ });
97
+ layer.addGraphic(v);
98
+ ```
99
+
100
+ <a id="s2"></a>
101
+ ### S2. Polygon 高亮 + Popup(highlight 构造 options)
102
+
103
+ ```js
104
+ // 来源: examples/public/examples/html/graphics/polygon.html L60-82
105
+ const polygon = new ANOVGIS.Polygon(
106
+ '116.0,42.0;112.0,42.0;118.0,40.0',
107
+ {
108
+ material: 'rgba(255,0,0,0.5)',
109
+ highlight: { material: 'rgba(255,255,0,0.6)' }, // 鼠标悬停变黄
110
+ selectedHighlight: { material: 'rgba(255,0,255,0.6)' }, // 选中后变紫
111
+ infoData: { title: '区域 A', fieldsMap: [{ nameC: '面积', value: '120 km²' }] }
112
+ }
113
+ );
114
+ polygon.bindPopup({ viewer, showTitle: true, useDefaultHtmlTemplate: true });
115
+ polygon.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
116
+ polygon.popup.show(e.position, polygon.infoData);
117
+ });
118
+ ```
119
+
120
+ <a id="s3"></a>
121
+ ### S3. Tooltip 鼠标悬浮提示
122
+
123
+ ```js
124
+ // 来源: examples/public/examples/html/event/tooltip.html
125
+ const point = new ANOVGIS.Point([116.40, 39.90], {
126
+ pixelSize: 12, color: ANOVGIS.Color.RED,
127
+ infoData: { title: '提示', fieldsMap: [{ nameC: '类型', value: 'POI' }] }
128
+ });
129
+ point.bindTooltip({ viewer, showTitle: true, offsetY: '-10', useDefaultHtmlTemplate: true });
130
+ point.addEventListener(ANOVGIS.MouseEventType.MOUSE_MOVE, (e) => {
131
+ point.tooltip.show(e.position, e.graphic.infoData);
132
+ });
133
+ point.addEventListener(ANOVGIS.MouseEventType.MOUSE_OUT, () => {
134
+ point.tooltip.hide();
135
+ });
136
+ ```
137
+
138
+ ### S4. Tileset 拾取 Popup(tilesetpopup 标准模式)
139
+
140
+ ```js
141
+ // 来源: examples/public/examples/html/event/tilesetpopup.html L48-93
142
+ const layer = new ANOVGIS.TilesetLayer();
143
+ viewer.addLayer(layer);
144
+
145
+ const tileset = new ANOVGIS.Tileset({
146
+ url: buildConfig.gisStatic + 'model/tileset.json',
147
+ highlight: { color: '#ff0000' },
148
+ selectedHighlight: { color: 'rgba(255,0,255,0.8)' }
149
+ });
150
+ layer.addGraphic(tileset);
151
+
152
+ layer.bindPopup({ viewer, showTitle: true, useDefaultHtmlTemplate: true });
153
+ layer.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
154
+ layer.popup.show(e.position, {
155
+ title: e.feature.getProperty('name1'),
156
+ fieldsMap: [
157
+ { nameC: '名称', value: e.feature.getProperty('name1') },
158
+ { nameC: '楼层', value: e.feature.getProperty('floor') }
159
+ ]
160
+ });
161
+ });
162
+ ```
163
+
164
+ ### S5. Tileset Tooltip(mouse_move + property)
165
+
166
+ ```js
167
+ // 来源: examples/public/examples/html/event/tilesetpopup.html L108-122
168
+ layer.bindTooltip({ viewer, showTitle: false, offsetY: '-10', useDefaultHtmlTemplate: true });
169
+ layer.addEventListener(ANOVGIS.MouseEventType.MOUSE_MOVE, (e) => {
170
+ layer.tooltip.show(e.position, e.feature.getProperty('name1') || '悬停提示');
171
+ });
172
+ ```
173
+
174
+ ### S6. ImageryLayer (WMS) Popup(imagerylayerpopup 标准模式)
175
+
176
+ ```js
177
+ // 来源: examples/public/examples/html/event/imagerylayerpopup.html
178
+ const wms = ANOVGIS.ImageryLayerFactory.createImageryLayer(ANOVGIS.ImageryType.WMS, {
179
+ url: 'http://server.mars3d.cn/geoserver/mars/wms',
180
+ layers: 'mars:hf',
181
+ parameters: { transparent: true, format: 'image/png' },
182
+ rectangle: Cesium.Rectangle.fromDegrees(116.85, 31.53, 117.63, 32.16),
183
+ getFeatureInfoParameters: { feature_count: 10 },
184
+ selectedHighlight: { material: 'rgba(255,255,0,0.6)', height: 0.01 }
185
+ });
186
+ wms.bindPopup({ viewer, showTitle: true, useDefaultHtmlTemplate: true });
187
+ wms.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
188
+ wms.popup.show(e.position, {
189
+ title: 'wms',
190
+ fieldsMap: [{ nameC: '名称', value: e.feature.data.properties['用地名称'] || '未知' }]
191
+ });
192
+ });
193
+ viewer.imageryLayers.addImageryProvider(wms);
194
+ ```
195
+
196
+ ### S6b. WMS 影像线拾取 — `event/imagerylayerpopup_line.html` L24-L93
197
+
198
+ ```js
199
+ // 来源: imagerylayerpopup_line.html L28-91
200
+ // 与 S6 的关键差异: getFeatureInfoParameters.query_layers 强制只查线图层
201
+ // selectedHighlight.width 控制高亮线宽
202
+ const wms = ANOVGIS.ImageryLayerFactory.createImageryLayer(ANOVGIS.ImageryType.WMS, {
203
+ url: 'https://ahocevar.com/geoserver/wms',
204
+ layers: 'ne:ne',
205
+ parameters: { transparent: true, format: 'image/png' },
206
+ rectangle: Cesium.Rectangle.fromDegrees(73, 18, 135, 53),
207
+ getFeatureInfoParameters: {
208
+ feature_count: 10,
209
+ query_layers: 'ne:ne_10m_admin_1_states_provinces_lines_shp' // 强制只查线图层
210
+ },
211
+ selectedHighlight: { material: 'rgba(255,255,0,0.6)', width: 5, height: 0.01 }
212
+ });
213
+ wms.bindPopup({ viewer, showTitle: true, useDefaultHtmlTemplate: true });
214
+ wms.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
215
+ const p = e.feature.data.properties || {};
216
+ wms.popup.show(e.position, {
217
+ title: e.feature.data.id || '没有名字',
218
+ fieldsMap: [
219
+ { nameC: '编号', value: e.feature.data.id },
220
+ { nameC: '类别', value: p.featurecla },
221
+ { nameC: '左侧', value: p.name_l },
222
+ { nameC: '右侧', value: p.name_r },
223
+ ]
224
+ });
225
+ });
226
+ viewer.imageryLayers.addImageryProvider(wms);
227
+ ```
228
+
229
+ ### S6c. WMS 影像点拾取 — `event/imagerylayerpopup_point.html` L24-L103
230
+
231
+ ```js
232
+ // 来源: imagerylayerpopup_point.html L28-101
233
+ // 与 S6 的关键差异: selectedHighlight 用 width:39, height:39 实现大圆点高亮
234
+ const wms = ANOVGIS.ImageryLayerFactory.createImageryLayer(ANOVGIS.ImageryType.WMS, {
235
+ url: 'https://ahocevar.com/geoserver/wms',
236
+ layers: 'ne:ne_10m_populated_places',
237
+ parameters: { transparent: true, format: 'image/png' },
238
+ rectangle: Cesium.Rectangle.fromDegrees(73, 18, 135, 53),
239
+ getFeatureInfoParameters: { feature_count: 10 },
240
+ selectedHighlight: { // 点高亮
241
+ color: 'rgba(255,0,255,0.99)',
242
+ width: 39, height: 39
243
+ }
244
+ });
245
+ wms.bindPopup({ viewer, showTitle: true, useDefaultHtmlTemplate: true });
246
+ wms.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
247
+ const p = e.feature.data.properties || {};
248
+ wms.popup.show(e.position, {
249
+ title: p.NAME || e.feature.data.id || '未查到名称',
250
+ fieldsMap: [
251
+ { nameC: '国家', value: p.ADM0NAME },
252
+ { nameC: '省级', value: p.ADM1NAME },
253
+ { nameC: '人口(万)', value: p.POP_MAX != null ? Math.round(p.POP_MAX / 10000) : '未知' },
254
+ { nameC: '首都', value: p.ADM0CAP == 1 ? '是' : '否' },
255
+ { nameC: '海拔(m)', value: p.ELEVATION },
256
+ ]
257
+ });
258
+ });
259
+ viewer.imageryLayers.addImageryProvider(wms);
260
+ ```
261
+
262
+ ### S7. 自定义 HTML 字符串 Popup(非默认模板)
263
+
264
+ ### S7. 自定义 HTML 字符串 Popup(非默认模板)
265
+
266
+ ```js
267
+ // 来源: examples/public/examples/html/event/popup.html L48-92 + graphics/divInfo.html
268
+ const htmlContent = `
269
+ <div class="custom-popup">
270
+ <h3>${entity.name}</h3>
271
+ <p>坐标:${entity.position.lng}, ${entity.position.lat}</p>
272
+ <button onclick="alert('Clicked!')">操作</button>
273
+ </div>
274
+ `;
275
+ v.bindPopup({ viewer, useDefaultHtmlTemplate: false }); // 关闭默认模板
276
+ v.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
277
+ v.popup.show(e.position, htmlContent); // 直接传 HTML 字符串
278
+ });
279
+ ```
280
+
281
+ ### S8. Popup 偏移与对齐
282
+
283
+ ```js
284
+ // 来源: src/base/widgets/Popup.js + examples
285
+ v.bindPopup({
286
+ viewer, showTitle: true, useDefaultHtmlTemplate: true,
287
+ offsetX: 0, // 水平偏移(像素)
288
+ offsetY: -20, // 垂直偏移(像素)
289
+ horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 锚点
290
+ verticalOrigin: Cesium.VerticalOrigin.BOTTOM
291
+ });
292
+ ```
293
+
294
+ ### S9. DOM 弹窗(DivIcon)+ pointerEvents 交互
295
+
296
+ ```js
297
+ // 来源: examples/public/examples/html/graphics/divInfo.html L111-135
298
+ const layer = new ANOVGIS.HtmlLayer({ layerName: 'info' });
299
+ viewer.addLayer(layer);
300
+
301
+ const div = new ANOVGIS.DivIcon(
302
+ new ANOVGIS.Position(116.38, 39.10, 1),
303
+ `<div class="boxbg">
304
+ <img src="../modelData/images/gyqy.png" />
305
+ <div class="div-right">天然纤维是自然界原有的...</div>
306
+ <button onclick="alert('点击了')">详情</button>
307
+ </div>`
308
+ );
309
+ div.setOptions({
310
+ horizontalOrigin: 'CENTER', verticalOrigin: 'TOP',
311
+ offsetX: 0, offsetY: -60,
312
+ pointerEvents: true, // 开启后 DOM 可交互(点击、滚动)
313
+ scaleByDistance: { near: 0, nearValue: 1.0, far: 10000, farValue: 0.0 }
314
+ });
315
+ div.addEventListener(ANOVGIS.MouseEventType.CLICK, () => alert('点击了'));
316
+ layer.addGraphic(div);
317
+ ```
318
+
319
+ ### S10. 按视距缩放 Popup
320
+
321
+ ```js
322
+ // 来源: src/base/widgets/WidgetBase.js
323
+ v.bindPopup({
324
+ viewer, showTitle: true, useDefaultHtmlTemplate: true,
325
+ scaleByDistance: new ANOVGIS.NearFarScalar(
326
+ 100, 1.0, // 100m 内全尺寸
327
+ 10000, 0.1 // 10000m 外缩到 0.1
328
+ )
329
+ });
330
+ ```
331
+
332
+ ### S11. 手动控制 Popup 显隐
333
+
334
+ ```js
335
+ // 来源: src/base/widgets/Popup.js
336
+ const popup = v.popup; // bindPopup 后 v 上有 popup 实例
337
+ popup.show(Cesium.Cartesian3.fromDegrees(116.40, 39.90), infoData);
338
+ popup.hide(); // 关闭
339
+ popup.toggle(); // 切换显隐
340
+ // 销毁
341
+ popup.destroy();
342
+ ```
343
+
344
+ ### S12. Template 自定义模板(高级)
345
+
346
+ ```js
347
+ // 来源: src/base/widgets/Template.js
348
+ // SDK 默认模板在 Template.js 中定义。需深度自定义时,可继承 Template 重写 render
349
+ class MyTemplate extends ANOVGIS.Template {
350
+ render(infoData) {
351
+ return `
352
+ <div class="my-popup">
353
+ <h2>${infoData.title}</h2>
354
+ ${infoData.fieldsMap.map(f => `
355
+ <div><label>${f.nameC}:</label><span>${f.value}</span></div>
356
+ `).join('')}
357
+ </div>
358
+ `;
359
+ }
360
+ }
361
+ v.bindPopup({
362
+ viewer, useDefaultHtmlTemplate: true,
363
+ template: new MyTemplate() // 注入自定义模板
364
+ });
365
+ ```
366
+
367
+ ### S13. WidgetEventType 监听弹窗生命周期
368
+
369
+ ```js
370
+ // 来源: src/base/event/EventType.js
371
+ v.popup.addEventListener(ANOVGIS.WidgetEventType.OPEN, () => {
372
+ console.log('popup opened');
373
+ });
374
+ v.popup.addEventListener(ANOVGIS.WidgetEventType.CLOSE, () => {
375
+ console.log('popup closed');
376
+ });
377
+ ```
378
+
379
+ ### S14. 整 layer 统一 bindPopup(VectorLayer bindPopup 模式)
380
+
381
+ ```js
382
+ // 来源: examples/public/examples/html/event/popup.html L48-92
383
+ const layer = new ANOVGIS.VectorLayer();
384
+ viewer.addLayer(layer);
385
+ layer.bindPopup({ viewer, showTitle: true, useDefaultHtmlTemplate: true });
386
+
387
+ // 所有 graphic 自动有 popup(前提是 graphic.options.infoData 有值)
388
+ layer.addEventListener(ANOVGIS.MouseEventType.CLICK, (e) => {
389
+ layer.popup.show(e.position, e.graphic.infoData);
390
+ });
391
+ ```
392
+
393
+ ### S15. Popup 内容动态更新
394
+
395
+ ```js
396
+ // 来源: src/base/widgets/Popup.js
397
+ v.popup.show(position, { title: 'A', value: 1 });
398
+ // 3 秒后更新内容(不要 hide + show,直接 update)
399
+ setTimeout(() => {
400
+ v.popup.update({ title: 'A(已更新)', value: 2 });
401
+ }, 3000);
402
+ ```
403
+
404
+ ---
405
+
406
+ ## 4. 模板与字段格式
407
+
408
+ ### 4.1 infoData 默认格式
409
+
410
+ ```js
411
+ infoData = {
412
+ title: '标题', // 主标题
413
+ fieldsMap: [ // 字段映射数组
414
+ { nameC: '名称', value: '北京' }, // nameC = 列名中文, value = 值
415
+ { nameC: '人口', value: 21540000 },
416
+ { nameC: '面积', value: '16410 km²' }
417
+ ]
418
+ }
419
+ ```
420
+
421
+ `useDefaultHtmlTemplate: true` 时,SDK 走 `Template.js` 中的默认 HTML 模板渲染 infoData。
422
+
423
+ ### 4.2 自定义 HTML 字符串
424
+
425
+ ```js
426
+ popup.show(position, '<div>任意 HTML</div>'); // 直接传字符串
427
+ ```
428
+
429
+ `useDefaultHtmlTemplate: false` 时,第二个参数就是 HTML 字符串本身。
430
+
431
+ ### 4.3 Template 高级自定义
432
+
433
+ 继承 `ANOVGIS.Template`,重写 `render(infoData)` 方法,返回 HTML 字符串。`useDefaultHtmlTemplate: true` 时通过 `template: new MyTemplate()` 注入。
434
+
435
+ ---
436
+
437
+ ## 5. 反模式
438
+
439
+ | 错误 | 后果 | 正确做法 |
440
+ |---|---|---|
441
+ | `v.popup.show(pos, infoData)` 但没 `bindPopup` | popup 实例不存在 → 报错 | 先 `v.bindPopup({ viewer })` |
442
+ | Tileset Popup 用 `e.graphic.infoData` | undefined(feature ≠ graphic) | 改用 `e.feature.getProperty('xxx')` |
443
+ | ImageryLayer Popup 用 `e.feature.getProperty` | properties 路径不同 | 改用 `e.feature.data.properties['xxx']` |
444
+ | `pointerEvents: false` 但 DOM 想点击 | 点击穿透到 Cesium | 改 `true` 并确保 DOM 有 `cursor: pointer` |
445
+ | `scaleByDistance` 给 `Popup` 但没传 `NearFarScalar` | 视距缩放失效 | `new ANOVGIS.NearFarScalar(near, nearValue, far, farValue)` |
446
+ | `infoData` 字段缺失 `title` | Popup 标题为空 | 始终传 `title: '...'` |
447
+ | `bindPopup` 后没监听 CLICK 事件 | Popup 永远不显示 | 必须 `addEventListener(MouseEventType.CLICK, e => popup.show(...))` |
448
+ | `popup.destroy()` 后还想 show | 报错 | 重新 `bindPopup` 一次 |
449
+
450
+ ---
451
+
452
+ ## 6. 关联阅读
453
+
454
+ - SDK 源码:
455
+ - `src/base/widgets/Popup.js`
456
+ - `src/base/widgets/Tooltip.js`
457
+ - `src/base/widgets/Template.js`
458
+ - `src/base/widgets/WidgetBase.js`
459
+ - `src/base/widgets/InfoBox.js`
460
+ - `src/base/event/EventType.js`(WidgetEventType)
461
+ - 兄弟 skill:
462
+ - [`anovgis-vector-graphics`](../anovgis-vector-graphics/SKILL.md) — `bindPopup` 基础用法(在 §5 已有 8 个 snippet)
463
+ - [`anovgis-models-3dtiles`](../anovgis-models-3dtiles/SKILL.md) — tilesetpopup 完整示例
464
+ - [`anovgis-layers`](../anovgis-layers/SKILL.md) — layer.bindPopup 整层模式
465
+ - [`anovgis-imagery-terrain`](../anovgis-imagery-terrain/SKILL.md) — ImageryLayer WMS Popup
466
+ - 关键 demo:
467
+ - `examples/public/examples/html/event/popup.html`
468
+ - `examples/public/examples/html/event/tooltip.html`
469
+ - `examples/public/examples/html/event/highlight.html`
470
+ - `examples/public/examples/html/event/tilesetpopup.html`、`tilesetpopup1.html`
471
+ - `examples/public/examples/html/event/imagerylayerpopup.html`、`imagerylayerpopup_line.html`、`imagerylayerpopup_point.html`
472
+ - `examples/public/examples/html/graphics/divInfo.html`、`divInfo2.html`
473
+ - DOMAINS.md:`#1.6-base/Popup/Widget`、第 3 节反归属清单
474
+ - DEMO-SKILL-MAP.md:`#8-event/`、`#2-graphics/divInfo*`