maplibre-gl-basemap-control 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -2
- package/dist/{BasemapControl-DD97GXiq.js → BasemapControl-DCusTnvr.js} +243 -36
- package/dist/BasemapControl-DCusTnvr.js.map +1 -0
- package/dist/{BasemapControl-DrZ_VXsL.cjs → BasemapControl-DDvY9KVh.cjs} +243 -36
- 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 +88 -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 +18 -2
- 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/types.d.ts +55 -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-DD97GXiq.js.map +0 -1
- package/dist/BasemapControl-DrZ_VXsL.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -190,14 +190,50 @@ https://api.mapbox.com/styles/v1/mapbox/{styleId}?access_token={api-key}
|
|
|
190
190
|
| `providers` | `BasemapProvider[]` | `[]` | Custom provider labels |
|
|
191
191
|
| `includeDefaultBasemaps` | `boolean` | `true` | Include the built-in public catalog |
|
|
192
192
|
| `defaultBasemapId` | `string` | `undefined` | Basemap to apply after the control is added |
|
|
193
|
+
| `allowMultiple` | `boolean` | `false` | Stack raster basemaps instead of replacing the active one |
|
|
194
|
+
| `showMultipleToggle` | `boolean` | `true` | Show the in-panel toggle that switches between adding and replacing |
|
|
195
|
+
| `resizable` | `boolean` | `true` | Allow resizing the panel by dragging its bottom-left or bottom-right corner |
|
|
196
|
+
|
|
197
|
+
### Multiple Basemaps
|
|
198
|
+
|
|
199
|
+
By default, selecting a basemap replaces the active one. Set `allowMultiple: true`
|
|
200
|
+
to stack raster basemaps instead: each click adds the selected raster basemap as
|
|
201
|
+
an additional overlay, and clicking an already-active raster basemap removes it.
|
|
202
|
+
This lets a project hold several raster basemaps at once and switch between them by
|
|
203
|
+
toggling the entries in the panel.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
const control = new BasemapControl({
|
|
207
|
+
allowMultiple: true,
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The panel also shows an **Add basemaps** toggle so users can switch between adding
|
|
212
|
+
and replacing at runtime. Hide it with `showMultipleToggle: false`.
|
|
213
|
+
|
|
214
|
+
### Resizable Panel
|
|
215
|
+
|
|
216
|
+
The panel can be resized by dragging either of its bottom corners (bottom-left or
|
|
217
|
+
bottom-right). The resized width and height are reflected in `state.panelWidth` and
|
|
218
|
+
`state.panelHeight`. Set `resizable: false` to disable the handles.
|
|
219
|
+
|
|
220
|
+
Style basemaps cannot stack because they replace the entire map style, so selecting
|
|
221
|
+
a style basemap always replaces the active basemaps (and clears any stacked raster
|
|
222
|
+
overlays). Use the `before_id` input to control where each raster basemap is
|
|
223
|
+
inserted relative to existing layers.
|
|
193
224
|
|
|
194
225
|
### Methods
|
|
195
226
|
|
|
196
227
|
- `setBasemap(id)` - Apply a basemap and remove the previous plugin-managed basemap
|
|
228
|
+
- `addBasemap(id)` - Add a raster basemap as an additional overlay (style basemaps replace instead)
|
|
229
|
+
- `removeBasemap(id)` - Remove a previously added managed raster basemap
|
|
230
|
+
- `toggleBasemap(id)` - Add the raster basemap if inactive, otherwise remove it
|
|
231
|
+
- `isBasemapActive(id)` - Whether the basemap is currently active
|
|
197
232
|
- `setMapTilerApiKey(apiKey)` - Set or update the MapTiler API key used by MapTiler styles
|
|
198
233
|
- `setAmazonCredentials(apiKey, awsRegion)` - Set or update Amazon Location credentials
|
|
199
234
|
- `setMapboxAccessToken(accessToken)` - Set or update the Mapbox access token
|
|
200
|
-
- `getActiveBasemap()` - Return the
|
|
235
|
+
- `getActiveBasemap()` - Return the most recently selected basemap definition
|
|
236
|
+
- `getActiveBasemaps()` - Return all currently active basemap definitions
|
|
201
237
|
- `getBasemaps()` - Return the catalog
|
|
202
238
|
- `setBasemaps(basemaps)` - Replace the catalog
|
|
203
239
|
- `toggle()`, `expand()`, `collapse()` - Control panel visibility
|
|
@@ -211,7 +247,8 @@ before that layer.
|
|
|
211
247
|
|
|
212
248
|
### Events
|
|
213
249
|
|
|
214
|
-
- `basemapchange`
|
|
250
|
+
- `basemapchange` (includes a `mode` of `'replace'` or `'add'`)
|
|
251
|
+
- `basemapremove`
|
|
215
252
|
- `error`
|
|
216
253
|
- `collapse`
|
|
217
254
|
- `expand`
|
|
@@ -1101,7 +1101,10 @@ const DEFAULT_OPTIONS = {
|
|
|
1101
1101
|
title: "Basemaps",
|
|
1102
1102
|
panelWidth: 340,
|
|
1103
1103
|
className: "",
|
|
1104
|
-
includeDefaultBasemaps: true
|
|
1104
|
+
includeDefaultBasemaps: true,
|
|
1105
|
+
allowMultiple: false,
|
|
1106
|
+
showMultipleToggle: true,
|
|
1107
|
+
resizable: true
|
|
1105
1108
|
};
|
|
1106
1109
|
const CONTROL_SOURCE_PREFIX = "maplibre-basemap-control-source";
|
|
1107
1110
|
const CONTROL_LAYER_PREFIX = "";
|
|
@@ -1110,6 +1113,9 @@ const MAPTILER_API_KEY_EXAMPLE = "YOUR_MAPTILER_API_KEY";
|
|
|
1110
1113
|
const MAPTILER_API_KEY_QUERY = "?key";
|
|
1111
1114
|
const MAPTILER_API_KEY_EMPTY_QUERY = "?key=";
|
|
1112
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;
|
|
1113
1119
|
class BasemapControl {
|
|
1114
1120
|
constructor(options) {
|
|
1115
1121
|
__publicField(this, "_map");
|
|
@@ -1122,8 +1128,10 @@ class BasemapControl {
|
|
|
1122
1128
|
__publicField(this, "_basemaps");
|
|
1123
1129
|
__publicField(this, "_providers");
|
|
1124
1130
|
__publicField(this, "_eventHandlers", new globalThis.Map());
|
|
1125
|
-
|
|
1126
|
-
|
|
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());
|
|
1127
1135
|
__publicField(this, "_mapTilerApiKey", "");
|
|
1128
1136
|
__publicField(this, "_amazonApiKey", "");
|
|
1129
1137
|
__publicField(this, "_awsRegion", "");
|
|
@@ -1131,6 +1139,33 @@ class BasemapControl {
|
|
|
1131
1139
|
__publicField(this, "_providerSettingsCollapsed", true);
|
|
1132
1140
|
__publicField(this, "_resizeHandler", null);
|
|
1133
1141
|
__publicField(this, "_mapResizeHandler", null);
|
|
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
|
+
});
|
|
1134
1169
|
this._options = { ...DEFAULT_OPTIONS, ...options };
|
|
1135
1170
|
this._mapTilerApiKey = (options == null ? void 0 : options.mapTilerApiKey) ?? "";
|
|
1136
1171
|
this._amazonApiKey = (options == null ? void 0 : options.amazonApiKey) ?? "";
|
|
@@ -1149,6 +1184,8 @@ class BasemapControl {
|
|
|
1149
1184
|
collapsed: this._options.collapsed,
|
|
1150
1185
|
panelWidth: this._options.panelWidth,
|
|
1151
1186
|
activeBasemapId: this._options.defaultBasemapId,
|
|
1187
|
+
activeBasemapIds: this._options.defaultBasemapId ? [this._options.defaultBasemapId] : [],
|
|
1188
|
+
allowMultiple: this._options.allowMultiple,
|
|
1152
1189
|
query: "",
|
|
1153
1190
|
providerFilter: "",
|
|
1154
1191
|
categoryFilter: "",
|
|
@@ -1169,7 +1206,8 @@ class BasemapControl {
|
|
|
1169
1206
|
}
|
|
1170
1207
|
this._renderContent();
|
|
1171
1208
|
if (this._state.activeBasemapId) {
|
|
1172
|
-
this.
|
|
1209
|
+
this.setBasemap(this._state.activeBasemapId).catch(() => {
|
|
1210
|
+
});
|
|
1173
1211
|
}
|
|
1174
1212
|
return this._container;
|
|
1175
1213
|
}
|
|
@@ -1183,6 +1221,11 @@ class BasemapControl {
|
|
|
1183
1221
|
this._map.off("resize", this._mapResizeHandler);
|
|
1184
1222
|
this._mapResizeHandler = null;
|
|
1185
1223
|
}
|
|
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;
|
|
1186
1229
|
(_b = (_a = this._panel) == null ? void 0 : _a.parentNode) == null ? void 0 : _b.removeChild(this._panel);
|
|
1187
1230
|
(_d = (_c = this._container) == null ? void 0 : _c.parentNode) == null ? void 0 : _d.removeChild(this._container);
|
|
1188
1231
|
this._map = void 0;
|
|
@@ -1197,9 +1240,24 @@ class BasemapControl {
|
|
|
1197
1240
|
}
|
|
1198
1241
|
setState(newState) {
|
|
1199
1242
|
this._state = { ...this._state, ...newState };
|
|
1243
|
+
this._syncActiveBasemapState(newState);
|
|
1200
1244
|
this._renderContent();
|
|
1201
1245
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1202
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
|
+
}
|
|
1203
1261
|
getBasemaps() {
|
|
1204
1262
|
return [...this._basemaps];
|
|
1205
1263
|
}
|
|
@@ -1210,9 +1268,14 @@ class BasemapControl {
|
|
|
1210
1268
|
this._options.providers,
|
|
1211
1269
|
this._options.includeDefaultBasemaps
|
|
1212
1270
|
);
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
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
|
+
};
|
|
1216
1279
|
this._renderContent();
|
|
1217
1280
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1218
1281
|
}
|
|
@@ -1238,7 +1301,54 @@ class BasemapControl {
|
|
|
1238
1301
|
getActiveBasemap() {
|
|
1239
1302
|
return this._basemaps.find((basemap) => basemap.id === this._state.activeBasemapId);
|
|
1240
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.
|
|
1241
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) {
|
|
1242
1352
|
const basemap = this._basemaps.find((candidate) => candidate.id === id);
|
|
1243
1353
|
if (!basemap) {
|
|
1244
1354
|
const error = new Error(`Basemap "${id}" was not found.`);
|
|
@@ -1250,14 +1360,20 @@ class BasemapControl {
|
|
|
1250
1360
|
this._handleError(error, basemap);
|
|
1251
1361
|
throw error;
|
|
1252
1362
|
}
|
|
1363
|
+
const isRaster = basemap.source.type === "raster";
|
|
1364
|
+
const effectiveMode = isRaster ? mode : "replace";
|
|
1253
1365
|
this._state = { ...this._state, loading: true, error: void 0 };
|
|
1254
1366
|
this._renderContent(true);
|
|
1255
1367
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1256
1368
|
try {
|
|
1257
1369
|
let managedRaster;
|
|
1258
|
-
if (
|
|
1370
|
+
if (isRaster) {
|
|
1259
1371
|
await this._waitForStyleReady();
|
|
1260
|
-
|
|
1372
|
+
if (effectiveMode === "replace") {
|
|
1373
|
+
this._removeManagedBasemap();
|
|
1374
|
+
} else {
|
|
1375
|
+
this._removeManagedRaster(basemap.id);
|
|
1376
|
+
}
|
|
1261
1377
|
managedRaster = this._addRasterBasemap(basemap);
|
|
1262
1378
|
} else {
|
|
1263
1379
|
const styleUrl = this._resolveStyleUrl(basemap);
|
|
@@ -1270,9 +1386,11 @@ class BasemapControl {
|
|
|
1270
1386
|
}
|
|
1271
1387
|
}
|
|
1272
1388
|
this._applyBasemapView(basemap);
|
|
1389
|
+
const activeBasemapIds = effectiveMode === "add" ? [...this._state.activeBasemapIds.filter((value) => value !== basemap.id), basemap.id] : [basemap.id];
|
|
1273
1390
|
this._state = {
|
|
1274
1391
|
...this._state,
|
|
1275
1392
|
activeBasemapId: basemap.id,
|
|
1393
|
+
activeBasemapIds,
|
|
1276
1394
|
loading: false,
|
|
1277
1395
|
error: void 0
|
|
1278
1396
|
};
|
|
@@ -1281,7 +1399,8 @@ class BasemapControl {
|
|
|
1281
1399
|
type: "basemapchange",
|
|
1282
1400
|
state: this.getState(),
|
|
1283
1401
|
basemap,
|
|
1284
|
-
managedRaster
|
|
1402
|
+
managedRaster,
|
|
1403
|
+
mode: effectiveMode
|
|
1285
1404
|
});
|
|
1286
1405
|
this._emit({ type: "statechange", state: this.getState() });
|
|
1287
1406
|
} catch (cause) {
|
|
@@ -1292,10 +1411,18 @@ class BasemapControl {
|
|
|
1292
1411
|
throw error;
|
|
1293
1412
|
}
|
|
1294
1413
|
}
|
|
1295
|
-
//
|
|
1296
|
-
//
|
|
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
|
|
1297
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.
|
|
1298
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
|
+
}
|
|
1299
1426
|
this.setBasemap(id).catch(() => {
|
|
1300
1427
|
});
|
|
1301
1428
|
}
|
|
@@ -1367,7 +1494,11 @@ class BasemapControl {
|
|
|
1367
1494
|
_createPanel() {
|
|
1368
1495
|
const panel = document.createElement("div");
|
|
1369
1496
|
panel.className = "basemap-control-panel";
|
|
1370
|
-
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
|
+
}
|
|
1371
1502
|
const header = document.createElement("div");
|
|
1372
1503
|
header.className = "basemap-control-header";
|
|
1373
1504
|
const title = document.createElement("span");
|
|
@@ -1385,8 +1516,19 @@ class BasemapControl {
|
|
|
1385
1516
|
this._content.className = "basemap-control-content";
|
|
1386
1517
|
panel.appendChild(header);
|
|
1387
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
|
+
}
|
|
1388
1523
|
return panel;
|
|
1389
1524
|
}
|
|
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
|
+
}
|
|
1390
1532
|
_renderContent(preserveResultsScroll = false) {
|
|
1391
1533
|
var _a;
|
|
1392
1534
|
if (!this._content) return;
|
|
@@ -1395,6 +1537,7 @@ class BasemapControl {
|
|
|
1395
1537
|
const previousResultsScrollTop = preserveResultsScroll ? (_a = this._content.querySelector(".basemap-control-results")) == null ? void 0 : _a.scrollTop : void 0;
|
|
1396
1538
|
this._content.replaceChildren(
|
|
1397
1539
|
this._createSearchRow(),
|
|
1540
|
+
...this._options.showMultipleToggle ? [this._createMultipleToggleRow()] : [],
|
|
1398
1541
|
...this._hasProviderSettings() ? [this._createProviderSettingsSection()] : [],
|
|
1399
1542
|
this._createFilterRow(this._providers, categories),
|
|
1400
1543
|
this._createStatus(results.length),
|
|
@@ -1430,6 +1573,25 @@ class BasemapControl {
|
|
|
1430
1573
|
row.appendChild(this._createBeforeIdInput());
|
|
1431
1574
|
return row;
|
|
1432
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
|
+
}
|
|
1433
1595
|
_createSearchInput() {
|
|
1434
1596
|
const wrapper = document.createElement("div");
|
|
1435
1597
|
wrapper.className = "basemap-control-search";
|
|
@@ -1638,7 +1800,7 @@ class BasemapControl {
|
|
|
1638
1800
|
row.type = "button";
|
|
1639
1801
|
row.className = "basemap-control-result";
|
|
1640
1802
|
row.dataset.basemapId = basemap.id;
|
|
1641
|
-
if (
|
|
1803
|
+
if (this._state.activeBasemapIds.includes(basemap.id)) {
|
|
1642
1804
|
row.classList.add("is-active");
|
|
1643
1805
|
row.setAttribute("aria-current", "true");
|
|
1644
1806
|
}
|
|
@@ -1827,13 +1989,9 @@ class BasemapControl {
|
|
|
1827
1989
|
};
|
|
1828
1990
|
this._map.addSource(sourceId, source);
|
|
1829
1991
|
this._map.addLayer(layer, beforeId);
|
|
1830
|
-
|
|
1831
|
-
this.
|
|
1832
|
-
return
|
|
1833
|
-
sourceId,
|
|
1834
|
-
layerId,
|
|
1835
|
-
beforeId
|
|
1836
|
-
};
|
|
1992
|
+
const managed = { sourceId, layerId, beforeId };
|
|
1993
|
+
this._managedRasters.set(basemap.id, managed);
|
|
1994
|
+
return managed;
|
|
1837
1995
|
}
|
|
1838
1996
|
_waitForStyleReady() {
|
|
1839
1997
|
if (!this._map) return Promise.resolve();
|
|
@@ -1842,32 +2000,43 @@ class BasemapControl {
|
|
|
1842
2000
|
}
|
|
1843
2001
|
return new Promise((resolve) => {
|
|
1844
2002
|
var _a, _b;
|
|
2003
|
+
let settled = false;
|
|
2004
|
+
let timer;
|
|
1845
2005
|
const done = () => {
|
|
1846
2006
|
var _a2, _b2;
|
|
2007
|
+
if (settled) return;
|
|
2008
|
+
settled = true;
|
|
2009
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1847
2010
|
(_a2 = this._map) == null ? void 0 : _a2.off("load", done);
|
|
1848
2011
|
(_b2 = this._map) == null ? void 0 : _b2.off("style.load", done);
|
|
1849
2012
|
resolve();
|
|
1850
2013
|
};
|
|
2014
|
+
timer = setTimeout(done, 1500);
|
|
1851
2015
|
(_a = this._map) == null ? void 0 : _a.once("load", done);
|
|
1852
2016
|
(_b = this._map) == null ? void 0 : _b.once("style.load", done);
|
|
1853
2017
|
});
|
|
1854
2018
|
}
|
|
2019
|
+
// Remove every managed raster basemap from the map.
|
|
1855
2020
|
_removeManagedBasemap() {
|
|
1856
2021
|
if (!this._map) return;
|
|
1857
|
-
[...this.
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
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;
|
|
1871
2040
|
}
|
|
1872
2041
|
_applyBasemapView(basemap) {
|
|
1873
2042
|
if (!this._map || !basemap.view) return;
|
|
@@ -1939,6 +2108,44 @@ class BasemapControl {
|
|
|
1939
2108
|
break;
|
|
1940
2109
|
}
|
|
1941
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
|
+
}
|
|
1942
2149
|
}
|
|
1943
2150
|
export {
|
|
1944
2151
|
BasemapControl as B,
|
|
@@ -1950,4 +2157,4 @@ export {
|
|
|
1950
2157
|
getBasemapCategories as g,
|
|
1951
2158
|
resolveBasemapProviders as r
|
|
1952
2159
|
};
|
|
1953
|
-
//# sourceMappingURL=BasemapControl-
|
|
2160
|
+
//# sourceMappingURL=BasemapControl-DCusTnvr.js.map
|