@powerportalspro/react-maps 0.0.0-stage → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/maplibre-worker.ts","../src/core/styles.ts","../src/core/providers/basemaps.ts"],"names":[],"mappings":"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","file":"chunk-7HDK44TQ.js","sourcesContent":["// Kept apart from the MapLibre provider so setting it doesn't load MapLibre.\nlet workerUrl: string | (() => string | Promise<string>) | null = null;\n\n/**\n * Where MapLibre's worker script is served from. MapLibre 6 loads it as a file of its own, and a\n * bundled app has to say where its bundler put it — once, before a map is drawn:\n *\n * ```ts\n * // Vite\n * import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';\n * setMapLibreWorkerUrl(workerUrl);\n *\n * // webpack 5, rspack, Next.js\n * setMapLibreWorkerUrl(new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url).toString());\n * ```\n *\n * Calling MapLibre's own `setWorkerUrl` does the same. A function in place of the URL is called\n * when a MapLibre map is first drawn, so code that finds it — loading the worker's script, say —\n * runs only on a page that shows one.\n */\nexport function setMapLibreWorkerUrl(url: string | (() => string | Promise<string>)): void {\n workerUrl = url;\n finding = null;\n}\n\n// The function's answer, found once however many maps are drawn while it runs.\nlet finding: Promise<string> | null = null;\n\n/** The worker URL set, found now if a function was set; null when MapLibre is left to find it. */\nexport async function mapLibreWorkerUrl(): Promise<string | null> {\n if (typeof workerUrl !== 'function') return workerUrl;\n const find = workerUrl;\n finding ??= Promise.resolve().then(find);\n return await finding;\n}\n","// The map's own elements — pins, clusters, the popup's place — drawn with Fluent's tokens, so they\n// follow the portal's theme and accent on every provider. Hex values only as `var()` fallbacks, for\n// a page without Fluent's tokens.\nexport const MAP_CSS = `\n.ppp-map-host, .ppp-map-surface { position: absolute; inset: 0; }\n.ppp-map-marker {\n all: unset;\n box-sizing: content-box;\n display: block;\n width: 24px;\n height: 32px;\n cursor: pointer;\n filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));\n transition: transform 0.1s ease-out;\n transform-origin: 50% 100%;\n}\n.ppp-map-marker svg { display: block; }\n.ppp-map-marker .ppp-map-marker-pin {\n fill: var(--ppp-map-item-color);\n stroke: var(--colorNeutralBackground1, #ffffff);\n stroke-width: 1.5;\n}\n.ppp-map-marker .ppp-map-marker-dot { fill: var(--colorNeutralBackground1, #ffffff); }\n.ppp-map-marker[data-labeled] { position: relative; }\n.ppp-map-marker[data-labeled] .ppp-map-marker-dot { display: none; }\n.ppp-map-marker-label {\n position: absolute;\n left: 0;\n top: 1px;\n width: 24px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--colorNeutralForegroundOnBrand, #ffffff);\n font-family: var(--fontFamilyBase, 'Segoe UI', sans-serif);\n font-size: 11px;\n font-weight: var(--fontWeightBold, 700);\n line-height: 1;\n letter-spacing: -0.02em;\n pointer-events: none;\n}\n.ppp-map-marker-label[data-length=\"3\"] { font-size: 9px; }\n.ppp-map-marker-label[data-length=\"4\"] { font-size: 7.5px; }\n.ppp-map-marker-label[data-length=\"5\"] { font-size: 6px; }\n.ppp-map-marker:hover, .ppp-map-marker[data-selected] { transform: scale(1.2); }\n.ppp-map-marker:focus-visible { outline: none; }\n.ppp-map-marker:focus-visible .ppp-map-marker-pin {\n stroke: var(--colorStrokeFocus2, #000000);\n stroke-width: 2.5;\n}\n.ppp-map-cluster {\n all: unset;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 32px;\n height: 32px;\n padding: 0 var(--spacingHorizontalS, 8px);\n border-radius: var(--borderRadiusCircular, 10000px);\n border: var(--strokeWidthThick, 2px) solid var(--colorNeutralBackground1, #ffffff);\n background: var(--ppp-map-item-color, var(--colorBrandBackground, #0f6cbd));\n color: var(--colorNeutralForegroundOnBrand, #ffffff);\n font-family: var(--fontFamilyBase, 'Segoe UI', sans-serif);\n font-size: var(--fontSizeBase200, 12px);\n font-weight: var(--fontWeightSemibold, 600);\n line-height: 1;\n cursor: pointer;\n box-shadow: var(--shadow4, 0 1px 2px rgba(0, 0, 0, 0.3));\n transition: transform 0.1s ease-out;\n}\n.ppp-map-cluster[data-size=\"medium\"] { min-width: 38px; height: 38px; }\n.ppp-map-cluster[data-size=\"large\"] { min-width: 44px; height: 44px; font-size: var(--fontSizeBase300, 14px); }\n.ppp-map-cluster:hover { filter: brightness(0.92); transform: scale(1.08); }\n.ppp-map-cluster:focus-visible { outline: var(--strokeWidthThick, 2px) solid var(--colorStrokeFocus2, #000000); outline-offset: 1px; }\n.ppp-map-place {\n display: block;\n width: 24px;\n height: 32px;\n pointer-events: none;\n filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));\n}\n.ppp-map-place svg { display: block; }\n.ppp-map-place .ppp-map-marker-pin {\n fill: var(--colorPaletteRedBackground3, #d13438);\n stroke: var(--colorNeutralBackground1, #ffffff);\n stroke-width: 1.5;\n}\n.ppp-map-place .ppp-map-marker-dot { fill: var(--colorNeutralBackground1, #ffffff); }\n.ppp-map-search {\n position: absolute;\n top: 10px;\n left: 10px;\n z-index: 3;\n box-sizing: border-box;\n width: min(320px, calc(100% - 64px));\n font-family: var(--fontFamilyBase, 'Segoe UI', sans-serif);\n font-size: var(--fontSizeBase300, 14px);\n line-height: var(--lineHeightBase300, 20px);\n color: var(--colorNeutralForeground1, #242424);\n}\n.ppp-map-search-field {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--spacingHorizontalXS, 4px);\n box-sizing: border-box;\n height: 32px;\n padding: 0 var(--spacingHorizontalXS, 4px) 0 var(--spacingHorizontalS, 8px);\n background: var(--colorNeutralBackground1, #ffffff);\n border: var(--strokeWidthThin, 1px) solid var(--colorNeutralStroke1, #d1d1d1);\n border-bottom-color: var(--colorNeutralStrokeAccessible, #616161);\n border-radius: var(--borderRadiusMedium, 4px);\n box-shadow: var(--shadow4, 0 1px 2px rgba(0, 0, 0, 0.14));\n}\n.ppp-map-search-field::after {\n content: '';\n position: absolute;\n left: -1px;\n right: -1px;\n bottom: -1px;\n height: 2px;\n border-radius: 0 0 var(--borderRadiusMedium, 4px) var(--borderRadiusMedium, 4px);\n background: var(--colorCompoundBrandStroke, #0f6cbd);\n transform: scaleX(0);\n transition: transform 0.1s ease-out;\n}\n.ppp-map-search-field:focus-within::after { transform: scaleX(1); }\n.ppp-map-search-icon { display: flex; color: var(--colorNeutralForeground3, #616161); }\n.ppp-map-search-input {\n all: unset;\n flex: 1;\n min-width: 0;\n color: var(--colorNeutralForeground1, #242424);\n font: inherit;\n}\n.ppp-map-search-input::placeholder { color: var(--colorNeutralForeground4, #707070); opacity: 1; }\n.ppp-map-search-clear {\n all: unset;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n border-radius: var(--borderRadiusMedium, 4px);\n color: var(--colorNeutralForeground3, #616161);\n cursor: pointer;\n}\n.ppp-map-search-clear[hidden] { display: none; }\n.ppp-map-search-clear:hover { background: var(--colorSubtleBackgroundHover, #f5f5f5); color: var(--colorNeutralForeground1, #242424); }\n.ppp-map-search-clear:focus-visible { outline: var(--strokeWidthThick, 2px) solid var(--colorStrokeFocus2, #000000); }\n.ppp-map-search-panel {\n margin-top: var(--spacingVerticalXS, 4px);\n padding: var(--spacingVerticalXS, 4px);\n background: var(--colorNeutralBackground1, #ffffff);\n border-radius: var(--borderRadiusMedium, 4px);\n box-shadow: var(--shadow16, 0 6px 14px rgba(0, 0, 0, 0.14));\n max-height: 300px;\n overflow-y: auto;\n}\n.ppp-map-search-panel[hidden], .ppp-map-search-list[hidden], .ppp-map-search-status[hidden] { display: none; }\n.ppp-map-search-list { margin: 0; padding: 0; list-style: none; }\n.ppp-map-search-option {\n display: flex;\n flex-direction: column;\n padding: var(--spacingVerticalSNudge, 6px) var(--spacingHorizontalS, 8px);\n border-radius: var(--borderRadiusMedium, 4px);\n cursor: pointer;\n}\n.ppp-map-search-option:hover, .ppp-map-search-option[data-active] { background: var(--colorNeutralBackground1Hover, #f5f5f5); }\n.ppp-map-search-detail, .ppp-map-search-status {\n color: var(--colorNeutralForeground3, #616161);\n font-size: var(--fontSizeBase200, 12px);\n line-height: var(--lineHeightBase200, 16px);\n}\n.ppp-map-search-status { padding: var(--spacingVerticalSNudge, 6px) var(--spacingHorizontalS, 8px); }\n.ppp-map-search-status:empty { display: none; }\n.ppp-map-popup-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 2; }\n.ppp-map-popup-anchor { position: absolute; left: 0; top: 0; pointer-events: auto; }\n.ppp-map-popup-anchor[hidden] { display: none; }\n/* The print button over the top right corner, MapLibre's zoom buttons moved down beneath it. Its\n 10px matches the margin MapLibre gives its controls. */\n.ppp-map-print { position: absolute; top: 10px; right: 10px; z-index: 3; }\n.ppp-map-printable .maplibregl-ctrl-top-right { top: 38px; }\n.ppp-map-print-sheet { display: none; }\n/* A map printed as it is on the page — a provider whose map can't be copied into an image: only it\n and what is printed with it, every other element on the way to it left out. */\n@media print {\n html.ppp-map-printing [data-ppp-map-print-path] > :not([data-ppp-map-print-path]):not(.ppp-map-print-target):not(.ppp-map-print-sheet) {\n display: none !important;\n }\n html.ppp-map-printing [data-ppp-map-print-path] {\n display: block !important;\n position: static !important;\n margin: 0 !important;\n padding: 0 !important;\n border: 0 !important;\n width: auto !important;\n height: auto !important;\n min-height: 0 !important;\n max-height: none !important;\n overflow: visible !important;\n transform: none !important;\n box-shadow: none !important;\n background: none !important;\n }\n html.ppp-map-printing .ppp-map-print-target { break-inside: avoid; }\n html.ppp-map-printing .ppp-map-print-target :is(.ppp-map-print, .ppp-map-search, .ppp-map-popup-close) { display: none !important; }\n html.ppp-map-printing .ppp-map-print-target .ppp-map-popup { max-height: none !important; overflow: visible !important; }\n html.ppp-map-printing .ppp-map-print-sheet { display: block; }\n}\n`;\n\n/** Adds a stylesheet to the document once, by id. */\nexport function ensureStyleSheet(document: Document, id: string, css: string): void {\n if (document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n style.textContent = css;\n document.head.appendChild(style);\n}\n\n/** Adds the map's own stylesheet to the document once. */\nexport function ensureMapStyles(document: Document): void {\n ensureStyleSheet(document, 'ppp-map-styles', MAP_CSS);\n}\n","import type { MapOptions } from 'maplibre-gl';\nimport type {\n AzureMapsAccessToken,\n AzureMapsSettings,\n EsriSettings,\n MapLibreSettings,\n OpenStreetMapSettings,\n} from '../provider.js';\nimport type { MapStyle } from '../types.js';\n\n/** A MapLibre style document: MapLibre takes one, or its URL, but doesn't export its type. */\nexport type StyleSpecification = Exclude<NonNullable<MapOptions['style']>, string>;\n\n/** A base map MapLibre draws: its style, and what requests to its provider need. */\nexport interface Basemap {\n style: StyleSpecification | string;\n /** Attribution shown with the style's own, as HTML: what the provider's terms ask for. */\n attribution?: string;\n /** The Azure Maps tilesets drawn, whose attribution is asked for as the view moves. */\n azureTilesets?: string[];\n}\n\nexport const OPEN_STREET_MAP_TILES = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';\nexport const OPEN_STREET_MAP_ATTRIBUTION =\n '&copy; <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\" rel=\"noopener\">OpenStreetMap</a> contributors';\n\nexport const AZURE_MAPS_ENDPOINT = 'https://atlas.microsoft.com';\nexport const AZURE_MAPS_API_VERSION = '2024-04-01';\n\nexport const ESRI_STYLES_ENDPOINT = 'https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles';\nexport const ESRI_ATTRIBUTION = 'Powered by <a href=\"https://www.esri.com/\" target=\"_blank\" rel=\"noopener\">Esri</a>';\n\n/**\n * Raster tiles drawn darker for a dark theme, for tiles that have no dark style of their own:\n * lightness turned around (brightness from 1 down to 0) and hue turned back, so water stays blue.\n */\nconst DARKENED_RASTER = {\n 'raster-brightness-min': 0.92,\n 'raster-brightness-max': 0.08,\n 'raster-hue-rotate': 180,\n 'raster-saturation': -0.35,\n 'raster-contrast': 0.1,\n} as const;\n\n/** A style of raster tile layers, one source each, drawn in order. */\nexport function rasterStyle(\n layers: readonly { tiles: string; attribution?: string; maxZoom?: number; darken?: boolean }[],\n): StyleSpecification {\n const style: StyleSpecification = { version: 8, sources: {}, layers: [] };\n layers.forEach((layer, index) => {\n const id = `ppp-base-${index}`;\n style.sources[id] = {\n type: 'raster',\n tiles: [layer.tiles],\n tileSize: 256,\n ...(layer.attribution ? { attribution: layer.attribution } : {}),\n ...(layer.maxZoom !== undefined ? { maxzoom: layer.maxZoom } : {}),\n };\n style.layers.push({ id, type: 'raster', source: id, ...(layer.darken ? { paint: { ...DARKENED_RASTER } } : {}) });\n });\n return style;\n}\n\n/** OpenStreetMap's tiles, or the ones `tileUrl` names; darkened in a dark theme, as they have no dark style. */\nexport function openStreetMapBasemap(settings: OpenStreetMapSettings, dark: boolean): Basemap {\n return {\n style: rasterStyle([\n {\n tiles: settings.tileUrl || OPEN_STREET_MAP_TILES,\n attribution: settings.attribution || (settings.tileUrl ? '' : OPEN_STREET_MAP_ATTRIBUTION),\n maxZoom: 19,\n darken: dark,\n },\n ]),\n };\n}\n\n/** The Azure Maps raster tilesets for a style: its road or dark gray style, imagery, or both. */\nexport function azureMapsTilesets(style: MapStyle, dark: boolean): string[] {\n switch (style) {\n case 'satellite':\n return ['microsoft.imagery'];\n case 'hybrid':\n return ['microsoft.imagery', dark ? 'microsoft.base.hybrid.darkgrey' : 'microsoft.base.hybrid.road'];\n default:\n return [dark ? 'microsoft.base.darkgrey' : 'microsoft.base.road'];\n }\n}\n\n/** An Azure Maps tile URL template for a tileset, in the viewer's language. */\nexport function azureMapsTileUrl(tilesetId: string, language: string, view: string | undefined): string {\n const query = new URLSearchParams({\n 'api-version': AZURE_MAPS_API_VERSION,\n tilesetId,\n tileSize: '256',\n language,\n view: view || 'Auto',\n });\n // The placeholders stay as they are, for MapLibre to fill in per tile.\n return `${AZURE_MAPS_ENDPOINT}/map/tile?${query}&zoom={z}&x={x}&y={y}`;\n}\n\nexport function azureMapsBasemap(settings: AzureMapsSettings, style: MapStyle, dark: boolean, language: string): Basemap {\n const tilesets = azureMapsTilesets(style, dark);\n return {\n style: rasterStyle(\n tilesets.map((tileset) => ({\n tiles: azureMapsTileUrl(tileset, language, settings.view),\n maxZoom: tileset === 'microsoft.imagery' ? 19 : 22,\n })),\n ),\n azureTilesets: tilesets,\n };\n}\n\n/** The headers that sign a request to Azure Maps in with the portal's token; null before there is one. */\nexport function azureMapsHeaders(token: AzureMapsAccessToken | null): Record<string, string> | null {\n return token ? { Authorization: `Bearer ${token.accessToken}`, 'x-ms-client-id': token.clientId } : null;\n}\n\n/** The ArcGIS basemap style for a map style: the road style (or its dark one), imagery, or imagery with labels. */\nexport function esriStyleName(settings: EsriSettings, style: MapStyle, dark: boolean): string {\n switch (style) {\n case 'satellite':\n return 'arcgis/imagery/standard';\n case 'hybrid':\n return 'arcgis/imagery';\n default:\n return dark ? settings.darkStyleName || 'arcgis/dark-gray' : settings.styleName || 'arcgis/streets';\n }\n}\n\n// The languages the ArcGIS basemap styles take by more than their two letters.\nconst ESRI_REGIONAL_LANGUAGES = new Set(['pt-BR', 'pt-PT', 'zh-CN', 'zh-HK', 'zh-TW']);\n\n/** The ArcGIS language code for a culture: its two letters, or the culture for those it tells apart. */\nexport function esriLanguage(culture: string): string {\n const match = [...ESRI_REGIONAL_LANGUAGES].find((language) => language.toLowerCase() === culture.toLowerCase());\n return match ?? culture.split('-')[0]!.toLowerCase();\n}\n\nexport function esriBasemap(settings: EsriSettings, apiKey: string, style: MapStyle, dark: boolean, language: string): Basemap {\n const query = new URLSearchParams({ token: apiKey, language: esriLanguage(language) });\n return {\n style: `${ESRI_STYLES_ENDPOINT}/${esriStyleName(settings, style, dark)}?${query}`,\n attribution: ESRI_ATTRIBUTION,\n };\n}\n\n/**\n * A request to ArcGIS carrying the key: the style's own URLs usually do already, and one that\n * doesn't — a sprite or font on another of its hosts — gets it added.\n */\nexport function withEsriToken(url: string, apiKey: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return url;\n }\n if (!/(^|\\.)arcgis(online)?\\.com$/i.test(parsed.hostname) || parsed.searchParams.has('token')) return url;\n // Added to the text rather than through the URL, which would escape a template's braces.\n const [path, hash] = url.split('#', 2) as [string, string | undefined];\n return `${path}${path.includes('?') ? '&' : '?'}token=${encodeURIComponent(apiKey)}${hash === undefined ? '' : `#${hash}`}`;\n}\n\n/** The style a MapLibre provider names for a map style, or its raster tiles. */\nexport function mapLibreBasemap(settings: MapLibreSettings, style: MapStyle, dark: boolean): Basemap {\n const satellite = settings.satelliteStyleUrl;\n const url =\n style === 'hybrid'\n ? settings.hybridStyleUrl || satellite\n : style === 'satellite'\n ? satellite\n : dark\n ? settings.darkStyleUrl\n : undefined;\n\n const styleUrl = url || settings.styleUrl;\n if (styleUrl) return { style: styleUrl };\n\n if (!settings.tileUrl) throw new Error('A mapLibre provider needs a styleUrl or a tileUrl.');\n return {\n style: rasterStyle([\n {\n tiles: settings.tileUrl,\n ...(settings.attribution ? { attribution: settings.attribution } : {}),\n maxZoom: settings.maxZoom ?? 19,\n darken: dark,\n },\n ]),\n };\n}\n"]}
@@ -0,0 +1,238 @@
1
+ // src/core/geo.ts
2
+ var EARTH_RADIUS = 63710088e-1;
3
+ function isValidPosition(position) {
4
+ return !!position && Number.isFinite(position.latitude) && Number.isFinite(position.longitude) && Math.abs(position.latitude) <= 90 && Math.abs(position.longitude) <= 180;
5
+ }
6
+ function wrapLongitude(longitude) {
7
+ const wrapped = ((longitude + 180) % 360 + 360) % 360 - 180;
8
+ return wrapped === -180 && longitude > 0 ? 180 : wrapped;
9
+ }
10
+ function destination(origin, distance, bearing) {
11
+ const angular = distance / EARTH_RADIUS;
12
+ const theta = bearing * Math.PI / 180;
13
+ const phi1 = origin.latitude * Math.PI / 180;
14
+ const lambda1 = origin.longitude * Math.PI / 180;
15
+ const sinPhi2 = Math.sin(phi1) * Math.cos(angular) + Math.cos(phi1) * Math.sin(angular) * Math.cos(theta);
16
+ const phi2 = Math.asin(Math.max(-1, Math.min(1, sinPhi2)));
17
+ const lambda2 = lambda1 + Math.atan2(Math.sin(theta) * Math.sin(angular) * Math.cos(phi1), Math.cos(angular) - Math.sin(phi1) * sinPhi2);
18
+ return { latitude: phi2 * 180 / Math.PI, longitude: wrapLongitude(lambda2 * 180 / Math.PI) };
19
+ }
20
+ function circlePath(center, radius, steps = 64) {
21
+ const path = [];
22
+ for (let step = 0; step < steps; step++) {
23
+ path.push(destination(center, radius, step * 360 / steps));
24
+ }
25
+ path.push(path[0]);
26
+ return path;
27
+ }
28
+ function itemPositions(item) {
29
+ switch (item.kind) {
30
+ case "marker":
31
+ return [item.position];
32
+ case "polyline":
33
+ case "polygon":
34
+ return [...item.path];
35
+ case "circle":
36
+ return [0, 90, 180, 270].map((bearing) => destination(item.center, item.radius, bearing));
37
+ }
38
+ }
39
+ function boundsOf(positions) {
40
+ let bounds = null;
41
+ for (const position of positions) {
42
+ if (!isValidPosition(position)) continue;
43
+ if (!bounds) {
44
+ bounds = { north: position.latitude, south: position.latitude, east: position.longitude, west: position.longitude };
45
+ continue;
46
+ }
47
+ bounds.north = Math.max(bounds.north, position.latitude);
48
+ bounds.south = Math.min(bounds.south, position.latitude);
49
+ bounds.east = Math.max(bounds.east, position.longitude);
50
+ bounds.west = Math.min(bounds.west, position.longitude);
51
+ }
52
+ return bounds;
53
+ }
54
+ function boundsOfItems(items) {
55
+ return boundsOf(
56
+ (function* () {
57
+ for (const item of items) yield* itemPositions(item);
58
+ })()
59
+ );
60
+ }
61
+ function toBoundingBox(bounds) {
62
+ const south = Math.max(-90, bounds.south);
63
+ const north = Math.min(90, bounds.north);
64
+ if (bounds.east - bounds.west >= 360) return [-180, south, 180, north];
65
+ return [wrapLongitude(bounds.west), south, wrapLongitude(bounds.east), north];
66
+ }
67
+ function boundsContain(bounds, position) {
68
+ if (position.latitude < bounds.south || position.latitude > bounds.north) return false;
69
+ const [west, , east] = toBoundingBox(bounds);
70
+ const longitude = wrapLongitude(position.longitude);
71
+ return west <= east ? longitude >= west && longitude <= east : longitude >= west || longitude <= east;
72
+ }
73
+ function padBounds(bounds, ratio) {
74
+ const height = bounds.north - bounds.south;
75
+ const width = bounds.east - bounds.west;
76
+ return {
77
+ north: Math.min(90, bounds.north + height * ratio),
78
+ south: Math.max(-90, bounds.south - height * ratio),
79
+ east: bounds.east + width * ratio,
80
+ west: bounds.west - width * ratio
81
+ };
82
+ }
83
+ function approximateBounds(center, zoom, width, height) {
84
+ const size = 256 * 2 ** zoom;
85
+ const x = (center.longitude + 180) / 360 * size;
86
+ const sin = Math.sin(Math.max(-85.0511, Math.min(85.0511, center.latitude)) * Math.PI / 180);
87
+ const y = (0.5 - Math.log((1 + sin) / (1 - sin)) / (4 * Math.PI)) * size;
88
+ const latitudeAt = (pixelY) => {
89
+ const n = Math.PI - 2 * Math.PI * Math.max(0, Math.min(size, pixelY)) / size;
90
+ return Math.atan(Math.sinh(n)) * 180 / Math.PI;
91
+ };
92
+ const longitudeAt = (pixelX) => pixelX / size * 360 - 180;
93
+ return {
94
+ north: latitudeAt(y - height / 2),
95
+ south: latitudeAt(y + height / 2),
96
+ east: longitudeAt(x + width / 2),
97
+ west: longitudeAt(x - width / 2)
98
+ };
99
+ }
100
+
101
+ // src/core/geocoders.ts
102
+ var SUGGESTION_COUNT = 5;
103
+ var AZURE_MAPS_GEOCODE_API_VERSION = "2025-01-01";
104
+ var ESRI_GEOCODE_ENDPOINT = "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer";
105
+ var NOMINATIM_URL = "https://nominatim.openstreetmap.org";
106
+ function splitLabel(label) {
107
+ const comma = label.indexOf(", ");
108
+ return comma < 0 ? { text: label } : { text: label.slice(0, comma), detail: label.slice(comma + 2) };
109
+ }
110
+ var FoundPlaces = class {
111
+ next = 0;
112
+ places = /* @__PURE__ */ new Map();
113
+ add(place) {
114
+ if (this.places.size > 50) this.places.clear();
115
+ const id = `${++this.next}`;
116
+ this.places.set(id, place);
117
+ return { id, ...splitLabel(place.label) };
118
+ }
119
+ get(suggestion) {
120
+ return this.places.get(suggestion.id) ?? null;
121
+ }
122
+ };
123
+ async function readJson(response, provider) {
124
+ if (!response.ok) throw new Error(`${provider}'s search answered ${response.status} ${response.statusText}.`.trim());
125
+ return await response.json();
126
+ }
127
+ var toBounds = (west, south, east, north) => [west, south, east, north].every(Number.isFinite) && (west !== east || south !== north) ? { north, south, east, west } : void 0;
128
+ var inCountries = (countries, code) => countries.length === 0 || !!code && countries.some((country) => country.toLowerCase() === code.toLowerCase());
129
+ function azureMapsGeocoder(endpoint, headers, view, fetcher = fetch) {
130
+ const found = new FoundPlaces();
131
+ return {
132
+ suggestsAsYouType: true,
133
+ async suggest({ text, view: mapView, countries, language, signal }) {
134
+ const signIn = headers();
135
+ if (!signIn) throw new Error("Azure Maps has no token to search with yet.");
136
+ const query = new URLSearchParams({
137
+ "api-version": AZURE_MAPS_GEOCODE_API_VERSION,
138
+ query: text,
139
+ top: `${countries.length ? 20 : SUGGESTION_COUNT}`,
140
+ coordinates: `${mapView.center.longitude},${mapView.center.latitude}`,
141
+ view: view || "Auto"
142
+ });
143
+ const response = await fetcher(`${endpoint}/geocode?${query}`, {
144
+ headers: { ...signIn, "Accept-Language": language },
145
+ ...signal ? { signal } : {}
146
+ });
147
+ const answer = await readJson(response, "Azure Maps");
148
+ const suggestions = [];
149
+ for (const feature of answer.features ?? []) {
150
+ const [longitude, latitude] = feature.geometry?.coordinates ?? [];
151
+ const label = feature.properties?.address?.formattedAddress;
152
+ if (longitude === void 0 || latitude === void 0 || !label) continue;
153
+ if (!inCountries(countries, feature.properties?.address?.countryRegion?.ISO)) continue;
154
+ const [west, south, east, north] = feature.bbox ?? [];
155
+ const bounds = feature.bbox?.length === 4 ? toBounds(west, south, east, north) : void 0;
156
+ suggestions.push(found.add({ label, position: { latitude, longitude }, ...bounds ? { bounds } : {} }));
157
+ }
158
+ return suggestions.slice(0, SUGGESTION_COUNT);
159
+ },
160
+ resolve: async (suggestion) => found.get(suggestion)
161
+ };
162
+ }
163
+ function esriAnswer(answer) {
164
+ if (answer.error) throw new Error(`Esri's search refused the request: ${answer.error.message ?? answer.error.code}.`);
165
+ return answer;
166
+ }
167
+ function esriGeocoder(apiKey, endpoint = ESRI_GEOCODE_ENDPOINT, fetcher = fetch) {
168
+ const magicKeys = /* @__PURE__ */ new Map();
169
+ let next = 0;
170
+ return {
171
+ suggestsAsYouType: true,
172
+ async suggest({ text, view, countries, language, signal }) {
173
+ const query = new URLSearchParams({
174
+ f: "json",
175
+ text,
176
+ location: `${view.center.longitude},${view.center.latitude}`,
177
+ maxSuggestions: `${SUGGESTION_COUNT}`,
178
+ langCode: language,
179
+ token: apiKey,
180
+ ...countries.length ? { countryCode: countries.join(",") } : {}
181
+ });
182
+ const response = await fetcher(`${endpoint}/suggest?${query}`, signal ? { signal } : {});
183
+ const answer = esriAnswer(await readJson(response, "Esri"));
184
+ if (magicKeys.size > 50) magicKeys.clear();
185
+ return (answer.suggestions ?? []).flatMap((suggestion) => {
186
+ if (!suggestion.text || !suggestion.magicKey) return [];
187
+ const id = `${++next}`;
188
+ magicKeys.set(id, suggestion.magicKey);
189
+ return [{ id, ...splitLabel(suggestion.text) }];
190
+ });
191
+ },
192
+ async resolve(suggestion, signal) {
193
+ const magicKey = magicKeys.get(suggestion.id);
194
+ if (!magicKey) return null;
195
+ const label = suggestion.detail ? `${suggestion.text}, ${suggestion.detail}` : suggestion.text;
196
+ const query = new URLSearchParams({ f: "json", SingleLine: label, magicKey, maxLocations: "1", token: apiKey });
197
+ const response = await fetcher(`${endpoint}/findAddressCandidates?${query}`, signal ? { signal } : {});
198
+ const candidate = esriAnswer(await readJson(response, "Esri")).candidates?.[0];
199
+ const { x: longitude, y: latitude } = candidate?.location ?? {};
200
+ if (longitude === void 0 || latitude === void 0) return null;
201
+ const extent = candidate?.extent;
202
+ const bounds = extent ? toBounds(extent.xmin, extent.ymin, extent.xmax, extent.ymax) : void 0;
203
+ return { label: candidate?.address || label, position: { latitude, longitude }, ...bounds ? { bounds } : {} };
204
+ }
205
+ };
206
+ }
207
+ function nominatimGeocoder(url = NOMINATIM_URL, fetcher = fetch) {
208
+ const found = new FoundPlaces();
209
+ return {
210
+ suggestsAsYouType: false,
211
+ async suggest({ text, view, countries, language, signal }) {
212
+ const { north, south, east, west } = view.bounds;
213
+ const query = new URLSearchParams({
214
+ q: text,
215
+ format: "jsonv2",
216
+ limit: `${SUGGESTION_COUNT}`,
217
+ "accept-language": language,
218
+ viewbox: `${west},${north},${east},${south}`,
219
+ ...countries.length ? { countrycodes: countries.join(",").toLowerCase() } : {}
220
+ });
221
+ const response = await fetcher(`${url.replace(/\/+$/, "")}/search?${query}`, signal ? { signal } : {});
222
+ const places = await readJson(response, "Nominatim");
223
+ return places.flatMap((place) => {
224
+ const latitude = Number(place.lat);
225
+ const longitude = Number(place.lon);
226
+ if (!place.display_name || !Number.isFinite(latitude) || !Number.isFinite(longitude)) return [];
227
+ const [boxSouth, boxNorth, boxWest, boxEast] = (place.boundingbox ?? []).map(Number);
228
+ const bounds = place.boundingbox?.length === 4 ? toBounds(boxWest, boxSouth, boxEast, boxNorth) : void 0;
229
+ return [found.add({ label: place.display_name, position: { latitude, longitude }, ...bounds ? { bounds } : {} })];
230
+ });
231
+ },
232
+ resolve: async (suggestion) => found.get(suggestion)
233
+ };
234
+ }
235
+
236
+ export { SUGGESTION_COUNT, approximateBounds, azureMapsGeocoder, boundsContain, boundsOfItems, circlePath, esriGeocoder, isValidPosition, nominatimGeocoder, padBounds, toBoundingBox };
237
+ //# sourceMappingURL=chunk-G723VLPV.js.map
238
+ //# sourceMappingURL=chunk-G723VLPV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/geo.ts","../src/core/geocoders.ts"],"names":[],"mappings":";AAGA,IAAM,YAAA,GAAe,WAAA;AAGd,SAAS,gBAAgB,QAAA,EAAmE;AACjG,EAAA,OACE,CAAC,CAAC,QAAA,IACF,MAAA,CAAO,SAAS,QAAA,CAAS,QAAQ,CAAA,IACjC,MAAA,CAAO,QAAA,CAAS,QAAA,CAAS,SAAS,CAAA,IAClC,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,IAAK,MAC/B,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA,IAAK,GAAA;AAEpC;AAGO,SAAS,cAAc,SAAA,EAA2B;AACvD,EAAA,MAAM,OAAA,GAAA,CAAA,CAAc,SAAA,GAAY,GAAA,IAAO,GAAA,GAAO,OAAO,GAAA,GAAO,GAAA;AAC5D,EAAA,OAAO,OAAA,KAAY,IAAA,IAAQ,SAAA,GAAY,CAAA,GAAI,GAAA,GAAM,OAAA;AACnD;AAMO,SAAS,WAAA,CAAY,MAAA,EAAqB,QAAA,EAAkB,OAAA,EAA8B;AAC/F,EAAA,MAAM,UAAU,QAAA,GAAW,YAAA;AAC3B,EAAA,MAAM,KAAA,GAAS,OAAA,GAAU,IAAA,CAAK,EAAA,GAAM,GAAA;AACpC,EAAA,MAAM,IAAA,GAAQ,MAAA,CAAO,QAAA,GAAW,IAAA,CAAK,EAAA,GAAM,GAAA;AAC3C,EAAA,MAAM,OAAA,GAAW,MAAA,CAAO,SAAA,GAAY,IAAA,CAAK,EAAA,GAAM,GAAA;AAE/C,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,GAAI,IAAA,CAAK,IAAI,OAAO,CAAA,GAAI,KAAK,GAAA,CAAI,IAAI,IAAI,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,GAAI,IAAA,CAAK,IAAI,KAAK,CAAA;AACxG,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAC,CAAC,CAAA;AACzD,EAAA,MAAM,OAAA,GACJ,OAAA,GACA,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,IAAI,KAAK,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,GAAI,KAAK,GAAA,CAAI,IAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,OAAO,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,GAAI,OAAO,CAAA;AAE/G,EAAA,OAAO,EAAE,QAAA,EAAW,IAAA,GAAO,GAAA,GAAO,IAAA,CAAK,EAAA,EAAI,SAAA,EAAW,aAAA,CAAe,OAAA,GAAU,GAAA,GAAO,IAAA,CAAK,EAAE,CAAA,EAAE;AACjG;AAGO,SAAS,UAAA,CAAW,MAAA,EAAqB,MAAA,EAAgB,KAAA,GAAQ,EAAA,EAAmB;AACzF,EAAA,MAAM,OAAsB,EAAC;AAC7B,EAAA,KAAA,IAAS,IAAA,GAAO,CAAA,EAAG,IAAA,GAAO,KAAA,EAAO,IAAA,EAAA,EAAQ;AACvC,IAAA,IAAA,CAAK,KAAK,WAAA,CAAY,MAAA,EAAQ,QAAS,IAAA,GAAO,GAAA,GAAO,KAAK,CAAC,CAAA;AAAA,EAC7D;AACA,EAAA,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,CAAC,CAAE,CAAA;AAClB,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,cAAc,IAAA,EAA8B;AAC1D,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,QAAA;AACH,MAAA,OAAO,CAAC,KAAK,QAAQ,CAAA;AAAA,IACvB,KAAK,UAAA;AAAA,IACL,KAAK,SAAA;AACH,MAAA,OAAO,CAAC,GAAG,IAAA,CAAK,IAAI,CAAA;AAAA,IACtB,KAAK,QAAA;AACH,MAAA,OAAO,CAAC,CAAA,EAAG,EAAA,EAAI,GAAA,EAAK,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,OAAA,KAAY,YAAY,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,OAAO,CAAC,CAAA;AAAA;AAE9F;AAGO,SAAS,SAAS,SAAA,EAAoD;AAC3E,EAAA,IAAI,MAAA,GAA2B,IAAA;AAC/B,EAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,IAAA,IAAI,CAAC,eAAA,CAAgB,QAAQ,CAAA,EAAG;AAChC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAA,GAAS,EAAE,KAAA,EAAO,QAAA,CAAS,QAAA,EAAU,KAAA,EAAO,QAAA,CAAS,QAAA,EAAU,IAAA,EAAM,QAAA,CAAS,SAAA,EAAW,IAAA,EAAM,QAAA,CAAS,SAAA,EAAU;AAClH,MAAA;AAAA,IACF;AACA,IAAA,MAAA,CAAO,QAAQ,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,SAAS,QAAQ,CAAA;AACvD,IAAA,MAAA,CAAO,QAAQ,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,SAAS,QAAQ,CAAA;AACvD,IAAA,MAAA,CAAO,OAAO,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,SAAS,SAAS,CAAA;AACtD,IAAA,MAAA,CAAO,OAAO,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,IAAA,EAAM,SAAS,SAAS,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,cAAc,KAAA,EAA4C;AACxE,EAAA,OAAO,QAAA;AAAA,IAAA,CACJ,aAAa;AACZ,MAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,OAAO,aAAA,CAAc,IAAI,CAAA;AAAA,IACrD,CAAA;AAAG,GACL;AACF;AAMO,SAAS,cAAc,MAAA,EAAqD;AACjF,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,OAAO,KAAK,CAAA;AACxC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,OAAO,KAAK,CAAA;AACvC,EAAA,IAAI,MAAA,CAAO,IAAA,GAAO,MAAA,CAAO,IAAA,IAAQ,GAAA,SAAY,CAAC,IAAA,EAAM,KAAA,EAAO,GAAA,EAAK,KAAK,CAAA;AACrE,EAAA,OAAO,CAAC,aAAA,CAAc,MAAA,CAAO,IAAI,CAAA,EAAG,OAAO,aAAA,CAAc,MAAA,CAAO,IAAI,CAAA,EAAG,KAAK,CAAA;AAC9E;AAGO,SAAS,aAAA,CAAc,QAAmB,QAAA,EAAgC;AAC/E,EAAA,IAAI,QAAA,CAAS,WAAW,MAAA,CAAO,KAAA,IAAS,SAAS,QAAA,GAAW,MAAA,CAAO,OAAO,OAAO,KAAA;AACjF,EAAA,MAAM,CAAC,IAAA,IAAQ,IAAI,CAAA,GAAI,cAAc,MAAM,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,QAAA,CAAS,SAAS,CAAA;AAClD,EAAA,OAAO,IAAA,IAAQ,OAAO,SAAA,IAAa,IAAA,IAAQ,aAAa,IAAA,GAAO,SAAA,IAAa,QAAQ,SAAA,IAAa,IAAA;AACnG;AAGO,SAAS,SAAA,CAAU,QAAmB,KAAA,EAA0B;AACrE,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,GAAQ,MAAA,CAAO,KAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,GAAO,MAAA,CAAO,IAAA;AACnC,EAAA,OAAO;AAAA,IACL,OAAO,IAAA,CAAK,GAAA,CAAI,IAAI,MAAA,CAAO,KAAA,GAAQ,SAAS,KAAK,CAAA;AAAA,IACjD,OAAO,IAAA,CAAK,GAAA,CAAI,KAAK,MAAA,CAAO,KAAA,GAAQ,SAAS,KAAK,CAAA;AAAA,IAClD,IAAA,EAAM,MAAA,CAAO,IAAA,GAAO,KAAA,GAAQ,KAAA;AAAA,IAC5B,IAAA,EAAM,MAAA,CAAO,IAAA,GAAO,KAAA,GAAQ;AAAA,GAC9B;AACF;AAMO,SAAS,iBAAA,CAAkB,MAAA,EAAqB,IAAA,EAAc,KAAA,EAAe,MAAA,EAA2B;AAC7G,EAAA,MAAM,IAAA,GAAO,MAAM,CAAA,IAAK,IAAA;AACxB,EAAA,MAAM,CAAA,GAAA,CAAM,MAAA,CAAO,SAAA,GAAY,GAAA,IAAO,GAAA,GAAO,IAAA;AAC7C,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAK,IAAA,CAAK,IAAI,QAAA,EAAU,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,OAAO,QAAQ,CAAC,CAAA,GAAI,IAAA,CAAK,KAAM,GAAG,CAAA;AAC7F,EAAA,MAAM,CAAA,GAAA,CAAK,GAAA,GAAM,IAAA,CAAK,GAAA,CAAA,CAAK,CAAA,GAAI,GAAA,KAAQ,CAAA,GAAI,GAAA,CAAI,CAAA,IAAK,CAAA,GAAI,IAAA,CAAK,EAAA,CAAA,IAAO,IAAA;AAEpE,EAAA,MAAM,UAAA,GAAa,CAAC,MAAA,KAAmB;AACrC,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,EAAA,GAAM,CAAA,GAAI,KAAK,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,MAAM,CAAC,CAAA,GAAK,IAAA;AAC1E,IAAA,OAAQ,IAAA,CAAK,KAAK,IAAA,CAAK,IAAA,CAAK,CAAC,CAAC,CAAA,GAAI,MAAO,IAAA,CAAK,EAAA;AAAA,EAChD,CAAA;AACA,EAAA,MAAM,WAAA,GAAc,CAAC,MAAA,KAAoB,MAAA,GAAS,OAAQ,GAAA,GAAM,GAAA;AAEhE,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,UAAA,CAAW,CAAA,GAAI,MAAA,GAAS,CAAC,CAAA;AAAA,IAChC,KAAA,EAAO,UAAA,CAAW,CAAA,GAAI,MAAA,GAAS,CAAC,CAAA;AAAA,IAChC,IAAA,EAAM,WAAA,CAAY,CAAA,GAAI,KAAA,GAAQ,CAAC,CAAA;AAAA,IAC/B,IAAA,EAAM,WAAA,CAAY,CAAA,GAAI,KAAA,GAAQ,CAAC;AAAA,GACjC;AACF;;;AC3IO,IAAM,gBAAA,GAAmB;AAEzB,IAAM,8BAAA,GAAiC,YAAA;AACvC,IAAM,qBAAA,GAAwB,yEAAA;AAC9B,IAAM,aAAA,GAAgB,qCAAA;AAQtB,SAAS,WAAW,KAAA,EAA8D;AACvF,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAChC,EAAA,OAAO,QAAQ,CAAA,GAAI,EAAE,MAAM,KAAA,EAAM,GAAI,EAAE,IAAA,EAAM,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,EAAG,MAAA,EAAQ,MAAM,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,EAAE;AACrG;AAMA,IAAM,cAAN,MAAkB;AAAA,EACR,IAAA,GAAO,CAAA;AAAA,EACE,MAAA,uBAAa,GAAA,EAAsB;AAAA,EAEpD,IAAI,KAAA,EAAuC;AACzC,IAAA,IAAI,KAAK,MAAA,CAAO,IAAA,GAAO,EAAA,EAAI,IAAA,CAAK,OAAO,KAAA,EAAM;AAC7C,IAAA,MAAM,EAAA,GAAK,CAAA,EAAG,EAAE,IAAA,CAAK,IAAI,CAAA,CAAA;AACzB,IAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAA,EAAI,KAAK,CAAA;AACzB,IAAA,OAAO,EAAE,EAAA,EAAI,GAAG,UAAA,CAAW,KAAA,CAAM,KAAK,CAAA,EAAE;AAAA,EAC1C;AAAA,EAEA,IAAI,UAAA,EAAmD;AACrD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,EAAE,CAAA,IAAK,IAAA;AAAA,EAC3C;AACF,CAAA;AAEA,eAAe,QAAA,CAAY,UAAoB,QAAA,EAA8B;AAC3E,EAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,MAAM,IAAI,MAAM,CAAA,EAAG,QAAQ,CAAA,mBAAA,EAAsB,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,UAAU,CAAA,CAAA,CAAA,CAAI,MAAM,CAAA;AACnH,EAAA,OAAQ,MAAM,SAAS,IAAA,EAAK;AAC9B;AAEA,IAAM,QAAA,GAAW,CAAC,IAAA,EAAc,KAAA,EAAe,IAAA,EAAc,UAC3D,CAAC,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,KAAK,CAAA,CAAE,MAAM,MAAA,CAAO,QAAQ,CAAA,KAAM,IAAA,KAAS,IAAA,IAAQ,KAAA,KAAU,KAAA,CAAA,GAAS,EAAE,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,IAAA,EAAK,GAAI,MAAA;AAE3H,IAAM,cAAc,CAAC,SAAA,EAA8B,SACjD,SAAA,CAAU,MAAA,KAAW,KAAM,CAAC,CAAC,QAAQ,SAAA,CAAU,IAAA,CAAK,CAAC,OAAA,KAAY,OAAA,CAAQ,aAAY,KAAM,IAAA,CAAK,aAAa,CAAA;AAgBxG,SAAS,iBAAA,CACd,QAAA,EACA,OAAA,EACA,IAAA,EACA,UAAiB,KAAA,EACJ;AACb,EAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY;AAC9B,EAAA,OAAO;AAAA,IACL,iBAAA,EAAmB,IAAA;AAAA,IACnB,MAAM,QAAQ,EAAE,IAAA,EAAM,MAAM,OAAA,EAAS,SAAA,EAAW,QAAA,EAAU,MAAA,EAAO,EAAoB;AACnF,MAAA,MAAM,SAAS,OAAA,EAAQ;AACvB,MAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,6CAA6C,CAAA;AAC1E,MAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,CAAgB;AAAA,QAChC,aAAA,EAAe,8BAAA;AAAA,QACf,KAAA,EAAO,IAAA;AAAA,QACP,GAAA,EAAK,CAAA,EAAG,SAAA,CAAU,MAAA,GAAS,KAAK,gBAAgB,CAAA,CAAA;AAAA,QAChD,WAAA,EAAa,GAAG,OAAA,CAAQ,MAAA,CAAO,SAAS,CAAA,CAAA,EAAI,OAAA,CAAQ,OAAO,QAAQ,CAAA,CAAA;AAAA,QACnE,MAAM,IAAA,IAAQ;AAAA,OACf,CAAA;AACD,MAAA,MAAM,WAAW,MAAM,OAAA,CAAQ,GAAG,QAAQ,CAAA,SAAA,EAAY,KAAK,CAAA,CAAA,EAAI;AAAA,QAC7D,OAAA,EAAS,EAAE,GAAG,MAAA,EAAQ,mBAAmB,QAAA,EAAS;AAAA,QAClD,GAAI,MAAA,GAAS,EAAE,MAAA,KAAW;AAAC,OAC5B,CAAA;AACD,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAA+B,QAAA,EAAU,YAAY,CAAA;AAC1E,MAAA,MAAM,cAAsC,EAAC;AAC7C,MAAA,KAAA,MAAW,OAAA,IAAW,MAAA,CAAO,QAAA,IAAY,EAAC,EAAG;AAC3C,QAAA,MAAM,CAAC,SAAA,EAAW,QAAQ,IAAI,OAAA,CAAQ,QAAA,EAAU,eAAe,EAAC;AAChE,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,UAAA,EAAY,OAAA,EAAS,gBAAA;AAC3C,QAAA,IAAI,SAAA,KAAc,MAAA,IAAa,QAAA,KAAa,MAAA,IAAa,CAAC,KAAA,EAAO;AACjE,QAAA,IAAI,CAAC,YAAY,SAAA,EAAW,OAAA,CAAQ,YAAY,OAAA,EAAS,aAAA,EAAe,GAAG,CAAA,EAAG;AAC9E,QAAA,MAAM,CAAC,MAAM,KAAA,EAAO,IAAA,EAAM,KAAK,CAAA,GAAI,OAAA,CAAQ,QAAQ,EAAC;AACpD,QAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,IAAA,EAAM,MAAA,KAAW,CAAA,GAAI,SAAS,IAAA,EAAO,KAAA,EAAQ,IAAA,EAAO,KAAM,CAAA,GAAI,MAAA;AACrF,QAAA,WAAA,CAAY,KAAK,KAAA,CAAM,GAAA,CAAI,EAAE,KAAA,EAAO,QAAA,EAAU,EAAE,QAAA,EAAU,SAAA,EAAU,EAAG,GAAI,SAAS,EAAE,MAAA,KAAW,EAAC,EAAI,CAAC,CAAA;AAAA,MACzG;AACA,MAAA,OAAO,WAAA,CAAY,KAAA,CAAM,CAAA,EAAG,gBAAgB,CAAA;AAAA,IAC9C,CAAA;AAAA,IACA,OAAA,EAAS,OAAO,UAAA,KAAe,KAAA,CAAM,IAAI,UAAU;AAAA,GACrD;AACF;AAqBA,SAAS,WAAgC,MAAA,EAAc;AACrD,EAAA,IAAI,MAAA,CAAO,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,MAAA,CAAO,KAAA,CAAM,OAAA,IAAW,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,CAAA,CAAG,CAAA;AACpH,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,YAAA,CAAa,MAAA,EAAgB,QAAA,GAAmB,qBAAA,EAAuB,UAAiB,KAAA,EAAoB;AAC1H,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAoB;AAC1C,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,OAAO;AAAA,IACL,iBAAA,EAAmB,IAAA;AAAA,IACnB,MAAM,QAAQ,EAAE,IAAA,EAAM,MAAM,SAAA,EAAW,QAAA,EAAU,QAAO,EAAoB;AAC1E,MAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,CAAgB;AAAA,QAChC,CAAA,EAAG,MAAA;AAAA,QACH,IAAA;AAAA,QACA,QAAA,EAAU,GAAG,IAAA,CAAK,MAAA,CAAO,SAAS,CAAA,CAAA,EAAI,IAAA,CAAK,OAAO,QAAQ,CAAA,CAAA;AAAA,QAC1D,cAAA,EAAgB,GAAG,gBAAgB,CAAA,CAAA;AAAA,QACnC,QAAA,EAAU,QAAA;AAAA,QACV,KAAA,EAAO,MAAA;AAAA,QACP,GAAI,SAAA,CAAU,MAAA,GAAS,EAAE,WAAA,EAAa,UAAU,IAAA,CAAK,GAAG,CAAA,EAAE,GAAI;AAAC,OAChE,CAAA;AACD,MAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,CAAA,EAAG,QAAQ,CAAA,SAAA,EAAY,KAAK,CAAA,CAAA,EAAI,MAAA,GAAS,EAAE,MAAA,EAAO,GAAI,EAAE,CAAA;AACvF,MAAA,MAAM,SAAS,UAAA,CAAW,MAAM,QAAA,CAA8B,QAAA,EAAU,MAAM,CAAC,CAAA;AAC/E,MAAA,IAAI,SAAA,CAAU,IAAA,GAAO,EAAA,EAAI,SAAA,CAAU,KAAA,EAAM;AACzC,MAAA,OAAA,CAAQ,OAAO,WAAA,IAAe,EAAC,EAAG,OAAA,CAAQ,CAAC,UAAA,KAAe;AACxD,QAAA,IAAI,CAAC,UAAA,CAAW,IAAA,IAAQ,CAAC,UAAA,CAAW,QAAA,SAAiB,EAAC;AACtD,QAAA,MAAM,EAAA,GAAK,CAAA,EAAG,EAAE,IAAI,CAAA,CAAA;AACpB,QAAA,SAAA,CAAU,GAAA,CAAI,EAAA,EAAI,UAAA,CAAW,QAAQ,CAAA;AACrC,QAAA,OAAO,CAAC,EAAE,EAAA,EAAI,GAAG,WAAW,UAAA,CAAW,IAAI,GAAG,CAAA;AAAA,MAChD,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,MAAM,OAAA,CAAQ,UAAA,EAAY,MAAA,EAAQ;AAChC,MAAA,MAAM,QAAA,GAAW,SAAA,CAAU,GAAA,CAAI,UAAA,CAAW,EAAE,CAAA;AAC5C,MAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,MAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,MAAA,GAAS,CAAA,EAAG,UAAA,CAAW,IAAI,CAAA,EAAA,EAAK,UAAA,CAAW,MAAM,CAAA,CAAA,GAAK,UAAA,CAAW,IAAA;AAC1F,MAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,CAAgB,EAAE,CAAA,EAAG,MAAA,EAAQ,UAAA,EAAY,KAAA,EAAO,QAAA,EAAU,YAAA,EAAc,GAAA,EAAK,KAAA,EAAO,QAAQ,CAAA;AAC9G,MAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,CAAA,EAAG,QAAQ,CAAA,uBAAA,EAA0B,KAAK,CAAA,CAAA,EAAI,MAAA,GAAS,EAAE,MAAA,EAAO,GAAI,EAAE,CAAA;AACrG,MAAA,MAAM,SAAA,GAAY,WAAW,MAAM,QAAA,CAAiC,UAAU,MAAM,CAAC,CAAA,CAAE,UAAA,GAAa,CAAC,CAAA;AACrG,MAAA,MAAM,EAAE,GAAG,SAAA,EAAW,CAAA,EAAG,UAAS,GAAI,SAAA,EAAW,YAAY,EAAC;AAC9D,MAAA,IAAI,SAAA,KAAc,MAAA,IAAa,QAAA,KAAa,MAAA,EAAW,OAAO,IAAA;AAC9D,MAAA,MAAM,SAAS,SAAA,EAAW,MAAA;AAC1B,MAAA,MAAM,MAAA,GAAS,MAAA,GAAS,QAAA,CAAS,MAAA,CAAO,IAAA,EAAO,MAAA,CAAO,IAAA,EAAO,MAAA,CAAO,IAAA,EAAO,MAAA,CAAO,IAAK,CAAA,GAAI,MAAA;AAC3F,MAAA,OAAO,EAAE,KAAA,EAAO,SAAA,EAAW,OAAA,IAAW,KAAA,EAAO,UAAU,EAAE,QAAA,EAAU,SAAA,EAAU,EAAG,GAAI,MAAA,GAAS,EAAE,MAAA,EAAO,GAAI,EAAC,EAAG;AAAA,IAChH;AAAA,GACF;AACF;AAgBO,SAAS,iBAAA,CAAkB,GAAA,GAAc,aAAA,EAAe,OAAA,GAAiB,KAAA,EAAoB;AAClG,EAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY;AAC9B,EAAA,OAAO;AAAA,IACL,iBAAA,EAAmB,KAAA;AAAA,IACnB,MAAM,QAAQ,EAAE,IAAA,EAAM,MAAM,SAAA,EAAW,QAAA,EAAU,QAAO,EAAoB;AAC1E,MAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,IAAA,KAAS,IAAA,CAAK,MAAA;AAC1C,MAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,CAAgB;AAAA,QAChC,CAAA,EAAG,IAAA;AAAA,QACH,MAAA,EAAQ,QAAA;AAAA,QACR,KAAA,EAAO,GAAG,gBAAgB,CAAA,CAAA;AAAA,QAC1B,iBAAA,EAAmB,QAAA;AAAA,QACnB,OAAA,EAAS,GAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,IAAI,IAAI,KAAK,CAAA,CAAA;AAAA,QAC1C,GAAI,SAAA,CAAU,MAAA,GAAS,EAAE,YAAA,EAAc,SAAA,CAAU,IAAA,CAAK,GAAG,CAAA,CAAE,WAAA,EAAY,EAAE,GAAI;AAAC,OAC/E,CAAA;AACD,MAAA,MAAM,WAAW,MAAM,OAAA,CAAQ,CAAA,EAAG,GAAA,CAAI,QAAQ,MAAA,EAAQ,EAAE,CAAC,CAAA,QAAA,EAAW,KAAK,CAAA,CAAA,EAAI,MAAA,GAAS,EAAE,MAAA,EAAO,GAAI,EAAE,CAAA;AACrG,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAA2B,QAAA,EAAU,WAAW,CAAA;AACrE,MAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC/B,QAAA,MAAM,QAAA,GAAW,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AACjC,QAAA,MAAM,SAAA,GAAY,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAClC,QAAA,IAAI,CAAC,KAAA,CAAM,YAAA,IAAgB,CAAC,OAAO,QAAA,CAAS,QAAQ,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,SAAS,CAAA,SAAU,EAAC;AAC9F,QAAA,MAAM,CAAC,QAAA,EAAU,QAAA,EAAU,OAAA,EAAS,OAAO,CAAA,GAAA,CAAK,KAAA,CAAM,WAAA,IAAe,EAAC,EAAG,GAAA,CAAI,MAAM,CAAA;AACnF,QAAA,MAAM,MAAA,GAAS,KAAA,CAAM,WAAA,EAAa,MAAA,KAAW,CAAA,GAAI,SAAS,OAAA,EAAU,QAAA,EAAW,OAAA,EAAU,QAAS,CAAA,GAAI,MAAA;AACtG,QAAA,OAAO,CAAC,MAAM,GAAA,CAAI,EAAE,OAAO,KAAA,CAAM,YAAA,EAAc,UAAU,EAAE,QAAA,EAAU,WAAU,EAAG,GAAI,SAAS,EAAE,MAAA,KAAW,EAAC,EAAI,CAAC,CAAA;AAAA,MACpH,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,OAAA,EAAS,OAAO,UAAA,KAAe,KAAA,CAAM,IAAI,UAAU;AAAA,GACrD;AACF","file":"chunk-G723VLPV.js","sourcesContent":["import type { MapBounds, MapItem, MapPosition } from './types.js';\n\n/** The mean radius of the Earth in meters, as WGS84 distances on the map are measured. */\nconst EARTH_RADIUS = 6_371_008.8;\n\n/** Whether a latitude and longitude are numbers on the globe. */\nexport function isValidPosition(position: MapPosition | null | undefined): position is MapPosition {\n return (\n !!position &&\n Number.isFinite(position.latitude) &&\n Number.isFinite(position.longitude) &&\n Math.abs(position.latitude) <= 90 &&\n Math.abs(position.longitude) <= 180\n );\n}\n\n/** A longitude brought into -180 to 180, as a map that wraps around the world reports past them. */\nexport function wrapLongitude(longitude: number): number {\n const wrapped = ((((longitude + 180) % 360) + 360) % 360) - 180;\n return wrapped === -180 && longitude > 0 ? 180 : wrapped;\n}\n\n/**\n * The position `distance` meters from `origin` on `bearing` degrees from north: a point on a\n * great circle, so a circle drawn from these is round on the ground at any latitude.\n */\nexport function destination(origin: MapPosition, distance: number, bearing: number): MapPosition {\n const angular = distance / EARTH_RADIUS;\n const theta = (bearing * Math.PI) / 180;\n const phi1 = (origin.latitude * Math.PI) / 180;\n const lambda1 = (origin.longitude * Math.PI) / 180;\n\n const sinPhi2 = Math.sin(phi1) * Math.cos(angular) + Math.cos(phi1) * Math.sin(angular) * Math.cos(theta);\n const phi2 = Math.asin(Math.max(-1, Math.min(1, sinPhi2)));\n const lambda2 =\n lambda1 +\n Math.atan2(Math.sin(theta) * Math.sin(angular) * Math.cos(phi1), Math.cos(angular) - Math.sin(phi1) * sinPhi2);\n\n return { latitude: (phi2 * 180) / Math.PI, longitude: wrapLongitude((lambda2 * 180) / Math.PI) };\n}\n\n/** A circle on the ground as a closed ring of `steps` points, for a provider that draws no circles. */\nexport function circlePath(center: MapPosition, radius: number, steps = 64): MapPosition[] {\n const path: MapPosition[] = [];\n for (let step = 0; step < steps; step++) {\n path.push(destination(center, radius, (step * 360) / steps));\n }\n path.push(path[0]!);\n return path;\n}\n\n/** The positions an item covers: a marker's own, a line's or area's path, a circle's extremes. */\nexport function itemPositions(item: MapItem): MapPosition[] {\n switch (item.kind) {\n case 'marker':\n return [item.position];\n case 'polyline':\n case 'polygon':\n return [...item.path];\n case 'circle':\n return [0, 90, 180, 270].map((bearing) => destination(item.center, item.radius, bearing));\n }\n}\n\n/** The smallest bounds holding every position, or null for none. Never across the antimeridian. */\nexport function boundsOf(positions: Iterable<MapPosition>): MapBounds | null {\n let bounds: MapBounds | null = null;\n for (const position of positions) {\n if (!isValidPosition(position)) continue;\n if (!bounds) {\n bounds = { north: position.latitude, south: position.latitude, east: position.longitude, west: position.longitude };\n continue;\n }\n bounds.north = Math.max(bounds.north, position.latitude);\n bounds.south = Math.min(bounds.south, position.latitude);\n bounds.east = Math.max(bounds.east, position.longitude);\n bounds.west = Math.min(bounds.west, position.longitude);\n }\n return bounds;\n}\n\n/** The bounds of every item's positions, or null when none has any. */\nexport function boundsOfItems(items: Iterable<MapItem>): MapBounds | null {\n return boundsOf(\n (function* () {\n for (const item of items) yield* itemPositions(item);\n })(),\n );\n}\n\n/**\n * Bounds as `[west, south, east, north]`, the box a cluster index is asked for: longitudes in\n * -180 to 180, the whole width when the view spans the world.\n */\nexport function toBoundingBox(bounds: MapBounds): [number, number, number, number] {\n const south = Math.max(-90, bounds.south);\n const north = Math.min(90, bounds.north);\n if (bounds.east - bounds.west >= 360) return [-180, south, 180, north];\n return [wrapLongitude(bounds.west), south, wrapLongitude(bounds.east), north];\n}\n\n/** Whether `bounds` contains `position`, across the antimeridian when `west` is east of `east`. */\nexport function boundsContain(bounds: MapBounds, position: MapPosition): boolean {\n if (position.latitude < bounds.south || position.latitude > bounds.north) return false;\n const [west, , east] = toBoundingBox(bounds);\n const longitude = wrapLongitude(position.longitude);\n return west <= east ? longitude >= west && longitude <= east : longitude >= west || longitude <= east;\n}\n\n/** Bounds grown by a share of their size on every side: what is about to scroll into view. */\nexport function padBounds(bounds: MapBounds, ratio: number): MapBounds {\n const height = bounds.north - bounds.south;\n const width = bounds.east - bounds.west;\n return {\n north: Math.min(90, bounds.north + height * ratio),\n south: Math.max(-90, bounds.south - height * ratio),\n east: bounds.east + width * ratio,\n west: bounds.west - width * ratio,\n };\n}\n\n/**\n * The bounds a view of `width` by `height` CSS pixels shows around `center` at `zoom` (on\n * 256-pixel tiles), in Web Mercator: for a provider that can't report its bounds yet.\n */\nexport function approximateBounds(center: MapPosition, zoom: number, width: number, height: number): MapBounds {\n const size = 256 * 2 ** zoom;\n const x = ((center.longitude + 180) / 360) * size;\n const sin = Math.sin((Math.max(-85.0511, Math.min(85.0511, center.latitude)) * Math.PI) / 180);\n const y = (0.5 - Math.log((1 + sin) / (1 - sin)) / (4 * Math.PI)) * size;\n\n const latitudeAt = (pixelY: number) => {\n const n = Math.PI - (2 * Math.PI * Math.max(0, Math.min(size, pixelY))) / size;\n return (Math.atan(Math.sinh(n)) * 180) / Math.PI;\n };\n const longitudeAt = (pixelX: number) => (pixelX / size) * 360 - 180;\n\n return {\n north: latitudeAt(y - height / 2),\n south: latitudeAt(y + height / 2),\n east: longitudeAt(x + width / 2),\n west: longitudeAt(x - width / 2),\n };\n}\n","import type { MapAddressQuery, MapGeocoder } from './provider.js';\nimport type { MapAddressSuggestion, MapBounds, MapPlace } from './types.js';\n\n/** How many places a search suggests. */\nexport const SUGGESTION_COUNT = 5;\n\nexport const AZURE_MAPS_GEOCODE_API_VERSION = '2025-01-01';\nexport const ESRI_GEOCODE_ENDPOINT = 'https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer';\nexport const NOMINATIM_URL = 'https://nominatim.openstreetmap.org';\n\ntype Fetch = typeof fetch;\n\n/**\n * A place's label as two lines: its first part — the street address, the place's name — and the\n * rest, where it is.\n */\nexport function splitLabel(label: string): Pick<MapAddressSuggestion, 'text' | 'detail'> {\n const comma = label.indexOf(', ');\n return comma < 0 ? { text: label } : { text: label.slice(0, comma), detail: label.slice(comma + 2) };\n}\n\n/**\n * The places a geocoder suggested, by suggestion id, for the one chosen: those of its latest\n * searches, as a list chosen from may be one search behind the one being typed.\n */\nclass FoundPlaces {\n private next = 0;\n private readonly places = new Map<string, MapPlace>();\n\n add(place: MapPlace): MapAddressSuggestion {\n if (this.places.size > 50) this.places.clear();\n const id = `${++this.next}`;\n this.places.set(id, place);\n return { id, ...splitLabel(place.label) };\n }\n\n get(suggestion: MapAddressSuggestion): MapPlace | null {\n return this.places.get(suggestion.id) ?? null;\n }\n}\n\nasync function readJson<T>(response: Response, provider: string): Promise<T> {\n if (!response.ok) throw new Error(`${provider}'s search answered ${response.status} ${response.statusText}.`.trim());\n return (await response.json()) as T;\n}\n\nconst toBounds = (west: number, south: number, east: number, north: number): MapBounds | undefined =>\n [west, south, east, north].every(Number.isFinite) && (west !== east || south !== north) ? { north, south, east, west } : undefined;\n\nconst inCountries = (countries: readonly string[], code: string | undefined) =>\n countries.length === 0 || (!!code && countries.some((country) => country.toLowerCase() === code.toLowerCase()));\n\n// ---- Azure Maps ----\n\ninterface AzureGeocodeResponse {\n features?: {\n bbox?: number[];\n geometry?: { coordinates?: number[] };\n properties?: { address?: { formattedAddress?: string; countryRegion?: { ISO?: string } } };\n }[];\n}\n\n/**\n * Azure Maps' Geocoding API, signed in with the portal's token as its tiles are. It takes no country\n * with free text, so the places it finds are kept to the countries asked for here.\n */\nexport function azureMapsGeocoder(\n endpoint: string,\n headers: () => Record<string, string> | null,\n view: string | undefined,\n fetcher: Fetch = fetch,\n): MapGeocoder {\n const found = new FoundPlaces();\n return {\n suggestsAsYouType: true,\n async suggest({ text, view: mapView, countries, language, signal }: MapAddressQuery) {\n const signIn = headers();\n if (!signIn) throw new Error('Azure Maps has no token to search with yet.');\n const query = new URLSearchParams({\n 'api-version': AZURE_MAPS_GEOCODE_API_VERSION,\n query: text,\n top: `${countries.length ? 20 : SUGGESTION_COUNT}`,\n coordinates: `${mapView.center.longitude},${mapView.center.latitude}`,\n view: view || 'Auto',\n });\n const response = await fetcher(`${endpoint}/geocode?${query}`, {\n headers: { ...signIn, 'Accept-Language': language },\n ...(signal ? { signal } : {}),\n });\n const answer = await readJson<AzureGeocodeResponse>(response, 'Azure Maps');\n const suggestions: MapAddressSuggestion[] = [];\n for (const feature of answer.features ?? []) {\n const [longitude, latitude] = feature.geometry?.coordinates ?? [];\n const label = feature.properties?.address?.formattedAddress;\n if (longitude === undefined || latitude === undefined || !label) continue;\n if (!inCountries(countries, feature.properties?.address?.countryRegion?.ISO)) continue;\n const [west, south, east, north] = feature.bbox ?? [];\n const bounds = feature.bbox?.length === 4 ? toBounds(west!, south!, east!, north!) : undefined;\n suggestions.push(found.add({ label, position: { latitude, longitude }, ...(bounds ? { bounds } : {}) }));\n }\n return suggestions.slice(0, SUGGESTION_COUNT);\n },\n resolve: async (suggestion) => found.get(suggestion),\n };\n}\n\n// ---- Esri ----\n\ninterface EsriError {\n error?: { code?: number; message?: string };\n}\n\ninterface EsriSuggestResponse extends EsriError {\n suggestions?: { text?: string; magicKey?: string }[];\n}\n\ninterface EsriCandidatesResponse extends EsriError {\n candidates?: {\n address?: string;\n location?: { x?: number; y?: number };\n extent?: { xmin?: number; ymin?: number; xmax?: number; ymax?: number };\n }[];\n}\n\n// ArcGIS answers a refused key or a bad request with an error in a 200.\nfunction esriAnswer<T extends EsriError>(answer: T): T {\n if (answer.error) throw new Error(`Esri's search refused the request: ${answer.error.message ?? answer.error.code}.`);\n return answer;\n}\n\n/** The ArcGIS geocoding service, with the portal's key, which needs its geocoding privilege. */\nexport function esriGeocoder(apiKey: string, endpoint: string = ESRI_GEOCODE_ENDPOINT, fetcher: Fetch = fetch): MapGeocoder {\n const magicKeys = new Map<string, string>();\n let next = 0;\n return {\n suggestsAsYouType: true,\n async suggest({ text, view, countries, language, signal }: MapAddressQuery) {\n const query = new URLSearchParams({\n f: 'json',\n text,\n location: `${view.center.longitude},${view.center.latitude}`,\n maxSuggestions: `${SUGGESTION_COUNT}`,\n langCode: language,\n token: apiKey,\n ...(countries.length ? { countryCode: countries.join(',') } : {}),\n });\n const response = await fetcher(`${endpoint}/suggest?${query}`, signal ? { signal } : {});\n const answer = esriAnswer(await readJson<EsriSuggestResponse>(response, 'Esri'));\n if (magicKeys.size > 50) magicKeys.clear();\n return (answer.suggestions ?? []).flatMap((suggestion) => {\n if (!suggestion.text || !suggestion.magicKey) return [];\n const id = `${++next}`;\n magicKeys.set(id, suggestion.magicKey);\n return [{ id, ...splitLabel(suggestion.text) }];\n });\n },\n async resolve(suggestion, signal) {\n const magicKey = magicKeys.get(suggestion.id);\n if (!magicKey) return null;\n const label = suggestion.detail ? `${suggestion.text}, ${suggestion.detail}` : suggestion.text;\n const query = new URLSearchParams({ f: 'json', SingleLine: label, magicKey, maxLocations: '1', token: apiKey });\n const response = await fetcher(`${endpoint}/findAddressCandidates?${query}`, signal ? { signal } : {});\n const candidate = esriAnswer(await readJson<EsriCandidatesResponse>(response, 'Esri')).candidates?.[0];\n const { x: longitude, y: latitude } = candidate?.location ?? {};\n if (longitude === undefined || latitude === undefined) return null;\n const extent = candidate?.extent;\n const bounds = extent ? toBounds(extent.xmin!, extent.ymin!, extent.xmax!, extent.ymax!) : undefined;\n return { label: candidate?.address || label, position: { latitude, longitude }, ...(bounds ? { bounds } : {}) };\n },\n };\n}\n\n// ---- Nominatim ----\n\ninterface NominatimPlace {\n display_name?: string;\n lat?: string;\n lon?: string;\n /** South, north, west, east. */\n boundingbox?: string[];\n}\n\n/**\n * A Nominatim server: OpenStreetMap's own unless the portal names another. OpenStreetMap's usage\n * policy rules out searching as the viewer types, so this one searches when they press Enter.\n */\nexport function nominatimGeocoder(url: string = NOMINATIM_URL, fetcher: Fetch = fetch): MapGeocoder {\n const found = new FoundPlaces();\n return {\n suggestsAsYouType: false,\n async suggest({ text, view, countries, language, signal }: MapAddressQuery) {\n const { north, south, east, west } = view.bounds;\n const query = new URLSearchParams({\n q: text,\n format: 'jsonv2',\n limit: `${SUGGESTION_COUNT}`,\n 'accept-language': language,\n viewbox: `${west},${north},${east},${south}`,\n ...(countries.length ? { countrycodes: countries.join(',').toLowerCase() } : {}),\n });\n const response = await fetcher(`${url.replace(/\\/+$/, '')}/search?${query}`, signal ? { signal } : {});\n const places = await readJson<NominatimPlace[]>(response, 'Nominatim');\n return places.flatMap((place) => {\n const latitude = Number(place.lat);\n const longitude = Number(place.lon);\n if (!place.display_name || !Number.isFinite(latitude) || !Number.isFinite(longitude)) return [];\n const [boxSouth, boxNorth, boxWest, boxEast] = (place.boundingbox ?? []).map(Number);\n const bounds = place.boundingbox?.length === 4 ? toBounds(boxWest!, boxSouth!, boxEast!, boxNorth!) : undefined;\n return [found.add({ label: place.display_name, position: { latitude, longitude }, ...(bounds ? { bounds } : {}) })];\n });\n },\n resolve: async (suggestion) => found.get(suggestion),\n };\n}\n"]}
@@ -0,0 +1,293 @@
1
+ import { approximateBounds, SUGGESTION_COUNT } from './chunk-G723VLPV.js';
2
+
3
+ // src/core/providers/google.ts
4
+ var CALLBACK = "__pppGoogleMapsLoaded";
5
+ var SHARED = /* @__PURE__ */ Symbol.for("powerportalspro.maps.google");
6
+ function shared() {
7
+ return globalThis[SHARED] ??= { loading: null, authFailureListeners: /* @__PURE__ */ new Set() };
8
+ }
9
+ function loadGoogleMaps(apiKey, language, document2) {
10
+ const global = globalThis;
11
+ if (typeof global.google?.maps?.importLibrary === "function") return Promise.resolve();
12
+ const state = shared();
13
+ state.loading ??= new Promise((resolve, reject) => {
14
+ const previousFailure = global.gm_authFailure;
15
+ global.gm_authFailure = () => {
16
+ previousFailure?.();
17
+ for (const listener of state.authFailureListeners) listener();
18
+ };
19
+ global[CALLBACK] = () => resolve();
20
+ const query = new URLSearchParams({ key: apiKey, v: "weekly", loading: "async", callback: CALLBACK, language });
21
+ const script = document2.createElement("script");
22
+ script.src = `https://maps.googleapis.com/maps/api/js?${query}`;
23
+ script.async = true;
24
+ script.onerror = () => {
25
+ state.loading = null;
26
+ script.remove();
27
+ reject(new Error("Google Maps' script could not be loaded."));
28
+ };
29
+ document2.head.appendChild(script);
30
+ });
31
+ return state.loading;
32
+ }
33
+ var MAP_TYPES = { road: "roadmap", satellite: "satellite", hybrid: "hybrid" };
34
+ var googleProvider = {
35
+ name: "google",
36
+ async create(context) {
37
+ if (!context.settings.apiKey) throw new Error("Google Maps needs the portal's API key: PowerPortalsPro:Maps:Google:ApiKey.");
38
+ await loadGoogleMaps(context.settings.apiKey, context.language, context.container.ownerDocument);
39
+ const [maps, core] = await Promise.all([
40
+ google.maps.importLibrary("maps"),
41
+ google.maps.importLibrary("core")
42
+ ]);
43
+ return new GoogleSurface(context, maps, core);
44
+ }
45
+ };
46
+ var GoogleSurface = class {
47
+ constructor(context, maps, core) {
48
+ this.context = context;
49
+ this.maps = maps;
50
+ this.core = core;
51
+ this.style = context.style;
52
+ this.dark = context.dark;
53
+ this.map = new maps.Map(context.container, {
54
+ center: toLatLngLiteral(context.camera.center),
55
+ zoom: context.camera.zoom,
56
+ mapTypeId: MAP_TYPES[context.style],
57
+ // Google's dark scheme can only be chosen as the map is made: the map is made again when the
58
+ // portal's theme changes (setStyle returns false).
59
+ colorScheme: context.dark ? "DARK" : "LIGHT",
60
+ ...context.settings.mapId ? { mapId: context.settings.mapId } : {},
61
+ // The map's style is the page's to choose, and a place's own card would cover the popup.
62
+ mapTypeControl: false,
63
+ streetViewControl: false,
64
+ fullscreenControl: false,
65
+ clickableIcons: false,
66
+ // Last, so the host's own options win: Street View, its controls, gesture handling.
67
+ ...context.nativeOptions
68
+ });
69
+ this.layer = createElementLayer(
70
+ maps,
71
+ () => this.viewKey() === this.idleView ? context.events.redrawn() : context.events.viewChanging()
72
+ );
73
+ this.layer.setMap(this.map);
74
+ const events = context.events;
75
+ this.listeners.push(
76
+ this.map.addListener("click", (event) => {
77
+ if (!event.latLng) return;
78
+ const position = fromLatLng(event.latLng);
79
+ events.click(position, this.project(position));
80
+ }),
81
+ this.map.addListener("bounds_changed", () => events.viewChanging()),
82
+ this.map.addListener("idle", () => {
83
+ this.idleView = this.viewKey();
84
+ events.viewChanged();
85
+ })
86
+ );
87
+ this.onAuthFailure = () => events.error("Google Maps refused the API key.");
88
+ shared().authFailureListeners.add(this.onAuthFailure);
89
+ }
90
+ context;
91
+ maps;
92
+ core;
93
+ geocoder = new GooglePlaces();
94
+ map;
95
+ layer;
96
+ listeners = [];
97
+ shapes = [];
98
+ onAuthFailure;
99
+ // Where the map was when it last stopped: a draw anywhere else is a move, one there a redraw.
100
+ idleView = null;
101
+ style;
102
+ dark;
103
+ get native() {
104
+ return this.map;
105
+ }
106
+ getView() {
107
+ const center = this.map.getCenter();
108
+ const zoom = this.map.getZoom() ?? this.context.camera.zoom;
109
+ const position = center ? fromLatLng(center) : this.context.camera.center;
110
+ const bounds = this.map.getBounds();
111
+ const container = this.context.container;
112
+ return {
113
+ center: position,
114
+ zoom,
115
+ // Until the map has drawn once, Google has no bounds to give: worked out from the camera.
116
+ bounds: bounds ? {
117
+ north: bounds.getNorthEast().lat(),
118
+ east: bounds.getNorthEast().lng(),
119
+ south: bounds.getSouthWest().lat(),
120
+ west: bounds.getSouthWest().lng()
121
+ } : approximateBounds(position, zoom, container.clientWidth, container.clientHeight)
122
+ };
123
+ }
124
+ setCamera(camera, animate) {
125
+ if (animate) {
126
+ this.map.panTo(toLatLngLiteral(camera.center));
127
+ this.map.setZoom(camera.zoom);
128
+ } else {
129
+ this.map.moveCamera({ center: toLatLngLiteral(camera.center), zoom: camera.zoom });
130
+ }
131
+ }
132
+ fitBounds(bounds, padding, maxZoom) {
133
+ this.map.fitBounds(
134
+ { north: bounds.north, south: bounds.south, east: bounds.east, west: bounds.west },
135
+ padding
136
+ );
137
+ const listener = this.map.addListener("idle", () => {
138
+ listener.remove();
139
+ if ((this.map.getZoom() ?? 0) > maxZoom) this.map.setZoom(maxZoom);
140
+ });
141
+ }
142
+ panBy(x, y) {
143
+ this.map.panBy(x, y);
144
+ }
145
+ // Where the map is looking, to tell a draw where it last stopped from one somewhere else.
146
+ viewKey() {
147
+ const center = this.map.getCenter();
148
+ return `${center?.lat()},${center?.lng()},${this.map.getZoom()}`;
149
+ }
150
+ project(position) {
151
+ const point = this.layer.getProjection()?.fromLatLngToContainerPixel(new this.core.LatLng(position.latitude, position.longitude));
152
+ if (point) return { x: point.x, y: point.y };
153
+ return { x: this.context.container.clientWidth / 2, y: this.context.container.clientHeight / 2 };
154
+ }
155
+ addOverlay(element, position, anchor) {
156
+ const placed = { element, anchor, position: new this.core.LatLng(position.latitude, position.longitude) };
157
+ element.style.position = "absolute";
158
+ element.style.transform = anchor === "bottom" ? "translate(-50%, -100%)" : "translate(-50%, -50%)";
159
+ this.maps.OverlayView.preventMapHitsAndGesturesFrom(element);
160
+ this.layer.placed.add(placed);
161
+ this.layer.place(placed);
162
+ return {
163
+ setPosition: (next) => {
164
+ placed.position = new this.core.LatLng(next.latitude, next.longitude);
165
+ this.layer.place(placed);
166
+ },
167
+ remove: () => {
168
+ this.layer.placed.delete(placed);
169
+ element.remove();
170
+ }
171
+ };
172
+ }
173
+ setShapes(shapes) {
174
+ for (const { shape, listener } of this.shapes) {
175
+ listener.remove();
176
+ shape.setMap(null);
177
+ }
178
+ this.shapes = shapes.map((item) => {
179
+ const stroke = { strokeColor: item.color ?? "", strokeOpacity: 1, map: this.map, clickable: true };
180
+ const area = { ...stroke, strokeWeight: 2, fillColor: item.color ?? "", fillOpacity: 0.2 };
181
+ const shape = item.kind === "polyline" ? new this.maps.Polyline({ ...stroke, strokeWeight: item.width ?? 3, path: item.path.map(toLatLngLiteral) }) : item.kind === "polygon" ? new this.maps.Polygon({ ...area, paths: item.path.map(toLatLngLiteral) }) : new this.maps.Circle({ ...area, center: toLatLngLiteral(item.center), radius: item.radius });
182
+ const listener = shape.addListener("click", (event) => {
183
+ if (!event.latLng) return;
184
+ const position = fromLatLng(event.latLng);
185
+ this.context.events.shapeClick(item.id, position, this.project(position));
186
+ });
187
+ return { shape, listener };
188
+ });
189
+ }
190
+ setStyle(style, dark) {
191
+ if (dark !== this.dark) return false;
192
+ if (style !== this.style) {
193
+ this.style = style;
194
+ this.map.setMapTypeId(MAP_TYPES[style]);
195
+ }
196
+ return true;
197
+ }
198
+ resize() {
199
+ }
200
+ dispose() {
201
+ shared().authFailureListeners.delete(this.onAuthFailure);
202
+ for (const listener of this.listeners) listener.remove();
203
+ this.setShapes([]);
204
+ this.layer.setMap(null);
205
+ google.maps.event.clearInstanceListeners(this.map);
206
+ this.context.container.replaceChildren();
207
+ }
208
+ };
209
+ async function googlePlaceFinder(apiKey, language, document2) {
210
+ await loadGoogleMaps(apiKey, language, document2);
211
+ return new GooglePlaces();
212
+ }
213
+ var GooglePlaces = class {
214
+ suggestsAsYouType = true;
215
+ session = null;
216
+ predictions = /* @__PURE__ */ new Map();
217
+ async suggest({ text, view, countries, language }) {
218
+ const places = await google.maps.importLibrary("places");
219
+ this.session ??= new places.AutocompleteSessionToken();
220
+ const { suggestions } = await places.AutocompleteSuggestion.fetchAutocompleteSuggestions({
221
+ input: text,
222
+ sessionToken: this.session,
223
+ language,
224
+ locationBias: { ...view.bounds },
225
+ // Google takes 15 at most.
226
+ ...countries.length ? { includedRegionCodes: countries.slice(0, 15).map((country) => country.toLowerCase()) } : {}
227
+ });
228
+ if (this.predictions.size > 50) this.predictions.clear();
229
+ return suggestions.slice(0, SUGGESTION_COUNT).flatMap(({ placePrediction: prediction }) => {
230
+ if (!prediction) return [];
231
+ this.predictions.set(prediction.placeId, prediction);
232
+ const detail = prediction.secondaryText?.text;
233
+ return [{ id: prediction.placeId, text: prediction.mainText?.text ?? prediction.text.text, ...detail ? { detail } : {} }];
234
+ });
235
+ }
236
+ async resolve(suggestion) {
237
+ const prediction = this.predictions.get(suggestion.id);
238
+ if (!prediction) return null;
239
+ const place = prediction.toPlace();
240
+ this.session = null;
241
+ await place.fetchFields({ fields: ["displayName", "formattedAddress", "location", "viewport"] });
242
+ if (!place.location) return null;
243
+ const viewport = place.viewport;
244
+ const label = place.formattedAddress ?? place.displayName ?? suggestion.text;
245
+ return {
246
+ label: place.displayName && label && !label.startsWith(place.displayName) ? `${place.displayName}, ${label}` : label,
247
+ position: fromLatLng(place.location),
248
+ ...viewport ? {
249
+ bounds: {
250
+ north: viewport.getNorthEast().lat(),
251
+ east: viewport.getNorthEast().lng(),
252
+ south: viewport.getSouthWest().lat(),
253
+ west: viewport.getSouthWest().lng()
254
+ }
255
+ } : {}
256
+ };
257
+ }
258
+ };
259
+ function createElementLayer(maps, onDraw) {
260
+ class ElementLayer extends maps.OverlayView {
261
+ placed = /* @__PURE__ */ new Set();
262
+ root = document.createElement("div");
263
+ onAdd() {
264
+ this.getPanes()?.overlayMouseTarget.appendChild(this.root);
265
+ for (const placed of this.placed) this.root.appendChild(placed.element);
266
+ }
267
+ draw() {
268
+ for (const placed of this.placed) this.place(placed);
269
+ onDraw();
270
+ }
271
+ onRemove() {
272
+ this.root.remove();
273
+ }
274
+ place(placed) {
275
+ if (placed.element.parentElement !== this.root) this.root.appendChild(placed.element);
276
+ const point = this.getProjection()?.fromLatLngToDivPixel(placed.position);
277
+ if (!point) return;
278
+ placed.element.style.left = `${point.x}px`;
279
+ placed.element.style.top = `${point.y}px`;
280
+ }
281
+ }
282
+ return new ElementLayer();
283
+ }
284
+ function toLatLngLiteral(position) {
285
+ return { lat: position.latitude, lng: position.longitude };
286
+ }
287
+ function fromLatLng(latLng) {
288
+ return { latitude: latLng.lat(), longitude: latLng.lng() };
289
+ }
290
+
291
+ export { googlePlaceFinder, googleProvider, loadGoogleMaps };
292
+ //# sourceMappingURL=google-6EZOUTYI.js.map
293
+ //# sourceMappingURL=google-6EZOUTYI.js.map