proximiio-js-library 1.5.1 → 1.6.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/README.md CHANGED
@@ -119,8 +119,19 @@ const map = new Proximiio.Map({
119
119
  initPolygons: false, // optional, default: false, if enabled and yours geojson includes required data the map will show defined features as polygons with hover/click effect
120
120
  considerVisibilityParam: false, // optional, default: true, if enabled all pois with visibility property defined as 'hidden' will not be visible as default, will be possible to toggle them with toggleHiddenPois() method
121
121
  fitBoundsPadding: 200, // optional, default 250, number | PaddingOptions, the amount of padding in pixels to add to the given bounds for found route, https://docs.mapbox.com/mapbox-gl-js/api/properties/#paddingoptions
122
+ minFitBoundsDistance: 50, // optional, default 15, number, the minimum route length in meters to zoom into it's bounds, if length is smaller regular center change will be used
122
123
  showLevelDirectionIcon: false // optional, default: false, if enabled arrow icon will be shown at the levelchanger indicating direction of level change along the found route,
123
- showRasterFloorplans: false // optional, default: false, if enabled raster floorplans will be visible
124
+ showRasterFloorplans: false // optional, default: false, if enabled raster floorplans will be visible,
125
+ animatedRoute: false // optional, default: false, EXPERIMENTAL, if enabled animated dot will be displayed along the route,
126
+ useRasterTiles: false, // optional, default: false, this will add raster tile source and layer with defined options from rasterTilesOptions
127
+ rasterTilesOptions: {
128
+ tilesUrl: string[], mandatory
129
+ tileSize: number, optional, default: 256,
130
+ minZoom: number, optional, default: 15,
131
+ maxZoom: number, optional, default: 22,
132
+ beforeLayer: string, optional, default: 'proximiio-shop',
133
+ attribution: string, optional
134
+ },
124
135
  });
125
136
  ```
126
137
  #### Required Data for 3D Polygons
@@ -289,6 +300,36 @@ map.getMapReadyListener().subscribe(ready => {
289
300
  });
290
301
  ```
291
302
 
303
+ ###### by coords
304
+ This method will generate route based on attached coords.
305
+ ```
306
+ // @param latTo {number} finish latitude coordinate
307
+ // @param lngTo {number} finish longitude coordinate
308
+ // @param levelTo {number} finish level
309
+ // @param latFrom {number} start latitude coordinate, optional for kiosk
310
+ // @param lngFrom {number} start longitude coordinate, optional for kiosk
311
+ // @param levelFrom {number} start level, optional for kiosk
312
+ // @param accessibleRoute {boolean} if true generated routed will be accessible without stairs, etc., optional
313
+
314
+ map.getMapReadyListener().subscribe(ready => {
315
+ console.log('map ready', ready);
316
+ map.findRouteByCoords(48.606703739771774, 17.833092384506614, 0, 48.60684545080579, 17.833450676669543, 0);
317
+ });
318
+ ```
319
+
320
+ ###### by nearest amenity feature
321
+ This method will generate route based on nearest amenity feature.
322
+ ```
323
+ // @param amenityId {string} amenity id of a nearest feature to look for
324
+ // @param idFrom {string} start feature id, optional for kiosk
325
+ // @param accessibleRoute {boolean} if true generated routed will be accessible without stairs, etc., optional
326
+
327
+ map.getMapReadyListener().subscribe(ready => {
328
+ console.log('map ready', ready);
329
+ map.findRouteToNearestFeature('amenityId');
330
+ });
331
+ ```
332
+
292
333
  ##### Cancel Route
293
334
  Use this method to cancel generated route.
