@movk/maplibre 1.0.0 → 1.1.0
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.en.md +2 -2
- package/README.md +2 -2
- package/dist/module.d.mts +7 -0
- package/dist/module.d.ts +7 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +25 -11
- package/dist/runtime/components/CustomLayer.d.vue.ts +1 -1
- package/dist/runtime/components/CustomLayer.vue +18 -4
- package/dist/runtime/components/CustomLayer.vue.d.ts +1 -1
- package/dist/runtime/components/Layer.d.vue.ts +4 -4
- package/dist/runtime/components/Layer.vue +43 -18
- package/dist/runtime/components/Layer.vue.d.ts +4 -4
- package/dist/runtime/components/LayerGroup.d.vue.ts +23 -10
- package/dist/runtime/components/LayerGroup.vue +44 -4
- package/dist/runtime/components/LayerGroup.vue.d.ts +23 -10
- package/dist/runtime/components/LottieMarker.d.vue.ts +3 -3
- package/dist/runtime/components/LottieMarker.vue +6 -2
- package/dist/runtime/components/LottieMarker.vue.d.ts +3 -3
- package/dist/runtime/components/Map.d.vue.ts +2 -1
- package/dist/runtime/components/Map.vue +2 -6
- package/dist/runtime/components/Map.vue.d.ts +2 -1
- package/dist/runtime/components/Marker.d.vue.ts +2 -1
- package/dist/runtime/components/Marker.vue +33 -9
- package/dist/runtime/components/Marker.vue.d.ts +2 -1
- package/dist/runtime/components/Popup.d.vue.ts +1 -1
- package/dist/runtime/components/Popup.vue +23 -4
- package/dist/runtime/components/Popup.vue.d.ts +1 -1
- package/dist/runtime/components/Source.d.vue.ts +2 -2
- package/dist/runtime/components/Source.vue +3 -15
- package/dist/runtime/components/Source.vue.d.ts +2 -2
- package/dist/runtime/components/Tooltip.d.vue.ts +2 -2
- package/dist/runtime/components/Tooltip.vue +47 -19
- package/dist/runtime/components/Tooltip.vue.d.ts +2 -2
- package/dist/runtime/components/buffers/BufferCircle.d.vue.ts +1 -1
- package/dist/runtime/components/buffers/BufferCircle.vue.d.ts +1 -1
- package/dist/runtime/components/buffers/BufferEllipse.d.vue.ts +1 -1
- package/dist/runtime/components/buffers/BufferEllipse.vue.d.ts +1 -1
- package/dist/runtime/components/buffers/BufferLine.d.vue.ts +1 -1
- package/dist/runtime/components/buffers/BufferLine.vue.d.ts +1 -1
- package/dist/runtime/components/buffers/BufferPolygon.d.vue.ts +1 -1
- package/dist/runtime/components/buffers/BufferPolygon.vue.d.ts +1 -1
- package/dist/runtime/components/buffers/BufferSector.d.vue.ts +1 -1
- package/dist/runtime/components/buffers/BufferSector.vue.d.ts +1 -1
- package/dist/runtime/components/controls/BasemapControl.d.vue.ts +35 -0
- package/dist/runtime/components/controls/BasemapControl.vue +60 -0
- package/dist/runtime/components/controls/BasemapControl.vue.d.ts +35 -0
- package/dist/runtime/components/controls/Control.d.vue.ts +51 -0
- package/dist/runtime/components/controls/Control.vue +95 -0
- package/dist/runtime/components/controls/Control.vue.d.ts +51 -0
- package/dist/runtime/components/controls/GlobeControl.d.vue.ts +18 -0
- package/dist/runtime/components/controls/GlobeControl.vue +15 -0
- package/dist/runtime/components/controls/GlobeControl.vue.d.ts +18 -0
- package/dist/runtime/components/controls/LayerControl.d.vue.ts +44 -0
- package/dist/runtime/components/controls/LayerControl.vue +63 -0
- package/dist/runtime/components/controls/LayerControl.vue.d.ts +44 -0
- package/dist/runtime/components/controls/Legend.d.vue.ts +47 -0
- package/dist/runtime/components/controls/Legend.vue +69 -0
- package/dist/runtime/components/controls/Legend.vue.d.ts +47 -0
- package/dist/runtime/components/controls/Minimap.d.vue.ts +45 -0
- package/dist/runtime/components/controls/Minimap.vue +31 -0
- package/dist/runtime/components/controls/Minimap.vue.d.ts +45 -0
- package/dist/runtime/components/effects/AnimatedImage.d.vue.ts +1 -1
- package/dist/runtime/components/effects/AnimatedImage.vue +9 -6
- package/dist/runtime/components/effects/AnimatedImage.vue.d.ts +1 -1
- package/dist/runtime/components/effects/DiffusionCircle.d.vue.ts +1 -1
- package/dist/runtime/components/effects/DiffusionCircle.vue.d.ts +1 -1
- package/dist/runtime/components/effects/FlowBuilding.d.vue.ts +1 -1
- package/dist/runtime/components/effects/FlowBuilding.vue.d.ts +1 -1
- package/dist/runtime/components/effects/GlowCircle.d.vue.ts +1 -1
- package/dist/runtime/components/effects/GlowCircle.vue.d.ts +1 -1
- package/dist/runtime/components/effects/GradientBuilding.d.vue.ts +1 -1
- package/dist/runtime/components/effects/GradientBuilding.vue.d.ts +1 -1
- package/dist/runtime/components/effects/Migration.d.vue.ts +1 -1
- package/dist/runtime/components/effects/Migration.vue.d.ts +1 -1
- package/dist/runtime/components/effects/Radar.d.vue.ts +1 -1
- package/dist/runtime/components/effects/Radar.vue.d.ts +1 -1
- package/dist/runtime/components/effects/SpriteImage.d.vue.ts +1 -1
- package/dist/runtime/components/effects/SpriteImage.vue +40 -24
- package/dist/runtime/components/effects/SpriteImage.vue.d.ts +1 -1
- package/dist/runtime/components/effects/TextureBuilding.d.vue.ts +1 -1
- package/dist/runtime/components/effects/TextureBuilding.vue +1 -1
- package/dist/runtime/components/effects/TextureBuilding.vue.d.ts +1 -1
- package/dist/runtime/components/effects/Trail.d.vue.ts +1 -1
- package/dist/runtime/components/effects/Trail.vue.d.ts +1 -1
- package/dist/runtime/components/effects/WaveCircle.d.vue.ts +1 -1
- package/dist/runtime/components/effects/WaveCircle.vue.d.ts +1 -1
- package/dist/runtime/components/effects/WindowBuilding.d.vue.ts +1 -1
- package/dist/runtime/components/effects/WindowBuilding.vue.d.ts +1 -1
- package/dist/runtime/components/environment/Projection.d.vue.ts +28 -0
- package/dist/runtime/components/environment/Projection.vue +27 -0
- package/dist/runtime/components/environment/Projection.vue.d.ts +28 -0
- package/dist/runtime/components/environment/Temperature.d.vue.ts +1 -1
- package/dist/runtime/components/environment/Temperature.vue.d.ts +1 -1
- package/dist/runtime/components/environment/Terrain.d.vue.ts +1 -1
- package/dist/runtime/components/environment/Terrain.vue +5 -0
- package/dist/runtime/components/environment/Terrain.vue.d.ts +1 -1
- package/dist/runtime/components/extensions/DrawControl.vue +23 -19
- package/dist/runtime/components/extensions/Swipe.d.vue.ts +48 -0
- package/dist/runtime/components/extensions/Swipe.vue +141 -0
- package/dist/runtime/components/extensions/Swipe.vue.d.ts +48 -0
- package/dist/runtime/components/layers/BuildingLayer.d.vue.ts +1 -1
- package/dist/runtime/components/layers/BuildingLayer.vue.d.ts +1 -1
- package/dist/runtime/components/layers/ClusterLayer.d.vue.ts +1 -1
- package/dist/runtime/components/layers/ClusterLayer.vue.d.ts +1 -1
- package/dist/runtime/components/layers/ContourLayer.d.vue.ts +59 -0
- package/dist/runtime/components/layers/ContourLayer.vue +84 -0
- package/dist/runtime/components/layers/ContourLayer.vue.d.ts +59 -0
- package/dist/runtime/components/layers/GraticuleLayer.d.vue.ts +31 -0
- package/dist/runtime/components/layers/GraticuleLayer.vue +88 -0
- package/dist/runtime/components/layers/GraticuleLayer.vue.d.ts +31 -0
- package/dist/runtime/components/layers/ImageLayer.d.vue.ts +1 -1
- package/dist/runtime/components/layers/ImageLayer.vue.d.ts +1 -1
- package/dist/runtime/components/layers/MaskLayer.d.vue.ts +44 -0
- package/dist/runtime/components/layers/MaskLayer.vue +32 -0
- package/dist/runtime/components/layers/MaskLayer.vue.d.ts +44 -0
- package/dist/runtime/components/layers/RasterLayer.d.vue.ts +5 -3
- package/dist/runtime/components/layers/RasterLayer.vue +9 -2
- package/dist/runtime/components/layers/RasterLayer.vue.d.ts +5 -3
- package/dist/runtime/components/layers/VideoLayer.d.vue.ts +1 -1
- package/dist/runtime/components/layers/VideoLayer.vue.d.ts +1 -1
- package/dist/runtime/composables/useFeatureState.js +27 -5
- package/dist/runtime/composables/useFrameIcon.d.ts +4 -3
- package/dist/runtime/composables/useFrameIcon.js +18 -8
- package/dist/runtime/composables/useLayerTree.d.ts +11 -0
- package/dist/runtime/composables/useLayerTree.js +12 -0
- package/dist/runtime/composables/useMapAnimation.d.ts +4 -2
- package/dist/runtime/composables/useMapAnimation.js +5 -4
- package/dist/runtime/composables/useMapExport.js +2 -5
- package/dist/runtime/composables/useMapSync.d.ts +16 -0
- package/dist/runtime/composables/useMapSync.js +42 -0
- package/dist/runtime/composables/useMaplibreCamera.d.ts +1 -1
- package/dist/runtime/composables/useMaplibreCamera.js +1 -1
- package/dist/runtime/composables/useMaplibreImage.d.ts +3 -3
- package/dist/runtime/composables/useMaplibreImage.js +26 -5
- package/dist/runtime/domains/map/config.js +2 -3
- package/dist/runtime/domains/map/context.js +15 -0
- package/dist/runtime/domains/map/control.d.ts +1 -1
- package/dist/runtime/domains/map/control.js +1 -1
- package/dist/runtime/domains/map/draw-modes.d.ts +9 -0
- package/dist/runtime/domains/map/draw-modes.js +53 -0
- package/dist/runtime/domains/map/draw-registry.d.ts +2 -3
- package/dist/runtime/domains/map/draw-registry.js +6 -9
- package/dist/runtime/domains/map/draw-theme.d.ts +12 -0
- package/dist/runtime/domains/map/draw-toolbar.js +11 -10
- package/dist/runtime/domains/map/layer-group.d.ts +15 -4
- package/dist/runtime/domains/map/layer-tree.d.ts +3 -0
- package/dist/runtime/domains/map/layer-tree.js +10 -0
- package/dist/runtime/domains/map/minimap.d.ts +18 -0
- package/dist/runtime/domains/map/minimap.js +86 -0
- package/dist/runtime/domains/map/registry.js +4 -3
- package/dist/runtime/domains/map/style-layers.d.ts +7 -0
- package/dist/runtime/domains/map/style-layers.js +54 -0
- package/dist/runtime/domains/map/style.d.ts +3 -0
- package/dist/runtime/domains/map/style.js +5 -0
- package/dist/runtime/domains/map/swipe.d.ts +9 -0
- package/dist/runtime/domains/map/swipe.js +62 -0
- package/dist/runtime/index.css +1 -1
- package/dist/runtime/types/draw.d.ts +34 -1
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/types/layer.d.ts +40 -0
- package/dist/runtime/types/layer.js +0 -0
- package/dist/runtime/types/map.d.ts +6 -0
- package/dist/runtime/utils/cog.d.ts +2 -0
- package/dist/runtime/utils/cog.js +9 -0
- package/dist/runtime/utils/effects.js +2 -1
- package/dist/runtime/utils/events.d.ts +6 -0
- package/dist/runtime/utils/events.js +25 -0
- package/dist/runtime/utils/frame-icon.d.ts +2 -5
- package/dist/runtime/utils/frame-icon.js +10 -4
- package/dist/runtime/utils/graticule.d.ts +19 -0
- package/dist/runtime/utils/graticule.js +62 -0
- package/dist/runtime/utils/layer-opacity.d.ts +7 -0
- package/dist/runtime/utils/layer-opacity.js +59 -0
- package/dist/runtime/utils/layer.js +2 -1
- package/dist/runtime/utils/legend.d.ts +9 -0
- package/dist/runtime/utils/legend.js +52 -0
- package/dist/runtime/utils/marker.d.ts +11 -0
- package/dist/runtime/utils/marker.js +28 -0
- package/dist/runtime/utils/mask.d.ts +8 -0
- package/dist/runtime/utils/mask.js +33 -0
- package/dist/runtime/utils/minimap.d.ts +6 -0
- package/dist/runtime/utils/minimap.js +15 -0
- package/dist/runtime/utils/pmtiles.d.ts +3 -0
- package/dist/runtime/utils/pmtiles.js +10 -0
- package/dist/runtime/utils/source.d.ts +7 -0
- package/dist/runtime/utils/source.js +35 -0
- package/dist/runtime/utils/swipe.d.ts +32 -0
- package/dist/runtime/utils/swipe.js +18 -0
- package/dist/runtime/utils/tianditu.d.ts +10 -1
- package/dist/runtime/utils/tianditu.js +11 -0
- package/dist/unplugin.d.mts +1 -1
- package/dist/unplugin.d.ts +1 -1
- package/dist/unplugin.mjs +1 -7
- package/package.json +20 -12
- package/dist/runtime/draw-modes/index.d.ts +0 -16
- package/dist/runtime/draw-modes/index.js +0 -32
- package/dist/runtime/utils/draw-theme.d.ts +0 -47
- /package/dist/runtime/{utils → domains/map}/draw-theme.js +0 -0
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { onMounted, onUnmounted, ref, useSlots, useTemplateRef, watch } from "vue";
|
|
3
3
|
import { Marker } from "maplibre-gl";
|
|
4
4
|
import { useMap } from "../composables/useMap";
|
|
5
|
+
import { isDeepEqual } from "@movk/core";
|
|
6
|
+
import { applyMarkerOptions, markerNeedsRebuild, removeMarkerClassName } from "../utils/marker";
|
|
5
7
|
import MaplibrePopup from "./Popup.vue";
|
|
6
8
|
const props = defineProps({
|
|
7
9
|
options: { type: Object, required: false },
|
|
@@ -15,7 +17,9 @@ const slots = useSlots();
|
|
|
15
17
|
const el = useTemplateRef("el");
|
|
16
18
|
const ready = ref(false);
|
|
17
19
|
let marker;
|
|
20
|
+
let applied = {};
|
|
18
21
|
let unbindTrigger;
|
|
22
|
+
let disposed = false;
|
|
19
23
|
function openPopup() {
|
|
20
24
|
open.value = true;
|
|
21
25
|
}
|
|
@@ -46,25 +50,45 @@ function bindTrigger() {
|
|
|
46
50
|
element.removeEventListener("mouseleave", closePopup);
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
function onDragEnd() {
|
|
54
|
+
if (!marker) return;
|
|
55
|
+
const { lng, lat } = marker.getLngLat();
|
|
56
|
+
lnglat.value = [lng, lat];
|
|
57
|
+
}
|
|
58
|
+
function createMarker(map) {
|
|
51
59
|
const useSlot = Boolean(slots.default && el.value);
|
|
52
|
-
|
|
60
|
+
applied = { ...props.options };
|
|
61
|
+
marker = new Marker({ ...applied, ...useSlot ? { element: el.value } : {} });
|
|
53
62
|
marker.setLngLat(lnglat.value).addTo(map);
|
|
54
|
-
|
|
63
|
+
marker.on("dragend", onDragEnd);
|
|
55
64
|
bindTrigger();
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
}
|
|
66
|
+
onMounted(async () => {
|
|
67
|
+
const map = await ctx.whenAttached();
|
|
68
|
+
if (disposed) return;
|
|
69
|
+
createMarker(map);
|
|
70
|
+
ready.value = true;
|
|
71
|
+
});
|
|
72
|
+
watch(() => props.options, (value) => {
|
|
73
|
+
const map = ctx.map.value;
|
|
74
|
+
const next = value ?? {};
|
|
75
|
+
if (!marker || !map || isDeepEqual(next, applied)) return;
|
|
76
|
+
if (markerNeedsRebuild(next, applied)) {
|
|
77
|
+
removeMarkerClassName(marker, applied.className);
|
|
78
|
+
unbindTrigger?.();
|
|
79
|
+
marker.remove();
|
|
80
|
+
createMarker(map);
|
|
81
|
+
return;
|
|
61
82
|
}
|
|
83
|
+
applyMarkerOptions(marker, next, applied);
|
|
84
|
+
applied = { ...next };
|
|
62
85
|
});
|
|
63
86
|
watch(lnglat, (value) => {
|
|
64
87
|
if (value) marker?.setLngLat(value);
|
|
65
88
|
});
|
|
66
89
|
watch(() => props.trigger, bindTrigger);
|
|
67
90
|
onUnmounted(() => {
|
|
91
|
+
disposed = true;
|
|
68
92
|
unbindTrigger?.();
|
|
69
93
|
marker?.remove();
|
|
70
94
|
});
|
|
@@ -3,7 +3,8 @@ import type { LngLatLike, MarkerOptions, PopupOptions } from 'maplibre-gl';
|
|
|
3
3
|
import type { PopupTrigger } from '../types';
|
|
4
4
|
type __VLS_Props = {
|
|
5
5
|
/**
|
|
6
|
-
* 标记选项;element
|
|
6
|
+
* 标记选项;element 由默认插槽提供,无需在此传入。
|
|
7
|
+
* 有 setter 的字段(rotation、draggable 等)增量更新,anchor、color、scale 变化时重建
|
|
7
8
|
* @see https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MarkerOptions/
|
|
8
9
|
*/
|
|
9
10
|
options?: Omit<MarkerOptions, 'element'>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { onMounted, onUnmounted, useTemplateRef, watch } from "vue";
|
|
3
3
|
import { Popup } from "maplibre-gl";
|
|
4
4
|
import { useMap } from "../composables/useMap";
|
|
5
|
+
import { isDeepEqual } from "@movk/core";
|
|
5
6
|
const props = defineProps({
|
|
6
7
|
lnglat: { type: [Object, Array], required: true },
|
|
7
8
|
options: { type: Object, required: false }
|
|
@@ -11,16 +12,34 @@ defineOptions({ inheritAttrs: false });
|
|
|
11
12
|
const ctx = useMap();
|
|
12
13
|
const el = useTemplateRef("el");
|
|
13
14
|
let popup;
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
let disposed = false;
|
|
16
|
+
function onClose() {
|
|
17
|
+
emit("close");
|
|
18
|
+
}
|
|
19
|
+
function createPopup(map) {
|
|
16
20
|
popup = new Popup(props.options);
|
|
17
21
|
popup.setLngLat(props.lnglat);
|
|
18
22
|
if (el.value) popup.setDOMContent(el.value);
|
|
19
|
-
popup.on("close",
|
|
23
|
+
popup.on("close", onClose);
|
|
20
24
|
popup.addTo(map);
|
|
25
|
+
}
|
|
26
|
+
onMounted(async () => {
|
|
27
|
+
const map = await ctx.whenAttached();
|
|
28
|
+
if (disposed) return;
|
|
29
|
+
createPopup(map);
|
|
21
30
|
});
|
|
22
31
|
watch(() => props.lnglat, (value) => popup?.setLngLat(value));
|
|
23
|
-
|
|
32
|
+
watch(() => props.options, (next, prev) => {
|
|
33
|
+
const map = ctx.map.value;
|
|
34
|
+
if (!popup || !map || isDeepEqual(next, prev)) return;
|
|
35
|
+
popup.off("close", onClose);
|
|
36
|
+
popup.remove();
|
|
37
|
+
createPopup(map);
|
|
38
|
+
});
|
|
39
|
+
onUnmounted(() => {
|
|
40
|
+
disposed = true;
|
|
41
|
+
popup?.remove();
|
|
42
|
+
});
|
|
24
43
|
defineExpose({ popup: () => popup });
|
|
25
44
|
</script>
|
|
26
45
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { SourceSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
2
2
|
type __VLS_Props = {
|
|
3
|
-
/** 数据源 id,供图层经 source
|
|
3
|
+
/** 数据源 id,供图层经 source 字段按字符串引用;变更需配合 `:key` 重建 */
|
|
4
4
|
sourceId: string;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* 数据源定义,变化时按类型增量更新(setData / setTiles 等)
|
|
7
7
|
* @see https://maplibre.org/maplibre-style-spec/sources/
|
|
8
8
|
*/
|
|
9
9
|
source: SourceSpecification;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { onUnmounted, watch } from "vue";
|
|
3
3
|
import { useMap } from "../composables/useMap";
|
|
4
|
+
import { updateSource } from "../utils/source";
|
|
4
5
|
const props = defineProps({
|
|
5
6
|
sourceId: { type: String, required: true },
|
|
6
7
|
source: { type: Object, required: true }
|
|
@@ -11,22 +12,9 @@ const stopReady = ctx.onReady((map) => {
|
|
|
11
12
|
map.addSource(props.sourceId, props.source);
|
|
12
13
|
}
|
|
13
14
|
});
|
|
14
|
-
watch(() => props.source, (next) => {
|
|
15
|
+
watch(() => props.source, (next, prev) => {
|
|
15
16
|
const source = ctx.map.value?.getSource(props.sourceId);
|
|
16
|
-
if (
|
|
17
|
-
if (next.type === "geojson" && next.data) {
|
|
18
|
-
source.setData(next.data);
|
|
19
|
-
} else if (next.type === "vector") {
|
|
20
|
-
if (next.url) source.setUrl(next.url);
|
|
21
|
-
if (next.tiles) source.setTiles(next.tiles);
|
|
22
|
-
} else if (next.type === "raster" || next.type === "raster-dem") {
|
|
23
|
-
if (next.url) source.setUrl(next.url);
|
|
24
|
-
if (next.tiles) source.setTiles(next.tiles);
|
|
25
|
-
} else if (next.type === "image" && next.url) {
|
|
26
|
-
source.updateImage(next);
|
|
27
|
-
} else if (next.type === "video" && next.coordinates) {
|
|
28
|
-
source.setCoordinates(next.coordinates);
|
|
29
|
-
}
|
|
17
|
+
if (source) updateSource(source, next, prev);
|
|
30
18
|
}, { deep: true });
|
|
31
19
|
onUnmounted(() => {
|
|
32
20
|
stopReady();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { SourceSpecification } from '@maplibre/maplibre-gl-style-spec';
|
|
2
2
|
type __VLS_Props = {
|
|
3
|
-
/** 数据源 id,供图层经 source
|
|
3
|
+
/** 数据源 id,供图层经 source 字段按字符串引用;变更需配合 `:key` 重建 */
|
|
4
4
|
sourceId: string;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* 数据源定义,变化时按类型增量更新(setData / setTiles 等)
|
|
7
7
|
* @see https://maplibre.org/maplibre-style-spec/sources/
|
|
8
8
|
*/
|
|
9
9
|
source: SourceSpecification;
|
|
@@ -2,10 +2,10 @@ import type { GeoJSONFeature, PopupOptions } from 'maplibre-gl';
|
|
|
2
2
|
import type { PopupTrigger } from '../types';
|
|
3
3
|
/** 目标图层要素的弹窗:按 trigger 以悬浮或点击触发,作用域插槽拿到当前要素。 */
|
|
4
4
|
type __VLS_Props = {
|
|
5
|
-
/** 目标图层 id */
|
|
5
|
+
/** 目标图层 id;变化时改绑到新图层 */
|
|
6
6
|
layerId: string;
|
|
7
7
|
/**
|
|
8
|
-
* Popup 选项(hover 模式下 closeButton/closeOnClick
|
|
8
|
+
* Popup 选项(hover 模式下 closeButton/closeOnClick 由组件接管);值变化时重建弹窗
|
|
9
9
|
* @see https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/PopupOptions/
|
|
10
10
|
*/
|
|
11
11
|
options?: PopupOptions;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { onMounted, onUnmounted, shallowRef, useTemplateRef, watch } from "vue";
|
|
3
3
|
import { Popup } from "maplibre-gl";
|
|
4
4
|
import { useMap } from "../composables/useMap";
|
|
5
|
+
import { isDeepEqual } from "@movk/core";
|
|
6
|
+
import { onLayerDataChange } from "../utils/events";
|
|
5
7
|
const props = defineProps({
|
|
6
8
|
layerId: { type: String, required: true },
|
|
7
9
|
options: { type: Object, required: false },
|
|
@@ -12,22 +14,35 @@ const ctx = useMap();
|
|
|
12
14
|
const el = useTemplateRef("el");
|
|
13
15
|
const hovered = shallowRef();
|
|
14
16
|
let popup;
|
|
17
|
+
let anchor;
|
|
15
18
|
let unbind;
|
|
19
|
+
let disposed = false;
|
|
16
20
|
function setCursor(value) {
|
|
17
21
|
const map = ctx.map.value;
|
|
18
22
|
if (map) map.getCanvas().style.cursor = value;
|
|
19
23
|
}
|
|
20
|
-
function
|
|
24
|
+
function open(lngLat, feature) {
|
|
21
25
|
const map = ctx.map.value;
|
|
22
26
|
if (!map || !popup || !el.value) return;
|
|
23
|
-
hovered.value =
|
|
24
|
-
|
|
27
|
+
hovered.value = feature;
|
|
28
|
+
anchor = lngLat;
|
|
29
|
+
popup.setLngLat(lngLat).setDOMContent(el.value);
|
|
25
30
|
if (!popup.isOpen()) popup.addTo(map);
|
|
26
31
|
}
|
|
32
|
+
function show(event) {
|
|
33
|
+
open(event.lngLat, event.features?.[0]);
|
|
34
|
+
}
|
|
27
35
|
function close() {
|
|
28
36
|
hovered.value = void 0;
|
|
37
|
+
anchor = void 0;
|
|
29
38
|
popup?.remove();
|
|
30
39
|
}
|
|
40
|
+
function revalidate(map) {
|
|
41
|
+
if (!popup?.isOpen() || !anchor) return;
|
|
42
|
+
const [feature] = map.queryRenderedFeatures(map.project(anchor), { layers: [props.layerId] });
|
|
43
|
+
if (feature) hovered.value = feature;
|
|
44
|
+
else close();
|
|
45
|
+
}
|
|
31
46
|
function onMove(event) {
|
|
32
47
|
setCursor(props.cursor);
|
|
33
48
|
show(event);
|
|
@@ -50,22 +65,26 @@ function popupOptions() {
|
|
|
50
65
|
}
|
|
51
66
|
function bind(map) {
|
|
52
67
|
if (props.trigger === "none") return;
|
|
68
|
+
const { layerId } = props;
|
|
69
|
+
const stopDataChange = onLayerDataChange(map, layerId, () => revalidate(map));
|
|
53
70
|
if (props.trigger === "hover") {
|
|
54
|
-
map.on("mousemove",
|
|
55
|
-
map.on("mouseleave",
|
|
71
|
+
map.on("mousemove", layerId, onMove);
|
|
72
|
+
map.on("mouseleave", layerId, onLeave);
|
|
56
73
|
unbind = () => {
|
|
57
|
-
|
|
58
|
-
map.off("
|
|
74
|
+
stopDataChange();
|
|
75
|
+
map.off("mousemove", layerId, onMove);
|
|
76
|
+
map.off("mouseleave", layerId, onLeave);
|
|
59
77
|
};
|
|
60
78
|
return;
|
|
61
79
|
}
|
|
62
|
-
map.on("click",
|
|
63
|
-
map.on("mouseenter",
|
|
64
|
-
map.on("mouseleave",
|
|
80
|
+
map.on("click", layerId, onClick);
|
|
81
|
+
map.on("mouseenter", layerId, onEnter);
|
|
82
|
+
map.on("mouseleave", layerId, onLeaveCursor);
|
|
65
83
|
unbind = () => {
|
|
66
|
-
|
|
67
|
-
map.off("
|
|
68
|
-
map.off("
|
|
84
|
+
stopDataChange();
|
|
85
|
+
map.off("click", layerId, onClick);
|
|
86
|
+
map.off("mouseenter", layerId, onEnter);
|
|
87
|
+
map.off("mouseleave", layerId, onLeaveCursor);
|
|
69
88
|
};
|
|
70
89
|
}
|
|
71
90
|
function teardown() {
|
|
@@ -81,16 +100,25 @@ function setup(map) {
|
|
|
81
100
|
bind(map);
|
|
82
101
|
}
|
|
83
102
|
onMounted(async () => {
|
|
84
|
-
const map = await ctx.
|
|
103
|
+
const map = await ctx.whenAttached();
|
|
104
|
+
if (disposed) return;
|
|
85
105
|
setup(map);
|
|
86
106
|
});
|
|
87
|
-
watch(
|
|
88
|
-
|
|
89
|
-
|
|
107
|
+
watch(
|
|
108
|
+
[() => props.trigger, () => props.layerId, () => props.options],
|
|
109
|
+
([trigger, layerId, options], [prevTrigger, prevLayerId, prevOptions]) => {
|
|
110
|
+
const map = ctx.map.value;
|
|
111
|
+
if (!map || !popup || trigger === prevTrigger && layerId === prevLayerId && isDeepEqual(options, prevOptions)) return;
|
|
112
|
+
const restore = trigger === "click" && trigger === prevTrigger && layerId === prevLayerId && popup.isOpen() && anchor ? { lngLat: anchor, feature: hovered.value } : void 0;
|
|
113
|
+
teardown();
|
|
114
|
+
setup(map);
|
|
115
|
+
if (restore) open(restore.lngLat, restore.feature);
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
onUnmounted(() => {
|
|
119
|
+
disposed = true;
|
|
90
120
|
teardown();
|
|
91
|
-
setup(map);
|
|
92
121
|
});
|
|
93
|
-
onUnmounted(teardown);
|
|
94
122
|
defineExpose({
|
|
95
123
|
/** 当前激活要素 */
|
|
96
124
|
hovered: () => hovered.value
|
|
@@ -2,10 +2,10 @@ import type { GeoJSONFeature, PopupOptions } from 'maplibre-gl';
|
|
|
2
2
|
import type { PopupTrigger } from '../types';
|
|
3
3
|
/** 目标图层要素的弹窗:按 trigger 以悬浮或点击触发,作用域插槽拿到当前要素。 */
|
|
4
4
|
type __VLS_Props = {
|
|
5
|
-
/** 目标图层 id */
|
|
5
|
+
/** 目标图层 id;变化时改绑到新图层 */
|
|
6
6
|
layerId: string;
|
|
7
7
|
/**
|
|
8
|
-
* Popup 选项(hover 模式下 closeButton/closeOnClick
|
|
8
|
+
* Popup 选项(hover 模式下 closeButton/closeOnClick 由组件接管);值变化时重建弹窗
|
|
9
9
|
* @see https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/PopupOptions/
|
|
10
10
|
*/
|
|
11
11
|
options?: PopupOptions;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ControlPosition, StyleSpecification } from 'maplibre-gl';
|
|
2
|
+
import type { BasemapItem } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* 底图切换:受控组件,只发出选中项的 style,不直接调用 setStyle。
|
|
5
|
+
* 将同一个值绑定到 MaplibreMap 的 options.style,由地图负责切换并重建叠加图层。
|
|
6
|
+
*/
|
|
7
|
+
type __VLS_Props = {
|
|
8
|
+
/** 候选底图 */
|
|
9
|
+
items: BasemapItem[];
|
|
10
|
+
/** 控件停靠位置;省略用地图默认位置 */
|
|
11
|
+
position?: ControlPosition;
|
|
12
|
+
/**
|
|
13
|
+
* 折叠按钮与选项组的无障碍标签
|
|
14
|
+
* @defaultValue 'Basemap'
|
|
15
|
+
*/
|
|
16
|
+
label?: string;
|
|
17
|
+
};
|
|
18
|
+
type __VLS_ModelProps = {
|
|
19
|
+
/** 当前底图样式,与 MaplibreMap 的 options.style 绑定同一个值;按引用或字符串相等判断选中项 */
|
|
20
|
+
modelValue?: StyleSpecification | string;
|
|
21
|
+
/** 面板是否展开 */
|
|
22
|
+
'open'?: boolean;
|
|
23
|
+
};
|
|
24
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
25
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
26
|
+
"update:open": (value: boolean) => any;
|
|
27
|
+
"update:modelValue": (value: string | StyleSpecification | undefined) => any;
|
|
28
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
29
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
30
|
+
"onUpdate:modelValue"?: ((value: string | StyleSpecification | undefined) => any) | undefined;
|
|
31
|
+
}>, {
|
|
32
|
+
label: string;
|
|
33
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
34
|
+
declare const _default: typeof __VLS_export;
|
|
35
|
+
export default _default;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, toRaw } from "vue";
|
|
3
|
+
import MaplibreControl from "./Control.vue";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
items: { type: Array, required: true },
|
|
6
|
+
position: { type: String, required: false },
|
|
7
|
+
label: { type: String, required: false, default: "Basemap" }
|
|
8
|
+
});
|
|
9
|
+
const style = defineModel({ type: [Object, String] });
|
|
10
|
+
const open = defineModel("open", { type: Boolean, ...{ default: false } });
|
|
11
|
+
const grid = computed(() => props.items.some((item) => item.thumbnail));
|
|
12
|
+
function isSelected(item) {
|
|
13
|
+
return style.value !== void 0 && toRaw(item.style) === toRaw(style.value);
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<MaplibreControl
|
|
19
|
+
v-model:open="open"
|
|
20
|
+
:position="position"
|
|
21
|
+
:label="label"
|
|
22
|
+
collapsible
|
|
23
|
+
>
|
|
24
|
+
<template #trigger>
|
|
25
|
+
<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
|
|
26
|
+
<path
|
|
27
|
+
fill="none"
|
|
28
|
+
stroke="currentColor"
|
|
29
|
+
stroke-linecap="round"
|
|
30
|
+
stroke-linejoin="round"
|
|
31
|
+
stroke-width="2"
|
|
32
|
+
d="M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0zm.894.211v15M9 3.236v15"
|
|
33
|
+
/>
|
|
34
|
+
</svg>
|
|
35
|
+
</template>
|
|
36
|
+
<div
|
|
37
|
+
class="movk-maplibre-basemap-control"
|
|
38
|
+
:class="{ 'movk-maplibre-basemap-control--grid': grid }"
|
|
39
|
+
role="radiogroup"
|
|
40
|
+
:aria-label="label"
|
|
41
|
+
>
|
|
42
|
+
<button
|
|
43
|
+
v-for="item in items"
|
|
44
|
+
:key="item.label"
|
|
45
|
+
type="button"
|
|
46
|
+
role="radio"
|
|
47
|
+
class="movk-maplibre-basemap-control__item"
|
|
48
|
+
:aria-checked="isSelected(item)"
|
|
49
|
+
@click="style = item.style"
|
|
50
|
+
>
|
|
51
|
+
<img v-if="item.thumbnail" :src="item.thumbnail" alt="" class="movk-maplibre-basemap-control__thumbnail">
|
|
52
|
+
<span>{{ item.label }}</span>
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
</MaplibreControl>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<style>
|
|
59
|
+
:where(.movk-maplibre-basemap-control){display:flex;flex-direction:column;gap:2px;min-width:120px}:where(.movk-maplibre-basemap-control--grid){display:grid;gap:6px;grid-template-columns:repeat(2,72px)}.movk-maplibre-control .movk-maplibre-basemap-control__item{align-items:flex-start;background:transparent;border:1px solid transparent;border-radius:4px;color:inherit;cursor:pointer;display:flex;flex-direction:column;font:inherit;gap:2px;height:auto;padding:3px 6px;text-align:left;width:100%}.movk-maplibre-control .movk-maplibre-basemap-control__item:hover{background:rgba(0,0,0,.05)}.movk-maplibre-control .movk-maplibre-basemap-control__item[aria-checked=true]{border-color:#3b82f6;color:#1d4ed8}.movk-maplibre-control .movk-maplibre-basemap-control--grid .movk-maplibre-basemap-control__item{align-items:center;padding:3px}:where(.movk-maplibre-basemap-control__thumbnail){border-radius:3px;height:48px;-o-object-fit:cover;object-fit:cover;width:64px}
|
|
60
|
+
</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ControlPosition, StyleSpecification } from 'maplibre-gl';
|
|
2
|
+
import type { BasemapItem } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* 底图切换:受控组件,只发出选中项的 style,不直接调用 setStyle。
|
|
5
|
+
* 将同一个值绑定到 MaplibreMap 的 options.style,由地图负责切换并重建叠加图层。
|
|
6
|
+
*/
|
|
7
|
+
type __VLS_Props = {
|
|
8
|
+
/** 候选底图 */
|
|
9
|
+
items: BasemapItem[];
|
|
10
|
+
/** 控件停靠位置;省略用地图默认位置 */
|
|
11
|
+
position?: ControlPosition;
|
|
12
|
+
/**
|
|
13
|
+
* 折叠按钮与选项组的无障碍标签
|
|
14
|
+
* @defaultValue 'Basemap'
|
|
15
|
+
*/
|
|
16
|
+
label?: string;
|
|
17
|
+
};
|
|
18
|
+
type __VLS_ModelProps = {
|
|
19
|
+
/** 当前底图样式,与 MaplibreMap 的 options.style 绑定同一个值;按引用或字符串相等判断选中项 */
|
|
20
|
+
modelValue?: StyleSpecification | string;
|
|
21
|
+
/** 面板是否展开 */
|
|
22
|
+
'open'?: boolean;
|
|
23
|
+
};
|
|
24
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
25
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
26
|
+
"update:open": (value: boolean) => any;
|
|
27
|
+
"update:modelValue": (value: string | StyleSpecification | undefined) => any;
|
|
28
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
29
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
30
|
+
"onUpdate:modelValue"?: ((value: string | StyleSpecification | undefined) => any) | undefined;
|
|
31
|
+
}>, {
|
|
32
|
+
label: string;
|
|
33
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
34
|
+
declare const _default: typeof __VLS_export;
|
|
35
|
+
export default _default;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ControlPosition } from 'maplibre-gl';
|
|
2
|
+
/** 通用控件容器:把任意 Vue 内容挂到 maplibre 控件槽位,可选折叠为图标按钮。 */
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
/** 控件停靠位置;省略用地图默认位置 */
|
|
5
|
+
position?: ControlPosition;
|
|
6
|
+
/**
|
|
7
|
+
* 是否使用 maplibre 控件组样式(白底圆角卡片)
|
|
8
|
+
* @defaultValue true
|
|
9
|
+
*/
|
|
10
|
+
group?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* 是否可折叠:收起时只显示触发按钮,点击展开,面板内关闭按钮或 Esc 收起
|
|
13
|
+
* @defaultValue false
|
|
14
|
+
*/
|
|
15
|
+
collapsible?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 可折叠时点击控件外部是否收起;常驻展示的内容(如图例)应关闭
|
|
18
|
+
* @defaultValue true
|
|
19
|
+
*/
|
|
20
|
+
dismissible?: boolean;
|
|
21
|
+
/** 折叠按钮的无障碍标签 */
|
|
22
|
+
label?: string;
|
|
23
|
+
};
|
|
24
|
+
type __VLS_Slots = {
|
|
25
|
+
/** 控件内容;可折叠时为展开后的面板 */
|
|
26
|
+
default?: () => unknown;
|
|
27
|
+
/** 折叠按钮内容(通常是图标) */
|
|
28
|
+
trigger?: () => unknown;
|
|
29
|
+
};
|
|
30
|
+
type __VLS_ModelProps = {
|
|
31
|
+
/** 可折叠时的展开状态 */
|
|
32
|
+
'open'?: boolean;
|
|
33
|
+
};
|
|
34
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
35
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
36
|
+
"update:open": (value: boolean) => any;
|
|
37
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
38
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
39
|
+
}>, {
|
|
40
|
+
group: boolean;
|
|
41
|
+
collapsible: boolean;
|
|
42
|
+
dismissible: boolean;
|
|
43
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
44
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
45
|
+
declare const _default: typeof __VLS_export;
|
|
46
|
+
export default _default;
|
|
47
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
48
|
+
new (): {
|
|
49
|
+
$slots: S;
|
|
50
|
+
};
|
|
51
|
+
};
|