@mapvx/web-js 4.0.3 → 4.0.4
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/index.js +4 -2
- package/dist/es/assets/icons.d.ts +0 -1
- package/dist/es/assets/icons.js +0 -50
- package/dist/es/config/draco.d.ts +0 -1
- package/dist/es/config/draco.js +0 -10
- package/dist/es/config/sdkConfig.d.ts +0 -1
- package/dist/es/config/sdkConfig.js +0 -1
- package/dist/es/controllers/markerLayoutController.d.ts +0 -1
- package/dist/es/controllers/markerLayoutController.js +0 -103
- package/dist/es/controllers/routeController.d.ts +0 -1
- package/dist/es/controllers/routeController.js +1 -473
- package/dist/es/domain/models/_internal.d.ts +0 -1
- package/dist/es/domain/models/_internal.js +0 -8
- package/dist/es/domain/models/animation.d.ts +0 -1
- package/dist/es/domain/models/animation.js +0 -6
- package/dist/es/domain/models/banner.d.ts +0 -1
- package/dist/es/domain/models/banner.js +0 -10
- package/dist/es/domain/models/campaign.d.ts +0 -1
- package/dist/es/domain/models/campaign.js +0 -29
- package/dist/es/domain/models/categories.d.ts +0 -1
- package/dist/es/domain/models/categories.js +0 -20
- package/dist/es/domain/models/circle.d.ts +0 -1
- package/dist/es/domain/models/circle.js +0 -118
- package/dist/es/domain/models/cityFilterOption.d.ts +0 -1
- package/dist/es/domain/models/cityFilterOption.js +0 -1
- package/dist/es/domain/models/configuration.d.ts +0 -1
- package/dist/es/domain/models/configuration.js +0 -1
- package/dist/es/domain/models/cssCustomization.d.ts +0 -1
- package/dist/es/domain/models/cssCustomization.js +0 -1
- package/dist/es/domain/models/fitOptions.d.ts +0 -1
- package/dist/es/domain/models/fitOptions.js +0 -1
- package/dist/es/domain/models/innerFloors.d.ts +0 -1
- package/dist/es/domain/models/innerFloors.js +0 -1
- package/dist/es/domain/models/institution.d.ts +0 -1
- package/dist/es/domain/models/institution.js +0 -26
- package/dist/es/domain/models/latLng.d.ts +0 -1
- package/dist/es/domain/models/latLng.js +0 -1
- package/dist/es/domain/models/location.d.ts +0 -1
- package/dist/es/domain/models/location.js +0 -1
- package/dist/es/domain/models/loggeable.d.ts +0 -1
- package/dist/es/domain/models/loggeable.js +0 -24
- package/dist/es/domain/models/mapCamera.d.ts +0 -1
- package/dist/es/domain/models/mapCamera.js +0 -1
- package/dist/es/domain/models/mapConfig.d.ts +0 -1
- package/dist/es/domain/models/mapConfig.js +1 -17
- package/dist/es/domain/models/marker.d.ts +0 -1
- package/dist/es/domain/models/marker.js +0 -292
- package/dist/es/domain/models/multilanguage.d.ts +0 -1
- package/dist/es/domain/models/multilanguage.js +0 -10
- package/dist/es/domain/models/openingHours.d.ts +0 -1
- package/dist/es/domain/models/openingHours.js +0 -1
- package/dist/es/domain/models/place.d.ts +0 -1
- package/dist/es/domain/models/place.js +0 -68
- package/dist/es/domain/models/platform.d.ts +0 -1
- package/dist/es/domain/models/platform.js +0 -1
- package/dist/es/domain/models/popover.d.ts +0 -1
- package/dist/es/domain/models/popover.js +0 -1
- package/dist/es/domain/models/product.d.ts +0 -1
- package/dist/es/domain/models/product.js +0 -1
- package/dist/es/domain/models/property.d.ts +0 -1
- package/dist/es/domain/models/property.js +0 -16
- package/dist/es/domain/models/route.d.ts +0 -1
- package/dist/es/domain/models/route.js +0 -71
- package/dist/es/domain/models/routeConfiguration.d.ts +0 -1
- package/dist/es/domain/models/routeConfiguration.js +0 -36
- package/dist/es/domain/models/routeInstance.d.ts +0 -1
- package/dist/es/domain/models/routeInstance.js +0 -8
- package/dist/es/domain/models/routeStyle.d.ts +0 -1
- package/dist/es/domain/models/routeStyle.js +0 -1
- package/dist/es/domain/models/scene3D.d.ts +0 -1
- package/dist/es/domain/models/scene3D.js +0 -1
- package/dist/es/domain/models/transport.d.ts +0 -1
- package/dist/es/domain/models/transport.js +0 -12
- package/dist/es/domain/ports/ICache.d.ts +0 -1
- package/dist/es/domain/ports/ICache.js +0 -1
- package/dist/es/domain/ports/IHttpClient.d.ts +0 -1
- package/dist/es/domain/ports/IHttpClient.js +0 -1
- package/dist/es/domain/ports/ILogger.d.ts +0 -1
- package/dist/es/domain/ports/ILogger.js +0 -9
- package/dist/es/domain/ports/index.d.ts +0 -1
- package/dist/es/domain/ports/index.js +0 -5
- package/dist/es/index.d.ts +0 -1
- package/dist/es/index.js +1 -28
- package/dist/es/infrastructure/cache/CacheManager.d.ts +0 -1
- package/dist/es/infrastructure/cache/CacheManager.js +0 -94
- package/dist/es/infrastructure/cache/LRUCache.d.ts +0 -1
- package/dist/es/infrastructure/cache/LRUCache.js +0 -57
- package/dist/es/infrastructure/cache/PersistentCache.d.ts +0 -1
- package/dist/es/infrastructure/cache/PersistentCache.js +0 -51
- package/dist/es/infrastructure/cache/cacheConfig.d.ts +0 -1
- package/dist/es/infrastructure/cache/cacheConfig.js +8 -27
- package/dist/es/infrastructure/http/FetchHttpClient.d.ts +0 -1
- package/dist/es/infrastructure/http/FetchHttpClient.js +0 -36
- package/dist/es/infrastructure/logging/MVXLogger.d.ts +0 -1
- package/dist/es/infrastructure/logging/MVXLogger.js +0 -37
- package/dist/es/interfaces/cache.d.ts +0 -1
- package/dist/es/interfaces/cache.js +0 -1
- package/dist/es/interfaces/healthResponse.d.ts +0 -1
- package/dist/es/interfaces/healthResponse.js +0 -1
- package/dist/es/interfaces/institutionResponse.d.ts +0 -1
- package/dist/es/interfaces/institutionResponse.js +0 -1
- package/dist/es/interfaces/metadata.d.ts +0 -1
- package/dist/es/interfaces/metadata.js +0 -1
- package/dist/es/interfaces/placeResponse.d.ts +0 -1
- package/dist/es/interfaces/placeResponse.js +0 -1
- package/dist/es/interfaces/routeCacheResponse.d.ts +0 -1
- package/dist/es/interfaces/routeCacheResponse.js +0 -1
- package/dist/es/interfaces/routeResponse.d.ts +0 -1
- package/dist/es/interfaces/routeResponse.js +0 -1
- package/dist/es/interfaces/styleResponse.d.ts +0 -1
- package/dist/es/interfaces/styleResponse.js +0 -1
- package/dist/es/logger/logger.d.ts +0 -1
- package/dist/es/logger/logger.js +0 -10
- package/dist/es/logger/sentry.d.ts +0 -1
- package/dist/es/logger/sentry.js +1 -39
- package/dist/es/map/fitCamera.d.ts +0 -1
- package/dist/es/map/fitCamera.js +0 -44
- package/dist/es/map/generated/maplibreWorkerSource.d.ts +0 -1
- package/dist/es/map/generated/maplibreWorkerSource.js +0 -12
- package/dist/es/map/installMapLibreWorker.d.ts +0 -1
- package/dist/es/map/installMapLibreWorker.js +0 -100
- package/dist/es/map/liveMapFitTransform.d.ts +0 -1
- package/dist/es/map/liveMapFitTransform.js +0 -82
- package/dist/es/map/map.d.ts +0 -1
- package/dist/es/map/map.js +4 -681
- package/dist/es/map/mapInteractionOptions.d.ts +0 -1
- package/dist/es/map/mapInteractionOptions.js +0 -35
- package/dist/es/map/scene3DController.d.ts +0 -1
- package/dist/es/map/scene3DController.js +0 -221
- package/dist/es/repository/repository.d.ts +0 -1
- package/dist/es/repository/repository.js +0 -56
- package/dist/es/repository/requester.d.ts +0 -1
- package/dist/es/repository/requester.js +0 -233
- package/dist/es/sdk.d.ts +0 -1
- package/dist/es/sdk.js +0 -35
- package/dist/es/utils/3d.d.ts +0 -1
- package/dist/es/utils/3d.js +0 -79
- package/dist/es/utils/deckLayers.d.ts +0 -1
- package/dist/es/utils/deckLayers.js +1 -27
- package/dist/es/utils/error.d.ts +0 -1
- package/dist/es/utils/error.js +0 -7
- package/dist/es/utils/images.d.ts +0 -1
- package/dist/es/utils/images.js +0 -7
- package/dist/es/utils/loadGlb.d.ts +0 -1
- package/dist/es/utils/loadGlb.js +2 -96
- package/dist/es/utils/mapvxHostname.d.ts +0 -1
- package/dist/es/utils/mapvxHostname.js +0 -11
- package/dist/es/utils/nav-functions.d.ts +0 -1
- package/dist/es/utils/nav-functions.js +0 -82
- package/dist/es/utils/opening-hours-helper.d.ts +0 -1
- package/dist/es/utils/opening-hours-helper.js +6 -382
- package/dist/es/utils/preconnect.d.ts +0 -1
- package/dist/es/utils/preconnect.js +0 -61
- package/dist/es/utils/route-utils.d.ts +0 -1
- package/dist/es/utils/route-utils.js +0 -25
- package/dist/es/utils/semaphore.d.ts +0 -1
- package/dist/es/utils/semaphore.js +0 -78
- package/dist/es/utils/three.d.ts +0 -1
- package/dist/es/utils/three.js +0 -43
- package/dist/es/utils/threeScene.d.ts +0 -1
- package/dist/es/utils/threeScene.js +0 -38
- package/dist/es/utils/update-css.d.ts +0 -1
- package/dist/es/utils/update-css.js +0 -26
- package/dist/es/utils/utils.d.ts +0 -1
- package/dist/es/utils/utils.js +0 -53
- package/dist/umd/index.js +4 -29240
- package/dist/umd/index.js.LICENSE.txt +1 -0
- package/dist/umd/styles.css +0 -1
- package/dist/umd/styles.js +3 -32
- package/package.json +11 -5
- package/dist/cjs/index.js.map +0 -1
- package/dist/es/assets/icons.d.ts.map +0 -1
- package/dist/es/assets/icons.js.map +0 -1
- package/dist/es/config/draco.d.ts.map +0 -1
- package/dist/es/config/draco.js.map +0 -1
- package/dist/es/config/sdkConfig.d.ts.map +0 -1
- package/dist/es/config/sdkConfig.js.map +0 -1
- package/dist/es/controllers/markerLayoutController.d.ts.map +0 -1
- package/dist/es/controllers/markerLayoutController.js.map +0 -1
- package/dist/es/controllers/routeController.d.ts.map +0 -1
- package/dist/es/controllers/routeController.js.map +0 -1
- package/dist/es/domain/models/_internal.d.ts.map +0 -1
- package/dist/es/domain/models/_internal.js.map +0 -1
- package/dist/es/domain/models/animation.d.ts.map +0 -1
- package/dist/es/domain/models/animation.js.map +0 -1
- package/dist/es/domain/models/banner.d.ts.map +0 -1
- package/dist/es/domain/models/banner.js.map +0 -1
- package/dist/es/domain/models/campaign.d.ts.map +0 -1
- package/dist/es/domain/models/campaign.js.map +0 -1
- package/dist/es/domain/models/categories.d.ts.map +0 -1
- package/dist/es/domain/models/categories.js.map +0 -1
- package/dist/es/domain/models/circle.d.ts.map +0 -1
- package/dist/es/domain/models/circle.js.map +0 -1
- package/dist/es/domain/models/cityFilterOption.d.ts.map +0 -1
- package/dist/es/domain/models/cityFilterOption.js.map +0 -1
- package/dist/es/domain/models/configuration.d.ts.map +0 -1
- package/dist/es/domain/models/configuration.js.map +0 -1
- package/dist/es/domain/models/cssCustomization.d.ts.map +0 -1
- package/dist/es/domain/models/cssCustomization.js.map +0 -1
- package/dist/es/domain/models/fitOptions.d.ts.map +0 -1
- package/dist/es/domain/models/fitOptions.js.map +0 -1
- package/dist/es/domain/models/innerFloors.d.ts.map +0 -1
- package/dist/es/domain/models/innerFloors.js.map +0 -1
- package/dist/es/domain/models/institution.d.ts.map +0 -1
- package/dist/es/domain/models/institution.js.map +0 -1
- package/dist/es/domain/models/latLng.d.ts.map +0 -1
- package/dist/es/domain/models/latLng.js.map +0 -1
- package/dist/es/domain/models/location.d.ts.map +0 -1
- package/dist/es/domain/models/location.js.map +0 -1
- package/dist/es/domain/models/loggeable.d.ts.map +0 -1
- package/dist/es/domain/models/loggeable.js.map +0 -1
- package/dist/es/domain/models/mapCamera.d.ts.map +0 -1
- package/dist/es/domain/models/mapCamera.js.map +0 -1
- package/dist/es/domain/models/mapConfig.d.ts.map +0 -1
- package/dist/es/domain/models/mapConfig.js.map +0 -1
- package/dist/es/domain/models/marker.d.ts.map +0 -1
- package/dist/es/domain/models/marker.js.map +0 -1
- package/dist/es/domain/models/multilanguage.d.ts.map +0 -1
- package/dist/es/domain/models/multilanguage.js.map +0 -1
- package/dist/es/domain/models/openingHours.d.ts.map +0 -1
- package/dist/es/domain/models/openingHours.js.map +0 -1
- package/dist/es/domain/models/place.d.ts.map +0 -1
- package/dist/es/domain/models/place.js.map +0 -1
- package/dist/es/domain/models/platform.d.ts.map +0 -1
- package/dist/es/domain/models/platform.js.map +0 -1
- package/dist/es/domain/models/popover.d.ts.map +0 -1
- package/dist/es/domain/models/popover.js.map +0 -1
- package/dist/es/domain/models/product.d.ts.map +0 -1
- package/dist/es/domain/models/product.js.map +0 -1
- package/dist/es/domain/models/property.d.ts.map +0 -1
- package/dist/es/domain/models/property.js.map +0 -1
- package/dist/es/domain/models/route.d.ts.map +0 -1
- package/dist/es/domain/models/route.js.map +0 -1
- package/dist/es/domain/models/routeConfiguration.d.ts.map +0 -1
- package/dist/es/domain/models/routeConfiguration.js.map +0 -1
- package/dist/es/domain/models/routeInstance.d.ts.map +0 -1
- package/dist/es/domain/models/routeInstance.js.map +0 -1
- package/dist/es/domain/models/routeStyle.d.ts.map +0 -1
- package/dist/es/domain/models/routeStyle.js.map +0 -1
- package/dist/es/domain/models/scene3D.d.ts.map +0 -1
- package/dist/es/domain/models/scene3D.js.map +0 -1
- package/dist/es/domain/models/transport.d.ts.map +0 -1
- package/dist/es/domain/models/transport.js.map +0 -1
- package/dist/es/domain/ports/ICache.d.ts.map +0 -1
- package/dist/es/domain/ports/ICache.js.map +0 -1
- package/dist/es/domain/ports/IHttpClient.d.ts.map +0 -1
- package/dist/es/domain/ports/IHttpClient.js.map +0 -1
- package/dist/es/domain/ports/ILogger.d.ts.map +0 -1
- package/dist/es/domain/ports/ILogger.js.map +0 -1
- package/dist/es/domain/ports/index.d.ts.map +0 -1
- package/dist/es/domain/ports/index.js.map +0 -1
- package/dist/es/index.d.ts.map +0 -1
- package/dist/es/index.js.map +0 -1
- package/dist/es/infrastructure/cache/CacheManager.d.ts.map +0 -1
- package/dist/es/infrastructure/cache/CacheManager.js.map +0 -1
- package/dist/es/infrastructure/cache/LRUCache.d.ts.map +0 -1
- package/dist/es/infrastructure/cache/LRUCache.js.map +0 -1
- package/dist/es/infrastructure/cache/PersistentCache.d.ts.map +0 -1
- package/dist/es/infrastructure/cache/PersistentCache.js.map +0 -1
- package/dist/es/infrastructure/cache/cacheConfig.d.ts.map +0 -1
- package/dist/es/infrastructure/cache/cacheConfig.js.map +0 -1
- package/dist/es/infrastructure/http/FetchHttpClient.d.ts.map +0 -1
- package/dist/es/infrastructure/http/FetchHttpClient.js.map +0 -1
- package/dist/es/infrastructure/logging/MVXLogger.d.ts.map +0 -1
- package/dist/es/infrastructure/logging/MVXLogger.js.map +0 -1
- package/dist/es/interfaces/cache.d.ts.map +0 -1
- package/dist/es/interfaces/cache.js.map +0 -1
- package/dist/es/interfaces/healthResponse.d.ts.map +0 -1
- package/dist/es/interfaces/healthResponse.js.map +0 -1
- package/dist/es/interfaces/institutionResponse.d.ts.map +0 -1
- package/dist/es/interfaces/institutionResponse.js.map +0 -1
- package/dist/es/interfaces/metadata.d.ts.map +0 -1
- package/dist/es/interfaces/metadata.js.map +0 -1
- package/dist/es/interfaces/placeResponse.d.ts.map +0 -1
- package/dist/es/interfaces/placeResponse.js.map +0 -1
- package/dist/es/interfaces/routeCacheResponse.d.ts.map +0 -1
- package/dist/es/interfaces/routeCacheResponse.js.map +0 -1
- package/dist/es/interfaces/routeResponse.d.ts.map +0 -1
- package/dist/es/interfaces/routeResponse.js.map +0 -1
- package/dist/es/interfaces/styleResponse.d.ts.map +0 -1
- package/dist/es/interfaces/styleResponse.js.map +0 -1
- package/dist/es/logger/logger.d.ts.map +0 -1
- package/dist/es/logger/logger.js.map +0 -1
- package/dist/es/logger/sentry.d.ts.map +0 -1
- package/dist/es/logger/sentry.js.map +0 -1
- package/dist/es/map/fitCamera.d.ts.map +0 -1
- package/dist/es/map/fitCamera.js.map +0 -1
- package/dist/es/map/generated/maplibreWorkerSource.d.ts.map +0 -1
- package/dist/es/map/generated/maplibreWorkerSource.js.map +0 -1
- package/dist/es/map/installMapLibreWorker.d.ts.map +0 -1
- package/dist/es/map/installMapLibreWorker.js.map +0 -1
- package/dist/es/map/liveMapFitTransform.d.ts.map +0 -1
- package/dist/es/map/liveMapFitTransform.js.map +0 -1
- package/dist/es/map/map.d.ts.map +0 -1
- package/dist/es/map/map.js.map +0 -1
- package/dist/es/map/mapInteractionOptions.d.ts.map +0 -1
- package/dist/es/map/mapInteractionOptions.js.map +0 -1
- package/dist/es/map/scene3DController.d.ts.map +0 -1
- package/dist/es/map/scene3DController.js.map +0 -1
- package/dist/es/repository/repository.d.ts.map +0 -1
- package/dist/es/repository/repository.js.map +0 -1
- package/dist/es/repository/requester.d.ts.map +0 -1
- package/dist/es/repository/requester.js.map +0 -1
- package/dist/es/sdk.d.ts.map +0 -1
- package/dist/es/sdk.js.map +0 -1
- package/dist/es/utils/3d.d.ts.map +0 -1
- package/dist/es/utils/3d.js.map +0 -1
- package/dist/es/utils/deckLayers.d.ts.map +0 -1
- package/dist/es/utils/deckLayers.js.map +0 -1
- package/dist/es/utils/error.d.ts.map +0 -1
- package/dist/es/utils/error.js.map +0 -1
- package/dist/es/utils/images.d.ts.map +0 -1
- package/dist/es/utils/images.js.map +0 -1
- package/dist/es/utils/loadGlb.d.ts.map +0 -1
- package/dist/es/utils/loadGlb.js.map +0 -1
- package/dist/es/utils/mapvxHostname.d.ts.map +0 -1
- package/dist/es/utils/mapvxHostname.js.map +0 -1
- package/dist/es/utils/nav-functions.d.ts.map +0 -1
- package/dist/es/utils/nav-functions.js.map +0 -1
- package/dist/es/utils/opening-hours-helper.d.ts.map +0 -1
- package/dist/es/utils/opening-hours-helper.js.map +0 -1
- package/dist/es/utils/preconnect.d.ts.map +0 -1
- package/dist/es/utils/preconnect.js.map +0 -1
- package/dist/es/utils/route-utils.d.ts.map +0 -1
- package/dist/es/utils/route-utils.js.map +0 -1
- package/dist/es/utils/semaphore.d.ts.map +0 -1
- package/dist/es/utils/semaphore.js.map +0 -1
- package/dist/es/utils/three.d.ts.map +0 -1
- package/dist/es/utils/three.js.map +0 -1
- package/dist/es/utils/threeScene.d.ts.map +0 -1
- package/dist/es/utils/threeScene.js.map +0 -1
- package/dist/es/utils/update-css.d.ts.map +0 -1
- package/dist/es/utils/update-css.js.map +0 -1
- package/dist/es/utils/utils.d.ts.map +0 -1
- package/dist/es/utils/utils.js.map +0 -1
- package/dist/umd/index.js.map +0 -1
- package/dist/umd/styles.css.map +0 -1
- package/dist/umd/styles.js.map +0 -1
package/dist/es/map/map.js
CHANGED
|
@@ -1,73 +1,27 @@
|
|
|
1
1
|
import { LngLatBounds, Map, NavigationControl, Popup, addProtocol, } from "maplibre-gl";
|
|
2
2
|
import { Semaphore } from "../utils/semaphore";
|
|
3
3
|
import { installMapLibreWorker } from "./installMapLibreWorker";
|
|
4
|
-
/** Shared GeoJSON source holding every circle drawn through the circle API. */
|
|
5
4
|
const CIRCLE_SOURCE_ID = "mapvx-circles";
|
|
6
|
-
/** Fill layer rendering the translucent interior of the circles. */
|
|
7
5
|
const CIRCLE_FILL_LAYER_ID = "mapvx-circles-fill";
|
|
8
|
-
/** Line layer rendering the circle outlines. */
|
|
9
6
|
const CIRCLE_LINE_LAYER_ID = "mapvx-circles-line";
|
|
10
|
-
/**
|
|
11
|
-
* Layer-id suffix per circle render order. The default placement keeps the
|
|
12
|
-
* unsuffixed ids so existing consumers referencing them keep working.
|
|
13
|
-
*/
|
|
14
7
|
const CIRCLE_LAYER_SUFFIXES = {
|
|
15
8
|
aboveBasemap: "",
|
|
16
9
|
belowLabels: "-below-labels",
|
|
17
10
|
top: "-top",
|
|
18
11
|
};
|
|
19
|
-
/**
|
|
20
|
-
* How many times a failed vector tile is reloaded before it is dropped from the retry
|
|
21
|
-
* queue. Bounded so a permanently unavailable tile stops being requested, while a tile
|
|
22
|
-
* that failed on a transient network error still gets several chances.
|
|
23
|
-
*/
|
|
24
12
|
const MAX_TILE_RETRIES = 5;
|
|
25
|
-
/**
|
|
26
|
-
* Base delay for the retry backoff. Attempt N waits `BASE * 2^(N-1)` before it is
|
|
27
|
-
* eligible again — 1s, 2s, 4s, 8s — so a tile that keeps failing is retried ever less
|
|
28
|
-
* often instead of once per timer tick.
|
|
29
|
-
*/
|
|
30
13
|
const TILE_RETRY_BASE_DELAY_MS = 1000;
|
|
31
|
-
/**
|
|
32
|
-
* Safety deadline for {@link InternalMapVXMap.setStyle}'s `onStyleReady` callback. The
|
|
33
|
-
* callback normally fires on the map's `idle` event, but `idle` may never arrive (the
|
|
34
|
-
* style request failed, the swap never settles). Callers hide the map behind a loading
|
|
35
|
-
* overlay until the callback arrives, so it must be released no matter what.
|
|
36
|
-
*/
|
|
37
14
|
const STYLE_READY_TIMEOUT_MS = 4000;
|
|
38
|
-
/**
|
|
39
|
-
* Frames a floor change waits before it will believe the indoor tiles are
|
|
40
|
-
* already rebuilt (see `updateMarkersWhenFloorSettles`). Genuinely a frame
|
|
41
|
-
* count: the reload is dispatched on the map's next render, so this is how
|
|
42
|
-
* many renders it gets to be observed in.
|
|
43
|
-
*/
|
|
44
15
|
const FLOOR_SETTLE_MIN_FRAMES = 3;
|
|
45
|
-
/**
|
|
46
|
-
* Longest a floor change waits for the new floor's tiles before switching the
|
|
47
|
-
* HTML markers anyway, so a stalled source never hides markers for good.
|
|
48
|
-
*
|
|
49
|
-
* A deadline rather than a frame count. The panels this matters on run at
|
|
50
|
-
* 20-30 fps, where a 60-frame cap is two to three seconds — and the wait also
|
|
51
|
-
* gates `addMarker`, so overshooting it is not merely a late marker switch.
|
|
52
|
-
*/
|
|
53
16
|
const FLOOR_SETTLE_MAX_MS = 1000;
|
|
54
|
-
/** Fill/line layer ids for one circle render-order bucket. */
|
|
55
17
|
function circleLayerIdsFor(order) {
|
|
56
18
|
const suffix = CIRCLE_LAYER_SUFFIXES[order];
|
|
57
19
|
return { fill: CIRCLE_FILL_LAYER_ID + suffix, line: CIRCLE_LINE_LAYER_ID + suffix };
|
|
58
20
|
}
|
|
59
|
-
/** True for the layer ids owned by the circle API, regardless of bucket. */
|
|
60
21
|
function isCircleLayerId(id) {
|
|
61
22
|
return id.startsWith(CIRCLE_FILL_LAYER_ID) || id.startsWith(CIRCLE_LINE_LAYER_ID);
|
|
62
23
|
}
|
|
63
|
-
// Flag to track if cached-tile protocol has been registered
|
|
64
24
|
let cachedTileProtocolRegistered = false;
|
|
65
|
-
/**
|
|
66
|
-
* Deep clone helper that works in all environments.
|
|
67
|
-
* Uses structuredClone if available, otherwise falls back to JSON serialization.
|
|
68
|
-
* @param obj The object to clone
|
|
69
|
-
* @returns A deep clone of the object
|
|
70
|
-
*/
|
|
71
25
|
function deepClone(obj) {
|
|
72
26
|
if (obj === undefined || obj === null) {
|
|
73
27
|
return obj;
|
|
@@ -77,28 +31,12 @@ function deepClone(obj) {
|
|
|
77
31
|
}
|
|
78
32
|
return JSON.parse(JSON.stringify(obj));
|
|
79
33
|
}
|
|
80
|
-
/**
|
|
81
|
-
* Register a custom protocol for cached tiles that routes requests through the main thread.
|
|
82
|
-
* This allows the service worker to intercept and cache tile requests.
|
|
83
|
-
*
|
|
84
|
-
* Wraps fetches in a {@link Semaphore} so tile CDN / WAFs are not hit with
|
|
85
|
-
* unbounded parallel requests (same host as the service worker cache). The
|
|
86
|
-
* semaphore is created once with the limit from the first map's config; later
|
|
87
|
-
* calls are no-ops because the protocol can only be registered once globally
|
|
88
|
-
* on MapLibre.
|
|
89
|
-
*
|
|
90
|
-
* @param maxConcurrentFetches - Maximum number of in-flight tile fetches.
|
|
91
|
-
*/
|
|
92
34
|
function registerCachedTileProtocol(maxConcurrentFetches) {
|
|
93
35
|
if (cachedTileProtocolRegistered)
|
|
94
36
|
return;
|
|
95
37
|
const semaphore = new Semaphore(maxConcurrentFetches);
|
|
96
38
|
addProtocol("cached-tile", (params, abortController) => {
|
|
97
39
|
const url = params.url.replace("cached-tile://", "https://");
|
|
98
|
-
// Pass the abort signal to acquire() so a request cancelled while still
|
|
99
|
-
// queued (e.g. during rapid zoom) drops out of the FIFO queue instead of
|
|
100
|
-
// waiting for a slot just to bail. release() runs only inside this chain,
|
|
101
|
-
// i.e. only after a slot was actually granted.
|
|
102
40
|
return semaphore.acquire(abortController.signal).then(() => fetch(url, { signal: abortController.signal })
|
|
103
41
|
.then((response) => {
|
|
104
42
|
if (!response.ok) {
|
|
@@ -113,12 +51,6 @@ function registerCachedTileProtocol(maxConcurrentFetches) {
|
|
|
113
51
|
});
|
|
114
52
|
cachedTileProtocolRegistered = true;
|
|
115
53
|
}
|
|
116
|
-
/**
|
|
117
|
-
* Converts a PaddingValue to pixels based on the container and viewport dimensions.
|
|
118
|
-
* @param value The padding value (number or string with unit)
|
|
119
|
-
* @param dimension The reference dimension in pixels (container width/height)
|
|
120
|
-
* @returns The padding value in pixels
|
|
121
|
-
*/
|
|
122
54
|
function parsePaddingValue(value, dimension) {
|
|
123
55
|
if (value === undefined) {
|
|
124
56
|
return 0;
|
|
@@ -145,13 +77,6 @@ function parsePaddingValue(value, dimension) {
|
|
|
145
77
|
return numericValue;
|
|
146
78
|
}
|
|
147
79
|
}
|
|
148
|
-
/**
|
|
149
|
-
* Converts PaddingOptions with mixed units to MapLibre's pixel-based padding format.
|
|
150
|
-
* @param padding The padding options with optional fields and mixed units
|
|
151
|
-
* @param containerWidth The map container width in pixels
|
|
152
|
-
* @param containerHeight The map container height in pixels
|
|
153
|
-
* @returns Padding object with all values in pixels
|
|
154
|
-
*/
|
|
155
80
|
function convertPaddingToPixels(padding, containerWidth, containerHeight) {
|
|
156
81
|
if (!padding) {
|
|
157
82
|
return { top: 0, bottom: 0, left: 0, right: 0 };
|
|
@@ -180,129 +105,38 @@ import { Scene3DController } from "./scene3DController";
|
|
|
180
105
|
import { computeOrientedCamera, refineCameraForPitch } from "./fitCamera";
|
|
181
106
|
import { LiveMapFitTransform } from "./liveMapFitTransform";
|
|
182
107
|
import { buildInteractionOptions, shouldDisableTouchRotation } from "./mapInteractionOptions";
|
|
183
|
-
/**
|
|
184
|
-
* Class to interact with the map.
|
|
185
|
-
* @category Map
|
|
186
|
-
* @hidden
|
|
187
|
-
*/
|
|
188
|
-
/**
|
|
189
|
-
* Whether a style publishes any `fill-extrusion` layer, i.e. whether it has extruded rooms for the
|
|
190
|
-
* 3D scene to stand on.
|
|
191
|
-
*
|
|
192
|
-
* This is the only reliable signal for "does 3D work here". `mapStyleJson` is served per API key,
|
|
193
|
-
* so the same venue comes back with extrusions on a 3D key and flat on a 2D one — the place id
|
|
194
|
-
* cannot answer the question.
|
|
195
|
-
*
|
|
196
|
-
* @param style The style about to be applied, or the one currently applied.
|
|
197
|
-
* @returns `true` when at least one layer is `fill-extrusion`.
|
|
198
|
-
*/
|
|
199
108
|
function styleHasExtrusions(style) {
|
|
200
109
|
return style.layers.some((layer) => layer.type === "fill-extrusion");
|
|
201
110
|
}
|
|
202
111
|
export class InternalMapVXMap extends Loggeable {
|
|
203
|
-
/** Whether a floor change is still rebuilding, so markers wait for it. */
|
|
204
112
|
get floorSettlePending() {
|
|
205
113
|
return this.floorSettleDeadline != null && this.now() < this.floorSettleDeadline;
|
|
206
114
|
}
|
|
207
|
-
/** Wall clock for the settle deadline; `Date.now` where `performance` is absent. */
|
|
208
115
|
now() {
|
|
209
116
|
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
210
117
|
}
|
|
211
|
-
/**
|
|
212
|
-
* Creates a new map instance with the parameters specified in mapConfig and assigns it to the provided HTML container.
|
|
213
|
-
* @param mapConfig Configuration parameters for the map.
|
|
214
|
-
* @param container Container where the assignment of the created map is required.
|
|
215
|
-
* @param parentPlace Parent place required for map floor mapping, along with the display of subplaces.
|
|
216
|
-
* @param token The token provided for the creation and fetching of map information.
|
|
217
|
-
* @returns A new instance of MapVXMap.
|
|
218
|
-
*/
|
|
219
118
|
constructor(mapConfig, container, token) {
|
|
220
119
|
var _a, _b, _c;
|
|
221
120
|
super();
|
|
222
|
-
/**
|
|
223
|
-
* Monotonic counter for {@link addLiveRoute} calls. Refreshes overlap (each one
|
|
224
|
-
* awaits a fetch), so only the call holding the latest ticket may touch the
|
|
225
|
-
* map — an older response resolving last is discarded instead of clobbering
|
|
226
|
-
* the newer route.
|
|
227
|
-
*/
|
|
228
121
|
this.liveRouteTicket = 0;
|
|
229
122
|
this.potentialParentPlaces = [];
|
|
230
123
|
this.innerFloors = [];
|
|
231
124
|
this.subPlaces = [];
|
|
232
125
|
this.currentFloor = "";
|
|
233
126
|
this.baseFilters = {};
|
|
234
|
-
/**
|
|
235
|
-
* Layer ids whose declared (base) filter has already been resolved — either captured
|
|
236
|
-
* into {@link baseFilters} or confirmed absent.
|
|
237
|
-
*
|
|
238
|
-
* `baseFilters[id] === undefined` cannot carry that information on its own: it means
|
|
239
|
-
* both "not looked at yet" and "looked at, the layer declares no filter". Without the
|
|
240
|
-
* distinction, a later pass re-reads the layer's LIVE filter — which by then is the
|
|
241
|
-
* one this class wrote — and stores our own floor/public-place filter as if it were
|
|
242
|
-
* the style's, so the layer keeps filtering by a stale floor forever.
|
|
243
|
-
*
|
|
244
|
-
* An id lands here the moment its declared filter is read from the style spec, or the
|
|
245
|
-
* moment this class writes a filter to that layer, whichever happens first. Layers
|
|
246
|
-
* added asynchronously after a `setStyle` swap are in neither situation, so their
|
|
247
|
-
* genuinely pristine live filter is still captured on first touch.
|
|
248
|
-
*/
|
|
249
127
|
this.capturedBaseFilters = new Set();
|
|
250
|
-
/**
|
|
251
|
-
* Monotonic id of the most recently STARTED style swap. Every {@link setStyle} call
|
|
252
|
-
* captures its own value and checks it again in each async continuation, so a
|
|
253
|
-
* superseded swap can neither touch the shared bookkeeping (`styleReadyTimer`,
|
|
254
|
-
* `pendingStyleSwapListener`) nor apply its obsolete style to the live map.
|
|
255
|
-
*
|
|
256
|
-
* A per-call `readied` flag is not enough: the timer and the listener slot are
|
|
257
|
-
* single-valued instance state, so two overlapping swaps otherwise clobber each
|
|
258
|
-
* other's — one caller's overlay is released by the other's failure, or an
|
|
259
|
-
* abandoned listener re-seeds filters from layer ids the current style lacks.
|
|
260
|
-
*/
|
|
261
128
|
this.styleSwapGeneration = 0;
|
|
262
129
|
this.markers = [];
|
|
263
130
|
this.circles = [];
|
|
264
131
|
this.enableHover = false;
|
|
265
132
|
this.hoveredId = "unselected";
|
|
266
133
|
this.failedTiles = new Set();
|
|
267
|
-
/**
|
|
268
|
-
* Retry bookkeeping per failed tile. A WeakMap so it can never outlive the tiles
|
|
269
|
-
* themselves — entries disappear with the tile objects, which is why none of the
|
|
270
|
-
* `failedTiles.clear()` paths have to reset it.
|
|
271
|
-
*/
|
|
272
134
|
this.tileRetryState = new WeakMap();
|
|
273
135
|
this.geoLocation = navigator.geolocation;
|
|
274
|
-
/** Floor-change settle bookkeeping (see `updateMarkersWhenFloorSettles`). */
|
|
275
136
|
this.floorSettleToken = 0;
|
|
276
|
-
/**
|
|
277
|
-
* When the floor-change settle stops holding markers back, or `null` when no
|
|
278
|
-
* change is in flight.
|
|
279
|
-
*
|
|
280
|
-
* A deadline rather than a flag, because `addMarker` reads it: the poll that
|
|
281
|
-
* would clear a flag runs on `requestAnimationFrame`, which does not fire in
|
|
282
|
-
* a backgrounded tab and does not run at all for a map torn down through
|
|
283
|
-
* MapLibre's own `remove()` rather than `destroyMap`. A flag left set there
|
|
284
|
-
* makes every later `addMarker` skip the call that attaches the marker, for
|
|
285
|
-
* good; a deadline expires on its own.
|
|
286
|
-
*/
|
|
287
137
|
this.floorSettleDeadline = null;
|
|
288
|
-
/** Owns the deck.gl overlay + GLB scene; created on style load only when 3D is active. */
|
|
289
138
|
this.scene3D = undefined;
|
|
290
|
-
/**
|
|
291
|
-
* Whether the style currently applied publishes `fill-extrusion` layers, i.e. whether there are
|
|
292
|
-
* roofs for the 3D scene to sit on. Recomputed on every style the map is given, because the style
|
|
293
|
-
* is served per API key, not per venue: the same place can come back 3D on one key and flat on
|
|
294
|
-
* another. Assumed true until a style says otherwise, so 2D maps (which never read it) are
|
|
295
|
-
* unaffected.
|
|
296
|
-
*/
|
|
297
139
|
this.styleSupports3D = true;
|
|
298
|
-
// First statement on purpose, and further forward than it looks necessary. MapLibre reads
|
|
299
|
-
// WORKER_URL once, when its first Dispatcher is built, and never again while any map is alive
|
|
300
|
-
// — so the worker has to be installed before *anything* touches MapLibre, not merely before
|
|
301
|
-
// `new Map(...)`. Today the constructor reaches MapLibre only through the map itself, but
|
|
302
|
-
// until recently it also called `setRTLTextPlugin()` here, which builds a Dispatcher of its
|
|
303
|
-
// own 200 lines ahead of the map; `prewarm()` and `importScriptInWorkers()` do the same.
|
|
304
|
-
// Keeping this first means no later edit can slip such a call in front of it.
|
|
305
|
-
// See installMapLibreWorker and DEVELOPER_DOCS/MAPLIBRE_V6_MIGRATION.md.
|
|
306
140
|
installMapLibreWorker();
|
|
307
141
|
this.repository = new Repository(token, (_a = mapConfig.lang) !== null && _a !== void 0 ? _a : "en", mapConfig.apiUrl, undefined, mapConfig.mapvxRequestContext, {
|
|
308
142
|
routeApiUrl: mapConfig.routeApiUrl,
|
|
@@ -331,9 +165,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
331
165
|
})();
|
|
332
166
|
this.markerLayoutConfig = Object.assign(Object.assign({}, DEFAULT_MARKER_LAYOUT_CONFIG), mapConfig.markerLayout);
|
|
333
167
|
this.markerLayoutController = new MarkerLayoutController(this, this.markerLayoutConfig);
|
|
334
|
-
// `container` is the very element handed to MapLibre below, and every
|
|
335
|
-
// marker is mounted inside it, so publishing the gap/width variables here
|
|
336
|
-
// covers markers added before the map's "load" event fires.
|
|
337
168
|
this.markerLayoutController.applyLayoutVariables(container);
|
|
338
169
|
if (mapConfig.parentPlaceId != null) {
|
|
339
170
|
this.initialPlaceDetailSetUp(mapConfig.parentPlaceId, mapConfig.authToken);
|
|
@@ -345,12 +176,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
345
176
|
this.enableHover = mapConfig.enableHover || false;
|
|
346
177
|
this.initialMapStyleSetUp(mapConfig, container);
|
|
347
178
|
}
|
|
348
|
-
/**
|
|
349
|
-
* Transform style sources to use cached-tile:// protocol for tile URLs.
|
|
350
|
-
* This enables the service worker to intercept and cache tile requests.
|
|
351
|
-
* @param style The original style specification
|
|
352
|
-
* @returns A new style with transformed tile URLs
|
|
353
|
-
*/
|
|
354
179
|
transformStyleForCaching(style) {
|
|
355
180
|
if (!style) {
|
|
356
181
|
return style;
|
|
@@ -359,9 +184,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
359
184
|
if (transformedStyle === null || transformedStyle === void 0 ? void 0 : transformedStyle.sources) {
|
|
360
185
|
for (const sourceKey of Object.keys(transformedStyle.sources)) {
|
|
361
186
|
const source = transformedStyle.sources[sourceKey];
|
|
362
|
-
// Transform vector and raster tile sources
|
|
363
|
-
// Only transform source.tiles (actual tile URLs), NOT source.url (TileJSON metadata URL)
|
|
364
|
-
// source.url points to a TileJSON file that returns JSON, not binary tile data
|
|
365
187
|
if (source.tiles && Array.isArray(source.tiles)) {
|
|
366
188
|
source.tiles = source.tiles.map((tileUrl) => {
|
|
367
189
|
if (tileUrl.startsWith("https://")) {
|
|
@@ -418,11 +240,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
418
240
|
.catch(console.error);
|
|
419
241
|
return;
|
|
420
242
|
}
|
|
421
|
-
// Through the same helper as `setStyle` and `changeParentPlaceTo`. This PR
|
|
422
|
-
// forwards `styleRef`/`styleTheme` to the initial load too, and a ref scoped
|
|
423
|
-
// to the user's client rather than to the api key resolves only over bearer
|
|
424
|
-
// — fetched over the api-key path it 4xx'd, and since this is the call that
|
|
425
|
-
// creates the map, the map was never created at all.
|
|
426
243
|
this.fetchVenueStyle(mapConfig.parentPlaceId, mapConfig.styleRef, mapConfig.styleTheme)
|
|
427
244
|
.then((style) => {
|
|
428
245
|
return this.onMapStyleLoaded(mapConfig, container, style);
|
|
@@ -433,15 +250,11 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
433
250
|
}
|
|
434
251
|
onMapStyleLoaded(mapConfig, container, style) {
|
|
435
252
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
436
|
-
// Determine if service worker caching should be enabled
|
|
437
253
|
const useServiceWorkerCaching = this.tileCacheConfig.enabled && this.tileCacheConfig.persistToServiceWorker;
|
|
438
254
|
if (useServiceWorkerCaching) {
|
|
439
255
|
registerCachedTileProtocol(this.tileCacheConfig.maxConcurrentTileFetches);
|
|
440
256
|
}
|
|
441
|
-
// Transform tile URLs only if service worker caching is enabled
|
|
442
257
|
const finalStyle = useServiceWorkerCaching ? this.transformStyleForCaching(style) : style;
|
|
443
|
-
// Read straight off the style object rather than `map.getStyle()`: the map does not exist yet
|
|
444
|
-
// here, and the decision has to be made before the 3D controller is constructed below.
|
|
445
258
|
this.styleSupports3D = styleHasExtrusions(finalStyle);
|
|
446
259
|
if (this.mode === "3D" && !this.styleSupports3D) {
|
|
447
260
|
this.logWarning(new Error("3D was requested but this style publishes no `fill-extrusion` layers, so there are no " +
|
|
@@ -450,18 +263,13 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
450
263
|
"floating above the ground. The style is served per API key, not per venue, so check " +
|
|
451
264
|
"that this key publishes 3D."), { functionName: "onMapStyleLoaded", parentPlaceId: (_a = this.parentPlaceId) !== null && _a !== void 0 ? _a : "" });
|
|
452
265
|
}
|
|
453
|
-
const mapOptions = Object.assign({ container, style: finalStyle, center: mapConfig.center, zoom: mapConfig.zoom, pitch: (_b = mapConfig.pitch) !== null && _b !== void 0 ? _b : 0, attributionControl: false, maplibreLogo: false, bearingSnap: (_c = mapConfig.bearingSnap) !== null && _c !== void 0 ? _c : 0, cancelPendingTileRequestsWhileZooming: true,
|
|
454
|
-
// Use configured maxTiles for MapLibre's memory cache
|
|
455
|
-
maxTileCacheSize: this.tileCacheConfig.maxTiles }, buildInteractionOptions(mapConfig));
|
|
266
|
+
const mapOptions = Object.assign({ container, style: finalStyle, center: mapConfig.center, zoom: mapConfig.zoom, pitch: (_b = mapConfig.pitch) !== null && _b !== void 0 ? _b : 0, attributionControl: false, maplibreLogo: false, bearingSnap: (_c = mapConfig.bearingSnap) !== null && _c !== void 0 ? _c : 0, cancelPendingTileRequestsWhileZooming: true, maxTileCacheSize: this.tileCacheConfig.maxTiles }, buildInteractionOptions(mapConfig));
|
|
456
267
|
if (mapConfig.maxZoom)
|
|
457
268
|
mapOptions.maxZoom = mapConfig.maxZoom;
|
|
458
269
|
if (mapConfig.minZoom)
|
|
459
270
|
mapOptions.minZoom = mapConfig.minZoom;
|
|
460
|
-
// Reduced internal resolution on request (fill-rate relief for low-end GPUs);
|
|
461
|
-
// MapLibre keeps devicePixelRatio when the option is left out.
|
|
462
271
|
if (mapConfig.pixelRatio !== undefined)
|
|
463
272
|
mapOptions.pixelRatio = mapConfig.pixelRatio;
|
|
464
|
-
// `0` disables the post-gesture fade tail entirely; keep MapLibre's default otherwise.
|
|
465
273
|
if (mapConfig.fadeDuration !== undefined)
|
|
466
274
|
mapOptions.fadeDuration = mapConfig.fadeDuration;
|
|
467
275
|
if (mapConfig.maxBounds && mapConfig.maxBounds.length > 1) {
|
|
@@ -469,13 +277,9 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
469
277
|
mapOptions.maxBounds = new LngLatBounds([boundingBox[0].lng, boundingBox[0].lat], [boundingBox[1].lng, boundingBox[1].lat]);
|
|
470
278
|
}
|
|
471
279
|
this.map = new Map(mapOptions);
|
|
472
|
-
// Create the 3D controller only when the map opts into 3D. All heavy WebGL / deck.gl work is
|
|
473
|
-
// owned by it; in 2D mode `this.scene3D` stays undefined and every hook below is a no-op.
|
|
474
280
|
if (this.is3DSceneActive() && this.scene3DConfig) {
|
|
475
281
|
this.scene3D = new Scene3DController(this.map, this.scene3DConfig, this.initialCenter, mapConfig.onScene3DModelsProgress);
|
|
476
282
|
}
|
|
477
|
-
// When rotation is disabled we still want pinch-to-zoom to work, so the
|
|
478
|
-
// two-finger rotation is turned off here instead of via the constructor.
|
|
479
283
|
if (shouldDisableTouchRotation(mapConfig)) {
|
|
480
284
|
(_e = (_d = this.map.touchZoomRotate) === null || _d === void 0 ? void 0 : _d.disableRotation) === null || _e === void 0 ? void 0 : _e.call(_d);
|
|
481
285
|
}
|
|
@@ -485,7 +289,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
485
289
|
}), (_h = mapConfig.navigationPosition) !== null && _h !== void 0 ? _h : "top-right");
|
|
486
290
|
this.map.on("load", () => {
|
|
487
291
|
var _a, _b;
|
|
488
|
-
// 3D libraries load asynchronously; the rest of the load flow does not wait on them.
|
|
489
292
|
void ((_a = this.scene3D) === null || _a === void 0 ? void 0 : _a.onMapLoad());
|
|
490
293
|
this.whenStyleUpdates(style);
|
|
491
294
|
if (mapConfig.lang)
|
|
@@ -495,8 +298,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
495
298
|
this.subscribeToFailedTiles();
|
|
496
299
|
this.markerLayoutController.attach();
|
|
497
300
|
});
|
|
498
|
-
// Self-healing for circles: a full style reload wipes custom sources and
|
|
499
|
-
// layers, and not every restyle path goes through whenStyleUpdates.
|
|
500
301
|
this.map.on("styledata", () => {
|
|
501
302
|
if (this.circles.length > 0)
|
|
502
303
|
this.ensureCircleLayers();
|
|
@@ -522,15 +323,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
522
323
|
style.layers
|
|
523
324
|
.filter((layer) => layer.id.startsWith("indoor-"))
|
|
524
325
|
.forEach((layer) => {
|
|
525
|
-
// Seed from the STYLE SPEC — the only pristine source — and do it BEFORE the
|
|
526
|
-
// setFilter below overwrites the live filter. Reading it back afterwards would
|
|
527
|
-
// return our own `publicPlaceFilter` and store it as the layer's declared one,
|
|
528
|
-
// turning `public_place` from an OR into an AND and hiding every private
|
|
529
|
-
// feature on the selected floor. Every indoor layer is covered, not just
|
|
530
|
-
// fill/line/symbol: a `circle` layer is discriminated by its filter just the
|
|
531
|
-
// same, and dropping it makes the layer repaint every feature.
|
|
532
|
-
// `filter` is absent from the union member for `background` layers, hence the
|
|
533
|
-
// structural read rather than `layer.filter`.
|
|
534
326
|
const declared = layer.filter;
|
|
535
327
|
this.captureDeclaredBaseFilter(layer.id, declared);
|
|
536
328
|
const baseFilter = this.baseFilters[layer.id];
|
|
@@ -543,18 +335,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
543
335
|
}
|
|
544
336
|
});
|
|
545
337
|
}
|
|
546
|
-
/**
|
|
547
|
-
* Records a layer's declared (base) filter the first time the layer is seen, from an
|
|
548
|
-
* explicit value (a style-spec `filter`) when one is available, otherwise by reading
|
|
549
|
-
* the live filter — which is only pristine for layers this class has never written to.
|
|
550
|
-
*
|
|
551
|
-
* Marking happens even when no filter exists, so the layer is never revisited: on a
|
|
552
|
-
* second visit its live filter is one we produced, and storing that as the "declared"
|
|
553
|
-
* filter is what freezes a layer to a stale floor.
|
|
554
|
-
*
|
|
555
|
-
* @param layerId Id of the layer whose base filter should be resolved.
|
|
556
|
-
* @param declared Declared filter straight from the style spec, when the caller has it.
|
|
557
|
-
*/
|
|
558
338
|
captureDeclaredBaseFilter(layerId, declared) {
|
|
559
339
|
if (this.capturedBaseFilters.has(layerId))
|
|
560
340
|
return;
|
|
@@ -566,7 +346,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
566
346
|
}
|
|
567
347
|
setLayersForLanguage(lang) {
|
|
568
348
|
var _a, _b;
|
|
569
|
-
// outdoor layers
|
|
570
349
|
const layersName = [
|
|
571
350
|
"aerodrome_label",
|
|
572
351
|
"mountain_peak",
|
|
@@ -607,7 +386,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
607
386
|
this.debugLog("Layer language update failed (layer may not exist)", error);
|
|
608
387
|
}
|
|
609
388
|
});
|
|
610
|
-
// indoor layers
|
|
611
389
|
const indoorLayerIds = layers
|
|
612
390
|
.filter((layer) => {
|
|
613
391
|
var _a;
|
|
@@ -632,11 +410,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
632
410
|
}
|
|
633
411
|
});
|
|
634
412
|
}
|
|
635
|
-
/**
|
|
636
|
-
* Add values to identify the client.
|
|
637
|
-
* @param segmentation The pair values to use as segmentation.
|
|
638
|
-
* @returns The segmentation with the added values.
|
|
639
|
-
*/
|
|
640
413
|
prepareSegmentation(segmentation) {
|
|
641
414
|
var _a;
|
|
642
415
|
return Object.assign(Object.assign({}, segmentation), { token: this.token, parentPlaceId: (_a = this.parentPlaceId) !== null && _a !== void 0 ? _a : "None" });
|
|
@@ -645,32 +418,20 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
645
418
|
var _a;
|
|
646
419
|
this.circles = [];
|
|
647
420
|
this.markerLayoutController.destroy();
|
|
648
|
-
// Drop any in-flight `setStyle` bookkeeping while the map still exists: the
|
|
649
|
-
// listener has to be detached before `map.remove()`, and the safety timer must not
|
|
650
|
-
// outlive the map and call `onStyleReady` for a map that is already gone.
|
|
651
421
|
this.clearPendingStyleSwapListener();
|
|
652
422
|
if (this.styleReadyTimer) {
|
|
653
423
|
clearTimeout(this.styleReadyTimer);
|
|
654
424
|
this.styleReadyTimer = undefined;
|
|
655
425
|
}
|
|
656
|
-
// Drop any floor-settle poll in flight: bumping the token makes the next
|
|
657
|
-
// `requestAnimationFrame` callback return instead of re-queueing itself and
|
|
658
|
-
// re-attaching markers to a map that has already been removed.
|
|
659
426
|
this.floorSettleToken++;
|
|
660
427
|
this.floorSettleDeadline = null;
|
|
661
|
-
// Dispose the 3D scene's GPU resources before the map (and its shared WebGL context) go away —
|
|
662
|
-
// MapLibre's own teardown never calls the custom GLB layer's `onRemove`.
|
|
663
428
|
(_a = this.scene3D) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
664
429
|
this.map.remove();
|
|
665
430
|
this.unsubscribeFromFailedTiles();
|
|
666
431
|
}
|
|
667
432
|
clearTileCache() {
|
|
668
433
|
try {
|
|
669
|
-
// Clear the failed tiles tracking set
|
|
670
434
|
this.failedTiles.clear();
|
|
671
|
-
// Force MapLibre to reload all visible tiles by triggering a repaint
|
|
672
|
-
// Note: MapLibre doesn't expose a direct cache clear method, so we
|
|
673
|
-
// trigger a style refresh which causes tiles to be re-requested
|
|
674
435
|
if (this.map) {
|
|
675
436
|
this.map.triggerRepaint();
|
|
676
437
|
}
|
|
@@ -680,18 +441,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
680
441
|
this.debugLog("Tile cache clear failed (cache may not exist)", error);
|
|
681
442
|
}
|
|
682
443
|
}
|
|
683
|
-
/**
|
|
684
|
-
* Whether 3D scene features (deck.gl overlay, declarative GLB custom layer, etc.) are active.
|
|
685
|
-
* Requires {@link MapConfig.mode} `"3D"`, {@link Scene3DConfig.enabled} not `false`, and a style
|
|
686
|
-
* that actually publishes `fill-extrusion` layers ({@link styleSupports3D}).
|
|
687
|
-
*
|
|
688
|
-
* That last condition is what keeps a caller from asking for 3D on a flat style: the overlay
|
|
689
|
-
* would float above the ground while `hideLayers` removed the 2D labels underneath, leaving a
|
|
690
|
-
* map with no labels at all — worse than the plain 2D map the caller would otherwise get.
|
|
691
|
-
*
|
|
692
|
-
* The heavy WebGL / deck.gl work lives in {@link Scene3DController}; this only decides whether one
|
|
693
|
-
* is created and wired up. When `scene3D` is omitted, 3D features remain available.
|
|
694
|
-
*/
|
|
695
444
|
is3DSceneActive() {
|
|
696
445
|
var _a;
|
|
697
446
|
return this.mode === "3D" && ((_a = this.scene3DConfig) === null || _a === void 0 ? void 0 : _a.enabled) !== false && this.styleSupports3D;
|
|
@@ -700,14 +449,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
700
449
|
var _a;
|
|
701
450
|
return (_a = this.currentFloor) !== null && _a !== void 0 ? _a : "";
|
|
702
451
|
}
|
|
703
|
-
/**
|
|
704
|
-
* Sets the route path used for GLB route-transparency collision, so 3D models a route passes
|
|
705
|
-
* through fade and reveal the floor plan underneath. Called by {@link RouteController} whenever
|
|
706
|
-
* the set of drawn routes changes. Points are tagged with the floor their segment is drawn on;
|
|
707
|
-
* only points on the displayed floor participate. Pass an empty array to clear.
|
|
708
|
-
*
|
|
709
|
-
* No-op unless the 3D scene is active.
|
|
710
|
-
*/
|
|
711
452
|
setRouteCollisionPath(points) {
|
|
712
453
|
var _a;
|
|
713
454
|
if (!this.is3DSceneActive()) {
|
|
@@ -715,11 +456,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
715
456
|
}
|
|
716
457
|
(_a = this.scene3D) === null || _a === void 0 ? void 0 : _a.setRouteCollisionPath(points);
|
|
717
458
|
}
|
|
718
|
-
/**
|
|
719
|
-
* Performs changes when parent place is updated
|
|
720
|
-
* @param place new parent place
|
|
721
|
-
* @param updateStyle defines if new parent place style must be set
|
|
722
|
-
*/
|
|
723
459
|
changeParentPlaceTo(place, updateStyle = false, onStyleReady) {
|
|
724
460
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
725
461
|
this.parentPlace = place;
|
|
@@ -737,52 +473,21 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
737
473
|
const useServiceWorkerCaching = this.tileCacheConfig.enabled && this.tileCacheConfig.persistToServiceWorker;
|
|
738
474
|
const finalStyle = useServiceWorkerCaching ? this.transformStyleForCaching(style) : style;
|
|
739
475
|
this.map.setStyle(finalStyle);
|
|
740
|
-
// The new place's style declares its own filters for the same `indoor-*` layer
|
|
741
|
-
// ids. Without this reset every id is still marked captured from the previous
|
|
742
|
-
// place, so `captureDeclaredBaseFilter` early-returns for all of them and the
|
|
743
|
-
// previous place's expressions keep filtering the new style forever. (The
|
|
744
|
-
// `switch (layer.type)` block that used to re-read them on every style load was
|
|
745
|
-
// removed when capture became once-per-id, which is what made this necessary.)
|
|
746
476
|
this.resetBaseFilters();
|
|
747
477
|
this.whenStyleUpdates(finalStyle);
|
|
748
478
|
onStyleReady === null || onStyleReady === void 0 ? void 0 : onStyleReady();
|
|
749
479
|
})
|
|
750
480
|
.catch((error) => {
|
|
751
481
|
this.logError(error, { functionName: "changeParentPlaceTo" });
|
|
752
|
-
// Release the caller either way. `onStyleReady` is what a consumer
|
|
753
|
-
// hides its loading overlay on, so swallowing the failure here left
|
|
754
|
-
// the overlay up for good rather than merely unstyled.
|
|
755
482
|
onStyleReady === null || onStyleReady === void 0 ? void 0 : onStyleReady();
|
|
756
483
|
});
|
|
757
484
|
}
|
|
758
485
|
}
|
|
759
|
-
/**
|
|
760
|
-
* Fetch the venue style over whichever endpoint this map is authorized on.
|
|
761
|
-
*
|
|
762
|
-
* A bearer token authorizes by the user's client access rather than the api
|
|
763
|
-
* key's scopes, so a client's branded style resolves without granting that
|
|
764
|
-
* place to a shared api key; api-key consumers keep the
|
|
765
|
-
* `/api/sdk/v2/mapStyleJson` path.
|
|
766
|
-
*
|
|
767
|
-
* Both callers go through here so they cannot disagree. They used to: once
|
|
768
|
-
* `setStyle` had stored a `styleRef` it resolved over bearer, the next
|
|
769
|
-
* parent-place change refetched that same ref over the api-key path, whose
|
|
770
|
-
* key does not scope it — a non-ok response, a rejected promise, and a style
|
|
771
|
-
* that was never applied, with `onStyleReady` left unfired under a caller's
|
|
772
|
-
* loading overlay.
|
|
773
|
-
*/
|
|
774
486
|
fetchVenueStyle(placeId, styleRef, styleTheme) {
|
|
775
487
|
return this.authToken
|
|
776
488
|
? this.repository.fetchAndParseMapStyleByBearer(placeId, this.authToken, styleRef, styleTheme)
|
|
777
489
|
: this.repository.fetchAndParseMapStyle(placeId, styleRef, styleTheme);
|
|
778
490
|
}
|
|
779
|
-
/**
|
|
780
|
-
* Update the parent place and the current floor.
|
|
781
|
-
* Does not update layers, markers, etc.
|
|
782
|
-
* @param parentPlaceId
|
|
783
|
-
* @param floorId
|
|
784
|
-
* @throws A error if the parent place is not one of the allowed places to show.
|
|
785
|
-
*/
|
|
786
491
|
updatePlaceAndFloor(parentPlaceId, floorId) {
|
|
787
492
|
var _a, _b, _c, _d, _e, _f;
|
|
788
493
|
const place = this.potentialParentPlaces.find((place) => place.mapvxId === parentPlaceId);
|
|
@@ -810,10 +515,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
810
515
|
setLang(lang) {
|
|
811
516
|
this.repository.setLang(lang);
|
|
812
517
|
this.currentLang = lang;
|
|
813
|
-
// setLayersForLanguage reads this.map.getStyle()?.layers, which is empty
|
|
814
|
-
// until the style finishes loading. If setLang is called right after
|
|
815
|
-
// createMap (before the "load" event), apply it once the style is ready
|
|
816
|
-
// so the language change is not silently dropped.
|
|
817
518
|
if (this.map.isStyleLoaded()) {
|
|
818
519
|
this.setLayersForLanguage(lang);
|
|
819
520
|
}
|
|
@@ -825,10 +526,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
825
526
|
this.changeParentPlaceTo(place, updateStyle, onStyleReady);
|
|
826
527
|
}
|
|
827
528
|
setStyle(styleRef, styleTheme, onStyleReady) {
|
|
828
|
-
// Every swap gets a generation. All shared bookkeeping below is touched only while
|
|
829
|
-
// this swap is still the current one, so two overlapping calls cannot release each
|
|
830
|
-
// other's overlay or apply an obsolete style. `readied` stays per-call because each
|
|
831
|
-
// caller's callback must still fire exactly once.
|
|
832
529
|
const generation = ++this.styleSwapGeneration;
|
|
833
530
|
const isCurrent = () => this.styleSwapGeneration === generation;
|
|
834
531
|
let readied = false;
|
|
@@ -836,30 +533,16 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
836
533
|
if (readied)
|
|
837
534
|
return;
|
|
838
535
|
readied = true;
|
|
839
|
-
// Only the current swap owns the shared timer; a superseded swap clearing it here
|
|
840
|
-
// would leave the live swap with no safety net (and its caller hidden forever).
|
|
841
536
|
if (isCurrent() && this.styleReadyTimer) {
|
|
842
537
|
clearTimeout(this.styleReadyTimer);
|
|
843
538
|
this.styleReadyTimer = undefined;
|
|
844
539
|
}
|
|
845
540
|
onStyleReady === null || onStyleReady === void 0 ? void 0 : onStyleReady(error);
|
|
846
541
|
};
|
|
847
|
-
// `onStyleReady` must fire on EVERY path — success, a rejected style request, or a
|
|
848
|
-
// swap that never settles — because callers keep the map hidden behind a loading
|
|
849
|
-
// overlay until it arrives. The safety timer is therefore armed before the request
|
|
850
|
-
// instead of inside `.then()`.
|
|
851
542
|
if (this.styleReadyTimer)
|
|
852
543
|
clearTimeout(this.styleReadyTimer);
|
|
853
544
|
this.styleReadyTimer = setTimeout(reportReady, STYLE_READY_TIMEOUT_MS);
|
|
854
|
-
// A previous swap may still hold a `styledata` listener whose style never reached the
|
|
855
|
-
// loaded state. Drop it before starting a new one: it captured an obsolete style and
|
|
856
|
-
// would otherwise fire on this swap, wiping `baseFilters` and calling `setFilter`
|
|
857
|
-
// with layer ids the new style does not have.
|
|
858
545
|
this.clearPendingStyleSwapListener();
|
|
859
|
-
// `this.map` is created asynchronously (see `onMapStyleLoaded`), so a `setStyle` call
|
|
860
|
-
// made right after `createMap` can land before it exists. Fail loudly instead of
|
|
861
|
-
// letting `this.map.setStyle` throw into `.catch`, which reported READY and left the
|
|
862
|
-
// caller revealing the previous style as if the swap had succeeded.
|
|
863
546
|
if (!this.map) {
|
|
864
547
|
const error = new Error("setStyle called before the map finished initializing; wait for the map's load event");
|
|
865
548
|
this.logError(error, { functionName: "setStyle" });
|
|
@@ -869,40 +552,15 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
869
552
|
const stylePromise = this.fetchVenueStyle(this.parentPlaceId, styleRef, styleTheme);
|
|
870
553
|
stylePromise
|
|
871
554
|
.then((style) => {
|
|
872
|
-
// A newer swap started while this style was in flight. Applying this one now
|
|
873
|
-
// would fight the newer style layer by layer, so drop it and let the newer swap
|
|
874
|
-
// own the map and its caller's callback.
|
|
875
555
|
if (!isCurrent())
|
|
876
556
|
return;
|
|
877
|
-
// Remember what is actually on screen: `changeParentPlaceTo` refetches the
|
|
878
|
-
// style with these, so without this an explicitly applied style would be
|
|
879
|
-
// silently reverted to the constructor's on the next parent-place change.
|
|
880
|
-
// After the generation check: a superseded swap never reached the map, so it
|
|
881
|
-
// must not claim to be what is on it.
|
|
882
557
|
this.styleRef = styleRef;
|
|
883
558
|
this.styleTheme = styleTheme;
|
|
884
559
|
const useServiceWorkerCaching = this.tileCacheConfig.enabled && this.tileCacheConfig.persistToServiceWorker;
|
|
885
560
|
const finalStyle = useServiceWorkerCaching ? this.transformStyleForCaching(style) : style;
|
|
886
|
-
// Full (non-diff) swap so the previewed style completely replaces the base —
|
|
887
|
-
// a diff would keep old base layers and reappear on the next floor change.
|
|
888
561
|
this.map.setStyle(finalStyle, { diff: false });
|
|
889
|
-
// Drop the previous style's base filters SYNCHRONOUSLY, right where the layers
|
|
890
|
-
// they describe stop existing. They are keyed by layer id and persist across
|
|
891
|
-
// swaps, so any code reading them before the apply pass below (the `idle`
|
|
892
|
-
// handler's `filterByFloorKey`, a floor change racing the swap) would AND the
|
|
893
|
-
// previous style's discriminator into the new style's layers — the stale-filter
|
|
894
|
-
// washout this reset exists to prevent. Gating it on `isStyleLoaded` left exactly
|
|
895
|
-
// that window open. Fresh declared filters are re-captured lazily in
|
|
896
|
-
// `applyLayerFilters` as each indoor layer is first touched.
|
|
897
562
|
this.resetBaseFilters();
|
|
898
|
-
// Re-apply floor filters, route/circle layers and markers ONLY once the new
|
|
899
|
-
// style's sources/layers have finished loading; running them mid-reload throws
|
|
900
|
-
// (`getSource` on an undefined style) and the floor filter would not stick.
|
|
901
563
|
const applyOnceLoaded = () => {
|
|
902
|
-
// Superseded: detach and leave the map to the newer swap. Without this the
|
|
903
|
-
// listener stays attached (the slot it was tracked in has been overwritten)
|
|
904
|
-
// and re-seeds filters from layer ids the current style does not have, which
|
|
905
|
-
// makes maplibre throw and aborts the newer swap's own listener.
|
|
906
564
|
if (!isCurrent()) {
|
|
907
565
|
this.map.off("styledata", applyOnceLoaded);
|
|
908
566
|
return;
|
|
@@ -914,28 +572,13 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
914
572
|
this.pendingStyleSwapListener = undefined;
|
|
915
573
|
}
|
|
916
574
|
this.whenStyleUpdates(finalStyle);
|
|
917
|
-
// A non-diff swap replaces every layer, so anything applied ON TOP of the
|
|
918
|
-
// style — label language, caller-requested place highlights, the 3D scene's
|
|
919
|
-
// GLB layer and hidden-layer overrides — is gone and has to be replayed.
|
|
920
|
-
// `whenStyleUpdates` covers only floor filters, routes and circles.
|
|
921
575
|
this.restoreStyleOverlays();
|
|
922
576
|
this.logEvent("setStyle");
|
|
923
577
|
};
|
|
924
578
|
this.pendingStyleSwapListener = applyOnceLoaded;
|
|
925
579
|
this.map.on("styledata", applyOnceLoaded);
|
|
926
580
|
applyOnceLoaded();
|
|
927
|
-
// Re-apply the floor filter and report ready once the map is idle. This is
|
|
928
|
-
// intentionally OUTSIDE applyOnceLoaded's `isStyleLoaded` gate: the indoor
|
|
929
|
-
// polygon layers settle a beat after the swap (so the floor filter in
|
|
930
|
-
// whenStyleUpdates misses them and the venue paints every floor at once), and
|
|
931
|
-
// `idle` only fires once the style is loaded and its first tiles rendered — so
|
|
932
|
-
// filterByFloorKey is safe here and does not depend on the sometimes-flaky
|
|
933
|
-
// isStyleLoaded check. onStyleReady lets callers reveal the map only once it is
|
|
934
|
-
// settled; the timer armed above just clears a hanging overlay if idle never fires.
|
|
935
581
|
this.map.once("idle", () => {
|
|
936
|
-
// `once` cannot be cancelled, so a superseded swap's handler still fires —
|
|
937
|
-
// filtering here keeps it from re-filtering the newer style's floors and from
|
|
938
|
-
// reporting the newer swap's caller ready ahead of time.
|
|
939
582
|
if (!isCurrent())
|
|
940
583
|
return;
|
|
941
584
|
this.filterByFloorKey(this.currentFloor);
|
|
@@ -943,46 +586,18 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
943
586
|
});
|
|
944
587
|
})
|
|
945
588
|
.catch((error) => {
|
|
946
|
-
// A superseded swap must not tear down the listener the CURRENT swap installed.
|
|
947
589
|
if (isCurrent()) {
|
|
948
590
|
this.clearPendingStyleSwapListener();
|
|
949
591
|
}
|
|
950
592
|
this.logError(error, { functionName: "setStyle" });
|
|
951
|
-
// Release the caller immediately instead of making it wait out the safety timer:
|
|
952
|
-
// the style will never arrive, so the overlay has nothing to wait for. The error
|
|
953
|
-
// is handed to the callback so a caller can tell a failed swap from an applied
|
|
954
|
-
// one — the previous style is still on screen either way.
|
|
955
593
|
reportReady(error instanceof Error ? error : new Error(String(error)));
|
|
956
594
|
});
|
|
957
595
|
}
|
|
958
|
-
/**
|
|
959
|
-
* Forgets every captured base filter so the next style's declared filters are read
|
|
960
|
-
* fresh from that style instead of inherited from the previous one.
|
|
961
|
-
*
|
|
962
|
-
* Both halves must move together: `baseFilters` holds the expressions and
|
|
963
|
-
* `capturedBaseFilters` records which layer ids have already been resolved, so
|
|
964
|
-
* clearing only the first would leave every id marked "already captured" and the new
|
|
965
|
-
* style's filters would never be read at all.
|
|
966
|
-
*/
|
|
967
596
|
resetBaseFilters() {
|
|
968
597
|
this.baseFilters = {};
|
|
969
598
|
this.capturedBaseFilters.clear();
|
|
970
599
|
}
|
|
971
|
-
/**
|
|
972
|
-
* Replays everything that lives ON TOP of the map style after a full (non-diff) swap
|
|
973
|
-
* has deleted it: label language expressions, caller-requested place highlights and
|
|
974
|
-
* the 3D scene's GLB layer / hidden-layer overrides.
|
|
975
|
-
*
|
|
976
|
-
* These are deliberately not part of `whenStyleUpdates`, which restores only
|
|
977
|
-
* style-derived state. These are decisions the SDK's callers made through `setLang`,
|
|
978
|
-
* `setPlacesAsSelected`, `addBorderToPlaces` and the 3D config, and nothing else would
|
|
979
|
-
* ever restore them.
|
|
980
|
-
*/
|
|
981
600
|
restoreStyleOverlays() {
|
|
982
|
-
// Each step is isolated: the style itself has already been applied by the time we get
|
|
983
|
-
// here, so one failing restore must neither skip the others nor bubble out into
|
|
984
|
-
// `setStyle`'s `.catch`, which would report the successful swap to `onStyleReady` as
|
|
985
|
-
// a failure. `setPlacesAsSelected` / `addBorderToPlaces` throw by contract.
|
|
986
601
|
const restore = (what, step) => {
|
|
987
602
|
try {
|
|
988
603
|
step();
|
|
@@ -1000,13 +615,7 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1000
615
|
const { placeIds, color, width } = this.borderedPlacesRequest;
|
|
1001
616
|
restore("borderedPlaces", () => this.addBorderToPlaces(placeIds, color, width));
|
|
1002
617
|
}
|
|
1003
|
-
// A style swap can cross the 3D/2D line: `changeParentPlaceTo` refetches `mapStyleJson`, and
|
|
1004
|
-
// the new venue's style may publish no extrusions. Re-read it from the live style before
|
|
1005
|
-
// deciding, or the reattach below would put the overlay back on flat ground.
|
|
1006
618
|
this.styleSupports3D = this.is3DStyle();
|
|
1007
|
-
// The swap removed the GLB custom layer, and MapLibre called its `onRemove`, which
|
|
1008
|
-
// disposes the whole three.js scene. Nothing else re-adds it, so without this every
|
|
1009
|
-
// 3D model disappears permanently and `hideLayers` stops being applied.
|
|
1010
619
|
restore("scene3D", () => {
|
|
1011
620
|
var _a;
|
|
1012
621
|
if (!this.is3DSceneActive())
|
|
@@ -1014,31 +623,16 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1014
623
|
(_a = this.scene3D) === null || _a === void 0 ? void 0 : _a.reattachToStyle();
|
|
1015
624
|
});
|
|
1016
625
|
}
|
|
1017
|
-
/**
|
|
1018
|
-
* Removes the `styledata` listener left by an in-flight {@link setStyle} swap, if any.
|
|
1019
|
-
* Called before starting a new swap and when one fails, so a listener holding an
|
|
1020
|
-
* obsolete style can never fire against a different style's layers.
|
|
1021
|
-
*/
|
|
1022
626
|
clearPendingStyleSwapListener() {
|
|
1023
627
|
var _a;
|
|
1024
628
|
if (!this.pendingStyleSwapListener)
|
|
1025
629
|
return;
|
|
1026
|
-
// `this.map?` — a listener can only have been installed while the map existed, but
|
|
1027
|
-
// this also runs from `destroyMap` and from `setStyle` before the map is created.
|
|
1028
630
|
(_a = this.map) === null || _a === void 0 ? void 0 : _a.off("styledata", this.pendingStyleSwapListener);
|
|
1029
631
|
this.pendingStyleSwapListener = undefined;
|
|
1030
632
|
}
|
|
1031
|
-
/**
|
|
1032
|
-
* Removes current parent place and updates style to default
|
|
1033
|
-
*/
|
|
1034
633
|
removeParentPlace() {
|
|
1035
634
|
this.changeParentPlaceTo(undefined, true);
|
|
1036
635
|
}
|
|
1037
|
-
/**
|
|
1038
|
-
* Applies filters and changes to layers according to given style.
|
|
1039
|
-
* Expected to be called every time a new style is loaded
|
|
1040
|
-
* @param newStyle
|
|
1041
|
-
*/
|
|
1042
636
|
whenStyleUpdates(newStyle) {
|
|
1043
637
|
var _a;
|
|
1044
638
|
if (newStyle) {
|
|
@@ -1049,17 +643,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1049
643
|
this.filterByFloorKey(this.currentFloor);
|
|
1050
644
|
(_a = this.scene3D) === null || _a === void 0 ? void 0 : _a.refreshOverlay(this.currentFloor);
|
|
1051
645
|
}
|
|
1052
|
-
/**
|
|
1053
|
-
* Internal accessor for every marker currently on the map, used by
|
|
1054
|
-
* {@link MarkerLayoutController} to compute collision avoidance. Not part
|
|
1055
|
-
* of the public `MapVXMap` interface.
|
|
1056
|
-
*
|
|
1057
|
-
* The user-location marker and the route controller's markers live outside
|
|
1058
|
-
* `this.markers`, but they still occupy screen space — leaving them out
|
|
1059
|
-
* would let labels be placed straight on top of them. They carry no label
|
|
1060
|
-
* of their own, so they only ever act as obstacles.
|
|
1061
|
-
* @internal
|
|
1062
|
-
*/
|
|
1063
646
|
getMarkers() {
|
|
1064
647
|
const unmanaged = this.routeController.getRouteMarkers();
|
|
1065
648
|
if (this.userLocationMarker)
|
|
@@ -1069,7 +652,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1069
652
|
addMarker(marker) {
|
|
1070
653
|
var _a;
|
|
1071
654
|
try {
|
|
1072
|
-
// Check if a marker with the same ID already exists and remove it
|
|
1073
655
|
if (marker.id) {
|
|
1074
656
|
const existingMarkerIndex = this.markers.findIndex((m) => m.id === marker.id);
|
|
1075
657
|
if (existingMarkerIndex !== -1) {
|
|
@@ -1083,8 +665,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1083
665
|
}
|
|
1084
666
|
}
|
|
1085
667
|
const markerCreated = new MarkerAttribute(Object.assign(Object.assign({}, marker), { maxLabelWidthPx: (_a = marker.maxLabelWidthPx) !== null && _a !== void 0 ? _a : this.markerLayoutConfig.maxLabelWidthPx }));
|
|
1086
|
-
// While a floor change is still being rebuilt, the marker is shown by that
|
|
1087
|
-
// change's settle step, together with the new floor.
|
|
1088
668
|
if (!this.floorSettlePending) {
|
|
1089
669
|
markerCreated.changeFloor(this.currentFloor, this.map, this.isOutdoorFloor(this.currentFloor));
|
|
1090
670
|
}
|
|
@@ -1181,11 +761,9 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1181
761
|
}
|
|
1182
762
|
addCircle(circle) {
|
|
1183
763
|
try {
|
|
1184
|
-
// Check if a circle with the same ID already exists and replace it
|
|
1185
764
|
if (circle.id) {
|
|
1186
765
|
this.circles = this.circles.filter((c) => c.id !== circle.id);
|
|
1187
766
|
}
|
|
1188
|
-
// resolveCircleConfig validates radiusMeters and coordinates
|
|
1189
767
|
const record = resolveCircleConfig(circle);
|
|
1190
768
|
this.circles.push(record);
|
|
1191
769
|
this.refreshCircles();
|
|
@@ -1201,7 +779,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1201
779
|
const index = this.circles.findIndex((c) => c.id === circleConfig.id);
|
|
1202
780
|
if (index === -1)
|
|
1203
781
|
return null;
|
|
1204
|
-
// resolveCircleConfig validates radiusMeters and coordinates
|
|
1205
782
|
this.circles[index] = resolveCircleConfig(circleConfig, this.circles[index].hidden);
|
|
1206
783
|
this.refreshCircles();
|
|
1207
784
|
this.logEvent("updateCircle");
|
|
@@ -1226,7 +803,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1226
803
|
const circle = this.circles.find((c) => c.id === circleId);
|
|
1227
804
|
if (circle === undefined)
|
|
1228
805
|
return false;
|
|
1229
|
-
// Validate inputs before modifying
|
|
1230
806
|
if (!center) {
|
|
1231
807
|
throw new Error("Circle center is required");
|
|
1232
808
|
}
|
|
@@ -1259,7 +835,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1259
835
|
const circle = this.circles.find((c) => c.id === circleId);
|
|
1260
836
|
if (circle === undefined)
|
|
1261
837
|
return false;
|
|
1262
|
-
// Update only style properties, clamp opacities
|
|
1263
838
|
if (style.fillColor !== undefined)
|
|
1264
839
|
circle.fillColor = style.fillColor;
|
|
1265
840
|
if (style.fillOpacity !== undefined)
|
|
@@ -1330,12 +905,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1330
905
|
return false;
|
|
1331
906
|
}
|
|
1332
907
|
}
|
|
1333
|
-
/**
|
|
1334
|
-
* Builds the GeoJSON FeatureCollection for every currently visible circle.
|
|
1335
|
-
* Visibility mirrors marker semantics: a circle with a floor is shown only
|
|
1336
|
-
* while that floor is displayed, and a circle without a floor is shown only
|
|
1337
|
-
* in outdoor contexts. Hidden circles are always omitted.
|
|
1338
|
-
*/
|
|
1339
908
|
circleFeatureCollection() {
|
|
1340
909
|
var _a;
|
|
1341
910
|
const floorId = (_a = this.currentFloor) !== null && _a !== void 0 ? _a : "";
|
|
@@ -1368,24 +937,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1368
937
|
}));
|
|
1369
938
|
return { type: "FeatureCollection", features };
|
|
1370
939
|
}
|
|
1371
|
-
/**
|
|
1372
|
-
* Idempotently adds the shared circle source and its fill/line layers.
|
|
1373
|
-
* Layers are inserted below the first symbol layer so place labels and
|
|
1374
|
-
* markers stay readable above the translucent fill. Safe to call at any
|
|
1375
|
-
* time: a style that is still loading simply rejects the calls, and the
|
|
1376
|
-
* styledata listener retries once the style is ready.
|
|
1377
|
-
*/
|
|
1378
|
-
/**
|
|
1379
|
-
* Resolves the layer id to insert circle layers before, for one render
|
|
1380
|
-
* order. `undefined` means "append on top".
|
|
1381
|
-
*
|
|
1382
|
-
* `aboveBasemap` finds the topmost non-symbol layer of the style and
|
|
1383
|
-
* inserts before the first symbol layer that follows it. On indoor styles
|
|
1384
|
-
* the floor-plate and building polygons are ordered after the first symbol
|
|
1385
|
-
* layer, so anchoring on the topmost geometry layer — instead of the first
|
|
1386
|
-
* symbol layer — guarantees circles are never occluded by basemap fills
|
|
1387
|
-
* while still rendering below the labels that follow them.
|
|
1388
|
-
*/
|
|
1389
940
|
circleBeforeIdFor(order) {
|
|
1390
941
|
var _a, _b, _c, _d;
|
|
1391
942
|
if (order === "top")
|
|
@@ -1394,7 +945,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1394
945
|
if (order === "belowLabels") {
|
|
1395
946
|
return (_c = layers.find((layer) => layer.type === "symbol")) === null || _c === void 0 ? void 0 : _c.id;
|
|
1396
947
|
}
|
|
1397
|
-
// aboveBasemap
|
|
1398
948
|
let lastNonSymbolIndex = -1;
|
|
1399
949
|
layers.forEach((layer, index) => {
|
|
1400
950
|
if (layer.type !== "symbol")
|
|
@@ -1402,15 +952,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1402
952
|
});
|
|
1403
953
|
return (_d = layers.slice(lastNonSymbolIndex + 1).find((layer) => layer.type === "symbol")) === null || _d === void 0 ? void 0 : _d.id;
|
|
1404
954
|
}
|
|
1405
|
-
/**
|
|
1406
|
-
* Idempotently ensures the shared circle source and one fill/line layer
|
|
1407
|
-
* pair per render order in use, at the placement that order requires.
|
|
1408
|
-
* Placement is recomputed and re-asserted (via moveLayer) on every call,
|
|
1409
|
-
* so circles regain their correct z-order after any style reload or
|
|
1410
|
-
* floor/parent-place change. Safe to call at any time: a style that is
|
|
1411
|
-
* still loading simply rejects the calls, and the styledata listener
|
|
1412
|
-
* retries once the style is ready.
|
|
1413
|
-
*/
|
|
1414
955
|
ensureCircleLayers() {
|
|
1415
956
|
if (!this.map)
|
|
1416
957
|
return;
|
|
@@ -1422,14 +963,7 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1422
963
|
});
|
|
1423
964
|
}
|
|
1424
965
|
const ordersInUse = new Set(this.circles.map((c) => c.renderOrder));
|
|
1425
|
-
// Always keep the default bucket alive so an empty map still renders
|
|
1426
|
-
// newly added circles without a layer rebuild
|
|
1427
966
|
ordersInUse.add("aboveBasemap");
|
|
1428
|
-
// Process buckets lowest-first (CIRCLE_RENDER_ORDERS is canonical):
|
|
1429
|
-
// when two buckets resolve to the same anchor, each addLayer/moveLayer
|
|
1430
|
-
// lands immediately before it, so a bucket processed later paints above
|
|
1431
|
-
// the ones processed earlier. Canonical order keeps
|
|
1432
|
-
// belowLabels < aboveBasemap < top regardless of circle insertion order.
|
|
1433
967
|
for (const order of CIRCLE_RENDER_ORDERS) {
|
|
1434
968
|
if (!ordersInUse.has(order))
|
|
1435
969
|
continue;
|
|
@@ -1475,11 +1009,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1475
1009
|
this.debugLog("Layers not added: style not loaded yet, the styledata listener will re-add them", error);
|
|
1476
1010
|
}
|
|
1477
1011
|
}
|
|
1478
|
-
/**
|
|
1479
|
-
* Re-renders all circles: ensures the source and layers exist, then pushes
|
|
1480
|
-
* the current FeatureCollection. Called after every mutation of the circle
|
|
1481
|
-
* list, on floor changes, and when the map style reloads.
|
|
1482
|
-
*/
|
|
1483
1012
|
refreshCircles() {
|
|
1484
1013
|
if (!this.map)
|
|
1485
1014
|
return;
|
|
@@ -1494,21 +1023,12 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1494
1023
|
this.debugLog("Source not found (a new style may still be loading)", error);
|
|
1495
1024
|
}
|
|
1496
1025
|
}
|
|
1497
|
-
/**
|
|
1498
|
-
* Use it to change the current layer
|
|
1499
|
-
* @param floorKey floor id
|
|
1500
|
-
*/
|
|
1501
1026
|
filterByFloorKey(floorKey) {
|
|
1502
1027
|
this.currentFloor = floorKey;
|
|
1503
1028
|
const floorKeyString = floorKey !== null && floorKey !== void 0 ? floorKey : "";
|
|
1504
1029
|
if (this.innerFloors.every((floor) => floor.key !== floorKey) && floorKey !== "") {
|
|
1505
1030
|
this.logEvent("invalidFloorKey", { floorKey: floorKeyString });
|
|
1506
1031
|
}
|
|
1507
|
-
// One style read for the whole floor change. `getStyle()` serializes every
|
|
1508
|
-
// source and layer of the venue style, and the second read is the expensive
|
|
1509
|
-
// one: `updateFiltersTo` writes filters and layout properties in between,
|
|
1510
|
-
// and each write nulls maplibre's `_serializedLayers` cache, so anything
|
|
1511
|
-
// that reads the style afterwards rebuilds it from scratch.
|
|
1512
1032
|
const layers = this.safeStyleLayers();
|
|
1513
1033
|
this.updateFiltersTo(floorKeyString, layers);
|
|
1514
1034
|
this.updateMarkersWhenFloorSettles(floorKeyString, layers);
|
|
@@ -1516,28 +1036,10 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1516
1036
|
this.routeController.updateRouteLayers(floorKeyString);
|
|
1517
1037
|
this.routeController.updateRouteMarkerVisibility(floorKeyString);
|
|
1518
1038
|
}
|
|
1519
|
-
/**
|
|
1520
|
-
* Show/hide the HTML markers for `floorId` once the indoor tiles have been
|
|
1521
|
-
* rebuilt with the new floor filters.
|
|
1522
|
-
*
|
|
1523
|
-
* A floor change is a `setFilter` on every indoor layer: MapLibre rebuilds the
|
|
1524
|
-
* tile buckets in its worker, so the new floor appears a few frames later
|
|
1525
|
-
* (hundreds of ms on a low-end panel) while a marker is a DOM element that
|
|
1526
|
-
* would move instantly. Waiting for the source to report loaded makes floor
|
|
1527
|
-
* polygons and markers switch in the same frame. The wait is bounded, is
|
|
1528
|
-
* dropped when a newer floor change arrives, and is skipped outside a
|
|
1529
|
-
* browser (no `requestAnimationFrame`).
|
|
1530
|
-
*/
|
|
1531
1039
|
updateMarkersWhenFloorSettles(floorId, styleLayers) {
|
|
1532
1040
|
const token = ++this.floorSettleToken;
|
|
1533
|
-
// Resolved rather than probed with `hasStyle()`, which is another full
|
|
1534
|
-
// `getStyle()` — and by this point the most expensive kind, because
|
|
1535
|
-
// `updateFiltersTo` has just invalidated the serialized-layer cache.
|
|
1536
1041
|
const layers = styleLayers === undefined ? this.safeStyleLayers() : styleLayers;
|
|
1537
1042
|
if (typeof requestAnimationFrame !== "function" || layers === null) {
|
|
1538
|
-
// No poll will run for this floor change, so nothing would ever clear the
|
|
1539
|
-
// flag later: leaving it set makes every subsequent `addMarker` skip
|
|
1540
|
-
// `changeFloor` and the marker is never attached to the map.
|
|
1541
1043
|
this.floorSettleDeadline = null;
|
|
1542
1044
|
this.updateMarkersTo(floorId);
|
|
1543
1045
|
return;
|
|
@@ -1554,9 +1056,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1554
1056
|
const loaded = sourceIds.every((id) => this.isSourceSettled(id));
|
|
1555
1057
|
if (!loaded)
|
|
1556
1058
|
sawReloading = true;
|
|
1557
|
-
// The reload is dispatched on the map's next render, which may run after
|
|
1558
|
-
// this callback within the same frame: give it a couple of frames to be
|
|
1559
|
-
// observed before concluding there was nothing to reload.
|
|
1560
1059
|
const settled = loaded && (sawReloading || frames >= FLOOR_SETTLE_MIN_FRAMES);
|
|
1561
1060
|
if (settled || this.now() >= deadline) {
|
|
1562
1061
|
this.floorSettleDeadline = null;
|
|
@@ -1567,19 +1066,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1567
1066
|
};
|
|
1568
1067
|
requestAnimationFrame(poll);
|
|
1569
1068
|
}
|
|
1570
|
-
/**
|
|
1571
|
-
* Sources whose tiles a switch to `floorId` actually reloads, and which the
|
|
1572
|
-
* marker settle therefore has to wait on.
|
|
1573
|
-
*
|
|
1574
|
-
* With a vector basemap that is the source the `indoor-*` layers draw from,
|
|
1575
|
-
* because the floor change is a `setFilter` over those layers. An offline
|
|
1576
|
-
* bundle's raster basemap switches floors by making `raster-floor-<key>`
|
|
1577
|
-
* visible instead, and those tiles only begin loading at that moment — while
|
|
1578
|
-
* its `indoor-*` layers carry labels and hover, are already loaded, and would
|
|
1579
|
-
* report settled at once, letting the markers switch a floor before its image
|
|
1580
|
-
* had painted. That is the configuration this wait exists for, so both are
|
|
1581
|
-
* waited on.
|
|
1582
|
-
*/
|
|
1583
1069
|
floorSettleSourceIds(floorId, layers) {
|
|
1584
1070
|
const ids = new Set();
|
|
1585
1071
|
const rasterFloor = layers.find((layer) => layer.id === `raster-floor-${floorId}`);
|
|
@@ -1589,7 +1075,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1589
1075
|
ids.add(this.indoorSourceId(layers));
|
|
1590
1076
|
return [...ids];
|
|
1591
1077
|
}
|
|
1592
|
-
/** The vector source the `indoor-*` layers draw from (`indoorequal` by default). */
|
|
1593
1078
|
indoorSourceId(layers) {
|
|
1594
1079
|
for (const layer of layers) {
|
|
1595
1080
|
if (layer.id.startsWith("indoor-") && "source" in layer && typeof layer.source === "string") {
|
|
@@ -1633,21 +1118,8 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1633
1118
|
var _a, _b, _c;
|
|
1634
1119
|
if (!this.map)
|
|
1635
1120
|
return;
|
|
1636
|
-
// `null` means the caller looked and there was no style; only `undefined`
|
|
1637
|
-
// means it did not look.
|
|
1638
1121
|
const layers = (_a = (styleLayers === undefined ? this.safeStyleLayers() : styleLayers)) !== null && _a !== void 0 ? _a : [];
|
|
1639
|
-
// Raster basemap (offline bundles baked with one raster archive per floor):
|
|
1640
|
-
// a floor is switched by showing its `raster-floor-<key>` layer and hiding
|
|
1641
|
-
// the others. The remaining `indoor-*` layers (labels, hover, highlights)
|
|
1642
|
-
// are still vector and keep going through the filter logic below.
|
|
1643
1122
|
const rasterFloorPrefix = "raster-floor-";
|
|
1644
|
-
// Only switch the raster basemap when there is a baked layer to switch to.
|
|
1645
|
-
// Hiding every raster floor leaves the basemap blank, and no id can match in
|
|
1646
|
-
// two cases: no floor at all (an outdoor place, or a venue with no floors,
|
|
1647
|
-
// where `currentFloor` is `""`), and a floor the bundle has no raster
|
|
1648
|
-
// archive for — a venue where only some floors are baked, or a floor added
|
|
1649
|
-
// after the bundle was built. Keeping the current one visible is the safe
|
|
1650
|
-
// fallback for both.
|
|
1651
1123
|
const rasterFloorLayerIds = layers
|
|
1652
1124
|
.filter((l) => l.id.startsWith(rasterFloorPrefix))
|
|
1653
1125
|
.map((l) => l.id);
|
|
@@ -1664,14 +1136,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1664
1136
|
});
|
|
1665
1137
|
const baseFloorId = (_b = this.innerFloors.find((floor) => floor.key === floorId)) === null || _b === void 0 ? void 0 : _b.baseFloor;
|
|
1666
1138
|
const indoorLayers = layers.filter((layer) => layer.id.startsWith("indoor-"));
|
|
1667
|
-
// Resolve each indoor layer's declared (base) filter before we start folding floor
|
|
1668
|
-
// filters into it — and before cloning it into a `base-indoor-*` layer, which copies
|
|
1669
|
-
// the base filter across. Layers added asynchronously after a `setStyle` swap are
|
|
1670
|
-
// missing when `setBaseFilters` runs, so this is where their still-pristine filter
|
|
1671
|
-
// is captured; without it the layer loses its own discrimination and repaints every
|
|
1672
|
-
// feature (the washed-out / blue-outline look after changing floors). Layers already
|
|
1673
|
-
// resolved are skipped, so a filter this class wrote is never mistaken for a
|
|
1674
|
-
// declared one.
|
|
1675
1139
|
indoorLayers.forEach((layer) => this.captureDeclaredBaseFilter(layer.id));
|
|
1676
1140
|
if (baseFloorId != undefined) {
|
|
1677
1141
|
const firstLayerId = (_c = indoorLayers[0]) === null || _c === void 0 ? void 0 : _c.id;
|
|
@@ -1689,11 +1153,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1689
1153
|
this.applyLayerFilters(layer, floorId);
|
|
1690
1154
|
});
|
|
1691
1155
|
}
|
|
1692
|
-
/**
|
|
1693
|
-
* Reads a layer's current filter, tolerating the layer having been removed or the
|
|
1694
|
-
* style being mid-swap (maplibre `getFilter` throws in those cases). Returns
|
|
1695
|
-
* `undefined` instead of throwing so base-filter capture never aborts floor filtering.
|
|
1696
|
-
*/
|
|
1697
1156
|
safeGetFilter(layerId) {
|
|
1698
1157
|
try {
|
|
1699
1158
|
return this.map.getFilter(layerId);
|
|
@@ -1704,15 +1163,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1704
1163
|
}
|
|
1705
1164
|
applyLayerFilters(layer, floorId) {
|
|
1706
1165
|
var _a;
|
|
1707
|
-
// Resolve the layer's declared (base) filter the first time we touch it. Indoor
|
|
1708
|
-
// layers such as `indoor-polygon-room` share one source and are told apart only by
|
|
1709
|
-
// their own filter (e.g. `["in","room",["get","tags"]]`); we must fold that into the
|
|
1710
|
-
// floor filter or the layer repaints every feature. Some of these layers are added
|
|
1711
|
-
// asynchronously after a `setStyle` swap, so they are absent when `setBaseFilters`
|
|
1712
|
-
// runs — capturing here, while their live filter is still pristine, is what keeps a
|
|
1713
|
-
// floor change from wiping the style (the washed-out, blue-outline look).
|
|
1714
|
-
// `base-indoor-*` clones inherit their base filter from the layer they were cloned
|
|
1715
|
-
// from, so they are never read back.
|
|
1716
1166
|
if (!layer.id.startsWith("base-indoor-")) {
|
|
1717
1167
|
this.captureDeclaredBaseFilter(layer.id);
|
|
1718
1168
|
}
|
|
@@ -1748,9 +1198,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1748
1198
|
(layer.type == "fill" || layer.type === "fill-extrusion")) {
|
|
1749
1199
|
customFilters.push(["!", ["in", this.hoveredId, ["get", "ref"]]]);
|
|
1750
1200
|
}
|
|
1751
|
-
// From here on this layer's live filter is ours, never the style's declared one.
|
|
1752
|
-
// Marking it keeps any later pass from reading it back as a base filter — that is
|
|
1753
|
-
// what used to AND the previous floor into the next one and blank the layer out.
|
|
1754
1201
|
this.capturedBaseFilters.add(layer.id);
|
|
1755
1202
|
if (baseFilter != null) {
|
|
1756
1203
|
const finalFilter = ["all", baseFilter, customFilters];
|
|
@@ -1760,21 +1207,9 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1760
1207
|
this.map.setFilter(layer.id, customFilters);
|
|
1761
1208
|
}
|
|
1762
1209
|
}
|
|
1763
|
-
/**
|
|
1764
|
-
* Floors of the parent place
|
|
1765
|
-
* @returns Inner floors of the parent place
|
|
1766
|
-
*/
|
|
1767
1210
|
getInnerFloors() {
|
|
1768
1211
|
return this.innerFloors;
|
|
1769
1212
|
}
|
|
1770
|
-
/**
|
|
1771
|
-
* Whether `floorId` shows the venue's outdoors, and so whether entities that
|
|
1772
|
-
* carry no floor of their own belong on screen with it.
|
|
1773
|
-
*
|
|
1774
|
-
* A map without a parent place is outdoors throughout; inside one, only a
|
|
1775
|
-
* floor reachable from GPS is. Markers, circles and the route marker all hang
|
|
1776
|
-
* their visibility on this, so they answer it the same way.
|
|
1777
|
-
*/
|
|
1778
1213
|
isOutdoorFloor(floorId) {
|
|
1779
1214
|
var _a, _b;
|
|
1780
1215
|
return (!this.parentPlace ||
|
|
@@ -1886,11 +1321,9 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1886
1321
|
maxLng !== null && maxLng !== void 0 ? maxLng : 0,
|
|
1887
1322
|
maxLat !== null && maxLat !== void 0 ? maxLat : 0,
|
|
1888
1323
|
];
|
|
1889
|
-
// Get container dimensions for percentage-based padding calculations
|
|
1890
1324
|
const container = this.map.getContainer();
|
|
1891
1325
|
const containerWidth = container.clientWidth;
|
|
1892
1326
|
const containerHeight = container.clientHeight;
|
|
1893
|
-
// Convert padding values with units to pixels
|
|
1894
1327
|
const padding = convertPaddingToPixels(options === null || options === void 0 ? void 0 : options.padding, containerWidth, containerHeight);
|
|
1895
1328
|
const fitOptions = Object.assign(Object.assign({}, options), { padding });
|
|
1896
1329
|
const bearing = this.map.getBearing();
|
|
@@ -1909,11 +1342,9 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1909
1342
|
return;
|
|
1910
1343
|
}
|
|
1911
1344
|
const onComplete = options === null || options === void 0 ? void 0 : options.onComplete;
|
|
1912
|
-
// Get container dimensions for percentage-based padding calculations
|
|
1913
1345
|
const container = this.map.getContainer();
|
|
1914
1346
|
const containerWidth = container.clientWidth;
|
|
1915
1347
|
const containerHeight = container.clientHeight;
|
|
1916
|
-
// Convert padding values with units to pixels
|
|
1917
1348
|
const padding = convertPaddingToPixels(options === null || options === void 0 ? void 0 : options.padding, containerWidth, containerHeight);
|
|
1918
1349
|
if (coordinates.length === 1) {
|
|
1919
1350
|
const [coord] = coordinates;
|
|
@@ -1933,17 +1364,8 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1933
1364
|
maxZoom: (_c = options === null || options === void 0 ? void 0 : options.maxZoom) !== null && _c !== void 0 ? _c : this.map.getMaxZoom(),
|
|
1934
1365
|
minZoom: this.map.getMinZoom(),
|
|
1935
1366
|
};
|
|
1936
|
-
// Orthographic oriented fit (exact for pitch 0). maplibre's fitBounds only
|
|
1937
|
-
// fits a north-up LngLatBounds, which wastes viewport space for diagonal
|
|
1938
|
-
// geometries under a bearing.
|
|
1939
1367
|
let camera = computeOrientedCamera(coordinates, cameraParams);
|
|
1940
|
-
// With a tilted camera the orthographic zoom is off due to perspective, so
|
|
1941
|
-
// refine it against maplibre's real projection on a cloned transform.
|
|
1942
1368
|
if (pitch > 0) {
|
|
1943
|
-
// Simulated on the live map through its public API rather than on `map.transform.clone()`:
|
|
1944
|
-
// MapLibre v6 removes the internal transform and exposes no replacement. The whole loop is
|
|
1945
|
-
// synchronous and ends in `restore()`, so no intermediate frame is ever painted.
|
|
1946
|
-
// See DEVELOPER_DOCS/MAPLIBRE_V6_MIGRATION.md.
|
|
1947
1369
|
const fitTransform = new LiveMapFitTransform(this.map);
|
|
1948
1370
|
try {
|
|
1949
1371
|
camera = refineCameraForPitch(fitTransform, coordinates, camera, Object.assign(Object.assign({}, cameraParams), { pitch }));
|
|
@@ -1960,12 +1382,10 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
1960
1382
|
padding }));
|
|
1961
1383
|
}
|
|
1962
1384
|
fitRouteByPlace(route, placeId, options) {
|
|
1963
|
-
// Filter steps that belong to the specified place
|
|
1964
1385
|
const stepsInPlace = route.steps.filter((step) => step.startInsidePlace === placeId || step.endInsidePlace === placeId);
|
|
1965
1386
|
if (stepsInPlace.length === 0) {
|
|
1966
1387
|
return;
|
|
1967
1388
|
}
|
|
1968
|
-
// Extract all coordinates from the filtered steps
|
|
1969
1389
|
const coords = stepsInPlace.flatMap((step) => extractStepCoordinates(step));
|
|
1970
1390
|
if (coords.length > 0) {
|
|
1971
1391
|
this.fitCoordinates(coords, options);
|
|
@@ -2019,27 +1439,14 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2019
1439
|
this.logEvent("addLiveRoute");
|
|
2020
1440
|
const fetchRouteConfig = new InternalGetRouteConfiguration(config);
|
|
2021
1441
|
const drawRouteConfig = new InternalDrawRouteConfiguration(drawConfig);
|
|
2022
|
-
// Take a ticket BEFORE awaiting: refreshes overlap, and an older response
|
|
2023
|
-
// resolving after a newer one must not clobber it (stale route drawn,
|
|
2024
|
-
// liveRouteId pointing at the wrong instance).
|
|
2025
1442
|
const ticket = ++this.liveRouteTicket;
|
|
2026
1443
|
const route = await this.repository.fetchAndParseLiveRoute(fetchRouteConfig);
|
|
2027
1444
|
if (ticket !== this.liveRouteTicket) {
|
|
2028
|
-
// Superseded while in flight — the map shows (or will show) the newer
|
|
2029
|
-
// route. Return the fetched data without drawing it.
|
|
2030
1445
|
return route;
|
|
2031
1446
|
}
|
|
2032
|
-
// Replace the previous live route so repeated refreshes don't stack paths
|
|
2033
|
-
// on the map. Removal happens AFTER the fetch, so a failed refresh leaves
|
|
2034
|
-
// the current route on screen. Targeted by id, so routes drawn with
|
|
2035
|
-
// addRoute are untouched.
|
|
2036
1447
|
if (this.liveRouteId !== undefined && this.liveRouteId !== route.id) {
|
|
2037
1448
|
this.routeController.removeRoute(this.liveRouteId);
|
|
2038
1449
|
}
|
|
2039
|
-
// Clear any instance already using this id (a same-id refresh, or the same
|
|
2040
|
-
// route previously drawn via addRoute) — the controller derives its
|
|
2041
|
-
// source/layer ids from the route id, so re-adding without removing would
|
|
2042
|
-
// throw "Source already exists".
|
|
2043
1450
|
if (this.routeController.getRouteIds().includes(route.id)) {
|
|
2044
1451
|
this.routeController.removeRoute(route.id);
|
|
2045
1452
|
}
|
|
@@ -2093,13 +1500,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2093
1500
|
}
|
|
2094
1501
|
this.syncLiveRouteId();
|
|
2095
1502
|
}
|
|
2096
|
-
/**
|
|
2097
|
-
* Drop {@link liveRouteId} when the instance it points at is no longer on the
|
|
2098
|
-
* map (removed via removeRoute/removeRouteById/removeAllRoutes — including the
|
|
2099
|
-
* no-arg removeRoute, which removes the last-added route). Keeps the live
|
|
2100
|
-
* bookkeeping in sync so a later {@link addLiveRoute} doesn't act on a
|
|
2101
|
-
* dangling id.
|
|
2102
|
-
*/
|
|
2103
1503
|
syncLiveRouteId() {
|
|
2104
1504
|
if (this.liveRouteId !== undefined &&
|
|
2105
1505
|
!this.routeController.getRouteIds().includes(this.liveRouteId)) {
|
|
@@ -2134,15 +1534,12 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2134
1534
|
this.map.on("click", async (e) => {
|
|
2135
1535
|
var _a, _b;
|
|
2136
1536
|
const features = this.map.queryRenderedFeatures(e.point);
|
|
2137
|
-
// Filter room features by current floor
|
|
2138
1537
|
const roomFeatures = features.filter((feature) => { var _a; return feature.properties.class === "room" && ((_a = feature.properties) === null || _a === void 0 ? void 0 : _a.floor_key) === this.currentFloor; });
|
|
2139
1538
|
const touchedFeature = roomFeatures[0];
|
|
2140
1539
|
const ref = touchedFeature === null || touchedFeature === void 0 ? void 0 : touchedFeature.properties.ref;
|
|
2141
1540
|
if (ref != null && typeof ref === "string" && ref.length > 0) {
|
|
2142
1541
|
console.log("touchedFeature", ref);
|
|
2143
|
-
// First, search in current subPlaces
|
|
2144
1542
|
let clickedPlace = this.subPlaces.find((subPlace) => subPlace.mapvxId === ref);
|
|
2145
|
-
// If not found, search in subplaces of potential parent places
|
|
2146
1543
|
if (clickedPlace === undefined) {
|
|
2147
1544
|
for (const potentialParentPlace of this.potentialParentPlaces) {
|
|
2148
1545
|
const cachedSubPlaces = this.repository.getCachedSubPlaces(potentialParentPlace.mapvxId);
|
|
@@ -2154,7 +1551,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2154
1551
|
}
|
|
2155
1552
|
}
|
|
2156
1553
|
}
|
|
2157
|
-
// As last resort, search in general cache
|
|
2158
1554
|
if (clickedPlace === undefined) {
|
|
2159
1555
|
const cachedPlaces = this.repository.getCachedPlaces([ref]);
|
|
2160
1556
|
if (cachedPlaces.length === 0) {
|
|
@@ -2190,8 +1586,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2190
1586
|
this.updateFiltersTo(this.currentFloor);
|
|
2191
1587
|
}
|
|
2192
1588
|
});
|
|
2193
|
-
// When the mouse leaves the state-fill layer, update the feature state of the
|
|
2194
|
-
// previously hovered feature.
|
|
2195
1589
|
this.map.on("mouseleave", "hoverable", () => {
|
|
2196
1590
|
this.hoveredId = "unselected";
|
|
2197
1591
|
this.updateFiltersTo(this.currentFloor);
|
|
@@ -2211,8 +1605,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2211
1605
|
const placeFilter = ["any", ...coloredPlacesFilters];
|
|
2212
1606
|
const condition = ["all", placeFilter, basicFilter];
|
|
2213
1607
|
this.map.setFilter("indoor-colored-places", condition);
|
|
2214
|
-
// Caller-defined base filter: mark it resolved so no later capture can
|
|
2215
|
-
// overwrite this customization with the layer's style-declared filter.
|
|
2216
1608
|
this.capturedBaseFilters.add("indoor-colored-places");
|
|
2217
1609
|
this.baseFilters["indoor-colored-places"] = placeFilter;
|
|
2218
1610
|
if (color !== undefined) {
|
|
@@ -2233,10 +1625,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2233
1625
|
this.debugLog("Place selection failed (layer may not exist)", error);
|
|
2234
1626
|
}
|
|
2235
1627
|
}
|
|
2236
|
-
/**
|
|
2237
|
-
* Same question as {@link styleHasExtrusions}, asked of the style the map is currently showing
|
|
2238
|
-
* rather than one about to be applied. Used after load, when `map.getStyle()` is available.
|
|
2239
|
-
*/
|
|
2240
1628
|
is3DStyle() {
|
|
2241
1629
|
return styleHasExtrusions(this.map.getStyle());
|
|
2242
1630
|
}
|
|
@@ -2303,8 +1691,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2303
1691
|
this.coloredPlacesRequest = undefined;
|
|
2304
1692
|
if (this.hasLayer("indoor-colored-places")) {
|
|
2305
1693
|
const condition = ["==", ["get", "ref"], "unselected"];
|
|
2306
|
-
// Caller-defined base filter: mark it resolved so no later capture can
|
|
2307
|
-
// overwrite this customization with the layer's style-declared filter.
|
|
2308
1694
|
this.capturedBaseFilters.add("indoor-colored-places");
|
|
2309
1695
|
this.baseFilters["indoor-colored-places"] = condition;
|
|
2310
1696
|
this.map.setFilter("indoor-colored-places", condition);
|
|
@@ -2488,7 +1874,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2488
1874
|
this.userLocationMarker.remove();
|
|
2489
1875
|
this.userLocationMarker = undefined;
|
|
2490
1876
|
this.markerLayoutController.scheduleRelayout();
|
|
2491
|
-
// Check if watchPosition ID is valid and stop tracking
|
|
2492
1877
|
if (this.watchPositionID) {
|
|
2493
1878
|
this.geoLocation.clearWatch(this.watchPositionID);
|
|
2494
1879
|
this.watchPositionID = undefined;
|
|
@@ -2512,8 +1897,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2512
1897
|
const placeFilter = ["any", ...coloredPlacesFilters];
|
|
2513
1898
|
const condition = ["all", placeFilter, basicFilter];
|
|
2514
1899
|
this.map.setFilter("indoor-bordered-places", condition);
|
|
2515
|
-
// Caller-defined base filter: mark it resolved so no later capture can
|
|
2516
|
-
// overwrite this customization with the layer's style-declared filter.
|
|
2517
1900
|
this.capturedBaseFilters.add("indoor-bordered-places");
|
|
2518
1901
|
this.baseFilters["indoor-bordered-places"] = placeFilter;
|
|
2519
1902
|
if (color !== undefined && width !== undefined) {
|
|
@@ -2543,8 +1926,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2543
1926
|
this.borderedPlacesRequest = undefined;
|
|
2544
1927
|
if (this.hasLayer("indoor-bordered-places")) {
|
|
2545
1928
|
const condition = ["==", ["get", "ref"], "unselected"];
|
|
2546
|
-
// Caller-defined base filter: mark it resolved so no later capture can
|
|
2547
|
-
// overwrite this customization with the layer's style-declared filter.
|
|
2548
1929
|
this.capturedBaseFilters.add("indoor-bordered-places");
|
|
2549
1930
|
this.baseFilters["indoor-bordered-places"] = condition;
|
|
2550
1931
|
this.map.setFilter("indoor-bordered-places", condition);
|
|
@@ -2554,30 +1935,26 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2554
1935
|
var _a, _b;
|
|
2555
1936
|
e.originalEvent.preventDefault();
|
|
2556
1937
|
console.warn("Contexto WebGL perdido 😢");
|
|
2557
|
-
// Intentar restaurar el contexto automáticamente
|
|
2558
1938
|
const canvas = (_a = this === null || this === void 0 ? void 0 : this.map) === null || _a === void 0 ? void 0 : _a.getCanvas();
|
|
2559
1939
|
const gl = (canvas === null || canvas === void 0 ? void 0 : canvas.getContext("webgl")) || (canvas === null || canvas === void 0 ? void 0 : canvas.getContext("webgl2"));
|
|
2560
1940
|
if (gl && gl.isContextLost()) {
|
|
2561
1941
|
canvas.addEventListener("webglcontextrestored", () => {
|
|
2562
1942
|
console.debug("Contexto WebGL restaurado, forzando re-render");
|
|
2563
|
-
this.map.triggerRepaint();
|
|
1943
|
+
this.map.triggerRepaint();
|
|
2564
1944
|
this.failedTiles.clear();
|
|
2565
1945
|
}, { once: true });
|
|
2566
1946
|
const ext = gl.getExtension("WEBGL_lose_context");
|
|
2567
|
-
(_b = ext === null || ext === void 0 ? void 0 : ext.restoreContext) === null || _b === void 0 ? void 0 : _b.call(ext);
|
|
1947
|
+
(_b = ext === null || ext === void 0 ? void 0 : ext.restoreContext) === null || _b === void 0 ? void 0 : _b.call(ext);
|
|
2568
1948
|
}
|
|
2569
1949
|
}
|
|
2570
1950
|
onWebGLContextRestored() {
|
|
2571
1951
|
console.debug("Evento webglcontextrestored recibido, haciendo map.redraw()");
|
|
2572
|
-
this.map.redraw();
|
|
1952
|
+
this.map.redraw();
|
|
2573
1953
|
this.failedTiles.clear();
|
|
2574
1954
|
}
|
|
2575
1955
|
onSourceData(e) {
|
|
2576
1956
|
var _a;
|
|
2577
|
-
// Only track tiles that actually failed to load (not aborted or never loaded)
|
|
2578
1957
|
if (e.source.type === "vector" && e.sourceId === "indoorequal" && e.tile && !e.isSourceLoaded) {
|
|
2579
|
-
// Check if tile has an error state before adding to retry queue
|
|
2580
|
-
// Access state property safely as it may not always be available
|
|
2581
1958
|
const tileState = (_a = e.tile) === null || _a === void 0 ? void 0 : _a.state;
|
|
2582
1959
|
if (tileState === "errored" || tileState === "expired") {
|
|
2583
1960
|
this.failedTiles.add(e.tile);
|
|
@@ -2585,25 +1962,10 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2585
1962
|
}
|
|
2586
1963
|
}
|
|
2587
1964
|
onSourceDataAbort(e) {
|
|
2588
|
-
// Remove aborted tiles from retry queue as they shouldn't be retried
|
|
2589
1965
|
if (e.source.type === "vector" && e.sourceId === "indoorequal" && e.tile) {
|
|
2590
1966
|
this.failedTiles.delete(e.tile);
|
|
2591
1967
|
}
|
|
2592
1968
|
}
|
|
2593
|
-
/**
|
|
2594
|
-
* True when a style object is attached to the map. During a full `setStyle` swap the
|
|
2595
|
-
* map is momentarily style-less and any `getSource`/`getFilter` call throws
|
|
2596
|
-
* ("Cannot read properties of undefined"), so call sites that only need the style to
|
|
2597
|
-
* exist should gate on this rather than on `isStyleLoaded()`.
|
|
2598
|
-
*/
|
|
2599
|
-
/**
|
|
2600
|
-
* This style's layers, or `null` when the map has no style right now.
|
|
2601
|
-
*
|
|
2602
|
-
* The one place the style is read for a floor change, so callers can pass the
|
|
2603
|
-
* result on instead of each probing again — `getStyle()` serializes every
|
|
2604
|
-
* source and layer, and `Style._updateLayer` drops the cache behind it on
|
|
2605
|
-
* every filter or layout write.
|
|
2606
|
-
*/
|
|
2607
1969
|
safeStyleLayers() {
|
|
2608
1970
|
var _a, _b, _c;
|
|
2609
1971
|
try {
|
|
@@ -2615,12 +1977,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2615
1977
|
}
|
|
2616
1978
|
hasStyle() {
|
|
2617
1979
|
var _a;
|
|
2618
|
-
// `map.getStyle()` is the PUBLIC probe: it returns the serialized style, or throws
|
|
2619
|
-
// while the map is momentarily style-less mid-swap. Reading maplibre's internal
|
|
2620
|
-
// `style` field instead (it is absent from the public typings, so it needed a double
|
|
2621
|
-
// cast) would fail closed and silently forever the moment a maplibre upgrade renames
|
|
2622
|
-
// or privatizes it — disabling both the tile-retry loop and `setStyle`'s apply pass
|
|
2623
|
-
// with no throw and no log. `safeGetFilter` already uses this try/catch shape.
|
|
2624
1980
|
try {
|
|
2625
1981
|
return ((_a = this.map) === null || _a === void 0 ? void 0 : _a.getStyle()) != null;
|
|
2626
1982
|
}
|
|
@@ -2628,12 +1984,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2628
1984
|
return false;
|
|
2629
1985
|
}
|
|
2630
1986
|
}
|
|
2631
|
-
/**
|
|
2632
|
-
* True when the map has a style object attached and fully loaded. Unlike
|
|
2633
|
-
* `map.isStyleLoaded()`, this does not emit maplibre's "There is no style
|
|
2634
|
-
* added to the map" warning when the style is momentarily absent (e.g. during
|
|
2635
|
-
* a `setStyle` swap), because it checks for the style object first.
|
|
2636
|
-
*/
|
|
2637
1987
|
hasLoadedStyle() {
|
|
2638
1988
|
if (!this.hasStyle())
|
|
2639
1989
|
return false;
|
|
@@ -2642,20 +1992,11 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2642
1992
|
subscribeToFailedTiles() {
|
|
2643
1993
|
if (this.retryTimer)
|
|
2644
1994
|
return;
|
|
2645
|
-
// Store bound functions for proper cleanup
|
|
2646
1995
|
this.boundOnSourceData = this.onSourceData.bind(this);
|
|
2647
1996
|
this.boundOnSourceDataAbort = this.onSourceDataAbort.bind(this);
|
|
2648
1997
|
this.boundOnWebGLContextLost = this.onWebGLContextLost.bind(this);
|
|
2649
1998
|
this.boundOnWebGLContextRestored = this.onWebGLContextRestored.bind(this);
|
|
2650
1999
|
this.retryTimer = setInterval(() => {
|
|
2651
|
-
// During a full style swap (`setStyle` with `diff: false`) the map can
|
|
2652
|
-
// momentarily have no style object attached. Calling `getSource` then
|
|
2653
|
-
// throws ("Cannot read properties of undefined (reading 'getSource')").
|
|
2654
|
-
// Only the style's PRESENCE is checked here, never `isStyleLoaded()`:
|
|
2655
|
-
// that is false while any source still has tiles in flight, which is
|
|
2656
|
-
// exactly when tiles fail — gating on it would skip every tick during a
|
|
2657
|
-
// bad-network burst. The queue is left untouched so the tiles queued
|
|
2658
|
-
// mid-swap are still retried on the next tick.
|
|
2659
2000
|
if (!this.hasStyle()) {
|
|
2660
2001
|
return;
|
|
2661
2002
|
}
|
|
@@ -2668,27 +2009,21 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2668
2009
|
this.failedTiles.clear();
|
|
2669
2010
|
return;
|
|
2670
2011
|
}
|
|
2671
|
-
// Process tiles and remove invalid ones
|
|
2672
2012
|
const tilesToRetry = [];
|
|
2673
2013
|
const tilesToRemove = [];
|
|
2674
2014
|
this.failedTiles.forEach((tile) => {
|
|
2675
|
-
// Check if tile is still valid before attempting reload
|
|
2676
2015
|
if (!tile || tile.state === "unloaded" || tile.state === "loading") {
|
|
2677
2016
|
tilesToRemove.push(tile);
|
|
2678
2017
|
return;
|
|
2679
2018
|
}
|
|
2680
|
-
// Only retry tiles that are in an error state
|
|
2681
2019
|
if (tile.state === "errored" || tile.state === "expired") {
|
|
2682
2020
|
tilesToRetry.push(tile);
|
|
2683
2021
|
}
|
|
2684
2022
|
else {
|
|
2685
|
-
// Tile is in a valid state, remove from retry queue
|
|
2686
2023
|
tilesToRemove.push(tile);
|
|
2687
2024
|
}
|
|
2688
2025
|
});
|
|
2689
|
-
// Remove invalid tiles from the set
|
|
2690
2026
|
tilesToRemove.forEach((tile) => this.failedTiles.delete(tile));
|
|
2691
|
-
// Attempt to reload valid failed tiles
|
|
2692
2027
|
const now = Date.now();
|
|
2693
2028
|
tilesToRetry.forEach((tile) => {
|
|
2694
2029
|
var _a;
|
|
@@ -2697,7 +2032,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2697
2032
|
nextAttemptAt: 0,
|
|
2698
2033
|
pending: false,
|
|
2699
2034
|
};
|
|
2700
|
-
// Skip tiles with a reload still in flight or still inside their backoff window.
|
|
2701
2035
|
if (retry.pending || now < retry.nextAttemptAt)
|
|
2702
2036
|
return;
|
|
2703
2037
|
const onFailure = (error) => {
|
|
@@ -2708,7 +2042,6 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2708
2042
|
this.tileRetryState.delete(tile);
|
|
2709
2043
|
return;
|
|
2710
2044
|
}
|
|
2711
|
-
// Stay in the queue and try again once the backoff has elapsed.
|
|
2712
2045
|
const backoffMs = TILE_RETRY_BASE_DELAY_MS * 2 ** (attempts - 1);
|
|
2713
2046
|
this.debugLog(`Tile reload failed (attempt ${attempts}/${MAX_TILE_RETRIES}), retrying in ${backoffMs}ms`, error);
|
|
2714
2047
|
this.tileRetryState.set(tile, {
|
|
@@ -2718,18 +2051,11 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2718
2051
|
});
|
|
2719
2052
|
};
|
|
2720
2053
|
try {
|
|
2721
|
-
// Verify tile still exists and is in a retryable state
|
|
2722
2054
|
if (tile && (tile.state === "errored" || tile.state === "expired")) {
|
|
2723
2055
|
this.tileRetryState.set(tile, Object.assign(Object.assign({}, retry), { pending: true }));
|
|
2724
|
-
// loadTile is async, so a rejection escapes this try/catch and has to be handled
|
|
2725
|
-
// on the promise itself - otherwise it surfaces as an unhandled rejection and the
|
|
2726
|
-
// tile is retried on every tick regardless of how often it has already failed.
|
|
2727
2056
|
source
|
|
2728
2057
|
.loadTile(tile)
|
|
2729
2058
|
.then(() => {
|
|
2730
|
-
// Loaded: forget the attempt history so a later failure starts from zero. The
|
|
2731
|
-
// tile leaves the queue through the tilesToRemove branch on the next tick,
|
|
2732
|
-
// once its state is no longer errored/expired.
|
|
2733
2059
|
this.tileRetryState.delete(tile);
|
|
2734
2060
|
})
|
|
2735
2061
|
.catch(onFailure);
|
|
@@ -2742,9 +2068,7 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2742
2068
|
}, 1000);
|
|
2743
2069
|
this.map.on("sourcedata", this.boundOnSourceData);
|
|
2744
2070
|
this.map.on("sourcedataabort", this.boundOnSourceDataAbort);
|
|
2745
|
-
// Escucha el evento de contexto perdido
|
|
2746
2071
|
this.map.on("webglcontextlost", this.boundOnWebGLContextLost);
|
|
2747
|
-
// Adicional: escucha evento restauración
|
|
2748
2072
|
this.map.on("webglcontextrestored", this.boundOnWebGLContextRestored);
|
|
2749
2073
|
}
|
|
2750
2074
|
unsubscribeFromFailedTiles() {
|
|
@@ -2771,4 +2095,3 @@ export class InternalMapVXMap extends Loggeable {
|
|
|
2771
2095
|
this.failedTiles.clear();
|
|
2772
2096
|
}
|
|
2773
2097
|
}
|
|
2774
|
-
//# sourceMappingURL=map.js.map
|