vue-maplibre-gl
Version:
Vue 3 plugin for maplibre-gl
1 lines • 125 kB
Source Map (JSON)
{"version":3,"file":"vue-maplibre-gl.cjs","sources":["../src/defaults.ts","../src/lib/map.lib.ts","../src/lib/mapRegistry.ts","../node_modules/modular-maptiler-sdk/src/language.ts","../src/components/map.component.ts","../src/components/controls/attribution.control.ts","../src/components/controls/fullscreen.control.ts","../src/components/controls/frameRate.control.ts","../src/components/controls/geolocation.control.ts","../src/components/controls/navigation.control.ts","../src/components/controls/scale.control.ts","../src/components/controls/styleSwitch.control.ts","../src/components/marker.component.ts","../src/lib/source.lib.ts","../src/lib/sourceLayer.registry.ts","../src/composable/useSource.ts","../src/components/sources/canvas.source.ts","../src/components/sources/geojson.source.ts","../src/components/sources/image.source.ts","../src/components/sources/raster.source.ts","../src/components/sources/rasterDem.source.ts","../src/components/sources/vector.source.ts","../src/components/sources/video.source.ts","../src/lib/layer.lib.ts","../src/composable/useDisposableLayer.ts","../src/components/layers/background.layer.ts","../src/components/layers/circle.layer.ts","../src/components/layers/fill.layer.ts","../src/components/layers/fillExtrusion.layer.ts","../src/components/layers/heatmap.layer.ts","../src/components/layers/hillshade.layer.ts","../src/components/layers/line.layer.ts","../src/components/layers/raster.layer.ts","../src/components/layers/smybol.layer.ts","../src/main.ts"],"sourcesContent":["import type { ValidLanguages } from '@/types';\nimport type { MapOptions as MaplibreMapOptions } from 'maplibre-gl';\nimport { reactive } from 'vue';\n\nexport type MapOptions = Omit<MaplibreMapOptions, 'container' | 'style'> & { style: object | string, language?: ValidLanguages };\n\nexport const defaults = reactive<MapOptions>({\n\tstyle : 'https://demotiles.maplibre.org/style.json',\n\tcenter : [ 0, 0 ],\n\tzoom : 1,\n\ttrackResize: false\n});\n","import type { MglMap } from '@/components';\nimport type { MglEvent } from '@/types';\nimport type { Map, MapOptions, MarkerOptions } from 'maplibre-gl';\n\nexport type MapEventHandler = (e: any) => void;\n\nexport class MapLib {\n\n\tstatic readonly MAP_OPTION_KEYS: Array<keyof MapOptions | 'mapStyle'> = [\n\t\t'attributionControl', 'bearing', 'bearingSnap', 'bounds', 'boxZoom', 'cancelPendingTileRequestsWhileZooming', 'canvasContextAttributes', 'center',\n\t\t'centerClampedToGround', 'clickTolerance', 'collectResourceTiming', 'cooperativeGestures', 'crossSourceCollisions', 'doubleClickZoom', 'dragPan',\n\t\t'dragRotate', 'elevation', 'fadeDuration', 'fitBoundsOptions', 'hash', 'interactive', 'keyboard', 'locale', 'localIdeographFontFamily',\n\t\t'logoPosition', 'maplibreLogo', 'maxBounds', 'maxCanvasSize', 'maxPitch', 'maxTileCacheSize', 'maxTileCacheZoomLevels', 'maxZoom', 'minPitch', 'minZoom',\n\t\t'pitch', 'pitchWithRotate', 'pixelRatio', 'refreshExpiredTiles', 'renderWorldCopies', 'roll', 'rollEnabled', 'scrollZoom', 'touchPitch',\n\t\t'touchZoomRotate', 'trackResize', 'transformCameraUpdate', 'transformRequest', 'validateStyle', 'zoom',\n\t\t'mapStyle'\n\t];\n\n\tstatic readonly MARKER_OPTION_KEYS: Array<keyof MarkerOptions> = [\n\t\t'element', 'offset', 'anchor', 'color', 'draggable', 'clickTolerance', 'rotation', 'rotationAlignment', 'pitchAlignment', 'scale'\n\t];\n\n\tstatic readonly MAP_EVENT_TYPES = [\n\t\t'boxzoomcancel', 'boxzoomend', 'boxzoomstart', 'click', 'contextmenu', 'cooperativegestureprevented', 'data', 'dataabort', 'dataloading', 'dblclick',\n\t\t'drag', 'dragend', 'dragstart', 'error', 'idle', 'load', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'move', 'moveend', 'movestart',\n\t\t'pitch', 'pitchend', 'pitchstart', 'projectiontransition', 'remove', 'render', 'resize', 'rotate', 'rotateend', 'rotatestart', 'sourcedata',\n\t\t'sourcedataabort', 'sourcedataloading', 'styledata', 'styledataloading', 'styleimagemissing', 'terrain', 'tiledataloading', 'touchcancel', 'touchend',\n\t\t'touchmove', 'touchstart', 'webglcontextlost', 'webglcontextrestored', 'wheel', 'zoom', 'zoomend', 'zoomstart'\n\t];\n\n\tstatic createEventHandler(component: InstanceType<typeof MglMap>, map: Map, ctx: {\n\t\temit: (t: string, payload: any) => void\n\t}, eventName: string): MapEventHandler {\n\t\treturn (payload = {}) => ctx.emit(eventName, { type: payload.type, map, component, event: payload } as MglEvent);\n\t}\n\n}\n","import type { MglMap } from '@/components';\nimport type { ValidLanguages } from '@/types';\nimport type { Map as MaplibreMap } from 'maplibre-gl';\nimport { reactive, type ShallowRef } from 'vue';\n\nexport interface MapInstance {\n\tcomponent?: InstanceType<typeof MglMap>;\n\tmap?: MaplibreMap;\n\tisMounted: boolean;\n\tisLoaded: boolean;\n\tlanguage: ValidLanguages | null;\n}\n\nconst instances = new Map<symbol | string, MapInstance>(),\n\t defaultKey = Symbol('default');\n\n// useMap returns reactive version of MapInstance\nexport function useMap(key: symbol | string = defaultKey): MapInstance {\n\tlet component = instances.get(key);\n\tif (!component) {\n\t\tcomponent = reactive({ isLoaded: false, isMounted: false, language: null });\n\t\tinstances.set(key, component);\n\t}\n\treturn component;\n}\n\nexport function registerMap(instance: InstanceType<typeof MglMap>, map: ShallowRef<MaplibreMap | undefined>, key: symbol | string = defaultKey): MapInstance {\n\tlet component = instances.get(key);\n\tif (!component) {\n\t\tcomponent = reactive({ isLoaded: false, isMounted: false, language: null });\n\t\tinstances.set(key, component);\n\t}\n\n\tcomponent.component = instance;\n\tcomponent.map = map.value;\n\tcomponent.isLoaded = map.value?.loaded() || false;\n\tcomponent.isMounted = false;\n\n\treturn component;\n}\n","import type { Map, SymbolLayerSpecification } from \"maplibre-gl\";\n\n/**\n * Languages. Note that not all the languages of this list are available but the compatibility list may be expanded in the future.\n */\nconst Language = {\n /**\n * AUTO mode uses the language of the browser\n */\n AUTO: \"auto\",\n\n /**\n * STYLE is a custom flag to keep the language of the map as defined into the style.\n * If STYLE is set in the constructor, then further modification of the language\n * with `.setLanguage()` is not possible.\n */\n STYLE_LOCK: \"style_lock\",\n\n /**\n * Default fallback languages that uses latin charaters\n */\n LATIN: \"latin\",\n\n /**\n * Default fallback languages that uses non-latin charaters\n */\n NON_LATIN: \"nonlatin\",\n\n /**\n * Labels are in their local language, when available\n */\n LOCAL: \"\",\n\n ALBANIAN: \"sq\",\n AMHARIC: \"am\",\n ARABIC: \"ar\",\n ARMENIAN: \"hy\",\n AZERBAIJANI: \"az\",\n BASQUE: \"eu\",\n BELORUSSIAN: \"be\",\n BOSNIAN: \"bs\",\n BRETON: \"br\",\n BULGARIAN: \"bg\",\n CATALAN: \"ca\",\n CHINESE: \"zh\",\n CORSICAN: \"co\",\n CROATIAN: \"hr\",\n CZECH: \"cs\",\n DANISH: \"da\",\n DUTCH: \"nl\",\n ENGLISH: \"en\",\n ESPERANTO: \"eo\",\n ESTONIAN: \"et\",\n FINNISH: \"fi\",\n FRENCH: \"fr\",\n FRISIAN: \"fy\",\n GEORGIAN: \"ka\",\n GERMAN: \"de\",\n GREEK: \"el\",\n HEBREW: \"he\",\n HINDI: \"hi\",\n HUNGARIAN: \"hu\",\n ICELANDIC: \"is\",\n INDONESIAN: \"id\",\n IRISH: \"ga\",\n ITALIAN: \"it\",\n JAPANESE: \"ja\",\n JAPANESE_HIRAGANA: \"ja-Hira\",\n JAPANESE_KANA: \"ja_kana\",\n JAPANESE_LATIN: \"ja_rm\",\n JAPANESE_2018: \"ja-Latn\",\n KANNADA: \"kn\",\n KAZAKH: \"kk\",\n KOREAN: \"ko\",\n KOREAN_LATIN: \"ko-Latn\",\n KURDISH: \"ku\",\n ROMAN_LATIN: \"la\",\n LATVIAN: \"lv\",\n LITHUANIAN: \"lt\",\n LUXEMBOURGISH: \"lb\",\n MACEDONIAN: \"mk\",\n MALAYALAM: \"ml\",\n MALTESE: \"mt\",\n NORWEGIAN: \"no\",\n OCCITAN: \"oc\",\n POLISH: \"pl\",\n PORTUGUESE: \"pt\",\n ROMANIAN: \"ro\",\n ROMANSH: \"rm\",\n RUSSIAN: \"ru\",\n SCOTTISH_GAELIC: \"gd\",\n SERBIAN_CYRILLIC: \"sr\",\n SERBIAN_LATIN: \"sr-Latn\",\n SLOVAK: \"sk\",\n SLOVENE: \"sl\",\n SPANISH: \"es\",\n SWEDISH: \"sv\",\n TAMIL: \"ta\",\n TELUGU: \"te\",\n THAI: \"th\",\n TURKISH: \"tr\",\n UKRAINIAN: \"uk\",\n WELSH: \"cy\",\n} as const;\n\nconst languagesIsoSet = new Set(Object.values(Language) as Array<string>);\n\nfunction isLanguageSupported(lang: string): boolean {\n return languagesIsoSet.has(lang);\n}\n\nconst languageCodeSet = new Set(Object.values(Language));\n\n/**\n * Type representing the key of the Language object\n */\ntype LanguageKey = keyof typeof Language;\n\ntype Values<T> = T[keyof T];\n\n/**\n * Built-in languages values as strings\n */\ntype LanguageString = Values<typeof Language>;\n\nfunction getBrowserLanguage(): LanguageString {\n if (typeof navigator === \"undefined\") {\n return Intl.DateTimeFormat()\n .resolvedOptions()\n .locale.split(\"-\")[0] as LanguageString;\n }\n\n const canditatelangs = Array.from(\n new Set(navigator.languages.map((l) => l.split(\"-\")[0]))\n ).filter((l) => languageCodeSet.has(l as LanguageString));\n\n return canditatelangs.length\n ? (canditatelangs[0] as LanguageString)\n : Language.LATIN;\n}\n\nfunction setPrimaryLanguage(map: Map, lang: string) {\n const layers = map.getStyle().layers;\n\n // detects pattern like \"{name:somelanguage}\" with loose spacing\n const strLanguageRegex = /^\\s*{\\s*name\\s*(:\\s*(\\S*))?\\s*}$/;\n\n // detects pattern like \"name:somelanguage\" with loose spacing\n const strLanguageInArrayRegex = /^\\s*name\\s*(:\\s*(\\S*))?\\s*$/;\n\n // for string based bilingual lang such as \"{name:latin} {name:nonlatin}\" or \"{name:latin} {name}\"\n const strBilingualRegex =\n /^\\s*{\\s*name\\s*(:\\s*(\\S*))?\\s*}(\\s*){\\s*name\\s*(:\\s*(\\S*))?\\s*}$/;\n\n // Regex to capture when there are more info, such as mountains elevation with unit m/ft\n const strMoreInfoRegex = /^(.*)({\\s*name\\s*(:\\s*(\\S*))?\\s*})(.*)$/;\n\n const langStr = lang ? `name:${lang}` : \"name\"; // to handle local lang\n const replacer = [\n \"case\",\n [\"has\", langStr],\n [\"get\", langStr],\n [\"get\", \"name\"],\n ];\n\n for (let i = 0; i < layers.length; i += 1) {\n const layer = layers[i] as SymbolLayerSpecification;\n const layout = layer.layout;\n\n if (!layout) {\n continue;\n }\n\n if (!layout[\"text-field\"]) {\n continue;\n }\n\n const textFieldLayoutProp = map.getLayoutProperty(layer.id, \"text-field\");\n\n // Note:\n // The value of the 'text-field' property can take multiple shape;\n // 1. can be an array with 'concat' on its first element (most likely means bilingual)\n // 2. can be an array with 'get' on its first element (monolingual)\n // 3. can be a string of shape '{name:latin}'\n // 4. can be a string referencing another prop such as '{housenumber}' or '{ref}'\n //\n // The case 1, 2 and 3 will be updated while maintaining their original type and shape.\n // The case 3 will not be updated\n\n let regexMatch;\n\n // This is case 1\n if (\n Array.isArray(textFieldLayoutProp) &&\n textFieldLayoutProp.length >= 2 &&\n textFieldLayoutProp[0].trim().toLowerCase() === \"concat\"\n ) {\n const newProp = textFieldLayoutProp.slice(); // newProp is Array\n // The style could possibly have defined more than 2 concatenated language strings but we only want to edit the first\n // The style could also define that there are more things being concatenated and not only languages\n\n for (let j = 0; j < textFieldLayoutProp.length; j += 1) {\n const elem = textFieldLayoutProp[j];\n\n // we are looking for an elem of shape '{name:somelangage}' (string) of `[\"get\", \"name:somelanguage\"]` (array)\n\n // the entry of of shape '{name:somelangage}', possibly with loose spacing\n if (\n (typeof elem === \"string\" || elem instanceof String) &&\n strLanguageRegex.exec(elem.toString())\n ) {\n newProp[j] = replacer;\n break; // we just want to update the primary language\n }\n // the entry is of an array of shape `[\"get\", \"name:somelanguage\"]`\n else if (\n Array.isArray(elem) &&\n elem.length >= 2 &&\n elem[0].trim().toLowerCase() === \"get\" &&\n strLanguageInArrayRegex.exec(elem[1].toString())\n ) {\n newProp[j] = replacer;\n break; // we just want to update the primary language\n } else if (\n Array.isArray(elem) &&\n elem.length === 4 &&\n elem[0].trim().toLowerCase() === \"case\"\n ) {\n newProp[j] = replacer;\n break; // we just want to update the primary language\n }\n }\n\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n }\n\n // This is case 2\n else if (\n Array.isArray(textFieldLayoutProp) &&\n textFieldLayoutProp.length >= 2 &&\n textFieldLayoutProp[0].trim().toLowerCase() === \"get\" &&\n strLanguageInArrayRegex.exec(textFieldLayoutProp[1].toString())\n ) {\n const newProp = replacer;\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n }\n\n // This is case 3\n else if (\n (typeof textFieldLayoutProp === \"string\" ||\n textFieldLayoutProp instanceof String) &&\n strLanguageRegex.exec(textFieldLayoutProp.toString())\n ) {\n const newProp = replacer;\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n } else if (\n Array.isArray(textFieldLayoutProp) &&\n textFieldLayoutProp.length === 4 &&\n textFieldLayoutProp[0].trim().toLowerCase() === \"case\"\n ) {\n const newProp = replacer;\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n } else if (\n (typeof textFieldLayoutProp === \"string\" ||\n textFieldLayoutProp instanceof String) &&\n (regexMatch = strBilingualRegex.exec(textFieldLayoutProp.toString())) !==\n null\n ) {\n const newProp = `{${langStr}}${regexMatch[3]}{name${\n regexMatch[4] || \"\"\n }}`;\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n } else if (\n (typeof textFieldLayoutProp === \"string\" ||\n textFieldLayoutProp instanceof String) &&\n (regexMatch = strMoreInfoRegex.exec(textFieldLayoutProp.toString())) !==\n null\n ) {\n const newProp = `${regexMatch[1]}{${langStr}}${regexMatch[5]}`;\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n }\n }\n}\n\nfunction setSecondaryLanguage(map: Map, lang: string) {\n const layers = map.getStyle().layers;\n\n // detects pattern like \"{name:somelanguage}\" with loose spacing\n const strLanguageRegex = /^\\s*{\\s*name\\s*(:\\s*(\\S*))?\\s*}$/;\n\n // detects pattern like \"name:somelanguage\" with loose spacing\n const strLanguageInArrayRegex = /^\\s*name\\s*(:\\s*(\\S*))?\\s*$/;\n\n // for string based bilingual lang such as \"{name:latin} {name:nonlatin}\" or \"{name:latin} {name}\"\n const strBilingualRegex =\n /^\\s*{\\s*name\\s*(:\\s*(\\S*))?\\s*}(\\s*){\\s*name\\s*(:\\s*(\\S*))?\\s*}$/;\n\n let regexMatch;\n\n for (let i = 0; i < layers.length; i += 1) {\n const layer = layers[i] as SymbolLayerSpecification;\n const layout = layer.layout;\n\n if (!layout) {\n continue;\n }\n\n if (!layout[\"text-field\"]) {\n continue;\n }\n\n const textFieldLayoutProp = map.getLayoutProperty(layer.id, \"text-field\");\n\n let newProp;\n\n // Note:\n // The value of the 'text-field' property can take multiple shape;\n // 1. can be an array with 'concat' on its first element (most likely means bilingual)\n // 2. can be an array with 'get' on its first element (monolingual)\n // 3. can be a string of shape '{name:latin}'\n // 4. can be a string referencing another prop such as '{housenumber}' or '{ref}'\n //\n // Only the case 1 will be updated because we don't want to change the styling (read: add a secondary language where the original styling is only displaying 1)\n\n // This is case 1\n if (\n Array.isArray(textFieldLayoutProp) &&\n textFieldLayoutProp.length >= 2 &&\n textFieldLayoutProp[0].trim().toLowerCase() === \"concat\"\n ) {\n newProp = textFieldLayoutProp.slice(); // newProp is Array\n // The style could possibly have defined more than 2 concatenated language strings but we only want to edit the first\n // The style could also define that there are more things being concatenated and not only languages\n\n let languagesAlreadyFound = 0;\n\n for (let j = 0; j < textFieldLayoutProp.length; j += 1) {\n const elem = textFieldLayoutProp[j];\n\n // we are looking for an elem of shape '{name:somelangage}' (string) of `[\"get\", \"name:somelanguage\"]` (array)\n\n // the entry of of shape '{name:somelangage}', possibly with loose spacing\n if (\n (typeof elem === \"string\" || elem instanceof String) &&\n strLanguageRegex.exec(elem.toString())\n ) {\n if (languagesAlreadyFound === 1) {\n newProp[j] = `{name:${lang}}`;\n break; // we just want to update the secondary language\n }\n\n languagesAlreadyFound += 1;\n }\n // the entry is of an array of shape `[\"get\", \"name:somelanguage\"]`\n else if (\n Array.isArray(elem) &&\n elem.length >= 2 &&\n elem[0].trim().toLowerCase() === \"get\" &&\n strLanguageInArrayRegex.exec(elem[1].toString())\n ) {\n if (languagesAlreadyFound === 1) {\n newProp[j][1] = `name:${lang}`;\n break; // we just want to update the secondary language\n }\n\n languagesAlreadyFound += 1;\n } else if (\n Array.isArray(elem) &&\n elem.length === 4 &&\n elem[0].trim().toLowerCase() === \"case\"\n ) {\n if (languagesAlreadyFound === 1) {\n newProp[j] = [\"get\", `name:${lang}`]; // the situation with 'case' is supposed to only happen with the primary lang\n break; // but in case a styling also does that for secondary...\n }\n\n languagesAlreadyFound += 1;\n }\n }\n\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n }\n\n // the language (both first and second) are defined into a single string model\n else if (\n (typeof textFieldLayoutProp === \"string\" ||\n textFieldLayoutProp instanceof String) &&\n (regexMatch = strBilingualRegex.exec(textFieldLayoutProp.toString())) !==\n null\n ) {\n const langStr = lang ? `name:${lang}` : \"name\"; // to handle local lang\n newProp = `{name${regexMatch[1] || \"\"}}${regexMatch[3]}{${langStr}}`;\n map.setLayoutProperty(layer.id, \"text-field\", newProp);\n }\n }\n}\n\nexport {\n Language,\n getBrowserLanguage,\n isLanguageSupported,\n setPrimaryLanguage,\n setSecondaryLanguage,\n};\n\nexport type { LanguageString, LanguageKey };\n","import { defaults } from '@/defaults';\nimport { debounce } from '@/lib/debounce';\nimport { MapLib } from '@/lib/map.lib';\nimport { registerMap } from '@/lib/mapRegistry';\nimport {\n\tcomponentIdSymbol,\n\temitterSymbol,\n\ttype FitBoundsOptions,\n\tfitBoundsOptionsSymbol,\n\tisInitializedSymbol,\n\tisLoadedSymbol,\n\tmapSymbol,\n\ttype MglEvents,\n\tsourceIdSymbol,\n\ttype ValidLanguages\n} from '@/types';\nimport type { ProjectionSpecification } from '@maplibre/maplibre-gl-style-spec';\nimport { Map as MaplibreMap, type MapOptions, type StyleSpecification } from 'maplibre-gl';\nimport mitt from 'mitt';\nimport { setPrimaryLanguage } from 'modular-maptiler-sdk/src/language';\nimport {\n\tdefineComponent,\n\tgetCurrentInstance,\n\th,\n\tmarkRaw,\n\tnextTick,\n\tonBeforeUnmount,\n\tonMounted,\n\ttype PropType,\n\tprovide,\n\tref,\n\tshallowRef,\n\ttype SlotsType,\n\tunref,\n\twatch\n} from 'vue';\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglMap',\n\tprops: {\n\t\twidth : { type: [ Number, String ] as PropType<number | string>, default: '100%' },\n\t\theight : { type: [ Number, String ] as PropType<number | string>, default: '100%' },\n\t\tattributionControl: { type: [ Boolean, Object ] as PropType<MapOptions['attributionControl']>, default: () => defaults.attributionControl },\n\t\tbearing : { type: Number as PropType<MapOptions['bearing']>, default: () => defaults.bearing },\n\t\tbearingSnap : { type: Number as PropType<MapOptions['bearingSnap']>, default: () => defaults.bearingSnap },\n\t\tbounds : { type: [ Array, Object ] as PropType<MapOptions['bounds']>, default: () => defaults.bounds },\n\t\tboxZoom : { type: Boolean as PropType<MapOptions['boxZoom']>, default: () => defaults.boxZoom },\n\n\t\tcancelPendingTileRequestsWhileZooming: {\n\t\t\ttype: Boolean as PropType<MapOptions['cancelPendingTileRequestsWhileZooming']>, default: () => defaults.cancelPendingTileRequestsWhileZooming\n\t\t},\n\n\t\tcanvasContextAttributes: { type: Object as PropType<MapOptions['canvasContextAttributes']>, default: () => defaults.canvasContextAttributes },\n\t\tcenter : { type: [ Array, Object ] as PropType<MapOptions['center']>, default: () => defaults.center },\n\t\tcenterClampedToGround : { type: Boolean as PropType<MapOptions['centerClampedToGround']>, default: () => defaults.centerClampedToGround },\n\t\tclickTolerance : { type: Number as PropType<MapOptions['clickTolerance']>, default: () => defaults.clickTolerance },\n\t\tcollectResourceTiming : { type: Boolean as PropType<MapOptions['collectResourceTiming']>, default: () => defaults.collectResourceTiming },\n\t\tcooperativeGestures : { type: [ Boolean, Object ] as PropType<MapOptions['cooperativeGestures']>, default: () => defaults.cooperativeGestures },\n\t\tcrossSourceCollisions : { type: Boolean as PropType<MapOptions['crossSourceCollisions']>, default: () => defaults.crossSourceCollisions },\n\t\tdoubleClickZoom : { type: Boolean as PropType<MapOptions['doubleClickZoom']>, default: () => defaults.doubleClickZoom },\n\t\tdragPan : { type: Boolean as PropType<MapOptions['dragPan']>, default: () => defaults.dragPan },\n\t\tdragRotate : { type: Boolean as PropType<MapOptions['dragRotate']>, default: () => defaults.dragRotate },\n\t\televation : { type: Number as PropType<MapOptions['elevation']>, default: () => defaults.elevation },\n\t\tfadeDuration : { type: Number as PropType<MapOptions['fadeDuration']>, default: () => defaults.fadeDuration },\n\t\tfitBoundsOptions : { type: Object as PropType<FitBoundsOptions>, default: () => defaults.fitBoundsOptions },\n\t\thash : { type: [ Boolean, String ] as PropType<MapOptions['hash']>, default: () => defaults.hash },\n\t\tinteractive : { type: Boolean as PropType<MapOptions['interactive']>, default: () => defaults.interactive },\n\t\tkeyboard : { type: Boolean as PropType<MapOptions['keyboard']>, default: () => defaults.keyboard },\n\t\tlanguage : { type: String as PropType<ValidLanguages | null>, default: () => defaults.language || null },\n\t\tlocale : { type: Object as PropType<MapOptions['locale']>, default: () => defaults.locale },\n\n\t\tlocalIdeographFontFamily: {\n\t\t\ttype: String as PropType<MapOptions['localIdeographFontFamily']>, default: () => defaults.localIdeographFontFamily\n\t\t},\n\n\t\tlogoPosition: { type: [ String ] as PropType<MapOptions['logoPosition']>, default: () => defaults.logoPosition },\n\t\tmapKey : { type: [ String, Symbol ] as PropType<string | symbol> },\n\t\tmaplibreLogo: { type: Boolean as PropType<MapOptions['maplibreLogo']>, default: () => defaults.maplibreLogo },\n\t\t// StyleSpecification triggers TS7056, so users must handle typings themselves\n\t\tmapStyle : { type: [ String, Object ] as PropType<object | string>, default: () => defaults.style },\n\t\tmaxBounds : { type: [ Array, Object ] as PropType<MapOptions['maxBounds']>, default: () => defaults.maxBounds },\n\t\tmaxCanvasSize : { type: Array as unknown as PropType<MapOptions['maxCanvasSize']>, default: () => defaults.maxCanvasSize },\n\t\tmaxPitch : { type: Number as PropType<MapOptions['maxPitch']>, default: () => defaults.maxPitch },\n\t\tmaxTileCacheSize : { type: Number as PropType<number>, default: () => defaults.maxTileCacheSize },\n\t\tmaxTileCacheZoomLevels: { type: Number as PropType<MapOptions['maxTileCacheZoomLevels']>, default: () => defaults.maxTileCacheZoomLevels },\n\t\tmaxZoom : { type: Number as PropType<MapOptions['maxZoom']>, default: () => defaults.maxZoom },\n\t\tminPitch : { type: Number as PropType<MapOptions['minPitch']>, default: () => defaults.minPitch },\n\t\tminZoom : { type: Number as PropType<MapOptions['minZoom']>, default: () => defaults.minZoom },\n\t\tpitch : { type: Number as PropType<MapOptions['pitch']>, default: () => defaults.pitch },\n\t\tpitchWithRotate : { type: Boolean as PropType<MapOptions['pitchWithRotate']>, default: () => defaults.pitchWithRotate },\n\t\tpixelRatio : { type: Number as PropType<MapOptions['pixelRatio']>, default: () => defaults.pixelRatio },\n\t\trefreshExpiredTiles : { type: Boolean as PropType<MapOptions['refreshExpiredTiles']>, default: () => defaults.refreshExpiredTiles },\n\t\trenderWorldCopies : { type: Boolean as PropType<MapOptions['renderWorldCopies']>, default: () => defaults.renderWorldCopies },\n\t\troll : { type: Number as PropType<MapOptions['roll']>, default: () => defaults.roll },\n\t\trollEnabled : { typed: Boolean as PropType<MapOptions['rollEnabled']>, default: () => defaults.rollEnabled },\n\t\tscrollZoom : { type: Boolean as PropType<MapOptions['scrollZoom']>, default: () => defaults.scrollZoom },\n\t\ttouchPitch : { type: Boolean as PropType<MapOptions['touchPitch']>, default: () => defaults.touchPitch },\n\t\ttouchZoomRotate : { type: Boolean as PropType<MapOptions['touchZoomRotate']>, default: () => defaults.touchZoomRotate },\n\t\ttrackResize : { type: Boolean as PropType<MapOptions['trackResize']>, default: () => defaults.trackResize },\n\t\ttransformCameraUpdate : { type: Function as PropType<NonNullable<MapOptions['transformCameraUpdate']>>, default: defaults.transformCameraUpdate },\n\t\ttransformRequest : { type: Function as PropType<NonNullable<MapOptions['transformRequest']>>, default: defaults.transformRequest },\n\t\tvalidateStyle : { type: Boolean as PropType<MapOptions['validateStyle']>, default: () => defaults.validateStyle },\n\t\tzoom : { type: Number as PropType<MapOptions['zoom']>, default: () => defaults.zoom },\n\t\tprojection : { type: Object as PropType<ProjectionSpecification> }\n\t},\n\temits: [\n\t\t'map:boxzoomcancel', 'map:boxzoomend', 'map:boxzoomstart', 'map:click', 'map:contextmenu', 'map:cooperativegestureprevented', 'map:data',\n\t\t'map:dataabort', 'map:dataloading', 'map:dblclick', 'map:drag', 'map:dragend', 'map:dragstart', 'map:error', 'map:idle', 'map:load', 'map:mousedown',\n\t\t'map:mousemove', 'map:mouseout', 'map:mouseover', 'map:mouseup', 'map:move', 'map:moveend', 'map:movestart', 'map:pitch', 'map:pitchend',\n\t\t'map:pitchstart', 'map:projectiontransition', 'map:remove', 'map:render', 'map:resize', 'map:rotate', 'map:rotateend', 'map:rotatestart',\n\t\t'map:sourcedata', 'map:sourcedataabort', 'map:sourcedataloading', 'map:styledata', 'map:styledataloading', 'map:styleimagemissing', 'map:terrain',\n\t\t'map:tiledataloading', 'map:touchcancel', 'map:touchend', 'map:touchmove', 'map:touchstart', 'map:webglcontextlost', 'map:webglcontextrestored',\n\t\t'map:wheel', 'map:zoom', 'map:zoomend', 'map:zoomstart'\n\t],\n\tslots: Object as SlotsType<{ default: {} }>,\n\tsetup(props, ctx) {\n\n\t\tconst component = markRaw(getCurrentInstance()!),\n\t\t\t container = shallowRef<HTMLDivElement>(),\n\t\t\t map = shallowRef<MaplibreMap>(),\n\t\t\t isInitialized = ref(false),\n\t\t\t isLoaded = ref(false),\n\t\t\t isStyleReady = ref(false),\n\t\t\t boundMapEvents = new Map<string, Function>(),\n\t\t\t emitter = mitt<MglEvents>(),\n\t\t\t registryItem = registerMap(component as any, map, props.mapKey);\n\n\t\tlet resizeObserver: ResizeObserver | undefined;\n\n\t\tprovide(mapSymbol, map);\n\t\tprovide(isLoadedSymbol, isLoaded);\n\t\tprovide(isInitializedSymbol, isInitialized);\n\t\tprovide(componentIdSymbol, component.uid);\n\t\tprovide(sourceIdSymbol, '');\n\t\tprovide(emitterSymbol, emitter);\n\t\tprovide(fitBoundsOptionsSymbol, props.fitBoundsOptions);\n\n\t\t/*\n\t\t * bind prop watchers\n\t\t */\n\t\twatch(() => props.bearing, v => v && map.value?.setBearing(v));\n\t\twatch(() => props.bounds, v => v && map.value?.fitBounds(v, props.fitBoundsOptions?.useOnBoundsUpdate ? props.fitBoundsOptions : undefined));\n\t\twatch(() => props.center, v => v && map.value?.setCenter(v));\n\t\twatch(() => props.maxBounds, v => v && map.value?.setMaxBounds(v));\n\t\twatch(() => props.maxPitch, v => v && map.value?.setMaxPitch(v));\n\t\twatch(() => props.maxZoom, v => v && map.value?.setMaxZoom(v));\n\t\twatch(() => props.minPitch, v => v && map.value?.setMinPitch(v));\n\t\twatch(() => props.minZoom, v => v && map.value?.setMinZoom(v));\n\t\twatch(() => props.pitch, v => v && map.value?.setPitch(v));\n\t\twatch(() => props.renderWorldCopies, v => v && map.value?.setRenderWorldCopies(v));\n\t\twatch(() => props.mapStyle, v => v && map.value?.setStyle(v as StyleSpecification | string));\n\t\twatch(() => props.transformRequest, v => v && map.value?.setTransformRequest(v));\n\t\twatch(() => props.zoom, v => v && map.value?.setZoom(v));\n\t\twatch(() => props.projection, v => v && map.value?.setProjection(v));\n\n\t\twatch(() => props.language, v => {\n\t\t\tif (isStyleReady.value && map.value && registryItem.language !== (v || null)) {\n\t\t\t\tsetPrimaryLanguage(map.value as any, v || '');\n\t\t\t\tregistryItem.language = v || null;\n\t\t\t}\n\t\t});\n\t\twatch(() => registryItem.language, v => {\n\t\t\tif (isStyleReady.value && map.value) {\n\t\t\t\tsetPrimaryLanguage(map.value as any, v || '');\n\t\t\t}\n\t\t});\n\n\t\tfunction onStyleReady() {\n\t\t\tisStyleReady.value = true;\n\t\t\tif (props.language) {\n\t\t\t\tregistryItem.language = props.language;\n\t\t\t} else if (registryItem.language) {\n\t\t\t\tsetPrimaryLanguage(map.value! as any, props.language || '');\n\t\t\t}\n\t\t\tif (props.projection) {\n\t\t\t\tmap.value!.setProjection(props.projection);\n\t\t\t}\n\t\t}\n\n\t\tfunction initialize() {\n\n\t\t\tregistryItem.isMounted = true;\n\n\t\t\t// build options\n\t\t\tconst opts: MapOptions = Object.keys(props)\n\t\t\t\t\t\t\t\t\t\t .filter(opt => (props as any)[ opt ] !== undefined && MapLib.MAP_OPTION_KEYS.indexOf(opt as keyof MapOptions) !== -1)\n\t\t\t\t\t\t\t\t\t\t .reduce<MapOptions>((obj, opt) => {\n\t\t\t\t\t\t\t\t\t\t\t (obj as any)[ opt === 'mapStyle' ? 'style' : opt ] = unref((props as any)[ opt ]);\n\t\t\t\t\t\t\t\t\t\t\t return obj;\n\t\t\t\t\t\t\t\t\t\t }, { container: container.value as HTMLDivElement } as any);\n\n\t\t\t// init map\n\t\t\tmap.value = markRaw(new MaplibreMap(opts));\n\t\t\tregistryItem.map = map.value;\n\t\t\tisInitialized.value = true;\n\t\t\tboundMapEvents.set('__load', () => (isLoaded.value = true, registryItem.isLoaded = true));\n\t\t\tmap.value.once('styledata', onStyleReady);\n\t\t\tmap.value.on('load', boundMapEvents.get('__load') as any);\n\n\t\t\t// bind events\n\t\t\tif (component.vnode.props) {\n\t\t\t\tfor (let i = 0, len = MapLib.MAP_EVENT_TYPES.length; i < len; i++) {\n\t\t\t\t\tif (component.vnode.props[ 'onMap:' + MapLib.MAP_EVENT_TYPES[ i ] ]) {\n\t\t\t\t\t\tconst handler = MapLib.createEventHandler(component as any, map.value, ctx as any, 'map:' + MapLib.MAP_EVENT_TYPES[ i ]);\n\t\t\t\t\t\tboundMapEvents.set(MapLib.MAP_EVENT_TYPES[ i ], handler);\n\t\t\t\t\t\tmap.value.on(MapLib.MAP_EVENT_TYPES[ i ], handler);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// automatic re-initialization of map on CONTEXT_LOST_WEBGL\n\t\t\tmap.value.getCanvas().addEventListener('webglcontextlost', restart);\n\n\t\t}\n\n\t\tasync function dispose() {\n\n\t\t\tregistryItem.isMounted = false;\n\t\t\tregistryItem.isLoaded = false;\n\t\t\tisLoaded.value = false;\n\n\t\t\tif (map.value) {\n\t\t\t\t// unbind events\n\t\t\t\tmap.value.getCanvas().removeEventListener('webglcontextlost', restart);\n\t\t\t\tmap.value._controls.forEach((control) => {\n\t\t\t\t\tmap.value!.removeControl(control);\n\t\t\t\t});\n\t\t\t\tisInitialized.value = false;\n\t\t\t\tboundMapEvents.forEach((func, en) => {\n\t\t\t\t\tmap.value!.off(en.startsWith('__') ? en.substring(2) : en, func as any);\n\t\t\t\t});\n\t\t\t\t// destroy map\n\t\t\t\tmap.value.remove();\n\t\t\t}\n\n\t\t}\n\n\t\tfunction restart() {\n\t\t\tdispose();\n\t\t\tnextTick(initialize);\n\t\t}\n\n\t\t/*\n\t\t * init map\n\t\t */\n\t\tonMounted(() => {\n\n\t\t\tinitialize();\n\n\t\t\t// bind resize observer\n\t\t\tif (map.value) {\n\t\t\t\tresizeObserver = new ResizeObserver(debounce(map.value.resize.bind(map.value), 100));\n\t\t\t\tresizeObserver.observe(container.value as HTMLDivElement);\n\t\t\t}\n\n\t\t});\n\n\t\t/*\n\t\t * Dispose component\n\t\t */\n\t\tonBeforeUnmount(() => {\n\n\t\t\t// unbind resize observer\n\t\t\tif (resizeObserver !== undefined) {\n\t\t\t\tresizeObserver.disconnect();\n\t\t\t\tresizeObserver = undefined;\n\t\t\t}\n\n\t\t\tdispose();\n\n\t\t});\n\n\t\tctx.expose({ map });\n\n\t\treturn () => h(\n\t\t\t'div',\n\t\t\t{\n\t\t\t\t'class': 'mgl-container',\n\t\t\t\tstyle : { height: props.height, width: props.width }\n\t\t\t},\n\t\t\t[\n\t\t\t\th('div', { ref: container, 'class': 'mgl-wrapper' }),\n\t\t\t\tisInitialized.value && ctx.slots.default ? ctx.slots.default({}) : undefined\n\t\t\t]\n\t\t);\n\n\t}\n});\n","import { Position, type PositionProp, PositionValues } from '@/components/controls/position.enum';\nimport { usePositionWatcher } from '@/composable/usePositionWatcher';\nimport { isInitializedSymbol, mapSymbol } from '@/types';\nimport { AttributionControl } from 'maplibre-gl';\nimport { defineComponent, inject, onBeforeUnmount, type PropType } from 'vue';\n\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglAttributionControl',\n\tprops: {\n\t\tposition : {\n\t\t\ttype : String as PropType<PositionProp>,\n\t\t\tvalidator: (v: Position) => {\n\t\t\t\treturn PositionValues.indexOf(v) !== -1;\n\t\t\t}\n\t\t},\n\t\tcompact : Boolean as PropType<boolean>,\n\t\tcustomAttribution: [ String, Array ] as PropType<string | string[]>\n\t},\n\tsetup(props) {\n\n\t\tconst map = inject(mapSymbol)!,\n\t\t\t isInitialized = inject(isInitializedSymbol)!,\n\t\t\t control = new AttributionControl({ compact: props.compact, customAttribution: props.customAttribution });\n\n\t\tusePositionWatcher(() => props.position, map, control);\n\t\tonBeforeUnmount(() => isInitialized.value && map.value!.removeControl(control));\n\n\t},\n\trender() {\n\t\t// nothing\n\t}\n});\n","import { Position, type PositionProp, PositionValues } from '@/components/controls/position.enum';\nimport { usePositionWatcher } from '@/composable/usePositionWatcher';\nimport { isInitializedSymbol, mapSymbol } from '@/types';\nimport { FullscreenControl } from 'maplibre-gl';\nimport { defineComponent, inject, nextTick, onBeforeUnmount, type PropType } from 'vue';\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglFullscreenControl',\n\tprops: {\n\t\tposition : {\n\t\t\ttype : String as PropType<PositionProp>,\n\t\t\tdefault : Position.TOP_RIGHT,\n\t\t\tvalidator: (v: Position) => {\n\t\t\t\treturn PositionValues.indexOf(v) !== -1;\n\t\t\t}\n\t\t},\n\t\tcontainer: {\n\t\t\ttype : Object as PropType<HTMLElement>,\n\t\t\tdefault: null\n\t\t},\n\t},\n\tsetup(props) {\n\n\t\tconst map = inject(mapSymbol)!,\n\t\t\t isInitialized = inject(isInitializedSymbol)!,\n\t\t\t control = new FullscreenControl({ container: props.container || undefined });\n\n\t\t// fire map.resize just a 2nd time\n\t\tfunction triggerResize() {\n\t\t\tnextTick(() => map.value?.resize());\n\t\t}\n\n\t\tcontrol.on('fullscreenstart', triggerResize);\n\t\tcontrol.on('fullscreenend', triggerResize);\n\n\t\tusePositionWatcher(() => props.position, map, control);\n\t\tonBeforeUnmount(() => {\n\t\t\tcontrol.off('fullscreenstart', triggerResize);\n\t\t\tcontrol.off('fullscreenend', triggerResize);\n\t\t\tisInitialized.value && map.value?.removeControl(control);\n\t\t});\n\n\t},\n\trender() {\n\t\t// nothing\n\t}\n});\n","import { Position, type PositionProp, PositionValues } from '@/components/controls/position.enum';\nimport { usePositionWatcher } from '@/composable/usePositionWatcher';\nimport { isInitializedSymbol, mapSymbol } from '@/types';\nimport type { IControl, Map as MMap } from 'maplibre-gl';\nimport { defineComponent, inject, onBeforeUnmount, type PropType } from 'vue';\n\nexport class FrameRateControl implements IControl {\n\n\tprivate frames = 0;\n\tprivate totalTime = 0;\n\tprivate totalFrames = 0;\n\n\tprivate time: number | null = null;\n\tprivate map?: MMap;\n\tprivate container?: HTMLDivElement;\n\tprivate readOutput?: HTMLDivElement;\n\tprivate canvas?: HTMLCanvasElement;\n\n\tprivate eventHandlers = new Map<string, Function>();\n\n\tconstructor(private background = 'rgba(0,0,0,0.9)',\n\t\t\t\tprivate barWidth = 4 * window.devicePixelRatio,\n\t\t\t\tprivate color = '#7cf859',\n\t\t\t\tprivate font = 'Monaco, Consolas, Courier, monospace',\n\t\t\t\tprivate graphHeight = 60 * window.devicePixelRatio,\n\t\t\t\tprivate graphWidth = 90 * window.devicePixelRatio,\n\t\t\t\tprivate graphTop = 0,\n\t\t\t\tprivate graphRight = 5 * window.devicePixelRatio,\n\t\t\t\tprivate width = 100 * window.devicePixelRatio) {\n\t}\n\n\tgetDefaultPosition(): Position {\n\t\treturn Position.TOP_RIGHT;\n\t}\n\n\tonAdd(map: MMap): HTMLElement {\n\t\tthis.map = map;\n\n\t\tconst el = (this.container = document.createElement('div'));\n\t\tel.className = 'maplibregl-ctrl maplibregl-ctrl-fps';\n\n\t\tel.style.backgroundColor = this.background;\n\t\tel.style.borderRadius = '6px';\n\n\t\tthis.readOutput = document.createElement('div');\n\t\tthis.readOutput.style.color = this.color;\n\t\tthis.readOutput.style.fontFamily = this.font;\n\t\tthis.readOutput.style.padding = '0 5px 5px';\n\t\tthis.readOutput.style.fontSize = '9px';\n\t\tthis.readOutput.style.fontWeight = 'bold';\n\t\tthis.readOutput.textContent = 'Waiting…';\n\n\t\tthis.canvas = document.createElement('canvas');\n\t\tthis.canvas.className = 'maplibregl-ctrl-canvas';\n\t\tthis.canvas.width = this.width;\n\t\tthis.canvas.height = this.graphHeight;\n\t\tthis.canvas.style.cssText = `width: ${this.width / window.devicePixelRatio}px; height: ${this.graphHeight / window.devicePixelRatio}px;`;\n\n\t\tel.appendChild(this.readOutput);\n\t\tel.appendChild(this.canvas);\n\n\t\tthis.eventHandlers.set('movestart', this.onMoveStart.bind(this));\n\t\tthis.eventHandlers.set('moveend', this.onMoveEnd.bind(this));\n\t\tthis.map.on('movestart', this.eventHandlers.get('movestart') as any);\n\t\tthis.map.on('moveend', this.eventHandlers.get('moveend') as any);\n\t\treturn this.container;\n\t}\n\n\tonRemove(): void {\n\t\tthis.map!.off('movestart', this.eventHandlers.get('movestart') as any);\n\t\tthis.map!.off('moveend', this.eventHandlers.get('moveend') as any);\n\t\tthis.eventHandlers.clear();\n\t\tthis.container!.parentNode!.removeChild(this.container!);\n\t\tthis.map = undefined;\n\t}\n\n\tonMoveStart() {\n\t\tthis.frames = 0;\n\t\tthis.time = performance.now();\n\t\tthis.eventHandlers.set('render', this.onRender.bind(this));\n\t\tthis.map!.on('render', this.eventHandlers.get('render') as any);\n\t}\n\n\tonMoveEnd() {\n\t\tconst now = performance.now();\n\t\tthis.updateGraph(this.getFPS(now));\n\t\tthis.frames = 0;\n\t\tthis.time = null;\n\t\tthis.map!.off('render', this.eventHandlers.get('render') as any);\n\t}\n\n\tonRender() {\n\t\tif (this.time) {\n\t\t\tthis.frames++;\n\t\t\tconst now = performance.now();\n\t\t\tif (now >= this.time + 1e3) {\n\t\t\t\tthis.updateGraph(this.getFPS(now));\n\t\t\t\tthis.frames = 0;\n\t\t\t\tthis.time = performance.now();\n\t\t\t}\n\t\t}\n\t}\n\n\tgetFPS(now: number) {\n\t\tthis.totalTime += now - this.time!;\n\t\tthis.totalFrames += this.frames;\n\t\treturn Math.round((1e3 * this.frames) / (now - this.time!)) || 0;\n\t}\n\n\tupdateGraph(fpsNow: number) {\n\t\tconst context = this.canvas!.getContext('2d')!;\n\t\tconst fps = Math.round((1e3 * this.totalFrames) / this.totalTime) || 0;\n\t\tconst rect = (this.graphHeight, this.barWidth);\n\n\t\tcontext.fillStyle = this.background;\n\t\tcontext.globalAlpha = 1;\n\t\tcontext.fillRect(0, 0, this.graphWidth, this.graphTop);\n\t\tcontext.fillStyle = this.color;\n\n\t\tthis.readOutput!.textContent = `${fpsNow} FPS (${fps} Avg)`;\n\t\tcontext.drawImage(\n\t\t\tthis.canvas!,\n\t\t\tthis.graphRight + rect,\n\t\t\tthis.graphTop,\n\t\t\tthis.graphWidth - rect,\n\t\t\tthis.graphHeight,\n\t\t\tthis.graphRight,\n\t\t\tthis.graphTop,\n\t\t\tthis.graphWidth - rect,\n\t\t\tthis.graphHeight\n\t\t);\n\t\tcontext.fillRect(\n\t\t\tthis.graphRight + this.graphWidth - rect,\n\t\t\tthis.graphTop,\n\t\t\trect,\n\t\t\tthis.graphHeight\n\t\t);\n\t\tcontext.fillStyle = this.background;\n\t\tcontext.globalAlpha = 0.75;\n\t\tcontext.fillRect(\n\t\t\tthis.graphRight + this.graphWidth - rect,\n\t\t\tthis.graphTop,\n\t\t\trect,\n\t\t\t(1 - fpsNow / 100) * this.graphHeight\n\t\t);\n\t}\n\n}\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglFrameRateControl',\n\tprops: {\n\t\tposition : {\n\t\t\ttype : String as PropType<PositionProp>,\n\t\t\tvalidator: (v: Position) => {\n\t\t\t\treturn PositionValues.indexOf(v) !== -1;\n\t\t\t}\n\t\t},\n\t\tbackground : {\n\t\t\ttype : String as PropType<string>,\n\t\t\tdefault: 'rgba(0,0,0,0.9)'\n\t\t},\n\t\tbarWidth : {\n\t\t\ttype : Number as PropType<number>,\n\t\t\tdefault: 4 * window.devicePixelRatio\n\t\t},\n\t\tcolor : {\n\t\t\ttype : String as PropType<string>,\n\t\t\tdefault: '#7cf859'\n\t\t},\n\t\tfont : {\n\t\t\ttype : String as PropType<string>,\n\t\t\tdefault: 'Monaco, Consolas, Courier, monospace'\n\t\t},\n\t\tgraphHeight: {\n\t\t\ttype : Number as PropType<number>,\n\t\t\tdefault: 60 * window.devicePixelRatio\n\t\t},\n\t\tgraphWidth : {\n\t\t\ttype : Number as PropType<number>,\n\t\t\tdefault: 90 * window.devicePixelRatio\n\t\t},\n\t\tgraphTop : {\n\t\t\ttype : Number as PropType<number>,\n\t\t\tdefault: 0\n\t\t},\n\t\tgraphRight : {\n\t\t\ttype : Number as PropType<number>,\n\t\t\tdefault: 5 * window.devicePixelRatio\n\t\t},\n\t\twidth : {\n\t\t\ttype : Number as PropType<number>,\n\t\t\tdefault: 100 * window.devicePixelRatio\n\t\t}\n\t},\n\tsetup(props) {\n\n\t\tconst map = inject(mapSymbol)!,\n\t\t\t isInitialized = inject(isInitializedSymbol)!,\n\t\t\t control = new FrameRateControl(\n\t\t\t\t props.background,\n\t\t\t\t props.barWidth,\n\t\t\t\t props.color,\n\t\t\t\t props.font,\n\t\t\t\t props.graphHeight,\n\t\t\t\t props.graphWidth,\n\t\t\t\t props.graphTop,\n\t\t\t\t props.graphRight,\n\t\t\t\t props.width\n\t\t\t );\n\n\t\tusePositionWatcher(() => props.position, map, control);\n\t\tonBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control));\n\n\t},\n\trender() {\n\t\t// nothing\n\t}\n});\n","import { Position, type PositionProp, PositionValues } from '@/components/controls/position.enum';\nimport { usePositionWatcher } from '@/composable/usePositionWatcher';\nimport { isInitializedSymbol, mapSymbol } from '@/types';\nimport { type FitBoundsOptions, GeolocateControl } from 'maplibre-gl';\nimport { defineComponent, inject, onBeforeUnmount, type PropType } from 'vue';\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglGeolocationControl',\n\tprops: {\n\t\tposition : {\n\t\t\ttype : String as PropType<PositionProp>,\n\t\t\tdefault : Position.TOP_RIGHT,\n\t\t\tvalidator: (v: Position) => {\n\t\t\t\treturn PositionValues.indexOf(v) !== -1;\n\t\t\t}\n\t\t},\n\t\tpositionOptions : {\n\t\t\ttype : Object as PropType<PositionOptions>,\n\t\t\tdefault: { enableHighAccuracy: false, timeout: 6000 } as PositionOptions\n\t\t},\n\t\tfitBoundsOptions : {\n\t\t\ttype : Object as PropType<FitBoundsOptions>,\n\t\t\tdefault: { maxZoom: 15 } as FitBoundsOptions\n\t\t},\n\t\ttrackUserLocation : {\n\t\t\ttype : Boolean as PropType<boolean>,\n\t\t\tdefault: false\n\t\t},\n\t\tshowAccuracyCircle: {\n\t\t\ttype : Boolean as PropType<boolean>,\n\t\t\tdefault: true\n\t\t},\n\t\tshowUserLocation : {\n\t\t\ttype : Boolean as PropType<boolean>,\n\t\t\tdefault: true\n\t\t}\n\t},\n\tsetup(props) {\n\n\t\tconst map = inject(mapSymbol)!,\n\t\t\t isInitialized = inject(isInitializedSymbol)!,\n\t\t\t control = new GeolocateControl({\n\t\t\t\t positionOptions : props.positionOptions,\n\t\t\t\t fitBoundsOptions : props.fitBoundsOptions,\n\t\t\t\t trackUserLocation : props.trackUserLocation,\n\t\t\t\t showAccuracyCircle: props.showAccuracyCircle,\n\t\t\t\t showUserLocation : props.showUserLocation\n\t\t\t });\n\n\t\tusePositionWatcher(() => props.position, map, control);\n\t\tonBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control));\n\n\t},\n\trender() {\n\t\t// nothing\n\t}\n});\n","import { Position, type PositionProp, PositionValues } from '@/components/controls/position.enum';\nimport { usePositionWatcher } from '@/composable/usePositionWatcher';\nimport { isInitializedSymbol, mapSymbol } from '@/types';\nimport { NavigationControl } from 'maplibre-gl';\nimport { defineComponent, inject, onBeforeUnmount, type PropType } from 'vue';\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglNavigationControl',\n\tprops: {\n\t\tposition : {\n\t\t\ttype : String as PropType<PositionProp>,\n\t\t\tdefault : Position.TOP_RIGHT,\n\t\t\tvalidator: (v: Position) => {\n\t\t\t\treturn PositionValues.indexOf(v) !== -1;\n\t\t\t}\n\t\t},\n\t\tshowCompass : { type: Boolean as PropType<boolean>, default: true },\n\t\tshowZoom : { type: Boolean as PropType<boolean>, default: true },\n\t\tvisualizePitch: Boolean as PropType<boolean>\n\t},\n\tsetup(props) {\n\n\t\tconst map = inject(mapSymbol)!,\n\t\t\t isInitialized = inject(isInitializedSymbol)!,\n\t\t\t control = new NavigationControl({ showCompass: props.showCompass, showZoom: props.showZoom, visualizePitch: props.visualizePitch });\n\n\t\tusePositionWatcher(() => props.position, map, control);\n\t\tonBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control));\n\n\t},\n\trender() {\n\t\t// nothing\n\t}\n});\n","import { Position, type PositionProp, PositionValues } from '@/components/controls/position.enum';\nimport { usePositionWatcher } from '@/composable/usePositionWatcher';\nimport { isInitializedSymbol, mapSymbol } from '@/types';\nimport { ScaleControl } from 'maplibre-gl';\nimport { defineComponent, inject, onBeforeUnmount, type PropType } from 'vue';\n\nexport enum ScaleControlUnit {\n\tIMPERIAL = 'imperial',\n\tMETRIC = 'metric',\n\tNAUTICAL = 'nautical'\n}\n\ntype UnitValue = ScaleControlUnit | 'imperial' | 'metric' | 'nautical';\nconst UnitValues = Object.values(ScaleControlUnit);\n\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglScaleControl',\n\tprops: {\n\t\tposition: {\n\t\t\ttype : String as PropType<PositionProp>,\n\t\t\tvalidator: (v: Position) => {\n\t\t\t\treturn PositionValues.indexOf(v) !== -1;\n\t\t\t}\n\t\t},\n\t\tmaxWidth: { type: Number as PropType<number>, default: 100 },\n\t\tunit : {\n\t\t\ttype : String as PropType<UnitValue>,\n\t\t\tdefault : ScaleControlUnit.METRIC,\n\t\t\tvalidator: (v: ScaleControlUnit) => {\n\t\t\t\treturn UnitValues.indexOf(v) !== -1;\n\t\t\t}\n\t\t}\n\t},\n\tsetup(props) {\n\n\t\tconst map = inject(mapSymbol)!,\n\t\t\t isInitialized = inject(isInitializedSymbol)!,\n\t\t\t control = new ScaleControl({ maxWidth: props.maxWidth, unit: props.unit });\n\n\t\tusePositionWatcher(() => props.position, map, control);\n\t\tonBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control));\n\n\t},\n\trender() {\n\t\t// nothing\n\t}\n});\n","import { MglButton } from '@/components';\nimport { ButtonType } from '@/components/button.component';\nimport { CustomControl } from '@/components/controls/custom.control';\nimport { Position, type PositionProp, PositionValues } from '@/components/controls/position.enum';\nimport { usePositionWatcher } from '@/composable/usePositionWatcher';\nimport { emitterSymbol, isInitializedSymbol, isLoadedSymbol, mapSymbol, type StyleSwitchItem } from '@/types';\nimport {\n\tcreateCommentVNode,\n\tcreateTextVNode,\n\tdefineComponent,\n\th,\n\tinject,\n\tonBeforeUnmount,\n\ttype PropType,\n\ttype Ref,\n\tref,\n\tshallowRef,\n\ttype SlotsType,\n\tTeleport,\n\twatch\n} from 'vue';\n\nfunction isEvent(e: any): e is Event {\n\treturn e && !!(e as Event).stopPropagation;\n}\n\ninterface SlotProps {\n\tisOpen: Ref<boolean>,\n\ttoggleOpen: (forceIsOpen?: boolean | Event, e?: Event) => void,\n\tsetStyle: (s: StyleSwitchItem) => void,\n\tmapStyles: StyleSwitchItem[],\n\tcurrentStyle: Ref<StyleSwitchItem | null>,\n}\n\nexport default /*#__PURE__*/ defineComponent({\n\tname : 'MglSt