294
335
  ```
@@ -18,6 +18,8 @@ exports.PolygonsLayer = new fill_extrusion_layer_1.default({
18
18
  '#6945ed',
19
19
  ['boolean', ['feature-state', 'hover'], false],
20
20
  '#a58dfa',
21
+ ['boolean', ['feature-state', 'active'], false],
22
+ '#ac94ff',
21
23
  ['boolean', ['feature-state', 'disabled'], false],
22
24
  '#8a8a8a',
23
25
  '#dbd7e8',
@@ -43,8 +43,19 @@ interface Options {
43
43
  zoomLevel?: number;
44
44
  considerVisibilityParam?: boolean;
45
45
  fitBoundsPadding?: number | PaddingOptions;
46
+ minFitBoundsDistance?: number;
46
47
  showLevelDirectionIcon?: boolean;
47
48
  showRasterFloorplans?: boolean;
49
+ animatedRoute?: boolean;
50
+ useRasterTiles?: boolean;
51
+ rasterTilesOptions?: {
52
+ tilesUrl: string[];
53
+ tileSize?: number;
54
+ minZoom?: number;
55
+ maxZoom?: number;
56
+ beforeLayer?: string;
57
+ attribution?: string;
58
+ };
48
59
  }
49
60
  interface PaddingOptions {
50
61
  bottom: number;
@@ -92,6 +103,8 @@ export declare class Map {
92
103
  private initKiosk;
93
104
  private onSetKiosk;
94
105
  private initDirectionIcon;
106
+ private initAnimatedRoute;
107
+ private initRasterTiles;
95
108
  private initPolygons;
96
109
  private onShopClick;
97
110
  handlePolygonSelection(poi?: Feature): void;
@@ -107,6 +120,8 @@ export declare class Map {
107
120
  private onRemoveAmenityFilter;
108
121
  private onResetAmenityFilters;
109
122
  private filterOutFeatures;
123
+ private activePolygonsAmenity;
124
+ private setActivePolygons;
110
125
  private handlePoiVisibility;
111
126
  private onToggleHiddenPois;
112
127
  private onSetPerson;
@@ -132,6 +147,14 @@ export declare class Map {
132
147
  private updateImages;
133
148
  private getUpcomingFloorNumber;
134
149
  private addDirectionFeatures;
150
+ private counter;
151
+ private arc;
152
+ private steps;
153
+ private animationInstances;
154
+ private addAnimatedRouteFeatures;
155
+ private animate;
156
+ private cancelAnimation;
157
+ private getClosestFeature;
135
158
  /**
136
159
  * @memberof Map
137
160
  * @name getMapboxInstance
@@ -281,6 +304,21 @@ export declare class Map {
281
304
  * });
282
305
  */
283
306
  findRouteByCoords(latTo: number, lngTo: number, levelTo: number, latFrom?: number, lngFrom?: number, levelFrom?: number, accessibleRoute?: boolean): void;
307
+ /**
308
+ * This method will generate route to nearest amenity feature
309
+ * @memberof Map
310
+ * @name findRouteToNearestFeature
311
+ * @param amenityId {string} amenity id of a nearest feature to look for
312
+ * @param idFrom {string} start feature id, optional for kiosk
313
+ * @param accessibleRoute {boolean} if true generated routed will be accessible without stairs, etc., optional
314
+ * @example
315
+ * const map = new Proximiio.Map();
316
+ * map.getMapReadyListener().subscribe(ready => {
317
+ * console.log('map ready', ready);
318
+ * map.findRouteToNearestFeature('amenityId');
319
+ * });
320
+ */
321
+ findRouteToNearestFeature(amenityId: string, idFrom?: string, accessibleRoute?: boolean): void;
284
322
  /**
285
323
  * This method will cancel generated route
286
324
  * @memberof Map
@@ -126,14 +126,26 @@ var Map = /** @class */ (function () {
126
126
  initPolygons: false,
127
127
  considerVisibilityParam: true,
128
128
  fitBoundsPadding: 250,
129
+ minFitBoundsDistance: 15,
129
130
  showLevelDirectionIcon: false,
130
131
  showRasterFloorplans: false,
132
+ animatedRoute: false,
133
+ useRasterTiles: false,
131
134
  };
132
135
  this.showStartPoint = false;
133
136
  this.amenityIds = [];
134
137
  this.filteredAmenities = [];
135
138
  this.amenityFilters = [];
136
139
  this.amenityCategories = {};
140
+ // Used to increment the value of the point measurement against the route.
141
+ this.counter = 0;
142
+ // store route part animation points
143
+ this.arc = {};
144
+ // Number of steps to use in the arc and animation, more steps means
145
+ // a smoother arc and animation, but too many steps will result in a
146
+ // low frame rate
147
+ this.steps = 300;
148
+ this.animationInstances = [];
137
149
  // fix centering in case of kiosk with defined pitch/bearing/etc. in mapbox options
138
150
  if (options.isKiosk && options.mapboxOptions && options.kioskSettings && !options.mapboxOptions.center) {
139
151
  options.mapboxOptions.center = options.kioskSettings.coordinates;
@@ -297,6 +309,12 @@ var Map = /** @class */ (function () {
297
309
  if (this.defaultOptions.showLevelDirectionIcon) {
298
310
  this.initDirectionIcon();
299
311
  }
312
+ if (this.defaultOptions.animatedRoute) {
313
+ this.initAnimatedRoute();
314
+ }
315
+ if (this.defaultOptions.useRasterTiles) {
316
+ this.initRasterTiles();
317
+ }
300
318
  this.initPersonsMap();
301
319
  this.map.on('click', 'proximiio-pois-icons', function (ev) {
302
320
  _this.onShopClick(ev);
@@ -386,6 +404,54 @@ var Map = /** @class */ (function () {
386
404
  this.map.setStyle(this.state.style);
387
405
  }
388
406
  };
407
+ Map.prototype.initAnimatedRoute = function () {
408
+ if (this.map) {
409
+ this.state.style.addSource('route-point', {
410
+ type: 'geojson',
411
+ data: {
412
+ type: 'FeatureCollection',
413
+ features: [],
414
+ },
415
+ });
416
+ this.state.style.addLayer({
417
+ id: 'route-point',
418
+ type: 'circle',
419
+ source: 'route-point',
420
+ minzoom: 17,
421
+ maxzoom: 24,
422
+ paint: {
423
+ 'circle-color': '#1d8a9f',
424
+ 'circle-radius': 10,
425
+ },
426
+ filter: ['all', ['==', ['to-number', ['get', 'level']], this.state.floor.level]],
427
+ });
428
+ this.map.setStyle(this.state.style);
429
+ }
430
+ };
431
+ Map.prototype.initRasterTiles = function () {
432
+ if (this.map) {
433
+ this.state.style.addSource('raster-tiles', {
434
+ type: 'raster',
435
+ tiles: this.defaultOptions.rasterTilesOptions.tilesUrl,
436
+ tileSize: this.defaultOptions.rasterTilesOptions.tileSize
437
+ ? this.defaultOptions.rasterTilesOptions.tileSize
438
+ : 256,
439
+ attribution: this.defaultOptions.rasterTilesOptions.attribution
440
+ ? this.defaultOptions.rasterTilesOptions.attribution
441
+ : '',
442
+ });
443
+ this.state.style.addLayer({
444
+ id: 'raster-tiles',
445
+ type: 'raster',
446
+ source: 'raster-tiles',
447
+ minzoom: this.defaultOptions.rasterTilesOptions.minZoom ? this.defaultOptions.rasterTilesOptions.minZoom : 15,
448
+ maxzoom: this.defaultOptions.rasterTilesOptions.maxZoom ? this.defaultOptions.rasterTilesOptions.maxZoom : 22,
449
+ }, this.defaultOptions.rasterTilesOptions.maxZoom
450
+ ? this.defaultOptions.rasterTilesOptions.beforeLayer
451
+ : 'proximiio-shop');
452
+ this.map.setStyle(this.state.style);
453
+ }
454
+ };
389
455
  Map.prototype.initPolygons = function () {
390
456
  var _this = this;
391
457
  if (this.map) {
@@ -444,19 +510,21 @@ var Map = /** @class */ (function () {
444
510
  }
445
511
  if (connectedPolygonId) {
446
512
  this.selectedPolygon = this.state.allFeatures.features.find(function (i) { return i.properties.id === connectedPolygonId; });
447
- this.map.setFeatureState({
448
- source: 'main',
449
- id: this.selectedPolygon.id,
450
- }, {
451
- selected: true,
452
- });
453
- if (this.selectedPolygon.properties.label_id) {
513
+ if (this.selectedPolygon) {
454
514
  this.map.setFeatureState({
455
515
  source: 'main',
456
- id: this.selectedPolygon.properties.label_id,
516
+ id: this.selectedPolygon.id,
457
517
  }, {
458
518
  selected: true,
459
519
  });
520
+ if (this.selectedPolygon.properties.label_id) {
521
+ this.map.setFeatureState({
522
+ source: 'main',
523
+ id: this.selectedPolygon.properties.label_id,
524
+ }, {
525
+ selected: true,
526
+ });
527
+ }
460
528
  }
461
529
  }
462
530
  };
@@ -738,6 +806,7 @@ var Map = /** @class */ (function () {
738
806
  }
739
807
  this.filteredAmenities = this.amenityFilters;
740
808
  this.filterOutFeatures();
809
+ this.setActivePolygons(amenityId);
741
810
  };
742
811
  Map.prototype.onRemoveAmenityFilter = function (amenityId, category) {
743
812
  if (category &&
@@ -752,6 +821,7 @@ var Map = /** @class */ (function () {
752
821
  }
753
822
  this.filteredAmenities = this.amenityFilters.length > 0 ? this.amenityFilters : this.amenityIds;
754
823
  this.filterOutFeatures();
824
+ this.setActivePolygons(null);
755
825
  };
756
826
  Map.prototype.onResetAmenityFilters = function () {
757
827
  this.amenityFilters = [];
@@ -762,6 +832,7 @@ var Map = /** @class */ (function () {
762
832
  }
763
833
  this.filteredAmenities = this.amenityIds;
764
834
  this.filterOutFeatures();
835
+ this.setActivePolygons(null);
765
836
  };
766
837
  Map.prototype.filterOutFeatures = function () {
767
838
  var _this = this;
@@ -801,6 +872,59 @@ var Map = /** @class */ (function () {
801
872
  });
802
873
  this.state.style.notify('filter-change');
803
874
  };
875
+ Map.prototype.setActivePolygons = function (amenityId) {
876
+ var _this = this;
877
+ if (this.defaultOptions.initPolygons) {
878
+ var activeFeatures = this.activePolygonsAmenity
879
+ ? this.state.allFeatures.features.filter(function (f) {
880
+ var _a;
881
+ return f.properties.amenity === _this.activePolygonsAmenity &&
882
+ ((_a = f.properties.metadata) === null || _a === void 0 ? void 0 : _a.polygon_id) &&
883
+ f.geometry.type === 'Point';
884
+ })
885
+ : [];
886
+ var amenityFeatures = amenityId
887
+ ? this.state.allFeatures.features.filter(function (f) { var _a; return f.properties.amenity === amenityId && ((_a = f.properties.metadata) === null || _a === void 0 ? void 0 : _a.polygon_id) && f.geometry.type === 'Point'; })
888
+ : [];
889
+ if (activeFeatures.length > 0) {
890
+ var _loop_2 = function (f) {
891
+ var polygon = this_2.state.allFeatures.features.find(function (i) { return i.properties.id === f.properties.metadata.polygon_id; });
892
+ if (polygon) {
893
+ this_2.map.setFeatureState({
894
+ source: 'main',
895
+ id: polygon.id,
896
+ }, {
897
+ active: false,
898
+ });
899
+ }
900
+ };
901
+ var this_2 = this;
902
+ for (var _i = 0, activeFeatures_1 = activeFeatures; _i < activeFeatures_1.length; _i++) {
903
+ var f = activeFeatures_1[_i];
904
+ _loop_2(f);
905
+ }
906
+ }
907
+ if (amenityFeatures.length > 0) {
908
+ var _loop_3 = function (f) {
909
+ var polygon = this_3.state.allFeatures.features.find(function (i) { return i.properties.id === f.properties.metadata.polygon_id; });
910
+ if (polygon) {
911
+ this_3.map.setFeatureState({
912
+ source: 'main',
913
+ id: polygon.id,
914
+ }, {
915
+ active: true,
916
+ });
917
+ }
918
+ };
919
+ var this_3 = this;
920
+ for (var _a = 0, amenityFeatures_1 = amenityFeatures; _a < amenityFeatures_1.length; _a++) {
921
+ var f = amenityFeatures_1[_a];
922
+ _loop_3(f);
923
+ }
924
+ }
925
+ }
926
+ this.activePolygonsAmenity = amenityId;
927
+ };
804
928
  Map.prototype.handlePoiVisibility = function () {
805
929
  var _this = this;
806
930
  // proximiio-pois-icons, proximiio-pois-labels, 'pois-icons', 'pois-labels'
@@ -910,11 +1034,14 @@ var Map = /** @class */ (function () {
910
1034
  if (this.routingSource.route) {
911
1035
  var routeStart = this.routingSource.lines[0];
912
1036
  var textNavigation = this.routeFactory.generateRoute(JSON.stringify(this.routingSource.points), JSON.stringify(this.endPoint));
913
- this.centerOnRoute(routeStart);
1037
+ this.state = __assign(__assign({}, this.state), { loadingRoute: false, textNavigation: textNavigation });
914
1038
  if (this.defaultOptions.showLevelDirectionIcon) {
915
1039
  this.addDirectionFeatures();
916
1040
  }
917
- this.state = __assign(__assign({}, this.state), { loadingRoute: false, textNavigation: textNavigation });
1041
+ if (this.defaultOptions.animatedRoute) {
1042
+ this.addAnimatedRouteFeatures();
1043
+ }
1044
+ this.centerOnRoute(routeStart);
918
1045
  this.onRouteFoundListener.next({
919
1046
  route: this.routingSource.route,
920
1047
  TBTNav: this.defaultOptions.enableTBTNavigation ? textNavigation : null,
@@ -1097,13 +1224,20 @@ var Map = /** @class */ (function () {
1097
1224
  });
1098
1225
  if (route) {
1099
1226
  var routePoints = helpers_1.lineString(this.routingSource.levelPoints[floor.level].map(function (i) { return i.geometry.coordinates; }));
1227
+ var lengthInMeters = turf.length(routePoints, { units: 'kilometers' }) * 1000;
1100
1228
  var bbox = turf.bbox(routePoints);
1101
- // @ts-ignore;
1102
- map.fitBounds(bbox, {
1103
- padding: this.defaultOptions.fitBoundsPadding,
1104
- bearing: this.map.getBearing(),
1105
- pitch: this.map.getPitch(),
1106
- });
1229
+ if (lengthInMeters >= this.defaultOptions.minFitBoundsDistance) {
1230
+ // @ts-ignore;
1231
+ map.fitBounds(bbox, {
1232
+ padding: this.defaultOptions.fitBoundsPadding,
1233
+ bearing: this.map.getBearing(),
1234
+ pitch: this.map.getPitch(),
1235
+ });
1236
+ }
1237
+ else {
1238
+ // @ts-ignore
1239
+ this.map.flyTo({ center: turf.center(routePoints).geometry.coordinates });
1240
+ }
1107
1241
  }
1108
1242
  if (this.defaultOptions.isKiosk && map.getLayer('my-location-layer')) {
1109
1243
  var filter = ['all', ['==', ['to-number', ['get', 'level']], floor.level]];
@@ -1120,6 +1254,11 @@ var Map = /** @class */ (function () {
1120
1254
  map.setFilter('direction-icon-layer', filter);
1121
1255
  this.state.style.getLayer('direction-icon-layer').filter = filter;
1122
1256
  }
1257
+ if (this.defaultOptions.animatedRoute && map.getLayer('route-point')) {
1258
+ var filter = ['all', ['==', ['to-number', ['get', 'level']], floor.level]];
1259
+ map.setFilter('route-point', filter);
1260
+ this.state.style.getLayer('route-point').filter = filter;
1261
+ }
1123
1262
  }
1124
1263
  this.state = __assign(__assign({}, this.state), { floor: floor, style: this.state.style });
1125
1264
  this.updateCluster();
@@ -1132,6 +1271,9 @@ var Map = /** @class */ (function () {
1132
1271
  if (finish && this.defaultOptions.initPolygons) {
1133
1272
  this.handlePolygonSelection(finish);
1134
1273
  }
1274
+ if (finish && this.defaultOptions.animatedRoute) {
1275
+ this.cancelAnimation();
1276
+ }
1135
1277
  this.routingSource.update(start, finish);
1136
1278
  }
1137
1279
  catch (e) {
@@ -1144,6 +1286,20 @@ var Map = /** @class */ (function () {
1144
1286
  if (this.defaultOptions.initPolygons) {
1145
1287
  this.handlePolygonSelection();
1146
1288
  }
1289
+ if (this.defaultOptions.showLevelDirectionIcon) {
1290
+ this.state.style.sources['direction-icon-source'].data = {
1291
+ type: 'FeatureCollection',
1292
+ features: [],
1293
+ };
1294
+ }
1295
+ if (this.defaultOptions.animatedRoute) {
1296
+ this.state.style.sources['route-point'].data = {
1297
+ type: 'FeatureCollection',
1298
+ features: [],
1299
+ };
1300
+ this.cancelAnimation();
1301
+ }
1302
+ this.map.setStyle(this.state.style);
1147
1303
  this.routingSource.cancel();
1148
1304
  this.onRouteCancelListener.next('route cancelled');
1149
1305
  };
@@ -1166,13 +1322,20 @@ var Map = /** @class */ (function () {
1166
1322
  }
1167
1323
  if (this.map) {
1168
1324
  var routePoints = helpers_1.lineString(this.routingSource.levelPoints[this.state.floor.level].map(function (i) { return i.geometry.coordinates; }));
1325
+ var lengthInMeters = turf.length(routePoints, { units: 'kilometers' }) * 1000;
1169
1326
  var bbox = turf.bbox(routePoints);
1170
- // @ts-ignore
1171
- this.map.fitBounds(bbox, {
1172
- padding: this.defaultOptions.fitBoundsPadding,
1173
- bearing: this.map.getBearing(),
1174
- pitch: this.map.getPitch(),
1175
- });
1327
+ if (lengthInMeters >= this.defaultOptions.minFitBoundsDistance) {
1328
+ // @ts-ignore;
1329
+ this.map.fitBounds(bbox, {
1330
+ padding: this.defaultOptions.fitBoundsPadding,
1331
+ bearing: this.map.getBearing(),
1332
+ pitch: this.map.getPitch(),
1333
+ });
1334
+ }
1335
+ else {
1336
+ // @ts-ignore
1337
+ this.map.flyTo({ center: turf.center(routePoints).geometry.coordinates });
1338
+ }
1176
1339
  }
1177
1340
  }
1178
1341
  };
@@ -1235,6 +1398,80 @@ var Map = /** @class */ (function () {
1235
1398
  };
1236
1399
  this.map.setStyle(this.state.style);
1237
1400
  };
1401
+ Map.prototype.addAnimatedRouteFeatures = function () {
1402
+ this.counter = 0;
1403
+ this.arc = {};
1404
+ var pointsArray = [];
1405
+ for (var _i = 0, _a = this.routingSource.lines; _i < _a.length; _i++) {
1406
+ var routePart = _a[_i];
1407
+ // Calculate the distance in kilometers between route start/end point.
1408
+ var lineDistance = turf.length(routePart);
1409
+ this.arc[routePart.id] = [];
1410
+ // Draw an arc between the `origin` & `destination` of the two points
1411
+ for (var i = 0; i < lineDistance; i += lineDistance / this.steps) {
1412
+ var segment = turf.along(turf.lineString(routePart.geometry.coordinates), i);
1413
+ this.arc[routePart.id].push(segment.geometry.coordinates);
1414
+ }
1415
+ var point = turf.point(routePart.geometry.coordinates[0], __assign(__assign({}, routePart.properties), { routePartId: routePart.id }));
1416
+ pointsArray.push(point);
1417
+ }
1418
+ this.state.style.sources['route-point'].data = turf.featureCollection(pointsArray);
1419
+ this.map.setStyle(this.state.style);
1420
+ this.animate();
1421
+ };
1422
+ Map.prototype.animate = function () {
1423
+ var _this = this;
1424
+ if (Object.keys(this.arc).length > 0) {
1425
+ var pointsArray = [];
1426
+ for (var _i = 0, _a = Object.entries(this.arc); _i < _a.length; _i++) {
1427
+ var _b = _a[_i], routeKey = _b[0], routePositions = _b[1];
1428
+ if (routePositions[this.counter]) {
1429
+ var point = turf.point(routePositions[this.counter], __assign(__assign({}, this.routingSource.route[routeKey].properties), { routePartId: routeKey }));
1430
+ pointsArray.push(point);
1431
+ }
1432
+ }
1433
+ // Update the source with this new data
1434
+ this.state.style.sources['route-point'].data = turf.featureCollection(pointsArray);
1435
+ this.map.setStyle(this.state.style);
1436
+ // Request the next frame of animation as long as the end has not been reached
1437
+ if (this.counter < this.steps) {
1438
+ var animationInstance = window.requestAnimationFrame(this.animate.bind(this));
1439
+ this.animationInstances.push(animationInstance);
1440
+ }
1441
+ if (this.counter === this.steps) {
1442
+ setTimeout(function () {
1443
+ // Reset the counter
1444
+ _this.counter = 0;
1445
+ // cancel animation
1446
+ // this.cancelAnimation();
1447
+ // Restart the animation
1448
+ _this.animate();
1449
+ }, 2000);
1450
+ }
1451
+ this.counter++;
1452
+ }
1453
+ };
1454
+ Map.prototype.cancelAnimation = function () {
1455
+ for (var _i = 0, _a = this.animationInstances; _i < _a.length; _i++) {
1456
+ var instance = _a[_i];
1457
+ window.cancelAnimationFrame(instance);
1458
+ }
1459
+ };
1460
+ Map.prototype.getClosestFeature = function (amenityId, fromFeature) {
1461
+ var sameLevelfeatures = this.state.allFeatures.features.filter(function (i) {
1462
+ return i.properties.amenity === amenityId &&
1463
+ i.geometry.type === 'Point' &&
1464
+ i.properties.level === fromFeature.properties.level;
1465
+ });
1466
+ var features = this.state.allFeatures.features.filter(function (i) { return i.properties.amenity === amenityId && i.geometry.type === 'Point'; });
1467
+ var targetPoint = turf.point(fromFeature.geometry.coordinates);
1468
+ if (sameLevelfeatures.length > 0 || features.length > 0) {
1469
+ return turf.nearestPoint(targetPoint, turf.featureCollection(sameLevelfeatures.length > 0 ? sameLevelfeatures : features));
1470
+ }
1471
+ else {
1472
+ return false;
1473
+ }
1474
+ };
1238
1475
  /**
1239
1476
  * @memberof Map
1240
1477
  * @name getMapboxInstance
@@ -1458,6 +1695,33 @@ var Map = /** @class */ (function () {
1458
1695
  this.routingSource.toggleAccessible(accessibleRoute);
1459
1696
  this.onRouteUpdate(this.defaultOptions.isKiosk ? this.startPoint : fromFeature, toFeature);
1460
1697
  };
1698
+ /**
1699
+ * This method will generate route to nearest amenity feature
1700
+ * @memberof Map
1701
+ * @name findRouteToNearestFeature
1702
+ * @param amenityId {string} amenity id of a nearest feature to look for
1703
+ * @param idFrom {string} start feature id, optional for kiosk
1704
+ * @param accessibleRoute {boolean} if true generated routed will be accessible without stairs, etc., optional
1705
+ * @example
1706
+ * const map = new Proximiio.Map();
1707
+ * map.getMapReadyListener().subscribe(ready => {
1708
+ * console.log('map ready', ready);
1709
+ * map.findRouteToNearestFeature('amenityId');
1710
+ * });
1711
+ */
1712
+ Map.prototype.findRouteToNearestFeature = function (amenityId, idFrom, accessibleRoute) {
1713
+ var fromFeature = this.defaultOptions.isKiosk
1714
+ ? this.startPoint
1715
+ : this.state.allFeatures.features.find(function (f) { return f.id === idFrom || f.properties.id === idFrom; });
1716
+ var toFeature = this.getClosestFeature(amenityId, fromFeature);
1717
+ if (toFeature) {
1718
+ this.routingSource.toggleAccessible(accessibleRoute);
1719
+ this.onRouteUpdate(this.defaultOptions.isKiosk ? this.startPoint : fromFeature, toFeature);
1720
+ }
1721
+ else {
1722
+ throw new Error("Feature not found");
1723
+ }
1724
+ };
1461
1725
  /**
1462
1726
  * This method will cancel generated route
1463
1727
  * @memberof Map