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