gis-view-webgl2 0.1.0 → 0.1.1

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 (86) hide show
  1. package/README.md +28 -8
  2. package/dist/gis-view.css +1 -1
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.d.ts +781 -246
  5. package/dist/index.js +1 -1
  6. package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +129 -0
  7. package/docs/GisView.md +9 -8
  8. package/docs/GisView/345/256/236/347/216/260/345/216/237/347/220/206.md +2 -2
  9. 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 +114 -0
  10. package/docs/api/index.html +545 -59
  11. package/docs/demos/BackendSyncDemo.vue +10 -8
  12. package/docs/demos/BasicDemo.vue +101 -101
  13. package/docs/demos/BatchAddDemo.vue +5 -5
  14. package/docs/demos/ChannelDemo.vue +51 -4
  15. package/docs/demos/ConnectDemo.vue +392 -0
  16. package/docs/demos/CopyMergeDemo.vue +936 -936
  17. package/docs/demos/DecorationDraftDemo.vue +1300 -0
  18. package/docs/demos/DemoShell.vue +569 -240
  19. package/docs/demos/DragDropDemo.vue +11 -11
  20. package/docs/demos/EffectsDemo.vue +6 -6
  21. package/docs/demos/EventDemo.vue +327 -327
  22. package/docs/demos/ExtensionDemo.vue +458 -0
  23. package/docs/demos/GisViewDemo.vue +61 -48
  24. package/docs/demos/GraphicDemo.vue +338 -0
  25. package/docs/demos/LabelDemo.vue +509 -509
  26. package/docs/demos/MinimapDemo.vue +358 -0
  27. package/docs/demos/PerfDemo.vue +29 -0
  28. package/docs/demos/SearchFilterDemo.vue +412 -0
  29. package/docs/demos/StyleDemo.vue +121 -121
  30. package/docs/demos/api-index.js +87 -76
  31. package/docs/demos/demos.js +159 -135
  32. package/docs/demos/shared/demoData.js +107 -107
  33. package/docs/demos/shared/demoStyle.css +249 -249
  34. package/docs/demos/shared/fakeBackend.js +93 -6
  35. package/docs/format/03-/346/213/220/347/202/271/350/243/205/351/245/260/344/270/216/346/240/267/345/274/217.md +24 -6
  36. package/docs/format/06-/345/257/274/345/205/245/345/257/274/345/207/272/344/270/216/346/240/207/345/207/206/346/226/207/346/241/243.md +8 -6
  37. 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 +6 -6
  38. package/docs/guide/sample-document.html +4 -4
  39. package/docs/index.html +180 -9
  40. package/docs/internals/11-/350/246/206/347/233/226/345/261/202/346/240/207/347/255/276/344/270/216/346/217/220/347/244/272.md +1 -1
  41. package/docs/internals/13-/351/271/260/347/234/274/345/233/276.md +3 -2
  42. package/docs/internals/15-03-/351/200/220/350/275/256/350/256/260/345/275/225-/346/200/247/350/203/275/344/270/216/344/277/256/345/244/215-/344/270/213.md +16 -0
  43. package/docs/internals/16-03-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/213.md +11 -0
  44. package/docs/internals/17-/350/260/203/350/257/225/344/270/216/346/211/251/345/261/225/345/273/272/350/256/256.md +1 -1
  45. package/docs/manual/02-/345/235/220/346/240/207/344/270/216/346/225/260/346/215/256.md +11 -2
  46. package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +89 -20
  47. package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +13 -8
  48. package/docs/manual/06-/346/225/260/346/215/256/344/270/216/345/234/272/346/231/257/346/233/264/346/226/260.md +11 -10
  49. 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 +9 -9
  50. package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +13 -11
  51. package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +3 -3
  52. 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 +47 -5
  53. package/docs/manual/11-/346/240/267/345/274/217/344/270/216/350/247/204/345/210/231.md +3 -2
  54. package/docs/manual/12-/346/240/207/347/255/276/344/270/216/350/243/205/351/245/260.md +215 -2
  55. package/docs/manual/13-/345/212/250/346/225/210/344/270/216/345/233/276/345/205/203.md +6 -5
  56. package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +27 -14
  57. package/docs/manual/15-/345/257/274/345/207/272/344/270/216/351/233/206/346/210/220.md +142 -49
  58. package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +25 -29
  59. package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +47 -39
  60. package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +161 -64
  61. package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +4 -4
  62. package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +39 -2
  63. 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 +21 -5
  64. package/docs/playground/index.html +5 -5
  65. package/docs/steps/README.md +12 -10
  66. package/docs/steps/check-doc-truth.mjs +1 -1
  67. package/docs/steps/selftest-actions.html +10 -10
  68. package/docs/steps/selftest-data.html +96 -14
  69. package/docs/steps/selftest-decoration.html +577 -0
  70. package/docs/steps/selftest-demo.html +6 -5
  71. package/docs/steps/selftest-demos.html +2048 -1624
  72. package/docs/steps/selftest-docs.html +86 -14
  73. package/docs/steps/selftest-effects.html +5 -5
  74. package/docs/steps/selftest-features.html +544 -85
  75. package/docs/steps/selftest-full.html +583 -583
  76. package/docs/steps/selftest-labels.html +797 -660
  77. package/docs/steps/selftest-perf.html +1899 -1844
  78. package/docs/steps/selftest-scale.html +117 -7
  79. package/docs/steps/selftest-select.html +24 -17
  80. package/docs/steps/step-10-full.js +1 -1
  81. package/docs//346/216/245/345/217/243/345/215/217/350/256/256.md +151 -7
  82. package/docs//346/225/260/346/215/256/346/240/274/345/274/217.md +1 -1
  83. package/package.json +42 -42
  84. package/docs/demos/HistoryDemo.vue +0 -230
  85. package/docs/demos/InterfaceDemo.vue +0 -309
  86. package/docs/demos/SampleDemo.vue +0 -283
package/README.md CHANGED
@@ -4,10 +4,12 @@
4
4
 
5
5
  - 渲染层:原生 WebGL2(GLSL ES 3.00 + 实例化绘制),没有任何运行时依赖,也不需要 Vue。
6
6
  - 交互层:拖拽平移、滚轮缩放、按关键字搜索并定位(节点 / 线路 / 通道)、点击 / 双击拾取、点拖拽(相连线路同步移动)、Shift 拖动框选与 Ctrl 点击累加多选(多选后整组同步移动;`selectionKinds` 可限定只选节点 / 线路 / 通道或任意组合)、复制只带选中要素、节点合并可指定保留端并改写最终信息与样式、线路拐点编辑与通道多回线,全部走配置与回调 —— **这些能力缺省全关**,要哪一项显式打开(`features` 预设 / 开关表,或 `interactive: true` / `clickable: true` / `draggable: true` 这类详细配置,见 `docs/GisView.md` 的「功能开关」)。
