Commit a1b84834fc442964d221b678a1166d46810c02c5

Authored by Vladyslav_Prykhodko
1 parent 140ae29f

Update trip-animation widget

... ... @@ -130,7 +130,7 @@
130 130 "controllerScript": " self.onInit = function() {\n var $scope = self.ctx.$scope;\n $scope.self = self;\n }\n \n \n self.actionSources = function () {\n return {\n 'tooltipAction': {\n name: 'widget-action.tooltip-tag-action',\n multiple: false\n }\n }\n };\n \n self.getSettingsSchema = function() {\n return TbTripAnimationWidget.getSettingsSchema();\n}\n",
131 131 "settingsSchema": "",
132 132 "dataKeySettingsSchema": "{}",
133   - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 0 : value + 2)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 1 : value + 2)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"history\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":500}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"mapProvider\":\"OpenStreetMap.Mapnik\",\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"showTooltip\":true,\"tooltipColor\":\"#fff\",\"tooltipFontColor\":\"#000\",\"tooltipOpacity\":1,\"tooltipPattern\":\"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><b>End Time:</b> ${maxTime}<br/><b>Start Time:</b> ${minTime}\",\"strokeWeight\":2,\"strokeOpacity\":1,\"pointSize\":10,\"markerImageSize\":34,\"rotationAngle\":180,\"provider\":\"openstreet-map\",\"normalizationStep\":1000,\"polKeyName\":\"coordinates\",\"decoratorSymbol\":\"arrowHead\",\"decoratorSymbolSize\":10,\"decoratorCustomColor\":\"#000\",\"decoratorOffset\":\"20px\",\"endDecoratorOffset\":\"20px\",\"decoratorRepeat\":\"20px\",\"polygonTooltipPattern\":\"<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}\",\"polygonOpacity\":0.5,\"polygonStrokeOpacity\":1,\"polygonStrokeWeight\":1,\"pointTooltipOnRightPanel\":true,\"autocloseTooltip\":true},\"title\":\"Trip Animation\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":false,\"showLegend\":false,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"displayTimewindow\":true}"
  133 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 0 : (value + 2) % gpsData.length)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var gpsData = [\\n37.771210000, -122.510960000,\\n 37.771990000, -122.497070000,\\n 37.772730000, -122.480740000,\\n 37.773360000, -122.466870000,\\n 37.774270000, -122.458520000,\\n 37.771980000, -122.454110000,\\n 37.768250000, -122.453380000,\\n 37.765920000, -122.456810000,\\n 37.765930000, -122.467680000,\\n 37.765500000, -122.477180000,\\n 37.765300000, -122.481660000,\\n 37.764780000, -122.493350000,\\n 37.764120000, -122.508360000,\\n 37.766410000, -122.510260000,\\n 37.770010000, -122.510830000,\\n 37.770980000, -122.510930000\\n];\\n let value = gpsData.indexOf(prevValue); \\nreturn gpsData[(value == -1 ? 1 : (value + 2) % gpsData.length)];\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"history\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":500}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"mapProvider\":\"OpenStreetMap.Mapnik\",\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"showTooltip\":true,\"tooltipColor\":\"#fff\",\"tooltipFontColor\":\"#000\",\"tooltipOpacity\":1,\"tooltipPattern\":\"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><b>End Time:</b> ${maxTime}<br/><b>Start Time:</b> ${minTime}\",\"strokeWeight\":2,\"strokeOpacity\":1,\"pointSize\":10,\"markerImageSize\":34,\"rotationAngle\":180,\"provider\":\"openstreet-map\",\"normalizationStep\":1000,\"polKeyName\":\"coordinates\",\"decoratorSymbol\":\"arrowHead\",\"decoratorSymbolSize\":10,\"decoratorCustomColor\":\"#000\",\"decoratorOffset\":\"20px\",\"endDecoratorOffset\":\"20px\",\"decoratorRepeat\":\"20px\",\"polygonTooltipPattern\":\"<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}\",\"polygonOpacity\":0.5,\"polygonStrokeOpacity\":1,\"polygonStrokeWeight\":1,\"pointTooltipOnRightPanel\":true,\"autocloseTooltip\":true},\"title\":\"Trip Animation\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":false,\"showLegend\":false,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"displayTimewindow\":true}"
