venue-js 1.2.0-next.14 → 1.2.0-next.16

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/index.mjs CHANGED
@@ -81,7 +81,8 @@ var defaultFeatureQueryOptionsMap = {
81
81
  // refresh every 5 min
82
82
  },
83
83
  element: {},
84
- page: {}
84
+ page: {},
85
+ model3d: {}
85
86
  };
86
87
 
87
88
  // src/data/api/delivery-project.ts
@@ -97,6 +98,14 @@ async function fetchDeliveryApi(projectId, apiKey, featureType, baseUrl = DEFAUL
97
98
  const items = await res.json();
98
99
  return items;
99
100
  }
101
+ case "model3d": {
102
+ const res = await fetch(
103
+ `${baseUrl}/delivery/projects/${projectId}/${featureType}.geojson?api-key=${apiKey}`
104
+ );
105
+ if (res.status !== 200) return [];
106
+ const items = await res.json();
107
+ return items.features;
108
+ }
100
109
  case "sponsored-content": {
101
110
  const res = await fetch(
102
111
  `${baseUrl}/delivery/projects/${projectId}/sponsored-content.json?api-key=${apiKey}`
@@ -789,6 +798,13 @@ function featureCollection(features, options = {}) {
789
798
  fc.features = features;
790
799
  return fc;
791
800
  }
801
+ function multiPoint(coordinates, properties, options = {}) {
802
+ const geom = {
803
+ type: "MultiPoint",
804
+ coordinates
805
+ };
806
+ return feature(geom, properties, options);
807
+ }
792
808
  function isNumber(num) {
793
809
  return !isNaN(num) && num !== null && !Array.isArray(num);
794
810
  }
@@ -889,11 +905,8 @@ import turfBuffer from "@turf/buffer";
889
905
  import {
890
906
  TextureLoader as TextureLoader2,
891
907
  SpriteMaterial as SpriteMaterial3,
892
- MeshLambertMaterial,
893
- AmbientLight,
894
- DirectionalLight
908
+ MeshLambertMaterial
895
909
  } from "three";
896
- import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
897
910
 
898
911
  // src/IndoorMap/object3d/Billboard.js
899
912
  import * as maptalks from "maptalks";
@@ -1487,36 +1500,6 @@ var createPedestrianOpening = (feature2, style, options = {}) => {
1487
1500
  console.log(`error creating pedestrian opening:`, feature2);
1488
1501
  }
1489
1502
  };
1490
- var loadModel3d = (model3d, coordinate, threeLayer) => {
1491
- return new Promise((resolve, reject) => {
1492
- const loader = new GLTFLoader();
1493
- const { url, properties: modelProperties } = model3d;
1494
- loader.load(
1495
- url,
1496
- (gltf) => {
1497
- const object3d = gltf.scene;
1498
- object3d.rotation.x = _4.get(modelProperties, "rotation.x");
1499
- object3d.rotation.y = _4.get(modelProperties, "rotation.y");
1500
- object3d.scale.set(..._4.get(modelProperties, "scale") || []);
1501
- const object = threeLayer.toModel(object3d, {
1502
- coordinate
1503
- });
1504
- object.getObject3d().traverse((child) => {
1505
- if (child.isMesh === true) {
1506
- child.material.transparent = true;
1507
- child.material.metalness = 0.1;
1508
- }
1509
- });
1510
- resolve(object);
1511
- },
1512
- (xhr) => {
1513
- },
1514
- (error) => {
1515
- reject(error);
1516
- }
1517
- );
1518
- });
1519
- };
1520
1503
  var createExtrudePolygon = (geometry, threeLayer, material, height, properties = {}, options) => {
1521
1504
  const { offset = 0, altitude = 0 } = options;
1522
1505
  const offsetGeometry = turfBuffer(geometry, offset, { units: "meters" });
@@ -2190,42 +2173,6 @@ var styledFeatureGenerator = (mapTheme) => {
2190
2173
  return null;
2191
2174
  }
2192
2175
  },
2193
- /** Three JS */
2194
- create3DFootprint: async (feature2, threeLayer, options) => {
2195
- const objects = [];
2196
- const extrudeHeight = _4.get(options, "height");
2197
- if (!extrudeHeight) return objects;
2198
- const { properties } = feature2;
2199
- const footprintProperties = getFeatureProperties(feature2);
2200
- const hasModel3ds = Array.isArray(properties.model3d) && properties.model3d.length > 0;
2201
- if (hasModel3ds) {
2202
- const models = properties.model3d;
2203
- const center2 = turfCenter(feature2);
2204
- const coordinate = _4.get(center2, "geometry.coordinates");
2205
- for (const model of models) {
2206
- const object = await loadModel3d(model, coordinate, threeLayer);
2207
- object.properties = footprintProperties;
2208
- objects.push(object);
2209
- }
2210
- } else {
2211
- const color = footprintProperties.defaultColor;
2212
- if (color === "transparent") return;
2213
- const material = new MeshLambertMaterial({
2214
- color,
2215
- transparent: true
2216
- });
2217
- const object = createExtrudePolygon(
2218
- feature2.geometry,
2219
- threeLayer,
2220
- material,
2221
- extrudeHeight,
2222
- footprintProperties,
2223
- {}
2224
- );
2225
- objects.push(object);
2226
- }
2227
- return objects;
2228
- },
2229
2176
  create3DBillboard: (billboard, threeLayer) => {
2230
2177
  const { id, feature_type, properties } = billboard;
2231
2178
  const {
@@ -2726,8 +2673,7 @@ var CameraManager = class {
2726
2673
  };
2727
2674
 
2728
2675
  // src/IndoorMap/renderer/RendererManager.ts
2729
- import _isFunction from "lodash/isFunction";
2730
- import _min from "lodash/min";
2676
+ import { min, compact, isFunction } from "lodash-es";
2731
2677
  import { center as turfCenter2 } from "@turf/center";
2732
2678
  import * as THREE3 from "three";
2733
2679
 
@@ -2736,6 +2682,12 @@ import * as maptalks4 from "maptalks-gl";
2736
2682
  import * as THREE from "three";
2737
2683
  import { BaseObject as BaseObject5 } from "maptalks.three";
2738
2684
  import turfBuffer2 from "@turf/buffer";
2685
+ import { cleanCoords } from "@turf/clean-coords";
2686
+ import { polygonToLine } from "@turf/polygon-to-line";
2687
+ import { nearestPointOnLine } from "@turf/nearest-point-on-line";
2688
+ import { length } from "@turf/length";
2689
+ import { along } from "@turf/along";
2690
+ import { pointToLineDistance } from "@turf/point-to-line-distance";
2739
2691
 
2740
2692
  // src/IndoorMap/renderer/3d/objects/GroundLabel.ts
2741
2693
  import * as maptalks3 from "maptalks-gl";
@@ -3042,15 +2994,15 @@ var GroundLabel = class extends BaseObject4 {
3042
2994
  // src/IndoorMap/renderer/3d/element3DRendererOptions.ts
3043
2995
  var element3DRendererOptions = {
3044
2996
  unit: {
3045
- default: { color: "#ffffff", height: 4 },
2997
+ default: { color: "#ffffff", height: 0.2 },
3046
2998
  byCategory: {
3047
2999
  walkway: { color: "#cccccc", height: 0.1 },
3048
3000
  terrace: { color: "#cccccc", height: 0.1 },
3049
3001
  unenclosedarea: { color: "#cccccc", height: 0.2 },
3050
3002
  nonpublic: { color: "#999999", height: 0.3 },
3051
3003
  escalator: { height: 0.2 },
3052
- parking: { height: 0.1 },
3053
- room: { color: "#ffffff", height: 2, bottomHeight: 0.12 }
3004
+ parking: { color: "#999999", height: 0.1 },
3005
+ room: { color: "#ffffff", height: 0.5, bottomHeight: 0.12 }
3054
3006
  }
3055
3007
  },
3056
3008
  kiosk: {
@@ -3082,6 +3034,7 @@ var get3DRendererOption = (featureType, category, options) => {
3082
3034
  };
3083
3035
 
3084
3036
  // src/IndoorMap/renderer/3d/Element3DRenderer.ts
3037
+ import lineSplit from "@turf/line-split";
3085
3038
  var HEIGHT_METER = 4;
3086
3039
  var MULTIORDINAL_HEIGHT_METER = 9;
3087
3040
  var Element3DRenderer = class extends EventTarget {
@@ -3213,6 +3166,68 @@ var Element3DRenderer = class extends EventTarget {
3213
3166
  console.log(`error createGeometry`, err, { feature: feature2, options });
3214
3167
  }
3215
3168
  };
3169
+ createRoomWall(unit, openings = []) {
3170
+ const polygons = unit.geometry.type === "Polygon" ? [unit.geometry.coordinates] : unit.geometry.coordinates;
3171
+ return polygons.map((plg) => {
3172
+ return plg.map((ring) => {
3173
+ const roomWall = cleanCoords(polygonToLine(polygon([ring])));
3174
+ if (openings.length === 0) {
3175
+ const color = "#ababab";
3176
+ const material = this.getOrCreateMaterialByColor(color);
3177
+ const extrudedWall = this.threeLayer.toExtrudeLine(
3178
+ new maptalks4.LineString(roomWall.geometry.coordinates),
3179
+ { height: 4, width: 1 },
3180
+ material
3181
+ );
3182
+ return extrudedWall;
3183
+ }
3184
+ let openingPoints = [];
3185
+ openings.forEach((opening) => {
3186
+ const doorCoords = opening?.geometry?.coordinates;
3187
+ const p0 = point(doorCoords[0]);
3188
+ const p1 = point(doorCoords[doorCoords.length - 1]);
3189
+ const s0 = nearestPointOnLine(roomWall, p0, { units: "meters" });
3190
+ const s1 = nearestPointOnLine(roomWall, p1, { units: "meters" });
3191
+ const d0 = s0.properties.dist;
3192
+ const d1 = s1.properties.dist;
3193
+ if (d0 > 1 || d1 > 1) {
3194
+ } else {
3195
+ openingPoints = openingPoints.concat([s0.geometry.coordinates, s1.geometry.coordinates]);
3196
+ }
3197
+ });
3198
+ try {
3199
+ const split = lineSplit(roomWall, multiPoint(openingPoints));
3200
+ const wallsOnly = split.features.filter((seg) => {
3201
+ const mid = along(seg, length(seg, { units: "meters" }) / 2, { units: "meters" });
3202
+ for (const opening of openings) {
3203
+ const dist = pointToLineDistance(mid, opening, { units: "meters" });
3204
+ if (dist < 0.05) return false;
3205
+ }
3206
+ return true;
3207
+ });
3208
+ const wallMeshes = wallsOnly.map((feature2, i) => {
3209
+ const color = "#ababab";
3210
+ const material = this.getOrCreateMaterialByColor(color);
3211
+ const extrudedLine = this.threeLayer.toExtrudeLine(
3212
+ new maptalks4.LineString(feature2.geometry.coordinates),
3213
+ { height: 3, width: 0.4, id: unit.id },
3214
+ material
3215
+ );
3216
+ extrudedLine.getObject3d().userData = {
3217
+ unitId: unit.id,
3218
+ coords: feature2.geometry.coordinates
3219
+ };
3220
+ return extrudedLine;
3221
+ }).flat();
3222
+ this.threeLayer.addMesh(wallMeshes);
3223
+ return wallMeshes;
3224
+ } catch (e) {
3225
+ console.log(e.message, { unit, roomWall });
3226
+ return [];
3227
+ }
3228
+ }).flat();
3229
+ }).flat();
3230
+ }
3216
3231
  async createEscalator(f, coordinate, options) {
3217
3232
  const model = {
3218
3233
  url: "https://cdn.venue.in.th/static/glb/escalator.glb",
@@ -3242,14 +3257,14 @@ var Element3DRenderer = class extends EventTarget {
3242
3257
  this.threeLayer.addMesh(groundLabel);
3243
3258
  return groundLabel;
3244
3259
  }
3245
- async createTree(coordinate, ordinal) {
3246
- const treeMarker = new maptalks4.GLTFMarker(coordinate, {
3260
+ async createModel3d(f) {
3261
+ const marker = new maptalks4.GLTFMarker(f.properties.center, {
3247
3262
  symbol: {
3248
- url: "https://dashboard.situm.com/uploads/3dmodels/demoaccount/new_escalator.glb"
3263
+ url: f.properties.model
3249
3264
  }
3250
3265
  });
3251
- treeMarker.addTo(this.gltfLayer);
3252
- return treeMarker;
3266
+ marker.addTo(this.gltfLayer);
3267
+ return marker;
3253
3268
  }
3254
3269
  async createBuilding(coordinate, ordinal) {
3255
3270
  return Promise.resolve(null);
@@ -3408,6 +3423,9 @@ var Element2DRenderer = class extends EventTarget {
3408
3423
  return geometry;
3409
3424
  }
3410
3425
  };
3426
+ createRoomWall(unit, openings) {
3427
+ return null;
3428
+ }
3411
3429
  async createEscalator(f, coordinates) {
3412
3430
  return Promise.resolve(null);
3413
3431
  }
@@ -3416,9 +3434,6 @@ var Element2DRenderer = class extends EventTarget {
3416
3434
  const bound = f.geometry.coordinates[0];
3417
3435
  return null;
3418
3436
  }
3419
- async createTree(coordinates) {
3420
- return Promise.resolve(null);
3421
- }
3422
3437
  async createBuilding(coordinate, ordinal) {
3423
3438
  return Promise.resolve(null);
3424
3439
  }
@@ -4290,6 +4305,38 @@ var RendererManager = class extends EventTarget {
4290
4305
  const groupLayer = this.map.getLayer("group");
4291
4306
  const threeLayer = groupLayer.getLayer("three");
4292
4307
  threeLayer.prepareToDraw = function(gl, scene, camera) {
4308
+ function findBadMeshes(scene2) {
4309
+ const bad = [];
4310
+ scene2.traverse((obj) => {
4311
+ if (!obj?.isMesh) return;
4312
+ const geom = obj.geometry;
4313
+ const pos = geom?.attributes?.position?.array;
4314
+ if (!pos || pos.length === 0) return;
4315
+ for (let i = 0; i < pos.length; i++) {
4316
+ const v2 = pos[i];
4317
+ if (!Number.isFinite(v2)) {
4318
+ bad.push({ mesh: obj, index: i, value: v2 });
4319
+ break;
4320
+ }
4321
+ }
4322
+ });
4323
+ if (bad.length) {
4324
+ console.group(`\u274C Found ${bad.length} meshes with invalid positions`);
4325
+ for (const b of bad) {
4326
+ console.log({
4327
+ name: b.mesh.name,
4328
+ userData: b.mesh.userData,
4329
+ uuid: b.mesh.uuid,
4330
+ badIndex: b.index,
4331
+ badValue: b.value
4332
+ });
4333
+ }
4334
+ console.groupEnd();
4335
+ } else {
4336
+ console.log("\u2705 No invalid meshes found");
4337
+ }
4338
+ return bad;
4339
+ }
4293
4340
  const ambientLight = new THREE3.AmbientLight(16777215, 0.3);
4294
4341
  scene.add(ambientLight);
4295
4342
  const dirColor = 16777215;
@@ -4304,6 +4351,9 @@ var RendererManager = class extends EventTarget {
4304
4351
  options.onRendererReady();
4305
4352
  }
4306
4353
  _this.#createElements();
4354
+ setTimeout(() => {
4355
+ findBadMeshes(scene);
4356
+ }, 3e3);
4307
4357
  };
4308
4358
  } else {
4309
4359
  this.elementRenderer = new Element2DRenderer(map, options.elements);
@@ -4318,7 +4368,7 @@ var RendererManager = class extends EventTarget {
4318
4368
  if (this.#isClicked) return;
4319
4369
  this.#isClicked = true;
4320
4370
  const onClickElement = this.#onClickElement;
4321
- if (!_isFunction(onClickElement)) return;
4371
+ if (!isFunction(onClickElement)) return;
4322
4372
  this.#onClickElement(e);
4323
4373
  this.#isClicked = false;
4324
4374
  };
@@ -4345,6 +4395,9 @@ var RendererManager = class extends EventTarget {
4345
4395
  const levels = await this.#dataClient.filterByType("level", {
4346
4396
  populate: true
4347
4397
  });
4398
+ const openings = await this.#dataClient.filterByType("opening", {
4399
+ populate: true
4400
+ });
4348
4401
  const relationships = await this.#dataClient.filterByType("relationship");
4349
4402
  const fixtures = await this.#dataClient.filterByType("fixture", { populate: true });
4350
4403
  fixtures.forEach((fixture) => {
@@ -4358,7 +4411,7 @@ var RendererManager = class extends EventTarget {
4358
4411
  populate: true
4359
4412
  });
4360
4413
  units.filter(
4361
- (u4) => !["opentobelow", "escalator"].includes(u4.properties.category)
4414
+ (u4) => !["opentobelow", "escalator", "room"].includes(u4.properties.category)
4362
4415
  ).forEach((unit) => {
4363
4416
  const element = this.elementRenderer.createGeometry(unit);
4364
4417
  if (element) {
@@ -4366,6 +4419,22 @@ var RendererManager = class extends EventTarget {
4366
4419
  this.addElementsToManager(unit.id, _elements, unit.properties.level.properties.ordinal);
4367
4420
  }
4368
4421
  });
4422
+ units.filter((u4) => u4.properties.category === "room").forEach((unit) => {
4423
+ const openingRelationships = relationships.filter((r) => r.properties.origin?.id === unit.id || r.properties.destination?.id === unit.id);
4424
+ const roomOpenings = compact(openingRelationships.map((rel) => {
4425
+ const openingId = rel?.properties.intermediary[0].id;
4426
+ return openings.find((o) => o.id === openingId);
4427
+ }));
4428
+ const innerElements = this.elementRenderer.createGeometry(unit);
4429
+ const wallElements = this.elementRenderer.createRoomWall(unit, roomOpenings);
4430
+ if (innerElements || wallElements) {
4431
+ const _innerElements = Array.isArray(innerElements) ? innerElements : [innerElements];
4432
+ const _wallElements = Array.isArray(wallElements) ? wallElements : [wallElements];
4433
+ const _elements = [..._innerElements, ..._wallElements];
4434
+ const ordinal = unit.properties.level.properties.ordinal;
4435
+ this.addElementsToManager(unit.id, _elements, ordinal);
4436
+ }
4437
+ });
4369
4438
  const kiosks = await this.#dataClient.filterByType("kiosk", {
4370
4439
  populate: true
4371
4440
  });
@@ -4413,12 +4482,17 @@ var RendererManager = class extends EventTarget {
4413
4482
  const center2 = turfCenter2(polygon(label.geometry.coordinates)).geometry.coordinates;
4414
4483
  const unit = findUnitOnPoint(units, center2);
4415
4484
  const element = this.elementRenderer.createGroundLabel(label, unit);
4416
- console.log({ element });
4417
4485
  if (element) {
4418
4486
  const _elements = Array.isArray(element) ? element : [element];
4419
4487
  this.addElementsToManager(label.id, _elements, label.properties.ordinal);
4420
4488
  }
4421
4489
  }
4490
+ if (this.options.type === "3D") {
4491
+ const model3ds = await this.#dataClient.filterByType("model3d");
4492
+ for (const model3d of model3ds) {
4493
+ this.elementRenderer.createModel3d(model3d);
4494
+ }
4495
+ }
4422
4496
  this.changeLevelByOrdinal(this.currentOrdinals);
4423
4497
  this.dispatchEvent(new CustomEvent("renderermanager:elements_created"));
4424
4498
  }
@@ -4433,7 +4507,7 @@ var RendererManager = class extends EventTarget {
4433
4507
  this.markerRenderer.showMarkers(markers, ordinal - baseOrdinal);
4434
4508
  }
4435
4509
  } else {
4436
- const baseOrdinal = Array.isArray(targetOrdinal) ? _min(targetOrdinal) : targetOrdinal;
4510
+ const baseOrdinal = Array.isArray(targetOrdinal) ? min(targetOrdinal) : targetOrdinal;
4437
4511
  for (const [ordinal, elements] of this.elementsByOrdinal) {
4438
4512
  const inOrdinal = Array.isArray(targetOrdinal) ? targetOrdinal.includes(ordinal) : ordinal === targetOrdinal;
4439
4513
  if (inOrdinal) {
@@ -4460,7 +4534,7 @@ var RendererManager = class extends EventTarget {
4460
4534
  const elements = elemIds.map((id) => this.elementsMap.get(id)).flat();
4461
4535
  elements.forEach((element) => {
4462
4536
  const controller = this.elementRenderer.createHighlightController(element);
4463
- if (controller && _isFunction(controller.start)) {
4537
+ if (controller && isFunction(controller.start)) {
4464
4538
  controller.start();
4465
4539
  this.highlightControllers.push(controller);
4466
4540
  }
@@ -4468,7 +4542,7 @@ var RendererManager = class extends EventTarget {
4468
4542
  };
4469
4543
  clearHighlightElements = () => {
4470
4544
  this.highlightControllers.forEach((controller) => {
4471
- if (_isFunction(controller?.clear)) controller.clear();
4545
+ if (isFunction(controller?.clear)) controller.clear();
4472
4546
  });
4473
4547
  };
4474
4548
  /**
@@ -4744,18 +4818,12 @@ var IndoorMap = class extends EventTarget {
4744
4818
  async #legacy_createElements() {
4745
4819
  const {
4746
4820
  // 2D
4747
- createVenue,
4748
4821
  createOpening,
4749
4822
  createSection,
4750
- createFixture,
4751
- createOccupant,
4752
4823
  createDecoration,
4753
4824
  // 3D
4754
- create3DFootprint,
4755
4825
  create3DBillboard,
4756
- createExtrudedUnit,
4757
4826
  create3DAmenityMarker,
4758
- create3DOccupantAmenityMarker,
4759
4827
  create3DOpeningMarker
4760
4828
  } = this.#styler;
4761
4829
  let elements = {};