gis-view-webgl2 0.1.2 → 0.1.4

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 (66) hide show
  1. package/README.md +21 -14
  2. package/dist/gis-view.css +1 -1
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.ts +421 -76
  5. package/dist/index.js +1 -1
  6. package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +151 -0
  7. package/docs/GisView.md +4 -4
  8. 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 +137 -0
  9. package/docs/api/index.html +23 -9
  10. package/docs/demos/ApiCoverageDemo.vue +644 -0
  11. package/docs/demos/ChannelDemo.vue +14 -12
  12. package/docs/demos/ClusterDemo.vue +251 -0
  13. package/docs/demos/CopyMergeDemo.vue +3 -4
  14. package/docs/demos/EventDemo.vue +3 -3
  15. package/docs/demos/ExtensionDemo.vue +69 -12
  16. package/docs/demos/GisViewDemo.vue +64 -8809
  17. package/docs/demos/SearchFilterDemo.vue +13 -11
  18. package/docs/demos/api-index.js +58 -47
  19. package/docs/demos/demos.js +34 -17
  20. package/docs/demos/gis-view-demo/GisViewDemoCardHeader.vue +29 -0
  21. package/docs/demos/gis-view-demo/GisViewDemoDialogs.vue +82 -0
  22. package/docs/demos/gis-view-demo/GisViewDemoFooter.vue +16 -0
  23. package/docs/demos/gis-view-demo/GisViewDemoHeading.vue +16 -0
  24. package/docs/demos/gis-view-demo/GisViewDemoPanelStack.vue +71 -0
  25. package/docs/demos/gis-view-demo/GisViewDemoStage.vue +219 -0
  26. package/docs/demos/gis-view-demo/demo.css +1230 -0
  27. package/docs/demos/gis-view-demo/demoContext.js +12 -0
  28. package/docs/demos/gis-view-demo/panels/DataPanels.vue +303 -0
  29. package/docs/demos/gis-view-demo/panels/OpsPanels.vue +174 -0
  30. package/docs/demos/gis-view-demo/panels/StylePanels.vue +561 -0
  31. package/docs/demos/gis-view-demo/panels/ViewPanels.vue +396 -0
  32. package/docs/demos/gis-view-demo/useGisViewDemo.js +6188 -0
  33. package/docs/format/07-/344/272/213/344/273/266/350/275/275/350/215/267/344/270/216/347/244/272/344/276/213/346/225/260/346/215/256.md +3 -2
  34. package/docs/index.html +41 -4
  35. package/docs/internals/16-03-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/213.md +1 -1
  36. package/docs/manual/02-/345/235/220/346/240/207/344/270/216/346/225/260/346/215/256.md +3 -2
  37. package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +104 -16
  38. package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +15 -14
  39. package/docs/manual/07-/346/214/207/351/222/210/344/270/216/350/246/201/347/264/240/347/274/226/350/276/221.md +40 -3
  40. package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +50 -3
  41. package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +6 -2
  42. 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 +39 -7
  43. package/docs/manual/12-/346/240/207/347/255/276/344/270/216/350/243/205/351/245/260.md +13 -4
  44. package/docs/manual/13-/345/212/250/346/225/210/344/270/216/345/233/276/345/205/203.md +3 -0
  45. package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +121 -49
  46. package/docs/manual/15-/345/257/274/345/207/272/344/270/216/351/233/206/346/210/220.md +37 -3
  47. package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +17 -8
  48. package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +45 -25
  49. package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +91 -20
  50. 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 +3 -3
  51. package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +25 -1
  52. 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 +11 -8
  53. package/docs/steps/README.md +17 -11
  54. package/docs/steps/selftest-actions.html +3 -5
  55. package/docs/steps/selftest-demo.html +27 -18
  56. package/docs/steps/selftest-demos.html +409 -32
  57. package/docs/steps/selftest-docs.html +33 -4
  58. package/docs/steps/selftest-effects.html +200 -0
  59. package/docs/steps/selftest-features.html +603 -21
  60. package/docs/steps/selftest-labels.html +74 -0
  61. package/docs/steps/selftest-perf.html +293 -20
  62. package/docs/steps/selftest-scale.html +150 -29
  63. package/docs/steps/selftest-select.html +90 -0
  64. package/docs/steps/step-10-full.js +1 -1
  65. package/docs/steps/step-12-events.js +1 -1
  66. package/package.json +1 -1
@@ -7,8 +7,8 @@
7
7
  * 源码或文档改过之后重跑一遍;`node docs/steps/check-doc-coverage.mjs` 会对账。
8
8
  */
9
9
 
10
- /** { members: 249, methods: 246, properties: 3, options: 92, sections: 16 } */
11
- export const API_SUMMARY = {"members":249,"methods":246,"properties":3,"options":92,"sections":16}
10
+ /** { members: 256, methods: 253, properties: 3, options: 96, sections: 16 } */
11
+ export const API_SUMMARY = {"members":256,"methods":253,"properties":3,"options":96,"sections":16}
12
12
 
13
13
  /** 实例成员,按 docs/GisView.md「参数速查」的分组排 */