7
- - 数据层:按属性筛选(点被过滤时绑在它身上的线路与通道一起消失,大数据量走 Web Worker)、按属性批量配色 / 换符号、节点标签(内容、贴边方式、HTML 定制、数量与显隐可配,十万级数据下有候选上限兜底)与点 / 线 / 通道的悬浮提示,筛选、规则与标签共用同一套条件语言;节点标签与线路标签分开配置、都支持 `auto`(智能隐藏)/ `always` / `hidden` 三种显隐策略,线路标签的位置沿线走(比例 / 百分比 / 绝对距离)、候选还会按屏幕小格摊开(通道里的并行回线不会把扫描名额占光),线路上还能按同样的位置写法挂图片或 SVG 装饰(`decorations`,通道回线可以用 `linePropsByMember` 逐条配;装饰缺省 `auto` —— 线路上没有拐点时按比例跟随(挂在中点就一直保持中点),有了拐点就跟拐点一样钉在线路上(位置不再沿路径挪动,线路几何一变就把锚点投回线身最近的点),写 `anchor: 'follow'` 强制一直跟随、`anchor: 'fixed'` + `at: [x, y]` 则固定在写死的坐标上;装饰与线路标签都能写 `parallel: true` 跟着线路方向转,通道里的每条回线也能各显示各的标签)。平移 / 缩放 / 拖拽期间两类标签都能各自配 `hideOnInteract`(`true` 或者「标签数超过 N 才收」),收起时只切一个 class、不写标签 DOM,停手自动补齐;线路标签另有 `followOnInteract`(默认开)—— 没收起时拖节点 / 拖拐点期间跟着线路走,关掉则停手后统一归位;通道回线的提示范围用 `tooltip.channelScope` 在整条通道 / 所属分组 / 单条回线之间切。
8
- - 界面尽量不内置:控制面板、读数、图例都不生成,组件只提供画布与实例方法,样式完全由使用方决定(标签与提示框是覆盖层,默认外观可以整体改写);唯一可选的界面是内置鹰眼图——配 `minimap` 才挂一层小地图(位置、尺寸、节点 / 线路 / 视口框三份样式与交互都可配,`zoomable` 打开后小图自身也能整体放大缩小:空白处拖动可以平移小图、或直接框选让主图显示过去,每格倍率 `zoomStep` 单独配,通道还能只画一根回线;小图同样吃规则——`pointRules` / `lineRules` 决定每个节点 / 每条线的颜色、大小与层级,`levels` 只看某几层、`layered` 控制分层叠画、`pointZoomScale` / `lineZoomScale` 让节点与线路跟着小图倍数放大,不配自己的规则时自动沿用主图规则的颜色与层级),不配不产生任何 DOM。
9
- - 数据切换与加载信号:`updateData(points, lines, channels)` 一次换完整个场景(也收 `{ points, lines, channels }`;接口列名不一样时先在调用方映射成这三列,见 demo 页签「接口数据」),场站 / 回线按批补用 `addPoints` / `addChannels`(批量通道只重排一次、只记一步历史),`onDataRendered` / `whenRendered` / `whenDataRendered` 给出「这一份数据已经画到屏幕上」的信号 —— loading 遮罩在这之后收,不会闪一帧旧画面。
10
- - 整包只有一个组件:`gis-view`,只从根入口导出,不预留后续扩展。
7
+ - 数据层:按属性筛选(点被过滤时绑在它身上的线路与通道一起消失,大数据量走 Web Worker)、按属性批量配色 / 换符号、节点标签(内容、贴边方式、HTML 定制、数量与显隐可配,十万级数据下有候选上限兜底)与点 / 线 / 通道的悬浮提示,筛选、规则与标签共用同一套条件语言;节点标签与线路标签分开配置、都支持 `auto`(智能隐藏)/ `always` / `hidden` 三种显隐策略,线路标签的位置沿线走(比例 / 百分比 / 绝对距离)、候选还会按屏幕小格摊开(通道里的并行回线不会把扫描名额占光),线路上还能按同样的位置写法挂图片或 SVG 装饰(`decorations`,通道回线可以用 `linePropsByMember` 逐条配;装饰缺省 `auto` —— 线路上没有拐点时按比例跟随(挂在中点就一直保持中点),有了拐点就跟拐点一样钉在线路上(位置不再沿路径挪动,线路几何一变就把锚点投回线身最近的点),写 `anchor: 'follow'` 强制一直跟随、`anchor: 'fixed'` + `at: [x, y]` 则固定在写死的坐标上;装饰与线路标签都能写 `parallel: true` 跟着线路方向转,通道里的每条回线也能各显示各的标签)。节点也能用 `points[].decorations` 挂图片 / SVG:`offset` 或 `distance` + `direction` 是相对节点的屏幕像素偏移(缩放时保持像素距离),`anchor: 'fixed'` / `at` 是固定世界坐标,`connector` 可从节点中心画连接线。平移 / 缩放 / 拖拽期间两类标签都能各自配 `hideOnInteract`(`true` 或者「标签数超过 N 才收」),收起时只切一个 class、不写标签 DOM,停手自动补齐;线路标签另有 `followOnInteract`(默认开)—— 没收起时拖节点 / 拖拐点期间跟着线路走,关掉则停手后统一归位;通道回线的提示范围用 `tooltip.channelScope` 在整条通道 / 所属分组 / 单条回线之间切。
8
+ - 大数据与导出:`denseMode` 缺省 `'auto'`,按可见节点数(4000)、屏幕密度(每百万 CSS 像素 3000)或数据总量(5 万)自动进入密集档,标签切到避让 / 截断、线路动点与节点涟漪暂停,退出留 22% 回滞并恢复用户原来的 `effects`,当前状态看 `getStats().dense`;导出统一收口到 `exportData({ scope, parts, format })`,`scope` 选全量 / 视口 / 选中,`parts` 选场站 / 线路 / 通道 / 拐点。需要自己画 WebGL 标记或特效时,用 `webglLayers` / `addWebGLLayer()` 或直接取 `view.gl`。
9
+ - 动态装饰器:`beginDecorationDraft` 用 `target` 选择只挂线路、只挂节点或两类同时开启(`both` 时按屏幕距离取更近者、等距优先节点,最近目标不可用时回退另一类);线路侧保留单线 / 分组 / 整条通道三种范围与平行方向,节点侧可切相对偏移 / 固定坐标 / 鼠标位置并画连接线。触发半径默认收紧到 14px,离开目标立即收掉;`maxPerLine` / `maxPerPoint` 分别限制每线 / 每点数量,`allowedLines` / `allowedChannels` / `allowedGroups` / `allowedPoints` 限定白名单,超限或不在白名单的目标静默不触发,提交前还会按最新数据复核;`allowDuplicate: false` 时按 `duplicateDistance` 检测同一位置,`duplicateStrategy` 可选自动避让或直接拒绝。空白处松手不发事件,只有命中的左键松开才发 `ready`;确认走 `commitDecorationDraft` 一次批量写入(线路与节点同一批、一条历史),取消走 `cancelDecorationDraft`,数据与历史在确认前不动。演示页可从左侧图标拖到线路,也可分别开启节点 / 线路装饰并现场调吸附方式、白名单与重复策略。
10
+ - 界面尽量不内置:控制面板、读数、图例都不生成,组件只提供画布与实例方法,样式完全由使用方决定(标签与提示框是覆盖层,默认外观可以整体改写);唯一可选的界面是内置鹰眼图——配 `minimap` 才挂一层小地图(位置、尺寸、节点 / 线路 / 视口框三份样式与交互都可配,`zoomable` 打开后小图自身也能整体放大缩小:空白处拖动可以平移小图、或直接框选让主图显示过去,每格倍率 `zoomStep` 单独配,通道还能只画一根回线;小图同样吃规则——`pointRules` / `lineRules` 决定每个节点 / 每条线的颜色、大小与层级,`levels` 只看某几层、`layered` 控制分层叠画、`pointZoomScale` / `lineZoomScale` 让节点与线路跟着小图倍数放大,不配自己的规则时自动沿用主图规则的颜色与层级;自定义内容可以用 `layers` 按 `placement` 分到数据前 / 数据后、段内按 `order` 叠放,旧的单层 `draw` 仍兼容,手势完成时可通过 `onInteraction` 获取类型 / 世界坐标 / 相机,`maxPixelRatio` 可限制高分屏 / 宿主放大时的备份倍率),不配不产生任何 DOM。
11
+ - 数据切换与加载信号:`updateData(points, lines, channels)` 一次换完整个场景(也收 `{ points, lines, channels }`;接口列名不一样时先在调用方映射成这三列,见 [06 数据与场景更新](docs/manual/06-数据与场景更新.md#接口列名不一样映射放在调用方)),场站 / 回线按批补用 `addPoints` / `addChannels`(批量通道只重排一次、只记一步历史),`onDataRendered` / `whenRendered` / `whenDataRendered` 给出「这一份数据已经画到屏幕上」的信号 —— loading 遮罩在这之后收,不会闪一帧旧画面。
12
+ - 整包只有一个组件:`gis-view`,只从根入口导出;扩展点集中在插件、自定义图元 / 条件运算符与自定义导出格式(`defineExportFormat` / `registerExportFormat`),不需要改组件源码。
11
13
 
12
14
  ## 开发
13
15
 
@@ -19,11 +21,13 @@ npm run dev
19
21
  打开终端提示的地址,页面就是 `docs/demos/GisViewDemo.vue`:下拉第一项是仓库根目录 `new.json` 的真实数据(2164 个站点 / 3669 条线路 / 2629 条通道,点位与走向直接照它渲染),也可以切到同在根目录的样例数据 `test.json`(320 个站点 / 449 条线路,按 `channel_id` 聚合成 107 条多回线通道),或切回 900 / 5000 / 10 万的合成数据;真实与样例数据的线色、线宽和站点符号照 `test.js` 的 `getGisStyle` / `getSymbolPath` 分档,转成组件的批量规则表(`docs/demos/gisStyle.js`),关掉「按属性批量配色 / 换符号」就能对比同一份数据的两套外观。演示点击、双击、悬停、拖拽节点、Shift 框选与 Ctrl 点击多选、拐点编辑(加过 / 拖过拐点的通道与线路会归到「新增拐点集合」,读数栏下面直接列出来,点「导出拐点集合」把 `getParallelGroups()` 的结果复制到剪贴板),两端锚在节点上的二 / 三 / 四 / 五回线通道(可切换偏移方式、通道宽度与内收距离,也可以勾「隐藏通道端点节点」看通道与回线一起消失),以及新增的筛选下拉框(电压、站点类型、名称关键字、联动方式与「线路也按电压过滤」)、按属性配色换符号开关(站点符号可选原 SVG 路径或内置方块,路径描边粗细可调)、按电压分层(`zIndex`,高电压等级压在上面)、节点形状(圆 / 正方形 / 圆角方形)、标签位置 / 内容 / HTML 渲染 / 数量 / 候选上限与悬浮提示开关;筛选读数会显示隐藏了多少点 / 线、这次判定走的是 Web Worker 还是主线程、耗时多少。右下角的鹰眼图现在由组件自带(`minimap`):demo 只给尺寸、线路显隐、回线根数、拖动动作、步进、三份样式,以及这一轮新增的规则配色 / 分层开关 / 只看某几层(`levels`)/ 节点与线路跟随小图放大(`pointZoomScale` / `lineZoomScale`)(「可缩放」打开后滚轮与 - / + 按钮按 `zoomStep` 整体放大缩小鹰眼图自身,Ctrl / ⌘ + 滚轮留给主图;空白处拖动按 `dragAction` 平移小图或直接框选,按住 Ctrl / ⌘ 是另一个动作),缩略图画的是筛选后仍可见的节点与线路(含通道回线,关掉「回线」一个通道只画中间那一根),在视口框上按下直接拖框、空白处长按后视角跟随、单击不再改动视角。通道面板下面还有「通道分组」与「定向更新」两行:前者把选中的通道按每组的回线数拆开或合并回去(读数里能看到每个分组几回线、有没有拐点),后者改一个节点 / 线路 / 通道就立刻重渲染相关的视图,演示 `splitChannelGroups` / `mergeChannelGroups` / `moveChannelLine` / `updatePoint` / `updateLine` / `updateChannel` 这几个接口(右键框里每条回线都能单独分配:拆成新分组、或并进第 n 组,两回线拆成两个分组各一条);界面(按钮、滑块、读数浮层)仍然全部写在 demo 里。这一轮把 demo 重新排了一遍:说明段落收进「展开说明」、配置按组折进可折叠面板,画布右上角多了「全屏」按钮(`requestFullscreen` + `resize()`);节点标签默认只标最高电压那一档、线路标签默认不显示(面板上各有一份「显示范围」),新增的「规则更新」面板可以把规则写成 JSON 再点一下重新渲染。这一轮再把面板收进「视图 / 样式 / 数据」三个分页(整块面板栈独立滚动、鹰眼图设置默认折叠),画布默认垫一层由 `docs/demos/demoBackground.js` 现生成的 GeoJSON 底图(街区 + 环线 + 经纬网,可切三档底图与透明度),并新增「初始视图与背景」面板:首屏不再铺满整屏,默认聚焦数据中心放大 3 倍,也能切「适应全部 / 2× / 3×」或自己填中心点与倍数;demo 里还内置了一份插件示例 `focusSelectionPlugin`(按 F 聚焦当前选中),演示 `plugins` 的挂载与随视图销毁。
20
22
  通道面板这一轮又多了一块:分组按整条通道的车道错开,拆分 / 合并不会挪动任何一条回线(两回线拆成两组各一条时两根线一左一右分居骨架两侧,四回线拆成两组时四条线还停在原来的位置上),想把某一组拐到别的走廊上就用「加拐点分开分组 / 去掉分开的拐点」按组挪拐点(`addChannelGroupWaypoint` / `removeChannelGroupWaypoint`);右键点通道回线弹出交互框,`onChannelContextMenu` 里给出这条通道有几组、当前是哪一组、每组几条回线与可用交互(点空白处收到 `null` 收框);「新增通道」点两次节点、草稿线跟着光标走,第二个节点点完在框里选「新建通道 / 变成新分组 / 并入某一组」,也可以勾自动提交或直接调 `addChannel`。右键框这一轮又加了「线路分配」:当前分组的每条回线各有一个下拉(拆成新分组 / 并入第 n 组)+「分配」按钮,走 `moveChannelLine`,组数 / 回线数到上限会被拒绝并在读数里给出原因。这一轮右键框再补齐:分组列表点一下就是 `setCurrentChannelGroup`(顺带选中这一组的回线、当前组高亮),下面一排「选中该分组 / 加拐点 / 删拐点 / 拆成多组 / 合并回一组」走 `runChannelAction`(灰掉的按钮悬停能看到原因),Esc / × / 点空白处收框;这两件事都要显式开开关:`features: { drag: true, channelMenu: true }` 与 `waypointEditable: true`(开关缺省全关;通道右键框还要 `contextMenu` 开着,通常给 `features: 'view'` 再加 `channelMenu: true`)。
21
23
 
22
- 这一轮的 demo 拆成了「一个壳 + 多个标签页」:入口是 `docs/demos/DemoShell.vue` 配 `docs/demos/demos.js`(id / 标题 / 一句说明 / 懒加载的 `component`),切标签页会把 `?demo=<id>` 用 `replaceState` 写回地址栏,收藏一个链接就能直接打开某一页。页签各自只演示一件事(现在是十四个功能页 + 综合示例):`basic` 最小画布与拾取、`labels` 节点与线路标签(拖动 / 点击 / 右键 / 双击 / 批量加标签 API)、`style` 规则配色与符号、`channel` 通道与分组、`events` 事件日志、`copy-merge` 框选类型过滤(节点 / 线路 / 通道任意组合)、只复制选中要素、手动 `addPoint` 落点与自动副本二选一、指定保留来源 / 目标并改写最终信息与样式的合并、剪贴板、`batch-add` 多节点 / 线路 / 通道 / 分组 / 拐点的批量新增、`drag` 拖拽落点、`history` 历史与批量、`samples` 完整样本、`interface` 接口数据、`backend` 编辑与保存、`perf` 大数据与画质档位、`effects` 动画效果,`full` 保留原来那份全功能 demo(缺省页签);共用数据与样式抽在 `docs/demos/shared/demoData.js` / `docs/demos/shared/demoStyle.css`,新增自测页 `docs/steps/selftest-demos.html` 逐个页签挂载一遍。
24
+ 这一轮的 demo 拆成了「一个壳 + 多个标签页」:入口是 `docs/demos/DemoShell.vue` 配 `docs/demos/demos.js`(id / 标题 / 一句说明 / 懒加载的 `component`),切标签页会把 `?demo=<id>` 用 `replaceState` 写回地址栏,收藏一个链接就能直接打开某一页;顶部按基础 / 交互 / 样式 / 数据 / 性能 / 综合分组,一次只展开当前组。页签各自只演示一件事(现在是 19 个功能页 + 综合示例):`basic` 最小画布与拾取、`labels` 节点与线路标签(拖动 / 点击 / 右键 / 双击 / 批量加标签 API)、`label-display` 标签内容与显示策略、`minimap` 鹰眼图配置(尺寸 / 位置 / 范围 / 规则 / 层级 / 备份倍率 / 小图缩放 / 数据前后分段绘制 / 手势回调)、`style` 规则配色与符号、`hover-tooltip` 悬停高亮与提示模板、`channel` 通道与分组、`events` 事件日志、`copy-merge` 框选类型过滤(节点 / 线路 / 通道任意组合)、只复制选中要素、手动 `addPoint` 落点与自动副本二选一、指定保留来源 / 目标并改写最终信息与样式的合并、剪贴板、`batch-add` 多节点 / 线路 / 通道 / 分组 / 拐点的批量新增、`search-filter` 同步 / Worker 检索与筛选、`drag` 拖拽落点、`connect` 可视化连线(无通道也能只用点与线;直线 / 正交折线、箭头、颜色与线宽,取消 / 默认提交 / `addLines` / `addChannels` 三种落地)、`decoration` 动态装饰器(线路 / 节点分开开关或同时开启、悬停预览、节点偏移 / 固定 / 鼠标吸附、白名单与重复策略、确认才写数据)、`extension` 四类扩展点(插件 / 图元 / 运算符 / 导出格式,图元支持同名换画笔并当场重烘焙)、`backend` 编辑与保存、`perf` 大数据与画质档位、`effects` 动画效果、`graphic` 扩展图形(SVG 路径 / 图片 / Canvas,相机联动与运行时增删改),`full` 保留原来那份全功能 demo(缺省页签);共用数据与样式抽在 `docs/demos/shared/demoData.js` / `docs/demos/shared/demoStyle.css`,新增自测页 `docs/steps/selftest-demos.html` 逐个页签挂载一遍。
25
+
26
+ 演示外壳会缓存已经加载过的模块;当前演示渲染完成后,利用空闲时间预取前后两个页签,失败时显示错误与「重新加载」,切页签不再重复下载。新增的 `extension` 页把 `view.use` / `registerSymbol` / `registerOperator` / `defineExportFormat` 四个扩展点放在同一块画布里,并给出注册表、插件挂载状态与业务 DTO 的同屏读数。
23
27
 
24
28
  源码本身就是 JS:`src/gis-view/*.js` 逐文件带中文注释,对外类型集中在 `src/gis-view/types.d.ts`(构建时复制成 `dist/index.d.ts`),不用先编译就能直接读。想照着从零写一遍看 [从 0 到完整的实现](docs/从0到完整的实现.md),里面有一份可以照抄的 mini 实现与验收清单。
25
29
 
26
- 想知道组件到底有哪些属性和方法:[GisView 文档](docs/GisView.md) 的「实例方法」一节把 223 个实例成员(220 个方法 + `el` / `canvas` / `gl`)与 85 个 `options` 键逐个列全;demo 的「视图 · 交互」页签里有同一份清单(`?demo=full`,可搜索、点一条就对当前视图求值);`node docs/steps/check-doc-coverage.mjs` 负责 10 项双向对账,改完源码或文档先跑 `node docs/steps/gen-api-index.mjs` 重生成 demo 读的那一份(三类查询的口径见 [docs/steps/README.md](docs/steps/README.md) 的「怎么查全部属性与方法」)。
30
+ 想知道组件到底有哪些属性和方法:[GisView 文档](docs/GisView.md) 的「实例方法」一节把 241 个实例成员(方法 + `el` / `canvas` / `gl` 这类属性)与 90 个 `options` 键逐个列全;demo 的「视图 · 交互」页签里有同一份清单(`?demo=full`,可搜索、点一条就对当前视图求值);`node docs/steps/check-doc-coverage.mjs` 负责 10 项双向对账,改完源码或文档先跑 `node docs/steps/gen-api-index.mjs` 重生成 demo 读的那一份(三类查询的口径见 [docs/steps/README.md](docs/steps/README.md) 的「怎么查全部属性与方法」)。
27
31
 
28
32
  ## 构建 npm 包
29
33
 
@@ -133,7 +137,7 @@ const view = createGisView('#map', {
133
137
  })
134
138
  ```
135
139
 
136
- 状态样式按字段覆盖,`selectStyle: {}` 表示命中时不改变外观;不配样式就什么都不画(悬停仍然触发回调与提示、选中仍然进选中集合),要退回旧的「尺寸 / 宽度增幅加一圈强调环」就把 `defaultHighlight` 设为 `true`。框选与 Ctrl 点击得到同一份选中集合,用 `getSelections()` / `getSelectedIds()` 读回,也可以用 `select(id | id[])` 受控设置选中、`selectInBox(box)` 直接框选,多选之后拖动任意一个被选中的节点就是整组移动。拐点写在线路的 `path` 里,拖动或增删之后 `getData()` 与 `onWaypointChange` 的 `line` 都是最新数据;通道内的回线把拐点挂在共用骨架上,改一条就是改整条通道,`getWaypoints()` 读当前显示的拐点、`getChannels()` 读骨架 / 偏移 / 每条回线的折线;被加过 / 拖过拐点的通道与线路还会归到 `getParallelGroups()` 的「新增拐点集合」里,结构对齐 `test.json` 的 `parallel_groups`(一条通道一组、回线列在 `member_line_ids`、`group_route` 是它们共用的骨架),删掉最后一个拐点这条组就退出集合。拖拽点时,`from` / `to` 绑定的线与坐标相同的线都会跟着移动。 多选(Ctrl + 点击)与框选(Shift + 拖动)各有自己的样式:`pointMultiSelectStyle` / `pointBoxSelectStyle` / `lineMultiSelectStyle` 是整体配置,要素自己的 `multiSelectStyle` / `boxSelectStyle` 优先,两者都没配就回落到选中样式。节点尺寸与线宽各由两组独立系数控制:`pointSizeScale` / `lineWidthScale` 是与地图无关的整体放大,`pointZoomScale` / `lineZoomScale` 是地图缩放的联动指数(0 表示不跟随,基准是 `zoomBaseScale` 或首次适应视图时的比例),实际绘制尺寸是两者相乘,整体放大不会被联动再放大一次,拾取容差跟着一起放大。`size` 与 `sizeScale` 的关系是「尺寸 × 倍数」:`size` 是节点的宽度(正方形取边长,圆的直径按面积对齐正方形、等于宽度的 `2 / √π` 倍,同一个 `size` 下圆与方摆在一起不会一大一小),规则与状态样式里的 `sizeScale` 依次往这条链上乘,因此「电压越高越大 + 悬停统一放大 1.25 倍」这类组合可以各配各的。
140
+ 状态样式按字段覆盖,`selectStyle: {}` 表示命中时不改变外观;不配样式就什么都不画(悬停仍然触发回调与提示、选中仍然进选中集合),要退回旧的「尺寸 / 宽度增幅加一圈强调环」就把 `defaultHighlight` 设为 `true`。框选与 Ctrl 点击得到同一份选中集合,用 `getSelections()` / `getSelectedIds()` 读回,也可以用 `selectFeatures(refs)` 受控设置选中、`selectInBox(box)` 直接框选,多选之后拖动任意一个被选中的节点就是整组移动。拐点写在线路的 `path` 里,拖动或增删之后 `getData()` 与 `onWaypointChange` 的 `line` 都是最新数据;通道内的回线把拐点挂在共用骨架上,改一条就是改整条通道,`getWaypoints()` 读当前显示的拐点、`getChannels()` 读骨架 / 偏移 / 每条回线的折线;被加过 / 拖过拐点的通道与线路还会归到 `getParallelGroups()` 的「新增拐点集合」里,结构对齐 `test.json` 的 `parallel_groups`(一条通道一组、回线列在 `member_line_ids`、`group_route` 是它们共用的骨架),删掉最后一个拐点这条组就退出集合。拖拽点时,`from` / `to` 绑定的线与坐标相同的线都会跟着移动。 多选(Ctrl + 点击)与框选(Shift + 拖动)各有自己的样式:`pointMultiSelectStyle` / `pointBoxSelectStyle` / `lineMultiSelectStyle` 是整体配置,要素自己的 `multiSelectStyle` / `boxSelectStyle` 优先,两者都没配就回落到选中样式。节点尺寸与线宽各由两组独立系数控制:`pointSizeScale` / `lineWidthScale` 是与地图无关的整体放大,`pointZoomScale` / `lineZoomScale` 是地图缩放的联动指数(0 表示不跟随,基准是 `zoomBaseScale` 或首次适应视图时的比例),实际绘制尺寸是两者相乘,整体放大不会被联动再放大一次,拾取容差跟着一起放大。`size` 与 `sizeScale` 的关系是「尺寸 × 倍数」:`size` 是节点的宽度(正方形取边长,圆的直径按面积对齐正方形、等于宽度的 `2 / √π` 倍,同一个 `size` 下圆与方摆在一起不会一大一小),规则与状态样式里的 `sizeScale` 依次往这条链上乘,因此「电压越高越大 + 悬停统一放大 1.25 倍」这类组合可以各配各的。
137
141
 
138
142
  回线数量多时用 `createChannels` 组装:它按 `circuits` 把一条通道声明展开成多条只绑两端节点的回线,并生成共用的通道对象(id、名称、配色都可以按序覆盖),返回的 `{ lines, channels }` 直接交给 `createGisView` / `updateOptions`:
139
143
 
@@ -208,7 +212,7 @@ view.updateOptions({ preventContextMenu: false })
208
212
 
209
213
  // 导出带 labels 列(缺省 'auto' 只给有标签要说的记录带):记录原样喂回 points / lines 就能回显
210
214
  const rows = view.exportData({ parts: ['station'], labels: true }).points
211
- view.clearFilter()
215
+ view.setFilter(null)
212
216
  ```
213
217
 
214
218
  搜索与相机定位(搜索只找不藏,筛选才负责隐藏):
@@ -355,3 +359,19 @@ view.zoomTo(12).zoomToBounds({ minX: 116, minY: 39, maxX: 117, maxY: 40 }, 60)
355
359
  - 这一轮(「问题.txt」三条:屏幕坐标与真实坐标互转 / addChannel 连同线路一起新建 / beginAddChannel 选完两个节点交接):① 坐标互转补「浏览器事件」这一档 —— `project` / `unproject` 管世界 ↔ 画布 CSS 像素、`lngLatToWorld` / `worldToLngLat` 管经纬度,新增 `clientToWorld(clientX, clientY)` / `worldToClient(x, y)` 管鼠标事件坐标 ↔ 世界坐标(内部自动减 canvas rect、除宿主缩放,`worldToClient` 出来的就是 `position: fixed` 浮层直接可用的坐标);② `addChannel(input, lineItems?)` 补第二段(`addLine` / `addChannels` 每项同款、入参 `lineItems` 也认):一条或一批逐条属性,给了几条就建几条(`circuits` / `count` 忽略),与 `linePropsByMember` 按下标合并、第二段优先;③ `beginAddChannel({ handoff: true })` 交接模式:两个节点选完、`phase: 'ready'` 发完,草稿当场静默收掉(不补 `cancel`),使用方拿 ready 载荷自己调 `addChannel` 落地。验证:`selftest-features` 379 → **390**、十三页共 **1433** 条 0 FAIL、`npx tsc --noEmit` 0 错、`check-doc-coverage` 10 项 / `check-doc-truth` 6 项 PASS、`gen-api-index.mjs` 重生成(**219** 成员)、`npm run build` 通过(细节见《实现原理》15.83 / 16.53)。
356
360
  - 这一轮(「问题.txt」三条:`addChannel` 更新已有通道的 `lineIds`、位置对账 `getMovedPoints` / `clearMovedPoints`、拐点与接口的交互方案):① `addChannel` 支持更新已有通道的成员表 —— 顶层 `channelId` / `groupId` / `groupIndex` 就是 `resolution` 的简写(与 `updateLine` 的分组指令同一套写法;只给 `channelId` 时按这条通道自己的推荐顺序挑:新分组 → 第一个能并的分组;两个节点之间还没有通道时它仍是新建通道的 id),结果与 `onChannelDraft` 的 `commit` 载荷回带 `channelLineIds`(落地后这条通道的完整成员表,独立线路为 `null`);② 新增「位置对账」:`getMovedPoints()` 一趟给出相对上次对账搬过位置的节点(`[{ index, id, x, y, item }]`,按 id 去重、拖动 / `updatePoint` / `patchPoints` / 撤销都算、`removePoints` 删掉的记录顺手清掉、整份换数据重新对齐),`clearMovedPoints(refs?)` 把当前坐标记成新基准(不传 = 全部对账,引用写法与 `removePoints` 一致)——「先取、发接口、发完对账」就是一条实时位置同步回路;③ 拐点与后端交互的推荐口径写进文档(整份覆盖不给 delta、优先攒批、改完就传要合并 + 延迟 + 失败回滚、分组拐点按组给)—— 演示页「编辑与保存」补位置对账读数与对账按钮。验证:`selftest-features` 390 → **406**(mvView 块 17 条)、`selftest-demos` 141 → **143**、十三页共 **1451** 条 0 FAIL、`npx tsc --noEmit` 0 错、`check-doc-coverage` 10 项 / `check-doc-truth` 6 项 PASS、`gen-api-index.mjs` 重生成(**221** 成员)、`npm run build` 通过(细节见《实现原理》15.84 / 16.54)。
357
361
  - 这一轮(1 条问题:检查 bug、优化性能、组件内部方法审计,见「问题.txt」):起了一个临时审计页把 50k 点 / 30k 线(+ 1 条通道)场景下的实例方法逐条量了一遍,配 CPU profile 抓出四处真问题并修掉。① **有通道时「追加式补点」整份回落**:`canAppendPoints` 原来见到通道就返回 false,一次补 100 条 44 ms —— 改成只挡「新点正是通道声明的 `from` / `to` 锚点」的那种(`appendedClaimsChannelAnchor`),实测 44 → 3.3 ~ 6.3 ms;② **有通道时删除整份回落**:`canRemoveResolve` 的通道闸门原来把「有通道」并成一个否定,删 1 条也要 35 ms —— 改成「声明逐条没变(同引用)+ 没删到任何回线 + 没删到锚点」才认增量的纯删点,实测删 50 条 35 → 18.7 ~ 21 ms、删 1 条 35 → 12.5 ms(删锚点时通道整条收拾的行为不变);③ **一批按 id 的定位不再整表重建**:`removePoints` / `updateItems` 在条数 ≥ 32 时原来 `syncIdMaps()` 整表重建(8 ~ 10 ms,profile 占 6.8%),新增 `locateIdsInBatch` 一趟扫出要的那几十个 id;④ **两条读数**:`getSymbolCombos()` 先按颜色数组身份去重再转 CSS(30k 线 2.32 → 0.22 ms/次),`getMovedPoints()` 不再逐点开坐标数组(2.2 → 2.0 ms/次;这条的下限就是 O(数据量) 的查账,取舍见《实现原理》16.55)。`exportData({ format: 'full' })` 的 15 ~ 16 ms 留作候选(16.56)。验证:`selftest-features` 406 → **410**(通道在场时增删无关点的读数逐字节不变 / 删锚点连带收拾 / 通道等未到的锚点补点后当场可解析)、`selftest-perf` 124 → **125**(通道在场时补 / 删 2 个点:1.6 / 6.3 ms,改前 40 / 35 ms 上下)、十三页共 **1456** 条 0 FAIL、`npx tsc --noEmit` 0 错、`check-doc-coverage` 10 项 / `check-doc-truth` 6 项 PASS、`npm run build` 通过(细节见《实现原理》15.85 / 16.55)。
362
+ - 这一轮(「修改.txt」:修 bug / 性能 / 可扩展性 / 文档 / demo):① **同名重新注册图元继续用旧贴图**:贴图缓存键原来只带注册名,`registerSymbol('spark', 新画笔)` 会命中旧缓存,画面停在上一支画笔;现在键里带注册代次,同名重新注册(即使画笔函数引用没变)都会重新烘焙,`refreshSymbols` 同时重排标签锚点,旧注销函数仍不会误删后注册项。② **标签 `when` 的编译缓存**:覆盖层原来只有点 / 线各一条单槽缓存,多条不同 `when` 每轮排版互相顶掉、反复编译;改成按条件对象身份放进 `WeakMap`,并给运算符注册表加版本号,注册 / 覆盖 / 注销后整份失效 —— 自定义运算符改了语义或注销,标签当场按新判定重排,动态配置对象也不会被缓存留住。③ **demo 与文档**:扩展能力页补「同名换画笔」(十字 ↔ 菱形,读数与画面同步),演示旧注销函数不误删新注册;手册补同名重注册 / 标签缓存口径,自测补像素级同名换贴图、标签 `when` 同步重编译与多条条件缓存三条断言。验证:`selftest-scale` 104 → **106**、`selftest-features` 537 → **538**、`selftest-demos` 248 → **249**,十三页共 **1845** 条 0 FAIL;`npm run check:docs` 全 PASS、`npm run build` 通过。
363
+ - 这一轮(「问题.txt」:性能 / 大数据交互 / 可扩展性 / 文档):① **节点视口遍历走点网格**:`forEachPointInView` 在 2048 个节点以上、点网格可用且估计候选不足总量 1/32 时只查视口覆盖的格子,候选排回数据顺序后逐个精确判定;网格脏或视口接近全图时仍走整份扫描,新增 `createPointGrid.estimate()` 与 `query()` 共用格子口径并支持 `stopAfter` 提前封顶,枚举顺序、`visit` 提前结束与可见判定不变。② **线路框选不再做完整快照**:`selectInBox` 的线路 / 通道收集改走 `forEachLineInView`,保留点击 / 可见 / 类型 / `channelSelectMode` 判定与按下标排序,但不再为每条候选复制 `path` / `bounds` / `color` / `width`。③ **插件上下文**:`options.plugins` 与 `view.use()` 统一传 `(view, context)`,`context` 是冻结的 `{ apiVersion: 1, view }`,旧的一参插件写法兼容;类型声明与手册同步。④ **文档**:手册补点网格 / 框选快路径与插件上下文,文档中心「回到顶部」显示阅读百分比,自测补视口顺序 / 提前结束、`estimate` 口径、三类框选与插件上下文断言。验证:`selftest-perf` 134 → **136**、`selftest-scale` 106 → **107**、`selftest-select` 58 → **59**,十三页共 **1849** 条 0 FAIL;`npx tsc --noEmit` 0 错、`npm run check:docs` 全 PASS、`npm run build` 通过。
364
+ - 这一轮(「修改.txt」:动态装饰器):新增 `beginDecorationDraft` / `getDecorationDraft` / `updateDecorationDraft` / `commitDecorationDraft` / `cancelDecorationDraft` 五个接口,开启后按 `scope`(单线 / 分组 / 整条通道)在指针命中的线路上画临时装饰,移出即收、空白松手不发事件、在线路上松手才发 `ready`,`parallel` 控制是否随线路转向;确认前不写数据 / 历史,确认时一次批量追加、只发一条 `batch` 数据变更,`cancelDecorationDraft` / Esc / 右键只清假装饰。配套新增 `decorationDraft` 事件、`onDecorationDraft` 回调、`docs/demos/DecorationDraftDemo.vue`(页签「动态装饰器」)与 `selftest-decoration.html`,手册补动态装饰器草稿 / 事件 / 指针动作与五个方法条目。验证:十四页自测共 **1877** 条 0 FAIL(`selftest-decoration` 26 条、`selftest-demos` 249 → **251**)、`npx tsc --noEmit` 0 错、`npm run check:docs` 全 PASS、`npm run build` 通过。
365
+ - 这一轮(「修改.txt」:节点装饰器 / 节点与线路分开演示 / 白名单与上限 / 重复策略 / 性能):节点新增 `points[].decorations` 与 `getPointDecorations` / `setPointDecorations` / `addPointDecoration` / `updatePointDecoration` / `removePointDecoration`,支持 `offset` 或 `distance + direction` 的屏幕像素偏移、`at` / `anchor: 'fixed'` 世界坐标和草稿的鼠标位置,`connector` 可从节点中心连到装饰中心。动态装饰器新增 `target: 'line' | 'point' | 'both'`,`both` 按屏幕距离取更近目标、等距优先节点、最近目标被白名单或上限拦住时回退另一类;节点侧支持 `allowedPoints` / `maxPerPoint`,线路侧沿用 `maxPerLine` / 三类白名单,不允许的目标不触发 `hover` / `ready`,提交前再按最新数据复核;`allowDuplicate: false` 时按 `duplicateDistance` 检测同一位置,`duplicateStrategy` 可选自动避让或拒绝。节点装饰进入圆点 / 贴图批次,连接线单独成批、拖点 / 缩放按槽位刷新而不重铺整份场景,并纳入 `snapshotScene` 的线路层;角度对外按度、实例与 SVG 快照统一为弧度。演示页把线路 / 节点拆成两个开关,可单选或同开,节点侧可切偏移 / 固定 / 指针、调方向距离、白名单、上限与重复策略。验证:`npx tsc --noEmit` / `npm run build` 通过,`check:docs` 253 成员 / 235 字段 / 87 options 全 PASS,十四页自测 **1918** 条 0 FAIL。
366
+ - 这一轮(「修改.txt」:节点合并触发时机 / 装饰随移动 / 组件优化):① `merge.trigger` 新增 `'collision'`(缺省,两个节点屏幕半径相碰)与 `'center'`(拖动节点中心进入目标节点区域)两种时机,均叠加 `merge.distance`;`onPointMerge` 拖拽载荷新增 `trigger` 回传本次档位,候选查询同时把来源半径与容差算进空间索引 padding,避免容差较大时漏候选。② 复核并补齐装饰随动链路:节点拖动 / 整组移动 / `updatePoint` 走 `refreshPointDecorationPoints`,线路重排 / 拖节点 / 拖拐点走 `refreshLineDecorations`;`follow` 与 `auto` 投影跟新几何,节点屏幕偏移保持像素距离,固定坐标档不动,并新增 2 条专项断言。③ 节点装饰槽位刷新跳过无装饰且无旧槽位的节点,单节点拖动不再临时建 `Set` 或空数组;新增 3 条合并触发时机断言。验证:`npx tsc --noEmit`、`npm run check:docs`、`node docs/steps/gen-api-index.mjs --check`、十四页自测共 **1923** 条 0 FAIL、`npm run build` 全部通过。
367
+
368
+ - 这一轮(「修改.txt」:gis-view 组件优化 / channel.path 的必要性 / 全部功能开关):① `features` 统一为 **18 个开关**,拐点编辑只保留 `waypoint` / `waypointEditable` 一道总闸:关闭后新增、移动与删除一起失效,不再提供 `waypointAdd` 细分开关。② `features: 'static'` 改为显式关闭全部开关(含已配置的标签 / 提示 / 鹰眼图),与「全部功能关闭」的文档口径一致;同时合并 `create.js` / `engine.js` 两处重复的表现型配置键清单。③ 文档明确 `channel.path` 是可选骨架:两端锚定时省略即直连、写了只写中间拐点;未锚定时省略回落到首条回线路径,分组第一组可回落到顶层 `path`,不该删除。类型声明、开关表、demo 复选框、FAQ 与 API 清单同步。
369
+ - 这一轮(「修改.txt」:aimd 同步 / 扩展图形 / 手动删除装饰 / 大数据标签 / 拐点总开关):① 新增根 `AGENTS.md`,修改相关 Markdown 时必须同步 `docs/AI对话汇总.md` 与 `docs/ai/06-会话索引与复查方法.md`,并记录需求来源、核心文件与验证结果。② 新增 `graphics` 配置与 `src/gis-view/graphic.js`:按世界坐标绘制 SVG `path`、图片与外部 Canvas,支持 `anchor` / `offset` / 旋转 / 缩放 / 透明度 / `zIndex` / `scaleWithView`,位于画布之上、标签之下且不参与拾取;运行时用 `addGraphic` / `addGraphics` / `updateGraphic` / `removeGraphic` / `clearGraphics` / `getGraphic` / `getGraphics` 增删改查,场景快照、PNG 与 SVG 导出都会合成这一层。③ 手册补充「手动删除装饰」:线路 / 节点各用 `remove...Decoration` 或 `set...Decorations([])`,草稿用 `cancelDecorationDraft()`,扩展图形用 `removeGraphic` / `clearGraphics`。④ 大数据优化档的节点标签先按 32px 细格去重、再按 160px 粗格每格最多 3 条主候选,其余进补位队列并按屏幕行列排序;已显示节点参与同一趟稳定候选扫描与格位占位,稳态重排不再因候选漂移反复量布局。⑤ 删除 `waypointAdd`,`waypoint` / `waypointEditable` 关闭时新增、移动、删除一起停,`shortcuts.addWaypoint` 只决定加点组合键。验证:14 个自测页 **1941** 条 0 FAIL;`npx tsc --noEmit`、`npm run check:docs`(260 个成员 / 236 个数据字段 / 88 个 options / 18 个功能开关 / 15 个分组)、`node docs/steps/gen-api-index.mjs --check`、`npm run build` 与 `git diff --check` 全部通过。
370
+
371
+ - 这一轮(「修改.txt」四条:优化组件性能 / 增加 graphic 使用 demo / 提高规范性 / 简化重复方法):① `graphic.js` 的图形节点改为静态样式只在建 DOM 时写一次,相机与 resize 布局缓存 `left` / `top` / `width` / `height` 和隐藏状态、只在变化时写;`snapshotScene()` 不再为了取坐标写 DOM,图片加载只重排对应图形,增删改收口到 `markChanged()`、三处重复排序收口到 `sortedEntries()`。② 新增 `docs/demos/GraphicDemo.vue`(页签「扩展图形」):SVG 路径 / 图片 / Canvas 三类同屏,现场切 `scaleWithView`、改旋转 / 透明度 / `zIndex`,并演示 `addGraphic` / `addGraphics` / `updateGraphic` / `removeGraphic` / `clearGraphics` / `getGraphics()`;演示页签 20 → 21。③ 规范性:`addGraphics` 重复 id 与 `addGraphic` 一样点名告警,显式非法 `type` 跳过并报原因,不再静默按 `path` 推断。④ 简化:删除只转发 `resolvePointMerge(true / false)` 的 `confirmPointMerge` / `cancelPointMerge` 两个别名,实例成员 260 → **258**(方法 257 → 255),类型、手册、demo 与 API 清单同步。验证:14 个自测页 **1954** 条 0 FAIL(`selftest-features` 558、`selftest-demos` 262);`npx tsc --noEmit`、`npm run check:docs`(258 个成员 / 255 个方法 / 88 个 options / 236 个数据字段)、`node docs/steps/gen-api-index.mjs --check`、`npm run build` 与 `git diff --check` 全部通过。
372
+
373
+ - 这一轮(「修改.txt」五条续:性能 / 规范性 / 简化 / 文档准确性 / 页面展示):① `overlay.js` 的 GeoJSON 区域文字改为按下标复用 DOM、逐条用 `JSON.stringify([...])` 生成签名,单条文字或样式变化只更新那一条并作废对应尺寸缓存;`display` / `transform` 按节点缓存,同一相机重复刷新不再写 `style`。② `minimap.js` 的鹰眼视口框缓存上一次的位置与尺寸,没变就直接返回;`create.js` 新增 `fallbackViewport()`,统一覆盖层、鹰眼图、`getViewport()` 与 `getViewState().viewport` 的引擎未就绪兜底口径;`graphic.js` 删除未使用的 `GRAPHIC_ANCHOR_NAMES`。③ API 速查页补齐深色主题(与文档中心共用 `gisDocs.reading`)、左侧分组滚动 / 点选高亮、`scroll-margin-top` 深链落点、卡片 / 代码块 / 窄屏 / 滚动条展示细节,快速开始里的成员数改为读取 `API_SUMMARY.members`,不再写死。④ 同步 `docs/GisView.md`、`docs/manual/20-性能与大数据.md`、`docs/steps/README.md` 与 API 速查说明。验证:14 个自测页 **1958** 条 0 FAIL(`selftest-labels` 129、`selftest-docs` 125);`npx tsc --noEmit`、`npm run check:docs`(258 个成员 / 255 个方法 / 236 个数据字段 / 88 个 options / 18 个功能开关 / 15 个分组)、`node docs/steps/gen-api-index.mjs --check`、`npm run build` 与 `git diff --check` 全部通过。
374
+
375
+ - 这一轮(「修改.txt」两条:装饰吸附分级 / 继续简化优化):① 动态装饰器的节点吸附改成两级:先选「跟随 / 固定」,固定档再选「固定位置 / 鼠标位置」;API 仍对应 `placement: offset / fixed / pointer`,鼠标位置档不传 `at`。② 合并 13 个重复的单项 / 清空快捷入口:`setEffects` / `setPointSize` / `setPointSymbol` / `setPointColor` / `setLineWidth` / `setLineColor` / `setChannelWidth` / `setChannelNodeWidth` / `setChannelInset` / `setChannelTangentInset` / `setChannelName` / `clearFilter` / `clearDropPreview` 从实例删除,分别统一到 `updateOptions({ effects })` / `updatePoint` / `updateLine` / `updateChannel` / `setFilter(null)` / `setDropPreview(null)`。③ `getChannel()` 改走引擎窄查询 `getChannel(channelId, index)`,不再复制全部通道再查找。实例成员 254 → **241**(方法 251 → **238**,属性仍为 3),数据字段 / options / 功能开关 / 分组保持 **238 / 90 / 18 / 16**。验证:14 个自测页 **2022** 条 0 FAIL(`selftest-features` 582、`selftest-demos` 283、`selftest-docs` 130);`npx tsc --noEmit`、`npm run check:docs`、`node docs/steps/gen-api-index.mjs --check`、`npm run build` 与 `git diff --check` 全部通过。
376
+
377
+ - 这一轮(「修改.txt」两条:装饰 Demo 的吸附方式与位置解耦 / 继续简化优化):① 节点草稿的 `placement` 收窄为**位置来源**(`offset` 相对节点 / `fixed` 固定坐标 / `pointer` 鼠标位置),新增 `anchor` 表示**落地关系**(`follow` 跟随节点 / `fixed` 钉在世界坐标);两者自由组合,所以「跟随 / 固定」与三种位置来源的笛卡尔积都可用,缺省仍是 `offset → follow`、`fixed / pointer → fixed`。`DecorationDraftDemo.vue` 的「吸附方式」只留跟随 / 固定,「位置来源」三档始终显示,日志与确认文案同时显示当前组合。② 删除 `GisViewPointDecoration.placement` 这个与 `anchor` 重叠的旧别名,节点数据只保留 `anchor: 'offset' | 'fixed'`;草稿候选对象去掉未使用的 `placement` / `at` 临时字段,只留 `anchor` / `offset` / `world` / `screen`。实例成员 / 数据字段 / options / 功能开关 / 分组计数保持 **241 / 238 / 90 / 18 / 16**。验证:14 个自测页 **2031** 条 0 FAIL(`selftest-decoration` 75、`selftest-demos` 286,新增 9 条正交组合断言);`npx tsc --noEmit`、`npm run check:docs`、`node docs/steps/gen-api-index.mjs --check`、`npm run build` 与 `git diff --check` 全部通过。
package/dist/gis-view.css CHANGED
@@ -1 +1 @@
1
- .gis-view{box-sizing:border-box;--gis-view-cursor-grab:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23ffffff' stroke='%23ffffff' stroke-width='3' stroke-linejoin='round'/><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%2325313f'/></svg>") 12 12, grab;--gis-view-cursor-grabbing:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23ffffff' stroke='%23ffffff' stroke-width='3' stroke-linejoin='round'/><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%232f6fd0'/></svg>") 12 12, grabbing;--gis-view-cursor-move:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23ffffff' stroke='%23ffffff' stroke-width='3' stroke-linejoin='round'/><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23c2761b'/></svg>") 12 12, move;--gis-view-cursor-box:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 3.5V9M12 15v5.5M3.5 12H9M15 12h5.5' fill='none' stroke='%23ffffff' stroke-width='4.6' stroke-linecap='round'/><circle cx='12' cy='12' r='2.8' fill='%23ffffff'/><path d='M12 3.5V9M12 15v5.5M3.5 12H9M15 12h5.5' fill='none' stroke='%2325313f' stroke-width='1.8' stroke-linecap='round'/><circle cx='12' cy='12' r='1.4' fill='%2325313f'/></svg>") 12 12, crosshair;--gis-view-cursor-copy:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><g fill='none' stroke-linejoin='round'><rect x='4' y='4' width='11' height='11' rx='2' stroke='%23ffffff' stroke-width='5.4'/><rect x='9' y='9' width='11' height='11' rx='2' stroke='%23ffffff' stroke-width='5.4'/><rect x='4' y='4' width='11' height='11' rx='2' stroke='%2325313f' stroke-width='2'/><rect x='9' y='9' width='11' height='11' rx='2' stroke='%2325313f' stroke-width='2'/></g></svg>") 12 12, copy;--gis-view-cursor-point:pointer;--gis-view-cursor-line:pointer;--gis-view-cursor-channel:pointer;--gis-view-cursor-waypoint:pointer;outline:none;width:100%;height:100%;position:relative;overflow:hidden}.gis-view__canvas{touch-action:none;width:100%;height:100%;display:block}.gis-view__labels{pointer-events:none;transform-origin:0 0;will-change:transform;position:absolute;inset:0;overflow:hidden}.gis-view__label-layer{position:absolute;inset:0}.gis-view__label-layer--hidden{visibility:hidden}.gis-view__label{white-space:nowrap;color:#1f3550;will-change:transform;background:#ffffffe0;border-radius:4px;padding:1px 6px;font-size:12px;line-height:16px;position:absolute;top:0;left:0}.gis-view__label--draggable,.gis-view__label--editable{pointer-events:auto;touch-action:none}.gis-view__label--draggable{cursor:grab}.gis-view__label--editable{cursor:pointer}.gis-view__label--dragging{cursor:grabbing;z-index:2;-webkit-user-select:none;user-select:none}.gis-view__background-label{white-space:nowrap;pointer-events:none;will-change:transform;text-shadow:0 1px 2px #ffffffe6,0 0 2px #fffc;position:absolute;top:0;left:0}.gis-view__tooltip{color:#f3f7fc;white-space:pre-line;pointer-events:none;will-change:transform;background:#172436eb;border-radius:6px;max-width:280px;padding:6px 10px;font-size:12px;line-height:18px;position:absolute;top:0;left:0}.gis-view__tooltip[hidden]{display:none}.gis-view__minimap{z-index:2;box-sizing:border-box;touch-action:none;cursor:default;position:absolute;overflow:hidden}.gis-view__minimap[hidden]{display:none}.gis-view__minimap-canvas{width:100%;height:100%;display:block}.gis-view__minimap-box{box-sizing:border-box;pointer-events:none;will-change:transform;position:absolute;top:0;left:0}.gis-view__minimap-select{box-sizing:border-box;pointer-events:none;will-change:transform;background:#3678bf1f;border:1px dashed #3678bf;display:none;position:absolute;top:0;left:0}
1
+ .gis-view{box-sizing:border-box;--gis-view-cursor-grab:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23ffffff' stroke='%23ffffff' stroke-width='3' stroke-linejoin='round'/><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%2325313f'/></svg>") 12 12, grab;--gis-view-cursor-grabbing:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23ffffff' stroke='%23ffffff' stroke-width='3' stroke-linejoin='round'/><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%232f6fd0'/></svg>") 12 12, grabbing;--gis-view-cursor-move:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23ffffff' stroke='%23ffffff' stroke-width='3' stroke-linejoin='round'/><path d='M12 2 16 6 13 6 13 11 18 11 18 8 22 12 18 16 18 13 13 13 13 18 16 18 12 22 8 18 11 18 11 13 6 13 6 16 2 12 6 8 6 11 11 11 11 6 8 6Z' fill='%23c2761b'/></svg>") 12 12, move;--gis-view-cursor-box:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 3.5V9M12 15v5.5M3.5 12H9M15 12h5.5' fill='none' stroke='%23ffffff' stroke-width='4.6' stroke-linecap='round'/><circle cx='12' cy='12' r='2.8' fill='%23ffffff'/><path d='M12 3.5V9M12 15v5.5M3.5 12H9M15 12h5.5' fill='none' stroke='%2325313f' stroke-width='1.8' stroke-linecap='round'/><circle cx='12' cy='12' r='1.4' fill='%2325313f'/></svg>") 12 12, crosshair;--gis-view-cursor-copy:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><g fill='none' stroke-linejoin='round'><rect x='4' y='4' width='11' height='11' rx='2' stroke='%23ffffff' stroke-width='5.4'/><rect x='9' y='9' width='11' height='11' rx='2' stroke='%23ffffff' stroke-width='5.4'/><rect x='4' y='4' width='11' height='11' rx='2' stroke='%2325313f' stroke-width='2'/><rect x='9' y='9' width='11' height='11' rx='2' stroke='%2325313f' stroke-width='2'/></g></svg>") 12 12, copy;--gis-view-cursor-point:pointer;--gis-view-cursor-line:pointer;--gis-view-cursor-channel:pointer;--gis-view-cursor-waypoint:pointer;outline:none;width:100%;height:100%;position:relative;overflow:hidden}.gis-view__canvas{touch-action:none;width:100%;height:100%;display:block}.gis-view__graphics{pointer-events:none;z-index:1;isolation:isolate;position:absolute;inset:0;overflow:hidden}.gis-view__graphic{pointer-events:none;will-change:transform, left, top, width, height;position:absolute;top:0;left:0}.gis-view__graphic-image{pointer-events:none;-webkit-user-select:none;user-select:none}.gis-view__labels{pointer-events:none;z-index:2;contain:layout style paint;isolation:isolate;transform-origin:0 0;will-change:transform;position:absolute;inset:0;overflow:hidden}.gis-view__label-layer{position:absolute;inset:0}.gis-view__label-layer--hidden{visibility:hidden}.gis-view__label{white-space:nowrap;color:#1f3550;background:#ffffffe0;border-radius:4px;padding:1px 6px;font-size:12px;line-height:16px;position:absolute;top:0;left:0}.gis-view__label--draggable,.gis-view__label--editable{pointer-events:auto;touch-action:none}.gis-view__label--draggable{cursor:grab}.gis-view__label--editable{cursor:pointer}.gis-view__label--dragging{cursor:grabbing;z-index:2;-webkit-user-select:none;user-select:none}.gis-view__background-label{white-space:nowrap;pointer-events:none;text-shadow:0 1px 2px #ffffffe6,0 0 2px #fffc;position:absolute;top:0;left:0}.gis-view__tooltip{color:#f3f7fc;white-space:pre-line;pointer-events:none;will-change:transform;background:#172436eb;border-radius:6px;max-width:280px;padding:6px 10px;font-size:12px;line-height:18px;position:absolute;top:0;left:0}.gis-view__tooltip[hidden]{display:none}.gis-view__minimap{z-index:2;box-sizing:border-box;contain:layout paint;isolation:isolate;touch-action:none;cursor:default;position:absolute;overflow:hidden}.gis-view__minimap[hidden]{display:none}.gis-view__minimap-canvas{width:100%;height:100%;display:block}.gis-view__minimap-box{box-sizing:border-box;pointer-events:none;will-change:transform;position:absolute;top:0;left:0}.gis-view__minimap-select{box-sizing:border-box;pointer-events:none;will-change:transform;background:#3678bf1f;border:1px dashed #3678bf;display:none;position:absolute;top:0;left:0}