incyclist-services 1.1.83 → 1.1.85

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.
@@ -1,5 +1,30 @@
1
- import { CoachSettings } from "./types";
1
+ import { EventLogger } from "gd-eventlog";
2
+ import { CoachEditProps, CoachSettings } from "./types";
3
+ import { IncyclistDeviceAdapter } from 'incyclist-devices';
4
+ import { RoutePoint } from "../routes/base/types";
2
5
  export declare class Coach {
3
- protected settings: CoachSettings;
6
+ protected _settings: CoachSettings;
7
+ protected _id: string;
8
+ protected routeDistance: number;
9
+ protected riderPosition: number;
10
+ protected simulator: IncyclistDeviceAdapter;
11
+ protected logger: EventLogger;
12
+ protected position: RoutePoint;
4
13
  constructor(settings: CoachSettings);
14
+ get id(): string;
15
+ get settings(): CoachSettings;
16
+ get lead(): number;
17
+ setProgress(routeDistance: number): void;
18
+ getProgess(): number;
19
+ setPosition(point: RoutePoint): void;
20
+ getPosition(): RoutePoint;
21
+ setRiderPosition(routeDistance: number): void;
22
+ sendDeviceUpdate(request: any): void;
23
+ getDisplayProperties(): CoachEditProps;
24
+ update(settings: CoachEditProps): void;
25
+ initSimulator(user: {
26
+ weight: number;
27
+ }, bikeType: string): void;
28
+ start(onData: any): Promise<void>;
29
+ stop(): void;
5
30
  }
@@ -1,9 +1,108 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.Coach = void 0;
13
+ const gd_eventlog_1 = require("gd-eventlog");
14
+ const incyclist_devices_1 = require("incyclist-devices");
4
15
  class Coach {
5
16
  constructor(settings) {
6
- this.settings = settings;
17
+ this._settings = settings;
18
+ this._id = Date.now().toString();
19
+ this.logger = new gd_eventlog_1.EventLogger('Coach');
20
+ }
21
+ get id() {
22
+ return this._id;
23
+ }
24
+ get settings() {
25
+ return this._settings;
26
+ }
27
+ get lead() {
28
+ const lead = this.routeDistance - this.riderPosition;
29
+ if (isNaN(lead))
30
+ return 0;
31
+ return lead;
32
+ }
33
+ setProgress(routeDistance) {
34
+ this.routeDistance = routeDistance;
35
+ }
36
+ getProgess() {
37
+ return this.routeDistance;
38
+ }
39
+ setPosition(point) {
40
+ this.position = point;
41
+ }
42
+ getPosition() {
43
+ return this.position;
44
+ }
45
+ setRiderPosition(routeDistance) {
46
+ this.riderPosition = routeDistance;
47
+ }
48
+ sendDeviceUpdate(request) {
49
+ if (this.simulator)
50
+ this.simulator.sendUpdate(request);
51
+ }
52
+ getDisplayProperties() {
53
+ const { name, type, target, lead } = this._settings;
54
+ const power = type === 'power' ? target : undefined;
55
+ const speed = type === 'speed' ? target : undefined;
56
+ const props = {
57
+ name, type, speed, power, lead
58
+ };
59
+ if (this.routeDistance !== undefined && this.riderPosition !== undefined)
60
+ props.lead = this.lead;
61
+ return props;
62
+ }
63
+ update(settings) {
64
+ const { name, power, speed, lead } = settings;
65
+ if (settings.type.toLowerCase() === 'power') {
66
+ this._settings = { name, type: 'power', target: power, lead };
67
+ if (!name || name.length === 0 && power !== undefined)
68
+ this._settings.name = `${power.toFixed(0)}W Coach`;
69
+ }
70
+ else if (settings.type.toLowerCase() === 'speed') {
71
+ this._settings = { name, type: 'speed', target: speed, lead };
72
+ if (!name || name.length === 0 && speed !== undefined)
73
+ this._settings.name = `${speed.toFixed(0)}km/h Coach`;
74
+ }
75
+ }
76
+ initSimulator(user, bikeType) {
77
+ const { type, target } = this.settings;
78
+ const mode = type === 'power' ? 'Power' : 'Speed';
79
+ const power = type === 'power' ? target : undefined;
80
+ const speed = type === 'speed' ? target : undefined;
81
+ const deviceSettings = { name: this.settings.name, interface: incyclist_devices_1.INTERFACE.SIMULATOR };
82
+ const props = { port: '', isBot: true, user, settings: { bikeType, mode, power, speed } };
83
+ if (!this.simulator)
84
+ this.simulator = incyclist_devices_1.AdapterFactory.create(deviceSettings, props);
85
+ }
86
+ start(onData) {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ if (!this.simulator)
89
+ return;
90
+ try {
91
+ yield this.simulator.start({});
92
+ this.simulator.onData((data) => {
93
+ onData(this, data);
94
+ });
95
+ }
96
+ catch (err) {
97
+ this.logger.logEvent({ message: 'error', fn: 'startCoach()', coach: this.settings.name, error: err.message || err });
98
+ }
99
+ });
100
+ }
101
+ stop() {
102
+ if (!this.simulator)
103
+ return;
104
+ this.simulator.stop();
105
+ this.routeDistance = undefined;
7
106
  }
