@mapvx/web-js 1.2.1 → 1.3.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cjs/controllers/routeController.js +19 -19
- package/dist/cjs/controllers/routeController.js.map +1 -1
- package/dist/cjs/domain/models/categories.js +23 -10
- package/dist/cjs/domain/models/categories.js.map +1 -1
- package/dist/cjs/domain/models/mapConfig.js +10 -1
- package/dist/cjs/domain/models/mapConfig.js.map +1 -1
- package/dist/cjs/domain/models/marker.js +86 -80
- package/dist/cjs/domain/models/marker.js.map +1 -1
- package/dist/cjs/domain/models/routeConfiguration.js +3 -1
- package/dist/cjs/domain/models/routeConfiguration.js.map +1 -1
- package/dist/cjs/index.js +17 -12
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/logger/logger.js +13 -8
- package/dist/cjs/logger/logger.js.map +1 -1
- package/dist/cjs/logger/rollbar.js +11 -6
- package/dist/cjs/logger/rollbar.js.map +1 -1
- package/dist/cjs/map/map.js +549 -28
- package/dist/cjs/map/map.js.map +1 -1
- package/dist/cjs/map/mapInteractionOptions.js +56 -0
- package/dist/cjs/map/mapInteractionOptions.js.map +1 -0
- package/dist/cjs/repository/repository.js +25 -26
- package/dist/cjs/repository/repository.js.map +1 -1
- package/dist/cjs/repository/requester.js +71 -91
- package/dist/cjs/repository/requester.js.map +1 -1
- package/dist/cjs/sdk.js +18 -0
- package/dist/cjs/sdk.js.map +1 -1
- package/dist/cjs/utils/3d.js +12 -0
- package/dist/cjs/utils/3d.js.map +1 -0
- package/dist/cjs/utils/semaphore.js +143 -0
- package/dist/cjs/utils/semaphore.js.map +1 -0
- package/dist/es/controllers/routeController.d.ts.map +1 -1
- package/dist/es/controllers/routeController.js +19 -19
- package/dist/es/controllers/routeController.js.map +1 -1
- package/dist/es/domain/models/categories.d.ts +34 -10
- package/dist/es/domain/models/categories.d.ts.map +1 -1
- package/dist/es/domain/models/categories.js +21 -9
- package/dist/es/domain/models/categories.js.map +1 -1
- package/dist/es/domain/models/configuration.d.ts +8 -0
- package/dist/es/domain/models/configuration.d.ts.map +1 -1
- package/dist/es/domain/models/mapConfig.d.ts +129 -3
- package/dist/es/domain/models/mapConfig.d.ts.map +1 -1
- package/dist/es/domain/models/mapConfig.js +9 -0
- package/dist/es/domain/models/mapConfig.js.map +1 -1
- package/dist/es/domain/models/marker.d.ts +8 -0
- package/dist/es/domain/models/marker.d.ts.map +1 -1
- package/dist/es/domain/models/marker.js +86 -80
- package/dist/es/domain/models/marker.js.map +1 -1
- package/dist/es/domain/models/routeConfiguration.d.ts +47 -0
- package/dist/es/domain/models/routeConfiguration.d.ts.map +1 -1
- package/dist/es/domain/models/routeConfiguration.js +3 -1
- package/dist/es/domain/models/routeConfiguration.js.map +1 -1
- package/dist/es/index.d.ts +13 -12
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +8 -6
- package/dist/es/index.js.map +1 -1
- package/dist/es/logger/logger.d.ts.map +1 -1
- package/dist/es/logger/logger.js +13 -8
- package/dist/es/logger/logger.js.map +1 -1
- package/dist/es/logger/rollbar.d.ts.map +1 -1
- package/dist/es/logger/rollbar.js +11 -6
- package/dist/es/logger/rollbar.js.map +1 -1
- package/dist/es/map/map.d.ts +106 -1
- package/dist/es/map/map.d.ts.map +1 -1
- package/dist/es/map/map.js +551 -30
- package/dist/es/map/map.js.map +1 -1
- package/dist/es/map/mapInteractionOptions.d.ts +37 -0
- package/dist/es/map/mapInteractionOptions.d.ts.map +1 -0
- package/dist/es/map/mapInteractionOptions.js +51 -0
- package/dist/es/map/mapInteractionOptions.js.map +1 -0
- package/dist/es/repository/repository.d.ts +0 -1
- package/dist/es/repository/repository.d.ts.map +1 -1
- package/dist/es/repository/repository.js +25 -26
- package/dist/es/repository/repository.js.map +1 -1
- package/dist/es/repository/requester.d.ts +12 -2
- package/dist/es/repository/requester.d.ts.map +1 -1
- package/dist/es/repository/requester.js +71 -91
- package/dist/es/repository/requester.js.map +1 -1
- package/dist/es/sdk.d.ts +2 -0
- package/dist/es/sdk.d.ts.map +1 -1
- package/dist/es/sdk.js +18 -0
- package/dist/es/sdk.js.map +1 -1
- package/dist/es/utils/3d.d.ts +2 -0
- package/dist/es/utils/3d.d.ts.map +1 -0
- package/dist/es/utils/3d.js +8 -0
- package/dist/es/utils/3d.js.map +1 -0
- package/dist/es/utils/semaphore.d.ts +70 -0
- package/dist/es/utils/semaphore.d.ts.map +1 -0
- package/dist/es/utils/semaphore.js +139 -0
- package/dist/es/utils/semaphore.js.map +1 -0
- package/dist/umd/index.js +154429 -2148
- package/dist/umd/index.js.map +1 -1
- package/dist/umd/styles.css +32 -14
- package/dist/umd/styles.css.map +1 -1
- package/package.json +19 -5
package/dist/cjs/map/map.js
CHANGED
|
@@ -24,7 +24,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.InternalMapVXMap = void 0;
|
|
27
|
+
const geo_layers_1 = require("@deck.gl/geo-layers");
|
|
28
|
+
const layers_1 = require("@deck.gl/layers");
|
|
27
29
|
const maplibre_gl_1 = __importStar(require("maplibre-gl"));
|
|
30
|
+
const THREE = __importStar(require("three"));
|
|
31
|
+
const GLTFLoader_js_1 = require("three/examples/jsm/loaders/GLTFLoader.js");
|
|
32
|
+
const semaphore_1 = require("../utils/semaphore");
|
|
28
33
|
/** Shared GeoJSON source holding every circle drawn through the circle API. */
|
|
29
34
|
const CIRCLE_SOURCE_ID = "mapvx-circles";
|
|
30
35
|
/** Fill layer rendering the translucent interior of the circles. */
|
|
@@ -69,21 +74,36 @@ function deepClone(obj) {
|
|
|
69
74
|
/**
|
|
70
75
|
* Register a custom protocol for cached tiles that routes requests through the main thread.
|
|
71
76
|
* This allows the service worker to intercept and cache tile requests.
|
|
77
|
+
*
|
|
78
|
+
* Wraps fetches in a {@link Semaphore} so tile CDN / WAFs are not hit with
|
|
79
|
+
* unbounded parallel requests (same host as the service worker cache). The
|
|
80
|
+
* semaphore is created once with the limit from the first map's config; later
|
|
81
|
+
* calls are no-ops because the protocol can only be registered once globally
|
|
82
|
+
* on MapLibre.
|
|
83
|
+
*
|
|
84
|
+
* @param maxConcurrentFetches - Maximum number of in-flight tile fetches.
|
|
72
85
|
*/
|
|
73
|
-
function registerCachedTileProtocol() {
|
|
86
|
+
function registerCachedTileProtocol(maxConcurrentFetches) {
|
|
74
87
|
if (cachedTileProtocolRegistered)
|
|
75
88
|
return;
|
|
89
|
+
const semaphore = new semaphore_1.Semaphore(maxConcurrentFetches);
|
|
76
90
|
maplibre_gl_1.default.addProtocol("cached-tile", (params, abortController) => {
|
|
77
|
-
// Convert cached-tile:// URL back to https://
|
|
78
91
|
const url = params.url.replace("cached-tile://", "https://");
|
|
79
|
-
|
|
92
|
+
// Pass the abort signal to acquire() so a request cancelled while still
|
|
93
|
+
// queued (e.g. during rapid zoom) drops out of the FIFO queue instead of
|
|
94
|
+
// waiting for a slot just to bail. release() runs only inside this chain,
|
|
95
|
+
// i.e. only after a slot was actually granted.
|
|
96
|
+
return semaphore.acquire(abortController.signal).then(() => fetch(url, { signal: abortController.signal })
|
|
80
97
|
.then((response) => {
|
|
81
98
|
if (!response.ok) {
|
|
82
99
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
83
100
|
}
|
|
84
101
|
return response.arrayBuffer();
|
|
85
102
|
})
|
|
86
|
-
.then((data) => ({ data }))
|
|
103
|
+
.then((data) => ({ data }))
|
|
104
|
+
.finally(() => {
|
|
105
|
+
semaphore.release();
|
|
106
|
+
}));
|
|
87
107
|
});
|
|
88
108
|
cachedTileProtocolRegistered = true;
|
|
89
109
|
}
|
|
@@ -137,19 +157,21 @@ function convertPaddingToPixels(padding, containerWidth, containerHeight) {
|
|
|
137
157
|
right: parsePaddingValue(padding.right, containerWidth),
|
|
138
158
|
};
|
|
139
159
|
}
|
|
160
|
+
const mapbox_1 = require("@deck.gl/mapbox");
|
|
140
161
|
const icons_1 = require("../assets/icons");
|
|
141
162
|
const routeController_1 = require("../controllers/routeController");
|
|
142
163
|
const _rtl_1 = require("../domain/models/_rtl");
|
|
143
164
|
const animation_1 = require("../domain/models/animation");
|
|
165
|
+
const circle_1 = require("../domain/models/circle");
|
|
144
166
|
const loggeable_1 = require("../domain/models/loggeable");
|
|
145
167
|
const mapConfig_1 = require("../domain/models/mapConfig");
|
|
146
|
-
const circle_1 = require("../domain/models/circle");
|
|
147
168
|
const marker_1 = require("../domain/models/marker");
|
|
148
169
|
const route_1 = require("../domain/models/route");
|
|
149
170
|
const routeConfiguration_1 = require("../domain/models/routeConfiguration");
|
|
150
171
|
const repository_1 = require("../repository/repository");
|
|
151
|
-
const utils_1 = require("../utils/utils");
|
|
152
172
|
const route_utils_1 = require("../utils/route-utils");
|
|
173
|
+
const utils_1 = require("../utils/utils");
|
|
174
|
+
const mapInteractionOptions_1 = require("./mapInteractionOptions");
|
|
153
175
|
/**
|
|
154
176
|
* Class to interact with the map.
|
|
155
177
|
* @category Map
|
|
@@ -165,7 +187,7 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
165
187
|
* @returns A new instance of MapVXMap.
|
|
166
188
|
*/
|
|
167
189
|
constructor(mapConfig, container, token) {
|
|
168
|
-
var _a, _b;
|
|
190
|
+
var _a, _b, _c;
|
|
169
191
|
super();
|
|
170
192
|
this.potentialParentPlaces = [];
|
|
171
193
|
this.innerFloors = [];
|
|
@@ -178,6 +200,22 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
178
200
|
this.hoveredId = "unselected";
|
|
179
201
|
this.failedTiles = new Set();
|
|
180
202
|
this.geoLocation = navigator.geolocation;
|
|
203
|
+
// 3d related variables
|
|
204
|
+
this.mode = "2D";
|
|
205
|
+
this.deckOverlay = undefined;
|
|
206
|
+
this.escalatorScene = undefined;
|
|
207
|
+
this.escalatorModelTemplate = undefined;
|
|
208
|
+
this.escalatorCenter = undefined;
|
|
209
|
+
this.escalatorCache = {};
|
|
210
|
+
this.ESCALATOR_MODEL_URL = "https://mapvx-glb-assets.s3.us-east-1.amazonaws.com/shared/escalator.glb";
|
|
211
|
+
/**
|
|
212
|
+
* Number of lights to use for the escalators
|
|
213
|
+
*
|
|
214
|
+
*/
|
|
215
|
+
this.ESCALATOR_LIGHTS = 3;
|
|
216
|
+
this.SPRITE_URL = "https://lazarillo.app/internal/maps/vector-style/cenco-cl-pe-co-ar-3D/sprites_cencosud";
|
|
217
|
+
this.spriteIconMapping = {};
|
|
218
|
+
this.spriteAtlasImage = new Image();
|
|
181
219
|
if (_rtl_1.rtlLanguages.includes((_a = mapConfig.lang) !== null && _a !== void 0 ? _a : "")) {
|
|
182
220
|
this.setRTLSupport();
|
|
183
221
|
}
|
|
@@ -189,8 +227,16 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
189
227
|
this.watchPositionID = undefined;
|
|
190
228
|
this.onFloorChange = mapConfig.onFloorChange;
|
|
191
229
|
this.onParentPlaceChange = mapConfig.onParentPlaceChange;
|
|
192
|
-
|
|
193
|
-
this.
|
|
230
|
+
this.mode = (_c = mapConfig.mode) !== null && _c !== void 0 ? _c : "2D";
|
|
231
|
+
this.initialCenter = mapConfig.center;
|
|
232
|
+
this.tileCacheConfig = (() => {
|
|
233
|
+
const merged = Object.assign(Object.assign({}, mapConfig_1.DEFAULT_TILE_CACHE_CONFIG), mapConfig.tileCache);
|
|
234
|
+
merged.maxTiles = Math.min(merged.maxTiles, mapConfig_1.MAPLIBRE_MAX_TILE_CACHE_HARD_CAP);
|
|
235
|
+
return merged;
|
|
236
|
+
})();
|
|
237
|
+
if (this.mode === "3D") {
|
|
238
|
+
this.loadSpriteAtlas().catch(console.error);
|
|
239
|
+
}
|
|
194
240
|
if (mapConfig.parentPlaceId != null) {
|
|
195
241
|
this.initialPlaceDetailSetUp(mapConfig.parentPlaceId, mapConfig.authToken);
|
|
196
242
|
}
|
|
@@ -287,28 +333,17 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
287
333
|
.catch(console.error);
|
|
288
334
|
}
|
|
289
335
|
onMapStyleLoaded(mapConfig, container, style) {
|
|
290
|
-
var _a, _b, _c;
|
|
336
|
+
var _a, _b, _c, _d, _e;
|
|
291
337
|
// Determine if service worker caching should be enabled
|
|
292
338
|
const useServiceWorkerCaching = this.tileCacheConfig.enabled && this.tileCacheConfig.persistToServiceWorker;
|
|
293
|
-
// Register cached-tile protocol only if service worker caching is enabled
|
|
294
339
|
if (useServiceWorkerCaching) {
|
|
295
|
-
registerCachedTileProtocol();
|
|
340
|
+
registerCachedTileProtocol(this.tileCacheConfig.maxConcurrentTileFetches);
|
|
296
341
|
}
|
|
297
342
|
// Transform tile URLs only if service worker caching is enabled
|
|
298
343
|
const finalStyle = useServiceWorkerCaching ? this.transformStyleForCaching(style) : style;
|
|
299
|
-
const mapOptions = {
|
|
300
|
-
container,
|
|
301
|
-
style: finalStyle,
|
|
302
|
-
center: mapConfig.center,
|
|
303
|
-
zoom: mapConfig.zoom,
|
|
304
|
-
pitch: (_a = mapConfig.pitch) !== null && _a !== void 0 ? _a : 0,
|
|
305
|
-
attributionControl: false,
|
|
306
|
-
maplibreLogo: false,
|
|
307
|
-
bearingSnap: (_b = mapConfig.bearingSnap) !== null && _b !== void 0 ? _b : 0,
|
|
308
|
-
cancelPendingTileRequestsWhileZooming: false,
|
|
344
|
+
const mapOptions = Object.assign({ container, style: finalStyle, center: mapConfig.center, zoom: mapConfig.zoom, pitch: (_a = mapConfig.pitch) !== null && _a !== void 0 ? _a : 0, attributionControl: false, maplibreLogo: false, bearingSnap: (_b = mapConfig.bearingSnap) !== null && _b !== void 0 ? _b : 0, cancelPendingTileRequestsWhileZooming: true,
|
|
309
345
|
// Use configured maxTiles for MapLibre's memory cache
|
|
310
|
-
maxTileCacheSize: this.tileCacheConfig.maxTiles,
|
|
311
|
-
};
|
|
346
|
+
maxTileCacheSize: this.tileCacheConfig.maxTiles }, (0, mapInteractionOptions_1.buildInteractionOptions)(mapConfig));
|
|
312
347
|
if (mapConfig.maxZoom)
|
|
313
348
|
mapOptions.maxZoom = mapConfig.maxZoom;
|
|
314
349
|
if (mapConfig.minZoom)
|
|
@@ -318,12 +353,41 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
318
353
|
mapOptions.maxBounds = new maplibre_gl_1.LngLatBounds([boundingBox[0].lng, boundingBox[0].lat], [boundingBox[1].lng, boundingBox[1].lat]);
|
|
319
354
|
}
|
|
320
355
|
this.map = new maplibre_gl_1.Map(mapOptions);
|
|
356
|
+
// When rotation is disabled we still want pinch-to-zoom to work, so the
|
|
357
|
+
// two-finger rotation is turned off here instead of via the constructor.
|
|
358
|
+
if ((0, mapInteractionOptions_1.shouldDisableTouchRotation)(mapConfig)) {
|
|
359
|
+
(_d = (_c = this.map.touchZoomRotate) === null || _c === void 0 ? void 0 : _c.disableRotation) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
360
|
+
}
|
|
321
361
|
this.map.addControl(new maplibre_gl_1.NavigationControl({
|
|
322
362
|
showCompass: mapConfig.showCompass !== undefined ? mapConfig.showCompass : true,
|
|
323
363
|
showZoom: mapConfig.showZoom !== undefined ? mapConfig.showZoom : true,
|
|
324
|
-
}), (
|
|
364
|
+
}), (_e = mapConfig.navigationPosition) !== null && _e !== void 0 ? _e : "top-right");
|
|
325
365
|
this.map.on("load", () => {
|
|
326
366
|
var _a;
|
|
367
|
+
if (this.mode === "3D") {
|
|
368
|
+
this.deckOverlay = new mapbox_1.MapboxOverlay({ layers: [] });
|
|
369
|
+
this.map.addControl(this.deckOverlay);
|
|
370
|
+
this.hideIndoorSymbolLayers();
|
|
371
|
+
// Hide MapLibre icon layers — replaced by deck.gl IconLayer
|
|
372
|
+
this.map.setLayoutProperty("indoor-poi-logo", "visibility", "none");
|
|
373
|
+
const style = this.map.getStyle();
|
|
374
|
+
for (const layer of style.layers) {
|
|
375
|
+
if (layer.id.startsWith("indoor-logo-tiendas-ancla")) {
|
|
376
|
+
this.map.setLayoutProperty(layer.id, "visibility", "none");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Add 3D escalator layer and hide 2D transportation line
|
|
380
|
+
this.map.addLayer(this.createEscalatorLayer());
|
|
381
|
+
this.map.setPaintProperty("indoor-transportation", "line-opacity", 0);
|
|
382
|
+
// Capture escalator positions when new tiles arrive (stops once cached)
|
|
383
|
+
this.map.on("sourcedata", (e) => {
|
|
384
|
+
if (e.sourceId === "indoorequal" &&
|
|
385
|
+
this.currentFloor &&
|
|
386
|
+
!this.escalatorCache[this.currentFloor]) {
|
|
387
|
+
this.placeEscalators();
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
}
|
|
327
391
|
this.whenStyleUpdates(style);
|
|
328
392
|
if (mapConfig.lang)
|
|
329
393
|
this.setLayersForLanguage(mapConfig.lang);
|
|
@@ -346,7 +410,6 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
346
410
|
(_a = mapConfig.onRotate) === null || _a === void 0 ? void 0 : _a.call(mapConfig, this.map.getBearing());
|
|
347
411
|
});
|
|
348
412
|
this.defaultClickListener();
|
|
349
|
-
return this.map;
|
|
350
413
|
}
|
|
351
414
|
setBaseFilters(style) {
|
|
352
415
|
if (!style)
|
|
@@ -475,6 +538,386 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
475
538
|
// Tile cache clear may fail if cache doesn't exist
|
|
476
539
|
}
|
|
477
540
|
}
|
|
541
|
+
// Start 3D related methods ------------------------------------------------------------
|
|
542
|
+
hideIndoorSymbolLayers() {
|
|
543
|
+
var _a, _b;
|
|
544
|
+
const style = this.map.getStyle();
|
|
545
|
+
for (const layer of style.layers) {
|
|
546
|
+
if (layer.type === "symbol" && layer.id.startsWith("indoor-")) {
|
|
547
|
+
const hasText = !!((_a = layer.layout) === null || _a === void 0 ? void 0 : _a["text-field"]);
|
|
548
|
+
const hasIcon = !!((_b = layer.layout) === null || _b === void 0 ? void 0 : _b["icon-image"]);
|
|
549
|
+
// Hide text-only layers (replaced by deck.gl)
|
|
550
|
+
if (hasText && !hasIcon) {
|
|
551
|
+
this.map.setLayoutProperty(layer.id, "visibility", "none");
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
createEscalatorLayer() {
|
|
557
|
+
const refMercator = maplibre_gl_1.MercatorCoordinate.fromLngLat(this.initialCenter, 0);
|
|
558
|
+
const meterScale = refMercator.meterInMercatorCoordinateUnits();
|
|
559
|
+
const modelTransform = new THREE.Matrix4()
|
|
560
|
+
.makeTranslation(refMercator.x, refMercator.y, refMercator.z)
|
|
561
|
+
.scale(new THREE.Vector3(meterScale, -meterScale, meterScale))
|
|
562
|
+
.multiply(new THREE.Matrix4().makeRotationX(Math.PI / 2));
|
|
563
|
+
this.escalatorScene = new THREE.Scene();
|
|
564
|
+
const dirLight = new THREE.DirectionalLight(0xffffff, 2.0);
|
|
565
|
+
dirLight.position.set(50, 100, 80);
|
|
566
|
+
this.escalatorScene.add(dirLight);
|
|
567
|
+
const dirLight2 = new THREE.DirectionalLight(0xffffff, 1.5);
|
|
568
|
+
dirLight2.position.set(-50, 80, -60);
|
|
569
|
+
this.escalatorScene.add(dirLight2);
|
|
570
|
+
this.escalatorScene.add(new THREE.AmbientLight(0xffffff, 1.5));
|
|
571
|
+
new GLTFLoader_js_1.GLTFLoader().load(this.ESCALATOR_MODEL_URL, (gltf) => {
|
|
572
|
+
this.escalatorModelTemplate = gltf.scene;
|
|
573
|
+
const box = new THREE.Box3().setFromObject(this.escalatorModelTemplate);
|
|
574
|
+
this.escalatorCenter = box.getCenter(new THREE.Vector3());
|
|
575
|
+
this.escalatorCenter.y = box.min.y; // align bottom to ground
|
|
576
|
+
this.placeEscalators();
|
|
577
|
+
});
|
|
578
|
+
let renderer = undefined;
|
|
579
|
+
let camera = undefined;
|
|
580
|
+
const tmpMatrix = new THREE.Matrix4();
|
|
581
|
+
return {
|
|
582
|
+
id: "3d-escalators",
|
|
583
|
+
type: "custom",
|
|
584
|
+
renderingMode: "3d",
|
|
585
|
+
onAdd(_map, gl) {
|
|
586
|
+
camera = new THREE.Camera();
|
|
587
|
+
renderer = new THREE.WebGLRenderer({
|
|
588
|
+
canvas: _map.getCanvas(),
|
|
589
|
+
context: gl,
|
|
590
|
+
antialias: true,
|
|
591
|
+
});
|
|
592
|
+
renderer.autoClear = false;
|
|
593
|
+
},
|
|
594
|
+
render: (gl, args) => {
|
|
595
|
+
var _a, _b;
|
|
596
|
+
if (!camera ||
|
|
597
|
+
!renderer ||
|
|
598
|
+
!this.escalatorModelTemplate ||
|
|
599
|
+
!this.escalatorScene ||
|
|
600
|
+
this.escalatorScene.children.length <= this.ESCALATOR_LIGHTS)
|
|
601
|
+
return;
|
|
602
|
+
const matrixData = (_b = (_a = args === null || args === void 0 ? void 0 : args.defaultProjectionData) === null || _a === void 0 ? void 0 : _a.mainMatrix) !== null && _b !== void 0 ? _b : args;
|
|
603
|
+
tmpMatrix.fromArray(matrixData).multiply(modelTransform);
|
|
604
|
+
camera.projectionMatrix.copy(tmpMatrix);
|
|
605
|
+
renderer.resetState();
|
|
606
|
+
renderer.render(this.escalatorScene, camera);
|
|
607
|
+
},
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
placeEscalators() {
|
|
611
|
+
if (!this.escalatorModelTemplate ||
|
|
612
|
+
!this.escalatorScene ||
|
|
613
|
+
!this.currentFloor ||
|
|
614
|
+
!this.escalatorCenter)
|
|
615
|
+
return;
|
|
616
|
+
// Try to capture positions if not cached yet
|
|
617
|
+
this.captureEscalatorPositions();
|
|
618
|
+
const positions = this.escalatorCache[this.currentFloor];
|
|
619
|
+
if (!positions)
|
|
620
|
+
return;
|
|
621
|
+
// Clear scene models (keep lights)
|
|
622
|
+
while (this.escalatorScene.children.length > this.ESCALATOR_LIGHTS) {
|
|
623
|
+
const lastChild = this.escalatorScene.children.at(-1);
|
|
624
|
+
if (lastChild) {
|
|
625
|
+
this.escalatorScene.remove(lastChild);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
const refMercator = maplibre_gl_1.MercatorCoordinate.fromLngLat(this.initialCenter, 0);
|
|
629
|
+
const meterScale = refMercator.meterInMercatorCoordinateUnits();
|
|
630
|
+
for (const pos of positions) {
|
|
631
|
+
const target = maplibre_gl_1.default.MercatorCoordinate.fromLngLat([pos.lng, pos.lat], 0);
|
|
632
|
+
const sx = (target.x - refMercator.x) / meterScale;
|
|
633
|
+
const sz = (target.y - refMercator.y) / meterScale;
|
|
634
|
+
const pivot = new THREE.Group();
|
|
635
|
+
pivot.position.set(sx, 0, sz);
|
|
636
|
+
pivot.rotation.y = Math.PI / 2 - pos.bearing;
|
|
637
|
+
pivot.scale.set(0.3, 0.3, 0.3);
|
|
638
|
+
const model = this.escalatorModelTemplate.clone();
|
|
639
|
+
model.position.set(-this.escalatorCenter.x, -this.escalatorCenter.y - 3, -this.escalatorCenter.z);
|
|
640
|
+
pivot.add(model);
|
|
641
|
+
this.escalatorScene.add(pivot);
|
|
642
|
+
}
|
|
643
|
+
this.map.triggerRepaint();
|
|
644
|
+
}
|
|
645
|
+
captureEscalatorPositions() {
|
|
646
|
+
if (this.currentFloor && this.escalatorCache[this.currentFloor])
|
|
647
|
+
return;
|
|
648
|
+
// queryRenderedFeatures uses exact rendered coordinates (not tile-approximated)
|
|
649
|
+
const features = this.map
|
|
650
|
+
.queryRenderedFeatures(undefined, {
|
|
651
|
+
layers: ["indoor-transportation"],
|
|
652
|
+
})
|
|
653
|
+
.filter((f) => { var _a; return ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.floor_key) === this.currentFloor; });
|
|
654
|
+
if (!features.length)
|
|
655
|
+
return;
|
|
656
|
+
// Collect all midpoints first
|
|
657
|
+
const allMids = [];
|
|
658
|
+
for (const f of features) {
|
|
659
|
+
const coords = f.geometry.coordinates;
|
|
660
|
+
if (!coords || coords.length < 2)
|
|
661
|
+
continue;
|
|
662
|
+
const start = coords[0];
|
|
663
|
+
const end = coords[coords.length - 1];
|
|
664
|
+
const midLng = (start[0] + end[0]) / 2;
|
|
665
|
+
const midLat = (start[1] + end[1]) / 2;
|
|
666
|
+
const bearing = Math.atan2(end[0] - start[0], end[1] - start[1]);
|
|
667
|
+
allMids.push({ lng: midLng, lat: midLat, bearing });
|
|
668
|
+
}
|
|
669
|
+
// Merge points within ~15m of each other into one
|
|
670
|
+
const MERGE_DEG = 0.00015; // ~15m
|
|
671
|
+
const positions = [];
|
|
672
|
+
const used = new Set();
|
|
673
|
+
for (let i = 0; i < allMids.length; i++) {
|
|
674
|
+
if (used.has(i))
|
|
675
|
+
continue;
|
|
676
|
+
used.add(i);
|
|
677
|
+
const group = [allMids[i]];
|
|
678
|
+
for (let j = i + 1; j < allMids.length; j++) {
|
|
679
|
+
if (used.has(j))
|
|
680
|
+
continue;
|
|
681
|
+
const dLng = allMids[i].lng - allMids[j].lng;
|
|
682
|
+
const dLat = allMids[i].lat - allMids[j].lat;
|
|
683
|
+
if (Math.abs(dLng) < MERGE_DEG && Math.abs(dLat) < MERGE_DEG) {
|
|
684
|
+
used.add(j);
|
|
685
|
+
group.push(allMids[j]);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
// Use average position and first bearing
|
|
689
|
+
const avgLng = group.reduce((s, p) => s + p.lng, 0) / group.length;
|
|
690
|
+
const avgLat = group.reduce((s, p) => s + p.lat, 0) / group.length;
|
|
691
|
+
positions.push({ lng: avgLng, lat: avgLat, bearing: group[0].bearing });
|
|
692
|
+
}
|
|
693
|
+
if (positions.length && this.currentFloor) {
|
|
694
|
+
this.escalatorCache[this.currentFloor] = positions;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
async loadSpriteAtlas() {
|
|
698
|
+
const [json, img] = await Promise.all([
|
|
699
|
+
fetch(`${this.SPRITE_URL}.json`).then((r) => r.json()),
|
|
700
|
+
new Promise((resolve, reject) => {
|
|
701
|
+
const image = new Image();
|
|
702
|
+
image.crossOrigin = "anonymous";
|
|
703
|
+
image.onload = () => resolve(image);
|
|
704
|
+
image.onerror = reject;
|
|
705
|
+
image.src = `${this.SPRITE_URL}.png`;
|
|
706
|
+
}),
|
|
707
|
+
]);
|
|
708
|
+
this.spriteIconMapping = json;
|
|
709
|
+
this.spriteAtlasImage = img;
|
|
710
|
+
}
|
|
711
|
+
makeMVTLayer(floorKey) {
|
|
712
|
+
return new geo_layers_1.MVTLayer({
|
|
713
|
+
id: "indoor-lines-elevated",
|
|
714
|
+
data: "https://tiles.mapvx.com/",
|
|
715
|
+
binary: false,
|
|
716
|
+
renderSubLayers: (props) => {
|
|
717
|
+
var _a;
|
|
718
|
+
const roomData = (props.data || []);
|
|
719
|
+
const roomFeatures = roomData.filter((f) => {
|
|
720
|
+
var _a, _b, _c;
|
|
721
|
+
return ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.class) === "room" &&
|
|
722
|
+
((_b = f.properties) === null || _b === void 0 ? void 0 : _b.subclass) !== "empty" &&
|
|
723
|
+
((_c = f.properties) === null || _c === void 0 ? void 0 : _c.floor_key) === floorKey;
|
|
724
|
+
});
|
|
725
|
+
if (!roomFeatures.length)
|
|
726
|
+
return null;
|
|
727
|
+
const paths = [];
|
|
728
|
+
for (const f of roomFeatures) {
|
|
729
|
+
const z = ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.height) ? Number(f.properties.height) : 5;
|
|
730
|
+
const geom = f.geometry;
|
|
731
|
+
const polygons = geom.type === "Polygon"
|
|
732
|
+
? [geom.coordinates]
|
|
733
|
+
: geom.type === "MultiPolygon"
|
|
734
|
+
? geom.coordinates
|
|
735
|
+
: [];
|
|
736
|
+
for (const rings of polygons) {
|
|
737
|
+
for (const ring of rings) {
|
|
738
|
+
paths.push({ path: ring.map(([lon, lat]) => [lon, lat, z]) });
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return new layers_1.PathLayer(Object.assign(Object.assign({}, props), { id: `${props.id}-paths`, data: paths, getPath: (d) => d.path, getColor: [203, 203, 203], getWidth: 1.5, widthUnits: "pixels", pickable: false }));
|
|
743
|
+
},
|
|
744
|
+
updateTriggers: {
|
|
745
|
+
renderSubLayers: [floorKey],
|
|
746
|
+
},
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
makeLabelLayer(floorKey, useSdf = true) {
|
|
750
|
+
return new geo_layers_1.MVTLayer({
|
|
751
|
+
id: "indoor-labels",
|
|
752
|
+
data: "https://tiles.mapvx.com/",
|
|
753
|
+
binary: false,
|
|
754
|
+
minZoom: 19.5,
|
|
755
|
+
maxZoom: 24,
|
|
756
|
+
renderSubLayers: (props) => {
|
|
757
|
+
// Use area_name and poi Point features — unique per tile, no duplicates
|
|
758
|
+
// If logo-{name} image exists in sprite, icon has priority over text label
|
|
759
|
+
const labelData = (props.data || []);
|
|
760
|
+
const labelFeatures = labelData.filter((f) => {
|
|
761
|
+
var _a, _b, _c, _d, _e, _f;
|
|
762
|
+
if (((_a = f.properties) === null || _a === void 0 ? void 0 : _a.layerName) !== "area_name" && ((_b = f.properties) === null || _b === void 0 ? void 0 : _b.layerName) !== "poi")
|
|
763
|
+
return false;
|
|
764
|
+
if (((_c = f.geometry) === null || _c === void 0 ? void 0 : _c.type) !== "Point")
|
|
765
|
+
return false;
|
|
766
|
+
const name = ((_d = f.properties) === null || _d === void 0 ? void 0 : _d["name:latin"]) || ((_e = f.properties) === null || _e === void 0 ? void 0 : _e.name);
|
|
767
|
+
if (!name)
|
|
768
|
+
return false;
|
|
769
|
+
if (((_f = f.properties) === null || _f === void 0 ? void 0 : _f.floor_key) && f.properties.floor_key !== floorKey)
|
|
770
|
+
return false;
|
|
771
|
+
if (this.map.hasImage("logo-" + name))
|
|
772
|
+
return false; // icon has priority
|
|
773
|
+
return true;
|
|
774
|
+
});
|
|
775
|
+
if (!labelFeatures.length)
|
|
776
|
+
return null;
|
|
777
|
+
const textData = labelFeatures.map((f) => {
|
|
778
|
+
var _a, _b, _c;
|
|
779
|
+
return ({
|
|
780
|
+
position: [
|
|
781
|
+
...f.geometry.coordinates.slice(0, 2),
|
|
782
|
+
((_a = f.properties) === null || _a === void 0 ? void 0 : _a.height) ? Number(f.properties.height) : 5,
|
|
783
|
+
],
|
|
784
|
+
text: ((_b = f.properties) === null || _b === void 0 ? void 0 : _b["name:latin"]) || ((_c = f.properties) === null || _c === void 0 ? void 0 : _c.name) || "",
|
|
785
|
+
});
|
|
786
|
+
});
|
|
787
|
+
return new layers_1.TextLayer(Object.assign(Object.assign({}, props), { id: `${props.id}-labels`, data: textData, getPosition: (d) => d.position, getText: (d) => d.text, getSize: 16, getColor: [145, 150, 155, 255], outlineColor: useSdf ? [255, 255, 255, 255] : [0, 0, 0, 0], outlineWidth: useSdf ? 4 : 0, fontSettings: { sdf: useSdf }, fontFamily: "Open Sans, sans-serif", fontWeight: 600, billboard: true, pickable: false, characterSet: "auto", wordBreak: "break-word", maxWidth: 150 }));
|
|
788
|
+
},
|
|
789
|
+
updateTriggers: {
|
|
790
|
+
renderSubLayers: [floorKey],
|
|
791
|
+
},
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
makePoiIconLayer(floorKey) {
|
|
795
|
+
if (!this.spriteIconMapping || !this.spriteAtlasImage)
|
|
796
|
+
return null;
|
|
797
|
+
return new geo_layers_1.MVTLayer({
|
|
798
|
+
id: "indoor-poi-icons",
|
|
799
|
+
data: "https://tiles.mapvx.com/",
|
|
800
|
+
binary: false,
|
|
801
|
+
minZoom: 17,
|
|
802
|
+
maxZoom: 24,
|
|
803
|
+
renderSubLayers: (props) => {
|
|
804
|
+
const poiData = (props.data || []);
|
|
805
|
+
const poiFeatures = poiData.filter((f) => {
|
|
806
|
+
var _a, _b, _c;
|
|
807
|
+
if (((_a = f.geometry) === null || _a === void 0 ? void 0 : _a.type) !== "Point")
|
|
808
|
+
return false;
|
|
809
|
+
if (((_b = f.properties) === null || _b === void 0 ? void 0 : _b.floor_key) && f.properties.floor_key !== floorKey)
|
|
810
|
+
return false;
|
|
811
|
+
const sub = (_c = f.properties) === null || _c === void 0 ? void 0 : _c.subclass;
|
|
812
|
+
return sub === "elevator" || sub === "toilets";
|
|
813
|
+
});
|
|
814
|
+
if (!poiFeatures.length)
|
|
815
|
+
return null;
|
|
816
|
+
const iconData = poiFeatures.map((f) => {
|
|
817
|
+
var _a, _b, _c;
|
|
818
|
+
const tags = ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.tags) || "";
|
|
819
|
+
let icon;
|
|
820
|
+
if (tags.includes("wheelchair"))
|
|
821
|
+
icon = "accessible_toilets";
|
|
822
|
+
else if (tags.includes("changing_table"))
|
|
823
|
+
icon = "changing_table";
|
|
824
|
+
else
|
|
825
|
+
icon = ((_b = f.properties) === null || _b === void 0 ? void 0 : _b.subclass) || "";
|
|
826
|
+
return {
|
|
827
|
+
position: [
|
|
828
|
+
...f.geometry.coordinates.slice(0, 2),
|
|
829
|
+
((_c = f.properties) === null || _c === void 0 ? void 0 : _c.height) ? Number(f.properties.height) : 5,
|
|
830
|
+
],
|
|
831
|
+
icon,
|
|
832
|
+
};
|
|
833
|
+
});
|
|
834
|
+
return new layers_1.IconLayer(Object.assign(Object.assign({}, props), { id: `${props.id}-poi-icons`, data: iconData, iconAtlas: this.spriteAtlasImage, iconMapping: this.spriteIconMapping, getIcon: (d) => d.icon, getPosition: (d) => d.position, getSize: 2, sizeUnits: "meters", sizeScale: 1, billboard: true, pickable: false }));
|
|
835
|
+
},
|
|
836
|
+
updateTriggers: {
|
|
837
|
+
renderSubLayers: [floorKey],
|
|
838
|
+
},
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
makeStoreLogoLayer(floorKey) {
|
|
842
|
+
if (!this.spriteIconMapping || !this.spriteAtlasImage)
|
|
843
|
+
return null;
|
|
844
|
+
return new geo_layers_1.MVTLayer({
|
|
845
|
+
id: "indoor-store-logos",
|
|
846
|
+
data: "https://tiles.mapvx.com/",
|
|
847
|
+
binary: false,
|
|
848
|
+
minZoom: 13,
|
|
849
|
+
maxZoom: 24,
|
|
850
|
+
renderSubLayers: (props) => {
|
|
851
|
+
const propsData = (props.data || []);
|
|
852
|
+
const logoFeatures = propsData.filter((f) => {
|
|
853
|
+
var _a, _b, _c;
|
|
854
|
+
if (((_a = f.geometry) === null || _a === void 0 ? void 0 : _a.type) !== "Point")
|
|
855
|
+
return false;
|
|
856
|
+
if (((_b = f.properties) === null || _b === void 0 ? void 0 : _b.floor_key) && f.properties.floor_key !== floorKey)
|
|
857
|
+
return false;
|
|
858
|
+
const name = (_c = f.properties) === null || _c === void 0 ? void 0 : _c.name;
|
|
859
|
+
if (!name)
|
|
860
|
+
return false;
|
|
861
|
+
return !!this.spriteIconMapping["logo-" + name];
|
|
862
|
+
});
|
|
863
|
+
if (!logoFeatures.length)
|
|
864
|
+
return null;
|
|
865
|
+
const logoData = logoFeatures.map((f) => {
|
|
866
|
+
var _a, _b, _c;
|
|
867
|
+
const name = (_a = f.properties) === null || _a === void 0 ? void 0 : _a.name;
|
|
868
|
+
const icon = "logo-" + name;
|
|
869
|
+
const rotation = ((_b = f.properties) === null || _b === void 0 ? void 0 : _b.rotation_icon) ? Number(f.properties.rotation_icon) : 0;
|
|
870
|
+
return {
|
|
871
|
+
position: [
|
|
872
|
+
...f.geometry.coordinates.slice(0, 2),
|
|
873
|
+
((_c = f.properties) === null || _c === void 0 ? void 0 : _c.height) ? Number(f.properties.height) : 5,
|
|
874
|
+
],
|
|
875
|
+
icon,
|
|
876
|
+
rotation,
|
|
877
|
+
};
|
|
878
|
+
});
|
|
879
|
+
return new layers_1.IconLayer(Object.assign(Object.assign({}, props), { id: `${props.id}-store-logos`, data: logoData, iconAtlas: this.spriteAtlasImage, iconMapping: this.spriteIconMapping, getIcon: (d) => d.icon, getPosition: (d) => d.position, getAngle: (d) => -d.rotation, getSize: (d) => {
|
|
880
|
+
const LOGO_SCALE = {
|
|
881
|
+
"logo-Maxi-K": 0.4,
|
|
882
|
+
"logo-Ripley": 2,
|
|
883
|
+
"logo-Falabella": 2,
|
|
884
|
+
"logo-CasaIdeas": 2,
|
|
885
|
+
"logo-Sky Costanera": 0.6,
|
|
886
|
+
"logo-Easy": 1.4,
|
|
887
|
+
"logo-Jumbo": 2,
|
|
888
|
+
"logo-Decathlon": 1.4,
|
|
889
|
+
};
|
|
890
|
+
const m = this.spriteIconMapping[d.icon];
|
|
891
|
+
if (!m)
|
|
892
|
+
return 10;
|
|
893
|
+
const pr = m.pixelRatio;
|
|
894
|
+
const w = m.width / pr;
|
|
895
|
+
const h = m.height / pr;
|
|
896
|
+
const base = 10 * (h / Math.max(w, h));
|
|
897
|
+
return base * (LOGO_SCALE[d.icon] || 1);
|
|
898
|
+
}, sizeUnits: "meters", sizeScale: 1, billboard: false, pickable: false }));
|
|
899
|
+
},
|
|
900
|
+
updateTriggers: {
|
|
901
|
+
renderSubLayers: [floorKey],
|
|
902
|
+
},
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
updateDeckOverlay() {
|
|
906
|
+
if (!this.deckOverlay || !this.currentFloor)
|
|
907
|
+
return;
|
|
908
|
+
const layers = [
|
|
909
|
+
this.makeMVTLayer(this.currentFloor),
|
|
910
|
+
this.makeLabelLayer(this.currentFloor, false),
|
|
911
|
+
];
|
|
912
|
+
const poiLayer = this.makePoiIconLayer(this.currentFloor);
|
|
913
|
+
if (poiLayer)
|
|
914
|
+
layers.push(poiLayer);
|
|
915
|
+
const storeLayer = this.makeStoreLogoLayer(this.currentFloor);
|
|
916
|
+
if (storeLayer)
|
|
917
|
+
layers.push(storeLayer);
|
|
918
|
+
this.deckOverlay.setProps({ layers });
|
|
919
|
+
}
|
|
920
|
+
// End 3D related methods ------------------------------------------------------------
|
|
478
921
|
getCurrentFloor() {
|
|
479
922
|
var _a;
|
|
480
923
|
return (_a = this.currentFloor) !== null && _a !== void 0 ? _a : "";
|
|
@@ -494,6 +937,10 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
494
937
|
if (place) {
|
|
495
938
|
this.subPlacesLoad(place.mapvxId);
|
|
496
939
|
}
|
|
940
|
+
if (this.mode === "3D") {
|
|
941
|
+
this.updateDeckOverlay();
|
|
942
|
+
this.placeEscalators();
|
|
943
|
+
}
|
|
497
944
|
if (updateStyle) {
|
|
498
945
|
this.repository
|
|
499
946
|
.fetchAndParseMapStyle(place === null || place === void 0 ? void 0 : place.mapvxId)
|
|
@@ -522,6 +969,10 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
522
969
|
this.innerFloors = (_a = place === null || place === void 0 ? void 0 : place.innerFloors.sort((a, b) => a.index - b.index)) !== null && _a !== void 0 ? _a : [];
|
|
523
970
|
this.currentFloor =
|
|
524
971
|
(_e = (_c = floorId !== null && floorId !== void 0 ? floorId : (_b = this.innerFloors.find((floor) => floor.defaultFloor)) === null || _b === void 0 ? void 0 : _b.key) !== null && _c !== void 0 ? _c : (_d = this.innerFloors[0]) === null || _d === void 0 ? void 0 : _d.key) !== null && _e !== void 0 ? _e : "";
|
|
972
|
+
if (this.mode === "3D") {
|
|
973
|
+
this.updateDeckOverlay();
|
|
974
|
+
this.placeEscalators();
|
|
975
|
+
}
|
|
525
976
|
}
|
|
526
977
|
updateParentPlaceAndFloor(parentPlaceId, floorId, options) {
|
|
527
978
|
var _a, _b, _c, _d;
|
|
@@ -539,6 +990,19 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
539
990
|
}
|
|
540
991
|
setLang(lang) {
|
|
541
992
|
this.repository.setLang(lang);
|
|
993
|
+
if (_rtl_1.rtlLanguages.includes(lang)) {
|
|
994
|
+
this.setRTLSupport();
|
|
995
|
+
}
|
|
996
|
+
// setLayersForLanguage reads this.map.getStyle()?.layers, which is empty
|
|
997
|
+
// until the style finishes loading. If setLang is called right after
|
|
998
|
+
// createMap (before the "load" event), apply it once the style is ready
|
|
999
|
+
// so the language change is not silently dropped.
|
|
1000
|
+
if (this.map.isStyleLoaded()) {
|
|
1001
|
+
this.setLayersForLanguage(lang);
|
|
1002
|
+
}
|
|
1003
|
+
else {
|
|
1004
|
+
this.map.once("load", () => this.setLayersForLanguage(lang));
|
|
1005
|
+
}
|
|
542
1006
|
}
|
|
543
1007
|
setParentPlace(place, updateStyle, onStyleReady) {
|
|
544
1008
|
this.changeParentPlaceTo(place, updateStyle, onStyleReady);
|
|
@@ -561,6 +1025,9 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
561
1025
|
this.routeController.addSourcesAndLayers();
|
|
562
1026
|
this.refreshCircles();
|
|
563
1027
|
this.filterByFloorKey(this.currentFloor);
|
|
1028
|
+
if (this.mode === "3D") {
|
|
1029
|
+
this.updateDeckOverlay();
|
|
1030
|
+
}
|
|
564
1031
|
}
|
|
565
1032
|
addMarker(marker) {
|
|
566
1033
|
var _a, _b;
|
|
@@ -910,7 +1377,14 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
910
1377
|
// Always keep the default bucket alive so an empty map still renders
|
|
911
1378
|
// newly added circles without a layer rebuild
|
|
912
1379
|
ordersInUse.add("aboveBasemap");
|
|
913
|
-
|
|
1380
|
+
// Process buckets lowest-first (CIRCLE_RENDER_ORDERS is canonical):
|
|
1381
|
+
// when two buckets resolve to the same anchor, each addLayer/moveLayer
|
|
1382
|
+
// lands immediately before it, so a bucket processed later paints above
|
|
1383
|
+
// the ones processed earlier. Canonical order keeps
|
|
1384
|
+
// belowLabels < aboveBasemap < top regardless of circle insertion order.
|
|
1385
|
+
for (const order of circle_1.CIRCLE_RENDER_ORDERS) {
|
|
1386
|
+
if (!ordersInUse.has(order))
|
|
1387
|
+
continue;
|
|
914
1388
|
const ids = circleLayerIdsFor(order);
|
|
915
1389
|
const beforeId = this.circleBeforeIdFor(order);
|
|
916
1390
|
const orderFilter = ["==", ["get", "renderOrder"], order];
|
|
@@ -982,6 +1456,10 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
982
1456
|
if (this.innerFloors.every((floor) => floor.key !== floorKey) && floorKey !== "") {
|
|
983
1457
|
this.logEvent("invalidFloorKey", { floorKey: floorKeyString });
|
|
984
1458
|
}
|
|
1459
|
+
if (this.mode === "3D") {
|
|
1460
|
+
this.updateDeckOverlay();
|
|
1461
|
+
this.placeEscalators();
|
|
1462
|
+
}
|
|
985
1463
|
this.updateFiltersTo(floorKeyString);
|
|
986
1464
|
this.updateMarkersTo(floorKeyString);
|
|
987
1465
|
this.refreshCircles();
|
|
@@ -1090,6 +1568,49 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
1090
1568
|
this.map.setMinZoom(zoomLvl);
|
|
1091
1569
|
(_a = options === null || options === void 0 ? void 0 : options.onComplete) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
1092
1570
|
}
|
|
1571
|
+
setBearing(degrees, options) {
|
|
1572
|
+
var _a;
|
|
1573
|
+
if (!Number.isFinite(degrees))
|
|
1574
|
+
return;
|
|
1575
|
+
if (options === null || options === void 0 ? void 0 : options.animate) {
|
|
1576
|
+
if (options.onComplete)
|
|
1577
|
+
void this.map.once("moveend", options.onComplete);
|
|
1578
|
+
this.map.rotateTo(degrees, { duration: 600 });
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
this.map.setBearing(degrees);
|
|
1582
|
+
(_a = options === null || options === void 0 ? void 0 : options.onComplete) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
1583
|
+
}
|
|
1584
|
+
setRotationEnabled(enabled) {
|
|
1585
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1586
|
+
if (enabled) {
|
|
1587
|
+
(_b = (_a = this.map.dragRotate) === null || _a === void 0 ? void 0 : _a.enable) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1588
|
+
(_d = (_c = this.map.touchZoomRotate) === null || _c === void 0 ? void 0 : _c.enableRotation) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1589
|
+
(_f = (_e = this.map.keyboard) === null || _e === void 0 ? void 0 : _e.enable) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|
1590
|
+
}
|
|
1591
|
+
else {
|
|
1592
|
+
(_h = (_g = this.map.dragRotate) === null || _g === void 0 ? void 0 : _g.disable) === null || _h === void 0 ? void 0 : _h.call(_g);
|
|
1593
|
+
(_k = (_j = this.map.touchZoomRotate) === null || _j === void 0 ? void 0 : _j.disableRotation) === null || _k === void 0 ? void 0 : _k.call(_j);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
setPanEnabled(enabled) {
|
|
1597
|
+
var _a, _b, _c, _d;
|
|
1598
|
+
if (enabled) {
|
|
1599
|
+
(_b = (_a = this.map.dragPan) === null || _a === void 0 ? void 0 : _a.enable) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1600
|
+
}
|
|
1601
|
+
else {
|
|
1602
|
+
(_d = (_c = this.map.dragPan) === null || _c === void 0 ? void 0 : _c.disable) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
setScrollZoomEnabled(enabled) {
|
|
1606
|
+
var _a, _b, _c, _d;
|
|
1607
|
+
if (enabled) {
|
|
1608
|
+
(_b = (_a = this.map.scrollZoom) === null || _a === void 0 ? void 0 : _a.enable) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1609
|
+
}
|
|
1610
|
+
else {
|
|
1611
|
+
(_d = (_c = this.map.scrollZoom) === null || _c === void 0 ? void 0 : _c.disable) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1093
1614
|
isInsideBounds(point) {
|
|
1094
1615
|
const mapBounds = this.map.getMaxBounds();
|
|
1095
1616
|
if (mapBounds != null) {
|
|
@@ -1258,7 +1779,7 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
1258
1779
|
if (pointedPlace !== undefined) {
|
|
1259
1780
|
new maplibre_gl_1.default.Popup()
|
|
1260
1781
|
.setLngLat(pointedPlace.position)
|
|
1261
|
-
.
|
|
1782
|
+
.setText(pointedPlace.title)
|
|
1262
1783
|
.addTo(this.map);
|
|
1263
1784
|
}
|
|
1264
1785
|
}
|