gis-view-webgl2 0.1.4 → 0.1.6

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 (37) hide show
  1. package/README.md +10 -7
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.d.ts +225 -20
  4. package/dist/index.js +1 -1
  5. package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +109 -0
  6. package/docs/GisView.md +53 -53
  7. package/docs/ai/06-/344/274/232/350/257/235/347/264/242/345/274/225/344/270/216/345/244/215/346/237/245/346/226/271/346/263/225.md +91 -0
  8. package/docs/demos/ConnectDemo.vue +114 -3
  9. package/docs/demos/MinimapDemo.vue +216 -17
  10. package/docs/demos/SearchFilterDemo.vue +113 -1
  11. package/docs/demos/api-index.js +28 -20
  12. package/docs/demos/demos.js +1 -1
  13. package/docs/demos/gis-view-demo/GisViewDemoStage.vue +25 -16
  14. package/docs/demos/gis-view-demo/useGisViewDemo.js +27 -16
  15. package/docs/index.html +3 -3
  16. package/docs/internals/13-/351/271/260/347/234/274/345/233/276.md +8 -5
  17. package/docs/internals/16-01-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/212.md +18 -5
  18. package/docs/internals/16-03-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/213.md +11 -1
  19. package/docs/internals/18-/346/200/247/350/203/275/345/256/236/346/265/213/344/270/216WebGPU/350/257/204/344/274/260.md +73 -1
  20. package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +14 -5
  21. package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +2 -2
  22. package/docs/manual/05-/347/224/273/350/264/250/344/270/216/346/211/271/351/207/217/346/233/264/346/226/260.md +1 -1
  23. package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +1 -1
  24. package/docs/manual/10-/351/200/232/351/201/223/347/274/226/350/276/221/344/270/216/346/226/260/345/242/236.md +423 -3
  25. package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +99 -30
  26. package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +12 -7
  27. package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +14 -6
  28. package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +137 -6
  29. package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +4 -0
  30. package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +8 -3
  31. package/docs/manual/21-/350/257/264/346/230/216/344/270/216/345/270/270/350/247/201/351/227/256/351/242/230.md +6 -3
  32. package/docs/steps/README.md +6 -6
  33. package/docs/steps/selftest-demos.html +252 -9
  34. package/docs/steps/selftest-docs.html +3 -3
  35. package/docs/steps/selftest-full.html +357 -13
  36. package/docs/steps/selftest-perf.html +599 -382
  37. package/package.json +1 -1
@@ -165,10 +165,22 @@ view.focusOn('station-1024', { center: true }) // 要素:id / { ty
165
165
  view.focusOn({ type: 'channel', channelId: 'channel-a' }, { center: true }) // 通道:取它范围的中心
166
166
  view.focusOn({ lngLat: [116.4, 39.9] }, { center: true }) // 配了 GeoJSON 底图时按经纬度
167
167
  view.focusOn({ minX: 116, minY: 39, maxX: 117, maxY: 40 }, { center: true }) // 一段范围:取中心
168
+
169
+ // flyTo:目标与选项和 focusOn 完全一致,只多 duration / easing,把相机平滑飞过去
170
+ view.flyTo(hit, { zoom: true, duration: 600, easing: 'ease-in-out' })
171
+ view.flyTo(grouped, { zoom: true, select: true })
172
+ view.flyTo('station-1024', { duration: 0 }) // 立即落位,不播动画
173
+ view.stopCameraAnimation() // 停在当前帧,不补跳到终点
174
+ const flight = view.getCameraAnimation() // { active, progress, duration, from, to } 或 null
175
+ const flying = view.cameraAnimating // 只读:按钮在「飞向 / 停止」之间切换
168
176
  ```
169
177
 
170
178
  字符串 / 数字仍然兼容旧写法:先按节点 id 找,再按线路 id 找;同一个 id 同时出现在节点与线路里时用 `{ type: 'point' | 'line', id }` 消歧。裸字符串不表示通道;整条通道可以写 `{ channelId }`,要和通用 `id` / `index` 写法区分时再用 `{ type: 'channel', ... }`。分组必须写 `{ type: 'group', channelId?, groupId }`,`groupId` 在全部通道里唯一时可以省略通道。节点、线路、通道与分组都先解析成世界坐标范围;**缺省只按这个范围的中心调 `centerOn`,比例一点不动**,要适配就显式写 `zoom: true`,这时才交给 `zoomToBounds` 按解析出的真实 `bounds` 计算,没有为某类目标额外乘放大倍率。`scale` 的优先级高于 `zoom`;`maxZoom` 只给单点 / 单线这类零面积目标补最小范围。
171
179
 
180
+ 需要动画过渡时把同一个目标与选项交给 `flyTo`:默认 450 ms,中心线性、比例按对数插值;`easing` 可写 `'linear'` / `'ease-in'` / `'ease-out'` / `'ease-in-out'` 或自定义函数。`duration <= 0` 与系统 `prefers-reduced-motion: reduce` 都直接落位。飞行中用户拖拽 / 滚轮、再次 `flyTo`,或调用 `setCamera` / `centerOn` / `zoomTo` / `fitView` / `resetView` / `applyInitialView` 都会停在当前帧;`stopCameraAnimation()` 也是同一口径,`cameraAnimating` / `getCameraAnimation()` 用来驱动停止按钮与进度读数。
181
+
182
+ 如果目标本来就是一份相机读数(例如保存 / 恢复视图、`getCamera()` 的回灌、或外部时间轴算出来的中心与比例),用 `flyToCamera({ center?, scale? }, { duration, easing })` 直接飞向它:缺省的字段沿用当前相机,不经过要素解析,也不改选中与数据;`duration <= 0` 同样立即落位。它和 `setCamera` 的分工是「要不要过渡」:`setCamera` 当场落位,`flyToCamera` 走同一套飞行动画与取消口径。
183
+
172
184
  | `focusOn` 的选项 | 说明 |
173
185
  | --- | --- |
174
186
  | `zoom: true` | 显式要求按目标范围适配视图;不写就只居中、比例不动 |
@@ -193,7 +205,7 @@ view.focusOn({ minX: 116, minY: 39, maxX: 117, maxY: 40 }, { center: true }) //
193
205
  - 默认全字段模式会跳过 `symbol` / `style` / `tooltip` 这类外观结构;但 `fields` 显式点名时按路径直接读取,不受这条跳过规则限制。例如 `fields: ['symbol']`、`fields: ['style.color']` 能命中对应值。
194
206
  - 搜索基于当前数据:`hide` 模式下被隐藏的要素仍在数据里,因此仍然可以被搜到;`remove` 模式下已经删掉的要素搜不到。`scope` 写错或传空数组时会回落到四类全搜;重复线路 id 按数据里的第一条解析(见 [ID 解析口径](02-坐标与数据.md#id-解析口径))。
195
207
 
196
- 搜索**不动视角**:命中里带着 `bounds`,要定位就自己调 `focusOn(result.hits, …)` —— 缺省只把一批命中的整体中心当屏幕中心;要按范围适配就写 `{ zoom: true }`,`{ select: true }` 还能顺带把它们选上。`zoom` / `scale` / `padding` / `maxZoom` 属于 `focusOn` 的选项,搜索本身没有这些参数。
208
+ 搜索**不动视角**:命中里带着 `bounds`,要定位就自己调 `focusOn(result.hits, …)` —— 缺省只把一批命中的整体中心当屏幕中心;要按范围适配就写 `{ zoom: true }`,`{ select: true }` 还能顺带把它们选上。需要平滑过渡就把同一份调用换成 `flyTo(result.hits, { zoom: true, duration: 600 })`。`zoom` / `scale` / `padding` / `maxZoom` / `duration` / `easing` 属于定位方法的选项,搜索本身没有这些参数。
197
209
 
198
210
  匹配的是要素自己的字段:`id`、`name`、`from` / `to`,以及任意业务字段——`props` 这类普通对象会再往里摊一层,所以 `props.vn_kv` 里的值也能搜到;样式与符号字段不参与匹配。**通道连成员回线一起搜**:命中的是通道里的某条回线时,命中里会带上 `channelIndex`、`memberIndex`(第几回,0 开始)与 `memberLineIndex` / `memberLineId`,`bounds` 也换成那条回线的范围,`focusOn(hit)` 会把中心移到通道里的这条线路上,`focusOn(hit, { zoom: true })` 才按它的范围适配;反过来搜线路时,属于通道的线路也会带上 `channelIndex` / `memberIndex`。
199
211
 
@@ -230,6 +242,8 @@ const search = async keyword => {
230
242
 
231
243
  同步的 `search` 与 `searchAsync` 在**同一个数据版本 + 同一个请求**上结果逐字段一致(四类命中、命中的字段与值、`item` 引用、`bounds`);分组范围的当前轻量快照会随请求交给 Worker,分组字段或分组 id 改过之后也不会拿旧快照匹配。环境不支持 Worker、数据量不到阈值或 Worker 报错时,`searchAsync` 会退回同步计算再 resolve,调用方不用写两条路。
232
244
 
245
+ 这个「数据版本」现在也对外开放为只读属性 `view.dataVersion`:每次数据变更(`updatePoint` / `updateLine` / 批量补丁 / 拖拽落地 / 增删 / 撤销重做 / 换数据)递增,样式类 `updateOptions` / `updateLineStyle` 不递增,`onDataChange` 载荷里的 `dataVersion` 与它同一时刻同一个数。外部搜索缓存、增量统计或「这份结果是否过期」的判定可以直接比它,不必自己维护修订号;要读某条线路当前解析后的线宽 / 颜色快照用 `getLineStyle(index)`。
246
+
233
247
  ## 初始视图
234
248
 
235
249
  不配 `initialView` 时,首次拿到数据会 `fitView()`:整个数据范围铺满画布。数据一多,一屏全是点线看不出重点,`initialView` 用一份配置决定首屏落在哪里:
@@ -388,13 +402,22 @@ createGisView(container, {
388
402
  height: 132,
389
403
  position: 'bottom-right',
390
404
  margin: 12,
405
+ // 相对当前角落的位移(CSS 像素):x 正数向右、y 正数向下;updateOptions 改它就能移动整张图
406
+ offset: [0, 0],
407
+ // 外部宿主:HTMLElement 或选择器;不写就挂在主视图根节点。外部宿主需要 position: relative
408
+ // container: document.querySelector('#my-minimap-host'),
391
409
  padding: 0.04, // 数据四周留白,取短边比例
392
410
  // 范围:'auto'(默认)数据与底图合起来、'data' 只看数据(老行为)、'background' 只看底图
393
411
  // 也能直接写死一份世界范围:extent: { minX: 0, minY: 0, maxX: 1000, maxY: 800 }(固定按它铺,不跟数据与底图走)
394
412
  extent: 'auto',
413
+ // 动态范围是否跟着当前可见内容重算:默认 false,首次铺好后筛选 / 隐藏 / 删除都不会改小图范围
414
+ extentFollowContent: false,
415
+ // 仅 extent: 'auto' 生效;默认 false 始终按数据 ∪ 底图,打开后才允许按相机位置收窄
416
+ extentFollowCamera: false,
395
417
  // 小图背景:inherit(默认,复用主视图解析好的背景)/ false 关掉 / 对象自己配一份
396
418
  background: 'inherit',
397
- backgroundStyle: 'rgba(255, 255, 255, 0.92)', // 小图容器自身的 CSS 底色
419
+ // 显式设置时接管画布底色:继承的底图仍画图片 / GeoJSON,但不再用主图底色盖住它
420
+ backgroundStyle: 'rgba(255, 255, 255, 0.92)',
398
421
  borderColor: '#d7e2ef',
399
422
  radius: 6,
400
423
  pointStyle: { color: '#4b8dff', size: 1.4 },
@@ -404,13 +427,13 @@ createGisView(container, {
404
427
  lineWidthScale: 1,
405
428
  pointMapZoomScale: 0.5, // 主图放大 4 倍,小图节点放大 2 倍(基准缺省取主图适应视图时的比例)
406
429
  lineMapZoomScale: 0.5,
407
- // 小图自己的规则:颜色、半径 / 线宽、形状、层级都能按属性给;不配就沿用主图规则的颜色与层级
430
+ // 小图自己的规则:颜色、半径 / 线宽、形状、层级都能按属性给;不配就沿用主图样式(含尺寸与图标)
408
431
  pointRules: [
409
432
  { when: { vn_kv: { gte: 500 } }, style: { color: '#ff4d4f', size: 1.8, shape: 'square', zIndex: 2 } },
410
433
  { when: { vn_kv: { lt: 500 } }, style: { color: '#8c9aae', size: 1.2, zIndex: 1 } }
411
434
  ],
412
435
  lineRules: [{ when: { vn_kv: { gte: 500 } }, style: { color: '#ff8a3d', width: 1.2, opacity: 0.9, zIndex: 1 } }],
413
- inheritRules: true, // 没配自己的规则时才沿用主图的(只取颜色 / 描边色 / 透明度 / 层级,主图的尺寸是主画布上的像素)
436
+ inheritRules: true, // 没配自己的规则时才沿用主图:颜色 / 透明度 / 层级 + 最终节点尺寸与图标、线路线宽
414
437
  levels: [1, 2], // 只画这两层(按规则的 zIndex 分层,没写 zIndex 算第 0 层);不配就是全画
415
438
  cascade: 'binding', // 被 levels 挡掉的节点,连在它身上的线路一起隐藏;写法与筛选的 cascade 一样
416
439
  layered: true, // 分层叠画:zIndex 大的盖在上面;关掉就按数据顺序画
@@ -424,13 +447,14 @@ createGisView(container, {
424
447
  // 一次手势完成后的回调(无位移的点击不发):载荷带 type / local / world / zoom / extent / camera / viewport
425
448
  onInteraction: info => console.log(info.type, info.world),
426
449
  longPressDelay: 180,
427
- zoomable: false, // 打开后小图自身也能整体放大缩小,滚轮与下面这组倍数都归它
428
- zoom: 1, // 初始倍数,1 表示「刚好铺满小图」
450
+ zoomable: false, // false 关闭;true 手动缩放小图;'follow' 整体范围跟随主图。true 与 'follow' 互斥
451
+ followZoomScale: 1, // 仅 'follow' 生效:主图倍数的指数,1 同倍率、0.5 为主图放大 4 倍时小图放大 2 倍
452
+ zoom: 1, // 小图倍数;手动模式是初始值,跟随模式是基准倍数。1 表示「刚好铺满小图」
429
453
  minZoom: 0.5,
430
454
  maxZoom: 8,
431
455
  zoomStep: 1.4, // 每一次放大 / 缩小的倍率(滚轮一格、zoomInStep / zoomOutStep 可分别覆盖)
432
- dragAction: 'pan', // 开了 zoomable 之后,空白处拖动是平移小图(默认)还是直接框选
433
- channelCircuits: true, // 通道画全部回线;false 时一个通道只画偏移最靠中间的那一根
456
+ dragAction: 'pan', // 空白处拖动是平移小图(默认,需手动缩放)还是直接框选;box 不依赖 zoomable
457
+ channelCircuits: true, // 通道画全部回线;false 时每组按可见成员逐顶点平均成一根居中代表线
434
458
  // 容器外观:附加类名 + 内联样式(中划线 / CSS 变量与驼峰键都认,换配置时旧键会清掉)
435
459
  className: 'my-minimap',
436
460
  style: { boxShadow: '0 2px 10px rgba(0, 0, 0, 0.18)' },
@@ -463,64 +487,108 @@ createGisView(container, {
463
487
  | `width` / `height` | `number` | `168` / `120` | 小图尺寸(CSS 像素) |
464
488
  | `position` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `'bottom-right'` | 贴在画布的哪一角 |
465
489
  | `margin` | `number` | `12` | 与画布边缘的距离(CSS 像素) |
490
+ | `offset` | `[number, number]` | `[0, 0]` | 相对 `position` 那个角的位移(CSS 像素):`x` 正数向右、`y` 正数向下。`updateOptions({ minimap: { ...old, offset: [x, y] } })` 就能动态移动整张鹰眼图,四个角都按同一套方向换算 |
491
+ | `container` | `HTMLElement \| string \| null` | 无(主视图根节点) | 把鹰眼图挂到外部 `div`:可传元素或 CSS 选择器。给了就把同一根节点移进它,`position` / `margin` / `offset` 都相对这个宿主;宿主需要 `position: relative`(或 `absolute` / `fixed`)。选择器找不到时回落到主视图根节点;运行时换容器只移动节点,不重建画布。用 `view.getMinimapElement()` 可以拿到这个根节点做整图拖动 |
466
492
  | `padding` | `number` | `0.04` | 数据四周留白,取短边比例 |
467
- | `extent` | `'auto' \| 'data' \| 'background' \| GisViewBounds \| [[number, number], [number, number]]` | `'auto'` | 小图按哪段世界范围铺:`auto` 取「数据范围 ∪ 底图范围」,`data` 只看数据(旧行为),`background` 只看底图;数据与 GeoJSON 底图不在一个坐标系时,`auto` 能把两者一起框进小图,底图不会缩成一个点/糊成一片。例外:相机正落在其中一份范围里、而那一份合并后连 6 个像素都占不到时,`auto` 只画正在看的那一份(数据还没映射到底图、两者离得很远就是这样),相机挪进 / 挪出会各重画一次。也可以直接写一份世界范围(`{ minX, minY, maxX, maxY }`,也认 `[[minX, minY], [maxX, maxY]]`):固定按它铺,不跟数据与底图走 |
493
+ | `extent` | `'auto' \| 'data' \| 'background' \| GisViewBounds \| [[number, number], [number, number]]` | `'auto'` | 小图按哪段世界范围铺:`auto` 取「数据范围 ∪ 底图范围」,`data` 只看数据(旧行为),`background` 只看底图;数据与 GeoJSON 底图不在一个坐标系时,`auto` 能把两者一起框进小图,底图不会缩成一个点/糊成一片。也可以直接写一份世界范围(`{ minX, minY, maxX, maxY }`,也认 `[[minX, minY], [maxX, maxY]]`):固定按它铺,不跟数据与底图走 |
494
+ | `extentFollowContent` | `boolean` | `false` | 动态范围是否跟着当前可见内容重算。默认关闭:首次拿到数据 / 底图范围后锁住小图的世界范围,筛选、删除、隐藏或新增要素都不会改缩放与中心,外围内容消失时鹰眼图和视口框不会自己跳;打开后,每次数据或筛选结果变化都会按当前内容重算。显式改 `extent`(包括直接写固定范围)始终立即生效 |
495
+ | `extentFollowCamera` | `boolean` | `false` | `extent: 'auto'` 时是否允许包围盒跟着相机收窄。默认关闭,始终按「数据 ∪ 底图」铺;打开后,相机正落在其中一份范围里、而那一份合并后连 6 个像素都占不到时,只画正在看的那一份(数据还没映射到底图、两者离得很远时最明显),相机挪进 / 挪出会各重画一次。`extentFollowContent: false` 时参与比较的是锁定下来的那一份数据 / 底图范围 |
468
496
  | `className` / `style` | `string` / `Record<string, string \| number>` | 无 | 小图容器自己的类名与内联样式(中划线 / CSS 变量键与驼峰键都认):想按自己的设计系统改外观时用;换配置时上一轮写过、这一轮没写的键会被清掉 |
469
497
  | `draw` | `(info: GisViewMinimapDrawInfo) => void` | 无 | 兼容旧写法的最终一层:在所有 `layers` 之后、视口框之前调用(`info.stage === 'overlay'`;视口框由 DOM 画在它上面)。`info` 里是 `context`(已按备份像素比缩放好,直接按 CSS 像素画)、`canvas`、`width` / `height` / `ratio`、`extent` / `bounds` / `scale` / `zoom`、`project` / `unproject`(与内置图层同一套投影)与这一帧的 `data` / `background`;钩子里改过的上下文状态由组件 save / restore 收好,不会漏进下一帧 |
470
498
  | `layers` | `GisViewMinimapLayer[]` | 无 | 可拆分的自定义绘制层:每项写 `{ id?, order?, placement?, enabled?, draw }`。`placement: 'below-data'` 画在内置线路 / 节点之前,`'above-data'`(默认)画在之后;同一段内按 `order` 从小到大,相同或未写时按数组顺序。每层独立 `save` / `restore`,一层改过的画布状态不会串到下一层;`enabled: false` 可临时关掉一层。回调里的 `stage` 就是当前段,旧的单层 `draw` 固定最后执行。排序在 `updateOptions` 时缓存,绘制帧不再逐层排序 |
471
499
  | `maxPixelRatio` | `number` | `4` | 小图画布备份像素比的上限(实际倍率 = `min(devicePixelRatio × 宿主显示比例, maxPixelRatio)`,夹在 1 ~ 4)。默认 4 保留高分屏清晰度;小图尺寸大或高分屏填充压力高时降到 1 ~ 2 可明显减少像素填充,代价是缩略图边缘变软 |
472
500
  | `background` | `'inherit' \| false \| 'none' \| GisViewBackground \| string` | `'inherit'` | 小图画什么底图:`inherit` 复用主视图解析好的背景(底色 / 图片 / GeoJSON 的逐区域配色与区域文字都跟着),传对象就是小图自己的一份(结构与主视图的 `background` 完全一致,用 Canvas2D 画),`false` / `'none'` 关掉;传字符串按旧行为当容器底色 |
473
- | `backgroundStyle` | `string` | `'rgba(255, 255, 255, 0.92)'` | 小图容器自己的 CSS 底色,垫在 `background` 下面(想让小图透出主视图底色就写 `transparent`) |
501
+ | `backgroundStyle` | `string` | `'rgba(255, 255, 255, 0.92)'` | 小图容器自己的 CSS 底色。**显式设置时接管画布底色**:继承 / 独立的底图仍画图片与 GeoJSON,但画布不再铺一层不透明底色把它盖住;不写时保持旧行为。想要完全透出宿主就写 `transparent` |
474
502
  | `borderColor` / `borderWidth` / `radius` | `string` / `number` | `#d7e2ef`、1px、6px | 小图自身的外观 |
