@mapvx/web-js 3.5.0-dev.3 → 3.5.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/dist/cjs/controllers/routeController.js +396 -106
- package/dist/cjs/controllers/routeController.js.map +1 -1
- package/dist/cjs/domain/models/routeInstance.js +1 -0
- package/dist/cjs/domain/models/routeInstance.js.map +1 -1
- package/dist/cjs/logger/sentry.js +1 -1
- package/dist/cjs/map/map.js +250 -24
- package/dist/cjs/map/map.js.map +1 -1
- package/dist/cjs/map/mapInteractionOptions.js +18 -0
- package/dist/cjs/map/mapInteractionOptions.js.map +1 -1
- package/dist/es/controllers/routeController.d.ts +91 -13
- package/dist/es/controllers/routeController.d.ts.map +1 -1
- package/dist/es/controllers/routeController.js +396 -106
- package/dist/es/controllers/routeController.js.map +1 -1
- package/dist/es/domain/models/mapConfig.d.ts +76 -0
- package/dist/es/domain/models/mapConfig.d.ts.map +1 -1
- package/dist/es/domain/models/routeInstance.d.ts +70 -1
- package/dist/es/domain/models/routeInstance.d.ts.map +1 -1
- package/dist/es/domain/models/routeInstance.js +1 -0
- package/dist/es/domain/models/routeInstance.js.map +1 -1
- package/dist/es/logger/sentry.js +1 -1
- package/dist/es/map/map.d.ts +76 -0
- package/dist/es/map/map.d.ts.map +1 -1
- package/dist/es/map/map.js +250 -24
- package/dist/es/map/map.js.map +1 -1
- package/dist/es/map/mapInteractionOptions.d.ts +5 -1
- package/dist/es/map/mapInteractionOptions.d.ts.map +1 -1
- package/dist/es/map/mapInteractionOptions.js +18 -0
- package/dist/es/map/mapInteractionOptions.js.map +1 -1
- package/dist/umd/index.js +844 -208
- package/dist/umd/index.js.map +1 -1
- package/package.json +1 -1
package/dist/es/map/map.js
CHANGED
|
@@ -34,6 +34,22 @@ const TILE_RETRY_BASE_DELAY_MS = 1000;
|
|
|
34
34
|
* overlay until the callback arrives, so it must be released no matter what.
|
|
35
35
|
*/
|
|
36
36
|
const STYLE_READY_TIMEOUT_MS = 4000;
|
|
37
|
+
/**
|
|
38
|
+
* Frames a floor change waits before it will believe the indoor tiles are
|
|
39
|
+
* already rebuilt (see `updateMarkersWhenFloorSettles`). Genuinely a frame
|
|
40
|
+
* count: the reload is dispatched on the map's next render, so this is how
|
|
41
|
+
* many renders it gets to be observed in.
|
|
42
|
+
*/
|
|
43
|
+
const FLOOR_SETTLE_MIN_FRAMES = 3;
|
|
44
|
+
/**
|
|
45
|
+
* Longest a floor change waits for the new floor's tiles before switching the
|
|
46
|
+
* HTML markers anyway, so a stalled source never hides markers for good.
|
|
47
|
+
*
|
|
48
|
+
* A deadline rather than a frame count. The panels this matters on run at
|
|
49
|
+
* 20-30 fps, where a 60-frame cap is two to three seconds — and the wait also
|
|
50
|
+
* gates `addMarker`, so overshooting it is not merely a late marker switch.
|
|
51
|
+
*/
|
|
52
|
+
const FLOOR_SETTLE_MAX_MS = 1000;
|
|
37
53
|
/** Fill/line layer ids for one circle render-order bucket. */
|
|
38
54
|
function circleLayerIdsFor(order) {
|
|
39
55
|
const suffix = CIRCLE_LAYER_SUFFIXES[order];
|
|
@@ -169,6 +185,14 @@ import { buildInteractionOptions, shouldDisableTouchRotation } from "./mapIntera
|
|
|
169
185
|
* @hidden
|
|
170
186
|
*/
|
|
171
187
|
export class InternalMapVXMap extends Loggeable {
|
|
188
|
+
/** Whether a floor change is still rebuilding, so markers wait for it. */
|
|
189
|
+
get floorSettlePending() {
|
|
190
|
+
return this.floorSettleDeadline != null && this.now() < this.floorSettleDeadline;
|
|
191
|
+
}
|
|
192
|
+
/** Wall clock for the settle deadline; `Date.now` where `performance` is absent. */
|
|
193
|
+
now() {
|
|
194
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
195
|
+
}
|
|
172
196
|
/**
|
|
173
197
|
* Creates a new map instance with the parameters specified in mapConfig and assigns it to the provided HTML container.
|
|
174
198
|
* @param mapConfig Configuration parameters for the map.
|
|
@@ -232,6 +256,20 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
232
256
|
*/
|
|
233
257
|
this.tileRetryState = new WeakMap();
|
|
234
258
|
this.geoLocation = navigator.geolocation;
|
|
259
|
+
/** Floor-change settle bookkeeping (see `updateMarkersWhenFloorSettles`). */
|
|
260
|
+
this.floorSettleToken = 0;
|
|
261
|
+
/**
|
|
262
|
+
* When the floor-change settle stops holding markers back, or `null` when no
|
|
263
|
+
* change is in flight.
|
|
264
|
+
*
|
|
265
|
+
* A deadline rather than a flag, because `addMarker` reads it: the poll that
|
|
266
|
+
* would clear a flag runs on `requestAnimationFrame`, which does not fire in
|
|
267
|
+
* a backgrounded tab and does not run at all for a map torn down through
|
|
268
|
+
* MapLibre's own `remove()` rather than `destroyMap`. A flag left set there
|
|
269
|
+
* makes every later `addMarker` skip the call that attaches the marker, for
|
|
270
|
+
* good; a deadline expires on its own.
|
|
271
|
+
*/
|
|
272
|
+
this.floorSettleDeadline = null;
|
|
235
273
|
/** Owns the deck.gl overlay + GLB scene; created on style load only when 3D is active. */
|
|
236
274
|
this.scene3D = undefined;
|
|
237
275
|
if (rtlLanguages.includes((_a = mapConfig.lang) !== null && _a !== void 0 ? _a : "")) {
|
|
@@ -253,6 +291,8 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
253
291
|
this.onFloorChange = mapConfig.onFloorChange;
|
|
254
292
|
this.onParentPlaceChange = mapConfig.onParentPlaceChange;
|
|
255
293
|
this.mode = (_d = mapConfig.mode) !== null && _d !== void 0 ? _d : "2D";
|
|
294
|
+
this.styleRef = mapConfig.styleRef;
|
|
295
|
+
this.styleTheme = mapConfig.styleTheme;
|
|
256
296
|
this.scene3DConfig = mapConfig.scene3D;
|
|
257
297
|
this.initialCenter = mapConfig.center;
|
|
258
298
|
this.tileCacheConfig = (() => {
|
|
@@ -354,12 +394,18 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
354
394
|
.catch(console.error);
|
|
355
395
|
return;
|
|
356
396
|
}
|
|
357
|
-
|
|
358
|
-
|
|
397
|
+
// Through the same helper as `setStyle` and `changeParentPlaceTo`. This PR
|
|
398
|
+
// forwards `styleRef`/`styleTheme` to the initial load too, and a ref scoped
|
|
399
|
+
// to the user's client rather than to the api key resolves only over bearer
|
|
400
|
+
// — fetched over the api-key path it 4xx'd, and since this is the call that
|
|
401
|
+
// creates the map, the map was never created at all.
|
|
402
|
+
this.fetchVenueStyle(mapConfig.parentPlaceId, mapConfig.styleRef, mapConfig.styleTheme)
|
|
359
403
|
.then((style) => {
|
|
360
404
|
return this.onMapStyleLoaded(mapConfig, container, style);
|
|
361
405
|
})
|
|
362
|
-
.catch(
|
|
406
|
+
.catch((error) => {
|
|
407
|
+
this.logError(error, { functionName: "initialMapStyleSetUp" });
|
|
408
|
+
});
|
|
363
409
|
}
|
|
364
410
|
onMapStyleLoaded(mapConfig, container, style) {
|
|
365
411
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
@@ -377,6 +423,13 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
377
423
|
mapOptions.maxZoom = mapConfig.maxZoom;
|
|
378
424
|
if (mapConfig.minZoom)
|
|
379
425
|
mapOptions.minZoom = mapConfig.minZoom;
|
|
426
|
+
// Reduced internal resolution on request (fill-rate relief for low-end GPUs);
|
|
427
|
+
// MapLibre keeps devicePixelRatio when the option is left out.
|
|
428
|
+
if (mapConfig.pixelRatio !== undefined)
|
|
429
|
+
mapOptions.pixelRatio = mapConfig.pixelRatio;
|
|
430
|
+
// `0` disables the post-gesture fade tail entirely; keep MapLibre's default otherwise.
|
|
431
|
+
if (mapConfig.fadeDuration !== undefined)
|
|
432
|
+
mapOptions.fadeDuration = mapConfig.fadeDuration;
|
|
380
433
|
if (mapConfig.maxBounds && mapConfig.maxBounds.length > 1) {
|
|
381
434
|
const boundingBox = getBoundingBox(mapConfig.maxBounds);
|
|
382
435
|
mapOptions.maxBounds = new LngLatBounds([boundingBox[0].lng, boundingBox[0].lat], [boundingBox[1].lng, boundingBox[1].lat]);
|
|
@@ -566,6 +619,11 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
566
619
|
clearTimeout(this.styleReadyTimer);
|
|
567
620
|
this.styleReadyTimer = undefined;
|
|
568
621
|
}
|
|
622
|
+
// Drop any floor-settle poll in flight: bumping the token makes the next
|
|
623
|
+
// `requestAnimationFrame` callback return instead of re-queueing itself and
|
|
624
|
+
// re-attaching markers to a map that has already been removed.
|
|
625
|
+
this.floorSettleToken++;
|
|
626
|
+
this.floorSettleDeadline = null;
|
|
569
627
|
// Dispose the 3D scene's GPU resources before the map (and its shared WebGL context) go away —
|
|
570
628
|
// MapLibre's own teardown never calls the custom GLB layer's `onRemove`.
|
|
571
629
|
(_a = this.scene3D) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
@@ -634,8 +692,7 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
634
692
|
}
|
|
635
693
|
(_g = this.scene3D) === null || _g === void 0 ? void 0 : _g.onFloorChange(this.currentFloor);
|
|
636
694
|
if (updateStyle) {
|
|
637
|
-
this.
|
|
638
|
-
.fetchAndParseMapStyle(place === null || place === void 0 ? void 0 : place.mapvxId)
|
|
695
|
+
this.fetchVenueStyle(place === null || place === void 0 ? void 0 : place.mapvxId, this.styleRef, this.styleTheme)
|
|
639
696
|
.then((style) => {
|
|
640
697
|
const useServiceWorkerCaching = this.tileCacheConfig.enabled && this.tileCacheConfig.persistToServiceWorker;
|
|
641
698
|
const finalStyle = useServiceWorkerCaching ? this.transformStyleForCaching(style) : style;
|
|
@@ -650,9 +707,35 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
650
707
|
this.whenStyleUpdates(finalStyle);
|
|
651
708
|
onStyleReady === null || onStyleReady === void 0 ? void 0 : onStyleReady();
|
|
652
709
|
})
|
|
653
|
-
.catch(
|
|
710
|
+
.catch((error) => {
|
|
711
|
+
this.logError(error, { functionName: "changeParentPlaceTo" });
|
|
712
|
+
// Release the caller either way. `onStyleReady` is what a consumer
|
|
713
|
+
// hides its loading overlay on, so swallowing the failure here left
|
|
714
|
+
// the overlay up for good rather than merely unstyled.
|
|
715
|
+
onStyleReady === null || onStyleReady === void 0 ? void 0 : onStyleReady();
|
|
716
|
+
});
|
|
654
717
|
}
|
|
655
718
|
}
|
|
719
|
+
/**
|
|
720
|
+
* Fetch the venue style over whichever endpoint this map is authorized on.
|
|
721
|
+
*
|
|
722
|
+
* A bearer token authorizes by the user's client access rather than the api
|
|
723
|
+
* key's scopes, so a client's branded style resolves without granting that
|
|
724
|
+
* place to a shared api key; api-key consumers keep the
|
|
725
|
+
* `/api/sdk/v2/mapStyleJson` path.
|
|
726
|
+
*
|
|
727
|
+
* Both callers go through here so they cannot disagree. They used to: once
|
|
728
|
+
* `setStyle` had stored a `styleRef` it resolved over bearer, the next
|
|
729
|
+
* parent-place change refetched that same ref over the api-key path, whose
|
|
730
|
+
* key does not scope it — a non-ok response, a rejected promise, and a style
|
|
731
|
+
* that was never applied, with `onStyleReady` left unfired under a caller's
|
|
732
|
+
* loading overlay.
|
|
733
|
+
*/
|
|
734
|
+
fetchVenueStyle(placeId, styleRef, styleTheme) {
|
|
735
|
+
return this.authToken
|
|
736
|
+
? this.repository.fetchAndParseMapStyleByBearer(placeId, this.authToken, styleRef, styleTheme)
|
|
737
|
+
: this.repository.fetchAndParseMapStyle(placeId, styleRef, styleTheme);
|
|
738
|
+
}
|
|
656
739
|
/**
|
|
657
740
|
* Update the parent place and the current floor.
|
|
658
741
|
* Does not update layers, markers, etc.
|
|
@@ -746,14 +829,7 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
746
829
|
reportReady(error);
|
|
747
830
|
return;
|
|
748
831
|
}
|
|
749
|
-
|
|
750
|
-
// bearer-authenticated endpoint, which authorizes by the user's client access
|
|
751
|
-
// rather than the api key's scopes — so a client's branded style can be
|
|
752
|
-
// previewed/applied without granting that place to a shared api key.
|
|
753
|
-
// Api-key consumers keep the `/api/sdk/v2/mapStyleJson` path.
|
|
754
|
-
const stylePromise = this.authToken
|
|
755
|
-
? this.repository.fetchAndParseMapStyleByBearer(this.parentPlaceId, this.authToken, styleRef, styleTheme)
|
|
756
|
-
: this.repository.fetchAndParseMapStyle(this.parentPlaceId, styleRef, styleTheme);
|
|
832
|
+
const stylePromise = this.fetchVenueStyle(this.parentPlaceId, styleRef, styleTheme);
|
|
757
833
|
stylePromise
|
|
758
834
|
.then((style) => {
|
|
759
835
|
// A newer swap started while this style was in flight. Applying this one now
|
|
@@ -761,6 +837,13 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
761
837
|
// own the map and its caller's callback.
|
|
762
838
|
if (!isCurrent())
|
|
763
839
|
return;
|
|
840
|
+
// Remember what is actually on screen: `changeParentPlaceTo` refetches the
|
|
841
|
+
// style with these, so without this an explicitly applied style would be
|
|
842
|
+
// silently reverted to the constructor's on the next parent-place change.
|
|
843
|
+
// After the generation check: a superseded swap never reached the map, so it
|
|
844
|
+
// must not claim to be what is on it.
|
|
845
|
+
this.styleRef = styleRef;
|
|
846
|
+
this.styleTheme = styleTheme;
|
|
764
847
|
const useServiceWorkerCaching = this.tileCacheConfig.enabled && this.tileCacheConfig.persistToServiceWorker;
|
|
765
848
|
const finalStyle = useServiceWorkerCaching ? this.transformStyleForCaching(style) : style;
|
|
766
849
|
// Full (non-diff) swap so the previewed style completely replaces the base —
|
|
@@ -954,7 +1037,11 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
954
1037
|
}
|
|
955
1038
|
}
|
|
956
1039
|
const markerCreated = new MarkerAttribute(Object.assign(Object.assign({}, marker), { maxLabelWidthPx: (_a = marker.maxLabelWidthPx) !== null && _a !== void 0 ? _a : this.markerLayoutConfig.maxLabelWidthPx }));
|
|
957
|
-
|
|
1040
|
+
// While a floor change is still being rebuilt, the marker is shown by that
|
|
1041
|
+
// change's settle step, together with the new floor.
|
|
1042
|
+
if (!this.floorSettlePending) {
|
|
1043
|
+
markerCreated.changeFloor(this.currentFloor, this.map, this.isOutdoorFloor(this.currentFloor));
|
|
1044
|
+
}
|
|
958
1045
|
this.markers.push(markerCreated);
|
|
959
1046
|
this.markerLayoutController.scheduleRelayout();
|
|
960
1047
|
this.logEvent("addMarker");
|
|
@@ -1371,12 +1458,110 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1371
1458
|
if (this.innerFloors.every((floor) => floor.key !== floorKey) && floorKey !== "") {
|
|
1372
1459
|
this.logEvent("invalidFloorKey", { floorKey: floorKeyString });
|
|
1373
1460
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1461
|
+
// One style read for the whole floor change. `getStyle()` serializes every
|
|
1462
|
+
// source and layer of the venue style, and the second read is the expensive
|
|
1463
|
+
// one: `updateFiltersTo` writes filters and layout properties in between,
|
|
1464
|
+
// and each write nulls maplibre's `_serializedLayers` cache, so anything
|
|
1465
|
+
// that reads the style afterwards rebuilds it from scratch.
|
|
1466
|
+
const layers = this.safeStyleLayers();
|
|
1467
|
+
this.updateFiltersTo(floorKeyString, layers);
|
|
1468
|
+
this.updateMarkersWhenFloorSettles(floorKeyString, layers);
|
|
1376
1469
|
this.refreshCircles();
|
|
1377
1470
|
this.routeController.updateRouteLayers(floorKeyString);
|
|
1378
1471
|
this.routeController.updateRouteMarkerVisibility(floorKeyString);
|
|
1379
1472
|
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Show/hide the HTML markers for `floorId` once the indoor tiles have been
|
|
1475
|
+
* rebuilt with the new floor filters.
|
|
1476
|
+
*
|
|
1477
|
+
* A floor change is a `setFilter` on every indoor layer: MapLibre rebuilds the
|
|
1478
|
+
* tile buckets in its worker, so the new floor appears a few frames later
|
|
1479
|
+
* (hundreds of ms on a low-end panel) while a marker is a DOM element that
|
|
1480
|
+
* would move instantly. Waiting for the source to report loaded makes floor
|
|
1481
|
+
* polygons and markers switch in the same frame. The wait is bounded, is
|
|
1482
|
+
* dropped when a newer floor change arrives, and is skipped outside a
|
|
1483
|
+
* browser (no `requestAnimationFrame`).
|
|
1484
|
+
*/
|
|
1485
|
+
updateMarkersWhenFloorSettles(floorId, styleLayers) {
|
|
1486
|
+
const token = ++this.floorSettleToken;
|
|
1487
|
+
// Resolved rather than probed with `hasStyle()`, which is another full
|
|
1488
|
+
// `getStyle()` — and by this point the most expensive kind, because
|
|
1489
|
+
// `updateFiltersTo` has just invalidated the serialized-layer cache.
|
|
1490
|
+
const layers = styleLayers === undefined ? this.safeStyleLayers() : styleLayers;
|
|
1491
|
+
if (typeof requestAnimationFrame !== "function" || layers === null) {
|
|
1492
|
+
// No poll will run for this floor change, so nothing would ever clear the
|
|
1493
|
+
// flag later: leaving it set makes every subsequent `addMarker` skip
|
|
1494
|
+
// `changeFloor` and the marker is never attached to the map.
|
|
1495
|
+
this.floorSettleDeadline = null;
|
|
1496
|
+
this.updateMarkersTo(floorId);
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
const sourceIds = this.floorSettleSourceIds(floorId, layers);
|
|
1500
|
+
const deadline = this.now() + FLOOR_SETTLE_MAX_MS;
|
|
1501
|
+
this.floorSettleDeadline = deadline;
|
|
1502
|
+
let sawReloading = false;
|
|
1503
|
+
let frames = 0;
|
|
1504
|
+
const poll = () => {
|
|
1505
|
+
if (token !== this.floorSettleToken)
|
|
1506
|
+
return;
|
|
1507
|
+
frames++;
|
|
1508
|
+
const loaded = sourceIds.every((id) => this.isSourceSettled(id));
|
|
1509
|
+
if (!loaded)
|
|
1510
|
+
sawReloading = true;
|
|
1511
|
+
// The reload is dispatched on the map's next render, which may run after
|
|
1512
|
+
// this callback within the same frame: give it a couple of frames to be
|
|
1513
|
+
// observed before concluding there was nothing to reload.
|
|
1514
|
+
const settled = loaded && (sawReloading || frames >= FLOOR_SETTLE_MIN_FRAMES);
|
|
1515
|
+
if (settled || this.now() >= deadline) {
|
|
1516
|
+
this.floorSettleDeadline = null;
|
|
1517
|
+
this.updateMarkersTo(floorId);
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
requestAnimationFrame(poll);
|
|
1521
|
+
};
|
|
1522
|
+
requestAnimationFrame(poll);
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Sources whose tiles a switch to `floorId` actually reloads, and which the
|
|
1526
|
+
* marker settle therefore has to wait on.
|
|
1527
|
+
*
|
|
1528
|
+
* With a vector basemap that is the source the `indoor-*` layers draw from,
|
|
1529
|
+
* because the floor change is a `setFilter` over those layers. An offline
|
|
1530
|
+
* bundle's raster basemap switches floors by making `raster-floor-<key>`
|
|
1531
|
+
* visible instead, and those tiles only begin loading at that moment — while
|
|
1532
|
+
* its `indoor-*` layers carry labels and hover, are already loaded, and would
|
|
1533
|
+
* report settled at once, letting the markers switch a floor before its image
|
|
1534
|
+
* had painted. That is the configuration this wait exists for, so both are
|
|
1535
|
+
* waited on.
|
|
1536
|
+
*/
|
|
1537
|
+
floorSettleSourceIds(floorId, layers) {
|
|
1538
|
+
const ids = new Set();
|
|
1539
|
+
const rasterFloor = layers.find((layer) => layer.id === `raster-floor-${floorId}`);
|
|
1540
|
+
if (rasterFloor && "source" in rasterFloor && typeof rasterFloor.source === "string") {
|
|
1541
|
+
ids.add(rasterFloor.source);
|
|
1542
|
+
}
|
|
1543
|
+
ids.add(this.indoorSourceId(layers));
|
|
1544
|
+
return [...ids];
|
|
1545
|
+
}
|
|
1546
|
+
/** The vector source the `indoor-*` layers draw from (`indoorequal` by default). */
|
|
1547
|
+
indoorSourceId(layers) {
|
|
1548
|
+
for (const layer of layers) {
|
|
1549
|
+
if (layer.id.startsWith("indoor-") && "source" in layer && typeof layer.source === "string") {
|
|
1550
|
+
return layer.source;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
return "indoorequal";
|
|
1554
|
+
}
|
|
1555
|
+
isSourceSettled(sourceId) {
|
|
1556
|
+
try {
|
|
1557
|
+
if (!this.map.getSource(sourceId))
|
|
1558
|
+
return true;
|
|
1559
|
+
return this.map.isSourceLoaded(sourceId) !== false;
|
|
1560
|
+
}
|
|
1561
|
+
catch (_a) {
|
|
1562
|
+
return true;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1380
1565
|
getContainer() {
|
|
1381
1566
|
return this.map.getContainer();
|
|
1382
1567
|
}
|
|
@@ -1398,17 +1583,40 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1398
1583
|
});
|
|
1399
1584
|
this.markerLayoutController.scheduleRelayout();
|
|
1400
1585
|
}
|
|
1401
|
-
updateFiltersTo(floorId) {
|
|
1402
|
-
var _a, _b, _c
|
|
1586
|
+
updateFiltersTo(floorId, styleLayers) {
|
|
1587
|
+
var _a, _b, _c;
|
|
1403
1588
|
if (!this.map)
|
|
1404
1589
|
return;
|
|
1405
|
-
|
|
1590
|
+
// `null` means the caller looked and there was no style; only `undefined`
|
|
1591
|
+
// means it did not look.
|
|
1592
|
+
const layers = (_a = (styleLayers === undefined ? this.safeStyleLayers() : styleLayers)) !== null && _a !== void 0 ? _a : [];
|
|
1593
|
+
// Raster basemap (offline bundles baked with one raster archive per floor):
|
|
1594
|
+
// a floor is switched by showing its `raster-floor-<key>` layer and hiding
|
|
1595
|
+
// the others. The remaining `indoor-*` layers (labels, hover, highlights)
|
|
1596
|
+
// are still vector and keep going through the filter logic below.
|
|
1597
|
+
const rasterFloorPrefix = "raster-floor-";
|
|
1598
|
+
// Only switch the raster basemap when there is a baked layer to switch to.
|
|
1599
|
+
// Hiding every raster floor leaves the basemap blank, and no id can match in
|
|
1600
|
+
// two cases: no floor at all (an outdoor place, or a venue with no floors,
|
|
1601
|
+
// where `currentFloor` is `""`), and a floor the bundle has no raster
|
|
1602
|
+
// archive for — a venue where only some floors are baked, or a floor added
|
|
1603
|
+
// after the bundle was built. Keeping the current one visible is the safe
|
|
1604
|
+
// fallback for both.
|
|
1605
|
+
const rasterFloorLayerIds = layers
|
|
1606
|
+
.filter((l) => l.id.startsWith(rasterFloorPrefix))
|
|
1607
|
+
.map((l) => l.id);
|
|
1608
|
+
const targetRasterFloor = rasterFloorPrefix + floorId;
|
|
1609
|
+
if (floorId && rasterFloorLayerIds.includes(targetRasterFloor)) {
|
|
1610
|
+
rasterFloorLayerIds.forEach((id) => {
|
|
1611
|
+
this.map.setLayoutProperty(id, "visibility", id === targetRasterFloor ? "visible" : "none");
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1406
1614
|
layers
|
|
1407
1615
|
.filter((l) => l.id.startsWith("base-indoor-"))
|
|
1408
1616
|
.forEach((l) => {
|
|
1409
1617
|
this.map.removeLayer(l.id);
|
|
1410
1618
|
});
|
|
1411
|
-
const baseFloorId = (
|
|
1619
|
+
const baseFloorId = (_b = this.innerFloors.find((floor) => floor.key === floorId)) === null || _b === void 0 ? void 0 : _b.baseFloor;
|
|
1412
1620
|
const indoorLayers = layers.filter((layer) => layer.id.startsWith("indoor-"));
|
|
1413
1621
|
// Resolve each indoor layer's declared (base) filter before we start folding floor
|
|
1414
1622
|
// filters into it — and before cloning it into a `base-indoor-*` layer, which copies
|
|
@@ -1420,7 +1628,7 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1420
1628
|
// declared one.
|
|
1421
1629
|
indoorLayers.forEach((layer) => this.captureDeclaredBaseFilter(layer.id));
|
|
1422
1630
|
if (baseFloorId != undefined) {
|
|
1423
|
-
const firstLayerId = (
|
|
1631
|
+
const firstLayerId = (_c = indoorLayers[0]) === null || _c === void 0 ? void 0 : _c.id;
|
|
1424
1632
|
indoorLayers
|
|
1425
1633
|
.filter((layer) => layer.type !== "fill-extrusion")
|
|
1426
1634
|
.forEach((layer) => {
|
|
@@ -1727,8 +1935,9 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1727
1935
|
var _a;
|
|
1728
1936
|
try {
|
|
1729
1937
|
this.updatePlaceAndFloor(placeId, floorId);
|
|
1730
|
-
this.
|
|
1731
|
-
this.
|
|
1938
|
+
const layers = this.safeStyleLayers();
|
|
1939
|
+
this.updateFiltersTo(floorId, layers);
|
|
1940
|
+
this.updateMarkersWhenFloorSettles(floorId, layers);
|
|
1732
1941
|
(_a = this.onFloorChange) === null || _a === void 0 ? void 0 : _a.call(this, floorId);
|
|
1733
1942
|
this.logEvent("updatePlaceAndFloorForRouting", { floorId });
|
|
1734
1943
|
}
|
|
@@ -2331,6 +2540,23 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2331
2540
|
* ("Cannot read properties of undefined"), so call sites that only need the style to
|
|
2332
2541
|
* exist should gate on this rather than on `isStyleLoaded()`.
|
|
2333
2542
|
*/
|
|
2543
|
+
/**
|
|
2544
|
+
* This style's layers, or `null` when the map has no style right now.
|
|
2545
|
+
*
|
|
2546
|
+
* The one place the style is read for a floor change, so callers can pass the
|
|
2547
|
+
* result on instead of each probing again — `getStyle()` serializes every
|
|
2548
|
+
* source and layer, and `Style._updateLayer` drops the cache behind it on
|
|
2549
|
+
* every filter or layout write.
|
|
2550
|
+
*/
|
|
2551
|
+
safeStyleLayers() {
|
|
2552
|
+
var _a, _b, _c;
|
|
2553
|
+
try {
|
|
2554
|
+
return (_c = (_b = (_a = this.map) === null || _a === void 0 ? void 0 : _a.getStyle()) === null || _b === void 0 ? void 0 : _b.layers) !== null && _c !== void 0 ? _c : null;
|
|
2555
|
+
}
|
|
2556
|
+
catch (_d) {
|
|
2557
|
+
return null;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2334
2560
|
hasStyle() {
|
|
2335
2561
|
var _a;
|
|
2336
2562
|
// `map.getStyle()` is the PUBLIC probe: it returns the serialized style, or throws
|