14
14
  export const API_SECTIONS = [
@@ -50,13 +50,13 @@ export const API_SECTIONS = [
50
50
  { name: "zoomBy", kind: "method", params: "factor: number 缩放倍数(> 1 放大、< 1 缩小);origin?: [number, number] 缩放中心(画布 CSS 像素,缺省画布中心)", returns: "this", doc: "相对缩放,origin 为画布 CSS 像素锚点(缺省视口中心)", examples: [{"group":"相机与视图","code":"// zoomBy(factor, origin?):按倍数缩放;origin 是画布 CSS 像素的缩放中心\nview.zoomBy(1.5)\nview.zoomBy(0.5, [320, 200])\n","from":"header"}] },
51
51
  { name: "zoomTo", kind: "method", params: "scale: number 目标缩放值(世界单位 → CSS 像素的比例);origin?: [x, y] 缩放中心", returns: "this", doc: "直接设成指定比例(像素 / 世界单位)", examples: [{"group":"相机与视图","code":"// zoomTo(scale, origin?):直接给目标比例(世界单位 → CSS 像素)\nview.zoomTo(12)\n","from":"header"}] },
52
52
  { name: "zoomToBounds", kind: "method", params: "bounds: GisViewBounds 要装进画面的世界矩形 [minX, minY, maxX, maxY](也认 { minX, minY, maxX, maxY });padding?: number 四周留白", returns: "this", doc: "把一段世界坐标矩形适应到视图内,退化成一点时只居中不改比例", examples: [{"group":"相机与视图","code":"// zoomToBounds(bounds, padding?):把世界矩形装进画面(数组与对象写法都认)\nview.zoomToBounds([0, 0, 400, 200], 40)\nview.zoomToBounds({ minX: 116, minY: 39, maxX: 117, maxY: 40 })\n","from":"header"}] },
53
- { name: "focusOn", kind: "method", params: "target: GisViewFocusTargets 要对准的东西:id / { type, index } / [x, y] 坐标 / 一个矩形 / 通道写法 / { lngLat } / { center },或者一批(数组取整体包围盒 —— 搜到三个节点就是这三个点的中心当屏幕中心);options?: GisViewFocusOptions:scale / center(只居中、比例不动)/ padding / maxZoom / select(顺带选中,mode 决定怎么并进当前选中集)", returns: "this", doc: "把视角移到目标上:单条(搜索命中 / 要素 id / { type, index } / 坐标 / 矩形 / 通道写法 / { lngLat })或一批(数组取整体包围盒 —— 搜到三个节点就是这三个点的中心当屏幕中心);options 认 scale、center: true(只居中、比例一点不动)、padding、maxZoom、select(顺带选中这批,mode 决定怎么并进当前选中集)", examples: [{"group":"相机与视图","code":"// focusOn(target, options?):对准一个或多个目标(id / 下标 / 坐标 / 矩形 / 通道写法 / 搜索命中 / 一批)\nview.focusOn('a')\nview.focusOn(['a', 'b'], { padding: 60, maxZoom: 8, select: true })\nview.focusOn([120, 80], { center: true }) // 只居中,比例不动\nview.focusOn({ lngLat: [116.4, 39.9] })\n","from":"header"}] },
54
- { name: "search", kind: "method", params: "input: string | GisViewSearchOptions 关键字,或 { keyword, scope, fields, limit } 这类选项(scope 可选 'points' / 'lines' / 'channels',也认它们的数组)—— 只返回结果、不动视角,要定位就自己调 focusOn(result.hits, …)", returns: "GisViewSearchResult", doc: "按关键字搜索节点 / 线路 / 通道并返回命中(不动视角:要不要聚焦由调用方自己调 focusOn),见「搜索与定位」", examples: [{"group":"相机与视图","code":"// search(input) / searchAsync(input):搜索(只返回结果、不动视角)\nconst hits = view.search('甲站')\nconst scoped = view.search({ keyword: '甲', scope: ['points', 'channels'], limit: 10 })\nview.focusOn(hits.hits, { maxZoom: 8 }) // 命中集直接丢给 focusOn\nconst asyncHits = await view.searchAsync('甲站') // 大表走 Worker;stale 说明这一份不作数了\n","from":"header"}] },
55
- { name: "searchAsync", kind: "method", params: "同上", returns: "Promise<GisViewSearchResult>:多一个 worker(是不是在 Worker 里算的)与 stale(回来时数据已经改过、或又搜过一次,这一份不作数了)", doc: "同一份口径的异步版:数据量大时把扫描放进 Worker(10 万点 / 10 万线下同步要占主线程 40 ms 上下的那一段),返回 Promise<GisViewSearchResult>;结果带 worker 与 stale 两个字段,见「异步搜索」", examples: [{"group":"相机与视图","code":"// search(input) / searchAsync(input):搜索(只返回结果、不动视角)\nconst hits = view.search('甲站')\nconst scoped = view.search({ keyword: '甲', scope: ['points', 'channels'], limit: 10 })\nview.focusOn(hits.hits, { maxZoom: 8 }) // 命中集直接丢给 focusOn\nconst asyncHits = await view.searchAsync('甲站') // 大表走 Worker;stale 说明这一份不作数了\n","from":"header"}] },
53
+ { name: "focusOn", kind: "method", params: "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 决定怎么并进当前选中集。目标认不出来或参数非法时什么都不做", returns: "this(相机更新后发 onCameraChange;select 生效时另发 onSelect / onSelectChange)", doc: "把视角移到目标上:单条(搜索命中 / 要素 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 决定怎么并进当前选中集)", examples: [{"group":"相机与视图","code":"// focusOn(target, options?):对准一个或多个目标(id / 显式类型 / 坐标 / 矩形 / 搜索命中 / 一批)\nview.focusOn('a') // 缺省只居中,比例不动\nview.focusOn('a', { zoom: true, maxZoom: 8 }) // 显式按范围适配\nview.focusOn(['a', 'b'], { zoom: true, padding: 60, select: true })\nview.focusOn({ type: 'point', id: 'a' }) // 节点与线路同 id 时显式消歧\nview.focusOn({ type: 'line', id: 'a' })\nview.focusOn({ type: 'channel', channelId: 'c1' }) // 通道也可以直接写 { channelId: 'c1' }\nview.focusOn({ type: 'group', channelId: 'c1', groupId: 'c1::2' })\nview.focusOn({ type: 'group', groupId: 'global-group' }) // groupId 全局唯一时可省略通道\nview.focusOn([120, 80], { center: true }) // 显式只居中(与缺省一致)\nview.focusOn({ lngLat: [116.4, 39.9] })\n","from":"header"}] },
54
+ { name: "search", kind: "method", params: "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, …)", returns: "GisViewSearchResult:keyword / scope / points / lines / channels / groups / hits / total / truncated / durationMs", doc: "按关键字搜索节点 / 线路 / 通道 / 通道分组并返回命中:scope 认复数的 points / lines / channels / groups,也认与 focusOn 一致的单数别名 point / line / channel / group;结果分 points / lines / channels / groups 四类,分组命中带 channelIndex / groupId / groupIndex,可直接交给 focusOn / selectFeatures。不动视角:要不要聚焦由调用方自己调 focusOn,见「搜索与定位」", examples: [{"group":"相机与视图","code":"// search(input) / searchAsync(input):搜索(只返回结果、不动视角)\nconst hits = view.search('甲站')\nconst scoped = view.search({ keyword: '甲', scope: ['points', 'channels', 'groups'], limit: 10 })\nconst groupHits = view.search({ keyword: 'c1::2', scope: 'group' }) // 单数别名与 focusOn 一致\nview.focusOn(groupHits.groups[0], { zoom: true, select: true }) // 按整组范围适配并选中成员回线\nview.focusOn(hits.hits, { zoom: true, maxZoom: 8 }) // 命中集直接丢给 focusOn\nconst asyncHits = await view.searchAsync('甲站') // 大表走 Worker;stale 说明这一份不作数了\n","from":"header"}] },
55
+ { name: "searchAsync", kind: "method", params: "同上;分组范围的当前轻量快照会随请求交给 Worker", returns: "Promise<GisViewSearchResult>:多一个 worker(是不是在 Worker 里算的)与 stale(回来时数据已经改过、或又搜过一次,这一份不作数了)", doc: "同一份口径的异步版:数据量大时把扫描放进 Worker(10 万点 / 10 万线下同步要占主线程 40 ms 上下的那一段),返回 Promise<GisViewSearchResult>;结果带 worker 与 stale 两个字段,见「异步搜索」", examples: [{"group":"相机与视图","code":"// search(input) / searchAsync(input):搜索(只返回结果、不动视角)\nconst hits = view.search('甲站')\nconst scoped = view.search({ keyword: '甲', scope: ['points', 'channels', 'groups'], limit: 10 })\nconst groupHits = view.search({ keyword: 'c1::2', scope: 'group' }) // 单数别名与 focusOn 一致\nview.focusOn(groupHits.groups[0], { zoom: true, select: true }) // 按整组范围适配并选中成员回线\nview.focusOn(hits.hits, { zoom: true, maxZoom: 8 }) // 命中集直接丢给 focusOn\nconst asyncHits = await view.searchAsync('甲站') // 大表走 Worker;stale 说明这一份不作数了\n","from":"header"}] },
56
56
  { name: "setCamera", kind: "method", params: "camera: Partial<GisViewCamera> 要改的相机字段 { x, y, scale }(只写一个也行)", returns: "this", doc: "读写 { center, scale }", examples: [{"group":"相机与视图","code":"// setCamera(camera) / getCamera():读写相机(只写一个字段也行)\nview.setCamera({ scale: 10 })\nview.setCamera({ x: 200, y: 120 })\nconst camera = view.getCamera()\n","from":"header"}] },
57
57
  { name: "getCamera", kind: "method", params: "无", returns: "GisViewCamera", doc: "读写 { center, scale }", examples: [{"group":"相机与视图","code":"// setCamera(camera) / getCamera():读写相机(只写一个字段也行)\nview.setCamera({ scale: 10 })\nview.setCamera({ x: 200, y: 120 })\nconst camera = view.getCamera()\n","from":"header"}] },
58
- { name: "getZoomBaseScale", kind: "method", params: "无", returns: "number 缩放联动的基准比例(pointZoomScale / lineZoomScale / zoomScaleAuto 共用那一份;缺省是首次适应视图时的 camera.scale)", doc: "读 / 重定缩放联动的基准比例(缺省是首次适应视图时的比例):不传参数就取当下相机的比例 —— 把现在这一屏当成「原样大小」,之后放大缩小都从它算倍数;与自适应比例开关 zoomScaleAuto 配套,见「自适应比例(zoomScaleAuto)」", examples: [{"group":"相机与视图","code":"// zoomScaleAuto / getZoomBaseScale() / setZoomBaseScale(scale?):自适应比例(节点大小与通道间距按同一比例变)\nview.updateOptions({ zoomScaleAuto: true }) // 没写联动指数的那几项按 1 跟随地图(显式写过的仍以显式值为准)\nconst zoomBase = view.getZoomBaseScale() // 基准(缺省首次适应视图时的 camera.scale)\nview.setZoomBaseScale() // 以当下这一屏为「原样大小」,之后放大缩小都从它算倍数\nview.setZoomBaseScale(2.5) // 也可以直接给一个比例\n","from":"header"}] },
59
- { name: "setZoomBaseScale", kind: "method", params: "scale?: number 新的基准比例;不传取当下相机的比例(把现在这一屏当成「原样大小」)", returns: "this", doc: "读 / 重定缩放联动的基准比例(缺省是首次适应视图时的比例):不传参数就取当下相机的比例 —— 把现在这一屏当成「原样大小」,之后放大缩小都从它算倍数;与自适应比例开关 zoomScaleAuto 配套,见「自适应比例(zoomScaleAuto)」", examples: [{"group":"相机与视图","code":"// zoomScaleAuto / getZoomBaseScale() / setZoomBaseScale(scale?):自适应比例(节点大小与通道间距按同一比例变)\nview.updateOptions({ zoomScaleAuto: true }) // 没写联动指数的那几项按 1 跟随地图(显式写过的仍以显式值为准)\nconst zoomBase = view.getZoomBaseScale() // 基准(缺省首次适应视图时的 camera.scale)\nview.setZoomBaseScale() // 以当下这一屏为「原样大小」,之后放大缩小都从它算倍数\nview.setZoomBaseScale(2.5) // 也可以直接给一个比例\n","from":"header"}] },
58
+ { name: "getZoomBaseScale", kind: "method", params: "无", returns: "number 缩放联动的基准比例(pointZoomScale / lineZoomScale 共用那一份;缺省是首次适应视图时的 camera.scale)", doc: "读 / 重定缩放联动的基准比例(缺省是首次适应视图时的比例):不传参数就取当下相机的比例 —— 把现在这一屏当成「原样大小」,之后放大缩小都从它算倍数;配合 pointZoomScale / lineZoomScale 使用", examples: [{"group":"相机与视图","code":"// getZoomBaseScale() / setZoomBaseScale(scale?):缩放联动的基准比例(配合 pointZoomScale / lineZoomScale)\nconst zoomBase = view.getZoomBaseScale() // 基准(缺省首次适应视图时的 camera.scale)\nview.setZoomBaseScale() // 以当下这一屏为「原样大小」,之后放大缩小都从它算倍数\nview.setZoomBaseScale(2.5) // 也可以直接给一个比例\n","from":"header"}] },
59
+ { name: "setZoomBaseScale", kind: "method", params: "scale?: number 新的基准比例;不传取当下相机的比例(把现在这一屏当成「原样大小」)", returns: "this", doc: "读 / 重定缩放联动的基准比例(缺省是首次适应视图时的比例):不传参数就取当下相机的比例 —— 把现在这一屏当成「原样大小」,之后放大缩小都从它算倍数;配合 pointZoomScale / lineZoomScale 使用", examples: [{"group":"相机与视图","code":"// getZoomBaseScale() / setZoomBaseScale(scale?):缩放联动的基准比例(配合 pointZoomScale / lineZoomScale)\nconst zoomBase = view.getZoomBaseScale() // 基准(缺省首次适应视图时的 camera.scale)\nview.setZoomBaseScale() // 以当下这一屏为「原样大小」,之后放大缩小都从它算倍数\nview.setZoomBaseScale(2.5) // 也可以直接给一个比例\n","from":"header"}] },
60
60
  { name: "getBounds", kind: "method", params: "无", returns: "GisViewBounds", doc: "数据范围(没有点时回退到背景 GeoJSON 的 rawBounds,也就是 aspectScale 之前的真实经纬度范围)", examples: [{"group":"相机与视图","code":"// getBounds() / getViewRect() / getViewport():数据范围 / 视口世界矩形 / 画布尺寸读数\nconst dataBounds = view.getBounds()\nconst viewRect = view.getViewRect()\nconst { cssWidth, cssHeight, pixelRatio } = view.getViewport()\n","from":"header"}] },
61
61
  { name: "getViewport", kind: "method", params: "无", returns: "{ cssWidth, cssHeight, pixelRatio, displayScale }:画布 CSS 尺寸、设备像素比与渲染分辨率比例", doc: "/** * 当前视口。", examples: [{"group":"相机与视图","code":"// getBounds() / getViewRect() / getViewport():数据范围 / 视口世界矩形 / 画布尺寸读数\nconst dataBounds = view.getBounds()\nconst viewRect = view.getViewRect()\nconst { cssWidth, cssHeight, pixelRatio } = view.getViewport()\n","from":"header"}] },
62
62
  { name: "getViewRect", kind: "method", params: "无", returns: "GisViewBounds", doc: "当前可视范围的世界坐标矩形;自建缩略图 / 坐标读数用它换算视口框,内置鹰眼图见「鹰眼图」", examples: [{"group":"相机与视图","code":"// getBounds() / getViewRect() / getViewport():数据范围 / 视口世界矩形 / 画布尺寸读数\nconst dataBounds = view.getBounds()\nconst viewRect = view.getViewRect()\nconst { cssWidth, cssHeight, pixelRatio } = view.getViewport()\n","from":"header"}] },
@@ -109,6 +109,8 @@ export const API_SECTIONS = [
109
109
  { name: "getLine", kind: "method", params: "ref 线路定位(同上)", returns: "GisViewLineInfo | null", doc: "取一条线路:拾取载荷 + path / bounds / color / width(与 listLines() 的一项同一份口径),通道回线还带 channelId / groupId / channelIndex;找不到返回 null", examples: [{"group":"坐标、拾取与读数","code":"// getPoint(ref) / getLine(ref) / getChannel(ref):一个要素的几何读数\nconst pointInfo = view.getPoint('a')\nconst lineInfo = view.getLine('l1')\nconst channelInfo = view.getChannel('c1')\n","from":"header"}] },
110
110
  { name: "getChannel", kind: "method", params: "ref 通道定位:通道 id 或下标", returns: "GisViewChannelSnapshot | null", doc: "取一条通道:数据那一份(index / item / id)+ 成员表(lineIndexes / skeleton / offsets / paths)+ 分组上下文 context(几组 / 当前哪组 / 每组拐点数)、from / to / anchored / spacing;找不到返回 null", examples: [{"group":"坐标、拾取与读数","code":"// getPoint(ref) / getLine(ref) / getChannel(ref):一个要素的几何读数\nconst pointInfo = view.getPoint('a')\nconst lineInfo = view.getLine('l1')\nconst channelInfo = view.getChannel('c1')\n","from":"header"}] },
111
111
  { name: "listPoints", kind: "method", params: "options?: GisViewListOptions:indexes(只看这几个下标)、inView: boolean(只要当前视口里的)、withScreen: boolean(连屏幕坐标一起给)、visibleOnly: boolean(跳过隐藏的)、limit: number(最多几条)", returns: "GisViewListedPoint[]", doc: "按条件列节点快照 { index, item, x, y, radius, layerRank, screen? }:选项见 GisViewListOptions(indexes / inView / limit / withScreen / visibleOnly),可见判定与 isPointVisible 是同一份", examples: [{"group":"坐标、拾取与读数","code":"// listPoints(options?) / listLines(options?):按条件列一批\nconst listedPoints = view.listPoints({ limit: 5, withScreen: true })\nconst listedLines = view.listLines({ inView: true, limit: 200 })\n","from":"header"}] },
112
+ { name: "getClusters", kind: "method", params: "无", returns: "GisViewCluster[]。当前展示组(含 count: 1 的单成员),screen 按当前相机现算;聚合关掉时是空表", doc: "当前点聚合的展示组 GisViewCluster[]:按数据顺序返回,含 count: 1 的单成员与 count > 1 的聚合圆;每项带 id / pointIndexes / pointIds / 世界坐标 coordinate / 当前屏幕坐标 screen / 半径 radius / 包围盒 bounds。原始 points 与 getData() 不变,聚合关掉时返回空表", examples: [{"group":"坐标、拾取与读数","code":"// getClusters() / getPointCluster():读当前点聚合展示组与配置\nview.updateOptions({ pointCluster: { radius: 64, minPoints: 3, maxZoom: 2.5 } })\nconst clusterGroups = view.getClusters()\nconst clusteredOnly = clusterGroups.filter(group => group.count > 1)\nconst clusterState = view.getPointCluster() // { enabled, radius, minPoints, maxZoom, active }\nview.updateOptions({ pointCluster: false }) // 关掉聚合,原始点全部恢复\n","from":"header"}] },
113
+ { name: "getPointCluster", kind: "method", params: "无", returns: "GisViewPointClusterReadout | null。归一化配置 { enabled, radius, minPoints, maxZoom, active },超过 maxZoom 后 active 为 false", doc: "当前点聚合配置的归一化读数 GisViewPointClusterReadout | null:{ enabled, radius, minPoints, maxZoom, active },active 说明当前缩放档是否仍在聚合(超过 maxZoom 后为 false);引擎未就绪时为 null", examples: [{"group":"坐标、拾取与读数","code":"// getClusters() / getPointCluster():读当前点聚合展示组与配置\nview.updateOptions({ pointCluster: { radius: 64, minPoints: 3, maxZoom: 2.5 } })\nconst clusterGroups = view.getClusters()\nconst clusteredOnly = clusterGroups.filter(group => group.count > 1)\nconst clusterState = view.getPointCluster() // { enabled, radius, minPoints, maxZoom, active }\nview.updateOptions({ pointCluster: false }) // 关掉聚合,原始点全部恢复\n","from":"header"}] },
112
114
  { name: "listLines", kind: "method", params: "同 listPoints(inView / withScreen / limit…)", returns: "GisViewListedLine[]", doc: "按条件列线路快照 { index, item, path, bounds, color, width, channelId?, groupId?, channelIndex?, screen? }:选项与 listPoints 同一套;通道回线给的是骨架推导出来的那条折线(跟图上画的一致)", examples: [{"group":"坐标、拾取与读数","code":"// listPoints(options?) / listLines(options?):按条件列一批\nconst listedPoints = view.listPoints({ limit: 5, withScreen: true })\nconst listedLines = view.listLines({ inView: true, limit: 200 })\n","from":"header"}] },
113
115
  { name: "forEachPointInView", kind: "method", params: "rect: GisViewBounds 世界坐标矩形(一般直接给 getViewRect() 的返回值);visit: (index, item, x, y, radius) => void | false 逐个回调,返回 false 提前结束", returns: "void。只遍历矩形里的可见节点(数据顺序、不建中间数组):与 listPoints({ inView: true }) 同一份可见判定,但不生成清单 —— 放大看一小片时不会去碰整份数据", doc: "/** * 只遍历落在给定世界矩形({ minX, minY, maxX, maxY })里的可见节点,逐个回调 * (index, item, x, y, radius)。", examples: [{"group":"坐标、拾取与读数","code":"// forEachPointInView(rect, visit):只遍历视口里的节点,不建中间数组;回调返回 false 提前结束\nview.forEachPointInView(view.getViewRect(), (index, item, x, y, radius) => {\n readout.push(`${item.name}:半径 ${radius.toFixed(1)}px`)\n})\n","from":"header"}] },
114
116
  { name: "getVisibleData", kind: "method", params: "无", returns: "GisViewData", doc: "过滤之后的数据副本(points / lines)", examples: [{"group":"坐标、拾取与读数","code":"// getVisibleData() / isPointVisible(index):筛选之后的整份数据 / 某个节点在不在图上\nconst visibleData = view.getVisibleData()\nconst shown = view.isPointVisible(0)\n","from":"header"}] },
@@ -129,17 +131,19 @@ export const API_SECTIONS = [
129
131
  {
130
132
  title: "选中、复制与合并",
131
133
  items: [
132
- { name: "selectFeatures", kind: "method", params: "refs: GisViewSelectionRefs 要选中的东西:id / id 数组(多选)/ { type, index } / 通道写法 / 拾取载荷 / 搜索命中,传 null / 空数组等于清空;options?: GisViewSelectOptions 只有 mode('replace' 缺省 / 'add' / 'toggle' / 'remove')", returns: "this", doc: "接口选中(换一份选中集;selectFeatures(null) / 空数组就是清空):refs 认 id、id 数组、{ type, index }、通道写法({ type: 'channel', channelId } / { channelId, groupId } / { channelId, lineIds })以及拾取载荷与搜索命中;options.mode 给 'replace'(缺省,换一份)/ 'add' / 'toggle'(在就取消、不在就选上)/ 'remove',见「接口选中(selectFeatures)与读回选中」", examples: [{"group":"选中、复制与合并","code":"// selectFeatures(refs, options?):接口选中(与点击选中走同一份 state)\nview.selectFeatures('a') // 选中一个\nview.selectFeatures(['a', 'b']) // 一批\nview.selectFeatures('a', { mode: 'add' }) // mode:replace(缺省)/ add / toggle / remove\nview.selectFeatures([{ type: 'line', index: 0 }], { mode: 'toggle' })\nview.selectFeatures(null) // 清空(空数组同义)\n","from":"header"}] },
134
+ { name: "selectFeatures", kind: "method", params: "refs: GisViewSelectionRefs 要选中的东西:节点 / 线路 id、id 数组、{ type, index }、通道写法({ type: 'channel', channelId | channelIndex },可再给 groupIds / lineIds / lineIndexes 取子集)、分组写法({ type: 'group', channelId?, groupId },groupId 全局唯一时可省略通道)、拾取载荷 / 搜索命中,传 null / 空数组等于清空一份新的选中集。认不出来的条目逐条跳过;options?: GisViewSelectOptions 只有 mode:'replace' 缺省换一份、'add' 追加、'toggle' 在就取消 / 不在就选上、'remove' 去掉", returns: "this(选中真的变了才发 onSelect 与 onSelectChange,cause 为 api)", doc: "接口选中(换一份选中集;selectFeatures(null) / 空数组就是清空):refs 认节点 / 线路 id、id 数组、{ type, index }、通道写法({ type: 'channel', channelId } / { channelId, groupId } / { channelId, lineIds })、分组写法({ type: 'group', channelId?, groupId },全局唯一 groupId 可省略通道)以及拾取载荷与搜索命中;options.mode 给 'replace'(缺省,换一份)/ 'add' / 'toggle'(在就取消、不在就选上)/ 'remove',见「接口选中(selectFeatures)与读回选中」", examples: [{"group":"选中、复制与合并","code":"// selectFeatures(refs, options?):接口选中(与点击选中走同一份 state)\nview.selectFeatures('a') // 选中一个\nview.selectFeatures(['a', 'b']) // 一批\nview.selectFeatures('a', { mode: 'add' }) // mode:replace(缺省)/ add / toggle / remove\nview.selectFeatures([{ type: 'line', index: 0 }], { mode: 'toggle' })\nview.selectFeatures({ type: 'channel', channelId: 'c1' }) // 整条通道的全部回线\nview.selectFeatures({ type: 'group', channelId: 'c1', groupId: 'c1::2' })\nview.selectFeatures({ type: 'group', groupId: 'global-group' }) // groupId 全局唯一时可省略通道\nview.selectFeatures(null) // 清空(空数组同义)\n","from":"header"}] },
135
+ { name: "selectWaypoint", kind: "method", params: "lineRef 线路 id、lines 下标或 { lineIndex, pathIndex } / { lineId, pathIndex } 对象;pathIndex?: number 必须是 getWaypoints() 给出的可编辑中间拐点下标(首尾端点不算,通常直接从读数里取);options?: GisViewSelectOptions 的 mode 决定所在线路怎么并进当前选中集(缺省 replace)。有效拐点会同时选中线路;线路不存在 / 下标非法 / 拐点不可见时只清拐点选中,不猜位置;传 null 也只清拐点,不改要素选中集", returns: "this", doc: "代码选中一个拐点:selectWaypoint('line-1', 2) / { lineIndex, pathIndex } / { lineId, pathIndex },并同时选中所在线路;有效下标从 getWaypoints() 取。传 null 只取消拐点选中、不改要素选中集,见「代码选中拐点(selectWaypoint)」", examples: [{"group":"选中、复制与合并","code":"// selectWaypoint(lineRef, pathIndex? / { lineIndex | lineId, pathIndex }, options?):选中拐点并带选线路\nview.selectWaypoint('l1', 2) // pathIndex 从 getWaypoints() 取\nview.selectWaypoint({ lineIndex: 0, pathIndex: 1 }, { mode: 'add' })\nview.selectWaypoint({ lineId: 'l1', pathIndex: 2 })\nview.selectWaypoint(null) // 只取消拐点选中,不改要素选中集\n","from":"header"}] },
133
136
  { name: "deselect", kind: "method", params: "refs?: GisViewSelectionRefs 要取消的东西(写法与 selectFeatures 一致:节点 / 通道 / 线路 / 混合一批);不传 / null 等于取消全部(= selectFeatures(null)),空数组是「没有目标」什么都不做", returns: "this", doc: "取消选中:写法与 selectFeatures 完全一样,把这些从当前选中集里去掉、其余选中原样留着;不传 / null 等于取消全部(也就是 selectFeatures(null)),空数组是「没有目标」什么都不做,见「取消选中(deselect / selectFeatures(null))」", examples: [{"group":"选中、复制与合并","code":"// deselect(refs?):取消选中(写法与 selectFeatures 一致;不传 / null 全清,空数组什么都不做)\nview.deselect('a')\nview.deselect(['a', 'b'])\nview.deselect()\n","from":"header"}] },
134
137
  { name: "getSelections", kind: "method", params: "无", returns: "GisViewPickResult[]", doc: "读回选中结果 [{ type, index, item, … }](按选中顺序):要 id 列表 / 个数 / 包围盒看 getSelectionData()", examples: [{"group":"选中、复制与合并","code":"// getSelections() / getSelectionData() / isSelected(ref):读回选中\nconst picks = view.getSelections()\nconst selection = view.getSelectionData() // { ids, count, points, lines, channels, bounds, … }\nconst selected = view.isSelected('a')\n","from":"header"}] },
135
138
  { name: "isSelected", kind: "method", params: "ref: GisViewFeatureRef | GisViewFeatureKey | GisViewSelectionRefObject 要素定位(id / 下标 / { id } / { index } / { type, index } / { item })", returns: "boolean", doc: "这个要素在不在当前选中集里:isSelected('node-0')(id)/ isSelected({ type: 'line', index: 12 })(也可以只写下标,按 id 认不出来时当下标),返回 true / false。面板上高亮「当前这一行」时不必自己比对 getSelections();选中集变化时缓存一份键集合(见「接口选中」),十万级选中下这一问也是常数级", examples: [{"group":"选中、复制与合并","code":"// getSelections() / getSelectionData() / isSelected(ref):读回选中\nconst picks = view.getSelections()\nconst selection = view.getSelectionData() // { ids, count, points, lines, channels, bounds, … }\nconst selected = view.isSelected('a')\n","from":"header"}] },
136
139
  { name: "getSelectionData", kind: "method", params: "无", returns: "GisViewSelectionData:{ ids, count, pointCount, lineCount, channelCount, points, lines, channels, items, pointIndexes, lineIndexes, bounds }(bounds 是世界包围盒,空选中时 null)", doc: "选中集一次取全:读数(ids / count / pointCount / lineCount / channelCount)加要素本身(points / lines / channels(按通道去重,与 getData() 同一批对象)),另有 items(与 getSelections() 同一份)、pointIndexes / lineIndexes 与 bounds(世界包围盒,空选中时 null),见「接口选中(selectFeatures)与读回选中」", examples: [{"group":"选中、复制与合并","code":"// getSelections() / getSelectionData() / isSelected(ref):读回选中\nconst picks = view.getSelections()\nconst selection = view.getSelectionData() // { ids, count, points, lines, channels, bounds, … }\nconst selected = view.isSelected('a')\n","from":"header"}] },
137
- { name: "selectInBox", kind: "method", params: "box: GisViewRect 画布 CSS 像素矩形 { x, y, width, height }(与手动框选同一套坐标);options?: GisViewSelectInBoxOptions:selectionKinds 临时覆盖这一次的类型过滤('point' / 'line' / 'channel'、数组、'all' / true / false / null),originalEvent 原样带进 onSelect;第二段也兼容旧的 Event 写法", returns: "this", doc: "按画布 CSS 像素矩形框选,等价于 Shift + 拖动(跟随 shortcuts.boxSelect);options.selectionKinds 可只覆盖这一次的节点 / 线路 / 通道类型过滤", examples: [{"group":"选中、复制与合并","code":"// selectInBox(box, options?):用矩形框选(画布 CSS 像素,与手动框选同一套判定)\nview.selectInBox({ x: 40, y: 40, width: 320, height: 200 })\nview.selectInBox({ x: 40, y: 40, width: 320, height: 200 }, { selectionKinds: ['line', 'channel'] })\n","from":"header"}] },
138
- { name: "beginCopyPoint", kind: "method", params: "options: GisViewCopyStartOptions:id / index(复制哪个节点)、label(历史里这一步的名字)、style(草稿样式)", returns: "GisViewPointCopyPayload | null", doc: "开始复制一个节点:给 id / index 直接出预览(commit: true 出预览即落地,follow: true 跟随鼠标,autoCommit: false 停在预览态),不给来源就是「先点按钮再选节点」模式,见「节点复制」", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.beginCopyPoint({ id: 'a' }) // 出复制预览(跟着鼠标走)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 改预览节点的数据\nview.commitPointCopy() // 落地\nview.cancelPointCopy() // 取消\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
139
- { name: "commitPointCopy", kind: "method", params: "无", returns: "GisViewPointCopyPayload | null", doc: "落地 / 取消预览中的复制(返回 end / cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.beginCopyPoint({ id: 'a' }) // 出复制预览(跟着鼠标走)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 改预览节点的数据\nview.commitPointCopy() // 落地\nview.cancelPointCopy() // 取消\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
140
- { name: "cancelPointCopy", kind: "method", params: "无", returns: "GisViewPointCopyPayload | null", doc: "落地 / 取消预览中的复制(返回 end / cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.beginCopyPoint({ id: 'a' }) // 出复制预览(跟着鼠标走)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 改预览节点的数据\nview.commitPointCopy() // 落地\nview.cancelPointCopy() // 取消\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
141
- { name: "updateCopyPoint", kind: "method", params: "patch: Partial<GisViewPoint> 草稿节点要改的字段(主要是 x / y 跟着指针走)", returns: "GisViewPoint | null", doc: "改预览节点的数据(等价于回调里的 payload.update / setItem),返回改完的节点", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.beginCopyPoint({ id: 'a' }) // 出复制预览(跟着鼠标走)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 改预览节点的数据\nview.commitPointCopy() // 落地\nview.cancelPointCopy() // 取消\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
142
- { name: "getPointCopy", kind: "method", params: "无", returns: "GisViewPointCopyState | null", doc: "当前复制状态:预览中是 { phase: 'preview', index, item, source, … },等选点时是 { phase: 'pick' },没有就 null", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.beginCopyPoint({ id: 'a' }) // 出复制预览(跟着鼠标走)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 改预览节点的数据\nview.commitPointCopy() // 落地\nview.cancelPointCopy() // 取消\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
140
+ { name: "getCascadeHighlight", kind: "method", params: "无", returns: "GisViewCascadeHighlightInfo | null:当前点击级联高亮的来源、范围与节点 / 线路读数 { origin, scope, points, lines, pointIndexes, lineIndexes },不改变选中集", doc: "当前点击级联高亮的读数:{ origin, scope, points, lines, pointIndexes, lineIndexes };没有高亮或 cascadeHighlight 关着时返回 null。它只读、不改选中集,见「点击级联高亮」", examples: [{"group":"选中、复制与合并","code":"// getCascadeHighlight():读点击级联高亮(与选中集分开;没有高亮时为 null)\nconst cascade = view.getCascadeHighlight() // { origin, scope, points, lines, pointIndexes, lineIndexes }\nview.updateOptions({\n cascadeHighlight: {\n scope: 'points',\n triggerOnClick: true,\n triggerOnMultiSelect: false,\n triggerOnBoxSelect: true,\n clearOnEmptyClick: true\n }\n})\nview.on('cascadeHighlight', payload => console.log(payload?.pointIndexes, payload?.lineIndexes))\n","from":"header"}] },
141
+ { name: "selectInBox", kind: "method", params: "box: GisViewRect 画布 CSS 像素矩形 { x, y, width, height }(与手动框选同一套坐标);options?: GisViewSelectInBoxOptions:selectionKinds 临时覆盖这一次保留哪几类('point' / 'line' / 'channel'、数组、'all' / true / false / null,不写沿用全局 selectionKinds),originalEvent 原样带进 onSelect;第二段也兼容旧的 Event 写法。空框不会选中任何要素", returns: "this(发 onSelect / onSelectChange,cause 为框选)", doc: "按画布 CSS 像素矩形框选,等价于 Shift + 拖动(跟随 shortcuts.boxSelect);options.selectionKinds 可只覆盖这一次的节点 / 线路 / 通道类型过滤", examples: [{"group":"选中、复制与合并","code":"// selectInBox(box, options?):用矩形框选(画布 CSS 像素,与手动框选同一套判定)\nview.selectInBox({ x: 40, y: 40, width: 320, height: 200 })\nview.selectInBox({ x: 40, y: 40, width: 320, height: 200 }, { selectionKinds: ['line', 'channel'] })\n","from":"header"}] },
142
+ { name: "beginCopyPoint", kind: "method", params: "options: GisViewCopyStartOptions:id / index / item 三选一给来源,都不给就进入「下一次点选节点」模式;coordinate / screen 是落点(缺省按 copy.offset);follow 让预览跟指针;autoCommit 覆盖 copy.autoCommit;commit: true 出预览即落地;via / originalEvent 原样带回。必须配置 copy(enabled 不为 false),否则返回 null。预览节点插在 points 末尾且不带 id,不会把绑定源 id 的线路 / 通道带过去", returns: "GisViewPointCopyPayload | null:phase: 'start' 的预览载荷;来源认不出来时返回 null", doc: "开始复制一个节点:给 id / index 直接出预览(commit: true 出预览即落地,follow: true 跟随鼠标,autoCommit: false 停在预览态),不给来源就是「先点按钮再选节点」模式,见「节点复制」", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.updateOptions({ copy: { enabled: true, autoCommit: false } }) // API 复制入口要先开 copy 配置\nview.beginCopyPoint({ id: 'a', coordinate: [40, 30] }) // 出预览并钉在世界坐标 [40, 30]\nview.beginCopyPoint({ id: 'a', follow: true }) // 预览跟着指针走(autoCommit 缺省停住)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 字段级改预览节点(落点仍由 coordinate / 指针决定)\nconst copyEnd = view.commitPointCopy() // 落地:返回 end 载荷;没有预览时为 null\nview.cancelPointCopy() // 取消:预览撤掉,数据与历史不动\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
143
+ { name: "commitPointCopy", kind: "method", params: "无:把当前复制预览落地,先发 commit、落地后发 end;commit 阶段载荷里的 cancel() 可以拦住这次复制", returns: "GisViewPointCopyPayload | null:成功的 end 载荷;没有预览或已被取消时为 null", doc: "落地 / 取消预览中的复制(返回 end / cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.updateOptions({ copy: { enabled: true, autoCommit: false } }) // API 复制入口要先开 copy 配置\nview.beginCopyPoint({ id: 'a', coordinate: [40, 30] }) // 出预览并钉在世界坐标 [40, 30]\nview.beginCopyPoint({ id: 'a', follow: true }) // 预览跟着指针走(autoCommit 缺省停住)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 字段级改预览节点(落点仍由 coordinate / 指针决定)\nconst copyEnd = view.commitPointCopy() // 落地:返回 end 载荷;没有预览时为 null\nview.cancelPointCopy() // 取消:预览撤掉,数据与历史不动\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
144
+ { name: "cancelPointCopy", kind: "method", params: "无:撤掉预览并补一条 cancel,数据与历史不动", returns: "GisViewPointCopyPayload | null:取消载荷;没有预览时为 null", doc: "落地 / 取消预览中的复制(返回 end / cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.updateOptions({ copy: { enabled: true, autoCommit: false } }) // API 复制入口要先开 copy 配置\nview.beginCopyPoint({ id: 'a', coordinate: [40, 30] }) // 出预览并钉在世界坐标 [40, 30]\nview.beginCopyPoint({ id: 'a', follow: true }) // 预览跟着指针走(autoCommit 缺省停住)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 字段级改预览节点(落点仍由 coordinate / 指针决定)\nconst copyEnd = view.commitPointCopy() // 落地:返回 end 载荷;没有预览时为 null\nview.cancelPointCopy() // 取消:预览撤掉,数据与历史不动\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
145
+ { name: "updateCopyPoint", kind: "method", params: "patch: Partial<GisViewPoint> 预览节点的字段级合并(名称 / 样式等;x / y 仍以当前落点为准),只重解析这一个预览节点", returns: "GisViewPoint | null:改完的预览节点;没有预览或 patch 不是对象时 null", doc: "改预览节点的数据(等价于回调里的 payload.update / setItem),返回改完的节点", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.updateOptions({ copy: { enabled: true, autoCommit: false } }) // API 复制入口要先开 copy 配置\nview.beginCopyPoint({ id: 'a', coordinate: [40, 30] }) // 出预览并钉在世界坐标 [40, 30]\nview.beginCopyPoint({ id: 'a', follow: true }) // 预览跟着指针走(autoCommit 缺省停住)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 字段级改预览节点(落点仍由 coordinate / 指针决定)\nconst copyEnd = view.commitPointCopy() // 落地:返回 end 载荷;没有预览时为 null\nview.cancelPointCopy() // 取消:预览撤掉,数据与历史不动\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
146
+ { name: "getPointCopy", kind: "method", params: "无", returns: "GisViewPointCopyState | null", doc: "当前复制状态:预览中是 { phase: 'preview', index, item, source, … },等选点时是 { phase: 'pick' },没有就 null", examples: [{"group":"选中、复制与合并","code":"// beginCopyPoint(options) / getPointCopy() / updateCopyPoint(patch) / commitPointCopy() / cancelPointCopy()\nview.updateOptions({ copy: { enabled: true, autoCommit: false } }) // API 复制入口要先开 copy 配置\nview.beginCopyPoint({ id: 'a', coordinate: [40, 30] }) // 出预览并钉在世界坐标 [40, 30]\nview.beginCopyPoint({ id: 'a', follow: true }) // 预览跟着指针走(autoCommit 缺省停住)\nview.beginCopyPoint() // 先点按钮再选节点(点中下一个节点当来源)\nview.updateCopyPoint({ name: '新节点' }) // 字段级改预览节点(落点仍由 coordinate / 指针决定)\nconst copyEnd = view.commitPointCopy() // 落地:返回 end 载荷;没有预览时为 null\nview.cancelPointCopy() // 取消:预览撤掉,数据与历史不动\nconst copyState = view.getPointCopy() // 当前预览 / 选点态(没有就是 null)\n","from":"header"}] },
143
147
  { name: "copyPoint", kind: "method", params: "source?: string | number | GisViewCopyStartOptions 复制哪个节点(不给就用选中的 / 光标下的,都没有就进「点一个节点」模式)", returns: "GisViewCopyItem | null", doc: "复制一个节点到它旁边(一步到位):来源给 id / 下标 / 一份节点数据,不给就用选中的节点(再没有用光标下的);返回新节点 { index, item }", examples: [{"group":"选中、复制与合并","code":"// copyPoint(source?) / copyPoints(sources?, options?) / copySelectedPoints(options?) / copyPointToClipboard(sources?, options?) / copyPointsToClipboard(sources?, options?) / pastePoint(options?) / pastePoints(options?) / getPointClipboard()\nconst copyItem = view.copyPoint('a') // 一步到位,落在原位置旁边\nconst batchCopy = view.copyPoints(['a', 'b'], { select: true }) // 只复制这两个节点(不带未选中的线路 / 通道)\nconst selectedCopy = view.copySelectedPoints({ coordinate: [120, 80] }) // 复制当前选中集:节点 + 选中线路 / 通道\nview.copySelectedPoints({ withLines: true, withChannels: true }) // 恢复旧口径:来源内部线路 / 通道全带\nview.copyPoints(['a', 'b'], { lineIndexes: [0], channelIndexes: [1] }) // 再显式点名线路 / 通道\nview.copyPointToClipboard('a') // 收进剪贴板(默认整个选中集,Ctrl+C 的接口写法)\nview.copyPointsToClipboard(['a', 'b', 'c']) // 只把给定的一批收进剪贴板\nview.pastePoint({ screen: [320, 200] }) // 粘到光标处(Ctrl+V 的接口写法)\nview.pastePoint({ coordinate: [120, 80], offset: [40, 0] })\nconst pastedBatch = view.pastePoints({ coordinate: [160, 100] }) // 强制整组落地(单节点也走批量路)\nconsole.log(batchCopy.count, batchCopy.lines.length, selectedCopy.indexes, pastedBatch?.count)\nconst clipboard = view.getPointClipboard()\n","from":"header"}] },
144
148
  { name: "copyPoints", kind: "method", params: "sources?: GisViewPointRef | GisViewPointRef[] 要复制的节点(不给就取当前选中集;copySelectedPoints 不回落到光标);显式给 sources 时只复制这批节点,不再顺带选中的线路 / 通道。options: GisViewCopyPointsOptions:coordinate / screen(落点,缺省按 copy.offset)、offset(屏幕像素偏移)、lineIndexes / channelIndexes(显式点名选中的线路 / 通道)、withLines / withChannels(缺省 false:只复制选中要素;写 true 恢复「来源内部全带」的旧口径,写 false 连选中线路 / 通道也不带)、select(复制后选中新节点)、label / via / originalEvent", returns: "GisViewBatchCopyPayload", doc: "批量复制(不经过剪贴板):不给 sources 时复制当前选中集(框选之后一次复制整组);默认只带选中要素 —— 选中线路复制线路、选中通道复制整条通道及回线,并自动补所需端点(supportSources / supportItems / supportIndexes)。显式 sources 时只复制这批节点;lineIndexes / channelIndexes 可再点名,withLines: true / withChannels: true 才恢复「来源内部全带」的旧口径(写 false 则连选中线路 / 通道也不带)。落点按 coordinate / screen 或 copy.offset,select: true 复制后选中新节点。返回 phase: 'batch' 载荷(sources / items / indexes / selectedPointCount / lines / channels / count / revert()),复制不了时 ok: false + reason", examples: [{"group":"选中、复制与合并","code":"// copyPoint(source?) / copyPoints(sources?, options?) / copySelectedPoints(options?) / copyPointToClipboard(sources?, options?) / copyPointsToClipboard(sources?, options?) / pastePoint(options?) / pastePoints(options?) / getPointClipboard()\nconst copyItem = view.copyPoint('a') // 一步到位,落在原位置旁边\nconst batchCopy = view.copyPoints(['a', 'b'], { select: true }) // 只复制这两个节点(不带未选中的线路 / 通道)\nconst selectedCopy = view.copySelectedPoints({ coordinate: [120, 80] }) // 复制当前选中集:节点 + 选中线路 / 通道\nview.copySelectedPoints({ withLines: true, withChannels: true }) // 恢复旧口径:来源内部线路 / 通道全带\nview.copyPoints(['a', 'b'], { lineIndexes: [0], channelIndexes: [1] }) // 再显式点名线路 / 通道\nview.copyPointToClipboard('a') // 收进剪贴板(默认整个选中集,Ctrl+C 的接口写法)\nview.copyPointsToClipboard(['a', 'b', 'c']) // 只把给定的一批收进剪贴板\nview.pastePoint({ screen: [320, 200] }) // 粘到光标处(Ctrl+V 的接口写法)\nview.pastePoint({ coordinate: [120, 80], offset: [40, 0] })\nconst pastedBatch = view.pastePoints({ coordinate: [160, 100] }) // 强制整组落地(单节点也走批量路)\nconsole.log(batchCopy.count, batchCopy.lines.length, selectedCopy.indexes, pastedBatch?.count)\nconst clipboard = view.getPointClipboard()\n","from":"header"}] },
145
149
  { name: "copySelectedPoints", kind: "method", params: "options 同上;只复制当前选中集(节点 + 选中线路 / 通道,并自动补端点),没有可复制要素就返回 ok: false(不回落到光标节点)", returns: "GisViewBatchCopyPayload", doc: "批量复制(不经过剪贴板):不给 sources 时复制当前选中集(框选之后一次复制整组);默认只带选中要素 —— 选中线路复制线路、选中通道复制整条通道及回线,并自动补所需端点(supportSources / supportItems / supportIndexes)。显式 sources 时只复制这批节点;lineIndexes / channelIndexes 可再点名,withLines: true / withChannels: true 才恢复「来源内部全带」的旧口径(写 false 则连选中线路 / 通道也不带)。落点按 coordinate / screen 或 copy.offset,select: true 复制后选中新节点。返回 phase: 'batch' 载荷(sources / items / indexes / selectedPointCount / lines / channels / count / revert()),复制不了时 ok: false + reason", examples: [{"group":"选中、复制与合并","code":"// copyPoint(source?) / copyPoints(sources?, options?) / copySelectedPoints(options?) / copyPointToClipboard(sources?, options?) / copyPointsToClipboard(sources?, options?) / pastePoint(options?) / pastePoints(options?) / getPointClipboard()\nconst copyItem = view.copyPoint('a') // 一步到位,落在原位置旁边\nconst batchCopy = view.copyPoints(['a', 'b'], { select: true }) // 只复制这两个节点(不带未选中的线路 / 通道)\nconst selectedCopy = view.copySelectedPoints({ coordinate: [120, 80] }) // 复制当前选中集:节点 + 选中线路 / 通道\nview.copySelectedPoints({ withLines: true, withChannels: true }) // 恢复旧口径:来源内部线路 / 通道全带\nview.copyPoints(['a', 'b'], { lineIndexes: [0], channelIndexes: [1] }) // 再显式点名线路 / 通道\nview.copyPointToClipboard('a') // 收进剪贴板(默认整个选中集,Ctrl+C 的接口写法)\nview.copyPointsToClipboard(['a', 'b', 'c']) // 只把给定的一批收进剪贴板\nview.pastePoint({ screen: [320, 200] }) // 粘到光标处(Ctrl+V 的接口写法)\nview.pastePoint({ coordinate: [120, 80], offset: [40, 0] })\nconst pastedBatch = view.pastePoints({ coordinate: [160, 100] }) // 强制整组落地(单节点也走批量路)\nconsole.log(batchCopy.count, batchCopy.lines.length, selectedCopy.indexes, pastedBatch?.count)\nconst clipboard = view.getPointClipboard()\n","from":"header"}] },
@@ -153,14 +157,14 @@ export const API_SECTIONS = [
153
157
  { name: "splitPoint", kind: "method", params: "source: GisViewPointRef 要拆的节点;parts: GisViewSplitPointPart[] 至少两份,每份可直接写节点字段或放进 item,并用 lines / channels / channelFrom / channelTo 分配线路与通道端点;options?: GisViewSplitPointOptions:keepSourceId(缺省 true,第一份沿用来源 id)/ label", returns: "GisViewSplitPointOutcome:{ ok, reason, source, items, indexes, pointIds, linesChanged, removedLines, removedLineIds, removedLineIndexes, channelsChanged, removedChannels, removedChannelIds, skipped, changes };changes 可直接作为后端事务输入", doc: "mergePoints 的逆操作:把一个节点拆成两份或更多(第一份接在原下标上、缺省沿用原 id,其余追加到末尾),按每份的 item / 顶层字段生成新节点,按 lines 分配线路、按 channels / channelFrom / channelTo 分配受影响通道的两端。没显式分配的线路跟第一份;没显式分配的通道端点跟它第一条被分配过的成员回线。线路的 from / to 与和来源坐标重合的 start / end / path 顶点改到对应新节点;拆完后的自环 / 零长度线路与两端落到同一份的通道删掉,成员全没了的通道也删掉。整次调用只记一条历史、只发一条 splitPoint 数据变更,返回的 changes 可直接作为后端事务输入;至少两份、坐标必须有效、线路不能重复分配,写错时 ok: false 并在 reason 说明", examples: [{"group":"选中、复制与合并","code":"// splitPoint(source, parts, options?):把一个节点拆成多份(mergePoints 的逆操作)\nconst splitResult = view.splitPoint('a', [\n { x: 0, y: 0, name: '甲站(主)' }, // 第一份沿用原下标 / id\n { x: 80, y: 40, name: '甲站(东)', lines: ['l1'] } // 显式分给第二份;未分配的线路跟第一份\n], { label: '拆分甲站' })\nconsole.log(splitResult.pointIds, splitResult.linesChanged, splitResult.changes)\n","from":"header"}] },
154
158
  { name: "getPointMerge", kind: "method", params: "无(载荷带 impact:lineCount / linesChanged / removedLines / lineIds / removedLineIds 与通道读数,确认前就能估算影响)", returns: "GisViewPointMergePayload | null", doc: "读 / 裁决 / 收尾当前待确认的合并(把一个节点拖到另一个节点上之后):resolvePointMerge(true, { keep, item }) 推进到 confirm 阶段 —— keep 选保留碰撞目标(缺省)还是拖动的来源,item 改写最终节点的信息与样式,位置 / id 始终取保留端;resolvePointMerge(false) 让拖动的节点回原位。pending / confirm / getPointMerge() 的载荷带 impact(受影响线路条数、具体 lineIds 与通道读数;lineCount 按线路去重,linesChanged / removedLines 与落地结果同口径)。自己接管数据落地时用 commitPointMerge() 收状态、revertPointMerge() 还原(silent: true 不补发 cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// getPointMerge() / resolvePointMerge(confirmed?, options?) / commitPointMerge() / revertPointMerge()\nconst pendingMerge = view.getPointMerge() // 待确认的那一份载荷(没有就是 null)\nconsole.log(pendingMerge?.impact?.lineCount) // 这次合并会影响几条线路(改写 + 删除,按线路去重)\nconsole.log(pendingMerge?.impact?.lineIds) // 具体是哪几条(没有 id 时是 lines 下标)\nview.resolvePointMerge(true) // 确认(false = 取消)\nview.resolvePointMerge(true, { keep: 'source', item: { name: '合并结果', size: 18 } })\nview.resolvePointMerge(true, { keep: 'target', item: { color: '#2f6fd0', strokeColor: '#ffffff' } })\nview.resolvePointMerge(false) // 取消(拖动的节点回原位,数据不动)\nview.commitPointMerge() // 自己接管数据时收尾\nview.revertPointMerge() // 反悔(silent: true 时不补发 cancel 载荷)\n","from":"header"}] },
155
159
  { name: "resolvePointMerge", kind: "method", params: "confirmed?: boolean(缺省 true = 确认,false = 取消);options?: GisViewPointMergeConfirmOptions:keep 选 'target'(缺省,保留碰撞目标)/ 'source'(保留拖动的来源),item 是最终节点字段补丁(名称 / 分区 / 颜色 / 尺寸 / 图标 / 描边等;位置与 id 始终取保留端)", returns: "GisViewPointMergePayload | null", doc: "读 / 裁决 / 收尾当前待确认的合并(把一个节点拖到另一个节点上之后):resolvePointMerge(true, { keep, item }) 推进到 confirm 阶段 —— keep 选保留碰撞目标(缺省)还是拖动的来源,item 改写最终节点的信息与样式,位置 / id 始终取保留端;resolvePointMerge(false) 让拖动的节点回原位。pending / confirm / getPointMerge() 的载荷带 impact(受影响线路条数、具体 lineIds 与通道读数;lineCount 按线路去重,linesChanged / removedLines 与落地结果同口径)。自己接管数据落地时用 commitPointMerge() 收状态、revertPointMerge() 还原(silent: true 不补发 cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// getPointMerge() / resolvePointMerge(confirmed?, options?) / commitPointMerge() / revertPointMerge()\nconst pendingMerge = view.getPointMerge() // 待确认的那一份载荷(没有就是 null)\nconsole.log(pendingMerge?.impact?.lineCount) // 这次合并会影响几条线路(改写 + 删除,按线路去重)\nconsole.log(pendingMerge?.impact?.lineIds) // 具体是哪几条(没有 id 时是 lines 下标)\nview.resolvePointMerge(true) // 确认(false = 取消)\nview.resolvePointMerge(true, { keep: 'source', item: { name: '合并结果', size: 18 } })\nview.resolvePointMerge(true, { keep: 'target', item: { color: '#2f6fd0', strokeColor: '#ffffff' } })\nview.resolvePointMerge(false) // 取消(拖动的节点回原位,数据不动)\nview.commitPointMerge() // 自己接管数据时收尾\nview.revertPointMerge() // 反悔(silent: true 时不补发 cancel 载荷)\n","from":"header"}] },
156
- { name: "commitPointMerge", kind: "method", params: "无", returns: "boolean", doc: "读 / 裁决 / 收尾当前待确认的合并(把一个节点拖到另一个节点上之后):resolvePointMerge(true, { keep, item }) 推进到 confirm 阶段 —— keep 选保留碰撞目标(缺省)还是拖动的来源,item 改写最终节点的信息与样式,位置 / id 始终取保留端;resolvePointMerge(false) 让拖动的节点回原位。pending / confirm / getPointMerge() 的载荷带 impact(受影响线路条数、具体 lineIds 与通道读数;lineCount 按线路去重,linesChanged / removedLines 与落地结果同口径)。自己接管数据落地时用 commitPointMerge() 收状态、revertPointMerge() 还原(silent: true 不补发 cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// getPointMerge() / resolvePointMerge(confirmed?, options?) / commitPointMerge() / revertPointMerge()\nconst pendingMerge = view.getPointMerge() // 待确认的那一份载荷(没有就是 null)\nconsole.log(pendingMerge?.impact?.lineCount) // 这次合并会影响几条线路(改写 + 删除,按线路去重)\nconsole.log(pendingMerge?.impact?.lineIds) // 具体是哪几条(没有 id 时是 lines 下标)\nview.resolvePointMerge(true) // 确认(false = 取消)\nview.resolvePointMerge(true, { keep: 'source', item: { name: '合并结果', size: 18 } })\nview.resolvePointMerge(true, { keep: 'target', item: { color: '#2f6fd0', strokeColor: '#ffffff' } })\nview.resolvePointMerge(false) // 取消(拖动的节点回原位,数据不动)\nview.commitPointMerge() // 自己接管数据时收尾\nview.revertPointMerge() // 反悔(silent: true 时不补发 cancel 载荷)\n","from":"header"}] },
157
- { name: "revertPointMerge", kind: "method", params: "options?: { originalEvent?: Event | null; silent?: boolean }:silent: true 时不再补发一条 cancel 载荷", returns: "GisViewPointMergePayload | null", doc: "读 / 裁决 / 收尾当前待确认的合并(把一个节点拖到另一个节点上之后):resolvePointMerge(true, { keep, item }) 推进到 confirm 阶段 —— keep 选保留碰撞目标(缺省)还是拖动的来源,item 改写最终节点的信息与样式,位置 / id 始终取保留端;resolvePointMerge(false) 让拖动的节点回原位。pending / confirm / getPointMerge() 的载荷带 impact(受影响线路条数、具体 lineIds 与通道读数;lineCount 按线路去重,linesChanged / removedLines 与落地结果同口径)。自己接管数据落地时用 commitPointMerge() 收状态、revertPointMerge() 还原(silent: true 不补发 cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// getPointMerge() / resolvePointMerge(confirmed?, options?) / commitPointMerge() / revertPointMerge()\nconst pendingMerge = view.getPointMerge() // 待确认的那一份载荷(没有就是 null)\nconsole.log(pendingMerge?.impact?.lineCount) // 这次合并会影响几条线路(改写 + 删除,按线路去重)\nconsole.log(pendingMerge?.impact?.lineIds) // 具体是哪几条(没有 id 时是 lines 下标)\nview.resolvePointMerge(true) // 确认(false = 取消)\nview.resolvePointMerge(true, { keep: 'source', item: { name: '合并结果', size: 18 } })\nview.resolvePointMerge(true, { keep: 'target', item: { color: '#2f6fd0', strokeColor: '#ffffff' } })\nview.resolvePointMerge(false) // 取消(拖动的节点回原位,数据不动)\nview.commitPointMerge() // 自己接管数据时收尾\nview.revertPointMerge() // 反悔(silent: true 时不补发 cancel 载荷)\n","from":"header"}] },
160
+ { name: "commitPointMerge", kind: "method", params: "无:收掉「已确认、数据已由使用方并好」的合并状态;mergePoints / resolvePointMerge 的正常路径由组件自己调用,只有完全自建合并落地流程时才手动调", returns: "boolean:真的收掉了一个待确认合并为 true,没有可收的状态为 false", doc: "读 / 裁决 / 收尾当前待确认的合并(把一个节点拖到另一个节点上之后):resolvePointMerge(true, { keep, item }) 推进到 confirm 阶段 —— keep 选保留碰撞目标(缺省)还是拖动的来源,item 改写最终节点的信息与样式,位置 / id 始终取保留端;resolvePointMerge(false) 让拖动的节点回原位。pending / confirm / getPointMerge() 的载荷带 impact(受影响线路条数、具体 lineIds 与通道读数;lineCount 按线路去重,linesChanged / removedLines 与落地结果同口径)。自己接管数据落地时用 commitPointMerge() 收状态、revertPointMerge() 还原(silent: true 不补发 cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// getPointMerge() / resolvePointMerge(confirmed?, options?) / commitPointMerge() / revertPointMerge()\nconst pendingMerge = view.getPointMerge() // 待确认的那一份载荷(没有就是 null)\nconsole.log(pendingMerge?.impact?.lineCount) // 这次合并会影响几条线路(改写 + 删除,按线路去重)\nconsole.log(pendingMerge?.impact?.lineIds) // 具体是哪几条(没有 id 时是 lines 下标)\nview.resolvePointMerge(true) // 确认(false = 取消)\nview.resolvePointMerge(true, { keep: 'source', item: { name: '合并结果', size: 18 } })\nview.resolvePointMerge(true, { keep: 'target', item: { color: '#2f6fd0', strokeColor: '#ffffff' } })\nview.resolvePointMerge(false) // 取消(拖动的节点回原位,数据不动)\nview.commitPointMerge() // 自己接管数据时收尾\nview.revertPointMerge() // 反悔(silent: true 时不补发 cancel 载荷)\n","from":"header"}] },
161
+ { name: "revertPointMerge", kind: "method", params: "options?: { originalEvent?: Event | null; silent?: boolean }:把拖动的来源节点还原回原位并收掉合并状态;silent: true 时不补发 cancel 载荷", returns: "GisViewPointMergePayload | null:回退载荷;没有待回退的合并时为 null", doc: "读 / 裁决 / 收尾当前待确认的合并(把一个节点拖到另一个节点上之后):resolvePointMerge(true, { keep, item }) 推进到 confirm 阶段 —— keep 选保留碰撞目标(缺省)还是拖动的来源,item 改写最终节点的信息与样式,位置 / id 始终取保留端;resolvePointMerge(false) 让拖动的节点回原位。pending / confirm / getPointMerge() 的载荷带 impact(受影响线路条数、具体 lineIds 与通道读数;lineCount 按线路去重,linesChanged / removedLines 与落地结果同口径)。自己接管数据落地时用 commitPointMerge() 收状态、revertPointMerge() 还原(silent: true 不补发 cancel 载荷)", examples: [{"group":"选中、复制与合并","code":"// getPointMerge() / resolvePointMerge(confirmed?, options?) / commitPointMerge() / revertPointMerge()\nconst pendingMerge = view.getPointMerge() // 待确认的那一份载荷(没有就是 null)\nconsole.log(pendingMerge?.impact?.lineCount) // 这次合并会影响几条线路(改写 + 删除,按线路去重)\nconsole.log(pendingMerge?.impact?.lineIds) // 具体是哪几条(没有 id 时是 lines 下标)\nview.resolvePointMerge(true) // 确认(false = 取消)\nview.resolvePointMerge(true, { keep: 'source', item: { name: '合并结果', size: 18 } })\nview.resolvePointMerge(true, { keep: 'target', item: { color: '#2f6fd0', strokeColor: '#ffffff' } })\nview.resolvePointMerge(false) // 取消(拖动的节点回原位,数据不动)\nview.commitPointMerge() // 自己接管数据时收尾\nview.revertPointMerge() // 反悔(silent: true 时不补发 cancel 载荷)\n","from":"header"}] },
158
162
  { name: "removePoints", kind: "method", params: "refs: | GisViewFeatureRef | 数组 | 'all' | 'selection' | 'visible' 要删哪些节点;options?: { reason?: string } 记进事件载荷的删除原因", returns: "GisViewRemovePointsOutcome", doc: "移除节点(接口调用):'a' / { index: 2 } / 数组都收,绑在它上面的线路一并删掉、声明了它当端点的整条通道(含成员回线)跟着删,返回 { ok, indexes, items, removedLines, removedChannels }", examples: [{"group":"选中、复制与合并","code":"// removePoints(refs, options?):删节点 —— 一个、多个、按条件都认(绑在它上面的线路 / 通道一起删)\nview.removePoints('a') // 一个(id)\nview.removePoints(['a', 'b']) // 多个(id 数组)\nview.removePoints({ index: 2 }) // 按下标\nview.removePoints([{ id: 'a' }, { index: 1 }]) // 混合一批\nview.removePoints('selection') // 删选中的\nview.removePoints('visible') // 删当前可见的\nview.removePoints('all') // 全删\nview.removePoints('a', { reason: '误建' }) // 原因会带进数据变更载荷\n","from":"header"}] },
159
- { name: "removeSelected", kind: "method", params: "options?: { reason?: string } 同上", returns: "GisViewRemoveSelectedOutcome", doc: "移除当前选中的那一批(工具栏「删除选中」同一条路):选中的节点连同绑在它们身上的线路一起删、剩下的选中回线也删掉,删完清空选中;返回 { ok, reason, pointIndexes, lineIndexes, pointIds, lineIds, points, lines, removedChannels }(lineIds 里也含「因为节点被删而连带走掉」的线路),没有选中东西时 ok: false 并带回原因。一次调用只落一条历史、只发一条 removeSelected 数据变更", examples: [{"group":"选中、复制与合并","code":"// removeSelected(options?):删「当前选中的东西」(节点 / 线路 / 拐点按各自口径)\nview.removeSelected()\nview.removeSelected({ reason: '按 Delete 确认' })\n","from":"header"}] },
160
- { name: "requestRemove", kind: "method", params: "options?: { originalEvent?: Event | null } 原样带进载荷(键盘触发时是那一次 keydown)", returns: "GisViewRemoveOutcome", doc: "发起一次删除(Delete 键同一条路):把选中的拐点 / 线路 / 节点与它们的连带影响摊成一份载荷交给 onRemove / 'remove',停在 pending 等裁决(确认方式见 remove.confirm),没有可删的东西时返回 { phase: 'empty', ok: false, reason },见「删除(remove)」", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 发一条 phase: 'pending' 的 onRemove 载荷\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels'\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动)","from":"header"}] },
161
- { name: "getRemoveRequest", kind: "method", params: "无", returns: "GisViewRemovePayload | null", doc: "当前待确认的删除请求(没有就返回 null):面板自己弹确认框时拿它渲染", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 发一条 phase: 'pending' 的 onRemove 载荷\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels'\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动)","from":"header"}] },
162
- { name: "resolveRemove", kind: "method", params: "scope?: GisViewRemoveScope 删除范围(缺省用载荷里的 scope)", returns: "GisViewRemoveResult | null", doc: "确认这次删除:scope 为 'lines' / 'groups' / 'channels'(缺省用载荷里的 scope),返回删除结果;没有待确认的请求时返回 null", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 发一条 phase: 'pending' 的 onRemove 载荷\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels'\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动)","from":"header"}] },
163
- { name: "cancelRemove", kind: "method", params: "无", returns: "GisViewRemovePayload | null", doc: "取消这次删除(与 Esc 同一条路):数据一个字节都不动,返回取消掉的那份载荷(invalidated: true 表示请求因为数据变过而作废)", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 发一条 phase: 'pending' 的 onRemove 载荷\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels'\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动)","from":"header"}] },
163
+ { name: "removeSelected", kind: "method", params: "options?: { reason?: string } 记进删除载荷:直接删当前选中集(节点连带线路 / 空掉的通道,拐点先删),删完清空选中;整次调用只落一条历史、只发一条 removeSelected 数据变更", returns: "GisViewRemoveSelectedOutcome:{ ok, reason?, pointIndexes, lineIndexes, pointIds, lineIds, points, lines, removedChannels };没有选中可删时为 ok: false", doc: "移除当前选中的那一批(工具栏「删除选中」同一条路):选中的节点连同绑在它们身上的线路一起删、剩下的选中回线也删掉,删完清空选中;返回 { ok, reason, pointIndexes, lineIndexes, pointIds, lineIds, points, lines, removedChannels }(lineIds 里也含「因为节点被删而连带走掉」的线路),没有选中东西时 ok: false 并带回原因。一次调用只落一条历史、只发一条 removeSelected 数据变更", examples: [{"group":"选中、复制与合并","code":"// removeSelected(options?):删「当前选中的东西」(节点 / 线路 / 拐点按各自口径)\nconst removed = view.removeSelected() // 返回 pointIds / lineIds / removedChannels 等;删完清空选中\nview.removeSelected({ reason: '按 Delete 确认' }) // 整次只记一条历史、只发一条 removeSelected 数据变更\n","from":"header"}] },
164
+ { name: "requestRemove", kind: "method", params: "options?: { originalEvent?: Event | null } 原样带进载荷(键盘触发时是那一次 keydown):只生成待确认载荷,数据不动;remove.confirm 为 false 时当场删,为函数时按返回值 / Promise 裁决,不写就停在 pending", returns: "GisViewRemoveOutcome:phase: 'pending' | 'remove' | 'cancel' 的载荷,或没有可删要素时的 phase: 'empty' 失败读数", doc: "发起一次删除(Delete 键同一条路):把选中的拐点 / 线路 / 节点与它们的连带影响摊成一份载荷交给 onRemove / 'remove',停在 pending 等裁决(确认方式见 remove.confirm),没有可删的东西时返回 { phase: 'empty', ok: false, reason },见「删除(remove)」", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 只生成 phase: 'pending' 的载荷,数据不动\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels';无请求时返回 null\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动;无请求时返回 null)","from":"header"}] },
165
+ { name: "getRemoveRequest", kind: "method", params: "无:读当前待确认的删除请求,供自建确认框渲染", returns: "GisViewRemovePayload | null:没有待确认请求时为 null", doc: "当前待确认的删除请求(没有就返回 null):面板自己弹确认框时拿它渲染", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 只生成 phase: 'pending' 的载荷,数据不动\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels';无请求时返回 null\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动;无请求时返回 null)","from":"header"}] },
166
+ { name: "resolveRemove", kind: "method", params: "scope?: GisViewRemoveScope 删除范围(缺省用载荷里的 scope;可选 'lines' / 'groups' / 'channels')", returns: "GisViewRemoveResult | null:删除结果;没有待确认请求或请求已裁决时为 null", doc: "确认这次删除:scope 为 'lines' / 'groups' / 'channels'(缺省用载荷里的 scope),返回删除结果;没有待确认的请求时返回 null", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 只生成 phase: 'pending' 的载荷,数据不动\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels';无请求时返回 null\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动;无请求时返回 null)","from":"header"}] },
167
+ { name: "cancelRemove", kind: "method", params: "无:取消待确认删除,数据不动并补 cancel 载荷", returns: "GisViewRemovePayload | null:取消载荷;没有待确认请求时为 null", doc: "取消这次删除(与 Esc 同一条路):数据一个字节都不动,返回取消掉的那份载荷(invalidated: true 表示请求因为数据变过而作废)", examples: [{"group":"选中、复制与合并","code":"// requestRemove(options?) / getRemoveRequest() / resolveRemove(scope?) / cancelRemove():先出载荷、再裁决\nconst removePayload = view.requestRemove() // 只生成 phase: 'pending' 的载荷,数据不动\nconst pendingRemove = view.getRemoveRequest() // 从外面拿这一份(没有就是 null)\nview.resolveRemove('channels') // 按范围确认:'lines' / 'groups' / 'channels';无请求时返回 null\nview.resolveRemove() // 按载荷里的 scope 确认\nview.cancelRemove() // 取消(数据一个字节都不动;无请求时返回 null)","from":"header"}] },
164
168
  ]
165
169
  },
166
170
  {
@@ -189,13 +193,13 @@ export const API_SECTIONS = [
189
193
  { name: "addChannelGroupWaypoint", kind: "method", params: "channelId 通道 id;groupId 分组 id;coordinate 新拐点世界坐标", returns: "this", doc: "给某个分组加拐点、把这一组单独拉走:不给坐标就按默认位置放一个(第 n 组沿法线往外让 n 档),其余分组一根拐点都不动,见「分组拐点」", examples: [{"group":"拐点与通道","code":"// addChannelGroupWaypoint(channelId, groupId, coordinate) / removeChannelGroupWaypoint(channelId, groupId, pathIndex)\nview.addChannelGroupWaypoint('c1', 'c1::2', [200, 120])\nview.removeChannelGroupWaypoint('c1', 'c1::2', 1)\n","from":"header"}] },
190
194
  { name: "removeChannelGroupWaypoint", kind: "method", params: "channelId / groupId / pathIndex 要删的骨架顶点下标", returns: "this", doc: "删掉某个分组的拐点(缺省删最后一个)", examples: [{"group":"拐点与通道","code":"// addChannelGroupWaypoint(channelId, groupId, coordinate) / removeChannelGroupWaypoint(channelId, groupId, pathIndex)\nview.addChannelGroupWaypoint('c1', 'c1::2', [200, 120])\nview.removeChannelGroupWaypoint('c1', 'c1::2', 1)\n","from":"header"}] },
191
195
  { name: "runChannelAction", kind: "method", params: "actionId: GisViewChannelActionId 动作名('select-group' / 'deselect-group' / 'add-waypoint' / 'remove-waypoint' / 'split' / 'merge',见 getChannelContext().actions);options?: GisViewChannelActionOptions 动作自己的参数(groupId / lineId / coordinate…)", returns: "GisViewChannelContext | null", doc: "执行右键交互框里的动作:select-group / deselect-group / add-waypoint / remove-waypoint / split / merge(options 带 channelId / groupId / coordinate / pathIndex / size),返回执行之后的上下文", examples: [{"group":"拐点与通道","code":"// setCurrentChannelGroup(channelId, groupId) / runChannelAction(actionId, options?):当前分组与动作\nview.setCurrentChannelGroup('c1', 'c1::2')\nview.setCurrentChannelGroup('c1', null) // 不选中\nview.runChannelAction('select-group', { groupId: 'c1::2' })\nview.runChannelAction('split', { lineId: 'l2' })\n","from":"header"}] },
192
- { name: "beginAddChannel", kind: "method", params: "options?: GisViewChannelDraftOptions 草稿配置:kind / circuits / autoCommit / continuous / chain / name / lineId / lineProps / linePropsByMember / lineItems(第二段)/ routing / path(中间拐点)/ channelProps / channelDraftStyle(本次草稿的预览样式)/ handoff(交接模式)/ select(点中的节点顺手选中,走 onSelect 那一套)", returns: "this(只负责那条示例假通道,真正新增走 addChannel)", doc: "进入「新增通道」:点第一个节点当起点,一条线跟随光标,点第二个节点出方案;options 支持 kind('channel' 新建通道 / 'line' 新建独立线路,缺省 'channel')/ circuits(一次加几条,缺省 1)/ autoCommit / continuous / chain / name / lineId / lineProps / lineItems(第二段,连同线路一起新建)/ routing('straight' / 'orthogonal')/ path(中间拐点)/ channelProps / channelDraftStyle(本次草稿的预览样式)/ handoff(交接模式:ready 发完收起草稿,自己调 addChannel 落地)/ select(点中的节点顺手选中),见「新增通道」", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
193
- { name: "getAddChannelDraft", kind: "method", params: "无", returns: "GisViewChannelDraftPayload | null", doc: "当前新增通道草稿(两个节点的信息与可选方案),没有草稿时为 null", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
194
- { name: "updateAddChannelStyle", kind: "method", params: "patch?: GisViewChannelDraftStyle | null 字段级合并的预览样式(箭头位置 / 多回线间距 / 自绘等);传 null 回到全局 channelDraftStyle", returns: "this", doc: "字段级合并当前草稿的预览样式(color / width / dot / dotColor / arrow / arrowSize / arrowPositions / arrowReverse / arrowColor / circuitSpacing / opacity / customDraw);传 null 回到全局 channelDraftStyle,没有草稿时什么也不做", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
195
- { name: "continueAddChannel", kind: "method", params: "options?: GisViewChannelDraftOptions 开下一段草稿(写法与 beginAddChannel 一致,不传就沿用这一段原来的)", returns: "this", doc: "开下一段草稿:连续模式落地时内部自动调(发 phase: 'restart'),也可以手动调;草稿已经退出时按 options 重新进来", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
196
- { name: "cancelAddChannel", kind: "method", params: "无", returns: "this(收掉草稿并补一条 phase: 'cancel')", doc: "取消新增通道(草稿期间按 Esc 等价,会补一条 phase: 'cancel')", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
197
- { name: "endAddChannel", kind: "method", params: "无", returns: "this(静默收掉视图上的示例假通道 / 线路,数据不动、不补事件)", doc: "结束新增通道:静默收掉视图上的示例假通道 / 线路(不补 cancel 事件),数据一个字节都不改 —— 结束事件里决定「不新建了」就用它", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
198
- { name: "commitAddChannel", kind: "method", params: "resolution?: GisViewChannelAddResolution 落地方式('channel' / 'line',缺省看草稿);options?: GisViewChannelAddInput 要覆盖的字段(name / circuits / colors / lineWidth / routing / path…)", returns: "GisViewChannelAddResult", doc: "", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
196
+ { name: "beginAddChannel", kind: "method", params: "options?: GisViewChannelDraftOptions 草稿配置:from(预指定起点,下一步只选终点)/ kind / circuits / autoCommit / continuous / chain / name / lineId / id / lineProps / linePropsByMember / lineItems(第二段)/ routing / path(中间拐点)/ channelProps / channelDraftStyle(本次草稿的预览样式)/ handoff(交接模式)/ select(点中的节点顺手选中,走 onSelect 那一套)/ originalEvent", returns: "this(只负责那条示例假通道,真正新增走 addChannel)", doc: "进入「新增通道」:缺省点两个节点选起点 / 终点,或由 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,见「新增通道」", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nview.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
197
+ { name: "getAddChannelDraft", kind: "method", params: "无", returns: "GisViewChannelDraftPayload | null", doc: "当前新增通道草稿(两个节点的信息与可选方案),没有草稿时为 null", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nview.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
198
+ { name: "updateAddChannelStyle", kind: "method", params: "patch?: GisViewChannelDraftStyle | null 字段级合并的预览样式(箭头位置 / 多回线间距 / 自绘等);传 null 回到全局 channelDraftStyle", returns: "this", doc: "字段级合并当前草稿的预览样式(color / width / dot / dotColor / arrow / arrowSize / arrowPositions / arrowReverse / arrowColor / circuitSpacing / opacity / customDraw);传 null 回到全局 channelDraftStyle,没有草稿时什么也不做", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nview.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
199
+ { name: "continueAddChannel", kind: "method", params: "options?: GisViewChannelDraftOptions 开下一段草稿(写法与 beginAddChannel 一致,不传就沿用这一段原来的)", returns: "this", doc: "开下一段草稿:连续模式落地时内部自动调(发 phase: 'restart'),也可以手动调;草稿已经退出时按 options 重新进来", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nview.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
200
+ { name: "cancelAddChannel", kind: "method", params: "无", returns: "this(收掉草稿并补一条 phase: 'cancel')", doc: "取消新增通道(草稿期间按 Esc 等价,会补一条 phase: 'cancel')", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nview.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
201
+ { name: "endAddChannel", kind: "method", params: "无", returns: "this(静默收掉视图上的示例假通道 / 线路,数据不动、不补事件)", doc: "结束新增通道:静默收掉视图上的示例假通道 / 线路(不补 cancel 事件),数据一个字节都不改 —— 结束事件里决定「不新建了」就用它", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nview.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
202
+ { name: "commitAddChannel", kind: "method", params: "resolution?: GisViewChannelAddResolution 落地方式('channel' / 'line',缺省看草稿);options?: GisViewChannelAddInput 要覆盖的字段(name / circuits / colors / lineWidth / routing / path…)", returns: "GisViewChannelAddResult", doc: "", examples: [{"group":"拐点与通道","code":"// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?) / commitAddChannel(resolution?) / cancelAddChannel() / endAddChannel()\nview.beginAddChannel({\n kind: 'channel',\n circuits: 3,\n channelDraftStyle: {\n color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],\n circuitSpacing: 12, opacity: 0.9\n }\n}) // 点两个节点:第一个起点、第二个终点;通道 3 回时预览也画 3 条平行回线\nview.beginAddChannel({ from: 'station-a' }) // 预指定起点:接下来只点终点\nconst draft = view.getAddChannelDraft() // 草稿读数(跟随光标的预览、两个节点、方案表与实际 style)\nview.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头\nview.updateAddChannelStyle(null) // 回到全局 channelDraftStyle\nview.commitAddChannel() // 两个节点选完后落地(resolution 缺省用推荐方案)\nview.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2' }) // 指定方案\nview.continueAddChannel({ kind: 'line' }) // 连续模式下开下一段(也能换这一段加什么)\nview.cancelAddChannel() // 取消(Esc / 右键等价)\n","from":"header"}] },
199
203
  { name: "getChannelAddOptions", kind: "method", params: "from / to 两端节点 id;count?: number 回数(缺省 1);kind?: 'channel' | 'line'(缺省 'channel')", returns: "GisViewChannelAddPlan | null", doc: "两个节点之间的新增方案:新通道 / 新分组 / 并进某一组 / 无法添加;count 是这一次要加的回数(余量按它判),kind: 'line' 时方案表为空(独立线路不挑方案)", examples: [{"group":"拐点与通道","code":"// getChannelAddOptions(from, to, count?, kind?):两个节点之间能怎么加(界面拿它让用户选)\nconst plan = view.getChannelAddOptions('a', 'b', 2)\nconst linePlan = view.getChannelAddOptions('a', 'b', 1, 'line')\n","from":"header"}] },
200
204
  { name: "getChannelBetween", kind: "method", params: "from / to 两端节点 id", returns: "GisViewChannelBetween | null", doc: "两个节点之间的通道读数(只读):有通道时 hasChannel: true,channelId / channelIndex / groupCount / currentGroupId 与 groups / group / channel(id / name / lineIds / 分组明细)都给全;没有通道时 hasChannel: false、channel: null、groups: [],端点认不出来返回 null —— 与 getChannelAddOptions 的读数同一份,界面做「这两个点之间已经有通道 / 有几组」的判断用它,不必算方案表", examples: [{"group":"拐点与通道","code":"// getChannelBetween(from, to):只要通道读数 —— 有没有通道 / 几组 / 当前哪组(不做方案判断,端点认不出返回 null)\nconst between = view.getChannelBetween('a', 'b')\nif (between?.hasChannel) {\n console.log(between.channelId, between.groupCount, between.groups.map(group => group.id), between.currentGroupId)\n}\n","from":"header"}] },
201
205
  { name: "addChannel", kind: "method", params: "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 是中间拐点,独立线路落地成完整折线、通道只写骨架拐点", returns: "GisViewChannelAddResult(channelLineIds 是落地后通道的完整成员表,独立线路为 null)", doc: "程序化新增通道(新签名,只新建):第一段通道信息(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 给了几条就建几条", examples: [{"group":"拐点与通道","code":"// addChannel(spec, lineData?, group?) / addChannels(input, options?) / addChannelGroups(channelId, groups, options?) / addLine(input):程序化新增\nconst channelAdd = view.addChannel({ from: 'a', to: 'b', name: '二号通道', path: [[200, 120]] }, [{ id: 'm-1' }, { id: 'm-2' }])\nconst manyChannels = view.addChannels([{ from: 'a', to: 'b', circuits: 1 }, { from: 'b', to: 'a', circuits: 2, kind: 'line' }])\nconst manyGroups = view.addChannelGroups('c1', [\n { id: 'c1::4', path: [[130, 70]], lineData: [{ id: 'm-7' }, { id: 'm-8' }] },\n { path: [[150, 90]], lines: ['m-9'] }\n])\nconsole.log(manyGroups.count, manyGroups.lineIds, manyGroups.groupIds)\nconst lineAdd = view.addLine({ from: 'a', to: 'b', name: '三回' })","from":"header"}] },
@@ -287,31 +291,34 @@ export const API_SECTIONS = [
287
291
  title: "导出",
288
292
  items: [
289
293
  { name: "exportData", kind: "method", params: "options: GisViewExportDataOptions:scope('all' 缺省 / 'viewport' / 'selection',也认 visible / view / selected)、format('view' 缺省 / 'input' / 'new' / 'test' / 'full')、parts(只导 points / lines / channels / parallelGroups 里的哪几份)、points / lines / channels(只导指定要素)、withLines: false(selection 不要两端都在集合里的线路)、labels、extra。format: 'full' / 'input' 返回可直接回灌的数据,不夹带 scope / counts 读数", returns: "GisViewExportDataResult | GisViewDocument(format: 'full')", doc: "统一导出入口:scope 选范围('all' 缺省 / 'viewport' / 'selection',也认 visible / view / selected),parts 选分项,format 选口径。format: 'view'(缺省)给 { points, lines, channels, parallelGroups }、'new' 给 new.json 口径、'test' 给 test.json 口径、'input' 给与 createGisView 入参同构的回灌口径、'full' 给标准文档;format 也可以是注册过的自定义名字。points / lines / channels 可以只要一部分,解不出的引用进 warnings,format 写错(或没注册)抛异常,见「导出数据」与「自定义导出格式」", examples: [{"group":"导出","code":"// exportData(options?):统一入口 —— scope 选范围(all / viewport / selection),parts 选分项,format 选口径\nconst viewFormat = view.exportData() // 全量 + view 口径(缺省)\nconst inViewport = view.exportData({ scope: 'viewport', margin: 24 }) // 视口内,可外扩 24 屏幕像素\nconst picked = view.exportData({ scope: 'selection', parts: ['station', 'channel'], withLines: true })\nconst fullDoc = view.exportData({ format: 'full' }) // 标准数据文档:整份喂回 createGisView / importData 就回到这一屏\nconst testFormat = view.exportData({ format: 'test', parts: ['line', 'waypoint'] })\nconst onlyPoints = view.exportData({ points: ['a', 'b'], labels: false, extra: { exported_at: Date.now() } })\n","from":"header"},{"group":"导出","code":"// exportSelection(options?) / exportData({ scope: 'selection' }):导出选中的那几个\nconst exportedSelection = await view.exportSelection({ withLines: true, scale: 2 })\nview.exportSelection({ points: ['a', 1], format: 'data', withLines: false })\nconst selectionData = view.exportData({ scope: 'selection', parts: ['station', 'channel'] })","from":"header"}] },
290
- { name: "exportImage", kind: "method", params: "options?: GisViewExportImageOptions:type('image/png' / 'image/jpeg')、quality(JPEG 0 ~ 1)、scale(导出倍数)、background(底色)、transparent", returns: "Promise<string>", doc: "导出当前画面(含标签)为图片,返回 data URL,见「导出图片」", examples: [{"group":"导出","code":"// exportImage(options?):导出图片(Promise<dataURL>;type: 'svg' 走矢量导出)\nconst imageUrl = await view.exportImage({ scale: 2, background: '#ffffff' })\nawait view.exportImage({ type: 'image/jpeg', quality: 0.9, download: '场景.jpg' }) // 也可以直接下载\n","from":"header"}] },
294
+ { name: "exportImage", kind: "method", params: "options?: GisViewExportImageOptions:type('image/png' / 'image/jpeg' / 'image/webp' / 'svg')、quality(JPEG / WebP 0 ~ 1)、scale(导出倍数;SVG 只影响宽高)、scope('viewport' 缺省 / 'all' 全部内容)、padding(scope: 'all' 的留白,缺省 24)、background(缺省带背景 / false 或 'none' 透明 / 颜色字符串换底色)、includeLabels(缺省 true)、download(true 或文件名)", returns: "Promise<string>(data URL)", doc: "导出当前画面(含标签)为图片,返回 data URL;scope: 'viewport'(缺省)导当前视口、'all' 临时适应全部可见内容,另有 padding / type / quality / scale / background / includeLabels / download,见「导出图片」", examples: [{"group":"导出","code":"// exportImage(options?):导出图片(Promise<dataURL>;type: 'svg' 走矢量导出)\nconst imageUrl = await view.exportImage({ scale: 2, background: '#ffffff' })\nawait view.exportImage({ type: 'image/jpeg', quality: 0.9, download: '场景.jpg' }) // 也可以直接下载\nawait view.exportImage({ scope: 'all', padding: 24, includeLabels: false }) // 全部内容(导完恢复相机)\n","from":"header"}] },
291
295
  { name: "exportSelection", kind: "method", params: "options?: GisViewExportSelectionOptions:format / type / quality / scale / padding(只导选中要素那一块)", returns: "Promise<GisViewExportSelectionResult>", doc: "把选中的节点(可选带上两端都在集合里的线路)单独导成图片 / 数据:points 不给就用选中集,withLines / format / padding 见「导出选中的节点」;返回 { ok, reason, points, lines, counts, box, pointIndexes, lineIndexes, image },出图时临时藏起别的要素与相机、出完还原", examples: [{"group":"导出","code":"// exportSelection(options?) / exportData({ scope: 'selection' }):导出选中的那几个\nconst exportedSelection = await view.exportSelection({ withLines: true, scale: 2 })\nview.exportSelection({ points: ['a', 1], format: 'data', withLines: false })\nconst selectionData = view.exportData({ scope: 'selection', parts: ['station', 'channel'] })","from":"header"}] },
292
296
  ]
293
297
  },
294
298
  {
295
299
  title: "筛选",
296
300
  items: [
297
- { name: "setFilter", kind: "method", params: "filter: GisViewFilterInput | null 筛选条件:完整格式 { points, lines, cascade, worker };只筛节点时可以简写成节点条件本身;传 null 等于清空", returns: "this", doc: "设置或清空筛选条件(传 null 清空):完整格式 { points, lines, cascade, worker },只筛节点时可以简写成节点条件本身;见「筛选」", examples: [{"group":"筛选","code":"// setFilter(filter):设筛选条件(只筛节点可以写简写);传 null 等于清空\nview.setFilter({ vn_kv: { gte: 525 } })\nview.setFilter({ points: { station_type: 'coal' }, lines: { vn_kv: { gte: 525 } }, cascade: 'binding' })\nview.setFilter(null)\n","from":"header"}] },
298
- { name: "getFilter", kind: "method", params: "无", returns: "GisViewFilter | null", doc: "当前条件与最近一次结果:隐藏的点 / 线下标、可见数量、是否用了 Worker、耗时", examples: [{"group":"筛选","code":"// getFilter() / getFilterResult():当前条件(副本)/ 最近一次结果\nview.setFilter(null)\nconst filter = view.getFilter()\nconst filterResult = view.getFilterResult() // { hiddenPoints, hiddenLines, visiblePoints, visibleLines, worker, durationMs }","from":"header"}] },
299
- { name: "getFilterResult", kind: "method", params: "无", returns: "GisViewFilterResult | null", doc: "当前条件与最近一次结果:隐藏的点 / 线下标、可见数量、是否用了 Worker、耗时", examples: [{"group":"筛选","code":"// getFilter() / getFilterResult():当前条件(副本)/ 最近一次结果\nview.setFilter(null)\nconst filter = view.getFilter()\nconst filterResult = view.getFilterResult() // { hiddenPoints, hiddenLines, visiblePoints, visibleLines, worker, durationMs }","from":"header"}] },
301
+ { name: "setFilter", kind: "method", params: "filter: GisViewFilterInput | null 筛选条件:完整格式 { points, lines, cascade, mode, worker };只筛节点时可以简写成节点条件本身;传 null 等于清空。mode: 'hide'(缺省)只隐藏、不删数据、不清空选中集;mode: 'remove' 删除筛选结果,只发一条 filterRemove 与最终一条 onFilter", returns: "this", doc: "设置或清空筛选条件(传 null 清空):完整格式 { points, lines, cascade, mode, worker },只筛节点时可以简写成节点条件本身。mode: 'hide'(缺省)只隐藏、不删数据、也不清空选中集;mode: 'remove' 把筛选结果从数据里删掉,只发一条 filterRemove 数据变更与最终一条 onFilter,见「筛选」", examples: [{"group":"筛选","code":"// setFilter(filter):设筛选条件(只筛节点可以写简写);传 null 等于清空;默认只隐藏\nview.setFilter({ vn_kv: { gte: 525 } })\nview.setFilter({ points: { station_type: 'coal' }, lines: { vn_kv: { gte: 525 } }, cascade: 'binding' })\nview.setFilter(null)\n","from":"header"}] },
302
+ { name: "getFilter", kind: "method", params: "无", returns: "GisViewFilter | null", doc: "当前条件与最近一次结果:隐藏的点 / 线下标、可见数量、是否用了 Worker、耗时", examples: [{"group":"筛选","code":"// getFilter() / getFilterResult():当前条件(副本)/ 最近一次结果\nview.setFilter(null)\nconst filter = view.getFilter()\nconst filterResult = view.getFilterResult() // hide 模式是隐藏下标;remove 完成后 hidden 为空","from":"header"}] },
303
+ { name: "getFilterResult", kind: "method", params: "无", returns: "GisViewFilterResult | null", doc: "当前条件与最近一次结果:隐藏的点 / 线下标、可见数量、是否用了 Worker、耗时", examples: [{"group":"筛选","code":"// getFilter() / getFilterResult():当前条件(副本)/ 最近一次结果\nview.setFilter(null)\nconst filter = view.getFilter()\nconst filterResult = view.getFilterResult() // hide 模式是隐藏下标;remove 完成后 hidden 为空","from":"header"}] },
300
304
  ]
301
305
  },
302
306
  {
303
307
  title: "事件、开关与历史",
304
308
  items: [
305
309
  { name: "on", kind: "method", params: "name: GisViewEventName | '*' 事件名('dataChange' / 'labelClick'… 或 '*' 订阅全部);handler: (payload, name?) => void 回调,载荷字段见「事件」一节的表", returns: "() => void 取消订阅", doc: "订阅事件(与 options 里的回调同一条,可以挂多条):返回取消订阅的函数;'*' 订阅全部事件,回调拿到 (载荷, 事件名),见「事件订阅」", examples: [{"group":"事件、开关与历史","code":"// on(name, handler) / once(name, handler) / off(name, handler?):订阅('*' 订阅全部)\nconst offData = view.on('dataChange', payload => sync(payload))\nview.on('*', (payload, name) => log(name, payload))\nview.once('dataRendered', payload => { loading = false })\nview.off('dataChange') // 摘掉这个事件的全部回调\nview.off('dataChange', sync) // 只摘掉这一个(返回摘掉几条)\n","from":"header"}] },
306
- { name: "once", kind: "method", params: "同上,只触发一次(回调跑完自动摘掉)", returns: "() => void 取消订阅", doc: "订阅事件(与 options 里的回调同一条,可以挂多条):返回取消订阅的函数;'*' 订阅全部事件,回调拿到 (载荷, 事件名),见「事件订阅」", examples: [{"group":"事件、开关与历史","code":"// on(name, handler) / once(name, handler) / off(name, handler?):订阅('*' 订阅全部)\nconst offData = view.on('dataChange', payload => sync(payload))\nview.on('*', (payload, name) => log(name, payload))\nview.once('dataRendered', payload => { loading = false })\nview.off('dataChange') // 摘掉这个事件的全部回调\nview.off('dataChange', sync) // 只摘掉这一个(返回摘掉几条)\n","from":"header"}] },
307
- { name: "off", kind: "method", params: "name 事件名;handler? 只摘掉这一个回调(不传 = 摘掉这个事件的全部)", returns: "number 摘掉几条", doc: "取消订阅:不传 handler 就摘掉这个事件的全部订阅,返回摘掉几条", examples: [{"group":"事件、开关与历史","code":"// on(name, handler) / once(name, handler) / off(name, handler?):订阅('*' 订阅全部)\nconst offData = view.on('dataChange', payload => sync(payload))\nview.on('*', (payload, name) => log(name, payload))\nview.once('dataRendered', payload => { loading = false })\nview.off('dataChange') // 摘掉这个事件的全部回调\nview.off('dataChange', sync) // 只摘掉这一个(返回摘掉几条)\n","from":"header"}] },
310
+ { name: "once", kind: "method", params: "与 on 同一套事件名与载荷;只触发一次,回调跑完自动摘掉。返回的取消函数可提前撤销;即使提前取消,重复调用也安全", returns: "() => void 取消订阅", doc: "订阅事件(与 options 里的回调同一条,可以挂多条):返回取消订阅的函数;'*' 订阅全部事件,回调拿到 (载荷, 事件名),见「事件订阅」", examples: [{"group":"事件、开关与历史","code":"// on(name, handler) / once(name, handler) / off(name, handler?):订阅('*' 订阅全部)\nconst offData = view.on('dataChange', payload => sync(payload))\nview.on('*', (payload, name) => log(name, payload))\nview.once('dataRendered', payload => { loading = false })\nview.off('dataChange') // 摘掉这个事件的全部回调\nview.off('dataChange', sync) // 只摘掉这一个(返回摘掉几条)\n","from":"header"}] },
311
+ { name: "off", kind: "method", params: "name 事件名(也认 '*');handler? 只摘掉这一个回调,不传 = 摘掉这个事件的全部订阅", returns: "number 摘掉几条(没摘到返回 0)", doc: "取消订阅:不传 handler 就摘掉这个事件的全部订阅,返回摘掉几条", examples: [{"group":"事件、开关与历史","code":"// on(name, handler) / once(name, handler) / off(name, handler?):订阅('*' 订阅全部)\nconst offData = view.on('dataChange', payload => sync(payload))\nview.on('*', (payload, name) => log(name, payload))\nview.once('dataRendered', payload => { loading = false })\nview.off('dataChange') // 摘掉这个事件的全部回调\nview.off('dataChange', sync) // 只摘掉这一个(返回摘掉几条)\n","from":"header"}] },
308
312
  { name: "use", kind: "method", params: "plugin: GisViewPlugin((view, context) => hook,与 options.plugins 的写法一致):立即执行一次,返回卸载函数 —— 调它跑插件自己的 destroy(重复调用只清一次,实例销毁之后也安全)", returns: "() => void 卸载", doc: "运行时挂一个插件(写法与 options.plugins 里的一项一致):调用即执行,返回幂等的卸载函数(跑插件自己的 destroy),见「插件」", examples: [{"group":"事件、开关与历史","code":"// use(plugin):运行时挂插件(立即执行一次,返回卸载函数)\nconst dispose = view.use((view, context) => ({ destroy() { /* 插件自己的清理;context.apiVersion 当前为 1 */ } }))\ndispose()\n","from":"header"}] },
313
+ { name: "registerCommand", kind: "method", params: "name: string 命令名(会 trim,同名覆盖);handler: GisViewCommandHandler<Payload, Value> 同步处理函数 (payload, context) => Value,context 是冻结的 { view, name }。名字为空 / handler 不是函数只报 warning、不注册;视图销毁后注册不生效", returns: "() => void 幂等注销;同名已被后来者覆盖时不会误删新命令", doc: "注册一个实例命令:handler(payload, context) 同步执行,context 是冻结的 { view, name };同名覆盖,返回幂等的注销函数,旧卸载函数不会误删后来注册的同名命令,见「实例命令」", examples: [{"group":"事件、开关与历史","code":"// registerCommand(name, handler) / executeCommand(name, payload?) / listCommands():实例级业务命令\nconst disposeCommand = view.registerCommand('focusHighestLoad', (payload = {}, context) => {\n const threshold = Number(payload.threshold ?? 0.8)\n const target = view.getData().points\n .filter(point => Number(point.max_loading_rate ?? 0) >= threshold)\n .sort((left, right) => Number(right.max_loading_rate ?? 0) - Number(left.max_loading_rate ?? 0))[0]\n if (!target) return { focused: false, threshold }\n context.view.focusOn(target.id, { select: true, zoom: true, maxZoom: 12 })\n return { focused: true, id: target.id, command: context.name }\n})\nconst commandResult = view.executeCommand('focusHighestLoad', { threshold: 0.85 })\nconst commandNames = view.listCommands() // ['focusHighestLoad']\ndisposeCommand() // 幂等卸载;同名覆盖时不会误删新命令\n","from":"header"}] },
314
+ { name: "executeCommand", kind: "method", params: "name: string 命令名;payload?: unknown 原样交给 handler", returns: "GisViewCommandResult<Value>:{ ok: true, name, value } / { ok: false, name, reason }(未注册 / 名字非法 / handler 抛错)", doc: "执行实例命令:成功给 { ok: true, name, value };名字非法 / 未注册 / handler 抛错给 { ok: false, name, reason },见「实例命令」", examples: [{"group":"事件、开关与历史","code":"// registerCommand(name, handler) / executeCommand(name, payload?) / listCommands():实例级业务命令\nconst disposeCommand = view.registerCommand('focusHighestLoad', (payload = {}, context) => {\n const threshold = Number(payload.threshold ?? 0.8)\n const target = view.getData().points\n .filter(point => Number(point.max_loading_rate ?? 0) >= threshold)\n .sort((left, right) => Number(right.max_loading_rate ?? 0) - Number(left.max_loading_rate ?? 0))[0]\n if (!target) return { focused: false, threshold }\n context.view.focusOn(target.id, { select: true, zoom: true, maxZoom: 12 })\n return { focused: true, id: target.id, command: context.name }\n})\nconst commandResult = view.executeCommand('focusHighestLoad', { threshold: 0.85 })\nconst commandNames = view.listCommands() // ['focusHighestLoad']\ndisposeCommand() // 幂等卸载;同名覆盖时不会误删新命令\n","from":"header"}] },
315
+ { name: "listCommands", kind: "method", params: "无", returns: "string[] 当前注册的命令名(按注册顺序;同名覆盖不改变位置)", doc: "当前注册着哪些实例命令(按注册顺序;同名覆盖不改变原来的位置)", examples: [{"group":"事件、开关与历史","code":"// registerCommand(name, handler) / executeCommand(name, payload?) / listCommands():实例级业务命令\nconst disposeCommand = view.registerCommand('focusHighestLoad', (payload = {}, context) => {\n const threshold = Number(payload.threshold ?? 0.8)\n const target = view.getData().points\n .filter(point => Number(point.max_loading_rate ?? 0) >= threshold)\n .sort((left, right) => Number(right.max_loading_rate ?? 0) - Number(left.max_loading_rate ?? 0))[0]\n if (!target) return { focused: false, threshold }\n context.view.focusOn(target.id, { select: true, zoom: true, maxZoom: 12 })\n return { focused: true, id: target.id, command: context.name }\n})\nconst commandResult = view.executeCommand('focusHighestLoad', { threshold: 0.85 })\nconst commandNames = view.listCommands() // ['focusHighestLoad']\ndisposeCommand() // 幂等卸载;同名覆盖时不会误删新命令\n","from":"header"}] },
309
316
  { name: "getFeatures", kind: "method", params: "无", returns: "GisViewFeatureState", doc: "读当前生效的功能开关(跟随详细配置的也解析成 true / false)/ 换一份(预设名 / 开关表 / true / false),换完立刻生效并发一条 onFeatureChange", examples: [{"group":"事件、开关与历史","code":"// getFeatures() / setFeatures(next):功能开关的读 / 写(预设名 / 开关表 / 布尔值)\nconst features = view.getFeatures()\nview.setFeatures('view') // 'edit' / 'view' / 'static'\nview.setFeatures({ drag: false }) // 单个开关\nview.setFeatures(true) // 全开\n","from":"header"}] },
310
317
  { name: "setFeatures", kind: "method", params: "next: GisViewFeaturesInput 预设名('edit' / 'view' / 'static')、开关表或布尔值", returns: "this", doc: "读当前生效的功能开关(跟随详细配置的也解析成 true / false)/ 换一份(预设名 / 开关表 / true / false),换完立刻生效并发一条 onFeatureChange", examples: [{"group":"事件、开关与历史","code":"// getFeatures() / setFeatures(next):功能开关的读 / 写(预设名 / 开关表 / 布尔值)\nconst features = view.getFeatures()\nview.setFeatures('view') // 'edit' / 'view' / 'static'\nview.setFeatures({ drag: false }) // 单个开关\nview.setFeatures(true) // 全开\n","from":"header"}] },
311
- { name: "undo", kind: "method", params: "无", returns: "GisViewHistoryStepResult | null", doc: "撤销 / 重做一步:返回 { type, label, canUndo, canRedo },历史没开或没得撤销 / 重做时返回 null", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
312
- { name: "redo", kind: "method", params: "无", returns: "GisViewHistoryStepResult | null", doc: "撤销 / 重做一步:返回 { type, label, canUndo, canRedo },历史没开或没得撤销 / 重做时返回 null", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
313
- { name: "canUndo", kind: "method", params: "无", returns: "boolean", doc: "能不能撤销 / 重做(界面据此灰掉按钮)", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
314
- { name: "canRedo", kind: "method", params: "无", returns: "boolean", doc: "能不能撤销 / 重做(界面据此灰掉按钮)", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
318
+ { name: "undo", kind: "method", params: "无:从撤销 / 重做栈回放一步;会同步数据、发 history 与对应的 dataChange,并更新相机以外的运行时读数", returns: "GisViewHistoryStepResult | null:{ type, label, canUndo, canRedo };历史没开或栈空时为 null", doc: "撤销 / 重做一步:返回 { type, label, canUndo, canRedo },历史没开或没得撤销 / 重做时返回 null", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
319
+ { name: "redo", kind: "method", params: "无:从撤销 / 重做栈回放一步;会同步数据、发 history 与对应的 dataChange,并更新相机以外的运行时读数", returns: "GisViewHistoryStepResult | null:{ type, label, canUndo, canRedo };历史没开或栈空时为 null", doc: "撤销 / 重做一步:返回 { type, label, canUndo, canRedo },历史没开或没得撤销 / 重做时返回 null", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
320
+ { name: "canUndo", kind: "method", params: "无:只读当前两份栈,不触发历史变化;界面据此灰掉按钮", returns: "boolean", doc: "能不能撤销 / 重做(界面据此灰掉按钮)", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
321
+ { name: "canRedo", kind: "method", params: "无:只读当前两份栈,不触发历史变化;界面据此灰掉按钮", returns: "boolean", doc: "能不能撤销 / 重做(界面据此灰掉按钮)", examples: [{"group":"事件、开关与历史","code":"// undo() / redo() / canUndo() / canRedo():撤销 / 重做(历史的开关在 options.history)\nview.undo()\nview.redo()\nconst canGoBack = view.canUndo()\nconst canGoForward = view.canRedo()\n","from":"header"}] },
315
322
  { name: "getHistoryState", kind: "method", params: "无", returns: "GisViewHistoryState", doc: "历史读数 { enabled, limit, canUndo, canRedo, undoCount, redoCount } / 已经记下的操作(从旧到新,{ type, label, time })", examples: [{"group":"事件、开关与历史","code":"// getHistoryState() / getHistory() / clearHistory():历史读数 / 逐步清单 / 清空\nconst historyState = view.getHistoryState()\nconst steps = view.getHistory()\nview.clearHistory()","from":"header"}] },
316
323
  { name: "getHistory", kind: "method", params: "无", returns: "GisViewHistoryEntry[]", doc: "历史读数 { enabled, limit, canUndo, canRedo, undoCount, redoCount } / 已经记下的操作(从旧到新,{ type, label, time })", examples: [{"group":"事件、开关与历史","code":"// getHistoryState() / getHistory() / clearHistory():历史读数 / 逐步清单 / 清空\nconst historyState = view.getHistoryState()\nconst steps = view.getHistory()\nview.clearHistory()","from":"header"}] },
317
324
  { name: "clearHistory", kind: "method", params: "无", returns: "number", doc: "清空历史(撤销与重做两份栈一起),返回清掉的条数", examples: [{"group":"事件、开关与历史","code":"// getHistoryState() / getHistory() / clearHistory():历史读数 / 逐步清单 / 清空\nconst historyState = view.getHistoryState()\nconst steps = view.getHistory()\nview.clearHistory()","from":"header"}] },
@@ -352,6 +359,7 @@ export const API_OPTIONS = [
352
359
  { name: "points", type: "GisViewPoint[]", defaultValue: "[]", doc: "点数据,x / y 为世界坐标(经纬度、投影米或任意平面坐标)" },
353
360
  { name: "lines", type: "GisViewLine[]", defaultValue: "[]", doc: "线数据,start / end 支持 { x, y } 或 [x, y],折线用 path,端点可用 from / to 绑定点 id" },
354
361
  { name: "channels", type: "GisViewChannel[]", defaultValue: "[]", doc: "通道:把若干条线路组织成并行敷设的多回线走廊,回线几何由骨架折线按偏移推导;两端可用 from / to 绑在节点上" },
362
+ { name: "pointCluster", type: "boolean | GisViewPointClusterOptions", defaultValue: "关", doc: "点聚合:true 使用缺省档(屏幕半径 60px / 至少 2 点 / 不限缩放),对象写法可调 enabled / radius / minPoints / maxZoom。聚合圆替代密集原始点参与绘制、拾取、快照与导出;原始 points / getData() 不变,缩放超过 maxZoom 后恢复逐点显示,见「点聚合(pointCluster)」" },
355
363
  { name: "channelWidth", type: "number", defaultValue: "0.02", doc: "通道宽度的世界单位写法(tangent 模式下是最外侧两条回线中心的间距,inset 模式下先按它算再收),只在 nodeWidth 为 0 或两端没绑节点时才真正决定宽度;单个通道可用 width 覆盖" },
356
364
  { name: "channelInset", type: "number", defaultValue: "0", doc: "offsetMode: 'inset' 时从切点收 / 放的比例(占通道宽度):正数内收(最多 0.42),负数外收(最多 -0.5,可用区间撑到 2 倍宽);单个通道可用 inset 覆盖,见「通道与多回线」" },
357
365
  { name: "channelNodeWidth", type: "number", defaultValue: "1", doc: "节点宽度倍数:通道宽度按两端节点尺寸取的倍数,1 表示回线正好铺在节点两边、节点放大回线跟着变宽,0 表示所有通道退回 width / channelWidth 的世界单位写法,单个通道可用 nodeWidth 覆盖" },
@@ -371,31 +379,33 @@ export const API_OPTIONS = [
371
379
  { name: "prebake", type: "GisViewPrebakeOptions | true", defaultValue: "关", doc: "贴图符号预热:把「这次画面会出现什么」提前告诉组件 —— 两种写法:combos 逐组合(精确,getSymbolCombos() 收出来的那份)/ symbols × pointColors × sizes 与 lineColors × 线路动画图标 全排列(省事,颜色与尺寸由同一个字段决定时会多烤很多)—— 第一帧之前就烤好,画到它们时命中的是现成的贴图(省掉解码 + 光栅化那一下);组合数与数据量无关,不配就是从前那条按需路径。读数 getPrebake() / getSymbolCombos()、手动再烤一遍 runPrebake(),见「贴图符号预热(prebake)」" },
372
380
  { name: "label", type: "GisViewLabelOptions | GisViewLabelOptions[]", defaultValue: "无", doc: "节点标签:内容 / 位置 / 显隐 / 避让 / 拖动与编辑都可配,写数组就是同一个节点上多条标签,与 lineLabel 共用一套避让网格,见「节点标签」" },
373
381
  { name: "labelOptimize", type: "boolean", defaultValue: "false", doc: "标签显示优化开关:缺省关 = 强制显示(不避让、不按 maxCount 截断、不设 scanLimit / 扫描预算,节点 / 线路的每个可见要素该出现的标签一条不少);写 true 与从前一致 —— 避让 / 换落点 / 数量上限 / 候选上限全部生效。标签订得密、数据量大(十万级)时建议打开,见「标签显示优化开关」" },
374
- { name: "labelRender", type: "'auto' | 'dom'", defaultValue: "'auto'", doc: "纯文本标签的容器渲染方式:auto 在强制显示档(labelOptimize 未开且未进密集档)下,同一层纯文本标签达到 1024 条时改画到一张 Canvas,不再逐条建 div;HTML / 元素内容 / 可拖拽 / 可编辑 / 超出 Canvas 样式能力的标签仍走 DOM。dom 始终逐条建 .gis-view__label。只影响容器,不改内容、锚点、显隐与 html 解析,见「标签容器渲染(labelRender)」" },
382
+ { name: "labelRender", type: "'auto' | 'canvas' | 'dom'", defaultValue: "'auto'", doc: "纯文本标签的容器渲染方式:auto 在强制显示档(labelOptimize 未开且未进密集档)下,同一层纯文本标签达到 1024 条时改画到一张 Canvas;canvas 不受数量阈值限制,优化档 / 密集档也强制画布并直接用画布尺寸参与避让;dom 始终逐条建 .gis-view__label。HTML / 元素内容 / 可拖拽 / 可编辑 / 超出 Canvas 样式能力的标签仍走 DOM。只影响容器,不改内容、锚点、显隐以及 maxCount / when / scanLimit 等优化策略,见「标签容器渲染(labelRender)」" },
375
383
  { name: "lineLabel", type: "GisViewLineLabelOptions | GisViewLineLabelOptions[]", defaultValue: "无", doc: "线路标签:位置沿线走(比例 / 百分比 / 绝对距离),内容、避让、显隐都可配,与节点标签共用一套避让网格;写数组就是同一条线上多条标签,见「线路标签」" },
376
384
  { name: "labelStates", type: "GisViewLabelState[]", defaultValue: "无", doc: "标签的运行时状态(getLabelStates() 的那一份:拖出来的偏移、改过的内容与样式、运行时加的标签、隐藏覆盖):创建时喂回来就回显,等价于创建之后调 setLabelStates(states);updateOptions({ labelStates }) 同样认。exportData({ format: 'input' }) 的结果里就叫 labelStates,存档 → 回灌直接接上" },
377
385
  { name: "graphics", type: "GisViewGraphic[]", defaultValue: "无", doc: "与节点无关的扩展图形:按世界坐标放 SVG 路径 / 图片 / Canvas,支持锚点、偏移、旋转、透明度、zIndex 与 scaleWithView;位于画布之上、标签之下,运行时用 addGraphic / addGraphics / updateGraphic / removeGraphic / clearGraphics 增删改,见「扩展图形(graphic)」" },
378
386
  { name: "tooltip", type: "GisViewTooltipOptions", defaultValue: "无", doc: "悬停提示:点 / 线 / 通道分别配置内容,见「悬浮提示」" },
379
387
  { name: "minimap", type: "GisViewMinimapOptions | null", defaultValue: "无", doc: "内置鹰眼图:位置、尺寸、节点 / 线路 / 视口框三份样式与交互都可配,extent 决定小图按数据范围还是「数据 ∪ 底图」铺(默认 auto,GeoJSON 底图不会缩成一个点),zoomable 打开后小图自身可整体放大缩小(空白处拖动可以平移小图或直接框选让主图显示过去,每格倍率 zoomStep),通道还能只画一根;小图同样支持规则(pointRules / lineRules,缺省沿用主图规则的颜色与层级),可以只画某几层(levels)、关掉分层叠画(layered)、按三组系数给节点与线路定尺寸(整体倍数 pointSizeScale / lineWidthScale、跟随小图倍数 pointZoomScale / lineZoomScale(只在小图自身倍数 ≠ 1 时起作用)、跟随主视图地图倍数 pointMapZoomScale / lineMapZoomScale),视口框与框选矩形的颜色 / 背景 / 边框 / 圆角也能配(boxStyle / selectStyle),extent 还能直接写死一份世界范围、容器可加 className / style、layers 按 placement 分数据前 / 数据后、段内按 order 拆出多层自绘内容(旧 draw 钩子仍兼容并排在最后)、onInteraction 在手势结束时给出类型 / 世界坐标 / 相机、maxPixelRatio 限制备份倍率上限,不配则不产生任何 DOM,见「鹰眼图」" },
380
- { name: "filter", type: "GisViewFilterInput | null", defaultValue: "无", doc: "初始筛选条件,等价于创建之后调用 setFilter,见「筛选」" },
388
+ { name: "filter", type: "GisViewFilterInput | null", defaultValue: "无", doc: "初始筛选条件,等价于创建之后调用 setFilter;mode 缺省 'hide',写 'remove' 则删除不命中的要素,见「筛选」" },
381
389
  { name: "filterWorker", type: "boolean | GisViewFilterWorkerOptions", defaultValue: "{ threshold: 20000 }", doc: "筛选是否用 Web Worker 计算:默认点 + 线总数超过阈值才用,false 表示始终同步算" },
382
390
  { name: "searchWorker", type: "boolean | GisViewSearchWorkerOptions", defaultValue: "{ threshold: 20000 }", doc: "[异步搜索](14-视图与筛选.md#搜索与定位)是否用 Web Worker 计算:默认点 + 线总数超过阈值才用,false 表示 searchAsync 也同步算;同步的 search 一直在主线程算,不受这一项影响" },
383
391
  { name: "pointHoverStyle", type: "GisViewPointStyle", defaultValue: "无", doc: "点的悬停 / 选中样式;没配就不改变外观(悬停仍然触发回调与提示、选中仍然进选中集合),要反馈就自己配一份" },
384
392
  { name: "pointSelectStyle", type: "GisViewPointStyle", defaultValue: "无", doc: "点的悬停 / 选中样式;没配就不改变外观(悬停仍然触发回调与提示、选中仍然进选中集合),要反馈就自己配一份" },
385
393
  { name: "lineHoverStyle", type: "GisViewLineStyle", defaultValue: "无", doc: "线的悬停 / 选中样式;没配同样不改变外观" },
386
394
  { name: "lineSelectStyle", type: "GisViewLineStyle", defaultValue: "无", doc: "线的悬停 / 选中样式;没配同样不改变外观" },
395
+ { name: "cascadeHighlight", type: "boolean | GisViewCascadeHighlightOptions", defaultValue: "关", doc: "点击级联高亮:true 亮节点 + 直连线路;对象可设 enabled、scope、triggerOnClick、triggerOnMultiSelect、triggerOnBoxSelect、独立的 pointStyle / lineStyle 与 clearOnEmptyClick。它不改选中集,见「点击级联高亮」" },
387
396
  { name: "pointMultiSelectStyle", type: "GisViewPointStyle", defaultValue: "无", doc: "多选(Ctrl + 点击)/ 框选(Shift + 拖动,可改 shortcuts.boxSelect)命中的点样式,缺省与 pointSelectStyle 一致,单个点可用 multiSelectStyle / boxSelectStyle 覆盖" },
388
397
  { name: "pointBoxSelectStyle", type: "GisViewPointStyle", defaultValue: "无", doc: "多选(Ctrl + 点击)/ 框选(Shift + 拖动,可改 shortcuts.boxSelect)命中的点样式,缺省与 pointSelectStyle 一致,单个点可用 multiSelectStyle / boxSelectStyle 覆盖" },
389
398
  { name: "lineMultiSelectStyle", type: "GisViewLineStyle", defaultValue: "无", doc: "多选命中时的线样式,缺省与 lineSelectStyle 一致,单条线可用 multiSelectStyle 覆盖;框选出来的线路仍走 lineSelectStyle(线路没有单独的框选样式)" },
390
399
  { name: "defaultHighlight", type: "boolean", defaultValue: "false", doc: "没有配置状态样式时是否仍用尺寸 / 宽度增幅与强调环画出内置强调;默认 false(不配样式就不改变外观),设为 true 可退回旧行为" },
391
- { name: "pointSizeScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例;zoomScaleAuto 是自适应比例开关(见下一行)" },
392
- { name: "lineWidthScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例;zoomScaleAuto 是自适应比例开关(见下一行)" },
393
- { name: "pointZoomScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例;zoomScaleAuto 是自适应比例开关(见下一行)" },
394
- { name: "lineZoomScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例;zoomScaleAuto 是自适应比例开关(见下一行)" },
395
- { name: "zoomBaseScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例;zoomScaleAuto 是自适应比例开关(见下一行)" },
396
- { name: "zoomScaleAuto", type: "boolean", defaultValue: "false", doc: "自适应比例开关:打开后没写联动指数的 pointZoomScale / lineZoomScale 按 1(与地图同倍率)算 —— 包围盒变大、相机比例变小,节点与线宽跟着一起小,节点大小与通道间距的比例不再被带跑;显式写过指数以显式值为准,见「自适应比例(zoomScaleAuto)」" },
400
+ { name: "pointSizeScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例" },
401
+ { name: "lineWidthScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例" },
402
+ { name: "pointZoomScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例" },
403
+ { name: "lineZoomScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例" },
404
+ { name: "zoomBaseScale", type: "number", defaultValue: "1 / 0", doc: "两组系数各管一件事,不重复:pointSizeScale / lineWidthScale 是与地图无关的整体放大(常数倍数,屏幕上的大小因此恒定),pointZoomScale / lineZoomScale 是「跟随地图缩放」的指数(0 表示不跟随,1 表示与地图同倍率放大,0.5 是地图放大 4 倍、要素放大 2 倍),绘制尺寸是两者相乘;zoomBaseScale 是联动基准,缺省取首次适应视图时的比例" },
405
+ { name: "fitSpacing", type: "boolean | GisViewFitSpacingOptions", defaultValue: "关", doc: "适应视图的节点间距兜底:true 用 { minDistance: 24, maxZoom: 0 },对象可改最小中心距(CSS 像素)与相对普通适应比例的上限(0 表示不限);只在首次默认适应与 fitView() 生效,远处孤立点允许落到视口外,见「适应视图的节点间距(fitSpacing)」" },
397
406
  { name: "boxSelect", type: "boolean", defaultValue: "false", doc: "是否允许按住框选快捷键(shortcuts.boxSelect,默认 Shift)拖动鼠标框选要素;缺省关,写 boxSelect: true 或 features: { boxSelect: true } 才开。框选默认只收节点,selectionKinds 可把线路 / 通道也纳入" },
398
407
  { name: "multiSelect", type: "boolean", defaultValue: "false", doc: "多选开关:打开后不用按修饰键,直接单击节点 / 线路就取反累加选中(与按住 shortcuts.multiSelect 点击同一套行为、同一个 multiSelectStyle;取反那一下不经过 onClick,onSelectChange.action.type 是 toggleSelect);缺省关,关着时多选走框选(boxSelect)与按住多选快捷键(默认 Ctrl / ⌘)。运行时 updateOptions({ multiSelect }) 切换只重画一帧、不重排场景" },
408
+ { name: "selectTrigger", type: "'click' | 'dblClick'", defaultValue: "'click'", doc: "选中触发方式:click 第一次单击就改选中集;dblClick 第一下只派发 onClick,等双击判定命中的第二下才改选中集,并同时派发 onClick 与 onDblClick。Ctrl / ⌘ 多选与 multiSelect 在双击模式下同样等第二下才取反。运行时走 updateOptions({ selectTrigger }),只重画一帧、不重排场景" },
399
409
  { name: "selectionKinds", type: "GisViewSelectionKindsInput", defaultValue: "无(框选只收节点;Ctrl 多选收节点 / 线路 / 通道)", doc: "框选与 Ctrl / 多选点击的类型过滤:'point' 节点、'line' 通道外的独立线路、'channel' 通道回线;可写数组任意组合,'all' / true 全开,false / null 全关。通道回线只归 channel 管,通道外的线路只归 line 管;通道回线仍按 channelSelectMode 摊开。不写时保留旧口径;普通单选与 select / selectFeatures 不受它限制。运行时走 updateOptions({ selectionKinds }),见「框选」与「选择类型过滤」" },
400
410
  { name: "selectionBoxStyle", type: "GisViewSelectionBoxStyle", defaultValue: "蓝底 0.16 透明 + 1px 蓝框", doc: "框选矩形的填充与边框:fill、fillOpacity、stroke、strokeWidth" },
401
411
  { name: "selectionOnTop", type: "boolean", defaultValue: "true", doc: "选中的节点 / 拖动中的整组 / 待确认合并的目标节点,以及选中线路所在的整条通道,是否画在所有要素之上(与 zIndex 无关),见「选中 / 拖动的层级」" },
@@ -410,10 +420,11 @@ export const API_OPTIONS = [
410
420
  { name: "gridSize", type: "number", defaultValue: "96", doc: "网格线的屏幕目标间距,实际步长吸附到 1 / 2 / 5 × 10^n" },
411
421
  { name: "showGrid", type: "boolean", defaultValue: "false", doc: "是否绘制网格:与其它功能开关同一条口径,缺省关,写 showGrid: true 才画" },
412
422
  { name: "interactive", type: "boolean", defaultValue: "(缺省全关)", doc: "查看类交互的「详细配置手动打开」写法:写 true 打开拖拽平移 / 滚轮缩放 / 右键回调(等价 pan / zoom / contextMenu 三个开关),不写就是全关" },
413
- { name: "preventContextMenu", type: "boolean", defaultValue: "true", doc: "组件接住右键时是否收掉浏览器的系统菜单(contextmenu 的默认行为):contextMenu 开着(或 interactive: true / features: 'view')时组件才接右键,接住时一律 preventDefault(),点 / 线 / 空白 / 通道都一样;想让系统菜单自己弹就写 false(onContextMenu / onChannelContextMenu 照常发)。右键整个不接时(contextMenu 缺省关)系统菜单自然照弹" },
423
+ { name: "preventContextMenu", type: "boolean", defaultValue: "true", doc: "组件接住右键时是否收掉浏览器的系统菜单(contextmenu 的默认行为):contextMenu 开着(或 interactive: true / features: 'view')时组件才接右键,接住时一律 preventDefault(),点 / 线 / 空白 / 通道都一样;想让系统菜单自己弹就写 false(onContextMenu 照常发)。右键整个不接时(contextMenu 缺省关)系统菜单自然照弹" },
414
424
  { name: "clickable", type: "boolean", defaultValue: "(缺省全关)", doc: "查看类交互的「详细配置手动打开」写法:写 true 打开悬停高亮与点击选中(等价 hover / select 两个开关),要素自身可用 clickable: false 逐个关掉" },
415
425
  { name: "draggable", type: "boolean", defaultValue: "false", doc: "点是否可拖拽,单个点可用 draggable 覆盖;缺省关,写 draggable: true 或 features: { drag: true } 才开" },
416
426
  { name: "liveDrag", type: "boolean", defaultValue: "true", doc: "拖动节点时线路是否实时跟随:false 时拖动期间线路与通道原地不动,松手(pointerup)后一次性更新到新位置" },
427
+ { name: "lineFollowsNode", type: "boolean", defaultValue: "true", doc: "线路 / 通道是否跟随节点的生命周期:true 时隐藏、删除、筛选收起节点会连同绑定线路与通道一起处理;false 时节点退场只影响节点,线路 / 通道停在最后一份坐标与解析尺寸。筛选没有显式写 cascade 时,关闭它会把默认联动从 'binding' 改为 false;显式 cascade 始终优先。运行时用 updateOptions({ lineFollowsNode }) 切换,见「筛选」" },
417
428
  { name: "shortcuts", type: "GisViewShortcuts", defaultValue: "见「快捷键」", doc: "所有快捷键都可自定义:框选 / 多选 / 加点 / 复制 / 粘贴 / 取消 / 删除 / 适应视图,没写的动作沿用默认值,写 false 等于关掉这个动作的快捷键" },
418
429
  { name: "copy", type: "GisViewCopyOptions", defaultValue: "缺省关", doc: "复制节点(写了这份配置才算开,enabled: false 显式关掉):enabled 开关、offset 落点偏移(默认 [28, 24] 像素)、autoCommit(交互入口落地前是否自动确认:不写就是落地,false 停在预览态等 commitPointCopy() / 载荷里的 payload.commit())、idPrefix(默认 copy-)、createId / createItem 定制复制品,见「节点复制」" },
419
430
  { name: "remove", type: "GisViewRemoveOptions", defaultValue: "缺省关", doc: "删除选中的拐点 / 线路 / 节点(写了这份配置才算开,enabled: false 显式关掉):enabled 开关、scope(confirm() 不带参数时的缺省范围:'lines' 只删选中的回线 / 'groups' 连所在分组 / 'channels' 连整条通道,缺省 'lines')、confirm(不写停在 pending 等使用方裁决 / false 直接删 / 函数自行裁决,支持 Promise)。Delete 键与 requestRemove() 都先出一份「要删什么、连带什么」的载荷,确认之后才动数据;删节点会连挂在它身上的线路与被它锚定的通道一起删,见「删除(remove)」" },