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
|
@@ -192,8 +192,8 @@
|
|
|
192
192
|
await settleFrames()
|
|
193
193
|
const fillAuto = minimapFill()
|
|
194
194
|
check('鹰眼图 extent: auto 把远离数据的 GeoJSON 一起框进来', fillAuto > 100 && fillAuto > fillData + 100, `data=${fillData} auto=${fillAuto}`)
|
|
195
|
-
//
|
|
196
|
-
//
|
|
195
|
+
// 反过来:底图小到在合并范围里只剩一两个像素、而相机正好落在里面时,默认仍按并集铺;
|
|
196
|
+
// 显式打开 extentFollowCamera 后,auto 才以正在看的那一份为准。
|
|
197
197
|
const tinyHost = document.createElement('div')
|
|
198
198
|
tinyHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:420px;height:320px'
|
|
199
199
|
document.body.appendChild(tinyHost)
|
|
@@ -210,13 +210,62 @@
|
|
|
210
210
|
minimap: { width: 200, height: 160, extent: 'auto' }
|
|
211
211
|
})
|
|
212
212
|
await settleFrames()
|
|
213
|
-
const fillSquashed = minimapFill(tinyHost)
|
|
214
|
-
tinyView.zoomToBounds({ minX: 100, minY: 20, maxX: 101, maxY: 21 })
|
|
215
|
-
await settleFrames()
|
|
216
|
-
const
|
|
217
|
-
check('鹰眼图 extent: auto
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
const fillSquashed = minimapFill(tinyHost)
|
|
214
|
+
tinyView.zoomToBounds({ minX: 100, minY: 20, maxX: 101, maxY: 21 })
|
|
215
|
+
await settleFrames()
|
|
216
|
+
const fillDefault = minimapFill(tinyHost)
|
|
217
|
+
check('鹰眼图 extent: auto 默认不随相机收窄(外围内容消失后包围盒保持并集)',
|
|
218
|
+
(tinyView.getOptions().minimap.extentFollowCamera ?? false) === false && fillDefault > 0 && Math.abs(fillDefault - fillSquashed) < 40,
|
|
219
|
+
`squashed=${fillSquashed} default=${fillDefault}`)
|
|
220
|
+
tinyView.updateOptions({ minimap: { ...tinyView.getOptions().minimap, extentFollowCamera: true } })
|
|
221
|
+
await settleFrames()
|
|
222
|
+
const fillFocused = minimapFill(tinyHost)
|
|
223
|
+
check('鹰眼图 extent: 打开 extentFollowCamera 后,相机落进小范围时 auto 以它为准',
|
|
224
|
+
tinyView.getOptions().minimap.extentFollowCamera === true && fillFocused > 200 && fillFocused > fillSquashed + 200,
|
|
225
|
+
`squashed=${fillSquashed} focused=${fillFocused}`)
|
|
226
|
+
// extentFollowContent 默认关闭:筛选掉外围节点后,鹰眼图仍用首次铺好的范围;显式打开后才跟着当前可见内容缩。
|
|
227
|
+
const lockHost = document.createElement('div')
|
|
228
|
+
lockHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:420px;height:320px'
|
|
229
|
+
document.body.appendChild(lockHost)
|
|
230
|
+
const lockExtents = []
|
|
231
|
+
const lockView = createGisView(lockHost, {
|
|
232
|
+
points: [
|
|
233
|
+
{ id: 'near-a', x: 0, y: 0, zone: 'near' },
|
|
234
|
+
{ id: 'near-b', x: 10, y: 0, zone: 'near' },
|
|
235
|
+
{ id: 'far', x: 100, y: 40, zone: 'far' }
|
|
236
|
+
],
|
|
237
|
+
lines: [],
|
|
238
|
+
background: false,
|
|
239
|
+
minimap: {
|
|
240
|
+
width: 200,
|
|
241
|
+
height: 160,
|
|
242
|
+
background: false,
|
|
243
|
+
extent: 'auto',
|
|
244
|
+
extentFollowContent: false,
|
|
245
|
+
draw: info => lockExtents.push({ ...info.extent })
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
await settleFrames()
|
|
249
|
+
const lockBefore = lockExtents.at(-1)
|
|
250
|
+
lockView.setFilter({ points: { zone: 'near' }, worker: false })
|
|
251
|
+
await settleFrames()
|
|
252
|
+
const lockAfter = lockExtents.at(-1)
|
|
253
|
+
const sameExtent = lockBefore && lockAfter &&
|
|
254
|
+
Math.abs(lockBefore.minX - lockAfter.minX) < 1e-6 && Math.abs(lockBefore.minY - lockAfter.minY) < 1e-6 &&
|
|
255
|
+
Math.abs(lockBefore.maxX - lockAfter.maxX) < 1e-6 && Math.abs(lockBefore.maxY - lockAfter.maxY) < 1e-6
|
|
256
|
+
check('鹰眼图 extentFollowContent 默认关闭:外围节点被筛掉后包围盒保持不变',
|
|
257
|
+
lockView.getOptions().minimap.extentFollowContent === false && lockBefore?.maxX === 100 && lockBefore?.maxY === 40 && sameExtent,
|
|
258
|
+
`before=${JSON.stringify(lockBefore)} after=${JSON.stringify(lockAfter)}`)
|
|
259
|
+
lockView.updateOptions({ minimap: { ...lockView.getOptions().minimap, extentFollowContent: true } })
|
|
260
|
+
await settleFrames()
|
|
261
|
+
const lockFollowed = lockExtents.at(-1)
|
|
262
|
+
check('鹰眼图 extentFollowContent 打开后:包围盒按当前可见内容重算',
|
|
263
|
+
lockView.getOptions().minimap.extentFollowContent === true && lockFollowed?.maxX === 10 && lockFollowed?.maxY === 0,
|
|
264
|
+
JSON.stringify(lockFollowed))
|
|
265
|
+
lockView.destroy()
|
|
266
|
+
lockHost.remove()
|
|
267
|
+
// 这一轮:沿用主图规则取描边色(不再是白点)、继承尺寸不受主视图地图倍数影响、框与框选矩形的样式
|
|
268
|
+
const ruleHost = document.createElement('div')
|
|
220
269
|
ruleHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:420px;height:320px'
|
|
221
270
|
document.body.appendChild(ruleHost)
|
|
222
271
|
const ruleView = createGisView(ruleHost, {
|
|
@@ -254,7 +303,11 @@
|
|
|
254
303
|
ruleView.zoomTo(ruleView.getCamera().scale * 3, [210, 160])
|
|
255
304
|
await settleFrames()
|
|
256
305
|
const redZoomed = minimapRed()
|
|
257
|
-
check(
|
|
306
|
+
check(
|
|
307
|
+
'鹰眼图沿用主图规则时主图放大不改变节点尺寸(pointMapZoomScale 也不参与继承)',
|
|
308
|
+
redBefore > 0 && Math.abs(redZoomed - redBefore) <= 2,
|
|
309
|
+
`${redBefore} → ${redZoomed}`
|
|
310
|
+
)
|
|
258
311
|
const boxElement = ruleHost.querySelector('.gis-view__minimap-box')
|
|
259
312
|
const boxComputed = getComputedStyle(boxElement)
|
|
260
313
|
check(
|
|
@@ -319,9 +372,113 @@
|
|
|
319
372
|
bgRedBefore > 0 && Math.abs(bgRedAfter - bgRedBefore) <= Math.max(bgRedBefore * 0.2, 2),
|
|
320
373
|
`主图放大 3 倍前后小图红点像素 ${bgRedBefore} → ${bgRedAfter}`
|
|
321
374
|
)
|
|
322
|
-
bgView.destroy()
|
|
323
|
-
bgHost.remove()
|
|
324
|
-
//
|
|
375
|
+
bgView.destroy()
|
|
376
|
+
bgHost.remove()
|
|
377
|
+
// 这一轮:沿用主图规则时线路线宽也只跟视口比例走 —— 主图放大不变,小图自身放大才按 lineZoomScale 变
|
|
378
|
+
const lineHost = document.createElement('div')
|
|
379
|
+
lineHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:420px;height:320px'
|
|
380
|
+
document.body.appendChild(lineHost)
|
|
381
|
+
const lineView = createGisView(lineHost, {
|
|
382
|
+
points: [{ id: 'a', x: 0, y: 50 }, { id: 'b', x: 100, y: 50 }],
|
|
383
|
+
lines: [{ id: 'l', from: 'a', to: 'b' }],
|
|
384
|
+
background: false,
|
|
385
|
+
pointStyle: { size: 1, color: '#00aa00' },
|
|
386
|
+
lineStyle: { width: 8, color: '#ff3200', opacity: 1 },
|
|
387
|
+
minimap: {
|
|
388
|
+
width: 200,
|
|
389
|
+
height: 160,
|
|
390
|
+
background: false,
|
|
391
|
+
lineStyle: { color: '#ff3200', width: 1, opacity: 1 },
|
|
392
|
+
inheritRules: true,
|
|
393
|
+
pointMapZoomScale: 1,
|
|
394
|
+
lineMapZoomScale: 1,
|
|
395
|
+
lineZoomScale: 1,
|
|
396
|
+
maxZoom: 8
|
|
397
|
+
}
|
|
398
|
+
})
|
|
399
|
+
await settleFrames()
|
|
400
|
+
const lineBefore = minimapRedIn(lineHost)
|
|
401
|
+
lineView.zoomTo(lineView.getCamera().scale * 3, [210, 160])
|
|
402
|
+
await settleFrames()
|
|
403
|
+
const lineAfterMainZoom = minimapRedIn(lineHost)
|
|
404
|
+
check(
|
|
405
|
+
'鹰眼图沿用主图线宽时主图放大不改变线路宽度(lineMapZoomScale 也不参与继承)',
|
|
406
|
+
lineBefore > 20 && Math.abs(lineAfterMainZoom - lineBefore) <= 2,
|
|
407
|
+
`${lineBefore} → ${lineAfterMainZoom}`
|
|
408
|
+
)
|
|
409
|
+
lineView.updateOptions({ minimap: { ...lineView.getOptions().minimap, lineWidthScale: 2 } })
|
|
410
|
+
await settleFrames()
|
|
411
|
+
const lineWidthScaled = minimapRedIn(lineHost)
|
|
412
|
+
check(
|
|
413
|
+
'鹰眼图线路整体倍数 lineWidthScale 对继承线路生效',
|
|
414
|
+
lineWidthScaled > lineAfterMainZoom * 1.5,
|
|
415
|
+
`${lineAfterMainZoom} → ${lineWidthScaled}`
|
|
416
|
+
)
|
|
417
|
+
lineView.updateOptions({ minimap: { ...lineView.getOptions().minimap, lineWidthScale: 1 } })
|
|
418
|
+
await settleFrames()
|
|
419
|
+
lineView.setMinimapZoom(2)
|
|
420
|
+
await settleFrames()
|
|
421
|
+
const lineAfterMiniZoom = minimapRedIn(lineHost)
|
|
422
|
+
check(
|
|
423
|
+
'鹰眼图自身放大时沿用主图的线路按 lineZoomScale 变粗',
|
|
424
|
+
lineAfterMiniZoom > lineAfterMainZoom * 1.6,
|
|
425
|
+
`${lineAfterMainZoom} → ${lineAfterMiniZoom}`
|
|
426
|
+
)
|
|
427
|
+
lineView.destroy()
|
|
428
|
+
lineHost.remove()
|
|
429
|
+
// 沿用主图的节点:主图放大不变,小图自身放大时按 pointZoomScale 变大(pointMapZoomScale 不参与继承)
|
|
430
|
+
const inheritedPointHost = document.createElement('div')
|
|
431
|
+
inheritedPointHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:420px;height:320px'
|
|
432
|
+
document.body.appendChild(inheritedPointHost)
|
|
433
|
+
const inheritedPointView = createGisView(inheritedPointHost, {
|
|
434
|
+
points: [{ id: 'a', x: 45, y: 50 }, { id: 'b', x: 55, y: 50 }],
|
|
435
|
+
lines: [{ id: 'l', from: 'a', to: 'b' }],
|
|
436
|
+
background: false,
|
|
437
|
+
pointStyle: { size: 10, color: '#ff3200' },
|
|
438
|
+
lineStyle: { width: 1.5, color: '#00aa00' },
|
|
439
|
+
minimap: {
|
|
440
|
+
width: 200,
|
|
441
|
+
height: 160,
|
|
442
|
+
background: false,
|
|
443
|
+
extent: { minX: 0, minY: 0, maxX: 100, maxY: 100 },
|
|
444
|
+
inheritRules: true,
|
|
445
|
+
pointZoomScale: 1,
|
|
446
|
+
pointMapZoomScale: 1,
|
|
447
|
+
zoomable: true,
|
|
448
|
+
maxZoom: 8
|
|
449
|
+
}
|
|
450
|
+
})
|
|
451
|
+
await settleFrames()
|
|
452
|
+
const inheritedPointBefore = minimapRedIn(inheritedPointHost)
|
|
453
|
+
inheritedPointView.zoomTo(inheritedPointView.getCamera().scale * 3, [210, 160])
|
|
454
|
+
await settleFrames()
|
|
455
|
+
const inheritedPointAfterMainZoom = minimapRedIn(inheritedPointHost)
|
|
456
|
+
check(
|
|
457
|
+
'鹰眼图沿用主图节点时主图放大不改变节点大小(pointMapZoomScale 也不参与继承)',
|
|
458
|
+
inheritedPointBefore > 10 && Math.abs(inheritedPointAfterMainZoom - inheritedPointBefore) <= 2,
|
|
459
|
+
`${inheritedPointBefore} → ${inheritedPointAfterMainZoom}`
|
|
460
|
+
)
|
|
461
|
+
inheritedPointView.updateOptions({ minimap: { ...inheritedPointView.getOptions().minimap, pointSizeScale: 2 } })
|
|
462
|
+
await settleFrames()
|
|
463
|
+
const inheritedPointSizeScaled = minimapRedIn(inheritedPointHost)
|
|
464
|
+
check(
|
|
465
|
+
'鹰眼图节点整体倍数 pointSizeScale 对继承节点生效',
|
|
466
|
+
inheritedPointSizeScaled > inheritedPointAfterMainZoom * 2,
|
|
467
|
+
`${inheritedPointAfterMainZoom} → ${inheritedPointSizeScaled}`
|
|
468
|
+
)
|
|
469
|
+
inheritedPointView.updateOptions({ minimap: { ...inheritedPointView.getOptions().minimap, pointSizeScale: 1 } })
|
|
470
|
+
await settleFrames()
|
|
471
|
+
inheritedPointView.setMinimapZoom(2)
|
|
472
|
+
await settleFrames()
|
|
473
|
+
const inheritedPointAfterMiniZoom = minimapRedIn(inheritedPointHost)
|
|
474
|
+
check(
|
|
475
|
+
'鹰眼图自身放大时沿用主图的节点按 pointZoomScale 变大',
|
|
476
|
+
inheritedPointAfterMiniZoom > inheritedPointAfterMainZoom * 2,
|
|
477
|
+
`${inheritedPointAfterMainZoom} → ${inheritedPointAfterMiniZoom}`
|
|
478
|
+
)
|
|
479
|
+
inheritedPointView.destroy()
|
|
480
|
+
inheritedPointHost.remove()
|
|
481
|
+
// 这一轮:小图自身倍数的联动指数(pointZoomScale)真的生效 —— 放大鹰眼图 6 倍,节点半径按 6^指数 长
|
|
325
482
|
const zoomHost = document.createElement('div')
|
|
326
483
|
zoomHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:420px;height:320px'
|
|
327
484
|
document.body.appendChild(zoomHost)
|
|
@@ -458,6 +615,193 @@
|
|
|
458
615
|
)
|
|
459
616
|
extraView.destroy()
|
|
460
617
|
extraHost.remove()
|
|
618
|
+
// 本轮鹰眼图五项:回线居中、动态位移、backgroundStyle、主图尺寸 / 图标、外部挂载
|
|
619
|
+
const circuitHost = document.createElement('div')
|
|
620
|
+
circuitHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:420px;height:320px'
|
|
621
|
+
document.body.appendChild(circuitHost)
|
|
622
|
+
let circuitLines = []
|
|
623
|
+
const circuitView = createGisView(circuitHost, {
|
|
624
|
+
points: [{ id: 'ca', x: 0, y: 0 }, { id: 'cb', x: 100, y: 0 }],
|
|
625
|
+
lines: [
|
|
626
|
+
{ id: 'cl1', from: 'ca', to: 'cb' },
|
|
627
|
+
{ id: 'cl2', from: 'ca', to: 'cb' }
|
|
628
|
+
],
|
|
629
|
+
channels: [{ id: 'cch', from: 'ca', to: 'cb', lineIds: ['cl1', 'cl2'] }],
|
|
630
|
+
background: false,
|
|
631
|
+
minimap: {
|
|
632
|
+
width: 200,
|
|
633
|
+
height: 150,
|
|
634
|
+
background: false,
|
|
635
|
+
channelCircuits: true,
|
|
636
|
+
boxStyle: { fillOpacity: 0, strokeWidth: 0 },
|
|
637
|
+
draw: info => { circuitLines = info.data.lines }
|
|
638
|
+
}
|
|
639
|
+
})
|
|
640
|
+
await settleFrames()
|
|
641
|
+
const allCircuitPaths = circuitLines.map(line => line.path)
|
|
642
|
+
circuitLines = []
|
|
643
|
+
circuitView.updateOptions({ minimap: { ...circuitView.getOptions().minimap, channelCircuits: false } })
|
|
644
|
+
await settleFrames()
|
|
645
|
+
const representativePath = circuitLines[0]?.path ?? []
|
|
646
|
+
const expectedCenter = allCircuitPaths.length === 2
|
|
647
|
+
? allCircuitPaths[0].map((coordinate, index) => [
|
|
648
|
+
(coordinate[0] + allCircuitPaths[1][index][0]) / 2,
|
|
649
|
+
(coordinate[1] + allCircuitPaths[1][index][1]) / 2
|
|
650
|
+
])
|
|
651
|
+
: []
|
|
652
|
+
const centeredRepresentative = representativePath.length === expectedCenter.length && representativePath.every((coordinate, index) =>
|
|
653
|
+
Math.abs(coordinate[0] - expectedCenter[index][0]) < 1e-6 && Math.abs(coordinate[1] - expectedCenter[index][1]) < 1e-6
|
|
654
|
+
)
|
|
655
|
+
check(
|
|
656
|
+
'鹰眼图关闭回线后双回线取居中代表线',
|
|
657
|
+
allCircuitPaths.length === 2 && circuitLines.length === 1 && centeredRepresentative,
|
|
658
|
+
`原回线 ${allCircuitPaths.length} 条,代表线 ${circuitLines.length} 条,路径 ${JSON.stringify(representativePath)}`
|
|
659
|
+
)
|
|
660
|
+
circuitView.destroy()
|
|
661
|
+
circuitHost.remove()
|
|
662
|
+
const styleHost = document.createElement('div')
|
|
663
|
+
styleHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:360px;height:260px'
|
|
664
|
+
document.body.appendChild(styleHost)
|
|
665
|
+
const styleView = createGisView(styleHost, {
|
|
666
|
+
points: [],
|
|
667
|
+
lines: [],
|
|
668
|
+
background: { color: '#ffffff' },
|
|
669
|
+
minimap: {
|
|
670
|
+
width: 140,
|
|
671
|
+
height: 90,
|
|
672
|
+
background: 'inherit',
|
|
673
|
+
backgroundStyle: 'rgb(20, 40, 60)',
|
|
674
|
+
boxStyle: { fillOpacity: 0, strokeWidth: 0 }
|
|
675
|
+
}
|
|
676
|
+
})
|
|
677
|
+
await settleFrames()
|
|
678
|
+
const styledRoot = styleView.getMinimapElement()
|
|
679
|
+
const styledCanvas = styledRoot?.querySelector('.gis-view__minimap-canvas')
|
|
680
|
+
const styledPixels = styledCanvas?.getContext('2d').getImageData(0, 0, styledCanvas.width, styledCanvas.height).data ?? []
|
|
681
|
+
let opaqueBackgroundPixels = 0
|
|
682
|
+
for (let index = 3; index < styledPixels.length; index += 4) {
|
|
683
|
+
if (styledPixels[index] > 0) {
|
|
684
|
+
opaqueBackgroundPixels += 1
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
const styledColor = styledRoot ? getComputedStyle(styledRoot).backgroundColor : ''
|
|
688
|
+
check(
|
|
689
|
+
'鹰眼图显式 backgroundStyle 接管容器底色且画布让出底色',
|
|
690
|
+
styledColor === 'rgb(20, 40, 60)' && opaqueBackgroundPixels === 0,
|
|
691
|
+
`容器=${styledColor},画布不透明像素 ${opaqueBackgroundPixels}`
|
|
692
|
+
)
|
|
693
|
+
styleView.destroy()
|
|
694
|
+
styleHost.remove()
|
|
695
|
+
const minimapErrors = []
|
|
696
|
+
const captureMinimapError = event => minimapErrors.push(String(event.error?.stack ?? event.message))
|
|
697
|
+
window.addEventListener('error', captureMinimapError)
|
|
698
|
+
const pointHost = document.createElement('div')
|
|
699
|
+
pointHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:360px;height:260px'
|
|
700
|
+
document.body.appendChild(pointHost)
|
|
701
|
+
const pointView = createGisView(pointHost, {
|
|
702
|
+
points: [
|
|
703
|
+
{ id: 'square-node', x: 0, y: 0 },
|
|
704
|
+
{ id: 'circle-node', x: 100, y: 0 },
|
|
705
|
+
{ id: 'icon-node', x: 200, y: 0 }
|
|
706
|
+
],
|
|
707
|
+
lines: [],
|
|
708
|
+
pointRules: [
|
|
709
|
+
{ name: '小图方点', when: { id: 'square-node' }, style: { size: 64, symbol: 'square', color: '#0088ff', strokeColor: '#0088ff' } },
|
|
710
|
+
{ name: '小图圆点', when: { id: 'circle-node' }, style: { size: 64, symbol: 'circle', color: '#00cc66', strokeColor: '#00cc66' } },
|
|
711
|
+
{ name: '小图图标', when: { id: 'icon-node' }, style: { size: 64, symbol: { type: 'svg', path: 'M0 0H20V20H0Z', viewBox: [0, 0, 20, 20], fill: '#ff00ff' }, color: '#0088ff', strokeColor: '#0088ff' } }
|
|
712
|
+
],
|
|
713
|
+
background: false,
|
|
714
|
+
minimap: {
|
|
715
|
+
width: 220,
|
|
716
|
+
height: 120,
|
|
717
|
+
background: false,
|
|
718
|
+
extent: { minX: -20, minY: -20, maxX: 220, maxY: 20 },
|
|
719
|
+
boxStyle: { fillOpacity: 0, strokeWidth: 0 }
|
|
720
|
+
}
|
|
721
|
+
})
|
|
722
|
+
let pointInk = { blue: 0, green: 0, magenta: 0 }
|
|
723
|
+
for (let attempt = 0; attempt < 15; attempt += 1) {
|
|
724
|
+
await new Promise(resolve => setTimeout(resolve, 60))
|
|
725
|
+
const pointCanvas = pointView.getMinimapElement()?.querySelector('.gis-view__minimap-canvas')
|
|
726
|
+
const pointPixels = pointCanvas?.getContext('2d').getImageData(0, 0, pointCanvas.width, pointCanvas.height).data ?? []
|
|
727
|
+
pointInk = { blue: 0, green: 0, magenta: 0 }
|
|
728
|
+
for (let index = 0; index < pointPixels.length; index += 4) {
|
|
729
|
+
const red = pointPixels[index]
|
|
730
|
+
const green = pointPixels[index + 1]
|
|
731
|
+
const blue = pointPixels[index + 2]
|
|
732
|
+
if (red < 60 && green > 80 && green < 190 && blue > 200) {
|
|
733
|
+
pointInk.blue += 1
|
|
734
|
+
}
|
|
735
|
+
if (red < 60 && green > 150 && blue < 140) {
|
|
736
|
+
pointInk.green += 1
|
|
737
|
+
}
|
|
738
|
+
if (red > 220 && green < 50 && blue > 220) {
|
|
739
|
+
pointInk.magenta += 1
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (pointInk.magenta > 500 && pointInk.blue > 500 && pointInk.green > 500) {
|
|
743
|
+
break
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
const circleSquareRatio = pointInk.blue ? pointInk.green / pointInk.blue : 0
|
|
747
|
+
check(
|
|
748
|
+
'鹰眼图沿用主图规则后尺寸与 SVG 图标一致',
|
|
749
|
+
pointInk.blue > 500 && pointInk.green > 500 && pointInk.magenta > 500 && circleSquareRatio > 0.85 && circleSquareRatio < 1.15 && minimapErrors.length === 0,
|
|
750
|
+
'方点 ' + pointInk.blue + 'px,圆点 ' + pointInk.green + 'px(比值 ' + circleSquareRatio.toFixed(2) + '),图标 ' + pointInk.magenta + 'px,错误 ' + (minimapErrors[0] ?? '无')
|
|
751
|
+
)
|
|
752
|
+
pointView.destroy()
|
|
753
|
+
pointHost.remove()
|
|
754
|
+
window.removeEventListener('error', captureMinimapError)
|
|
755
|
+
const externalHostId = 'minimap-ext-' + Math.random().toString(36).slice(2)
|
|
756
|
+
const alternateHostId = 'minimap-alt-' + Math.random().toString(36).slice(2)
|
|
757
|
+
const externalHost = document.createElement('div')
|
|
758
|
+
externalHost.id = externalHostId
|
|
759
|
+
externalHost.style.cssText = 'position:fixed;left:-9999px;top:340px;width:280px;height:200px;background:#eef4fb'
|
|
760
|
+
const alternateHost = document.createElement('div')
|
|
761
|
+
alternateHost.id = alternateHostId
|
|
762
|
+
alternateHost.style.cssText = 'position:fixed;left:-9999px;top:560px;width:280px;height:200px;background:#f7eefb'
|
|
763
|
+
const externalViewHost = document.createElement('div')
|
|
764
|
+
externalViewHost.style.cssText = 'position:fixed;left:-9999px;top:0;width:360px;height:260px'
|
|
765
|
+
document.body.append(externalHost, alternateHost, externalViewHost)
|
|
766
|
+
const externalView = createGisView(externalViewHost, {
|
|
767
|
+
points: [{ id: 'ext-a', x: 0, y: 0 }, { id: 'ext-b', x: 30, y: 20 }],
|
|
768
|
+
lines: [{ id: 'ext-l', from: 'ext-a', to: 'ext-b' }],
|
|
769
|
+
background: false,
|
|
770
|
+
minimap: {
|
|
771
|
+
width: 140,
|
|
772
|
+
height: 90,
|
|
773
|
+
margin: 10,
|
|
774
|
+
background: false,
|
|
775
|
+
container: externalHost,
|
|
776
|
+
boxStyle: { fillOpacity: 0, strokeWidth: 0 }
|
|
777
|
+
}
|
|
778
|
+
})
|
|
779
|
+
await settleFrames()
|
|
780
|
+
const externalRoot = externalView.getMinimapElement()
|
|
781
|
+
const beforeMoveRect = externalRoot?.getBoundingClientRect()
|
|
782
|
+
externalView.updateOptions({ minimap: { ...externalView.getOptions().minimap, offset: [30, 20] } })
|
|
783
|
+
await settleFrames()
|
|
784
|
+
const afterMoveRect = externalRoot?.getBoundingClientRect()
|
|
785
|
+
const moved = Boolean(beforeMoveRect && afterMoveRect &&
|
|
786
|
+
Math.abs(afterMoveRect.left - beforeMoveRect.left - 30) < 0.75 &&
|
|
787
|
+
Math.abs(afterMoveRect.top - beforeMoveRect.top - 20) < 0.75)
|
|
788
|
+
check(
|
|
789
|
+
'鹰眼图能挂到外部 div,并用 offset 动态移动整张图',
|
|
790
|
+
externalRoot?.parentElement === externalHost && externalViewHost.querySelector('.gis-view__minimap') === null && moved,
|
|
791
|
+
'父元素 ' + (externalRoot?.parentElement?.id ?? 'null') + ',位移 ' + (beforeMoveRect ? Math.round(afterMoveRect.left - beforeMoveRect.left) + ',' + Math.round(afterMoveRect.top - beforeMoveRect.top) : 'null')
|
|
792
|
+
)
|
|
793
|
+
externalView.updateOptions({ minimap: { ...externalView.getOptions().minimap, container: '#' + alternateHostId } })
|
|
794
|
+
await settleFrames()
|
|
795
|
+
const movedHost = externalView.getMinimapElement() === externalRoot && externalRoot?.parentElement === alternateHost
|
|
796
|
+
externalView.destroy()
|
|
797
|
+
check(
|
|
798
|
+
'鹰眼图换外部容器复用同一根节点,destroy 后一并清理',
|
|
799
|
+
movedHost && !externalRoot?.isConnected && !alternateHost.querySelector('.gis-view__minimap'),
|
|
800
|
+
'换容器 ' + movedHost + ',销毁后 connected=' + (externalRoot?.isConnected ?? false)
|
|
801
|
+
)
|
|
802
|
+
externalHost.remove()
|
|
803
|
+
alternateHost.remove()
|
|
804
|
+
externalViewHost.remove()
|
|
461
805
|
// 宿主缩放(CSS zoom / 祖先的 transform: scale):引擎的 CSS 像素按布局像素算、画布备份仍是设备像素、
|
|
462
806
|
// DOM 标签与指针换算同除显示比例;三样对不上时,标签会飞出节点、指针也点不中
|
|
463
807
|
const plainScaleHost = document.createElement('div')
|