475
- | `pointStyle` | `{ color?, strokeColor?, size? }` | `#4b8dff` / `1.2` | 节点的颜色与画在小图上的半径,与主图样式无关;节点画在线路之上。小图上的点是一块**实心像素**,配了 `strokeColor` 就优先取它当填充色 —— 主图那套「白底 + 彩色描边」的规则沿用过来时,画出来就是描边色而不是白点 |
503
+ | `pointStyle` | `{ color?, strokeColor?, size? }` | `#4b8dff` / `1.2` | 小图自己的节点颜色与半径(CSS 像素),用于没有自己的 `pointRules` / 不继承主图样式时的回落;节点画在线路之上。小图上的点是一块**实心像素**,配了 `strokeColor` 就优先取它当填充色 —— 主图那套「白底 + 彩色描边」的规则沿用过来时,画出来就是描边色而不是白点 |
476
504
  | `lineStyle` | `{ color?, width?, opacity? }` | `#8fb2d8` / `1` / `0.55` | 线路的颜色、线宽与透明度,`opacity: 0` 就是不画线 |
477
505
  | `pointRules` | `GisViewMinimapPointRule[]` | 无 | 小图自己的节点规则:按属性给每个节点定颜色 / 半径 / 形状(`'circle'` / `'square'`)/ 层级,条件语言与主图的 `pointRules` 完全一样;规则里没写的字段回落到 `pointStyle` |
478
506
  | `lineRules` | `GisViewMinimapLineRule[]` | 无 | 小图自己的线路规则:颜色 / 线宽 / 透明度 / 层级,规则里没写的字段回落到 `lineStyle` |
479
507
  | `heatmap` | `GisViewHeatmap \| false` | 沿用主图 | 小图自己的热力图:不写就沿用主图的 `options.heatmap`(同一份色带与自动值域),写对象就单独换一份,`false` 表示小图不按热力着色(主图照旧),见「热力图」 |
480
- | `inheritRules` | `boolean` | `true` | 没配自己的规则时是否沿用主图的 `pointRules` / `lineRules`:只取颜色、透明度与层级这些**没有量纲**的字段(主图的 `size` / `width` 是主画布上的像素,照搬到小图上会糊成一片),尺寸仍由小图的 `pointStyle` / `lineStyle` 决定;显式 `false` 表示小图只用自己那份样式 |
508
+ | `inheritRules` | `boolean` | `true` | 没配自己的规则时是否沿用主图样式:节点取主图规则的颜色 / 描边色 / 层级,并沿主图最终解析出的尺寸与图标(点自身 > 规则 > `pointStyle`,圆、方、图片、SVG 与自定义图元都认);沿用尺寸 / 线宽时还会乘一次**小图与主图 CSS 视口宽高的较小比例**,只跟两边视口尺寸有关,不随主图相机倍数变化,小图比主图小时节点与线路不会仍顶着和主图一样的尺寸。线路沿用颜色 / 透明度与样式链线宽。显式 `false` 表示小图只用自己那份 `pointStyle` / `lineStyle` |
481
509
  | `levels` | `number[]` | 无 | 只画这些层级的节点:层级取规则的 `zIndex`(没写算第 0 层),不配表示全部画;「每一层显示什么级别」就是它 —— 按电压写了 `zIndex` 之后,只看 500kV 以上就写 `levels: [500, 1000]` |
