maplibre-gl-basemap-control 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -3
- package/dist/{BasemapControl-BBPUTp-_.js → BasemapControl-DCusTnvr.js} +831 -60
- package/dist/BasemapControl-DCusTnvr.js.map +1 -0
- package/dist/{BasemapControl-CMZxjxEY.cjs → BasemapControl-DDvY9KVh.cjs} +831 -60
- package/dist/BasemapControl-DDvY9KVh.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/maplibre-gl-basemap-control.css +105 -2
- package/dist/react.cjs +24 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.mjs +24 -2
- package/dist/react.mjs.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/core/BasemapControl.d.ts +41 -3
- package/dist/types/lib/core/BasemapControl.d.ts.map +1 -1
- package/dist/types/lib/core/BasemapControlReact.d.ts +1 -1
- package/dist/types/lib/core/BasemapControlReact.d.ts.map +1 -1
- package/dist/types/lib/core/catalog.d.ts.map +1 -1
- package/dist/types/lib/core/types.d.ts +59 -2
- package/dist/types/lib/core/types.d.ts.map +1 -1
- package/dist/types/lib/hooks/useBasemapState.d.ts +1 -0
- package/dist/types/lib/hooks/useBasemapState.d.ts.map +1 -1
- package/dist/types/react.d.ts +1 -1
- package/dist/types/react.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/BasemapControl-BBPUTp-_.js.map +0 -1
- package/dist/BasemapControl-CMZxjxEY.cjs.map +0 -1
|
@@ -2,20 +2,23 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
const DEFAULT_BASEMAP_PROVIDERS = [
|
|
5
|
-
{ id: "
|
|
6
|
-
{ id: "google", name: "Google", category: "General" },
|
|
5
|
+
{ id: "amazon", name: "Amazon Location", category: "General" },
|
|
7
6
|
{ id: "carto", name: "Carto", category: "General" },
|
|
8
7
|
{ id: "cyclosm", name: "CyclOSM", category: "Cycling" },
|
|
9
8
|
{ id: "esri", name: "ESRI", category: "Imagery" },
|
|
9
|
+
{ id: "google", name: "Google", category: "General" },
|
|
10
|
+
{ id: "mapbox", name: "Mapbox", category: "General" },
|
|
11
|
+
{ id: "maptiler", name: "MapTiler", category: "General" },
|
|
10
12
|
{ id: "nasa-gibs", name: "NASA GIBS", category: "Imagery" },
|
|
13
|
+
{ id: "nlmaps", name: "nlmaps", category: "Regional" },
|
|
14
|
+
{ id: "openfreemap", name: "OpenFreeMap", category: "Vector Styles" },
|
|
11
15
|
{ id: "openrailwaymap", name: "OpenRailwayMap", category: "Transport" },
|
|
16
|
+
{ id: "openstreetmap", name: "OpenStreetMap", category: "Community" },
|
|
12
17
|
{ id: "opentopomap", name: "OpenTopoMap", category: "Terrain" },
|
|
13
|
-
{ id: "openfreemap", name: "OpenFreeMap", category: "Vector Styles" },
|
|
14
18
|
{ id: "swisstopo", name: "Swiss Federal Geoportal", category: "Regional" },
|
|
15
19
|
{ id: "topplusopen", name: "TopPlusOpen", category: "Regional" },
|
|
16
20
|
{ id: "usgs", name: "USGS", category: "United States" },
|
|
17
|
-
{ id: "waymarkedtrails", name: "Waymarked Trails", category: "Outdoor" }
|
|
18
|
-
{ id: "nlmaps", name: "nlmaps", category: "Regional" }
|
|
21
|
+
{ id: "waymarkedtrails", name: "Waymarked Trails", category: "Outdoor" }
|
|
19
22
|
];
|
|
20
23
|
function rasterBasemap({
|
|
21
24
|
id,
|
|
@@ -45,8 +48,99 @@ function rasterBasemap({
|
|
|
45
48
|
tags
|
|
46
49
|
};
|
|
47
50
|
}
|
|
51
|
+
function styleBasemap({
|
|
52
|
+
id,
|
|
53
|
+
name,
|
|
54
|
+
provider,
|
|
55
|
+
category,
|
|
56
|
+
description,
|
|
57
|
+
attribution,
|
|
58
|
+
url,
|
|
59
|
+
view,
|
|
60
|
+
tags = []
|
|
61
|
+
}) {
|
|
62
|
+
return {
|
|
63
|
+
id,
|
|
64
|
+
name,
|
|
65
|
+
provider,
|
|
66
|
+
type: "style",
|
|
67
|
+
category,
|
|
68
|
+
description,
|
|
69
|
+
attribution,
|
|
70
|
+
source: {
|
|
71
|
+
type: "style",
|
|
72
|
+
url
|
|
73
|
+
},
|
|
74
|
+
view,
|
|
75
|
+
tags
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function mapTilerStyleBasemap({
|
|
79
|
+
id,
|
|
80
|
+
name,
|
|
81
|
+
mapId,
|
|
82
|
+
category,
|
|
83
|
+
description,
|
|
84
|
+
url,
|
|
85
|
+
tags = []
|
|
86
|
+
}) {
|
|
87
|
+
return styleBasemap({
|
|
88
|
+
id,
|
|
89
|
+
name,
|
|
90
|
+
provider: "maptiler",
|
|
91
|
+
category,
|
|
92
|
+
description,
|
|
93
|
+
attribution: MAPTILER_ATTRIBUTION,
|
|
94
|
+
url: url ?? `https://api.maptiler.com/maps/${mapId}/style.json?key={api-key}`,
|
|
95
|
+
tags: ["maptiler", "vector", "style", ...tags]
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function amazonStyleBasemap({
|
|
99
|
+
id,
|
|
100
|
+
name,
|
|
101
|
+
mapStyle,
|
|
102
|
+
category,
|
|
103
|
+
description,
|
|
104
|
+
tags = []
|
|
105
|
+
}) {
|
|
106
|
+
return styleBasemap({
|
|
107
|
+
id,
|
|
108
|
+
name,
|
|
109
|
+
provider: "amazon",
|
|
110
|
+
category,
|
|
111
|
+
description,
|
|
112
|
+
attribution: AMAZON_ATTRIBUTION,
|
|
113
|
+
url: `https://maps.geo.{aws-region}.amazonaws.com/v2/styles/${mapStyle}/descriptor?key={api-key}`,
|
|
114
|
+
tags: ["amazon", "aws", "location", "style", ...tags]
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function mapboxStyleBasemap({
|
|
118
|
+
id,
|
|
119
|
+
name,
|
|
120
|
+
styleId,
|
|
121
|
+
category,
|
|
122
|
+
description,
|
|
123
|
+
tags = []
|
|
124
|
+
}) {
|
|
125
|
+
return styleBasemap({
|
|
126
|
+
id,
|
|
127
|
+
name,
|
|
128
|
+
provider: "mapbox",
|
|
129
|
+
category,
|
|
130
|
+
description,
|
|
131
|
+
attribution: MAPBOX_ATTRIBUTION,
|
|
132
|
+
url: `https://api.mapbox.com/styles/v1/mapbox/${styleId}?access_token={api-key}`,
|
|
133
|
+
tags: ["mapbox", "vector", "style", ...tags]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function sortProviders(providers) {
|
|
137
|
+
return [...providers].sort((a, b) => a.name.localeCompare(b.name));
|
|
138
|
+
}
|
|
139
|
+
const AMAZON_ATTRIBUTION = "© Amazon Location Service";
|
|
48
140
|
const CARTO_ATTRIBUTION = "© OpenStreetMap contributors © CARTO";
|
|
49
141
|
const ESRI_ATTRIBUTION = "Tiles © Esri and the GIS User Community";
|
|
142
|
+
const MAPBOX_ATTRIBUTION = "© Mapbox © OpenStreetMap contributors";
|
|
143
|
+
const MAPTILER_ATTRIBUTION = "© MapTiler © OpenStreetMap contributors";
|
|
50
144
|
const OSM_ATTRIBUTION = "© OpenStreetMap contributors";
|
|
51
145
|
const OPENFREEMAP_ATTRIBUTION = "OpenFreeMap © OpenMapTiles Data from OpenStreetMap";
|
|
52
146
|
const DEFAULT_BASEMAPS = [
|
|
@@ -138,6 +232,216 @@ const DEFAULT_BASEMAPS = [
|
|
|
138
232
|
maxzoom: 20,
|
|
139
233
|
tags: ["google", "hybrid", "imagery"]
|
|
140
234
|
}),
|
|
235
|
+
amazonStyleBasemap({
|
|
236
|
+
id: "amazon-standard",
|
|
237
|
+
name: "Amazon Standard",
|
|
238
|
+
mapStyle: "Standard",
|
|
239
|
+
category: "Street",
|
|
240
|
+
description: "Amazon Location general-purpose vector map style.",
|
|
241
|
+
tags: ["standard", "street"]
|
|
242
|
+
}),
|
|
243
|
+
amazonStyleBasemap({
|
|
244
|
+
id: "amazon-monochrome",
|
|
245
|
+
name: "Amazon Monochrome",
|
|
246
|
+
mapStyle: "Monochrome",
|
|
247
|
+
category: "Light",
|
|
248
|
+
description: "Amazon Location grey scale map style for overlays.",
|
|
249
|
+
tags: ["monochrome", "light", "dataviz"]
|
|
250
|
+
}),
|
|
251
|
+
amazonStyleBasemap({
|
|
252
|
+
id: "amazon-hybrid",
|
|
253
|
+
name: "Amazon Hybrid",
|
|
254
|
+
mapStyle: "Hybrid",
|
|
255
|
+
category: "Imagery",
|
|
256
|
+
description: "Amazon Location satellite imagery with road and label overlay.",
|
|
257
|
+
tags: ["hybrid", "satellite", "imagery", "labels"]
|
|
258
|
+
}),
|
|
259
|
+
amazonStyleBasemap({
|
|
260
|
+
id: "amazon-satellite",
|
|
261
|
+
name: "Amazon Satellite",
|
|
262
|
+
mapStyle: "Satellite",
|
|
263
|
+
category: "Imagery",
|
|
264
|
+
description: "Amazon Location satellite imagery map style.",
|
|
265
|
+
tags: ["satellite", "imagery"]
|
|
266
|
+
}),
|
|
267
|
+
mapboxStyleBasemap({
|
|
268
|
+
id: "mapbox-streets",
|
|
269
|
+
name: "Mapbox Streets",
|
|
270
|
+
styleId: "streets-v12",
|
|
271
|
+
category: "Street",
|
|
272
|
+
description: "Mapbox general-purpose street map style.",
|
|
273
|
+
tags: ["streets", "street"]
|
|
274
|
+
}),
|
|
275
|
+
mapboxStyleBasemap({
|
|
276
|
+
id: "mapbox-outdoors",
|
|
277
|
+
name: "Mapbox Outdoors",
|
|
278
|
+
styleId: "outdoors-v12",
|
|
279
|
+
category: "Outdoor",
|
|
280
|
+
description: "Mapbox outdoor recreation and terrain style.",
|
|
281
|
+
tags: ["outdoors", "terrain", "recreation"]
|
|
282
|
+
}),
|
|
283
|
+
mapboxStyleBasemap({
|
|
284
|
+
id: "mapbox-light",
|
|
285
|
+
name: "Mapbox Light",
|
|
286
|
+
styleId: "light-v11",
|
|
287
|
+
category: "Light",
|
|
288
|
+
description: "Light Mapbox style for data overlays.",
|
|
289
|
+
tags: ["light", "dataviz"]
|
|
290
|
+
}),
|
|
291
|
+
mapboxStyleBasemap({
|
|
292
|
+
id: "mapbox-dark",
|
|
293
|
+
name: "Mapbox Dark",
|
|
294
|
+
styleId: "dark-v11",
|
|
295
|
+
category: "Dark",
|
|
296
|
+
description: "Dark Mapbox style for high-contrast overlays.",
|
|
297
|
+
tags: ["dark"]
|
|
298
|
+
}),
|
|
299
|
+
mapboxStyleBasemap({
|
|
300
|
+
id: "mapbox-satellite",
|
|
301
|
+
name: "Mapbox Satellite",
|
|
302
|
+
styleId: "satellite-v9",
|
|
303
|
+
category: "Imagery",
|
|
304
|
+
description: "Mapbox satellite imagery style.",
|
|
305
|
+
tags: ["satellite", "imagery"]
|
|
306
|
+
}),
|
|
307
|
+
mapboxStyleBasemap({
|
|
308
|
+
id: "mapbox-satellite-streets",
|
|
309
|
+
name: "Mapbox Satellite Streets",
|
|
310
|
+
styleId: "satellite-streets-v12",
|
|
311
|
+
category: "Imagery",
|
|
312
|
+
description: "Mapbox satellite imagery with streets and labels.",
|
|
313
|
+
tags: ["satellite", "streets", "imagery", "labels"]
|
|
314
|
+
}),
|
|
315
|
+
mapboxStyleBasemap({
|
|
316
|
+
id: "mapbox-navigation-day",
|
|
317
|
+
name: "Mapbox Navigation Day",
|
|
318
|
+
styleId: "navigation-day-v1",
|
|
319
|
+
category: "Navigation",
|
|
320
|
+
description: "Mapbox daytime navigation style.",
|
|
321
|
+
tags: ["navigation", "day"]
|
|
322
|
+
}),
|
|
323
|
+
mapboxStyleBasemap({
|
|
324
|
+
id: "mapbox-navigation-night",
|
|
325
|
+
name: "Mapbox Navigation Night",
|
|
326
|
+
styleId: "navigation-night-v1",
|
|
327
|
+
category: "Navigation",
|
|
328
|
+
description: "Mapbox nighttime navigation style.",
|
|
329
|
+
tags: ["navigation", "night", "dark"]
|
|
330
|
+
}),
|
|
331
|
+
mapTilerStyleBasemap({
|
|
332
|
+
id: "maptiler-aquarelle",
|
|
333
|
+
name: "MapTiler Aquarelle",
|
|
334
|
+
mapId: "aquarelle-v4",
|
|
335
|
+
category: "Artistic",
|
|
336
|
+
description: "Watercolor-style vector basemap.",
|
|
337
|
+
tags: ["aquarelle", "watercolor", "artistic"]
|
|
338
|
+
}),
|
|
339
|
+
mapTilerStyleBasemap({
|
|
340
|
+
id: "maptiler-backdrop",
|
|
341
|
+
name: "MapTiler Backdrop",
|
|
342
|
+
mapId: "backdrop-v4",
|
|
343
|
+
category: "Light",
|
|
344
|
+
description: "Subtle monochrome context map.",
|
|
345
|
+
tags: ["backdrop", "monochrome", "context"]
|
|
346
|
+
}),
|
|
347
|
+
mapTilerStyleBasemap({
|
|
348
|
+
id: "maptiler-base",
|
|
349
|
+
name: "MapTiler Base",
|
|
350
|
+
mapId: "base-v4",
|
|
351
|
+
category: "Street",
|
|
352
|
+
description: "General-purpose vector basemap.",
|
|
353
|
+
tags: ["base", "street"]
|
|
354
|
+
}),
|
|
355
|
+
mapTilerStyleBasemap({
|
|
356
|
+
id: "maptiler-dataviz",
|
|
357
|
+
name: "MapTiler Dataviz",
|
|
358
|
+
mapId: "dataviz-v4",
|
|
359
|
+
category: "Light",
|
|
360
|
+
description: "Minimal basemap for data visualization and overlays.",
|
|
361
|
+
tags: ["dataviz", "data", "light"]
|
|
362
|
+
}),
|
|
363
|
+
mapTilerStyleBasemap({
|
|
364
|
+
id: "maptiler-landscape",
|
|
365
|
+
name: "MapTiler Landscape",
|
|
366
|
+
mapId: "landscape-v4",
|
|
367
|
+
category: "Terrain",
|
|
368
|
+
description: "Light terrain and hillshade map.",
|
|
369
|
+
tags: ["landscape", "terrain", "hillshade"]
|
|
370
|
+
}),
|
|
371
|
+
mapTilerStyleBasemap({
|
|
372
|
+
id: "maptiler-ocean",
|
|
373
|
+
name: "MapTiler Ocean",
|
|
374
|
+
mapId: "ocean-v4",
|
|
375
|
+
category: "Marine",
|
|
376
|
+
description: "Ocean bathymetry and marine-focused basemap.",
|
|
377
|
+
tags: ["ocean", "marine", "bathymetry"]
|
|
378
|
+
}),
|
|
379
|
+
mapTilerStyleBasemap({
|
|
380
|
+
id: "maptiler-openstreetmap",
|
|
381
|
+
name: "MapTiler OpenStreetMap",
|
|
382
|
+
mapId: "openstreetmap",
|
|
383
|
+
category: "Street",
|
|
384
|
+
description: "OpenStreetMap style hosted by MapTiler.",
|
|
385
|
+
url: "https://api.maptiler.com/maps/openstreetmap/style.json?key",
|
|
386
|
+
tags: ["openstreetmap", "osm", "street"]
|
|
387
|
+
}),
|
|
388
|
+
mapTilerStyleBasemap({
|
|
389
|
+
id: "maptiler-outdoor",
|
|
390
|
+
name: "MapTiler Outdoor",
|
|
391
|
+
mapId: "outdoor-v4",
|
|
392
|
+
category: "Outdoor",
|
|
393
|
+
description: "Outdoor recreation basemap with terrain detail.",
|
|
394
|
+
tags: ["outdoor", "terrain", "recreation"]
|
|
395
|
+
}),
|
|
396
|
+
mapTilerStyleBasemap({
|
|
397
|
+
id: "maptiler-satellite-hybrid",
|
|
398
|
+
name: "MapTiler Satellite Hybrid",
|
|
399
|
+
mapId: "hybrid-v4",
|
|
400
|
+
category: "Imagery",
|
|
401
|
+
description: "Satellite imagery with labels, roads, and borders.",
|
|
402
|
+
tags: ["satellite", "hybrid", "imagery", "labels"]
|
|
403
|
+
}),
|
|
404
|
+
mapTilerStyleBasemap({
|
|
405
|
+
id: "maptiler-satellite-plain",
|
|
406
|
+
name: "MapTiler Satellite Plain",
|
|
407
|
+
mapId: "satellite-v4",
|
|
408
|
+
category: "Imagery",
|
|
409
|
+
description: "Satellite imagery without the hybrid reference overlay.",
|
|
410
|
+
tags: ["satellite", "imagery"]
|
|
411
|
+
}),
|
|
412
|
+
mapTilerStyleBasemap({
|
|
413
|
+
id: "maptiler-streets",
|
|
414
|
+
name: "MapTiler Streets",
|
|
415
|
+
mapId: "streets-v4",
|
|
416
|
+
category: "Street",
|
|
417
|
+
description: "Detailed street map for general navigation.",
|
|
418
|
+
tags: ["streets", "street", "navigation"]
|
|
419
|
+
}),
|
|
420
|
+
mapTilerStyleBasemap({
|
|
421
|
+
id: "maptiler-toner",
|
|
422
|
+
name: "MapTiler Toner",
|
|
423
|
+
mapId: "toner-v2",
|
|
424
|
+
category: "Dark",
|
|
425
|
+
description: "High-contrast monochrome basemap.",
|
|
426
|
+
url: "https://api.maptiler.com/maps/toner-v2/style.json?key=",
|
|
427
|
+
tags: ["toner", "monochrome", "contrast"]
|
|
428
|
+
}),
|
|
429
|
+
mapTilerStyleBasemap({
|
|
430
|
+
id: "maptiler-topo",
|
|
431
|
+
name: "MapTiler Topo",
|
|
432
|
+
mapId: "topo-v4",
|
|
433
|
+
category: "Terrain",
|
|
434
|
+
description: "Topographic basemap with contours and terrain context.",
|
|
435
|
+
tags: ["topo", "topographic", "terrain"]
|
|
436
|
+
}),
|
|
437
|
+
mapTilerStyleBasemap({
|
|
438
|
+
id: "maptiler-winter",
|
|
439
|
+
name: "MapTiler Winter",
|
|
440
|
+
mapId: "winter-v4",
|
|
441
|
+
category: "Outdoor",
|
|
442
|
+
description: "Winter sports and mountain activity basemap.",
|
|
443
|
+
tags: ["winter", "skiing", "outdoor"]
|
|
444
|
+
}),
|
|
141
445
|
rasterBasemap({
|
|
142
446
|
id: "carto-positron",
|
|
143
447
|
name: "Carto Positron",
|
|
@@ -750,7 +1054,7 @@ function combineProviders(defaults, custom = []) {
|
|
|
750
1054
|
const byId = /* @__PURE__ */ new Map();
|
|
751
1055
|
defaults.forEach((provider) => byId.set(provider.id, provider));
|
|
752
1056
|
custom.forEach((provider) => byId.set(provider.id, provider));
|
|
753
|
-
return [...byId.values()];
|
|
1057
|
+
return sortProviders([...byId.values()]);
|
|
754
1058
|
}
|
|
755
1059
|
function resolveBasemapProviders(basemaps, customProviders = [], includeDefaultProviders = true) {
|
|
756
1060
|
const byId = /* @__PURE__ */ new Map();
|
|
@@ -763,7 +1067,7 @@ function resolveBasemapProviders(basemaps, customProviders = [], includeDefaultP
|
|
|
763
1067
|
byId.set(basemap.provider, { id: basemap.provider, name: basemap.provider });
|
|
764
1068
|
}
|
|
765
1069
|
});
|
|
766
|
-
return [...byId.values()];
|
|
1070
|
+
return sortProviders([...byId.values()]);
|
|
767
1071
|
}
|
|
768
1072
|
function createBasemapCatalog(customBasemaps = [], includeDefaultBasemaps = true) {
|
|
769
1073
|
const basemaps = includeDefaultBasemaps ? [...DEFAULT_BASEMAPS, ...customBasemaps] : [...customBasemaps];
|
|
@@ -797,10 +1101,21 @@ const DEFAULT_OPTIONS = {
|
|
|
797
1101
|
title: "Basemaps",
|
|
798
1102
|
panelWidth: 340,
|
|
799
1103
|
className: "",
|
|
800
|
-
includeDefaultBasemaps: true
|
|
1104
|
+
includeDefaultBasemaps: true,
|
|
1105
|
+
allowMultiple: false,
|
|
1106
|
+
showMultipleToggle: true,
|
|
1107
|
+
resizable: true
|
|
801
1108
|
};
|
|
802
1109
|
const CONTROL_SOURCE_PREFIX = "maplibre-basemap-control-source";
|
|
803
1110
|
const CONTROL_LAYER_PREFIX = "";
|
|
1111
|
+
const API_KEY_PLACEHOLDER = "{api-key}";
|
|
1112
|
+
const MAPTILER_API_KEY_EXAMPLE = "YOUR_MAPTILER_API_KEY";
|
|
1113
|
+
const MAPTILER_API_KEY_QUERY = "?key";
|
|
1114
|
+
const MAPTILER_API_KEY_EMPTY_QUERY = "?key=";
|
|
1115
|
+
const AWS_REGION_PLACEHOLDER = "{aws-region}";
|
|
1116
|
+
const MIN_PANEL_WIDTH = 240;
|
|
1117
|
+
const MIN_PANEL_HEIGHT = 200;
|
|
1118
|
+
const PANEL_VIEWPORT_MARGIN = 12;
|
|
804
1119
|
class BasemapControl {
|
|
805
1120
|
constructor(options) {
|
|
806
1121
|
__publicField(this, "_map");
|
|
@@ -813,12 +1128,49 @@ class BasemapControl {
|
|
|
813
1128
|
__publicField(this, "_basemaps");
|
|
814
1129
|
__publicField(this, "_providers");
|
|
815
1130
|
__publicField(this, "_eventHandlers", new globalThis.Map());
|
|
816
|
-
|
|
817
|
-
|
|
1131
|
+
// Active managed raster basemaps keyed by basemap id, in insertion order. In
|
|
1132
|
+
// single mode this holds at most one entry; in multiple mode it tracks every
|
|
1133
|
+
// stacked raster overlay so each can be added or removed independently.
|
|
1134
|
+
__publicField(this, "_managedRasters", new globalThis.Map());
|
|
1135
|
+
__publicField(this, "_mapTilerApiKey", "");
|
|
1136
|
+
__publicField(this, "_amazonApiKey", "");
|
|
1137
|
+
__publicField(this, "_awsRegion", "");
|
|
1138
|
+
__publicField(this, "_mapboxAccessToken", "");
|
|
1139
|
+
__publicField(this, "_providerSettingsCollapsed", true);
|
|
818
1140
|
__publicField(this, "_resizeHandler", null);
|
|
819
1141
|
__publicField(this, "_mapResizeHandler", null);
|
|
820
|
-
__publicField(this, "
|
|
1142
|
+
__publicField(this, "_resizeAnchor", null);
|
|
1143
|
+
__publicField(this, "_resizeHandleEl", null);
|
|
1144
|
+
__publicField(this, "_onResizeMove", (event) => {
|
|
1145
|
+
if (!this._panel || !this._resizeAnchor) return;
|
|
1146
|
+
const { x, y, isLeft, isTop } = this._resizeAnchor;
|
|
1147
|
+
const bounds = this._getResizeBounds();
|
|
1148
|
+
const rawWidth = isLeft ? event.clientX - x : x - event.clientX;
|
|
1149
|
+
const rawHeight = isTop ? event.clientY - y : y - event.clientY;
|
|
1150
|
+
const width = this._clampSize(rawWidth, MIN_PANEL_WIDTH, bounds.maxWidth);
|
|
1151
|
+
const height = this._clampSize(rawHeight, MIN_PANEL_HEIGHT, bounds.maxHeight);
|
|
1152
|
+
this._panel.style.width = `${width}px`;
|
|
1153
|
+
this._panel.style.height = `${height}px`;
|
|
1154
|
+
this._panel.classList.add("is-resized");
|
|
1155
|
+
this._state = { ...this._state, panelWidth: width, panelHeight: height };
|
|
1156
|
+
this._updatePanelPosition();
|
|
1157
|
+
});
|
|
1158
|
+
__publicField(this, "_onResizeEnd", (event) => {
|
|
1159
|
+
var _a, _b;
|
|
1160
|
+
window.removeEventListener("pointermove", this._onResizeMove);
|
|
1161
|
+
window.removeEventListener("pointerup", this._onResizeEnd);
|
|
1162
|
+
window.removeEventListener("pointercancel", this._onResizeEnd);
|
|
1163
|
+
(_b = (_a = this._resizeHandleEl) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, event.pointerId);
|
|
1164
|
+
this._resizeHandleEl = null;
|
|
1165
|
+
if (!this._resizeAnchor) return;
|
|
1166
|
+
this._resizeAnchor = null;
|
|
1167
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1168
|
+
});
|
|
821
1169
|
this._options = { ...DEFAULT_OPTIONS, ...options };
|
|
1170
|
+
this._mapTilerApiKey = (options == null ? void 0 : options.mapTilerApiKey) ?? "";
|
|
1171
|
+
this._amazonApiKey = (options == null ? void 0 : options.amazonApiKey) ?? "";
|
|
1172
|
+
this._awsRegion = (options == null ? void 0 : options.awsRegion) ?? "us-east-1";
|
|
1173
|
+
this._mapboxAccessToken = (options == null ? void 0 : options.mapboxAccessToken) ?? "";
|
|
822
1174
|
this._basemaps = createBasemapCatalog(
|
|
823
1175
|
options == null ? void 0 : options.basemaps,
|
|
824
1176
|
this._options.includeDefaultBasemaps
|
|
@@ -832,6 +1184,8 @@ class BasemapControl {
|
|
|
832
1184
|
collapsed: this._options.collapsed,
|
|
833
1185
|
panelWidth: this._options.panelWidth,
|
|
834
1186
|
activeBasemapId: this._options.defaultBasemapId,
|
|
1187
|
+
activeBasemapIds: this._options.defaultBasemapId ? [this._options.defaultBasemapId] : [],
|
|
1188
|
+
allowMultiple: this._options.allowMultiple,
|
|
835
1189
|
query: "",
|
|
836
1190
|
providerFilter: "",
|
|
837
1191
|
categoryFilter: "",
|
|
@@ -852,7 +1206,8 @@ class BasemapControl {
|
|
|
852
1206
|
}
|
|
853
1207
|
this._renderContent();
|
|
854
1208
|
if (this._state.activeBasemapId) {
|
|
855
|
-
this.
|
|
1209
|
+
this.setBasemap(this._state.activeBasemapId).catch(() => {
|
|
1210
|
+
});
|
|
856
1211
|
}
|
|
857
1212
|
return this._container;
|
|
858
1213
|
}
|
|
@@ -866,10 +1221,11 @@ class BasemapControl {
|
|
|
866
1221
|
this._map.off("resize", this._mapResizeHandler);
|
|
867
1222
|
this._mapResizeHandler = null;
|
|
868
1223
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1224
|
+
window.removeEventListener("pointermove", this._onResizeMove);
|
|
1225
|
+
window.removeEventListener("pointerup", this._onResizeEnd);
|
|
1226
|
+
window.removeEventListener("pointercancel", this._onResizeEnd);
|
|
1227
|
+
this._resizeAnchor = null;
|
|
1228
|
+
this._resizeHandleEl = null;
|
|
873
1229
|
(_b = (_a = this._panel) == null ? void 0 : _a.parentNode) == null ? void 0 : _b.removeChild(this._panel);
|
|
874
1230
|
(_d = (_c = this._container) == null ? void 0 : _c.parentNode) == null ? void 0 : _d.removeChild(this._container);
|
|
875
1231
|
this._map = void 0;
|
|
@@ -884,9 +1240,24 @@ class BasemapControl {
|
|
|
884
1240
|
}
|
|
885
1241
|
setState(newState) {
|
|
886
1242
|
this._state = { ...this._state, ...newState };
|
|
1243
|
+
this._syncActiveBasemapState(newState);
|
|
887
1244
|
this._renderContent();
|
|
888
1245
|
this._emit({ type: "statechange", state: this.getState() });
|
|
889
1246
|
}
|
|
1247
|
+
// Keeps `activeBasemapId` and `activeBasemapIds` consistent when a caller
|
|
1248
|
+
// updates only one of them through setState (the React wrapper and external
|
|
1249
|
+
// consumers commonly set just `activeBasemapId`).
|
|
1250
|
+
_syncActiveBasemapState(applied) {
|
|
1251
|
+
const hasId = "activeBasemapId" in applied;
|
|
1252
|
+
const hasIds = "activeBasemapIds" in applied;
|
|
1253
|
+
if (hasId && !hasIds) {
|
|
1254
|
+
const id = this._state.activeBasemapId;
|
|
1255
|
+
this._state = { ...this._state, activeBasemapIds: id ? [id] : [] };
|
|
1256
|
+
} else if (hasIds && !hasId) {
|
|
1257
|
+
const ids = this._state.activeBasemapIds;
|
|
1258
|
+
this._state = { ...this._state, activeBasemapId: ids[ids.length - 1] };
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
890
1261
|
getBasemaps() {
|
|
891
1262
|
return [...this._basemaps];
|
|
892
1263
|
}
|
|
@@ -897,16 +1268,87 @@ class BasemapControl {
|
|
|
897
1268
|
this._options.providers,
|
|
898
1269
|
this._options.includeDefaultBasemaps
|
|
899
1270
|
);
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1271
|
+
const activeBasemapIds = this._state.activeBasemapIds.filter(
|
|
1272
|
+
(id) => this._basemaps.some((basemap) => basemap.id === id)
|
|
1273
|
+
);
|
|
1274
|
+
this._state = {
|
|
1275
|
+
...this._state,
|
|
1276
|
+
activeBasemapIds,
|
|
1277
|
+
activeBasemapId: this._state.activeBasemapId && activeBasemapIds.includes(this._state.activeBasemapId) ? this._state.activeBasemapId : activeBasemapIds[activeBasemapIds.length - 1]
|
|
1278
|
+
};
|
|
1279
|
+
this._renderContent();
|
|
1280
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1281
|
+
}
|
|
1282
|
+
setMapTilerApiKey(apiKey) {
|
|
1283
|
+
this._mapTilerApiKey = apiKey;
|
|
1284
|
+
this._state = { ...this._state, error: void 0 };
|
|
1285
|
+
this._renderContent();
|
|
1286
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1287
|
+
}
|
|
1288
|
+
setAmazonCredentials(apiKey, awsRegion = this._awsRegion) {
|
|
1289
|
+
this._amazonApiKey = apiKey;
|
|
1290
|
+
this._awsRegion = awsRegion;
|
|
1291
|
+
this._state = { ...this._state, error: void 0 };
|
|
1292
|
+
this._renderContent();
|
|
1293
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1294
|
+
}
|
|
1295
|
+
setMapboxAccessToken(accessToken) {
|
|
1296
|
+
this._mapboxAccessToken = accessToken;
|
|
1297
|
+
this._state = { ...this._state, error: void 0 };
|
|
903
1298
|
this._renderContent();
|
|
904
1299
|
this._emit({ type: "statechange", state: this.getState() });
|
|
905
1300
|
}
|
|
906
1301
|
getActiveBasemap() {
|
|
907
1302
|
return this._basemaps.find((basemap) => basemap.id === this._state.activeBasemapId);
|
|
908
1303
|
}
|
|
1304
|
+
getActiveBasemaps() {
|
|
1305
|
+
return this._state.activeBasemapIds.map((id) => this._basemaps.find((basemap) => basemap.id === id)).filter((basemap) => Boolean(basemap));
|
|
1306
|
+
}
|
|
1307
|
+
isBasemapActive(id) {
|
|
1308
|
+
return this._state.activeBasemapIds.includes(id);
|
|
1309
|
+
}
|
|
1310
|
+
// Apply a basemap, replacing any previously active basemaps.
|
|
909
1311
|
async setBasemap(id) {
|
|
1312
|
+
return this._applyBasemapChange(id, "replace");
|
|
1313
|
+
}
|
|
1314
|
+
// Add a raster basemap as an additional overlay without removing the active
|
|
1315
|
+
// ones. Style basemaps cannot stack, so they always replace the map style.
|
|
1316
|
+
async addBasemap(id) {
|
|
1317
|
+
return this._applyBasemapChange(id, "add");
|
|
1318
|
+
}
|
|
1319
|
+
// Remove a previously added managed raster basemap from the map.
|
|
1320
|
+
async removeBasemap(id) {
|
|
1321
|
+
const basemap = this._basemaps.find((candidate) => candidate.id === id);
|
|
1322
|
+
if (!basemap) {
|
|
1323
|
+
const error = new Error(`Basemap "${id}" was not found.`);
|
|
1324
|
+
this._handleError(error);
|
|
1325
|
+
throw error;
|
|
1326
|
+
}
|
|
1327
|
+
if (!this._map) {
|
|
1328
|
+
const error = new Error("BasemapControl must be added to a map before removing a basemap.");
|
|
1329
|
+
this._handleError(error, basemap);
|
|
1330
|
+
throw error;
|
|
1331
|
+
}
|
|
1332
|
+
const managedRaster = this._removeManagedRaster(id);
|
|
1333
|
+
const activeBasemapIds = this._state.activeBasemapIds.filter((value) => value !== id);
|
|
1334
|
+
this._state = {
|
|
1335
|
+
...this._state,
|
|
1336
|
+
activeBasemapIds,
|
|
1337
|
+
activeBasemapId: activeBasemapIds[activeBasemapIds.length - 1],
|
|
1338
|
+
error: void 0
|
|
1339
|
+
};
|
|
1340
|
+
this._renderContent(true);
|
|
1341
|
+
this._emit({ type: "basemapremove", state: this.getState(), basemap, managedRaster });
|
|
1342
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1343
|
+
}
|
|
1344
|
+
// Add the basemap if it is not active, otherwise remove it.
|
|
1345
|
+
async toggleBasemap(id) {
|
|
1346
|
+
if (this.isBasemapActive(id)) {
|
|
1347
|
+
return this.removeBasemap(id);
|
|
1348
|
+
}
|
|
1349
|
+
return this.addBasemap(id);
|
|
1350
|
+
}
|
|
1351
|
+
async _applyBasemapChange(id, mode) {
|
|
910
1352
|
const basemap = this._basemaps.find((candidate) => candidate.id === id);
|
|
911
1353
|
if (!basemap) {
|
|
912
1354
|
const error = new Error(`Basemap "${id}" was not found.`);
|
|
@@ -918,46 +1360,69 @@ class BasemapControl {
|
|
|
918
1360
|
this._handleError(error, basemap);
|
|
919
1361
|
throw error;
|
|
920
1362
|
}
|
|
1363
|
+
const isRaster = basemap.source.type === "raster";
|
|
1364
|
+
const effectiveMode = isRaster ? mode : "replace";
|
|
921
1365
|
this._state = { ...this._state, loading: true, error: void 0 };
|
|
922
|
-
this._renderContent();
|
|
1366
|
+
this._renderContent(true);
|
|
923
1367
|
this._emit({ type: "statechange", state: this.getState() });
|
|
924
1368
|
try {
|
|
925
1369
|
let managedRaster;
|
|
926
|
-
if (
|
|
1370
|
+
if (isRaster) {
|
|
927
1371
|
await this._waitForStyleReady();
|
|
928
|
-
|
|
1372
|
+
if (effectiveMode === "replace") {
|
|
1373
|
+
this._removeManagedBasemap();
|
|
1374
|
+
} else {
|
|
1375
|
+
this._removeManagedRaster(basemap.id);
|
|
1376
|
+
}
|
|
929
1377
|
managedRaster = this._addRasterBasemap(basemap);
|
|
930
1378
|
} else {
|
|
1379
|
+
const styleUrl = this._resolveStyleUrl(basemap);
|
|
1380
|
+
const styleOptions = this._getStyleOptions(basemap);
|
|
931
1381
|
this._removeManagedBasemap();
|
|
932
|
-
|
|
1382
|
+
if (styleOptions) {
|
|
1383
|
+
this._map.setStyle(styleUrl, styleOptions);
|
|
1384
|
+
} else {
|
|
1385
|
+
this._map.setStyle(styleUrl);
|
|
1386
|
+
}
|
|
933
1387
|
}
|
|
934
1388
|
this._applyBasemapView(basemap);
|
|
1389
|
+
const activeBasemapIds = effectiveMode === "add" ? [...this._state.activeBasemapIds.filter((value) => value !== basemap.id), basemap.id] : [basemap.id];
|
|
935
1390
|
this._state = {
|
|
936
1391
|
...this._state,
|
|
937
1392
|
activeBasemapId: basemap.id,
|
|
1393
|
+
activeBasemapIds,
|
|
938
1394
|
loading: false,
|
|
939
1395
|
error: void 0
|
|
940
1396
|
};
|
|
941
|
-
this._renderContent();
|
|
1397
|
+
this._renderContent(true);
|
|
942
1398
|
this._emit({
|
|
943
1399
|
type: "basemapchange",
|
|
944
1400
|
state: this.getState(),
|
|
945
1401
|
basemap,
|
|
946
|
-
managedRaster
|
|
1402
|
+
managedRaster,
|
|
1403
|
+
mode: effectiveMode
|
|
947
1404
|
});
|
|
948
1405
|
this._emit({ type: "statechange", state: this.getState() });
|
|
949
1406
|
} catch (cause) {
|
|
950
1407
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
951
1408
|
this._state = { ...this._state, loading: false, error: error.message };
|
|
952
|
-
this._renderContent();
|
|
1409
|
+
this._renderContent(true);
|
|
953
1410
|
this._handleError(error, basemap);
|
|
954
1411
|
throw error;
|
|
955
1412
|
}
|
|
956
1413
|
}
|
|
957
|
-
//
|
|
958
|
-
//
|
|
1414
|
+
// The public mutators rethrow after emitting the error event so callers that
|
|
1415
|
+
// await them can react. The panel's click handler uses this instead to avoid
|
|
959
1416
|
// unhandled promise rejections; the failure is still reported via `error`.
|
|
1417
|
+
// In multiple mode a raster basemap click toggles the overlay on or off.
|
|
960
1418
|
_selectBasemap(id) {
|
|
1419
|
+
const basemap = this._basemaps.find((candidate) => candidate.id === id);
|
|
1420
|
+
const isRaster = (basemap == null ? void 0 : basemap.source.type) === "raster";
|
|
1421
|
+
if (this._state.allowMultiple && isRaster) {
|
|
1422
|
+
this.toggleBasemap(id).catch(() => {
|
|
1423
|
+
});
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
961
1426
|
this.setBasemap(id).catch(() => {
|
|
962
1427
|
});
|
|
963
1428
|
}
|
|
@@ -1029,7 +1494,11 @@ class BasemapControl {
|
|
|
1029
1494
|
_createPanel() {
|
|
1030
1495
|
const panel = document.createElement("div");
|
|
1031
1496
|
panel.className = "basemap-control-panel";
|
|
1032
|
-
panel.style.width = `${this.
|
|
1497
|
+
panel.style.width = `${this._state.panelWidth}px`;
|
|
1498
|
+
if (this._state.panelHeight !== void 0) {
|
|
1499
|
+
panel.style.height = `${this._state.panelHeight}px`;
|
|
1500
|
+
panel.classList.add("is-resized");
|
|
1501
|
+
}
|
|
1033
1502
|
const header = document.createElement("div");
|
|
1034
1503
|
header.className = "basemap-control-header";
|
|
1035
1504
|
const title = document.createElement("span");
|
|
@@ -1047,18 +1516,37 @@ class BasemapControl {
|
|
|
1047
1516
|
this._content.className = "basemap-control-content";
|
|
1048
1517
|
panel.appendChild(header);
|
|
1049
1518
|
panel.appendChild(this._content);
|
|
1519
|
+
if (this._options.resizable) {
|
|
1520
|
+
panel.appendChild(this._createResizeHandle("bottom-left"));
|
|
1521
|
+
panel.appendChild(this._createResizeHandle("bottom-right"));
|
|
1522
|
+
}
|
|
1050
1523
|
return panel;
|
|
1051
1524
|
}
|
|
1052
|
-
|
|
1525
|
+
_createResizeHandle(corner) {
|
|
1526
|
+
const handle = document.createElement("div");
|
|
1527
|
+
handle.className = `basemap-control-resize-handle basemap-control-resize-${corner}`;
|
|
1528
|
+
handle.setAttribute("aria-hidden", "true");
|
|
1529
|
+
handle.addEventListener("pointerdown", (event) => this._startResize(event));
|
|
1530
|
+
return handle;
|
|
1531
|
+
}
|
|
1532
|
+
_renderContent(preserveResultsScroll = false) {
|
|
1533
|
+
var _a;
|
|
1053
1534
|
if (!this._content) return;
|
|
1054
1535
|
const categories = getBasemapCategories(this._basemaps);
|
|
1055
1536
|
const results = this._getFilteredBasemaps();
|
|
1537
|
+
const previousResultsScrollTop = preserveResultsScroll ? (_a = this._content.querySelector(".basemap-control-results")) == null ? void 0 : _a.scrollTop : void 0;
|
|
1056
1538
|
this._content.replaceChildren(
|
|
1057
1539
|
this._createSearchRow(),
|
|
1540
|
+
...this._options.showMultipleToggle ? [this._createMultipleToggleRow()] : [],
|
|
1541
|
+
...this._hasProviderSettings() ? [this._createProviderSettingsSection()] : [],
|
|
1058
1542
|
this._createFilterRow(this._providers, categories),
|
|
1059
1543
|
this._createStatus(results.length),
|
|
1060
1544
|
this._createResults(results)
|
|
1061
1545
|
);
|
|
1546
|
+
if (previousResultsScrollTop !== void 0) {
|
|
1547
|
+
const resultsElement = this._content.querySelector(".basemap-control-results");
|
|
1548
|
+
if (resultsElement) resultsElement.scrollTop = previousResultsScrollTop;
|
|
1549
|
+
}
|
|
1062
1550
|
}
|
|
1063
1551
|
_renderFilteredResults() {
|
|
1064
1552
|
var _a, _b;
|
|
@@ -1085,6 +1573,25 @@ class BasemapControl {
|
|
|
1085
1573
|
row.appendChild(this._createBeforeIdInput());
|
|
1086
1574
|
return row;
|
|
1087
1575
|
}
|
|
1576
|
+
_createMultipleToggleRow() {
|
|
1577
|
+
const label = document.createElement("label");
|
|
1578
|
+
label.className = "basemap-control-multiple-toggle";
|
|
1579
|
+
const checkbox = document.createElement("input");
|
|
1580
|
+
checkbox.type = "checkbox";
|
|
1581
|
+
checkbox.className = "basemap-control-multiple-checkbox";
|
|
1582
|
+
checkbox.checked = this._state.allowMultiple;
|
|
1583
|
+
checkbox.setAttribute("aria-label", "Add basemaps instead of replacing");
|
|
1584
|
+
checkbox.addEventListener("change", () => {
|
|
1585
|
+
this._state = { ...this._state, allowMultiple: checkbox.checked };
|
|
1586
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1587
|
+
});
|
|
1588
|
+
const text = document.createElement("span");
|
|
1589
|
+
text.className = "basemap-control-multiple-toggle-text";
|
|
1590
|
+
text.textContent = "Add basemaps (stack instead of replace)";
|
|
1591
|
+
label.appendChild(checkbox);
|
|
1592
|
+
label.appendChild(text);
|
|
1593
|
+
return label;
|
|
1594
|
+
}
|
|
1088
1595
|
_createSearchInput() {
|
|
1089
1596
|
const wrapper = document.createElement("div");
|
|
1090
1597
|
wrapper.className = "basemap-control-search";
|
|
@@ -1118,6 +1625,106 @@ class BasemapControl {
|
|
|
1118
1625
|
wrapper.appendChild(input);
|
|
1119
1626
|
return wrapper;
|
|
1120
1627
|
}
|
|
1628
|
+
_createProviderSettingsSection() {
|
|
1629
|
+
const details = document.createElement("details");
|
|
1630
|
+
details.className = "basemap-control-provider-settings";
|
|
1631
|
+
details.open = !this._providerSettingsCollapsed;
|
|
1632
|
+
details.addEventListener("toggle", () => {
|
|
1633
|
+
this._providerSettingsCollapsed = !details.open;
|
|
1634
|
+
});
|
|
1635
|
+
const summary = document.createElement("summary");
|
|
1636
|
+
summary.className = "basemap-control-provider-settings-summary";
|
|
1637
|
+
summary.textContent = "Provider settings";
|
|
1638
|
+
details.appendChild(summary);
|
|
1639
|
+
const fields = document.createElement("div");
|
|
1640
|
+
fields.className = "basemap-control-provider-settings-fields";
|
|
1641
|
+
if (this._hasMapTilerBasemaps()) {
|
|
1642
|
+
fields.appendChild(
|
|
1643
|
+
this._createProviderSettingsInput({
|
|
1644
|
+
className: "basemap-control-maptiler-key",
|
|
1645
|
+
type: "password",
|
|
1646
|
+
placeholder: "MapTiler API key",
|
|
1647
|
+
ariaLabel: "MapTiler API key",
|
|
1648
|
+
value: this._mapTilerApiKey,
|
|
1649
|
+
onInput: (value) => {
|
|
1650
|
+
this._mapTilerApiKey = value;
|
|
1651
|
+
}
|
|
1652
|
+
})
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
if (this._hasMapboxBasemaps()) {
|
|
1656
|
+
fields.appendChild(
|
|
1657
|
+
this._createProviderSettingsInput({
|
|
1658
|
+
className: "basemap-control-mapbox-token",
|
|
1659
|
+
type: "password",
|
|
1660
|
+
placeholder: "Mapbox access token",
|
|
1661
|
+
ariaLabel: "Mapbox access token",
|
|
1662
|
+
value: this._mapboxAccessToken,
|
|
1663
|
+
onInput: (value) => {
|
|
1664
|
+
this._mapboxAccessToken = value;
|
|
1665
|
+
}
|
|
1666
|
+
})
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
if (this._hasAmazonBasemaps()) {
|
|
1670
|
+
fields.appendChild(
|
|
1671
|
+
this._createProviderSettingsInput({
|
|
1672
|
+
className: "basemap-control-amazon-key",
|
|
1673
|
+
type: "password",
|
|
1674
|
+
placeholder: "Amazon API key",
|
|
1675
|
+
ariaLabel: "Amazon API key",
|
|
1676
|
+
value: this._amazonApiKey,
|
|
1677
|
+
onInput: (value) => {
|
|
1678
|
+
this._amazonApiKey = value;
|
|
1679
|
+
}
|
|
1680
|
+
})
|
|
1681
|
+
);
|
|
1682
|
+
fields.appendChild(
|
|
1683
|
+
this._createProviderSettingsInput({
|
|
1684
|
+
className: "basemap-control-aws-region",
|
|
1685
|
+
type: "text",
|
|
1686
|
+
placeholder: "AWS region",
|
|
1687
|
+
ariaLabel: "AWS region",
|
|
1688
|
+
value: this._awsRegion,
|
|
1689
|
+
onInput: (value) => {
|
|
1690
|
+
this._awsRegion = value;
|
|
1691
|
+
}
|
|
1692
|
+
})
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
details.appendChild(fields);
|
|
1696
|
+
return details;
|
|
1697
|
+
}
|
|
1698
|
+
_createProviderSettingsInput({
|
|
1699
|
+
className,
|
|
1700
|
+
type,
|
|
1701
|
+
placeholder,
|
|
1702
|
+
ariaLabel,
|
|
1703
|
+
value,
|
|
1704
|
+
onInput
|
|
1705
|
+
}) {
|
|
1706
|
+
const wrapper = document.createElement("div");
|
|
1707
|
+
wrapper.className = className;
|
|
1708
|
+
const input = document.createElement("input");
|
|
1709
|
+
input.className = "basemap-control-input";
|
|
1710
|
+
input.type = type;
|
|
1711
|
+
input.placeholder = placeholder;
|
|
1712
|
+
input.value = value;
|
|
1713
|
+
input.name = ariaLabel.toLowerCase().replace(/\s+/g, "-");
|
|
1714
|
+
input.autocomplete = "new-password";
|
|
1715
|
+
input.autocapitalize = "none";
|
|
1716
|
+
input.spellcheck = false;
|
|
1717
|
+
input.setAttribute("autocorrect", "off");
|
|
1718
|
+
input.setAttribute("aria-label", ariaLabel);
|
|
1719
|
+
input.addEventListener("input", () => {
|
|
1720
|
+
onInput(input.value);
|
|
1721
|
+
this._state = { ...this._state, error: void 0 };
|
|
1722
|
+
this._renderFilteredResults();
|
|
1723
|
+
this._emit({ type: "statechange", state: this.getState() });
|
|
1724
|
+
});
|
|
1725
|
+
wrapper.appendChild(input);
|
|
1726
|
+
return wrapper;
|
|
1727
|
+
}
|
|
1121
1728
|
_createFilterRow(providers, categories) {
|
|
1122
1729
|
const row = document.createElement("div");
|
|
1123
1730
|
row.className = "basemap-control-filters";
|
|
@@ -1193,7 +1800,7 @@ class BasemapControl {
|
|
|
1193
1800
|
row.type = "button";
|
|
1194
1801
|
row.className = "basemap-control-result";
|
|
1195
1802
|
row.dataset.basemapId = basemap.id;
|
|
1196
|
-
if (
|
|
1803
|
+
if (this._state.activeBasemapIds.includes(basemap.id)) {
|
|
1197
1804
|
row.classList.add("is-active");
|
|
1198
1805
|
row.setAttribute("aria-current", "true");
|
|
1199
1806
|
}
|
|
@@ -1235,6 +1842,132 @@ class BasemapControl {
|
|
|
1235
1842
|
template.innerHTML = value;
|
|
1236
1843
|
return template.content.textContent ?? value;
|
|
1237
1844
|
}
|
|
1845
|
+
_hasMapTilerBasemaps() {
|
|
1846
|
+
return this._basemaps.some((basemap) => basemap.provider === "maptiler");
|
|
1847
|
+
}
|
|
1848
|
+
_hasAmazonBasemaps() {
|
|
1849
|
+
return this._basemaps.some((basemap) => basemap.provider === "amazon");
|
|
1850
|
+
}
|
|
1851
|
+
_hasMapboxBasemaps() {
|
|
1852
|
+
return this._basemaps.some((basemap) => basemap.provider === "mapbox");
|
|
1853
|
+
}
|
|
1854
|
+
_hasProviderSettings() {
|
|
1855
|
+
return this._hasMapTilerBasemaps() || this._hasAmazonBasemaps() || this._hasMapboxBasemaps();
|
|
1856
|
+
}
|
|
1857
|
+
_resolveStyleUrl(basemap) {
|
|
1858
|
+
if (basemap.source.type === "raster") {
|
|
1859
|
+
throw new Error(`Basemap "${basemap.id}" is not a style basemap.`);
|
|
1860
|
+
}
|
|
1861
|
+
const url = basemap.source.url;
|
|
1862
|
+
if (basemap.provider === "amazon") {
|
|
1863
|
+
return this._resolveAmazonStyleUrl(url);
|
|
1864
|
+
}
|
|
1865
|
+
if (basemap.provider === "maptiler") {
|
|
1866
|
+
return this._resolveMapTilerStyleUrl(url);
|
|
1867
|
+
}
|
|
1868
|
+
if (basemap.provider === "mapbox") {
|
|
1869
|
+
return this._resolveMapboxStyleUrl(url);
|
|
1870
|
+
}
|
|
1871
|
+
return url;
|
|
1872
|
+
}
|
|
1873
|
+
_getStyleOptions(basemap) {
|
|
1874
|
+
if (basemap.provider === "mapbox") {
|
|
1875
|
+
return {
|
|
1876
|
+
validate: false,
|
|
1877
|
+
transformStyle: (_previousStyle, nextStyle) => this._transformMapboxStyle(nextStyle, this._mapboxAccessToken.trim())
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
return void 0;
|
|
1881
|
+
}
|
|
1882
|
+
_transformMapboxStyle(style, accessToken) {
|
|
1883
|
+
const encodedAccessToken = encodeURIComponent(accessToken);
|
|
1884
|
+
const sources = Object.fromEntries(
|
|
1885
|
+
Object.entries(style.sources).map(([id, source]) => {
|
|
1886
|
+
if ("url" in source && typeof source.url === "string") {
|
|
1887
|
+
return [id, { ...source, url: this._resolveMapboxInternalUrl(source.url, encodedAccessToken) }];
|
|
1888
|
+
}
|
|
1889
|
+
return [id, source];
|
|
1890
|
+
})
|
|
1891
|
+
);
|
|
1892
|
+
return {
|
|
1893
|
+
...style,
|
|
1894
|
+
glyphs: typeof style.glyphs === "string" ? this._resolveMapboxInternalUrl(style.glyphs, encodedAccessToken) : style.glyphs,
|
|
1895
|
+
sprite: this._resolveMapboxSprite(style.sprite, encodedAccessToken),
|
|
1896
|
+
projection: { type: "mercator" },
|
|
1897
|
+
sources
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
_resolveMapboxSprite(sprite, encodedAccessToken) {
|
|
1901
|
+
if (typeof sprite === "string") {
|
|
1902
|
+
return this._resolveMapboxInternalUrl(sprite, encodedAccessToken);
|
|
1903
|
+
}
|
|
1904
|
+
if (Array.isArray(sprite)) {
|
|
1905
|
+
return sprite.map((item) => ({
|
|
1906
|
+
...item,
|
|
1907
|
+
url: this._resolveMapboxInternalUrl(item.url, encodedAccessToken)
|
|
1908
|
+
}));
|
|
1909
|
+
}
|
|
1910
|
+
return sprite;
|
|
1911
|
+
}
|
|
1912
|
+
_resolveMapboxInternalUrl(url, encodedAccessToken) {
|
|
1913
|
+
if (url.startsWith("mapbox://sprites/")) {
|
|
1914
|
+
const [, owner, styleId] = /^mapbox:\/\/sprites\/([^/]+)\/(.+)$/.exec(url) ?? [];
|
|
1915
|
+
if (owner && styleId) {
|
|
1916
|
+
return `https://api.mapbox.com/styles/v1/${owner}/${styleId}/sprite?access_token=${encodedAccessToken}`;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (url.startsWith("mapbox://fonts/")) {
|
|
1920
|
+
const [, owner, fontPath] = /^mapbox:\/\/fonts\/([^/]+)\/(.+)$/.exec(url) ?? [];
|
|
1921
|
+
if (owner && fontPath) {
|
|
1922
|
+
return `https://api.mapbox.com/fonts/v1/${owner}/${fontPath}?access_token=${encodedAccessToken}`;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
if (url.startsWith("mapbox://")) {
|
|
1926
|
+
const tileset = url.replace(/^mapbox:\/\//, "");
|
|
1927
|
+
return `https://api.mapbox.com/v4/${tileset}.json?secure&access_token=${encodedAccessToken}`;
|
|
1928
|
+
}
|
|
1929
|
+
return url;
|
|
1930
|
+
}
|
|
1931
|
+
_resolveMapTilerStyleUrl(url) {
|
|
1932
|
+
const needsMapTilerKey = url.includes(API_KEY_PLACEHOLDER) || url.includes(MAPTILER_API_KEY_EXAMPLE) || url.endsWith(MAPTILER_API_KEY_QUERY) || url.endsWith(MAPTILER_API_KEY_EMPTY_QUERY);
|
|
1933
|
+
if (!needsMapTilerKey) return url;
|
|
1934
|
+
const apiKey = this._mapTilerApiKey.trim();
|
|
1935
|
+
if (!apiKey) {
|
|
1936
|
+
throw new Error("Enter a MapTiler API key before applying this basemap.");
|
|
1937
|
+
}
|
|
1938
|
+
const encodedApiKey = encodeURIComponent(apiKey);
|
|
1939
|
+
if (url.endsWith(MAPTILER_API_KEY_QUERY)) {
|
|
1940
|
+
return `${url}=${encodedApiKey}`;
|
|
1941
|
+
}
|
|
1942
|
+
if (url.endsWith(MAPTILER_API_KEY_EMPTY_QUERY)) {
|
|
1943
|
+
return `${url}${encodedApiKey}`;
|
|
1944
|
+
}
|
|
1945
|
+
return url.split(API_KEY_PLACEHOLDER).join(encodedApiKey).split(MAPTILER_API_KEY_EXAMPLE).join(encodedApiKey);
|
|
1946
|
+
}
|
|
1947
|
+
_resolveAmazonStyleUrl(url) {
|
|
1948
|
+
const apiKey = this._amazonApiKey.trim();
|
|
1949
|
+
const awsRegion = this._awsRegion.trim();
|
|
1950
|
+
if (url.includes(API_KEY_PLACEHOLDER) && !apiKey) {
|
|
1951
|
+
throw new Error("Enter an Amazon API key before applying this basemap.");
|
|
1952
|
+
}
|
|
1953
|
+
if (url.includes(AWS_REGION_PLACEHOLDER) && !awsRegion) {
|
|
1954
|
+
throw new Error("Enter an AWS region before applying this basemap.");
|
|
1955
|
+
}
|
|
1956
|
+
return url.split(AWS_REGION_PLACEHOLDER).join(awsRegion).split(API_KEY_PLACEHOLDER).join(encodeURIComponent(apiKey));
|
|
1957
|
+
}
|
|
1958
|
+
_resolveMapboxStyleUrl(url) {
|
|
1959
|
+
const accessToken = this._mapboxAccessToken.trim();
|
|
1960
|
+
if (url.includes(API_KEY_PLACEHOLDER) && !accessToken) {
|
|
1961
|
+
throw new Error("Enter a Mapbox access token before applying this basemap.");
|
|
1962
|
+
}
|
|
1963
|
+
if (this._isUrlLikeCredential(accessToken)) {
|
|
1964
|
+
throw new Error("Enter a valid Mapbox access token, not a URL.");
|
|
1965
|
+
}
|
|
1966
|
+
return url.split(API_KEY_PLACEHOLDER).join(encodeURIComponent(accessToken));
|
|
1967
|
+
}
|
|
1968
|
+
_isUrlLikeCredential(value) {
|
|
1969
|
+
return /^https?:\/\//i.test(value);
|
|
1970
|
+
}
|
|
1238
1971
|
_addRasterBasemap(basemap) {
|
|
1239
1972
|
if (!this._map || basemap.source.type !== "raster") return void 0;
|
|
1240
1973
|
const sourceId = `${CONTROL_SOURCE_PREFIX}-${basemap.id}`;
|
|
@@ -1256,13 +1989,9 @@ class BasemapControl {
|
|
|
1256
1989
|
};
|
|
1257
1990
|
this._map.addSource(sourceId, source);
|
|
1258
1991
|
this._map.addLayer(layer, beforeId);
|
|
1259
|
-
|
|
1260
|
-
this.
|
|
1261
|
-
return
|
|
1262
|
-
sourceId,
|
|
1263
|
-
layerId,
|
|
1264
|
-
beforeId
|
|
1265
|
-
};
|
|
1992
|
+
const managed = { sourceId, layerId, beforeId };
|
|
1993
|
+
this._managedRasters.set(basemap.id, managed);
|
|
1994
|
+
return managed;
|
|
1266
1995
|
}
|
|
1267
1996
|
_waitForStyleReady() {
|
|
1268
1997
|
if (!this._map) return Promise.resolve();
|
|
@@ -1271,32 +2000,43 @@ class BasemapControl {
|
|
|
1271
2000
|
}
|
|
1272
2001
|
return new Promise((resolve) => {
|
|
1273
2002
|
var _a, _b;
|
|
2003
|
+
let settled = false;
|
|
2004
|
+
let timer;
|
|
1274
2005
|
const done = () => {
|
|
1275
2006
|
var _a2, _b2;
|
|
2007
|
+
if (settled) return;
|
|
2008
|
+
settled = true;
|
|
2009
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1276
2010
|
(_a2 = this._map) == null ? void 0 : _a2.off("load", done);
|
|
1277
2011
|
(_b2 = this._map) == null ? void 0 : _b2.off("style.load", done);
|
|
1278
2012
|
resolve();
|
|
1279
2013
|
};
|
|
2014
|
+
timer = setTimeout(done, 1500);
|
|
1280
2015
|
(_a = this._map) == null ? void 0 : _a.once("load", done);
|
|
1281
2016
|
(_b = this._map) == null ? void 0 : _b.once("style.load", done);
|
|
1282
2017
|
});
|
|
1283
2018
|
}
|
|
2019
|
+
// Remove every managed raster basemap from the map.
|
|
1284
2020
|
_removeManagedBasemap() {
|
|
1285
2021
|
if (!this._map) return;
|
|
1286
|
-
[...this.
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
this.
|
|
2022
|
+
for (const id of [...this._managedRasters.keys()]) {
|
|
2023
|
+
this._removeManagedRaster(id);
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
// Remove a single managed raster basemap by its basemap id, returning the
|
|
2027
|
+
// managed source/layer record that was removed (if any).
|
|
2028
|
+
_removeManagedRaster(id) {
|
|
2029
|
+
var _a, _b;
|
|
2030
|
+
const managed = this._managedRasters.get(id);
|
|
2031
|
+
if (!managed) return void 0;
|
|
2032
|
+
if ((_a = this._map) == null ? void 0 : _a.getLayer(managed.layerId)) {
|
|
2033
|
+
this._map.removeLayer(managed.layerId);
|
|
2034
|
+
}
|
|
2035
|
+
if ((_b = this._map) == null ? void 0 : _b.getSource(managed.sourceId)) {
|
|
2036
|
+
this._map.removeSource(managed.sourceId);
|
|
2037
|
+
}
|
|
2038
|
+
this._managedRasters.delete(id);
|
|
2039
|
+
return managed;
|
|
1300
2040
|
}
|
|
1301
2041
|
_applyBasemapView(basemap) {
|
|
1302
2042
|
if (!this._map || !basemap.view) return;
|
|
@@ -1314,13 +2054,6 @@ class BasemapControl {
|
|
|
1314
2054
|
}
|
|
1315
2055
|
_setupEventListeners() {
|
|
1316
2056
|
var _a;
|
|
1317
|
-
this._clickOutsideHandler = (e) => {
|
|
1318
|
-
const target = e.target;
|
|
1319
|
-
if (this._container && this._panel && !this._container.contains(target) && !this._panel.contains(target)) {
|
|
1320
|
-
this.collapse();
|
|
1321
|
-
}
|
|
1322
|
-
};
|
|
1323
|
-
document.addEventListener("click", this._clickOutsideHandler);
|
|
1324
2057
|
this._resizeHandler = () => {
|
|
1325
2058
|
if (!this._state.collapsed) this._updatePanelPosition();
|
|
1326
2059
|
};
|
|
@@ -1375,6 +2108,44 @@ class BasemapControl {
|
|
|
1375
2108
|
break;
|
|
1376
2109
|
}
|
|
1377
2110
|
}
|
|
2111
|
+
// Begin a panel resize from a bottom corner. The panel stays pinned to its
|
|
2112
|
+
// toggle button, so resizing is measured from the button-anchored corner:
|
|
2113
|
+
// dragging either bottom handle grows or shrinks the panel away from it.
|
|
2114
|
+
_startResize(event) {
|
|
2115
|
+
var _a;
|
|
2116
|
+
if (!this._panel) return;
|
|
2117
|
+
event.preventDefault();
|
|
2118
|
+
event.stopPropagation();
|
|
2119
|
+
const position = this._getControlPosition();
|
|
2120
|
+
const isLeft = position === "top-left" || position === "bottom-left";
|
|
2121
|
+
const isTop = position === "top-left" || position === "top-right";
|
|
2122
|
+
const rect = this._panel.getBoundingClientRect();
|
|
2123
|
+
this._resizeAnchor = {
|
|
2124
|
+
x: isLeft ? rect.left : rect.right,
|
|
2125
|
+
y: isTop ? rect.top : rect.bottom,
|
|
2126
|
+
isLeft,
|
|
2127
|
+
isTop
|
|
2128
|
+
};
|
|
2129
|
+
const handle = event.currentTarget;
|
|
2130
|
+
this._resizeHandleEl = handle;
|
|
2131
|
+
(_a = handle.setPointerCapture) == null ? void 0 : _a.call(handle, event.pointerId);
|
|
2132
|
+
window.addEventListener("pointermove", this._onResizeMove);
|
|
2133
|
+
window.addEventListener("pointerup", this._onResizeEnd);
|
|
2134
|
+
window.addEventListener("pointercancel", this._onResizeEnd);
|
|
2135
|
+
}
|
|
2136
|
+
_getResizeBounds() {
|
|
2137
|
+
var _a;
|
|
2138
|
+
const mapRect = (_a = this._mapContainer) == null ? void 0 : _a.getBoundingClientRect();
|
|
2139
|
+
const availableWidth = ((mapRect == null ? void 0 : mapRect.width) ?? window.innerWidth) - PANEL_VIEWPORT_MARGIN * 2;
|
|
2140
|
+
const availableHeight = ((mapRect == null ? void 0 : mapRect.height) ?? window.innerHeight) - PANEL_VIEWPORT_MARGIN * 2;
|
|
2141
|
+
return {
|
|
2142
|
+
maxWidth: Math.max(MIN_PANEL_WIDTH, availableWidth),
|
|
2143
|
+
maxHeight: Math.max(MIN_PANEL_HEIGHT, availableHeight)
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
_clampSize(value, min, max) {
|
|
2147
|
+
return Math.round(Math.min(Math.max(value, min), max));
|
|
2148
|
+
}
|
|
1378
2149
|
}
|
|
1379
2150
|
export {
|
|
1380
2151
|
BasemapControl as B,
|
|
@@ -1386,4 +2157,4 @@ export {
|
|
|
1386
2157
|
getBasemapCategories as g,
|
|
1387
2158
|
resolveBasemapProviders as r
|
|
1388
2159
|
};
|
|
1389
|
-
//# sourceMappingURL=BasemapControl-
|
|
2160
|
+
//# sourceMappingURL=BasemapControl-DCusTnvr.js.map
|