gis-view-webgl2 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -14
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +252 -37
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +79 -0
- package/docs/GisView.md +53 -53
- 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 +66 -0
- package/docs/api/index.html +22 -8
- package/docs/demos/ApiCoverageDemo.vue +1 -1
- package/docs/demos/ConnectDemo.vue +114 -3
- package/docs/demos/ExtensionDemo.vue +69 -12
- package/docs/demos/MinimapDemo.vue +62 -16
- package/docs/demos/SearchFilterDemo.vue +13 -11
- package/docs/demos/api-index.js +26 -21
- package/docs/demos/demos.js +1 -1
- package/docs/demos/gis-view-demo/GisViewDemoCardHeader.vue +1 -0
- package/docs/demos/gis-view-demo/GisViewDemoStage.vue +25 -16
- package/docs/demos/gis-view-demo/panels/OpsPanels.vue +2 -2
- package/docs/demos/gis-view-demo/useGisViewDemo.js +36 -25
- package/docs/index.html +41 -4
- package/docs/internals/13-/351/271/260/347/234/274/345/233/276.md +6 -5
- package/docs/internals/16-01-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/212.md +5 -3
- package/docs/internals/18-/346/200/247/350/203/275/345/256/236/346/265/213/344/270/216WebGPU/350/257/204/344/274/260.md +12 -0
- package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +29 -6
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +7 -6
- package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +24 -3
- package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +1 -1
- package/docs/manual/10-/351/200/232/351/201/223/347/274/226/350/276/221/344/270/216/346/226/260/345/242/236.md +423 -3
- package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +169 -62
- package/docs/manual/15-/345/257/274/345/207/272/344/270/216/351/233/206/346/210/220.md +32 -3
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +12 -8
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +13 -9
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +156 -12
- package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +3 -3
- package/docs/manual/21-/350/257/264/346/230/216/344/270/216/345/270/270/350/247/201/351/227/256/351/242/230.md +11 -5
- package/docs/steps/README.md +8 -8
- package/docs/steps/selftest-demos.html +173 -12
- package/docs/steps/selftest-docs.html +33 -4
- package/docs/steps/selftest-features.html +91 -10
- package/docs/steps/selftest-full.html +315 -12
- package/docs/steps/selftest-perf.html +39 -1
- package/docs/steps/selftest-scale.html +98 -0
- package/docs/steps/selftest-select.html +90 -0
- package/package.json +1 -1
|
@@ -1274,11 +1274,11 @@ export const useGisViewDemo = () => {
|
|
|
1274
1274
|
hint = `getElementBounds(选中 ${selected.length} 个):世界包围盒;一个都没对上返回 null(先在画布上选几个)`
|
|
1275
1275
|
}
|
|
1276
1276
|
else if (kind === 'locate') {
|
|
1277
|
-
//
|
|
1277
|
+
// 一批目标(数组)取整体包围盒:zoom: true 才按这一批的范围适配,缺省只居中
|
|
1278
1278
|
const selection = view.getSelections()
|
|
1279
|
-
view.focusOn(selection, { maxZoom: 8, padding: 40 })
|
|
1279
|
+
view.focusOn(selection, { zoom: true, maxZoom: 8, padding: 40 })
|
|
1280
1280
|
value = { focused: selection.length }
|
|
1281
|
-
hint = `focusOn(getSelections(), { maxZoom: 8, padding: 40 }):把这一批(${selection.length} 个)整体居中并适配;只给一个节点时也会放大到 8 倍`
|
|
1281
|
+
hint = `focusOn(getSelections(), { zoom: true, maxZoom: 8, padding: 40 }):把这一批(${selection.length} 个)整体居中并适配;只给一个节点时也会放大到 8 倍`
|
|
1282
1282
|
}
|
|
1283
1283
|
else if (kind === 'contextAt') {
|
|
1284
1284
|
const pointer = view.getPointer()
|
|
@@ -1429,7 +1429,7 @@ export const useGisViewDemo = () => {
|
|
|
1429
1429
|
const count = payload.selection?.count ?? 0
|
|
1430
1430
|
return [
|
|
1431
1431
|
{ id: 'addStation', label: `新增场站(addPoint)· 落点 (${payload.world[0].toFixed(1)}, ${payload.world[1].toFixed(1)})`, enabled: !payload.hit, reason: '这一下命中了要素:在空白处右键才能新增场站' },
|
|
1432
|
-
{ id: 'locate', label:
|
|
1432
|
+
{ id: 'locate', label: `定位并适配选中(focusOn)${count ? ` · ${count} 个` : ''}`, enabled: count > 0, reason: '先在画布上选一个 / 一批要素' },
|
|
1433
1433
|
{ id: 'focus', label: '聚焦到命中的那一个(focusOn)', enabled: Boolean(payload.hit), reason: '这一下点在空白处:没有命中要素' },
|
|
1434
1434
|
{ id: 'fit', label: '适应视图(fitView)', enabled: true, reason: '' },
|
|
1435
1435
|
{ id: 'inspect', label: '读一下选中集(getSelectionData)', enabled: count > 0, reason: '选中集是空的' },
|
|
@@ -1450,8 +1450,8 @@ export const useGisViewDemo = () => {
|
|
|
1450
1450
|
}
|
|
1451
1451
|
else if (row.id === 'locate') {
|
|
1452
1452
|
const selection = view.getSelections()
|
|
1453
|
-
view.focusOn(selection, { maxZoom: 8, padding: 40 })
|
|
1454
|
-
lastEvent.value = `画布菜单:focusOn(选中 ${selection.length} 个, { maxZoom: 8, padding: 40 })${selection.length ? '
|
|
1453
|
+
view.focusOn(selection, { zoom: true, maxZoom: 8, padding: 40 })
|
|
1454
|
+
lastEvent.value = `画布菜单:focusOn(选中 ${selection.length} 个, { zoom: true, maxZoom: 8, padding: 40 })${selection.length ? '(视角挪到这一批的整体中心并按范围适配,单个节点也会放大到 8 倍)' : '(没选中:什么都没做)'}`
|
|
1455
1455
|
}
|
|
1456
1456
|
else if (row.id === 'focus') {
|
|
1457
1457
|
view.focusOn({ type: payload.type, index: payload.index })
|
|
@@ -2566,11 +2566,11 @@ export const useGisViewDemo = () => {
|
|
|
2566
2566
|
const kind = first.kind === 'point' ? '节点' : first.kind === 'line' ? '线路' : '通道'
|
|
2567
2567
|
const member = first.memberIndex === undefined ? '' : `第 ${first.memberIndex + 1} 回`
|
|
2568
2568
|
const value = first.value.length > 24 ? `${first.value.slice(0, 24)}…` : first.value
|
|
2569
|
-
// 命中的一批直接喂给 focusOn
|
|
2569
|
+
// 命中的一批直接喂给 focusOn:数组取整体包围盒,zoom: true 才按这批命中适配;
|
|
2570
2570
|
// select: true 顺带把它们选上(不想动视角就取消勾选,组件这边不会自己动)
|
|
2571
2571
|
const focused = searchFocus.value
|
|
2572
2572
|
if (focused) {
|
|
2573
|
-
view.focusOn(result.hits, { select: true, padding: 60 })
|
|
2573
|
+
view.focusOn(result.hits, { select: true, zoom: true, padding: 60 })
|
|
2574
2574
|
}
|
|
2575
2575
|
searchReadout.value = `${focused ? '已聚焦并选中' : '只返回结果(视角没动)'} ${kind}(${first.field} = ${value}${member ? ` · ${member}` : ''})· 命中 ${result.total}:节点 ${result.points.length} / 线路 ${result.lines.length} / 通道 ${result.channels.length}${result.truncated ? ' · 已截断' : ''}`
|
|
2576
2576
|
}
|
|
@@ -3443,7 +3443,8 @@ export const useGisViewDemo = () => {
|
|
|
3443
3443
|
/**
|
|
3444
3444
|
* 鹰眼图:改成组件自带的能力,这里只留开关与样式配置。
|
|
3445
3445
|
* 节点与线路各自一份样式,框可以直接拖,空白处长按之后视角跟过去;
|
|
3446
|
-
*
|
|
3446
|
+
* 缩放模式三选一:关闭 / 手动缩放小图(zoomable: true)/ 跟随主图(zoomable: 'follow');
|
|
3447
|
+
* 手动模式走滚轮与 setMinimapZoom 那一组,跟随模式只由主图倍数带动。
|
|
3447
3448
|
*/
|
|
3448
3449
|
const MINIMAP_SIZES = {
|
|
3449
3450
|
small: [132, 99],
|
|
@@ -3456,9 +3457,13 @@ export const useGisViewDemo = () => {
|
|
|
3456
3457
|
const minimapShowLines = ref(true)
|
|
3457
3458
|
/** 小图范围:auto 数据 ∪ 底图(GeoJSON 底图不会缩成一个点)、data 只看数据(老行为)、background 只看底图 */
|
|
3458
3459
|
const minimapExtent = ref('auto')
|
|
3459
|
-
/**
|
|
3460
|
-
const
|
|
3461
|
-
/**
|
|
3460
|
+
/** auto 范围是否随相机收窄:默认关,始终按数据 ∪ 底图铺 */
|
|
3461
|
+
const minimapExtentFollowCamera = ref(false)
|
|
3462
|
+
/** 缩放模式:off 关闭、manual 手动缩放小图、follow 整体范围跟随主图;后两者互斥 */
|
|
3463
|
+
const minimapZoomMode = ref('off')
|
|
3464
|
+
/** 跟随主图时主图倍数的指数:1 同倍率、0.5 是主图放大 4 倍小图放大 2 倍 */
|
|
3465
|
+
const minimapFollowZoomScale = ref(1)
|
|
3466
|
+
/** 小图空白处拖动做哪个动作:平移小图内容 / 直接框选;box 不依赖手动缩放 */
|
|
3462
3467
|
const minimapDragAction = ref('pan')
|
|
3463
3468
|
/** 通道在小图上画几根:true 画全部回线,false 一个通道只画偏移最靠中间的那一根 */
|
|
3464
3469
|
const minimapChannelCircuits = ref(true)
|
|
@@ -3523,7 +3528,8 @@ export const useGisViewDemo = () => {
|
|
|
3523
3528
|
/** 鹰眼图折叠条上的摘要:不展开设置也能看到当前档位 */
|
|
3524
3529
|
const minimapSummary = computed(() => {
|
|
3525
3530
|
const size = MINIMAP_SIZES[minimapSize.value] ?? []
|
|
3526
|
-
|
|
3531
|
+
const zoom = minimapZoomMode.value === 'manual' ? '手动缩放' : minimapZoomMode.value === 'follow' ? '跟随主图' : '不缩放'
|
|
3532
|
+
return `${size[0] ?? 0}×${size[1] ?? 0} · ${minimapEnabled.value ? '开' : '关'} · ${zoom} · ${minimapShowLines.value ? '线路' : '无线'} · ${minimapChannelCircuits.value ? '全部回线' : '一根回线'}`
|
|
3527
3533
|
})
|
|
3528
3534
|
/** 主图节点规则里出现过的层号:按电压分层关掉时全是 0,就没有可选的层 */
|
|
3529
3535
|
const minimapLayerOptions = computed(() => {
|
|
@@ -3579,6 +3585,8 @@ export const useGisViewDemo = () => {
|
|
|
3579
3585
|
height: MINIMAP_SIZES[minimapSize.value][1],
|
|
3580
3586
|
// 范围:默认数据与底图合起来,GeoJSON 底图不会因为与数据范围不重合而缩成一个点
|
|
3581
3587
|
extent: minimapExtent.value,
|
|
3588
|
+
// auto 默认不跟相机收窄;打开后相机进出数据 / 底图范围时才会重新算包围盒
|
|
3589
|
+
extentFollowCamera: minimapExtentFollowCamera.value,
|
|
3582
3590
|
position: 'bottom-right',
|
|
3583
3591
|
margin: 12,
|
|
3584
3592
|
pointStyle: { color: '#4b8dff', size: 1.4 },
|
|
@@ -3592,7 +3600,8 @@ export const useGisViewDemo = () => {
|
|
|
3592
3600
|
// 被 levels 挡掉的节点,连在它们身上的线路按同一套 cascade 一起隐藏('false' 表示不连锁)
|
|
3593
3601
|
cascade: minimapCascade.value,
|
|
3594
3602
|
layered: minimapLayered.value,
|
|
3595
|
-
// 节点 /
|
|
3603
|
+
// 节点 / 线路的尺寸系数:整体倍数对自有与沿用主图的要素都生效;小图自身倍数也两边都算;
|
|
3604
|
+
// 跟随主视图地图倍数只作用于小图自有规则 / 样式(沿用主图时尺寸按视口比例,不受主图缩放影响)
|
|
3596
3605
|
pointSizeScale: minimapPointSize.value,
|
|
3597
3606
|
lineWidthScale: minimapLineWidth.value,
|
|
3598
3607
|
// 节点与线路跟着小图自身的倍数放大:滚轮 / - + 放大鹰眼图时它们一起变大
|
|
@@ -3616,9 +3625,11 @@ export const useGisViewDemo = () => {
|
|
|
3616
3625
|
draw: minimapDrawLayer.value ? drawMinimapOverlay : undefined,
|
|
3617
3626
|
interactive: true,
|
|
3618
3627
|
longPressDelay: 180,
|
|
3619
|
-
//
|
|
3620
|
-
zoomable:
|
|
3621
|
-
//
|
|
3628
|
+
// 三档互斥:true 手动缩放小图,'follow' 整体范围跟随主图,false 关闭;minZoom / maxZoom 是倍数范围
|
|
3629
|
+
zoomable: minimapZoomMode.value === 'manual' ? true : minimapZoomMode.value === 'follow' ? 'follow' : false,
|
|
3630
|
+
// 跟随主图时主图相对基准倍数的指数;手动缩放模式下不参与
|
|
3631
|
+
followZoomScale: minimapFollowZoomScale.value,
|
|
3632
|
+
// 每一次放大 / 缩小的倍率、空白处拖动的动作(box 不依赖手动缩放)、通道画全部回线还是一根
|
|
3622
3633
|
zoomStep: minimapZoomStep.value,
|
|
3623
3634
|
dragAction: minimapDragAction.value,
|
|
3624
3635
|
channelCircuits: minimapChannelCircuits.value,
|
|
@@ -4774,24 +4785,24 @@ export const useGisViewDemo = () => {
|
|
|
4774
4785
|
}
|
|
4775
4786
|
/**
|
|
4776
4787
|
* 小图倍数的两个系数(pointZoomScale / lineZoomScale)只在小图自身被放大时起作用 ——
|
|
4777
|
-
*
|
|
4778
|
-
*
|
|
4788
|
+
* 缩放模式是关的时候,改这两个值看不出变化,容易被当成没生效。这里在用户真的填了正数时
|
|
4789
|
+
* 顺手切到「手动缩放小图」,并在读数里说一句怎么看到效果;跟随主图的模式不被覆盖。
|
|
4779
4790
|
*/
|
|
4780
4791
|
watch([minimapPointZoom, minimapLineZoom], ([point, line]) => {
|
|
4781
|
-
if (!minimapEnabled.value ||
|
|
4792
|
+
if (!minimapEnabled.value || minimapZoomMode.value !== 'off') {
|
|
4782
4793
|
return
|
|
4783
4794
|
}
|
|
4784
4795
|
if (!(Number(point) > 0) && !(Number(line) > 0)) {
|
|
4785
4796
|
return
|
|
4786
4797
|
}
|
|
4787
|
-
|
|
4788
|
-
writeLastEvent('「放大节点 /
|
|
4798
|
+
minimapZoomMode.value = 'manual'
|
|
4799
|
+
writeLastEvent('「放大节点 / 放大线路」跟的是小图自身的倍数:已自动切到「手动缩放」,滚轮或 + / - 放大鹰眼图就能看到节点 / 线路一起变大')
|
|
4789
4800
|
})
|
|
4790
4801
|
watch([showTooltip, tooltipHtml, tooltipChannelScope], () => viewRef.value?.updateOptions({ tooltip: buildTooltipOptions() }))
|
|
4791
4802
|
watch([filterVoltage, filterType, filterKeyword, filterLines, filterCascade], () => applyFilterFromControls())
|
|
4792
4803
|
// 数据映射:换模式 / 换比例就把当前数据按新映射重画一遍(数据不动,只换画出来的坐标)
|
|
4793
4804
|
watch([datasetProjection, datasetProjectionScale], () => applyDatasetMapping())
|
|
4794
|
-
watch([minimapSize, minimapEnabled, minimapShowLines, minimapExtent,
|
|
4805
|
+
watch([minimapSize, minimapEnabled, minimapShowLines, minimapExtent, minimapExtentFollowCamera, minimapZoomMode, minimapFollowZoomScale, minimapDragAction, minimapChannelCircuits, minimapZoomStep, minimapRuleMode, minimapLayered, minimapLevels, minimapCascade, minimapPointSize, minimapLineWidth, minimapPointZoom, minimapLineZoom, minimapPointMapZoom, minimapLineMapZoom, minimapBoxFill, minimapBoxFillOpacity, minimapBoxStroke, minimapBoxStrokeWidth, minimapBoxStrokeStyle, minimapBoxRadius, minimapDrawLayer], () => viewRef.value?.updateOptions({ minimap: buildMinimapOptions() }))
|
|
4795
4806
|
// 两种画法「好看」的门槛不一样:smooth 靠 alpha 往外淡,3% 就够;band 是硬边色块,抬到 15% 才留得住「大片浅色 + 环环相扣的热点」。
|
|
4796
4807
|
// 换画法时把这两个跟着画法走的滑杆带回它自己的缺省,免得拿 smooth 的 3% 去看 band(整张图糊成一片橙)
|
|
4797
4808
|
watch(heatmapDensityStyle, value => {
|
|
@@ -4980,7 +4991,7 @@ export const useGisViewDemo = () => {
|
|
|
4980
4991
|
return
|
|
4981
4992
|
}
|
|
4982
4993
|
// 聚焦与选中一步做完:select: true 就把这一条同时变成选中状态(一批目标时同样管用)
|
|
4983
|
-
view.focusOn(id, { padding: 220, select: true })
|
|
4994
|
+
view.focusOn(id, { zoom: true, padding: 220, select: true })
|
|
4984
4995
|
syncSelectionFromView()
|
|
4985
4996
|
lastEvent.value = `已定位到直流线路「${id}」:focusOn 一次把定位与选中做完,中点(position 0.5)挂着 PATH_DC_LINE 装饰,颜色跟线路的电压分档走`
|
|
4986
4997
|
}
|
|
@@ -6142,7 +6153,7 @@ export const useGisViewDemo = () => {
|
|
|
6142
6153
|
exportPartToFile, refreshExportSample, slimSample, sampleJson, refreshDataShape, scheduleDataShape,
|
|
6143
6154
|
printDataShape, exportWholeImage, startCopyPick, copyPointByApi, copyThenPaste, waypointPhaseText,
|
|
6144
6155
|
syncParallelGroups, copyParallelGroupRecords, handleWaypoint, MINIMAP_SIZES, minimapSize, minimapEnabled,
|
|
6145
|
-
minimapShowLines, minimapExtent,
|
|
6156
|
+
minimapShowLines, minimapExtent, minimapExtentFollowCamera, minimapZoomMode, minimapFollowZoomScale, minimapDragAction, minimapChannelCircuits, minimapZoomStep,
|
|
6146
6157
|
zoomMinimap, minimapRuleMode, minimapLayered, minimapLevels, minimapCascade, minimapPointSize,
|
|
6147
6158
|
minimapLineWidth, minimapPointZoom, minimapLineZoom, minimapPointMapZoom, minimapLineMapZoom, minimapBoxFill,
|
|
6148
6159
|
minimapBoxFillOpacity, minimapBoxStroke, minimapBoxStrokeWidth, minimapBoxStrokeStyle, minimapBoxRadius,
|
package/docs/index.html
CHANGED
|
@@ -1323,7 +1323,7 @@
|
|
|
1323
1323
|
{ file: 'manual/14-视图与筛选.md', title: '手册 14 · 视图与筛选', blurb: '筛选 / 搜索 / 视图与背景', parent: 'GisView.md' },
|
|
1324
1324
|
{ file: 'manual/15-导出与集成.md', title: '手册 15 · 导出与集成', blurb: '导出 / 插件 / 自建界面', parent: 'GisView.md' },
|
|
1325
1325
|
{ file: 'manual/16-实例方法总表.md', title: '手册 16 · 实例方法总表', blurb: '实例方法主表', parent: 'GisView.md' },
|
|
1326
|
-
{ file: 'manual/17-参数速查.md', title: '手册 17 · 参数速查', blurb: '
|
|
1326
|
+
{ file: 'manual/17-参数速查.md', title: '手册 17 · 参数速查', blurb: '257 个成员逐个列全', parent: 'GisView.md' },
|
|
1327
1327
|
{ file: 'manual/18-逐方法示例.md', title: '手册 18 · 逐方法示例', blurb: '每个成员一段示例', parent: 'GisView.md' },
|
|
1328
1328
|
{ file: 'manual/19-读数与拖拽预览.md', title: '手册 19 · 读数与拖拽预览', blurb: '读数 / 定位 / 落点预览', parent: 'GisView.md' },
|
|
1329
1329
|
{ file: 'manual/20-性能与大数据.md', title: '手册 20 · 性能与大数据', blurb: '大数据开关与实测', parent: 'GisView.md' },
|
|
@@ -1399,7 +1399,7 @@
|
|
|
1399
1399
|
{ file: '../src/gis-view/README.md', title: 'src/gis-view/README.md', blurb: '源码导读与逐轮实现记录' }
|
|
1400
1400
|
]
|
|
1401
1401
|
const PAGES = [
|
|
1402
|
-
{ href: 'api/index.html', title: 'API 速查(方法 + 示例)', blurb: '
|
|
1402
|
+
{ href: 'api/index.html', title: 'API 速查(方法 + 示例)', blurb: '257 个实例成员 / 96 个 options,逐个带示例与复制' },
|
|
1403
1403
|
{ href: 'playground/index.html', title: '调试演示页(粘代码就跑)', blurb: '左侧编辑、右侧真实实例 + GeoJSON 底图:内置示例与「这一份文档」的示例同在一个下拉,粘代码直接跑' },
|
|
1404
1404
|
{ href: 'guide/sample-document.html', title: 'sample-document.json 图解', blurb: '点数据看端点 / 拐点 / 分组骨架' },
|
|
1405
1405
|
{ href: 'steps/index.html', title: '从 0 手写分步 demo', blurb: '13 步,每步一个文件' },
|
|
@@ -1576,7 +1576,44 @@
|
|
|
1576
1576
|
continue
|
|
1577
1577
|
}
|
|
1578
1578
|
if (/^\s*\|/.test(line) && index + 1 < lines.length && /^\s*\|[\s:|-]+\|\s*$/.test(lines[index + 1])) {
|
|
1579
|
-
|
|
1579
|
+
/**
|
|
1580
|
+
* 表格行拆分:反引号里的竖线(类型联合 `'a' \| 'b'` 很常见)不是分隔符,
|
|
1581
|
+
* `\|` 按转义后的普通竖线收进单元格;只看分隔位置,不做第二次 replace。
|
|
1582
|
+
*/
|
|
1583
|
+
const parseRow = (row) => {
|
|
1584
|
+
const text = row.trim()
|
|
1585
|
+
const start = text.startsWith('|') ? 1 : 0
|
|
1586
|
+
let trailingBackslashes = 0
|
|
1587
|
+
for (let cursor = text.length - 2; cursor >= 0 && text[cursor] === '\\'; cursor -= 1) {
|
|
1588
|
+
trailingBackslashes += 1
|
|
1589
|
+
}
|
|
1590
|
+
const trailing = text.endsWith('|') && trailingBackslashes % 2 === 0
|
|
1591
|
+
const end = trailing ? text.length - 1 : text.length
|
|
1592
|
+
const cells = []
|
|
1593
|
+
let cell = ''
|
|
1594
|
+
let inCode = false
|
|
1595
|
+
for (let cursor = start; cursor < end; cursor += 1) {
|
|
1596
|
+
const character = text[cursor]
|
|
1597
|
+
if (character === '\\' && text[cursor + 1] === '|') {
|
|
1598
|
+
cell += '|'
|
|
1599
|
+
cursor += 1
|
|
1600
|
+
continue
|
|
1601
|
+
}
|
|
1602
|
+
if (character === '`') {
|
|
1603
|
+
inCode = !inCode
|
|
1604
|
+
cell += character
|
|
1605
|
+
continue
|
|
1606
|
+
}
|
|
1607
|
+
if (character === '|' && !inCode) {
|
|
1608
|
+
cells.push(cell.trim())
|
|
1609
|
+
cell = ''
|
|
1610
|
+
continue
|
|
1611
|
+
}
|
|
1612
|
+
cell += character
|
|
1613
|
+
}
|
|
1614
|
+
cells.push(cell.trim())
|
|
1615
|
+
return cells
|
|
1616
|
+
}
|
|
1580
1617
|
const head = parseRow(line)
|
|
1581
1618
|
index += 2
|
|
1582
1619
|
const rows = []
|
|
@@ -1919,7 +1956,7 @@
|
|
|
1919
1956
|
{ badge: 'START', title: '第一次使用', desc: '引入、最小数据与首屏配置,先把图画出来。', meta: '01 快速开始 · 约 10 分钟', file: 'manual/01-快速开始.md' },
|
|
1920
1957
|
{ badge: 'BACKEND', title: '接后端与导出', desc: '编辑接口、导出回灌、插件与自建界面。', meta: '15 导出与集成', file: 'manual/15-导出与集成.md' },
|
|
1921
1958
|
{ badge: 'PERF', title: '十万级性能', desc: 'Worker 筛选 / 异步搜索、批量更新与质量档。', meta: '20 性能与大数据', file: 'manual/20-性能与大数据.md' },
|
|
1922
|
-
{ badge: 'API', title: '查方法与参数', desc: '实例方法、options 与可复制示例集中检索。', meta: 'API 速查 ·
|
|
1959
|
+
{ badge: 'API', title: '查方法与参数', desc: '实例方法、options 与可复制示例集中检索。', meta: 'API 速查 · 257 个成员', href: 'api/index.html', external: true }
|
|
1923
1960
|
]
|
|
1924
1961
|
const renderReadingPaths = () => `<section class='doc-paths' aria-label='推荐阅读路径'>` +
|
|
1925
1962
|
`<div class='doc-paths__head'><strong>按任务选一条阅读路径</strong><span>第一次进来先看快速开始;带着明确目标时直接跳到对应章节。</span></div>` +
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
- **底图**:`minimap.js` 把节点与线条直接写进一块离屏像素缓冲(`ImageData`),按「层级 + 颜色 + 线宽 + 透明度」分桶后再画 —— 绘制次数随分桶数走,不随数据量走;底图只在数据或筛选结果变化时重画;节点像素结果按「数据引用 + 尺寸 + 范围 + 变换 + 样式」缓存,同一份数据前后两次重画直接复用(十万点重铺 20ms → 0.3ms),数据范围也按数据对象进 `WeakMap`。
|
|
6
6
|
- **视口框**:单独一个 DOM 元素,相机变化只改 `transform`(不重画底图),所以拖动小图不掉帧。
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- **挂载与位置**:`minimap.container` 接受 `HTMLElement` 或选择器,把 `.gis-view__minimap` 根节点挂到外部宿主;换容器只 `append` 同一根节点,画布、缓存与事件监听都不重建,`destroy()` 从当前宿主摘掉。`offset` 是相对 `position` 角落的 `[x, y]` 位移(正数向右 / 向下),`updateOptions` 只改 `left` / `right` / `top` / `bottom`,因此整图拖动不需要重画小图;根节点通过 `getMinimapElement()` 暴露给外部手势。
|
|
8
|
+
- **规则**:小图可以有自己的 `pointRules` / `lineRules`(颜色、半径 / 线宽、形状、层级),不配时沿用主图样式链:颜色 / 描边色 / 层级取规则,节点尺寸与符号取引擎最终解析结果(点自身 > 主图规则 > `pointStyle`),线路线宽取样式链的原始线宽(不含主图整体倍数 / 缩放联动 / 热力倍数)。`inheritSize` / `inheritWidth` 标记的节点 / 线路再乘一次「小图 CSS 视口宽高 ÷ 主图 CSS 视口宽高」的较小比例(`inheritedSizeFactor()`),这一份只跟两边视口尺寸有关,主图相机缩放不会改继承要素的大小;小图自身放大时仍可按 `pointZoomScale` / `lineZoomScale` 叠加,`pointSizeScale` / `lineWidthScale` 对自有与继承要素统一生效,`pointMapZoomScale` / `lineMapZoomScale` 只作用于小图自有规则 / 样式。小图自己的尺寸不受视口比例这一步影响。圆形按主图的面积对齐系数还原真实直径;图片 / SVG 图标与自定义图元异步解码后单独盖在点层上,解码前先用小图基准尺寸的圆 / 方回落,完成后只失效点层并补一帧。
|
|
9
|
+
- **交互**:视口框上按下 = 拖框;空白处长按(`longPressDelay`)= 视角跟随;`zoomable` 三态互斥:`true` 手动缩放小图自身(滚轮按 `zoomStep`、锚点落光标处,Ctrl / ⌘ + 滚轮留给主图),`'follow'` 让整体范围跟随主图(`followZoomScale` 是主图倍数的指数,`setMinimapZoom` / `zoomMinimapBy` 不抢控制权),`false` 只缩放主图。`dragAction` 决定空白处拖动是平移小图还是框选,`box` 不依赖 `zoomable`;只有手动模式按住 Ctrl / ⌘ 才自动切到另一个动作。拖框与视角跟随带来的相机变化是「程序化」的:标签层不进交互态(`hideOnInteract` 不会把主视图的标签收起来),拖动结束补一次真实排版。每次真正有位移的手势结束时通过 `onInteraction` 发一条 `{ type, originalEvent, local, world, zoom, extent, camera, viewport }`(`type` 为 `box-drag` / `select` / `pan` / `zoom` / `wheel-main` / `long-press`);无位移的点击不发,`pointermove` 不逐帧回调,长按在触发跟随时发。
|
|
10
|
+
- **范围**:`extent` 决定小图按哪段世界范围铺 —— `measure(data)` 量出可见数据的范围,`backgroundBoundsOf(background)` 量出底图范围(GeoJSON 用画出来的 `bounds`,图片用四角 quad 的包围盒),`auto`(默认)取两者的并集,`data` 只看数据(旧行为),`background` 只看底图。数据为空时 `measure()` 返回 `null`、不会当成「范围是正负一」;修掉的问题见 15.12。`extentFollowCamera` 默认 `false`,`auto` 始终用并集,外围内容消失不会让包围盒与视口框跳动;打开后才有例外:相机正落在其中一份范围里、而那一份在并集里连 6 个像素都占不到时(数据还没映射到底图坐标系就是这样)只画正在看的那一份;`followFocusedExtent()` 在相机挪进 / 挪出这份小范围时补一次重画 —— 判断只用上一次重画缓存的两份范围,每帧几次比较。
|
|
11
|
+
- **通道**:`channelCircuits: false` 时每个分组按当前可见成员逐顶点平均成一根代表线,双回线因此落在两根正中间,三回线落在中间那条;只剩一条可见成员时就是它自己,顶点数对不上时退回第一条可见成员(底图分辨率本来就在一像素上下,多回线只会糊成一片)。
|
|
12
|
+
- **背景**:默认 `background: 'inherit'`,直接拿引擎解析好的那份背景在 Canvas2D 上重画:底色铺满,图片按 quad 拆成两组三角形做仿射 + 裁剪(任意四边形都不会画歪),GeoJSON 面用奇偶规则填充(洞自动镂空)、纯线几何的区域再描一遍、点要素画成固定 1.2px 半径的小圆;底图的线宽(取配置值、最低 0.4px 保可见)与区域文字字号(固定档,夹在 5 ~ 12px)都是小图上的固定像素,不乘「小图视口 ÷ 主图视口」的比例 —— 缩放主视图时底图不会单独放大 / 缩小(本轮删掉了 `mapRatio`,见 15.17)。也可以给 `minimap.background` 单独配一份(结构与主视图的 `background` 完全一致,只是换 Canvas2D 画)。`backgroundStyle` 显式设置时由容器 CSS 接管底色:继承或独立的底图仍画图片与 GeoJSON,但画布底色改成透明,不再用主图的不透明底色盖住容器;不写时仍按主图底色铺满。区域文字先量「区域在小图上的屏幕矩形 ≥ 文字尺寸 × 0.85」再画,放不下就整条跳过(缩略图上那些小块本来也读不出来);能画的按区域从大到小排,和已经放下的标签重叠就跳过 —— 小图上几十个区域各画一行字只会叠成一团。
|
|
12
13
|
- **扩展层**:`layers` 接收一组 `{ id?, order?, placement?, enabled?, draw }`。`placement: 'below-data'` 在内置线路 / 节点之前执行,适合网格、分区底色;`'above-data'`(缺省)在数据之后执行,适合指北针、业务标记。两段内部各按 `order` 从小到大,相同或缺省 `order` 按数组顺序。`setOptions` 时把过滤、排序与分段结果缓存成两条数组,绘制帧只遍历当前段,不再每帧 `map` / `filter` / `sort`。每个回调独立 `save` / `restore`,一层改过的画布状态不会漏进下一层;`enabled: false` 可临时关掉一层,旧的单层 `draw` 保持兼容并固定最后执行,回调里的 `stage` 为 `'overlay'`。这样网格、指北针、业务标记可以各自维护,不必把所有内容堆进一个钩子。
|
|
13
14
|
- **清晰度与开销**:小图画布用自己的一份倍率(`clamp(devicePixelRatio × 宿主显示比例, 1, maxPixelRatio)`,`maxPixelRatio` 默认 4、夹在 1 ~ 4),主视图为全屏帧率按像素预算压低渲染倍率时,小图不受影响;小图尺寸大或高分屏填充压力高时可以把上限降到 1 ~ 2。容器另有 `contain: layout paint` 与 `isolation: isolate`,把布局与重绘影响收在自身。
|
|
14
15
|
|
|
@@ -284,11 +284,13 @@
|
|
|
284
284
|
|
|
285
285
|
10 万点 / 6 万线里删掉一条线,`removeLine` 实测 61 ms(最快一次):`removeLines` 收尾走 `applyOptions()` → 引擎 `setOptions({ points, lines, channels, hiddenPoints, hiddenLines })`,补丁里带了 `points`,于是整份 `buildScene()` —— 十万个节点重解析一遍、圆点与贴图批次整份重铺,纯粹陪跑(删一条线一个节点都没动)。收益是把点那一半摘掉(约 30 ms;其余是线路侧的重编号:删掉中间一条线,后面每条线的下标都往前挪一格,`lineSegmentSlots` / `decorationRanges` / 选中镜像 / 通道成员表全都要跟着重排)。要做的话得让 `setOptions` 认得「节点这一半逐元素还是上一轮那批对象」(`patch.points` 与内部副本逐元素比身份,十万次比较约 0.3 ms),再让 `resolveFeatures` 支持只跑线路那一半(符号预热账本 / 热力值域 / 点层序这些与点绑定的账要原样留着)。这一条按「值不值得做」排在建增量通道(16.35 末尾那条)之后:删一条线的场景不多,而它牵扯的是数据更新的主路径 —— **本轮(15.65)把它做掉了:判定改成「逐元素同引用 + 解析输入快照」两步,只跳过点那一半;`removeLine` 10 万点 / 6 万线 50.7 → 41.3 ms。** 剩下那 ~40 ms 是线路侧的整份重编号,见 16.37。
|
|
286
286
|
|
|
287
|
-
### 16.37
|
|
287
|
+
### 16.37 线路那一半也整半跳过(已在当前轮落地)
|
|
288
288
|
|
|
289
|
-
与 15.65
|
|
289
|
+
与 15.65 做掉的「点那一半」同构。判定分两层:先在 `applyOptions` 收配置前确认 `patch.lines` 与内部那一份**逐元素同引用**、`patch.hiddenLines` 内容没变、`patch.channels` 也逐条同引用、通道宽度 / 节点尺寸 / 整体倍率 / `lineFollowsNode` 这些会改车道与回线折线的输入没变,并且没有 `appendedPoints` / `appendedLines`;收完配置后再用快照确认线基准样式 / 规则 / 效果 / 线方向 / 热力图、节点基准样式与线路悬停 / 选中 / 多选状态样式都没变。`forceResolve`、交互中、销毁后以及增量删除路都直接回退整份重解析。
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
命中时 `resolveFeatures` 跳过 `resolveLines`、`lineByIndex` / 最大半线宽 / 虚线图案槽位 / 线路装饰与效果标记 / 布局层序 / 线路包围盒这几趟,直接沿用上一轮线路那一半的读数;排线路批次那一趟仍然照常跑。线路半包围盒不是只在整份解析时记账:追加补线会把新路径并进来,拖点 / 拐点 / 通道骨架这类增量改线也会在 `applyResolvedLinePath` 里把新路径并进来;还没有可信读数时记 `lineHalfOutOfSync`,下一轮放弃跳过,避免沿用旧范围。
|
|
292
|
+
|
|
293
|
+
收益只在「同一批线路对象原样再交一遍」的补丁上兑现(内容真的换了、`removeLine` 这种下标平移的路都不算)。`selftest-perf.html` 的 20000 点 / 8000 线回灌基准(同一批对象连交 5 次取中位)由 **14.3 ms** 降到 **6.3 ms**;同页新增三条断言,锁定条数与线路实例数不变、通道声明没换时派生折线原样保留、换通道骨架时线路几何必须重推。性能页当前为 **167 passed / 0 failed**。
|
|
292
294
|
|
|
293
295
|
|
|
294
296
|
### 16.38 `removePoints` 的反向增量(候选 → 已在 15.66 落地)
|
|
@@ -251,6 +251,18 @@
|
|
|
251
251
|
- **编辑类开关缺省关闭**(详见 15.39 与 15.25):`features` 与详细配置都没写时,框选 / 拖拽 / 拐点 / 复制 / 合并 / 新增通道 / 通道右键菜单一律关着 —— 缺省口径=只读浏览;`features: 'edit'` 一次全开,单开写 `draggable: true` / `boxSelect: true` / `waypointEditable: true` / `copy: {…}` / `merge: {…}` 或 `features: { drag: true }`。自测页与 demo 里要用这些交互的地方都显式打开了开关,因此断言与画面语义不变(变的只是「什么都不写」时的行为,这正是需求本身)。
|
|
252
252
|
- **验证**:十个自测页在真时间下逐页跑完全绿(`selftest` 26 / `selftest-actions` 96 / `selftest-effects` 85 / `selftest-labels` 90 / `selftest-demo` 112 / `selftest-demos` 61 / `selftest-scale` 42 / `selftest-perf` 72 / `selftest-full` 68 / `selftest-features` 264),`npx tsc --noEmit` 0 错,`node docs/steps/check-doc-coverage.mjs` 无缺口,`npm run build` 通过。
|
|
253
253
|
|
|
254
|
+
#### 第十六轮:同一批点线原样回灌,线路那一半整半复用
|
|
255
|
+
|
|
256
|
+
上一轮把节点那一半在「逐元素同引用」时整半跳过;这一轮把同一套判据补到线路侧,并额外核对隐藏集合、通道声明、通道车道输入与线路样式快照。命中后不再重跑 `resolveLines` 与其索引 / 虚线槽位 / 层序 / 包围盒,追加补线和增量改线则把新路径并进线路半包围盒,防止下一次回灌沿用旧范围。
|
|
257
|
+
|
|
258
|
+
`selftest-perf.html` 用 20000 点 / 8000 线、同一批对象连续回灌 5 次,取中位:
|
|
259
|
+
|
|
260
|
+
| 场景 | 优化前 | 优化后 |
|
|
261
|
+
| --- | --- | --- |
|
|
262
|
+
| 同一批点线原样回灌(20000 点 / 8000 线) | 14.3 ms | **6.3 ms** |
|
|
263
|
+
|
|
264
|
+
优化后的 5 次读数依次是 5.6 / 6.3 / 6.3 / 6.4 / 10.7 ms;同页新增三条断言分别核对条数与线路实例数不变、通道声明未变时派生折线原样保留、换通道骨架时线路几何必须重推。该快路只对原样回灌生效,内容真的换了或删除导致下标平移时仍走原来的整份 / 增量路径。
|
|
265
|
+
|
|
254
266
|
### WebGPU 值不值得上
|
|
255
267
|
|
|
256
268
|
| 维度 | 现状 | WebGPU 能带来的变化 |
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
| `channelTangentInset` | `number \| null` | `null` | 两端切点往节点里收多少 CSS 像素:缺省(`null`)按成员回线里最粗那条的线宽收,线因此不会从节点边缘探出去;`0` 表示切点正好落在节点边上,**负数外收**(切点往节点外让、回线整段比节点宽);单个通道可用 `tangentInset` 覆盖;内收两侧合计最多收掉节点宽度的 40%,外收单侧最多让出 50% |
|
|
27
27
|
| `channelMaxGroups` | `number` | `0` | 一条通道最多几个分组(`0` 表示不限):新增通道时用来判断还能不能变成新分组,见「新增通道」 |
|
|
28
28
|
| `channelGroupMaxLines` | `number` | `0` | 一个分组最多几条回线(`0` 表示不限):新增通道时用来判断还能不能并进某一组,见「新增通道」 |
|
|
29
|
-
| `channelDraftStyle` | `GisViewChannelDraftStyle` | 蓝色 2px + 两端圆点,箭头关闭 | 新增通道草稿预览的全局样式:`color` / `width` / `dot` / `dotColor` / `arrow` / `arrowSize` / `arrowPositions` / `arrowReverse` / `arrowColor` / `circuitSpacing` / `opacity` / `customDraw`;`beginAddChannel({ channelDraftStyle })` 可按这一次草稿覆盖,`updateAddChannelStyle(patch)` 可在草稿期间增量修改 |
|
|
29
|
+
| `channelDraftStyle` | `GisViewChannelDraftStyle` | 蓝色 2px + 两端圆点,箭头关闭 | 新增通道草稿预览的全局样式:`color` / `width` / `dot` / `dotColor` / `dots`(`false` 关示例点,或 `{ show, size, color, shape, from, to }` 分端配置;示例点固定在点中的节点中心)/ `layer`(`'above'` 默认,`'below-points'` 让示例线 / 箭头 / `customDraw` 位于真实节点之下)/ `arrow` / `arrowSize` / `arrowPositions` / `arrowReverse` / `arrowColor` / `circuitSpacing` / `opacity` / `customDraw`;`beginAddChannel({ channelDraftStyle })` 可按这一次草稿覆盖,`updateAddChannelStyle(patch)` 可在草稿期间增量修改 |
|
|
30
30
|
| `webglLayers` | `GisViewWebGLLayer[]` | `[]` | WebGL 自定义绘制层:每层提供 `draw({ gl, canvas, viewport, camera, frame, project, unproject, requestRender })`,在内置内容之后按 `order` 绘制;运行时也可用 `addWebGLLayer` / `updateWebGLLayer` / `removeWebGLLayer` 维护 |
|
|
31
31
|
| `background` | `GisViewBackground` | 浅色底 | 背景层,支持底色、图片与 GeoJSON |
|
|
32
32
|
| `pointStyle` | `GisViewPointStyle` | 见下 | 点的默认样式,可被单个点覆盖;运行时按字段合并用 `updatePointStyle(patch)`(`updateOptions({ pointStyle })` 是整份换) |
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
| `labelStates` | `GisViewLabelState[]` | 无 | 标签的运行时状态(`getLabelStates()` 的那一份:拖出来的偏移、改过的内容与样式、运行时加的标签、隐藏覆盖):创建时喂回来就回显,等价于创建之后调 `setLabelStates(states)`;`updateOptions({ labelStates })` 同样认。`exportData({ format: 'input' })` 的结果里就叫 `labelStates`,存档 → 回灌直接接上 |
|
|
44
44
|
| `graphics` | `GisViewGraphic[]` | 无 | 与节点无关的扩展图形:按世界坐标放 SVG 路径 / 图片 / Canvas,支持锚点、偏移、旋转、透明度、`zIndex` 与 `scaleWithView`;位于画布之上、标签之下,运行时用 `addGraphic` / `addGraphics` / `updateGraphic` / `removeGraphic` / `clearGraphics` 增删改,见「扩展图形(graphic)」 |
|
|
45
45
|
| `tooltip` | `GisViewTooltipOptions` | 无 | 悬停提示:点 / 线 / 通道分别配置内容,见「悬浮提示」 |
|
|
46
|
-
| `minimap` | `GisViewMinimapOptions \| null` | 无 | 内置鹰眼图:位置、尺寸、节点 / 线路 / 视口框三份样式与交互都可配,`extent` 决定小图按数据范围还是「数据 ∪ 底图」铺(默认 `auto`,GeoJSON 底图不会缩成一个点),`zoomable`
|
|
47
|
-
| `filter` | `GisViewFilterInput \| null` | 无 | 初始筛选条件,等价于创建之后调用 `setFilter
|
|
46
|
+
| `minimap` | `GisViewMinimapOptions \| null` | 无 | 内置鹰眼图:位置、尺寸、节点 / 线路 / 视口框三份样式与交互都可配,`extent` 决定小图按数据范围还是「数据 ∪ 底图」铺(默认 `auto`,GeoJSON 底图不会缩成一个点),`extentFollowCamera` 默认 `false`、打开后才允许 `auto` 范围随相机收窄。`zoomable` 三态互斥:`false` 关闭、`true` 手动缩放小图自身、`'follow'` 让整体范围跟随主图(`followZoomScale` 是主图倍数的指数,跟随模式下 `setMinimapZoom` / `zoomMinimapBy` 不抢控制权);空白处拖动可平移小图或直接框选让主图显示过去(`dragAction`,`box` 不依赖缩放,手动模式下 Ctrl / ⌘ 才切换动作),每格倍率 `zoomStep`。通道还能只画一根;小图同样支持规则(`pointRules` / `lineRules`,缺省沿用主图规则的颜色、层级、最终节点尺寸与图标、样式链线宽,节点 / 线路尺寸按两边视口比例缩放且不受主图相机倍数影响),可以只画某几层(`levels`)、关掉分层叠画(`layered`)、按三组系数给节点与线路定尺寸(整体倍数 `pointSizeScale` / `lineWidthScale` 对自有与继承要素都生效;跟随小图倍数 `pointZoomScale` / `lineZoomScale` 在小图自身放大时也作用于继承要素;跟随主视图地图倍数 `pointMapZoomScale` / `lineMapZoomScale` 只作用于自有规则 / 样式),视口框与框选矩形的颜色 / 背景 / 边框 / 圆角也能配(`boxStyle` / `selectStyle`),`extent` 还能直接写死一份世界范围、容器可加 `className` / `style`、`layers` 按 `placement` 分数据前 / 数据后、段内按 `order` 拆出多层自绘内容(旧 `draw` 钩子仍兼容并排在最后)、`onInteraction` 在手势结束时给出类型 / 世界坐标 / 相机、`maxPixelRatio` 限制备份倍率上限,不配则不产生任何 DOM,见「鹰眼图」 |
|
|
47
|
+
| `filter` | `GisViewFilterInput \| null` | 无 | 初始筛选条件,等价于创建之后调用 `setFilter`;`mode` 缺省 `'hide'`,写 `'remove'` 则删除不命中的要素,见「筛选」 |
|
|
48
48
|
| `filterWorker` | `boolean \| GisViewFilterWorkerOptions` | `{ threshold: 20000 }` | 筛选是否用 Web Worker 计算:默认点 + 线总数超过阈值才用,`false` 表示始终同步算 |
|
|
49
49
|
| `searchWorker` | `boolean \| GisViewSearchWorkerOptions` | `{ threshold: 20000 }` | [异步搜索](14-视图与筛选.md#搜索与定位)是否用 Web Worker 计算:默认点 + 线总数超过阈值才用,`false` 表示 `searchAsync` 也同步算;同步的 `search` 一直在主线程算,不受这一项影响 |
|
|
50
50
|
| `pointHoverStyle` / `pointSelectStyle` | `GisViewPointStyle` | 无 | 点的悬停 / 选中样式;没配就不改变外观(悬停仍然触发回调与提示、选中仍然进选中集合),要反馈就自己配一份 |
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
| `fitSpacing` | `boolean \| GisViewFitSpacingOptions` | 关 | 适应视图的节点间距兜底:`true` 用 `{ minDistance: 24, maxZoom: 0 }`,对象可改最小中心距(CSS 像素)与相对普通适应比例的上限(`0` 表示不限);只在首次默认适应与 `fitView()` 生效,远处孤立点允许落到视口外,见「适应视图的节点间距(fitSpacing)」 |
|
|
58
58
|
| `boxSelect` | `boolean` | `false` | 是否允许按住框选快捷键(`shortcuts.boxSelect`,默认 Shift)拖动鼠标框选要素;**缺省关**,写 `boxSelect: true` 或 `features: { boxSelect: true }` 才开。框选默认只收节点,`selectionKinds` 可把线路 / 通道也纳入 |
|
|
59
59
|
| `multiSelect` | `boolean` | `false` | 多选开关:打开后不用按修饰键,直接单击节点 / 线路就取反累加选中(与按住 `shortcuts.multiSelect` 点击同一套行为、同一个 `multiSelectStyle`;取反那一下不经过 `onClick`,`onSelectChange.action.type` 是 `toggleSelect`);**缺省关**,关着时多选走框选(`boxSelect`)与按住多选快捷键(默认 Ctrl / ⌘)。运行时 `updateOptions({ multiSelect })` 切换只重画一帧、不重排场景 |
|
|
60
|
+
| `selectTrigger` | `'click' \| 'dblClick'` | `'click'` | 选中触发方式:`click` 第一次单击就改选中集;`dblClick` 第一下只派发 `onClick`,等双击判定命中的第二下才改选中集,并同时派发 `onClick` 与 `onDblClick`。Ctrl / ⌘ 多选与 `multiSelect` 在双击模式下同样等第二下才取反。运行时走 `updateOptions({ selectTrigger })`,只重画一帧、不重排场景 |
|
|
60
61
|
| `selectionKinds` | `GisViewSelectionKindsInput` | 无(框选只收节点;Ctrl 多选收节点 / 线路 / 通道) | 框选与 Ctrl / 多选点击的类型过滤:`'point'` 节点、`'line'` 通道外的独立线路、`'channel'` 通道回线;可写数组任意组合,`'all'` / `true` 全开,`false` / `null` 全关。通道回线只归 `channel` 管,通道外的线路只归 `line` 管;通道回线仍按 `channelSelectMode` 摊开。不写时保留旧口径;普通单选与 `select` / `selectFeatures` 不受它限制。运行时走 `updateOptions({ selectionKinds })`,见「框选」与「选择类型过滤」 |
|
|
61
62
|
| `selectionBoxStyle` | `GisViewSelectionBoxStyle` | 蓝底 0.16 透明 + 1px 蓝框 | 框选矩形的填充与边框:`fill`、`fillOpacity`、`stroke`、`strokeWidth` |
|
|
62
63
|
| `selectionOnTop` | `boolean` | `true` | 选中的节点 / 拖动中的整组 / 待确认合并的目标节点,以及选中线路所在的整条通道,是否画在所有要素之上(与 `zIndex` 无关),见「选中 / 拖动的层级」 |
|
|
@@ -110,7 +111,7 @@
|
|
|
110
111
|
| 通道几何 | `channelWidth` · `channelInset` · `channelNodeWidth` · `channelTangentInset` · `channelMaxGroups` · `channelGroupMaxLines` · `channelDraftStyle` · `channelSelectMode` · `channelWaypointDragMode` |
|
|
111
112
|
| 样式与规则 | `pointStyle` · `lineStyle` · `pointRules` / `lineRules` · `heatmap` · `effects` · `lineDirection` · `prebake` · `label` · `labelOptimize` · `labelRender` · `lineLabel` · `labelStates` · `tooltip` · `pointSizeScale` / `lineWidthScale`、`pointZoomScale` / `lineZoomScale`、`zoomBaseScale` · `cursorStyle` · `gridColor` · `gridSize` · `showGrid` |
|
|
112
113
|
| 状态样式与选中 | `pointHoverStyle` / `pointSelectStyle` · `lineHoverStyle` / `lineSelectStyle` · `pointMultiSelectStyle` / `pointBoxSelectStyle` · `lineMultiSelectStyle` · `defaultHighlight` · `selectionBoxStyle` · `selectionOnTop` · `waypointStyle` / `waypointSelectStyle` |
|
|
113
|
-
| 交互开关 | `boxSelect` · `multiSelect` · `waypointEditable` · `waypointVisibility` · `interactive` · `preventContextMenu` · `clickable` · `draggable` · `liveDrag` · `lineFollowsNode` · `shortcuts` · `copy` · `remove` · `merge` |
|
|
114
|
+
| 交互开关 | `boxSelect` · `multiSelect` · `selectTrigger` · `waypointEditable` · `waypointVisibility` · `interactive` · `preventContextMenu` · `clickable` · `draggable` · `liveDrag` · `lineFollowsNode` · `shortcuts` · `copy` · `remove` · `merge` |
|
|
114
115
|
| 视图与相机 | `minScale` / `maxScale` · `fitPadding` · `fitOnInit` · `initialView` · `zoomStep` |
|
|
115
116
|
| 画质与渲染 | `quality` · `width` / `height` · `pixelRatio` · `maxCanvasPixels` · `antialias` · `interactionThinLines` · `interactionNoMsaa` · `renderer` · `webglLayers` |
|
|
116
117
|
| 大数据(筛选 / 搜索 / 读数) | `denseMode` · `filter` · `filterWorker` · `searchWorker` · `progressiveInit` · `statsInterval` · `renderEmitInterval` |
|
|
@@ -634,6 +635,19 @@ createGisView(container, { multiSelect: true }) // 单击即取反累加,不
|
|
|
634
635
|
// 按住快捷键的老写法照旧:Ctrl + 点击
|
|
635
636
|
```
|
|
636
637
|
|
|
638
|
+
#### `selectTrigger`
|
|
639
|
+
|
|
640
|
+
- **类型**:`'click' | 'dblClick'`(也认 `doubleClick` / `double` 两种别名)
|
|
641
|
+
- **默认值**:`'click'`
|
|
642
|
+
- **说明**:选中触发方式。`click` 保持缺省行为,第一次单击就改选中集;`dblClick` 下第一下只派发 `onClick`,同位置 320ms 内的第二下才应用选中 / 清空 / 取反,并在同一次点击里派发 `onClick`(`action.double: true`)与 `onDblClick`。Ctrl / ⌘ 多选与 `multiSelect` 也遵循这一档:双击模式下第二下才取反。普通双击在两种模式下都会于第二下派发 `onDblClick`,只是 `click` 模式第一次单击已经改过选中集;`click` 模式的 Ctrl / `multiSelect` 取反快捷路保持原口径,不额外发点击 / 双击事件。运行时切换会清掉上一次点击的双击判定状态,避免刚改完后的第一下被算成旧序列的第二下。
|
|
643
|
+
- **参考**:见「[08 选中与拐点](08-选中与拐点.md#点击选中与-dblclick)」与「[04 事件与回调](04-事件与回调.md#回调)」
|
|
644
|
+
- **示例**:
|
|
645
|
+
|
|
646
|
+
```js
|
|
647
|
+
createGisView(container, { selectTrigger: 'dblClick' })
|
|
648
|
+
view.updateOptions({ selectTrigger: 'click' })
|
|
649
|
+
```
|
|
650
|
+
|
|
637
651
|
#### `selectionKinds`
|
|
638
652
|
|
|
639
653
|
- **类型**:`GisViewSelectionKindsInput`
|
|
@@ -941,11 +955,12 @@ const { dense } = view.getStats() // { mode, active, reason, visiblePoin
|
|
|
941
955
|
|
|
942
956
|
- **类型**:`GisViewFilterInput | null`
|
|
943
957
|
- **默认值**:无
|
|
944
|
-
- **说明**:初始筛选条件,等价于创建之后调用 `setFilter
|
|
958
|
+
- **说明**:初始筛选条件,等价于创建之后调用 `setFilter`。`mode` 缺省 `'hide'` 只隐藏;写 `'remove'` 把不命中的要素从数据里删掉(先删线路、再删节点,只发一条 `filterRemove`),见「筛选」
|
|
945
959
|
- **参考**:见「筛选」一节,子字段在那里的表里逐个展开
|
|
946
960
|
|
|
947
961
|
```js
|
|
948
962
|
view.setFilter({ points: { voltage: { gte: 500 } }, cascade: 'binding' })
|
|
963
|
+
view.setFilter({ points: { voltage: { lt: 220 } }, mode: 'remove' }) // 不命中的要素直接从数据删除
|
|
949
964
|
view.getFilterResult() // { hiddenPoints, hiddenLines, visiblePoints, visibleLines, worker, durationMs }
|
|
950
965
|
view.setFilter(null) // 清掉筛选
|
|
951
966
|
```
|
|
@@ -989,7 +1004,7 @@ view.setFilter(null) // 清掉筛选
|
|
|
989
1004
|
|
|
990
1005
|
- **类型**:`GisViewMinimapOptions | null`
|
|
991
1006
|
- **默认值**:无
|
|
992
|
-
- **说明**:内置鹰眼图:位置、尺寸、节点 / 线路 /
|
|
1007
|
+
- **说明**:内置鹰眼图:位置、尺寸、节点 / 线路 / 视口框三份样式与交互都可配;`position` / `margin` 定角落,`offset` 相对角落动态移动整张图,`container` 可挂到外部 `div`(`getMinimapElement()` 取根节点做整图拖动)。`extent` 决定小图按数据范围还是「数据 ∪ 底图」铺(默认 `auto`,GeoJSON 底图不会缩成一个点),`extentFollowCamera` 默认 `false`、打开后才允许 `auto` 范围随相机收窄,避免外围要素消失时包围盒与视口框跳动。`zoomable` 三态互斥:`false` 关闭、`true` 手动缩放小图自身、`'follow'` 让整体范围跟随主图(`followZoomScale` 是主图倍数的指数;跟随模式下 `setMinimapZoom` / `zoomMinimapBy` 不抢控制权,`zoom` 是基准倍数);空白处拖动可平移小图或直接框选让主图显示过去(`dragAction`,`box` 不依赖缩放,手动模式下 Ctrl / ⌘ 才切换动作),每格倍率 `zoomStep`。通道关闭 `channelCircuits` 时按当前可见成员逐顶点平均成一根居中代表线;小图同样支持规则(`pointRules` / `lineRules`,缺省沿用主图规则的颜色 / 层级、最终节点尺寸与图标及样式链线宽,节点 / 线路尺寸按两边视口比例缩放且不受主图相机倍数影响),可以只画某几层(`levels`)、关掉分层叠画(`layered`)、按三组系数给节点与线路定尺寸(整体倍数 `pointSizeScale` / `lineWidthScale` 对自有与继承要素都生效;跟随小图倍数 `pointZoomScale` / `lineZoomScale` 在小图自身放大时也作用于继承要素;跟随主视图地图倍数 `pointMapZoomScale` / `lineMapZoomScale` 只作用于自有规则 / 样式),视口框与框选矩形的颜色 / 背景 / 边框 / 圆角也能配(`boxStyle` / `selectStyle`),`backgroundStyle` 显式设置时接管画布底色,`extent` 还能直接写死一份世界范围、容器可加 `className` / `style`、`layers` 按 `placement` 分数据前 / 数据后、段内按 `order` 拆出多层自绘内容(旧 `draw` 钩子仍兼容并排在最后)、`onInteraction` 在手势结束时给出类型 / 世界坐标 / 相机、`maxPixelRatio` 限制备份倍率上限,不配则不产生任何 DOM,见「鹰眼图」
|
|
993
1008
|
- **参考**:见「鹰眼图」一节,子字段在那里的表里逐个展开
|
|
994
1009
|
|
|
995
1010
|
```js
|
|
@@ -999,6 +1014,14 @@ createGisView(container, {
|
|
|
999
1014
|
width: 220,
|
|
1000
1015
|
height: 130,
|
|
1001
1016
|
position: 'bottom-right',
|
|
1017
|
+
offset: [0, 0],
|
|
1018
|
+
container: '#minimap-host',
|
|
1019
|
+
backgroundStyle: 'rgba(255, 255, 255, 0.92)',
|
|
1020
|
+
extent: 'auto',
|
|
1021
|
+
extentFollowCamera: false,
|
|
1022
|
+
dragAction: 'box',
|
|
1023
|
+
zoomable: 'follow',
|
|
1024
|
+
followZoomScale: 0.8,
|
|
1002
1025
|
levels: [1, 5, 20],
|
|
1003
1026
|
pointStyle: { color: '#2f6fed' },
|
|
1004
1027
|
layers: [
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
| --- | --- | --- |
|
|
9
9
|
| `onReady` | `{ canvas, gl }` | WebGL2 上下文与缓冲区就绪 |
|
|
10
10
|
| `onSelect` | `GisViewSelectPayload \| null` | 选中状态变化:点击为 `{ items, box: null, originalEvent }`,框选(默认按住 Shift)为 `{ items, box, originalEvent }`,点击空白处清空时为 `null`;Ctrl 点击节点的累加选中也走这里 |
|
|
11
|
-
| `onClick` | `GisViewClickPayload \| null` | 单击要素或空白处(空白处为 `null`):`type` / `item` / `index` / `screen` / `coordinate` / `button` / `selection` / `originalEvent` 之外还有 `action`(`type` 是 `select` / `clearSelection` / `click`,`double` 说明这一下是不是双击里的第二下,`press` / `duration` / `longPress`
|
|
11
|
+
| `onClick` | `GisViewClickPayload \| null` | 单击要素或空白处(空白处为 `null`):`type` / `item` / `index` / `screen` / `coordinate` / `button` / `selection` / `originalEvent` 之外还有 `action`(`type` 是 `select` / `toggleSelect` / `clearSelection` / `click`,`double` 说明这一下是不是双击里的第二下,`press` / `duration` / `longPress` 说明这一次按下想做什么、按了多久、算不算长按),见「指针事件」。`selectTrigger: 'dblClick'` 时第一下只发 `action.type: 'click'`,第二下才应用选中并带 `double: true` |
|
|
12
12
|
| `onClusterClick` | `GisViewClusterClickPayload` | 点中多成员聚合圆:带 `id` / `count` / `pointIndexes` / `pointIds` / `bounds` / `radius` / `coordinate` / `screen` / `selection` / `action`(`action.type` 恒为 `clusterClick`、`action.target` 为 `cluster`)。这一条**不会同时发 `onClick`**,也不会改动选中集;聚合圆内部的原始节点不参与普通点击 |
|
|
13
|
-
| `onDblClick` | `GisViewClickPayload \| null` | 双击要素或空白处(320ms / 6px 内连续两次单击):`action.type` 是 `dblClick`、`action.double` 为 `true` |
|
|
13
|
+
| `onDblClick` | `GisViewClickPayload \| null` | 双击要素或空白处(320ms / 6px 内连续两次单击):`action.type` 是 `dblClick`、`action.double` 为 `true`。普通双击在两种 `selectTrigger` 下都会于第二下派发;`dblClick` 模式下选中 / 清空 / 多选取反也在这一下应用,`click` 模式下第一下已经应用过。`click` 模式的 Ctrl / `multiSelect` 取反快捷路保持原口径,不额外发 `onClick` / `onDblClick` |
|
|
14
14
|
| `onPointerDown` | `GisViewPointerPayload` | 左键 / 中键 / 右键按下:命中的要素、`button` / `buttons` 与光标位置;`action.type` 是这一次按下的**意图**(`dragPoint` / `dragWaypoint` / `boxSelect` / `pan` / `copy` / `channelDraft` / `contextMenu`…),`action.target` 说明点的是什么、`action.data` 直接给到那份数据,见「指针事件」 |
|
|
15
15
|
| `onPointerUp` | `GisViewPointerPayload` | 左键 / 中键 / 右键抬起,与 `onPointerDown` 成对:`action.type` 是**刚做完的那件事**(拖过就是 `dragPoint` / `dragWaypoint` / `boxSelect` / `pan`,没拖就是 `click`),`action.moved` 说明这一次是拖还是点,另带 `action.press`(按下时的意图)/ `duration`(按了多久)/ `longPress`(长按) |
|
|
16
16
|
| `onContextMenu` | `GisViewPointerPayload` | 每一次右键:点、线、通道、空白都只发这一条(要素信息在载荷里);`action.type` 固定是 `contextMenu`、`action.target` 说明点的是点 / 线 / 通道 / 空白。命中通道回线时,同一载荷另带 `channelContext`(几组 / 当前哪组 / 可用交互),不再有单独的通道右键回调。要自己弹菜单就在回调里渲染。**右键回调缺省关**(`contextMenu` / `interactive` 都没写时组件不接右键),写 `interactive: true` / `contextMenu: true` 或 `features: 'view'` 才发;接住右键时系统菜单默认已被收掉(`preventContextMenu` 缺省 `true`),想看系统菜单写 `preventContextMenu: false` |
|
|
17
17
|
| `onCascadeHighlight` | `GisViewCascadeHighlightInfo \| null` | 点击级联高亮变了:载荷带来源 `origin`(节点 / 线路 / 通道回线)、范围 `scope` 与亮着的 `points` / `lines` / `pointIndexes` / `lineIndexes`,与 `getCascadeHighlight()` 同一份;点空白或关掉开关时是 `null`。这条高亮不改选中集,事件总线名为 `cascadeHighlight` |
|
|
18
18
|
| `onHover` | `GisViewHoverPayload \| null` | 悬停要素变化(空白处 / 移出画布是 `null`):与拾取结果同一份读数(`type` / `index` / `item` + 通道字段,另有光标位置 `x` / `y` / `world` / `clientX` / `clientY`、选中集 `selection` 与 `lngLat`)+ `action`(`type` 恒为 `hover`、`target` 说明停在什么上面、`button` 是 `none`、`modifiers` 是当下的修饰键);程序化悬停 `hoverAt()` 也走同一条 |
|
|
19
|
-
| `onFilter` | `GisViewFilterResult` | 筛选完成(含 Worker 异步返回):隐藏的点 / 线下标、剩余可见数量、是否用了 Worker
|
|
19
|
+
| `onFilter` | `GisViewFilterResult` | 筛选完成(含 Worker 异步返回):隐藏的点 / 线下标、剩余可见数量、是否用了 Worker 与计算耗时。`filter.mode: 'remove'` 时删除完成后只发最终一次,`hiddenPoints` / `hiddenLines` 为空 |
|
|
20
20
|
| `onCursor` | `[number, number] \| null` | 光标世界坐标,移出画布时为 `null` |
|
|
21
21
|
| `onPointer` | `GisViewPointerState` | 光标每次移动(含移出画布)都发:`{ inside, screen, world, lngLat }`,屏幕坐标是画布 CSS 像素、`lngLat` 要有 GeoJSON 背景才有;`getPointer()` 随时能读同一份,移出时 `inside: false` |
|
|
22
22
|
| `onPointDrag` | `GisViewPointDragPayload` | 拖拽点:`phase` 为 `start` / `drag` / `end`,载荷带最新坐标、本次移动的全部节点 `points` 与跟随移动的线路 `lines` |
|
|
@@ -79,11 +79,11 @@ const view = createGisView('#map', {
|
|
|
79
79
|
|
|
80
80
|
| 载荷字段 | 说明 |
|
|
81
81
|
| --- | --- |
|
|
82
|
-
| `type` | 动作名:`updateData` / `updatePoints` / `updateLines` / `updateOptions` / `updateBackground` / `updatePoint` / `updateLine` / `updateChannel` / `pointDrag` / `copyPoint` / `copyPoints` / `mergePoints` / `waypoint` / `addChannel` / `addChannels` / `addChannelGroups` / `addLine` / `addPoints` / `addLines` / `removePoints` / `removeSelected` / `removeLines` / `removeLine` / `removeChannel` / `channelGroups` / `batch` |
|
|
82
|
+
| `type` | 动作名:`updateData` / `updatePoints` / `updateLines` / `updateOptions` / `updateBackground` / `updatePoint` / `updateLine` / `updateChannel` / `pointDrag` / `copyPoint` / `copyPoints` / `mergePoints` / `waypoint` / `addChannel` / `addChannels` / `addChannelGroups` / `addLine` / `addPoints` / `addLines` / `removePoints` / `removeSelected` / `removeLines` / `filterRemove` / `removeLine` / `removeChannel` / `channelGroups` / `batch` |
|
|
83
83
|
| `points` / `lines` / `channels` | 变更之后的最新数据(组件内部那一份的引用,只读,不要就地改) |
|
|
84
84
|
| `counts` | `{ points, lines, channels }` 三个条数 |
|
|
85
85
|
| `ok` / `reason` | 这一次调用成没成(`addPoints` / `addLines` / `removePoints` 这类批量接口会带上),`reason` 说明没成的原因 |
|
|
86
|
-
| 动作专属字段 | 拖拽带 `movedPoints` / `movedLines`,复制带 `item` / `source` / `revert()`(`copyPoints` / 整组粘贴另有 `sources` / `items` / `indexes` / `lines` / `channels` / `count`),合并带 `source` / `target` / `removedLines` / `mergedChannels`,拐点带 `lineIndex` / `pathIndex` / `phase`,新增带 `lineIds` / `lineIndex` / `channelId` / `groupId`(`addPoints` / `addLines` 另有 `indexes` / `items` / `position`:新要素在数组里的位置与加进去的那几条,`addChannelGroups` 另有 `results` / `groupIds` / `items`),删除带 `indexes` / `item` / `removedLineIds`,分组带 `index` / `groups` / `action`(细分动作,与 `onChannelGroupChange` 同一份);批量补丁(`patchPoints` / `patchLines`)的 `updatePoints` / `updateLines` 带 `indexes` / `items` / `count` / `skipped`,`removeSelected` 带 `pointIds` / `lineIds` / `pointIndexes` / `lineIndexes` / `removedChannels` |
|
|
86
|
+
| 动作专属字段 | 拖拽带 `movedPoints` / `movedLines`,复制带 `item` / `source` / `revert()`(`copyPoints` / 整组粘贴另有 `sources` / `items` / `indexes` / `lines` / `channels` / `count`),合并带 `source` / `target` / `removedLines` / `mergedChannels`,拐点带 `lineIndex` / `pathIndex` / `phase`,新增带 `lineIds` / `lineIndex` / `channelId` / `groupId`(`addPoints` / `addLines` 另有 `indexes` / `items` / `position`:新要素在数组里的位置与加进去的那几条,`addChannelGroups` 另有 `results` / `groupIds` / `items`),删除带 `indexes` / `item` / `removedLineIds`,分组带 `index` / `groups` / `action`(细分动作,与 `onChannelGroupChange` 同一份);批量补丁(`patchPoints` / `patchLines`)的 `updatePoints` / `updateLines` 带 `indexes` / `items` / `count` / `skipped`,`removeSelected` 带 `pointIds` / `lineIds` / `pointIndexes` / `lineIndexes` / `removedChannels`,`filterRemove` 带 `mode: 'remove'` / `pointIndexes` / `removedPoints` / `removedLineIndexes` / `removedLineItems` / `lineIds` / `count` / `removedLines` / `removedChannels`(`points` / `lines` / `channels` 仍是删除后的最新数据) |
|
|
87
87
|
|
|
88
88
|
`onSelectChange` 与 `onSelect` 的区别只有一个:**只在选中集真的变了时发** —— 框选过程中的重复同步、
|
|
89
89
|
数据变化引起的补发都不发;并且**接口选中**(`selectFeatures()` / `selectFeatures(null)` / `selectInBox()`)也会发
|
|
@@ -93,7 +93,8 @@ const view = createGisView('#map', {
|
|
|
93
93
|
`action` 是更细的一份判读(与指针事件同一套写法):`action.type` 是 `select`(点中一个或接口选中)/
|
|
94
94
|
`toggleSelect`(Ctrl 点击取反,取反取没了也是它)/ `boxSelect`(框选,没框到东西也是它)/
|
|
95
95
|
`clearSelection`(点空白、Esc 或接口清空),`action.target` 是 `selection` / `empty`,`action.data` 就是
|
|
96
|
-
这一批 `items`,`action.modifiers`
|
|
96
|
+
这一批 `items`,`action.modifiers` 是这一次的修饰键。单击触发模式下,Ctrl 取反与点空白清空这两条路**不经过 `onClick`**;
|
|
97
|
+
`selectTrigger: 'dblClick'` 时第一下仍会发 `onClick`,第二下应用选中 / 取反 / 清空后会同时发 `onClick` 与 `onDblClick`。
|
|
97
98
|
要按操作分支的面板认这一个字段:
|
|
98
99
|
|
|
99
100
|
```js
|
|
@@ -34,7 +34,27 @@ createGisView(container, {
|
|
|
34
34
|
|
|
35
35
|
拖动期间选框实时跟随,但事件只在松手时派发一次,不会拖动一帧报一次。**框选默认只收节点**,保持旧口径;写 `selectionKinds` 后可以把通道外的线路与通道回线一起纳入(三类任意组合),见下节。选中结果用 `getSelections()` / `getSelectionData().ids` 读回。用代码框选等价于调用 `selectInBox({ x, y, width, height })`,矩形同样是画布 CSS 像素;第二段还能临时覆盖类型过滤。框选命中的节点套用框选样式(`options.pointBoxSelectStyle`,节点自己的 `boxSelectStyle` 优先),缺省与选中样式完全一致;框选出来的线路走普通的 `lineSelectStyle`(线路没有单独的框选样式)。
|
|
36
36
|
|
|
37
|
-
不想拖动时也可以用 Ctrl(macOS 为 Cmd)逐个点击节点累加选中,命中已选中的节点会把它取消掉;两种方式得到的选中集合一样,之后按住组内任意一个节点拖动就是整组移动。不想按修饰键就把多选开关打开(`options.multiSelect: true`,运行时用 `updateOptions({ multiSelect })` 切):普通单击即取反累加,线路也认(受 `channelSelectMode` 的整组 /
|
|
37
|
+
不想拖动时也可以用 Ctrl(macOS 为 Cmd)逐个点击节点累加选中,命中已选中的节点会把它取消掉;两种方式得到的选中集合一样,之后按住组内任意一个节点拖动就是整组移动。不想按修饰键就把多选开关打开(`options.multiSelect: true`,运行时用 `updateOptions({ multiSelect })` 切):普通单击即取反累加,线路也认(受 `channelSelectMode` 的整组 / 整条摊开约束);单击触发模式下双击的第二次点击不再取反,`onDblClick` 照常派发。多选命中的节点走多选样式(`options.pointMultiSelectStyle`,节点自己的 `multiSelectStyle` 优先),框选命中的走框选样式(`options.pointBoxSelectStyle`,节点自己的 `boxSelectStyle` 优先),两者缺省都与选中样式完全一致。注意框选样式只给节点;选中线路 / 通道回线时仍按 `lineSelectStyle` / `lineMultiSelectStyle` 上色。
|
|
38
|
+
|
|
39
|
+
### 点击选中与 dblClick
|
|
40
|
+
|
|
41
|
+
`selectTrigger` 缺省是 `'click'`:命中的节点 / 线路在第一次单击时就进选中集,点空白也在第一次单击时清空。写 `selectTrigger: 'dblClick'` 后,第一次点击只派发 `onClick`(`action.type` 是 `'click'`),同一位置 320ms 内、6px 范围内的第二下才应用选择结果:
|
|
42
|
+
|
|
43
|
+
- 点要素:选中它;`multiSelect` 或按住 Ctrl / ⌘ 时取反累加。第二下同时派发 `onClick`(`action.double: true`,取反时 `action.type` 为 `'toggleSelect'`,普通选中为 `'select'`)与 `onDblClick`(`action.type: 'dblClick'`)。
|
|
44
|
+
- 点空白:第二下才清空选中集并派发 `onDblClick`。
|
|
45
|
+
- `click` 模式下普通双击的 `onDblClick` 也照常派发,只是第一次单击已经完成了选中;Ctrl / `multiSelect` 的取反快捷路保持原口径(不额外发 `onClick` / `onDblClick`)。两种模式都不影响拐点双击删除与通道草稿等既有双击交互。
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
createGisView(container, {
|
|
49
|
+
features: { select: true },
|
|
50
|
+
selectTrigger: 'dblClick',
|
|
51
|
+
onDblClick: payload => panel.open(payload) // 第二下必发;payload.action.double === true
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
view.updateOptions({ selectTrigger: 'click' }) // 运行时切回单击选中
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
运行时切换 `selectTrigger` 会清掉上一次点击的双击判定状态,切换后的第一下不会被算成旧点击序列的第二下。`selectFeatures()` / `select()` 这类接口选中不受触发方式影响。
|
|
38
58
|
|
|
39
59
|
### 选择类型过滤(selectionKinds)
|
|
40
60
|
|
|
@@ -115,8 +135,9 @@ selection.lines // 选中的线路数据(通道回线也算一条)
|
|
|
115
135
|
selection.channels // 选中回线所属的通道(按通道去重,同一条通道的几回线算一条)
|
|
116
136
|
selection.items // 与 getSelections() 同一份:带下标、屏幕坐标与通道上下文
|
|
117
137
|
selection.bounds // 世界包围盒(空选中时 null),直接交给 zoomToBounds / focusOn
|
|
118
|
-
view.focusOn(selection.items)
|
|
119
|
-
view.focusOn(selection.items, {
|
|
138
|
+
view.focusOn(selection.items) // 把视角中心挪到这一批(比例不动)
|
|
139
|
+
view.focusOn(selection.items, { zoom: true }) // 按这一批的整体范围适配
|
|
140
|
+
view.focusOn(selection.items, { select: true, zoom: true }) // 反过来也行:聚焦的同时把它们选上
|
|
120
141
|
```
|
|
121
142
|
|
|
122
143
|
`mode` 只决定「这一批怎么并进当前选中集」,落地之后与手动选中完全一样(通道回线照旧按通道抬层,见上一节)。认不出来的条目跳过(与 `patchPoints` 的 `skipped` 一个态度)。按 id 定位用的是与 `patchPoints` 同一张 id 表(按数据版本缓存),`isSelected` 与 `selectFeatures` 的去重也都走常数级的键集合 —— 十万级数据下「按 id 选一批」是 O(选中数),不会每个 id 扫一遍全量。
|
package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md
CHANGED
|
@@ -241,7 +241,7 @@ Demo 的「通道与数据」页直接接了两类假接口:通道分组拐点
|
|
|
241
241
|
|
|
242
242
|
- **加点 / 删点 / 拖点只作用于同一分组**:同一分组共用一条骨架,其余分组的线路不动。
|
|
243
243
|
- 分组结果会写回 `channels[].groups`(`{ id?, lineIds, path?, waypointOffsets? }`),下次 `updateOptions` / 换数据按它重建;也可以一开始就手写 `groups` 而不是 `lineIds` + `path`。
|
|
244
|
-
- `getChannelMembers()` 与鹰眼图都按分组各成一份:`channelCircuits: false`
|
|
244
|
+
- `getChannelMembers()` 与鹰眼图都按分组各成一份:`channelCircuits: false` 时每个分组把当前可见成员逐顶点平均成一根居中代表线(双回线落在两根正中间,三回线落在中间那条)。
|
|
245
245
|
|
|
246
246
|
---
|
|
247
247
|
|