gis-view-webgl2 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +86 -1
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +64 -0
- package/docs/GisView.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 +55 -0
- package/docs/demos/MinimapDemo.vue +154 -1
- package/docs/demos/SearchFilterDemo.vue +113 -1
- package/docs/demos/api-index.js +16 -9
- package/docs/demos/demos.js +1 -1
- package/docs/internals/13-/351/271/260/347/234/274/345/233/276.md +2 -0
- package/docs/internals/16-01-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/212.md +13 -2
- package/docs/internals/16-03-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/213.md +11 -1
- package/docs/internals/18-/346/200/247/350/203/275/345/256/236/346/265/213/344/270/216WebGPU/350/257/204/344/274/260.md +61 -1
- package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +5 -4
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +2 -2
- package/docs/manual/05-/347/224/273/350/264/250/344/270/216/346/211/271/351/207/217/346/233/264/346/226/260.md +1 -1
- package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +23 -5
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +7 -3
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +10 -3
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +20 -1
- package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +4 -0
- package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +8 -3
- 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 +1 -1
- package/docs/steps/README.md +4 -4
- package/docs/steps/selftest-demos.html +105 -6
- package/docs/steps/selftest-docs.html +3 -3
- package/docs/steps/selftest-full.html +42 -1
- package/docs/steps/selftest-perf.html +600 -421
- package/package.json +1 -1
|
@@ -409,3 +409,67 @@
|
|
|
409
409
|
- **实测**:20000 点 / 8000 线同一批对象回灌 5 次取中位,**14.3 ms → 6.3 ms**(优化后 5.6 / 6.3 / 6.3 / 6.4 / 10.7 ms)。
|
|
410
410
|
- **核心文件**:`src/gis-view/engine.js`、`src/gis-view/types.d.ts`、`docs/manual/10` / `16` / `17` / `18`、`docs/steps/selftest-perf.html`、`docs/internals/16-01-优化与取舍-上.md`、`docs/internals/18-性能实测与WebGPU评估.md`、`docs/demos/api-index.js`(生成物)、本轮 aimd。
|
|
411
411
|
- **验证**:`node --check`(engine / create)、`node docs/steps/gen-api-index.mjs`、`npm run check:docs`(**257** 个实例成员 = **254** 个方法 + 3 个属性 / **96** 个 options / **250** 个数据字段 / **43** 个事件 / **17** 个功能开关)、五页自测 `full 92` + `features 672` + `demos 351` + `docs 134` + `perf 167` = **1416** 条通过 / 0 失败、`npx tsc --noEmit`、`npm run build` 与 `git diff --check` 全部通过。复查入口见 [06 的增量记录](ai/06-会话索引与复查方法.md#2026-10-23-增量修改txt三项commitaddchannel-文档--传参示例--线路半跳过)。
|
|
412
|
+
|
|
413
|
+
## 2026-10-23 增量(「问题.txt」两项:鹰眼图范围锁定开关 / 整图拖动 demo)
|
|
414
|
+
|
|
415
|
+
本轮仍是现有会话的继续增量,没有新建会话归档,因此不改上表的 39 条会话统计。需求原话来自仓库根目录的 `问题.txt`:① 鹰眼图不应因主视图外围内容消失而自动重算包围盒,把这个行为做成默认关闭的开关;② 增加整体拖拽鹰眼图的 demo。
|
|
416
|
+
|
|
417
|
+
- **范围跟随开关**:`minimap.extentFollowContent?: boolean` 默认 `false`。`resolveExtent()` 在开关关闭时用 `pinnedExtent` 锁定首次取得的动态数据 / 底图范围,筛选、显隐、删除、新增内容只重画要素,不再改小图 `bounds` / `scale` / 中心;打开后才按当前可见内容重算。显式改 `extent`(预设或固定范围按值比较)以及切换开关都会清锁,下一次重画重新取范围;`extentFollowCamera` 的相机取舍基于锁定后的两份范围。
|
|
418
|
+
- **整图拖动 demo**:`MinimapDemo.vue` 通过 `getMinimapElement()` 在根节点追加独立手柄,手柄手势 `stopPropagation()`,不触发小图原有框选 / 平移;位移累计写回 `minimap.offset`,窗口级 `pointermove` / `pointerup` 收尾,并提供方向键微调、复位按钮和位移读数。
|
|
419
|
+
- **测试与文档**:`selftest-full.html` 新增 2 条断言覆盖默认锁定与打开后跟随内容;`selftest-demos.html` 新增 4 条断言覆盖开关下发、手柄拖动与复位。同步更新配置项 / 视图手册、鹰眼图内部文档、两个 README、类型注释、demo 描述与生成的 `docs/demos/api-index.js`。
|
|
420
|
+
- **核心文件**:`src/gis-view/minimap.js`、`src/gis-view/types.d.ts`、`docs/demos/MinimapDemo.vue`、`docs/demos/demos.js`、`docs/demos/api-index.js`(生成物)、`docs/manual/03` / `14`、`docs/internals/13-鹰眼图.md`、`src/gis-view/README.md`、根 `README.md`、`docs/steps/selftest-full.html`、`docs/steps/selftest-demos.html` 与本轮 aimd。
|
|
421
|
+
- **验证**:定向三页 `selftest-full` **94** / `selftest-demos` **355** / `selftest-docs` **134**,合计 **583** 条通过 / 0 失败;全量 14 页 **2295** 条通过 / 2 条失败,失败均为 `selftest-scale` 的筛选回调计数(本轮未改动筛选链路)。`node --check src/gis-view/minimap.js`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(**257** 个实例成员 / **96** 个 options / **250** 个数据字段 / **43** 个事件 / **17** 个功能开关)、`npm run build` 与 `git diff --check` 全部通过。复查入口见 [06 的增量记录](ai/06-会话索引与复查方法.md#2026-10-23-增量问题txt两项鹰眼图范围锁定开关--整图拖动-demo)。
|
|
422
|
+
|
|
423
|
+
## 2026-10-23 增量(「修改.txt」两项:数据包围盒缓存与相机飞行)
|
|
424
|
+
|
|
425
|
+
本轮仍是现有会话的继续增量,没有新建会话归档,因此不改上表的 39 条会话统计。需求原话来自仓库根目录的 `修改.txt`:① 继续优化组件整体性能;② 增加一些后续可能需要的新功能、方法、属性,并补 demo。
|
|
426
|
+
|
|
427
|
+
- **数据包围盒缓存**:`engine.js` 增加 `cachedDataBounds` / `cachedDataBoundsValid`,整份解析完成时直接接住 `fusedDataBounds`,普通 `getBounds()` 不再每次扫描全部已解析节点与线路;缓存对象与 `fusedDataBounds` 各持一份,`getBounds()` 也返回独立副本,调用方就地修改不会污染后续读数。`updatePoint` 坐标变化、`updateLine` 路径变化、拖拽、追加点 / 线以及复制预览改坐标都会显式失效缓存。十万点 + 十万线(每条 10 顶点)连续 10 次读数由约 **5.2 ~ 6.6 ms / 次** 降到 **0.00 ms / 次**;改一个点后首次重建约 **3.6 ms**,读数正确。
|
|
428
|
+
- **相机飞行 API**:新增 `flyTo(target, options?)`、`stopCameraAnimation()`、`getCameraAnimation()` 与只读属性 `cameraAnimating`。`flyTo` 认与 `focusOn` 相同的目标及 `zoom` / `scale` / `center` / `padding` / `maxZoom` / `select` / `mode` 语义,另支持 `duration`(缺省 450 ms)和 `easing`(`linear` / `ease-in` / `ease-out` / `ease-in-out` / 自定义函数);中心线性插值、比例按对数插值。再次 `flyTo`、用户拖拽 / 滚轮、程序化改相机、`fitView` / `resetView` 和销毁都会取消上一条动画;`duration <= 0` 或系统 `prefers-reduced-motion: reduce` 时立即落位。
|
|
429
|
+
- **Demo**:`docs/demos/SearchFilterDemo.vue` 增加“飞向选中”“停止飞行”按钮与实时动画读数;`docs/steps/selftest-perf.html` 增加 3 条包围盒缓存 / 失效 / 防污染断言,`docs/steps/selftest-demos.html` 增加 5 条飞行 API 与 demo 交互断言,并同步成员清单 261。
|
|
430
|
+
- **核心文件**:`src/gis-view/engine.js`、`src/gis-view/create.js`、`src/gis-view/types.d.ts`、`docs/demos/SearchFilterDemo.vue`、`docs/demos/api-index.js`(生成物)、`docs/GisView.md`、`docs/manual/14` / `16` / `17` / `18` / `20`、`docs/steps/README.md`、`docs/steps/selftest-{perf,demos,docs}.html`、根 `README.md`、`src/gis-view/README.md` 与本轮 aimd。
|
|
431
|
+
- **验证**:`node --check`(engine / create)、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(**261** 个实例成员 = **257** 个方法 + **4** 个属性 / **96** 个 options / **250** 个数据字段 / **43** 个事件 / **17** 个功能开关 / **16** 个分组)、四页定向自测 `full 94` + `demos 360` + `docs 134` + `perf 170` = **758** 条通过 / 0 失败、`npm run build` 与 `git diff --check` 全部通过。复查入口见 [06 的增量记录](ai/06-会话索引与复查方法.md#2026-10-23-增量修改txt两项数据包围盒缓存与相机飞行)。
|
|
432
|
+
|
|
433
|
+
## 2026-10-23 增量(「问题.txt」两项:线路样式窄路与新 API 能力)
|
|
434
|
+
|
|
435
|
+
本轮仍是现有会话的继续增量,没有新建会话归档,因此不改上表的 39 条会话统计。需求原话来自仓库根目录的 `问题.txt`:① 继续深度优化 gis-view 组件整体性能;② 从长远角度补充可能需要的功能、方法、属性,并添加 demo。
|
|
436
|
+
|
|
437
|
+
- **线路样式窄路**:`line.js` 抽出 `resolveLinePaintInto`,整份解析与窄路共用基准宽 / 半宽 / 颜色 / 透明度的取值链;`engine.js` 新增 `NARROW_LINE_STYLE_BUCKETS` / `lineStyleNarrowChange()` / `applyLineNarrowFast()`,只换 `lineStyle.width` / `color` / `opacity` 时逐条重算 paint 并补实例槽位。规则、热力图、线型 / 阴影 / 效果 / 方向等结构输入存在时回退整份解析;逐线自身样式与状态样式仍优先。整份重解析、单线更新和窄路现在都会同步 `baseWidth`,`getLineStyle` 不会读回旧线宽。
|
|
438
|
+
- **新增 API**:`flyToCamera(camera, options?)` 直接飞 `{ center?, scale? }`,缺省项沿用当前相机;只读 `dataVersion` 在数据变更时 +1、样式 / 配置变更不递增,`onDataChange` 载荷同步带出版本;`getLineStyle(index)` 返回解析后的 `{ width, color, opacity, zIndex }`,线宽取要素自身 > 规则 > `lineStyle`,不含状态样式、热力倍率、整体倍率与缩放联动。成员总数为 **264 = 259 个方法 + 5 个属性**,options / 数据字段 / 事件 / 功能开关 / 分组保持 **96 / 250 / 43 / 17 / 16**。
|
|
439
|
+
- **Demo 与自测**:`SearchFilterDemo.vue` 增加固定相机飞行、线路换色 / 加宽、改点后版本读数;`selftest-demos.html` 覆盖 `flyToCamera`、`getLineStyle`、`dataVersion` 与 `onDataChange` 同步,`selftest-perf.html` 覆盖窄路读数、`dataVersion` 不变、逐线自身样式 / 虚线保持、规则回退,并记录 2000 线窄路耗时。
|
|
440
|
+
- **性能**:1000 点 + 50000 线连续 5 次交替(无头 Chrome + SwiftShader)。换色稳态 **10.1 ~ 11.7 ms → 6.1 ~ 7.4 ms**,换宽 **9.2 ~ 10.4 ms → 5.8 ~ 6.4 ms**;首轮 18.9 / 17.3 ms,包含槽位表与交互期细线账本首次重建。profile 热点为 `patchLineSlotsInner` 30.8% / `patchLineSlots` 17.3% / `applyLineNarrowFast` 13.0% / `resolveLinePaintInto` 3.8%。
|
|
441
|
+
- **核心文件**:`src/gis-view/line.js`、`src/gis-view/engine.js`、`src/gis-view/create.js`、`src/gis-view/types.d.ts`、`docs/demos/SearchFilterDemo.vue`、`docs/demos/api-index.js`(生成物)、`docs/GisView.md`、`docs/manual/04` / `14` / `16` / `17` / `18` / `19` / `20`、`docs/internals/16-01-优化与取舍-上.md`、`docs/internals/18-性能实测与WebGPU评估.md`、`docs/steps/README.md`、`docs/steps/selftest-{demos,docs,perf}.html`、根 `README.md`、`src/gis-view/README.md` 与本轮 aimd。
|
|
442
|
+
- **验证**:`node --check`(create / engine / line)、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(**264** 个实例成员 / **96** 个 options / **250** 个数据字段 / **43** 个事件 / **17** 个功能开关)、四页自测 `full 94` + `demos 365` + `docs 134` + `perf 174` = **767** 条通过 / 0 失败、`npm run build` 与 `git diff --check` 全部通过。复查入口见 [06 的增量记录](ai/06-会话索引与复查方法.md#2026-10-23-增量问题txt两项线路样式窄路与新-api-能力)。
|
|
443
|
+
|
|
444
|
+
## 2026-10-23 增量(「修改.txt」:继续深度优化 gis-view 整体性能)
|
|
445
|
+
|
|
446
|
+
本轮仍是现有会话的继续增量,没有新建会话归档,因此不改上表的 39 条会话统计。需求原话来自仓库根目录的 `修改.txt`:继续深度优化组件整体性能,允许大改,只要确实有效。
|
|
447
|
+
|
|
448
|
+
- **聚合空转**:`flushPointClusterLayout()` 在聚合未启用且上一帧没有聚合圆 / 隐藏点 / 聚合实例时只清脏标记,不再调用 `layoutScene()`;`notifyCameraChange()` 也只在聚合启用且当前档可能聚合、或上一帧确有聚合结果时因缩放标脏。关闭聚合后连续缩放不再整份重排点和重传实例缓冲。纯相机缩放引起的成员变化在运动期先沿用上一档,数据 / 配置 / 选中 / 拖动 / 跨出聚合档仍立即生效。
|
|
449
|
+
- **程序化相机运动**:新增 `cameraMoving` 160 ms 短窗口,`zoomBy` / `setCamera` / `centerOn` / `flyToCamera` 的真实位置变化复用细线 `gl.LINES` 与非 MSAA 后备缓冲;同一相机位置重复 `setCamera` 不续期,避免外部定时同步视角永久停在轻量档。停稳后补一张全质量帧、刷新通道宽度并恢复符号预烤。
|
|
450
|
+
- **停稳边界**:聚合重排被推迟时,即便当前场景没有线且显式关闭了后备缓冲、这一轮没有画出任何轻量几何,计时器也会补一帧完成聚合重算;新增 12000 点、无边场景的回归断言钉住这一条。
|
|
451
|
+
- **实测**:无头 Chrome + ANGLE(AMD Radeon Graphics / D3D11),1280×800,10 万点 / 5 万线,`quality: 'high'`;同一命令下连续缩放 p50 **67.9 → 22.5 ms**、p95 **76.2 → 25.1 ms**、avg **60.77 → 20.57 ms**。平移 p50 17.1 → 17.2 ms(帧节拍波动),`refresh()` 56.2 → 53.7 ms;终态 `thinLines=false`、`noMsaa=false`、`frameMs=0.10`。CPU profile 里 `render` 自身约 0.1%,剩余成本主要是 GPU 光栅化与帧节拍,收益口径是省掉整份重排 / 上传与运动期 MSAA 细线光栅化,不是把单帧渲染降到 1 ms。
|
|
452
|
+
- **核心文件**:`src/gis-view/engine.js`、`docs/steps/selftest-perf.html`、`docs/manual/20-性能与大数据.md`、`docs/internals/16-03-优化与取舍-下.md`、`docs/internals/18-性能实测与WebGPU评估.md`、根 `README.md`、`src/gis-view/README.md`、本轮 aimd。
|
|
453
|
+
- **验证**:`node --check src/gis-view/engine.js`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(**264** 个实例成员 / **96** 个 options / **250** 个数据字段 / **43** 个事件 / **17** 个功能开关)、四页自测 `full 94` / `demos 365` / `docs 134` / `perf 181`(合计 **774** 条通过 / 0 失败)、`npm run build` 与 `git diff --check` 全部通过。公开实例成员、options 与数据字段计数未变。复查入口见 [06 的增量记录](ai/06-会话索引与复查方法.md#2026-10-23-增量修改txt继续深度优化-gis-view-整体性能)。
|
|
454
|
+
|
|
455
|
+
## 2026-10-26 增量(「修改.txt」:修复放大缩小与移动时的短暂模糊)
|
|
456
|
+
|
|
457
|
+
本轮仍是现有会话的继续增量,没有新建会话归档,因此不改上表的 39 条会话统计。需求原话来自仓库根目录最新的 `修改.txt`:修改 gis-view 组件;修改之后放大缩小 / 移动会模糊一下。核对后确认根因是上一轮加入的运动期自适应分辨率:帧间隔超过 22 ms 时把后备缓冲降到 0.65× / 0.5×,再用线性过滤放大贴回。
|
|
458
|
+
|
|
459
|
+
- **根因与撤回**:`engine.js` 删除 `MOTION_RESOLUTION_STEPS` / `sampleMotionResolution()`,运动帧不再缩小 viewport,也不再按 `drawWidth` / `drawHeight` / `framePixelRatio` 计算像素尺度;`shaders.js` 的 `u_offsetScale`、`u_uvOffset` / `u_uvScale` 与 `create.js` 的 `exportFrame` 配套路径一并撤回。交互、滚轮和 `zoomBy` / `setCamera` / 飞行帧现在始终按画布全分辨率绘制,整幅贴回保持 1:1;停稳 160 ms 后照旧恢复 MSAA 静态帧。
|
|
460
|
+
- **保留的优化**:相机轻量窗口、细线 `gl.LINES` 与非 MSAA 后备缓冲仍保留,只换画法、不降分辨率。`pointSizeScale` / `lineWidthScale` / `pointZoomScale` / `lineZoomScale` / `zoomBaseScale` 连续变化时继续走 `scaleMotion` 窗口,暂停符号重烤与预烤,停手后对齐当前尺寸档;相机与尺寸窗口重叠时由最后停下的一方补质量帧。
|
|
461
|
+
- **回归与性能**:`selftest-perf.html` 新增 1 条断言:连续改相机并人为拉长帧间隔,记录到的每次 `gl.viewport` 都必须等于画布全尺寸。最终全分辨率基准为无头 Chrome + ANGLE / AMD D3D11、1280×800、三次取中位:10 万点 / 5 万线缩放 p50 **23.2 ms** / p95 **28.6 ms**、平移 **16.7 / 18.2 ms**;10 万点 / 10 万线缩放 **42.6 / 46.3 ms**、平移 **16.7 / 24.5 ms**。
|
|
462
|
+
- **核心文件**:`src/gis-view/engine.js`、`docs/steps/selftest-perf.html`、`docs/steps/README.md`、`docs/manual/20-性能与大数据.md`、根 `README.md`、`src/gis-view/README.md` 与本轮 aimd;`src/gis-view/shaders.js` / `create.js` 的上一轮配套改动已撤回至 HEAD。
|
|
463
|
+
- **验证**:`node --check src/gis-view/engine.js`、`node --check src/gis-view/create.js`、`node --check src/gis-view/shaders.js`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs`(264 个实例成员未变)、`npm run check:docs`(264 个实例成员 / 250 个方法 / 250 个数据字段 / 96 个 options / 43 个事件 / 17 个功能开关)、九个定向自测页 **1504** 条通过 / 0 失败(features 672 / actions 96 / data 103 / decoration 75 / select 69 / labels 165 / effects 96 / docs 134 / full 94)、`npm run build` 与 `git diff --check` 全部通过。`selftest-perf` **181 / 1**(共 182 条;标签定向重排读数 1313 次、重复 0 条,HEAD 基线已复现),新增的相机全分辨率断言通过;`selftest-scale` 117 / 2(onFilter 计数为 0,筛选链路未改)。公开实例成员、options 与数据字段计数未变。复查入口见 [06 的增量记录](ai/06-会话索引与复查方法.md#2026-10-26-增量修改txt修复放大缩小与移动时的短暂模糊)。
|
|
464
|
+
|
|
465
|
+
## 2026-10-26 增量(「修改.txt」:继续优化 gis-view,回答“感觉没提升多少”)
|
|
466
|
+
|
|
467
|
+
本轮仍是现有会话的继续增量,没有新建会话归档,因此不改上表的 39 条会话统计。需求原话来自仓库根目录最新的 `修改.txt`:修改 gis-view 组件;这样修改之后性能提升了吗,感觉没提升多少。
|
|
468
|
+
|
|
469
|
+
- **先排除 JS**:10 万线交互的 CPU profile 约 **98.6% idle**、`render` 自身约 **0.1%**;上一轮省掉的是场景重排、实例上传与相机排帧,主线程已经接近空转。用户仍会觉得慢,是因为每条可见线在 GPU 片元里继续执行虚线取模、`smoothstep`、边缘覆盖率与光晕分支,且此前优化没有覆盖所有线宽。
|
|
470
|
+
- **片元管线专用化**:`shaders.js` 新增 `THIN_LINE_FRAGMENT_SHADER`,交互期 `gl.LINES` 只输出实例颜色,顶点侧不再携带虚线 / AA / 光晕 varying;新增 `SOLID_LINE_FRAGMENT_SHADER`,整批无虚线且这一遍不是热力光晕的四边形线路跳过虚线取模 / `smoothstep` / 光晕分支,只保留颜色与非 MSAA 边缘覆盖率。`engine.js` 的 `drawLineBatch` 按批切换,`refreshLineThinLedger` 同时返回是否全实线;线宽、端点圆头、全分辨率与停稳后的 MSAA 静态帧都保持。另加属性槽位一致性检查,驱动给两个程序分配不同位置时自动回退通用片元,避免跨驱动画面异常。
|
|
471
|
+
- **门槛修正**:细线快路径实际条件是最大半宽 ≤ 0.6 设备像素且无虚线(dpr = 1 时约 1.2px 线宽,2px 实线不会命中);文档里此前写的「3px 以内」已同步纠正。2px 实线只吃四边形轻量片元,10 万线实测约 **82.4 → 63.9 ms**。
|
|
472
|
+
- **实测**:无头 Chrome + ANGLE / AMD D3D11、1280×800、`quality: 'high'`,三次运行取中位。10 万点 / 5 万线缩放 p50 **23.2 → 16.7 ms**、p95 **28.6 → 16.8 ~ 16.9 ms**;10 万点 / 10 万线缩放 p50 **42.6 → 18.0 ms**、p95 **46.3 → 21.4 ms**,平移 p50 **16.7 ms**。16 ~ 18 ms 已接近 60Hz 帧节拍,剩余成本是 GPU 填充率;继续明显提速只能减少可见线段数或屏幕覆盖面积。
|
|
473
|
+
- **正确性回归**:`selftest-perf.html` 新增 1 条像素级对拍,在同一交互状态下比较细线专用管线与四边形画法的线像素数量和整幅颜色差,防止新管线画丢、画黑或换色;新增断言与既有断言均通过。
|
|
474
|
+
- **核心文件**:`src/gis-view/shaders.js`、`src/gis-view/engine.js`、`docs/steps/selftest-perf.html`、`docs/steps/README.md`、`docs/manual/03-配置项.md`、`docs/manual/05-画质与批量更新.md`、`docs/manual/20-性能与大数据.md`、`docs/manual/21-说明与常见问题.md`、`docs/internals/18-性能实测与WebGPU评估.md`、根 `README.md`、`src/gis-view/README.md` 与本轮 aimd。
|
|
475
|
+
- **验证**:`node --check src/gis-view/engine.js`、`node --check src/gis-view/shaders.js`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs`(264 个实例成员未变)、`npm run check:docs`(264 个实例成员 / 250 个方法 / 250 个数据字段 / 96 个 options / 43 个事件 / 17 个功能开关)、九个定向自测页 **1504** 条通过 / 0 失败、`npm run build` 与 `git diff --check` 全部通过。`selftest-perf` **182 / 1**(共 183 条;标签读数 1313 次、重复 0 条,HEAD 基线已复现),新增像素断言通过;`selftest-scale` 117 / 2(既有的 onFilter 计数失败,筛选链路未改)。公开实例成员、options 与数据字段计数未变。复查入口见 [06 的增量记录](ai/06-会话索引与复查方法.md#2026-10-26-增量修改txt线片段着色管线专用化)。
|
package/docs/GisView.md
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
| [14 视图与筛选](manual/14-视图与筛选.md) | 筛选、搜索定位、初始视图与缩放范围、背景层、鹰眼图、近义入口 |
|
|
33
33
|
| [15 导出与集成](manual/15-导出与集成.md) | 导出图片 / 选中节点 / 数据、自定义导出格式,插件、自建界面与键盘交互 |
|
|
34
34
|
| [16 实例方法总表](manual/16-实例方法总表.md) | 按功能分组的实例方法主表(找方法从这一章开始) |
|
|
35
|
-
| [17 参数速查(逐个方法)](manual/17-参数速查.md) |
|
|
35
|
+
| [17 参数速查(逐个方法)](manual/17-参数速查.md) | 264 个成员逐个列全:参数、默认值与返回 |
|
|
36
36
|
| [18 逐方法示例(复制就能跑)](manual/18-逐方法示例.md) | 每个成员一段可复制的调用示例(API 速查页读的就是这一章) |
|
|
37
37
|
| [19 读数与拖拽预览](manual/19-读数与拖拽预览.md) | 自建界面常用的读数 / 定位方法;拖拽落点预览 |
|
|
38
38
|
| [20 性能与大数据](manual/20-性能与大数据.md) | 十万级数据的开关与实测、WebGPU 取舍、渲染后端开关 |
|
|
@@ -393,6 +393,61 @@
|
|
|
393
393
|
- **自测与文档**:`selftest-perf.html` 新增 3 条断言,锁住原样回灌、通道声明未变沿用派生折线、换骨架必须重推几何;性能页 **167** 条通过。性能记录同步到内部文档 `16-01` 的 16.37 与 `18` 的第十六轮。
|
|
394
394
|
- **验证**:五页自测 full **92** / features **672** / demos **351** / docs **134** / perf **167**,合计 **1416** 条通过 / 0 失败;`node --check`、`node docs/steps/gen-api-index.mjs`、`npm run check:docs`(257 个实例成员 / 96 个 options / 250 个数据字段 / 43 个事件 / 17 个功能开关)、`npx tsc --noEmit`、`npm run build` 与 `git diff --check` 全部通过。详细口径见 [AI 对话汇总的本轮增量](../AI对话汇总.md#2026-10-23-增量修改txt三项commitaddchannel-文档--传参示例--线路半跳过)。
|
|
395
395
|
|
|
396
|
+
### 2026-10-23 增量(「问题.txt」两项:鹰眼图范围锁定开关 / 整图拖动 demo)
|
|
397
|
+
|
|
398
|
+
本轮仍是现有会话的继续增量,没有独立会话归档,因此不改上表的 39 条统计。需求原话来自仓库根目录的 `问题.txt`:外围内容消失不应让鹰眼图自动重算包围盒,该行为做成默认关闭的开关;另补整体拖拽鹰眼图的 demo。
|
|
399
|
+
|
|
400
|
+
- **范围锁定**:`minimap.extentFollowContent` 默认 `false`。`minimap.js` 用 `pinnedExtent` 锁住首次取得的动态数据 / 底图范围,内容筛选、显隐或增删只重画要素,小图范围与视口框保持不动;打开后跟随当前可见内容。显式改 `extent` 或切换开关会清锁并重新取范围,`extentFollowCamera` 的相机取舍使用锁定后的两份范围。
|
|
401
|
+
- **整图拖动**:`MinimapDemo.vue` 在 `getMinimapElement()` 根节点挂独立手柄,手势不进入小图框选 / 平移;累计位移写回 `offset`,窗口级事件收尾,并提供方向键微调、复位与读数。
|
|
402
|
+
- **自测与文档**:`selftest-full.html` 增加 2 条范围锁定断言,`selftest-demos.html` 增加 4 条开关 / 拖动 / 复位断言;同步手册 `03` / `14`、内部文档 `13`、两个 README、类型注释与生成的 `docs/demos/api-index.js`。
|
|
403
|
+
- **验证**:定向三页 full **94** / demos **355** / docs **134**,合计 **583** 条通过 / 0 失败;全量 14 页 **2295** 条通过 / 2 条失败,失败均为 `selftest-scale` 的筛选回调计数,与 minimap 改动无关。`node --check`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(257 个实例成员 / 96 个 options / 250 个数据字段 / 43 个事件 / 17 个功能开关)、`npm run build` 与 `git diff --check` 全部通过。详细口径见 [AI 对话汇总的本轮增量](../AI对话汇总.md#2026-10-23-增量问题txt两项鹰眼图范围锁定开关--整图拖动-demo)。
|
|
404
|
+
|
|
405
|
+
### 2026-10-23 增量(「修改.txt」两项:数据包围盒缓存与相机飞行)
|
|
406
|
+
|
|
407
|
+
本轮仍是现有会话的继续增量,没有独立会话归档,因此不改上表的 39 条统计。需求原话来自仓库根目录的 `修改.txt`:① 继续优化组件整体性能;② 补充后续可能需要的新功能、方法、属性与 demo。
|
|
408
|
+
|
|
409
|
+
- **包围盒缓存**:`engine.js` 把整份解析得到的范围接给 `getBounds()` 读数缓存,读数返回独立副本,缓存本身不与 `fusedDataBounds` 共享;`updatePoint` 改坐标、`updateLine` 改路径、拖拽、追加点 / 线、复制预览改坐标都会失效缓存。十万点 + 十万线实测连续读数 **5.2 ~ 6.6 ms / 次 → 0.00 ms / 次**,单点改动后重建约 **3.6 ms**。
|
|
410
|
+
- **相机飞行**:新增 `flyTo` / `stopCameraAnimation` / `getCameraAnimation` / `cameraAnimating`;时长缺省 450 ms,中心线性、比例对数插值,支持三种预设缓动与自定义函数。用户操作、程序化改相机、再次飞行和销毁都会取消;零时长或系统减少动态效果时立即落位。`SearchFilterDemo.vue` 增加飞向选中、停止飞行与进度读数。
|
|
411
|
+
- **自测与文档**:`selftest-perf.html` 增 3 条缓存断言,`selftest-demos.html` 增 5 条飞行 / demo 断言并更新成员清单;同步方法总表、参数速查、逐方法示例、性能手册、两个 README、类型声明与生成的 `docs/demos/api-index.js`。
|
|
412
|
+
- **验证**:`node --check`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(261 个实例成员 / 96 个 options / 250 个数据字段 / 43 个事件 / 17 个功能开关)、四页自测 full **94** / demos **360** / docs **134** / perf **170**(合计 **758** 条通过 / 0 失败)、`npm run build` 与 `git diff --check` 全部通过。详细口径见 [AI 对话汇总的本轮增量](../AI对话汇总.md#2026-10-23-增量修改txt两项数据包围盒缓存与相机飞行)。
|
|
413
|
+
|
|
414
|
+
### 2026-10-23 增量(「问题.txt」两项:线路样式窄路与新 API 能力)
|
|
415
|
+
|
|
416
|
+
本轮仍是现有会话的继续增量,没有独立会话归档,因此不改上表的 39 条统计。需求原话来自仓库根目录的 `问题.txt`:① 继续深度优化组件整体性能;② 从长远角度补充可能需要的功能、方法、属性与 demo。
|
|
417
|
+
|
|
418
|
+
- **窄路**:`line.js` 抽出 `resolveLinePaintInto`;`engine.js` 用 `NARROW_LINE_STYLE_BUCKETS` / `lineStyleNarrowChange()` / `applyLineNarrowFast()` 认出只改线宽 / 颜色 / 透明度的补丁。命中时逐条重算 paint 并补实例槽位,规则、热力、线型 / 阴影 / 效果 / 方向存在时回退整份解析;逐线自身样式与状态样式仍优先。整份重解析、单线更新和窄路都会同步 `baseWidth`。
|
|
419
|
+
- **新 API**:`flyToCamera` 直接飞相机目标;`dataVersion` 只在数据变更时递增,`onDataChange` 载荷同步带出;`getLineStyle` 返回原始线宽 / RGBA / 透明度 / 层级快照,线宽不含状态样式、热力与缩放倍率。成员 264 = 259 方法 + 5 属性。
|
|
420
|
+
- **Demo 与文档**:`SearchFilterDemo.vue` 增加相机飞行、线路换色 / 加宽、改点与版本读数;自测覆盖 `flyToCamera`、`getLineStyle`、`dataVersion`、虚线保持与规则回退。同步 `docs/manual/04` / `14` / `16` / `17` / `18` / `19` / `20`、内部性能文档、两个 README、类型声明与生成的 `docs/demos/api-index.js`。
|
|
421
|
+
- **验证**:`node --check`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(264 个实例成员 / 96 个 options / 250 个数据字段 / 43 个事件 / 17 个功能开关)、四页自测 full **94** / demos **365** / docs **134** / perf **174**(合计 **767** 条通过 / 0 失败)、`npm run build` 与 `git diff --check` 全部通过。详细口径见 [AI 对话汇总的本轮增量](../AI对话汇总.md#2026-10-23-增量问题txt两项线路样式窄路与新-api-能力)。
|
|
422
|
+
|
|
423
|
+
### 2026-10-23 增量(「修改.txt」:继续深度优化 gis-view 整体性能)
|
|
424
|
+
|
|
425
|
+
本轮仍是现有会话的继续增量,没有独立会话归档,因此不改上表的 39 条统计。需求来自仓库根目录的 `修改.txt`:继续深度优化组件整体性能,允许大改,只要确实有效。
|
|
426
|
+
|
|
427
|
+
- **聚合空转**:`flushPointClusterLayout()` 在聚合未启用且没有上一帧聚合结果时只清脏标记,不跑 `layoutScene()`;`notifyCameraChange()` 只在聚合启用且当前档可能变化、或确有旧聚合结果时因缩放标脏。纯相机缩放引起的成员变化在运动期沿用旧档,停稳后重算;配置 / 数据 / 选中 / 拖动 / 跨出 `maxZoom` 仍立即生效。
|
|
428
|
+
- **程序化相机快路径**:`zoomBy` / `setCamera` / `centerOn` / `flyToCamera` 的真实相机变化进入 160 ms 短窗口,运动帧走细线 `gl.LINES` 与非 MSAA 后备缓冲;同一位置重复 `setCamera` 不续期。停稳后补全质量帧、刷新通道宽度并恢复符号预烤。若聚合重排被推迟但这一轮没有轻量几何,计时器仍会补帧完成重算。
|
|
429
|
+
- **核心文件**:`src/gis-view/engine.js`、`docs/steps/selftest-perf.html`、`docs/manual/20-性能与大数据.md`、`docs/internals/16-03-优化与取舍-下.md`、`docs/internals/18-性能实测与WebGPU评估.md`、根 `README.md`、`src/gis-view/README.md`、`docs/AI对话汇总.md`。
|
|
430
|
+
- **实测**:无头 Chrome + ANGLE / AMD D3D11,1280×800,10 万点 / 5 万线,`quality: 'high'`;连续缩放 p50 **67.9 → 22.5 ms**、p95 **76.2 → 25.1 ms**、avg **60.77 → 20.57 ms**。平移 p50 17.1 → 17.2 ms(帧节拍波动),`refresh()` 56.2 → 53.7 ms;终态 `thinLines=false`、`noMsaa=false`。收益口径是消除整份重排 / 上传与运动期 MSAA 细线光栅化,不是把单帧渲染降到 1 ms。
|
|
431
|
+
- **验证**:`node --check`、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs --check`、`npm run check:docs`(264 个实例成员 / 96 个 options / 250 个数据字段 / 43 个事件 / 17 个功能开关)、四页自测 `full 94` / `demos 365` / `docs 134` / `perf 181` 共 **774** 条通过 / 0 失败、`npm run build` 与 `git diff --check` 全部通过。详细口径见 [AI 对话汇总的本轮增量](../AI对话汇总.md#2026-10-23-增量修改txt继续深度优化-gis-view-整体性能)。
|
|
432
|
+
|
|
433
|
+
### 2026-10-26 增量(「修改.txt」:修复放大缩小与移动时的短暂模糊)
|
|
434
|
+
|
|
435
|
+
本轮仍是现有会话的继续增量,没有独立会话归档,因此不改上表的 39 条统计。需求原话来自仓库根目录最新的 `修改.txt`:修改 gis-view 组件;修改之后放大缩小 / 移动会模糊一下。根因是上一轮运动帧按 rAF 间隔降到 0.65× / 0.5× 后线性放大贴回,本轮已移除。
|
|
436
|
+
|
|
437
|
+
- **撤回降采样**:`engine.js` 删除 `MOTION_RESOLUTION_STEPS` / `sampleMotionResolution()` 与 `drawWidth` / `drawHeight` / `framePixelRatio` 一套像素尺度,运动帧 viewport 始终是画布全尺寸;`shaders.js` 的 `u_offsetScale` / `u_uvOffset` / `u_uvScale` 和 `create.js` 的 `exportFrame` 配套标记同步撤回至 HEAD。交互、滚轮、程序化相机与尺寸倍率变化都保持全分辨率,停稳 160 ms 后恢复 MSAA 静态帧。
|
|
438
|
+
- **保留轻量窗口**:相机运动窗口、细线 `gl.LINES`、非 MSAA 后备缓冲不变;`scaleMotion` 仍只在尺寸倍率连续变化时暂停符号重烤与预烤,停手后对齐当前档,不改变分辨率。相机与尺寸窗口重叠时由最后停下的一方补质量帧。
|
|
439
|
+
- **回归与实测**:`selftest-perf.html` 新增 1 条断言,拉长运动帧间隔并连续改相机,所有 `gl.viewport` 仍必须等于画布全尺寸。无头 Chrome + ANGLE / AMD D3D11、1280×800、三次取中位:10 万点 / 5 万线缩放 p50 **23.2 ms** / p95 **28.6 ms**、平移 **16.7 / 18.2 ms**;10 万点 / 10 万线缩放 **42.6 / 46.3 ms**、平移 **16.7 / 24.5 ms**。
|
|
440
|
+
- **核心文件**:`src/gis-view/engine.js`、`docs/steps/selftest-perf.html`、`docs/steps/README.md`、`docs/manual/20-性能与大数据.md`、根 `README.md`、`src/gis-view/README.md` 与本轮 aimd。
|
|
441
|
+
- **验证**:`node --check`(engine / create / shaders)、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs`(264 个实例成员未变)、`npm run check:docs`(264 个实例成员 / 250 个方法 / 250 个数据字段 / 96 个 options / 43 个事件 / 17 个功能开关)、九个定向自测页 **1504** 条通过 / 0 失败(features / actions / data / decoration / select / labels / effects / docs / full)、`npm run build` 与 `git diff --check` 全部通过。`selftest-perf` **181 / 1**(共 182 条;新增相机全分辨率断言通过,标签布局读数在 HEAD 基线已复现);`selftest-scale` 117 / 2(onFilter 计数,筛选链路未改)。公开 API 计数未变。详细口径见 [AI 对话汇总的本轮增量](../AI对话汇总.md#2026-10-26-增量修改txt修复放大缩小与移动时的短暂模糊)。
|
|
442
|
+
### 2026-10-26 增量(「修改.txt」:线片段着色管线专用化)
|
|
443
|
+
|
|
444
|
+
本轮仍是现有会话的继续增量,没有独立会话归档,因此不改上表的 39 条统计。需求原话来自仓库根目录最新的 `修改.txt`:修改 gis-view 组件;这样修改之后性能提升了吗,感觉没提升多少。
|
|
445
|
+
|
|
446
|
+
- **判断**:CPU profile 约 **98.6% idle**、`render` 约 **0.1%**,说明上一轮主要省的是场景重排 / 上传 / 相机调度,剩余在 GPU 片元。用户感觉提升有限,还因为细线快路径的真实门槛是最大半宽 ≤ 0.6 设备像素且无虚线(dpr = 1 约 1.2px 线宽),2px 线不会命中 `gl.LINES`。
|
|
447
|
+
- **改动**:`shaders.js` 新增 `THIN_LINE_FRAGMENT_SHADER`(细线只输出颜色)与 `SOLID_LINE_FRAGMENT_SHADER`(全实线、非光晕四边形跳过虚线取模 / `smoothstep` / 光晕分支,保留非 MSAA 覆盖率);`engine.js` 的 `drawLineBatch` 按批切换,`refreshLineThinLedger` 同时提供是否全实线;两个程序属性槽位不一致时自动回退通用片元。端点圆头、全分辨率与停稳后的 MSAA 静态帧不变。
|
|
448
|
+
- **实测**:10 万点 / 5 万线缩放 p50 **23.2 → 16.7 ms**、p95 **28.6 → 16.8 ~ 16.9 ms**;10 万点 / 10 万线缩放三次中位 p50 **42.6 → 18.0 ms**、p95 **46.3 → 21.4 ms**;2px 实线的 10 万线只走四边形轻量片元时约 **82.4 → 63.9 ms**。16 ~ 18 ms 已接近 60Hz 帧节拍,剩余成本是 GPU 填充率。
|
|
449
|
+
- **核心文件**:`src/gis-view/shaders.js`、`src/gis-view/engine.js`、`docs/steps/selftest-perf.html`、`docs/steps/README.md`、`docs/manual/03-配置项.md`、`docs/manual/05-画质与批量更新.md`、`docs/manual/20-性能与大数据.md`、`docs/manual/21-说明与常见问题.md`、`docs/internals/18-性能实测与WebGPU评估.md`、根 `README.md`、`src/gis-view/README.md` 与本轮 aimd。
|
|
450
|
+
- **验证**:`node --check`(engine / shaders)、`npx tsc --noEmit`、`node docs/steps/gen-api-index.mjs`(264 个实例成员未变)、`npm run check:docs`(264 个实例成员 / 250 个方法 / 250 个数据字段 / 96 个 options / 43 个事件 / 17 个功能开关)、九个定向自测页 **1504** 条通过 / 0 失败、`npm run build` 与 `git diff --check` 全部通过。`selftest-perf` **182 / 1**(共 183 条;新增像素对拍通过,标签读数失败在 HEAD 已复现);`selftest-scale` 117 / 2(既有 onFilter 计数失败)。公开 API 计数未变。详细口径见 [AI 对话汇总的本轮增量](../AI对话汇总.md#2026-10-26-增量修改txt继续优化-gis-view回答感觉没提升多少)。
|
|
396
451
|
## 六、怎么自己复查
|
|
397
452
|
|
|
398
453
|
会话文件是逐行 JSON,不用整份读 —— 只挑两种行解析就够:`session_meta` 行里的 `payload.cwd` 认项目,`payload.type === 'user_message'` 行里的 `payload.message` 是用户原话:
|
|
@@ -27,7 +27,9 @@ const channelCircuits = ref(true)
|
|
|
27
27
|
const zoomMode = ref('manual')
|
|
28
28
|
const followZoomScale = ref(1)
|
|
29
29
|
const dragAction = ref('pan')
|
|
30
|
+
const extentFollowContent = ref(false)
|
|
30
31
|
const extentFollowCamera = ref(false)
|
|
32
|
+
const offset = ref([0, 0])
|
|
31
33
|
const maxPixelRatio = ref('2')
|
|
32
34
|
const gridPlacement = ref('below-data')
|
|
33
35
|
const customLayers = ref(true)
|
|
@@ -36,6 +38,7 @@ const zoomReadout = ref('—')
|
|
|
36
38
|
const layerReadout = ref('—')
|
|
37
39
|
const eventText = ref('—')
|
|
38
40
|
const interactionReadout = ref('还没有手势')
|
|
41
|
+
const offsetReadout = ref('整图位移 0, 0')
|
|
39
42
|
|
|
40
43
|
const SIZES = {
|
|
41
44
|
small: [148, 104],
|
|
@@ -45,6 +48,8 @@ const SIZES = {
|
|
|
45
48
|
|
|
46
49
|
const dataset = buildDemoData({ count: 64, channels: 3 })
|
|
47
50
|
let view = null
|
|
51
|
+
let minimapHandle = null
|
|
52
|
+
let wholeMapDrag = null
|
|
48
53
|
let layerPaints = { grid: 0, compass: 0, gridStage: '—' }
|
|
49
54
|
|
|
50
55
|
const drawGrid = ({ context, width, height, stage }) => {
|
|
@@ -130,7 +135,9 @@ const minimapOptions = () => {
|
|
|
130
135
|
margin: 12,
|
|
131
136
|
padding: 0.05,
|
|
132
137
|
extent: extent.value,
|
|
138
|
+
extentFollowContent: extentFollowContent.value,
|
|
133
139
|
extentFollowCamera: extentFollowCamera.value,
|
|
140
|
+
offset: [...offset.value],
|
|
134
141
|
background: 'inherit',
|
|
135
142
|
backgroundStyle: 'rgba(255, 255, 255, 0.94)',
|
|
136
143
|
borderColor: '#c7d8eb',
|
|
@@ -179,6 +186,7 @@ const refreshReadout = () => {
|
|
|
179
186
|
if (view) {
|
|
180
187
|
zoomReadout.value = `小图倍数 ${view.getMinimapZoom().toFixed(2)} · ${zoomModeLabel.value}`
|
|
181
188
|
}
|
|
189
|
+
offsetReadout.value = `整图位移 ${Math.round(offset.value[0])}, ${Math.round(offset.value[1])}`
|
|
182
190
|
}
|
|
183
191
|
|
|
184
192
|
const zoomModeLabel = computed(() => zoomMode.value === 'manual'
|
|
@@ -192,6 +200,9 @@ const applyMinimap = () => {
|
|
|
192
200
|
view.updateOptions({ minimap: minimapOptions() })
|
|
193
201
|
eventText.value = `updateOptions:${enabled.value ? '已更新鹰眼图配置' : '已卸载鹰眼图'}`
|
|
194
202
|
requestAnimationFrame(refreshReadout)
|
|
203
|
+
if (enabled.value) {
|
|
204
|
+
requestAnimationFrame(installMinimapHandle)
|
|
205
|
+
}
|
|
195
206
|
}
|
|
196
207
|
|
|
197
208
|
const resetZoom = () => {
|
|
@@ -220,6 +231,96 @@ const showDragDemo = (action) => {
|
|
|
220
231
|
: '拖拽演示:已切到手动缩放,在小图空白处拖动平移小图内容'
|
|
221
232
|
}
|
|
222
233
|
|
|
234
|
+
/** 把 offset 写回实例:整图拖动只改角落位移,不重画小图,也不碰主图相机 */
|
|
235
|
+
const setWholeMapOffset = (next) => {
|
|
236
|
+
const x = Number(next?.[0])
|
|
237
|
+
const y = Number(next?.[1])
|
|
238
|
+
offset.value = [Number.isFinite(x) ? x : 0, Number.isFinite(y) ? y : 0]
|
|
239
|
+
const options = view?.getOptions().minimap
|
|
240
|
+
if (options) {
|
|
241
|
+
view.updateOptions({ minimap: { ...options, offset: [...offset.value] } })
|
|
242
|
+
}
|
|
243
|
+
offsetReadout.value = `整图位移 ${Math.round(offset.value[0])}, ${Math.round(offset.value[1])}`
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const resetWholeMapOffset = () => {
|
|
247
|
+
setWholeMapOffset([0, 0])
|
|
248
|
+
eventText.value = '整图拖动:位置已复位到当前角落'
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const beginWholeMapDrag = (event) => {
|
|
252
|
+
if (!view || event.button !== 0) {
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
event.preventDefault()
|
|
256
|
+
event.stopPropagation()
|
|
257
|
+
const current = view.getOptions().minimap?.offset
|
|
258
|
+
const origin = Array.isArray(current) ? [Number(current[0]) || 0, Number(current[1]) || 0] : [...offset.value]
|
|
259
|
+
wholeMapDrag = { pointerId: event.pointerId, clientX: event.clientX, clientY: event.clientY, origin }
|
|
260
|
+
minimapHandle?.classList.add('is-dragging')
|
|
261
|
+
eventText.value = '整图拖动:按住顶部手柄移动,松手停在当前角落'
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const moveWholeMapDrag = (event) => {
|
|
265
|
+
if (!wholeMapDrag || event.pointerId !== wholeMapDrag.pointerId) {
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
event.preventDefault()
|
|
269
|
+
event.stopPropagation()
|
|
270
|
+
setWholeMapOffset([
|
|
271
|
+
wholeMapDrag.origin[0] + event.clientX - wholeMapDrag.clientX,
|
|
272
|
+
wholeMapDrag.origin[1] + event.clientY - wholeMapDrag.clientY
|
|
273
|
+
])
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const endWholeMapDrag = (event) => {
|
|
277
|
+
if (!wholeMapDrag || (event?.pointerId !== undefined && event.pointerId !== wholeMapDrag.pointerId)) {
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
event?.preventDefault()
|
|
281
|
+
event?.stopPropagation()
|
|
282
|
+
minimapHandle?.classList.remove('is-dragging')
|
|
283
|
+
wholeMapDrag = null
|
|
284
|
+
eventText.value = `整图拖动:已停在位移 ${Math.round(offset.value[0])}, ${Math.round(offset.value[1])}`
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const nudgeWholeMap = (event) => {
|
|
288
|
+
const step = event.shiftKey ? 10 : 2
|
|
289
|
+
const delta = event.key === 'ArrowLeft' ? [-step, 0]
|
|
290
|
+
: event.key === 'ArrowRight' ? [step, 0]
|
|
291
|
+
: event.key === 'ArrowUp' ? [0, -step]
|
|
292
|
+
: event.key === 'ArrowDown' ? [0, step] : null
|
|
293
|
+
if (!delta) {
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
event.preventDefault()
|
|
297
|
+
event.stopPropagation()
|
|
298
|
+
setWholeMapOffset([offset.value[0] + delta[0], offset.value[1] + delta[1]])
|
|
299
|
+
eventText.value = '整图拖动:方向键也能微调整图位置(按住 Shift 每次 10px)'
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** 给库创建的根节点挂一个独立的拖动手柄:手柄自己 stopPropagation,不会触发小图框选 / 平移手势 */
|
|
303
|
+
const installMinimapHandle = () => {
|
|
304
|
+
if (!view || minimapHandle) {
|
|
305
|
+
return
|
|
306
|
+
}
|
|
307
|
+
const root = view.getMinimapElement()
|
|
308
|
+
if (!root) {
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
minimapHandle = document.createElement('div')
|
|
312
|
+
minimapHandle.className = 'demo-minimap-drag-handle'
|
|
313
|
+
minimapHandle.dataset.demo = 'minimap-drag-handle'
|
|
314
|
+
minimapHandle.setAttribute('role', 'button')
|
|
315
|
+
minimapHandle.setAttribute('tabindex', '0')
|
|
316
|
+
minimapHandle.setAttribute('aria-label', '拖动整张鹰眼图')
|
|
317
|
+
minimapHandle.title = '按住拖动整张鹰眼图;方向键可微调'
|
|
318
|
+
minimapHandle.textContent = '拖动整图'
|
|
319
|
+
minimapHandle.addEventListener('pointerdown', beginWholeMapDrag)
|
|
320
|
+
minimapHandle.addEventListener('keydown', nudgeWholeMap)
|
|
321
|
+
root.append(minimapHandle)
|
|
322
|
+
}
|
|
323
|
+
|
|
223
324
|
const refreshLayerReadout = () => {
|
|
224
325
|
layerReadout.value = `网格层 ${layerPaints.grid} 次(${layerPaints.gridStage}) · 指北针层 ${layerPaints.compass} 次`
|
|
225
326
|
refreshReadout()
|
|
@@ -252,9 +353,18 @@ onMounted(() => {
|
|
|
252
353
|
eventText.value = `warning:${text}`
|
|
253
354
|
}
|
|
254
355
|
})
|
|
356
|
+
installMinimapHandle()
|
|
357
|
+
window.addEventListener('pointermove', moveWholeMapDrag, true)
|
|
358
|
+
window.addEventListener('pointerup', endWholeMapDrag, true)
|
|
359
|
+
window.addEventListener('pointercancel', endWholeMapDrag, true)
|
|
255
360
|
})
|
|
256
361
|
|
|
257
362
|
onBeforeUnmount(() => {
|
|
363
|
+
window.removeEventListener('pointermove', moveWholeMapDrag, true)
|
|
364
|
+
window.removeEventListener('pointerup', endWholeMapDrag, true)
|
|
365
|
+
window.removeEventListener('pointercancel', endWholeMapDrag, true)
|
|
366
|
+
minimapHandle?.remove()
|
|
367
|
+
minimapHandle = null
|
|
258
368
|
view?.destroy()
|
|
259
369
|
view = null
|
|
260
370
|
})
|
|
@@ -312,10 +422,16 @@ const sizeSummary = computed(() => `${SIZES[size.value]?.[0] ?? 0}×${SIZES[size
|
|
|
312
422
|
</select>
|
|
313
423
|
</label>
|
|
314
424
|
</div>
|
|
425
|
+
<div class="dv-row">
|
|
426
|
+
<label><input v-model="extentFollowContent" type="checkbox" data-demo="minimap-extent-content" @change="applyMinimap" /> 自动范围随内容更新(默认关)</label>
|
|
427
|
+
</div>
|
|
315
428
|
<div class="dv-row">
|
|
316
429
|
<label><input v-model="extentFollowCamera" type="checkbox" data-demo="minimap-extent-follow" @change="applyMinimap" /> 自动范围随相机收窄(默认关)</label>
|
|
317
430
|
</div>
|
|
318
|
-
<
|
|
431
|
+
<div class="dv-row">
|
|
432
|
+
<button type="button" class="dv-button" data-demo="minimap-offset-reset" @click="resetWholeMapOffset">整图位置复位</button>
|
|
433
|
+
</div>
|
|
434
|
+
<p class="dv-hint"><code>extentFollowContent</code> 默认关闭:筛选或删除外围要素不会改小图范围。按住小图顶部的「拖动整图」手柄可移动整张鹰眼图,方向键可微调;<code>offset</code> 会随其他控件一起保留。<code>maxPixelRatio</code> 越大越清晰,也越吃填充率;高分屏按机器档位调到 2 通常就够。</p>
|
|
319
435
|
</div>
|
|
320
436
|
<div class="dv-group">
|
|
321
437
|
<h3>规则与交互</h3>
|
|
@@ -396,9 +512,46 @@ const sizeSummary = computed(() => `${SIZES[size.value]?.[0] ?? 0}×${SIZES[size
|
|
|
396
512
|
<div class="dv-group">
|
|
397
513
|
<h3>读数</h3>
|
|
398
514
|
<p class="dv-readout" data-demo="minimap-readout">{{ readout }}</p>
|
|
515
|
+
<p class="dv-readout" data-demo="minimap-offset-readout">{{ offsetReadout }}</p>
|
|
399
516
|
<p class="dv-readout" data-demo="minimap-event" aria-live="polite">{{ eventText }}</p>
|
|
400
517
|
<p class="dv-readout" data-demo="minimap-interaction" aria-live="polite">{{ interactionReadout }}</p>
|
|
401
518
|
</div>
|
|
402
519
|
</aside>
|
|
403
520
|
</section>
|
|
404
521
|
</template>
|
|
522
|
+
|
|
523
|
+
<style scoped>
|
|
524
|
+
:deep(.demo-minimap-drag-handle) {
|
|
525
|
+
position: absolute;
|
|
526
|
+
z-index: 4;
|
|
527
|
+
top: 4px;
|
|
528
|
+
left: 50%;
|
|
529
|
+
box-sizing: border-box;
|
|
530
|
+
min-width: 68px;
|
|
531
|
+
padding: 2px 9px;
|
|
532
|
+
transform: translateX(-50%);
|
|
533
|
+
border: 1px solid rgba(54, 120, 191, 0.38);
|
|
534
|
+
border-radius: 999px;
|
|
535
|
+
background: rgba(255, 255, 255, 0.9);
|
|
536
|
+
box-shadow: 0 2px 7px rgba(31, 62, 105, 0.14);
|
|
537
|
+
color: #2f5e94;
|
|
538
|
+
font-size: 10px;
|
|
539
|
+
line-height: 16px;
|
|
540
|
+
text-align: center;
|
|
541
|
+
cursor: grab;
|
|
542
|
+
user-select: none;
|
|
543
|
+
touch-action: none;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
:deep(.demo-minimap-drag-handle:hover),
|
|
547
|
+
:deep(.demo-minimap-drag-handle:focus-visible) {
|
|
548
|
+
border-color: #3678bf;
|
|
549
|
+
background: #fff;
|
|
550
|
+
outline: none;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
:deep(.demo-minimap-drag-handle.is-dragging) {
|
|
554
|
+
cursor: grabbing;
|
|
555
|
+
background: #eaf2fc;
|
|
556
|
+
}
|
|
557
|
+
</style>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
|
11
11
|
import { createGisView } from '../../src/index.js'
|
|
12
|
-
import { buildDemoData } from './shared/demoData.js'
|
|
12
|
+
import { buildDemoData, DEMO_CENTER } from './shared/demoData.js'
|
|
13
13
|
import './shared/demoStyle.css'
|
|
14
14
|
|
|
15
15
|
const emit = defineEmits(['notice'])
|
|
@@ -44,8 +44,15 @@ const searchResult = ref(null)
|
|
|
44
44
|
const filterResult = ref(null)
|
|
45
45
|
const visibleDataText = ref('未读取')
|
|
46
46
|
const activeFilter = ref('none')
|
|
47
|
+
const cameraReadout = ref('cameraAnimating: false')
|
|
48
|
+
const apiReadout = ref('dataVersion: -')
|
|
49
|
+
const lineStyleReadout = ref('getLineStyle(0): -')
|
|
50
|
+
const lastDataVersion = ref(null)
|
|
51
|
+
const lineStyleWarm = ref(false)
|
|
47
52
|
let view = null
|
|
48
53
|
let requestSeq = 0
|
|
54
|
+
let cameraReadoutFrame = 0
|
|
55
|
+
let pointTweakCursor = 0
|
|
49
56
|
|
|
50
57
|
const SCOPES = [
|
|
51
58
|
{ id: 'all', label: '全部四类' },
|
|
@@ -186,6 +193,59 @@ const focusAllHits = () => {
|
|
|
186
193
|
view?.focusOn(hits, { select: true, zoom: true })
|
|
187
194
|
actionText.value = `focusOn(hits, { select: true, zoom: true }):${hits.length} 条命中一起进包围盒并选中`
|
|
188
195
|
}
|
|
196
|
+
const syncCameraReadout = () => {
|
|
197
|
+
const animation = view?.getCameraAnimation() ?? null
|
|
198
|
+
cameraReadout.value = animation
|
|
199
|
+
? `cameraAnimating: true · ${Math.round(animation.progress * 100)}% · ${animation.duration} ms`
|
|
200
|
+
: `cameraAnimating: ${view?.cameraAnimating === true} · 没有飞行`
|
|
201
|
+
}
|
|
202
|
+
const syncApiReadout = () => {
|
|
203
|
+
const data = view?.getData()
|
|
204
|
+
const style = view?.getLineStyle(0) ?? null
|
|
205
|
+
apiReadout.value = `dataVersion=${view?.dataVersion ?? '-'} · onDataChange=${lastDataVersion.value ?? '-'} · ${data?.points.length ?? 0} 节点 / ${data?.lines.length ?? 0} 线路`
|
|
206
|
+
lineStyleReadout.value = style
|
|
207
|
+
? `getLineStyle(0):width=${style.width.toFixed(2)} · color=[${style.color.map(value => value.toFixed(2)).join(', ')}] · opacity=${style.opacity.toFixed(2)} · zIndex=${style.zIndex}`
|
|
208
|
+
: 'getLineStyle(0):null'
|
|
209
|
+
}
|
|
210
|
+
const pumpCameraReadout = () => {
|
|
211
|
+
if (cameraReadoutFrame) {
|
|
212
|
+
cancelAnimationFrame(cameraReadoutFrame)
|
|
213
|
+
}
|
|
214
|
+
const tick = () => {
|
|
215
|
+
cameraReadoutFrame = 0
|
|
216
|
+
syncCameraReadout()
|
|
217
|
+
if (view?.cameraAnimating) {
|
|
218
|
+
cameraReadoutFrame = requestAnimationFrame(tick)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
cameraReadoutFrame = requestAnimationFrame(tick)
|
|
222
|
+
}
|
|
223
|
+
const flyToAllHits = () => {
|
|
224
|
+
const hits = searchResult.value?.hits ?? []
|
|
225
|
+
if (!hits.length) {
|
|
226
|
+
actionText.value = '当前没有可飞向的命中'
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
view?.flyTo(hits, { select: true, zoom: true, duration: 700, easing: 'ease-in-out' })
|
|
230
|
+
actionText.value = `flyTo(hits, { select: true, zoom: true, duration: 700 }):${hits.length} 条命中飞向同一包围盒`
|
|
231
|
+
syncCameraReadout()
|
|
232
|
+
pumpCameraReadout()
|
|
233
|
+
}
|
|
234
|
+
const flyToCameraPreset = () => {
|
|
235
|
+
if (!view) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
const scale = Math.max((view.getZoomBaseScale() || 1) * 1.6, 1)
|
|
239
|
+
view.flyToCamera({ center: [...DEMO_CENTER], scale }, { duration: 600, easing: 'ease-out' })
|
|
240
|
+
actionText.value = `flyToCamera({ center: [${DEMO_CENTER.join(', ')}], scale: ${scale.toFixed(2)} }, { duration: 600 }):不经过要素解析,直接飞相机`
|
|
241
|
+
syncCameraReadout()
|
|
242
|
+
pumpCameraReadout()
|
|
243
|
+
}
|
|
244
|
+
const stopCameraFlight = () => {
|
|
245
|
+
view?.stopCameraAnimation()
|
|
246
|
+
syncCameraReadout()
|
|
247
|
+
actionText.value = 'stopCameraAnimation():停在当前帧,不补跳到终点'
|
|
248
|
+
}
|
|
189
249
|
const readVisibleData = () => {
|
|
190
250
|
if (!view) {
|
|
191
251
|
return null
|
|
@@ -214,6 +274,35 @@ const applyFilter = (filter) => {
|
|
|
214
274
|
filterResult.value = view.getFilterResult()
|
|
215
275
|
readVisibleData()
|
|
216
276
|
}
|
|
277
|
+
const bumpDataVersion = () => {
|
|
278
|
+
if (!view) {
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
const points = view.getData().points
|
|
282
|
+
if (!points.length) {
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
const item = points[pointTweakCursor % points.length]
|
|
286
|
+
pointTweakCursor += 1
|
|
287
|
+
const nextLoading = Number(((Number(item.max_loading_rate) || 0) + 0.01).toFixed(3))
|
|
288
|
+
view.updatePoint(item.id ?? pointTweakCursor - 1, { max_loading_rate: nextLoading })
|
|
289
|
+
actionText.value = `updatePoint(${item.id ?? pointTweakCursor - 1}, { max_loading_rate: ${nextLoading} }):数据变了,dataVersion 应 +1`
|
|
290
|
+
syncApiReadout()
|
|
291
|
+
}
|
|
292
|
+
const toggleLineStyle = () => {
|
|
293
|
+
if (!view) {
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
lineStyleWarm.value = !lineStyleWarm.value
|
|
297
|
+
if (lineStyleWarm.value) {
|
|
298
|
+
view.updateLineStyle({ color: '#f59f4b', width: 3.2, opacity: 1 })
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
view.updateLineStyle({ color: 'rgba(120, 168, 226, 0.43)', width: 1.2, opacity: 0.43 })
|
|
302
|
+
}
|
|
303
|
+
actionText.value = `updateLineStyle(${lineStyleWarm.value ? '暖色 + 3.2px' : '恢复 1.2px' }):只重算线宽 / 颜色链,dataVersion 不变`
|
|
304
|
+
syncApiReadout()
|
|
305
|
+
}
|
|
217
306
|
|
|
218
307
|
onMounted(() => {
|
|
219
308
|
view = createGisView(container.value, {
|
|
@@ -241,6 +330,10 @@ onMounted(() => {
|
|
|
241
330
|
onReady: () => {
|
|
242
331
|
emit('notice', `${dataset.points.length} 节点 / ${dataset.lines.length} 线路,搜索与筛选都是只读口径`)
|
|
243
332
|
},
|
|
333
|
+
onDataChange: payload => {
|
|
334
|
+
lastDataVersion.value = payload.dataVersion
|
|
335
|
+
syncApiReadout()
|
|
336
|
+
},
|
|
244
337
|
onFilter: result => syncFilterReadout(result),
|
|
245
338
|
onWarning: text => {
|
|
246
339
|
actionText.value = `warning:${text}`
|
|
@@ -248,10 +341,15 @@ onMounted(() => {
|
|
|
248
341
|
})
|
|
249
342
|
runSearch('sync')
|
|
250
343
|
readVisibleData()
|
|
344
|
+
syncApiReadout()
|
|
251
345
|
})
|
|
252
346
|
|
|
253
347
|
onBeforeUnmount(() => {
|
|
254
348
|
requestSeq += 1
|
|
349
|
+
if (cameraReadoutFrame) {
|
|
350
|
+
cancelAnimationFrame(cameraReadoutFrame)
|
|
351
|
+
cameraReadoutFrame = 0
|
|
352
|
+
}
|
|
255
353
|
view?.destroy()
|
|
256
354
|
view = null
|
|
257
355
|
})
|
|
@@ -301,9 +399,12 @@ onBeforeUnmount(() => {
|
|
|
301
399
|
<p class='dv-hint'>scope 可写 points / lines / channels / groups,也认 point / line / channel / group;显式 fields 能搜默认会跳过的 symbol。搜索基于全量数据,不隐藏、也不自动移动视角。</p>
|
|
302
400
|
<div class='dv-row'>
|
|
303
401
|
<button type='button' class='dv-button' data-demo='search-filter-focus-all' @click='focusAllHits'>聚焦并选中全部命中</button>
|
|
402
|
+
<button type='button' class='dv-button dv-button--primary' data-demo='search-filter-fly-all' @click='flyToAllHits'>飞向选中(flyTo)</button>
|
|
403
|
+
<button type='button' class='dv-button' data-demo='search-filter-stop-flight' @click='stopCameraFlight'>停止飞行</button>
|
|
304
404
|
</div>
|
|
305
405
|
<p class='dv-readout' data-demo='search-filter-summary'>{{ searchSummary }}</p>
|
|
306
406
|
<p class='dv-readout' data-demo='search-filter-meta'>{{ searchMeta }}</p>
|
|
407
|
+
<p class='dv-readout' data-demo='search-filter-camera'>{{ cameraReadout }}</p>
|
|
307
408
|
<p class='dv-hint' data-demo='search-filter-action'>{{ actionText }}</p>
|
|
308
409
|
<ul v-if='hitRows.length' class='sf-hits'>
|
|
309
410
|
<li v-for='row in hitRows' :key='row.key'>
|
|
@@ -335,6 +436,17 @@ onBeforeUnmount(() => {
|
|
|
335
436
|
</div>
|
|
336
437
|
<p class='dv-hint' data-demo='search-filter-filter-action'>{{ filterAction }}</p>
|
|
337
438
|
</div>
|
|
439
|
+
<div class='dv-group'>
|
|
440
|
+
<h3>相机、版本与线路读数<span class='dv-chip'>flyToCamera</span></h3>
|
|
441
|
+
<div class='dv-row'>
|
|
442
|
+
<button type='button' class='dv-button dv-button--primary' data-demo='search-filter-fly-camera' @click='flyToCameraPreset'>飞向固定相机</button>
|
|
443
|
+
<button type='button' class='dv-button' data-demo='search-filter-data-bump' @click='bumpDataVersion'>改一个点(dataVersion +1)</button>
|
|
444
|
+
<button type='button' class='dv-button' data-demo='search-filter-line-recolor' @click='toggleLineStyle'>线路换色 / 加宽</button>
|
|
445
|
+
</div>
|
|
446
|
+
<p class='dv-readout' data-demo='search-filter-data-version'>{{ apiReadout }}</p>
|
|
447
|
+
<p class='dv-readout' data-demo='search-filter-line-style'>{{ lineStyleReadout }}</p>
|
|
448
|
+
<p class='dv-hint'>flyToCamera 直接收 <code>{ center?, scale? }</code>,没写的字段沿用当前相机;updateLineStyle 只改全局线宽 / 颜色时走窄路,dataVersion 不增加,getLineStyle 仍能读到最新解析值。</p>
|
|
449
|
+
</div>
|
|
338
450
|
<div class='dv-group'>
|
|
339
451
|
<h3>两件事别混用</h3>
|
|
340
452
|
<p class='dv-hint'>search 只把要素找出来,结果带 bounds;要居中就再调 focusOn。setFilter 只隐藏显示、不删数据,也不清空选中集:条件放宽后,原本选中的要素仍保持选中。</p>
|