proximiio-js-library 1.17.5 → 1.17.6
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 +9 -0
- package/lib/components/map/main.d.ts +2 -0
- package/lib/components/map/main.js +6 -1
- package/lib/components/map/routing.d.ts +14 -1
- package/lib/components/map/routing.js +38 -3
- package/lib/components/map/sources/routing_source.d.ts +2 -1
- package/lib/components/map/sources/routing_source.js +7 -0
- package/lib/components/map/workingHours.d.ts +37 -0
- package/lib/components/map/workingHours.js +76 -0
- package/lib/proximiio.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -446,6 +446,15 @@ const map = new Proximiio.Map({
|
|
|
446
446
|
// If set to true only features inside defined time range in metadata.dateStart and metadata.dateEnd will be shown
|
|
447
447
|
useTimerangeData: false,
|
|
448
448
|
|
|
449
|
+
// If set to true, routing will avoid paths that are closed according to their working hours
|
|
450
|
+
// (properties._workingHoursEnabled + properties.workingHours), evaluated against the device's local time.
|
|
451
|
+
// Paths marked properties.available: false are always avoided, regardless of this option.
|
|
452
|
+
useWorkingHours: false,
|
|
453
|
+
|
|
454
|
+
// If set to true (together with useWorkingHours), routing to a destination POI that is currently
|
|
455
|
+
// closed according to its working hours will be refused instead of computed
|
|
456
|
+
excludeClosedPois: false,
|
|
457
|
+
|
|
449
458
|
// If enabled we automatically send analytics from routing to our API, default: true
|
|
450
459
|
sendAnalytics: true,
|
|
451
460
|
|
|
@@ -205,6 +205,8 @@ export interface Options {
|
|
|
205
205
|
blockFeatureClickWhileRouting?: boolean;
|
|
206
206
|
hiddenAmenities?: string[];
|
|
207
207
|
useTimerangeData?: boolean;
|
|
208
|
+
useWorkingHours?: boolean;
|
|
209
|
+
excludeClosedPois?: boolean;
|
|
208
210
|
sendAnalytics?: boolean;
|
|
209
211
|
defaultFilter?: {
|
|
210
212
|
key: string;
|
|
@@ -250,6 +250,8 @@ export class Map {
|
|
|
250
250
|
routeWithDetails: true,
|
|
251
251
|
blockFeatureClickWhileRouting: false,
|
|
252
252
|
useTimerangeData: false,
|
|
253
|
+
useWorkingHours: false,
|
|
254
|
+
excludeClosedPois: false,
|
|
253
255
|
sendAnalytics: true,
|
|
254
256
|
autoLevelChange: false,
|
|
255
257
|
autoRestartAnimationAfterFloorChange: false,
|
|
@@ -772,7 +774,10 @@ export class Map {
|
|
|
772
774
|
this.routingSource.setLevelChangers(levelChangers);
|
|
773
775
|
this.routingSource.setFloors(this.state.floors);
|
|
774
776
|
this.geojsonSource.fetch(optimizedFeatures);
|
|
775
|
-
this.routingSource.routing.setData(features.originalFeatures
|
|
777
|
+
this.routingSource.routing.setData(features.originalFeatures, {
|
|
778
|
+
useWorkingHours: this.defaultOptions.useWorkingHours,
|
|
779
|
+
excludeClosedPois: this.defaultOptions.excludeClosedPois,
|
|
780
|
+
});
|
|
776
781
|
this.prepareStyle(this.state.style);
|
|
777
782
|
this.state = Object.assign(Object.assign({}, this.state), { initializing: false, kiosks: (_a = kiosks === null || kiosks === void 0 ? void 0 : kiosks.data) !== null && _a !== void 0 ? _a : [], amenities, features: features.modifiedFeatures, ads: (_b = ads === null || ads === void 0 ? void 0 : ads.data) !== null && _b !== void 0 ? _b : [], optimizedFeatures, allFeatures: new FeatureCollection(features.modifiedFeatures), levelChangers: new FeatureCollection({ features: levelChangers }), zoom: this.defaultOptions.zoomLevel ? this.defaultOptions.zoomLevel : (_c = this.defaultOptions.mapboxOptions) === null || _c === void 0 ? void 0 : _c.zoom });
|
|
778
783
|
this.onDataFetchedListener.next(true);
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import Feature from '../../models/feature';
|
|
2
2
|
import { FeatureCollection } from '@turf/helpers';
|
|
3
3
|
import { WayfindingConfigModel } from '../../models/wayfinding';
|
|
4
|
+
export interface RoutingWorkingHoursOptions {
|
|
5
|
+
useWorkingHours?: boolean;
|
|
6
|
+
excludeClosedPois?: boolean;
|
|
7
|
+
/** Override "now" for previewing a route at a different time. Defaults to the device's current time. */
|
|
8
|
+
datetime?: Date;
|
|
9
|
+
}
|
|
4
10
|
export default class Routing {
|
|
5
11
|
data: FeatureCollection;
|
|
12
|
+
rawData: FeatureCollection;
|
|
6
13
|
wayfinding: any;
|
|
7
14
|
forceFloorLevel: number;
|
|
8
15
|
routeWithDetails: boolean;
|
|
9
16
|
config: WayfindingConfigModel;
|
|
17
|
+
workingHoursOptions: RoutingWorkingHoursOptions;
|
|
10
18
|
constructor();
|
|
11
|
-
|
|
19
|
+
private filterRoutableFeatures;
|
|
20
|
+
setData(collection: FeatureCollection, options?: RoutingWorkingHoursOptions): void;
|
|
21
|
+
setWorkingHoursOptions(options: RoutingWorkingHoursOptions): void;
|
|
12
22
|
toggleOnlyAccessible(onlyAccessible: any): void;
|
|
13
23
|
setConfig(config: WayfindingConfigModel): void;
|
|
14
24
|
route({ start, finish, stops, stepsNavigation, priorityEntrance, }: {
|
|
@@ -18,6 +28,9 @@ export default class Routing {
|
|
|
18
28
|
stepsNavigation?: 'disabled' | 'simple' | 'simple-levelChangers' | 'full' | 'full-levelChangers' | 'landmark' | 'landmark-levelChangers';
|
|
19
29
|
priorityEntrance?: Feature;
|
|
20
30
|
}): {
|
|
31
|
+
destinationOpen: boolean;
|
|
32
|
+
} | {
|
|
33
|
+
destinationOpen: boolean;
|
|
21
34
|
paths: any;
|
|
22
35
|
points: any;
|
|
23
36
|
route: {};
|
|
@@ -12,14 +12,33 @@ import { Wayfinding } from '../../../lib/assets/wayfinding';
|
|
|
12
12
|
import Feature from '../../models/feature';
|
|
13
13
|
import { lineString, point } from '@turf/helpers';
|
|
14
14
|
import osrmTextInstructionsPackage from 'osrm-text-instructions';
|
|
15
|
+
import { isOpenAt, nowClientTime } from './workingHours';
|
|
15
16
|
const version = 'v5';
|
|
16
17
|
const osrmTextInstructions = osrmTextInstructionsPackage(version);
|
|
17
18
|
export default class Routing {
|
|
18
19
|
constructor() {
|
|
20
|
+
this.workingHoursOptions = {};
|
|
19
21
|
this.data = {};
|
|
20
22
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
filterRoutableFeatures(collection) {
|
|
24
|
+
const time = nowClientTime(this.workingHoursOptions.datetime);
|
|
25
|
+
const features = (collection.features || []).filter((f) => {
|
|
26
|
+
var _a;
|
|
27
|
+
if (((_a = f.properties) === null || _a === void 0 ? void 0 : _a.class) !== 'path')
|
|
28
|
+
return true;
|
|
29
|
+
// Unavailable paths are always avoided, independently of any option.
|
|
30
|
+
if (f.properties.available === false)
|
|
31
|
+
return false;
|
|
32
|
+
if (this.workingHoursOptions.useWorkingHours && !isOpenAt(f.properties, time))
|
|
33
|
+
return false;
|
|
34
|
+
return true;
|
|
35
|
+
});
|
|
36
|
+
return Object.assign(Object.assign({}, collection), { features });
|
|
37
|
+
}
|
|
38
|
+
setData(collection, options) {
|
|
39
|
+
this.rawData = collection;
|
|
40
|
+
this.workingHoursOptions = Object.assign(Object.assign({}, this.workingHoursOptions), options);
|
|
41
|
+
this.data = this.filterRoutableFeatures(this.rawData);
|
|
23
42
|
this.wayfinding = new Wayfinding(this.data);
|
|
24
43
|
this.wayfinding.preprocess();
|
|
25
44
|
// pathfinding.load(neighbourList, wallOffsets);
|
|
@@ -29,6 +48,14 @@ export default class Routing {
|
|
|
29
48
|
// avoidRevolvingDoors: true
|
|
30
49
|
// });
|
|
31
50
|
}
|
|
51
|
+
setWorkingHoursOptions(options) {
|
|
52
|
+
this.workingHoursOptions = Object.assign(Object.assign({}, this.workingHoursOptions), options);
|
|
53
|
+
if (this.rawData) {
|
|
54
|
+
this.data = this.filterRoutableFeatures(this.rawData);
|
|
55
|
+
this.wayfinding = new Wayfinding(this.data);
|
|
56
|
+
this.wayfinding.preprocess();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
32
59
|
toggleOnlyAccessible(onlyAccessible) {
|
|
33
60
|
if (onlyAccessible) {
|
|
34
61
|
this.wayfinding.setConfiguration({
|
|
@@ -62,6 +89,11 @@ export default class Routing {
|
|
|
62
89
|
this.wayfinding.setConfiguration(config);
|
|
63
90
|
}
|
|
64
91
|
route({ start, finish, stops, stepsNavigation = 'full', priorityEntrance, }) {
|
|
92
|
+
const time = nowClientTime(this.workingHoursOptions.datetime);
|
|
93
|
+
const destinationOpen = this.workingHoursOptions.useWorkingHours && finish ? isOpenAt(finish.properties, time) : undefined;
|
|
94
|
+
if (destinationOpen === false && this.workingHoursOptions.excludeClosedPois) {
|
|
95
|
+
return { destinationOpen: false };
|
|
96
|
+
}
|
|
65
97
|
const isMultipoint = stops && stops.length > 1;
|
|
66
98
|
let points = null;
|
|
67
99
|
let details = null;
|
|
@@ -397,7 +429,10 @@ export default class Routing {
|
|
|
397
429
|
}
|
|
398
430
|
levelPoints[point.properties.level].push(point);
|
|
399
431
|
});
|
|
400
|
-
return { paths,
|
|
432
|
+
return Object.assign({ paths,
|
|
433
|
+
points, route: {}, fullPath: {}, levelPaths,
|
|
434
|
+
levelPoints,
|
|
435
|
+
details }, (destinationOpen !== undefined && { destinationOpen }));
|
|
401
436
|
}
|
|
402
437
|
cityRoute({ start, finish, language = 'en' }) {
|
|
403
438
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import DataSource from './data_source';
|
|
2
2
|
import Feature from '../../../models/feature';
|
|
3
|
-
import Routing from '../routing';
|
|
3
|
+
import Routing, { RoutingWorkingHoursOptions } from '../routing';
|
|
4
4
|
import { GuidanceStep, WayfindingConfigModel } from '../../../models/wayfinding';
|
|
5
5
|
import { FloorModel } from '../../../models/floor';
|
|
6
6
|
interface ChangeContainer {
|
|
@@ -45,6 +45,7 @@ export default class RoutingSource extends DataSource {
|
|
|
45
45
|
constructor();
|
|
46
46
|
toggleAccessible(value: any): void;
|
|
47
47
|
setConfig(config: WayfindingConfigModel): void;
|
|
48
|
+
setWorkingHoursOptions(options: RoutingWorkingHoursOptions): void;
|
|
48
49
|
setNavigationType(type: 'mall' | 'city' | 'combined'): void;
|
|
49
50
|
setStepsNavigation(value: 'disabled' | 'simple' | 'simple-levelChangers' | 'full' | 'full-levelChangers' | 'landmark' | 'landmark-levelChangers'): void;
|
|
50
51
|
setInitialBearing(initialBearing: number): void;
|
|
@@ -28,6 +28,9 @@ export default class RoutingSource extends DataSource {
|
|
|
28
28
|
setConfig(config) {
|
|
29
29
|
this.routing.setConfig(config);
|
|
30
30
|
}
|
|
31
|
+
setWorkingHoursOptions(options) {
|
|
32
|
+
this.routing.setWorkingHoursOptions(options);
|
|
33
|
+
}
|
|
31
34
|
setNavigationType(type) {
|
|
32
35
|
this.navigationType = type;
|
|
33
36
|
}
|
|
@@ -108,6 +111,10 @@ export default class RoutingSource extends DataSource {
|
|
|
108
111
|
}
|
|
109
112
|
}
|
|
110
113
|
// @ts-ignore
|
|
114
|
+
if ((route === null || route === void 0 ? void 0 : route.destinationOpen) === false) {
|
|
115
|
+
this.notify('destination-closed');
|
|
116
|
+
}
|
|
117
|
+
// @ts-ignore
|
|
111
118
|
let paths = route === null || route === void 0 ? void 0 : route.paths;
|
|
112
119
|
// @ts-ignore
|
|
113
120
|
this.route = route === null || route === void 0 ? void 0 : route.paths;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Working-hours support for client-side routing.
|
|
3
|
+
*
|
|
4
|
+
* Features may carry on `properties`:
|
|
5
|
+
* _workingHoursEnabled: true
|
|
6
|
+
* workingHours: [ ["14:00","22:00"], ... ] // 7 entries, index 0 = SUNDAY
|
|
7
|
+
*
|
|
8
|
+
* This runs on the end user's own device, so "now" is simply the browser's
|
|
9
|
+
* local clock — unlike a server serving clients across timezones, there is
|
|
10
|
+
* no offset to strip: `Date#getDay/getHours/getMinutes` already reflect the
|
|
11
|
+
* device's local wall-clock time.
|
|
12
|
+
*
|
|
13
|
+
* Malformed or missing data fails OPEN: bad venue data must never make a
|
|
14
|
+
* feature unroutable.
|
|
15
|
+
*/
|
|
16
|
+
export type ClientTime = {
|
|
17
|
+
/** 0 = Sunday … 6 = Saturday, matching the workingHours array order. */
|
|
18
|
+
weekday: number;
|
|
19
|
+
/** Minutes since local midnight, 0–1439. */
|
|
20
|
+
minutes: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Derive weekday + wall-clock minutes from a local Date (defaults to now).
|
|
24
|
+
*/
|
|
25
|
+
export declare function nowClientTime(date?: Date): ClientTime;
|
|
26
|
+
/**
|
|
27
|
+
* Is a feature open at the given client time?
|
|
28
|
+
*
|
|
29
|
+
* - Features without `_workingHoursEnabled: true` (or with malformed
|
|
30
|
+
* `workingHours`) are always open.
|
|
31
|
+
* - A window with `from < to` covers [from, to) that day.
|
|
32
|
+
* - An overnight window (`from > to`, e.g. 22:00–06:00) covers [from, 24:00)
|
|
33
|
+
* that day plus [00:00, to) of the NEXT day — so we also check whether
|
|
34
|
+
* yesterday's window spills past midnight into now.
|
|
35
|
+
* - `from === to` means closed all day (zero-length window).
|
|
36
|
+
*/
|
|
37
|
+
export declare function isOpenAt(properties: any, time: ClientTime): boolean;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Working-hours support for client-side routing.
|
|
3
|
+
*
|
|
4
|
+
* Features may carry on `properties`:
|
|
5
|
+
* _workingHoursEnabled: true
|
|
6
|
+
* workingHours: [ ["14:00","22:00"], ... ] // 7 entries, index 0 = SUNDAY
|
|
7
|
+
*
|
|
8
|
+
* This runs on the end user's own device, so "now" is simply the browser's
|
|
9
|
+
* local clock — unlike a server serving clients across timezones, there is
|
|
10
|
+
* no offset to strip: `Date#getDay/getHours/getMinutes` already reflect the
|
|
11
|
+
* device's local wall-clock time.
|
|
12
|
+
*
|
|
13
|
+
* Malformed or missing data fails OPEN: bad venue data must never make a
|
|
14
|
+
* feature unroutable.
|
|
15
|
+
*/
|
|
16
|
+
const HH_MM = /^(\d{1,2}):(\d{2})$/;
|
|
17
|
+
const MINUTES_PER_DAY = 24 * 60;
|
|
18
|
+
/**
|
|
19
|
+
* Derive weekday + wall-clock minutes from a local Date (defaults to now).
|
|
20
|
+
*/
|
|
21
|
+
export function nowClientTime(date = new Date()) {
|
|
22
|
+
return { weekday: date.getDay(), minutes: date.getHours() * 60 + date.getMinutes() };
|
|
23
|
+
}
|
|
24
|
+
function toMinutes(value) {
|
|
25
|
+
if (typeof value !== 'string')
|
|
26
|
+
return undefined;
|
|
27
|
+
const m = HH_MM.exec(value.trim());
|
|
28
|
+
if (!m)
|
|
29
|
+
return undefined;
|
|
30
|
+
const hours = Number(m[1]);
|
|
31
|
+
const minutes = Number(m[2]);
|
|
32
|
+
if (hours > 24 || minutes > 59)
|
|
33
|
+
return undefined;
|
|
34
|
+
return Math.min(hours * 60 + minutes, MINUTES_PER_DAY);
|
|
35
|
+
}
|
|
36
|
+
function dayWindow(workingHours, weekday) {
|
|
37
|
+
if (!Array.isArray(workingHours) || workingHours.length !== 7)
|
|
38
|
+
return undefined;
|
|
39
|
+
const day = workingHours[weekday];
|
|
40
|
+
if (!Array.isArray(day) || day.length < 2)
|
|
41
|
+
return undefined;
|
|
42
|
+
const from = toMinutes(day[0]);
|
|
43
|
+
const to = toMinutes(day[1]);
|
|
44
|
+
if (from === undefined || to === undefined)
|
|
45
|
+
return undefined;
|
|
46
|
+
return { from, to };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Is a feature open at the given client time?
|
|
50
|
+
*
|
|
51
|
+
* - Features without `_workingHoursEnabled: true` (or with malformed
|
|
52
|
+
* `workingHours`) are always open.
|
|
53
|
+
* - A window with `from < to` covers [from, to) that day.
|
|
54
|
+
* - An overnight window (`from > to`, e.g. 22:00–06:00) covers [from, 24:00)
|
|
55
|
+
* that day plus [00:00, to) of the NEXT day — so we also check whether
|
|
56
|
+
* yesterday's window spills past midnight into now.
|
|
57
|
+
* - `from === to` means closed all day (zero-length window).
|
|
58
|
+
*/
|
|
59
|
+
export function isOpenAt(properties, time) {
|
|
60
|
+
if ((properties === null || properties === void 0 ? void 0 : properties._workingHoursEnabled) !== true)
|
|
61
|
+
return true;
|
|
62
|
+
const workingHours = properties.workingHours;
|
|
63
|
+
if (!Array.isArray(workingHours) || workingHours.length !== 7)
|
|
64
|
+
return true;
|
|
65
|
+
const today = dayWindow(workingHours, time.weekday);
|
|
66
|
+
if (today === undefined)
|
|
67
|
+
return true;
|
|
68
|
+
if (today.from < today.to && time.minutes >= today.from && time.minutes < today.to)
|
|
69
|
+
return true;
|
|
70
|
+
if (today.from > today.to && time.minutes >= today.from)
|
|
71
|
+
return true;
|
|
72
|
+
const yesterday = dayWindow(workingHours, (time.weekday + 6) % 7);
|
|
73
|
+
if (yesterday !== undefined && yesterday.from > yesterday.to && time.minutes < yesterday.to)
|
|
74
|
+
return true;
|
|
75
|
+
return false;
|
|
76
|
+
}
|