@movk/maplibre 1.0.0 → 1.2.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.
Files changed (202) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/module.d.mts +12 -3
  4. package/dist/module.d.ts +12 -3
  5. package/dist/module.json +1 -1
  6. package/dist/module.mjs +26 -11
  7. package/dist/runtime/components/CustomLayer.d.vue.ts +1 -1
  8. package/dist/runtime/components/CustomLayer.vue +18 -4
  9. package/dist/runtime/components/CustomLayer.vue.d.ts +1 -1
  10. package/dist/runtime/components/Layer.d.vue.ts +4 -4
  11. package/dist/runtime/components/Layer.vue +43 -18
  12. package/dist/runtime/components/Layer.vue.d.ts +4 -4
  13. package/dist/runtime/components/LayerGroup.d.vue.ts +23 -10
  14. package/dist/runtime/components/LayerGroup.vue +44 -4
  15. package/dist/runtime/components/LayerGroup.vue.d.ts +23 -10
  16. package/dist/runtime/components/LottieMarker.d.vue.ts +3 -3
  17. package/dist/runtime/components/LottieMarker.vue +6 -2
  18. package/dist/runtime/components/LottieMarker.vue.d.ts +3 -3
  19. package/dist/runtime/components/Map.d.vue.ts +2 -1
  20. package/dist/runtime/components/Map.vue +2 -6
  21. package/dist/runtime/components/Map.vue.d.ts +2 -1
  22. package/dist/runtime/components/Marker.d.vue.ts +2 -1
  23. package/dist/runtime/components/Marker.vue +33 -9
  24. package/dist/runtime/components/Marker.vue.d.ts +2 -1
  25. package/dist/runtime/components/Popup.d.vue.ts +1 -1
  26. package/dist/runtime/components/Popup.vue +23 -4
  27. package/dist/runtime/components/Popup.vue.d.ts +1 -1
  28. package/dist/runtime/components/Source.d.vue.ts +2 -2
  29. package/dist/runtime/components/Source.vue +3 -15
  30. package/dist/runtime/components/Source.vue.d.ts +2 -2
  31. package/dist/runtime/components/Tooltip.d.vue.ts +2 -2
  32. package/dist/runtime/components/Tooltip.vue +47 -19
  33. package/dist/runtime/components/Tooltip.vue.d.ts +2 -2
  34. package/dist/runtime/components/buffers/BufferCircle.d.vue.ts +1 -1
  35. package/dist/runtime/components/buffers/BufferCircle.vue.d.ts +1 -1
  36. package/dist/runtime/components/buffers/BufferEllipse.d.vue.ts +1 -1
  37. package/dist/runtime/components/buffers/BufferEllipse.vue.d.ts +1 -1
  38. package/dist/runtime/components/buffers/BufferLine.d.vue.ts +1 -1
  39. package/dist/runtime/components/buffers/BufferLine.vue.d.ts +1 -1
  40. package/dist/runtime/components/buffers/BufferPolygon.d.vue.ts +1 -1
  41. package/dist/runtime/components/buffers/BufferPolygon.vue.d.ts +1 -1
  42. package/dist/runtime/components/buffers/BufferSector.d.vue.ts +1 -1
  43. package/dist/runtime/components/buffers/BufferSector.vue.d.ts +1 -1
  44. package/dist/runtime/components/controls/BasemapControl.d.vue.ts +35 -0
  45. package/dist/runtime/components/controls/BasemapControl.vue +60 -0
  46. package/dist/runtime/components/controls/BasemapControl.vue.d.ts +35 -0
  47. package/dist/runtime/components/controls/Control.d.vue.ts +51 -0
  48. package/dist/runtime/components/controls/Control.vue +95 -0
  49. package/dist/runtime/components/controls/Control.vue.d.ts +51 -0
  50. package/dist/runtime/components/controls/GlobeControl.d.vue.ts +18 -0
  51. package/dist/runtime/components/controls/GlobeControl.vue +15 -0
  52. package/dist/runtime/components/controls/GlobeControl.vue.d.ts +18 -0
  53. package/dist/runtime/components/controls/LayerControl.d.vue.ts +44 -0
  54. package/dist/runtime/components/controls/LayerControl.vue +63 -0
  55. package/dist/runtime/components/controls/LayerControl.vue.d.ts +44 -0
  56. package/dist/runtime/components/controls/Legend.d.vue.ts +47 -0
  57. package/dist/runtime/components/controls/Legend.vue +69 -0
  58. package/dist/runtime/components/controls/Legend.vue.d.ts +47 -0
  59. package/dist/runtime/components/controls/Minimap.d.vue.ts +45 -0
  60. package/dist/runtime/components/controls/Minimap.vue +31 -0
  61. package/dist/runtime/components/controls/Minimap.vue.d.ts +45 -0
  62. package/dist/runtime/components/effects/AnimatedImage.d.vue.ts +1 -1
  63. package/dist/runtime/components/effects/AnimatedImage.vue +9 -6
  64. package/dist/runtime/components/effects/AnimatedImage.vue.d.ts +1 -1
  65. package/dist/runtime/components/effects/DiffusionCircle.d.vue.ts +1 -1
  66. package/dist/runtime/components/effects/DiffusionCircle.vue.d.ts +1 -1
  67. package/dist/runtime/components/effects/FlowBuilding.d.vue.ts +1 -1
  68. package/dist/runtime/components/effects/FlowBuilding.vue.d.ts +1 -1
  69. package/dist/runtime/components/effects/GlowCircle.d.vue.ts +1 -1
  70. package/dist/runtime/components/effects/GlowCircle.vue.d.ts +1 -1
  71. package/dist/runtime/components/effects/GradientBuilding.d.vue.ts +1 -1
  72. package/dist/runtime/components/effects/GradientBuilding.vue.d.ts +1 -1
  73. package/dist/runtime/components/effects/Migration.d.vue.ts +1 -1
  74. package/dist/runtime/components/effects/Migration.vue.d.ts +1 -1
  75. package/dist/runtime/components/effects/Radar.d.vue.ts +1 -1
  76. package/dist/runtime/components/effects/Radar.vue.d.ts +1 -1
  77. package/dist/runtime/components/effects/SpriteImage.d.vue.ts +1 -1
  78. package/dist/runtime/components/effects/SpriteImage.vue +40 -24
  79. package/dist/runtime/components/effects/SpriteImage.vue.d.ts +1 -1
  80. package/dist/runtime/components/effects/TextureBuilding.d.vue.ts +1 -1
  81. package/dist/runtime/components/effects/TextureBuilding.vue +1 -1
  82. package/dist/runtime/components/effects/TextureBuilding.vue.d.ts +1 -1
  83. package/dist/runtime/components/effects/Trail.d.vue.ts +1 -1
  84. package/dist/runtime/components/effects/Trail.vue.d.ts +1 -1
  85. package/dist/runtime/components/effects/WaveCircle.d.vue.ts +1 -1
  86. package/dist/runtime/components/effects/WaveCircle.vue.d.ts +1 -1
  87. package/dist/runtime/components/effects/WindowBuilding.d.vue.ts +1 -1
  88. package/dist/runtime/components/effects/WindowBuilding.vue.d.ts +1 -1
  89. package/dist/runtime/components/environment/Projection.d.vue.ts +28 -0
  90. package/dist/runtime/components/environment/Projection.vue +27 -0
  91. package/dist/runtime/components/environment/Projection.vue.d.ts +28 -0
  92. package/dist/runtime/components/environment/Temperature.d.vue.ts +1 -1
  93. package/dist/runtime/components/environment/Temperature.vue.d.ts +1 -1
  94. package/dist/runtime/components/environment/Terrain.d.vue.ts +1 -1
  95. package/dist/runtime/components/environment/Terrain.vue +5 -0
  96. package/dist/runtime/components/environment/Terrain.vue.d.ts +1 -1
  97. package/dist/runtime/components/extensions/DrawControl.vue +23 -19
  98. package/dist/runtime/components/extensions/Swipe.d.vue.ts +48 -0
  99. package/dist/runtime/components/extensions/Swipe.vue +141 -0
  100. package/dist/runtime/components/extensions/Swipe.vue.d.ts +48 -0
  101. package/dist/runtime/components/layers/BuildingLayer.d.vue.ts +1 -1
  102. package/dist/runtime/components/layers/BuildingLayer.vue.d.ts +1 -1
  103. package/dist/runtime/components/layers/ClusterLayer.d.vue.ts +1 -1
  104. package/dist/runtime/components/layers/ClusterLayer.vue.d.ts +1 -1
  105. package/dist/runtime/components/layers/ContourLayer.d.vue.ts +59 -0
  106. package/dist/runtime/components/layers/ContourLayer.vue +84 -0
  107. package/dist/runtime/components/layers/ContourLayer.vue.d.ts +59 -0
  108. package/dist/runtime/components/layers/GraticuleLayer.d.vue.ts +31 -0
  109. package/dist/runtime/components/layers/GraticuleLayer.vue +88 -0
  110. package/dist/runtime/components/layers/GraticuleLayer.vue.d.ts +31 -0
  111. package/dist/runtime/components/layers/ImageLayer.d.vue.ts +1 -1
  112. package/dist/runtime/components/layers/ImageLayer.vue.d.ts +1 -1
  113. package/dist/runtime/components/layers/MaskLayer.d.vue.ts +44 -0
  114. package/dist/runtime/components/layers/MaskLayer.vue +32 -0
  115. package/dist/runtime/components/layers/MaskLayer.vue.d.ts +44 -0
  116. package/dist/runtime/components/layers/RasterLayer.d.vue.ts +5 -3
  117. package/dist/runtime/components/layers/RasterLayer.vue +9 -2
  118. package/dist/runtime/components/layers/RasterLayer.vue.d.ts +5 -3
  119. package/dist/runtime/components/layers/VideoLayer.d.vue.ts +1 -1
  120. package/dist/runtime/components/layers/VideoLayer.vue.d.ts +1 -1
  121. package/dist/runtime/composables/useFeatureState.js +27 -5
  122. package/dist/runtime/composables/useFrameIcon.d.ts +4 -3
  123. package/dist/runtime/composables/useFrameIcon.js +18 -8
  124. package/dist/runtime/composables/useLayerTree.d.ts +11 -0
  125. package/dist/runtime/composables/useLayerTree.js +12 -0
  126. package/dist/runtime/composables/useMapAnimation.d.ts +4 -2
  127. package/dist/runtime/composables/useMapAnimation.js +5 -4
  128. package/dist/runtime/composables/useMapExport.js +2 -5
  129. package/dist/runtime/composables/useMapSync.d.ts +16 -0
  130. package/dist/runtime/composables/useMapSync.js +42 -0
  131. package/dist/runtime/composables/useMaplibreCamera.d.ts +1 -1
  132. package/dist/runtime/composables/useMaplibreCamera.js +1 -1
  133. package/dist/runtime/composables/useMaplibreImage.d.ts +3 -3
  134. package/dist/runtime/composables/useMaplibreImage.js +26 -5
  135. package/dist/runtime/domains/map/config.js +2 -3
  136. package/dist/runtime/domains/map/context.js +15 -0
  137. package/dist/runtime/domains/map/control.d.ts +1 -1
  138. package/dist/runtime/domains/map/control.js +1 -1
  139. package/dist/runtime/domains/map/draw-modes.d.ts +9 -0
  140. package/dist/runtime/domains/map/draw-modes.js +53 -0
  141. package/dist/runtime/domains/map/draw-registry.d.ts +2 -3
  142. package/dist/runtime/domains/map/draw-registry.js +6 -9
  143. package/dist/runtime/domains/map/draw-theme.d.ts +12 -0
  144. package/dist/runtime/domains/map/draw-toolbar.js +11 -10
  145. package/dist/runtime/domains/map/layer-group.d.ts +15 -4
  146. package/dist/runtime/domains/map/layer-tree.d.ts +3 -0
  147. package/dist/runtime/domains/map/layer-tree.js +10 -0
  148. package/dist/runtime/domains/map/minimap.d.ts +18 -0
  149. package/dist/runtime/domains/map/minimap.js +86 -0
  150. package/dist/runtime/domains/map/registry.js +4 -3
  151. package/dist/runtime/domains/map/style-layers.d.ts +7 -0
  152. package/dist/runtime/domains/map/style-layers.js +54 -0
  153. package/dist/runtime/domains/map/style.d.ts +3 -0
  154. package/dist/runtime/domains/map/style.js +5 -0
  155. package/dist/runtime/domains/map/swipe.d.ts +9 -0
  156. package/dist/runtime/domains/map/swipe.js +62 -0
  157. package/dist/runtime/index.css +1 -1
  158. package/dist/runtime/types/draw.d.ts +34 -1
  159. package/dist/runtime/types/index.d.ts +1 -0
  160. package/dist/runtime/types/layer.d.ts +40 -0
  161. package/dist/runtime/types/layer.js +0 -0
  162. package/dist/runtime/types/map.d.ts +6 -0
  163. package/dist/runtime/utils/cog.d.ts +2 -0
  164. package/dist/runtime/utils/cog.js +9 -0
  165. package/dist/runtime/utils/effects.js +2 -1
  166. package/dist/runtime/utils/events.d.ts +6 -0
  167. package/dist/runtime/utils/events.js +25 -0
  168. package/dist/runtime/utils/frame-icon.d.ts +2 -5
  169. package/dist/runtime/utils/frame-icon.js +10 -4
  170. package/dist/runtime/utils/graticule.d.ts +19 -0
  171. package/dist/runtime/utils/graticule.js +62 -0
  172. package/dist/runtime/utils/layer-opacity.d.ts +7 -0
  173. package/dist/runtime/utils/layer-opacity.js +59 -0
  174. package/dist/runtime/utils/layer.js +2 -1
  175. package/dist/runtime/utils/legend.d.ts +9 -0
  176. package/dist/runtime/utils/legend.js +52 -0
  177. package/dist/runtime/utils/marker.d.ts +11 -0
  178. package/dist/runtime/utils/marker.js +28 -0
  179. package/dist/runtime/utils/mask.d.ts +8 -0
  180. package/dist/runtime/utils/mask.js +33 -0
  181. package/dist/runtime/utils/minimap.d.ts +6 -0
  182. package/dist/runtime/utils/minimap.js +15 -0
  183. package/dist/runtime/utils/pmtiles.d.ts +3 -0
  184. package/dist/runtime/utils/pmtiles.js +10 -0
  185. package/dist/runtime/utils/source.d.ts +7 -0
  186. package/dist/runtime/utils/source.js +35 -0
  187. package/dist/runtime/utils/swipe.d.ts +32 -0
  188. package/dist/runtime/utils/swipe.js +18 -0
  189. package/dist/runtime/utils/tianditu.d.ts +10 -1
  190. package/dist/runtime/utils/tianditu.js +11 -0
  191. package/dist/runtime/utils/zzts-tile.d.ts +54 -0
  192. package/dist/runtime/utils/zzts-tile.js +85 -0
  193. package/dist/runtime/utils/zzts.d.ts +14 -0
  194. package/dist/runtime/utils/zzts.js +72 -0
  195. package/dist/unplugin.d.mts +1 -1
  196. package/dist/unplugin.d.ts +1 -1
  197. package/dist/unplugin.mjs +1 -7
  198. package/package.json +29 -21
  199. package/dist/runtime/draw-modes/index.d.ts +0 -16
  200. package/dist/runtime/draw-modes/index.js +0 -32
  201. package/dist/runtime/utils/draw-theme.d.ts +0 -47
  202. /package/dist/runtime/{utils → domains/map}/draw-theme.js +0 -0
