gis-view-webgl2 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -8
- package/dist/gis-view.css +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +781 -246
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +129 -0
- package/docs/GisView.md +9 -8
- package/docs/GisView/345/256/236/347/216/260/345/216/237/347/220/206.md +2 -2
- package/docs/ai/06-/344/274/232/350/257/235/347/264/242/345/274/225/344/270/216/345/244/215/346/237/245/346/226/271/346/263/225.md +114 -0
- package/docs/api/index.html +545 -59
- package/docs/demos/BackendSyncDemo.vue +10 -8
- package/docs/demos/BasicDemo.vue +101 -101
- package/docs/demos/BatchAddDemo.vue +5 -5
- package/docs/demos/ChannelDemo.vue +51 -4
- package/docs/demos/ConnectDemo.vue +392 -0
- package/docs/demos/CopyMergeDemo.vue +936 -936
- package/docs/demos/DecorationDraftDemo.vue +1300 -0
- package/docs/demos/DemoShell.vue +569 -240
- package/docs/demos/DragDropDemo.vue +11 -11
- package/docs/demos/EffectsDemo.vue +6 -6
- package/docs/demos/EventDemo.vue +327 -327
- package/docs/demos/ExtensionDemo.vue +458 -0
- package/docs/demos/GisViewDemo.vue +61 -48
- package/docs/demos/GraphicDemo.vue +338 -0
- package/docs/demos/LabelDemo.vue +509 -509
- package/docs/demos/MinimapDemo.vue +358 -0
- package/docs/demos/PerfDemo.vue +29 -0
- package/docs/demos/SearchFilterDemo.vue +412 -0
- package/docs/demos/StyleDemo.vue +121 -121
- package/docs/demos/api-index.js +87 -76
- package/docs/demos/demos.js +159 -135
- package/docs/demos/shared/demoData.js +107 -107
- package/docs/demos/shared/demoStyle.css +249 -249
- package/docs/demos/shared/fakeBackend.js +93 -6
- package/docs/format/03-/346/213/220/347/202/271/350/243/205/351/245/260/344/270/216/346/240/267/345/274/217.md +24 -6
- package/docs/format/06-/345/257/274/345/205/245/345/257/274/345/207/272/344/270/216/346/240/207/345/207/206/346/226/207/346/241/243.md +8 -6
- package/docs/format/07-/344/272/213/344/273/266/350/275/275/350/215/267/344/270/216/347/244/272/344/276/213/346/225/260/346/215/256.md +6 -6
- package/docs/guide/sample-document.html +4 -4
- package/docs/index.html +180 -9
- package/docs/internals/11-/350/246/206/347/233/226/345/261/202/346/240/207/347/255/276/344/270/216/346/217/220/347/244/272.md +1 -1
- package/docs/internals/13-/351/271/260/347/234/274/345/233/276.md +3 -2
- package/docs/internals/15-03-/351/200/220/350/275/256/350/256/260/345/275/225-/346/200/247/350/203/275/344/270/216/344/277/256/345/244/215-/344/270/213.md +16 -0
- package/docs/internals/16-03-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/213.md +11 -0
- package/docs/internals/17-/350/260/203/350/257/225/344/270/216/346/211/251/345/261/225/345/273/272/350/256/256.md +1 -1
- package/docs/manual/02-/345/235/220/346/240/207/344/270/216/346/225/260/346/215/256.md +11 -2
- package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +89 -20
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +13 -8
- package/docs/manual/06-/346/225/260/346/215/256/344/270/216/345/234/272/346/231/257/346/233/264/346/226/260.md +11 -10
- package/docs/manual/07-/346/214/207/351/222/210/344/270/216/350/246/201/347/264/240/347/274/226/350/276/221.md +9 -9
- package/docs/manual/08-/351/200/211/344/270/255/344/270/216/346/213/220/347/202/271.md +13 -11
- package/docs/manual/09-/351/200/232/351/201/223/344/270/216/345/244/232/345/233/236/347/272/277.md +3 -3
- package/docs/manual/10-/351/200/232/351/201/223/347/274/226/350/276/221/344/270/216/346/226/260/345/242/236.md +47 -5
- package/docs/manual/11-/346/240/267/345/274/217/344/270/216/350/247/204/345/210/231.md +3 -2
- package/docs/manual/12-/346/240/207/347/255/276/344/270/216/350/243/205/351/245/260.md +215 -2
- package/docs/manual/13-/345/212/250/346/225/210/344/270/216/345/233/276/345/205/203.md +6 -5
- package/docs/manual/14-/350/247/206/345/233/276/344/270/216/347/255/233/351/200/211.md +27 -14
- package/docs/manual/15-/345/257/274/345/207/272/344/270/216/351/233/206/346/210/220.md +142 -49
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +25 -29
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +47 -39
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +161 -64
- package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +4 -4
- package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +39 -2
- package/docs/manual/21-/350/257/264/346/230/216/344/270/216/345/270/270/350/247/201/351/227/256/351/242/230.md +21 -5
- package/docs/playground/index.html +5 -5
- package/docs/steps/README.md +12 -10
- package/docs/steps/check-doc-truth.mjs +1 -1
- package/docs/steps/selftest-actions.html +10 -10
- package/docs/steps/selftest-data.html +96 -14
- package/docs/steps/selftest-decoration.html +577 -0
- package/docs/steps/selftest-demo.html +6 -5
- package/docs/steps/selftest-demos.html +2048 -1624
- package/docs/steps/selftest-docs.html +86 -14
- package/docs/steps/selftest-effects.html +5 -5
- package/docs/steps/selftest-features.html +544 -85
- package/docs/steps/selftest-full.html +583 -583
- package/docs/steps/selftest-labels.html +797 -660
- package/docs/steps/selftest-perf.html +1899 -1844
- package/docs/steps/selftest-scale.html +117 -7
- package/docs/steps/selftest-select.html +24 -17
- package/docs/steps/step-10-full.js +1 -1
- package/docs//346/216/245/345/217/243/345/215/217/350/256/256.md +151 -7
- package/docs//346/225/260/346/215/256/346/240/274/345/274/217.md +1 -1
- package/package.json +42 -42
- package/docs/demos/HistoryDemo.vue +0 -230
- package/docs/demos/InterfaceDemo.vue +0 -309
- package/docs/demos/SampleDemo.vue +0 -283
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* 推送策略(这一轮新增):「攒批」是缺省 —— 改动只进队列,点提交 / 整份保存时一次发;「改完就传」
|
|
34
34
|
* 落地就发,但同一目标的中间态只留最后一份(合并),拖拽只在 phase === 'end' 发一条。画布上的拖节点 /
|
|
35
35
|
* 拖拐点也接进同一套:onPointDrag / onWaypointChange 里按 phase 过滤,中间态一条请求都不发。
|
|
36
|
-
* 「视口导出」那一块是
|
|
36
|
+
* 「视口导出」那一块是 exportData({ scope: 'viewport' }):只取屏幕上看得见的那一撮(节点 / 线路 / 通道 + 拐点分组)。
|
|
37
37
|
*/
|
|
38
38
|
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
|
|
39
39
|
import { createGisView } from '../../src/index.js'
|
|
@@ -749,19 +749,21 @@ const pullServer = () => {
|
|
|
749
749
|
pushLog(result.ok ? `importData:服务端那一份已回灌(${data.points.length} 节点 / ${data.lines.length} 线路 / ${(view.getOptions().channels ?? []).length} 通道)` : `importData 没吃下服务端那一份:${result.reason ?? ''}`)
|
|
750
750
|
}
|
|
751
751
|
|
|
752
|
-
/** 视口导出:只取屏幕上看得见的那一撮(
|
|
752
|
+
/** 视口导出:只取屏幕上看得见的那一撮(exportData · scope: viewport) */
|
|
753
753
|
const exportViewport = (format) => {
|
|
754
|
-
const
|
|
754
|
+
const range = Number(margin.value) || 0
|
|
755
|
+
const result = view.exportData({ scope: 'viewport', margin: range, format })
|
|
755
756
|
const counts = result.counts ?? {}
|
|
756
|
-
|
|
757
|
+
const viewRect = result.viewRect ?? view.getViewRect()
|
|
758
|
+
viewportText.value = `${format === 'input' ? 'input 口径' : '业务口径'}:${counts.points ?? 0} 节点 / ${counts.lines ?? 0} 线路 / ${counts.channels ?? 0} 通道 / ${counts.parallelGroups ?? 0} 拐点分组 · margin ${result.margin ?? range}px`
|
|
757
759
|
viewportSample.value = shortJson({
|
|
758
760
|
counts: result.counts,
|
|
759
|
-
viewRect
|
|
761
|
+
viewRect,
|
|
760
762
|
...(format === 'input'
|
|
761
763
|
? { points: (result.points ?? []).map(point => point.id), lines: (result.lines ?? []).map(line => line.id), channels: (result.channels ?? []).map(channel => channel.id) }
|
|
762
764
|
: { parallelGroups: result.parallelGroups ?? [] })
|
|
763
765
|
}, 2000)
|
|
764
|
-
pushLog(`
|
|
766
|
+
pushLog(`exportData({ scope: 'viewport', format: '${format}', margin: ${result.margin ?? range} }):${counts.points ?? 0} 节点 / ${counts.lines ?? 0} 线路 / ${counts.channels ?? 0} 通道`)
|
|
765
767
|
}
|
|
766
768
|
|
|
767
769
|
onMounted(() => {
|
|
@@ -1049,7 +1051,7 @@ PUT /gis/documents
|
|
|
1049
1051
|
</div>
|
|
1050
1052
|
|
|
1051
1053
|
<div class="dv-group">
|
|
1052
|
-
<h3>视口内导出(
|
|
1054
|
+
<h3>视口内导出(exportData · scope: viewport)</h3>
|
|
1053
1055
|
<div class="dv-row">
|
|
1054
1056
|
<label>margin <input v-model.number="margin" type="number" step="8" min="0" data-demo="sync-margin" /></label>
|
|
1055
1057
|
<button type="button" class="dv-button" data-demo="sync-export-view" @click="exportViewport('view')">业务口径</button>
|
|
@@ -1057,7 +1059,7 @@ PUT /gis/documents
|
|
|
1057
1059
|
</div>
|
|
1058
1060
|
<p class="dv-readout" data-demo="sync-viewport-text">{{ viewportText }}</p>
|
|
1059
1061
|
<pre class="bs-json" data-demo="sync-viewport-sample">{{ viewportSample }}</pre>
|
|
1060
|
-
<p class="dv-hint">`view.
|
|
1062
|
+
<p class="dv-hint">`view.exportData({ scope: 'viewport', margin })`:只出屏幕上看得见的那一撮 —— 节点按中心、线路按包围盒、通道跟着成员回线走(分组不拆散);margin 是屏幕 CSS 像素的外扩。业务口径另带 `viewRect` / `margin`,input / full / 自定义格式保持导出器原始结果。</p>
|
|
1061
1063
|
</div>
|
|
1062
1064
|
|
|
1063
1065
|
<div class="dv-group">
|
package/docs/demos/BasicDemo.vue
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
/**
|
|
3
|
-
* 基础视图:一份数据 + 最少的配置,重点看相机与拾取这两组读数怎么拿。
|
|
4
|
-
*
|
|
5
|
-
* 面板上就四个开关(数据量 / 网格 / 节点标签 / 通道),读数栏把
|
|
6
|
-
* onCameraChange / onClick / onSelect / onStats 的值直接摊开 ——
|
|
7
|
-
* 事件载荷长什么样、什么时候发,一眼能对上。
|
|
8
|
-
*/
|
|
9
|
-
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
|
10
|
-
import { createGisView } from '../../src/index.js'
|
|
11
|
-
import { buildDemoData } from './shared/demoData.js'
|
|
12
|
-
import './shared/demoStyle.css'
|
|
13
|
-
|
|
14
|
-
const emit = defineEmits(['notice'])
|
|
15
|
-
const container = ref(null)
|
|
16
|
-
const pointCount = ref(28)
|
|
17
|
-
const gridOn = ref(true)
|
|
18
|
-
const labelOn = ref(true)
|
|
19
|
-
const channelOn = ref(true)
|
|
1
|
+
<script setup>
|
|
2
|
+
/**
|
|
3
|
+
* 基础视图:一份数据 + 最少的配置,重点看相机与拾取这两组读数怎么拿。
|
|
4
|
+
*
|
|
5
|
+
* 面板上就四个开关(数据量 / 网格 / 节点标签 / 通道),读数栏把
|
|
6
|
+
* onCameraChange / onClick / onSelect / onStats 的值直接摊开 ——
|
|
7
|
+
* 事件载荷长什么样、什么时候发,一眼能对上。
|
|
8
|
+
*/
|
|
9
|
+
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
|
10
|
+
import { createGisView } from '../../src/index.js'
|
|
11
|
+
import { buildDemoData } from './shared/demoData.js'
|
|
12
|
+
import './shared/demoStyle.css'
|
|
13
|
+
|
|
14
|
+
const emit = defineEmits(['notice'])
|
|
15
|
+
const container = ref(null)
|
|
16
|
+
const pointCount = ref(28)
|
|
17
|
+
const gridOn = ref(true)
|
|
18
|
+
const labelOn = ref(true)
|
|
19
|
+
const channelOn = ref(true)
|
|
20
20
|
const readouts = ref({ camera: '—', pick: '未选中', stats: '—', event: '—' })
|
|
21
21
|
let dataset = buildDemoData({ count: 28 })
|
|
22
22
|
let view = null
|
|
@@ -69,10 +69,10 @@ const buildOptions = () => ({
|
|
|
69
69
|
// 功能开关缺省全关:这一页要能平移缩放、能悬停选中,显式打开查看类(见 docs/GisView.md 的「功能开关」)
|
|
70
70
|
features: 'view',
|
|
71
71
|
label: labelOptions(),
|
|
72
|
-
onReady: () => {
|
|
73
|
-
emit('notice', `已加载 ${dataset.points.length} 个节点 / ${dataset.lines.length} 条线路`)
|
|
74
|
-
readouts.value = { ...readouts.value, event: 'ready:WebGL2 上下文就绪' }
|
|
75
|
-
},
|
|
72
|
+
onReady: () => {
|
|
73
|
+
emit('notice', `已加载 ${dataset.points.length} 个节点 / ${dataset.lines.length} 条线路`)
|
|
74
|
+
readouts.value = { ...readouts.value, event: 'ready:WebGL2 上下文就绪' }
|
|
75
|
+
},
|
|
76
76
|
onClick: (payload) => {
|
|
77
77
|
readouts.value = { ...readouts.value, pick: describeTarget(payload), event: `click:${describeTarget(payload)}` }
|
|
78
78
|
},
|
|
@@ -86,10 +86,10 @@ const buildOptions = () => ({
|
|
|
86
86
|
event: count ? `select:${mode} 选中 ${count} 个` : 'select:清空选中'
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
|
-
onCameraChange: (camera) => {
|
|
90
|
-
// 相机每帧都在变:只把读数写进面板,不再触发别的重活
|
|
91
|
-
readouts.value = { ...readouts.value, camera: `scale ${camera.scale.toPrecision(4)} px/单位 · 中心 ${camera.center[0].toFixed(3)}, ${camera.center[1].toFixed(3)}` }
|
|
92
|
-
},
|
|
89
|
+
onCameraChange: (camera) => {
|
|
90
|
+
// 相机每帧都在变:只把读数写进面板,不再触发别的重活
|
|
91
|
+
readouts.value = { ...readouts.value, camera: `scale ${camera.scale.toPrecision(4)} px/单位 · 中心 ${camera.center[0].toFixed(3)}, ${camera.center[1].toFixed(3)}` }
|
|
92
|
+
},
|
|
93
93
|
onStats: (next) => {
|
|
94
94
|
// fps 每帧都变,节流后再写响应式数据(十万级数据下每帧重渲染面板本身也是开销)
|
|
95
95
|
const now = performance.now()
|
|
@@ -101,23 +101,23 @@ const buildOptions = () => ({
|
|
|
101
101
|
const speed = next.idle ? '空闲' : `${Math.round(next.fps)} fps`
|
|
102
102
|
readouts.value = { ...readouts.value, stats: `${speed} · 最近一帧 ${next.frameMs.toFixed(2)} ms · ${next.pointCount.toLocaleString()} 点 / ${next.lineCount.toLocaleString()} 线` }
|
|
103
103
|
},
|
|
104
|
-
onWarning: (text) => {
|
|
105
|
-
readouts.value = { ...readouts.value, event: `warning:${text}` }
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
/** 换数据量:数据与通道一起换掉,相机重新适应(不改选项里的样式,所以点位外观不跳) */
|
|
110
|
-
const applyData = () => {
|
|
111
|
-
if (!view) {
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
dataset = buildDemoData({ count: pointCount.value })
|
|
115
|
-
view.updateData(dataset.points, channelOn.value ? dataset.lines : dataset.linesWithoutChannel)
|
|
116
|
-
view.updateOptions({ channels: channelOn.value ? dataset.channels : [] })
|
|
117
|
-
view.fitView(40)
|
|
118
|
-
emit('notice', `已换成 ${dataset.points.length} 个节点 / ${dataset.lines.length} 条线路`)
|
|
119
|
-
}
|
|
120
|
-
|
|
104
|
+
onWarning: (text) => {
|
|
105
|
+
readouts.value = { ...readouts.value, event: `warning:${text}` }
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
/** 换数据量:数据与通道一起换掉,相机重新适应(不改选项里的样式,所以点位外观不跳) */
|
|
110
|
+
const applyData = () => {
|
|
111
|
+
if (!view) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
dataset = buildDemoData({ count: pointCount.value })
|
|
115
|
+
view.updateData(dataset.points, channelOn.value ? dataset.lines : dataset.linesWithoutChannel)
|
|
116
|
+
view.updateOptions({ channels: channelOn.value ? dataset.channels : [] })
|
|
117
|
+
view.fitView(40)
|
|
118
|
+
emit('notice', `已换成 ${dataset.points.length} 个节点 / ${dataset.lines.length} 条线路`)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
121
|
/**
|
|
122
122
|
* 开关键:只改与自己相关的那几项 —— 一次「把整份 options 再发一遍」会连数据一起重发,
|
|
123
123
|
* 拖过的节点与标签偏移都会被冲回原样,这里只改网格与标签两项。
|
|
@@ -133,15 +133,15 @@ const applyChannel = () => {
|
|
|
133
133
|
channels: channelOn.value ? dataset.channels : []
|
|
134
134
|
})
|
|
135
135
|
}
|
|
136
|
-
|
|
137
|
-
const resetCamera = () => {
|
|
138
|
-
view?.fitView(40)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const zoomBy = (factor) => {
|
|
142
|
-
view?.zoomBy(factor)
|
|
143
|
-
}
|
|
144
|
-
|
|
136
|
+
|
|
137
|
+
const resetCamera = () => {
|
|
138
|
+
view?.fitView(40)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const zoomBy = (factor) => {
|
|
142
|
+
view?.zoomBy(factor)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
145
|
onMounted(() => {
|
|
146
146
|
view = createGisView(container.value, buildOptions())
|
|
147
147
|
// 标签拖动:面板上给一行「偏移记在状态里」的读数,松手后偏移一直留在 getLabelStates() 里
|
|
@@ -152,52 +152,52 @@ onMounted(() => {
|
|
|
152
152
|
readouts.value = { ...readouts.value, event: `labelDrag:${payload.phase} · ${payload.id ?? payload.index} 偏移 [${payload.offset.map(value => Math.round(value)).join(', ')}]` }
|
|
153
153
|
})
|
|
154
154
|
})
|
|
155
|
-
|
|
156
|
-
onBeforeUnmount(() => {
|
|
157
|
-
view?.destroy()
|
|
158
|
-
view = null
|
|
159
|
-
})
|
|
160
|
-
</script><template>
|
|
161
|
-
<section class="dv-demo">
|
|
162
|
-
<div class="dv-stage">
|
|
163
|
-
<div ref="container" class="dv-canvas"></div>
|
|
164
|
-
<div class="dv-toolbar">
|
|
165
|
-
<button type="button" @click="resetCamera">适应全部</button>
|
|
166
|
-
<button type="button" @click="zoomBy(1.4)">放大</button>
|
|
167
|
-
<button type="button" @click="zoomBy(1 / 1.4)">缩小</button>
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
170
|
-
<aside class="dv-panel">
|
|
171
|
-
<div class="dv-group">
|
|
172
|
-
<h3>数据</h3>
|
|
173
|
-
<div class="dv-row">
|
|
174
|
-
<label>节点数
|
|
175
|
-
<select v-model.number="pointCount" @change="applyData">
|
|
176
|
-
<option :value="12">12</option>
|
|
177
|
-
<option :value="28">28</option>
|
|
178
|
-
<option :value="60">60</option>
|
|
179
|
-
</select>
|
|
180
|
-
</label>
|
|
181
|
-
<button type="button" class="dv-button" @click="applyData">重建数据</button>
|
|
182
|
-
</div>
|
|
183
|
-
<div class="dv-row">
|
|
184
|
-
<label><input v-model="gridOn" type="checkbox" @change="applyOptions" /> 网格</label>
|
|
185
|
-
<label><input v-model="labelOn" type="checkbox" @change="applyOptions" /> 节点标签</label>
|
|
155
|
+
|
|
156
|
+
onBeforeUnmount(() => {
|
|
157
|
+
view?.destroy()
|
|
158
|
+
view = null
|
|
159
|
+
})
|
|
160
|
+
</script><template>
|
|
161
|
+
<section class="dv-demo">
|
|
162
|
+
<div class="dv-stage">
|
|
163
|
+
<div ref="container" class="dv-canvas"></div>
|
|
164
|
+
<div class="dv-toolbar">
|
|
165
|
+
<button type="button" @click="resetCamera">适应全部</button>
|
|
166
|
+
<button type="button" @click="zoomBy(1.4)">放大</button>
|
|
167
|
+
<button type="button" @click="zoomBy(1 / 1.4)">缩小</button>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
<aside class="dv-panel">
|
|
171
|
+
<div class="dv-group">
|
|
172
|
+
<h3>数据</h3>
|
|
173
|
+
<div class="dv-row">
|
|
174
|
+
<label>节点数
|
|
175
|
+
<select v-model.number="pointCount" @change="applyData">
|
|
176
|
+
<option :value="12">12</option>
|
|
177
|
+
<option :value="28">28</option>
|
|
178
|
+
<option :value="60">60</option>
|
|
179
|
+
</select>
|
|
180
|
+
</label>
|
|
181
|
+
<button type="button" class="dv-button" @click="applyData">重建数据</button>
|
|
182
|
+
</div>
|
|
183
|
+
<div class="dv-row">
|
|
184
|
+
<label><input v-model="gridOn" type="checkbox" @change="applyOptions" /> 网格</label>
|
|
185
|
+
<label><input v-model="labelOn" type="checkbox" @change="applyOptions" /> 节点标签</label>
|
|
186
186
|
<label><input v-model="channelOn" type="checkbox" @change="applyChannel" /> 通道</label>
|
|
187
|
-
</div>
|
|
188
|
-
<p class="dv-hint">打开标签后可以拖着标签走一段:松手后偏移记在状态里,再移动节点标签跟着走。</p>
|
|
189
|
-
</div>
|
|
190
|
-
<div class="dv-group">
|
|
191
|
-
<h3>读数</h3>
|
|
192
|
-
<p class="dv-readout">相机:{{ readouts.camera }}</p>
|
|
193
|
-
<p class="dv-readout">拾取:{{ readouts.pick }}</p>
|
|
194
|
-
<p class="dv-readout">性能:{{ readouts.stats }}</p>
|
|
195
|
-
<p class="dv-readout">事件:{{ readouts.event }}</p>
|
|
196
|
-
</div>
|
|
197
|
-
<div class="dv-group">
|
|
198
|
-
<h3>试一下</h3>
|
|
199
|
-
<p class="dv-hint">单击节点 / 线路 / 通道看「拾取」;空白处拖框看「选中」;滚轮缩放、拖动平移时看相机的 scale 与中心。</p>
|
|
200
|
-
</div>
|
|
201
|
-
</aside>
|
|
202
|
-
</section>
|
|
203
|
-
</template>
|
|
187
|
+
</div>
|
|
188
|
+
<p class="dv-hint">打开标签后可以拖着标签走一段:松手后偏移记在状态里,再移动节点标签跟着走。</p>
|
|
189
|
+
</div>
|
|
190
|
+
<div class="dv-group">
|
|
191
|
+
<h3>读数</h3>
|
|
192
|
+
<p class="dv-readout">相机:{{ readouts.camera }}</p>
|
|
193
|
+
<p class="dv-readout">拾取:{{ readouts.pick }}</p>
|
|
194
|
+
<p class="dv-readout">性能:{{ readouts.stats }}</p>
|
|
195
|
+
<p class="dv-readout">事件:{{ readouts.event }}</p>
|
|
196
|
+
</div>
|
|
197
|
+
<div class="dv-group">
|
|
198
|
+
<h3>试一下</h3>
|
|
199
|
+
<p class="dv-hint">单击节点 / 线路 / 通道看「拾取」;空白处拖框看「选中」;滚轮缩放、拖动平移时看相机的 scale 与中心。</p>
|
|
200
|
+
</div>
|
|
201
|
+
</aside>
|
|
202
|
+
</section>
|
|
203
|
+
</template>
|
|
@@ -74,7 +74,7 @@ const addPointBatch = () => runAction('addPoints', () => {
|
|
|
74
74
|
}))
|
|
75
75
|
const result = view.addPoints(items)
|
|
76
76
|
if (result.ok) {
|
|
77
|
-
view.
|
|
77
|
+
view.selectFeatures(result.items.map(item => item.id))
|
|
78
78
|
}
|
|
79
79
|
return `addPoints → ${result.count} 个节点 · indexes=[${result.indexes.join(', ')}]`
|
|
80
80
|
})
|
|
@@ -95,7 +95,7 @@ const addLineBatch = () => runAction('addLines', () => {
|
|
|
95
95
|
]
|
|
96
96
|
const result = view.addLines(items)
|
|
97
97
|
if (result.ok) {
|
|
98
|
-
view.
|
|
98
|
+
view.selectFeatures(result.items.map(item => item.id))
|
|
99
99
|
}
|
|
100
100
|
return `addLines → ${result.count} 条线路 · ${items.map(item => item.name).join(' / ')}`
|
|
101
101
|
})
|
|
@@ -133,7 +133,7 @@ const addChannelBatch = () => runAction('addChannels', () => {
|
|
|
133
133
|
lineProps: { vn_kv: 230, max_loading_rate: 0.61 }
|
|
134
134
|
}
|
|
135
135
|
])
|
|
136
|
-
view.
|
|
136
|
+
view.selectFeatures(result.lineIds)
|
|
137
137
|
return `addChannels → ${result.count} 条通道 · ${result.channelIds.join(' / ')} · ${result.lineIds.length} 条回线`
|
|
138
138
|
})
|
|
139
139
|
|
|
@@ -162,7 +162,7 @@ const addWaypointBatch = () => runAction('addWaypoints', () => {
|
|
|
162
162
|
[Number((from.x + dx * 0.72 + normal[0] * 0.08).toFixed(5)), Number((from.y + dy * 0.72 + normal[1] * 0.08).toFixed(5))]
|
|
163
163
|
]
|
|
164
164
|
const result = view.addWaypoints(line.id, coordinates)
|
|
165
|
-
view.
|
|
165
|
+
view.selectFeatures(line.id)
|
|
166
166
|
return result.ok
|
|
167
167
|
? `addWaypoints → ${result.count} 个拐点 · ${line.id} · ${JSON.stringify(result.coordinates)}`
|
|
168
168
|
: `addWaypoints 没有落地:${result.reason}`
|
|
@@ -205,7 +205,7 @@ const addChannelGroupBatch = () => runAction('addChannelGroups', () => {
|
|
|
205
205
|
}
|
|
206
206
|
]
|
|
207
207
|
const result = view.addChannelGroups(channel.id, groups)
|
|
208
|
-
view.
|
|
208
|
+
view.selectFeatures(result.lineIds)
|
|
209
209
|
return result.ok
|
|
210
210
|
? `addChannelGroups → ${result.count} 组 / ${result.lineIds.length} 条回线 · ${result.groupIds.join(' / ')}`
|
|
211
211
|
: `addChannelGroups 没有落地:${result.reason}`
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
* 确认之后才动数据(组件不弹界面,框是这一页自己按载荷画的)。
|
|
15
15
|
* - 导出:`exportData({ format: 'input' })` 拿回与输入同构的一份数据(含通道与拐点),
|
|
16
16
|
* 点「按导出重建」就把它喂回 `updateData` + `updateOptions` —— 导出再导入即回显;
|
|
17
|
-
* 旁边一并给一份 `format: 'view'` 的业务口径(line_data / parallel_groups
|
|
17
|
+
* 旁边一并给一份 `format: 'view'` 的业务口径(line_data / parallel_groups 那套列名);
|
|
18
|
+
* 「后端 DTO」按钮演示 `defineExportFormat` 带作用域注册的项目自定义格式。
|
|
18
19
|
*/
|
|
19
20
|
import { computed, onBeforeUnmount, onMounted, ref, shallowRef } from 'vue'
|
|
20
|
-
import { createGisView } from '../../src/index.js'
|
|
21
|
+
import { createGisView, defineExportFormat, listExportFormats } from '../../src/index.js'
|
|
21
22
|
import { buildDemoData } from './shared/demoData.js'
|
|
22
23
|
import { createFakeBackend, cloneFakeData, FAKE_BACKEND_MODES } from './shared/fakeBackend.js'
|
|
23
24
|
import './shared/demoStyle.css'
|
|
@@ -49,6 +50,35 @@ const backendLastSuccess = shallowRef(null)
|
|
|
49
50
|
const backendLogLines = ref([])
|
|
50
51
|
const waypointSyncText = ref('拐点 / 分组同步:—')
|
|
51
52
|
const fakeBackend = createFakeBackend({ initialVersion: 8, latency: 420, prefix: 'channel' })
|
|
53
|
+
const DTO_FORMAT = 'channel-backend-dto'
|
|
54
|
+
let disposeDtoFormat = null
|
|
55
|
+
/** 自定义导出格式:只把标准文档映射成这一页后端要的列名,不碰组件内部数组 */
|
|
56
|
+
const backendDtoAdapter = ({ document: source, counts }) => ({
|
|
57
|
+
schema: 'gis-view.channel-demo.v1',
|
|
58
|
+
counts,
|
|
59
|
+
camera: source.view?.camera ?? null,
|
|
60
|
+
stations: source.points.map(point => ({
|
|
61
|
+
station_id: point.id,
|
|
62
|
+
station_name: point.name ?? '',
|
|
63
|
+
x: point.x,
|
|
64
|
+
y: point.y
|
|
65
|
+
})),
|
|
66
|
+
routes: source.lines.map(line => ({
|
|
67
|
+
route_id: line.id,
|
|
68
|
+
from: line.from ?? null,
|
|
69
|
+
to: line.to ?? null,
|
|
70
|
+
coords: line.path ?? []
|
|
71
|
+
})),
|
|
72
|
+
channels: source.channels.map(channel => ({
|
|
73
|
+
channel_id: channel.id,
|
|
74
|
+
channel_name: channel.name ?? '',
|
|
75
|
+
groups: (channel.groups ?? []).map(group => ({
|
|
76
|
+
group_id: group.id,
|
|
77
|
+
line_ids: group.lineIds,
|
|
78
|
+
waypoints: group.path
|
|
79
|
+
}))
|
|
80
|
+
}))
|
|
81
|
+
})
|
|
52
82
|
let logSeq = 0
|
|
53
83
|
let backendLogSeq = 0
|
|
54
84
|
let backendJobSeq = 0
|
|
@@ -661,6 +691,18 @@ const exportData = () => {
|
|
|
661
691
|
return exported
|
|
662
692
|
}
|
|
663
693
|
|
|
694
|
+
/** 自定义格式按钮:同一份标准文档,不必再手写深拷贝 / 坐标归一 / JSON 安全 */
|
|
695
|
+
const exportBackendDto = () => {
|
|
696
|
+
const dto = view?.exportData({ format: DTO_FORMAT })
|
|
697
|
+
if (!dto) {
|
|
698
|
+
return
|
|
699
|
+
}
|
|
700
|
+
exportText.value = `自定义格式 ${DTO_FORMAT}:${dto.counts.points} 站 / ${dto.counts.lines} 线路 / ${dto.counts.channels} 通道 · 通道分组 ${dto.counts.groups}`
|
|
701
|
+
+ ` | 当前可注册表:${listExportFormats().join(' / ')}`
|
|
702
|
+
pushLog(`自定义导出:${dto.schema},${dto.stations.length} 站 / ${dto.routes.length} 线 / ${dto.channels.length} 通道`)
|
|
703
|
+
return dto
|
|
704
|
+
}
|
|
705
|
+
|
|
664
706
|
/** 回灌:把 input 口径的那份直接喂回视图(点 / 线走 updateData,通道走 updateOptions) */
|
|
665
707
|
const rebuildFromExport = () => {
|
|
666
708
|
const exported = exportData()
|
|
@@ -675,6 +717,7 @@ const rebuildFromExport = () => {
|
|
|
675
717
|
}
|
|
676
718
|
|
|
677
719
|
onMounted(() => {
|
|
720
|
+
disposeDtoFormat = defineExportFormat(DTO_FORMAT, backendDtoAdapter)
|
|
678
721
|
view = createGisView(container.value, buildOptions())
|
|
679
722
|
// 删除请求走 'remove' 事件(与 onRemove 同一份载荷):pending / remove / cancel 三个阶段都在这一条上
|
|
680
723
|
view.on('remove', handleRemoveRequest)
|
|
@@ -687,6 +730,8 @@ onMounted(() => {
|
|
|
687
730
|
|
|
688
731
|
onBeforeUnmount(() => {
|
|
689
732
|
disposed = true
|
|
733
|
+
disposeDtoFormat?.()
|
|
734
|
+
disposeDtoFormat = null
|
|
690
735
|
window.removeEventListener('keydown', onWindowKeyDown)
|
|
691
736
|
view?.destroy()
|
|
692
737
|
view = null
|
|
@@ -901,12 +946,14 @@ onBeforeUnmount(() => {
|
|
|
901
946
|
<h3>导出 / 回灌</h3>
|
|
902
947
|
<div class="dv-row">
|
|
903
948
|
<button type="button" class="dv-button" @click="exportData">导出(exportData)</button>
|
|
949
|
+
<button type="button" class="dv-button" data-demo="channel-export-dto" @click="exportBackendDto">后端 DTO(自定义格式)</button>
|
|
904
950
|
<button type="button" class="dv-button dv-button--primary" @click="rebuildFromExport">按导出重建</button>
|
|
905
951
|
</div>
|
|
906
|
-
<p class="dv-readout">{{ exportText || '还没导出:点一下看导出的份量' }}</p>
|
|
952
|
+
<p class="dv-readout" data-demo="channel-export-readout">{{ exportText || '还没导出:点一下看导出的份量' }}</p>
|
|
907
953
|
<p class="dv-hint">
|
|
908
954
|
回灌用的是 input 口径(与 createGisView 入参同构);view 口径是给后端 / 别的系统的业务记录
|
|
909
|
-
(station_data / line_data / parallel_groups
|
|
955
|
+
(station_data / line_data / parallel_groups 那套列名),不拿来回灌。后端 DTO 口径由
|
|
956
|
+
`defineExportFormat` 注册,卸载时只清掉自己这一个适配器;演示把标准文档映射成项目自己的表。
|
|
910
957
|
</p>
|
|
911
958
|
</div>
|
|
912
959
|
|