@mapvx/web-js 1.2.3 → 1.3.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +2 -2
- package/README.md +9 -10
- package/dist/cjs/assets/icons.js +8 -6
- package/dist/cjs/assets/icons.js.map +1 -1
- package/dist/cjs/assets/route_animation_icon.svg +15 -0
- package/dist/cjs/assets/user-dot-icon.svg +3 -0
- package/dist/cjs/domain/models/animation.js +2 -2
- package/dist/cjs/logger/logger.js +1 -1
- package/dist/cjs/logger/rollbar.js +1 -1
- package/dist/cjs/map/map.js +490 -5
- package/dist/cjs/map/map.js.map +1 -1
- package/dist/cjs/sdk.js +1 -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/es/assets/icons.d.ts +4 -4
- package/dist/es/assets/icons.d.ts.map +1 -1
- package/dist/es/assets/icons.js +8 -6
- package/dist/es/assets/icons.js.map +1 -1
- package/dist/es/assets/route_animation_icon.svg +15 -0
- package/dist/es/assets/user-dot-icon.svg +3 -0
- package/dist/es/domain/models/animation.d.ts +3 -3
- package/dist/es/domain/models/animation.js +2 -2
- package/dist/es/domain/models/mapConfig.d.ts +11 -0
- package/dist/es/domain/models/mapConfig.d.ts.map +1 -1
- package/dist/es/interfaces/routeCacheResponse.d.ts.map +1 -1
- package/dist/es/logger/logger.js +1 -1
- package/dist/es/logger/rollbar.js +1 -1
- package/dist/es/map/map.d.ts +27 -1
- package/dist/es/map/map.d.ts.map +1 -1
- package/dist/es/map/map.js +491 -6
- package/dist/es/map/map.js.map +1 -1
- package/dist/es/sdk.d.ts.map +1 -1
- package/dist/es/sdk.js +1 -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/umd/index.js +153836 -1958
- package/dist/umd/index.js.map +1 -1
- package/package.json +62 -62
package/dist/cjs/map/map.js
CHANGED
|
@@ -24,7 +24,11 @@ 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");
|
|
28
32
|
const semaphore_1 = require("../utils/semaphore");
|
|
29
33
|
/** Shared GeoJSON source holding every circle drawn through the circle API. */
|
|
30
34
|
const CIRCLE_SOURCE_ID = "mapvx-circles";
|
|
@@ -153,19 +157,20 @@ function convertPaddingToPixels(padding, containerWidth, containerHeight) {
|
|
|
153
157
|
right: parsePaddingValue(padding.right, containerWidth),
|
|
154
158
|
};
|
|
155
159
|
}
|
|
160
|
+
const mapbox_1 = require("@deck.gl/mapbox");
|
|
156
161
|
const icons_1 = require("../assets/icons");
|
|
157
162
|
const routeController_1 = require("../controllers/routeController");
|
|
158
163
|
const _rtl_1 = require("../domain/models/_rtl");
|
|
159
164
|
const animation_1 = require("../domain/models/animation");
|
|
165
|
+
const circle_1 = require("../domain/models/circle");
|
|
160
166
|
const loggeable_1 = require("../domain/models/loggeable");
|
|
161
167
|
const mapConfig_1 = require("../domain/models/mapConfig");
|
|
162
|
-
const circle_1 = require("../domain/models/circle");
|
|
163
168
|
const marker_1 = require("../domain/models/marker");
|
|
164
169
|
const route_1 = require("../domain/models/route");
|
|
165
170
|
const routeConfiguration_1 = require("../domain/models/routeConfiguration");
|
|
166
171
|
const repository_1 = require("../repository/repository");
|
|
167
|
-
const utils_1 = require("../utils/utils");
|
|
168
172
|
const route_utils_1 = require("../utils/route-utils");
|
|
173
|
+
const utils_1 = require("../utils/utils");
|
|
169
174
|
const mapInteractionOptions_1 = require("./mapInteractionOptions");
|
|
170
175
|
/**
|
|
171
176
|
* Class to interact with the map.
|
|
@@ -182,7 +187,7 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
182
187
|
* @returns A new instance of MapVXMap.
|
|
183
188
|
*/
|
|
184
189
|
constructor(mapConfig, container, token) {
|
|
185
|
-
var _a, _b;
|
|
190
|
+
var _a, _b, _c;
|
|
186
191
|
super();
|
|
187
192
|
this.potentialParentPlaces = [];
|
|
188
193
|
this.innerFloors = [];
|
|
@@ -195,6 +200,22 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
195
200
|
this.hoveredId = "unselected";
|
|
196
201
|
this.failedTiles = new Set();
|
|
197
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();
|
|
198
219
|
if (_rtl_1.rtlLanguages.includes((_a = mapConfig.lang) !== null && _a !== void 0 ? _a : "")) {
|
|
199
220
|
this.setRTLSupport();
|
|
200
221
|
}
|
|
@@ -206,11 +227,16 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
206
227
|
this.watchPositionID = undefined;
|
|
207
228
|
this.onFloorChange = mapConfig.onFloorChange;
|
|
208
229
|
this.onParentPlaceChange = mapConfig.onParentPlaceChange;
|
|
230
|
+
this.mode = (_c = mapConfig.mode) !== null && _c !== void 0 ? _c : "2D";
|
|
231
|
+
this.initialCenter = mapConfig.center;
|
|
209
232
|
this.tileCacheConfig = (() => {
|
|
210
233
|
const merged = Object.assign(Object.assign({}, mapConfig_1.DEFAULT_TILE_CACHE_CONFIG), mapConfig.tileCache);
|
|
211
234
|
merged.maxTiles = Math.min(merged.maxTiles, mapConfig_1.MAPLIBRE_MAX_TILE_CACHE_HARD_CAP);
|
|
212
235
|
return merged;
|
|
213
236
|
})();
|
|
237
|
+
if (this.mode === "3D") {
|
|
238
|
+
this.loadSpriteAtlas().catch(console.error);
|
|
239
|
+
}
|
|
214
240
|
if (mapConfig.parentPlaceId != null) {
|
|
215
241
|
this.initialPlaceDetailSetUp(mapConfig.parentPlaceId, mapConfig.authToken);
|
|
216
242
|
}
|
|
@@ -338,6 +364,30 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
338
364
|
}), (_e = mapConfig.navigationPosition) !== null && _e !== void 0 ? _e : "top-right");
|
|
339
365
|
this.map.on("load", () => {
|
|
340
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
|
+
}
|
|
341
391
|
this.whenStyleUpdates(style);
|
|
342
392
|
if (mapConfig.lang)
|
|
343
393
|
this.setLayersForLanguage(mapConfig.lang);
|
|
@@ -360,7 +410,6 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
360
410
|
(_a = mapConfig.onRotate) === null || _a === void 0 ? void 0 : _a.call(mapConfig, this.map.getBearing());
|
|
361
411
|
});
|
|
362
412
|
this.defaultClickListener();
|
|
363
|
-
return this.map;
|
|
364
413
|
}
|
|
365
414
|
setBaseFilters(style) {
|
|
366
415
|
if (!style)
|
|
@@ -489,6 +538,415 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
489
538
|
// Tile cache clear may fail if cache doesn't exist
|
|
490
539
|
}
|
|
491
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
|
+
// Guard against an invalid initial center before it reaches fromLngLat.
|
|
629
|
+
if (!this.initialCenter ||
|
|
630
|
+
!Number.isFinite(this.initialCenter.lng) ||
|
|
631
|
+
!Number.isFinite(this.initialCenter.lat))
|
|
632
|
+
return;
|
|
633
|
+
const refMercator = maplibre_gl_1.MercatorCoordinate.fromLngLat(this.initialCenter, 0);
|
|
634
|
+
const meterScale = refMercator.meterInMercatorCoordinateUnits();
|
|
635
|
+
for (const pos of positions) {
|
|
636
|
+
// Defense in depth: never feed a non-finite coordinate to fromLngLat.
|
|
637
|
+
if (!Number.isFinite(pos.lng) || !Number.isFinite(pos.lat))
|
|
638
|
+
continue;
|
|
639
|
+
const target = maplibre_gl_1.default.MercatorCoordinate.fromLngLat([pos.lng, pos.lat], 0);
|
|
640
|
+
const sx = (target.x - refMercator.x) / meterScale;
|
|
641
|
+
const sz = (target.y - refMercator.y) / meterScale;
|
|
642
|
+
const pivot = new THREE.Group();
|
|
643
|
+
pivot.position.set(sx, 0, sz);
|
|
644
|
+
pivot.rotation.y = Math.PI / 2 - pos.bearing;
|
|
645
|
+
pivot.scale.set(0.3, 0.3, 0.3);
|
|
646
|
+
const model = this.escalatorModelTemplate.clone();
|
|
647
|
+
model.position.set(-this.escalatorCenter.x, -this.escalatorCenter.y - 3, -this.escalatorCenter.z);
|
|
648
|
+
pivot.add(model);
|
|
649
|
+
this.escalatorScene.add(pivot);
|
|
650
|
+
}
|
|
651
|
+
this.map.triggerRepaint();
|
|
652
|
+
}
|
|
653
|
+
captureEscalatorPositions() {
|
|
654
|
+
if (this.currentFloor && this.escalatorCache[this.currentFloor])
|
|
655
|
+
return;
|
|
656
|
+
// queryRenderedFeatures uses exact rendered coordinates (not tile-approximated)
|
|
657
|
+
const features = this.map
|
|
658
|
+
.queryRenderedFeatures(undefined, {
|
|
659
|
+
layers: ["indoor-transportation"],
|
|
660
|
+
})
|
|
661
|
+
.filter((f) => { var _a; return ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.floor_key) === this.currentFloor; });
|
|
662
|
+
if (!features.length)
|
|
663
|
+
return;
|
|
664
|
+
// Collect all midpoints first
|
|
665
|
+
const allMids = [];
|
|
666
|
+
for (const f of features) {
|
|
667
|
+
const geom = f.geometry;
|
|
668
|
+
// queryRenderedFeatures may return a LineString or, when a line is split
|
|
669
|
+
// across tile boundaries, a MultiLineString. The previous code assumed
|
|
670
|
+
// LineString and read coords[0]/coords[n-1] as [lng,lat], producing
|
|
671
|
+
// NaN for MultiLineString (coordinates is number[][][]). Normalize both
|
|
672
|
+
// shapes to a list of line parts (Position[][]).
|
|
673
|
+
let lineParts;
|
|
674
|
+
if (geom.type === "LineString") {
|
|
675
|
+
lineParts = [geom.coordinates];
|
|
676
|
+
}
|
|
677
|
+
else if (geom.type === "MultiLineString") {
|
|
678
|
+
lineParts = geom.coordinates;
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
for (const coords of lineParts) {
|
|
684
|
+
if (!coords || coords.length < 2)
|
|
685
|
+
continue;
|
|
686
|
+
const start = coords[0];
|
|
687
|
+
const end = coords[coords.length - 1];
|
|
688
|
+
const midLng = (start[0] + end[0]) / 2;
|
|
689
|
+
const midLat = (start[1] + end[1]) / 2;
|
|
690
|
+
const bearing = Math.atan2(end[0] - start[0], end[1] - start[1]);
|
|
691
|
+
// Skip any non-finite result so a bad feature can never poison the
|
|
692
|
+
// cache (and later crash MercatorCoordinate.fromLngLat).
|
|
693
|
+
if (!Number.isFinite(midLng) || !Number.isFinite(midLat) || !Number.isFinite(bearing))
|
|
694
|
+
continue;
|
|
695
|
+
allMids.push({ lng: midLng, lat: midLat, bearing });
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// Merge points within ~15m of each other into one
|
|
699
|
+
const MERGE_DEG = 0.00015; // ~15m
|
|
700
|
+
const positions = [];
|
|
701
|
+
const used = new Set();
|
|
702
|
+
for (let i = 0; i < allMids.length; i++) {
|
|
703
|
+
if (used.has(i))
|
|
704
|
+
continue;
|
|
705
|
+
used.add(i);
|
|
706
|
+
const group = [allMids[i]];
|
|
707
|
+
for (let j = i + 1; j < allMids.length; j++) {
|
|
708
|
+
if (used.has(j))
|
|
709
|
+
continue;
|
|
710
|
+
const dLng = allMids[i].lng - allMids[j].lng;
|
|
711
|
+
const dLat = allMids[i].lat - allMids[j].lat;
|
|
712
|
+
if (Math.abs(dLng) < MERGE_DEG && Math.abs(dLat) < MERGE_DEG) {
|
|
713
|
+
used.add(j);
|
|
714
|
+
group.push(allMids[j]);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
// Use average position and first bearing
|
|
718
|
+
const avgLng = group.reduce((s, p) => s + p.lng, 0) / group.length;
|
|
719
|
+
const avgLat = group.reduce((s, p) => s + p.lat, 0) / group.length;
|
|
720
|
+
positions.push({ lng: avgLng, lat: avgLat, bearing: group[0].bearing });
|
|
721
|
+
}
|
|
722
|
+
if (positions.length && this.currentFloor) {
|
|
723
|
+
this.escalatorCache[this.currentFloor] = positions;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
async loadSpriteAtlas() {
|
|
727
|
+
const [json, img] = await Promise.all([
|
|
728
|
+
fetch(`${this.SPRITE_URL}.json`).then((r) => r.json()),
|
|
729
|
+
new Promise((resolve, reject) => {
|
|
730
|
+
const image = new Image();
|
|
731
|
+
image.crossOrigin = "anonymous";
|
|
732
|
+
image.onload = () => resolve(image);
|
|
733
|
+
image.onerror = reject;
|
|
734
|
+
image.src = `${this.SPRITE_URL}.png`;
|
|
735
|
+
}),
|
|
736
|
+
]);
|
|
737
|
+
this.spriteIconMapping = json;
|
|
738
|
+
this.spriteAtlasImage = img;
|
|
739
|
+
}
|
|
740
|
+
makeMVTLayer(floorKey) {
|
|
741
|
+
return new geo_layers_1.MVTLayer({
|
|
742
|
+
id: "indoor-lines-elevated",
|
|
743
|
+
data: "https://tiles.mapvx.com/",
|
|
744
|
+
binary: false,
|
|
745
|
+
renderSubLayers: (props) => {
|
|
746
|
+
var _a;
|
|
747
|
+
const roomData = (props.data || []);
|
|
748
|
+
const roomFeatures = roomData.filter((f) => {
|
|
749
|
+
var _a, _b, _c;
|
|
750
|
+
return ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.class) === "room" &&
|
|
751
|
+
((_b = f.properties) === null || _b === void 0 ? void 0 : _b.subclass) !== "empty" &&
|
|
752
|
+
((_c = f.properties) === null || _c === void 0 ? void 0 : _c.floor_key) === floorKey;
|
|
753
|
+
});
|
|
754
|
+
if (!roomFeatures.length)
|
|
755
|
+
return null;
|
|
756
|
+
const paths = [];
|
|
757
|
+
for (const f of roomFeatures) {
|
|
758
|
+
const z = ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.height) ? Number(f.properties.height) : 5;
|
|
759
|
+
const geom = f.geometry;
|
|
760
|
+
const polygons = geom.type === "Polygon"
|
|
761
|
+
? [geom.coordinates]
|
|
762
|
+
: geom.type === "MultiPolygon"
|
|
763
|
+
? geom.coordinates
|
|
764
|
+
: [];
|
|
765
|
+
for (const rings of polygons) {
|
|
766
|
+
for (const ring of rings) {
|
|
767
|
+
paths.push({ path: ring.map(([lon, lat]) => [lon, lat, z]) });
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
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 }));
|
|
772
|
+
},
|
|
773
|
+
updateTriggers: {
|
|
774
|
+
renderSubLayers: [floorKey],
|
|
775
|
+
},
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
makeLabelLayer(floorKey, useSdf = true) {
|
|
779
|
+
return new geo_layers_1.MVTLayer({
|
|
780
|
+
id: "indoor-labels",
|
|
781
|
+
data: "https://tiles.mapvx.com/",
|
|
782
|
+
binary: false,
|
|
783
|
+
minZoom: 19.5,
|
|
784
|
+
maxZoom: 24,
|
|
785
|
+
renderSubLayers: (props) => {
|
|
786
|
+
// Use area_name and poi Point features — unique per tile, no duplicates
|
|
787
|
+
// If logo-{name} image exists in sprite, icon has priority over text label
|
|
788
|
+
const labelData = (props.data || []);
|
|
789
|
+
const labelFeatures = labelData.filter((f) => {
|
|
790
|
+
var _a, _b, _c, _d, _e, _f;
|
|
791
|
+
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")
|
|
792
|
+
return false;
|
|
793
|
+
if (((_c = f.geometry) === null || _c === void 0 ? void 0 : _c.type) !== "Point")
|
|
794
|
+
return false;
|
|
795
|
+
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);
|
|
796
|
+
if (!name)
|
|
797
|
+
return false;
|
|
798
|
+
if (((_f = f.properties) === null || _f === void 0 ? void 0 : _f.floor_key) && f.properties.floor_key !== floorKey)
|
|
799
|
+
return false;
|
|
800
|
+
if (this.map.hasImage("logo-" + name))
|
|
801
|
+
return false; // icon has priority
|
|
802
|
+
return true;
|
|
803
|
+
});
|
|
804
|
+
if (!labelFeatures.length)
|
|
805
|
+
return null;
|
|
806
|
+
const textData = labelFeatures.map((f) => {
|
|
807
|
+
var _a, _b, _c;
|
|
808
|
+
return ({
|
|
809
|
+
position: [
|
|
810
|
+
...f.geometry.coordinates.slice(0, 2),
|
|
811
|
+
((_a = f.properties) === null || _a === void 0 ? void 0 : _a.height) ? Number(f.properties.height) : 5,
|
|
812
|
+
],
|
|
813
|
+
text: ((_b = f.properties) === null || _b === void 0 ? void 0 : _b["name:latin"]) || ((_c = f.properties) === null || _c === void 0 ? void 0 : _c.name) || "",
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
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 }));
|
|
817
|
+
},
|
|
818
|
+
updateTriggers: {
|
|
819
|
+
renderSubLayers: [floorKey],
|
|
820
|
+
},
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
makePoiIconLayer(floorKey) {
|
|
824
|
+
if (!this.spriteIconMapping || !this.spriteAtlasImage)
|
|
825
|
+
return null;
|
|
826
|
+
return new geo_layers_1.MVTLayer({
|
|
827
|
+
id: "indoor-poi-icons",
|
|
828
|
+
data: "https://tiles.mapvx.com/",
|
|
829
|
+
binary: false,
|
|
830
|
+
minZoom: 17,
|
|
831
|
+
maxZoom: 24,
|
|
832
|
+
renderSubLayers: (props) => {
|
|
833
|
+
const poiData = (props.data || []);
|
|
834
|
+
const poiFeatures = poiData.filter((f) => {
|
|
835
|
+
var _a, _b, _c;
|
|
836
|
+
if (((_a = f.geometry) === null || _a === void 0 ? void 0 : _a.type) !== "Point")
|
|
837
|
+
return false;
|
|
838
|
+
if (((_b = f.properties) === null || _b === void 0 ? void 0 : _b.floor_key) && f.properties.floor_key !== floorKey)
|
|
839
|
+
return false;
|
|
840
|
+
const sub = (_c = f.properties) === null || _c === void 0 ? void 0 : _c.subclass;
|
|
841
|
+
return sub === "elevator" || sub === "toilets";
|
|
842
|
+
});
|
|
843
|
+
if (!poiFeatures.length)
|
|
844
|
+
return null;
|
|
845
|
+
const iconData = poiFeatures.map((f) => {
|
|
846
|
+
var _a, _b, _c;
|
|
847
|
+
const tags = ((_a = f.properties) === null || _a === void 0 ? void 0 : _a.tags) || "";
|
|
848
|
+
let icon;
|
|
849
|
+
if (tags.includes("wheelchair"))
|
|
850
|
+
icon = "accessible_toilets";
|
|
851
|
+
else if (tags.includes("changing_table"))
|
|
852
|
+
icon = "changing_table";
|
|
853
|
+
else
|
|
854
|
+
icon = ((_b = f.properties) === null || _b === void 0 ? void 0 : _b.subclass) || "";
|
|
855
|
+
return {
|
|
856
|
+
position: [
|
|
857
|
+
...f.geometry.coordinates.slice(0, 2),
|
|
858
|
+
((_c = f.properties) === null || _c === void 0 ? void 0 : _c.height) ? Number(f.properties.height) : 5,
|
|
859
|
+
],
|
|
860
|
+
icon,
|
|
861
|
+
};
|
|
862
|
+
});
|
|
863
|
+
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 }));
|
|
864
|
+
},
|
|
865
|
+
updateTriggers: {
|
|
866
|
+
renderSubLayers: [floorKey],
|
|
867
|
+
},
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
makeStoreLogoLayer(floorKey) {
|
|
871
|
+
if (!this.spriteIconMapping || !this.spriteAtlasImage)
|
|
872
|
+
return null;
|
|
873
|
+
return new geo_layers_1.MVTLayer({
|
|
874
|
+
id: "indoor-store-logos",
|
|
875
|
+
data: "https://tiles.mapvx.com/",
|
|
876
|
+
binary: false,
|
|
877
|
+
minZoom: 13,
|
|
878
|
+
maxZoom: 24,
|
|
879
|
+
renderSubLayers: (props) => {
|
|
880
|
+
const propsData = (props.data || []);
|
|
881
|
+
const logoFeatures = propsData.filter((f) => {
|
|
882
|
+
var _a, _b, _c;
|
|
883
|
+
if (((_a = f.geometry) === null || _a === void 0 ? void 0 : _a.type) !== "Point")
|
|
884
|
+
return false;
|
|
885
|
+
if (((_b = f.properties) === null || _b === void 0 ? void 0 : _b.floor_key) && f.properties.floor_key !== floorKey)
|
|
886
|
+
return false;
|
|
887
|
+
const name = (_c = f.properties) === null || _c === void 0 ? void 0 : _c.name;
|
|
888
|
+
if (!name)
|
|
889
|
+
return false;
|
|
890
|
+
return !!this.spriteIconMapping["logo-" + name];
|
|
891
|
+
});
|
|
892
|
+
if (!logoFeatures.length)
|
|
893
|
+
return null;
|
|
894
|
+
const logoData = logoFeatures.map((f) => {
|
|
895
|
+
var _a, _b, _c;
|
|
896
|
+
const name = (_a = f.properties) === null || _a === void 0 ? void 0 : _a.name;
|
|
897
|
+
const icon = "logo-" + name;
|
|
898
|
+
const rotation = ((_b = f.properties) === null || _b === void 0 ? void 0 : _b.rotation_icon) ? Number(f.properties.rotation_icon) : 0;
|
|
899
|
+
return {
|
|
900
|
+
position: [
|
|
901
|
+
...f.geometry.coordinates.slice(0, 2),
|
|
902
|
+
((_c = f.properties) === null || _c === void 0 ? void 0 : _c.height) ? Number(f.properties.height) : 5,
|
|
903
|
+
],
|
|
904
|
+
icon,
|
|
905
|
+
rotation,
|
|
906
|
+
};
|
|
907
|
+
});
|
|
908
|
+
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) => {
|
|
909
|
+
const LOGO_SCALE = {
|
|
910
|
+
"logo-Maxi-K": 0.4,
|
|
911
|
+
"logo-Ripley": 2,
|
|
912
|
+
"logo-Falabella": 2,
|
|
913
|
+
"logo-CasaIdeas": 2,
|
|
914
|
+
"logo-Sky Costanera": 0.6,
|
|
915
|
+
"logo-Easy": 1.4,
|
|
916
|
+
"logo-Jumbo": 2,
|
|
917
|
+
"logo-Decathlon": 1.4,
|
|
918
|
+
};
|
|
919
|
+
const m = this.spriteIconMapping[d.icon];
|
|
920
|
+
if (!m)
|
|
921
|
+
return 10;
|
|
922
|
+
const pr = m.pixelRatio;
|
|
923
|
+
const w = m.width / pr;
|
|
924
|
+
const h = m.height / pr;
|
|
925
|
+
const base = 10 * (h / Math.max(w, h));
|
|
926
|
+
return base * (LOGO_SCALE[d.icon] || 1);
|
|
927
|
+
}, sizeUnits: "meters", sizeScale: 1, billboard: false, pickable: false }));
|
|
928
|
+
},
|
|
929
|
+
updateTriggers: {
|
|
930
|
+
renderSubLayers: [floorKey],
|
|
931
|
+
},
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
updateDeckOverlay() {
|
|
935
|
+
if (!this.deckOverlay || !this.currentFloor)
|
|
936
|
+
return;
|
|
937
|
+
const layers = [
|
|
938
|
+
this.makeMVTLayer(this.currentFloor),
|
|
939
|
+
this.makeLabelLayer(this.currentFloor, false),
|
|
940
|
+
];
|
|
941
|
+
const poiLayer = this.makePoiIconLayer(this.currentFloor);
|
|
942
|
+
if (poiLayer)
|
|
943
|
+
layers.push(poiLayer);
|
|
944
|
+
const storeLayer = this.makeStoreLogoLayer(this.currentFloor);
|
|
945
|
+
if (storeLayer)
|
|
946
|
+
layers.push(storeLayer);
|
|
947
|
+
this.deckOverlay.setProps({ layers });
|
|
948
|
+
}
|
|
949
|
+
// End 3D related methods ------------------------------------------------------------
|
|
492
950
|
getCurrentFloor() {
|
|
493
951
|
var _a;
|
|
494
952
|
return (_a = this.currentFloor) !== null && _a !== void 0 ? _a : "";
|
|
@@ -508,6 +966,10 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
508
966
|
if (place) {
|
|
509
967
|
this.subPlacesLoad(place.mapvxId);
|
|
510
968
|
}
|
|
969
|
+
if (this.mode === "3D") {
|
|
970
|
+
this.updateDeckOverlay();
|
|
971
|
+
this.placeEscalators();
|
|
972
|
+
}
|
|
511
973
|
if (updateStyle) {
|
|
512
974
|
this.repository
|
|
513
975
|
.fetchAndParseMapStyle(place === null || place === void 0 ? void 0 : place.mapvxId)
|
|
@@ -536,6 +998,10 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
536
998
|
this.innerFloors = (_a = place === null || place === void 0 ? void 0 : place.innerFloors.sort((a, b) => a.index - b.index)) !== null && _a !== void 0 ? _a : [];
|
|
537
999
|
this.currentFloor =
|
|
538
1000
|
(_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 : "";
|
|
1001
|
+
if (this.mode === "3D") {
|
|
1002
|
+
this.updateDeckOverlay();
|
|
1003
|
+
this.placeEscalators();
|
|
1004
|
+
}
|
|
539
1005
|
}
|
|
540
1006
|
updateParentPlaceAndFloor(parentPlaceId, floorId, options) {
|
|
541
1007
|
var _a, _b, _c, _d;
|
|
@@ -588,6 +1054,9 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
588
1054
|
this.routeController.addSourcesAndLayers();
|
|
589
1055
|
this.refreshCircles();
|
|
590
1056
|
this.filterByFloorKey(this.currentFloor);
|
|
1057
|
+
if (this.mode === "3D") {
|
|
1058
|
+
this.updateDeckOverlay();
|
|
1059
|
+
}
|
|
591
1060
|
}
|
|
592
1061
|
addMarker(marker) {
|
|
593
1062
|
var _a, _b;
|
|
@@ -1016,11 +1485,26 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
1016
1485
|
if (this.innerFloors.every((floor) => floor.key !== floorKey) && floorKey !== "") {
|
|
1017
1486
|
this.logEvent("invalidFloorKey", { floorKey: floorKeyString });
|
|
1018
1487
|
}
|
|
1488
|
+
// Critical base-map updates run first and must never be blocked by an
|
|
1489
|
+
// optional 3D decoration failing. A throw in placeEscalators used to abort
|
|
1490
|
+
// this method before updateFiltersTo, leaving the base polygons unfiltered
|
|
1491
|
+
// (showing the wrong floor) while the caller's empty catch hid the error.
|
|
1019
1492
|
this.updateFiltersTo(floorKeyString);
|
|
1020
1493
|
this.updateMarkersTo(floorKeyString);
|
|
1021
1494
|
this.refreshCircles();
|
|
1022
1495
|
this.routeController.updateRouteLayers(floorKeyString);
|
|
1023
1496
|
this.routeController.updateRouteMarkerVisibility(floorKeyString);
|
|
1497
|
+
// 3D decorations are best-effort: isolate so any failure here can never
|
|
1498
|
+
// break base-map rendering.
|
|
1499
|
+
if (this.mode === "3D") {
|
|
1500
|
+
try {
|
|
1501
|
+
this.updateDeckOverlay();
|
|
1502
|
+
this.placeEscalators();
|
|
1503
|
+
}
|
|
1504
|
+
catch (error) {
|
|
1505
|
+
this.logError(error, "filterByFloorKey: 3D layer update failed");
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1024
1508
|
}
|
|
1025
1509
|
getContainer() {
|
|
1026
1510
|
return this.map.getContainer();
|
|
@@ -1285,7 +1769,7 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
1285
1769
|
throw new Error("Error: Failed to add route");
|
|
1286
1770
|
}
|
|
1287
1771
|
}
|
|
1288
|
-
updateRouteProgress(routeId, position, behindStyle = { type: "Solid", color: "#
|
|
1772
|
+
updateRouteProgress(routeId, position, behindStyle = { type: "Solid", color: "#757575" }) {
|
|
1289
1773
|
try {
|
|
1290
1774
|
const behindConfig = new routeConfiguration_1.InternalDrawRouteConfiguration({
|
|
1291
1775
|
routeStyle: behindStyle,
|
|
@@ -1341,6 +1825,7 @@ class InternalMapVXMap extends loggeable_1.Loggeable {
|
|
|
1341
1825
|
}
|
|
1342
1826
|
return "";
|
|
1343
1827
|
}
|
|
1828
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1344
1829
|
removePopOver(id) {
|
|
1345
1830
|
throw Error("Not implemented");
|
|
1346
1831
|
}
|