134 134 }
135 135 },
136 136 {
... ... @@ -150,4 +150,4 @@
150 150 }
151 151 }
152 152 ]
153   -}
\ No newline at end of file
  153 +}
... ...
... ... @@ -7969,14 +7969,6 @@
7969 7969 "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.6.0.tgz",
7970 7970 "integrity": "sha512-CPkhyqWUKZKFJ6K8umN5/D2wrJ2+/8UIpXppY7QDnUZW5bZL5+SEI2J7GBpwh4LIupOKqbNSQXgqmrEJopHVNQ=="
7971 7971 },
7972   - "leaflet-geometryutil": {
7973   - "version": "0.9.3",
7974   - "resolved": "https://registry.npmjs.org/leaflet-geometryutil/-/leaflet-geometryutil-0.9.3.tgz",
7975   - "integrity": "sha512-Wi6YvfNx/Xu9q35AEfXpsUXmIFLen/MO+C2qimxHRnjyeyOxBhdcZa6kSiReaOX0cGK7yQInqrzz0dkIqZ8Dpg==",
7976   - "requires": {
7977   - "leaflet": ">=0.7.0"
7978   - }
7979   - },
7980 7972 "leaflet-polylinedecorator": {
7981 7973 "version": "1.6.0",
7982 7974 "resolved": "https://registry.npmjs.org/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz",
... ...
... ... @@ -58,7 +58,6 @@
58 58 "jstree-bootstrap-theme": "^1.0.1",
59 59 "jszip": "^3.4.0",
60 60 "leaflet": "^1.6.0",
61   - "leaflet-geometryutil": "^0.9.3",
62 61 "leaflet-polylinedecorator": "^1.6.0",
63 62 "leaflet-providers": "^1.9.1",
64 63 "leaflet.gridlayer.googlemutant": "0.8.0",
... ...
... ... @@ -56,6 +56,19 @@ export function getRatio(firsMoment: number, secondMoment: number, intermediateM
56 56 return (intermediateMoment - firsMoment) / (secondMoment - firsMoment);
57 57 }
58 58
  59 +export function interpolateOnLineSegment(
  60 + pointA: FormattedData,
  61 + oointB: FormattedData,
  62 + latKeyName: string,
  63 + lngKeyName: string,
  64 + ratio: number
  65 +): { [key: string]: number } {
  66 + return {
  67 + [latKeyName]: (pointA[latKeyName] + (oointB[latKeyName] - pointA[latKeyName]) * ratio),
  68 + [lngKeyName]: (pointA[lngKeyName] + (oointB[lngKeyName] - pointA[lngKeyName]) * ratio)
  69 + };
  70 +}
  71 +
59 72 export function findAngle(startPoint: FormattedData, endPoint: FormattedData, latKeyName: string, lngKeyName: string): number {
60 73 let angle = -Math.atan2(endPoint[latKeyName] - startPoint[latKeyName], endPoint[lngKeyName] - startPoint[lngKeyName]);
61 74 angle = angle * 180 / Math.PI;
... ...
... ... @@ -841,52 +841,57 @@ export const pathSchema =
841 841 };
842 842
843 843 export const pointSchema =
844   -{
  844 + {
845 845 schema: {
846   - title: 'Trip Animation Path Configuration',
847   - type: 'object',
848   - properties: {
849   - showPoints: {
850   - title: 'Show points',
851   - type: 'boolean',
852   - default: false
853   - },
854   - pointColor: {
855   - title: 'Point color',
856   - type: 'string'
857   - },
858   - pointSize: {
859   - title: 'Point size (px)',
860   - type: 'number',
861   - default: 10
862   - },
863   - usePointAsAnchor: {
864   - title: 'Use point as anchor',
865   - type: 'boolean',
866   - default: false
867   - },
868   - pointAsAnchorFunction: {
869   - title: 'Point as anchor function: f(data, dsData, dsIndex)',
870   - type: 'string'
871   - },
872   - pointTooltipOnRightPanel: {
873   - title: 'Independant point tooltip',
874   - type: 'boolean',
875   - default: true
876   - },
  846 + title: 'Trip Animation Path Configuration',
  847 + type: 'object',
  848 + properties: {
  849 + showPoints: {
  850 + title: 'Show points',
  851 + type: 'boolean',
  852 + default: false
877 853 },
878   - required: []
  854 + pointColor: {
  855 + title: 'Point color',
  856 + type: 'string'
  857 + },
  858 + pointSize: {
  859 + title: 'Point size (px)',
  860 + type: 'number',
  861 + default: 10
  862 + },
  863 + // usePointAsAnchor: {
  864 + // title: 'Use point as anchor',
  865 + // type: 'boolean',
  866 + // default: false
  867 + // },
  868 + // pointAsAnchorFunction: {
  869 + // title: 'Point as anchor function: f(data, dsData, dsIndex)',
  870 + // type: 'string'
  871 + // },
  872 + pointTooltipOnRightPanel: {
  873 + title: 'Independant point tooltip',
  874 + type: 'boolean',
  875 + default: true
  876 + },
  877 + },
  878 + required: []
879 879 },
880 880 form: [
881   - 'showPoints', {
882   - key: 'pointColor',
883   - type: 'color'
884   - }, 'pointSize', 'usePointAsAnchor', {
885   - key: 'pointAsAnchorFunction',
886   - type: 'javascript'
887   - }, 'pointTooltipOnRightPanel',
  881 + 'showPoints',
  882 + {
  883 + key: 'pointColor',
  884 + type: 'color'
  885 + },
  886 + 'pointSize',
  887 + // 'usePointAsAnchor',
  888 + // {
  889 + // key: 'pointAsAnchorFunction',
  890 + // type: 'javascript'
  891 + // },
  892 + 'pointTooltipOnRightPanel',
888 893 ]
889   -};
  894 + };
890 895
891 896 export const mapProviderSchema =
892 897 {
... ...
... ... @@ -32,6 +32,10 @@
32 32 [ngStyle]="{'background-color': settings.tooltipColor, 'opacity': settings.tooltipOpacity, 'color': settings.tooltipFontColor}">
33 33 </div>
34 34 </div>
35   - <tb-history-selector *ngIf="historicalData" [settings]="settings" [intervals]="intervals" [anchors]="anchors" [useAnchors]="useAnchors"
36   - (timeUpdated)="timeUpdated($event)"></tb-history-selector>
37   -</div>
\ No newline at end of file
  35 + <tb-history-selector *ngIf="historicalData"
  36 + [settings]="settings"
  37 + [minTime]="minTime"
  38 + [maxTime]="maxTime"
  39 + [step]="normalizationStep"
  40 + (timeUpdated)="timeUpdated($event)"></tb-history-selector>
  41 +</div>
... ...
... ... @@ -14,10 +14,8 @@
14 14 /// limitations under the License.
15 15 ///
16 16
17   -import L from 'leaflet';
18 17 import _ from 'lodash';
19 18 import tinycolor from 'tinycolor2';
20   -import { interpolateOnPointSegment } from 'leaflet-geometryutil';
21 19
22 20 import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, SecurityContext, ViewChild } from '@angular/core';
23 21 import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2';
... ... @@ -26,9 +24,17 @@ import { addCondition, addGroupInfo, addToSchema, initSchema } from '@app/core/s
26 24 import { mapPolygonSchema, pathSchema, pointSchema, tripAnimationSchema } from '../lib/maps/schemes';
27 25 import { DomSanitizer } from '@angular/platform-browser';
28 26 import { WidgetContext } from '@app/modules/home/models/widget-component.models';
29   -import { findAngle, getRatio, parseArray, parseWithTranslation, safeExecute } from '../lib/maps/maps-utils';
  27 +import {
  28 + findAngle,
  29 + getRatio,
  30 + interpolateOnLineSegment,
  31 + parseArray,
  32 + parseWithTranslation,
  33 + safeExecute
  34 +} from '../lib/maps/maps-utils';
30 35 import { JsonSettingsSchema, WidgetConfig } from '@shared/models/widget.models';
31 36 import moment from 'moment';
  37 +import { isUndefined } from '@core/utils';
32 38
33 39
34 40 @Component({
... ... @@ -46,20 +52,21 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
46 52 @ViewChild('map') mapContainer;
47 53
48 54 mapWidget: MapWidgetController;
49   - historicalData;
50   - intervals;
51   - normalizationStep = 1000;
52   - interpolatedData = [];
  55 + historicalData: FormattedData[][];
  56 + normalizationStep: number;
  57 + interpolatedTimeData = [];
53 58 widgetConfig: WidgetConfig;
54 59 settings;
55 60 mainTooltip = '';
56 61 visibleTooltip = false;
57   - activeTrip;
  62 + activeTrip: FormattedData;
58 63 label;
59   - minTime;
60   - maxTime;
  64 + minTime: number;
  65 + minTimeFormat: string;
  66 + maxTime: number;
  67 + maxTimeFormat: string;
61 68 anchors = [];
62   - useAnchors = false;
  69 + useAnchors: boolean;
63 70
64 71 static getSettingsSchema(): JsonSettingsSchema {
65 72 const schema = initSchema();
... ... @@ -95,7 +102,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
95 102 this.historicalData = parseArray(this.ctx.data);
96 103 this.activeTrip = this.historicalData[0][0];
97 104 this.calculateIntervals();
98   - this.timeUpdated(this.intervals[0]);
  105 + this.timeUpdated(this.minTime);
99 106 this.mapWidget.map.map?.invalidateSize();
100 107 this.cd.detectChanges();
101 108 }
... ... @@ -108,23 +115,37 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
108 115 }
109 116
110 117 timeUpdated(time: number) {
111   - const currentPosition = this.interpolatedData.map(dataSource => dataSource[time]);
  118 + const currentPosition = this.interpolatedTimeData.map(dataSource => dataSource[time]);
  119 + if(isUndefined(currentPosition[0])){
  120 + const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10));
  121 + for (let i = 1; i < timePoints.length; i++) {
  122 + if (timePoints[i - 1] < time && timePoints[i] > time) {
  123 + const beforePosition = this.interpolatedTimeData[0][timePoints[i - 1]];
  124 + const afterPosition = this.interpolatedTimeData[0][timePoints[i]];
  125 + const ratio = getRatio(timePoints[i - 1], timePoints[i], time);
  126 + currentPosition[0] = {
  127 + ...beforePosition,
  128 + time,
  129 + ...interpolateOnLineSegment(beforePosition, afterPosition, this.settings.latKeyName, this.settings.lngKeyName, ratio)
  130 + }
  131 + break;
  132 + }
  133 + }
  134 + }
112 135 this.activeTrip = currentPosition[0];
113   - this.minTime = moment(this.intervals[this.intervals.length - 1]).format('YYYY-MM-DD HH:mm:ss')
114   - this.maxTime = moment(this.intervals[0]).format('YYYY-MM-DD HH:mm:ss')
115 136 this.calcLabel();
116 137 this.calcTooltip();
117 138 if (this.mapWidget) {
118   - this.mapWidget.map.updatePolylines(this.interpolatedData.map(ds => _.values(ds)));
  139 + this.mapWidget.map.updatePolylines(this.interpolatedTimeData.map(ds => _.values(ds)));
119 140 if (this.settings.showPolygon) {
120   - this.mapWidget.map.updatePolygons(this.interpolatedData);
  141 + this.mapWidget.map.updatePolygons(this.interpolatedTimeData);
121 142 }
122 143 if (this.settings.showPoints) {
123   - this.mapWidget.map.updatePoints(this.historicalData[0], this.calcTooltip);
124   - this.anchors = this.historicalData[0]
125   - .filter(data =>
126   - this.settings.usePointAsAnchor ||
127   - safeExecute(this.settings.pointAsAnchorFunction, [this.historicalData, data, data.dsIndex])).map(data => data.time);
  144 + this.mapWidget.map.updatePoints(this.interpolatedTimeData, this.calcTooltip);
  145 + // this.anchors = this.interpolatedTimeData
  146 + // .filter(data =>
  147 + // this.settings.usePointAsAnchor ||
  148 + // safeExecute(this.settings.pointAsAnchorFunction, [this.interpolatedTimeData, data, data.dsIndex])).map(data => data.time);
128 149 }
129 150 this.mapWidget.map.updateMarkers(currentPosition);
130 151 }
... ... @@ -135,12 +156,11 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
135 156
136 157 calculateIntervals() {
137 158 this.historicalData.forEach((dataSource, index) => {
138   - this.intervals = [];
139   - for (let time = dataSource[0]?.time; time < dataSource[dataSource.length - 1]?.time; time += this.normalizationStep) {
140   - this.intervals.push(time);
141   - }
142   - this.intervals.push(dataSource[dataSource.length - 1]?.time);
143   - this.interpolatedData[index] = this.interpolateArray(dataSource, this.intervals);
  159 + this.minTime = dataSource[0]?.time || Infinity;
  160 + this.minTimeFormat = this.minTime !== Infinity ? moment(this.minTime).format('YYYY-MM-DD HH:mm:ss') : '';
  161 + this.maxTime = dataSource[dataSource.length - 1]?.time || -Infinity;
  162 + this.maxTimeFormat = this.maxTime !== -Infinity ? moment(this.maxTime).format('YYYY-MM-DD HH:mm:ss') : '';
  163 + this.interpolatedTimeData[index] = this.interpolateArray(dataSource);
144 164 });
145 165
146 166 }
... ... @@ -149,9 +169,13 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
149 169 if (!point) {
150 170 point = this.activeTrip;
151 171 }
152   - const data = { ...point, maxTime: this.maxTime, minTime: this.minTime }
  172 + const data = {
  173 + ...this.activeTrip,
  174 + maxTime: this.maxTimeFormat,
  175 + minTime: this.minTimeFormat
  176 + }
153 177 const tooltipPattern: string = this.settings.useTooltipFunction ?
154   - safeExecute(this.settings.tooolTipFunction, [data, this.historicalData, 0]) : this.settings.tooltipPattern;
  178 + safeExecute(this.settings.tooolTipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern;
155 179 const tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true);
156 180 if (setTooltip) {
157 181 this.mainTooltip = this.sanitizer.sanitize(
... ... @@ -162,34 +186,37 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
162 186 }
163 187
164 188 calcLabel() {
165   - const data = { ...this.activeTrip, maxTime: this.maxTime, minTime: this.minTime }
  189 + const data = {
  190 + ...this.activeTrip,
  191 + maxTime: this.maxTimeFormat,
  192 + minTime: this.minTimeFormat
  193 + }
166 194 const labelText: string = this.settings.useLabelFunction ?
167   - safeExecute(this.settings.labelFunction, [data, this.historicalData, 0]) : this.settings.label;
  195 + safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label;
168 196 this.label = (parseWithTranslation.parseTemplate(labelText, data, true));
169 197 }
170 198
171   - interpolateArray(originData, interpolatedIntervals) {
  199 + interpolateArray(originData: FormattedData[]) {
172 200 const result = {};
173   - for (let i = 1, j = 0; i < originData.length && j < interpolatedIntervals.length;) {
174   - const currentTime = interpolatedIntervals[j];
175   - while (originData[i].time < currentTime) i++;
176   - const before = originData[i - 1];
177   - const after = originData[i];
178   - const interpolation = interpolateOnPointSegment(
179   - new L.Point(before[this.settings.latKeyName], before[this.settings.lngKeyName]),
180   - new L.Point(after[this.settings.latKeyName], after[this.settings.lngKeyName]),
181   - getRatio(before.time, after.time, currentTime));
182   - result[currentTime] = ({
183   - ...originData[i],
184   - rotationAngle: findAngle(before, after, this.settings.latKeyName, this.settings.lngKeyName) + this.settings.rotationAngle,
185   - latitude: interpolation.x,
186   - longitude: interpolation.y
187   - });
188   - j++;
  201 + const latKeyName = this.settings.latKeyName;
  202 + const lngKeyName = this.settings.lngKeyName;
  203 + for (let i = 0; i < originData.length; i++) {
  204 + const currentTime = originData[i].time;
  205 + const normalizeTime = this.minTime + Math.ceil((currentTime - this.minTime) / this.normalizationStep) * this.normalizationStep;
  206 + if (i !== originData.length - 1) {
  207 + result[normalizeTime] = {
  208 + ...originData[i],
  209 + rotationAngle: this.settings.rotationAngle + findAngle(originData[i], originData[i + 1], latKeyName, lngKeyName)
  210 + };
  211 + } else {
  212 + result[normalizeTime] = {
  213 + ...originData[i],
  214 + rotationAngle: findAngle(originData[i - 1], originData[i], latKeyName, lngKeyName) + this.settings.rotationAngle
  215 + };
  216 + }
189 217 }
190 218 return result;
191 219 }
192 220 }
193 221
194 222 export let TbTripAnimationWidget = TripAnimationComponent;
195   -
... ...
... ... @@ -27,8 +27,8 @@
27 27 <mat-slider [(ngModel)]="index" [min]="minTimeIndex" [max]="maxTimeIndex" (change)="changeIndex()">
28 28 </mat-slider>
29 29 <div class="panel-timer">
30   - <span *ngIf="this.intervals[this.index]">{{ this.intervals[this.index] | date:'medium'}}</span>
31   - <span *ngIf="!this.intervals[this.index]">{{ "widget.no-data-found" | translate}}</span>
  30 + <span *ngIf="this.currentTime">{{ this.currentTime | date:'medium'}}</span>
  31 + <span *ngIf="!this.currentTime">{{ "widget.no-data-found" | translate}}</span>
32 32 </div>
33 33 </div>
34 34 <button mat-icon-button class="mat-icon-button" aria-label="Next" (click)="moveNext()">
... ... @@ -47,8 +47,9 @@
47 47 pause_circle_outline
48 48 </mat-icon>
49 49 </button>
50   - <mat-select matInput [(ngModel)]="speed" (selectionChange)="reeneble()" class="speed-select"
  50 + <mat-select [(ngModel)]="speed" (selectionChange)="reeneble()" class="speed-select"
51 51 aria-label="Speed selector">
52 52 <mat-option [value]="speedValue" *ngFor="let speedValue of speeds">{{speedValue}} </mat-option>
53 53 </mat-select>
54   - </div>
\ No newline at end of file
  54 + </div>
  55 +</div>
... ...
... ... @@ -14,7 +14,7 @@
14 14 /// limitations under the License.
15 15 ///
16 16
17   -import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
  17 +import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
18 18 import { interval } from 'rxjs';
19 19 import { filter } from 'rxjs/operators';
20 20 import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/maps/map-models';
... ... @@ -27,13 +27,12 @@ import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/m
27 27 export class HistorySelectorComponent implements OnInit, OnChanges {
28 28
29 29 @Input() settings: HistorySelectSettings
30   - @Input() intervals = [];
31   - @Input() anchors = [];
32   - @Input() useAnchors = false;
  30 + @Input() minTime: number;
  31 + @Input() maxTime: number;
  32 + @Input() step = 1000;
33 33
34 34 @Output() timeUpdated: EventEmitter<number> = new EventEmitter();
35 35
36   - animationTime;
37 36 minTimeIndex = 0;
38 37 maxTimeIndex = 0;
39 38 speed = 1;
... ... @@ -41,6 +40,7 @@ export class HistorySelectorComponent implements OnInit, OnChanges {
41 40 playing = false;
42 41 interval;
43 42 speeds = [1, 5, 10, 25];
  43 + currentTime = null;
44 44
45 45
46 46 constructor(private cd: ChangeDetectorRef) { }
... ... @@ -49,7 +49,8 @@ export class HistorySelectorComponent implements OnInit, OnChanges {
49 49 }
50 50
51 51 ngOnChanges() {
52   - this.maxTimeIndex = this.intervals?.length - 1;
  52 + this.maxTimeIndex = Math.ceil((this.maxTime - this.minTime) / this.step);
  53 + this.currentTime = this.minTime === Infinity ? null : this.minTime;
53 54 }
54 55
55 56 play() {
... ... @@ -59,17 +60,18 @@ export class HistorySelectorComponent implements OnInit, OnChanges {
59 60 .pipe(
60 61 filter(() => this.playing)).subscribe(() => {
61 62 this.index++;
62   - if (this.index < this.maxTimeIndex) {
  63 + this.currentTime = this.minTime + this.index * this.step;
  64 + if (this.index <= this.maxTimeIndex) {
63 65 this.cd.detectChanges();
64   - this.timeUpdated.emit(this.intervals[this.index]);
  66 + this.timeUpdated.emit(this.currentTime);
65 67 }
66 68 else {
67 69 this.interval.complete();
68 70 }
69 71 }, err => {
70   - console.log(err);
  72 + console.error(err);
71 73 }, () => {
72   - this.index = this.minTimeIndex;
  74 + this.currentTime = this.index = this.minTimeIndex;
73 75 this.playing = false;
74 76 this.interval = null;
75 77 this.cd.detectChanges();
... ... @@ -87,30 +89,21 @@ export class HistorySelectorComponent implements OnInit, OnChanges {
87 89
88 90 pause() {
89 91 this.playing = false;
  92 + this.currentTime = this.minTime + this.index * this.step;
90 93 this.cd.detectChanges();
91   - this.timeUpdated.emit(this.intervals[this.index]);
  94 + this.timeUpdated.emit(this.currentTime);
92 95 }
93 96
94 97 moveNext() {
95   - if (this.index < this.maxTimeIndex) {
96   - if (this.useAnchors) {
97   - const anchorIndex = this.findIndex(this.intervals[this.index], this.anchors)+1;
98   - this.index = this.findIndex(this.anchors[anchorIndex], this.intervals);
99   - }
100   - else
101   - this.index++;
  98 + if (this.index <= this.maxTimeIndex) {
  99 + this.index++;
102 100 }
103 101 this.pause();
104 102 }
105 103
106 104 movePrev() {
107 105 if (this.index > this.minTimeIndex) {
108   - if (this.useAnchors) {
109   - const anchorIndex = this.findIndex(this.intervals[this.index], this.anchors) - 1;
110   - this.index = this.findIndex(this.anchors[anchorIndex], this.intervals);
111   - }
112   - else
113   - this.index--;
  106 + this.index--;
114 107 }
115 108 this.pause();
116 109 }
... ... @@ -125,15 +118,8 @@ export class HistorySelectorComponent implements OnInit, OnChanges {
125 118 this.pause();
126 119 }
127 120
128   - findIndex(value, array: any[]) {
129   - let i = 0;
130   - while (array[i] < value) {
131   - i++;
132   - };
133   - return i;
134   - }
135   -
136 121 changeIndex() {
137   - this.timeUpdated.emit(this.intervals[this.index]);
  122 + this.currentTime = this.minTime + this.index * this.step;
  123 + this.timeUpdated.emit(this.currentTime);
138 124 }
139 125 }
... ...