482
510
  | `cascade` | `false \| 'binding' \| 'coordinate' \| 'both'` | `'binding'` | 被 `levels` 挡掉的节点,连在它们身上的线路怎么跟着隐藏:`binding` 按 `from` / `to` 绑定、`coordinate` 按端点坐标(端点正好落在被挡掉的节点上)、`both` 两者都算、`false` 不联动。与主视图筛选的 `cascade` 是同一套说法 —— 主视图筛掉的要素本来就带联动,这里管的是小图**自己**挡掉的那部分;只看某几层时不会留下一堆凭空断掉的线 |
483
511
  | `layered` | `boolean` | `true` | 节点是否分层叠画:`zIndex` 大的后画、盖在上面;关掉就按数据顺序画(同坐标的节点谁在上面看数据顺序) |
484
- | `pointSizeScale` / `lineWidthScale` | `number` | `1` | 节点半径 / 线宽的**整体倍数**(常数,与小图倍数无关),与主视图的 `pointSizeScale` / `lineWidthScale` 同名同义,乘在 `pointStyle` / 规则给出的尺寸上 |
485
- | `pointZoomScale` / `lineZoomScale` | `number` | `0` | 小图**自身**倍数对节点半径 / 线宽的放大指数:`0` 不跟随、`1` 与小图同倍率放大,`0.5` 是小图放大 4 倍、节点放大 2 倍(`zoomable` 打开后放大小图,节点与线路跟着变大,放大多少就是它) |
486
- | `pointMapZoomScale` / `lineMapZoomScale` | `number` | `0` | **主视图地图倍数**对节点半径 / 线宽的放大指数:`0` 不跟随、`1` 与主视图同倍率放大、`0.5` 是主视图放大 4 倍、小图节点放大 2 倍;与主视图的 `pointZoomScale` / `lineZoomScale` 是同一套说法,缩放主视图时小图上的节点 / 线路跟着变大小(相机一变就重铺一次像素) |
512
+ | `pointSizeScale` / `lineWidthScale` | `number` | `1` | 节点半径 / 线宽的**整体倍数**(常数,与小图自身倍数、主图相机倍数都无关),与主视图的 `pointSizeScale` / `lineWidthScale` 同名同义;自有规则 / 样式与沿用主图的节点 / 线路都乘这一份(继承尺寸先按两图比例缩放,再叠这一层) |
513
+ | `pointZoomScale` / `lineZoomScale` | `number` | `0` | 小图**自身**倍数对节点半径 / 线宽的放大指数:`0` 不跟随、`1` 与小图同倍率放大,`0.5` 是小图放大 4 倍、节点放大 2 倍;手动缩放(`zoomable: true`)与跟随主图(`zoomable: 'follow'`)都会改变小图倍数,因此这两种模式下都能看到效果;沿用主图的节点 / 线路也按这一份联动,但主图相机本身不会直接改它们的大小 |
514
+ | `pointMapZoomScale` / `lineMapZoomScale` | `number` | `0` | **主视图地图倍数**对节点半径 / 线宽的放大指数:`0` 不跟随、`1` 与主视图同倍率放大、`0.5` 是主视图放大 4 倍、小图节点放大 2 倍;只作用于小图自有规则 / 样式,沿用主图的节点 / 线路不吃这一份(它们按两边视口比例缩放,主图相机变化不改大小) |
487
515
  | `mapZoomBaseScale` | `number` | 主视图适应视图时的比例 | 上面这组联动的基准比例,缺省与主视图共用同一份(主视图的 `zoomBaseScale` 或首次适应视图时的比例),等于它时联动系数为 1 |
488
516
  | `boxStyle` | `{ fill?, fillOpacity?, stroke?, strokeWidth?, strokeStyle?, radius?, shadow? }` | 蓝底 0.14 + 1px 蓝框 | 视口框(代表当前视口)的样式:填充色与不透明度、边框颜色 / 宽度 / 线型(`solid` / `dashed` / `dotted`,`strokeWidth: 0` 不画边框)、圆角与 CSS `box-shadow` |
489
517
  | `selectStyle` | `GisViewMinimapBoxStyle` | 沿用 `boxStyle`(虚线框、填充 0.12) | 拖动时拉出的框选矩形单独覆盖的样式字段,没写的字段继续沿用 `boxStyle` —— 只换底色 / 边框色就能和视口框区分开 |
490
518
  | `interactive` | `boolean` | `true` | 是否允许在小图上拖动 |
491
519
  | `onInteraction` | `(info: GisViewMinimapInteractionInfo) => void` | 无 | 一次手势真正完成时通知一条:`type` 为 `box-drag` / `select` / `pan` / `zoom` / `wheel-main` / `long-press`;载荷带 `local` / `world`、小图倍数 `zoom`、当前范围 `extent`、相机 `camera` 与视口 `viewport`。没有位移的点击不触发,`pointermove` 期间也不逐帧回调;长按在触发跟随的那一刻回调。适合同步业务状态、埋点或驱动外部图例 |
492
520
  | `longPressDelay` | `number` | `180` | 空白处按住多久之后开始跟着拖(毫秒) |
493
- | `wheelZoom` | `boolean` | `true` | 是否允许在小图上用滚轮缩放**主图**(锚点落在光标处);`zoomable` 打开时主图改成 Ctrl / ⌘ + 滚轮 |
494
- | `zoomable` | `boolean` | `false` | 鹰眼图自身是否可以整体放大缩小:打开后滚轮直接缩放小图(锚点落在光标处),Ctrl / ⌘ + 滚轮仍然缩放主图 |
495
- | `zoom` / `minZoom` / `maxZoom` | `number` | `1` / `0.5` / `8` | 小图自身的倍数与范围:`1` 是刚刚铺满,`zoom` 是初始值,`setMinimapZoom` / `zoomMinimapBy` 与滚轮都在这个范围里夹取;`updateOptions` 里改了 `zoom` 或关掉 `zoomable` 会重置回铺满 |
521
+ | `wheelZoom` | `boolean` | `true` | 是否允许在小图上用滚轮缩放**主图**(锚点落在光标处);`zoomable: true` 时主图改成 Ctrl / ⌘ + 滚轮,`zoomable: 'follow'` 仍直接缩放主图 |
522
+ | `zoomable` | `boolean \| 'follow'` | `false` | 缩放模式:`false` 关闭;`true` 手动缩放小图自身(滚轮以光标为锚点,Ctrl / ⌘ + 滚轮留给主图);`'follow'` 让整体显示范围跟随主图倍数变化,滚轮仍缩放主图。`true` 与 `'follow'` 互斥,跟随模式下 `setMinimapZoom` / `zoomMinimapBy` 不抢控制权 |
523
+ | `followZoomScale` | `number` | `1` | 仅 `zoomable: 'follow'` 生效:主图相对基准倍数的指数。`1` 同倍率、`0.5` 是主图放大 4 倍时小图放大 2 倍、`0` 表示小图倍数不随主图变化;结果仍夹在 `minZoom` ~ `maxZoom` 之间 |
524
+ | `zoom` / `minZoom` / `maxZoom` | `number` | `1` / `0.5` / `8` | 小图自身的倍数与范围:`1` 是刚刚铺满;`zoom` 在手动模式下是初始值、在跟随模式下是基准倍数。`setMinimapZoom` / `zoomMinimapBy` 与手动滚轮都在这个范围里夹取;`updateOptions` 里改了 `zoom` 或切换缩放模式会按新模式重置/重算 |
496
525
  | `zoomStep` | `number` | `1.4` | 每一次放大 / 缩小的倍率:滚轮一格正好一个步进(连续滚动按比例取幂,单次最多两步),`zoomMinimapBy` 传的就是这个系数;`zoomInStep` / `zoomOutStep` 可以只覆盖放大或缩小一侧 |
497
- | `dragAction` | `'pan' \| 'box'` | `'pan'` | 开了 `zoomable` 之后,小图空白处(视口框之外)拖动的动作:`pan` 平移小图内容(主图不动,内容夹在数据范围里),`box` 直接拉出框选矩形;按住 Ctrl / ⌘ 拖动始终是另一个动作 |
498
- | `channelCircuits` | `boolean` | `true` | 通道是否画出全部回线:`false` 时一个通道只画偏移最靠中间的那一根(通道走向仍然看得出来),通道多的底图更清爽 |
526
+ | `dragAction` | `'pan' \| 'box'` | `'pan'` | 小图空白处(视口框之外)拖动的动作:`pan` 平移小图内容(主图不动,内容夹在数据范围里,需手动缩放才有可移动余量),`box` 直接拉出框选矩形让主图显示过去。`box` 不依赖 `zoomable`,关闭缩放时也能直接框选;只有手动缩放模式下,按住 Ctrl / ⌘ 才切换成另一个动作 |
527
+ | `channelCircuits` | `boolean` | `true` | 通道是否画出全部回线:`false` 时每个分组按当前可见成员逐顶点取平均,只画一根居中的代表线(双回线落在两根正中间,三回线落在中间那条),通道走向仍然看得出来,通道多的底图更清爽 |
528
+
529
+ 规则的用法与主图一致(同一套条件语言、按顺序命中、后命中的覆盖前面的),但只管小图的画法:节点按 `zIndex` 分层,`levels` 只留下指定层的节点,`layered: false` 时不排序、按数据顺序画;线路按「层级 + 颜色 + 线宽 + 透明度」分桶,一桶一条路径、一次 `stroke`,规则再多也不会把小图的绘制次数拉爆。没配自己的规则时(`inheritRules !== false`)完整沿用主图样式链:颜色 / 描边色 / 层级来自主图规则,节点尺寸与图标取主图最终解析出的那一份(点自身 > `pointRules` > `pointStyle`),线路线宽取主图样式链解析出的原始值,再按小图与主图 CSS 视口宽高的较小比例缩一次(不跟主图相机倍数走)—— 圆、方、图片、SVG 与自定义图元都保留主图的形状,但不会在小图上仍和主图一样大。显式配了小图自己的 `pointRules` / `lineRules`(或 `inheritRules: false`)时,对应的尺寸 / 线宽不受这一步影响,仍由小图自己的规则与样式决定;只配 `pointStyle` / `lineStyle` 不会单独关掉继承。节点的颜色取规则里的 `strokeColor`、没有才回落 `color`:主图的节点是白底 + 一圈电压色的描边,小图上一个点是一块实心像素,不这样取就会画成一堆白点(自己配的小图规则同样可以写 `strokeColor`)。
530
+
531
+ **动态位置与外部挂载**:`offset` 是整张鹰眼图相对当前角落的位移,最适合做「拖动整个小图」的底移量 —— 指针每移动一段,就把累计位移写回 `updateOptions`;`position` / `margin` 仍决定基准角落。`docs/demos/MinimapDemo.vue`(`?demo=minimap`)在小图顶部内置了一个「拖动整图」手柄:把 `getMinimapElement()` 返回的根节点当作拖动目标,指针位移累计到 `offset`,同时保留了小图内部的框选 / 平移手势;右侧还有「整图位置复位」按钮可以直接回到 `[0, 0]`。
532
+
533
+ ```js
534
+ const minimapHost = document.querySelector('#minimap-slot')
535
+ const minimapHandle = document.querySelector('#minimap-handle')
536
+ view.updateOptions({ minimap: { ...view.getOptions().minimap, container: minimapHost } })
537
+
538
+ // 整图拖动:用宿主里的拖动条累计指针位移,再写回 offset;小图内容与视口框都不会重建
539
+ let drag = null
540
+ minimapHandle.addEventListener('pointerdown', event => {
541
+ const [offsetX, offsetY] = view.getOptions().minimap?.offset ?? [0, 0]
542
+ drag = { pointerX: event.clientX, pointerY: event.clientY, offsetX, offsetY }
543
+ minimapHandle.setPointerCapture(event.pointerId)
544
+ })
545
+ minimapHandle.addEventListener('pointermove', event => {
546
+ if (!drag) return
547
+ const options = view.getOptions().minimap
548
+ view.updateOptions({
549
+ minimap: {
550
+ ...options,
551
+ offset: [
552
+ drag.offsetX + event.clientX - drag.pointerX,
553
+ drag.offsetY + event.clientY - drag.pointerY
554
+ ]
555
+ }
556
+ })
557
+ })
558
+ const stopDrag = () => { drag = null }
559
+ minimapHandle.addEventListener('pointerup', stopDrag)
560
+ minimapHandle.addEventListener('pointercancel', stopDrag)
499
561
 
500
- 规则的用法与主图一致(同一套条件语言、按顺序命中、后命中的覆盖前面的),但只管小图的画法:节点按 `zIndex` 分层,`levels` 只留下指定层的节点,`layered: false` 时不排序、按数据顺序画;线路按「层级 + 颜色 + 线宽 + 透明度」分桶,一桶一条路径、一次 `stroke`,规则再多也不会把小图的绘制次数拉爆。没配自己的规则时沿用主图规则的颜色 / 透明度 / 层级(`inheritRules !== false`):主图按电压配色时小图自动同色,但主图那几十像素的尺寸不会搬过来 —— 小图上的半径仍然由 `pointStyle.size`(默认 1.2)与规则自己的 `size` 决定。节点的颜色取规则里的 `strokeColor`、没有才回落 `color`:主图的节点是白底 + 一圈电压色的描边,小图上一个点是一块实心像素,不这样取就会画成一堆白点(自己配的小图规则同样可以写 `strokeColor`)。
562
+ const minimapElement = view.getMinimapElement()
563
+ console.log(minimapElement?.parentElement === minimapHost) // true
564
+ ```
565
+
566
+ `container` 写元素或选择器都可以;外部宿主要设成 `position: relative`(`absolute` / `fixed` 也行),否则绝对定位会继续向上找基准。换容器只是移动同一个 `.gis-view__minimap` 根节点,画布、缓存与事件监听都保留;`destroy()` 会把它从当前外部宿主里一并摘掉。没配 `minimap` 时 `getMinimapElement()` 返回 `null`。
501
567
 
