atriusmaps-node-sdk 3.3.632 → 3.3.633
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 +1 -2
- package/README.md +15 -16
- package/dist/cjs/deploy/prepareSDKConfig.js +73 -57
- package/dist/cjs/nodesdk/nodeEntry.js +51 -44
- package/dist/cjs/package.json.js +4 -1
- package/dist/cjs/plugins/clientAPI/src/clientAPI.js +6 -4
- package/dist/cjs/plugins/dynamicPois/src/dynamicPois.js +32 -26
- package/dist/cjs/plugins/dynamicPois/src/processors.js +41 -35
- package/dist/cjs/plugins/poiDataManager/src/poiDataManager.js +102 -95
- package/dist/cjs/plugins/sdkServer/src/sdkHeadless.js +52 -26
- package/dist/cjs/plugins/sdkServer/src/sdkServer.js +86 -66
- package/dist/cjs/plugins/searchService/src/flexsearchExports/lang.js +16 -16
- package/dist/cjs/plugins/searchService/src/flexsearchExports/simple.js +31 -8
- package/dist/cjs/plugins/searchService/src/poiSearch.js +14 -17
- package/dist/cjs/plugins/searchService/src/searchService.js +41 -39
- package/dist/cjs/plugins/searchService/src/searchTypeahead.js +14 -19
- package/dist/cjs/plugins/searchService/src/utils.js +4 -5
- package/dist/cjs/plugins/venueDataLoader/src/venueDataLoader.js +145 -127
- package/dist/cjs/plugins/venueDataLoader/src/venueLoadingUtils.js +37 -39
- package/dist/cjs/plugins/wayfinder/src/findRoute.js +11 -18
- package/dist/cjs/plugins/wayfinder/src/minPriorityQueue.js +18 -19
- package/dist/cjs/plugins/wayfinder/src/navGraph.js +111 -91
- package/dist/cjs/plugins/wayfinder/src/navGraphDebug.js +19 -16
- package/dist/cjs/plugins/wayfinder/src/segmentBadges.js +1 -1
- package/dist/cjs/plugins/wayfinder/src/segmentBuilder.js +79 -76
- package/dist/cjs/plugins/wayfinder/src/segmentCategories.js +1 -1
- package/dist/cjs/plugins/wayfinder/src/stepBuilder.js +147 -107
- package/dist/cjs/plugins/wayfinder/src/wayfinder.js +178 -148
- package/dist/cjs/src/app.js +64 -44
- package/dist/cjs/src/configs/postproc-mol-url-parms.js +22 -21
- package/dist/cjs/src/configs/postproc-stateTracking.js +5 -8
- package/dist/cjs/src/controller.js +11 -6
- package/dist/cjs/src/debugTools.js +61 -34
- package/dist/cjs/src/env.js +7 -4
- package/dist/cjs/src/extModules/bustle.js +35 -45
- package/dist/cjs/src/extModules/flexapi/src/help.js +16 -8
- package/dist/cjs/src/extModules/flexapi/src/index.js +39 -18
- package/dist/cjs/src/extModules/flexapi/src/validate.js +129 -87
- package/dist/cjs/src/extModules/geohasher.js +7 -7
- package/dist/cjs/src/extModules/log.js +20 -22
- package/dist/cjs/src/historyManager.js +2 -2
- package/dist/cjs/src/utils/bounds.js +6 -6
- package/dist/cjs/src/utils/buildStructureLookup.js +3 -3
- package/dist/cjs/src/utils/configUtils.js +14 -18
- package/dist/cjs/src/utils/dom.js +12 -18
- package/dist/cjs/src/utils/funcs.js +12 -15
- package/dist/cjs/src/utils/geodesy.js +7 -9
- package/dist/cjs/src/utils/geom.js +52 -40
- package/dist/cjs/src/utils/i18n.js +47 -36
- package/dist/cjs/src/utils/location.js +12 -13
- package/dist/cjs/src/utils/observable.js +27 -28
- package/dist/cjs/src/utils/rand.js +9 -10
- package/dist/package.json.js +1 -1
- package/package.json +1 -1
|
@@ -9,10 +9,10 @@ const nodeColorsOb = {
|
|
|
9
9
|
blue: '\x1b[34m',
|
|
10
10
|
magenta: '\x1b[35m',
|
|
11
11
|
cyan: '\x1b[36m',
|
|
12
|
-
white: '\x1b[37m'
|
|
12
|
+
white: '\x1b[37m',
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
function clog
|
|
15
|
+
function clog(name, options = {}) {
|
|
16
16
|
let prefix = name + ': ';
|
|
17
17
|
let style = null;
|
|
18
18
|
|
|
@@ -22,34 +22,29 @@ function clog (name, options = { }) {
|
|
|
22
22
|
style = `color: ${options.color}`;
|
|
23
23
|
} else {
|
|
24
24
|
const cstring = nodeColorsOb[options.color];
|
|
25
|
-
if (cstring)
|
|
26
|
-
prefix = cstring + prefix;
|
|
25
|
+
if (cstring) prefix = cstring + prefix;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
const trunc = (str, len) => str && str.length > len ? str.substring(0, len) + '...' : str;
|
|
30
|
-
const checkPassesFilter = (args, filter) =>
|
|
31
|
-
? args[0].includes(filter)
|
|
32
|
-
: filter.test(args[0]);
|
|
28
|
+
const trunc = (str, len) => (str && str.length > len ? str.substring(0, len) + '...' : str);
|
|
29
|
+
const checkPassesFilter = (args, filter) =>
|
|
30
|
+
typeof filter === 'string' ? args[0].includes(filter) : filter.test(args[0]);
|
|
33
31
|
|
|
34
|
-
function logGen
|
|
32
|
+
function logGen(cmethod) {
|
|
35
33
|
return function () {
|
|
36
34
|
const isEnabled = options.enabled === undefined ? true : !!options.enabled;
|
|
37
35
|
if (isEnabled || cmethod === console.error) {
|
|
38
36
|
let args = Array.from(arguments);
|
|
39
|
-
if (style)
|
|
40
|
-
args.unshift(style);
|
|
37
|
+
if (style) args.unshift(style);
|
|
41
38
|
args.unshift(prefix);
|
|
42
39
|
if (options.truncateObjects && cmethod !== console.error)
|
|
43
40
|
args = args.map(arg => {
|
|
44
|
-
if (typeof arg === 'object')
|
|
45
|
-
|
|
46
|
-
return arg
|
|
41
|
+
if (typeof arg === 'object') return trunc(JSON.stringify(arg), parseInt(options.truncateObjects) || 100);
|
|
42
|
+
return arg;
|
|
47
43
|
});
|
|
48
44
|
const passesFilter = !options.logFilter || checkPassesFilter(args, options.logFilter);
|
|
49
|
-
if (passesFilter || cmethod === console.error)
|
|
50
|
-
cmethod.apply(console, args);
|
|
45
|
+
if (passesFilter || cmethod === console.error) cmethod.apply(console, args);
|
|
51
46
|
}
|
|
52
|
-
}
|
|
47
|
+
};
|
|
53
48
|
}
|
|
54
49
|
|
|
55
50
|
const log = logGen(options.trace ? console.trace : console.log);
|
|
@@ -58,15 +53,18 @@ function clog (name, options = { }) {
|
|
|
58
53
|
log.detailed = logGen(console.debug);
|
|
59
54
|
log.error = logGen(console.error);
|
|
60
55
|
|
|
61
|
-
log.setEnabled = e => {
|
|
56
|
+
log.setEnabled = e => {
|
|
57
|
+
options.enabled = e;
|
|
58
|
+
};
|
|
62
59
|
|
|
63
|
-
return log
|
|
60
|
+
return log;
|
|
64
61
|
}
|
|
65
62
|
|
|
66
|
-
function initLog
|
|
63
|
+
function initLog(name, options) {
|
|
67
64
|
const log = clog(name, options);
|
|
68
|
-
log.sublog = (sublogName, sublogOptions) =>
|
|
69
|
-
|
|
65
|
+
log.sublog = (sublogName, sublogOptions) =>
|
|
66
|
+
initLog(name + '.' + sublogName, Object.assign(Object.create(options), sublogOptions));
|
|
67
|
+
return log;
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
exports.initLog = initLog;
|
|
@@ -9,7 +9,7 @@ const initHistoryManager = ({ bus }) => {
|
|
|
9
9
|
const layersToHide = [];
|
|
10
10
|
const current = stepStack.pop();
|
|
11
11
|
|
|
12
|
-
if (!current) return
|
|
12
|
+
if (!current) return;
|
|
13
13
|
|
|
14
14
|
layersToHide.push(current.viewId);
|
|
15
15
|
for (let i = stepStack.length - 1; i >= 0; --i) {
|
|
@@ -17,7 +17,7 @@ const initHistoryManager = ({ bus }) => {
|
|
|
17
17
|
const same = stepStack.pop();
|
|
18
18
|
layersToHide.push(same.viewId);
|
|
19
19
|
} else {
|
|
20
|
-
break
|
|
20
|
+
break;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
bus.send('layers/hideMultiple', layersToHide);
|
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
var R = require('ramda');
|
|
4
4
|
|
|
5
|
-
function findBoundsOfWaypoints
|
|
5
|
+
function findBoundsOfWaypoints(waypoints) {
|
|
6
6
|
const latitudes = waypoints.map(R.path(['position', 'lat'])).filter(R.identity);
|
|
7
7
|
const longitudes = waypoints.map(R.path(['position', 'lng'])).filter(R.identity);
|
|
8
|
-
return findBounds(latitudes, longitudes)
|
|
8
|
+
return findBounds(latitudes, longitudes);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
function findBoundsOfCoordinates
|
|
11
|
+
function findBoundsOfCoordinates(coordinates) {
|
|
12
12
|
const latitudes = coordinates.map(R.prop(0)).filter(R.identity);
|
|
13
13
|
const longitudes = coordinates.map(R.prop(1)).filter(R.identity);
|
|
14
|
-
return findBounds(latitudes, longitudes)
|
|
14
|
+
return findBounds(latitudes, longitudes);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
function findBounds
|
|
17
|
+
function findBounds(latitudes, longitudes) {
|
|
18
18
|
const n = Math.max(...latitudes);
|
|
19
19
|
const s = Math.min(...latitudes);
|
|
20
20
|
const e = Math.max(...longitudes);
|
|
21
21
|
const w = Math.min(...longitudes);
|
|
22
|
-
return { n, s, e, w }
|
|
22
|
+
return { n, s, e, w };
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
exports.findBoundsOfCoordinates = findBoundsOfCoordinates;
|
|
@@ -21,7 +21,7 @@ function _interopNamespaceDefault(e) {
|
|
|
21
21
|
|
|
22
22
|
var R__namespace = /*#__PURE__*/_interopNamespaceDefault(R);
|
|
23
23
|
|
|
24
|
-
const buildStructuresLookup =
|
|
24
|
+
const buildStructuresLookup = structures => {
|
|
25
25
|
const floors = R__namespace.mergeAll(structures.map(R__namespace.prop('levels')));
|
|
26
26
|
const floorIdToFloor = floorId => floors[floorId];
|
|
27
27
|
const floorIdToOrdinal = R__namespace.pipe(floorIdToFloor, R__namespace.prop('ordinal'));
|
|
@@ -31,8 +31,8 @@ const buildStructuresLookup = (structures) => {
|
|
|
31
31
|
floorIdToOrdinal,
|
|
32
32
|
floorIdToFloor,
|
|
33
33
|
floorIdToStructureId,
|
|
34
|
-
floorIdToStructure
|
|
35
|
-
}
|
|
34
|
+
floorIdToStructure,
|
|
35
|
+
};
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
exports.buildStructuresLookup = buildStructuresLookup;
|
|
@@ -17,47 +17,43 @@
|
|
|
17
17
|
* @param {string} lang language code
|
|
18
18
|
* @param {any} def default value to return if no value is found through localized checks
|
|
19
19
|
*/
|
|
20
|
-
function getLocalized
|
|
20
|
+
function getLocalized(config, name, lang, def) {
|
|
21
21
|
let key = name;
|
|
22
|
-
if (lang)
|
|
23
|
-
key += '-' + lang;
|
|
22
|
+
if (lang) key += '-' + lang;
|
|
24
23
|
|
|
25
24
|
const value = config[key];
|
|
26
25
|
|
|
27
|
-
if (value)
|
|
28
|
-
return value
|
|
26
|
+
if (value) return value;
|
|
29
27
|
|
|
30
28
|
if (lang) {
|
|
31
|
-
if (lang.indexOf('-') > 0)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
if (lang.indexOf('-') > 0)
|
|
30
|
+
// we have sublocales, so strip last one and try again
|
|
31
|
+
return getLocalized(config, name, lang.substring(0, lang.indexOf('-')), def);
|
|
32
|
+
// no sublanguage, so next is try the name on its own
|
|
33
|
+
else return getLocalized(config, name, null, def);
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
// we are here means we just checked the name (no lang arg) and there was no value found, so
|
|
38
37
|
// we simply return the def
|
|
39
|
-
return def
|
|
38
|
+
return def;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
// A debug property is considered "true" if:
|
|
43
42
|
// The key is defined as a property within the debug object AND
|
|
44
43
|
// the value of that key is not "no" or "false" or false (boolean) or undefined or null
|
|
45
44
|
// Any other value will be considered true - even 0 and ""
|
|
46
|
-
function debugIsTrue
|
|
47
|
-
if (!app.config.debug)
|
|
48
|
-
return false
|
|
45
|
+
function debugIsTrue(app, key) {
|
|
46
|
+
if (!app.config.debug) return false;
|
|
49
47
|
|
|
50
48
|
let value = app.config.debug[key];
|
|
51
49
|
|
|
52
|
-
if (value === undefined || value === null || value === false)
|
|
53
|
-
return false
|
|
50
|
+
if (value === undefined || value === null || value === false) return false;
|
|
54
51
|
|
|
55
|
-
if (value === true)
|
|
56
|
-
return true
|
|
52
|
+
if (value === true) return true;
|
|
57
53
|
|
|
58
54
|
value = value.toLowerCase ? value.toLowerCase() : value; // lower case it if possible
|
|
59
55
|
|
|
60
|
-
return value !== 'no' && value !== 'false'
|
|
56
|
+
return value !== 'no' && value !== 'false';
|
|
61
57
|
}
|
|
62
58
|
|
|
63
59
|
// import this global to access to the "window" or "global" variables from
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const $ = (expr, container) => typeof expr === 'string' ? (container || document).querySelector(expr) : expr || null;
|
|
3
|
+
const $ = (expr, container) => (typeof expr === 'string' ? (container || document).querySelector(expr) : expr || null);
|
|
4
4
|
const $$ = (expr, container) => Array.prototype.slice.call((document).querySelectorAll(expr));
|
|
5
5
|
|
|
6
6
|
// adds an element (default: div) defined in eConf to parent element (default: body) - returns element
|
|
@@ -8,43 +8,37 @@ const $$ = (expr, container) => Array.prototype.slice.call((document).querySelec
|
|
|
8
8
|
// const newDiv = ad() = creates a new div, adds to end of page and returns it
|
|
9
9
|
// const newDiv = ad({klass: "foo"}) = same as above with class of "foo"
|
|
10
10
|
// const newImg = ad({tag: "img", src: "test.png"}, "#top") = image at end of top
|
|
11
|
-
function ad
|
|
11
|
+
function ad(eConf, parent) {
|
|
12
12
|
const c = eConf || {};
|
|
13
13
|
parent = parent ? (typeof parent === 'string' ? document.querySelector(parent) : parent) : document.body;
|
|
14
14
|
|
|
15
15
|
let tag = 'div';
|
|
16
16
|
|
|
17
|
-
if (c.tag)
|
|
18
|
-
tag = c.tag;
|
|
17
|
+
if (c.tag) tag = c.tag;
|
|
19
18
|
|
|
20
19
|
const node = document.createElement(tag);
|
|
21
20
|
|
|
22
21
|
for (const cc in c) {
|
|
23
|
-
if (c[cc] != null)
|
|
22
|
+
if (c[cc] != null)
|
|
24
23
|
if (cc === 'klass')
|
|
24
|
+
// null or undefined
|
|
25
25
|
node.setAttribute('class', c.klass);
|
|
26
|
-
else if (cc === 'tag')
|
|
27
|
-
|
|
28
|
-
else if (cc === '
|
|
29
|
-
|
|
30
|
-
else
|
|
31
|
-
node.textContent = c.text;
|
|
32
|
-
else if (cc === 'html')
|
|
33
|
-
node.innerHTML = c.html;
|
|
34
|
-
else
|
|
35
|
-
node.setAttribute(cc, c[cc]);
|
|
26
|
+
else if (cc === 'tag'); // already swallowed this
|
|
27
|
+
else if (cc === 'styles') setStyles(node, c.styles);
|
|
28
|
+
else if (cc === 'text') node.textContent = c.text;
|
|
29
|
+
else if (cc === 'html') node.innerHTML = c.html;
|
|
30
|
+
else node.setAttribute(cc, c[cc]);
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
parent.appendChild(node);
|
|
39
34
|
|
|
40
|
-
return node
|
|
35
|
+
return node;
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
const del = element => element?.parentNode?.removeChild(element);
|
|
44
39
|
|
|
45
40
|
const setStyles = (node, styles) => {
|
|
46
|
-
for (const style in styles)
|
|
47
|
-
node.style[style] = styles[style];
|
|
41
|
+
for (const style in styles) node.style[style] = styles[style];
|
|
48
42
|
};
|
|
49
43
|
|
|
50
44
|
exports.$ = $;
|
|
@@ -5,14 +5,13 @@ require('zousan');
|
|
|
5
5
|
|
|
6
6
|
// Ensures only a single asynchronous function wrapped in this function runs at a time.
|
|
7
7
|
let lastFn = null;
|
|
8
|
-
const singleFile = fn =>
|
|
9
|
-
|
|
10
|
-
lastFn = lastFn.then(() => fn.apply(null, arguments));
|
|
11
|
-
|
|
12
|
-
lastFn = fn.apply(null, arguments);
|
|
8
|
+
const singleFile = fn =>
|
|
9
|
+
function () {
|
|
10
|
+
if (lastFn) lastFn = lastFn.then(() => fn.apply(null, arguments));
|
|
11
|
+
else lastFn = fn.apply(null, arguments);
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
};
|
|
13
|
+
return lastFn;
|
|
14
|
+
};
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* returns a copy of an object with any (top-level) properties that do not
|
|
@@ -22,14 +21,12 @@ const singleFile = fn => function () {
|
|
|
22
21
|
* @param {object} ob The object to filter (top level properties only)
|
|
23
22
|
* @returns (object) The newly created object with filtered properties
|
|
24
23
|
*/
|
|
25
|
-
function filterOb
|
|
26
|
-
const ret = {
|
|
27
|
-
Object.keys(ob)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
return ret
|
|
24
|
+
function filterOb(fn, ob) {
|
|
25
|
+
const ret = {};
|
|
26
|
+
Object.keys(ob).forEach(key => {
|
|
27
|
+
if (fn(key, ob[key])) ret[key] = ob[key];
|
|
28
|
+
});
|
|
29
|
+
return ret;
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
exports.filterOb = filterOb;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
// degrees to radians
|
|
11
|
-
const toRadians = d => d * Math.PI / 180;
|
|
11
|
+
const toRadians = d => (d * Math.PI) / 180;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Haversine formula for finding distance between two lat/lng points.
|
|
@@ -19,22 +19,20 @@ const toRadians = d => d * Math.PI / 180;
|
|
|
19
19
|
* @param {float} lng2 longitude of point 2
|
|
20
20
|
* @returns number (in meters) between p1 and p2
|
|
21
21
|
*/
|
|
22
|
-
function distance
|
|
22
|
+
function distance(lat1, lng1, lat2, lng2) {
|
|
23
23
|
const R = 6371000; // approx. earth radius (meters)
|
|
24
24
|
const φ1 = toRadians(lat1);
|
|
25
25
|
const φ2 = toRadians(lat2);
|
|
26
26
|
const Δφ = toRadians(lat2 - lat1);
|
|
27
27
|
const Δλ = toRadians(lng2 - lng1);
|
|
28
28
|
|
|
29
|
-
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
|
|
30
|
-
Math.cos(φ1) * Math.cos(φ2) *
|
|
31
|
-
Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
|
|
29
|
+
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
|
|
32
30
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
33
31
|
|
|
34
|
-
return R * c
|
|
32
|
+
return R * c;
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
function bearingToDirection
|
|
35
|
+
function bearingToDirection(deg, T) {
|
|
38
36
|
const names = [
|
|
39
37
|
T('wayfinder:north'), // 0
|
|
40
38
|
T('wayfinder:northeast'), // 45
|
|
@@ -43,13 +41,13 @@ function bearingToDirection (deg, T) {
|
|
|
43
41
|
T('wayfinder:south'), // 180 / -180
|
|
44
42
|
T('wayfinder:southwest'), // -135
|
|
45
43
|
T('wayfinder:west'), // -90
|
|
46
|
-
T('wayfinder:northwest') // -45
|
|
44
|
+
T('wayfinder:northwest'), // -45
|
|
47
45
|
];
|
|
48
46
|
// normalize -180..180
|
|
49
47
|
const d = ((deg + 180) % 360) - 180;
|
|
50
48
|
|
|
51
49
|
const index = Math.round(d / 45);
|
|
52
|
-
return names[(index + 8) % 8]
|
|
50
|
+
return names[(index + 8) % 8];
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
exports.bearingToDirection = bearingToDirection;
|
|
@@ -37,17 +37,22 @@ const pointInPolygon = (point, vs) => {
|
|
|
37
37
|
const yi = vs[i][1];
|
|
38
38
|
const xj = vs[j][0];
|
|
39
39
|
const yj = vs[j][1];
|
|
40
|
-
const intersect =
|
|
41
|
-
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
|
40
|
+
const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
|
|
42
41
|
if (intersect) {
|
|
43
42
|
inside = !inside;
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
return inside
|
|
46
|
+
return inside;
|
|
48
47
|
};
|
|
49
48
|
|
|
50
|
-
const bounds2Coords = ({ n, s, e, w }) => [
|
|
49
|
+
const bounds2Coords = ({ n, s, e, w }) => [
|
|
50
|
+
[n, e],
|
|
51
|
+
[n, w],
|
|
52
|
+
[s, w],
|
|
53
|
+
[s, e],
|
|
54
|
+
[n, e],
|
|
55
|
+
];
|
|
51
56
|
const NULL_STRUCTURE_AND_FLOOR = { structure: null, floor: null };
|
|
52
57
|
|
|
53
58
|
/**
|
|
@@ -63,15 +68,18 @@ const NULL_STRUCTURE_AND_FLOOR = { structure: null, floor: null };
|
|
|
63
68
|
* @param {boolean} preciseFlag if false, we provide a fuzzy reading, allowing for the map center to be "close enough" to a building/floor
|
|
64
69
|
* @returns {structure: object, floor: object} structure/building and floor that contains the point passed (or {structure:null,floor:null})
|
|
65
70
|
*/
|
|
66
|
-
function getStructureAndFloorAtPoint
|
|
67
|
-
|
|
71
|
+
function getStructureAndFloorAtPoint(structures, lat, lng, ord, mapviewBBox, preciseFlag = false) {
|
|
72
|
+
// Step 1 of logic flow
|
|
73
|
+
if (!R__namespace.length(structures)) return NULL_STRUCTURE_AND_FLOOR;
|
|
68
74
|
|
|
69
75
|
structures = structures.filter(s => s.shouldDisplay == null || s.shouldDisplay === true);
|
|
70
76
|
|
|
71
|
-
const floorsToConsider = structures
|
|
72
|
-
|
|
77
|
+
const floorsToConsider = structures.map(structure => ({
|
|
78
|
+
structure,
|
|
79
|
+
floor: ordToFloor(structure, ord),
|
|
80
|
+
})); // array of {structure,floor} obs
|
|
73
81
|
|
|
74
|
-
return getStructureAndFloorWithinFloorsAtPoint(structures, floorsToConsider, lat, lng, mapviewBBox, preciseFlag)
|
|
82
|
+
return getStructureAndFloorWithinFloorsAtPoint(structures, floorsToConsider, lat, lng, mapviewBBox, preciseFlag);
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
/**
|
|
@@ -84,7 +92,7 @@ function getStructureAndFloorAtPoint (structures, lat, lng, ord, mapviewBBox, pr
|
|
|
84
92
|
* @param {boolean} preciseFlag if false, we provide a fuzzy reading, allowing for the map center to be "close enough" to a building/floor
|
|
85
93
|
* @returns {structure: object, floor: object} structure/building and floor that contains the point passed (or {structure:null,floor:null})
|
|
86
94
|
*/
|
|
87
|
-
function getStructureAndFloorWithinFloorsAtPoint
|
|
95
|
+
function getStructureAndFloorWithinFloorsAtPoint(structures, floorsToConsider, lat, lng, mapviewBBox, preciseFlag) {
|
|
88
96
|
// Step 2 - Select floors whose bounding box contains map center
|
|
89
97
|
const pointWithinFloorsBBox = floorsToConsider
|
|
90
98
|
.filter(ftc => ftc.floor) // ignore structures with no floor on this ord
|
|
@@ -96,20 +104,19 @@ function getStructureAndFloorWithinFloorsAtPoint (structures, floorsToConsider,
|
|
|
96
104
|
//
|
|
97
105
|
if (preciseFlag) {
|
|
98
106
|
// not within any floor's bounding box? return nulls
|
|
99
|
-
if (pointWithinFloorsBBox.length === 0)
|
|
100
|
-
return NULL_STRUCTURE_AND_FLOOR
|
|
107
|
+
if (pointWithinFloorsBBox.length === 0) return NULL_STRUCTURE_AND_FLOOR;
|
|
101
108
|
|
|
102
109
|
// Step 3 (precise) - We need to determine which of the floors found above are we ACTUALLY in:
|
|
103
|
-
const floorsWithinBoundsPolygon = pointWithinFloorsBBox
|
|
104
|
-
|
|
110
|
+
const floorsWithinBoundsPolygon = pointWithinFloorsBBox.filter(ftc =>
|
|
111
|
+
pointInPolygon([lat, lng], ftc.floor.boundsPolygon),
|
|
112
|
+
);
|
|
105
113
|
|
|
106
114
|
// We should never be in MORE than one floor's bounding polygon, so return 1st one
|
|
107
115
|
// and in unlikely case we ARE in multiple, user will get first one...
|
|
108
|
-
if (floorsWithinBoundsPolygon.length >= 1)
|
|
109
|
-
return R__namespace.head(floorsWithinBoundsPolygon)
|
|
116
|
+
if (floorsWithinBoundsPolygon.length >= 1) return R__namespace.head(floorsWithinBoundsPolygon);
|
|
110
117
|
|
|
111
118
|
// precise yet not within any floor polygon, "so you get nothing. you lose. good day sir!"
|
|
112
|
-
return NULL_STRUCTURE_AND_FLOOR
|
|
119
|
+
return NULL_STRUCTURE_AND_FLOOR;
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
//
|
|
@@ -124,32 +131,38 @@ function getStructureAndFloorWithinFloorsAtPoint (structures, floorsToConsider,
|
|
|
124
131
|
// .map(structure => ({ structure, floor: structure.levels[structure.defaultLevelId] }))
|
|
125
132
|
.map(structure => ({ structure, floor: null }));
|
|
126
133
|
|
|
127
|
-
if (floorsWithinBuildingBoundingBox.length >= 1)
|
|
128
|
-
return floorsWithinBuildingBoundingBox[0]
|
|
134
|
+
if (floorsWithinBuildingBoundingBox.length >= 1) return floorsWithinBuildingBoundingBox[0];
|
|
129
135
|
|
|
130
|
-
return NULL_STRUCTURE_AND_FLOOR // user does not seem to be near ANYTHING!
|
|
136
|
+
return NULL_STRUCTURE_AND_FLOOR; // user does not seem to be near ANYTHING!
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
// Step 4 - If we are only in the bounding box of a single floor, return it
|
|
134
|
-
if (pointWithinFloorsBBox.length === 1)
|
|
135
|
-
return pointWithinFloorsBBox[0]
|
|
140
|
+
if (pointWithinFloorsBBox.length === 1) return pointWithinFloorsBBox[0];
|
|
136
141
|
|
|
137
142
|
// Step 5 - Ok, so from here, we are NOT precise, and the map center is within MULTIPLE bounding boxes
|
|
138
143
|
// so how do we determine WHICH item to select...?
|
|
139
144
|
|
|
140
|
-
const floorsContainingPoint = pointWithinFloorsBBox.filter(ftc =>
|
|
145
|
+
const floorsContainingPoint = pointWithinFloorsBBox.filter(ftc =>
|
|
146
|
+
pointInPolygon([lat, lng], ftc.floor.boundsPolygon),
|
|
147
|
+
);
|
|
141
148
|
|
|
142
149
|
// We will score the building/floor's "prominence" and pick the highest scoring building/floor
|
|
143
|
-
const prominenceScores = pointWithinFloorsBBox.map(ftc =>
|
|
150
|
+
const prominenceScores = pointWithinFloorsBBox.map(ftc =>
|
|
151
|
+
prominence(
|
|
152
|
+
ftc,
|
|
153
|
+
mapviewBBox,
|
|
154
|
+
floorsContainingPoint.some(fcp => fcp.floor.id === ftc.floor.id),
|
|
155
|
+
),
|
|
156
|
+
);
|
|
144
157
|
const bestScore = Math.max.apply(null, prominenceScores);
|
|
145
158
|
|
|
146
|
-
return pointWithinFloorsBBox[prominenceScores.indexOf(bestScore)]
|
|
159
|
+
return pointWithinFloorsBBox[prominenceScores.indexOf(bestScore)];
|
|
147
160
|
}
|
|
148
161
|
|
|
149
162
|
// Returns a prominenceScore from 0 to 100
|
|
150
163
|
// This is calculated by a % of screen taken by the
|
|
151
164
|
// floor polygon
|
|
152
|
-
function prominence
|
|
165
|
+
function prominence({ structure, floor }, mapviewBBox, pointWithinFloorPoly) {
|
|
153
166
|
// Take the polygon of the floor...
|
|
154
167
|
const floorPolygon = coords2Poly(floor.boundsPolygon);
|
|
155
168
|
|
|
@@ -163,7 +176,7 @@ function prominence ({ structure, floor }, mapviewBBox, pointWithinFloorPoly) {
|
|
|
163
176
|
const viewableMapArea = area.area(mapviewBBoxPoly);
|
|
164
177
|
|
|
165
178
|
// now the prominence is simply the ratio of viewable floor to viewable map (with 20% bonus if center within floor)
|
|
166
|
-
return floorArea * (pointWithinFloorPoly ? 150 : 100) / viewableMapArea
|
|
179
|
+
return (floorArea * (pointWithinFloorPoly ? 150 : 100)) / viewableMapArea;
|
|
167
180
|
}
|
|
168
181
|
|
|
169
182
|
const latLngSwap = point => [point[1], point[0]];
|
|
@@ -172,26 +185,25 @@ const coords2Poly = coords => helpers.polygon([coords.map(latLngSwap)]);
|
|
|
172
185
|
/**
|
|
173
186
|
* given a building and ord, return the floor (or undefined if doesn't exist)
|
|
174
187
|
*/
|
|
175
|
-
const ordToFloor = (building, ord) =>
|
|
176
|
-
Object.values(building.levels).find(floor => floor.ordinal === ord);
|
|
188
|
+
const ordToFloor = (building, ord) => Object.values(building.levels).find(floor => floor.ordinal === ord);
|
|
177
189
|
|
|
178
190
|
/**
|
|
179
191
|
* Return the floor based on its ID (pass in buildings array and floorId)
|
|
180
192
|
*/
|
|
181
193
|
const getFloor = (structures, selectedLevelId) =>
|
|
182
|
-
structures.reduce(
|
|
183
|
-
Object.values(building.levels).find(floor => floor.id === selectedLevelId) || fmatch,
|
|
194
|
+
structures.reduce(
|
|
195
|
+
(fmatch, building) => Object.values(building.levels).find(floor => floor.id === selectedLevelId) || fmatch,
|
|
196
|
+
undefined,
|
|
197
|
+
);
|
|
184
198
|
|
|
185
199
|
// pass in the structures array and a floorId and this will return the structure
|
|
186
200
|
// that contains the floorId.
|
|
187
201
|
const getStructureForFloorId = (structures, floorId) =>
|
|
188
|
-
structures.reduce((sMatch, structure) =>
|
|
189
|
-
buildContainsFloorWithId(structure, floorId) ? structure : sMatch, null);
|
|
202
|
+
structures.reduce((sMatch, structure) => (buildContainsFloorWithId(structure, floorId) ? structure : sMatch), null);
|
|
190
203
|
|
|
191
204
|
// returns true if the building specified contains the floorId specified
|
|
192
205
|
const buildContainsFloorWithId = (building, floorId) =>
|
|
193
|
-
Object.values(building.levels).reduce((fmatch, floor) =>
|
|
194
|
-
floor.id === floorId ? true : fmatch, false);
|
|
206
|
+
Object.values(building.levels).reduce((fmatch, floor) => (floor.id === floorId ? true : fmatch), false);
|
|
195
207
|
|
|
196
208
|
/**
|
|
197
209
|
* Calculate the points for a bezier cubic curve
|
|
@@ -206,7 +218,7 @@ const buildContainsFloorWithId = (building, floorId) =>
|
|
|
206
218
|
* @param {number} toY - Destination point y
|
|
207
219
|
* @return {Object[]} Array of points of the curve
|
|
208
220
|
*/
|
|
209
|
-
function bezierCurveTo
|
|
221
|
+
function bezierCurveTo(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) {
|
|
210
222
|
const n = 20; // controls smoothness of line
|
|
211
223
|
let dt = 0;
|
|
212
224
|
let dt2 = 0;
|
|
@@ -219,7 +231,7 @@ function bezierCurveTo (fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) {
|
|
|
219
231
|
for (let i = 1, j = 0; i <= n; ++i) {
|
|
220
232
|
j = i / n;
|
|
221
233
|
|
|
222
|
-
dt =
|
|
234
|
+
dt = 1 - j;
|
|
223
235
|
dt2 = dt * dt;
|
|
224
236
|
dt3 = dt2 * dt;
|
|
225
237
|
|
|
@@ -227,12 +239,12 @@ function bezierCurveTo (fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) {
|
|
|
227
239
|
t3 = t2 * j;
|
|
228
240
|
|
|
229
241
|
path.push({
|
|
230
|
-
x:
|
|
231
|
-
y:
|
|
242
|
+
x: dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX,
|
|
243
|
+
y: dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY,
|
|
232
244
|
});
|
|
233
245
|
}
|
|
234
246
|
|
|
235
|
-
return path
|
|
247
|
+
return path;
|
|
236
248
|
}
|
|
237
249
|
|
|
238
250
|
exports.bezierCurveTo = bezierCurveTo;
|