@squirkle-ui/map 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +41 -2
- package/dist/styles.css +80 -0
- package/dist/types/SqMap.vue.d.ts +535 -0
- package/dist/types/adapters.d.ts +44 -0
- package/dist/types/cluster.d.ts +40 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/markers.d.ts +26 -0
- package/dist/vue2/index.cjs +459 -0
- package/dist/vue2/index.cjs.map +1 -0
- package/dist/vue2/index.mjs +437 -0
- package/dist/vue2/index.mjs.map +1 -0
- package/dist/vue3/index.cjs +522 -0
- package/dist/vue3/index.cjs.map +1 -0
- package/dist/vue3/index.mjs +500 -0
- package/dist/vue3/index.mjs.map +1 -0
- package/dist/vue3/styles.css +80 -0
- package/package.json +75 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/adapters.ts","../../src/markers.ts","../../src/cluster.ts","../../src/SqMap.vue","../../src/index.ts"],"sourcesContent":["/**\n * Thin engine adapters so SqMap renders markers, clusters and popups the same way on\n * MapLibre GL (vector tiles) and Leaflet (raster tiles). Engines are imported lazily (browser only).\n */\nimport type * as ML from 'maplibre-gl'\nimport type * as Leaflet from 'leaflet'\nimport type { BBox } from './cluster'\n\nexport type LatLng = [number, number]\n\nexport interface MarkerHandle {\n remove: () => void\n}\n\nexport interface MapAdapter {\n readonly engine: 'vector' | 'raster'\n /** The underlying maplibregl.Map or L.Map. */\n readonly native: unknown\n getCenter: () => LatLng\n getZoom: () => number\n getBounds: () => BBox\n setView: (center: LatLng, zoom: number, animate?: boolean) => void\n fitPoints: (points: LatLng[], padding: number, maxZoom: number) => void\n zoomIn: () => void\n zoomOut: () => void\n addMarker: (el: HTMLElement, at: LatLng, anchor: 'bottom' | 'center') => MarkerHandle\n openPopup: (at: LatLng, content: HTMLElement, offset: number) => void\n setStyle: (style: string | object) => void\n on: (event: 'moveend' | 'click' | 'error', cb: (payload?: unknown) => void) => void\n destroy: () => void\n}\n\nlet workerUrl: string | null = null\n\n/**\n * Where MapLibre loads its web worker from. Bundlers don't copy `maplibre-gl-worker.mjs` on their own, so apps pass\n * a bundler-resolved URL, e.g. `import url from 'maplibre-gl/dist/maplibre-gl-worker.mjs?url'` (Vite). Applied lazily.\n */\nexport function setMapWorkerUrl(url: string | null) {\n workerUrl = url\n}\n\n/** Keyless vector styles (verified 2026-10-24). */\nexport const MAP_STYLES: Record<string, string> = {\n positron: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',\n voyager: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json',\n 'dark-matter': 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',\n liberty: 'https://tiles.openfreemap.org/styles/liberty',\n bright: 'https://tiles.openfreemap.org/styles/bright',\n 'openfreemap-dark': 'https://tiles.openfreemap.org/styles/dark',\n fiord: 'https://tiles.openfreemap.org/styles/fiord',\n}\n\n/** `auto` follows the app theme; names map to MAP_STYLES; anything else is passed through (URL or style object). */\nexport function resolveMapStyle(style: string | object, dark: boolean): string | object {\n if (typeof style !== 'string') return style\n if (style === 'auto') return dark ? MAP_STYLES['dark-matter'] : MAP_STYLES.positron\n return MAP_STYLES[style] ?? style\n}\n\nconst defaultOf = <T>(mod: unknown): T => ((mod as { default?: T }).default ?? mod) as T\n\nexport async function createVectorAdapter(el: HTMLElement, opts: { center: LatLng; zoom: number; style: string | object; scrollZoom: boolean }): Promise<MapAdapter> {\n const [mod] = await Promise.all([import('maplibre-gl'), import('maplibre-gl/dist/maplibre-gl.css')])\n const ml = defaultOf<typeof ML>(mod)\n if (workerUrl) ml.setWorkerUrl(workerUrl)\n const map = new ml.Map({\n container: el,\n style: opts.style as ML.StyleSpecification | string,\n center: [opts.center[1], opts.center[0]],\n zoom: opts.zoom,\n attributionControl: { compact: true },\n scrollZoom: opts.scrollZoom,\n cooperativeGestures: false,\n })\n let popup: ML.Popup | null = null\n return {\n engine: 'vector',\n native: map,\n getCenter: () => { const c = map.getCenter(); return [c.lat, c.lng] },\n getZoom: () => map.getZoom(),\n getBounds: () => { const b = map.getBounds(); return [b.getWest(), b.getSouth(), b.getEast(), b.getNorth()] },\n setView: (c, z, animate) => (animate ? map.easeTo({ center: [c[1], c[0]], zoom: z, duration: 450 }) : map.jumpTo({ center: [c[1], c[0]], zoom: z })),\n fitPoints: (pts, padding, maxZoom) => {\n if (!pts.length) return\n const b = new ml.LngLatBounds([pts[0][1], pts[0][0]], [pts[0][1], pts[0][0]])\n pts.forEach((p) => b.extend([p[1], p[0]]))\n map.fitBounds(b, { padding, maxZoom, duration: 0 })\n },\n zoomIn: () => map.zoomIn(),\n zoomOut: () => map.zoomOut(),\n addMarker: (element, at, anchor) => {\n const m = new ml.Marker({ element, anchor }).setLngLat([at[1], at[0]]).addTo(map)\n return { remove: () => m.remove() }\n },\n openPopup: (at, content, offset) => {\n popup?.remove()\n popup = new ml.Popup({ offset, closeButton: false, className: 'sq-map__popup', maxWidth: '280px' }).setLngLat([at[1], at[0]]).setDOMContent(content).addTo(map)\n },\n setStyle: (style) => map.setStyle(style as ML.StyleSpecification | string),\n on: (event, cb) => {\n if (event === 'click') map.on('click', (e) => cb({ lat: e.lngLat.lat, lng: e.lngLat.lng }))\n else if (event === 'error') map.on('error', (e) => cb(e.error ?? e))\n else map.on('moveend', () => cb())\n },\n destroy: () => map.remove(),\n }\n}\n\nexport async function createRasterAdapter(el: HTMLElement, opts: { center: LatLng; zoom: number; tileUrl: string; attribution: string; scrollZoom: boolean }): Promise<MapAdapter> {\n const [mod] = await Promise.all([import('leaflet'), import('leaflet/dist/leaflet.css')])\n const L = defaultOf<typeof Leaflet>(mod)\n const map = L.map(el, { center: opts.center, zoom: opts.zoom, zoomControl: false, scrollWheelZoom: opts.scrollZoom })\n const tiles = L.tileLayer(opts.tileUrl, { attribution: opts.attribution, maxZoom: 19 }).addTo(map)\n return {\n engine: 'raster',\n native: map,\n getCenter: () => { const c = map.getCenter(); return [c.lat, c.lng] },\n getZoom: () => map.getZoom(),\n getBounds: () => { const b = map.getBounds(); return [b.getWest(), b.getSouth(), b.getEast(), b.getNorth()] },\n setView: (c, z, animate) => map.setView(c, z, { animate: !!animate }),\n fitPoints: (pts, padding, maxZoom) => pts.length && map.fitBounds(L.latLngBounds(pts), { padding: [padding, padding], maxZoom }),\n zoomIn: () => map.zoomIn(),\n zoomOut: () => map.zoomOut(),\n addMarker: (element, at, anchor) => {\n const wrap = document.createElement('div')\n wrap.className = `sq-map__anchor sq-map__anchor--${anchor}`\n wrap.appendChild(element)\n const m = L.marker(at, { icon: L.divIcon({ html: wrap, className: 'sq-map__marker-wrap', iconSize: [0, 0] }), keyboard: false }).addTo(map)\n return { remove: () => m.remove() }\n },\n openPopup: (at, content, offset) => {\n L.popup({ className: 'sq-map__popup', offset: [0, -offset], closeButton: false }).setLatLng(at).setContent(content).openOn(map)\n },\n setStyle: (style) => typeof style === 'string' && tiles.setUrl(style),\n on: (event, cb) => {\n if (event === 'click') map.on('click', (e: Leaflet.LeafletMouseEvent) => cb({ lat: e.latlng.lat, lng: e.latlng.lng }))\n else if (event === 'error') tiles.on('tileerror', (e) => cb(e))\n else map.on('moveend', () => cb())\n },\n destroy: () => map.remove(),\n }\n}\n","/** DOM builders for markers and cluster bubbles (shared by the vector and raster engines). */\nimport { colorValue, resolveIcon } from '@squirkle-ui/ui'\n\nexport type MarkerShape = 'pin' | 'dot' | 'squircle' | 'avatar'\n\nexport interface MapMarker {\n id?: string | number\n lat: number\n lng: number\n title?: string\n popup?: string\n /** Theme color name or CSS color. */\n color?: string\n /** Short text inside the marker (e.g. \"3\", \"$\"). */\n label?: string\n /** Built-in or Iconify icon name, e.g. `lucide:coffee`. */\n icon?: string\n /** Image URL for the `avatar` shape. */\n image?: string\n shape?: MarkerShape\n /** Marker size in px (default 30). */\n size?: number\n [key: string]: unknown\n}\n\n/** Anchor point used by the engines: pins stand on their tip, other shapes are centred. */\nexport const markerAnchor = (shape: MarkerShape) => (shape === 'pin' ? 'bottom' : 'center')\n\nfunction iconNode(icon: string): SVGElement | null {\n const r = resolveIcon(icon)\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n svg.setAttribute('aria-hidden', 'true')\n if (r.kind === 'path') {\n svg.setAttribute('viewBox', '0 0 24 24')\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n path.setAttribute('d', r.d)\n svg.appendChild(path)\n return svg\n }\n if (r.kind === 'svg') {\n svg.setAttribute('viewBox', `0 0 ${r.data.width} ${r.data.height}`)\n // Iconify body: same trust rule as SqIcon (addCollection data or the configured Iconify API host).\n svg.innerHTML = r.data.body\n return svg\n }\n return null\n}\n\n/** Builds a marker element with DOM APIs (text is never parsed as HTML). */\nexport function markerElement(m: MapMarker, defaults: Partial<MapMarker> = {}): HTMLElement {\n const o = { ...defaults, ...m }\n const shape = (o.shape ?? 'pin') as MarkerShape\n const el = document.createElement('div')\n el.className = `sq-map-marker sq-map-marker--${shape}`\n el.style.setProperty('--sq-pin', colorValue(o.color ?? 'primary') ?? 'var(--sq-primary)')\n el.style.setProperty('--sq-pin-size', `${o.size ?? 30}px`)\n el.setAttribute('role', 'button')\n el.setAttribute('tabindex', '0')\n el.setAttribute('aria-label', o.title ?? o.label ?? 'Marker')\n const body = document.createElement('span')\n body.className = 'sq-map-marker__body'\n if (shape === 'avatar' && o.image) {\n const img = document.createElement('img')\n img.src = o.image\n img.alt = ''\n img.loading = 'lazy'\n body.appendChild(img)\n } else if (shape !== 'dot') {\n const icon = o.icon ? iconNode(o.icon) : null\n const content = document.createElement('span')\n content.className = 'sq-map-marker__content'\n if (icon) content.appendChild(icon)\n else if (o.label) content.textContent = String(o.label)\n else content.classList.add('sq-map-marker__content--empty')\n body.appendChild(content)\n }\n el.appendChild(body)\n return el\n}\n\n/** Squircle bubble sized by the number of points it holds. */\nexport function clusterElement(count: number, color?: string): HTMLElement {\n const el = document.createElement('div')\n el.className = 'sq-map-cluster'\n const size = Math.round(34 + Math.min(30, Math.log2(count) * 5))\n el.style.setProperty('--sq-cluster-size', `${size}px`)\n el.style.setProperty('--sq-pin', colorValue(color ?? 'primary') ?? 'var(--sq-primary)')\n el.setAttribute('role', 'button')\n el.setAttribute('tabindex', '0')\n el.setAttribute('aria-label', `${count} places — zoom in`)\n const span = document.createElement('span')\n span.textContent = count >= 1000 ? `${(count / 1000).toFixed(count >= 10000 ? 0 : 1)}k` : String(count)\n el.appendChild(span)\n return el\n}\n","/** Engine-independent marker clustering (supercluster). Pure functions — unit-tested in test/cluster.test.ts. */\nimport Supercluster from 'supercluster'\n\nexport interface ClusterOptions {\n /** Cluster radius in screen pixels (default 60). */\n radius?: number\n /** Zoom level above which points are never clustered (default 16). */\n maxZoom?: number\n /** Minimum points to form a cluster (default 2). */\n minPoints?: number\n}\n\nexport type ClusterIndex = Supercluster<{ i: number }>\n\nexport type ClusterItem =\n | { kind: 'cluster'; id: number; lat: number; lng: number; count: number }\n | { kind: 'point'; index: number; lat: number; lng: number }\n\n/** West, south, east, north in degrees. */\nexport type BBox = [number, number, number, number]\n\n/** `tileSize` is the engine's tile size in px (MapLibre 512, Leaflet 256) so `radius` stays in screen pixels. */\nexport function createClusterIndex(points: { lat: number; lng: number }[], opts: ClusterOptions = {}, tileSize = 512): ClusterIndex {\n const index: ClusterIndex = new Supercluster({ radius: opts.radius ?? 60, maxZoom: opts.maxZoom ?? 16, minPoints: opts.minPoints ?? 2, extent: tileSize })\n index.load(points.map((p, i) => ({ type: 'Feature' as const, geometry: { type: 'Point' as const, coordinates: [p.lng, p.lat] }, properties: { i } })))\n return index\n}\n\n/** Clusters and single points visible in `bbox` at `zoom`. */\nexport function clustersFor(index: ClusterIndex, bbox: BBox, zoom: number): ClusterItem[] {\n return index.getClusters(bbox, Math.floor(zoom)).map((f) => {\n const [lng, lat] = f.geometry.coordinates\n const p = f.properties as { cluster?: boolean; cluster_id?: number; point_count?: number; i?: number }\n return p.cluster\n ? { kind: 'cluster' as const, id: p.cluster_id!, lat, lng, count: p.point_count! }\n : { kind: 'point' as const, index: p.i!, lat, lng }\n })\n}\n\n/** Zoom level at which a cluster splits apart. */\nexport const expansionZoom = (index: ClusterIndex, clusterId: number) => index.getClusterExpansionZoom(clusterId)\n\n/** Indices (into the original points array) of every point inside a cluster. */\nexport const clusterLeaves = (index: ClusterIndex, clusterId: number) =>\n index.getLeaves(clusterId, Infinity).map((f) => (f.properties as { i: number }).i)\n\n/** Grows a bbox by `ratio` on each side so markers just outside the view are ready before they scroll in. */\nexport function padBBox([w, s, e, n]: BBox, ratio = 0.25): BBox {\n const dx = (e - w) * ratio\n const dy = (n - s) * ratio\n return [Math.max(-180, w - dx), Math.max(-85, s - dy), Math.min(180, e + dx), Math.min(85, n + dy)]\n}\n","<template>\n <div class=\"sq-map sq-surface\" :style=\"{ height: toUnit(height), '--sq-r': radiusValue(rounded), '--sq-bg': 'var(--sq-surface-variant)', '--sq-bd': 'var(--sq-border)', '--sq-bw': '1px' }\">\n <SqShape clip />\n <div ref=\"el\" class=\"sq-map__canvas\" role=\"application\" :aria-label=\"label\"></div>\n <div v-if=\"!ready\" class=\"sq-map__loading\"><SqProgressCircular indeterminate :size=\"24\" :width=\"3\" /></div>\n <div class=\"sq-map__controls\">\n <SqBtn icon=\"plus\" color=\"surface\" variant=\"elevated\" size=\"small\" aria-label=\"Zoom in\" @click=\"adapter && adapter.zoomIn()\" />\n <SqBtn icon=\"minus\" color=\"surface\" variant=\"elevated\" size=\"small\" aria-label=\"Zoom out\" @click=\"adapter && adapter.zoomOut()\" />\n <SqBtn v-if=\"markers.length > 1\" icon=\"place\" color=\"surface\" variant=\"elevated\" size=\"small\" aria-label=\"Fit markers\" @click=\"fit\" />\n </div>\n <!-- Slot templates: cloned into popups / marker elements by the engine. -->\n <div class=\"sq-map__templates\" aria-hidden=\"true\">\n <div v-for=\"(m, i) in markers\" :key=\"'p' + keyOf(m, i)\" :data-popup=\"keyOf(m, i)\"><slot name=\"popup\" :marker=\"m\"><b v-if=\"m.title\">{{ m.title }}</b><div v-if=\"m.popup\">{{ m.popup }}</div></slot></div>\n <template v-if=\"has('marker')\">\n <div v-for=\"(m, i) in markers\" :key=\"'m' + keyOf(m, i)\" :data-marker=\"keyOf(m, i)\"><slot name=\"marker\" :marker=\"m\" /></div>\n </template>\n </div>\n <slot :map=\"adapter ? adapter.native : null\" />\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, getCurrentInstance, markRaw, onBeforeUnmount, onMounted, ref, shallowRef, watch, type PropType } from 'vue'\nimport { toUnit } from '@squirkle-ui/core'\nimport { SqBtn, SqProgressCircular, SqShape, config, iconStoreVersion, radiusValue } from '@squirkle-ui/ui'\nimport { createRasterAdapter, createVectorAdapter, resolveMapStyle, type LatLng, type MapAdapter, type MarkerHandle } from './adapters'\nimport { clusterElement, markerAnchor, markerElement, type MapMarker, type MarkerShape } from './markers'\nimport { clusterLeaves, clustersFor, createClusterIndex, expansionZoom, padBBox, type ClusterIndex, type ClusterOptions } from './cluster'\n\n/**\n * Squircle map. `engine=\"vector\"` (default) renders vector tiles with MapLibre GL; `engine=\"raster\"` uses Leaflet.\n * Both are optional peer dependencies loaded on mount, so the component is SSR-safe.\n * Markers: shapes pin / dot / squircle / avatar, icons, labels, or a `#marker` slot. `cluster` groups dense markers.\n */\nexport default defineComponent({\n name: 'SqMap',\n components: { SqBtn, SqProgressCircular, SqShape },\n props: {\n engine: { type: String as PropType<'vector' | 'raster'>, default: 'vector' },\n /** Vector style: `auto` (follows light/dark), a preset name (positron, voyager, dark-matter, liberty, bright, openfreemap-dark, fiord), a style URL or a style object. */\n mapStyle: { type: [String, Object] as PropType<string | object>, default: 'auto' },\n center: { type: Array as unknown as PropType<LatLng>, default: () => [11.5564, 104.9282] },\n zoom: { type: Number, default: 12 },\n markers: { type: Array as PropType<MapMarker[]>, default: () => [] },\n /** Defaults merged into every marker (shape, color, size, icon…). */\n markerDefaults: { type: Object as PropType<Partial<MapMarker>>, default: () => ({}) },\n cluster: { type: [Boolean, Object] as PropType<boolean | ClusterOptions>, default: false },\n clusterColor: { type: String, default: 'primary' },\n /** Raster engine tile template. */\n tileUrl: { type: String, default: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' },\n attribution: { type: String, default: '© <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\" rel=\"noopener noreferrer\">OpenStreetMap</a> contributors' },\n height: { type: [Number, String], default: 400 },\n rounded: { type: [String, Number], default: 'xl' },\n fitMarkers: Boolean,\n scrollWheelZoom: { type: Boolean, default: false },\n label: { type: String, default: 'Map' },\n },\n emits: ['update:center', 'update:zoom', 'click', 'marker-click', 'cluster-click', 'ready', 'error'],\n setup(props, { emit, slots }) {\n const el = ref<HTMLElement | null>(null)\n const adapter = shallowRef<MapAdapter | null>(null)\n const ready = ref(false)\n const inst = getCurrentInstance()\n const handles = new Map<string, MarkerHandle>()\n let index: ClusterIndex | null = null\n let epoch = 0\n const keyOf = (m: MapMarker, i: number) => String(m.id ?? i)\n const isDark = computed(() => !!config.theme.themes[config.theme.name]?.dark)\n const root = () => inst?.proxy?.$el as HTMLElement\n\n const clearMarkers = () => {\n handles.forEach((h) => h.remove())\n handles.clear()\n }\n const pointElement = (m: MapMarker, i: number) => {\n const tpl = slots.marker ? root().querySelector<HTMLElement>(`[data-marker=\"${CSS.escape(keyOf(m, i))}\"]`)?.firstElementChild : null\n const node = tpl ? (tpl.cloneNode(true) as HTMLElement) : markerElement(m, props.markerDefaults)\n if (tpl) node.classList.add('sq-map-marker', 'sq-map-marker--custom')\n const open = (e: Event) => {\n e.stopPropagation()\n emit('marker-click', m)\n const popup = root().querySelector<HTMLElement>(`[data-popup=\"${CSS.escape(keyOf(m, i))}\"]`)\n if (popup && popup.textContent?.trim()) adapter.value?.openPopup([m.lat, m.lng], popup.cloneNode(true) as HTMLElement, (m.size ?? props.markerDefaults.size ?? 30) + 4)\n }\n node.addEventListener('click', open)\n node.addEventListener('keydown', (e) => (e.key === 'Enter' || e.key === ' ') && open(e))\n return node\n }\n const shapeOf = (m: MapMarker) => (slots.marker ? 'center' : markerAnchor((m.shape ?? props.markerDefaults.shape ?? 'pin') as MarkerShape))\n\n /** Adds/removes DOM markers so only visible points and clusters exist. */\n const render = () => {\n const a = adapter.value\n if (!a) return\n const want = new Map<string, () => MarkerHandle>()\n if (index) {\n for (const item of clustersFor(index, padBBox(a.getBounds()), a.getZoom())) {\n if (item.kind === 'cluster') {\n const key = `c${item.id}`\n want.set(key, () => {\n const node = clusterElement(item.count, props.clusterColor)\n const zoomIn = (e: Event) => {\n e.stopPropagation()\n const idx = index!\n emit('cluster-click', { count: item.count, markers: clusterLeaves(idx, item.id).map((i) => props.markers[i]) })\n a.setView([item.lat, item.lng], Math.min(expansionZoom(idx, item.id), 20), true)\n }\n node.addEventListener('click', zoomIn)\n node.addEventListener('keydown', (e) => (e.key === 'Enter' || e.key === ' ') && zoomIn(e))\n return a.addMarker(node, [item.lat, item.lng], 'center')\n })\n } else {\n const m = props.markers[item.index]\n want.set(`p${item.index}`, () => a.addMarker(pointElement(m, item.index), [m.lat, m.lng], shapeOf(m)))\n }\n }\n } else {\n props.markers.forEach((m, i) => want.set(`p${i}`, () => a.addMarker(pointElement(m, i), [m.lat, m.lng], shapeOf(m))))\n }\n for (const [k, h] of handles) if (!want.has(k)) { h.remove(); handles.delete(k) }\n for (const [k, make] of want) if (!handles.has(k)) handles.set(k, make())\n }\n const rebuild = () => {\n clearMarkers()\n index = props.cluster ? createClusterIndex(props.markers, typeof props.cluster === 'object' ? props.cluster : {}, props.engine === 'raster' ? 256 : 512) : null\n render()\n }\n const fit = () => adapter.value?.fitPoints(props.markers.map((m) => [m.lat, m.lng]), 48, 15)\n\n const mount = async () => {\n const my = ++epoch\n if (!el.value) return\n ready.value = false\n const a = props.engine === 'raster'\n ? await createRasterAdapter(el.value, { center: props.center, zoom: props.zoom, tileUrl: props.tileUrl, attribution: props.attribution, scrollZoom: props.scrollWheelZoom })\n : await createVectorAdapter(el.value, { center: props.center, zoom: props.zoom, style: resolveMapStyle(props.mapStyle, isDark.value), scrollZoom: props.scrollWheelZoom })\n if (my !== epoch) return a.destroy()\n adapter.value = markRaw(a)\n a.on('moveend', () => {\n const c = a.getCenter()\n emit('update:center', c)\n emit('update:zoom', Math.round(a.getZoom() * 100) / 100)\n if (index) render()\n })\n a.on('click', (p) => emit('click', p))\n a.on('error', (e) => emit('error', e))\n if (props.fitMarkers) fit()\n rebuild()\n ready.value = true\n emit('ready', a.native)\n }\n const unmountMap = () => {\n clearMarkers()\n adapter.value?.destroy()\n adapter.value = null\n }\n\n // Nuxt client-only components render a placeholder while hydrating, so the canvas ref can still be empty here.\n onMounted(() => {\n if (el.value) return mount()\n const stop = watch(el, (node) => { if (node) { stop(); return mount() } })\n })\n onBeforeUnmount(() => { epoch++; unmountMap() })\n watch(() => props.engine, () => { unmountMap(); mount() })\n watch(() => props.markers, () => { if (!adapter.value) return; if (props.fitMarkers) fit(); requestAnimationFrame(rebuild) }, { deep: true, flush: 'post' })\n watch(() => [props.cluster, props.markerDefaults, props.clusterColor], () => adapter.value && rebuild(), { deep: true })\n // Iconify icons arrive asynchronously; rebuild markers that use them.\n watch(iconStoreVersion, () => adapter.value && props.markers.some((m) => m.icon || props.markerDefaults.icon) && rebuild())\n watch([() => props.mapStyle, isDark], () => {\n const a = adapter.value\n if (a && a.engine === 'vector') a.setStyle(resolveMapStyle(props.mapStyle, isDark.value))\n })\n watch(() => props.tileUrl, (url) => adapter.value?.engine === 'raster' && adapter.value.setStyle(url))\n watch(() => [props.center[0], props.center[1], props.zoom], () => {\n const a = adapter.value\n if (!a) return\n const c = a.getCenter()\n if (Math.abs(c[0] - props.center[0]) > 1e-6 || Math.abs(c[1] - props.center[1]) > 1e-6 || Math.abs(a.getZoom() - props.zoom) > 0.01) a.setView(props.center, props.zoom)\n })\n return { el, adapter, ready, keyOf, fit, toUnit, radiusValue, has: (n: string) => !!slots[n] }\n },\n})\n</script>\n\n<style>\n.sq-map { position: relative; overflow: hidden; isolation: isolate; }\n/* Two classes: MapLibre's lazily loaded CSS sets `.maplibregl-map { position: relative }` and would collapse the canvas to 0 px. */\n.sq-map .sq-map__canvas { position: absolute; inset: 0; z-index: 0; border-radius: inherit; background: var(--sq-surface-variant); font: inherit; }\n.sq-map__loading { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 1; }\n.sq-map__controls { position: absolute; top: var(--sq-space-3); right: var(--sq-space-3); z-index: 500; display: flex; flex-direction: column; gap: 6px; }\n.sq-map__templates { display: none; }\n\n/* markers */\n.sq-map-marker { --sq-pin: var(--sq-primary); --sq-pin-size: 30px; position: relative; cursor: pointer; outline: none; transition: transform var(--sq-duration-fast) var(--sq-ease-spring); }\n.sq-map-marker:hover, .sq-map-marker:focus-visible { transform: scale(1.12); z-index: 2; }\n.sq-map-marker__body { display: flex; align-items: center; justify-content: center; width: var(--sq-pin-size); height: var(--sq-pin-size); background: var(--sq-pin); color: #fff; box-shadow: 0 3px 10px rgb(0 0 0 / 0.28), inset 0 0 0 2px rgb(255 255 255 / 0.92); }\n.sq-map-marker__content { display: flex; align-items: center; justify-content: center; font: 700 calc(var(--sq-pin-size) * 0.38) / 1 var(--sq-font); }\n.sq-map-marker__content svg { width: calc(var(--sq-pin-size) * 0.52); height: calc(var(--sq-pin-size) * 0.52); fill: currentColor; }\n.sq-map-marker__content--empty::after { content: ''; display: block; width: 30%; height: 30%; min-width: 8px; min-height: 8px; border-radius: 30%; background: #fff; }\n.sq-map-marker--pin .sq-map-marker__body { border-radius: 38% 38% 38% 10%; transform: rotate(-45deg); margin-bottom: calc(var(--sq-pin-size) * 0.2); }\n.sq-map-marker--pin .sq-map-marker__content { transform: rotate(45deg); }\n.sq-map-marker--squircle .sq-map-marker__body { border-radius: 32%; }\n.sq-map-marker--avatar .sq-map-marker__body { border-radius: 34%; overflow: hidden; padding: 2px; background: #fff; box-shadow: 0 3px 10px rgb(0 0 0 / 0.28), 0 0 0 2px var(--sq-pin); }\n.sq-map-marker--avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 30%; }\n.sq-map-marker--dot .sq-map-marker__body { width: calc(var(--sq-pin-size) * 0.5); height: calc(var(--sq-pin-size) * 0.5); border-radius: 50%; box-shadow: 0 0 0 3px #fff, 0 0 0 7px color-mix(in srgb, var(--sq-pin) 28%, transparent), 0 2px 6px rgb(0 0 0 / 0.3); }\n@supports (corner-shape: squircle) {\n .sq-map-marker--pin .sq-map-marker__body { border-radius: 58% 58% 58% 14%; corner-shape: squircle; }\n .sq-map-marker--squircle .sq-map-marker__body, .sq-map-marker--avatar .sq-map-marker__body, .sq-map-marker--avatar img, .sq-map-cluster { corner-shape: squircle; }\n .sq-map-marker--squircle .sq-map-marker__body, .sq-map-marker--avatar .sq-map-marker__body { border-radius: 50%; }\n .sq-map-marker--avatar img { border-radius: 46%; }\n .sq-map-cluster { border-radius: 50%; }\n .sq-map__canvas { corner-shape: inherit; }\n}\n.sq-map-cluster { --sq-cluster-size: 40px; display: flex; align-items: center; justify-content: center; width: var(--sq-cluster-size); height: var(--sq-cluster-size); border-radius: 34%; background: var(--sq-pin); color: #fff; font: 700 13px/1 var(--sq-font); cursor: pointer; outline: none; box-shadow: 0 0 0 5px color-mix(in srgb, var(--sq-pin) 26%, transparent), 0 4px 12px rgb(0 0 0 / 0.25); transition: transform var(--sq-duration-fast) var(--sq-ease-spring); }\n.sq-map-cluster:hover, .sq-map-cluster:focus-visible { transform: scale(1.1); }\n\n/* Leaflet marker anchoring (MapLibre anchors natively) */\n.sq-map__marker-wrap { background: none; border: 0; }\n.sq-map__anchor { position: absolute; left: 0; top: 0; }\n.sq-map__anchor--center { transform: translate(-50%, -50%); }\n.sq-map__anchor--bottom { transform: translate(-50%, -100%); }\n\n/* popups (both engines) */\n.sq-map .maplibregl-popup-content, .sq-map .leaflet-popup-content-wrapper { border-radius: var(--sq-radius-lg); background: var(--sq-surface-raised); color: var(--sq-on-surface); box-shadow: var(--sq-elevation-3); padding: 10px 14px; font: var(--sq-text-sm) / 1.5 var(--sq-font); }\n.sq-map .leaflet-popup-content { margin: 0; }\n.sq-map .maplibregl-popup-tip { border-top-color: var(--sq-surface-raised) !important; border-bottom-color: var(--sq-surface-raised) !important; }\n.sq-map .leaflet-popup-tip { background: var(--sq-surface-raised); }\n.sq-map .maplibregl-ctrl-attrib, .sq-map .leaflet-control-attribution { border-radius: var(--sq-radius-sm); font-size: 10px; background: color-mix(in srgb, var(--sq-surface) 82%, transparent); color: var(--sq-muted); }\n.sq-map .maplibregl-ctrl-attrib a, .sq-map .leaflet-control-attribution a { color: var(--sq-primary); }\n</style>\n","import SqMap from './SqMap.vue'\n\nexport { SqMap }\nexport { MAP_STYLES, resolveMapStyle, setMapWorkerUrl, createVectorAdapter, createRasterAdapter, type MapAdapter, type LatLng } from './adapters'\nexport { markerElement, clusterElement, type MapMarker, type MarkerShape } from './markers'\nexport { createClusterIndex, clustersFor, clusterLeaves, expansionZoom, type ClusterOptions, type ClusterItem } from './cluster'\nexport const componentNames = ['SqMap'] as const\nexport default SqMap\n"],"names":["resolveIcon","colorValue","defineComponent","SqBtn","SqProgressCircular","SqShape","ref","shallowRef","getCurrentInstance","computed","config","markRaw","onMounted","watch","onBeforeUnmount","iconStoreVersion","toUnit","radiusValue","_openBlock","_createElementBlock","_normalizeStyle","_createVNode","_createElementVNode","_createBlock","_createCommentVNode","_Fragment","_renderList","_renderSlot","_toDisplayString"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAI,YAA2B;AAMxB,SAAS,gBAAgB,KAAoB;AAClD,cAAY;AACd;AAGO,MAAM,aAAqC;AAAA,EAChD,UAAU;AAAA,EACV,SAAS;AAAA,EACT,eAAe;AAAA,EACf,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,oBAAoB;AAAA,EACpB,OAAO;AACT;AAGO,SAAS,gBAAgB,OAAwB,MAAgC;AACtF,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,UAAU,OAAQ,QAAO,OAAO,WAAW,aAAa,IAAI,WAAW;AAC3E,SAAO,WAAW,KAAK,KAAK;AAC9B;AAEA,MAAM,YAAY,CAAI,QAAsB,IAAwB,WAAW;AAE/E,eAAsB,oBAAoB,IAAiB,MAA0G;AACnK,QAAM,CAAC,GAAG,IAAI,MAAM,QAAQ,IAAI,CAAC,OAAO,aAAa,GAAG,OAAO,kCAAkC,CAAC,CAAC;AACnG,QAAM,KAAK,UAAqB,GAAG;AACnC,MAAI,UAAW,IAAG,aAAa,SAAS;AACxC,QAAM,MAAM,IAAI,GAAG,IAAI;AAAA,IACrB,WAAW;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,QAAQ,CAAC,KAAK,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC;AAAA,IACvC,MAAM,KAAK;AAAA,IACX,oBAAoB,EAAE,SAAS,KAAA;AAAA,IAC/B,YAAY,KAAK;AAAA,IACjB,qBAAqB;AAAA,EAAA,CACtB;AACD,MAAI,QAAyB;AAC7B,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW,MAAM;AAAE,YAAM,IAAI,IAAI,UAAA;AAAa,aAAO,CAAC,EAAE,KAAK,EAAE,GAAG;AAAA,IAAE;AAAA,IACpE,SAAS,MAAM,IAAI,QAAA;AAAA,IACnB,WAAW,MAAM;AAAE,YAAM,IAAI,IAAI,UAAA;AAAa,aAAO,CAAC,EAAE,QAAA,GAAW,EAAE,YAAY,EAAE,QAAA,GAAW,EAAE,SAAA,CAAU;AAAA,IAAE;AAAA,IAC5G,SAAS,CAAC,GAAG,GAAG,YAAa,UAAU,IAAI,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,MAAM,GAAG,UAAU,KAAK,IAAI,IAAI,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,MAAM,GAAG;AAAA,IAClJ,WAAW,CAAC,KAAK,SAAS,YAAY;AACpC,UAAI,CAAC,IAAI,OAAQ;AACjB,YAAM,IAAI,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5E,UAAI,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,UAAI,UAAU,GAAG,EAAE,SAAS,SAAS,UAAU,GAAG;AAAA,IACpD;AAAA,IACA,QAAQ,MAAM,IAAI,OAAA;AAAA,IAClB,SAAS,MAAM,IAAI,QAAA;AAAA,IACnB,WAAW,CAAC,SAAS,IAAI,WAAW;AAClC,YAAM,IAAI,IAAI,GAAG,OAAO,EAAE,SAAS,OAAA,CAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG;AAChF,aAAO,EAAE,QAAQ,MAAM,EAAE,SAAO;AAAA,IAClC;AAAA,IACA,WAAW,CAAC,IAAI,SAAS,WAAW;AAClC,aAAO,OAAA;AACP,cAAQ,IAAI,GAAG,MAAM,EAAE,QAAQ,aAAa,OAAO,WAAW,iBAAiB,UAAU,QAAA,CAAS,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,cAAc,OAAO,EAAE,MAAM,GAAG;AAAA,IAChK;AAAA,IACA,UAAU,CAAC,UAAU,IAAI,SAAS,KAAuC;AAAA,IACzE,IAAI,CAAC,OAAO,OAAO;AACjB,UAAI,UAAU,QAAS,KAAI,GAAG,SAAS,CAAC,MAAM,GAAG,EAAE,KAAK,EAAE,OAAO,KAAK,KAAK,EAAE,OAAO,IAAA,CAAK,CAAC;AAAA,eACjF,UAAU,QAAS,KAAI,GAAG,SAAS,CAAC,MAAM,GAAG,EAAE,SAAS,CAAC,CAAC;AAAA,UAC9D,KAAI,GAAG,WAAW,MAAM,IAAI;AAAA,IACnC;AAAA,IACA,SAAS,MAAM,IAAI,OAAA;AAAA,EAAO;AAE9B;AAEA,eAAsB,oBAAoB,IAAiB,MAAwH;AACjL,QAAM,CAAC,GAAG,IAAI,MAAM,QAAQ,IAAI,CAAC,OAAO,SAAS,GAAG,OAAO,0BAA0B,CAAC,CAAC;AACvF,QAAM,IAAI,UAA0B,GAAG;AACvC,QAAM,MAAM,EAAE,IAAI,IAAI,EAAE,QAAQ,KAAK,QAAQ,MAAM,KAAK,MAAM,aAAa,OAAO,iBAAiB,KAAK,YAAY;AACpH,QAAM,QAAQ,EAAE,UAAU,KAAK,SAAS,EAAE,aAAa,KAAK,aAAa,SAAS,GAAA,CAAI,EAAE,MAAM,GAAG;AACjG,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW,MAAM;AAAE,YAAM,IAAI,IAAI,UAAA;AAAa,aAAO,CAAC,EAAE,KAAK,EAAE,GAAG;AAAA,IAAE;AAAA,IACpE,SAAS,MAAM,IAAI,QAAA;AAAA,IACnB,WAAW,MAAM;AAAE,YAAM,IAAI,IAAI,UAAA;AAAa,aAAO,CAAC,EAAE,QAAA,GAAW,EAAE,YAAY,EAAE,QAAA,GAAW,EAAE,SAAA,CAAU;AAAA,IAAE;AAAA,IAC5G,SAAS,CAAC,GAAG,GAAG,YAAY,IAAI,QAAQ,GAAG,GAAG,EAAE,SAAS,CAAC,CAAC,SAAS;AAAA,IACpE,WAAW,CAAC,KAAK,SAAS,YAAY,IAAI,UAAU,IAAI,UAAU,EAAE,aAAa,GAAG,GAAG,EAAE,SAAS,CAAC,SAAS,OAAO,GAAG,SAAS;AAAA,IAC/H,QAAQ,MAAM,IAAI,OAAA;AAAA,IAClB,SAAS,MAAM,IAAI,QAAA;AAAA,IACnB,WAAW,CAAC,SAAS,IAAI,WAAW;AAClC,YAAM,OAAO,SAAS,cAAc,KAAK;AACzC,WAAK,YAAY,kCAAkC,MAAM;AACzD,WAAK,YAAY,OAAO;AACxB,YAAM,IAAI,EAAE,OAAO,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,MAAM,WAAW,uBAAuB,UAAU,CAAC,GAAG,CAAC,EAAA,CAAG,GAAG,UAAU,MAAA,CAAO,EAAE,MAAM,GAAG;AAC1I,aAAO,EAAE,QAAQ,MAAM,EAAE,SAAO;AAAA,IAClC;AAAA,IACA,WAAW,CAAC,IAAI,SAAS,WAAW;AAClC,QAAE,MAAM,EAAE,WAAW,iBAAiB,QAAQ,CAAC,GAAG,CAAC,MAAM,GAAG,aAAa,MAAA,CAAO,EAAE,UAAU,EAAE,EAAE,WAAW,OAAO,EAAE,OAAO,GAAG;AAAA,IAChI;AAAA,IACA,UAAU,CAAC,UAAU,OAAO,UAAU,YAAY,MAAM,OAAO,KAAK;AAAA,IACpE,IAAI,CAAC,OAAO,OAAO;AACjB,UAAI,UAAU,QAAS,KAAI,GAAG,SAAS,CAAC,MAAiC,GAAG,EAAE,KAAK,EAAE,OAAO,KAAK,KAAK,EAAE,OAAO,IAAA,CAAK,CAAC;AAAA,eAC5G,UAAU,QAAS,OAAM,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;AAAA,UACzD,KAAI,GAAG,WAAW,MAAM,IAAI;AAAA,IACnC;AAAA,IACA,SAAS,MAAM,IAAI,OAAA;AAAA,EAAO;AAE9B;ACpHO,MAAM,eAAe,CAAC,UAAwB,UAAU,QAAQ,WAAW;AAElF,SAAS,SAAS,MAAiC;AACjD,QAAM,IAAIA,GAAAA,YAAY,IAAI;AAC1B,QAAM,MAAM,SAAS,gBAAgB,8BAA8B,KAAK;AACxE,MAAI,aAAa,eAAe,MAAM;AACtC,MAAI,EAAE,SAAS,QAAQ;AACrB,QAAI,aAAa,WAAW,WAAW;AACvC,UAAM,OAAO,SAAS,gBAAgB,8BAA8B,MAAM;AAC1E,SAAK,aAAa,KAAK,EAAE,CAAC;AAC1B,QAAI,YAAY,IAAI;AACpB,WAAO;AAAA,EACT;AACA,MAAI,EAAE,SAAS,OAAO;AACpB,QAAI,aAAa,WAAW,OAAO,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,MAAM,EAAE;AAElE,QAAI,YAAY,EAAE,KAAK;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,SAAS,cAAc,GAAc,WAA+B,IAAiB;AAC1F,QAAM,IAAI,EAAE,GAAG,UAAU,GAAG,EAAA;AAC5B,QAAM,QAAS,EAAE,SAAS;AAC1B,QAAM,KAAK,SAAS,cAAc,KAAK;AACvC,KAAG,YAAY,gCAAgC,KAAK;AACpD,KAAG,MAAM,YAAY,YAAYC,GAAAA,WAAW,EAAE,SAAS,SAAS,KAAK,mBAAmB;AACxF,KAAG,MAAM,YAAY,iBAAiB,GAAG,EAAE,QAAQ,EAAE,IAAI;AACzD,KAAG,aAAa,QAAQ,QAAQ;AAChC,KAAG,aAAa,YAAY,GAAG;AAC/B,KAAG,aAAa,cAAc,EAAE,SAAS,EAAE,SAAS,QAAQ;AAC5D,QAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,OAAK,YAAY;AACjB,MAAI,UAAU,YAAY,EAAE,OAAO;AACjC,UAAM,MAAM,SAAS,cAAc,KAAK;AACxC,QAAI,MAAM,EAAE;AACZ,QAAI,MAAM;AACV,QAAI,UAAU;AACd,SAAK,YAAY,GAAG;AAAA,EACtB,WAAW,UAAU,OAAO;AAC1B,UAAM,OAAO,EAAE,OAAO,SAAS,EAAE,IAAI,IAAI;AACzC,UAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,YAAQ,YAAY;AACpB,QAAI,KAAM,SAAQ,YAAY,IAAI;AAAA,aACzB,EAAE,MAAO,SAAQ,cAAc,OAAO,EAAE,KAAK;AAAA,QACjD,SAAQ,UAAU,IAAI,+BAA+B;AAC1D,SAAK,YAAY,OAAO;AAAA,EAC1B;AACA,KAAG,YAAY,IAAI;AACnB,SAAO;AACT;AAGO,SAAS,eAAe,OAAe,OAA6B;AACzE,QAAM,KAAK,SAAS,cAAc,KAAK;AACvC,KAAG,YAAY;AACf,QAAM,OAAO,KAAK,MAAM,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;AAC/D,KAAG,MAAM,YAAY,qBAAqB,GAAG,IAAI,IAAI;AACrD,KAAG,MAAM,YAAY,YAAYA,GAAAA,WAAW,SAAS,SAAS,KAAK,mBAAmB;AACtF,KAAG,aAAa,QAAQ,QAAQ;AAChC,KAAG,aAAa,YAAY,GAAG;AAC/B,KAAG,aAAa,cAAc,GAAG,KAAK,mBAAmB;AACzD,QAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,OAAK,cAAc,SAAS,MAAO,IAAI,QAAQ,KAAM,QAAQ,SAAS,MAAQ,IAAI,CAAC,CAAC,MAAM,OAAO,KAAK;AACtG,KAAG,YAAY,IAAI;AACnB,SAAO;AACT;ACxEO,SAAS,mBAAmB,QAAwC,OAAuB,CAAA,GAAI,WAAW,KAAmB;AAClI,QAAM,QAAsB,IAAI,aAAa,EAAE,QAAQ,KAAK,UAAU,IAAI,SAAS,KAAK,WAAW,IAAI,WAAW,KAAK,aAAa,GAAG,QAAQ,UAAU;AACzJ,QAAM,KAAK,OAAO,IAAI,CAAC,GAAG,OAAO,EAAE,MAAM,WAAoB,UAAU,EAAE,MAAM,SAAkB,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,EAAA,GAAK,YAAY,EAAE,EAAA,EAAE,EAAI,CAAC;AACrJ,SAAO;AACT;AAGO,SAAS,YAAY,OAAqB,MAAY,MAA6B;AACxF,SAAO,MAAM,YAAY,MAAM,KAAK,MAAM,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM;AAC1D,UAAM,CAAC,KAAK,GAAG,IAAI,EAAE,SAAS;AAC9B,UAAM,IAAI,EAAE;AACZ,WAAO,EAAE,UACL,EAAE,MAAM,WAAoB,IAAI,EAAE,YAAa,KAAK,KAAK,OAAO,EAAE,gBAClE,EAAE,MAAM,SAAkB,OAAO,EAAE,GAAI,KAAK,IAAA;AAAA,EAClD,CAAC;AACH;AAGO,MAAM,gBAAgB,CAAC,OAAqB,cAAsB,MAAM,wBAAwB,SAAS;AAGzG,MAAM,gBAAgB,CAAC,OAAqB,cACjD,MAAM,UAAU,WAAW,QAAQ,EAAE,IAAI,CAAC,MAAO,EAAE,WAA6B,CAAC;AAG5E,SAAS,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,GAAS,QAAQ,MAAY;AAC9D,QAAM,MAAM,IAAI,KAAK;AACrB,QAAM,MAAM,IAAI,KAAK;AACrB,SAAO,CAAC,KAAK,IAAI,MAAM,IAAI,EAAE,GAAG,KAAK,IAAI,KAAK,IAAI,EAAE,GAAG,KAAK,IAAI,KAAK,IAAI,EAAE,GAAG,KAAK,IAAI,IAAI,IAAI,EAAE,CAAC;AACpG;ACjBA,MAAA,YAAeC,oBAAgB;AAAA,EAC7B,MAAM;AAAA,EACN,YAAY,EAAA,OAAEC,GAAAA,2BAAOC,GAAAA,oBAAA,SAAoBC,WAAA;AAAA,EACzC,OAAO;AAAA,IACL,QAAQ,EAAE,MAAM,QAAyC,SAAS,SAAA;AAAA;AAAA,IAElE,UAAU,EAAE,MAAM,CAAC,QAAQ,MAAM,GAAgC,SAAS,OAAA;AAAA,IAC1E,QAAQ,EAAE,MAAM,OAAsC,SAAS,MAAM,CAAC,SAAS,QAAQ,EAAA;AAAA,IACvF,MAAM,EAAE,MAAM,QAAQ,SAAS,GAAA;AAAA,IAC/B,SAAS,EAAE,MAAM,OAAgC,SAAS,MAAM,CAAA,EAAC;AAAA;AAAA,IAEjE,gBAAgB,EAAE,MAAM,QAAwC,SAAS,OAAO,CAAA,GAAC;AAAA,IACjF,SAAS,EAAE,MAAM,CAAC,SAAS,MAAM,GAAyC,SAAS,MAAA;AAAA,IACnF,cAAc,EAAE,MAAM,QAAQ,SAAS,UAAA;AAAA;AAAA,IAEvC,SAAS,EAAE,MAAM,QAAQ,SAAS,qDAAA;AAAA,IAClC,aAAa,EAAE,MAAM,QAAQ,SAAS,oIAAA;AAAA,IACtC,QAAQ,EAAE,MAAM,CAAC,QAAQ,MAAM,GAAG,SAAS,IAAA;AAAA,IAC3C,SAAS,EAAE,MAAM,CAAC,QAAQ,MAAM,GAAG,SAAS,KAAA;AAAA,IAC5C,YAAY;AAAA,IACZ,iBAAiB,EAAE,MAAM,SAAS,SAAS,MAAA;AAAA,IAC3C,OAAO,EAAE,MAAM,QAAQ,SAAS,MAAA;AAAA,EAAM;AAAA,EAExC,OAAO,CAAC,iBAAiB,eAAe,SAAS,gBAAgB,iBAAiB,SAAS,OAAO;AAAA,EAClG,MAAM,OAAO,EAAE,MAAM,SAAS;AAC5B,UAAM,KAAKC,IAAAA,IAAwB,IAAI;AACvC,UAAM,UAAUC,IAAAA,WAA8B,IAAI;AAClD,UAAM,QAAQD,IAAAA,IAAI,KAAK;AACvB,UAAM,OAAOE,IAAAA,mBAAA;AACb,UAAM,8BAAc,IAAA;AACpB,QAAI,QAA6B;AACjC,QAAI,QAAQ;AACZ,UAAM,QAAQ,CAAC,GAAc,MAAc,OAAO,EAAE,MAAM,CAAC;AAC3D,UAAM,SAASC,IAAAA,SAAS,MAAM,CAAC,CAACC,GAAAA,OAAO,MAAM,OAAOA,UAAO,MAAM,IAAI,GAAG,IAAI;AAC5E,UAAM,OAAO,MAAM,MAAM,OAAO;AAEhC,UAAM,eAAe,MAAM;AACzB,cAAQ,QAAQ,CAAC,MAAM,EAAE,QAAQ;AACjC,cAAQ,MAAA;AAAA,IACV;AACA,UAAM,eAAe,CAAC,GAAc,MAAc;AAChD,YAAM,MAAM,MAAM,SAAS,KAAA,EAAO,cAA2B,iBAAiB,IAAI,OAAO,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,oBAAoB;AAChI,YAAM,OAAO,MAAO,IAAI,UAAU,IAAI,IAAoB,cAAc,GAAG,MAAM,cAAc;AAC/F,UAAI,IAAK,MAAK,UAAU,IAAI,iBAAiB,uBAAuB;AACpE,YAAM,OAAO,CAAC,MAAa;AACzB,UAAE,gBAAA;AACF,aAAK,gBAAgB,CAAC;AACtB,cAAM,QAAQ,KAAA,EAAO,cAA2B,gBAAgB,IAAI,OAAO,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI;AAC3F,YAAI,SAAS,MAAM,aAAa,KAAA,WAAgB,OAAO,UAAU,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,MAAM,UAAU,IAAI,IAAmB,EAAE,QAAQ,MAAM,eAAe,QAAQ,MAAM,CAAC;AAAA,MACxK;AACA,WAAK,iBAAiB,SAAS,IAAI;AACnC,WAAK,iBAAiB,WAAW,CAAC,OAAO,EAAE,QAAQ,WAAW,EAAE,QAAQ,QAAQ,KAAK,CAAC,CAAC;AACvF,aAAO;AAAA,IACT;AACA,UAAM,UAAU,CAAC,MAAkB,MAAM,SAAS,WAAW,aAAc,EAAE,SAAS,MAAM,eAAe,SAAS,KAAqB;AAGzI,UAAM,SAAS,MAAM;AACnB,YAAM,IAAI,QAAQ;AAClB,UAAI,CAAC,EAAG;AACR,YAAM,2BAAW,IAAA;AACjB,UAAI,OAAO;AACT,mBAAW,QAAQ,YAAY,OAAO,QAAQ,EAAE,WAAW,GAAG,EAAE,QAAA,CAAS,GAAG;AAC1E,cAAI,KAAK,SAAS,WAAW;AAC3B,kBAAM,MAAM,IAAI,KAAK,EAAE;AACvB,iBAAK,IAAI,KAAK,MAAM;AAClB,oBAAM,OAAO,eAAe,KAAK,OAAO,MAAM,YAAY;AAC1D,oBAAM,SAAS,CAAC,MAAa;AAC3B,kBAAE,gBAAA;AACF,sBAAM,MAAM;AACZ,qBAAK,iBAAiB,EAAE,OAAO,KAAK,OAAO,SAAS,cAAc,KAAK,KAAK,EAAE,EAAE,IAAI,CAAC,MAAM,MAAM,QAAQ,CAAC,CAAC,GAAG;AAC9G,kBAAE,QAAQ,CAAC,KAAK,KAAK,KAAK,GAAG,GAAG,KAAK,IAAI,cAAc,KAAK,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI;AAAA,cACjF;AACA,mBAAK,iBAAiB,SAAS,MAAM;AACrC,mBAAK,iBAAiB,WAAW,CAAC,OAAO,EAAE,QAAQ,WAAW,EAAE,QAAQ,QAAQ,OAAO,CAAC,CAAC;AACzF,qBAAO,EAAE,UAAU,MAAM,CAAC,KAAK,KAAK,KAAK,GAAG,GAAG,QAAQ;AAAA,YACzD,CAAC;AAAA,UACH,OAAO;AACL,kBAAM,IAAI,MAAM,QAAQ,KAAK,KAAK;AAClC,iBAAK,IAAI,IAAI,KAAK,KAAK,IAAI,MAAM,EAAE,UAAU,aAAa,GAAG,KAAK,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC;AAAA,UACvG;AAAA,QACF;AAAA,MACF,OAAO;AACL,cAAM,QAAQ,QAAQ,CAAC,GAAG,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,MAAM,EAAE,UAAU,aAAa,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAAA,MACtH;AACA,iBAAW,CAAC,GAAG,CAAC,KAAK,aAAa,CAAC,KAAK,IAAI,CAAC,GAAG;AAAE,UAAE,OAAA;AAAU,gBAAQ,OAAO,CAAC;AAAA,MAAE;AAChF,iBAAW,CAAC,GAAG,IAAI,KAAK,KAAM,KAAI,CAAC,QAAQ,IAAI,CAAC,EAAG,SAAQ,IAAI,GAAG,MAAM;AAAA,IAC1E;AACA,UAAM,UAAU,MAAM;AACpB,mBAAA;AACA,cAAQ,MAAM,UAAU,mBAAmB,MAAM,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,CAAA,GAAI,MAAM,WAAW,WAAW,MAAM,GAAG,IAAI;AAC3J,aAAA;AAAA,IACF;AACA,UAAM,MAAM,MAAM,QAAQ,OAAO,UAAU,MAAM,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE;AAE3F,UAAM,QAAQ,YAAY;AACxB,YAAM,KAAK,EAAE;AACb,UAAI,CAAC,GAAG,MAAO;AACf,YAAM,QAAQ;AACd,YAAM,IAAI,MAAM,WAAW,WACvB,MAAM,oBAAoB,GAAG,OAAO,EAAE,QAAQ,MAAM,QAAQ,MAAM,MAAM,MAAM,SAAS,MAAM,SAAS,aAAa,MAAM,aAAa,YAAY,MAAM,iBAAiB,IACzK,MAAM,oBAAoB,GAAG,OAAO,EAAE,QAAQ,MAAM,QAAQ,MAAM,MAAM,MAAM,OAAO,gBAAgB,MAAM,UAAU,OAAO,KAAK,GAAG,YAAY,MAAM,iBAAiB;AAC3K,UAAI,OAAO,MAAO,QAAO,EAAE,QAAA;AAC3B,cAAQ,QAAQC,IAAAA,QAAQ,CAAC;AACzB,QAAE,GAAG,WAAW,MAAM;AACpB,cAAM,IAAI,EAAE,UAAA;AACZ,aAAK,iBAAiB,CAAC;AACvB,aAAK,eAAe,KAAK,MAAM,EAAE,YAAY,GAAG,IAAI,GAAG;AACvD,YAAI,MAAO,QAAA;AAAA,MACb,CAAC;AACD,QAAE,GAAG,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACrC,QAAE,GAAG,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACrC,UAAI,MAAM,WAAY,KAAA;AACtB,cAAA;AACA,YAAM,QAAQ;AACd,WAAK,SAAS,EAAE,MAAM;AAAA,IACxB;AACA,UAAM,aAAa,MAAM;AACvB,mBAAA;AACA,cAAQ,OAAO,QAAA;AACf,cAAQ,QAAQ;AAAA,IAClB;AAGAC,QAAAA,UAAU,MAAM;AACd,UAAI,GAAG,MAAO,QAAO,MAAA;AACrB,YAAM,OAAOC,IAAAA,MAAM,IAAI,CAAC,SAAS;AAAE,YAAI,MAAM;AAAE,eAAA;AAAQ,iBAAO,MAAA;AAAA,QAAQ;AAAA,MAAE,CAAC;AAAA,IAC3E,CAAC;AACDC,QAAAA,gBAAgB,MAAM;AAAE;AAAS,iBAAA;AAAA,IAAa,CAAC;AAC/CD,cAAM,MAAM,MAAM,QAAQ,MAAM;AAAE,iBAAA;AAAc,YAAA;AAAA,IAAQ,CAAC;AACzDA,cAAM,MAAM,MAAM,SAAS,MAAM;AAAE,UAAI,CAAC,QAAQ,MAAO;AAAQ,UAAI,MAAM,WAAY,KAAA;AAAO,4BAAsB,OAAO;AAAA,IAAE,GAAG,EAAE,MAAM,MAAM,OAAO,QAAQ;AAC3JA,QAAAA,MAAM,MAAM,CAAC,MAAM,SAAS,MAAM,gBAAgB,MAAM,YAAY,GAAG,MAAM,QAAQ,SAAS,QAAA,GAAW,EAAE,MAAM,MAAM;AAEvHA,QAAAA,MAAME,GAAAA,kBAAkB,MAAM,QAAQ,SAAS,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,eAAe,IAAI,KAAK,SAAS;AAC1HF,QAAAA,MAAM,CAAC,MAAM,MAAM,UAAU,MAAM,GAAG,MAAM;AAC1C,YAAM,IAAI,QAAQ;AAClB,UAAI,KAAK,EAAE,WAAW,SAAU,GAAE,SAAS,gBAAgB,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAC1F,CAAC;AACDA,QAAAA,MAAM,MAAM,MAAM,SAAS,CAAC,QAAQ,QAAQ,OAAO,WAAW,YAAY,QAAQ,MAAM,SAAS,GAAG,CAAC;AACrGA,QAAAA,MAAM,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,MAAM;AAChE,YAAM,IAAI,QAAQ;AAClB,UAAI,CAAC,EAAG;AACR,YAAM,IAAI,EAAE,UAAA;AACZ,UAAI,KAAK,IAAI,EAAE,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,IAAI,QAAQ,KAAK,IAAI,EAAE,YAAY,MAAM,IAAI,IAAI,KAAM,GAAE,QAAQ,MAAM,QAAQ,MAAM,IAAI;AAAA,IACzK,CAAC;AACD,WAAO,EAAE,IAAI,SAAS,OAAO,OAAO,KAAA,QAAKG,KAAAA,QAAA,aAAQC,GAAAA,aAAa,KAAK,CAAC,MAAc,CAAC,CAAC,MAAM,CAAC,EAAA;AAAA,EAC7F;AACF,CAAC;;;;;;;;;;;EAjLsB,OAAM;;AACpB,MAAA,aAAA,EAAA,OAAM,mBAAA;;EAMN,OAAM;AAAA,EAAoB,eAAY;;;;;;;;;;AAV7C,SAAAC,IAAAA,UAAA,GAAAC,IAAAA;AAAAA,IAiBM;AAAA,IAAA;AAAA,MAjBD,OAAM;AAAA,MAAqB,OAAKC,IAAAA,eAAA,EAAA,QAAY,KAAA,OAAO,KAAA,MAAM,GAAA,UAAa,iBAAY,KAAA,OAAO,GAAA,WAAA,6BAAA,WAAA,oBAAA,WAAA,MAAA,CAAA;AAAA,IAAA;AAAA;MAC5FC,IAAAA,YAAgB,sBAAP,MAAA,GAAA,CAAI;AAAA,MACbC,IAAAA,mBAAkF,OAAA;AAAA,QAA7E,KAAI;AAAA,QAAK,OAAM;AAAA,QAAiB,MAAK;AAAA,QAAe,cAAY,KAAA;AAAA,MAAA,GAAA,MAAA,GAAA,UAAA;AAAA,OACzD,KAAA,SAAAJ,IAAAA,UAAA,GAAZC,IAAAA,mBAA2G,OAA3G,YAA2G;AAAA,QAAhEE,IAAAA,YAA0D,+BAAA;AAAA,UAAtC,eAAA;AAAA,UAAe,MAAM;AAAA,UAAK,OAAO;AAAA,QAAA,CAAA;AAAA;MAChGC,IAAAA,mBAIM,OAJN,YAIM;AAAA,QAHJD,IAAAA,YAA+H,kBAAA;AAAA,UAAxH,MAAK;AAAA,UAAO,OAAM;AAAA,UAAU,SAAQ;AAAA,UAAW,MAAK;AAAA,UAAQ,cAAW;AAAA,UAAW,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,KAAA,WAAW,KAAA,QAAQ,OAAA;AAAA,QAAM,CAAA;AAAA,QACzHA,IAAAA,YAAkI,kBAAA;AAAA,UAA3H,MAAK;AAAA,UAAQ,OAAM;AAAA,UAAU,SAAQ;AAAA,UAAW,MAAK;AAAA,UAAQ,cAAW;AAAA,UAAY,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,KAAA,WAAW,KAAA,QAAQ,QAAA;AAAA,QAAO,CAAA;AAAA,QAC/G,KAAA,QAAQ,SAAM,sBAA3BE,IAAAA,YAAsI,kBAAA;AAAA,UAAA,KAAA;AAAA,UAArG,MAAK;AAAA,UAAQ,OAAM;AAAA,UAAU,SAAQ;AAAA,UAAW,MAAK;AAAA,UAAQ,cAAW;AAAA,UAAe,SAAO,KAAA;AAAA,QAAA,GAAA,MAAA,GAAA,CAAA,SAAA,CAAA,KAAAC,IAAAA,mBAAA,QAAA,IAAA;AAAA;MAEjIA,IAAAA,mBAAA,uEAAA;AAAA,MACAF,IAAAA,mBAKM,OALN,YAKM;AAAA,SAAAJ,IAAAA,UAAA,IAAA,GAJJC,IAAAA;AAAAA,UAAwMM,IAAAA;AAAAA,UAAA;AAAA,UAAAC,IAAAA,WAAlL,KAAA,SAAO,CAAhB,GAAG,MAAC;oCAAjBP,IAAAA,mBAAwM,OAAA;AAAA,cAAxK,KAAG,MAAQ,KAAA,MAAM,GAAG,CAAC;AAAA,cAAI,cAAY,KAAA,MAAM,GAAG,CAAC;AAAA,YAAA,GAAA;AAAA,cAAGQ,IAAAA,WAAgH,KAAA,QAAA,SAAA,EAA5F,QAAQ,EAAA,GAA5B,MAAgH;AAAA,gBAAxE,EAAE,SAAAT,IAAAA,UAAA,GAAXC,IAAAA;AAAAA,kBAAmC;AAAA,kBAAA;AAAA,kBAAAS,IAAAA,gBAAd,EAAE,KAAK;AAAA,kBAAA;AAAA;AAAA,gBAAA,KAAAJ,IAAAA,mBAAA,QAAA,IAAA;AAAA,gBAAkB,EAAE,SAAAN,IAAAA,UAAA,GAAbC,IAAAA;AAAAA,kBAAuC;AAAA,kBAAA;AAAA,kBAAAS,IAAAA,gBAAhB,EAAE,KAAK;AAAA,kBAAA;AAAA;AAAA,gBAAA,KAAAJ,IAAAA,mBAAA,QAAA,IAAA;AAAA;;;;;;QAClK,KAAA,IAAG,QAAA,KAAAN,IAAAA,UAAA,IAAA,GACjBC,IAAAA;AAAAA,UAA2HM,IAAAA;AAAAA,UAAA,EAAA,KAAA,EAAA;AAAA,UAAAC,IAAAA,WAArG,KAAA,SAAO,CAAhB,GAAG,MAAC;oCAAjBP,IAAAA,mBAA2H,OAAA;AAAA,cAA3F,KAAG,MAAQ,KAAA,MAAM,GAAG,CAAC;AAAA,cAAI,eAAa,KAAA,MAAM,GAAG,CAAC;AAAA,YAAA,GAAA;AAAA,cAAGQ,IAAAA,WAAkC,KAAA,QAAA,UAAA,EAAb,QAAQ,EAAA,CAAC;AAAA,YAAA,GAAA,GAAA,UAAA;AAAA;;;;;MAGrHA,eAA+C,KAAA,QAAA,WAAA;AAAA,QAAxC,KAAK,KAAA,UAAU,KAAA,QAAQ,SAAM;AAAA,MAAA,CAAA;AAAA;;;;;;ACXjC,MAAM,iBAAiB,CAAC,OAAO;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { defineComponent, ref, shallowRef, getCurrentInstance, computed, onMounted, watch, onBeforeUnmount, markRaw, resolveComponent, openBlock, createElementBlock, normalizeStyle, createVNode, createElementVNode, createCommentVNode, createBlock, Fragment, renderList, renderSlot, toDisplayString } from "vue";
|
|
2
|
+
import { toUnit } from "@squirkle-ui/core";
|
|
3
|
+
import { colorValue, resolveIcon, SqShape, SqProgressCircular, SqBtn, config, iconStoreVersion, radiusValue } from "@squirkle-ui/ui";
|
|
4
|
+
import Supercluster from "supercluster";
|
|
5
|
+
let workerUrl = null;
|
|
6
|
+
function setMapWorkerUrl(url) {
|
|
7
|
+
workerUrl = url;
|
|
8
|
+
}
|
|
9
|
+
const MAP_STYLES = {
|
|
10
|
+
positron: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
|
|
11
|
+
voyager: "https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json",
|
|
12
|
+
"dark-matter": "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",
|
|
13
|
+
liberty: "https://tiles.openfreemap.org/styles/liberty",
|
|
14
|
+
bright: "https://tiles.openfreemap.org/styles/bright",
|
|
15
|
+
"openfreemap-dark": "https://tiles.openfreemap.org/styles/dark",
|
|
16
|
+
fiord: "https://tiles.openfreemap.org/styles/fiord"
|
|
17
|
+
};
|
|
18
|
+
function resolveMapStyle(style, dark) {
|
|
19
|
+
if (typeof style !== "string") return style;
|
|
20
|
+
if (style === "auto") return dark ? MAP_STYLES["dark-matter"] : MAP_STYLES.positron;
|
|
21
|
+
return MAP_STYLES[style] ?? style;
|
|
22
|
+
}
|
|
23
|
+
const defaultOf = (mod) => mod.default ?? mod;
|
|
24
|
+
async function createVectorAdapter(el, opts) {
|
|
25
|
+
const [mod] = await Promise.all([import("maplibre-gl"), import("maplibre-gl/dist/maplibre-gl.css")]);
|
|
26
|
+
const ml = defaultOf(mod);
|
|
27
|
+
if (workerUrl) ml.setWorkerUrl(workerUrl);
|
|
28
|
+
const map = new ml.Map({
|
|
29
|
+
container: el,
|
|
30
|
+
style: opts.style,
|
|
31
|
+
center: [opts.center[1], opts.center[0]],
|
|
32
|
+
zoom: opts.zoom,
|
|
33
|
+
attributionControl: { compact: true },
|
|
34
|
+
scrollZoom: opts.scrollZoom,
|
|
35
|
+
cooperativeGestures: false
|
|
36
|
+
});
|
|
37
|
+
let popup = null;
|
|
38
|
+
return {
|
|
39
|
+
engine: "vector",
|
|
40
|
+
native: map,
|
|
41
|
+
getCenter: () => {
|
|
42
|
+
const c = map.getCenter();
|
|
43
|
+
return [c.lat, c.lng];
|
|
44
|
+
},
|
|
45
|
+
getZoom: () => map.getZoom(),
|
|
46
|
+
getBounds: () => {
|
|
47
|
+
const b = map.getBounds();
|
|
48
|
+
return [b.getWest(), b.getSouth(), b.getEast(), b.getNorth()];
|
|
49
|
+
},
|
|
50
|
+
setView: (c, z, animate) => animate ? map.easeTo({ center: [c[1], c[0]], zoom: z, duration: 450 }) : map.jumpTo({ center: [c[1], c[0]], zoom: z }),
|
|
51
|
+
fitPoints: (pts, padding, maxZoom) => {
|
|
52
|
+
if (!pts.length) return;
|
|
53
|
+
const b = new ml.LngLatBounds([pts[0][1], pts[0][0]], [pts[0][1], pts[0][0]]);
|
|
54
|
+
pts.forEach((p) => b.extend([p[1], p[0]]));
|
|
55
|
+
map.fitBounds(b, { padding, maxZoom, duration: 0 });
|
|
56
|
+
},
|
|
57
|
+
zoomIn: () => map.zoomIn(),
|
|
58
|
+
zoomOut: () => map.zoomOut(),
|
|
59
|
+
addMarker: (element, at, anchor) => {
|
|
60
|
+
const m = new ml.Marker({ element, anchor }).setLngLat([at[1], at[0]]).addTo(map);
|
|
61
|
+
return { remove: () => m.remove() };
|
|
62
|
+
},
|
|
63
|
+
openPopup: (at, content, offset) => {
|
|
64
|
+
popup?.remove();
|
|
65
|
+
popup = new ml.Popup({ offset, closeButton: false, className: "sq-map__popup", maxWidth: "280px" }).setLngLat([at[1], at[0]]).setDOMContent(content).addTo(map);
|
|
66
|
+
},
|
|
67
|
+
setStyle: (style) => map.setStyle(style),
|
|
68
|
+
on: (event, cb) => {
|
|
69
|
+
if (event === "click") map.on("click", (e) => cb({ lat: e.lngLat.lat, lng: e.lngLat.lng }));
|
|
70
|
+
else if (event === "error") map.on("error", (e) => cb(e.error ?? e));
|
|
71
|
+
else map.on("moveend", () => cb());
|
|
72
|
+
},
|
|
73
|
+
destroy: () => map.remove()
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function createRasterAdapter(el, opts) {
|
|
77
|
+
const [mod] = await Promise.all([import("leaflet"), import("leaflet/dist/leaflet.css")]);
|
|
78
|
+
const L = defaultOf(mod);
|
|
79
|
+
const map = L.map(el, { center: opts.center, zoom: opts.zoom, zoomControl: false, scrollWheelZoom: opts.scrollZoom });
|
|
80
|
+
const tiles = L.tileLayer(opts.tileUrl, { attribution: opts.attribution, maxZoom: 19 }).addTo(map);
|
|
81
|
+
return {
|
|
82
|
+
engine: "raster",
|
|
83
|
+
native: map,
|
|
84
|
+
getCenter: () => {
|
|
85
|
+
const c = map.getCenter();
|
|
86
|
+
return [c.lat, c.lng];
|
|
87
|
+
},
|
|
88
|
+
getZoom: () => map.getZoom(),
|
|
89
|
+
getBounds: () => {
|
|
90
|
+
const b = map.getBounds();
|
|
91
|
+
return [b.getWest(), b.getSouth(), b.getEast(), b.getNorth()];
|
|
92
|
+
},
|
|
93
|
+
setView: (c, z, animate) => map.setView(c, z, { animate: !!animate }),
|
|
94
|
+
fitPoints: (pts, padding, maxZoom) => pts.length && map.fitBounds(L.latLngBounds(pts), { padding: [padding, padding], maxZoom }),
|
|
95
|
+
zoomIn: () => map.zoomIn(),
|
|
96
|
+
zoomOut: () => map.zoomOut(),
|
|
97
|
+
addMarker: (element, at, anchor) => {
|
|
98
|
+
const wrap = document.createElement("div");
|
|
99
|
+
wrap.className = `sq-map__anchor sq-map__anchor--${anchor}`;
|
|
100
|
+
wrap.appendChild(element);
|
|
101
|
+
const m = L.marker(at, { icon: L.divIcon({ html: wrap, className: "sq-map__marker-wrap", iconSize: [0, 0] }), keyboard: false }).addTo(map);
|
|
102
|
+
return { remove: () => m.remove() };
|
|
103
|
+
},
|
|
104
|
+
openPopup: (at, content, offset) => {
|
|
105
|
+
L.popup({ className: "sq-map__popup", offset: [0, -offset], closeButton: false }).setLatLng(at).setContent(content).openOn(map);
|
|
106
|
+
},
|
|
107
|
+
setStyle: (style) => typeof style === "string" && tiles.setUrl(style),
|
|
108
|
+
on: (event, cb) => {
|
|
109
|
+
if (event === "click") map.on("click", (e) => cb({ lat: e.latlng.lat, lng: e.latlng.lng }));
|
|
110
|
+
else if (event === "error") tiles.on("tileerror", (e) => cb(e));
|
|
111
|
+
else map.on("moveend", () => cb());
|
|
112
|
+
},
|
|
113
|
+
destroy: () => map.remove()
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const markerAnchor = (shape) => shape === "pin" ? "bottom" : "center";
|
|
117
|
+
function iconNode(icon) {
|
|
118
|
+
const r = resolveIcon(icon);
|
|
119
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
120
|
+
svg.setAttribute("aria-hidden", "true");
|
|
121
|
+
if (r.kind === "path") {
|
|
122
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
123
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
124
|
+
path.setAttribute("d", r.d);
|
|
125
|
+
svg.appendChild(path);
|
|
126
|
+
return svg;
|
|
127
|
+
}
|
|
128
|
+
if (r.kind === "svg") {
|
|
129
|
+
svg.setAttribute("viewBox", `0 0 ${r.data.width} ${r.data.height}`);
|
|
130
|
+
svg.innerHTML = r.data.body;
|
|
131
|
+
return svg;
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
function markerElement(m, defaults = {}) {
|
|
136
|
+
const o = { ...defaults, ...m };
|
|
137
|
+
const shape = o.shape ?? "pin";
|
|
138
|
+
const el = document.createElement("div");
|
|
139
|
+
el.className = `sq-map-marker sq-map-marker--${shape}`;
|
|
140
|
+
el.style.setProperty("--sq-pin", colorValue(o.color ?? "primary") ?? "var(--sq-primary)");
|
|
141
|
+
el.style.setProperty("--sq-pin-size", `${o.size ?? 30}px`);
|
|
142
|
+
el.setAttribute("role", "button");
|
|
143
|
+
el.setAttribute("tabindex", "0");
|
|
144
|
+
el.setAttribute("aria-label", o.title ?? o.label ?? "Marker");
|
|
145
|
+
const body = document.createElement("span");
|
|
146
|
+
body.className = "sq-map-marker__body";
|
|
147
|
+
if (shape === "avatar" && o.image) {
|
|
148
|
+
const img = document.createElement("img");
|
|
149
|
+
img.src = o.image;
|
|
150
|
+
img.alt = "";
|
|
151
|
+
img.loading = "lazy";
|
|
152
|
+
body.appendChild(img);
|
|
153
|
+
} else if (shape !== "dot") {
|
|
154
|
+
const icon = o.icon ? iconNode(o.icon) : null;
|
|
155
|
+
const content = document.createElement("span");
|
|
156
|
+
content.className = "sq-map-marker__content";
|
|
157
|
+
if (icon) content.appendChild(icon);
|
|
158
|
+
else if (o.label) content.textContent = String(o.label);
|
|
159
|
+
else content.classList.add("sq-map-marker__content--empty");
|
|
160
|
+
body.appendChild(content);
|
|
161
|
+
}
|
|
162
|
+
el.appendChild(body);
|
|
163
|
+
return el;
|
|
164
|
+
}
|
|
165
|
+
function clusterElement(count, color) {
|
|
166
|
+
const el = document.createElement("div");
|
|
167
|
+
el.className = "sq-map-cluster";
|
|
168
|
+
const size = Math.round(34 + Math.min(30, Math.log2(count) * 5));
|
|
169
|
+
el.style.setProperty("--sq-cluster-size", `${size}px`);
|
|
170
|
+
el.style.setProperty("--sq-pin", colorValue(color ?? "primary") ?? "var(--sq-primary)");
|
|
171
|
+
el.setAttribute("role", "button");
|
|
172
|
+
el.setAttribute("tabindex", "0");
|
|
173
|
+
el.setAttribute("aria-label", `${count} places — zoom in`);
|
|
174
|
+
const span = document.createElement("span");
|
|
175
|
+
span.textContent = count >= 1e3 ? `${(count / 1e3).toFixed(count >= 1e4 ? 0 : 1)}k` : String(count);
|
|
176
|
+
el.appendChild(span);
|
|
177
|
+
return el;
|
|
178
|
+
}
|
|
179
|
+
function createClusterIndex(points, opts = {}, tileSize = 512) {
|
|
180
|
+
const index = new Supercluster({ radius: opts.radius ?? 60, maxZoom: opts.maxZoom ?? 16, minPoints: opts.minPoints ?? 2, extent: tileSize });
|
|
181
|
+
index.load(points.map((p, i) => ({ type: "Feature", geometry: { type: "Point", coordinates: [p.lng, p.lat] }, properties: { i } })));
|
|
182
|
+
return index;
|
|
183
|
+
}
|
|
184
|
+
function clustersFor(index, bbox, zoom) {
|
|
185
|
+
return index.getClusters(bbox, Math.floor(zoom)).map((f) => {
|
|
186
|
+
const [lng, lat] = f.geometry.coordinates;
|
|
187
|
+
const p = f.properties;
|
|
188
|
+
return p.cluster ? { kind: "cluster", id: p.cluster_id, lat, lng, count: p.point_count } : { kind: "point", index: p.i, lat, lng };
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const expansionZoom = (index, clusterId) => index.getClusterExpansionZoom(clusterId);
|
|
192
|
+
const clusterLeaves = (index, clusterId) => index.getLeaves(clusterId, Infinity).map((f) => f.properties.i);
|
|
193
|
+
function padBBox([w, s, e, n], ratio = 0.25) {
|
|
194
|
+
const dx = (e - w) * ratio;
|
|
195
|
+
const dy = (n - s) * ratio;
|
|
196
|
+
return [Math.max(-180, w - dx), Math.max(-85, s - dy), Math.min(180, e + dx), Math.min(85, n + dy)];
|
|
197
|
+
}
|
|
198
|
+
const _sfc_main = defineComponent({
|
|
199
|
+
name: "SqMap",
|
|
200
|
+
components: { SqBtn, SqProgressCircular, SqShape },
|
|
201
|
+
props: {
|
|
202
|
+
engine: { type: String, default: "vector" },
|
|
203
|
+
/** Vector style: `auto` (follows light/dark), a preset name (positron, voyager, dark-matter, liberty, bright, openfreemap-dark, fiord), a style URL or a style object. */
|
|
204
|
+
mapStyle: { type: [String, Object], default: "auto" },
|
|
205
|
+
center: { type: Array, default: () => [11.5564, 104.9282] },
|
|
206
|
+
zoom: { type: Number, default: 12 },
|
|
207
|
+
markers: { type: Array, default: () => [] },
|
|
208
|
+
/** Defaults merged into every marker (shape, color, size, icon…). */
|
|
209
|
+
markerDefaults: { type: Object, default: () => ({}) },
|
|
210
|
+
cluster: { type: [Boolean, Object], default: false },
|
|
211
|
+
clusterColor: { type: String, default: "primary" },
|
|
212
|
+
/** Raster engine tile template. */
|
|
213
|
+
tileUrl: { type: String, default: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" },
|
|
214
|
+
attribution: { type: String, default: '© <a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors' },
|
|
215
|
+
height: { type: [Number, String], default: 400 },
|
|
216
|
+
rounded: { type: [String, Number], default: "xl" },
|
|
217
|
+
fitMarkers: Boolean,
|
|
218
|
+
scrollWheelZoom: { type: Boolean, default: false },
|
|
219
|
+
label: { type: String, default: "Map" }
|
|
220
|
+
},
|
|
221
|
+
emits: ["update:center", "update:zoom", "click", "marker-click", "cluster-click", "ready", "error"],
|
|
222
|
+
setup(props, { emit, slots }) {
|
|
223
|
+
const el = ref(null);
|
|
224
|
+
const adapter = shallowRef(null);
|
|
225
|
+
const ready = ref(false);
|
|
226
|
+
const inst = getCurrentInstance();
|
|
227
|
+
const handles = /* @__PURE__ */ new Map();
|
|
228
|
+
let index = null;
|
|
229
|
+
let epoch = 0;
|
|
230
|
+
const keyOf = (m, i) => String(m.id ?? i);
|
|
231
|
+
const isDark = computed(() => !!config.theme.themes[config.theme.name]?.dark);
|
|
232
|
+
const root = () => inst?.proxy?.$el;
|
|
233
|
+
const clearMarkers = () => {
|
|
234
|
+
handles.forEach((h) => h.remove());
|
|
235
|
+
handles.clear();
|
|
236
|
+
};
|
|
237
|
+
const pointElement = (m, i) => {
|
|
238
|
+
const tpl = slots.marker ? root().querySelector(`[data-marker="${CSS.escape(keyOf(m, i))}"]`)?.firstElementChild : null;
|
|
239
|
+
const node = tpl ? tpl.cloneNode(true) : markerElement(m, props.markerDefaults);
|
|
240
|
+
if (tpl) node.classList.add("sq-map-marker", "sq-map-marker--custom");
|
|
241
|
+
const open = (e) => {
|
|
242
|
+
e.stopPropagation();
|
|
243
|
+
emit("marker-click", m);
|
|
244
|
+
const popup = root().querySelector(`[data-popup="${CSS.escape(keyOf(m, i))}"]`);
|
|
245
|
+
if (popup && popup.textContent?.trim()) adapter.value?.openPopup([m.lat, m.lng], popup.cloneNode(true), (m.size ?? props.markerDefaults.size ?? 30) + 4);
|
|
246
|
+
};
|
|
247
|
+
node.addEventListener("click", open);
|
|
248
|
+
node.addEventListener("keydown", (e) => (e.key === "Enter" || e.key === " ") && open(e));
|
|
249
|
+
return node;
|
|
250
|
+
};
|
|
251
|
+
const shapeOf = (m) => slots.marker ? "center" : markerAnchor(m.shape ?? props.markerDefaults.shape ?? "pin");
|
|
252
|
+
const render = () => {
|
|
253
|
+
const a = adapter.value;
|
|
254
|
+
if (!a) return;
|
|
255
|
+
const want = /* @__PURE__ */ new Map();
|
|
256
|
+
if (index) {
|
|
257
|
+
for (const item of clustersFor(index, padBBox(a.getBounds()), a.getZoom())) {
|
|
258
|
+
if (item.kind === "cluster") {
|
|
259
|
+
const key = `c${item.id}`;
|
|
260
|
+
want.set(key, () => {
|
|
261
|
+
const node = clusterElement(item.count, props.clusterColor);
|
|
262
|
+
const zoomIn = (e) => {
|
|
263
|
+
e.stopPropagation();
|
|
264
|
+
const idx = index;
|
|
265
|
+
emit("cluster-click", { count: item.count, markers: clusterLeaves(idx, item.id).map((i) => props.markers[i]) });
|
|
266
|
+
a.setView([item.lat, item.lng], Math.min(expansionZoom(idx, item.id), 20), true);
|
|
267
|
+
};
|
|
268
|
+
node.addEventListener("click", zoomIn);
|
|
269
|
+
node.addEventListener("keydown", (e) => (e.key === "Enter" || e.key === " ") && zoomIn(e));
|
|
270
|
+
return a.addMarker(node, [item.lat, item.lng], "center");
|
|
271
|
+
});
|
|
272
|
+
} else {
|
|
273
|
+
const m = props.markers[item.index];
|
|
274
|
+
want.set(`p${item.index}`, () => a.addMarker(pointElement(m, item.index), [m.lat, m.lng], shapeOf(m)));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
props.markers.forEach((m, i) => want.set(`p${i}`, () => a.addMarker(pointElement(m, i), [m.lat, m.lng], shapeOf(m))));
|
|
279
|
+
}
|
|
280
|
+
for (const [k, h] of handles) if (!want.has(k)) {
|
|
281
|
+
h.remove();
|
|
282
|
+
handles.delete(k);
|
|
283
|
+
}
|
|
284
|
+
for (const [k, make] of want) if (!handles.has(k)) handles.set(k, make());
|
|
285
|
+
};
|
|
286
|
+
const rebuild = () => {
|
|
287
|
+
clearMarkers();
|
|
288
|
+
index = props.cluster ? createClusterIndex(props.markers, typeof props.cluster === "object" ? props.cluster : {}, props.engine === "raster" ? 256 : 512) : null;
|
|
289
|
+
render();
|
|
290
|
+
};
|
|
291
|
+
const fit = () => adapter.value?.fitPoints(props.markers.map((m) => [m.lat, m.lng]), 48, 15);
|
|
292
|
+
const mount = async () => {
|
|
293
|
+
const my = ++epoch;
|
|
294
|
+
if (!el.value) return;
|
|
295
|
+
ready.value = false;
|
|
296
|
+
const a = props.engine === "raster" ? await createRasterAdapter(el.value, { center: props.center, zoom: props.zoom, tileUrl: props.tileUrl, attribution: props.attribution, scrollZoom: props.scrollWheelZoom }) : await createVectorAdapter(el.value, { center: props.center, zoom: props.zoom, style: resolveMapStyle(props.mapStyle, isDark.value), scrollZoom: props.scrollWheelZoom });
|
|
297
|
+
if (my !== epoch) return a.destroy();
|
|
298
|
+
adapter.value = markRaw(a);
|
|
299
|
+
a.on("moveend", () => {
|
|
300
|
+
const c = a.getCenter();
|
|
301
|
+
emit("update:center", c);
|
|
302
|
+
emit("update:zoom", Math.round(a.getZoom() * 100) / 100);
|
|
303
|
+
if (index) render();
|
|
304
|
+
});
|
|
305
|
+
a.on("click", (p) => emit("click", p));
|
|
306
|
+
a.on("error", (e) => emit("error", e));
|
|
307
|
+
if (props.fitMarkers) fit();
|
|
308
|
+
rebuild();
|
|
309
|
+
ready.value = true;
|
|
310
|
+
emit("ready", a.native);
|
|
311
|
+
};
|
|
312
|
+
const unmountMap = () => {
|
|
313
|
+
clearMarkers();
|
|
314
|
+
adapter.value?.destroy();
|
|
315
|
+
adapter.value = null;
|
|
316
|
+
};
|
|
317
|
+
onMounted(() => {
|
|
318
|
+
if (el.value) return mount();
|
|
319
|
+
const stop = watch(el, (node) => {
|
|
320
|
+
if (node) {
|
|
321
|
+
stop();
|
|
322
|
+
return mount();
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
onBeforeUnmount(() => {
|
|
327
|
+
epoch++;
|
|
328
|
+
unmountMap();
|
|
329
|
+
});
|
|
330
|
+
watch(() => props.engine, () => {
|
|
331
|
+
unmountMap();
|
|
332
|
+
mount();
|
|
333
|
+
});
|
|
334
|
+
watch(() => props.markers, () => {
|
|
335
|
+
if (!adapter.value) return;
|
|
336
|
+
if (props.fitMarkers) fit();
|
|
337
|
+
requestAnimationFrame(rebuild);
|
|
338
|
+
}, { deep: true, flush: "post" });
|
|
339
|
+
watch(() => [props.cluster, props.markerDefaults, props.clusterColor], () => adapter.value && rebuild(), { deep: true });
|
|
340
|
+
watch(iconStoreVersion, () => adapter.value && props.markers.some((m) => m.icon || props.markerDefaults.icon) && rebuild());
|
|
341
|
+
watch([() => props.mapStyle, isDark], () => {
|
|
342
|
+
const a = adapter.value;
|
|
343
|
+
if (a && a.engine === "vector") a.setStyle(resolveMapStyle(props.mapStyle, isDark.value));
|
|
344
|
+
});
|
|
345
|
+
watch(() => props.tileUrl, (url) => adapter.value?.engine === "raster" && adapter.value.setStyle(url));
|
|
346
|
+
watch(() => [props.center[0], props.center[1], props.zoom], () => {
|
|
347
|
+
const a = adapter.value;
|
|
348
|
+
if (!a) return;
|
|
349
|
+
const c = a.getCenter();
|
|
350
|
+
if (Math.abs(c[0] - props.center[0]) > 1e-6 || Math.abs(c[1] - props.center[1]) > 1e-6 || Math.abs(a.getZoom() - props.zoom) > 0.01) a.setView(props.center, props.zoom);
|
|
351
|
+
});
|
|
352
|
+
return { el, adapter, ready, keyOf, fit, toUnit, radiusValue, has: (n) => !!slots[n] };
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
const _export_sfc = (sfc, props) => {
|
|
356
|
+
const target = sfc.__vccOpts || sfc;
|
|
357
|
+
for (const [key, val] of props) {
|
|
358
|
+
target[key] = val;
|
|
359
|
+
}
|
|
360
|
+
return target;
|
|
361
|
+
};
|
|
362
|
+
const _hoisted_1 = ["aria-label"];
|
|
363
|
+
const _hoisted_2 = {
|
|
364
|
+
key: 0,
|
|
365
|
+
class: "sq-map__loading"
|
|
366
|
+
};
|
|
367
|
+
const _hoisted_3 = { class: "sq-map__controls" };
|
|
368
|
+
const _hoisted_4 = {
|
|
369
|
+
class: "sq-map__templates",
|
|
370
|
+
"aria-hidden": "true"
|
|
371
|
+
};
|
|
372
|
+
const _hoisted_5 = ["data-popup"];
|
|
373
|
+
const _hoisted_6 = { key: 0 };
|
|
374
|
+
const _hoisted_7 = { key: 1 };
|
|
375
|
+
const _hoisted_8 = ["data-marker"];
|
|
376
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
377
|
+
const _component_SqShape = resolveComponent("SqShape");
|
|
378
|
+
const _component_SqProgressCircular = resolveComponent("SqProgressCircular");
|
|
379
|
+
const _component_SqBtn = resolveComponent("SqBtn");
|
|
380
|
+
return openBlock(), createElementBlock(
|
|
381
|
+
"div",
|
|
382
|
+
{
|
|
383
|
+
class: "sq-map sq-surface",
|
|
384
|
+
style: normalizeStyle({ height: _ctx.toUnit(_ctx.height), "--sq-r": _ctx.radiusValue(_ctx.rounded), "--sq-bg": "var(--sq-surface-variant)", "--sq-bd": "var(--sq-border)", "--sq-bw": "1px" })
|
|
385
|
+
},
|
|
386
|
+
[
|
|
387
|
+
createVNode(_component_SqShape, { clip: "" }),
|
|
388
|
+
createElementVNode("div", {
|
|
389
|
+
ref: "el",
|
|
390
|
+
class: "sq-map__canvas",
|
|
391
|
+
role: "application",
|
|
392
|
+
"aria-label": _ctx.label
|
|
393
|
+
}, null, 8, _hoisted_1),
|
|
394
|
+
!_ctx.ready ? (openBlock(), createElementBlock("div", _hoisted_2, [
|
|
395
|
+
createVNode(_component_SqProgressCircular, {
|
|
396
|
+
indeterminate: "",
|
|
397
|
+
size: 24,
|
|
398
|
+
width: 3
|
|
399
|
+
})
|
|
400
|
+
])) : createCommentVNode("v-if", true),
|
|
401
|
+
createElementVNode("div", _hoisted_3, [
|
|
402
|
+
createVNode(_component_SqBtn, {
|
|
403
|
+
icon: "plus",
|
|
404
|
+
color: "surface",
|
|
405
|
+
variant: "elevated",
|
|
406
|
+
size: "small",
|
|
407
|
+
"aria-label": "Zoom in",
|
|
408
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.adapter && _ctx.adapter.zoomIn())
|
|
409
|
+
}),
|
|
410
|
+
createVNode(_component_SqBtn, {
|
|
411
|
+
icon: "minus",
|
|
412
|
+
color: "surface",
|
|
413
|
+
variant: "elevated",
|
|
414
|
+
size: "small",
|
|
415
|
+
"aria-label": "Zoom out",
|
|
416
|
+
onClick: _cache[1] || (_cache[1] = ($event) => _ctx.adapter && _ctx.adapter.zoomOut())
|
|
417
|
+
}),
|
|
418
|
+
_ctx.markers.length > 1 ? (openBlock(), createBlock(_component_SqBtn, {
|
|
419
|
+
key: 0,
|
|
420
|
+
icon: "place",
|
|
421
|
+
color: "surface",
|
|
422
|
+
variant: "elevated",
|
|
423
|
+
size: "small",
|
|
424
|
+
"aria-label": "Fit markers",
|
|
425
|
+
onClick: _ctx.fit
|
|
426
|
+
}, null, 8, ["onClick"])) : createCommentVNode("v-if", true)
|
|
427
|
+
]),
|
|
428
|
+
createCommentVNode(" Slot templates: cloned into popups / marker elements by the engine. "),
|
|
429
|
+
createElementVNode("div", _hoisted_4, [
|
|
430
|
+
(openBlock(true), createElementBlock(
|
|
431
|
+
Fragment,
|
|
432
|
+
null,
|
|
433
|
+
renderList(_ctx.markers, (m, i) => {
|
|
434
|
+
return openBlock(), createElementBlock("div", {
|
|
435
|
+
key: "p" + _ctx.keyOf(m, i),
|
|
436
|
+
"data-popup": _ctx.keyOf(m, i)
|
|
437
|
+
}, [
|
|
438
|
+
renderSlot(_ctx.$slots, "popup", { marker: m }, () => [
|
|
439
|
+
m.title ? (openBlock(), createElementBlock(
|
|
440
|
+
"b",
|
|
441
|
+
_hoisted_6,
|
|
442
|
+
toDisplayString(m.title),
|
|
443
|
+
1
|
|
444
|
+
/* TEXT */
|
|
445
|
+
)) : createCommentVNode("v-if", true),
|
|
446
|
+
m.popup ? (openBlock(), createElementBlock(
|
|
447
|
+
"div",
|
|
448
|
+
_hoisted_7,
|
|
449
|
+
toDisplayString(m.popup),
|
|
450
|
+
1
|
|
451
|
+
/* TEXT */
|
|
452
|
+
)) : createCommentVNode("v-if", true)
|
|
453
|
+
])
|
|
454
|
+
], 8, _hoisted_5);
|
|
455
|
+
}),
|
|
456
|
+
128
|
|
457
|
+
/* KEYED_FRAGMENT */
|
|
458
|
+
)),
|
|
459
|
+
_ctx.has("marker") ? (openBlock(true), createElementBlock(
|
|
460
|
+
Fragment,
|
|
461
|
+
{ key: 0 },
|
|
462
|
+
renderList(_ctx.markers, (m, i) => {
|
|
463
|
+
return openBlock(), createElementBlock("div", {
|
|
464
|
+
key: "m" + _ctx.keyOf(m, i),
|
|
465
|
+
"data-marker": _ctx.keyOf(m, i)
|
|
466
|
+
}, [
|
|
467
|
+
renderSlot(_ctx.$slots, "marker", { marker: m })
|
|
468
|
+
], 8, _hoisted_8);
|
|
469
|
+
}),
|
|
470
|
+
128
|
|
471
|
+
/* KEYED_FRAGMENT */
|
|
472
|
+
)) : createCommentVNode("v-if", true)
|
|
473
|
+
]),
|
|
474
|
+
renderSlot(_ctx.$slots, "default", {
|
|
475
|
+
map: _ctx.adapter ? _ctx.adapter.native : null
|
|
476
|
+
})
|
|
477
|
+
],
|
|
478
|
+
4
|
|
479
|
+
/* STYLE */
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
const SqMap = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
|
|
483
|
+
const componentNames = ["SqMap"];
|
|
484
|
+
export {
|
|
485
|
+
MAP_STYLES,
|
|
486
|
+
SqMap,
|
|
487
|
+
clusterElement,
|
|
488
|
+
clusterLeaves,
|
|
489
|
+
clustersFor,
|
|
490
|
+
componentNames,
|
|
491
|
+
createClusterIndex,
|
|
492
|
+
createRasterAdapter,
|
|
493
|
+
createVectorAdapter,
|
|
494
|
+
SqMap as default,
|
|
495
|
+
expansionZoom,
|
|
496
|
+
markerElement,
|
|
497
|
+
resolveMapStyle,
|
|
498
|
+
setMapWorkerUrl
|
|
499
|
+
};
|
|
500
|
+
//# sourceMappingURL=index.mjs.map
|