502
- `levels` 挡掉的节点会按 `cascade`(默认 `'binding'`)把连在它们身上的线路一起隐藏 —— 与主视图筛选的联动是同一套写法、同一个默认值:只看某几层的电压时,层外的节点与它们的线路一起消失,不会在小图上留下一堆凭空断掉的线。`cascade: 'coordinate'` 认的是端点坐标(线路数据只有 `path`、没有 `from` / `to` 时用它),`'both'` 两种写法都认,`false` 表示挡掉节点时线路照旧画。联动只影响小图的画法:数据、主视图、主视图的筛选结果都不动;小图的范围也跟着剩下的可见要素走(`measure` 只量小图真正画出来的节点与线路)。
568
+ `levels` 挡掉的节点会按 `cascade`(默认 `'binding'`)把连在它们身上的线路一起隐藏 —— 与主视图筛选的联动是同一套写法、同一个默认值:只看某几层的电压时,层外的节点与它们的线路一起消失,不会在小图上留下一堆凭空断掉的线。`cascade: 'coordinate'` 认的是端点坐标(线路数据只有 `path`、没有 `from` / `to` 时用它),`'both'` 两种写法都认,`false` 表示挡掉节点时线路照旧画。联动只影响小图的画法:数据、主视图、主视图的筛选结果都不动;`measure` 只量小图真正画出来的节点与线路,但 `extentFollowContent: true` 时范围才跟着剩下的可见要素重算,默认锁定首次范围,避免筛选后整张小图缩放漂移。
503
569
 
504
- 小图的尺寸系数与主视图一一对应,三组各管一件事、相乘叠加:`pointSizeScale` / `lineWidthScale` 是整体倍数(常数,屏幕上恒定),`pointZoomScale` / `lineZoomScale` 跟的是**小图自身的倍数**(`zoomable` 打开、小图放大到 4 倍时,`pointZoomScale: 0.5` 让节点半径放大 2 倍、`1` 是同倍率放大、`0` 保持不变),`pointMapZoomScale` / `lineMapZoomScale` 跟的是**主视图的地图倍数**(相机比例 ÷ 基准,基准就是主视图 `pointZoomScale` 用的那一份,可以用 `mapZoomBaseScale` 覆盖):主图放大 4 倍时 `0.5` 让小图节点放大 2 倍、`1` 同倍率;配了这一组之后相机一变小图就重铺一次像素(只挪视口框不够用了),没配时一次比较都不做。注意前两个指数的「倍数」量的是**小图自身的倍数**:小图没开 `zoomable`、或者倍数还在 `1`(刚好铺满)时它们是恒等系数,怎么调都看不出变化;想让小图跟着主视图的缩放一起变,要配的是后面那组 `pointMapZoomScale` / `lineMapZoomScale`。
570
+ 小图的尺寸系数分三组,前两组对所有节点 / 线路生效,第三组只作用于小图自有规则 / 样式:`pointSizeScale` / `lineWidthScale` 是整体倍数(常数,屏幕上恒定),`pointZoomScale` / `lineZoomScale` 跟的是**小图自身的倍数**(手动缩放 `zoomable: true` 或跟随主图 `zoomable: 'follow'` 都会改这个倍数;小图倍数到 4 倍时,`pointZoomScale: 0.5` 让节点半径放大 2 倍、`1` 是同倍率放大、`0` 保持不变;沿用主图的节点 / 线路也按这一份联动),`pointMapZoomScale` / `lineMapZoomScale` 跟的是**主视图的地图倍数**(相机比例 ÷ 基准,基准就是主视图 `pointZoomScale` 用的那一份,可以用 `mapZoomBaseScale` 覆盖):主图放大 4 倍时 `0.5` 让小图节点放大 2 倍、`1` 同倍率;这一组只作用于小图自有规则 / 样式;沿用主图时节点尺寸与线宽按「小图视口 ÷ 主图视口」换算,主图放大缩小不会改变它们的大小(两边视口尺寸变化除外)。注意前两个指数量的是**小图自身的倍数**:小图没开 `zoomable`、或者倍数还在 `1`(刚好铺满)时它们是恒等系数,怎么调都看不出变化;只想让小图的整体显示范围跟着主图缩放,用 `zoomable: 'follow'`。
505
571
 
506
- 小图的背景默认跟主视图一致(`background: 'inherit'`):底色、图片、GeoJSON 的填充 / 描边 / 逐区域配色与区域文字都换到小图自己的尺子上重画 —— GeoJSON 的线宽(最低 0.4px 保可见)、点要素半径(固定 1.2px)与区域文字字号(固定档,夹在 5 ~ 12px)都是小图上的固定像素,不再乘「小图比例 ÷ 主图比例」:缩放主视图时底图不会单独跟着放大 / 缩小,底图也不跟 `pointMapZoomScale` / `lineMapZoomScale` 走(那两个指数只管节点与线路),区域装不下这行字(屏幕矩形比文字小)就整条跳过;排布时按区域从大到小放,和已经放下的标签重叠的也跳过 —— 小图上几十个区域各画一行字只会叠成一团,最后一条都读不出来;图片按四角或 `fit` 算出的四边形做仿射 + 裁剪贴图(任意四边形都不会画歪),GeoJSON 面用奇偶规则填充(洞自动镂空)、纯线几何的区域再描一遍。也可以给 `minimap.background` 单独配一份(结构与主视图的 `background` 一样:`color` / `image` / `geoJson` / `geoJsonStyle` / `opacity`),「主图画数据、小图画行政边界」这类分工就很直接;`backgroundStyle` 是小图容器自己的 CSS 底色,垫在背景下面。主视图换了背景(`updateBackground` / `updateOptions({ background })`)小图会自动跟着重画。
572
+ 小图的背景默认跟主视图一致(`background: 'inherit'`):底色、图片、GeoJSON 的填充 / 描边 / 逐区域配色与区域文字都换到小图自己的尺子上重画 —— GeoJSON 的线宽(最低 0.4px 保可见)、点要素半径(固定 1.2px)与区域文字字号(固定档,夹在 5 ~ 12px)都是小图上的固定像素,不再乘「小图比例 ÷ 主图比例」:缩放主视图时底图不会单独跟着放大 / 缩小,底图也不跟 `pointMapZoomScale` / `lineMapZoomScale` 走(那两个指数只管小图自有规则 / 样式的节点与线路),区域装不下这行字(屏幕矩形比文字小)就整条跳过;排布时按区域从大到小放,和已经放下的标签重叠的也跳过 —— 小图上几十个区域各画一行字只会叠成一团,最后一条都读不出来;图片按四角或 `fit` 算出的四边形做仿射 + 裁剪贴图(任意四边形都不会画歪),GeoJSON 面用奇偶规则填充(洞自动镂空)、纯线几何的区域再描一遍。也可以给 `minimap.background` 单独配一份(结构与主视图的 `background` 一样:`color` / `image` / `geoJson` / `geoJsonStyle` / `opacity`),「主图画数据、小图画行政边界」这类分工就很直接。`backgroundStyle` 是容器的 CSS 底色;显式设置时它接管画布底色,继承或独立的底图仍画图片与 GeoJSON,但画布不再铺主图的不透明底色,不写时仍按主图底色铺满。主视图换了背景(`updateBackground` / `updateOptions({ background })`)小图会自动跟着重画。
507
573
 
508
- 交互与开销:**在框上按下直接拖框**(世界位移 = 屏幕位移 ÷ 小图比例),**空白处单击不改变视角**,按住超过 `longPressDelay` 才进入「跟着拖」,拖动过程中始终跟着光标;光标停在小图上滚动滚轮按光标位置缩放主图(`wheelZoom: false` 关掉)。每个有位移的手势结束时可通过 `onInteraction` 收到一条通知,不必自己在小图 DOM 上再挂一套指针监听。底图画的是筛选之后真正画出来的线,通道骨架与回线都在内(直接问引擎要几何,不用自己再推一遍通道偏移),画法是先铺线、再把节点整层盖上去 —— 节点层级高于线路,密集底图上的节点不会被线咬掉。底图只在数据或筛选结果变化时重画(节点直接写进像素缓冲,十万级也只在重建时花一次时间),相机变化只改视口框的 `transform`,所以拖动小图不掉帧。小图还会缓存**上一次的节点像素结果**与**数据范围**:一次改动排在前后两帧各重画一次(引擎重排之后要再取一次几何),第二次与第一次的数据、范围、尺寸完全一样时直接复用那份像素,十万点下第二次重画从 ~20ms 降到 0.3ms(配了 `pointMapZoomScale` / `lineMapZoomScale` 时把「主视图倍数」也并进缓存的键,倍数变了才重铺);`extent: auto` 的取舍跟相机有关,相机挪进 / 挪出那份小范围时才补一次重画(每帧只做几次比较,判断用的范围是缓存的)。小图拖框 / 小图滚轮带来的相机变化不算主画布上的交互:配了 `hideOnInteract` 的图层不会在这时被收起来,拖动结束还会补一次真实排版 —— 不会出现「动一下鹰眼图,主视图标签全没了」。真在主画布上拖动过之后、两层标签同时收着时,收尾计时器也照样挂上 —— 覆盖层停手的收尾是无条件的,不会因为「两层都在收着、当下没东西可排」把恢复一起跳过。
574
+ 交互与开销:**在框上按下直接拖框**(世界位移 = 屏幕位移 ÷ 小图比例),**空白处单击不改变视角**;未手动缩放且 `dragAction` 为 `pan` 时,按住超过 `longPressDelay` 才进入「跟着拖」;`dragAction: 'box'` 或手动缩放时,空白处按住即按对应动作开始,拖动过程中始终跟着光标;光标停在小图上滚动滚轮按光标位置缩放主图(`wheelZoom: false` 关掉)。每个有位移的手势结束时可通过 `onInteraction` 收到一条通知,不必自己在小图 DOM 上再挂一套指针监听。底图画的是筛选之后真正画出来的线,通道骨架与回线都在内(直接问引擎要几何,不用自己再推一遍通道偏移),画法是先铺线、再把节点整层盖上去 —— 节点层级高于线路,密集底图上的节点不会被线咬掉。底图只在数据或筛选结果变化时重画(节点直接写进像素缓冲,十万级也只在重建时花一次时间),相机变化只改视口框的 `transform`,所以拖动小图不掉帧。小图还会缓存**上一次的节点像素结果**与**数据范围**:一次改动排在前后两帧各重画一次(引擎重排之后要再取一次几何),第二次与第一次的数据、范围、尺寸完全一样时直接复用那份像素,十万点下第二次重画从 ~20ms 降到 0.3ms(配了 `pointMapZoomScale` / `lineMapZoomScale`(或存在沿用主图线宽的线路)时把「主视图倍数 / 两边视口比例」也并进缓存的键,倍数变了才重铺);打开 `extentFollowCamera` 后 `extent: auto` 的取舍才跟相机有关,相机挪进 / 挪出那份小范围时才补一次重画(每帧只做几次比较,判断用的范围是缓存的)。小图拖框 / 小图滚轮带来的相机变化不算主画布上的交互:配了 `hideOnInteract` 的图层不会在这时被收起来,拖动结束还会补一次真实排版 —— 不会出现「动一下鹰眼图,主视图标签全没了」。真在主画布上拖动过之后、两层标签同时收着时,收尾计时器也照样挂上 —— 覆盖层停手的收尾是无条件的,不会因为「两层都在收着、当下没东西可排」把恢复一起跳过。
509
575
 