8
107
  }
9
108
  exports.Coach = Coach;
@@ -0,0 +1,3 @@
1
+ export * from './service';
2
+ export * from './types';
3
+ export * from './coach';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./service"), exports);
18
+ __exportStar(require("./types"), exports);
19
+ __exportStar(require("./coach"), exports);
@@ -1,12 +1,32 @@
1
1
  import { IncyclistService } from "../base/service";
2
+ import { Observer } from "../base/types/observer";
3
+ import { DeviceConfigurationService, DevicePairingService, DeviceRideService } from "../devices";
4
+ import { RouteListService } from "../routes";
5
+ import { UserSettingsService } from "../settings";
2
6
  import { Coach } from "./coach";
3
- import { CoachSettings } from "./types";
7
+ import { CoachStatus } from "./types";
8
+ import { IncyclistAdapterData } from "incyclist-devices/lib/types";
4
9
  export declare class CoachesService extends IncyclistService {
5
10
  protected coaches: Array<Coach>;
11
+ protected activeRide: Observer;
12
+ protected isPaused: boolean;
6
13
  constructor();
7
- openCoachSettings(): void;
8
- add(settings: CoachSettings): void;
9
- startRide(): void;
14
+ getCoaches(): Array<Coach>;
15
+ openCoachEdit(coach?: Coach): Coach;
16
+ saveCoach(coach: Coach): void;
17
+ deleteCoach(coach: Coach): void;
18
+ startRide(): Promise<Observer | null>;
19
+ stopRide(): Promise<void>;
20
+ pauseRide(): void;
21
+ resumeRide(): void;
10
22
  updateRiderPosition(routeDistance: number): void;
23
+ getCoachesRideInfo(): Array<CoachStatus>;
24
+ protected onCoachDataUpdate(coach: Coach, data: IncyclistAdapterData): void;
25
+ protected setCoachPosition(coach: Coach, distance: number): void;
26
+ protected get routesService(): RouteListService;
27
+ protected get rideService(): DeviceRideService;
28
+ protected get deviceConfig(): DeviceConfigurationService;
29
+ protected get pairingService(): DevicePairingService;
30
+ protected get userService(): UserSettingsService;
11
31
  }
12
32
  export declare const getCoachesService: () => CoachesService;
@@ -33,15 +33,31 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
33
33
  }
34
34
  return useValue ? value : void 0;
35
35
  };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
36
45
  var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
37
46
  if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
38
47
  return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
39
48
  };
40
49
  Object.defineProperty(exports, "__esModule", { value: true });
41
50
  exports.getCoachesService = exports.CoachesService = void 0;
51
+ const incyclist_devices_1 = require("incyclist-devices");
42
52
  const service_1 = require("../base/service");
43
53
  const types_1 = require("../base/types");
54
+ const observer_1 = require("../base/types/observer");
55
+ const devices_1 = require("../devices");
56
+ const routes_1 = require("../routes");
57
+ const settings_1 = require("../settings");
58
+ const utils_1 = require("../utils");
44
59
  const coach_1 = require("./coach");
