gis-view-webgl2 0.1.4 → 0.1.5

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 (30) hide show
  1. package/README.md +7 -7
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.d.ts +140 -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 +45 -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 +36 -0
  8. package/docs/demos/ConnectDemo.vue +114 -3
  9. package/docs/demos/MinimapDemo.vue +62 -16
  10. package/docs/demos/api-index.js +15 -14
  11. package/docs/demos/gis-view-demo/GisViewDemoStage.vue +25 -16
  12. package/docs/demos/gis-view-demo/useGisViewDemo.js +27 -16
  13. package/docs/index.html +3 -3
  14. package/docs/internals/13-/351/271/260/347/234/274/345/233/276.md +6 -5
  15. package/docs/internals/16-01-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/212.md +5 -3
  16. 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 +12 -0
  17. package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +11 -3
  18. 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
  19. 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
  20. package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +79 -28
  21. package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +6 -5
  22. package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +5 -4
  23. package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +117 -5
  24. 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 +5 -2
  25. package/docs/steps/README.md +5 -5
  26. package/docs/steps/selftest-demos.html +149 -5
  27. package/docs/steps/selftest-docs.html +3 -3
  28. package/docs/steps/selftest-full.html +315 -12
  29. package/docs/steps/selftest-perf.html +39 -1
  30. package/package.json +1 -1
