gis-view-webgl2 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +225 -20
- package/dist/index.js +1 -1
- package/docs/AI/345/257/271/350/257/235/346/261/207/346/200/273.md +109 -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 +91 -0
- package/docs/demos/ConnectDemo.vue +114 -3
- package/docs/demos/MinimapDemo.vue +216 -17
- package/docs/demos/SearchFilterDemo.vue +113 -1
- package/docs/demos/api-index.js +28 -20
- package/docs/demos/demos.js +1 -1
- package/docs/demos/gis-view-demo/GisViewDemoStage.vue +25 -16
- package/docs/demos/gis-view-demo/useGisViewDemo.js +27 -16
- package/docs/index.html +3 -3
- package/docs/internals/13-/351/271/260/347/234/274/345/233/276.md +8 -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 +18 -5
- package/docs/internals/16-03-/344/274/230/345/214/226/344/270/216/345/217/226/350/210/215-/344/270/213.md +11 -1
- package/docs/internals/18-/346/200/247/350/203/275/345/256/236/346/265/213/344/270/216WebGPU/350/257/204/344/274/260.md +73 -1
- package/docs/manual/03-/351/205/215/347/275/256/351/241/271.md +14 -5
- package/docs/manual/04-/344/272/213/344/273/266/344/270/216/345/233/236/350/260/203.md +2 -2
- package/docs/manual/05-/347/224/273/350/264/250/344/270/216/346/211/271/351/207/217/346/233/264/346/226/260.md +1 -1
- package/docs/manual/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 +99 -30
- package/docs/manual/16-/345/256/236/344/276/213/346/226/271/346/263/225/346/200/273/350/241/250.md +12 -7
- package/docs/manual/17-/345/217/202/346/225/260/351/200/237/346/237/245.md +14 -6
- package/docs/manual/18-/351/200/220/346/226/271/346/263/225/347/244/272/344/276/213.md +137 -6
- package/docs/manual/19-/350/257/273/346/225/260/344/270/216/346/213/226/346/213/275/351/242/204/350/247/210.md +4 -0
- package/docs/manual/20-/346/200/247/350/203/275/344/270/216/345/244/247/346/225/260/346/215/256.md +8 -3
- package/docs/manual/21-/350/257/264/346/230/216/344/270/216/345/270/270/350/247/201/351/227/256/351/242/230.md +6 -3
- package/docs/steps/README.md +6 -6
- package/docs/steps/selftest-demos.html +252 -9
- package/docs/steps/selftest-docs.html +3 -3
- package/docs/steps/selftest-full.html +357 -13
- package/docs/steps/selftest-perf.html +599 -382
- package/package.json +1 -1
|
@@ -28,6 +28,13 @@ const arrow = ref(true)
|
|
|
28
28
|
const arrowSize = ref(12)
|
|
29
29
|
const arrowPositionsText = ref('0.5')
|
|
30
30
|
const circuitSpacing = ref(12)
|
|
31
|
+
const startPointId = ref('')
|
|
32
|
+
const dotsVisible = ref(true)
|
|
33
|
+
const dotSize = ref(5)
|
|
34
|
+
const startDotColor = ref('#2f6fd0')
|
|
35
|
+
const endDotColor = ref('#d9544d')
|
|
36
|
+
const dotShape = ref('circle')
|
|
37
|
+
const draftLayer = ref('above')
|
|
31
38
|
const draft = ref(null)
|
|
32
39
|
const actionText = ref('配置好线条之后点「开始连线」,依次点两个节点')
|
|
33
40
|
const dataText = ref('正在创建视图…')
|
|
@@ -72,6 +79,10 @@ const createInitialLines = () => {
|
|
|
72
79
|
const isChannel = computed(() => linkKind.value !== 'line')
|
|
73
80
|
const circuits = computed(() => linkKind.value === 'channel-3' ? 3 : linkKind.value === 'channel-2' ? 2 : 1)
|
|
74
81
|
const arrowPositions = computed(() => arrowPositionsText.value.split(',').map(value => Number(value.trim())).filter(value => Number.isFinite(value)))
|
|
82
|
+
const startPointLabel = computed(() => {
|
|
83
|
+
const point = points.find(item => String(item.id) === String(startPointId.value))
|
|
84
|
+
return point ? point.name ?? String(point.id) : ''
|
|
85
|
+
})
|
|
75
86
|
const isDraftLive = computed(() => Boolean(draft.value) && ['start', 'from', 'ready', 'restart', 'pick'].includes(draft.value.phase))
|
|
76
87
|
const canFinish = computed(() => draft.value?.phase === 'ready')
|
|
77
88
|
const draftText = computed(() => {
|
|
@@ -110,10 +121,19 @@ const currentDraftStyle = () => ({
|
|
|
110
121
|
color: lineColor.value,
|
|
111
122
|
width: lineWidth.value,
|
|
112
123
|
dot: 4,
|
|
124
|
+
dots: dotsVisible.value
|
|
125
|
+
? {
|
|
126
|
+
size: dotSize.value,
|
|
127
|
+
shape: dotShape.value,
|
|
128
|
+
from: { color: startDotColor.value },
|
|
129
|
+
to: { color: endDotColor.value }
|
|
130
|
+
}
|
|
131
|
+
: false,
|
|
113
132
|
arrow: arrow.value,
|
|
114
133
|
arrowSize: arrowSize.value,
|
|
115
134
|
arrowPositions: arrowPositions.value,
|
|
116
|
-
circuitSpacing: circuitSpacing.value
|
|
135
|
+
circuitSpacing: circuitSpacing.value,
|
|
136
|
+
layer: draftLayer.value
|
|
117
137
|
})
|
|
118
138
|
|
|
119
139
|
/** 预览与真实落地共用同一份线条字段:颜色 / 线宽 / 方向箭头都从这里出发 */
|
|
@@ -129,6 +149,7 @@ const startDraft = () => {
|
|
|
129
149
|
}
|
|
130
150
|
view.endAddChannel()
|
|
131
151
|
view.beginAddChannel({
|
|
152
|
+
...(startPointId.value ? { from: startPointId.value } : {}),
|
|
132
153
|
kind: isChannel.value ? 'channel' : 'line',
|
|
133
154
|
circuits: circuits.value,
|
|
134
155
|
routing: routing.value,
|
|
@@ -136,7 +157,9 @@ const startDraft = () => {
|
|
|
136
157
|
channelDraftStyle: currentDraftStyle(),
|
|
137
158
|
lineProps: currentLineProps()
|
|
138
159
|
})
|
|
139
|
-
actionText.value =
|
|
160
|
+
actionText.value = startPointId.value
|
|
161
|
+
? `开始连线:起点已指定为 ${startPointLabel.value},下一次点节点只选终点(${isChannel.value ? `通道 ${circuits.value} 回` : '独立线路'} / ${routing.value === 'orthogonal' ? '正交折线' : '直线'})`
|
|
162
|
+
: `开始连线:先点起点,再点终点(${isChannel.value ? `通道 ${circuits.value} 回` : '独立线路'} / ${routing.value === 'orthogonal' ? '正交折线' : '直线'})`
|
|
140
163
|
pushLog('beginAddChannel', actionText.value)
|
|
141
164
|
}
|
|
142
165
|
|
|
@@ -177,6 +200,60 @@ const commitDraft = () => {
|
|
|
177
200
|
emit('notice', actionText.value)
|
|
178
201
|
}
|
|
179
202
|
|
|
203
|
+
/** 直接把本次新增的线路 / 通道对象交给 commitAddChannel:不再先 addLine / addChannel */
|
|
204
|
+
const commitWithObject = () => {
|
|
205
|
+
if (!view || !canFinish.value) {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
const current = view.getAddChannelDraft()
|
|
209
|
+
if (!current?.from || !current?.to) {
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
sequence += 1
|
|
213
|
+
const from = current.from.id
|
|
214
|
+
const to = current.to.id
|
|
215
|
+
const middle = middlePathOf(current)
|
|
216
|
+
const fullPath = fullPathOf(current)
|
|
217
|
+
let payload
|
|
218
|
+
if (current.kind === 'line') {
|
|
219
|
+
payload = {
|
|
220
|
+
id: `connect-object-line-${sequence}`,
|
|
221
|
+
name: `对象线路 ${sequence}`,
|
|
222
|
+
from,
|
|
223
|
+
to,
|
|
224
|
+
...(fullPath ? { path: fullPath } : {}),
|
|
225
|
+
...currentLineProps()
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
const lineIds = Array.from({ length: current.circuits }, (_item, index) => `connect-object-line-${sequence}-${index + 1}`)
|
|
230
|
+
const channelId = `connect-object-channel-${sequence}`
|
|
231
|
+
payload = {
|
|
232
|
+
id: channelId,
|
|
233
|
+
name: `对象通道 ${sequence}`,
|
|
234
|
+
from,
|
|
235
|
+
to,
|
|
236
|
+
lineIds,
|
|
237
|
+
...(middle ? { path: middle } : {}),
|
|
238
|
+
groups: [{ id: channelId, lineIds, ...(middle ? { path: middle } : {}) }]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const result = view.commitAddChannel(payload)
|
|
242
|
+
refreshState()
|
|
243
|
+
if (!result.ok) {
|
|
244
|
+
actionText.value = `commitAddChannel(对象) 没有落地:${result.reason ?? '未知原因'}`
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
const lines = result.lines?.length ?? (result.line ? 1 : 0)
|
|
248
|
+
actionText.value = `commitAddChannel(对象) → ${result.kind === 'line' ? '线路对象' : '通道对象'} ${String(result.channelId ?? result.lineId ?? '')} · ${lines} 回线`
|
|
249
|
+
if (result.lineIds?.length) {
|
|
250
|
+
view.selectFeatures(result.lineIds)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
pushLog('commitAddChannel(对象)', actionText.value)
|
|
254
|
+
emit('notice', actionText.value)
|
|
255
|
+
}
|
|
256
|
+
|
|
180
257
|
const middlePathOf = current => (current.path?.length ? current.path.map(point => [point[0], point[1]]) : null)
|
|
181
258
|
const fullPathOf = current => {
|
|
182
259
|
const middle = middlePathOf(current)
|
|
@@ -267,7 +344,7 @@ const resetScene = () => {
|
|
|
267
344
|
pushLog('reset', actionText.value)
|
|
268
345
|
}
|
|
269
346
|
|
|
270
|
-
watch([lineColor, lineWidth, arrow, arrowSize, arrowPositionsText, circuitSpacing], () => {
|
|
347
|
+
watch([lineColor, lineWidth, arrow, arrowSize, arrowPositionsText, circuitSpacing, dotsVisible, dotSize, startDotColor, endDotColor, dotShape, draftLayer], () => {
|
|
271
348
|
if (view && isDraftLive.value) {
|
|
272
349
|
view.updateAddChannelStyle(currentDraftStyle())
|
|
273
350
|
draft.value = view.getAddChannelDraft()
|
|
@@ -333,6 +410,14 @@ onBeforeUnmount(() => {
|
|
|
333
410
|
</select>
|
|
334
411
|
</label>
|
|
335
412
|
</div>
|
|
413
|
+
<div class="dv-row">
|
|
414
|
+
<label>指定起点
|
|
415
|
+
<select v-model="startPointId" data-demo="connect-start-point" :disabled="isDraftLive">
|
|
416
|
+
<option value="">点击时再选</option>
|
|
417
|
+
<option v-for="point in points" :key="String(point.id)" :value="String(point.id)">{{ point.name ?? point.id }}</option>
|
|
418
|
+
</select>
|
|
419
|
+
</label>
|
|
420
|
+
</div>
|
|
336
421
|
<div class="dv-row">
|
|
337
422
|
<label>线色 <input v-model="lineColor" type="color" data-demo="connect-color" /></label>
|
|
338
423
|
<label>线宽 <input v-model.number="lineWidth" type="range" min="1" max="6" step="0.2" data-demo="connect-width" /> {{ lineWidth.toFixed(1) }}</label>
|
|
@@ -356,6 +441,31 @@ onBeforeUnmount(() => {
|
|
|
356
441
|
<p class="dv-hint">草稿样式直接传给 <code>beginAddChannel({ channelDraftStyle })</code>;连线期间改颜色 / 线宽 / 箭头位置 / 回线间距会走 <code>updateAddChannelStyle()</code>,预览立即更新。正交折线会自动补一个 90 度拐点;落地线路用完整 path,通道只写中间拐点。</p>
|
|
357
442
|
</div>
|
|
358
443
|
|
|
444
|
+
<div class="dv-group">
|
|
445
|
+
<h3>示例点与层级</h3>
|
|
446
|
+
<div class="dv-row">
|
|
447
|
+
<label><input v-model="dotsVisible" type="checkbox" data-demo="connect-dots-visible" /> 显示两端示例点</label>
|
|
448
|
+
<label>形状
|
|
449
|
+
<select v-model="dotShape" data-demo="connect-dot-shape">
|
|
450
|
+
<option value="circle">圆形</option>
|
|
451
|
+
<option value="square">方形</option>
|
|
452
|
+
</select>
|
|
453
|
+
</label>
|
|
454
|
+
<label>尺寸 <input v-model.number="dotSize" type="range" min="2" max="12" step="1" data-demo="connect-dot-size" /> {{ dotSize }}px</label>
|
|
455
|
+
</div>
|
|
456
|
+
<div class="dv-row">
|
|
457
|
+
<label>起点色 <input v-model="startDotColor" type="color" data-demo="connect-dot-from-color" :disabled="!dotsVisible" /></label>
|
|
458
|
+
<label>终点色 <input v-model="endDotColor" type="color" data-demo="connect-dot-to-color" :disabled="!dotsVisible" /></label>
|
|
459
|
+
<label>示例线路层级
|
|
460
|
+
<select v-model="draftLayer" data-demo="connect-draft-layer">
|
|
461
|
+
<option value="above">真实节点之上</option>
|
|
462
|
+
<option value="below-points">真实节点之下</option>
|
|
463
|
+
</select>
|
|
464
|
+
</label>
|
|
465
|
+
</div>
|
|
466
|
+
<p class="dv-hint">示例点始终落在被点击节点的正中心(多回线偏移不会带走它),可通过 <code>dots: false</code> 关闭,或用 <code>dots.from / dots.to</code> 分别配颜色、尺寸与形状。层级只作用于示例线 / 箭头 / <code>customDraw</code>;示例点仍画在真实节点之后,保证看得见。</p>
|
|
467
|
+
</div>
|
|
468
|
+
|
|
359
469
|
<div class="dv-group">
|
|
360
470
|
<h3>草稿与落地</h3>
|
|
361
471
|
<div class="dv-row">
|
|
@@ -364,6 +474,7 @@ onBeforeUnmount(() => {
|
|
|
364
474
|
</div>
|
|
365
475
|
<div class="dv-row">
|
|
366
476
|
<button type="button" class="dv-button" data-demo="connect-default" :disabled="!canFinish" @click="commitDraft">默认添加(commitAddChannel)</button>
|
|
477
|
+
<button type="button" class="dv-button" data-demo="connect-commit-object" :disabled="!canFinish" @click="commitWithObject">对象提交(通道 / 线路对象)</button>
|
|
367
478
|
<button type="button" class="dv-button" data-demo="connect-add-lines" :disabled="!canFinish" @click="addWithLines">用 addLines 添加</button>
|
|
368
479
|
<button type="button" class="dv-button" data-demo="connect-add-channels" :disabled="!canFinish" @click="addWithChannels">用 addChannels 添加</button>
|
|
369
480
|
</div>
|
|
@@ -17,12 +17,19 @@ const enabled = ref(true)
|
|
|
17
17
|
const size = ref('medium')
|
|
18
18
|
const position = ref('bottom-right')
|
|
19
19
|
const extent = ref('auto')
|
|
20
|
-
const ruleMode = ref('
|
|
20
|
+
const ruleMode = ref('inherit')
|
|
21
21
|
const levelMode = ref('all')
|
|
22
|
-
const
|
|
22
|
+
const pointSizeScale = ref(1)
|
|
23
|
+
const lineWidthScale = ref(1)
|
|
24
|
+
const pointZoomScale = ref(0)
|
|
25
|
+
const lineZoomScale = ref(0)
|
|
23
26
|
const channelCircuits = ref(true)
|
|
24
|
-
const
|
|
27
|
+
const zoomMode = ref('manual')
|
|
28
|
+
const followZoomScale = ref(1)
|
|
25
29
|
const dragAction = ref('pan')
|
|
30
|
+
const extentFollowContent = ref(false)
|
|
31
|
+
const extentFollowCamera = ref(false)
|
|
32
|
+
const offset = ref([0, 0])
|
|
26
33
|
const maxPixelRatio = ref('2')
|
|
27
34
|
const gridPlacement = ref('below-data')
|
|
28
35
|
const customLayers = ref(true)
|
|
@@ -31,6 +38,7 @@ const zoomReadout = ref('—')
|
|
|
31
38
|
const layerReadout = ref('—')
|
|
32
39
|
const eventText = ref('—')
|
|
33
40
|
const interactionReadout = ref('还没有手势')
|
|
41
|
+
const offsetReadout = ref('整图位移 0, 0')
|
|
34
42
|
|
|
35
43
|
const SIZES = {
|
|
36
44
|
small: [148, 104],
|
|
@@ -40,6 +48,8 @@ const SIZES = {
|
|
|
40
48
|
|
|
41
49
|
const dataset = buildDemoData({ count: 64, channels: 3 })
|
|
42
50
|
let view = null
|
|
51
|
+
let minimapHandle = null
|
|
52
|
+
let wholeMapDrag = null
|
|
43
53
|
let layerPaints = { grid: 0, compass: 0, gridStage: '—' }
|
|
44
54
|
|
|
45
55
|
const drawGrid = ({ context, width, height, stage }) => {
|
|
@@ -125,6 +135,9 @@ const minimapOptions = () => {
|
|
|
125
135
|
margin: 12,
|
|
126
136
|
padding: 0.05,
|
|
127
137
|
extent: extent.value,
|
|
138
|
+
extentFollowContent: extentFollowContent.value,
|
|
139
|
+
extentFollowCamera: extentFollowCamera.value,
|
|
140
|
+
offset: [...offset.value],
|
|
128
141
|
background: 'inherit',
|
|
129
142
|
backgroundStyle: 'rgba(255, 255, 255, 0.94)',
|
|
130
143
|
borderColor: '#c7d8eb',
|
|
@@ -140,16 +153,19 @@ const minimapOptions = () => {
|
|
|
140
153
|
levels: levelMode.value === 'top' ? [2] : undefined,
|
|
141
154
|
cascade: 'both',
|
|
142
155
|
layered: true,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
156
|
+
// 自己规则 / 沿用主图都乘这一份;与主图相机倍数、小图自身倍数都无关
|
|
157
|
+
pointSizeScale: Number(pointSizeScale.value),
|
|
158
|
+
lineWidthScale: Number(lineWidthScale.value),
|
|
159
|
+
// 只有小图自身放大时才按这两个指数联动;沿用主图的节点 / 线路也一样
|
|
160
|
+
pointZoomScale: Number(pointZoomScale.value),
|
|
161
|
+
lineZoomScale: Number(lineZoomScale.value),
|
|
147
162
|
boxStyle: { fill: '#3678bf', fillOpacity: 0.16, stroke: '#3678bf', strokeWidth: 1, strokeStyle: 'dashed', radius: 3 },
|
|
148
163
|
selectStyle: { fill: '#f0a43c', stroke: '#f0a43c' },
|
|
149
164
|
interactive: true,
|
|
150
165
|
onInteraction: handleMinimapInteraction,
|
|
151
166
|
longPressDelay: 180,
|
|
152
|
-
zoomable:
|
|
167
|
+
zoomable: zoomMode.value === 'manual' ? true : zoomMode.value === 'follow' ? 'follow' : false,
|
|
168
|
+
followZoomScale: Number(followZoomScale.value),
|
|
153
169
|
minZoom: 0.7,
|
|
154
170
|
maxZoom: 6,
|
|
155
171
|
zoomStep: 1.35,
|
|
@@ -168,10 +184,15 @@ const refreshReadout = () => {
|
|
|
168
184
|
const sizeText = root ? `${Math.round(root.getBoundingClientRect().width)}×${Math.round(root.getBoundingClientRect().height)}` : '未挂载'
|
|
169
185
|
readout.value = `${sizeText} · 备份 ${canvas?.width ?? 0}×${canvas?.height ?? 0} · 像素比 ${ratio ? ratio.toFixed(2) : '—'} · 范围 ${extent.value} · 自定义层 ${options.layers.length}`
|
|
170
186
|
if (view) {
|
|
171
|
-
zoomReadout.value = `小图倍数 ${view.getMinimapZoom().toFixed(2)} · ${
|
|
187
|
+
zoomReadout.value = `小图倍数 ${view.getMinimapZoom().toFixed(2)} · ${zoomModeLabel.value}`
|
|
172
188
|
}
|
|
189
|
+
offsetReadout.value = `整图位移 ${Math.round(offset.value[0])}, ${Math.round(offset.value[1])}`
|
|
173
190
|
}
|
|
174
191
|
|
|
192
|
+
const zoomModeLabel = computed(() => zoomMode.value === 'manual'
|
|
193
|
+
? '手动缩放小图'
|
|
194
|
+
: zoomMode.value === 'follow' ? `跟随主图(指数 ${Number(followZoomScale.value).toFixed(1)})` : '不缩放小图,滚轮缩放主图')
|
|
195
|
+
|
|
175
196
|
const applyMinimap = () => {
|
|
176
197
|
if (!view) {
|
|
177
198
|
return
|
|
@@ -179,6 +200,9 @@ const applyMinimap = () => {
|
|
|
179
200
|
view.updateOptions({ minimap: minimapOptions() })
|
|
180
201
|
eventText.value = `updateOptions:${enabled.value ? '已更新鹰眼图配置' : '已卸载鹰眼图'}`
|
|
181
202
|
requestAnimationFrame(refreshReadout)
|
|
203
|
+
if (enabled.value) {
|
|
204
|
+
requestAnimationFrame(installMinimapHandle)
|
|
205
|
+
}
|
|
182
206
|
}
|
|
183
207
|
|
|
184
208
|
const resetZoom = () => {
|
|
@@ -193,8 +217,108 @@ const zoomMinimap = (factor) => {
|
|
|
193
217
|
|
|
194
218
|
const refreshZoom = () => {
|
|
195
219
|
if (view) {
|
|
196
|
-
zoomReadout.value = `小图倍数 ${view.getMinimapZoom().toFixed(2)} · ${
|
|
220
|
+
zoomReadout.value = `小图倍数 ${view.getMinimapZoom().toFixed(2)} · ${zoomModeLabel.value}`
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** 拖拽演示:框选不依赖 zoomable;平移才需要手动缩放后内容有可移动余量 */
|
|
225
|
+
const showDragDemo = (action) => {
|
|
226
|
+
dragAction.value = action
|
|
227
|
+
zoomMode.value = action === 'box' ? 'off' : 'manual'
|
|
228
|
+
applyMinimap()
|
|
229
|
+
eventText.value = action === 'box'
|
|
230
|
+
? '拖拽演示:缩放模式已关闭,在小图空白处直接拖动仍能拉出框选矩形'
|
|
231
|
+
: '拖拽演示:已切到手动缩放,在小图空白处拖动平移小图内容'
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** 把 offset 写回实例:整图拖动只改角落位移,不重画小图,也不碰主图相机 */
|
|
235
|
+
const setWholeMapOffset = (next) => {
|
|
236
|
+
const x = Number(next?.[0])
|
|
237
|
+
const y = Number(next?.[1])
|
|
238
|
+
offset.value = [Number.isFinite(x) ? x : 0, Number.isFinite(y) ? y : 0]
|
|
239
|
+
const options = view?.getOptions().minimap
|
|
240
|
+
if (options) {
|
|
241
|
+
view.updateOptions({ minimap: { ...options, offset: [...offset.value] } })
|
|
197
242
|
}
|
|
243
|
+
offsetReadout.value = `整图位移 ${Math.round(offset.value[0])}, ${Math.round(offset.value[1])}`
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const resetWholeMapOffset = () => {
|
|
247
|
+
setWholeMapOffset([0, 0])
|
|
248
|
+
eventText.value = '整图拖动:位置已复位到当前角落'
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const beginWholeMapDrag = (event) => {
|
|
252
|
+
if (!view || event.button !== 0) {
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
event.preventDefault()
|
|
256
|
+
event.stopPropagation()
|
|
257
|
+
const current = view.getOptions().minimap?.offset
|
|
258
|
+
const origin = Array.isArray(current) ? [Number(current[0]) || 0, Number(current[1]) || 0] : [...offset.value]
|
|
259
|
+
wholeMapDrag = { pointerId: event.pointerId, clientX: event.clientX, clientY: event.clientY, origin }
|
|
260
|
+
minimapHandle?.classList.add('is-dragging')
|
|
261
|
+
eventText.value = '整图拖动:按住顶部手柄移动,松手停在当前角落'
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const moveWholeMapDrag = (event) => {
|
|
265
|
+
if (!wholeMapDrag || event.pointerId !== wholeMapDrag.pointerId) {
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
event.preventDefault()
|
|
269
|
+
event.stopPropagation()
|
|
270
|
+
setWholeMapOffset([
|
|
271
|
+
wholeMapDrag.origin[0] + event.clientX - wholeMapDrag.clientX,
|
|
272
|
+
wholeMapDrag.origin[1] + event.clientY - wholeMapDrag.clientY
|
|
273
|
+
])
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const endWholeMapDrag = (event) => {
|
|
277
|
+
if (!wholeMapDrag || (event?.pointerId !== undefined && event.pointerId !== wholeMapDrag.pointerId)) {
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
event?.preventDefault()
|
|
281
|
+
event?.stopPropagation()
|
|
282
|
+
minimapHandle?.classList.remove('is-dragging')
|
|
283
|
+
wholeMapDrag = null
|
|
284
|
+
eventText.value = `整图拖动:已停在位移 ${Math.round(offset.value[0])}, ${Math.round(offset.value[1])}`
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const nudgeWholeMap = (event) => {
|
|
288
|
+
const step = event.shiftKey ? 10 : 2
|
|
289
|
+
const delta = event.key === 'ArrowLeft' ? [-step, 0]
|
|
290
|
+
: event.key === 'ArrowRight' ? [step, 0]
|
|
291
|
+
: event.key === 'ArrowUp' ? [0, -step]
|
|
292
|
+
: event.key === 'ArrowDown' ? [0, step] : null
|
|
293
|
+
if (!delta) {
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
event.preventDefault()
|
|
297
|
+
event.stopPropagation()
|
|
298
|
+
setWholeMapOffset([offset.value[0] + delta[0], offset.value[1] + delta[1]])
|
|
299
|
+
eventText.value = '整图拖动:方向键也能微调整图位置(按住 Shift 每次 10px)'
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** 给库创建的根节点挂一个独立的拖动手柄:手柄自己 stopPropagation,不会触发小图框选 / 平移手势 */
|
|
303
|
+
const installMinimapHandle = () => {
|
|
304
|
+
if (!view || minimapHandle) {
|
|
305
|
+
return
|
|
306
|
+
}
|
|
307
|
+
const root = view.getMinimapElement()
|
|
308
|
+
if (!root) {
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
minimapHandle = document.createElement('div')
|
|
312
|
+
minimapHandle.className = 'demo-minimap-drag-handle'
|
|
313
|
+
minimapHandle.dataset.demo = 'minimap-drag-handle'
|
|
314
|
+
minimapHandle.setAttribute('role', 'button')
|
|
315
|
+
minimapHandle.setAttribute('tabindex', '0')
|
|
316
|
+
minimapHandle.setAttribute('aria-label', '拖动整张鹰眼图')
|
|
317
|
+
minimapHandle.title = '按住拖动整张鹰眼图;方向键可微调'
|
|
318
|
+
minimapHandle.textContent = '拖动整图'
|
|
319
|
+
minimapHandle.addEventListener('pointerdown', beginWholeMapDrag)
|
|
320
|
+
minimapHandle.addEventListener('keydown', nudgeWholeMap)
|
|
321
|
+
root.append(minimapHandle)
|
|
198
322
|
}
|
|
199
323
|
|
|
200
324
|
const refreshLayerReadout = () => {
|
|
@@ -229,9 +353,18 @@ onMounted(() => {
|
|
|
229
353
|
eventText.value = `warning:${text}`
|
|
230
354
|
}
|
|
231
355
|
})
|
|
356
|
+
installMinimapHandle()
|
|
357
|
+
window.addEventListener('pointermove', moveWholeMapDrag, true)
|
|
358
|
+
window.addEventListener('pointerup', endWholeMapDrag, true)
|
|
359
|
+
window.addEventListener('pointercancel', endWholeMapDrag, true)
|
|
232
360
|
})
|
|
233
361
|
|
|
234
362
|
onBeforeUnmount(() => {
|
|
363
|
+
window.removeEventListener('pointermove', moveWholeMapDrag, true)
|
|
364
|
+
window.removeEventListener('pointerup', endWholeMapDrag, true)
|
|
365
|
+
window.removeEventListener('pointercancel', endWholeMapDrag, true)
|
|
366
|
+
minimapHandle?.remove()
|
|
367
|
+
minimapHandle = null
|
|
235
368
|
view?.destroy()
|
|
236
369
|
view = null
|
|
237
370
|
})
|
|
@@ -289,7 +422,16 @@ const sizeSummary = computed(() => `${SIZES[size.value]?.[0] ?? 0}×${SIZES[size
|
|
|
289
422
|
</select>
|
|
290
423
|
</label>
|
|
291
424
|
</div>
|
|
292
|
-
<
|
|
425
|
+
<div class="dv-row">
|
|
426
|
+
<label><input v-model="extentFollowContent" type="checkbox" data-demo="minimap-extent-content" @change="applyMinimap" /> 自动范围随内容更新(默认关)</label>
|
|
427
|
+
</div>
|
|
428
|
+
<div class="dv-row">
|
|
429
|
+
<label><input v-model="extentFollowCamera" type="checkbox" data-demo="minimap-extent-follow" @change="applyMinimap" /> 自动范围随相机收窄(默认关)</label>
|
|
430
|
+
</div>
|
|
431
|
+
<div class="dv-row">
|
|
432
|
+
<button type="button" class="dv-button" data-demo="minimap-offset-reset" @click="resetWholeMapOffset">整图位置复位</button>
|
|
433
|
+
</div>
|
|
434
|
+
<p class="dv-hint"><code>extentFollowContent</code> 默认关闭:筛选或删除外围要素不会改小图范围。按住小图顶部的「拖动整图」手柄可移动整张鹰眼图,方向键可微调;<code>offset</code> 会随其他控件一起保留。<code>maxPixelRatio</code> 越大越清晰,也越吃填充率;高分屏按机器档位调到 2 通常就够。</p>
|
|
293
435
|
</div>
|
|
294
436
|
<div class="dv-group">
|
|
295
437
|
<h3>规则与交互</h3>
|
|
@@ -309,11 +451,24 @@ const sizeSummary = computed(() => `${SIZES[size.value]?.[0] ?? 0}×${SIZES[size
|
|
|
309
451
|
</label>
|
|
310
452
|
</div>
|
|
311
453
|
<div class="dv-row">
|
|
312
|
-
<label
|
|
454
|
+
<label>节点整体倍数 <input v-model.number="pointSizeScale" type="range" min="0" max="3" step="0.1" data-demo="minimap-point-size-scale" @change="applyMinimap" /> {{ Number(pointSizeScale).toFixed(1) }}</label>
|
|
455
|
+
<label>线路整体倍数 <input v-model.number="lineWidthScale" type="range" min="0" max="3" step="0.1" data-demo="minimap-line-width-scale" @change="applyMinimap" /> {{ Number(lineWidthScale).toFixed(1) }}</label>
|
|
456
|
+
</div>
|
|
457
|
+
<div class="dv-row">
|
|
458
|
+
<label>小图放大节点 <input v-model.number="pointZoomScale" type="range" min="0" max="1" step="0.1" data-demo="minimap-point-zoom-scale" @change="applyMinimap" /> {{ Number(pointZoomScale).toFixed(1) }}</label>
|
|
459
|
+
<label>小图放大线路 <input v-model.number="lineZoomScale" type="range" min="0" max="1" step="0.1" data-demo="minimap-line-zoom-scale" @change="applyMinimap" /> {{ Number(lineZoomScale).toFixed(1) }}</label>
|
|
460
|
+
</div>
|
|
461
|
+
<div class="dv-row">
|
|
313
462
|
<label><input v-model="channelCircuits" type="checkbox" data-demo="minimap-circuits" @change="applyMinimap" /> 画全部回线</label>
|
|
314
463
|
</div>
|
|
315
464
|
<div class="dv-row">
|
|
316
|
-
<label
|
|
465
|
+
<label>缩放模式
|
|
466
|
+
<select v-model="zoomMode" data-demo="minimap-zoomable" @change="applyMinimap">
|
|
467
|
+
<option value="off">关闭</option>
|
|
468
|
+
<option value="manual">手动缩放小图</option>
|
|
469
|
+
<option value="follow">跟随主图</option>
|
|
470
|
+
</select>
|
|
471
|
+
</label>
|
|
317
472
|
<label>空白拖动
|
|
318
473
|
<select v-model="dragAction" data-demo="minimap-drag-action" @change="applyMinimap">
|
|
319
474
|
<option value="pan">平移小图</option>
|
|
@@ -321,7 +476,14 @@ const sizeSummary = computed(() => `${SIZES[size.value]?.[0] ?? 0}×${SIZES[size
|
|
|
321
476
|
</select>
|
|
322
477
|
</label>
|
|
323
478
|
</div>
|
|
324
|
-
<
|
|
479
|
+
<div class="dv-row">
|
|
480
|
+
<label>跟随指数 <input v-model.number="followZoomScale" type="range" min="0" max="2" step="0.1" data-demo="minimap-follow-scale" @change="applyMinimap" /> {{ Number(followZoomScale).toFixed(1) }}</label>
|
|
481
|
+
</div>
|
|
482
|
+
<div class="dv-row">
|
|
483
|
+
<button type="button" class="dv-button" data-demo="minimap-drag-box" @click="showDragDemo('box')">拖拽演示:框选</button>
|
|
484
|
+
<button type="button" class="dv-button" data-demo="minimap-drag-pan" @click="showDragDemo('pan')">拖拽演示:平移</button>
|
|
485
|
+
</div>
|
|
486
|
+
<p class="dv-hint">沿用主图规则时,节点 / 线路先按「小图视口 ÷ 主图视口」缩放,主图放大缩小不会改变它们的大小;滚轮或 + / - 放大鹰眼图时,再按 <code>pointZoomScale</code> / <code>lineZoomScale</code> 的指数变化。两个整体倍数对自有规则与沿用主图的要素都生效。<code>zoomable: true</code> 是小图手动缩放,<code>'follow'</code> 是整体范围跟随主图,两者互斥;<code>followZoomScale</code> 是主图倍数的指数。框选不依赖缩放开关:选「关闭」+ <code>dragAction: 'box'</code>,空白处拖动仍会直接框选。视口框可以拖,空白处长按跟随。</p>
|
|
325
487
|
</div>
|
|
326
488
|
<div class="dv-group">
|
|
327
489
|
<h3>扩展层</h3>
|
|
@@ -341,18 +503,55 @@ const sizeSummary = computed(() => `${SIZES[size.value]?.[0] ?? 0}×${SIZES[size
|
|
|
341
503
|
<div class="dv-group">
|
|
342
504
|
<h3>小图倍数</h3>
|
|
343
505
|
<div class="dv-row">
|
|
344
|
-
<button type="button" class="dv-button" data-demo="minimap-zoom-out" @click="zoomMinimap(1 / 1.35)">-</button>
|
|
345
|
-
<button type="button" class="dv-button dv-button--primary" data-demo="minimap-zoom-reset" @click="resetZoom">1×</button>
|
|
346
|
-
<button type="button" class="dv-button" data-demo="minimap-zoom-in" @click="zoomMinimap(1.35)">+</button>
|
|
506
|
+
<button type="button" class="dv-button" data-demo="minimap-zoom-out" :disabled="zoomMode === 'follow'" @click="zoomMinimap(1 / 1.35)">-</button>
|
|
507
|
+
<button type="button" class="dv-button dv-button--primary" data-demo="minimap-zoom-reset" :disabled="zoomMode === 'follow'" @click="resetZoom">1×</button>
|
|
508
|
+
<button type="button" class="dv-button" data-demo="minimap-zoom-in" :disabled="zoomMode === 'follow'" @click="zoomMinimap(1.35)">+</button>
|
|
347
509
|
</div>
|
|
348
510
|
<p class="dv-readout" data-demo="minimap-zoom-readout">{{ zoomReadout }}</p>
|
|
349
511
|
</div>
|
|
350
512
|
<div class="dv-group">
|
|
351
513
|
<h3>读数</h3>
|
|
352
514
|
<p class="dv-readout" data-demo="minimap-readout">{{ readout }}</p>
|
|
515
|
+
<p class="dv-readout" data-demo="minimap-offset-readout">{{ offsetReadout }}</p>
|
|
353
516
|
<p class="dv-readout" data-demo="minimap-event" aria-live="polite">{{ eventText }}</p>
|
|
354
517
|
<p class="dv-readout" data-demo="minimap-interaction" aria-live="polite">{{ interactionReadout }}</p>
|
|
355
518
|
</div>
|
|
356
519
|
</aside>
|
|
357
520
|
</section>
|
|
358
521
|
</template>
|
|
522
|
+
|
|
523
|
+
<style scoped>
|
|
524
|
+
:deep(.demo-minimap-drag-handle) {
|
|
525
|
+
position: absolute;
|
|
526
|
+
z-index: 4;
|
|
527
|
+
top: 4px;
|
|
528
|
+
left: 50%;
|
|
529
|
+
box-sizing: border-box;
|
|
530
|
+
min-width: 68px;
|
|
531
|
+
padding: 2px 9px;
|
|
532
|
+
transform: translateX(-50%);
|
|
533
|
+
border: 1px solid rgba(54, 120, 191, 0.38);
|
|
534
|
+
border-radius: 999px;
|
|
535
|
+
background: rgba(255, 255, 255, 0.9);
|
|
536
|
+
box-shadow: 0 2px 7px rgba(31, 62, 105, 0.14);
|
|
537
|
+
color: #2f5e94;
|
|
538
|
+
font-size: 10px;
|
|
539
|
+
line-height: 16px;
|
|
540
|
+
text-align: center;
|
|
541
|
+
cursor: grab;
|
|
542
|
+
user-select: none;
|
|
543
|
+
touch-action: none;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
:deep(.demo-minimap-drag-handle:hover),
|
|
547
|
+
:deep(.demo-minimap-drag-handle:focus-visible) {
|
|
548
|
+
border-color: #3678bf;
|
|
549
|
+
background: #fff;
|
|
550
|
+
outline: none;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
:deep(.demo-minimap-drag-handle.is-dragging) {
|
|
554
|
+
cursor: grabbing;
|
|
555
|
+
background: #eaf2fc;
|
|
556
|
+
}
|
|
557
|
+
</style>
|