60
+ const route_1 = require("../routes/base/utils/route");
45
61
  let CoachesService = (() => {
46
62
  let _classDecorators = [types_1.Singleton];
47
63
  let _classDescriptor;
@@ -52,16 +68,166 @@ let CoachesService = (() => {
52
68
  constructor() {
53
69
  super('Coaches');
54
70
  this.coaches = [];
71
+ this.isPaused = false;
72
+ }
73
+ getCoaches() {
74
+ return this.coaches;
55
75
  }
56
- openCoachSettings() {
76
+ openCoachEdit(coach) {
77
+ if (coach)
78
+ return coach;
79
+ return new coach_1.Coach({ name: '', type: undefined, target: undefined });
57
80
  }
58
- add(settings) {
59
- const coach = new coach_1.Coach(settings);
60
- this.coaches.push(coach);
81
+ saveCoach(coach) {
82
+ try {
83
+ const idx = this.coaches.findIndex(c => c.id === coach.id);
84
+ if (idx !== -1)
85
+ this.coaches[idx] = coach;
86
+ else
87
+ this.coaches.push(coach);
88
+ }
89
+ catch (err) {
90
+ this.logError(err, 'saveCoach');
91
+ }
92
+ }
93
+ deleteCoach(coach) {
94
+ try {
95
+ const idx = this.coaches.findIndex(c => c.id === coach.id);
96
+ if (idx !== -1) {
97
+ if (this.activeRide) {
98
+ coach.stop();
99
+ }
100
+ this.coaches.splice(idx, 1);
101
+ }
102
+ }
103
+ catch (err) {
104
+ this.logError(err, 'deleteCoach');
105
+ }
61
106
  }
62
107
  startRide() {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ try {
110
+ if (this.activeRide) {
111
+ yield this.stopRide();
112
+ }
113
+ if (!this.coaches)
114
+ return null;
115
+ this.activeRide = new observer_1.Observer();
116
+ this.isPaused = false;
117
+ const onDataUpdate = this.onCoachDataUpdate.bind(this);
118
+ this.coaches.forEach(c => {
119
+ const startSettings = this.routesService.getStartSettings();
120
+ let pos = 0;
121
+ if (startSettings.type === 'Route') {
122
+ pos = startSettings.startPos;
123
+ }
124
+ c.setProgress(c.settings.lead + pos);
125
+ c.setRiderPosition(pos);
126
+ this.setCoachPosition(c, c.settings.lead + pos);
127
+ const user = this.userService.get('user', {});
128
+ const adapter = this.deviceConfig.getSelected(incyclist_devices_1.IncyclistCapability.Control);
129
+ const bikeType = adapter.getCyclingMode().getSetting('bikeType') || 'Race';
130
+ c.initSimulator(user, bikeType);
131
+ c.start(onDataUpdate);
132
+ });
133
+ (0, utils_1.waitNextTick)().then(() => { this.activeRide.emit('started'); });
134
+ }
135
+ catch (err) {
136
+ this.logError(err, 'startRide');
137
+ }
138
+ return this.activeRide;
139
+ });
140
+ }
141
+ stopRide() {
142
+ return __awaiter(this, void 0, void 0, function* () {
143
+ try {
144
+ this.coaches.forEach(c => { c.stop(); });
145
+ this.isPaused = false;
146
+ delete this.activeRide;
147
+ }
148
+ catch (err) {
149
+ this.logError(err, 'stopRide');
150
+ }
151
+ });
152
+ }
153
+ pauseRide() {
154
+ try {
155
+ this.isPaused = true;
156
+ }
157
+ catch (err) {
158
+ this.logError(err, 'pauseRide');
159
+ }
160
+ }
161
+ resumeRide() {
162
+ try {
163
+ this.isPaused = false;
164
+ }
165
+ catch (err) {
166
+ this.logError(err, 'resumeRide');
167
+ }
63
168
  }
64
169
  updateRiderPosition(routeDistance) {
170
+ try {
171
+ this.coaches.forEach(c => { c.setRiderPosition(routeDistance); });
172
+ }
173
+ catch (err) {
174
+ this.logError(err, 'updateRiderPosition');
175
+ }
176
+ }
177
+ getCoachesRideInfo() {
178
+ try {
179
+ const a = [];
180
+ return a;
181
+ }
182
+ catch (err) {
183
+ this.logError(err, 'resumeRide');
184
+ }
185
+ }
186
+ onCoachDataUpdate(coach, data) {
187
+ if (this.isPaused)
188
+ return;
189
+ const startSettings = this.routesService.getStartSettings();
190
+ const { distance } = data;
191
+ const route = this.routesService.getSelected();
192
+ if (!route || !coach || !data)
193
+ return;
194
+ const prevRouteDistance = coach.getProgess();
195
+ const newRouteDistance = prevRouteDistance + data.distance;
196
+ coach.setProgress(newRouteDistance);
197
+ if (startSettings.type === 'Free-Ride')
198
+ return;
199
+ this.setCoachPosition(coach, distance);
200
+ }
201
+ setCoachPosition(coach, distance) {
202
+ if (!this.activeRide)
203
+ return;
204
+ const startSettings = this.routesService.getStartSettings();
205
+ const { realityFactor = 0 } = startSettings;
206
+ const route = this.routesService.getSelected();
207
+ const prevPosition = coach.getPosition() || route.points[0];
208
+ let nextPosition = undefined;
209
+ if (distance > 0) {
210
+ nextPosition = (0, route_1.getNextPosition)(route, { distance, prev: prevPosition });
211
+ if (nextPosition) {
212
+ const { slope } = nextPosition;
213
+ coach.sendDeviceUpdate({ slope: slope * realityFactor / 100 });
214
+ }
215
+ }
216
+ }
217
+ get routesService() {
218
+ return (0, routes_1.useRouteList)();
219
+ }
220
+ get rideService() {
221
+ return (0, devices_1.useDeviceRide)();
222
+ }
223
+ get deviceConfig() {
224
+ return (0, devices_1.useDeviceConfiguration)();
225
+ }
226
+ get pairingService() {
227
+ return (0, devices_1.useDevicePairing)();
228
+ }
229
+ get userService() {
230
+ return (0, settings_1.useUserSettings)();
65
231
  }
66
232
  };
67
233
  __setFunctionName(_classThis, "CoachesService");
@@ -1,13 +1,24 @@
1
- export type CoachType = 'Speed' | 'Power';
1
+ export type CoachType = 'speed' | 'power';
2
2
  export type CoachSettings = {
3
3
  name: string;
4
4
  type: CoachType;
5
5
  target: number;
6
6
  lead?: number;
7
7
  };
8
+ export type CoachEditProps = {
9
+ name: string;
10
+ type: string;
11
+ power?: number;
12
+ speed?: number;
13
+ lead?: number;
14
+ };
8
15
  export type CoachStatus = {
9
16
  routePosition?: number;
10
17
  riderPosition?: number;
11
18
  speed?: number;
12
19
  power?: number;
20
+ name: string;
21
+ avatar: string;
22
+ lat?: number;
23
+ lng?: number;
13
24
  };
@@ -514,6 +514,8 @@ class DeviceRideService extends events_1.default {
514
514
  if (ai.ivToCheck) {
515
515
  this.stopHealthCheck(ai);
516
516
  }
517
+ if (ai.adapter.getInterface() === 'simulator')
518
+ return;
517
519
  ai.ivToCheck = (0, timers_1.setInterval)(() => { check(); }, 1000);
518
520
  ai.isHealthy = true;
519
521
  }
package/lib/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export * from './devices';
2
2
  export * from './utils';
3
3
  export * from './api';
4
4
  export * from './routes';
5
+ export * from './coaches';
5
6
  export { useUserSettings, initUserSettings, UserSettingsService, UserSettingsBinding, IUserSettingsBinding } from './settings';
package/lib/index.js CHANGED
@@ -19,6 +19,7 @@ __exportStar(require("./devices"), exports);
19
19
  __exportStar(require("./utils"), exports);
20
20
  __exportStar(require("./api"), exports);
21
21
  __exportStar(require("./routes"), exports);
22
+ __exportStar(require("./coaches"), exports);
22
23
  var settings_1 = require("./settings");
23
24
  Object.defineProperty(exports, "useUserSettings", { enumerable: true, get: function () { return settings_1.useUserSettings; } });
24
25
  Object.defineProperty(exports, "initUserSettings", { enumerable: true, get: function () { return settings_1.initUserSettings; } });
@@ -1,3 +1,4 @@
1
+ import { LatLng } from "../../../utils/geo";
1
2
  import { RouteApiDetail } from "../api/types";
2
3
  import { Route } from "../model/route";
3
4
  import { RoutePoint, RouteSegment } from "../types";
@@ -8,3 +9,21 @@ export declare const validateRoute: (route: RouteApiDetail) => void;
8
9
  export declare const getTotalElevation: (route: RouteApiDetail) => number;
9
10
  export declare const getTotalDistance: (route: RouteApiDetail) => number;
10
11
  export declare const getRouteHash: (route: RouteApiDetail) => string;
12
+ export interface LapPoint extends RoutePoint {
13
+ lap?: number;
14
+ totalDistance?: number;
15
+ }
16
+ export interface GetNextPositionProps {
17
+ routeDistance?: number;
18
+ distance?: number;
19
+ prev?: LapPoint;
20
+ }
21
+ export declare const getNextPosition: (route: Route, props: GetNextPositionProps) => any;
22
+ interface GetPositionProps {
23
+ cnt?: number;
24
+ distance?: number;
25
+ nearest?: boolean;
26
+ latlng?: LatLng;
27
+ }
28
+ export declare const getPosition: (route: Route, props: GetPositionProps) => RoutePoint;
29
+ export {};
@@ -3,9 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getRouteHash = exports.getTotalDistance = exports.getTotalElevation = exports.validateRoute = exports.getSegments = exports.updateSlopes = exports.checkIsLoop = void 0;
6
+ exports.getPosition = exports.getNextPosition = exports.getRouteHash = exports.getTotalDistance = exports.getTotalElevation = exports.validateRoute = exports.getSegments = exports.updateSlopes = exports.checkIsLoop = void 0;
7
7
  const utils_1 = require("../../../utils");
8
8
  const geo_1 = require("../../../utils/geo");
9
+ const valid_1 = require("../../../utils/valid");
9
10
  const md5_1 = __importDefault(require("md5"));
10
11
  const MAX_LAPMODE_DISTANCE = 50;
11
12
  const checkIsLoop = (_route) => {
@@ -142,3 +143,146 @@ const getRouteHash = (route) => {
142
143
  return routeHash;
143
144
  };
144
145
  exports.getRouteHash = getRouteHash;
146
+ const getLapTotalDistance = (route, point) => {
147
+ const lap = (0, valid_1.valid)(point.lap) ? point.lap : 1;
148
+ return (lap - 1) * route.description.distance + point.routeDistance;
149
+ };
150
+ const getNextPosition = (route, props) => {
151
+ var _a;
152
+ const points = route.points;
153
+ if (props === undefined) {
154
+ return;
155
+ }
156
+ if (props.distance === undefined && props.routeDistance === undefined) {
157
+ return;
158
+ }
159
+ if (props.routeDistance === undefined && (props.prev === undefined || props.prev.routeDistance === undefined)) {
160
+ return;
161
+ }
162
+ const distance = props.distance !== undefined ? props.distance : props.routeDistance - getLapTotalDistance(route, props.prev);
163
+ const targetRouteDistance = props.routeDistance !== undefined ? props.routeDistance : getLapTotalDistance(route, props.prev) + distance;
164
+ let pPrev = props.prev || Object.assign(Object.assign({}, points[0]), { lap: 1 });
165
+ let point, p;
166
+ let lap = (0, valid_1.valid)(pPrev.lap) ? pPrev.lap : 1;
167
+ let cnt = ((_a = props.prev) === null || _a === void 0 ? void 0 : _a.cnt) || 0;
168
+ let targetRouteInLap;
169
+ if (route.description.isLoop) {
170
+ targetRouteInLap = targetRouteDistance % route.description.distance;
171
+ const prevTargetRouteinLap = props.prev.routeDistance;
172
+ if (prevTargetRouteinLap > targetRouteInLap) {
173
+ cnt = 0;
174
+ lap++;
175
+ }
176
+ }
177
+ else {
178
+ lap = 1;
179
+ targetRouteInLap = targetRouteDistance;
180
+ }
181
+ for (; cnt < points.length; cnt++) {
182
+ p = points[cnt];
183
+ if (p.routeDistance >= targetRouteInLap) {
184
+ point = Object.assign({}, p);
185
+ if (pPrev !== undefined) {
186
+ let pDest;
187
+ if (pPrev.cnt === point.cnt) {
188
+ pDest = utils_1.geo.getPointBetween(props.prev, p, distance);
189
+ }
190
+ else {
191
+ const distanceToPrev = targetRouteInLap - pPrev.routeDistance;
192
+ pDest = utils_1.geo.getPointBetween(pPrev, p, distanceToPrev);
193
+ point.cnt = pPrev.cnt;
194
+ }
195
+ point.lat = pDest.lat;
196
+ point.lng = pDest.lng;
197
+ point.routeDistance = targetRouteInLap;
198
+ point.distance = point.routeDistance - pPrev.routeDistance;
199
+ if (route.description.isLoop) {
200
+ point.lap = lap;
201
+ }
202
+ }
203
+ return point;
204
+ }
205
+ pPrev = p;
206
+ }
207
+ return;
208
+ };
209
+ exports.getNextPosition = getNextPosition;
210
+ const getPosition = (route, props) => {
211
+ if (props === undefined || route.points === undefined)
212
+ return;
213
+ const { cnt, distance, nearest = true, latlng } = props;
214
+ if (props.cnt !== undefined) {
215
+ return getPointAtIndex(route, cnt);
216
+ }
217
+ if (props.distance !== undefined) {
218
+ return getPointAtDistance(route, distance, nearest);
219
+ }
220
+ if (props.latlng !== undefined) {
221
+ return getPointAtLatLng(route, latlng, nearest);
222
+ }
223
+ };
224
+ exports.getPosition = getPosition;
225
+ const getPointAtIndex = (route, idx) => {
226
+ const points = route.points;
227
+ if (idx >= points.length || idx < 0)
228
+ return;
229
+ const point = Object.assign({}, points[idx]);
230
+ point.cnt = idx;
231
+ return point;
232
+ };
233
+ const getPointAtDistance = (route, routeDistance, nearest = true) => {
234
+ const points = route.points;
235
+ if (!points)
236
+ return;
237
+ const exact = !nearest;
238
+ let cnt = 0;
239
+ let closestDistance = undefined;
240
+ let point;
241
+ points.forEach(p => {
242
+ if (exact) {
243
+ if (p.routeDistance === routeDistance) {
244
+ point = Object.assign({}, p);
245
+ point.cnt = cnt;
246
+ }
247
+ }
248
+ else {
249
+ let distance = p.routeDistance - routeDistance;
250
+ if (distance < 0)
251
+ distance = distance * -1;
252
+ if (closestDistance === undefined || distance < closestDistance) {
253
+ point = Object.assign({}, p);
254
+ point.cnt = cnt;
255
+ closestDistance = distance;
256
+ }
257
+ }
258
+ cnt++;
259
+ });
260
+ return point;
261
+ };
262
+ const getPointAtLatLng = (route, latlng, nearest = true) => {
263
+ const points = route.points;
264
+ if (!points || !route.description.hasGpx)
265
+ return;
266
+ const exact = !nearest;
267
+ let cnt = 0;
268
+ let closestDistance = undefined;
269
+ let point;
270
+ points.forEach(p => {
271
+ if (exact) {
272
+ if (p.lat === latlng.lat && p.lng === latlng.lng) {
273
+ point = Object.assign({}, p);
274
+ point.cnt = cnt;
275
+ }
276
+ }
277
+ else {
278
+ const distance = Math.abs(utils_1.geo.calculateDistance(p.lat, p.lng, latlng.lat, latlng.lng));
279
+ if (closestDistance === undefined || distance < closestDistance) {
280
+ point = Object.assign({}, p);
281
+ point.cnt = cnt;
282
+ closestDistance = distance;
283
+ }
284
+ }
285
+ cnt++;
286
+ });
287
+ return point;
288
+ };