venue-js 1.0.0-1 → 1.0.0-3

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.js CHANGED
@@ -221,7 +221,6 @@ var createPopulator = ({
221
221
  const populateAddress = (address) => Promise.resolve(address);
222
222
  const populateBuilding = (building) => Promise.resolve(building);
223
223
  const populateDetail = (detail) => Promise.resolve(detail);
224
- const populateFixture = (fixture) => Promise.resolve(fixture);
225
224
  const populateFootprint = (footprint) => Promise.resolve(footprint);
226
225
  const populateGeofence = (geofence) => Promise.resolve(geofence);
227
226
  const populateOpening = (opening) => Promise.resolve(opening);
@@ -277,6 +276,21 @@ var createPopulator = ({
277
276
  }
278
277
  };
279
278
  };
279
+ const populateFixture = async (fixture) => {
280
+ const level = await internalFindById(fixture.properties.level_id);
281
+ const venue = await internalFindById(fixture.properties.venue_id);
282
+ const anchor = await internalFindById(fixture.properties.anchor_id);
283
+ return {
284
+ ...fixture,
285
+ properties: {
286
+ ...fixture.properties,
287
+ anchor: anchor ? await populateAnchor(anchor) : null,
288
+ level: await populateLevel(level),
289
+ venue: await populateVenue(venue),
290
+ ordinal: level.properties.ordinal
291
+ }
292
+ };
293
+ };
280
294
  const populateKiosk = async (kiosk) => {
281
295
  const level = await internalFindById(kiosk.properties.level_id);
282
296
  const venue = await internalFindById(kiosk.properties.venue_id);
@@ -467,23 +481,33 @@ var getDataClient = (options) => {
467
481
  };
468
482
  const populator = createPopulator({ internalFindById, internalFilterByType });
469
483
  const registerObserver = (featureType, refetchInterval) => {
470
- let observer = observers.get(featureType);
471
- if (!observer) {
472
- const options2 = createDeliveryApiQueryOptions(featureType);
473
- observer = new import_query_core.QueryObserver(queryClient, {
474
- ...options2,
475
- refetchInterval
476
- });
477
- observers.set(featureType, observer);
478
- } else {
479
- console.error(
480
- `An observer for featureType ${featureType} already exists, fail to register new one`
481
- );
484
+ if (observers.has(featureType)) {
485
+ console.warn(`Observer for ${featureType} already exists`);
486
+ const record = observers.get(featureType);
487
+ return record.observer;
482
488
  }
489
+ const options2 = createDeliveryApiQueryOptions(featureType);
490
+ const observer = new import_query_core.QueryObserver(queryClient, {
491
+ ...options2,
492
+ refetchInterval
493
+ });
494
+ const unsubscribe = observer.subscribe(() => {
495
+ console.log(`[venue-js] Listening to ${featureType} changes (interval = ${refetchInterval}ms)`);
496
+ });
497
+ observers.set(featureType, { observer, unsubscribe });
483
498
  return observer;
484
499
  };
500
+ const destroyObserver = (featureType) => {
501
+ const record = observers.get(featureType);
502
+ if (!record) return;
503
+ record.unsubscribe();
504
+ observers.delete(featureType);
505
+ };
485
506
  const destroyObservers = () => {
486
- observers.forEach((o) => o.destroy());
507
+ observers.forEach(({ observer, unsubscribe }) => {
508
+ unsubscribe();
509
+ observer.destroy();
510
+ });
487
511
  observers.clear();
488
512
  };
489
513
  const createFilterByTypeQueryOptions = (featureType, params = {}, options2 = {}) => ({
@@ -523,6 +547,7 @@ var getDataClient = (options) => {
523
547
  projectId,
524
548
  queryClient,
525
549
  registerObserver,
550
+ destroyObserver,
526
551
  destroyObservers,
527
552
  createFilterByTypeQueryOptions,
528
553
  createFindByIdQueryOptions,
@@ -3158,50 +3183,16 @@ var createHighlighExtrudeObjectController = (obj, { color }) => {
3158
3183
  };
3159
3184
 
3160
3185
  // src/IndoorMap/camera/CameraManager.ts
3186
+ var ZOOM_OUT_LEVEL = 21;
3187
+ var ZOOM_IN_LEVEL = 24;
3161
3188
  var CameraManager = class {
3162
3189
  map;
3163
- // Use for various animation view
3164
- #defaultCenter;
3165
- #defaultZoom;
3166
- #defaultBearing = 0;
3167
- #defaultPitch = 45;
3168
- // Store current map zoomlevel
3169
- constructor(map, { defaultCenter, defaultZoom }) {
3190
+ constructor(map, options) {
3170
3191
  this.map = map;
3171
- this.#defaultCenter = defaultCenter;
3172
- if (defaultZoom) {
3173
- this.#defaultZoom = defaultZoom;
3174
- this.map.setZoom(defaultZoom);
3192
+ if (options?.defaultView) {
3193
+ this.setView(options?.defaultView);
3175
3194
  }
3176
3195
  }
3177
- set defaultBearing(value) {
3178
- this.#defaultBearing = value;
3179
- }
3180
- set defaultPitch(value) {
3181
- this.#defaultPitch = value;
3182
- }
3183
- set defaultCenter(value) {
3184
- this.#defaultCenter = value;
3185
- }
3186
- set defaultZoom(value) {
3187
- this.#defaultZoom = value;
3188
- }
3189
- get defaultCenter() {
3190
- return this.#defaultCenter;
3191
- }
3192
- get defaultZoom() {
3193
- return this.#defaultZoom;
3194
- }
3195
- get defaultBearing() {
3196
- return this.#defaultBearing;
3197
- }
3198
- get defaultPitch() {
3199
- return this.#defaultPitch;
3200
- }
3201
- getBearing = () => this.map.getBearing();
3202
- getPitch = () => this.map.getPitch();
3203
- getZoom = () => this.map.getZoom();
3204
- setBearing = (bearing) => this.map.setBearing(bearing);
3205
3196
  /** Private method */
3206
3197
  #animateflyTo(viewOptions = {}, options = {}, callbackOption = () => {
3207
3198
  }) {
@@ -3219,13 +3210,23 @@ var CameraManager = class {
3219
3210
  });
3220
3211
  }
3221
3212
  /** Public methods */
3213
+ getView = () => {
3214
+ return this.map.getView();
3215
+ };
3216
+ getZoom = () => {
3217
+ return this.map.getView().zoom;
3218
+ };
3219
+ setView = (value) => {
3220
+ this.map.setView(value);
3221
+ };
3222
3222
  flyTo = (center2, options = {}) => {
3223
+ const currentView = this.getView();
3223
3224
  const {
3224
- zoom = this.#defaultZoom,
3225
+ zoom = ZOOM_OUT_LEVEL,
3225
3226
  pitch = 60,
3226
3227
  duration = 600,
3227
3228
  easing = "out",
3228
- bearing = this.getBearing()
3229
+ bearing = currentView.bearing
3229
3230
  } = options;
3230
3231
  this.#animateflyTo(
3231
3232
  {
@@ -3239,7 +3240,7 @@ var CameraManager = class {
3239
3240
  };
3240
3241
  flyToAndZoomIn = (centerPoint, options = {}) => {
3241
3242
  const {
3242
- zoom = this.#defaultZoom + 3,
3243
+ zoom = ZOOM_IN_LEVEL,
3243
3244
  pitch = 60,
3244
3245
  duration = 600,
3245
3246
  easing = "out"
@@ -3419,7 +3420,7 @@ var DEFAULT_POLYGON_OPTION = {
3419
3420
  offset: 0,
3420
3421
  altitude: 0
3421
3422
  };
3422
- var HEIGHT_METER = 16;
3423
+ var HEIGHT_METER = 4;
3423
3424
  var getGeometryOption = (feature2, options) => {
3424
3425
  try {
3425
3426
  const option = options[feature2.feature_type];
@@ -3457,7 +3458,7 @@ var Element3DRenderer = class extends EventTarget {
3457
3458
  const hemi = new THREE2.HemisphereLight(16777215, 4473924, 0.4);
3458
3459
  scene.add(hemi);
3459
3460
  this.isReady = true;
3460
- _this.dispatchEvent(new CustomEvent("renderer:ready"));
3461
+ _this.dispatchEvent(new CustomEvent("threelayer:ready"));
3461
3462
  };
3462
3463
  this.lineMaterial = new THREE2.LineBasicMaterial({ color: "#000" });
3463
3464
  this.threeLayer.addTo(this.map);
@@ -3489,7 +3490,7 @@ var Element3DRenderer = class extends EventTarget {
3489
3490
  markerPath: [
3490
3491
  {
3491
3492
  path: "M21.75 0H0.25V21.5H8.35L11.3 24L14.2 21.5H21.75V0Z",
3492
- fill: "#044B7F"
3493
+ fill: "#ff0000"
3493
3494
  }
3494
3495
  ],
3495
3496
  markerPathWidth: 24,
@@ -3518,33 +3519,55 @@ var Element3DRenderer = class extends EventTarget {
3518
3519
  }
3519
3520
  createGeometry = (feature2) => {
3520
3521
  const options = getGeometryOption(feature2, this.options);
3521
- const offset = options.offset ?? 0;
3522
+ const offset = options?.offset ?? 0;
3523
+ const createPolygon = (geometry, feature3) => {
3524
+ const [outerRing, ...innerRings] = geometry.coordinates;
3525
+ const offsetFeature = offset !== 0 ? (0, import_buffer2.default)(geometry, offset, { units: "meters" }) : feature3;
3526
+ const color = options.color ?? feature3.properties.style.polygonFill ?? "#ffffff";
3527
+ if (color === "transparent") return;
3528
+ const material = this.getOrCreateMaterialByColor(color);
3529
+ const altitude = feature3.properties.ordinal * HEIGHT_METER;
3530
+ const bottomHeight = options.bottomHeight ?? 0;
3531
+ const polygon = this.threeLayer.toExtrudePolygon(
3532
+ offsetFeature,
3533
+ { asynchronous: true, ...options, altitude },
3534
+ material
3535
+ );
3536
+ const topLineStrings = [
3537
+ new maptalks5.LineString(outerRing),
3538
+ ...innerRings.map((innerRing) => new maptalks5.LineString(innerRing))
3539
+ ];
3540
+ const topLines = this.threeLayer.toLines(
3541
+ topLineStrings,
3542
+ { altitude: altitude + options.height + 1e-3, bottomHeight, interactive: false },
3543
+ this.lineMaterial
3544
+ );
3545
+ const bottomLineStrings = [
3546
+ new maptalks5.LineString(outerRing),
3547
+ ...innerRings.map((innerRing) => new maptalks5.LineString(innerRing))
3548
+ ];
3549
+ const bottomLines = this.threeLayer.toLines(
3550
+ bottomLineStrings,
3551
+ { altitude, bottomHeight, interactive: false },
3552
+ this.lineMaterial
3553
+ );
3554
+ return [polygon, topLines, bottomLines];
3555
+ };
3522
3556
  try {
3523
3557
  switch (feature2.geometry.type) {
3524
- case "Polygon": {
3525
- const offsetFeature = offset !== 0 ? (0, import_buffer2.default)(feature2.geometry, offset, { units: "meters" }) : feature2;
3526
- const color = options.color ?? feature2.properties.style.polygonFill ?? "#ffffff";
3527
- if (color === "transparent") return;
3528
- const material = this.getOrCreateMaterialByColor(color);
3529
- const altitude = feature2.properties.ordinal * HEIGHT_METER;
3530
- const polygon = this.threeLayer.toExtrudePolygon(
3531
- offsetFeature,
3532
- { asynchronous: true, ...options, altitude },
3533
- material
3534
- );
3535
- const lineString2 = new maptalks5.LineString(
3536
- feature2.geometry.coordinates[0]
3537
- );
3538
- const line = this.threeLayer.toLine(
3539
- lineString2,
3540
- { altitude: altitude + options.height + 1e-3, interactive: false },
3541
- this.lineMaterial
3542
- );
3543
- this.threeLayer.addMesh([polygon, line]);
3544
- return [polygon, line];
3545
- }
3546
3558
  case "MultiPolygon": {
3547
- throw new Error("Dost not support MultiPolygon");
3559
+ const { coordinates } = feature2.geometry;
3560
+ const multiMeshes = coordinates.flatMap((polygonCoordinates) => {
3561
+ const meshes = createPolygon({ type: "Polygon", coordinates: polygonCoordinates }, feature2);
3562
+ this.threeLayer.addMesh(meshes);
3563
+ return meshes;
3564
+ });
3565
+ return multiMeshes;
3566
+ }
3567
+ case "Polygon": {
3568
+ const meshes = createPolygon(feature2.geometry, feature2);
3569
+ this.threeLayer.addMesh(meshes);
3570
+ return meshes;
3548
3571
  }
3549
3572
  }
3550
3573
  } catch (err) {
@@ -3554,7 +3577,7 @@ var Element3DRenderer = class extends EventTarget {
3554
3577
  createMarker = (coordinates, ordinal, label) => {
3555
3578
  const options = {
3556
3579
  scale: 0.05,
3557
- altitude: ordinal * HEIGHT_METER + 4,
3580
+ altitude: ordinal * HEIGHT_METER,
3558
3581
  // highlight: highlightOptions,
3559
3582
  interactive: true
3560
3583
  };
@@ -3706,7 +3729,8 @@ var Element2DRenderer = class extends EventTarget {
3706
3729
  };
3707
3730
 
3708
3731
  // src/IndoorMap/renderer/RendererManager.ts
3709
- var RendererManager = class {
3732
+ var RendererManager = class extends EventTarget {
3733
+ map;
3710
3734
  options;
3711
3735
  // Client for fetching data
3712
3736
  #dataClient;
@@ -3715,6 +3739,8 @@ var RendererManager = class {
3715
3739
  elementsMap;
3716
3740
  elementsByOrdinal;
3717
3741
  constructor(map, options) {
3742
+ super();
3743
+ this.map = map;
3718
3744
  this.options = options;
3719
3745
  this.elementsMap = /* @__PURE__ */ new Map();
3720
3746
  this.elementsByOrdinal = /* @__PURE__ */ new Map();
@@ -3725,17 +3751,31 @@ var RendererManager = class {
3725
3751
  if (this.elementRenderer.isReady) {
3726
3752
  this.#createElements();
3727
3753
  } else {
3728
- this.elementRenderer.addEventListener("renderer:ready", (e) => {
3754
+ this.elementRenderer.addEventListener("threelayer:ready", (e) => {
3755
+ this.dispatchEvent(new CustomEvent("renderermanager:ready"));
3729
3756
  this.#createElements();
3730
3757
  });
3731
3758
  }
3732
3759
  }
3760
+ getElementsByOrdinal = (ordinal) => {
3761
+ const exist = this.elementsByOrdinal.get(ordinal);
3762
+ if (!exist) this.elementsByOrdinal.set(ordinal, []);
3763
+ return this.elementsByOrdinal.get(ordinal);
3764
+ };
3733
3765
  async #createElements() {
3734
3766
  const levels = await this.#dataClient.filterByType("level", {
3735
3767
  populate: true
3736
3768
  });
3737
- levels.forEach((level) => {
3738
- this.elementsByOrdinal.set(level.properties.ordinal, []);
3769
+ const fixtures = await this.#dataClient.filterByType("fixture", { populate: true });
3770
+ fixtures.forEach((fixture) => {
3771
+ const element = this.elementRenderer.createGeometry(fixture);
3772
+ if (element) {
3773
+ const _elements = Array.isArray(element) ? element : [element];
3774
+ _elements.forEach((el) => {
3775
+ this.elementsMap.set(fixture.id, el);
3776
+ this.getElementsByOrdinal(fixture.properties.level.properties.ordinal).push(el);
3777
+ });
3778
+ }
3739
3779
  });
3740
3780
  const units = await this.#dataClient.filterByType("unit", {
3741
3781
  populate: true
@@ -3748,7 +3788,7 @@ var RendererManager = class {
3748
3788
  const _elements = Array.isArray(element) ? element : [element];
3749
3789
  _elements.forEach((el) => {
3750
3790
  this.elementsMap.set(unit.id, el);
3751
- this.elementsByOrdinal.get(unit.properties.level.properties.ordinal).push(el);
3791
+ this.getElementsByOrdinal(unit.properties.level.properties.ordinal).push(el);
3752
3792
  });
3753
3793
  }
3754
3794
  });
@@ -3761,10 +3801,11 @@ var RendererManager = class {
3761
3801
  const _elements = Array.isArray(element) ? element : [element];
3762
3802
  _elements.forEach((el) => {
3763
3803
  this.elementsMap.set(kiosk.id, el);
3764
- this.elementsByOrdinal.get(kiosk.properties.level.properties.ordinal).push(el);
3804
+ this.getElementsByOrdinal(kiosk.properties.level.properties.ordinal).push(el);
3765
3805
  });
3766
3806
  }
3767
3807
  });
3808
+ this.dispatchEvent(new CustomEvent("renderermanager:elements_created"));
3768
3809
  }
3769
3810
  changeLevelByOrdinal(targetOrdinal) {
3770
3811
  for (const [ordinal, elements] of this.elementsByOrdinal) {
@@ -3783,19 +3824,19 @@ var RendererManager = class {
3783
3824
  createMarker(coordinate, ordinal, label) {
3784
3825
  const marker = this.elementRenderer.createMarker(coordinate, ordinal, label);
3785
3826
  this.elementsMap.set(label, marker);
3786
- this.elementsByOrdinal.get(ordinal).push(marker);
3827
+ this.getElementsByOrdinal(ordinal).push(marker);
3787
3828
  }
3788
3829
  };
3789
3830
 
3790
3831
  // src/IndoorMap/IndoorMap.ts
3832
+ var INITIAL_CENTER = [100.5017051, 13.7572619];
3833
+ var INITIAL_ZOOM = 18.5;
3834
+ var CLICK_TOLERANCE = 20;
3791
3835
  var defaultOptions = {
3792
- center: [100.5017051, 13.7572619],
3793
- defaultZoom: 18.5,
3794
3836
  pixelRatio: 1,
3795
3837
  locale: DEFAULT_LOCALE
3796
3838
  };
3797
- var CLICK_TOLERANCE = 20;
3798
- var IndoorMap = class {
3839
+ var IndoorMap = class extends EventTarget {
3799
3840
  //TODO: refac functions; let them do only 1 thing in a function
3800
3841
  /** Note: "#" means private variables */
3801
3842
  #styler = null;
@@ -3837,7 +3878,7 @@ var IndoorMap = class {
3837
3878
  #animationsToRun = [];
3838
3879
  map = null;
3839
3880
  #dataClient;
3840
- cameraManager;
3881
+ camera;
3841
3882
  rendererManager;
3842
3883
  showVenueObject = false;
3843
3884
  threeLayer = null;
@@ -3846,9 +3887,8 @@ var IndoorMap = class {
3846
3887
  onMapLoading = () => {
3847
3888
  };
3848
3889
  constructor(elementId, options) {
3890
+ super();
3849
3891
  const {
3850
- center: center2,
3851
- defaultZoom,
3852
3892
  onMapReady,
3853
3893
  onMapLoading,
3854
3894
  pixelRatio,
@@ -3856,13 +3896,13 @@ var IndoorMap = class {
3856
3896
  } = import_lodash6.default.merge({}, defaultOptions, options);
3857
3897
  this.map = new import_maptalks8.Map(elementId, {
3858
3898
  attribution: false,
3859
- center: center2,
3860
- zoom: defaultZoom,
3899
+ center: INITIAL_CENTER,
3900
+ zoom: INITIAL_ZOOM,
3861
3901
  clickTimeThreshold: 600,
3862
3902
  baseLayer: new import_maptalks8.TileLayer("base", {
3863
3903
  urlTemplate: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
3864
3904
  subdomains: ["a", "b", "c", "d"],
3865
- opacity: 0.6,
3905
+ opacity: 1,
3866
3906
  attribution: "",
3867
3907
  hitDetect: false,
3868
3908
  decodeImageInWorker: true,
@@ -3870,11 +3910,14 @@ var IndoorMap = class {
3870
3910
  }),
3871
3911
  layers: []
3872
3912
  });
3873
- this.cameraManager = new CameraManager(this.map, {
3874
- defaultCenter: center2,
3875
- defaultZoom
3876
- });
3877
3913
  this.rendererManager = new RendererManager(this.map, options.renderer);
3914
+ this.rendererManager.addEventListener("renderermanager:ready", (e) => {
3915
+ this.dispatchEvent(new CustomEvent("renderer:ready"));
3916
+ });
3917
+ this.rendererManager.addEventListener("renderermanager:elements_created", (e) => {
3918
+ this.dispatchEvent(new CustomEvent("renderer:elements_created"));
3919
+ });
3920
+ this.camera = new CameraManager(this.map);
3878
3921
  this.locale = locale;
3879
3922
  this.pixelRatio = pixelRatio;
3880
3923
  this.onMapReady = onMapReady;
@@ -3885,7 +3928,13 @@ var IndoorMap = class {
3885
3928
  }
3886
3929
  set dataClient(value) {
3887
3930
  this.#dataClient = value;
3888
- if (this.rendererManager) this.rendererManager.dataClient = this.#dataClient;
3931
+ this.#dataClient.filterByType("venue").then((venues) => {
3932
+ const venueCenters = (0, import_center3.default)(featureCollection(venues));
3933
+ const [x, y] = venueCenters.geometry.coordinates;
3934
+ const center2 = new import_maptalks8.Coordinate(x, y);
3935
+ this.camera.setView({ center: center2, pitch: 60, zoom: 19 });
3936
+ });
3937
+ this.rendererManager.dataClient = this.#dataClient;
3889
3938
  }
3890
3939
  /**
3891
3940
  * Events
@@ -3914,30 +3963,6 @@ var IndoorMap = class {
3914
3963
  /**
3915
3964
  * Getters & Setters
3916
3965
  */
3917
- set defaultBearing(value) {
3918
- this.cameraManager.defaultBearing = value;
3919
- }
3920
- set defaultPitch(value) {
3921
- this.cameraManager.defaultPitch = value;
3922
- }
3923
- set defaultCenter(value) {
3924
- this.cameraManager.defaultCenter = value;
3925
- }
3926
- set defaultZoom(value) {
3927
- this.cameraManager.defaultZoom = value;
3928
- }
3929
- get defaultBearing() {
3930
- return this.cameraManager.defaultBearing;
3931
- }
3932
- get defaultPitch() {
3933
- return this.cameraManager.defaultPitch;
3934
- }
3935
- get defaultCenter() {
3936
- return this.cameraManager.defaultCenter;
3937
- }
3938
- get defaultZoom() {
3939
- return this.cameraManager.defaultZoom;
3940
- }
3941
3966
  get elementsLoaded() {
3942
3967
  return this.#elementsLoaded;
3943
3968
  }
@@ -4369,7 +4394,7 @@ var IndoorMap = class {
4369
4394
  const {
4370
4395
  geometry: { coordinates }
4371
4396
  } = (0, import_center3.default)(feature2);
4372
- this.cameraManager.flyToAndZoomIn(coordinates, { pitch: 45 });
4397
+ this.camera.flyToAndZoomIn(coordinates, { pitch: 45 });
4373
4398
  });
4374
4399
  object3ds.push(object);
4375
4400
  this.#objects.push(object);
@@ -4520,7 +4545,7 @@ var IndoorMap = class {
4520
4545
  return result;
4521
4546
  };
4522
4547
  flyTo = (center2, options) => {
4523
- this.cameraManager.flyTo(center2, options);
4548
+ this.camera.flyTo(center2, options);
4524
4549
  };
4525
4550
  getLineStringBearing = (feature2) => {
4526
4551
  const { geometry } = feature2;
@@ -5072,7 +5097,7 @@ var IndoorMap = class {
5072
5097
  this.threeLayer.redraw();
5073
5098
  }
5074
5099
  if (this.threeLayer) {
5075
- const objectOpacity = import_lodash6.default.clamp(38 - 2 * this.cameraManager.getZoom(), 0, 1);
5100
+ const objectOpacity = import_lodash6.default.clamp(38 - 2 * this.camera.getZoom(), 0, 1);
5076
5101
  this.#objects.forEach((object) => {
5077
5102
  object.getObject3d().traverse((child) => {
5078
5103
  if (child.isMesh) child.material.opacity = objectOpacity;
@@ -5083,7 +5108,7 @@ var IndoorMap = class {
5083
5108
  if (this.#billboardObjects) {
5084
5109
  this.#billboardObjects.forEach((object) => {
5085
5110
  const objectScale = import_lodash6.default.clamp(
5086
- 20 - 1 * this.cameraManager.getZoom(),
5111
+ 20 - 1 * this.camera.getZoom(),
5087
5112
  1,
5088
5113
  1.05
5089
5114
  );