510
576
  线路层另有自己的离屏 canvas 与缓存:缓存键包含画布尺寸、范围、投影、小图倍率与线路样式,命中时整层直接合成,不再重复投影与描边;`collectMinimapData()` 复制路径时顺路算出每条线的包围盒,完全落在小图视野外的线不建路径。只有布局尺寸实际变化时才重设 canvas 尺寸,单纯补画或移动视口框不会清空这份缓存。
511
577
 
512
- `zoomable: true` 之后小图自身也能整体放大缩小,空白处的拖动换成下面两种动作(单击不再需要长按,空白处不再走 `longPressDelay` 那条路):
578
+ `zoomable` 有三种互斥的模式:`false`(默认)只看固定范围,滚轮缩放主图;`true` 手动缩放小图自身(滚轮以光标为锚点,Ctrl / ⌘ + 滚轮仍留给主图);`'follow'` 让整个小图的显示范围跟随主图倍数变化(滚轮仍直接缩放主图,`followZoomScale` 是主图相对基准倍数的指数,`0` 表示不跟随、`1` 同倍率、`0.5` 是主图放大 4 倍时小图放大 2 倍;`zoom` 在这里是基准倍数,结果仍夹在 `minZoom` ~ `maxZoom`)。跟随模式下 `setMinimapZoom` / `zoomMinimapBy` 不抢控制权,倍数始终由主图决定。
579
+
580
+ 空白处拖动的两种动作由 `dragAction` 决定:
513
581
 
514
582
  - **平移小图**(`dragAction: 'pan'`,默认):光标往哪拖,小图内容跟着走,主图不动;内容夹在数据范围内,拖到头就停住。主图视口框跟着内容一起挪,必要时会贴在边上指示方向。
515
- - **框选显示**(`dragAction: 'box'`,或按住 Ctrl / ⌘ 拖动):在小图上拉出一个矩形(虚线框),松手后主图直接适应到框住的那块区域 —— 与主图自己的 Shift + 拖动框选(可改 `shortcuts.boxSelect`)是同一套手势。
583
+ - **框选显示**(`dragAction: 'box'`,或手动缩放时按住 Ctrl / ⌘ 拖动):在小图上拉出一个矩形(虚线框),松手后主图直接适应到框住的那块区域 —— 与主图自己的 Shift + 拖动框选(可改 `shortcuts.boxSelect`)是同一套手势。**`box` 不依赖 `zoomable`**,缩放关闭或跟随主图时也能直接在空白处框选。
516
584
 
517
- 两个动作不用来回改配置:`dragAction` 配的是「不按修饰键时」的动作,按住 Ctrl / ⌘ 就是另一个。平移过内容之后,小图不再自动把内容拉回视口框(否则一边看别处一边被拽回去);`setMinimapZoom` / 关掉再打开 `zoomable` 会回到居中。滚轮(或 `zoomMinimapBy`)以光标处的世界坐标为锚点改倍数,每一格的倍率就是 `zoomStep`(放大用 `zoomInStep`、缩小用 `zoomOutStep` 可以单独覆盖,缺省都用 `zoomStep`),`getMinimapZoom` / `setMinimapZoom` 读写当前倍数(夹在 `minZoom` ~ `maxZoom`)。`channelCircuits: false` 时小图上一个通道只画偏移最靠中间的那一根回线:它按 `getChannelMembers()` 给的下标与偏移挑成员,底图的分辨率本来就在一个像素上下,多回线挤在一起只会糊成一片。
585
+ 只有手动缩放(`zoomable: true`)时,按住 Ctrl / ⌘ 才会把 `dragAction` 换成另一个动作;关闭缩放 / 跟随主图时修饰键不改变动作,不能把唯一可用的框选换没。`pan` 需要小图倍数大于 1 才有可移动余量;关闭手动缩放时,`pan` 档的空白处长按仍跟着主图视角走,想直接框选就把 `dragAction` 设成 `'box'`。平移过内容之后,小图不再自动把内容拉回视口框(否则一边看别处一边被拽回去);手动模式下 `setMinimapZoom` / 关掉再打开 `zoomable` 会回到居中,跟随主图时倍数与居中由主图决定。滚轮(或手动模式下的 `zoomMinimapBy`)以光标处的世界坐标为锚点改倍数,每一格的倍率就是 `zoomStep`(放大用 `zoomInStep`、缩小用 `zoomOutStep` 可以单独覆盖,缺省都用 `zoomStep`),`getMinimapZoom` / `setMinimapZoom` 读写当前倍数(夹在 `minZoom` ~ `maxZoom`)。`channelCircuits: false` 时每个通道分组只画一根代表线:`collectMinimapData()` 按 `getChannelMembers()` 找到这一组当前仍可见的回线,逐顶点取平均,双回线正好落在两根中间、三回线落在中间那条;底图的分辨率本来就在一个像素上下,多回线挤在一起只会糊成一片。
518
586
 
519
- 小图的范围(`extent`)默认是 `auto`:取「筛选后可见数据的范围」与「底图范围」的并集(GeoJSON 底图用画出来的 `bounds`,图片底图用四角算出的范围),所以数据与 GeoJSON 不在一个坐标系时两者会一起进小图 —— 底图铺满小图、数据落在自己该在的位置,不会出现「按数据范围缩放、底图缩成一个点或糊成一片」的旧问题。`extent: 'data'` 退回旧行为(只看数据),`extent: 'background'` 只看底图范围;数据为空时 `auto` 直接取底图范围。数据用 `createGeoMapper` 映射过之后两者本来就在同一个坐标系里,`auto` 下小图与主图的视野完全一致。
587
+ 小图的范围(`extent`)默认是 `auto`:取「筛选后可见数据的范围」与「底图范围」的并集(GeoJSON 底图用画出来的 `bounds`,图片底图用四角算出的范围),所以数据与 GeoJSON 不在一个坐标系时两者会一起进小图 —— 底图铺满小图、数据落在自己该在的位置,不会出现「按数据范围缩放、底图缩成一个点或糊成一片」的旧问题。`extent: 'data'` 退回旧行为(只看数据),`extent: 'background'` 只看底图范围;数据为空时 `auto` 直接取底图范围。**`extentFollowContent` 默认 `false`**:首次铺好后锁定数据与底图的世界范围,筛选 / 显隐 / 增删只会重画内容,不会改小图缩放、中心或视口框位置;打开后才按当前可见内容重算。`extentFollowCamera` 也默认 `false`:仅在打开后在相机落在数据 / 底图其中一份、且另一份在合并范围里小到不足 6 像素时,按正在看的那一份收窄;相机挪进 / 挪出会各补一次重画。
520
588
 
521
589
  **配置、扩展与开销**:`extent` 除了三档预设,还能直接写一份世界范围(`{ minX, minY, maxX, maxY }` 或 `[[minX, minY], [maxX, maxY]]`)—— 固定按它铺、不跟数据与底图走,「只看某个片区」或者让两张小图的视野对齐(前后对比、打印出图)时用;容器还能加 `className` 与 `style`(中划线 / CSS 变量键与驼峰键都认,换配置时上一轮写过、这一轮没写的键会清掉),按自己的设计系统做阴影、字号、层级这类外观不必再绕 `backgroundStyle`。**可扩展**:`layers` 把每帧的自定义内容拆成一组互不干扰的绘制层 —— `placement` 决定画在数据前还是数据后,同段内按 `order` 从小到大,独立 `save` / `restore`,适合把网格、分区底色、指北针、业务标记分开维护;排序与分段在 `updateOptions` 时缓存,绘制帧只遍历当前段,层数多也不会每帧重复排序;旧的单层 `draw` 继续兼容,`stage` 固定为 `overlay` 并排在最后。回调拿到 `context`(已经按备份像素比缩放好,直接按 CSS 像素画)、`width` / `height` / `ratio`、当前 `extent` / `bounds` / `scale` / `zoom` 与 `project` / `unproject`(与内置图层同一套投影),以及这一帧的 `data` 与 `background`。`maxPixelRatio` 是性能旋钮:默认 4,实际倍率取 `devicePixelRatio × 宿主显示比例` 与该上限的较小值;小图在高分屏 / 宿主放大时不必无限加像素,调到 1 ~ 2 能省填充率。
522
590
 
523
- 视口框的拖角编辑(曾经的 `boxEditable` / `boxHandleSize` 与四角把手)已按需求整块去掉:框上不再有把手,视口框只能整体拖动;改主图视野用滚轮 / 框选(`zoomable`)或 `fitBounds` 这类实例方法。
591
+ 视口框的拖角编辑(曾经的 `boxEditable` / `boxHandleSize` 与四角把手)已按需求整块去掉:框上不再有把手,视口框只能整体拖动;改主图视野用 `wheelZoom` 滚轮、`dragAction: 'box'` 框选,或 `fitBounds` / `zoomTo` / `setCamera` 这类实例方法。
524
592
 
525
593
  ## 近义入口与别名
526
594
 
