gis-view-webgl2 0.1.7 → 0.1.9
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.
- package/README.md +14 -11
- package/dist/gis-view.css +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +445 -241
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +65 -498
- package/docs/GisView.md +1 -1
- package/docs/GisView/345/256/236/347/216/260/345/216/237/347/220/206.md +1 -1
- 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 -478
- package/docs/demos/BasicDemo.vue +144 -27
- package/docs/demos/BatchAddDemo.vue +133 -7
- package/docs/demos/ChannelDemo.vue +61 -0
- package/docs/demos/ConnectDemo.vue +164 -33
- package/docs/demos/CopyMergeDemo.vue +144 -42
- package/docs/demos/EventDemo.vue +29 -24
- package/docs/demos/LabelDemo.vue +5 -5
- package/docs/demos/api-index.js +53 -41
- package/docs/demos/gis-view-demo/GisViewDemoCardHeader.vue +1 -1
- package/docs/demos/gis-view-demo/GisViewDemoStage.vue +1 -1
- package/docs/demos/gis-view-demo/panels/DataPanels.vue +1 -1
- package/docs/demos/gis-view-demo/useGisViewDemo.js +31 -33
- package/docs/format/02-/350/212/202/347/202/271/344/270/216/347/272/277/350/267/257.md +1 -0
- package/docs/format/04-/351/200/232/351/201/223/344/270/216/346/240/207/347/255/276.md +3 -0
- 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 +8 -7
- package/docs/from0/05-/347/233/270/346/234/272/344/270/216/344/272/244/344/272/222.md +1 -1
- package/docs/from0/07-/351/200/232/351/201/223/345/210/206/347/273/204/344/270/216/345/244/232/345/233/236/347/272/277.md +26 -10
- package/docs/index.html +136 -13
- package/docs/internals/15-04-/351/200/220/350/275/256/350/256/260/345/275/225-/347/203/255/345/212/233/345/233/276/344/270/216/346/200/247/350/203/275.md +10 -0
- package/docs/manual/02-/345/235/220/346/240/207/344/270/216/346/225/260/346/215/256.md +1 -1
- package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +82 -14
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +23 -17
- package/docs/manual/05-/347/224/273/350/264/250/344/270/216/346/211/271/351/207/217/346/233/264/346/226/260.md +65 -0
- 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 +9 -10
- 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 +100 -40
- package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +11 -7
- package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +66 -6
- 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 +226 -493
- package/docs/manual/12-/346/240/207/347/255/276/344/270/216/350/243/205/351/245/260.md +28 -5
- package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +46 -14
- package/docs/manual/15-/345/257/274/345/207/272/344/270/216/351/233/206/346/210/220.md +5 -2
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +34 -29
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +30 -22
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +168 -81
- 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 +1 -1
- package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +5 -3
- 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 +9 -6
- package/docs/steps/README.md +201 -120
- package/docs/steps/bench-scale.html +1 -1
- package/docs/steps/index.html +222 -6
- package/docs/steps/selftest-actions.html +26 -25
- package/docs/steps/selftest-data.html +1 -1
- package/docs/steps/selftest-demos.html +290 -16
- package/docs/steps/selftest-docs.html +17 -6
- package/docs/steps/selftest-features.html +594 -54
- package/docs/steps/selftest-full.html +3 -3
- package/docs/steps/selftest-labels.html +82 -1
- package/docs/steps/selftest-perf.html +62 -7
- package/docs/steps/selftest-select.html +71 -6
- package/docs/steps/step-05-pick.js +4 -8
- package/docs/steps/step-07-channels.js +3 -5
- package/docs/steps/step-08-labels.js +3 -3
- package/docs/steps/step-10-full.js +3 -3
- package/docs/steps/step-12-events.js +41 -24
- package/docs//344/273/2160/345/210/260/345/256/214/346/225/264/347/232/204/345/256/236/347/216/260.md +1 -0
- package/package.json +1 -1
- package/docs/ai/01-/350/265/267/346/272/220/344/270/216/350/277/231/344/273/275/346/261/207/346/200/273/347/232/204/347/224/261/346/235/245.md +0 -29
- package/docs/ai/02-/346/214/211/345/206/205/345/256/271/345/210/206/347/261/273-/350/277/231/344/270/200/350/267/257/351/203/275/345/234/250/346/224/271/344/273/200/344/271/210.md +0 -66
- package/docs/ai/03-/351/207/215/350/246/201/351/227/256/347/255/224/351/200/211/357/274/210/344/270/200/357/274/211/357/274/232/351/200/211/345/236/213/351/200/232/351/201/223/344/270/216/346/240/267/345/274/217.md +0 -178
- package/docs/ai/04-/351/207/215/350/246/201/351/227/256/347/255/224/351/200/211/357/274/210/344/272/214/357/274/211/357/274/232/344/272/244/344/272/222/346/200/247/350/203/275/344/270/216/346/225/260/346/215/256.md +0 -140
- package/docs/ai/05-/351/207/215/350/246/201/351/227/256/347/255/224/351/200/211/357/274/210/344/270/211/357/274/211/357/274/232/345/256/277/344/270/273/346/227/201/346/224/257/344/270/216/346/224/266/345/217/243.md +0 -43
package/docs/steps/README.md
CHANGED
|
@@ -1,140 +1,214 @@
|
|
|
1
|
-
# 从 0 手写 gis-view:分步 demo
|
|
1
|
+
# 从 0 手写 gis-view:分步 demo 与学习路线
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
十三步连起来正好把 `src/gis-view/` 的每一块都亲手写一遍(第 10 步之后是「换成真组件再补配置」,所以 10 ~ 13 步共用同一份数据)。配套的完整说明见
|
|
5
|
-
[《从 0 到完整的实现》](../从0到完整的实现.md);更粗的版本(一份文件写完)在 [`docs/mini`](../mini/index.html)。
|
|
3
|
+
这里不是 API 大全,而是一条**能亲手走完的搭建路线**:十三个文件,每一步只增加一件事,前一步的成果就是下一步的输入。第 1 ~ 9 步手写渲染与交互,第 10 步换成真实 `createGisView`,第 11 ~ 13 步补首屏、动作判读与上线配置。
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
配套材料分工如下:
|
|
6
|
+
|
|
7
|
+
- **边跑边看**:[`docs/steps/index.html`](index.html)。切步骤、看画面、读当前步骤的「产出 / 验收 / 源码对照」。
|
|
8
|
+
- **照着源码写**:[从 0 到完整的实现](../从0到完整的实现.md)。先看四段路线,再进 `docs/from0/13` / `14` 的可照抄代码。
|
|
9
|
+
- **只想使用组件**:[GisView 手册](../GisView.md)。不用从渲染管线读起。
|
|
10
|
+
- **查某个方法**:[API 速查](../api/index.html) 与 [`manual/18`](../manual/18-逐方法示例.md)。
|
|
11
|
+
|
|
12
|
+
## 30 秒跑起来
|
|
8
13
|
|
|
9
14
|
```bash
|
|
10
|
-
npm
|
|
15
|
+
npm install
|
|
16
|
+
npm run dev
|
|
11
17
|
# 打开 http://localhost:5173/docs/steps/index.html
|
|
12
18
|
```
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
每一步能接上的回调就自动接上(前面的步骤还没有那些事件,对应的按钮会自动灰掉)。
|
|
16
|
-
控制台里 `__gisSteps.view` 就是当前这一步的视图,`__gisSteps.DATA` 是那份园区数据,可以随手调 API。
|
|
17
|
-
地址栏里带步骤号(`index.html#7`)可以直接打开某一步,也能收藏 / 分享。
|
|
20
|
+
页面顶部的四张卡就是学习路线,点击会跳到对应步骤。每一步下方固定显示三块信息:
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
1. **本步产出**:这一步只解决什么问题。
|
|
23
|
+
2. **完成标准**:不看答案时,怎样判断自己真的做对了。
|
|
24
|
+
3. **源码对照**:回到 `src/gis-view/` 应该读哪个文件。
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
控制台里 `__gisSteps.view` 是当前步骤的视图,`__gisSteps.DATA` 是园区数据;地址栏 `#7` 可以直接打开第 7 步。建议每完成一步都改一个数、拖一次画布、看一次读数,再进入下一步。
|
|
27
|
+
|
|
28
|
+
## 先选路线
|
|
29
|
+
|
|
30
|
+
| 你的目标 | 建议顺序 | 不必先读 |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| 在业务项目里使用组件 | [`manual/01`](../manual/01-快速开始.md) → `GisView.md` → 对应 Demo | WebGL 着色器细节 |
|
|
33
|
+
| 从零写一遍,理解每一块 | 本页四段路线 → `docs/from0/13` / `14` → 对照源码 | 逐轮历史 |
|
|
34
|
+
| 修改或扩展当前组件 | 本页源码对照 → `GisView实现原理.md` → `docs/internals` | 从第 1 步重写一遍 |
|
|
35
|
+
| 排查性能 / 内存问题 | `manual/20` → `internals/18` → 自测页 | 先盲改渲染代码 |
|
|
36
|
+
|
|
37
|
+
> 不要一开始同时读 21 章手册、23 份实现原理和 93 轮记录。按目标选一条线,做完一个可运行的闭环,再扩阅读面。
|
|
38
|
+
|
|
39
|
+
## 四段路线与十三步验收
|
|
40
|
+
|
|
41
|
+
### 第 1 段:先让画面成立(1 ~ 3)
|
|
42
|
+
|
|
43
|
+
| 步骤 | 本步产出 | 完成标准 | 源码对照 |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| [`step-01-canvas.js`](step-01-canvas.js) | 跟随容器尺寸的 canvas、相机矩阵雏形、按需重绘入口 | 改窗口大小画布不糊;静止时不持续空转 | `engine.js` 的上下文 / resize / `requestRender` |
|
|
46
|
+
| [`step-02-points.js`](step-02-points.js) | 点的实例缓冲,一次 draw call 画完所有节点 | 改节点数量画面跟着变;圆 / 方边缘抗锯齿 | `point.js` + `shaders.js` |
|
|
47
|
+
| [`step-03-lines.js`](step-03-lines.js) | 每段线展开成四边形,顶点着色器里撑开线宽 | 缩放时线宽保持屏幕像素;折线不断裂 | `line.js` + `shaders.js` |
|
|
48
|
+
|
|
49
|
+
这一段不要接业务样式,也不要做标签。先把「输入几何 → 实例数据 → 一帧画面」跑通。
|
|
50
|
+
|
|
51
|
+
### 第 2 段:看懂视角与命中(4 ~ 5)
|
|
52
|
+
|
|
53
|
+
| 步骤 | 本步产出 | 完成标准 | 源码对照 |
|
|
54
|
+
| --- | --- | --- | --- |
|
|
55
|
+
| [`step-04-camera.js`](step-04-camera.js) | `fitView` / 滚轮缩放 / 拖动平移 | 滚轮围绕指针缩放;拖动像素跟手;适应视图包住数据 | `engine.js` 相机段 |
|
|
56
|
+
| [`step-05-pick.js`](step-05-pick.js) | 屏幕坐标拾取与六类指针回调 | 点、线、空白各自有明确结果;拖动不误报点击 | `utils.js` + `engine.js` |
|
|
57
|
+
|
|
58
|
+
这一段的关键不是事件名多,而是先统一「屏幕 ↔ 世界」换算。所有命中与拖拽都应该复用同一套相机和画布矩形。
|
|
59
|
+
|
|
60
|
+
### 第 3 段:长成业务组件(6 ~ 9)
|
|
61
|
+
|
|
62
|
+
| 步骤 | 本步产出 | 完成标准 | 源码对照 |
|
|
63
|
+
| --- | --- | --- | --- |
|
|
64
|
+
| [`step-06-style.js`](step-06-style.js) | 业务字段到样式的规则层 | 改规则不改业务数据;状态样式仍优先 | `rules.js` + `condition.js` |
|
|
65
|
+
| [`step-07-channels.js`](step-07-channels.js) | 通道骨架、平行回线与新增草稿 | 两次点击落成通道;回线间距稳定;取消不写数据 | `channel.js` + `engine.js` |
|
|
66
|
+
| [`step-08-labels.js`](step-08-labels.js) | DOM 标签、避让与提示框 | 平移缩放后标签贴住要素;超限能隐藏 / 避让 | `overlay.js` |
|
|
67
|
+
| [`step-09-minimap.js`](step-09-minimap.js) | 鹰眼图全景层、视口框与联动 | 视口框准确;点 / 拖能定位主图;销毁不残留 | `minimap.js` |
|
|
68
|
+
|
|
69
|
+
到这里,建议每加一层都问一句:它拿到的是原始业务数据,还是已经解析好的渲染实例?不要把所有判断都塞进渲染循环。
|
|
70
|
+
|
|
71
|
+
### 第 4 段:接入真组件并上线(10 ~ 13)
|
|
72
|
+
|
|
73
|
+
| 步骤 | 本步产出 | 完成标准 | 源码对照 |
|
|
74
|
+
| --- | --- | --- | --- |
|
|
75
|
+
| [`step-10-full.js`](step-10-full.js) | 用真实 `createGisView` 替换手写实现 | 同一份数据结果一致;销毁后监听、定时器与 GL 资源都归口 | `create.js` |
|
|
76
|
+
| [`step-11-background.js`](step-11-background.js) | 背景层、`initialView` 与顶层 `center` / `scale` | 底图可切换;首屏中心与比例准确;显式 `initialView` 整份优先 | `background.js` + `geojson.js` + `engine.js` |
|
|
77
|
+
| [`step-12-events.js`](step-12-events.js) | 稳定的 `action` 判读与三组只读查询 | 点击 / 框选 / 拖拽 / 右键能分清;查询与事件载荷同口径 | `engine.js` + `create.js` |
|
|
78
|
+
| [`step-13-engineering.js`](step-13-engineering.js) | 画质、批量、历史与功能预设 | 一批更新只发一次数据变更、只记一步历史;撤销 / 重做正确 | `quality.js` + `history.js` + `features.js` |
|
|
79
|
+
|
|
80
|
+
第 10 步之后不再重复「手写一遍」,而是学习**如何把组件接进业务**:数据副本、首屏落位、事件判读、批量提交、销毁和上线开关。
|
|
81
|
+
|
|
82
|
+
## 每一步怎么练
|
|
83
|
+
|
|
84
|
+
固定做五个动作,比一口气复制完整源码更有效:
|
|
85
|
+
|
|
86
|
+
1. **只跑这一步**:先看默认画面和读数,确认动手前基线是正常的。
|
|
87
|
+
2. **从头到尾读对应文件**:先读导出函数与选项,再读主循环;暂时跳过与当前步骤无关的补丁函数。
|
|
88
|
+
3. **只改一个变量**:节点数、颜色、线宽、拾取半径、标签上限……一次只改一个,看画面与读数如何变化。
|
|
89
|
+
4. **对照完成标准**:不靠“看起来差不多”,而是按本步验收逐条过。
|
|
90
|
+
5. **用一句话记数据流**:例如“点数组经规则解析,写进实例缓冲,再由相机矩阵投到屏幕”。写不出来说明这一步还没真正掌握。
|
|
91
|
+
|
|
92
|
+
## 搭建思路:先把四条边界划清
|
|
22
93
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
| 3 | `step-03-lines.js` | 每段线一个实例,线宽在顶点着色器里撑开 | `setLines` / `getSegments` | 第 3 章 |
|
|
38
|
-
| 4 | `step-04-camera.js` | 滚轮缩放、拖动平移、适应视图 | `fitView` / `zoomBy` / `panBy` / `project` / `unproject` | 第 4 章 |
|
|
39
|
-
| 5 | `step-05-pick.js` | 拾取(点优先于线)+ 全部指针事件回调 + 框选 | `pick` / `onHover` / `onClick` / `onDblClick` / `onPointerDown` / `onPointerUp` / `onContextMenu` / `onSelect` | 4.4 ~ 4.7 |
|
|
40
|
-
| 6 | `step-06-style.js` | 批量样式规则:数据只写业务字段,样式一次配好 | `setPointRules` / `setLineRules` | 5.1 / 5.2 |
|
|
41
|
-
| 7 | `step-07-channels.js` | 通道与多回线;新增通道草稿、连续新增、落地 / 取消 / 移除 | `setChannels` / `beginAddChannel` / `onChannelDraftClick` / `commitAddChannel` / `cancelAddChannel` / `removeLine` / `removeChannel` | 第 6 章 |
|
|
42
|
-
| 8 | `step-08-labels.js` | DOM 标签层 + 跟着光标的提示框 | `setLabelOf` / `setTooltipOf` | 第 7 章 |
|
|
43
|
-
| 9 | `step-09-minimap.js` | 鹰眼图:小画布、视口框、点与拖的联动 | `getMinimapCanvas` / `syncMinimap` | 第 8 章 |
|
|
44
|
-
| 10 | `step-10-full.js` | 换成真组件:同一份数据走公开 API,规则 / 标签 / 提示框 / 鹰眼图都改用内置配置 | `createGisView` / `createChannels` | 12.11 |
|
|
45
|
-
| 11 | `step-11-background.js` | 背景层与初始视图:五种底图档位(GeoJSON 经纬网 / 底图 / 逐区域配色 + 区域文字 / SVG 路径图片 / 关掉,底图几何与 demo 共用同一份生成器)+ 首屏只给中心点与倍数 | `background` / `geoJsonStyle` / `initialView` / `applyInitialView` | 背景层 / 初始视图 |
|
|
46
|
-
| 12 | `step-12-events.js` | 指针事件的动作判读:同一条画布上把 `action` 的每个字段边点边打印(含 `left` / `right`、`press` / `duration` / `longPress`),另给 `pickAt` / `getFeaturesInRect` 两个只读查询与程序化悬停 `hoverAt` | `createGisView` / `action` / `onSelectChange` / `pickAt` / `getFeaturesInRect` / `hoverAt` | action:一次操作的判读 / 实例方法 |
|
|
47
|
-
| 13 | `step-13-engineering.js` | 工程化四件套:画质四档(换档只影响绘制)、`batch`(一批改动作一条 `onDataChange` 与一步历史)、`history`(撤销 / 重做与两份栈读数,缺省是关的、这一步显式打开)、`features` 三个预设(`edit` / `view` / `static`) | `setQuality` / `getQuality` / `batch` / `undo` / `redo` / `getHistoryState` / `setFeatures` / `getFeatures` | 画质 / 批量更新 / 历史 / 功能开关 |
|
|
48
|
-
|
|
49
|
-
第 1 ~ 3 步先不管交互,只把「画出来」打通;第 4 ~ 6 步补上相机、拾取与样式;
|
|
50
|
-
第 7 ~ 9 步是通道、标签与鹰眼图;第 10 步把前面手写的东西换成 `src/gis-view` 里的实现,
|
|
51
|
-
API 名字与前面几步是一一对应的;第 11 步再补两件「数据之外」的配置:底图与首屏落位,
|
|
52
|
-
页面上多出的「切换底图 / 切换初始视图」两个按钮切的就是这两项 —— 底图切到「labels」能看到
|
|
53
|
-
`aspectScale` / 逐区域配色 / 区域文字,切到「image」是只给 `d` 字符串的 SVG 路径图片。
|
|
54
|
-
第 12 步回到事件本身:同一条画布上边点边看 `action`(是什么操作 / 点到了什么 / 拿到了什么数据 / 按的是哪个键、按了多久),
|
|
55
|
-
再给两个只读查询(`pickAt` / `getFeaturesInRect`)与程序化悬停(`hoverAt` / `clearHover`)—— 页面上多出来的「框内有什么」
|
|
56
|
-
按钮、「判读 / 这儿是什么」两行读数就是它们,鼠标停在「程序化悬停」按钮上会联动高亮视口里第一个节点。
|
|
57
|
-
第 13 步换到「上线前要配什么」:画质四档换档不重排也不动数据、`batch` 把一千次改动作一条记录、
|
|
58
|
-
`history` 给出撤销 / 重做与两份栈、`features` 用 `edit` / `view` / `static` 三个预设一次切好交互口径 ——
|
|
59
|
-
工具条的「画质档 / 批量移动 / 撤销 / 重做 / 功能预设」与读数栏最后三行(画质 / 历史 / 功能)就是它们;
|
|
60
|
-
历史显式打开(`history: { limit: 100 }`),点几次「批量移动」再用「撤销 / 重做」走一遍,能直接看到
|
|
61
|
-
`onDataChange` 那一条 `type: batch` 里躺着 8 笔改动、历史里却只有一步。
|
|
62
|
-
|
|
63
|
-
## 逐轮记录去哪儿了
|
|
64
|
-
|
|
65
|
-
从立项到现在的每一轮「修改.txt / 问题.txt」的落点表都搬到了 [docs/steps/rounds/](rounds/README.md)(共 93 轮 / 9 页,按时间排序);
|
|
66
|
-
本文件只留「怎么用这个文件夹」的部分:下面「十三步分别写了什么」讲每一步的成品,「三条需求分别落在哪」是最早那一轮的详细落点,「和库里文件的对照」把步骤文件对上库源码。
|
|
67
|
-
|
|
68
|
-
每一轮背后的实测与设计取舍在《实现原理》的 [15-01 逐轮记录](../internals/15-01-逐轮记录-新增与修复.md) 与 [16-01 优化与取舍](../internals/16-01-优化与取舍-上.md);
|
|
69
|
-
文档中心里这三层是并排的:`steps/README.md`(用法)、`steps/rounds/`(逐轮)、`internals/`(原理)。
|
|
70
|
-
## 三条需求分别落在哪
|
|
71
|
-
|
|
72
|
-
### 1. 新增通道:连续新增 + 每次点击都有回调
|
|
73
|
-
|
|
74
|
-
- 第 7 步(`step-07-channels.js`)是手写版:`beginAddChannel({ continuous, chain })` 进草稿之后,
|
|
75
|
-
**每一次点击**都发 `onChannelDraftClick`,载荷里的 `step` 直接告诉你这是第几次:
|
|
76
|
-
`step: 1` 是刚拿到起点(`payload.from`)、`step: 2` 是刚拿到终点(`payload.to`,`finished: true` 表示线路到此结束);
|
|
77
|
-
点空白 / 点回起点也会发一条(`step: 0`、`hit` 标记有没有点到节点、`reason` 说明原因)。
|
|
78
|
-
- 第二次点击之后线路就结束了,接下来是三条路:`commitAddChannel()` 落地成真实数据、
|
|
79
|
-
`cancelAddChannel()` 取消、`removeLine(lineId)` / `removeChannel(channelId)` 把刚落地的东西摘掉。
|
|
80
|
-
- 不想每加一条就重新点「新增通道」:`continuous: true` 时落地后自动重开一段(发 `phase: 'restart'`),
|
|
81
|
-
`chain: true`(或 `continuous: 'chain'`)再以这一段终点当下一段的起点,一路点下去就是首尾相接的一条条线路。
|
|
82
|
-
- 第 10 ~ 11 步与 `docs/demos/GisViewDemo.vue` 用的是真组件上的同名 API:
|
|
83
|
-
`view.beginAddChannel()` / `view.getAddChannelDraft()` / `view.continueAddChannel()` /
|
|
84
|
-
`view.commitAddChannel()` / `view.cancelAddChannel()` / `view.removeLine()` / `view.removeChannel()`。
|
|
85
|
-
|
|
86
|
-
### 2. 单击 / 双击 / 悬停 / 右键 / 左键都暴露回调
|
|
87
|
-
|
|
88
|
-
第 5 步起,同一个载荷结构贯穿所有鼠标动作:
|
|
89
|
-
|
|
90
|
-
| 回调 | 什么时候发 | 载荷 |
|
|
94
|
+
整个组件不是“一个巨大的渲染函数”,而是五层边界清楚的数据流:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
业务数据
|
|
98
|
+
→ 解析层(坐标、样式、规则、通道几何)
|
|
99
|
+
→ 场景 / 实例层(点、线、回线、图形)
|
|
100
|
+
→ 渲染与覆盖层(WebGL2 / DOM 标签 / 鹰眼图)
|
|
101
|
+
→ 相机与视口(世界、屏幕、CSS 像素)
|
|
102
|
+
→ 指针事件(拾取回查、动作判读、业务回调)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
开始写之前,先回答下面四个问题:
|
|
106
|
+
|
|
107
|
+
| 边界 | 必须固定下来的内容 | 常见返工原因 |
|
|
91
108
|
| --- | --- | --- |
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
97
|
-
|
|
109
|
+
| 数据契约 | `id`、坐标、端点引用、业务字段、缺省值 | 一会儿按下标、一会儿按 id;线上要素没有唯一身份 |
|
|
110
|
+
| 坐标契约 | 世界坐标是什么;中心 / 比例怎么定义;屏幕锚点用哪种像素 | 相机、拾取、标签各写一套换算 |
|
|
111
|
+
| 渲染契约 | 哪些数据进入 GPU;哪些状态只改样式;一次更新影响哪些缓冲 | 每帧重排全部场景;改颜色却重建 GPU 缓冲 |
|
|
112
|
+
| 交互契约 | 什么算点击、什么时候发 hover、选中集如何变化、回调载荷长什么样 | 拖动结束误发 click;上层猜不到 action.target |
|
|
113
|
+
|
|
114
|
+
### 推荐的开工顺序
|
|
115
|
+
|
|
116
|
+
1. **先做一条最小链路**:固定数据 → 点 → 线 → 相机 → 一帧画面。此时不接业务样式。
|
|
117
|
+
2. **再补交互**:屏幕拾取、拖动、框选、六个指针回调;先保证同一套坐标换算。
|
|
118
|
+
3. **然后做解析层**:规则优先级、通道几何、增量补丁;业务字段不直接散落在渲染循环里。
|
|
119
|
+
4. **覆盖层单独做**:标签和提示框是 DOM,不要和 WebGL 的点线绘制混成一个状态机。
|
|
120
|
+
5. **最后做工程化**:批量提交、历史、画质档、Worker、销毁与自测。
|
|
121
|
+
|
|
122
|
+
### 先写主流程,再写补丁
|
|
123
|
+
|
|
124
|
+
读 `engine.js` 时先抓这条主干:
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
createGisViewEngine
|
|
128
|
+
→ resolveFeatures / layoutScene
|
|
129
|
+
→ buildScene
|
|
130
|
+
→ render
|
|
131
|
+
→ pointer handlers
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
其他函数先当作“主干上的加速或兼容补丁”。第一次读不要从几百个工具函数按文件顺序硬啃。
|
|
135
|
+
|
|
136
|
+
## 完成整条路线后的验收清单
|
|
137
|
+
|
|
138
|
+
- [ ] 空容器能创建视图;宽高变化后画布跟随,CSS 缩放不模糊。
|
|
139
|
+
- [ ] 点、线、通道回线都能稳定绘制;缩放后节点尺寸与线宽符合预期。
|
|
140
|
+
- [ ] `fitView()` 能完整展示数据,滚轮围绕指针缩放,拖动平移跟手。
|
|
141
|
+
- [ ] 点、线、空白都能正确拾取;点击、双击、右键、拖动互不误判。
|
|
142
|
+
- [ ] 规则只改渲染样式,不改业务数据;状态样式优先级高于规则。
|
|
143
|
+
- [ ] 通道由公共骨架与平行回线组成;新增 / 取消 / 删除都不会留下脏数据。
|
|
144
|
+
- [ ] 标签与提示框随相机更新;超限时隐藏或避让,不拖垮交互帧率。
|
|
145
|
+
- [ ] 鹰眼图视口框与主图一致;点击、拖动、销毁都正常。
|
|
146
|
+
- [ ] 首屏可用 `initialView`,也可用顶层 `center` / `scale`;显式 `initialView` 优先。
|
|
147
|
+
- [ ] `onCameraChange` / `cameraChange` 能同时拿到中心与比例。
|
|
148
|
+
- [ ] 一批修改只发一次数据变更、只记一步历史;撤销 / 重做可回到预期状态。
|
|
149
|
+
- [ ] `destroy()` 后不再发回调、不再占动画帧,定时器、监听、Worker、DOM 与 WebGL 资源都有归口。
|
|
150
|
+
- [ ] `npx tsc --noEmit`、`npm run build`、`npm run check:docs` 全通过。
|
|
151
|
+
|
|
152
|
+
## 优化方向:按瓶颈排队,不按兴趣排队
|
|
153
|
+
|
|
154
|
+
| 优先级 | 先做什么 | 何时才做 | 怎么确认 |
|
|
155
|
+
| --- | --- | --- | --- |
|
|
156
|
+
| 0 | 用 `getStats()`、帧耗时与浏览器 Performance 找瓶颈 | 每次优化开始前 | 优化前后同一设备、同一数据、同一视角 |
|
|
157
|
+
| 1 | 减少每帧重排与全量解析 | 更新一个点却重算整场景时 | 增量更新前后 `dataChange` 次数与帧耗时 |
|
|
158
|
+
| 2 | 合并更新、批量提交、增量上传 GPU | 连续多次修改导致闪烁或卡顿时 | 一批 N 次修改只产生一次数据变更 / 一次上传 |
|
|
159
|
+
| 3 | 按需渲染、交互期轻量帧、停手补全质量帧 | 静止时还在持续消耗 CPU / GPU 时 | rAF 次数、GPU 占用、静止画面 fps 读数 |
|
|
160
|
+
| 4 | 裁剪不可见实例、标签上限、聚合与线路批次 | 数据量大但屏幕覆盖有限时 | `lineInstances`、实际 draw call、可见标签数 |
|
|
161
|
+
| 5 | 标签改 Canvas、加速避让索引、合并重投影 | DOM 标签数量成为主瓶颈时 | 标签 DOM 数、交互帧耗时、单帧重排次数 |
|
|
162
|
+
| 6 | 把筛选 / 搜索移入 Worker | 主线程被纯计算占满且可转移时 | Worker 往返耗时与主线程长任务 |
|
|
163
|
+
| 7 | 画质档、降级与回滞策略 | 不同设备需要不同上限时 | 各档画质与交互读数 |
|
|
164
|
+
| 8 | 评估 WebGPU / 新后端 | 前面几层都已做尽,瓶颈仍在 GPU | 同场景对照实测,而不是只看理论带宽 |
|
|
165
|
+
|
|
166
|
+
不要先做的三件事:为了“看起来高级”重写着色器、在数据量还很小时上 Worker、没有基线就同时改五处。项目的优化记录见 [`docs/internals/18`](../internals/18-性能实测与WebGPU评估.md)。
|
|
167
|
+
|
|
168
|
+
## 怎么查全部属性与方法
|
|
169
|
+
|
|
170
|
+
当前公开面是:实例成员 **273** 个(268 个方法 + `el` / `canvas` / `gl` / `cameraAnimating` / `dataVersion` 五个属性),`options` **100** 个键,数据字段 **266** 个,事件 **44** 个。查法有五处,口径相同:
|
|
171
|
+
|
|
172
|
+
- **按主题读手册**:[`docs/manual/`](../manual/) 共 21 章;找方法先看 [`16 实例方法总表`](../manual/16-实例方法总表.md),查参数看 [`17 参数速查`](../manual/17-参数速查.md)。
|
|
173
|
+
- **复制调用示例**:[`18 逐方法示例`](../manual/18-逐方法示例.md) 的每一段都可以直接改参数运行;API 速查页读的就是这一章。
|
|
174
|
+
- **页面搜索**:[`docs/api/index.html`](../api/index.html) 支持搜索、分组、方法 / 属性 / options 筛选,以及 `#成员名` 深链。
|
|
175
|
+
- **边改边跑**:[`docs/playground/index.html`](../playground/index.html) 里已有真实实例、示波数据和文档示例;改代码后直接看返回值和错误。
|
|
176
|
+
- **类型契约**:[`src/gis-view/types.d.ts`](../../src/gis-view/types.d.ts) 是对外类型唯一来源;改公开 API 后同步这里,再跑类型检查。
|
|
98
177
|
|
|
99
|
-
|
|
100
|
-
`world` 是光标处的世界坐标,`x` / `y` 是画布像素,命中空白处 `hit: false`、`type: null`。
|
|
178
|
+
生成物不要手改:改完手册的实例方法 / 参数 / 示例后运行 `node docs/steps/gen-api-index.mjs`,再用 `npm run check:docs` 对账。
|
|
101
179
|
|
|
102
|
-
|
|
180
|
+
## 自测页与工程门禁
|
|
103
181
|
|
|
104
|
-
|
|
182
|
+
所有自测页都在本目录,直接经 dev server 打开即可;标题会报 `PASS` / `FAIL`,页面清单逐条列出断言:
|
|
105
183
|
|
|
106
|
-
-
|
|
107
|
-
- `selftest-full.html`:真组件上的同一套断言,外加把 `index.html` 的十三个步骤逐个挂载一遍(第 13 步再点一遍画质 / 批量 / 撤销 / 重做 / 功能预设五个按钮);
|
|
108
|
-
本轮再补五条(双回线关闭后居中代表线、`backgroundStyle` 接管画布底色、主图方形 / 圆形尺寸与 SVG 图标、`container` 外部挂载与 `offset` 动态位移、换容器复用同一根节点并随 `destroy()` 清理);之前补的四条:小图上的 GeoJSON 底图在主视图放大 3 倍前后红色描边像素数不变(容差 20%)、小图放大 6 倍时 `pointZoomScale` 指数 0 / 1 的像素对比(指数 1 至少 4 倍面积、指数 0 不长大,且倍数回到 1 时指数 1 也不再放大)、以及 stub host 上「拖节点没有结束事件、空闲计时器也会把 `hideOnInteract` 收起的标签层放出来」。
|
|
109
|
-
- `selftest-features.html`(672 条):真组件上的线型 / 线路装饰 / 光标 / 表现型配置断言 —— 把画面用 `exportImage` 读回 2D 画布数像素(实线 > 虚线 > 点线的墨量、`dc_line` 中点装饰的像素差、`showGrid` 只重画一帧),光标则用合成的指针事件与 Ctrl 键读出 `canvas.style.cursor`;装饰那几条还会量「几何变了装饰跟不跟着走」—— 写回新路径、拖绑定的节点、加 / 删拐点之后,装饰的紫色像素质心都要落在新中点上(容差 3px);另外两条量的是**固定档**:`anchor: 'fixed'` + `at` 先把装饰钉在写死的世界坐标上,再把线从水平拖成斜的,装饰必须留在原坐标、不能跑到新中点。线路标签在单独一张画布上验:默认挂在中点、内容取 `name`,`position: 0` 落到起点,`hideOnInteract` 在缩放期间给整层加 `--hidden`、停手恢复,关掉 `lineLabel` 之后标签消失。装饰缺省 `auto` 的那一串也在这里量:没有拐点时拖端点装饰保持同一个比例(一直挂在中点)、加上拐点之后钉在那一刻的坐标上(改折线也不动)、把拐点删回直线又回到比例跟随、`anchor: 'follow'` 则一直跟到折线的新中点;`parallel` 用一条横条符号验(默认包围盒 26×6,平行之后转成 4×26),方形符号走的是 gl.POINTS 那条路(旋转后外接盒从 24×24 撑成 32×32)。通道里「每条回线各显示自己的标签」也在这里验:没有逐条配置时会被 32px 屏幕小格去重(只显示 1 ~ 2 条),给每条回线写上自己的 `lineLabelPosition` 之后 8 条全都在、位置各不相同,斜线上的标签按线路方向转、朝左的自动翻半圈(rotate = 0)。线路的层序(`zIndex`)也在这里验:画布正中一横一竖两条粗线交叉,默认后写的竖线在上(中心像素蓝),规则里给横线写 `zIndex: 5` 就换成红,`updateLine` 给竖线写 `zIndex: 9` 又换回蓝,写回 0 再回到红。这一轮另外验了插件上下文:`options.plugins` 与 `view.use()` 拿到的第二个参数是同一个冻结对象(`apiVersion === 1`、`view` 指回实例),旧的一参插件写法照常可用。这一轮另补 3 条合并触发时机断言(center 差 10px 不触发、继续拖入目标区域触发并带 trigger、collision 同距离照旧触发)。这一轮再补 1 条:13 个旧快捷方法已从实例删除,`updatePoint` / `updateLine` / `updateChannel` / `updateOptions` / `setFilter` / `setDropPreview` 仍在。对账组另补 8 条:`getChangedChannels({ ignoreGroups })` 忽略分组增删、已有分组拐点仍报、`reasons` 收窄与线路字段 / 路径 / 显隐变化,以及删除通道 / 删除线路 / 无通道场景同步清账。本轮再补实例命令的注册 / 同名覆盖 / 异常与销毁断言,并再补 16 条:筛选恢复后通道宽度与回线车道、`focusOn` 显式 `point` / `line` / `channel` / `group` 与统一缩放口径、`selectFeatures` 分组写法、`selectWaypoint` 带选线路,以及 `lineFollowsNode` 的隐藏 / 筛选 / 删除 / 撤销与动态切换。
|
|
110
|
-
- `selftest-decoration.html`(75 条):动态装饰器草稿专项自测 —— 开启后的 `start` 载荷、默认 14px 触发半径与每条线路不限量、指针在线路上 `hover`(命中线 / 自身 `decoration` / 平行角)、同一位置重复移动不重复发事件、移出目标 `leave`、在线路与空白处 `pointerup` 的 `ready` 差异、按下 / 抬起 `action.type` 都是 `decorationDraft`、单线 / 分组 / 整条通道三档作用域与非通道回退、`maxPerLine` 满额时悬浮与松手都不触发且提交前复核不写数据、`allowedLines` / `allowedChannels` / `allowedGroups` 三种白名单在悬浮与提交两处都拦截、`update` 改图标 / 尺寸 / 方向、`commit` 一次 `batch` 写四条且只发一条 `dataChange`、`cancel` 不改数据、重复 `begin` 替换旧草稿、整份换数据后过期草稿静默清掉。节点侧另有 32 条:`target: 'point'` 命中与只展开一个节点目标、方向 / 距离换算成屏幕偏移、相对偏移 / 固定世界坐标 / 鼠标位置三种位置来源、连接线样式随提交保存、`allowedPoints` 与 `maxPerPoint` 在悬浮 / 提交两处拦截、`both` 等距时节点优先且最近节点被白名单拦住时回退线路、节点与线路的重复 `reject` / `offset` 两种策略、节点装饰 get / update / remove 与整批提交、度转角与连接线进入矢量快照。这一轮另补 8 条节点断言:既有的 2 条「装饰随移动」仍保留;新增 6 条覆盖 `pointer + follow`、`fixed + follow`、`offset + fixed` 三种跨组合的预览与提交结果,确认位置来源和落地关系解耦后分别写成 `offset` 或 `at`。
|
|
111
|
-
- `selftest-demo.html`:demo 级自测 —— 面板上的「定位直流线路」按当前数据集的 `dc_line` 条数走(默认数据集 `new.json` 里现在自带 5 条,点一下直接选中并定位到第一条;一条都没有的数据集才切到样例数据、定位到「直流送电」,中点挂着 `PATH_DC_LINE` 装饰),断言按数据算出来的条数写、不写死数字,读数与选中面板都跟着更新;打开时说明段落默认收起、面板按组折叠,节点标签只给最高电压那一档、线路标签默认整个不显示(面板上勾「显示」再按「显示范围」展开),面板上有 PATH_DC_LINE 的「标记定位」下拉(自动 / 一直跟随 / 写死坐标三档)。「通道回线各自显示」这一档从数据层核对(勾上之后 3669 条回线都带上了自己的 `lineLabelPosition`),再放大三步后勾「与线路平行」,画出来的标签 transform 里要出现 `rotate(...)`。这一轮又补了「数据映射」下拉(raw / lngLat / fit / scale)与「节点 / geojson 比例」滑块:切到 fit 后 320 个站点都要落进 GeoJSON 画出来的范围、读数里给出换算比例;「经纬度 → 屏幕」「屏幕 → 经纬度」两个按钮来回换算一致(屏幕读数保留 1 位小数,允许 0.01° 的回差);在画布上挪一下鼠标,面板上就要出现屏幕像素与经纬度两行读数。
|
|
112
|
-
- `selftest-perf.html`(183 条):大数据量与画质档位的性能自测 —— 20000 点 / 8000 线的建场景与整份重排耗时、500 次拾取、逐个改 500 个节点对 `view.batch()`、四档画质与 `'auto'` 的自动升降;前面几轮补过 8 条交互期细线的断言(`getStats()` 给出 `antialias` / `software` / `thinLines` 三个读数;交互期 1px 实线整批走 `gl.LINES` 快路径、停手回到四边形展开;`interactionThinLines: false`、线宽 8px、整批带虚线这三种情况下都不走快路径,改回细实线又走);上一轮补过 7 条线路标签候选复用的断言(复用态与整层重排逐字一致,改线路内容 / 挪节点 / 相机变化之后缓存都作废)与 1 条连续更新的耗时 DIAG(2 万点 / 1 万线,中位 0.30 ms / 次);**这一轮再补 3 条标签避让盒的断言**(4 万点 + 4 万条长线放大后连续整层重排:第 2 轮起一次布局都不读、同一轮里没有哪条标签被量第二次)与 1 条量测读数 DIAG(逐轮 1427 / 0 / 0 / 0 / 0 次,旧写法 2662 / 0 … 次、第 1 轮重复量 1235 条;**上一轮把「没有哪条标签被量第二次」从按 DOM 节点去重改成按标签身份(`labelKind` # `labelIndex` # `labelLabel`)去重** —— 标签节点是池化复用的,按节点去重会把「同一格换了条标签」误报成重复量,旧代码实测第 1 轮 1235 条、新代码 0 条;**这一轮再补 3 条线路批次视口裁剪的断言**(20000 点 / 8000 线放大到 `scale: 10`:`lineInstances` 8000 → 27、相机挪回来回到 8000、来回一趟整幅像素差 0 / 241164)与 1 条读数 DIAG。这一轮再补 2 条点视口网格的断言(网格可用时枚举顺序与整份筛出来的下标序列一致、回调返回 `false` 最多只访问一个)。这一轮再补 19 条点聚合断言(归一化、1.2 万点建组与统计、原始数据不变、`visibleOnly` 排除成员、拾取 `type=cluster`、点击语义、`maxZoom` 展开、关闭恢复),页面每段之间让出一帧,边跑边出结果。这一轮另补 7 条热力图缓存断言:`styleKey` / `weightKey` 的语义、只改 `density.opacity` 不重采不重烤、换色带与定向改要素值会重烤。;本轮新增 1 条相机运动帧断言:人为拉长帧间隔并连续改相机,记录到的每次 `gl.viewport` 都必须等于画布全尺寸,防止运动期降采样重新引入模糊;本轮再补 1 条像素级断言:在同一交互状态下把细线专用片元管线与四边形画法逐像素对拍,线像素数量与整幅颜色差都必须在容差内,防止新管线把整批线画丢、画黑或换色。
|
|
113
|
-
- `selftest-scale.html`(125 条:119 PASS + 6 DIAG):大数据交互这一轮的自测 —— 2000 点 / 2000 线、筛选开着:`batch()` 里改 200 个节点只发 1 条 `onFilter` 与 1 条 `onDataChange`(对照组逐个调用是 200 条);改字段 / 改坐标 / 改线路之后「增量补写的隐藏集」与「从零建一个同样条件的视图」逐位一致;点挪到被筛掉的坐标上,按 `coordinate` 联动的线路当场隐藏、挪回去又出来;线段网格的步进登记与多层粗格(沿线查得到、线不经过的角落不进候选、跨层只返回一次、2 万条长线密集时小范围查询的候选远少于总条数、整图估计值与总条数同量级);点 / 线 / 空白的拾取;搜索文本缓存的命中与「改过字段之后按新值搜得到、旧值搜不到」。最底下几条 DIAG 是耗时读数(`Date.now()`),无头浏览器里虚拟时钟不往前走、显示 0.0 ms,带界面的浏览器里才是真实数字。;这一轮又补了 8 条:三万点的发散渲染(超过 2 万点走分批铺开)铺完之后装饰 400 个一条不少、挪一条带装饰的线的端点只动那一条线的装饰且落在新路径中点上、贴图符号进的是贴图批次、选中的节点抬到最上层、整份重排之后装饰与动点不翻倍,以及「节点自己配的涟漪数得清」(这一条顺带抓出了发散渲染期间涟漪补不齐的 bug)。这一轮再补一条 `createPointGrid.estimate` 与 `query` 同口径、带 `stopAfter` 提前封顶的断言(不建候选数组也能判断值不值得走网格);本轮又补了删除型筛选的 10 条回归:同步初始删除先于 `ready`、无 id 线路按下标删、级联线路与空通道一起清掉、单条 `filterRemove` / 单次 `onFilter`、历史一步、撤销不再次删除、重做不补发第二条事件、运行时 `setFilter` 与 `cascade: false` 对照,另校验载荷里的 `removedPoints` / `removedLineItems` 与剩余数据。
|
|
114
|
-
- `bench-filter.html`:基准页(不是自测,只会打印读数)—— 20000 点 / 20000 线、`cascade: 'binding'` 的筛选开着(`filterWorker: false`),量「连换 10 次筛选条件」「`batch()` 里改 500 个节点(筛选开着 / 关掉)」「单个 `updatePoint`」「默认全字段 `search` 跑两次」这几档,每档先热身一遍再计时(`Date.now()`)。标题从 `bench running` 变成 `bench done` 表示跑完;别用 `--virtual-time-budget` 打开它 —— 虚拟时钟下同步脚本里的 `Date.now()` 不往前走,量出来全是 0。
|
|
115
|
-
- `bench-scale.html`:百万级基准页(同样只打印读数)—— 点 / 线规模与视口走 URL 参数,`window.__bench.run(options)` 量生成数据、建场景与发散渲染、平移 / 缩放 / 放大 / 拾取、`refresh` / `updatePoint` / `updateOptions`、内存账与销毁回收;另有 `prepare`(只建场景)、`__bench.op(name)`(单步)与 `__bench.micro(count)`(原语微基准)。配 `scripts/bench-scale.mjs` 用(CDP 驱动,`--points=1000000 --gpu --port=93xx`,另有 `--profile` 抓 CPU profile、`--heap` 抓堆快照);跑全部自测页用 `scripts/run-selftests.mjs`(`node scripts/run-selftests.mjs [页面名…]`,无头 Chrome + 真时间),两个脚本都要先起 dev server。
|
|
116
|
-
- `selftest-labels.html`(165 条):标签拖动与编辑、HTML 语义、高密度画布、导出分项多选的专项自测 —— 按住标签拖 90 px 之后标签真的挪了那么多、同时画布不平移,`labelDrag` 的 `start` / `move` / `end` 三态与 `offset` / `delta` 对得上,偏移进得了 `getLabelStates()`、再拖动节点时偏移照旧叠在节点位移上,`resetLabel` 之后回到默认锚点;`updateLabel` 改内容 / 字号 / 颜色(`style` 是增量合并,只改字号不动颜色)、`resetLabels` 一次清干净;点一下标签发 `labelClick` 并把这一条交给面板;线路标签的拖动与恢复默认同一条路;导出侧验「选什么导什么」(选场站只出场站、选通道自动带上拐点、不认识的分项记一条提示),`exportData({ scope: 'selection' })` 验场站 + 通道 / 只出线路 / 没选中时的 `ok: false` 三个分支。HTML 专项验全局 / 逐条 `true` / `false`、模板与 `field` / 默认名称转义、`updateLabel` 双向切换、线路标签富文本、点击载荷保留 `html` 与原标记、`getLabels()` 报运行时偏移、只改样式不替换 HTML 子节点、导出 → 回灌保持逐条语义,以及 120 条同内容标签首轮布局读取 ≤ 4 次的缓存断言。高密度专项用 1100 条纯文本验缺省 `auto` 只留一张画布、混入一条 `html: true` 仍保留那一条 DOM、`labelRender: 'dom'` 回退逐条 DOM 并清空画布、切回 `auto` 回收上一轮 div、SVG 导出包含画布标签与缩放只推一次;新增断言还验 1100 条同文案只调用 `measureText` ≤ 2 次、同一任务连续 5 次缩放只重绘 1 ~ 2 次、显式 `canvas` 在优化档遵守 `maxCount: 200`,以及 6 条线路标签在优化档全部进画布且 DOM 为 0。另验 GeoJSON 区域文字同一相机重复刷新 0 次 `style` 写入、只改字号复用同一 DOM 节点、离屏时改样式再回到视野仍能恢复显示、只改锚点位置也会重新投影,以及同一帧 12 次相机变化只做 1 次重投影。设备像素专项把 `devicePixelRatio` 临时设为 1.25,验标签落点与拖动期整层位移都落在物理像素网格上,并确认逐条标签不再各自声明 `will-change`。
|
|
117
|
-
- `selftest-actions.html`:事件判读与只读接口的专项自测 —— 左右键、拖动、框选、拐点与标签的 `action` 三件套(type / target / data)、`button` / `modifiers` / `moved` / `double`、Shift 框选(含没框到东西的空框)与 Ctrl 取反在 `selectChange.action.type` 上的分辨、`pickAt` 的客户端坐标与只读性、`getFeaturesInRect`(含宽高为负的矩形)与 `getChannelsInView`、`addPoints` / `addPoint` / `addLines` / `removeLines` 的返回与 `dataChange` 类型;最后一段把第 12 步 `step-12-events.js` 挂起来跑一遍(判读读数、`probeAt` / `probeRect`、两条走廊)。页面底部流式打印 PASS / FAIL。
|
|
118
|
-
- `selftest-select.html`:选择与框选的专项自测(84 条)—— 点选 / 悬停 / Ctrl 取反 / 多选开关的像素级状态样式与恢复,`selectFeatures` / `selectAt` / `deselect` / 通道写法 / 变更来源的接口断言(含 selectFeatures 实际变化时发 onSelect + onSelectChange、重复设同一选中集不重复通知、selectAt 每次命中发 onSelect 且集合变化时再发 onSelectChange),以及 SVG 状态贴图的预热与不同尺寸配方;这一轮补了 `selectionKinds: 'all'` 下 `selectInBox` 一次收下节点、独立线路与按 `channelSelectMode` 摊开的通道回线、`selectAt` 的节点 / 线路 / 通道 / 空白四路、多分组通道在 pickAt / hoverAt / 鼠标事件里的 `group` / `groups`,以及 SVG 导出 `currentStrokeColor` 的描边色还原和 `selectTrigger` 的单击、双击、多选取反 / 累加 / 取消。本轮再加 4 条:`onSelect` / `onSelectChange` 的单通道顶层上下文与 `items[]` 标量归属、真实点击 `onClick → onSelect → onSelectChange` 顺序、`selectFeatures(整条通道)` 与 `selectAt` 的通道载荷和 `onSelect → onSelectChange` 顺序(其中 `channelIndex` 同时校验为通道声明下标);另补 1 条多通道选中断言,确认只给 `channelContexts`、不重复摊平,且两条事件共享同一批 `items`。
|
|
119
|
-
- `selftest-demos.html`:演示外壳与 22 个页签(21 个功能 + 综合,按基础 / 交互 / 样式 / 数据 / 性能 / 综合六组排列)的自测(**347** 条)—— 逐个用 `?demo=<id>` 打开基础视图、标签交互、标签显示、鹰眼图配置、样式与规则、悬停与提示、通道与数据、编辑与保存、事件与方法、接口能力、批量复制与合并、拖拽落点、可视化连线、动态装饰器、批量新增、搜索与筛选、扩展能力、性能与质量、点聚合、动画效果、扩展图形与综合示例,画布与右栏读数都在、切页签会把 `?demo=` 写回地址栏、切走之后上一个实例被销毁(不留画布)、缺省页签是综合示例、页签总数与注册表一致、顶部六个分组按钮一次只展开一组且组名可见;鹰眼图配置页另验 `layers` 的自定义 `draw` 真被调用、`placement` 切到数据前 / 后时 `drawInfo.stage` 跟着变、框拖动触发 `onInteraction` 并带相机、尺寸切换走 `updateOptions` 重铺画布、DPR 2 下 `maxPixelRatio` 的 1× / 2× 备份尺寸、关掉扩展层与 `zoomMinimapBy` / `setMinimapZoom`,以及 `extentFollowCamera` 默认关闭 / 打开生效、缩放关闭时 `dragAction: 'box'` 仍可框选、`zoomable: 'follow'` 跟随主图且 `setMinimapZoom` 不抢控制权;批量复制 / 合并、通道拐点 / 分组两页另有假接口断言(Shift 框选、整份请求体、标准响应包与资源级结果、版本号 / opId、200 / 网络失败 / 500 / 409、原 opId 重试与幂等重放不推进版本、409 rebase、本地回滚);假后端严格契约另有一组直接断言(请求头与 body 不一致返回 400、baseVersion 非有限数字返回 400、同 opId 换 body 返回 409 `IDEMPOTENCY_CONFLICT` 且版本不前进),通道页还验了自定义格式按钮注册 → 导出 → 注销;扩展能力页另验自定义运算符 / 图元 / `view.use` 插件 / `defineExportFormat` / 实例命令的注册、执行、同名覆盖、卸载与业务 DTO 结构,并验同名重新注册图元当场换画笔;可视化连线页另验初始 `channels` 为空、正交折线拐点、预览箭头、取消不写数据,默认提交 / `addLines` / `addChannels` 三种落地,指定起点后一次点击即可 ready、两端示例点的显隐 / 尺寸 / 形状 / 分端颜色与 `below-points` 层级、`commitAddChannel` 直接传线路 / 通道对象(含对象 path / 颜色 / 线宽优先);动态装饰器页另验吸附方式只有「跟随 / 固定」、两档下位置都有「相对节点 / 固定位置 / 鼠标位置」三档,固定 + 相对节点只改 `anchor`,固定 / 跟随 + 鼠标位置分别映射为 `placement: pointer` + 对应 `anchor` 且不带 `at`,跟随 + 固定位置仍传 `at`;通道与数据页另验「线路分组」弹框:分组卡片与「场站对标标识」都在,行内「确认移入」只改本地草稿、组件数据不动,取消 / Esc / 遮罩关闭不写数据,「确定分组」只调用一次 `splitChannelGroups` 把整份 groups 一次落地。点聚合页另验配置控件、聚合点击只增聚合计数、`maxZoom` 展开与适应全部后恢复、半径 / 重建 / 关闭统计;接口能力页另验三种级联触发独立开关、通道 / 分组 / 拐点程序化选中、通道 `focusOn`、`lineFollowsNode` 联动,以及样式字段合并、节点 / 线路装饰 CRUD、通道线宽与线路对账、GeoJSON 背景投影、历史 / 复制 / 删除收尾、`once`、WebGL 层清理、注册表注销与初始化 options 读数;页面底部流式打印 PASS / FAIL。鹰眼图线路层另有 3 条断言:首帧只铺固定范围里的线路、同一份数据补画命中缓存、小图缩放只重铺一次且仍裁剪范围外线路。
|
|
120
|
-
- `selftest-effects.html`:线路 / 节点动画与贴图预热的专项自测(96 条,页面自带「帧泵」—— 无头环境里 `requestAnimationFrame` 几乎不推进,它把 rAF 收进 Map、手动推帧,动画类断言才测得动):纯函数组(归一化、三层「关」的语义、按弧长采样、拐点连续、相位打散)、引擎组(铺批次 / 关掉一层 / 恢复 / 逐要素覆盖 / `getLineEffects` 全程贴线)、像素组(画布上真的有一个红点在两帧之间挪了位置)、**涟漪跟手组**(开着动画拖节点:拖动前圆心在节点坐标上、拖动中跟着走且是就地改实例缓冲、松手后整份重建也对齐、再拖回原位跟着回来,另有一条像素级断言量绿圈质心落在新坐标上)、**预热组**(全排列条数、第二次命中缓存、`getSymbolCombos()` 的去重与线路侧那一条、照着它配的一份**零张新画布**、反向一条「没画过的组合会当场烤、画布 +1」)、提醒组(`effects.line` 里写 `show` 被点名);这一轮另补 4 条动点缓存断言(5000 条普通线 + 2 条动点线:每帧只遍历动画线路,路径换短 / 换长后总长跟着更新)。
|
|
121
|
-
- `selftest-data.html`:标准数据文档与渲染后端开关的自测(103 条)—— `normalizeDocument` 的标准写法与 JSON 安全(无效日期写 `null` 并告警、类实例不静默变成空对象)、整份文档直接当 `createGisView` 入参、`exportData({ format: 'full' })` 导出 → 重建 → 再导出逐字节相同、`importData` 的整份与分列、`renderer` 三档与能力探测、网格顶点缓存窗口,以及自定义导出格式的注册 / 上下文 DTO 映射 / 深拷贝 / 视口导出 / 注销后失效;断言全在接口层,不读像素。
|
|
122
|
-
- `check-sample-fields.mjs`:不是页面、是对账脚本(`node docs/steps/check-sample-fields.mjs`)—— 核对 `sample-document.json` 自己就是标准写法(`normalizeDocument` 后逐字节相同、0 条提醒)、`docs/sample-document字段详解.md` 里的读数与 `documentCounts()` 一致、以及它的「字段索引」与从文件里摘出来的字段路径集合一个不多一个不少(当前 154 个);改完样本数据跑 `--write` 重写那两段机器块(幂等)。
|
|
123
|
-
- `selftest-docs.html`:三个文档页 + 调试页的自测(134 条)—— 文档中心(`docs/index.html`)的清单 92 份 md(10 个根 + 82 份子文档,含新的 `接口协议.md`;树形侧栏按 `parent` / `groupLabel` 分成 6 组 `details`)、首屏 README 渲染、markdown 渲染器(表格 / 带语言代码块 / 两级列表 / 引用 / 行内代码 / md 链接 / 目录 / 首条摘要卡片 / 首段导语)、元信息里的阅读时长、索引页的子文档链接、换一份子文档、代码块复制按钮、跨文档搜索与深链、跨文档锚点链接(`文件.md#小节` 原地切文档并闪一下)、能直接跑的围栏才有的「在调试页跑」与元信息行的「这一份的调试页(N 段示例)」、390px 窄屏首屏 / 深链 / 横向溢出回归、阅读百分比与「回到顶部」的联动;调试演示页(`docs/playground/index.html`)的一个示例下拉(内置示例 + 「这一份文档」两组 optgroup)、`?doc=` 读文档抽示例、片段标注与来源子栏、顶层 await 运行、`channels` 快照、光标行列、草稿自动保存与恢复、`Ctrl+S` 运行、复制 / 清空输出、状态胶囊;API 速查页(`docs/api/index.html`)的 `__gisApi` 钩子、六张统计卡、265 张成员卡都带签名网格与示例、96 个 options 四列网格、搜索过滤与命中读数、`select(名字)` 高亮、类型开关能单独收起属性、左侧当前分组高亮与即时跳转、顶栏文档深链、每个分组的手册章节链接、深浅主题切换与阅读设置共用;图解页(`docs/guide/sample-document.html`)的 47 条数据列表、点线路 / 分组 / 标签状态的图上标注、`点击时居中` 与 `显示编号` 开关、清空标注;三个页面都跑在 iframe 里,要用 dev server 打开。
|
|
184
|
+
[`selftest.html`](selftest.html)(分步核心交互)、[`selftest-demo.html`](selftest-demo.html)(综合 demo 与质量)、[`selftest-demos.html`](selftest-demos.html)(逐页功能 Demo)、[`selftest-labels.html`](selftest-labels.html)、[`selftest-select.html`](selftest-select.html)、[`selftest-actions.html`](selftest-actions.html)、[`selftest-scale.html`](selftest-scale.html)、[`selftest-perf.html`](selftest-perf.html)、[`selftest-features.html`](selftest-features.html)、[`selftest-full.html`](selftest-full.html)、[`selftest-effects.html`](selftest-effects.html)、[`selftest-data.html`](selftest-data.html)、[`selftest-decoration.html`](selftest-decoration.html)、[`selftest-docs.html`](selftest-docs.html)。
|
|
124
185
|
|
|
125
|
-
|
|
186
|
+
另有两张不报 PASS / FAIL 的交互基准页:[`bench-filter.html`](bench-filter.html) 量 2 万点 + 2 万线上的批量更新 / 筛选 / 搜索耗时,[`bench-scale.html`](bench-scale.html) 量建场景、平移缩放、拾取与改数据的帧耗时;两者都用真实时钟,前者看每一档的毫秒数,后者看输出里的 `DIAG` 行。
|
|
187
|
+
|
|
188
|
+
无头环境里 `requestAnimationFrame` 常不推进,动画类断言要用真时间(CDP 或真实浏览器)。仓库自带的 CDP 跑法:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# 终端 A
|
|
192
|
+
npm run dev -- --port 5199
|
|
126
193
|
|
|
127
|
-
|
|
194
|
+
# 终端 B:只跑关心的几页,省略参数就跑全部 selftest
|
|
195
|
+
node scripts/run-selftests.mjs selftest.html selftest-demos.html selftest-docs.html
|
|
196
|
+
```
|
|
128
197
|
|
|
129
|
-
|
|
198
|
+
提交前的固定四步:
|
|
130
199
|
|
|
131
|
-
|
|
200
|
+
```bash
|
|
201
|
+
npx tsc --noEmit
|
|
202
|
+
npm run check:docs
|
|
203
|
+
npm run build
|
|
204
|
+
git diff --check
|
|
205
|
+
```
|
|
132
206
|
|
|
133
|
-
|
|
207
|
+
改过公开成员或 options 时,先跑 `node docs/steps/gen-api-index.mjs`,再跑 `npm run check:docs`。改过文档时,同时更新 `docs/AI对话汇总.md` 与 `docs/ai/` 的对应章节。
|
|
134
208
|
|
|
135
209
|
## 和库里文件的对照
|
|
136
210
|
|
|
137
|
-
|
|
|
211
|
+
| 本目录 | 库里的位置 |
|
|
138
212
|
| --- | --- |
|
|
139
213
|
| `step-01-canvas.js` | `engine.js` 的上下文 / 尺寸 / `requestRender` |
|
|
140
214
|
| `step-02-points.js` | `point.js` + `shaders.js` 的点部分 |
|
|
@@ -146,10 +220,17 @@ API 名字与前面几步是一一对应的;第 11 步再补两件「数据之
|
|
|
146
220
|
| `step-08-labels.js` | `overlay.js` |
|
|
147
221
|
| `step-09-minimap.js` | `minimap.js` |
|
|
148
222
|
| `step-10-full.js` | `create.js`(`createGisView`) |
|
|
149
|
-
| `step-11-background.js` | `background.js` / `geojson.js` + `engine.js`
|
|
150
|
-
| `step-12-events.js` | `engine.js`
|
|
151
|
-
| `step-13-engineering.js` | `quality.js` + `history.js` + `features.js` + `create.js` 的
|
|
223
|
+
| `step-11-background.js` | `background.js` / `geojson.js` + `engine.js` 的初始视图 |
|
|
224
|
+
| `step-12-events.js` | `engine.js` 的动作判读 + `create.js` 的只读查询 |
|
|
225
|
+
| `step-13-engineering.js` | `quality.js` + `history.js` + `features.js` + `create.js` 的 batch 段 |
|
|
226
|
+
|
|
227
|
+
迷你版与完整版的差距主要集中在:批量 GPU 缓冲与增量上传、十万级初始化与标签避让、通道分组与拐点编辑、筛选(可进 Worker)与搜索、首屏落位与插件、打包与类型声明。需要哪块时按上表直接读库里的对应文件。
|
|
228
|
+
|
|
229
|
+
## 继续往下走
|
|
230
|
+
|
|
231
|
+
- 想把整套代码一次写完:[`docs/from0/13`](../from0/13-从零搭一整套-上.md) 与 [`docs/from0/14`](../from0/14-从零搭一整套-下.md)。
|
|
232
|
+
- 想先看单文件精简实现:[`docs/mini/index.html`](../mini/index.html) 与 `docs/mini/mini-map.js`。
|
|
233
|
+
- 想理解每帧机制:[`GisView 实现原理`](../GisView实现原理.md);想查某轮为什么这么改:[逐轮记录](rounds/README.md)。
|
|
234
|
+
- 想接入真实业务:[`manual/01`](../manual/01-快速开始.md) 起步,再按通道 / 标签 / 筛选 / 后端协议查对应章节。
|
|
152
235
|
|
|
153
|
-
|
|
154
|
-
通道分组与拐点编辑、筛选(可进 Worker)与搜索、首屏落位与插件、以及打包 / 类型声明。需要哪一块时,
|
|
155
|
-
对照上面这张表直接看库里的对应文件即可。
|
|
236
|
+
学习路线的目标不是把所有函数背下来,而是建立这条判断链:**数据在哪一层、视角由谁决定、这一帧为什么重绘、这次交互改了什么**。能稳定回答这四个问题,就已经能独立扩展这个组件了。
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
else if (name === 'addChannel') {
|
|
238
238
|
// 新增通道(每次新建一条两回的通道):走 uniqueLineId 查重与通道声明整份重排
|
|
239
239
|
const data = view.getData()
|
|
240
|
-
view.addChannel({ from: data.points[0].id, to: data.points[1].id,
|
|
240
|
+
view.addChannel({ from: data.points[0].id, to: data.points[1].id }, [{}, {}])
|
|
241
241
|
}
|
|
242
242
|
return +(now() - started).toFixed(1)
|
|
243
243
|
},
|