@@ -388,13 +388,20 @@ createGisView(container, {
388
388
  height: 132,
389
389
  position: 'bottom-right',
390
390
  margin: 12,
391
+ // 相对当前角落的位移(CSS 像素):x 正数向右、y 正数向下;updateOptions 改它就能移动整张图
392
+ offset: [0, 0],
393
+ // 外部宿主:HTMLElement 或选择器;不写就挂在主视图根节点。外部宿主需要 position: relative
394
+ // container: document.querySelector('#my-minimap-host'),
391
395
  padding: 0.04, // 数据四周留白,取短边比例
392
396
  // 范围:'auto'(默认)数据与底图合起来、'data' 只看数据(老行为)、'background' 只看底图
393
397
  // 也能直接写死一份世界范围:extent: { minX: 0, minY: 0, maxX: 1000, maxY: 800 }(固定按它铺,不跟数据与底图走)
394
398
  extent: 'auto',
399
+ // 仅 extent: 'auto' 生效;默认 false 始终按数据 ∪ 底图,打开后才允许按相机位置收窄
400
+ extentFollowCamera: false,
395
401
  // 小图背景:inherit(默认,复用主视图解析好的背景)/ false 关掉 / 对象自己配一份
396
402
  background: 'inherit',
397
- backgroundStyle: 'rgba(255, 255, 255, 0.92)', // 小图容器自身的 CSS 底色
403
+ // 显式设置时接管画布底色:继承的底图仍画图片 / GeoJSON,但不再用主图底色盖住它
404
+ backgroundStyle: 'rgba(255, 255, 255, 0.92)',
398
405
  borderColor: '#d7e2ef',
399
406
  radius: 6,
400
407
  pointStyle: { color: '#4b8dff', size: 1.4 },
@@ -404,13 +411,13 @@ createGisView(container, {
404
411
  lineWidthScale: 1,
405
412
  pointMapZoomScale: 0.5, // 主图放大 4 倍,小图节点放大 2 倍(基准缺省取主图适应视图时的比例)
406
413
  lineMapZoomScale: 0.5,
407
- // 小图自己的规则:颜色、半径 / 线宽、形状、层级都能按属性给;不配就沿用主图规则的颜色与层级
414
+ // 小图自己的规则:颜色、半径 / 线宽、形状、层级都能按属性给;不配就沿用主图样式(含尺寸与图标)
408
415
  pointRules: [
409
416
  { when: { vn_kv: { gte: 500 } }, style: { color: '#ff4d4f', size: 1.8, shape: 'square', zIndex: 2 } },
410
417
  { when: { vn_kv: { lt: 500 } }, style: { color: '#8c9aae', size: 1.2, zIndex: 1 } }
411
418
  ],
412
419
  lineRules: [{ when: { vn_kv: { gte: 500 } }, style: { color: '#ff8a3d', width: 1.2, opacity: 0.9, zIndex: 1 } }],
413
- inheritRules: true, // 没配自己的规则时才沿用主图的(只取颜色 / 描边色 / 透明度 / 层级,主图的尺寸是主画布上的像素)
420
+ inheritRules: true, // 没配自己的规则时才沿用主图:颜色 / 透明度 / 层级 + 最终节点尺寸与图标、线路线宽
414
421
  levels: [1, 2], // 只画这两层(按规则的 zIndex 分层,没写 zIndex 算第 0 层);不配就是全画
415
422
  cascade: 'binding', // 被 levels 挡掉的节点,连在它身上的线路一起隐藏;写法与筛选的 cascade 一样
416
423
  layered: true, // 分层叠画:zIndex 大的盖在上面;关掉就按数据顺序画
@@ -424,13 +431,14 @@ createGisView(container, {
424
431
  // 一次手势完成后的回调(无位移的点击不发):载荷带 type / local / world / zoom / extent / camera / viewport
425
432
  onInteraction: info => console.log(info.type, info.world),
426
433
  longPressDelay: 180,
427
- zoomable: false, // 打开后小图自身也能整体放大缩小,滚轮与下面这组倍数都归它
428
- zoom: 1, // 初始倍数,1 表示「刚好铺满小图」
434
+ zoomable: false, // false 关闭;true 手动缩放小图;'follow' 整体范围跟随主图。true 与 'follow' 互斥
435
+ followZoomScale: 1, // 仅 'follow' 生效:主图倍数的指数,1 同倍率、0.5 为主图放大 4 倍时小图放大 2 倍
436
+ zoom: 1, // 小图倍数;手动模式是初始值,跟随模式是基准倍数。1 表示「刚好铺满小图」
429
437
  minZoom: 0.5,
430
438
  maxZoom: 8,
431
439
  zoomStep: 1.4, // 每一次放大 / 缩小的倍率(滚轮一格、zoomInStep / zoomOutStep 可分别覆盖)
432
- dragAction: 'pan', // 开了 zoomable 之后,空白处拖动是平移小图(默认)还是直接框选
433
- channelCircuits: true, // 通道画全部回线;false 时一个通道只画偏移最靠中间的那一根
440
+ dragAction: 'pan', // 空白处拖动是平移小图(默认,需手动缩放)还是直接框选;box 不依赖 zoomable
441
+ channelCircuits: true, // 通道画全部回线;false 时每组按可见成员逐顶点平均成一根居中代表线
434
442
  // 容器外观:附加类名 + 内联样式(中划线 / CSS 变量与驼峰键都认,换配置时旧键会清掉)
435
443
  className: 'my-minimap',
436
444
  style: { boxShadow: '0 2px 10px rgba(0, 0, 0, 0.18)' },
@@ -463,64 +471,107 @@ createGisView(container, {
463
471
  | `width` / `height` | `number` | `168` / `120` | 小图尺寸(CSS 像素) |
464
472
  | `position` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `'bottom-right'` | 贴在画布的哪一角 |
465
473
  | `margin` | `number` | `12` | 与画布边缘的距离(CSS 像素) |
474
+ | `offset` | `[number, number]` | `[0, 0]` | 相对 `position` 那个角的位移(CSS 像素):`x` 正数向右、`y` 正数向下。`updateOptions({ minimap: { ...old, offset: [x, y] } })` 就能动态移动整张鹰眼图,四个角都按同一套方向换算 |
475
+ | `container` | `HTMLElement \| string \| null` | 无(主视图根节点) | 把鹰眼图挂到外部 `div`:可传元素或 CSS 选择器。给了就把同一根节点移进它,`position` / `margin` / `offset` 都相对这个宿主;宿主需要 `position: relative`(或 `absolute` / `fixed`)。选择器找不到时回落到主视图根节点;运行时换容器只移动节点,不重建画布。用 `view.getMinimapElement()` 可以拿到这个根节点做整图拖动 |
466
476
  | `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]]`):固定按它铺,不跟数据与底图走 |
477
+ | `extent` | `'auto' \| 'data' \| 'background' \| GisViewBounds \| [[number, number], [number, number]]` | `'auto'` | 小图按哪段世界范围铺:`auto` 取「数据范围 ∪ 底图范围」,`data` 只看数据(旧行为),`background` 只看底图;数据与 GeoJSON 底图不在一个坐标系时,`auto` 能把两者一起框进小图,底图不会缩成一个点/糊成一片。也可以直接写一份世界范围(`{ minX, minY, maxX, maxY }`,也认 `[[minX, minY], [maxX, maxY]]`):固定按它铺,不跟数据与底图走 |
478
+ | `extentFollowCamera` | `boolean` | `false` | `extent: 'auto'` 时是否允许包围盒跟着相机收窄。默认关闭,始终按「数据 ∪ 底图」铺,数据变化或相机进出某一份范围时包围盒与视口框不会自己跳;打开后,相机正落在其中一份范围里、而那一份合并后连 6 个像素都占不到时,只画正在看的那一份(数据还没映射到底图、两者离得很远时最明显),相机挪进 / 挪出会各重画一次 |
468
479
  | `className` / `style` | `string` / `Record<string, string \| number>` | 无 | 小图容器自己的类名与内联样式(中划线 / CSS 变量键与驼峰键都认):想按自己的设计系统改外观时用;换配置时上一轮写过、这一轮没写的键会被清掉 |
469
480
  | `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
481
  | `layers` | `GisViewMinimapLayer[]` | 无 | 可拆分的自定义绘制层:每项写 `{ id?, order?, placement?, enabled?, draw }`。`placement: 'below-data'` 画在内置线路 / 节点之前,`'above-data'`(默认)画在之后;同一段内按 `order` 从小到大,相同或未写时按数组顺序。每层独立 `save` / `restore`,一层改过的画布状态不会串到下一层;`enabled: false` 可临时关掉一层。回调里的 `stage` 就是当前段,旧的单层 `draw` 固定最后执行。排序在 `updateOptions` 时缓存,绘制帧不再逐层排序 |
471
482
  | `maxPixelRatio` | `number` | `4` | 小图画布备份像素比的上限(实际倍率 = `min(devicePixelRatio × 宿主显示比例, maxPixelRatio)`,夹在 1 ~ 4)。默认 4 保留高分屏清晰度;小图尺寸大或高分屏填充压力高时降到 1 ~ 2 可明显减少像素填充,代价是缩略图边缘变软 |
472
483
  | `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`) |
484
+ | `backgroundStyle` | `string` | `'rgba(255, 255, 255, 0.92)'` | 小图容器自己的 CSS 底色。**显式设置时接管画布底色**:继承 / 独立的底图仍画图片与 GeoJSON,但画布不再铺一层不透明底色把它盖住;不写时保持旧行为。想要完全透出宿主就写 `transparent` |
474
485
  | `borderColor` / `borderWidth` / `radius` | `string` / `number` | `#d7e2ef`、1px、6px | 小图自身的外观 |
475
- | `pointStyle` | `{ color?, strokeColor?, size? }` | `#4b8dff` / `1.2` | 节点的颜色与画在小图上的半径,与主图样式无关;节点画在线路之上。小图上的点是一块**实心像素**,配了 `strokeColor` 就优先取它当填充色 —— 主图那套「白底 + 彩色描边」的规则沿用过来时,画出来就是描边色而不是白点 |
486
+ | `pointStyle` | `{ color?, strokeColor?, size? }` | `#4b8dff` / `1.2` | 小图自己的节点颜色与半径(CSS 像素),用于没有自己的 `pointRules` / 不继承主图样式时的回落;节点画在线路之上。小图上的点是一块**实心像素**,配了 `strokeColor` 就优先取它当填充色 —— 主图那套「白底 + 彩色描边」的规则沿用过来时,画出来就是描边色而不是白点 |
476
487
  | `lineStyle` | `{ color?, width?, opacity? }` | `#8fb2d8` / `1` / `0.55` | 线路的颜色、线宽与透明度,`opacity: 0` 就是不画线 |
477
488
  | `pointRules` | `GisViewMinimapPointRule[]` | 无 | 小图自己的节点规则:按属性给每个节点定颜色 / 半径 / 形状(`'circle'` / `'square'`)/ 层级,条件语言与主图的 `pointRules` 完全一样;规则里没写的字段回落到 `pointStyle` |
478
489
  | `lineRules` | `GisViewMinimapLineRule[]` | 无 | 小图自己的线路规则:颜色 / 线宽 / 透明度 / 层级,规则里没写的字段回落到 `lineStyle` |
479
490
  | `heatmap` | `GisViewHeatmap \| false` | 沿用主图 | 小图自己的热力图:不写就沿用主图的 `options.heatmap`(同一份色带与自动值域),写对象就单独换一份,`false` 表示小图不按热力着色(主图照旧),见「热力图」 |
480
- | `inheritRules` | `boolean` | `true` | 没配自己的规则时是否沿用主图的 `pointRules` / `lineRules`:只取颜色、透明度与层级这些**没有量纲**的字段(主图的 `size` / `width` 是主画布上的像素,照搬到小图上会糊成一片),尺寸仍由小图的 `pointStyle` / `lineStyle` 决定;显式 `false` 表示小图只用自己那份样式 |
491
+ | `inheritRules` | `boolean` | `true` | 没配自己的规则时是否沿用主图样式:节点取主图规则的颜色 / 描边色 / 层级,并沿主图最终解析出的尺寸与图标(点自身 > 规则 > `pointStyle`,圆、方、图片、SVG 与自定义图元都认);沿用尺寸 / 线宽时还会乘一次**小图与主图 CSS 视口宽高的较小比例**,只跟两边视口尺寸有关,不随主图相机倍数变化,小图比主图小时节点与线路不会仍顶着和主图一样的尺寸。线路沿用颜色 / 透明度与样式链线宽。显式 `false` 表示小图只用自己那份 `pointStyle` / `lineStyle` |
481
492
  | `levels` | `number[]` | 无 | 只画这些层级的节点:层级取规则的 `zIndex`(没写算第 0 层),不配表示全部画;「每一层显示什么级别」就是它 —— 按电压写了 `zIndex` 之后,只看 500kV 以上就写 `levels: [500, 1000]` |
482
493
  | `cascade` | `false \| 'binding' \| 'coordinate' \| 'both'` | `'binding'` | 被 `levels` 挡掉的节点,连在它们身上的线路怎么跟着隐藏:`binding` 按 `from` / `to` 绑定、`coordinate` 按端点坐标(端点正好落在被挡掉的节点上)、`both` 两者都算、`false` 不联动。与主视图筛选的 `cascade` 是同一套说法 —— 主视图筛掉的要素本来就带联动,这里管的是小图**自己**挡掉的那部分;只看某几层时不会留下一堆凭空断掉的线 |
483
494
  | `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` 是同一套说法,缩放主视图时小图上的节点 / 线路跟着变大小(相机一变就重铺一次像素) |
495
+ | `pointSizeScale` / `lineWidthScale` | `number` | `1` | 节点半径 / 线宽的**整体倍数**(常数,与小图自身倍数、主图相机倍数都无关),与主视图的 `pointSizeScale` / `lineWidthScale` 同名同义;自有规则 / 样式与沿用主图的节点 / 线路都乘这一份(继承尺寸先按两图比例缩放,再叠这一层) |
496
+ | `pointZoomScale` / `lineZoomScale` | `number` | `0` | 小图**自身**倍数对节点半径 / 线宽的放大指数:`0` 不跟随、`1` 与小图同倍率放大,`0.5` 是小图放大 4 倍、节点放大 2 倍;手动缩放(`zoomable: true`)与跟随主图(`zoomable: 'follow'`)都会改变小图倍数,因此这两种模式下都能看到效果;沿用主图的节点 / 线路也按这一份联动,但主图相机本身不会直接改它们的大小 |
497
+ | `pointMapZoomScale` / `lineMapZoomScale` | `number` | `0` | **主视图地图倍数**对节点半径 / 线宽的放大指数:`0` 不跟随、`1` 与主视图同倍率放大、`0.5` 是主视图放大 4 倍、小图节点放大 2 倍;只作用于小图自有规则 / 样式,沿用主图的节点 / 线路不吃这一份(它们按两边视口比例缩放,主图相机变化不改大小) |
487
498
  | `mapZoomBaseScale` | `number` | 主视图适应视图时的比例 | 上面这组联动的基准比例,缺省与主视图共用同一份(主视图的 `zoomBaseScale` 或首次适应视图时的比例),等于它时联动系数为 1 |
488
499
  | `boxStyle` | `{ fill?, fillOpacity?, stroke?, strokeWidth?, strokeStyle?, radius?, shadow? }` | 蓝底 0.14 + 1px 蓝框 | 视口框(代表当前视口)的样式:填充色与不透明度、边框颜色 / 宽度 / 线型(`solid` / `dashed` / `dotted`,`strokeWidth: 0` 不画边框)、圆角与 CSS `box-shadow` |
489
500
  | `selectStyle` | `GisViewMinimapBoxStyle` | 沿用 `boxStyle`(虚线框、填充 0.12) | 拖动时拉出的框选矩形单独覆盖的样式字段,没写的字段继续沿用 `boxStyle` —— 只换底色 / 边框色就能和视口框区分开 |
490
501
  | `interactive` | `boolean` | `true` | 是否允许在小图上拖动 |
491
502
  | `onInteraction` | `(info: GisViewMinimapInteractionInfo) => void` | 无 | 一次手势真正完成时通知一条:`type` 为 `box-drag` / `select` / `pan` / `zoom` / `wheel-main` / `long-press`;载荷带 `local` / `world`、小图倍数 `zoom`、当前范围 `extent`、相机 `camera` 与视口 `viewport`。没有位移的点击不触发,`pointermove` 期间也不逐帧回调;长按在触发跟随的那一刻回调。适合同步业务状态、埋点或驱动外部图例 |
492
503
  | `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` 会重置回铺满 |
504
+ | `wheelZoom` | `boolean` | `true` | 是否允许在小图上用滚轮缩放**主图**(锚点落在光标处);`zoomable: true` 时主图改成 Ctrl / ⌘ + 滚轮,`zoomable: 'follow'` 仍直接缩放主图 |
505
+ | `zoomable` | `boolean \| 'follow'` | `false` | 缩放模式:`false` 关闭;`true` 手动缩放小图自身(滚轮以光标为锚点,Ctrl / ⌘ + 滚轮留给主图);`'follow'` 让整体显示范围跟随主图倍数变化,滚轮仍缩放主图。`true` 与 `'follow'` 互斥,跟随模式下 `setMinimapZoom` / `zoomMinimapBy` 不抢控制权 |
506
+ | `followZoomScale` | `number` | `1` | 仅 `zoomable: 'follow'` 生效:主图相对基准倍数的指数。`1` 同倍率、`0.5` 是主图放大 4 倍时小图放大 2 倍、`0` 表示小图倍数不随主图变化;结果仍夹在 `minZoom` ~ `maxZoom` 之间 |
507
+ | `zoom` / `minZoom` / `maxZoom` | `number` | `1` / `0.5` / `8` | 小图自身的倍数与范围:`1` 是刚刚铺满;`zoom` 在手动模式下是初始值、在跟随模式下是基准倍数。`setMinimapZoom` / `zoomMinimapBy` 与手动滚轮都在这个范围里夹取;`updateOptions` 里改了 `zoom` 或切换缩放模式会按新模式重置/重算 |
496
508
  | `zoomStep` | `number` | `1.4` | 每一次放大 / 缩小的倍率:滚轮一格正好一个步进(连续滚动按比例取幂,单次最多两步),`zoomMinimapBy` 传的就是这个系数;`zoomInStep` / `zoomOutStep` 可以只覆盖放大或缩小一侧 |
497
- | `dragAction` | `'pan' \| 'box'` | `'pan'` | 开了 `zoomable` 之后,小图空白处(视口框之外)拖动的动作:`pan` 平移小图内容(主图不动,内容夹在数据范围里),`box` 直接拉出框选矩形;按住 Ctrl / ⌘ 拖动始终是另一个动作 |
498
- | `channelCircuits` | `boolean` | `true` | 通道是否画出全部回线:`false` 时一个通道只画偏移最靠中间的那一根(通道走向仍然看得出来),通道多的底图更清爽 |
509
+ | `dragAction` | `'pan' \| 'box'` | `'pan'` | 小图空白处(视口框之外)拖动的动作:`pan` 平移小图内容(主图不动,内容夹在数据范围里,需手动缩放才有可移动余量),`box` 直接拉出框选矩形让主图显示过去。`box` 不依赖 `zoomable`,关闭缩放时也能直接框选;只有手动缩放模式下,按住 Ctrl / ⌘ 才切换成另一个动作 |
510
+ | `channelCircuits` | `boolean` | `true` | 通道是否画出全部回线:`false` 时每个分组按当前可见成员逐顶点取平均,只画一根居中的代表线(双回线落在两根正中间,三回线落在中间那条),通道走向仍然看得出来,通道多的底图更清爽 |
499
511
 
500
- 规则的用法与主图一致(同一套条件语言、按顺序命中、后命中的覆盖前面的),但只管小图的画法:节点按 `zIndex` 分层,`levels` 只留下指定层的节点,`layered: false` 时不排序、按数据顺序画;线路按「层级 + 颜色 + 线宽 + 透明度」分桶,一桶一条路径、一次 `stroke`,规则再多也不会把小图的绘制次数拉爆。没配自己的规则时沿用主图规则的颜色 / 透明度 / 层级(`inheritRules !== false`):主图按电压配色时小图自动同色,但主图那几十像素的尺寸不会搬过来 —— 小图上的半径仍然由 `pointStyle.size`(默认 1.2)与规则自己的 `size` 决定。节点的颜色取规则里的 `strokeColor`、没有才回落 `color`:主图的节点是白底 + 一圈电压色的描边,小图上一个点是一块实心像素,不这样取就会画成一堆白点(自己配的小图规则同样可以写 `strokeColor`)。
512
+ 规则的用法与主图一致(同一套条件语言、按顺序命中、后命中的覆盖前面的),但只管小图的画法:节点按 `zIndex` 分层,`levels` 只留下指定层的节点,`layered: false` 时不排序、按数据顺序画;线路按「层级 + 颜色 + 线宽 + 透明度」分桶,一桶一条路径、一次 `stroke`,规则再多也不会把小图的绘制次数拉爆。没配自己的规则时(`inheritRules !== false`)完整沿用主图样式链:颜色 / 描边色 / 层级来自主图规则,节点尺寸与图标取主图最终解析出的那一份(点自身 > `pointRules` > `pointStyle`),线路线宽取主图样式链解析出的原始值,再按小图与主图 CSS 视口宽高的较小比例缩一次(不跟主图相机倍数走)—— 圆、方、图片、SVG 与自定义图元都保留主图的形状,但不会在小图上仍和主图一样大。显式配了小图自己的 `pointRules` / `lineRules`(或 `inheritRules: false`)时,对应的尺寸 / 线宽不受这一步影响,仍由小图自己的规则与样式决定;只配 `pointStyle` / `lineStyle` 不会单独关掉继承。节点的颜色取规则里的 `strokeColor`、没有才回落 `color`:主图的节点是白底 + 一圈电压色的描边,小图上一个点是一块实心像素,不这样取就会画成一堆白点(自己配的小图规则同样可以写 `strokeColor`)。
513
+
514
+ **动态位置与外部挂载**:`offset` 是整张鹰眼图相对当前角落的位移,最适合做「拖动整个小图」的底移量 —— 指针每移动一段,就把累计位移写回 `updateOptions`;`position` / `margin` 仍决定基准角落。
515
+
516
+ ```js
517
+ const minimapHost = document.querySelector('#minimap-slot')
518
+ const minimapHandle = document.querySelector('#minimap-handle')
519
+ view.updateOptions({ minimap: { ...view.getOptions().minimap, container: minimapHost } })
520
+
521
+ // 整图拖动:用宿主里的拖动条累计指针位移,再写回 offset;小图内容与视口框都不会重建
522
+ let drag = null
523
+ minimapHandle.addEventListener('pointerdown', event => {
524
+ const [offsetX, offsetY] = view.getOptions().minimap?.offset ?? [0, 0]
525
+ drag = { pointerX: event.clientX, pointerY: event.clientY, offsetX, offsetY }
526
+ minimapHandle.setPointerCapture(event.pointerId)
527
+ })
528
+ minimapHandle.addEventListener('pointermove', event => {
529
+ if (!drag) return
530
+ const options = view.getOptions().minimap
531
+ view.updateOptions({
532
+ minimap: {
533
+ ...options,
534
+ offset: [
535
+ drag.offsetX + event.clientX - drag.pointerX,
536
+ drag.offsetY + event.clientY - drag.pointerY
537
+ ]
538
+ }
539
+ })
540
+ })
541
+ const stopDrag = () => { drag = null }
542
+ minimapHandle.addEventListener('pointerup', stopDrag)
543
+ minimapHandle.addEventListener('pointercancel', stopDrag)
544
+
545
+ const minimapElement = view.getMinimapElement()
546
+ console.log(minimapElement?.parentElement === minimapHost) // true
547
+ ```
548
+
549
+ `container` 写元素或选择器都可以;外部宿主要设成 `position: relative`(`absolute` / `fixed` 也行),否则绝对定位会继续向上找基准。换容器只是移动同一个 `.gis-view__minimap` 根节点,画布、缓存与事件监听都保留;`destroy()` 会把它从当前外部宿主里一并摘掉。没配 `minimap` 时 `getMinimapElement()` 返回 `null`。
501
550
 
502
551
  `levels` 挡掉的节点会按 `cascade`(默认 `'binding'`)把连在它们身上的线路一起隐藏 —— 与主视图筛选的联动是同一套写法、同一个默认值:只看某几层的电压时,层外的节点与它们的线路一起消失,不会在小图上留下一堆凭空断掉的线。`cascade: 'coordinate'` 认的是端点坐标(线路数据只有 `path`、没有 `from` / `to` 时用它),`'both'` 两种写法都认,`false` 表示挡掉节点时线路照旧画。联动只影响小图的画法:数据、主视图、主视图的筛选结果都不动;小图的范围也跟着剩下的可见要素走(`measure` 只量小图真正画出来的节点与线路)。
503
552
 
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`。
553
+ 小图的尺寸系数分三组,前两组对所有节点 / 线路生效,第三组只作用于小图自有规则 / 样式:`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
554
 
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 })`)小图会自动跟着重画。
555
+ 小图的背景默认跟主视图一致(`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
556
 
508
- 交互与开销:**在框上按下直接拖框**(世界位移 = 屏幕位移 ÷ 小图比例),**空白处单击不改变视角**,按住超过 `longPressDelay` 才进入「跟着拖」,拖动过程中始终跟着光标;光标停在小图上滚动滚轮按光标位置缩放主图(`wheelZoom: false` 关掉)。每个有位移的手势结束时可通过 `onInteraction` 收到一条通知,不必自己在小图 DOM 上再挂一套指针监听。底图画的是筛选之后真正画出来的线,通道骨架与回线都在内(直接问引擎要几何,不用自己再推一遍通道偏移),画法是先铺线、再把节点整层盖上去 —— 节点层级高于线路,密集底图上的节点不会被线咬掉。底图只在数据或筛选结果变化时重画(节点直接写进像素缓冲,十万级也只在重建时花一次时间),相机变化只改视口框的 `transform`,所以拖动小图不掉帧。小图还会缓存**上一次的节点像素结果**与**数据范围**:一次改动排在前后两帧各重画一次(引擎重排之后要再取一次几何),第二次与第一次的数据、范围、尺寸完全一样时直接复用那份像素,十万点下第二次重画从 ~20ms 降到 0.3ms(配了 `pointMapZoomScale` / `lineMapZoomScale` 时把「主视图倍数」也并进缓存的键,倍数变了才重铺);`extent: auto` 的取舍跟相机有关,相机挪进 / 挪出那份小范围时才补一次重画(每帧只做几次比较,判断用的范围是缓存的)。小图拖框 / 小图滚轮带来的相机变化不算主画布上的交互:配了 `hideOnInteract` 的图层不会在这时被收起来,拖动结束还会补一次真实排版 —— 不会出现「动一下鹰眼图,主视图标签全没了」。真在主画布上拖动过之后、两层标签同时收着时,收尾计时器也照样挂上 —— 覆盖层停手的收尾是无条件的,不会因为「两层都在收着、当下没东西可排」把恢复一起跳过。
557
+ 交互与开销:**在框上按下直接拖框**(世界位移 = 屏幕位移 ÷ 小图比例),**空白处单击不改变视角**;未手动缩放且 `dragAction` 为 `pan` 时,按住超过 `longPressDelay` 才进入「跟着拖」;`dragAction: 'box'` 或手动缩放时,空白处按住即按对应动作开始,拖动过程中始终跟着光标;光标停在小图上滚动滚轮按光标位置缩放主图(`wheelZoom: false` 关掉)。每个有位移的手势结束时可通过 `onInteraction` 收到一条通知,不必自己在小图 DOM 上再挂一套指针监听。底图画的是筛选之后真正画出来的线,通道骨架与回线都在内(直接问引擎要几何,不用自己再推一遍通道偏移),画法是先铺线、再把节点整层盖上去 —— 节点层级高于线路,密集底图上的节点不会被线咬掉。底图只在数据或筛选结果变化时重画(节点直接写进像素缓冲,十万级也只在重建时花一次时间),相机变化只改视口框的 `transform`,所以拖动小图不掉帧。小图还会缓存**上一次的节点像素结果**与**数据范围**:一次改动排在前后两帧各重画一次(引擎重排之后要再取一次几何),第二次与第一次的数据、范围、尺寸完全一样时直接复用那份像素,十万点下第二次重画从 ~20ms 降到 0.3ms(配了 `pointMapZoomScale` / `lineMapZoomScale`(或存在沿用主图线宽的线路)时把「主视图倍数 / 两边视口比例」也并进缓存的键,倍数变了才重铺);打开 `extentFollowCamera` 后 `extent: auto` 的取舍才跟相机有关,相机挪进 / 挪出那份小范围时才补一次重画(每帧只做几次比较,判断用的范围是缓存的)。小图拖框 / 小图滚轮带来的相机变化不算主画布上的交互:配了 `hideOnInteract` 的图层不会在这时被收起来,拖动结束还会补一次真实排版 —— 不会出现「动一下鹰眼图,主视图标签全没了」。真在主画布上拖动过之后、两层标签同时收着时,收尾计时器也照样挂上 —— 覆盖层停手的收尾是无条件的,不会因为「两层都在收着、当下没东西可排」把恢复一起跳过。
509
558
 
510
559
  线路层另有自己的离屏 canvas 与缓存:缓存键包含画布尺寸、范围、投影、小图倍率与线路样式,命中时整层直接合成,不再重复投影与描边;`collectMinimapData()` 复制路径时顺路算出每条线的包围盒,完全落在小图视野外的线不建路径。只有布局尺寸实际变化时才重设 canvas 尺寸,单纯补画或移动视口框不会清空这份缓存。
511
560
 
512
- `zoomable: true` 之后小图自身也能整体放大缩小,空白处的拖动换成下面两种动作(单击不再需要长按,空白处不再走 `longPressDelay` 那条路):
561
+ `zoomable` 有三种互斥的模式:`false`(默认)只看固定范围,滚轮缩放主图;`true` 手动缩放小图自身(滚轮以光标为锚点,Ctrl / ⌘ + 滚轮仍留给主图);`'follow'` 让整个小图的显示范围跟随主图倍数变化(滚轮仍直接缩放主图,`followZoomScale` 是主图相对基准倍数的指数,`0` 表示不跟随、`1` 同倍率、`0.5` 是主图放大 4 倍时小图放大 2 倍;`zoom` 在这里是基准倍数,结果仍夹在 `minZoom` ~ `maxZoom`)。跟随模式下 `setMinimapZoom` / `zoomMinimapBy` 不抢控制权,倍数始终由主图决定。
562
+
563
+ 空白处拖动的两种动作由 `dragAction` 决定:
513
564
 
514
565
  - **平移小图**(`dragAction: 'pan'`,默认):光标往哪拖,小图内容跟着走,主图不动;内容夹在数据范围内,拖到头就停住。主图视口框跟着内容一起挪,必要时会贴在边上指示方向。
515
- - **框选显示**(`dragAction: 'box'`,或按住 Ctrl / ⌘ 拖动):在小图上拉出一个矩形(虚线框),松手后主图直接适应到框住的那块区域 —— 与主图自己的 Shift + 拖动框选(可改 `shortcuts.boxSelect`)是同一套手势。
566
+ - **框选显示**(`dragAction: 'box'`,或手动缩放时按住 Ctrl / ⌘ 拖动):在小图上拉出一个矩形(虚线框),松手后主图直接适应到框住的那块区域 —— 与主图自己的 Shift + 拖动框选(可改 `shortcuts.boxSelect`)是同一套手势。**`box` 不依赖 `zoomable`**,缩放关闭或跟随主图时也能直接在空白处框选。
516
567
 
517
- 两个动作不用来回改配置:`dragAction` 配的是「不按修饰键时」的动作,按住 Ctrl / ⌘ 就是另一个。平移过内容之后,小图不再自动把内容拉回视口框(否则一边看别处一边被拽回去);`setMinimapZoom` / 关掉再打开 `zoomable` 会回到居中。滚轮(或 `zoomMinimapBy`)以光标处的世界坐标为锚点改倍数,每一格的倍率就是 `zoomStep`(放大用 `zoomInStep`、缩小用 `zoomOutStep` 可以单独覆盖,缺省都用 `zoomStep`),`getMinimapZoom` / `setMinimapZoom` 读写当前倍数(夹在 `minZoom` ~ `maxZoom`)。`channelCircuits: false` 时小图上一个通道只画偏移最靠中间的那一根回线:它按 `getChannelMembers()` 给的下标与偏移挑成员,底图的分辨率本来就在一个像素上下,多回线挤在一起只会糊成一片。
568
+ 只有手动缩放(`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
569
 
519
- 小图的范围(`extent`)默认是 `auto`:取「筛选后可见数据的范围」与「底图范围」的并集(GeoJSON 底图用画出来的 `bounds`,图片底图用四角算出的范围),所以数据与 GeoJSON 不在一个坐标系时两者会一起进小图 —— 底图铺满小图、数据落在自己该在的位置,不会出现「按数据范围缩放、底图缩成一个点或糊成一片」的旧问题。`extent: 'data'` 退回旧行为(只看数据),`extent: 'background'` 只看底图范围;数据为空时 `auto` 直接取底图范围。数据用 `createGeoMapper` 映射过之后两者本来就在同一个坐标系里,`auto` 下小图与主图的视野完全一致。
570
+ 小图的范围(`extent`)默认是 `auto`:取「筛选后可见数据的范围」与「底图范围」的并集(GeoJSON 底图用画出来的 `bounds`,图片底图用四角算出的范围),所以数据与 GeoJSON 不在一个坐标系时两者会一起进小图 —— 底图铺满小图、数据落在自己该在的位置,不会出现「按数据范围缩放、底图缩成一个点或糊成一片」的旧问题。`extent: 'data'` 退回旧行为(只看数据),`extent: 'background'` 只看底图范围;数据为空时 `auto` 直接取底图范围。**`extentFollowCamera` 默认 `false`**:数据因筛选 / 显隐 / 增删变化时包围盒不会自行收窄,外围要素消失也不会让可视图突然换尺寸或让视口框跳位置。打开后才在相机落在数据 / 底图其中一份、且另一份在合并范围里小到不足 6 像素时,按正在看的那一份收窄;相机挪进 / 挪出会各补一次重画。
520
571
 
521
572
  **配置、扩展与开销**:`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
573
 
523
- 视口框的拖角编辑(曾经的 `boxEditable` / `boxHandleSize` 与四角把手)已按需求整块去掉:框上不再有把手,视口框只能整体拖动;改主图视野用滚轮 / 框选(`zoomable`)或 `fitBounds` 这类实例方法。
574
+ 视口框的拖角编辑(曾经的 `boxEditable` / `boxHandleSize` 与四角把手)已按需求整块去掉:框上不再有把手,视口框只能整体拖动;改主图视野用 `wheelZoom` 滚轮、`dragAction: 'box'` 框选,或 `fitBounds` / `zoomTo` / `setCamera` 这类实例方法。
524
575
 
525
576
  ## 近义入口与别名
526
577
 
@@ -42,6 +42,7 @@
42
42
  | `getZoomBaseScale()` / `setZoomBaseScale(scale?)` | 读 / 重定**缩放联动的基准比例**(缺省是首次适应视图时的比例):不传参数就取当下相机的比例 —— 把现在这一屏当成「原样大小」,之后放大缩小都从它算倍数;配合 `pointZoomScale` / `lineZoomScale` 使用 |
43
43
  | `getBounds()` | 数据范围(没有点时回退到背景 GeoJSON 的 `rawBounds`,也就是 `aspectScale` 之前的真实经纬度范围) |
44
44
  | `getViewRect()` | 当前可视范围的世界坐标矩形;自建缩略图 / 坐标读数用它换算视口框,内置鹰眼图见「鹰眼图」 |
45
+ | `getMinimapElement()` | 鹰眼图根节点(没配 `minimap` 时为 `null`):接整图拖动或自定义手势;配合 `minimap.container` 挂到外部宿主时拿到的仍是同一根节点 |
45
46
  | `getMinimapZoom()` / `setMinimapZoom(zoom)` / `zoomMinimapBy(factor, origin?)` | 读 / 写鹰眼图自身的倍数:`set` 夹在 `minimap.minZoom` ~ `maxZoom` 之间,`zoomMinimapBy` 以画布 CSS 像素 `origin` 为锚点缩放(缺省小图中心),没配 `minimap` 时是空操作 |
46
47
  | `getPoint(ref)` | 按 id / 下标 / `{ id }` / `{ index }` 取一个节点:拾取载荷(`item` / `x` / `y` / `layer` / `layerRank`)之外再给一份屏幕半径 `radius`;找不到返回 `null`。自建读数面板、右键菜单用它,省掉「自己遍历 `getData()` + 算投影」那一段 |
47
48
  | `getLine(ref)` | 取一条线路:拾取载荷 + `path` / `bounds` / `color` / `width`(与 `listLines()` 的一项同一份口径),通道回线还带 `channelId` / `groupId` / `channelIndex`;找不到返回 `null` |
@@ -109,7 +110,7 @@
109
110
  | `addWaypoints(lineId, coordinates, options?)` | 一次给一条线路插多个拐点:按数组顺序插入,多个拐点合成**一步历史**;坐标写错的条目跳过,返回 `{ ok, reason, count, lineId, lineIndex, coordinates }`(`coordinates` 是实际插入成功的坐标),线路不存在或 `waypointEditable: false` 时 `ok: false` |
110
111
  | `getWaypoints(lineIndex?)` | 当前显示中的拐点(受 `waypointVisibility` 影响),带坐标与选中态 |
111
112
  | `getChannels()` | 通道运行时状态:骨架折线、每条回线的偏移、推导出来的折线路径与间距;分组之后一个通道的每个分组各一条,带 `channelId` / `channelIndex`(`id` 是分组 id) |
112
- | `getChannelMembers()` | 通道成员表:每个通道的成员下标与各自的偏移(不复制几何),需要按通道分流绘制时用它(内置鹰眼图的「一个通道只画一根」就按它挑中间那条) |
113
+ | `getChannelMembers()` | 通道成员表:每个通道的成员下标与各自的偏移(不复制几何),需要按通道分流绘制时用它(内置鹰眼图的「一个通道只画一根」按它取当前可见成员,再逐顶点平均成居中代表线) |
113
114
  | `getChannelGroups(channelId?)` | 通道分组现状:每组的成员(下标 + 线路 id)、骨架与可以直接写回声明的中间拐点(`path`);不传 `channelId` 返回所有分组,见「通道分组」 |
114
115
  | `getChannelGroupWaypoints(channelId?, groupId?)` | 一个分组的拐点现状:整组共用的骨架与中间拐点(`path`,给后端就是这一份)+ 组里每条回线按各自车道偏移后的折线与拐点(`lines[].waypoints`);`channelId` 不传取「当前分组」所在的通道、`groupId` 不传取第一组,见「分组拐点」 |
115
116
  | `splitChannelGroups(channelId, groups)` | 重设通道分组:每组至少一条线路,第一组沿用当前拐点,新拆出来的分组不带拐点 |
@@ -123,13 +124,13 @@
123
124
  | `addChannelGroupWaypoint(channelId, groupId?, coordinate?)` | 给某个分组加拐点、把这一组单独拉走:不给坐标就按默认位置放一个(第 n 组沿法线往外让 n 档),其余分组一根拐点都不动,见「分组拐点」 |
124
125
  | `removeChannelGroupWaypoint(channelId, groupId?, pathIndex?)` | 删掉某个分组的拐点(缺省删最后一个) |
125
126
  | `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`,见「新增通道」 |
127
+ | `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
128
  | `getAddChannelDraft()` | 当前新增通道草稿(两个节点的信息与可选方案),没有草稿时为 `null` |
128
- | `updateAddChannelStyle(patch?)` | 字段级合并当前草稿的预览样式(`color` / `width` / `dot` / `dotColor` / `arrow` / `arrowSize` / `arrowPositions` / `arrowReverse` / `arrowColor` / `circuitSpacing` / `opacity` / `customDraw`);传 `null` 回到全局 `channelDraftStyle`,没有草稿时什么也不做 |
129
+ | `updateAddChannelStyle(patch?)` | 字段级合并当前草稿的预览样式(`color` / `width` / `dot` / `dotColor` / `dots` / `layer` / `arrow` / `arrowSize` / `arrowPositions` / `arrowReverse` / `arrowColor` / `circuitSpacing` / `opacity` / `customDraw`);传 `null` 回到全局 `channelDraftStyle`,没有草稿时什么也不做 |
129
130
  | `continueAddChannel(options?)` | 开下一段草稿:连续模式落地时内部自动调(发 `phase: 'restart'`),也可以手动调;草稿已经退出时按 `options` 重新进来 |
130
131
  | `cancelAddChannel()` | 取消新增通道(草稿期间按 Esc 等价,会补一条 `phase: 'cancel'`) |
131
132
  | `endAddChannel()` | 结束新增通道:静默收掉视图上的示例假通道 / 线路(不补 `cancel` 事件),数据一个字节都不改 —— 结束事件里决定「不新建了」就用它 |
132
- | `commitAddChannel(resolution?, options?)` | 把草稿按方案落到数据上:`resolution` 缺省用草稿里的推荐方案 |;草稿里的 `routing` / `path` 会一起交给落地
133
+ | `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
134
  | `getChannelAddOptions(from, to, count?, kind?)` | 两个节点之间的新增方案:新通道 / 新分组 / 并进某一组 / 无法添加;`count` 是这一次要加的回数(余量按它判),`kind: 'line'` 时方案表为空(独立线路不挑方案) |
134
135
  | `getChannelBetween(from, to)` | 两个节点之间的通道读数(只读):有通道时 `hasChannel: true`,`channelId` / `channelIndex` / `groupCount` / `currentGroupId` 与 `groups` / `group` / `channel`(id / name / lineIds / 分组明细)都给全;没有通道时 `hasChannel: false`、`channel: null`、`groups: []`,端点认不出来返回 `null` —— 与 `getChannelAddOptions` 的读数同一份,界面做「这两个点之间已经有通道 / 有几组」的判断用它,不必算方案表 |
135
136
  | `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` 给了几条就建几条 |
@@ -195,7 +196,7 @@
195
196
 
196
197
  返回 `this` 的方法都可以链式调用;返回其它值的方法(`get*` / `list*` / `export*` / `search` / `pick*` / `add*` / `remove*` / `copy*` / `merge*` / `locate*` 这些)在下面的「参数速查」里都标了返回类型。
197
198
 
198
- **怎么确认「组件到底有哪些属性和方法」**:上面那张表按功能分组介绍,下面的「参数速查」把实例的**每个成员逐个列全**(当前 256 个:253 个方法 + `el` / `canvas` / `gl` 三个属性),`options` 表列全 96 个键,数据字段表列全 250 个字段。这三份清单不靠手抄 —— 它们直接对着源码与类型对账:
199
+ **怎么确认「组件到底有哪些属性和方法」**:上面那张表按功能分组介绍,下面的「参数速查」把实例的**每个成员逐个列全**(当前 257 个:254 个方法 + `el` / `canvas` / `gl` 三个属性),`options` 表列全 96 个键,数据字段表列全 250 个字段。这三份清单不靠手抄 —— 它们直接对着源码与类型对账:
199
200
 
200
201
  - `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
202
  - `node docs/steps/check-doc-coverage.mjs`:10 项双向对账 —— 实例成员 × 文档 / × 参数速查 / × 类型、参数速查与实例方法主表各自反查过期条目、类型反查过期声明、数据字段 × 文档、options 键 × 文档 / options 表反查过期字段、demo 清单是否最新。加一个实例成员、改一个 options 键而没同步文档时,这个脚本会直接报出来。
@@ -1,6 +1,6 @@
1
1
  # 17 参数速查(逐个方法)
2
2
 
3
- > 256 个成员逐个列全:参数、默认值与返回。
3
+ > 257 个成员逐个列全:参数、默认值与返回。
4
4
 
5
5
  ### 参数速查(逐个方法)
6
6
 
@@ -69,6 +69,7 @@
69
69
  | `getViewport()` | 无 | `{ cssWidth, cssHeight, pixelRatio, displayScale }`:画布 CSS 尺寸、设备像素比与渲染分辨率比例 |
70
70
  | `getViewRect()` | 无 | `GisViewBounds` |
71
71
  | `isLayoutReady()` | 无 | `boolean` |
72
+ | `getMinimapElement()` | 无 | `HTMLElement \| null` 鹰眼图根节点(没配 `minimap` 时为 `null`);外部整图拖动 / 自定义手势用它,配合 `minimap.container` 可挂到外部宿主 |
72
73
  | `getMinimapZoom()` | 无 | `number` |
73
74
  | `setMinimapZoom(zoom)` | `zoom: number` 鹰眼图的目标倍数(被 `minimap.minZoom` / `maxZoom` 夹住) | `this` |
74
75
  | `zoomMinimapBy(factor, origin?)` | `factor: number` 倍数;`origin?: [x, y]` 以小图里的哪个点为中心(缺省小图中心) | `this` |
@@ -201,13 +202,13 @@
201
202
  | `addChannelGroupWaypoint(channelId, groupId, coordinate)` | `channelId` 通道 id;`groupId` 分组 id;`coordinate` 新拐点世界坐标 | `this` |
202
203
  | `removeChannelGroupWaypoint(channelId, groupId, pathIndex)` | `channelId` / `groupId` / `pathIndex` 要删的骨架顶点下标 | `this` |
203
204
  | `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`) |
205
+ | `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
206
  | `getAddChannelDraft()` | 无 | `GisViewChannelDraftPayload \| null` |
206
- | `updateAddChannelStyle(patch = {})` | `patch?: GisViewChannelDraftStyle \| null` 字段级合并的预览样式(箭头位置 / 多回线间距 / 自绘等);传 `null` 回到全局 `channelDraftStyle` | `this` |
207
+ | `updateAddChannelStyle(patch = {})` | `patch?: GisViewChannelDraftStyle \| null` 字段级合并的预览样式(箭头位置 / 多回线间距 / 两端 `dots` / 层级 `layer` / 自绘等);传 `null` 回到全局 `channelDraftStyle` | `this` |
207
208
  | `continueAddChannel(options = {})` | `options?: GisViewChannelDraftOptions` 开下一段草稿(写法与 `beginAddChannel` 一致,不传就沿用这一段原来的) | `this` |
208
209
  | `cancelAddChannel()` | 无 | `this`(收掉草稿并补一条 `phase: 'cancel'`) |
209
210
  | `endAddChannel()` | 无 | `this`(静默收掉视图上的示例假通道 / 线路,数据不动、不补事件) |
210
- | `commitAddChannel(resolution?, options?)` | `resolution?: GisViewChannelAddResolution` 落地方式(`'channel'` / `'line'`,缺省看草稿);`options?: GisViewChannelAddInput` 要覆盖的字段(`name` / `circuits` / `colors` / `lineWidth` / `routing` / `path`…) | `GisViewChannelAddResult` |
211
+ | `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
212
  | `getChannelAddOptions(from, to, count?, kind?)` | `from` / `to` 两端节点 id;`count?: number` 回数(缺省 1);`kind?: 'channel' \| 'line'`(缺省 `'channel'`) | `GisViewChannelAddPlan \| null` |
212
213
  | `getChannelBetween(from, to)` | `from` / `to` 两端节点 id | `GisViewChannelBetween \| null` |
213
214
  | `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`) |
@@ -207,6 +207,9 @@ const { cssWidth, cssHeight, pixelRatio } = view.getViewport()
207
207
  // isLayoutReady():容器量到尺寸、首批布局完成没有
208
208
  const layoutReady = view.isLayoutReady()
209
209
 
210
+ // getMinimapElement():拿鹰眼图根节点做整图拖动 / 自定义手势(没配 minimap 时为 null)
211
+ const minimapElement = view.getMinimapElement()
212
+
210
213
  // getMinimapZoom() / setMinimapZoom(zoom) / zoomMinimapBy(factor, origin?):鹰眼图缩放
211
214
  view.setMinimapZoom(4)
212
215
  view.zoomMinimapBy(1.25)
@@ -538,21 +541,130 @@ view.runChannelAction('split', { lineId: 'l2' })
538
541
  view.addChannelGroupWaypoint('c1', 'c1::2', [200, 120])
539
542
  view.removeChannelGroupWaypoint('c1', 'c1::2', 1)
540
543
 
541
- // beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()
544
+ // beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?)
545
+ // commitAddChannel(input?, options?) / cancelAddChannel() / endAddChannel()
542
546
  view.beginAddChannel({
543
547
  kind: 'channel',
544
548
  circuits: 3,
545
549
  channelDraftStyle: {
546
550
  color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],
547
- circuitSpacing: 12, opacity: 0.9
551
+ circuitSpacing: 12, opacity: 0.9,
552
+ // 两端示例点:false 全关;对象可统一 size / color / shape,from / to 再分别覆盖
553
+ dots: { size: 5, shape: 'square', from: { color: '#2f6fd0' }, to: { color: '#d9544d' } },
554
+ layer: 'below-points' // 示例线 / 箭头 / customDraw 画在真实节点之下;示例点仍在节点之后
548
555
  }
549
556
  }) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线
550
- view.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点
557
+ view.beginAddChannel({ from: 'station-a' }) // 只预指定起点:接下来只点终点(没有 from + to 的写法)
551
558
  const draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)
552
559
  view.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头
553
560
  view.updateAddChannelStyle(null) // 回到全局 channelDraftStyle
554
- view.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)
555
- view.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案
561
+
562
+ // commitAddChannel 只负责把已 ready 的草稿落地;没有草稿的程序化新增用 addChannel / addLine。
563
+ // 下面每个 commit 例子都假设当前草稿已经重新 ready;实际连续调用请逐段 begin / 点选。
564
+ // 五类入参:无参、旧 resolution、直接线路、直接通道(必须有 lineIds)、容器(channel / line / lines / ...)。
565
+ // 1. 无参:沿用草稿的 preferred(newChannel / newGroup / joinGroup / newLine)
566
+ view.commitAddChannel()
567
+
568
+ // 2. 旧 resolution:字符串或只含 type / groupId / groupIndex / channelId 的对象
569
+ view.commitAddChannel('newChannel')
570
+ view.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2', groupIndex: 1, channelId: 'c1' })
571
+
572
+ // 3. 从 ready 的方案读数里选一条:只取四个定位字段,不能把整条 option 回传。
573
+ // 整条 option 还带 enabled / count / lineCount / lineIds,可能被误识别成直接通道或容器。
574
+ view.updateOptions({
575
+ onChannelDraft: payload => {
576
+ if (payload.phase !== 'ready' || payload.blocked) return
577
+ const chosen = payload.options.find(option => option.enabled && option.type === 'joinGroup')
578
+ if (!chosen) return
579
+ const result = view.commitAddChannel({
580
+ type: chosen.type,
581
+ groupId: chosen.groupId,
582
+ groupIndex: chosen.groupIndex,
583
+ channelId: chosen.channelId
584
+ })
585
+ console.log(result.ok, result.reason, result.lineIds)
586
+ }
587
+ })
588
+
589
+ // 4. 直接线路对象:没有 lineIds,但至少写 from / to / path / kind: 'line' 之一。
590
+ // 业务字段和 lineProps 都透传到新线路;path 是中间拐点(不含首尾)。
591
+ view.commitAddChannel({
592
+ id: 'new-line',
593
+ name: '对象线路',
594
+ from: 'station-a',
595
+ to: 'station-b',
596
+ path: [[116.72, 39.91], [116.86, 39.95]],
597
+ color: '#ff7a45', // 直接业务字段 → lineProps
598
+ width: 3,
599
+ lineType: 'dashed',
600
+ voltageLevel: '10kV',
601
+ lineProps: { opacity: 0.9 } // 合并顺序:业务字段 → 自己的 lineProps
602
+ })
603
+
604
+ // 5. 直接通道对象:必须写 lineIds;每个 id 生成一条回线,groups 是分组声明。
605
+ // id 只决定通道 id,不是回线 id 种子;并进已有通道要改用容器 + resolution。
606
+ view.commitAddChannel({
607
+ id: 'new-channel', name: '对象通道', from: 'station-a', to: 'station-b',
608
+ lineIds: ['new-channel-1', 'new-channel-2'],
609
+ groups: [
610
+ { id: 'new-group-1', lineIds: ['new-channel-1'], path: [[116.75, 39.86]] },
611
+ { id: 'new-group-2', lineIds: ['new-channel-2'], path: [[116.75, 39.98]] }
612
+ ],
613
+ width: 28,
614
+ lineProps: { color: '#2f6fd0', lineType: 'dashed' },
615
+ owner: '运维一班' // 其余字段 → channelProps
616
+ })
617
+
618
+ // 6. 容器写法:一段一段覆盖草稿,没写的继续用草稿。
619
+ // lines / lineData / lineItems 同义,优先级 lines > lineData > lineItems,给了几条就建几条。
620
+ view.commitAddChannel({
621
+ resolution: 'newChannel',
622
+ from: 'station-a',
623
+ to: 'station-b',
624
+ channel: { id: 'container-channel', name: '容器通道', nodeWidth: 1 },
625
+ lines: [
626
+ { id: 'n-1', color: '#dd4b2e', width: 2.2, name: '一回' },
627
+ 'n-2',
628
+ { id: 'n-3', color: '#2ea36b', voltageLevel: '10kV' }
629
+ ],
630
+ channelGroups: [
631
+ { id: 'container-channel::1', lineIds: ['n-1', 'n-2'] },
632
+ { id: 'container-channel::2', lineIds: ['n-3'], path: [[116.78, 39.96]] }
633
+ ],
634
+ routing: 'orthogonal', // 只有容器这一层的 routing 会改走线
635
+ path: [[116.78, 39.9]], // 中间拐点,不含两端
636
+ lineProps: { opacity: 0.9 }, // 容器合并:草稿 → 顶层 → line.lineProps → 逐条
637
+ channelProps: { width: 36 } // 最后覆盖新通道字段
638
+ })
639
+
640
+ // 7. 只给 channel.lineIds 当种子:没有 lines / line / lineData / lineItems 时,每个 id 建一条回线
641
+ view.commitAddChannel({
642
+ channel: { id: 'seed-channel', from: 'station-a', to: 'station-b', lineIds: ['seed-1', 'seed-2'] },
643
+ lineProps: { color: '#2f6fd0', width: 2 }
644
+ })
645
+
646
+ // 8. 空数组不覆盖草稿:lines / lineData / lineItems 给 [] 时,沿用草稿的 lineItems / circuits
647
+ view.commitAddChannel({ channel: { id: 'draft-lines' }, lines: [] })
648
+
649
+ // 9. 覆盖端点 / id / 名称 / 路由:顶层字段优先,lineId 是多回时自动展开的 id 种子
650
+ view.commitAddChannel({
651
+ from: 'station-c', to: 'station-d', name: '改道联络线',
652
+ lineId: 'rerouted', lines: [{ id: 'rerouted-1' }, { id: 'rerouted-2' }],
653
+ routing: 'orthogonal', path: [[116.9, 39.9]]
654
+ })
655
+
656
+ // 10. 并进已有通道 / 分组:直接通道默认新建,所以用容器并显式写 resolution
657
+ view.commitAddChannel({
658
+ resolution: { type: 'joinGroup', groupId: 'c1::2' },
659
+ lines: [{ id: 'join-1', color: '#dd4b2e' }, { id: 'join-2', color: '#2ea36b' }],
660
+ lineProps: { width: 2.4 }
661
+ })
662
+
663
+ // 11. 第二参数只管本次收尾:continuous: false 强制结束;originalEvent 原样带回重开的草稿
664
+ view.commitAddChannel(undefined, { continuous: false, originalEvent: null })
665
+ const commitResult = view.commitAddChannel()
666
+ console.log(commitResult.ok, commitResult.kind, commitResult.lineIds, commitResult.channelLineIds)
667
+
556
668
  view.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)
557
669
  view.cancelAddChannel() // 取消(Esc / 右键等价)
558
670
 
@@ -9,7 +9,7 @@
9
9
  - 网格与线宽都在屏幕空间计算,`devicePixelRatio` 变化后按设备像素重建场景。
10
10
  - 拾取在 CPU 侧按屏幕距离完成:先识别拐点,再按 Ctrl + 点击补拐点(点到线比点到节点更近就加点,否则走节点多选),最后才轮到要素,容差分别由拐点尺寸、点直径与线宽推导。点的拾取与框选共用一张随数据范围重建的均匀网格索引,线也有随线段重建的网格索引,每次交互只遍历光标附近的候选再做精确比较,耗时与总量基本脱钩(`getStats().pickMs` 可以直接读出来)。
11
11
  - 拐点用独立的圆点缓冲绘制,拖动只重算这一条线的线段与圆头,不触碰其它要素;框选矩形复用填充管线(一批顶点靠 `drawArrays` 偏移分段画填充与边框),悬停与选中强调仍走原来的高亮缓冲。
12
- - 内置界面只有鹰眼图,而且要显式配 `minimap` 才有:小图自己画筛选后仍可见的节点与线路(含通道回线,`channelCircuits: false` 时一个通道只画中间那一根),视口框跟着相机走,节点 / 线路 / 框三份样式与位置、尺寸、交互都能单独配,框上按下直接拖框、空白处长按后视角跟随,`zoomable: true` 时滚轮还能整体放大缩小小图自身(主图留给 Ctrl / ⌘ + 滚轮)、空白处拖动可以直接平移小图或框选出一块区域让主图显示过去(`dragAction` 与 Ctrl / ⌘ 各管一个动作,每格的倍率是 `zoomStep`),不配就完全不产生 DOM,见「鹰眼图」。要更自由的预览仍然可以用 `getBounds()` 画全量缩略图、`getViewRect()` 画当前视口矩形,再把小图坐标按比例换算成 `setCamera()` 的目标。`docs/demos/GisViewDemo.vue` 右下角用的就是内置鹰眼图:尺寸、线路显隐、回线根数、拖动动作、步进与三份样式,以及这一轮补上的规则配色 / 分层 / 只看某几层 / 节点与线路跟随放大的开关都在 demo 里换。
12
+ - 内置界面只有鹰眼图,而且要显式配 `minimap` 才有:小图自己画筛选后仍可见的节点与线路(含通道回线,`channelCircuits: false` 时每个分组只画一根逐顶点平均出的居中代表线),沿用主图规则时节点尺寸与圆 / 方 / 图片 / SVG / 自定义图元也和主图最终解析结果一致,但尺寸会再乘一次「小图视口 ÷ 主图视口」的比例,小图里的节点不会和主图一样大;视口框跟着相机走,节点 / 线路 / 框三份样式与位置、尺寸、交互都能单独配,`offset` 可动态移动整张图,`container` 可把根节点挂到外部 `div`(`getMinimapElement()` 用来接整图拖动),框上按下直接拖框。`zoomable` 三态互斥:`false` 关闭、`true` 手动缩放小图自身(主图留给 Ctrl / ⌘ + 滚轮)、`'follow'` 让整体范围跟随主图(`followZoomScale` 调指数);空白处拖动可以平移小图或框选让主图显示过去(`dragAction`,`box` 不依赖缩放,只有手动模式下 Ctrl / ⌘ 才切换动作),每格倍率是 `zoomStep`。`extentFollowCamera` 默认 `false`,外围要素消失时不会自行收窄包围盒;打开后才按相机取舍 `auto` 范围。不配就完全不产生 DOM,见「鹰眼图」。要更自由的预览仍然可以用 `getBounds()` 画全量缩略图、`getViewRect()` 画当前视口矩形,再把小图坐标按比例换算成 `setCamera()` 的目标。`docs/demos/GisViewDemo.vue` 右下角用的就是内置鹰眼图:尺寸、线路显隐、回线根数、拖动动作、缩放模式 / 跟随指数、范围开关与三份样式都在 demo 里换。
13
13
  - 拖拽与框选期间只更新受影响要素的坐标与缓冲,不重新解析符号与贴图;通道拖拐点只重算这条通道的成员线。
14
14
  - 配置写错不猜谜:键 / 预设 / 档位 / 事件名不认识时走 `onWarning`(与 `'warning'` 事件同一条消息)说一句,同一个错只提醒一次,不进 `onError`、也不打断流程;画质(`quality`)只改「画哪些批次 + 多大分辨率」,`view.getQuality()` 与 `onStats` 里的 `quality` 是同一份读数。
15
15
  - 只需要渲染能力时,可以用 `createGisViewEngine(canvas, options)` 在任意 canvas 上复用同一套管线,此时渲染调度由调用方负责;引擎同样通过 `onClick` / `onDblClick` / `onPointDrag` / `onSelect` / `onWaypointChange` 暴露交互,框选与拐点的实例方法在引擎上分别叫 `selectInBox`、`insertWaypoint` / `removeWaypoint` / `selectWaypoint`。
@@ -86,6 +86,9 @@
86
86
  **怎么一次给通道加多回?**
87
87
  `circuits` 就是「这一次加几条」:`beginAddChannel({ kind: 'channel', circuits: 3 })` / `addChannel({ from, to, circuits: 3 })`(旧写法),新建线路也一样(`addLine({ from, to, circuits: 2 })` 一次两条)。方案表的余量按它算 —— 加 3 回时只剩 2 回余量的分组会置灰,`reason` 写清「只剩 2 回余量,本次要加 3 回」;落地回执里 `lines` / `lineIds` 是这一批线,`onChannelDraft` 的 `commit` 载荷里也一样,`removeLine` 一条条摘掉就行(demo 的「移除上一条新增」就是整批摘)。
88
88
 
89
+ **鹰眼图的节点大小 / 范围 / 框选怎么调?**
90
+ 节点大小:`inheritRules` 打开(默认)时,小图取主图最终解析出的尺寸,再乘「小图视口 ÷ 主图视口」的较小比例 —— 只看两边 CSS 视口宽高,不随主图相机倍数变化;仍嫌大就调小图自己的 `pointSizeScale`,或配自己的 `pointRules` / `pointStyle` 接管尺寸。范围:`extent: 'auto'` 默认取数据 ∪ 底图且**不随相机收窄**;想要外围内容消失后跟着收窄才打开 `extentFollowCamera`。框选:`dragAction: 'box'` 不需要打开 `zoomable`,关闭缩放也能在空白处直接框;`zoomable: 'follow'` 是整体范围跟随主图,跟手动缩放 `true` 互斥。
91
+
89
92
  **虚线看不出来?**
90
93
  图案是 CSS 像素量屏幕距离,线很粗时应把图案调长(`[10, 6]` 在 3px 线宽下很清楚,在 12px 线宽下就显得密);另外图案槽位上限 16 组,超过的线会退回实线。
91
94
 
@@ -179,7 +182,7 @@
179
182
  | 覆盖层 | `GisViewLabelOptions`、`GisViewLineLabelOptions`、`GisViewItemLabel`、`GisViewLabelState`、`GisViewLabelPatch`、`GisViewSetLabelContentOptions`、`GisViewLabelListItem`、`GisViewItemLabelsInfo`、`GisViewRemoveLabelResult`、`GisViewSetLabelStatesResult`、`GisViewLabelChangePayload`、`GisViewLabelDragPayload`、`GisViewLabelClickPayload`、`GisViewLabelPointerPayload`、`GisViewLabelRef`、`GisViewLabelTarget`、`GisViewLabelBatchEntry`、`GisViewLabelRemoveEntry`、`GisViewLabelBatchSkip`、`GisViewAddLabelsResult`、`GisViewUpdateLabelsResult`、`GisViewRemoveLabelsResult`、`GisViewLineDecoration`、`GisViewTooltipOptions`、`GisViewLabelPayload`、`GisViewLineLabelPayload` |
180
183
  | 筛选 | `GisViewFilter`、`GisViewFilterInput`、`GisViewFilterShorthand`、`GisViewFilterResult`、`GisViewFilterCascade`、`GisViewFilterMode`、`GisViewFilterWorkerOptions` |
181
184
  | 大数据展示模式 | `GisViewDenseMode`、`GisViewDenseModeOptions`、`GisViewDenseModeInput`、`GisViewDenseState` |
182
- | 通道 | `GisViewChannelInput`、`GisViewChannelBuildOptions`、`GisViewChannelBuild`、`GisViewChannelInfo`、`GisViewChannelGroupInfo`、`GisViewChannelGroupWaypoints`、`GisViewChannelGroupLineWaypoints`、`GisViewChannelMember`、`GisViewChannelContext`、`GisViewChannelAddPlan`、`GisViewChannelBetween`、`GisViewChannelAddOption`、`GisViewChannelAddInput`、`GisViewChannelAddResult`、`GisViewChannelDraftOptions`、`GisViewChannelDraftPayload`、`GisViewChannelLineMoveTarget`、`GisViewChannelLineMoveResult`、`GisViewRemoveLineResult`、`GisViewRemoveChannelResult`、`GisViewRemoveLinesResult`、`GisViewChannelInView`、`GisViewChannelAction`、`GisViewChannelActionId`、`GisViewChannelDraftStyle`、`GisViewChannelWaypointDragMode`、`createChannels`、`CHANNEL_DEFAULT_COLORS` |
185
+ | 通道 | `GisViewChannelInput`、`GisViewChannelBuildOptions`、`GisViewChannelBuild`、`GisViewChannelInfo`、`GisViewChannelGroupInfo`、`GisViewChannelGroupWaypoints`、`GisViewChannelGroupLineWaypoints`、`GisViewChannelMember`、`GisViewChannelContext`、`GisViewChannelAddPlan`、`GisViewChannelBetween`、`GisViewChannelAddOption`、`GisViewChannelAddInput`、`GisViewChannelAddCommitInput`、`GisViewChannelAddResult`、`GisViewChannelDraftOptions`、`GisViewChannelDraftPayload`、`GisViewChannelLineMoveTarget`、`GisViewChannelLineMoveResult`、`GisViewRemoveLineResult`、`GisViewRemoveChannelResult`、`GisViewRemoveLinesResult`、`GisViewChannelInView`、`GisViewChannelAction`、`GisViewChannelActionId`、`GisViewChannelDraftStyle`、`GisViewChannelDraftDots`、`GisViewChannelDraftDotStyle`、`GisViewChannelWaypointDragMode`、`createChannels`、`CHANNEL_DEFAULT_COLORS` |
183
186
  | 事件载荷 | `GisViewPickResult`、`GisViewPickAtResult`、`GisViewRectQueryResult`、`GisViewSelectionInfo`、`GisViewSelectedItems`、`GisViewSelectPayload`、`GisViewClickPayload`、`GisViewPointerPayload、GisViewCascadeHighlightScope、GisViewCascadeHighlightOptions、GisViewCascadeHighlightInput、GisViewCascadeHighlightEntry、GisViewCascadeHighlightOrigin、GisViewCascadeHighlightInfo`、`GisViewPointerAction`、`GisViewPointerActionType`、`GisViewPointerTarget`、`GisViewPointerModifiers`、`GisViewWaypointActionData`、`GisViewLabelActionData`、`GisViewHoverPayload`、`GisViewCursorPayload`、`GisViewPointDragPayload`、`GisViewDragPointChange`、`GisViewDragLineChange`、`GisViewPointCopyPayload`、`GisViewPointCopyState`、`GisViewPointMergePayload`、`GisViewMergeImpact`、`GisViewMergeResult`、`GisViewMergeFailure`、`GisViewWaypointPayload`、`GisViewWaypointInfo`、`GisViewWaypointKey`、`GisViewParallelGroup`、`GisViewReadyPayload`、`GisViewEngineStats`、`GisViewEngineHeatDensity`、`GisViewDataChangeType`、`GisViewDataChangePayload`、`GisViewSelectChangePayload`、`GisViewShortcutPayload`、`GisViewRenderPayload`、`GisViewAddItemsResult`、`GisViewAddPointResult` |
184
187
  | 快捷键与复制 / 合并 / 删除 | `GisViewShortcuts`、`GisViewShortcut`、`GisViewShortcutAction`、`GisViewCopyOptions`、`GisViewCopyContext`、`GisViewCopyStartOptions`、`GisViewPasteOptions`、`GisViewCopyItem`、`GisViewClipboardItem`、`GisViewMergeOptions`、`GisViewMergeContext`、`GisViewPointStyleSnapshot`、`GisViewPointRef`、`GisViewMergeResult`、`GisViewMergeFailure`、`GisViewMergeOutcome`、`GisViewRemovePointsOutcome`、`GisViewRemoveSelectedOutcome`、`GisViewRemoveOptions`、`GisViewRemoveScope`、`GisViewRemovePayload`、`GisViewRemoveResult`、`GisViewRemoveOutcome`、`GisViewRemoveFailure`、`GisViewRemoveAction`、`GisViewRemovePoint`、`GisViewRemoveLine`、`GisViewRemoveWaypoint`、`GisViewRemoveGroup`、`GisViewRemoveChannel`、`GisViewRemoveCounts`、`GisViewChannelSelectMode`、`GisViewUpdateItemsOutcome`、`GisViewUpdateItemEntry` |
185
188
  | 相机与视图 | `GisViewCamera`、`GisViewViewport`、`GisViewFocusOptions`、`GisViewFocusTarget`、`GisViewExportImageOptions`、`GisViewExportSelectionOptions`、`GisViewExportSelectionResult` |