@@ -0,0 +1,48 @@
1
+ import type { StyleSpecification } from 'maplibre-gl';
2
+ import type { SwipeOrientation } from '../../utils/swipe';
3
+ type __VLS_Props = {
4
+ /**
5
+ * 分隔方向:vertical 为竖直分隔条左右对比,horizontal 为水平分隔条上下对比
6
+ * @defaultValue 'vertical'
7
+ */
8
+ orientation?: SwipeOrientation;
9
+ /**
10
+ * 方向键每次移动的比例
11
+ * @defaultValue 0.05
12
+ */
13
+ step?: number;
14
+ /** 对照图的底图样式(对象或样式 URL);省略时为空白样式,由插槽内图层提供内容 */
15
+ mapStyle?: StyleSpecification | string;
16
+ };
17
+ type __VLS_Slots = {
18
+ /** 对照内容:放置 MaplibreTiandituLayer、MaplibreLayer 等,作用于对照图 */
19
+ default?: () => unknown;
20
+ };
21
+ declare function revealed(point: {
22
+ x: number;
23
+ y: number;
24
+ }): boolean;
25
+ type __VLS_ModelProps = {
26
+ /** 分隔条位置,0..1 */
27
+ 'position'?: number;
28
+ };
29
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
30
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
31
+ /** 主图容器内的点是否落在对照图露出区域,供主图侧图层事件判断互斥 */
32
+ isPointRevealed: typeof revealed;
33
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
34
+ "update:position": (value: number) => any;
35
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
36
+ "onUpdate:position"?: ((value: number) => any) | undefined;
37
+ }>, {
38
+ step: number;
39
+ orientation: SwipeOrientation;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
41
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
42
+ declare const _default: typeof __VLS_export;
43
+ export default _default;
44
+ type __VLS_WithSlots<T, S> = T & {
45
+ new (): {
46
+ $slots: S;
47
+ };
48
+ };
@@ -0,0 +1,141 @@
1
+ <script setup>
2
+ import { computed, onMounted, onUnmounted, provide, ref, useId, useTemplateRef, watch, watchEffect } from "vue";
3
+ import { clamp, omitUndefined } from "@movk/core";
4
+ import { useMap } from "../../composables/useMap";
5
+ import { createMaplibreContext, MaplibreContextKey } from "../../domains/map/context";
6
+ import { createMaplibreGl } from "../../domains/map/create-map";
7
+ import { blankStyle } from "../../domains/map/style";
8
+ import { bindSwipeOverlay } from "../../domains/map/swipe";
9
+ import { collectAttributions, isPointRevealed, positionFromPointer, swipeClipPath } from "../../utils/swipe";
10
+ const props = defineProps({
11
+ orientation: { type: String, required: false, default: "vertical" },
12
+ step: { type: Number, required: false, default: 0.05 },
13
+ mapStyle: { type: [Object, String], required: false }
14
+ });
15
+ defineSlots();
16
+ const position = defineModel("position", { type: Number, ...{ default: 0.5 } });
17
+ const mainContext = useMap();
18
+ const root = useTemplateRef("root");
19
+ const container = useTemplateRef("container");
20
+ const { context, attach } = createMaplibreContext(`${mainContext.id}-swipe-${useId()}`);
21
+ provide(MaplibreContextKey, context);
22
+ const attributions = ref([]);
23
+ function revealed(point) {
24
+ const main = mainContext.map.value;
25
+ if (!main) return false;
26
+ const { clientWidth: width, clientHeight: height } = main.getContainer();
27
+ return isPointRevealed(point, { width, height }, position.value, props.orientation);
28
+ }
29
+ let unbind;
30
+ let disposed = false;
31
+ onMounted(async () => {
32
+ const main = await mainContext.whenAttached();
33
+ if (disposed || !container.value) return;
34
+ const overlay = createMaplibreGl(omitUndefined({
35
+ container: container.value,
36
+ style: props.mapStyle ?? blankStyle(),
37
+ center: main.getCenter(),
38
+ zoom: main.getZoom(),
39
+ bearing: main.getBearing(),
40
+ pitch: main.getPitch(),
41
+ interactive: false,
42
+ attributionControl: false
43
+ }));
44
+ attach(overlay);
45
+ unbind = bindSwipeOverlay(main, overlay, revealed);
46
+ const updateAttributions = () => {
47
+ attributions.value = collectAttributions(overlay);
48
+ };
49
+ overlay.on("sourcedata", updateAttributions);
50
+ overlay.on("style.load", updateAttributions);
51
+ });
52
+ onUnmounted(() => {
53
+ disposed = true;
54
+ unbind?.();
55
+ context.map.value?.remove();
56
+ });
57
+ watch(() => props.mapStyle, (style) => {
58
+ context.map.value?.setStyle(style ?? blankStyle(), { diff: false });
59
+ });
60
+ watchEffect(() => {
61
+ const overlay = context.map.value;
62
+ if (overlay) overlay.getCanvas().style.clipPath = swipeClipPath(position.value, props.orientation);
63
+ });
64
+ const offset = computed(() => `${clamp(position.value, 0, 1) * 100}%`);
65
+ const handleStyle = computed(() => ({ [props.orientation === "vertical" ? "left" : "top"]: offset.value }));
66
+ const attributionStyle = computed(() => props.orientation === "vertical" ? { left: offset.value, bottom: "0", maxWidth: `calc(100% - ${offset.value})` } : { top: offset.value, left: "0" });
67
+ const attributionHtml = computed(() => attributions.value.join(" | "));
68
+ const dragging = ref(false);
69
+ function updateFromPointer(event) {
70
+ if (!root.value) return;
71
+ position.value = positionFromPointer(
72
+ root.value.getBoundingClientRect(),
73
+ { x: event.clientX, y: event.clientY },
74
+ props.orientation
75
+ );
76
+ }
77
+ function onPointerDown(event) {
78
+ dragging.value = true;
79
+ event.currentTarget.setPointerCapture?.(event.pointerId);
80
+ updateFromPointer(event);
81
+ }
82
+ function onPointerMove(event) {
83
+ if (dragging.value) updateFromPointer(event);
84
+ }
85
+ function onPointerUp() {
86
+ dragging.value = false;
87
+ }
88
+ const KEY_DELTA = {
89
+ ArrowLeft: -1,
90
+ ArrowUp: -1,
91
+ ArrowRight: 1,
92
+ ArrowDown: 1
93
+ };
94
+ function onKeydown(event) {
95
+ let next;
96
+ if (event.key === "Home") next = 0;
97
+ else if (event.key === "End") next = 1;
98
+ else if (event.key in KEY_DELTA) next = position.value + KEY_DELTA[event.key] * props.step;
99
+ if (next === void 0) return;
100
+ event.preventDefault();
101
+ position.value = clamp(next, 0, 1);
102
+ }
103
+ defineExpose({
104
+ /** 主图容器内的点是否落在对照图露出区域,供主图侧图层事件判断互斥 */
105
+ isPointRevealed: revealed
106
+ });
107
+ </script>
108
+
109
+ <template>
110
+ <div
111
+ ref="root"
112
+ class="movk-maplibre-swipe"
113
+ :class="`movk-maplibre-swipe--${orientation}`"
114
+ >
115
+ <div ref="container" class="movk-maplibre-swipe__map" />
116
+ <!-- eslint-disable-next-line vue/no-v-html -->
117
+ <div v-if="attributionHtml" class="movk-maplibre-swipe__attribution" :style="attributionStyle" v-html="attributionHtml" />
118
+ <div
119
+ class="movk-maplibre-swipe__handle"
120
+ :class="{ 'is-dragging': dragging }"
121
+ :style="handleStyle"
122
+ role="slider"
123
+ tabindex="0"
124
+ aria-label="Swipe position"
125
+ :aria-orientation="orientation === 'vertical' ? 'horizontal' : 'vertical'"
126
+ aria-valuemin="0"
127
+ aria-valuemax="100"
128
+ :aria-valuenow="Math.round(clamp(position, 0, 1) * 100)"
129
+ @pointerdown="onPointerDown"
130
+ @pointermove="onPointerMove"
131
+ @pointerup="onPointerUp"
132
+ @pointercancel="onPointerUp"
133
+ @keydown="onKeydown"
134
+ />
135
+ <slot />
136
+ </div>
137
+ </template>
138
+
139
+ <style>
140
+ .movk-maplibre-swipe{pointer-events:none;z-index:1}.movk-maplibre-swipe,.movk-maplibre-swipe>.movk-maplibre-swipe__map{inset:0;position:absolute}.movk-maplibre-swipe__attribution{background:hsla(0,0%,100%,.65);color:rgba(0,0,0,.75);font:12px/20px Helvetica Neue,Arial,Helvetica,sans-serif;max-width:100%;overflow:hidden;padding:0 5px;pointer-events:auto;position:absolute;text-overflow:ellipsis;white-space:nowrap}.movk-maplibre-swipe__attribution a{color:inherit;text-decoration:none}.movk-maplibre-swipe__handle{outline:none;pointer-events:auto;position:absolute;touch-action:none}.movk-maplibre-swipe__handle:before{background:#fff;box-shadow:0 0 4px rgba(0,0,0,.4);content:"";position:absolute}.movk-maplibre-swipe__handle:after{background:#fff;border-radius:9999px;box-shadow:0 1px 4px rgba(0,0,0,.4);content:"";height:28px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:28px}.movk-maplibre-swipe__handle:focus-visible:after{box-shadow:0 0 0 3px rgba(59,130,246,.6)}.movk-maplibre-swipe--vertical>.movk-maplibre-swipe__handle{bottom:0;cursor:ew-resize;top:0;transform:translateX(-50%);width:24px}.movk-maplibre-swipe--vertical>.movk-maplibre-swipe__handle:before{bottom:0;left:50%;top:0;transform:translateX(-50%);width:2px}.movk-maplibre-swipe--horizontal>.movk-maplibre-swipe__handle{cursor:ns-resize;height:24px;left:0;right:0;transform:translateY(-50%)}.movk-maplibre-swipe--horizontal>.movk-maplibre-swipe__handle:before{height:2px;left:0;right:0;top:50%;transform:translateY(-50%)}
141
+ </style>
@@ -0,0 +1,48 @@
1
+ import type { StyleSpecification } from 'maplibre-gl';
2
+ import type { SwipeOrientation } from '../../utils/swipe';
3
+ type __VLS_Props = {
4
+ /**
5
+ * 分隔方向:vertical 为竖直分隔条左右对比,horizontal 为水平分隔条上下对比
6
+ * @defaultValue 'vertical'
7
+ */
8
+ orientation?: SwipeOrientation;
9
+ /**
10
+ * 方向键每次移动的比例
11
+ * @defaultValue 0.05
12
+ */
13
+ step?: number;
14
+ /** 对照图的底图样式(对象或样式 URL);省略时为空白样式,由插槽内图层提供内容 */
15
+ mapStyle?: StyleSpecification | string;
16
+ };
17
+ type __VLS_Slots = {
18
+ /** 对照内容:放置 MaplibreTiandituLayer、MaplibreLayer 等,作用于对照图 */
19
+ default?: () => unknown;
20
+ };
21
+ declare function revealed(point: {
22
+ x: number;
23
+ y: number;
24
+ }): boolean;
25
+ type __VLS_ModelProps = {
26
+ /** 分隔条位置,0..1 */
27
+ 'position'?: number;
28
+ };
29
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
30
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
31
+ /** 主图容器内的点是否落在对照图露出区域,供主图侧图层事件判断互斥 */
32
+ isPointRevealed: typeof revealed;
33
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
34
+ "update:position": (value: number) => any;
35
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
36
+ "onUpdate:position"?: ((value: number) => any) | undefined;
37
+ }>, {
38
+ step: number;
39
+ orientation: SwipeOrientation;
40
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
41
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
42
+ declare const _default: typeof __VLS_export;
43
+ export default _default;
44
+ type __VLS_WithSlots<T, S> = T & {
45
+ new (): {
46
+ $slots: S;
47
+ };
48
+ };
@@ -1,7 +1,7 @@
1
1
  import type { BuildingSourceOptions } from '../../utils/building';
2
2
  /** 3D 建筑:按要素高度属性拉伸的 fill-extrusion 图层。 */
3
3
  type __VLS_Props = BuildingSourceOptions & {
4
- /** 图层 id;省略时自动生成 */
4
+ /** 图层 id;省略时自动生成,变更需配合 `:key` 重建 */
5
5
  layerId?: string;
6
6
  /**
7
7
  * 建筑颜色
@@ -1,7 +1,7 @@
1
1
  import type { BuildingSourceOptions } from '../../utils/building';
2
2
  /** 3D 建筑:按要素高度属性拉伸的 fill-extrusion 图层。 */
3
3
  type __VLS_Props = BuildingSourceOptions & {
4
- /** 图层 id;省略时自动生成 */
4
+ /** 图层 id;省略时自动生成,变更需配合 `:key` 重建 */
5
5
  layerId?: string;
6
6
  /**
7
7
  * 建筑颜色
@@ -4,7 +4,7 @@ type PropBag = Record<string, unknown>;
4
4
  type __VLS_Props = {
5
5
  /** 点要素数据(GeoJSON 或其 URL) */
6
6
  data: GeoJSONSourceSpecification['data'];
7
- /** source 与图层 id 前缀;省略时自动生成 */
7
+ /** source 与图层 id 前缀;省略时自动生成,变更需配合 `:key` 重建 */
8
8
  sourceId?: string;
9
9
  /**
10
10
  * 聚合半径(像素)
@@ -4,7 +4,7 @@ type PropBag = Record<string, unknown>;
4
4
  type __VLS_Props = {
5
5
  /** 点要素数据(GeoJSON 或其 URL) */
6
6
  data: GeoJSONSourceSpecification['data'];
7
- /** source 与图层 id 前缀;省略时自动生成 */
7
+ /** source 与图层 id 前缀;省略时自动生成,变更需配合 `:key` 重建 */
8
8
  sourceId?: string;
9
9
  /**
10
10
  * 聚合半径(像素)
@@ -0,0 +1,59 @@
1
+ /** 等高线:由 raster-dem 瓦片在浏览器端实时生成矢量等高线,主次线按间距区分,可沿线标注高程。 */
2
+ type __VLS_Props = {
3
+ /** DEM 瓦片模板(含 {z}/{x}/{y}),可与 MaplibreTerrain 共用;变更需配合 `:key` 重建 */
4
+ demUrl: string;
5
+ /**
6
+ * DEM 高程编码;变更需配合 `:key` 重建
7
+ * @defaultValue 'terrarium'
8
+ */
9
+ encoding?: 'terrarium' | 'mapbox';
10
+ /**
11
+ * DEM 瓦片最大缩放级别;变更需配合 `:key` 重建
12
+ * @defaultValue 12
13
+ */
14
+ maxzoom?: number;
15
+ /**
16
+ * 缩放级别到 [次线间距, 主线间距] 的映射,未列出的级别沿用更低一级
17
+ * @defaultValue `{ 11: [200, 1000], 12: [100, 500], 14: [50, 200], 15: [20, 100] }`
18
+ */
19
+ thresholds?: Record<number, number | number[]>;
20
+ /**
21
+ * 高程换算系数,如 3.28084 将米换算为英尺
22
+ * @defaultValue 1
23
+ */
24
+ multiplier?: number;
25
+ /**
26
+ * 标注的高程单位后缀
27
+ * @defaultValue 'm'
28
+ */
29
+ unit?: string;
30
+ /** 图层 id 前缀;省略时自动生成,变更需配合 `:key` 重建 */
31
+ layerId?: string;
32
+ /**
33
+ * 线条颜色
34
+ * @defaultValue '#a0522d'
35
+ */
36
+ lineColor?: string;
37
+ /**
38
+ * 是否沿主线标注高程
39
+ * @defaultValue true
40
+ */
41
+ labels?: boolean;
42
+ /** 覆盖合并到等高线的 paint */
43
+ linePaint?: Record<string, unknown>;
44
+ /** 覆盖合并到标注的 layout */
45
+ labelLayout?: Record<string, unknown>;
46
+ /** 插入到该图层之前 */
47
+ beforeId?: string;
48
+ };
49
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
50
+ maxzoom: number;
51
+ unit: string;
52
+ encoding: "terrarium" | "mapbox";
53
+ thresholds: Record<number, number | number[]>;
54
+ multiplier: number;
55
+ lineColor: string;
56
+ labels: boolean;
57
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
58
+ declare const _default: typeof __VLS_export;
59
+ export default _default;
@@ -0,0 +1,84 @@
1
+ <script setup>
2
+ import { computed, onMounted, onUnmounted, shallowRef, useId } from "vue";
3
+ import { addProtocol, removeProtocol } from "maplibre-gl";
4
+ import mlcontour from "maplibre-contour";
5
+ import MaplibreSource from "../Source.vue";
6
+ import MaplibreLayer from "../Layer.vue";
7
+ import { textFontLayout } from "../../domains/map/config";
8
+ const props = defineProps({
9
+ demUrl: { type: String, required: true },
10
+ encoding: { type: String, required: false, default: "terrarium" },
11
+ maxzoom: { type: Number, required: false, default: 12 },
12
+ thresholds: { type: Object, required: false, default: () => ({ 11: [200, 1e3], 12: [100, 500], 14: [50, 200], 15: [20, 100] }) },
13
+ multiplier: { type: Number, required: false, default: 1 },
14
+ unit: { type: String, required: false, default: "m" },
15
+ layerId: { type: String, required: false },
16
+ lineColor: { type: String, required: false, default: "#a0522d" },
17
+ labels: { type: Boolean, required: false, default: true },
18
+ linePaint: { type: Object, required: false },
19
+ labelLayout: { type: Object, required: false },
20
+ beforeId: { type: String, required: false }
21
+ });
22
+ const CONTOUR_LAYER = "contours";
23
+ const id = props.layerId ?? `movk-contour-${useId()}`;
24
+ const demSource = shallowRef();
25
+ onMounted(() => {
26
+ const source2 = new mlcontour.DemSource({ url: props.demUrl, encoding: props.encoding, maxzoom: props.maxzoom, worker: true });
27
+ source2.setupMaplibre({ addProtocol });
28
+ demSource.value = source2;
29
+ });
30
+ onUnmounted(() => {
31
+ if (!demSource.value) return;
32
+ removeProtocol(demSource.value.sharedDemProtocolId);
33
+ removeProtocol(demSource.value.contourProtocolId);
34
+ });
35
+ const source = computed(() => demSource.value && {
36
+ type: "vector",
37
+ tiles: [demSource.value.contourProtocolUrl({
38
+ thresholds: props.thresholds,
39
+ multiplier: props.multiplier,
40
+ elevationKey: "ele",
41
+ levelKey: "level",
42
+ contourLayer: CONTOUR_LAYER
43
+ })],
44
+ maxzoom: 15
45
+ });
46
+ const paint = computed(() => ({
47
+ "line-color": props.lineColor,
48
+ "line-width": ["match", ["get", "level"], 1, 1, 0.5],
49
+ ...props.linePaint
50
+ }));
51
+ const labelPaint = computed(() => ({ "text-color": props.lineColor, "text-halo-color": "#fff", "text-halo-width": 1 }));
52
+ const layout = computed(() => ({
53
+ "symbol-placement": "line",
54
+ "text-field": ["concat", ["number-format", ["get", "ele"], {}], props.unit],
55
+ "text-size": 10,
56
+ ...textFontLayout(),
57
+ ...props.labelLayout
58
+ }));
59
+ const labelFilter = [">", ["get", "level"], 0];
60
+ </script>
61
+
62
+ <template>
63
+ <MaplibreSource v-if="source" :source-id="id" :source="source">
64
+ <MaplibreLayer
65
+ :layer-id="`${id}-line`"
66
+ type="line"
67
+ :source="id"
68
+ :source-layer="CONTOUR_LAYER"
69
+ :paint="paint"
70
+ :before-id="beforeId"
71
+ />
72
+ <MaplibreLayer
73
+ v-if="labels"
74
+ :layer-id="`${id}-label`"
75
+ type="symbol"
76
+ :source="id"
77
+ :source-layer="CONTOUR_LAYER"
78
+ :filter="labelFilter"
79
+ :layout="layout"
80
+ :paint="labelPaint"
81
+ :before-id="beforeId"
82
+ />
83
+ </MaplibreSource>
84
+ </template>
@@ -0,0 +1,59 @@
1
+ /** 等高线:由 raster-dem 瓦片在浏览器端实时生成矢量等高线,主次线按间距区分,可沿线标注高程。 */
2
+ type __VLS_Props = {
3
+ /** DEM 瓦片模板(含 {z}/{x}/{y}),可与 MaplibreTerrain 共用;变更需配合 `:key` 重建 */
4
+ demUrl: string;
5
+ /**
6
+ * DEM 高程编码;变更需配合 `:key` 重建
7
+ * @defaultValue 'terrarium'
8
+ */
9
+ encoding?: 'terrarium' | 'mapbox';
10
+ /**
11
+ * DEM 瓦片最大缩放级别;变更需配合 `:key` 重建
12
+ * @defaultValue 12
13
+ */
14
+ maxzoom?: number;
15
+ /**
16
+ * 缩放级别到 [次线间距, 主线间距] 的映射,未列出的级别沿用更低一级
17
+ * @defaultValue `{ 11: [200, 1000], 12: [100, 500], 14: [50, 200], 15: [20, 100] }`
18
+ */
19
+ thresholds?: Record<number, number | number[]>;
20
+ /**
21
+ * 高程换算系数,如 3.28084 将米换算为英尺
22
+ * @defaultValue 1
23
+ */
24
+ multiplier?: number;
25
+ /**
26
+ * 标注的高程单位后缀
27
+ * @defaultValue 'm'
28
+ */
29
+ unit?: string;
30
+ /** 图层 id 前缀;省略时自动生成,变更需配合 `:key` 重建 */
31
+ layerId?: string;
32
+ /**
33
+ * 线条颜色
34
+ * @defaultValue '#a0522d'
35
+ */
36
+ lineColor?: string;
37
+ /**
38
+ * 是否沿主线标注高程
39
+ * @defaultValue true
40
+ */
41
+ labels?: boolean;
42
+ /** 覆盖合并到等高线的 paint */
43
+ linePaint?: Record<string, unknown>;
44
+ /** 覆盖合并到标注的 layout */
45
+ labelLayout?: Record<string, unknown>;
46
+ /** 插入到该图层之前 */
47
+ beforeId?: string;
48
+ };
49
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
50
+ maxzoom: number;
51
+ unit: string;
52
+ encoding: "terrarium" | "mapbox";
53
+ thresholds: Record<number, number | number[]>;
54
+ multiplier: number;
55
+ lineColor: string;
56
+ labels: boolean;
57
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
58
+ declare const _default: typeof __VLS_export;
59
+ export default _default;
@@ -0,0 +1,31 @@
1
+ /** 经纬网:按缩放级别自动选择步长,平移缩放后按视口重算,球形投影下呈曲线。 */
2
+ type __VLS_Props = {
3
+ /** 固定步长(度);省略时按缩放级别自动选择 */
4
+ step?: number;
5
+ /** 图层 id 前缀;省略时自动生成,变更需配合 `:key` 重建 */
6
+ layerId?: string;
7
+ /**
8
+ * 线条与标注颜色
9
+ * @defaultValue '#888'
10
+ */
11
+ color?: string;
12
+ /**
13
+ * 线宽(像素)
14
+ * @defaultValue 0.5
15
+ */
16
+ width?: number;
17
+ /**
18
+ * 是否在视口边缘标注度数
19
+ * @defaultValue true
20
+ */
21
+ labels?: boolean;
22
+ /** 插入到该图层之前 */
23
+ beforeId?: string;
24
+ };
25
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
26
+ color: string;
27
+ width: number;
28
+ labels: boolean;
29
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
@@ -0,0 +1,88 @@
1
+ <script setup>
2
+ import { computed, onUnmounted, shallowRef, useId, watch } from "vue";
3
+ import MaplibreLayer from "../Layer.vue";
4
+ import { useMap } from "../../composables/useMap";
5
+ import { textFontLayout } from "../../domains/map/config";
6
+ import { graticuleLabels, graticuleLines, graticuleStep } from "../../utils/graticule";
7
+ const props = defineProps({
8
+ step: { type: Number, required: false },
9
+ layerId: { type: String, required: false },
10
+ color: { type: String, required: false, default: "#888" },
11
+ width: { type: Number, required: false, default: 0.5 },
12
+ labels: { type: Boolean, required: false, default: true },
13
+ beforeId: { type: String, required: false }
14
+ });
15
+ const WORLD = [-180, -85, 180, 85];
16
+ const WORLD_ZOOM = 3;
17
+ const id = props.layerId ?? `movk-graticule-${useId()}`;
18
+ const ctx = useMap();
19
+ const lines = shallowRef({ type: "FeatureCollection", features: [] });
20
+ const labelData = shallowRef({ type: "FeatureCollection", features: [] });
21
+ let current;
22
+ function viewBounds(map) {
23
+ if (map.getZoom() < WORLD_ZOOM) return WORLD;
24
+ const bounds = map.getBounds();
25
+ return [bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()];
26
+ }
27
+ function labelAnchor(map, [west, south]) {
28
+ if (map.getZoom() >= WORLD_ZOOM) return [west, south];
29
+ const { lng, lat } = map.getCenter();
30
+ return [lng, lat];
31
+ }
32
+ function contains([west, south, east, north], [w, s, e, n]) {
33
+ return w >= west && s >= south && e <= east && n <= north;
34
+ }
35
+ function update(map) {
36
+ const bounds = viewBounds(map);
37
+ const step = props.step ?? graticuleStep(map.getZoom());
38
+ if (!current || current.step !== step || !contains(current.extent, bounds)) {
39
+ const next = graticuleLines(bounds, step);
40
+ current = { extent: next.extent, step };
41
+ lines.value = next.data;
42
+ }
43
+ if (props.labels) labelData.value = graticuleLabels(bounds, step, labelAnchor(map, bounds));
44
+ }
45
+ let boundMap;
46
+ const onMoveEnd = () => boundMap && update(boundMap);
47
+ const stopReady = ctx.onReady((map) => {
48
+ boundMap?.off("moveend", onMoveEnd);
49
+ boundMap = map;
50
+ map.on("moveend", onMoveEnd);
51
+ current = void 0;
52
+ update(map);
53
+ });
54
+ watch(() => [props.step, props.labels], () => {
55
+ current = void 0;
56
+ if (boundMap) update(boundMap);
57
+ });
58
+ onUnmounted(() => {
59
+ stopReady();
60
+ boundMap?.off("moveend", onMoveEnd);
61
+ boundMap = void 0;
62
+ });
63
+ const lineSource = computed(() => ({ type: "geojson", data: lines.value, tolerance: 0 }));
64
+ const labelSource = computed(() => ({ type: "geojson", data: labelData.value }));
65
+ const linePaint = computed(() => ({ "line-color": props.color, "line-width": props.width }));
66
+ const labelPaint = computed(() => ({ "text-color": props.color, "text-halo-color": "#fff", "text-halo-width": 1 }));
67
+ const labelLayout = {
68
+ "text-field": ["get", "label"],
69
+ "text-size": 10,
70
+ "text-anchor": ["match", ["get", "axis"], "lon", "bottom", "left"],
71
+ "text-offset": ["match", ["get", "axis"], "lon", ["literal", [0, -0.3]], ["literal", [0.3, 0]]],
72
+ "text-allow-overlap": true,
73
+ ...textFontLayout()
74
+ };
75
+ </script>
76
+
77
+ <template>
78
+ <MaplibreLayer :layer-id="`${id}-line`" type="line" :source="lineSource" :paint="linePaint" :before-id="beforeId" />
79
+ <MaplibreLayer
80
+ v-if="labels"
81
+ :layer-id="`${id}-label`"
82
+ type="symbol"
83
+ :source="labelSource"
84
+ :layout="labelLayout"
85
+ :paint="labelPaint"
86
+ :before-id="beforeId"
87
+ />
88
+ </template>
@@ -0,0 +1,31 @@
1
+ /** 经纬网:按缩放级别自动选择步长,平移缩放后按视口重算,球形投影下呈曲线。 */
2
+ type __VLS_Props = {
3
+ /** 固定步长(度);省略时按缩放级别自动选择 */
4
+ step?: number;
5
+ /** 图层 id 前缀;省略时自动生成,变更需配合 `:key` 重建 */
6
+ layerId?: string;
7
+ /**
8
+ * 线条与标注颜色
9
+ * @defaultValue '#888'
10
+ */
11
+ color?: string;
12
+ /**
13
+ * 线宽(像素)
14
+ * @defaultValue 0.5
15
+ */
16
+ width?: number;
17
+ /**
18
+ * 是否在视口边缘标注度数
19
+ * @defaultValue true
20
+ */
21
+ labels?: boolean;
22
+ /** 插入到该图层之前 */
23
+ beforeId?: string;
24
+ };
25
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
26
+ color: string;
27
+ width: number;
28
+ labels: boolean;
29
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
@@ -1,6 +1,6 @@
1
1
  import type { ImageSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
2
2
  type __VLS_Props = {
3
- /** 图层 id;省略时自动生成 */
3
+ /** 图层 id;省略时自动生成,变更需配合 `:key` 重建 */
4
4
  layerId?: string;
5
5
  /** 图片地址 */
6
6
  url: string;
@@ -1,6 +1,6 @@
1
1
  import type { ImageSourceSpecification } from '@maplibre/maplibre-gl-style-spec';
2
2
  type __VLS_Props = {
3
- /** 图层 id;省略时自动生成 */
3
+ /** 图层 id;省略时自动生成,变更需配合 `:key` 重建 */
4
4
  layerId?: string;
5
5
  /** 图片地址 */
6
6
  url: string;