@@ -539,6 +607,7 @@ createGisView(container, {
539
607
  | `project(x, y)` / `unproject(x, y)` ↔ `clientToScreen(clientX, clientY)` / `screenToClient(x, y)` ↔ `clientToWorld(clientX, clientY)` / `worldToClient(x, y)` | 同一套换算链的三档入口:`project` / `unproject` 收**画布 CSS 像素**,`clientTo*` 这一对吃鼠标事件里的 `clientX` / `clientY`(自动减 canvas rect、除宿主缩放)只换到画布像素,再接一层就是世界坐标(`clientToWorld` / `worldToClient`);经纬度那一对是 `lngLatToScreen` / `screenToLngLat` |
540
608
  | `fitView(padding?)` / `applyInitialView()` / `resetView()` / `zoomToBounds(bounds, padding?)` | 视角的四个语义:适应**数据范围**(并记下首次落位)/ 按 `options.initialView` 落位(可反复调用)/ 回到**首次落位那一刻**的相机 / 按给定的世界坐标范围适应 |
541
609
  | `focusOn(ref, options?)` ↔ `zoomToBounds(bounds, padding?)` | `focusOn` 认要素(id / 下标 / 搜索命中 / 坐标 / 矩形 / 一批),缺省只按范围中心居中;写 `{ zoom: true }` 才走适应那一条,另带 `center` / `scale` / `maxZoom` / `select` 这些选项 |
610
+ | `flyTo(target, options?)` ↔ `focusOn(target, options?)` | 同一套目标与选项解析,区别只在落位方式:`focusOn` 立即改相机,`flyTo` 默认用 450 ms 平滑过去,并多认 `duration` / `easing`;需要随时停在当前帧用 `stopCameraAnimation()` |
542
611
  | `pick(x, y)` ↔ `pickAt(clientX, clientY)` | 坐标口径不同:`pick` 收画布 CSS 像素,`pickAt` 直接吃鼠标事件里的客户端坐标(结果里另加 `target` 与 `lngLat`) |
543
612
  | `hoverAt(clientX, clientY)` / `clearHover()` / `getHover()` | 三个动作:程序化悬停 / 撤掉并补发 `onHover(null)` / 读当前那一份(`hoverAt` 的返回与 `onHover` 载荷同一份) |
544
613
  | `getData()` / `getVisibleData()` / `getOptions()` | 读的层不同:全量数据副本(含拖拽后的最新坐标)/ 筛掉隐藏之后的点与线 / 整份配置与数据 |
@@ -36,14 +36,19 @@
36
36
  | `zoomTo(scale, origin?)` | 直接设成指定比例(像素 / 世界单位) |
37
37
  | `zoomToBounds(bounds, padding?)` | 把一段世界坐标矩形适应到视图内,退化成一点时只居中不改比例 |
38
38
  | `focusOn(target, options?)` | 把视角移到目标上:单条(搜索命中 / 要素 id / `{ type: 'point' \| 'line' \| 'channel', id \| index }` / `{ channelId }` 整条通道 / `{ type: 'group', channelId?, groupId }` / 坐标 / 矩形 / `{ lngLat }`)或**一批**(数组取整体包围盒 —— 搜到三个节点就是这三个点的中心当屏幕中心);字符串先节点后线路,裸字符串不表示通道,同 id 用 `type` 消歧,分组必须显式写 `type: 'group'`(全局唯一 `groupId` 可省略通道)。**缺省只居中、比例一点不动**;`options.zoom: true` 才按解析出的真实范围适配(节点 / 线路 / 通道 / 分组共用这一条,不额外放大),`scale` 优先级高于 `zoom`。`options` 还认 `center: true`(显式只居中,与缺省一致)、`padding`、`maxZoom`、`select`(顺带选中这批,`mode` 决定怎么并进当前选中集) |
39
+ | `flyTo(target, options?)` | 平滑飞到与 `focusOn` 相同的目标:目标写法与 `zoom` / `scale` / `center` / `padding` / `maxZoom` / `select` / `mode` 完全同义,另认 `duration`(毫秒,缺省 450)与 `easing`(`linear` / `ease-in` / `ease-out` / `ease-in-out` 或 `(progress) => progress`)。中心线性插值、比例按对数插值;`duration <= 0` 或系统要求减少动态效果时立即落位。再次飞行、用户拖拽 / 滚轮或任何程序化改相机都会停在当前帧,不补跳到终点 |
39
40
  | `search(keyword \| options)` | 按关键字搜索节点 / 线路 / 通道 / 通道分组并返回命中:`scope` 认复数的 `points` / `lines` / `channels` / `groups`,也认与 `focusOn` 一致的单数别名 `point` / `line` / `channel` / `group`;结果分 `points` / `lines` / `channels` / `groups` 四类,分组命中带 `channelIndex` / `groupId` / `groupIndex`,可直接交给 `focusOn` / `selectFeatures`。**不动视角**:要不要聚焦由调用方自己调 `focusOn`,见「搜索与定位」 |
40
41
  | `searchAsync(keyword \| options)` | 同一份口径的异步版:数据量大时把扫描放进 Worker(10 万点 / 10 万线下同步要占主线程 40 ms 上下的那一段),返回 `Promise<GisViewSearchResult>`;结果带 `worker` 与 `stale` 两个字段,见「异步搜索」 |
41
42
  | `setCamera(camera)` / `getCamera()` | 读写 `{ center, scale }` |
43
+ | `flyToCamera(camera, options?)` | 直接飞到相机目标 `{ center?, scale? }`:不写的那一项沿用当前相机,不经过要素解析、也不改选中与数据;`duration` / `easing` 与 `flyTo` 同义,参数非法时保持当前相机 |
44
+ | `stopCameraAnimation()` / `getCameraAnimation()` | 停止当前相机飞行(停在当前帧,返回实例)/ 读当前飞行 `{ active, progress, duration, from, to }`(没有动画时 `null`) |
42
45
  | `getZoomBaseScale()` / `setZoomBaseScale(scale?)` | 读 / 重定**缩放联动的基准比例**(缺省是首次适应视图时的比例):不传参数就取当下相机的比例 —— 把现在这一屏当成「原样大小」,之后放大缩小都从它算倍数;配合 `pointZoomScale` / `lineZoomScale` 使用 |
43
- | `getBounds()` | 数据范围(没有点时回退到背景 GeoJSON 的 `rawBounds`,也就是 `aspectScale` 之前的真实经纬度范围) |
46
+ | `getBounds()` | 数据范围(没有点时回退到背景 GeoJSON 的 `rawBounds`,也就是 `aspectScale` 之前的真实经纬度范围);每次返回独立副本,重复调用命中缓存 |
44
47
  | `getViewRect()` | 当前可视范围的世界坐标矩形;自建缩略图 / 坐标读数用它换算视口框,内置鹰眼图见「鹰眼图」 |
48
+ | `getMinimapElement()` | 鹰眼图根节点(没配 `minimap` 时为 `null`):接整图拖动或自定义手势;配合 `minimap.container` 挂到外部宿主时拿到的仍是同一根节点 |
45
49
  | `getMinimapZoom()` / `setMinimapZoom(zoom)` / `zoomMinimapBy(factor, origin?)` | 读 / 写鹰眼图自身的倍数:`set` 夹在 `minimap.minZoom` ~ `maxZoom` 之间,`zoomMinimapBy` 以画布 CSS 像素 `origin` 为锚点缩放(缺省小图中心),没配 `minimap` 时是空操作 |
46
50
  | `getPoint(ref)` | 按 id / 下标 / `{ id }` / `{ index }` 取一个节点:拾取载荷(`item` / `x` / `y` / `layer` / `layerRank`)之外再给一份屏幕半径 `radius`;找不到返回 `null`。自建读数面板、右键菜单用它,省掉「自己遍历 `getData()` + 算投影」那一段 |
51
+ | `getPointStyle(index)` / `getLineStyle(index)` | 节点 / 线路解析之后的样式快照:节点的 `size` / `symbol` 取样式链(自身 > 规则 > 全局),线路的 `width` / `color` / `opacity` / `zIndex` 同源;不含悬停 / 选中样式、整体倍率与热力倍率,下标不存在时返回 `null`。合并节点与鹰眼图沿用主图尺寸时走这一份 |
47
52
  | `getLine(ref)` | 取一条线路:拾取载荷 + `path` / `bounds` / `color` / `width`(与 `listLines()` 的一项同一份口径),通道回线还带 `channelId` / `groupId` / `channelIndex`;找不到返回 `null` |
48
53
  | `getChannel(ref)` | 取一条通道:数据那一份(`index` / `item` / `id`)+ 成员表(`lineIndexes` / `skeleton` / `offsets` / `paths`)+ 分组上下文 `context`(几组 / 当前哪组 / 每组拐点数)、`from` / `to` / `anchored` / `spacing`;找不到返回 `null` |
49
54
  | `listPoints(options?)` | 按条件列节点快照 `{ index, item, x, y, radius, layerRank, screen? }`:选项见 `GisViewListOptions`(`indexes` / `inView` / `limit` / `withScreen` / `visibleOnly`),可见判定与 `isPointVisible` 是同一份 |
@@ -109,7 +114,7 @@
109
114
  | `addWaypoints(lineId, coordinates, options?)` | 一次给一条线路插多个拐点:按数组顺序插入,多个拐点合成**一步历史**;坐标写错的条目跳过,返回 `{ ok, reason, count, lineId, lineIndex, coordinates }`(`coordinates` 是实际插入成功的坐标),线路不存在或 `waypointEditable: false` 时 `ok: false` |
110
115
  | `getWaypoints(lineIndex?)` | 当前显示中的拐点(受 `waypointVisibility` 影响),带坐标与选中态 |
111
116
  | `getChannels()` | 通道运行时状态:骨架折线、每条回线的偏移、推导出来的折线路径与间距;分组之后一个通道的每个分组各一条,带 `channelId` / `channelIndex`(`id` 是分组 id) |
112
- | `getChannelMembers()` | 通道成员表:每个通道的成员下标与各自的偏移(不复制几何),需要按通道分流绘制时用它(内置鹰眼图的「一个通道只画一根」就按它挑中间那条) |
117
+ | `getChannelMembers()` | 通道成员表:每个通道的成员下标与各自的偏移(不复制几何),需要按通道分流绘制时用它(内置鹰眼图的「一个通道只画一根」按它取当前可见成员,再逐顶点平均成居中代表线) |
113
118
  | `getChannelGroups(channelId?)` | 通道分组现状:每组的成员(下标 + 线路 id)、骨架与可以直接写回声明的中间拐点(`path`);不传 `channelId` 返回所有分组,见「通道分组」 |
114
119
  | `getChannelGroupWaypoints(channelId?, groupId?)` | 一个分组的拐点现状:整组共用的骨架与中间拐点(`path`,给后端就是这一份)+ 组里每条回线按各自车道偏移后的折线与拐点(`lines[].waypoints`);`channelId` 不传取「当前分组」所在的通道、`groupId` 不传取第一组,见「分组拐点」 |
115
120
  | `splitChannelGroups(channelId, groups)` | 重设通道分组:每组至少一条线路,第一组沿用当前拐点,新拆出来的分组不带拐点 |
@@ -123,13 +128,13 @@
123
128
  | `addChannelGroupWaypoint(channelId, groupId?, coordinate?)` | 给某个分组加拐点、把这一组单独拉走:不给坐标就按默认位置放一个(第 n 组沿法线往外让 n 档),其余分组一根拐点都不动,见「分组拐点」 |
124
129
  | `removeChannelGroupWaypoint(channelId, groupId?, pathIndex?)` | 删掉某个分组的拐点(缺省删最后一个) |
125
130
  | `runChannelAction(actionId, options?)` | 执行右键交互框里的动作:`select-group` / `deselect-group` / `add-waypoint` / `remove-waypoint` / `split` / `merge`(`options` 带 `channelId` / `groupId` / `coordinate` / `pathIndex` / `size`),返回执行之后的上下文 |
126
- | `beginAddChannel(options?)` | 进入「新增通道」:缺省点两个节点选起点 / 终点,或由 `options.from` 预指定起点、只需再点终点;`options` 还支持 `kind`(`'channel'` 新建通道 / `'line'` 新建独立线路,缺省 `'channel'`)/ `circuits`(一次加几条,缺省 1)/ `autoCommit` / `continuous` / `chain` / `name` / `lineId` / `id` / `lineProps` / `linePropsByMember` / `lineItems`(第二段,连同线路一起新建)/ `routing`(`'straight'` / `'orthogonal'`)/ `path`(中间拐点)/ `channelProps` / `channelDraftStyle`(本次草稿的预览样式)/ `handoff`(交接模式:ready 发完收起草稿,自己调 `addChannel` 落地)/ `select`(点中的节点顺手选中)/ `originalEvent`,见「新增通道」 |
131
+ | `beginAddChannel(options?)` | 进入「新增通道」:缺省点两个节点选起点 / 终点,或由 `options.from` 预指定起点、只需再点终点;`options` 还支持 `kind`(`'channel'` 新建通道 / `'line'` 新建独立线路,缺省 `'channel'`)/ `circuits`(一次加几条,缺省 1)/ `autoCommit` / `continuous` / `chain` / `name` / `lineId` / `id` / `lineProps` / `linePropsByMember` / `lineItems`(第二段,连同线路一起新建)/ `routing`(`'straight'` / `'orthogonal'`)/ `path`(中间拐点)/ `channelProps` / `channelDraftStyle`(本次草稿的预览样式,含 `dots` / `layer`)/ `handoff`(交接模式:ready 发完收起草稿,自己调 `addChannel` 落地)/ `select`(点中的节点顺手选中)/ `originalEvent`,见「新增通道」 |
127
132
  | `getAddChannelDraft()` | 当前新增通道草稿(两个节点的信息与可选方案),没有草稿时为 `null` |
128
- | `updateAddChannelStyle(patch?)` | 字段级合并当前草稿的预览样式(`color` / `width` / `dot` / `dotColor` / `arrow` / `arrowSize` / `arrowPositions` / `arrowReverse` / `arrowColor` / `circuitSpacing` / `opacity` / `customDraw`);传 `null` 回到全局 `channelDraftStyle`,没有草稿时什么也不做 |
133
+ | `updateAddChannelStyle(patch?)` | 字段级合并当前草稿的预览样式(`color` / `width` / `dot` / `dotColor` / `dots` / `layer` / `arrow` / `arrowSize` / `arrowPositions` / `arrowReverse` / `arrowColor` / `circuitSpacing` / `opacity` / `customDraw`);传 `null` 回到全局 `channelDraftStyle`,没有草稿时什么也不做 |
129
134
  | `continueAddChannel(options?)` | 开下一段草稿:连续模式落地时内部自动调(发 `phase: 'restart'`),也可以手动调;草稿已经退出时按 `options` 重新进来 |
130
135
  | `cancelAddChannel()` | 取消新增通道(草稿期间按 Esc 等价,会补一条 `phase: 'cancel'`) |
131
136
  | `endAddChannel()` | 结束新增通道:静默收掉视图上的示例假通道 / 线路(不补 `cancel` 事件),数据一个字节都不改 —— 结束事件里决定「不新建了」就用它 |
132
- | `commitAddChannel(resolution?, options?)` | 把草稿按方案落到数据上:`resolution` 缺省用草稿里的推荐方案 |;草稿里的 `routing` / `path` 会一起交给落地
137
+ | `commitAddChannel(input?, options?)` | 把已 `ready` 的草稿落到数据上。`input` 有五类:不传(用草稿 `preferred`)、旧 resolution(字符串,或只含 `type` / `groupId` / `groupIndex` / `channelId` 的对象)、直接线路对象(有 `from` / `to` / `path` / `kind: 'line'` 等线路形状)、直接通道对象(必须有 `lineIds`,缺省新建通道)、容器 `{ channel?, line?, lines?, lineData?, lineItems?, channelGroups?, group?, channelProps?, lineProps?, resolution?, ... }`。对象字段优先、没写的沿用草稿;`line` 缺省表示独立线路,`lines` 才是成员回线表;直接通道对象缺省新建,直接线路对象缺省按独立线路落地,要并进已有分组必须用容器并显式写 `resolution`。`options?: { auto?, continuous?, originalEvent? }` 只影响本次事件与连续草稿。方案读数不能整条回传,只取 `{ type, groupId, groupIndex, channelId }`。完整字段优先级与示例见「10 通道编辑与新增」的 `commitAddChannel` / 对象直传 |
133
138
  | `getChannelAddOptions(from, to, count?, kind?)` | 两个节点之间的新增方案:新通道 / 新分组 / 并进某一组 / 无法添加;`count` 是这一次要加的回数(余量按它判),`kind: 'line'` 时方案表为空(独立线路不挑方案) |
134
139
  | `getChannelBetween(from, to)` | 两个节点之间的通道读数(只读):有通道时 `hasChannel: true`,`channelId` / `channelIndex` / `groupCount` / `currentGroupId` 与 `groups` / `group` / `channel`(id / name / lineIds / 分组明细)都给全;没有通道时 `hasChannel: false`、`channel: null`、`groups: []`,端点认不出来返回 `null` —— 与 `getChannelAddOptions` 的读数同一份,界面做「这两个点之间已经有通道 / 有几组」的判断用它,不必算方案表 |
135
140
  | `addChannel(spec, lineData?, group?)` | 程序化新增通道(新签名,只新建):第一段通道信息(`from` / `to` / `name` / `id` / `path` 等通道字段),第二段线路数组 line_data —— 一条或一批(字符串 / 数字按 id 认),**按每项 id 建 `lineIds`**,第三段可选分组信息(`{ id?, lineIds?, path? }`,单个 / 一组一个)—— **第二段 / 第三段显式给了**才走这条新路;两个节点之间已经有通道时整条失败(`reason` 指路下面两条)。旧写法 `addChannel(input, lineItems?)`(带 `circuits` / `resolution` / `channelId` / `groupId` / `groupIndex` / `kind`,或只写 `{ from, to }`)照样认:按方案表新建或并进已有通道,第二段 `lineItems` 给了几条就建几条 |
@@ -188,14 +193,14 @@
188
193
  | `getPointEffects()` | 这一帧涟漪的读数 `{ index, x, y, color, radius, count, period, from }`(世界坐标 + 颜色 + 圈数 + 周期):自建覆盖层与自测用它;拖动就地挪过圈之后读到的就是挪完的位置,没配涟漪那些节点不在表里 |
189
194
  | `getPrebake()` / `runPrebake()` | 预热读数(这次配了哪些符号 / 颜色 / 尺寸 / 逐组合,没配是 `null`)/ 按当前配置再烤一遍并返回组合条数,见「贴图符号预热(prebake)」 |
190
195
  | `getSymbolCombos()` | 收出这份数据真正会用到的贴图组合 `{ combos, symbols, pointColors, sizes, lineColors }`:喂给 `prebake.combos` 就是不重不漏的一份(一条一张、逐条命中),见「贴图符号预热(prebake)」 |
191
- | `el` / `canvas` / `gl` | 根节点、画布元素与 WebGL2 上下文 |
196
+ | `el` / `canvas` / `gl` / `cameraAnimating` / `dataVersion` | 根节点、画布元素、WebGL2 上下文,只读的「相机是否正在飞行」,以及数据修订号(数据变更 +1,只改全局配置 / 样式不变) |
192
197
  | `requestRender()` | 请求重画一帧:WebGL 自定义层的数据源变了、组件自己不知道时调用;返回实例本身 |
193
198
  | `addWebGLLayer(layer)` | 加一个 WebGL 自定义层(同 id 覆盖),返回卸载函数;`draw` 拿 `gl` / `canvas` / `viewport` / `camera` / `frame` / `project` / `unproject` / `requestRender`,在内置内容之后绘制 |
194
199
  | `updateWebGLLayer(id, patch)` / `removeWebGLLayer(id)` / `clearWebGLLayers()` / `getWebGLLayers()` | 改 / 删 / 清空 / 读自定义层;`order` 小的先画,同 `order` 保持加入顺序,`enabled: false` 跳过,层不参与拾取与导出 |
195
200
 
196
201
  返回 `this` 的方法都可以链式调用;返回其它值的方法(`get*` / `list*` / `export*` / `search` / `pick*` / `add*` / `remove*` / `copy*` / `merge*` / `locate*` 这些)在下面的「参数速查」里都标了返回类型。
197
202
 
198
- **怎么确认「组件到底有哪些属性和方法」**:上面那张表按功能分组介绍,下面的「参数速查」把实例的**每个成员逐个列全**(当前 256 个:253 个方法 + `el` / `canvas` / `gl` 三个属性),`options` 表列全 96 个键,数据字段表列全 250 个字段。这三份清单不靠手抄 —— 它们直接对着源码与类型对账:
203
+ **怎么确认「组件到底有哪些属性和方法」**:上面那张表按功能分组介绍,下面的「参数速查」把实例的**每个成员逐个列全**(当前 264 个:259 个方法 + `el` / `canvas` / `gl` / `cameraAnimating` / `dataVersion` 五个属性),`options` 表列全 96 个键,数据字段表列全 250 个字段。这三份清单不靠手抄 —— 它们直接对着源码与类型对账:
199
204
 
200
205
  - `node docs/steps/gen-api-index.mjs`:从 `create.js` 的实例定义、本文档的两张表与 `types.d.ts` 生成 `docs/demos/api-index.js`(`API_SUMMARY` / `API_SECTIONS` / `API_OPTIONS`),demo 的「实例 API」面板读的就是它;带 `--check` 时只校验有没有过期。
201
206
  - `node docs/steps/check-doc-coverage.mjs`:10 项双向对账 —— 实例成员 × 文档 / × 参数速查 / × 类型、参数速查与实例方法主表各自反查过期条目、类型反查过期声明、数据字段 × 文档、options 键 × 文档 / options 表反查过期字段、demo 清单是否最新。加一个实例成员、改一个 options 键而没同步文档时,这个脚本会直接报出来。
@@ -1,6 +1,6 @@
1
1
  # 17 参数速查(逐个方法)
2
2
 
3
- > 256 个成员逐个列全:参数、默认值与返回。
3
+ > 264 个成员逐个列全:参数、默认值与返回。
4
4
 
5
5
  ### 参数速查(逐个方法)
6
6
 
@@ -15,7 +15,7 @@
15
15
  - **同步方法返回 `this` 时可链式调用**:所有 `update*` / `set*` / `add*` / `remove*`、选中与视角方法都先完成本地状态更新再返回实例;需要结果时用相邻的 `get*` / `list*` 读回。少数返回数组、对象或 `null` 的方法在「返回」列单独标出。
16
16
  - **数据写入只发一次通知**:`updatePoint`、`updateLine`、`patch*`、`add*`、`remove*` 等每次成功改数据都会发一条对应的 `dataChange`(底层统一为 `updatePoints` / `updateLines` / `updateChannels` 等类型)并落一步历史;在 `batch()` 里连续调用会合并成一条。`emit: false` 只写数据、不发通知,适合宿主自己在保存成功后统一刷新。
17
17
  - **选中方法会同步选中集**:`selectFeatures` / `selectWaypoint` / `selectInBox` 先更新引擎选中态,再同步 `getSelections()`、`getSelectionData()` 与 `isSelected()`;一次有效变更会发 `onSelect`(`cause` 标明是 `api`、`box` 或指针来源)和 `onSelectChange`。没有命中任何目标时不会凭空选中,`selectWaypoint(null)` 只清拐点、不动要素选中集。
18
- - **视角方法会更新相机**:`focusOn` / `zoomTo` / `setCamera` / `fitView` 成功落到目标范围后更新 `getCamera()`,并触发 `onCameraChange`;目标认不出来、视口尚未量出或参数非法时保持当前相机。`focusOn` 缺省只居中、不改比例;`zoom` / `scale` / `center` / `padding` / `maxZoom` 只影响这一次调用,不会改写持久配置。
18
+ - **视角方法会更新相机**:`focusOn` / `flyTo` / `zoomTo` / `setCamera` / `fitView` 成功落到目标范围后更新 `getCamera()`,并触发 `onCameraChange`;目标认不出来、视口尚未量出或参数非法时保持当前相机。`focusOn` 缺省只居中、不改比例;`flyTo` 只是同一条目标解析的平滑版,飞行中用户拖拽 / 滚轮、再次飞行或任何程序化改相机都会停在当前帧。`zoom` / `scale` / `center` / `padding` / `maxZoom` 只影响这一次调用,不会改写持久配置。
19
19
  - **只读方法返回快照或副本**:`getSelectionData()`、`getFilter()`、`getStats()`、`snapshotScene()`、`listPoints()` / `listLines()` 返回的是调用当时的读数,不会随后续数据变更自动更新;需要最新值就再调一次。对象型字段的含义以 `types.d.ts` 同名接口为准。
20
20
  - **失败是可控的**:找不到 id / 下标越界 / 不支持的写法会跳过这一条,能返回 `null` 或 `{ ok: false, reason }` 的就按对应签名返回;需要排查时订阅 `onWarning`。异步筛选 / 搜索通过完成事件、`getFilterResult()` / 搜索结果或返回的 Promise 取结果,不要在调用下一行假定 Worker 已经跑完。
21
21
 
@@ -59,16 +59,21 @@
59
59
  | `zoomTo(scale, origin?)` | `scale: number` 目标缩放值(世界单位 → CSS 像素的比例);`origin?: [x, y]` 缩放中心 | `this` |
60
60
  | `zoomToBounds(bounds, padding?)` | `bounds: GisViewBounds` 要装进画面的世界矩形 `[minX, minY, maxX, maxY]`(也认 `{ minX, minY, maxX, maxY }`);`padding?: number` 四周留白 | `this` |
61
61
  | `focusOn(target, options?)` | `target: GisViewFocusTargets` 要对准的东西:id / `{ type: 'point' \| 'line' \| 'channel' \| 'group', id \| index }` / `{ channelId }`(整条通道)/ `{ type: 'group', channelId?, groupId }` / `[x, y]` 坐标 / 矩形 / `{ lngLat }` / `{ center }`,或者**一批**(数组取整体包围盒)。字符串按「先节点、再线路」,裸字符串不能表示通道;同 id 用显式 `type` 消歧,分组必须用 `type: 'group'`(`groupId` 全局唯一时可省略 `channelId`)。**缺省只居中、比例一点不动**;`options.zoom: true` 才按解析出的真实范围适配,四类目标共用这一条、没有额外放大倍率;`scale` 优先级高于 `zoom`,`maxZoom` 只给单点 / 单线这类零面积目标补最小范围。`options?: GisViewFocusOptions`:`zoom: true` 显式适配、`scale` 直接给比例、`center: true` 显式只居中(与缺省一致)、`padding` 要四周留白(CSS 像素,缺省 40)、`maxZoom` 限制这次适配的最大比例、`select` 顺带选中(`true` 选这次目标,也可另给一批写法)、`mode` 决定怎么并进当前选中集。目标认不出来或参数非法时什么都不做 | `this`(相机更新后发 `onCameraChange`;`select` 生效时另发 `onSelect` / `onSelectChange`) |
62
+ | `flyTo(target, options?)` | 目标与世界坐标解析、`zoom` / `scale` / `center` / `padding` / `maxZoom` / `select` / `mode` 均与 `focusOn` 同义。`options?: GisViewFlyOptions` 另认 `duration`(毫秒,缺省 450;`<= 0` 立即落位)与 `easing`(`'linear'` / `'ease-in'` / `'ease-out'` / `'ease-in-out'`,缺省 `'ease-in-out'`,也可给自定义 `(progress) => eased`)。中心线性、比例按对数插值;系统 `prefers-reduced-motion: reduce` 时立即落位。再次 `flyTo`、用户拖拽 / 滚轮、`setCamera` / `centerOn` / `zoom*` / `fitView` / `resetView` / `applyInitialView` 都会停在当前帧 | `this`(相机变化时发 `onCameraChange`;`select` 生效时另发选中事件) |
63
+ | `flyToCamera(camera, options?)` | `camera: GisViewCameraTarget` 直接给相机目标 `{ center?, scale? }`:没写 center / scale 的那一项沿用当前相机,不经过要素解析,也不改选中与数据;`options?: GisViewFlyCameraOptions` 的 `duration` / `easing` 与 `flyTo` 同义。中心 / 比例插值、减少动态效果、用户手势取消都走同一条相机动画 | `this`(相机变化时发 `onCameraChange`;目标非法时保持当前相机) |
62
64
  | `search(input)` | `input: string \| GisViewSearchOptions` 关键字,或 `{ keyword, scope, fields, limit }` 这类选项。`scope` 可选 `'points'` / `'lines'` / `'channels'` / `'groups'`,也认与 `focusOn` 一致的单数别名 `'point'` / `'line'` / `'channel'` / `'group'` 及数组;省略或写错时四类全搜。`limit` 对每一类分别计数。返回的 `groups` / `hits` 带分组命中(`channelIndex` / `groupId` / `groupIndex`,`item` 是轻量快照)—— **只返回结果、不动视角**,要定位就自己调 `focusOn(result.hits, …)` | `GisViewSearchResult`:`keyword` / `scope` / `points` / `lines` / `channels` / `groups` / `hits` / `total` / `truncated` / `durationMs` |
63
65
  | `searchAsync(input)` | 同上;分组范围的当前轻量快照会随请求交给 Worker | `Promise<GisViewSearchResult>`:多一个 `worker`(是不是在 Worker 里算的)与 `stale`(回来时数据已经改过、或又搜过一次,这一份不作数了) |
64
66
  | `setCamera(camera)` | `camera: Partial<GisViewCamera>` 要改的相机字段 `{ x, y, scale }`(只写一个也行) | `this` |
65
67
  | `getCamera()` | 无 | `GisViewCamera` |
68
+ | `stopCameraAnimation()` | 无 | `this`:停止当前相机飞行并停在当前帧;没有飞行时是空操作 |
69
+ | `getCameraAnimation()` | 无 | `GisViewCameraAnimation \| null`:`{ active, progress, duration, from, to }`,`progress` 是时间进度(0 ~ 1),没有动画时 `null` |
66
70
  | `getZoomBaseScale()` | 无 | `number` 缩放联动的基准比例(`pointZoomScale` / `lineZoomScale` 共用那一份;缺省是首次适应视图时的 `camera.scale`) |
67
71
  | `setZoomBaseScale(scale?)` | `scale?: number` 新的基准比例;不传取当下相机的比例(把现在这一屏当成「原样大小」) | `this` |
68
- | `getBounds()` | 无 | `GisViewBounds` |
72
+ | `getBounds()` | 无 | `GisViewBounds`:每次返回独立副本;重复调用命中数据包围盒缓存,改点 / 改线 / 追加或拖拽后下一次读数自动重建 |
69
73
  | `getViewport()` | 无 | `{ cssWidth, cssHeight, pixelRatio, displayScale }`:画布 CSS 尺寸、设备像素比与渲染分辨率比例 |
70
74
  | `getViewRect()` | 无 | `GisViewBounds` |
71
75
  | `isLayoutReady()` | 无 | `boolean` |
76
+ | `getMinimapElement()` | 无 | `HTMLElement \| null` 鹰眼图根节点(没配 `minimap` 时为 `null`);外部整图拖动 / 自定义手势用它,配合 `minimap.container` 可挂到外部宿主 |
72
77
  | `getMinimapZoom()` | 无 | `number` |
73
78
  | `setMinimapZoom(zoom)` | `zoom: number` 鹰眼图的目标倍数(被 `minimap.minZoom` / `maxZoom` 夹住) | `this` |
74
79
  | `zoomMinimapBy(factor, origin?)` | `factor: number` 倍数;`origin?: [x, y]` 以小图里的哪个点为中心(缺省小图中心) | `this` |
@@ -114,6 +119,7 @@
114
119
  | `getDropPreview()` | 无 | `GisViewDropPreview \| null`:当前拖拽落点预览的读数,没有预览时 `null` |
115
120
  | `getPoint(ref)` | `ref: GisViewFeatureRef` 节点定位:id、下标、`{ id }` / `{ index }` | `GisViewPointInfo \| null` |
116
121
  | `getPointStyle(index)` | `index: number` 节点下标 | `GisViewPointStyleSnapshot \| null`:节点解析后的样式快照 `{ index, size, symbol, zIndex }`,`size` / `symbol` 取样式链(节点自身 > 规则 > `pointStyle`)定下来的那一份,含 `sizeScale`、不含悬停 / 选中样式与热力倍率;落点预览的读数与它同源 |
122
+ | `getLineStyle(index)` | `index: number` 线路在 `lines` 里的下标 | `GisViewLineStyleSnapshot \| null`:`{ index, width, color, opacity, zIndex }`;`width` 取样式链(线路自身 > 规则 > `lineStyle`)定下来的原始线宽,不含 `lineWidthScale` / 缩放联动 / 热力倍率,`color` 是解析后的 RGBA(0 ~ 1)。局部更新与线路窄样式快路径之后读到的都是最新值;下标不存在时 `null` |
117
123
  | `getLine(ref)` | `ref` 线路定位(同上) | `GisViewLineInfo \| null` |
118
124
  | `getChannel(ref)` | `ref` 通道定位:通道 id 或下标 | `GisViewChannelSnapshot \| null` |
119
125
  | `listPoints(options?)` | `options?: GisViewListOptions`:`indexes`(只看这几个下标)、`inView: boolean`(只要当前视口里的)、`withScreen: boolean`(连屏幕坐标一起给)、`visibleOnly: boolean`(跳过隐藏的)、`limit: number`(最多几条) | `GisViewListedPoint[]` |
@@ -201,13 +207,13 @@
201
207
  | `addChannelGroupWaypoint(channelId, groupId, coordinate)` | `channelId` 通道 id;`groupId` 分组 id;`coordinate` 新拐点世界坐标 | `this` |
202
208
  | `removeChannelGroupWaypoint(channelId, groupId, pathIndex)` | `channelId` / `groupId` / `pathIndex` 要删的骨架顶点下标 | `this` |
203
209
  | `runChannelAction(actionId, options?)` | `actionId: GisViewChannelActionId` 动作名(`'select-group'` / `'deselect-group'` / `'add-waypoint'` / `'remove-waypoint'` / `'split'` / `'merge'`,见 `getChannelContext().actions`);`options?: GisViewChannelActionOptions` 动作自己的参数(`groupId` / `lineId` / `coordinate`…) | `GisViewChannelContext \| null` |
204
- | `beginAddChannel(options = {})` | `options?: GisViewChannelDraftOptions` 草稿配置:`from`(预指定起点,下一步只选终点)/ `kind` / `circuits` / `autoCommit` / `continuous` / `chain` / `name` / `lineId` / `id` / `lineProps` / `linePropsByMember` / `lineItems`(第二段)/ `routing` / `path`(中间拐点)/ `channelProps` / `channelDraftStyle`(本次草稿的预览样式)/ `handoff`(交接模式)/ `select`(点中的节点顺手选中,走 `onSelect` 那一套)/ `originalEvent` | `this`(只负责那条示例假通道,真正新增走 `addChannel`) |
210
+ | `beginAddChannel(options = {})` | `options?: GisViewChannelDraftOptions` 草稿配置:`from`(预指定起点,下一步只选终点)/ `kind` / `circuits` / `autoCommit` / `continuous` / `chain` / `name` / `lineId` / `id` / `lineProps` / `linePropsByMember` / `lineItems`(第二段)/ `routing` / `path`(中间拐点)/ `channelProps` / `channelDraftStyle`(本次草稿的预览样式,含 `dots` 与 `layer`)/ `handoff`(交接模式)/ `select`(点中的节点顺手选中,走 `onSelect` 那一套)/ `originalEvent` | `this`(只负责那条示例假通道,真正新增走 `commitAddChannel` / `addChannel`) |
205
211
  | `getAddChannelDraft()` | 无 | `GisViewChannelDraftPayload \| null` |
206
- | `updateAddChannelStyle(patch = {})` | `patch?: GisViewChannelDraftStyle \| null` 字段级合并的预览样式(箭头位置 / 多回线间距 / 自绘等);传 `null` 回到全局 `channelDraftStyle` | `this` |
212
+ | `updateAddChannelStyle(patch = {})` | `patch?: GisViewChannelDraftStyle \| null` 字段级合并的预览样式(箭头位置 / 多回线间距 / 两端 `dots` / 层级 `layer` / 自绘等);传 `null` 回到全局 `channelDraftStyle` | `this` |
207
213
  | `continueAddChannel(options = {})` | `options?: GisViewChannelDraftOptions` 开下一段草稿(写法与 `beginAddChannel` 一致,不传就沿用这一段原来的) | `this` |
208
214
  | `cancelAddChannel()` | 无 | `this`(收掉草稿并补一条 `phase: 'cancel'`) |
209
215
  | `endAddChannel()` | 无 | `this`(静默收掉视图上的示例假通道 / 线路,数据不动、不补事件) |
210
- | `commitAddChannel(resolution?, options?)` | `resolution?: GisViewChannelAddResolution` 落地方式(`'channel'` / `'line'`,缺省看草稿);`options?: GisViewChannelAddInput` 要覆盖的字段(`name` / `circuits` / `colors` / `lineWidth` / `routing` / `path`…) | `GisViewChannelAddResult` |
216
+ | `commitAddChannel(input?, options?)` | `input?: GisViewChannelAddResolution \| GisViewChannel \| GisViewLine \| GisViewChannelAddCommitInput`,五种写法:① 不传 / `null` = 用草稿 `preferred`;② 旧 resolution:字符串或只含非 `undefined` 的 `type` / `groupId` / `groupIndex` / `channelId` 的对象;③ 直接线路对象:没有 `lineIds` 数组,且写了 `kind: 'line'` / `path` / `from` / `to` / `start` / `end` 之一,业务字段与自己的 `lineProps` 透传到新线路;④ 直接通道对象:`Array.isArray(lineIds)` 且没有容器键,`lineIds` 逐条作新回线 id 种子、`groups` 作分组声明、自己的 `lineProps` 对所有新回线生效,其余字段进 `channelProps`,缺省 `resolution: 'newChannel'`;⑤ 容器:出现 `channel` / `line` / `lines` / `lineData` / `lineItems` / `channelGroups` / `group` / `channelProps` / `resolution` 任一键(只写 `lineProps` 也算)。容器里 `line` 缺省是独立线路,`lines` 是成员表(给了几条建几条,空数组沿用草稿);`channel.lineIds` 只在没有 `lines` 时当种子。字段优先级:`from` / `to` = 顶层 → `channel` → `line` → `lineItems` 第一个对象项(裸 id 跳过)→ 草稿;`path` = 顶层 → `line` → `channel` → 草稿;分组 = `channelGroups` → `group` → `channel.groups`;容器 `lineProps` = 草稿 → 顶层 → `line.lineProps` → 逐条,**不读 `channel.lineProps`**;`channelProps` = 草稿 → `channel` 业务字段 → 顶层 `channelProps`。直接线路 / 直接通道对象默认新建,要并进已有分组必须用容器并显式写 `resolution`。`options?: { auto?: boolean; continuous?: boolean; originalEvent?: Event \| null }`:`auto` 只标记自动提交,`continuous: false` 强制本次后结束,`originalEvent` 带回重开的草稿。`ready` 的方案对象不能整条回传,只取 `{ type, groupId, groupIndex, channelId }` 子集。调用前草稿必须 `ready`,否则不写数据;没有草稿的程序化新增用 `addChannel` / `addLine`。完整示例见「10 通道编辑与新增」与「18 逐方法示例」 | `GisViewChannelAddResult` |
211
217
  | `getChannelAddOptions(from, to, count?, kind?)` | `from` / `to` 两端节点 id;`count?: number` 回数(缺省 1);`kind?: 'channel' \| 'line'`(缺省 `'channel'`) | `GisViewChannelAddPlan \| null` |
212
218
  | `getChannelBetween(from, to)` | `from` / `to` 两端节点 id | `GisViewChannelBetween \| null` |
213
219
  | `addChannel(channel, lineData?, group?)` | `channel: GisViewChannelAddSpec` 通道信息 `{ from, to, name?, id?, lineData?, group? }`(后两个是第二 / 第三段写在对象上的别名);`lineData?: GisViewChannelLineData` 线路数组(`Partial<GisViewLine>` / `string` / `number` 的一条或一批,按每项 id 建 `lineIds`);`group?: GisViewChannelAddGroup \| GisViewChannelAddGroup[]` 可选分组信息 `{ id?, lineIds?, path? }`。旧写法 `addChannel(input, lineItems?)`(`GisViewChannelAddInput`:`circuits` / `resolution` / `channelId` / `groupId` / `groupIndex` / `kind` / `routing` / `path` 那套)照样认;`path` 是中间拐点,独立线路落地成完整折线、通道只写骨架拐点 | `GisViewChannelAddResult`(`channelLineIds` 是落地后通道的完整成员表,独立线路为 `null`) |
@@ -352,6 +358,8 @@
352
358
  | `el` | `HTMLElement` | 组件插入的 `.gis-view` 根节点(`destroy()` 会移除它;容器本身不动) |
353
359
  | `canvas` | `HTMLCanvasElement` | WebGL2 画布元素(导出 / 截图 / 自己叠加 DOM 时定位用它) |
354
360
  | `gl` | `WebGL2RenderingContext \| null` | 引擎拿到的 WebGL2 上下文,创建失败时 `null`(这时 `onError` 会报一条) |
361
+ | `cameraAnimating` | `boolean` | 相机是否正在飞行(只读)。按钮据此在「飞向 / 停止」之间切换,不触发重绘 |
362
+ | `dataVersion` | `number` | 数据修订号(只读):每次数据变更 +1,`onDataChange` 载荷里是同一个数;只改全局配置 / 样式不推。外部缓存、Worker 请求与增量计算据它判断是否重算 |
355
363
 
356
364
  ---
357
365