gis-view-webgl2 0.1.7 → 0.1.8
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 +9 -8
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +232 -228
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +49 -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 +48 -0
- package/docs/demos/BasicDemo.vue +2 -2
- package/docs/demos/BatchAddDemo.vue +6 -6
- package/docs/demos/ConnectDemo.vue +164 -33
- package/docs/demos/CopyMergeDemo.vue +27 -14
- package/docs/demos/EventDemo.vue +17 -20
- package/docs/demos/LabelDemo.vue +5 -5
- package/docs/demos/api-index.js +31 -29
- package/docs/demos/gis-view-demo/GisViewDemoCardHeader.vue +1 -1
- package/docs/demos/gis-view-demo/GisViewDemoStage.vue +1 -1
- package/docs/demos/gis-view-demo/panels/DataPanels.vue +1 -1
- package/docs/demos/gis-view-demo/useGisViewDemo.js +31 -33
- package/docs/format/07-/344/272/213/344/273/266/350/275/275/350/215/267/344/270/216/347/244/272/344/276/213/346/225/260/346/215/256.md +8 -7
- package/docs/from0/05-/347/233/270/346/234/272/344/270/216/344/272/244/344/272/222.md +1 -1
- package/docs/from0/07-/351/200/232/351/201/223/345/210/206/347/273/204/344/270/216/345/244/232/345/233/236/347/272/277.md +26 -10
- package/docs/manual/02-/345/235/220/346/240/207/344/270/216/346/225/260/346/215/256.md +1 -1
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +21 -16
- package/docs/manual/06-/346/225/260/346/215/256/344/270/216/345/234/272/346/231/257/346/233/264/346/226/260.md +9 -10
- package/docs/manual/07-/346/214/207/351/222/210/344/270/216/350/246/201/347/264/240/347/274/226/350/276/221.md +54 -31
- package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +3 -3
- package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +9 -6
- package/docs/manual/10-/351/200/232/351/201/223/347/274/226/350/276/221/344/270/216/346/226/260/345/242/236.md +226 -493
- package/docs/manual/12-/346/240/207/347/255/276/344/270/216/350/243/205/351/245/260.md +2 -2
- package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +12 -13
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +23 -21
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +19 -17
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +125 -78
- package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +1 -1
- package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +2 -2
- 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 +4 -4
- package/docs/steps/README.md +9 -7
- package/docs/steps/bench-scale.html +1 -1
- package/docs/steps/index.html +6 -6
- package/docs/steps/selftest-actions.html +26 -25
- package/docs/steps/selftest-data.html +1 -1
- package/docs/steps/selftest-demos.html +102 -6
- package/docs/steps/selftest-docs.html +3 -3
- package/docs/steps/selftest-features.html +283 -51
- package/docs/steps/selftest-full.html +3 -3
- package/docs/steps/selftest-labels.html +1 -1
- package/docs/steps/selftest-perf.html +31 -4
- package/docs/steps/selftest-select.html +20 -5
- package/docs/steps/step-05-pick.js +4 -8
- package/docs/steps/step-07-channels.js +3 -5
- package/docs/steps/step-08-labels.js +3 -3
- package/docs/steps/step-10-full.js +3 -3
- package/docs/steps/step-12-events.js +41 -24
- package/package.json +1 -1
|
@@ -178,7 +178,7 @@ view.focusOn({ type: 'line', id: 'a' })
|
|
|
178
178
|
view.focusOn({ type: 'channel', channelId: 'c1' }) // 通道也可以直接写 { channelId: 'c1' }
|
|
179
179
|
view.focusOn({ type: 'group', channelId: 'c1', groupId: 'c1::2' })
|
|
180
180
|
view.focusOn({ type: 'group', groupId: 'global-group' }) // groupId 全局唯一时可省略通道
|
|
181
|
-
view.focusOn([120, 80]
|
|
181
|
+
view.focusOn([120, 80]) // 缺省只居中、比例不动
|
|
182
182
|
view.focusOn({ lngLat: [116.4, 39.9] })
|
|
183
183
|
|
|
184
184
|
// flyTo(target, options?):与 focusOn 同一套目标解析,平滑飞过去
|
|
@@ -384,8 +384,9 @@ view.deselect('a')
|
|
|
384
384
|
view.deselect(['a', 'b'])
|
|
385
385
|
view.deselect()
|
|
386
386
|
|
|
387
|
-
// getSelections() / getSelectionData() / isSelected(ref):读回选中
|
|
387
|
+
// getSelections() / getSelectionInfo() / getSelectionData() / isSelected(ref):读回选中
|
|
388
388
|
const picks = view.getSelections()
|
|
389
|
+
const info = view.getSelectionInfo() // { ids, count, points, lines, channels }
|
|
389
390
|
const selection = view.getSelectionData() // { ids, count, points, lines, channels, bounds, … }
|
|
390
391
|
const selected = view.isSelected('a')
|
|
391
392
|
|
|
@@ -446,9 +447,12 @@ view.mergeSelectedPoints({ target: 'b', sources: ['a', 'c'], force: true })
|
|
|
446
447
|
// splitPoint(source, parts, options?):把一个节点拆成多份(mergePoints 的逆操作)
|
|
447
448
|
const splitResult = view.splitPoint('a', [
|
|
448
449
|
{ x: 0, y: 0, name: '甲站(主)' }, // 第一份沿用原下标 / id
|
|
449
|
-
{ x: 80, y: 40, name: '甲站(东)', lines: ['l1'] } //
|
|
450
|
-
], { label: '
|
|
451
|
-
|
|
450
|
+
{ x: 80, y: 40, name: '甲站(东)', lines: ['l1'] } // 显式分给第二份
|
|
451
|
+
], { autoLines: 'alternate', label: '解除合并' })
|
|
452
|
+
// options.autoLines: 'first'(缺省,未分配的线路跟第一份)| 'alternate'
|
|
453
|
+
// alternate:同一条通道的成员成组、独立线路单条,轮流给负载最少的一份,解除合并推荐
|
|
454
|
+
console.log(splitResult.pointIds, splitResult.autoAssignedLines, splitResult.lineAssignments)
|
|
455
|
+
console.log(splitResult.autoLines, splitResult.changes) // lineAssignments 每项带 index / pointId / lineIds / lineCount
|
|
452
456
|
|
|
453
457
|
// getPointMerge() / resolvePointMerge(confirmed?, options?) / commitPointMerge() / revertPointMerge()
|
|
454
458
|
const pendingMerge = view.getPointMerge() // 待确认的那一份载荷(没有就是 null)
|
|
@@ -564,10 +568,9 @@ view.runChannelAction('split', { lineId: 'l2' })
|
|
|
564
568
|
view.addChannelGroupWaypoint('c1', 'c1::2', [200, 120])
|
|
565
569
|
view.removeChannelGroupWaypoint('c1', 'c1::2', 1)
|
|
566
570
|
|
|
567
|
-
// beginAddChannel(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?)
|
|
571
|
+
// beginAddChannel(options?) / beginAddLine(options?) / getAddChannelDraft() / updateAddChannelStyle(patch?) / continueAddChannel(options?)
|
|
568
572
|
// commitAddChannel(input?, options?) / cancelAddChannel() / endAddChannel()
|
|
569
573
|
view.beginAddChannel({
|
|
570
|
-
kind: 'channel',
|
|
571
574
|
circuits: 3,
|
|
572
575
|
channelDraftStyle: {
|
|
573
576
|
color: '#2f6fd0', width: 2.5, arrow: true, arrowSize: 14, arrowPositions: [0, 0.5, 1],
|
|
@@ -582,70 +585,93 @@ const draft = view.getAddChannelDraft() // 草稿读数(跟随
|
|
|
582
585
|
view.updateAddChannelStyle({ arrowPositions: [0.25, 0.75], arrowReverse: true }) // 字段级合并,只改箭头
|
|
583
586
|
view.updateAddChannelStyle(null) // 回到全局 channelDraftStyle
|
|
584
587
|
|
|
588
|
+
// 草稿的 select 只决定点节点时是否顺手选中节点;缺省 false
|
|
589
|
+
view.beginAddChannel({ from: 'station-a', select: true })
|
|
590
|
+
// 这一段最终落地几条回线由 circuits / lineData 决定;落地后是否选中新回线由 commitAddChannel 的 options.select 决定
|
|
591
|
+
view.commitAddChannel({}, { select: true })
|
|
592
|
+
|
|
593
|
+
// 单一通道 / 已有通道策略:singleChannel 只约束 beginAddChannel
|
|
594
|
+
view.beginAddChannel({ from: 'station-a', singleChannel: true }) // 两端已有通道 -> plan.blocked,commit 发 phase: 'blocked'
|
|
595
|
+
view.beginAddChannel({ from: 'station-a', existingChannel: 'newGroup' })
|
|
596
|
+
view.beginAddChannel({ from: 'station-a', existingChannel: 'joinGroup', groupId: 'c1::2' })
|
|
597
|
+
view.beginAddChannel({ from: 'station-a', existingChannel: 'joinGroup', groupIndex: 1 })
|
|
598
|
+
view.beginAddChannel({ from: 'station-a', existingChannel: 'auto' }) // 有新分组余量就新分组,否则并组
|
|
599
|
+
|
|
600
|
+
// beginAddLine:入口固定为线路语义;缺省独立线路,显式 existingChannel 且已有通道时才挂进通道
|
|
601
|
+
view.beginAddLine({ from: 'station-a' })
|
|
602
|
+
view.beginAddLine({ from: 'station-a', existingChannel: 'newGroup' })
|
|
603
|
+
view.beginAddLine({ from: 'station-a', existingChannel: 'joinGroup', groupId: 'c1::2' })
|
|
604
|
+
// 旧 beginAddChannel({ kind: 'line' }) 已移除;线路入口只认 beginAddLine
|
|
605
|
+
|
|
585
606
|
// commitAddChannel 只负责把已 ready 的草稿落地;没有草稿的程序化新增用 addChannel / addLine。
|
|
586
607
|
// 下面每个 commit 例子都假设当前草稿已经重新 ready;实际连续调用请逐段 begin / 点选。
|
|
587
|
-
// 五类入参:无参、旧 resolution、直接线路、直接通道(必须有 lineIds)、容器(channel / line / lines / ...)。
|
|
588
608
|
// 1. 无参:沿用草稿的 preferred(newChannel / newGroup / joinGroup / newLine)
|
|
589
609
|
view.commitAddChannel()
|
|
590
610
|
|
|
591
|
-
// 2.
|
|
592
|
-
view.commitAddChannel('newChannel')
|
|
593
|
-
view.commitAddChannel({ type: 'joinGroup', groupId: 'c1::2', groupIndex: 1, channelId: 'c1' })
|
|
611
|
+
// 2. 只改落点:所有 commitAddChannel 入参都写在一个容器对象里
|
|
612
|
+
view.commitAddChannel({ resolution: 'newChannel' })
|
|
613
|
+
view.commitAddChannel({ resolution: { type: 'joinGroup', groupId: 'c1::2', groupIndex: 1, channelId: 'c1' } })
|
|
594
614
|
|
|
595
615
|
// 3. 从 ready 的方案读数里选一条:只取四个定位字段,不能把整条 option 回传。
|
|
596
|
-
// 整条 option 还带 enabled / count / lineCount / lineIds
|
|
616
|
+
// 整条 option 还带 enabled / count / lineCount / lineIds,只取 resolution 需要的子集。
|
|
597
617
|
view.updateOptions({
|
|
598
618
|
onChannelDraft: payload => {
|
|
599
619
|
if (payload.phase !== 'ready' || payload.blocked) return
|
|
600
620
|
const chosen = payload.options.find(option => option.enabled && option.type === 'joinGroup')
|
|
601
621
|
if (!chosen) return
|
|
602
622
|
const result = view.commitAddChannel({
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
623
|
+
resolution: {
|
|
624
|
+
type: chosen.type,
|
|
625
|
+
groupId: chosen.groupId,
|
|
626
|
+
groupIndex: chosen.groupIndex,
|
|
627
|
+
channelId: chosen.channelId
|
|
628
|
+
}
|
|
607
629
|
})
|
|
608
630
|
console.log(result.ok, result.reason, result.lineIds)
|
|
609
631
|
}
|
|
610
632
|
})
|
|
611
633
|
|
|
612
|
-
// 4.
|
|
613
|
-
//
|
|
634
|
+
// 4. 独立线路对象放在 line 里:from / to、业务字段与 lineProps 都透传到新线路;
|
|
635
|
+
// path 是中间拐点(不含首尾)。线路对象不要直接放在顶层。
|
|
614
636
|
view.commitAddChannel({
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
637
|
+
line: {
|
|
638
|
+
id: 'new-line',
|
|
639
|
+
name: '对象线路',
|
|
640
|
+
from: 'station-a',
|
|
641
|
+
to: 'station-b',
|
|
642
|
+
color: '#ff7a45',
|
|
643
|
+
width: 3,
|
|
644
|
+
lineType: 'dashed',
|
|
645
|
+
voltageLevel: '10kV',
|
|
646
|
+
lineProps: { opacity: 0.9 }
|
|
647
|
+
},
|
|
648
|
+
path: [[116.72, 39.91], [116.86, 39.95]]
|
|
625
649
|
})
|
|
626
650
|
|
|
627
|
-
// 5.
|
|
628
|
-
// id 只决定通道 id,不是回线 id
|
|
651
|
+
// 5. 通道对象放在 channel 里:lineIds 的每个 id 生成一条回线,groups 是分组声明。
|
|
652
|
+
// id 只决定通道 id,不是回线 id 种子;并进已有通道要显式写 resolution。
|
|
629
653
|
view.commitAddChannel({
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
654
|
+
channel: {
|
|
655
|
+
id: 'new-channel', name: '对象通道', from: 'station-a', to: 'station-b',
|
|
656
|
+
lineIds: ['new-channel-1', 'new-channel-2'],
|
|
657
|
+
groups: [
|
|
658
|
+
{ id: 'new-group-1', lineIds: ['new-channel-1'], path: [[116.75, 39.86]] },
|
|
659
|
+
{ id: 'new-group-2', lineIds: ['new-channel-2'], path: [[116.75, 39.98]] }
|
|
660
|
+
],
|
|
661
|
+
width: 28,
|
|
662
|
+
owner: '运维一班'
|
|
663
|
+
},
|
|
664
|
+
lineProps: { color: '#2f6fd0', lineType: 'dashed' }
|
|
639
665
|
})
|
|
640
666
|
|
|
641
667
|
// 6. 容器写法:一段一段覆盖草稿,没写的继续用草稿。
|
|
642
|
-
// lines / lineData
|
|
668
|
+
// lines / lineData 同义,优先级 lines > lineData,给了几条就建几条。
|
|
643
669
|
view.commitAddChannel({
|
|
644
670
|
resolution: 'newChannel',
|
|
645
671
|
from: 'station-a',
|
|
646
672
|
to: 'station-b',
|
|
647
673
|
channel: { id: 'container-channel', name: '容器通道', nodeWidth: 1 },
|
|
648
|
-
|
|
674
|
+
lineData: [
|
|
649
675
|
{ id: 'n-1', color: '#dd4b2e', width: 2.2, name: '一回' },
|
|
650
676
|
'n-2',
|
|
651
677
|
{ id: 'n-3', color: '#2ea36b', voltageLevel: '10kV' }
|
|
@@ -654,52 +680,56 @@ view.commitAddChannel({
|
|
|
654
680
|
{ id: 'container-channel::1', lineIds: ['n-1', 'n-2'] },
|
|
655
681
|
{ id: 'container-channel::2', lineIds: ['n-3'], path: [[116.78, 39.96]] }
|
|
656
682
|
],
|
|
657
|
-
routing: 'orthogonal',
|
|
658
|
-
path: [[116.78, 39.9]],
|
|
659
|
-
lineProps: { opacity: 0.9 },
|
|
660
|
-
channelProps: { width: 36 }
|
|
683
|
+
routing: 'orthogonal',
|
|
684
|
+
path: [[116.78, 39.9]],
|
|
685
|
+
lineProps: { opacity: 0.9 },
|
|
686
|
+
channelProps: { width: 36 }
|
|
661
687
|
})
|
|
662
688
|
|
|
663
|
-
// 7. 只给 channel.lineIds 当种子:没有 lines / line / lineData
|
|
689
|
+
// 7. 只给 channel.lineIds 当种子:没有 lines / line / lineData 时,每个 id 建一条回线
|
|
664
690
|
view.commitAddChannel({
|
|
665
691
|
channel: { id: 'seed-channel', from: 'station-a', to: 'station-b', lineIds: ['seed-1', 'seed-2'] },
|
|
666
692
|
lineProps: { color: '#2f6fd0', width: 2 }
|
|
667
693
|
})
|
|
668
694
|
|
|
669
|
-
// 8. 空数组不覆盖草稿:
|
|
695
|
+
// 8. 空数组不覆盖草稿:lineData / lines 给 [] 时,沿用草稿的 lineData / circuits
|
|
670
696
|
view.commitAddChannel({ channel: { id: 'draft-lines' }, lines: [] })
|
|
671
697
|
|
|
672
|
-
// 9. 覆盖端点 / id / 名称 / 路由:顶层字段优先,
|
|
698
|
+
// 9. 覆盖端点 / id / 名称 / 路由:顶层字段优先,id 是线路 id 种子
|
|
673
699
|
view.commitAddChannel({
|
|
674
|
-
from: 'station-c', to: 'station-d', name: '改道联络线',
|
|
675
|
-
|
|
700
|
+
from: 'station-c', to: 'station-d', name: '改道联络线', id: 'rerouted',
|
|
701
|
+
lineData: [{ id: 'rerouted-1' }, { id: 'rerouted-2' }],
|
|
676
702
|
routing: 'orthogonal', path: [[116.9, 39.9]]
|
|
677
703
|
})
|
|
678
704
|
|
|
679
|
-
// 10. 并进已有通道 /
|
|
705
|
+
// 10. 并进已有通道 / 分组:显式写 resolution
|
|
680
706
|
view.commitAddChannel({
|
|
681
707
|
resolution: { type: 'joinGroup', groupId: 'c1::2' },
|
|
682
|
-
|
|
708
|
+
lineData: [{ id: 'join-1', color: '#dd4b2e' }, { id: 'join-2', color: '#2ea36b' }],
|
|
683
709
|
lineProps: { width: 2.4 }
|
|
684
710
|
})
|
|
685
711
|
|
|
686
|
-
// 11.
|
|
687
|
-
view.commitAddChannel(undefined, { continuous: false, originalEvent: null })
|
|
712
|
+
// 11. 第二参数只管本次收尾与选中:continuous: false 强制结束,select: true 才选中新回线
|
|
713
|
+
view.commitAddChannel(undefined, { continuous: false, originalEvent: null, select: true })
|
|
688
714
|
const commitResult = view.commitAddChannel()
|
|
689
715
|
console.log(commitResult.ok, commitResult.kind, commitResult.lineIds, commitResult.channelLineIds)
|
|
690
716
|
|
|
691
|
-
|
|
717
|
+
// 连续模式只续草稿配置,不能把这一段切换成线路;要线路请重新 beginAddLine
|
|
718
|
+
view.continueAddChannel({ from: 'station-b' })
|
|
692
719
|
view.cancelAddChannel() // 取消(Esc / 右键等价)
|
|
693
720
|
|
|
694
|
-
// 交接模式:两个节点选完发完 ready,假通道当场收掉,使用方自己走 addChannel
|
|
721
|
+
// 交接模式:两个节点选完发完 ready,假通道当场收掉,使用方自己走 addChannel。
|
|
722
|
+
// 新增回线缺省不选中;这里显式传 options.select: true。
|
|
695
723
|
view.beginAddChannel({ handoff: true })
|
|
696
724
|
view.updateOptions({
|
|
697
725
|
onChannelDraft: payload => {
|
|
698
726
|
if (payload.phase === 'ready') {
|
|
699
|
-
view.addChannel(
|
|
700
|
-
{ id:
|
|
701
|
-
{ id: 'm-2', color: '#2ea36b' }
|
|
702
|
-
|
|
727
|
+
view.addChannel(
|
|
728
|
+
{ from: payload.from.id, to: payload.to.id, name: '手填通道' },
|
|
729
|
+
[{ id: 'm-1', color: '#dd4b2e' }, { id: 'm-2', color: '#2ea36b' }],
|
|
730
|
+
undefined,
|
|
731
|
+
{ select: true }
|
|
732
|
+
)
|
|
703
733
|
}
|
|
704
734
|
}
|
|
705
735
|
})
|
|
@@ -714,27 +744,44 @@ if (between?.hasChannel) {
|
|
|
714
744
|
console.log(between.channelId, between.groupCount, between.groups.map(group => group.id), between.currentGroupId)
|
|
715
745
|
}
|
|
716
746
|
|
|
717
|
-
// addChannel(spec, lineData?, group?) / addChannels(input, options?)
|
|
718
|
-
|
|
719
|
-
|
|
747
|
+
// addChannel(spec, lineData?, group?, options?) / addChannels(input, options?)
|
|
748
|
+
// addChannelGroupLines(channelId, lineData?, group?, options?) / joinChannelGroupLines(channelId, groupId?, lineData?, options?)
|
|
749
|
+
// addChannelGroups(channelId, groups, options?) / addLine(spec, lineData?, options?):程序化新增
|
|
750
|
+
// 所有入口缺省都不改变选中集;只有 options.select: true 才选中这一次新建的回线。
|
|
751
|
+
const channelAdd = view.addChannel(
|
|
752
|
+
{ from: 'a', to: 'b', name: '二号通道', path: [[200, 120]] },
|
|
753
|
+
[{ id: 'm-1' }, { id: 'm-2' }],
|
|
754
|
+
undefined,
|
|
755
|
+
{ select: true }
|
|
756
|
+
)
|
|
757
|
+
const manyChannels = view.addChannels([
|
|
758
|
+
{ from: 'a', to: 'b', name: '三号通道', lineData: [{ id: 'm-3' }, { id: 'm-4' }] },
|
|
759
|
+
{ from: 'b', to: 'a', name: '四号通道', lineData: ['m-5'] }
|
|
760
|
+
])
|
|
761
|
+
console.log(channelAdd.lineIds, manyChannels.lineIds)
|
|
762
|
+
|
|
763
|
+
// 独立线路:第二段 lineData 给几条就建几条;只碰 lines,不碰 channels
|
|
764
|
+
const lineAdd = view.addLine(
|
|
765
|
+
{ from: 'c', to: 'd', name: '三回' },
|
|
766
|
+
[
|
|
767
|
+
{ id: 'wl-1', name: '第一回', color: '#dd4b2e', width: 5 },
|
|
768
|
+
{ id: 'wl-2', color: '#2ea36b' }
|
|
769
|
+
],
|
|
770
|
+
{ select: true }
|
|
771
|
+
)
|
|
772
|
+
console.log(lineAdd.lineIds, lineAdd.channelId) // channelId 为 null:独立线路不挂通道
|
|
773
|
+
|
|
774
|
+
// 已有通道:新加一组 / 并进某一组(语义直说,不用自己拼 resolution)
|
|
775
|
+
const addedGroup = view.addChannelGroupLines('c1', [{ id: 'm-6' }], { id: 'c1::3' }, { select: true })
|
|
776
|
+
const joined = view.joinChannelGroupLines('c1', 'c1::2', [{ id: 'm-7' }])
|
|
777
|
+
console.log(addedGroup.channelLineIds, joined.channelLineIds) // 更新后这条通道的完整成员表
|
|
778
|
+
|
|
779
|
+
// 一次加多组:每组写 lineData / lines,lineItems 已移除;缺省不选中
|
|
720
780
|
const manyGroups = view.addChannelGroups('c1', [
|
|
721
|
-
{ id: 'c1::4', path: [[130, 70]], lineData: [{ id: 'm-
|
|
722
|
-
{ path: [[150, 90]], lines: ['m-
|
|
781
|
+
{ id: 'c1::4', path: [[130, 70]], lineData: [{ id: 'm-8' }, { id: 'm-9' }] },
|
|
782
|
+
{ path: [[150, 90]], lines: ['m-10'] }
|
|
723
783
|
])
|
|
724
784
|
console.log(manyGroups.count, manyGroups.lineIds, manyGroups.groupIds)
|
|
725
|
-
const lineAdd = view.addLine({ from: 'a', to: 'b', name: '三回' })
|
|
726
|
-
// 第二段 lineItems:连同线路一起新建(一条或一批逐条属性),给了几条就建几条(circuits 忽略)
|
|
727
|
-
const withLines = view.addChannel({ from: 'c', to: 'd', name: '三号通道' }, [
|
|
728
|
-
{ id: 'wl-1', name: '第一回', color: '#dd4b2e', width: 5 },
|
|
729
|
-
{ id: 'wl-2', color: '#2ea36b' }
|
|
730
|
-
])
|
|
731
|
-
// 并进已有通道:resolution 或顶层简写(channelId / groupId / groupIndex)
|
|
732
|
-
view.addChannel({ from: 'a', to: 'b', resolution: { type: 'joinGroup', groupId: 'c1::1' } })
|
|
733
|
-
const joined = view.addChannel({ from: 'a', to: 'b', channelId: 'c1', groupIndex: 0 }) // 旧写法:取这条通道的第 0 组
|
|
734
|
-
// 已经有通道时用拆出来的两条(语义直说,不用自己拼 resolution)
|
|
735
|
-
view.addChannelGroupLines('c1', [{ id: 'm-5' }], { id: 'c1::3' }) // 新加一组
|
|
736
|
-
view.joinChannelGroupLines('c1', 'c1::2', [{ id: 'm-6' }]) // 并进某一组(序号 1 也认)
|
|
737
|
-
console.log(joined.channelLineIds) // 更新后这条通道的完整成员表(lineIds)
|
|
738
785
|
|
|
739
786
|
// removeLine(lineId) / removeLines(lineIds) / removeChannel(channelId):删线路 / 删多条 / 删整条通道
|
|
740
787
|
view.removeLine('l1')
|
|
@@ -36,7 +36,7 @@ canvas.addEventListener('contextmenu', (event) => {
|
|
|
36
36
|
|
|
37
37
|
`GisViewListOptions` 的几个筛选条件是「与」的关系:`indexes`(只看这几个下标)、`inView`(`true` 按当前视口,或者直接给一份世界矩形 `{ minX, minY, maxX, maxY }`)、`limit`(最多几条)、`visibleOnly`(缺省 `true`:被筛选 / `visible: false` 隐藏掉的不算)、`withScreen`(补一份画布 CSS 像素坐标)。都不给就是「全部可见的」;十万级数据下这套方法适合面板读数、导出与校验,别逐帧调。
|
|
38
38
|
|
|
39
|
-
`listPoints()` 用的就是引擎画点那一份可见判定(旧版单独暴露的 `getVisiblePoints()` 并进了这一条):`radius` / 图层号 / 屏幕坐标这些几何读数都在它给的条目里。`focusOn()`
|
|
39
|
+
`listPoints()` 用的就是引擎画点那一份可见判定(旧版单独暴露的 `getVisiblePoints()` 并进了这一条):`radius` / 图层号 / 屏幕坐标这些几何读数都在它给的条目里。`focusOn()` 只移动相机、不改数据:缺省只居中、比例不动,`{ zoom: true }` 才按目标范围适配,`{ select: true }` 顺带把这批选上,传一批目标(数组)就是整体居中。
|
|
40
40
|
|
|
41
41
|
`getPointStyle()` / `getLineStyle()` 给的是**当前解析结果**:节点看尺寸 / 图标 / 层级,线路看原始线宽 / RGBA / 透明度 / 层级;悬停 / 选中样式、整体倍率、热力倍率都不算在里面。逐条自己写死的字段优先于规则与全局样式,所以用它们对账「预览里多大、落地后多大」或者鹰眼图的小图尺寸时,不需要自己重跑样式链。
|
|
42
42
|
|
package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md
CHANGED
|
@@ -62,7 +62,7 @@ const stats = view.getStats() // clusterCount / clusterPointCount /
|
|
|
62
62
|
- 视口里的节点遍历也先查点网格:`forEachPointInView` 在节点超过 `POINT_VIEW_GRID_MIN_POINTS`(2048)、点网格不脏且估计候选不足总数的 1/32(`POINT_VIEW_GRID_COST_SHARE`)时,只查视口覆盖的格子、把候选排回数据顺序再逐个精确判定;网格脏着(刚改过数据 / 拖拽中)或视口几乎铺满时仍走整份扫描,避免为了省一趟遍历先付出建网格和排序的成本。`createPointGrid.estimate(..., stopAfter)` 与查询共用同一套格子口径,传 `stopAfter` 时一旦超过阈值立即返回,只判断候选是否过密时不必扫完视口里的全部格子;框选线路则复用已有的 `forEachLineInView`,不再为每条候选线复制路径 / 包围盒 / 颜色快照。
|
|
63
63
|
- 数据包围盒读数改为缓存:整份解析本来已经顺路算出点与线的范围,`getBounds()` 直接接住这一份;定向改点 / 改线、拖拽、追加要素与复制预览只把缓存标脏,下一次真被问到时才用点坐标和每条线的 `line.bounds` 重建,不再逐顶点重扫。`getBounds()` 每次返回独立副本,调用方就地修改不会污染下一次读数;追加到原范围之外、拖出边界这类增量也会立即失效。10 万点 + 10 万线(每条 10 顶点)实测连续 10 次 `getBounds()`:优化前 **5.2 ~ 6.6 ms / 次**,优化后 **0.00 ms / 次**;改一个点后缓存重建一次 **3.6 ms**,读数正确。
|
|
64
64
|
- 悬停、选中、拖拽只做增量更新:选中集合用点 / 线两张下标 `Set` 维护,样式变化按要素下标重新解析,顶点与实例数据就地改写后按「实例槽位」上传,不重建整批缓冲。
|
|
65
|
-
-
|
|
65
|
+
- 选中事件的通道上下文只在外层出现一次:同一条通道的 `groups` 只构造一份,`onSelect` / `onSelectChange` 与载荷顶层共享对象引用,不深拷贝;单通道把通道 / 当前组与本次选中的 `lineIndexes` / `lineIds` 摊平到顶层,不再额外生成 `channelContexts`,多通道才使用 `channelContexts`。`items[]` 里的回线完全不挂 `channelId` / `channelIndex` / `groupId` / `groups` 等通道字段,十万级选中时不为每条线路重复写同一份归属。组件侧按载荷外层的 `lineIndexes` 一次建立“线路下标 → 通道”缓存;选中数组换新时按引用失效,其他改动路径用引擎 O(1) 的 `getLineChannel()` 补建,`getSelectionInfo()`、复制与 `getSelectionData()` 直接查表,不再逐条 `describe()`。通道重建时顺手按 `channelIndex` 收好分组状态与组序号,后续悬停 / 选中查同通道分组和组号都是 O(1);构造一条通道的全部分组读数从 O(组数 × 通道数) 降为 O(组数)。指针载荷先展开拾取结果再补 `action` / 光标读数,不再把 `type` / `index` / `item` 和整个结果各写一遍;`selection`、按键 / 修饰键、`clientX` / `clientY` 这类可再取得的读数不再每条事件复制一份,`lngLat` 也改为就地补字段。`selectFeatures` 对同内容、同顺序的重设会在引擎刷新和 `describeSelection` 之前直接返回;事件本身只在选中操作 / 选中集变化时发生,不进入逐帧渲染路径。
|
|
66
66
|
- 状态样式就地更新:悬停 / 选中样式只改颜色、大小、描边时按实例槽位覆盖,不重建整批;符号换成 / 换出贴图、阴影条数变化这类批次结构变化才回退整批重排。哪些要素当前真的按状态样式画过另有一份记账(`stateStyledSignatures`),整体重建后立刻重算,取消选中时按它精确还原本体样式,不会留下残留。
|
|
67
67
|
- 动效只维护真正的动画线路:`lineEffectRuns` 让每帧的动点循环只遍历配了 `effect` 的线路,路径就地变化时只重算这一条的总长与包围盒;普通线路再多,也不会进入动画的逐帧扫描。
|
|
68
68
|
- 热力图的要素采样与密度烘焙分开缓存:坐标 / 权重 / 显隐变化才重新采集,核参数 / 色带变化复用采样重烤,`density.opacity` 与 `layer` 只改绘制;拖动期间延迟到停手统一补烤。
|
|
@@ -106,7 +106,7 @@ const stats = view.getStats() // clusterCount / clusterPointCount /
|
|
|
106
106
|
- **运动期保持全分辨率**:`interactionNoMsaa` 的非 MSAA 后备缓冲只换抗锯齿与细线画法,不降低 viewport / 后备存储尺寸。相机拖动、滚轮、`zoomBy` / `setCamera` / 飞行与尺寸倍率变化的帧都按画布实际像素绘制,整幅贴回保持 1:1,停手 160 ms 后恢复 MSAA 静态帧。上一轮曾按整帧间隔把运动帧降到 **0.65× / 0.5×** 再线性放大贴回,实测会让缩放 / 移动中的画面短暂模糊,现已整体移除;与之配套的 `drawWidth` / `drawHeight` / `framePixelRatio`、`u_offsetScale` 和 UV 裁剪也一并删除。尺寸倍率连续变化仍复用 160 ms 的 `scaleMotion` 窗口,暂停符号贴图重烤与预烤,停手后再对齐当前尺寸档;这部分只省重烤,不改变当前帧分辨率。最终全分辨率基准(1280×800,无头 Chrome + ANGLE / AMD D3D11,`quality: 'high'`,三次运行取中位):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**。`selftest-perf.html` 另有回归断言记录每次 `gl.viewport`,人为拉长运动帧间隔时也必须始终等于画布全尺寸。
|
|
107
107
|
- **片元管线专用化(为什么此前「感觉没提升多少」)**:之前的优化主要落在相机排帧、聚合脏标记、整份重排与符号预烤上;10 万线交互的 CPU profile 约 **98.6% idle**、`render` 自身约 **0.1%**,说明主线程不是瓶颈。真正剩余的是每条可见线在 GPU 上重复执行虚线取模 / `smoothstep` / 光晕分支的填充成本。`shaders.js` 现在给交互期 `gl.LINES` 一条只输出颜色的 `THIN_LINE_FRAGMENT_SHADER`,并给「全实线、无光晕」的四边形批次一条 `SOLID_LINE_FRAGMENT_SHADER`:跳过虚线取模、`smoothstep` 与光晕分支,只保留颜色与(非 MSAA 帧的)边缘覆盖率;有虚线或热力光晕的批次仍走通用片元。`engine.js` 的 `drawLineBatch` 按批选择,`refreshLineThinLedger` 同时给出是否全实线;线宽、端点圆头、全分辨率与停稳后的 MSAA 静态帧都不变。实测(1280×800,无头 Chrome + ANGLE / AMD D3D11,`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**。16 ~ 18 ms 已接近 60Hz 帧节拍,剩余成本仍是 GPU 填充率;细线快路径的实际门槛是**最大半宽 ≤ 0.6 设备像素且无虚线**(dpr = 1 时约 1.2px 线宽),2px 实线不会走 `gl.LINES`,但轻量四边形片元仍把同一 10 万线场景从约 **82.4 → 63.9 ms**。要继续明显提速,方向是减少可见线段数或屏幕覆盖面积,而不是继续抠 JS。
|
|
108
108
|
|
|
109
|
-
- 框选提交(`pointerup`)只做必要的工作:选中集每次同步整份换新,抬层集合因此只比引用(没有拖动 / 合并这类额外抬层时直接引用选中集本身,空集合三处共用一份),撤销选中与「同内容再框一次」不再逐个搬 / 逐个比 3.4 万个下标;组件层的选中集读数(id 表、键集合、点 / 线 / 通道条数)在一趟循环里收好并按数组引用缓存,`
|
|
109
|
+
- 框选提交(`pointerup`)只做必要的工作:选中集每次同步整份换新,抬层集合因此只比引用(没有拖动 / 合并这类额外抬层时直接引用选中集本身,空集合三处共用一份),撤销选中与「同内容再框一次」不再逐个搬 / 逐个比 3.4 万个下标;组件层的选中集读数(id 表、键集合、点 / 线 / 通道条数)在一趟循环里收好并按数组引用缓存,`getSelectionInfo()` / `selectChanged()` / `selectChange` 载荷直接取现成的;选中集的存活校验走 `isKeyAlive` 的键查表,不再为每个键造对象、投影一次;抬层欠下的整份重排记在 `raiseLayoutPending` 上、由 `flushRaiseLayout` 在下一帧渲染之前补,`pointerup` 回调里不再同步排十万级场景。实测(10 万点 / 10 万线):框住 3.4 万个节点的 `pointerup` 48.7 → 15.7 ms(框小一些的几轮 9.5 / 6.5 / 6.8 ms),提交后第一帧 19.5 ~ 24.2 → 15.6 / 6.7 ~ 9.5 ms。
|
|
110
110
|
- 整份重排(`layoutScene`)也少扫几趟十万条:点 glyph 从对象池里复用(逐字段就地改写,不再每轮造十万个对象)、圆点实例用 `writeCircleGlyph` 直写进 `prepareInstances` 的批次数组(不再逐条造 `circleFromGlyph` 的中间对象);没有线路装饰 / 没有跑动动画 / 没有节点阴影 / 没有逐要素状态样式时,各自的十万级空扫直接跳过(`hasLineDecorations` / `hasLineEffects` / `hasPointShadows`,节点侧另有 `hasPointStateStyles()`);细线快路径的账本只在「线宽或虚线开关真的变了」时才标脏;`zIndex` 分层只有一层(绝大多数场景)时不再重铺点顺序。同一份 10 万级的 CPU profile 里 `syncRaiseSets` 6.2 → 0 ms、`buildLineEffectGlyphs` 3.69 → 0 ms、`buildLineDecorationGlyphs` 1.66 → 0.62 ms、`thinLineBatchEligible` 2.2 → 0 ms。
|
|
111
111
|
- 定向更新的线路标签候选复用:`updatePoint` / `patchPoints` 只改节点侧(补丁没动坐标 / id、筛选也没开)时,线路标签层接着用上一轮收好的候选 —— 视口矩形、画布尺寸与「上一轮显示过的下标集合」逐项核对(定义对象是缓存键),十万条线的视口扫描整个省掉;改线路内容 / 挪节点 / 换 id / 筛选联动时判据返回 `undefined`,照旧整层重扫。10 万点 / 10 万条长线 + 两层标签(DOM 75 条)实测单次 `updatePoint` p50 **4.7 → 1.7 ms**,CPU profile 采样 531 → 226、`forEachLineInView` 从热点清单消失。
|
|
112
112
|
- 超长线段换更粗的一层网格:线段网格原来给「一层里铺不下的长线」只记一条包围盒、查询按盒子先筛,长线密布时几乎等于全量重算;现在每层格子边长 ×4,粗层同样只登记线段真正穿过的格子(跨层 stamp 去重),候选从「包围盒相交」变成「几何上真的经过光标附近」。10 万条随机长线实测一次查询的候选 11101 → **2210** 条、`pick` p50 / p95 / 平均 **0.9 / 6.2 / 1.90 → 0.3 / 1.7 / 0.53 ms**;代价是极限数据集建网格 16.3 → 41.6 ms、堆内存多约 26 MB(短线为主的数据集不变)。
|
|
@@ -78,13 +78,13 @@
|
|
|
78
78
|
**密度场那一层怎么看都糊成一片 / 看不出色带?** 先看三个数:`threshold`(门槛,抬到 0.15 ~ 0.3 就只留热点,参考图那种「大片浅色 + 白心」就是把门槛抬起来)、`gamma`(对比度,大于 1 把色带一圈圈收在热核外面)、`max`(`'auto'` 是分位膝盖,长尾数据别写死成场的峰值)。再看 `radiusRatio`:太小色斑会碎成一堆点、太大就糊成一整片,缺省 5.5% 是「一眼能看出色斑」的档。数据本身也要有疏密差别 —— 均匀铺满一屏的网格数据,密度场本来就该是平的。
|
|
79
79
|
|
|
80
80
|
**没有通道,能只用点和线吗?**
|
|
81
|
-
可以。`channels` 是可选声明,省略或写 `channels: []` 都能正常运行;`lines` 自己的 `path` / `from` / `to`、`direction`、`lineType` 与新增 / 选中 / 拐点编辑都不依赖通道。交互新增用 `
|
|
81
|
+
可以。`channels` 是可选声明,省略或写 `channels: []` 都能正常运行;`lines` 自己的 `path` / `from` / `to`、`direction`、`lineType` 与新增 / 选中 / 拐点编辑都不依赖通道。交互新增用 `beginAddLine()`,程序化用 `addLine` / `addLines`,不会往 `channels` 写任何东西。`?demo=connect` 就是从 `channels: []` 开始的纯点 + 线示例。
|
|
82
82
|
|
|
83
83
|
**怎么加一条不挂通道的线路?**
|
|
84
|
-
`view.addLine({ from, to })
|
|
84
|
+
`view.addLine({ from, to })` 新增一条独立线路,走交互就是 `beginAddLine()`;要一次加多回就传第二段 `lineData`(例如 `view.addLine({ from, to }, [{ id: 'l-1' }, { id: 'l-2' }])`)。它只往 `lines` 里加普通线路,`channels` 声明一个字节都不动 —— `getChannels()` 里不会出现它,之后也不用担心它被通道分组、拆分、整条通道删除这些操作牵连。`addLine` 缺省不改变选中集,需要选中新线时传 `{ select: true }`。反过来 `beginAddChannel()` / `addChannel()` 是新建通道:`addChannel` 只负责新建,已经存在通道时要加一组 / 并进某一组用 `addChannelGroupLines` / `joinChannelGroupLines`。
|
|
85
85
|
|
|
86
86
|
**怎么一次给通道加多回?**
|
|
87
|
-
`circuits`
|
|
87
|
+
通道草稿和 `commitAddChannel` 用 `circuits` 表示「这一次加几条」;程序化 `addChannel` / `addLine` 的新版入口用第二段 `lineData` 的长度表示回数。例如 `addChannel({ from, to }, [{ id: 'l-1' }, { id: 'l-2' }, { id: 'l-3' }])` 一次建三回,独立线路写成 `addLine({ from, to }, ['l-1', 'l-2'])`。方案表的余量按本次条数算 —— 加 3 回时只剩 2 回余量的分组会置灰,`reason` 写清「只剩 2 回余量,本次要加 3 回」;落地回执里 `lines` / `lineIds` 是这一批线,`onChannelDraft` 的 `commit` 载荷里也一样,`removeLine` 一条条摘掉就行(demo 的「移除上一条新增」就是整批摘)。这些入口缺省都不选中新回线,`options.select: true` 才会选中。
|
|
88
88
|
|
|
89
89
|
**鹰眼图的节点大小 / 范围 / 框选怎么调?**
|
|
90
90
|
节点大小:`inheritRules` 打开(默认)时,小图取主图最终解析出的尺寸,再乘「小图视口 ÷ 主图视口」的较小比例 —— 只看两边 CSS 视口宽高,不随主图相机倍数变化;仍嫌大就调小图自己的 `pointSizeScale`,或配自己的 `pointRules` / `pointStyle` 接管尺寸。范围:`extent: 'auto'` 默认取数据 ∪ 底图且**不随相机收窄**;想要外围内容消失后跟着收窄才打开 `extentFollowCamera`。框选:`dragAction: 'box'` 不需要打开 `zoomable`,关闭缩放也能在空白处直接框;`zoomable: 'follow'` 是整体范围跟随主图,跟手动缩放 `true` 互斥。
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
| 覆盖层 | `GisViewLabelOptions`、`GisViewLineLabelOptions`、`GisViewItemLabel`、`GisViewLabelState`、`GisViewLabelPatch`、`GisViewSetLabelContentOptions`、`GisViewLabelListItem`、`GisViewItemLabelsInfo`、`GisViewRemoveLabelResult`、`GisViewSetLabelStatesResult`、`GisViewLabelChangePayload`、`GisViewLabelDragPayload`、`GisViewLabelClickPayload`、`GisViewLabelPointerPayload`、`GisViewLabelRef`、`GisViewLabelTarget`、`GisViewLabelBatchEntry`、`GisViewLabelRemoveEntry`、`GisViewLabelBatchSkip`、`GisViewAddLabelsResult`、`GisViewUpdateLabelsResult`、`GisViewRemoveLabelsResult`、`GisViewLineDecoration`、`GisViewTooltipOptions`、`GisViewLabelPayload`、`GisViewLineLabelPayload` |
|
|
183
183
|
| 筛选 | `GisViewFilter`、`GisViewFilterInput`、`GisViewFilterShorthand`、`GisViewFilterResult`、`GisViewFilterCascade`、`GisViewFilterMode`、`GisViewFilterWorkerOptions` |
|
|
184
184
|
| 大数据展示模式 | `GisViewDenseMode`、`GisViewDenseModeOptions`、`GisViewDenseModeInput`、`GisViewDenseState` |
|
|
185
|
-
| 通道 | `GisViewChannelInput`、`GisViewChannelBuildOptions`、`GisViewChannelBuild`、`GisViewChannelInfo`、`GisViewChannelGroupInfo`、`GisViewChannelGroupWaypoints`、`GisViewChannelGroupLineWaypoints`、`GisViewChannelMember`、`GisViewChannelContext`、`GisViewChannelAddPlan`、`GisViewChannelBetween`、`GisViewChannelAddOption`、`
|
|
185
|
+
| 通道 | `GisViewChannelInput`、`GisViewChannelBuildOptions`、`GisViewChannelBuild`、`GisViewChannelInfo`、`GisViewChannelGroupInfo`、`GisViewChannelGroupWaypoints`、`GisViewChannelGroupLineWaypoints`、`GisViewChannelMember`、`GisViewChannelContext`、`GisViewChannelAddPlan`、`GisViewChannelBetween`、`GisViewChannelAddOption`、`GisViewChannelAddSpec`、`GisViewLineAddSpec`、`GisViewChannelLineData`、`GisViewChannelAddGroup`、`GisViewChannelAddResolution`、`GisViewChannelAddCommitInput`、`GisViewChannelAddResult`、`GisViewChannelDraftOptions`、`GisViewChannelDraftPayload`、`GisViewChannelLineMoveTarget`、`GisViewChannelLineMoveResult`、`GisViewRemoveLineResult`、`GisViewRemoveChannelResult`、`GisViewRemoveLinesResult`、`GisViewChannelInView`、`GisViewChannelAction`、`GisViewChannelActionId`、`GisViewChannelDraftStyle`、`GisViewChannelDraftDots`、`GisViewChannelDraftDotStyle`、`GisViewChannelWaypointDragMode`、`createChannels`、`CHANNEL_DEFAULT_COLORS` |
|
|
186
186
|
| 事件载荷 | `GisViewPickResult`、`GisViewPickAtResult`、`GisViewRectQueryResult`、`GisViewSelectionInfo`、`GisViewSelectedItems`、`GisViewSelectPayload`、`GisViewClickPayload`、`GisViewPointerPayload、GisViewCascadeHighlightScope、GisViewCascadeHighlightOptions、GisViewCascadeHighlightInput、GisViewCascadeHighlightEntry、GisViewCascadeHighlightOrigin、GisViewCascadeHighlightInfo`、`GisViewPointerAction`、`GisViewPointerActionType`、`GisViewPointerTarget`、`GisViewPointerModifiers`、`GisViewWaypointActionData`、`GisViewLabelActionData`、`GisViewHoverPayload`、`GisViewCursorPayload`、`GisViewPointDragPayload`、`GisViewDragPointChange`、`GisViewDragLineChange`、`GisViewPointCopyPayload`、`GisViewPointCopyState`、`GisViewPointMergePayload`、`GisViewMergeImpact`、`GisViewMergeResult`、`GisViewMergeFailure`、`GisViewWaypointPayload`、`GisViewWaypointInfo`、`GisViewWaypointKey`、`GisViewParallelGroup`、`GisViewReadyPayload`、`GisViewEngineStats`、`GisViewEngineHeatDensity`、`GisViewDataChangeType`、`GisViewDataChangePayload`、`GisViewSelectChangePayload`、`GisViewShortcutPayload`、`GisViewRenderPayload`、`GisViewAddItemsResult`、`GisViewAddPointResult` |
|
|
187
187
|
| 快捷键与复制 / 合并 / 删除 | `GisViewShortcuts`、`GisViewShortcut`、`GisViewShortcutAction`、`GisViewCopyOptions`、`GisViewCopyContext`、`GisViewCopyStartOptions`、`GisViewPasteOptions`、`GisViewCopyItem`、`GisViewClipboardItem`、`GisViewMergeOptions`、`GisViewMergeContext`、`GisViewPointStyleSnapshot`、`GisViewPointRef`、`GisViewMergeResult`、`GisViewMergeFailure`、`GisViewMergeOutcome`、`GisViewRemovePointsOutcome`、`GisViewRemoveSelectedOutcome`、`GisViewRemoveOptions`、`GisViewRemoveScope`、`GisViewRemovePayload`、`GisViewRemoveResult`、`GisViewRemoveOutcome`、`GisViewRemoveFailure`、`GisViewRemoveAction`、`GisViewRemovePoint`、`GisViewRemoveLine`、`GisViewRemoveWaypoint`、`GisViewRemoveGroup`、`GisViewRemoveChannel`、`GisViewRemoveCounts`、`GisViewChannelSelectMode`、`GisViewUpdateItemsOutcome`、`GisViewUpdateItemEntry` |
|
|
188
188
|
| 相机与视图 | `GisViewCamera`、`GisViewViewport`、`GisViewFocusOptions`、`GisViewFocusTarget`、`GisViewExportImageOptions`、`GisViewExportSelectionOptions`、`GisViewExportSelectionResult` |
|
package/docs/steps/README.md
CHANGED
|
@@ -16,11 +16,11 @@ npm run dev # 或 npx vite
|
|
|
16
16
|
控制台里 `__gisSteps.view` 就是当前这一步的视图,`__gisSteps.DATA` 是那份园区数据,可以随手调 API。
|
|
17
17
|
地址栏里带步骤号(`index.html#7`)可以直接打开某一步,也能收藏 / 分享。
|
|
18
18
|
|
|
19
|
-
自测页就在同一个目录下(`selftest.html` / `selftest-demo.html` / `selftest-demos.html` / `selftest-labels.html` / `selftest-select.html` / `selftest-actions.html` / `selftest-scale.html` / `selftest-perf.html` / `selftest-features.html` / `selftest-full.html` / `selftest-effects.html` / `selftest-data.html` / `selftest-decoration.html` / `selftest-docs.html`):打开就跑,标题报 `PASS` / `FAIL`,页面上的清单是逐条断言。**无头环境下 `requestAnimationFrame` 基本不推进**,动画类断言要用真时间(CDP 或直接开浏览器)跑 —— `selftest-effects.html` 因此自己装了一个「帧泵」(把 `requestAnimationFrame` 收进 Map、手动按帧推进),涟漪与动点的断言才测得动。另有 docs/index.html(文档中心:把仓库里的 markdown 读成 HTML)、docs/api/index.html(API 速查:
|
|
19
|
+
自测页就在同一个目录下(`selftest.html` / `selftest-demo.html` / `selftest-demos.html` / `selftest-labels.html` / `selftest-select.html` / `selftest-actions.html` / `selftest-scale.html` / `selftest-perf.html` / `selftest-features.html` / `selftest-full.html` / `selftest-effects.html` / `selftest-data.html` / `selftest-decoration.html` / `selftest-docs.html`):打开就跑,标题报 `PASS` / `FAIL`,页面上的清单是逐条断言。**无头环境下 `requestAnimationFrame` 基本不推进**,动画类断言要用真时间(CDP 或直接开浏览器)跑 —— `selftest-effects.html` 因此自己装了一个「帧泵」(把 `requestAnimationFrame` 收进 Map、手动按帧推进),涟漪与动点的断言才测得动。另有 docs/index.html(文档中心:把仓库里的 markdown 读成 HTML)、docs/api/index.html(API 速查:267 个实例成员逐个一张卡,参数 / 返回 / 说明 / 示例与复制,搜索 + `#成员名` 深链、左侧分组跟随与深浅主题)、docs/guide/sample-document.html(sample-document.json 的交互图解)与 docs/steps/selftest-docs.html(上面这三个页面的自测:清单 / 渲染 / 点选标注一页跑完)。
|
|
20
20
|
|
|
21
21
|
## 怎么查全部属性与方法
|
|
22
22
|
|
|
23
|
-
组件的完整 API 是同一份清单的五个去处(当前:实例成员 **
|
|
23
|
+
组件的完整 API 是同一份清单的五个去处(当前:实例成员 **267** 个 = 262 个方法 + `el` / `canvas` / `gl` / `cameraAnimating` / `dataVersion` 五个属性,`options` **96** 个键,数据字段 **250** 个):
|
|
24
24
|
|
|
25
25
|
- **手册里查**:`docs/manual/` 把整本手册拆成 21 章(索引页 `docs/GisView.md` 有目录与按任务的快速跳转)—— 找方法先看 [`16 实例方法总表`](../manual/16-实例方法总表.md)、要把每个成员逐个列全(参数写「名字: 类型 = 默认值」、返回值只写类型)看 [`17 参数速查`](../manual/17-参数速查.md)、要能直接复制的调用看 [`18 逐方法示例`](../manual/18-逐方法示例.md);`options` 表与数据字段表分别在 [`03 配置项(options)`](../manual/03-配置项.md) 与 [`02 坐标与数据`](../manual/02-坐标与数据.md)。同名的接口在 `src/gis-view/types.d.ts`。
|
|
26
26
|
- **页面上查**:`docs/api/index.html`(API 速查)—— 左栏按 16 个分组列出全部成员,带搜索(Ctrl+K)与方法 / 属性 / options 三档开关,当前读到的分组会跟着高亮;右栏每个成员一张卡,参数 / 返回 / 说明之外,示例块直接来自 [`18 逐方法示例`](../manual/18-逐方法示例.md),带高亮与「复制名字 / 复制代码」,旁边还有「在调试页跑 →」;地址栏带 `#updateLine` 这样的 hash 直接跳到那一条。右上角主题按钮与文档中心共用 `gisDocs.reading`,跟随系统 / 浅色 / 深色三档换页不会各记一套;深链落点还留了 `scroll-margin-top`,不会被吸顶栏盖住。页面数据来自 `docs/demos/api-index.js`(生成物,禁止手改),自测页 `docs/steps/selftest-docs.html` 盯着它别掉队。
|
|
@@ -91,7 +91,7 @@ API 名字与前面几步是一一对应的;第 11 步再补两件「数据之
|
|
|
91
91
|
| --- | --- | --- |
|
|
92
92
|
| `onHover` | 光标下的元素变了 | 命中的元素,离开画布发 `null` |
|
|
93
93
|
| `onClick` / `onDblClick` | 左键单击 / 双击(没拖动) | 命中的元素 + `originalEvent` |
|
|
94
|
-
| `onPointerDown` / `onPointerUp` | 按下与抬起(含中键 / 右键) | 元素 +
|
|
94
|
+
| `onPointerDown` / `onPointerUp` | 按下与抬起(含中键 / 右键) | 元素 + 光标世界坐标;按键 / 修饰键读 `originalEvent` |
|
|
95
95
|
| `onContextMenu` | 右键 | 同上(要自己弹菜单就在这里 `preventDefault()`) |
|
|
96
96
|
| `onSelect` | 选中集合变化(点选 / Shift 框选 / 清空) | `{ items, box }` |
|
|
97
97
|
| `onChannelDraftClick` | 新增通道草稿里每点一次 | `phase` / `step` / `from` / `to` |
|
|
@@ -106,7 +106,7 @@ API 名字与前面几步是一一对应的;第 11 步再补两件「数据之
|
|
|
106
106
|
- `selftest.html`:手写版第 1 ~ 9 步的断言(拾取、草稿的 step 1 / 2、落地、移除、连续新增、平移……);
|
|
107
107
|
- `selftest-full.html`:真组件上的同一套断言,外加把 `index.html` 的十三个步骤逐个挂载一遍(第 13 步再点一遍画质 / 批量 / 撤销 / 重做 / 功能预设五个按钮);
|
|
108
108
|
本轮再补五条(双回线关闭后居中代表线、`backgroundStyle` 接管画布底色、主图方形 / 圆形尺寸与 SVG 图标、`container` 外部挂载与 `offset` 动态位移、换容器复用同一根节点并随 `destroy()` 清理);之前补的四条:小图上的 GeoJSON 底图在主视图放大 3 倍前后红色描边像素数不变(容差 20%)、小图放大 6 倍时 `pointZoomScale` 指数 0 / 1 的像素对比(指数 1 至少 4 倍面积、指数 0 不长大,且倍数回到 1 时指数 1 也不再放大)、以及 stub host 上「拖节点没有结束事件、空闲计时器也会把 `hideOnInteract` 收起的标签层放出来」。
|
|
109
|
-
- `selftest-features.html`(
|
|
109
|
+
- `selftest-features.html`(683 条):真组件上的线型 / 线路装饰 / 光标 / 表现型配置断言 —— 把画面用 `exportImage` 读回 2D 画布数像素(实线 > 虚线 > 点线的墨量、`dc_line` 中点装饰的像素差、`showGrid` 只重画一帧),光标则用合成的指针事件与 Ctrl 键读出 `canvas.style.cursor`;装饰那几条还会量「几何变了装饰跟不跟着走」—— 写回新路径、拖绑定的节点、加 / 删拐点之后,装饰的紫色像素质心都要落在新中点上(容差 3px);另外两条量的是**固定档**:`anchor: 'fixed'` + `at` 先把装饰钉在写死的世界坐标上,再把线从水平拖成斜的,装饰必须留在原坐标、不能跑到新中点。线路标签在单独一张画布上验:默认挂在中点、内容取 `name`,`position: 0` 落到起点,`hideOnInteract` 在缩放期间给整层加 `--hidden`、停手恢复,关掉 `lineLabel` 之后标签消失。装饰缺省 `auto` 的那一串也在这里量:没有拐点时拖端点装饰保持同一个比例(一直挂在中点)、加上拐点之后钉在那一刻的坐标上(改折线也不动)、把拐点删回直线又回到比例跟随、`anchor: 'follow'` 则一直跟到折线的新中点;`parallel` 用一条横条符号验(默认包围盒 26×6,平行之后转成 4×26),方形符号走的是 gl.POINTS 那条路(旋转后外接盒从 24×24 撑成 32×32)。通道里「每条回线各显示自己的标签」也在这里验:没有逐条配置时会被 32px 屏幕小格去重(只显示 1 ~ 2 条),给每条回线写上自己的 `lineLabelPosition` 之后 8 条全都在、位置各不相同,斜线上的标签按线路方向转、朝左的自动翻半圈(rotate = 0)。线路的层序(`zIndex`)也在这里验:画布正中一横一竖两条粗线交叉,默认后写的竖线在上(中心像素蓝),规则里给横线写 `zIndex: 5` 就换成红,`updateLine` 给竖线写 `zIndex: 9` 又换回蓝,写回 0 再回到红。这一轮另外验了插件上下文:`options.plugins` 与 `view.use()` 拿到的第二个参数是同一个冻结对象(`apiVersion === 1`、`view` 指回实例),旧的一参插件写法照常可用。这一轮另补 3 条合并触发时机断言(center 差 10px 不触发、继续拖入目标区域触发并带 trigger、collision 同距离照旧触发)。这一轮再补 1 条:13 个旧快捷方法已从实例删除,`updatePoint` / `updateLine` / `updateChannel` / `updateOptions` / `setFilter` / `setDropPreview` 仍在。对账组另补 8 条:`getChangedChannels({ ignoreGroups })` 忽略分组增删、已有分组拐点仍报、`reasons` 收窄与线路字段 / 路径 / 显隐变化,以及删除通道 / 删除线路 / 无通道场景同步清账。本轮再补实例命令的注册 / 同名覆盖 / 异常与销毁断言,并再补 16 条:筛选恢复后通道宽度与回线车道、`focusOn` 显式 `point` / `line` / `channel` / `group` 与统一缩放口径、`selectFeatures` 分组写法、`selectWaypoint` 带选线路,以及 `lineFollowsNode` 的隐藏 / 筛选 / 删除 / 撤销与动态切换。
|
|
110
110
|
- `selftest-decoration.html`(75 条):动态装饰器草稿专项自测 —— 开启后的 `start` 载荷、默认 14px 触发半径与每条线路不限量、指针在线路上 `hover`(命中线 / 自身 `decoration` / 平行角)、同一位置重复移动不重复发事件、移出目标 `leave`、在线路与空白处 `pointerup` 的 `ready` 差异、按下 / 抬起 `action.type` 都是 `decorationDraft`、单线 / 分组 / 整条通道三档作用域与非通道回退、`maxPerLine` 满额时悬浮与松手都不触发且提交前复核不写数据、`allowedLines` / `allowedChannels` / `allowedGroups` 三种白名单在悬浮与提交两处都拦截、`update` 改图标 / 尺寸 / 方向、`commit` 一次 `batch` 写四条且只发一条 `dataChange`、`cancel` 不改数据、重复 `begin` 替换旧草稿、整份换数据后过期草稿静默清掉。节点侧另有 32 条:`target: 'point'` 命中与只展开一个节点目标、方向 / 距离换算成屏幕偏移、相对偏移 / 固定世界坐标 / 鼠标位置三种位置来源、连接线样式随提交保存、`allowedPoints` 与 `maxPerPoint` 在悬浮 / 提交两处拦截、`both` 等距时节点优先且最近节点被白名单拦住时回退线路、节点与线路的重复 `reject` / `offset` 两种策略、节点装饰 get / update / remove 与整批提交、度转角与连接线进入矢量快照。这一轮另补 8 条节点断言:既有的 2 条「装饰随移动」仍保留;新增 6 条覆盖 `pointer + follow`、`fixed + follow`、`offset + fixed` 三种跨组合的预览与提交结果,确认位置来源和落地关系解耦后分别写成 `offset` 或 `at`。
|
|
111
111
|
- `selftest-demo.html`:demo 级自测 —— 面板上的「定位直流线路」按当前数据集的 `dc_line` 条数走(默认数据集 `new.json` 里现在自带 5 条,点一下直接选中并定位到第一条;一条都没有的数据集才切到样例数据、定位到「直流送电」,中点挂着 `PATH_DC_LINE` 装饰),断言按数据算出来的条数写、不写死数字,读数与选中面板都跟着更新;打开时说明段落默认收起、面板按组折叠,节点标签只给最高电压那一档、线路标签默认整个不显示(面板上勾「显示」再按「显示范围」展开),面板上有 PATH_DC_LINE 的「标记定位」下拉(自动 / 一直跟随 / 写死坐标三档)。「通道回线各自显示」这一档从数据层核对(勾上之后 3669 条回线都带上了自己的 `lineLabelPosition`),再放大三步后勾「与线路平行」,画出来的标签 transform 里要出现 `rotate(...)`。这一轮又补了「数据映射」下拉(raw / lngLat / fit / scale)与「节点 / geojson 比例」滑块:切到 fit 后 320 个站点都要落进 GeoJSON 画出来的范围、读数里给出换算比例;「经纬度 → 屏幕」「屏幕 → 经纬度」两个按钮来回换算一致(屏幕读数保留 1 位小数,允许 0.01° 的回差);在画布上挪一下鼠标,面板上就要出现屏幕像素与经纬度两行读数。
|
|
112
112
|
- `selftest-perf.html`(183 条):大数据量与画质档位的性能自测 —— 20000 点 / 8000 线的建场景与整份重排耗时、500 次拾取、逐个改 500 个节点对 `view.batch()`、四档画质与 `'auto'` 的自动升降;前面几轮补过 8 条交互期细线的断言(`getStats()` 给出 `antialias` / `software` / `thinLines` 三个读数;交互期 1px 实线整批走 `gl.LINES` 快路径、停手回到四边形展开;`interactionThinLines: false`、线宽 8px、整批带虚线这三种情况下都不走快路径,改回细实线又走);上一轮补过 7 条线路标签候选复用的断言(复用态与整层重排逐字一致,改线路内容 / 挪节点 / 相机变化之后缓存都作废)与 1 条连续更新的耗时 DIAG(2 万点 / 1 万线,中位 0.30 ms / 次);**这一轮再补 3 条标签避让盒的断言**(4 万点 + 4 万条长线放大后连续整层重排:第 2 轮起一次布局都不读、同一轮里没有哪条标签被量第二次)与 1 条量测读数 DIAG(逐轮 1427 / 0 / 0 / 0 / 0 次,旧写法 2662 / 0 … 次、第 1 轮重复量 1235 条;**上一轮把「没有哪条标签被量第二次」从按 DOM 节点去重改成按标签身份(`labelKind` # `labelIndex` # `labelLabel`)去重** —— 标签节点是池化复用的,按节点去重会把「同一格换了条标签」误报成重复量,旧代码实测第 1 轮 1235 条、新代码 0 条;**这一轮再补 3 条线路批次视口裁剪的断言**(20000 点 / 8000 线放大到 `scale: 10`:`lineInstances` 8000 → 27、相机挪回来回到 8000、来回一趟整幅像素差 0 / 241164)与 1 条读数 DIAG。这一轮再补 2 条点视口网格的断言(网格可用时枚举顺序与整份筛出来的下标序列一致、回调返回 `false` 最多只访问一个)。这一轮再补 19 条点聚合断言(归一化、1.2 万点建组与统计、原始数据不变、`visibleOnly` 排除成员、拾取 `type=cluster`、点击语义、`maxZoom` 展开、关闭恢复),页面每段之间让出一帧,边跑边出结果。这一轮另补 7 条热力图缓存断言:`styleKey` / `weightKey` 的语义、只改 `density.opacity` 不重采不重烤、换色带与定向改要素值会重烤。;本轮新增 1 条相机运动帧断言:人为拉长帧间隔并连续改相机,记录到的每次 `gl.viewport` 都必须等于画布全尺寸,防止运动期降采样重新引入模糊;本轮再补 1 条像素级断言:在同一交互状态下把细线专用片元管线与四边形画法逐像素对拍,线像素数量与整幅颜色差都必须在容差内,防止新管线把整批线画丢、画黑或换色。
|
|
@@ -115,12 +115,12 @@ API 名字与前面几步是一一对应的;第 11 步再补两件「数据之
|
|
|
115
115
|
- `bench-scale.html`:百万级基准页(同样只打印读数)—— 点 / 线规模与视口走 URL 参数,`window.__bench.run(options)` 量生成数据、建场景与发散渲染、平移 / 缩放 / 放大 / 拾取、`refresh` / `updatePoint` / `updateOptions`、内存账与销毁回收;另有 `prepare`(只建场景)、`__bench.op(name)`(单步)与 `__bench.micro(count)`(原语微基准)。配 `scripts/bench-scale.mjs` 用(CDP 驱动,`--points=1000000 --gpu --port=93xx`,另有 `--profile` 抓 CPU profile、`--heap` 抓堆快照);跑全部自测页用 `scripts/run-selftests.mjs`(`node scripts/run-selftests.mjs [页面名…]`,无头 Chrome + 真时间),两个脚本都要先起 dev server。
|
|
116
116
|
- `selftest-labels.html`(165 条):标签拖动与编辑、HTML 语义、高密度画布、导出分项多选的专项自测 —— 按住标签拖 90 px 之后标签真的挪了那么多、同时画布不平移,`labelDrag` 的 `start` / `move` / `end` 三态与 `offset` / `delta` 对得上,偏移进得了 `getLabelStates()`、再拖动节点时偏移照旧叠在节点位移上,`resetLabel` 之后回到默认锚点;`updateLabel` 改内容 / 字号 / 颜色(`style` 是增量合并,只改字号不动颜色)、`resetLabels` 一次清干净;点一下标签发 `labelClick` 并把这一条交给面板;线路标签的拖动与恢复默认同一条路;导出侧验「选什么导什么」(选场站只出场站、选通道自动带上拐点、不认识的分项记一条提示),`exportData({ scope: 'selection' })` 验场站 + 通道 / 只出线路 / 没选中时的 `ok: false` 三个分支。HTML 专项验全局 / 逐条 `true` / `false`、模板与 `field` / 默认名称转义、`updateLabel` 双向切换、线路标签富文本、点击载荷保留 `html` 与原标记、`getLabels()` 报运行时偏移、只改样式不替换 HTML 子节点、导出 → 回灌保持逐条语义,以及 120 条同内容标签首轮布局读取 ≤ 4 次的缓存断言。高密度专项用 1100 条纯文本验缺省 `auto` 只留一张画布、混入一条 `html: true` 仍保留那一条 DOM、`labelRender: 'dom'` 回退逐条 DOM 并清空画布、切回 `auto` 回收上一轮 div、SVG 导出包含画布标签与缩放只推一次;新增断言还验 1100 条同文案只调用 `measureText` ≤ 2 次、同一任务连续 5 次缩放只重绘 1 ~ 2 次、显式 `canvas` 在优化档遵守 `maxCount: 200`,以及 6 条线路标签在优化档全部进画布且 DOM 为 0。另验 GeoJSON 区域文字同一相机重复刷新 0 次 `style` 写入、只改字号复用同一 DOM 节点、离屏时改样式再回到视野仍能恢复显示、只改锚点位置也会重新投影,以及同一帧 12 次相机变化只做 1 次重投影。设备像素专项把 `devicePixelRatio` 临时设为 1.25,验标签落点与拖动期整层位移都落在物理像素网格上,并确认逐条标签不再各自声明 `will-change`。
|
|
117
117
|
- `selftest-actions.html`:事件判读与只读接口的专项自测 —— 左右键、拖动、框选、拐点与标签的 `action` 三件套(type / target / data)、`button` / `modifiers` / `moved` / `double`、Shift 框选(含没框到东西的空框)与 Ctrl 取反在 `selectChange.action.type` 上的分辨、`pickAt` 的客户端坐标与只读性、`getFeaturesInRect`(含宽高为负的矩形)与 `getChannelsInView`、`addPoints` / `addPoint` / `addLines` / `removeLines` 的返回与 `dataChange` 类型;最后一段把第 12 步 `step-12-events.js` 挂起来跑一遍(判读读数、`probeAt` / `probeRect`、两条走廊)。页面底部流式打印 PASS / FAIL。
|
|
118
|
-
- `selftest-select.html`:选择与框选的专项自测(
|
|
119
|
-
- `selftest-demos.html`:演示外壳与 22 个页签(21 个功能 + 综合,按基础 / 交互 / 样式 / 数据 / 性能 / 综合六组排列)的自测(**
|
|
118
|
+
- `selftest-select.html`:选择与框选的专项自测(85 条)—— 点选 / 悬停 / Ctrl 取反 / 多选开关的像素级状态样式与恢复,`selectFeatures` / `selectAt` / `deselect` / 通道写法 / 变更来源的接口断言(含 selectFeatures 实际变化时发 onSelect + onSelectChange、重复设同一选中集不重复通知、selectAt 每次命中发 onSelect 且集合变化时再发 onSelectChange),以及 SVG 状态贴图的预热与不同尺寸配方;这一轮补了 `selectionKinds: 'all'` 下 `selectInBox` 一次收下节点、独立线路与按 `channelSelectMode` 摊开的通道回线、`selectAt` 的节点 / 线路 / 通道 / 空白四路、多分组通道在 pickAt / hoverAt / 鼠标事件里的 `group` / `groups`,以及 SVG 导出 `currentStrokeColor` 的描边色还原和 `selectTrigger` 的单击、双击、多选取反 / 累加 / 取消。这几轮累计补了 5 条:`onSelect` / `onSelectChange` 的单通道顶层上下文(含本次选中的 `lineIndexes` / `lineIds`)与 `items[]` 不挂任何通道字段、真实点击 `onClick → onSelect → onSelectChange` 顺序、`selectFeatures(整条通道)` 与 `selectAt` 的通道载荷和 `onSelect → onSelectChange` 顺序(其中 `channelIndex` 同时校验为通道声明下标)、`getSelections()` / `getSelectionData()` 的选中镜像不挂通道字段且 `getLineChannel()` 仍能反查通道与分组;另补多通道选中断言,确认只给 `channelContexts`、不重复摊平,且两条事件共享同一批 `items`。
|
|
119
|
+
- `selftest-demos.html`:演示外壳与 22 个页签(21 个功能 + 综合,按基础 / 交互 / 样式 / 数据 / 性能 / 综合六组排列)的自测(**373** 条)—— 逐个用 `?demo=<id>` 打开基础视图、标签交互、标签显示、鹰眼图配置、样式与规则、悬停与提示、通道与数据、编辑与保存、事件与方法、接口能力、批量复制与合并、拖拽落点、可视化连线、动态装饰器、批量新增、搜索与筛选、扩展能力、性能与质量、点聚合、动画效果、扩展图形与综合示例,画布与右栏读数都在、切页签会把 `?demo=` 写回地址栏、切走之后上一个实例被销毁(不留画布)、缺省页签是综合示例、页签总数与注册表一致、顶部六个分组按钮一次只展开一组且组名可见;鹰眼图配置页另验 `layers` 的自定义 `draw` 真被调用、`placement` 切到数据前 / 后时 `drawInfo.stage` 跟着变、框拖动触发 `onInteraction` 并带相机、尺寸切换走 `updateOptions` 重铺画布、DPR 2 下 `maxPixelRatio` 的 1× / 2× 备份尺寸、关掉扩展层与 `zoomMinimapBy` / `setMinimapZoom`,以及 `extentFollowCamera` 默认关闭 / 打开生效、缩放关闭时 `dragAction: 'box'` 仍可框选、`zoomable: 'follow'` 跟随主图且 `setMinimapZoom` 不抢控制权;批量复制 / 合并、通道拐点 / 分组两页另有假接口断言(Shift 框选、整份请求体、标准响应包与资源级结果、版本号 / opId、200 / 网络失败 / 500 / 409、原 opId 重试与幂等重放不推进版本、409 rebase、本地回滚);假后端严格契约另有一组直接断言(请求头与 body 不一致返回 400、baseVersion 非有限数字返回 400、同 opId 换 body 返回 409 `IDEMPOTENCY_CONFLICT` 且版本不前进),通道页还验了自定义格式按钮注册 → 导出 → 注销;扩展能力页另验自定义运算符 / 图元 / `view.use` 插件 / `defineExportFormat` / 实例命令的注册、执行、同名覆盖、卸载与业务 DTO 结构,并验同名重新注册图元当场换画笔;可视化连线页另验初始 `channels` 为空、正交折线拐点、预览箭头、取消不写数据,默认提交 / `addLines` / `addChannels` 三种落地,指定起点后一次点击即可 ready、两端示例点的显隐 / 尺寸 / 形状 / 分端颜色与 `below-points` 层级、`commitAddChannel` 直接传线路 / 通道对象(含对象 path / 颜色 / 线宽优先);动态装饰器页另验吸附方式只有「跟随 / 固定」、两档下位置都有「相对节点 / 固定位置 / 鼠标位置」三档,固定 + 相对节点只改 `anchor`,固定 / 跟随 + 鼠标位置分别映射为 `placement: pointer` + 对应 `anchor` 且不带 `at`,跟随 + 固定位置仍传 `at`;通道与数据页另验「线路分组」弹框:分组卡片与「场站对标标识」都在,行内「确认移入」只改本地草稿、组件数据不动,取消 / Esc / 遮罩关闭不写数据,「确定分组」只调用一次 `splitChannelGroups` 把整份 groups 一次落地。点聚合页另验配置控件、聚合点击只增聚合计数、`maxZoom` 展开与适应全部后恢复、半径 / 重建 / 关闭统计;接口能力页另验三种级联触发独立开关、通道 / 分组 / 拐点程序化选中、通道 `focusOn`、`lineFollowsNode` 联动,以及样式字段合并、节点 / 线路装饰 CRUD、通道线宽与线路对账、GeoJSON 背景投影、历史 / 复制 / 删除收尾、`once`、WebGL 层清理、注册表注销与初始化 options 读数;页面底部流式打印 PASS / FAIL。鹰眼图线路层另有 3 条断言:首帧只铺固定范围里的线路、同一份数据补画命中缓存、小图缩放只重铺一次且仍裁剪范围外线路。
|
|
120
120
|
- `selftest-effects.html`:线路 / 节点动画与贴图预热的专项自测(96 条,页面自带「帧泵」—— 无头环境里 `requestAnimationFrame` 几乎不推进,它把 rAF 收进 Map、手动推帧,动画类断言才测得动):纯函数组(归一化、三层「关」的语义、按弧长采样、拐点连续、相位打散)、引擎组(铺批次 / 关掉一层 / 恢复 / 逐要素覆盖 / `getLineEffects` 全程贴线)、像素组(画布上真的有一个红点在两帧之间挪了位置)、**涟漪跟手组**(开着动画拖节点:拖动前圆心在节点坐标上、拖动中跟着走且是就地改实例缓冲、松手后整份重建也对齐、再拖回原位跟着回来,另有一条像素级断言量绿圈质心落在新坐标上)、**预热组**(全排列条数、第二次命中缓存、`getSymbolCombos()` 的去重与线路侧那一条、照着它配的一份**零张新画布**、反向一条「没画过的组合会当场烤、画布 +1」)、提醒组(`effects.line` 里写 `show` 被点名);这一轮另补 4 条动点缓存断言(5000 条普通线 + 2 条动点线:每帧只遍历动画线路,路径换短 / 换长后总长跟着更新)。
|
|
121
121
|
- `selftest-data.html`:标准数据文档与渲染后端开关的自测(103 条)—— `normalizeDocument` 的标准写法与 JSON 安全(无效日期写 `null` 并告警、类实例不静默变成空对象)、整份文档直接当 `createGisView` 入参、`exportData({ format: 'full' })` 导出 → 重建 → 再导出逐字节相同、`importData` 的整份与分列、`renderer` 三档与能力探测、网格顶点缓存窗口,以及自定义导出格式的注册 / 上下文 DTO 映射 / 深拷贝 / 视口导出 / 注销后失效;断言全在接口层,不读像素。
|
|
122
122
|
- `check-sample-fields.mjs`:不是页面、是对账脚本(`node docs/steps/check-sample-fields.mjs`)—— 核对 `sample-document.json` 自己就是标准写法(`normalizeDocument` 后逐字节相同、0 条提醒)、`docs/sample-document字段详解.md` 里的读数与 `documentCounts()` 一致、以及它的「字段索引」与从文件里摘出来的字段路径集合一个不多一个不少(当前 154 个);改完样本数据跑 `--write` 重写那两段机器块(幂等)。
|
|
123
|
-
- `selftest-docs.html`:三个文档页 + 调试页的自测(134 条)—— 文档中心(`docs/index.html`)的清单 92 份 md(10 个根 + 82 份子文档,含新的 `接口协议.md`;树形侧栏按 `parent` / `groupLabel` 分成 6 组 `details`)、首屏 README 渲染、markdown 渲染器(表格 / 带语言代码块 / 两级列表 / 引用 / 行内代码 / md 链接 / 目录 / 首条摘要卡片 / 首段导语)、元信息里的阅读时长、索引页的子文档链接、换一份子文档、代码块复制按钮、跨文档搜索与深链、跨文档锚点链接(`文件.md#小节` 原地切文档并闪一下)、能直接跑的围栏才有的「在调试页跑」与元信息行的「这一份的调试页(N 段示例)」、390px 窄屏首屏 / 深链 / 横向溢出回归、阅读百分比与「回到顶部」的联动;调试演示页(`docs/playground/index.html`)的一个示例下拉(内置示例 + 「这一份文档」两组 optgroup)、`?doc=` 读文档抽示例、片段标注与来源子栏、顶层 await 运行、`channels` 快照、光标行列、草稿自动保存与恢复、`Ctrl+S` 运行、复制 / 清空输出、状态胶囊;API 速查页(`docs/api/index.html`)的 `__gisApi` 钩子、六张统计卡、
|
|
123
|
+
- `selftest-docs.html`:三个文档页 + 调试页的自测(134 条)—— 文档中心(`docs/index.html`)的清单 92 份 md(10 个根 + 82 份子文档,含新的 `接口协议.md`;树形侧栏按 `parent` / `groupLabel` 分成 6 组 `details`)、首屏 README 渲染、markdown 渲染器(表格 / 带语言代码块 / 两级列表 / 引用 / 行内代码 / md 链接 / 目录 / 首条摘要卡片 / 首段导语)、元信息里的阅读时长、索引页的子文档链接、换一份子文档、代码块复制按钮、跨文档搜索与深链、跨文档锚点链接(`文件.md#小节` 原地切文档并闪一下)、能直接跑的围栏才有的「在调试页跑」与元信息行的「这一份的调试页(N 段示例)」、390px 窄屏首屏 / 深链 / 横向溢出回归、阅读百分比与「回到顶部」的联动;调试演示页(`docs/playground/index.html`)的一个示例下拉(内置示例 + 「这一份文档」两组 optgroup)、`?doc=` 读文档抽示例、片段标注与来源子栏、顶层 await 运行、`channels` 快照、光标行列、草稿自动保存与恢复、`Ctrl+S` 运行、复制 / 清空输出、状态胶囊;API 速查页(`docs/api/index.html`)的 `__gisApi` 钩子、六张统计卡、267 张成员卡都带签名网格与示例、96 个 options 四列网格、搜索过滤与命中读数、`select(名字)` 高亮、类型开关能单独收起属性、左侧当前分组高亮与即时跳转、顶栏文档深链、每个分组的手册章节链接、深浅主题切换与阅读设置共用;图解页(`docs/guide/sample-document.html`)的 47 条数据列表、点线路 / 分组 / 标签状态的图上标注、`点击时居中` 与 `显示编号` 开关、清空标注;三个页面都跑在 iframe 里,要用 dev server 打开。
|
|
124
124
|
|
|
125
125
|
上一轮补上的两组断言:`selftest-features.html` 新增 8 条 —— 3 条验 `channelSelectMode` 在 Ctrl + 点击加点后的高亮范围(`line` / `group` / `channel`),5 条验分组 `channelWaypointDragMode: 'vertex'`(`{ x, y }` 偏移归一化并参与实际路由、同组同序号拐点按世界增量平移、相邻拐点与其它分组不动、只写 `waypointOffsets` 不改公共 `path`、`parallel_groups.group_route` 带刚性偏移)。`selftest-demos.html` 新增 1 条,验通道演示页可切到 `vertex`,且「准备两分组拐点」会拆成两组、每组两个拐点。
|
|
126
126
|
|
|
@@ -130,6 +130,8 @@ API 名字与前面几步是一一对应的;第 11 步再补两件「数据之
|
|
|
130
130
|
|
|
131
131
|
本轮补上的断言:`selftest-demos.html` 321 → **333** 条,新增「接口能力」页的 12 条 —— 三种级联触发默认值与单独关闭、通道 / 分组 / 拐点 `selectFeatures`、`selectWaypoint` 补点并选中线路、`lineFollowsNode` 隐藏端点对照、通道 `focusOn`,以及样式字段合并、装饰 CRUD、通道线宽 / 线路对账、GeoJSON 背景投影、历史 / 复制 / 删除收尾、`once` / WebGL / 注册表 / 初始化 options 读数。`selftest-scale.html` 保持 109 PASS + 6 DIAG:`fitSpacing` 三条断言改为验证「比例提高但中心保持普通适应中心」,无筛选的 `visible: false` 联动对照组显式写 `lineFollowsNode: false`。
|
|
132
132
|
|
|
133
|
+
本轮补上的断言:`selftest-features.html` 新增 11 条,覆盖 `beginAddLine` 不因 `singleChannel` 阻断、`singleChannel` / `existingChannel: 'block'` 的 `blocked` 与失败事件、`newGroup`、`joinGroup + groupId`、`beginAddLine + joinGroup` 挂已有通道、`auto` 策略,以及 `splitPoint({ autoLines: 'alternate' })` 按通道成组分配与 `lineAssignments` 读数;`selftest-demos.html` 新增 8 条,覆盖 ConnectDemo 的预置已有通道、策略 / 目标分组控件和 blocked 读数,CopyMergeDemo 的「解除合并」按钮、`autoLines: 'alternate'`、自动分线数及通道成组读数。
|
|
134
|
+
|
|
133
135
|
这些页面都要用 dev server 打开(第 10 ~ 13 步与 demo 自测要加载 `src/gis-view` 的 CSS;`selftest-demo.html` 会把 7 MB 的 `new.json` 与样例数据都加载一遍),页面底部会打印 PASS / FAIL。
|
|
134
136
|
|
|
135
137
|
## 和库里文件的对照
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
else if (name === 'addChannel') {
|
|
238
238
|
// 新增通道(每次新建一条两回的通道):走 uniqueLineId 查重与通道声明整份重排
|
|
239
239
|
const data = view.getData()
|
|
240
|
-
view.addChannel({ from: data.points[0].id, to: data.points[1].id,
|
|
240
|
+
view.addChannel({ from: data.points[0].id, to: data.points[1].id }, [{}, {}])
|
|
241
241
|
}
|
|
242
242
|
return +(now() - started).toFixed(1)
|
|
243
243
|
},
|
package/docs/steps/index.html
CHANGED
|
@@ -265,7 +265,7 @@
|
|
|
265
265
|
{ file: 'step-09-minimap.js', factory: 'createMinimapView', load: () => import('./step-09-minimap.js'), title: '鹰眼图', api: '小图 + 视口框', note: '小画布画全景、DOM 画视口框、点与拖都能联动主图(文档第 8 章)' },
|
|
266
266
|
{ file: 'step-10-full.js', factory: 'createFullView', load: () => import('./step-10-full.js'), title: '换成真组件', api: 'createGisView', note: '同一份数据换成 src/gis-view 的完整实现,API 与前面几步一一对应(文档 12.11)' },
|
|
267
267
|
{ file: 'step-11-background.js', factory: 'createBackgroundView', load: () => import('./step-11-background.js'), title: '背景层与初始视图', api: 'background / initialView / applyInitialView', note: '底图走 background.geoJson(几何与 demo 共用同一份生成器),最后一档换成 SVG 路径图片(background.image 只给 d 字符串);GeoJSON 还演示 aspectScale、逐区域配色(regions / itemStyle)与区域文字(label)。首屏落位走 initialView:默认聚焦数据中心放大 1.8 倍,不再一上来铺满整屏(GisView.md:背景层 / 初始视图)' },
|
|
268
|
-
{ file: 'step-12-events.js', factory: 'createActionView', load: () => import('./step-12-events.js'), title: '事件的动作判读与只读查询', api: 'action / pickAt / getFeaturesInRect / hoverAt', note: '每一条指针事件都带 action:type 是操作(按下时是意图、松开时是刚做完的那件事、点击与右键是真正发生的那一件)、target 是点到了什么(通道回线单独给 channel
|
|
268
|
+
{ file: 'step-12-events.js', factory: 'createActionView', load: () => import('./step-12-events.js'), title: '事件的动作判读与只读查询', api: 'action / pickAt / getFeaturesInRect / hoverAt', note: '每一条指针事件都带 action:type 是操作(按下时是意图、松开时是刚做完的那件事、点击与右键是真正发生的那一件)、target 是点到了什么(通道回线单独给 channel)、命中的数据直接读载荷顶层(节点 / 线路 item、通道 channel、标签 label),moved / double / press / duration / longPress 是同一份操作判读;按键、修饰键与 clientX / clientY 读 originalEvent(中键就是 originalEvent.button === 1,长按按 action.longPress 认),选中集读数用 getSelectionInfo();两个只读查询 pickAt(鼠标坐标问「这儿是什么」)与 getFeaturesInRect(画布矩形里有什么,与框选同一套判定),再加程序化悬停 hoverAt / clearHover / getHover(把鼠标停到「程序化悬停」按钮上试试)。点一下、框一下、右键一下,读数栏的「判读」都会跟着换(GisView.md:action:一次操作的判读 / 实例方法)' },
|
|
269
269
|
{ file: 'step-13-engineering.js', factory: 'createEngineeringView', load: () => import('./step-13-engineering.js'), title: '工程化四件套', api: 'quality / batch / history / features', note: '上线前要配的四项:画质四档(setQuality / getQuality,换档只影响绘制,不重排、不动数据)、batch(一批改动作一条 onDataChange 与一步历史,一千次 updatePoint 也只算一步)、history(undo / redo / getHistoryState,Ctrl+Z / Ctrl+Shift+Z 也接上;缺省是关的,这一步显式打开)、features(edit 全开 / view 只读 / static 静态图三个预设,一次切好交互口径)。工具条的「画质档」「批量移动」「撤销 / 重做」「功能预设」逐个点点,读数栏最后三行跟着换(GisView.md:画质 / 批量更新 / 历史 / 功能开关)' }
|
|
270
270
|
]
|
|
271
271
|
|
|
@@ -359,12 +359,12 @@
|
|
|
359
359
|
},
|
|
360
360
|
onDblClick: payload => log('onDblClick', describeElement(payload)),
|
|
361
361
|
onSelect: payload => log('onSelect', payload ? `${payload.items.length} 个要素` : '清空选中'),
|
|
362
|
-
onPointerDown:
|
|
363
|
-
setReadout('pointer', `按下:${describeElement(payload)}(button ${
|
|
362
|
+
onPointerDown: payload => {
|
|
363
|
+
setReadout('pointer', `按下:${describeElement(payload)}(button ${payload.originalEvent?.button})`)
|
|
364
364
|
},
|
|
365
|
-
onPointerUp:
|
|
366
|
-
onContextMenu:
|
|
367
|
-
|
|
365
|
+
onPointerUp: payload => log('onPointerUp', `${describeElement(payload)}(button ${payload.originalEvent?.button})`),
|
|
366
|
+
onContextMenu: payload => {
|
|
367
|
+
payload.originalEvent?.preventDefault()
|
|
368
368
|
log('onContextMenu', describeElement(payload))
|
|
369
369
|
},
|
|
370
370
|
// 需求 1 的核心:草稿里每点一次都回调,第一次拿起点、第二次拿终点
|