Commit b990349c8b962510c6aa227a4bc8ec1efd633612

Authored by Igor Kulikov
Committed by GitHub
2 parents 1702ba55 aac5b0e7

Merge pull request #2799 from ArtemHalushko/trip-select

Trip select
@@ -20,12 +20,12 @@ import 'leaflet-providers'; @@ -20,12 +20,12 @@ import 'leaflet-providers';
20 import 'leaflet.markercluster/dist/leaflet.markercluster'; 20 import 'leaflet.markercluster/dist/leaflet.markercluster';
21 21
22 import { 22 import {
23 - FormattedData,  
24 - MapSettings,  
25 - MarkerSettings,  
26 - PolygonSettings,  
27 - PolylineSettings,  
28 - UnitedMapSettings 23 + FormattedData,
  24 + MapSettings,
  25 + MarkerSettings,
  26 + PolygonSettings,
  27 + PolylineSettings,
  28 + UnitedMapSettings
29 } from './map-models'; 29 } from './map-models';
30 import { Marker } from './markers'; 30 import { Marker } from './markers';
31 import { BehaviorSubject, Observable } from 'rxjs'; 31 import { BehaviorSubject, Observable } from 'rxjs';
@@ -158,9 +158,9 @@ export default abstract class LeafletMap { @@ -158,9 +158,9 @@ export default abstract class LeafletMap {
158 this.map = map; 158 this.map = map;
159 if (this.options.useDefaultCenterPosition) { 159 if (this.options.useDefaultCenterPosition) {
160 this.map.panTo(this.options.defaultCenterPosition); 160 this.map.panTo(this.options.defaultCenterPosition);
161 - this.bounds = map.getBounds(); 161 + this.bounds = map.getBounds();
162 } 162 }
163 - else this.bounds = new L.LatLngBounds(null, null); 163 + else this.bounds = new L.LatLngBounds(null, null);
164 if (this.options.draggableMarker) { 164 if (this.options.draggableMarker) {
165 this.addMarkerControl(); 165 this.addMarkerControl();
166 } 166 }
@@ -244,7 +244,7 @@ export default abstract class LeafletMap { @@ -244,7 +244,7 @@ export default abstract class LeafletMap {
244 } 244 }
245 245
246 // Markers 246 // Markers
247 - updateMarkers(markersData) { 247 + updateMarkers(markersData, callback?) {
248 markersData.filter(mdata => !!this.convertPosition(mdata)).forEach(data => { 248 markersData.filter(mdata => !!this.convertPosition(mdata)).forEach(data => {
249 if (data.rotationAngle || data.rotationAngle === 0) { 249 if (data.rotationAngle || data.rotationAngle === 0) {
250 const currentImage = this.options.useMarkerImageFunction ? 250 const currentImage = this.options.useMarkerImageFunction ?
@@ -265,7 +265,7 @@ export default abstract class LeafletMap { @@ -265,7 +265,7 @@ export default abstract class LeafletMap {
265 this.updateMarker(data.entityName, data, markersData, this.options) 265 this.updateMarker(data.entityName, data, markersData, this.options)
266 } 266 }
267 else { 267 else {
268 - this.createMarker(data.entityName, data, markersData, this.options as MarkerSettings); 268 + this.createMarker(data.entityName, data, markersData, this.options as MarkerSettings, callback);
269 } 269 }
270 }); 270 });
271 this.markersData = markersData; 271 this.markersData = markersData;
@@ -276,9 +276,11 @@ export default abstract class LeafletMap { @@ -276,9 +276,11 @@ export default abstract class LeafletMap {
276 this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) }); 276 this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) });
277 } 277 }
278 278
279 - private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings) { 279 + private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, callback?) {
280 this.ready$.subscribe(() => { 280 this.ready$.subscribe(() => {
281 const newMarker = new Marker(this.convertPosition(data), settings, data, dataSources, this.dragMarker); 281 const newMarker = new Marker(this.convertPosition(data), settings, data, dataSources, this.dragMarker);
  282 + if (callback)
  283 + newMarker.leafletMarker.on('click', () => { callback(data, true) });
282 if (this.bounds) 284 if (this.bounds)
283 this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng())); 285 this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()));
284 this.markers.set(key, newMarker); 286 this.markers.set(key, newMarker);
@@ -344,41 +346,58 @@ export default abstract class LeafletMap { @@ -344,41 +346,58 @@ export default abstract class LeafletMap {
344 // Polyline 346 // Polyline
345 347
346 updatePolylines(polyData: FormattedData[][], data?: FormattedData) { 348 updatePolylines(polyData: FormattedData[][], data?: FormattedData) {
347 - polyData.forEach((dataSource) => {  
348 - if (dataSource.length) {  
349 - data = data || dataSource[0];  
350 - if (this.polylines.get(data.$datasource.entityName)) { 349 + polyData.forEach((dataSource: FormattedData[]) => {
  350 + data = data || dataSource[0];
  351 + if (dataSource.length && data.entityName === dataSource[0].entityName) {
  352 + if (this.polylines.get(data.entityName)) {
351 this.updatePolyline(data, dataSource, this.options); 353 this.updatePolyline(data, dataSource, this.options);
352 } 354 }
353 else { 355 else {
354 this.createPolyline(data, dataSource, this.options); 356 this.createPolyline(data, dataSource, this.options);
355 } 357 }
356 } 358 }
  359 + else {
  360 + if (data)
  361 + this.removePolyline(dataSource[0]?.entityName)
  362 + }
357 }) 363 })
358 } 364 }
359 365
360 createPolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) { 366 createPolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) {
361 this.ready$.subscribe(() => { 367 this.ready$.subscribe(() => {
362 const poly = new Polyline(this.map, 368 const poly = new Polyline(this.map,
363 - dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); 369 + dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings);
364 const bounds = poly.leafletPoly.getBounds(); 370 const bounds = poly.leafletPoly.getBounds();
365 this.fitBounds(bounds); 371 this.fitBounds(bounds);
366 - this.polylines.set(data.$datasource.entityName, poly); 372 + this.polylines.set(data.entityName, poly);
367 }); 373 });
368 } 374 }
369 375
370 updatePolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) { 376 updatePolyline(data: FormattedData, dataSources: FormattedData[], settings: PolylineSettings) {
371 this.ready$.subscribe(() => { 377 this.ready$.subscribe(() => {
372 - const poly = this.polylines.get(data.$datasource.entityName); 378 + const poly = this.polylines.get(data.entityName);
  379 + const oldBounds = poly.leafletPoly.getBounds();
373 poly.updatePolyline(dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); 380 poly.updatePolyline(dataSources.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings);
  381 + const newBounds = poly.leafletPoly.getBounds();
  382 + if (oldBounds.toBBoxString() !== newBounds.toBBoxString()) {
  383 + this.fitBounds(newBounds);
  384 + }
374 }); 385 });
375 } 386 }
376 387
  388 + removePolyline(name: string) {
  389 + const poly = this.polylines.get(name);
  390 + if (poly) {
  391 + this.map.removeLayer(poly.leafletPoly);
  392 + this.polylines.delete(name);
  393 + }
  394 + }
  395 +
377 // Polygon 396 // Polygon
378 397
379 updatePolygons(polyData: FormattedData[]) { 398 updatePolygons(polyData: FormattedData[]) {
380 polyData.forEach((data: FormattedData) => { 399 polyData.forEach((data: FormattedData) => {
381 - if (data.hasOwnProperty(this.options.polygonKeyName)) { 400 + if (data && data.hasOwnProperty(this.options.polygonKeyName)) {
382 if (typeof (data[this.options.polygonKeyName]) === 'string') { 401 if (typeof (data[this.options.polygonKeyName]) === 'string') {
383 data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]) as LatLngTuple[]; 402 data[this.options.polygonKeyName] = JSON.parse(data[this.options.polygonKeyName]) as LatLngTuple[];
384 } 403 }
@@ -403,8 +422,13 @@ export default abstract class LeafletMap { @@ -403,8 +422,13 @@ export default abstract class LeafletMap {
403 422
404 updatePolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { 423 updatePolygon(polyData: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
405 this.ready$.subscribe(() => { 424 this.ready$.subscribe(() => {
406 - const poly = this.polygons.get(polyData.$datasource.entityName); 425 + const poly = this.polygons.get(polyData.entityName);
  426 + const oldBounds = poly.leafletPoly.getBounds();
407 poly.updatePolygon(polyData, dataSources, settings); 427 poly.updatePolygon(polyData, dataSources, settings);
  428 + const newBounds = poly.leafletPoly.getBounds();
  429 + if (oldBounds.toBBoxString() !== newBounds.toBBoxString()) {
  430 + this.fitBounds(newBounds);
  431 + }
408 }); 432 });
409 } 433 }
410 } 434 }
@@ -26,6 +26,7 @@ import { @@ -26,6 +26,7 @@ import {
26 26
27 export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; 27 export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
28 export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; 28 export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
  29 +export type GetTooltip= (point: FormattedData, setTooltip?: boolean) => string;
29 30
30 export type MapSettings = { 31 export type MapSettings = {
31 draggableMarker: boolean; 32 draggableMarker: boolean;
@@ -69,7 +69,6 @@ export class MapWidgetController implements MapWidgetInterface { @@ -69,7 +69,6 @@ export class MapWidgetController implements MapWidgetInterface {
69 this.settings.markerClick = this.getDescriptors('markerClick'); 69 this.settings.markerClick = this.getDescriptors('markerClick');
70 this.settings.polygonClick = this.getDescriptors('polygonClick'); 70 this.settings.polygonClick = this.getDescriptors('polygonClick');
71 71
72 - // this.settings.  
73 const MapClass = providerSets[this.provider]?.MapClass; 72 const MapClass = providerSets[this.provider]?.MapClass;
74 if (!MapClass) { 73 if (!MapClass) {
75 return; 74 return;
@@ -258,7 +258,7 @@ export function parseArray(input: any[]): any[] { @@ -258,7 +258,7 @@ export function parseArray(input: any[]): any[] {
258 time: el[0], 258 time: el[0],
259 deviceType: null 259 deviceType: null
260 }; 260 };
261 - entityArray.filter(e => e.data.length).forEach(entity => { 261 + entityArray.filter(e => e.data.length && e.data[i]).forEach(entity => {
262 obj[entity?.dataKey?.label] = entity?.data[i][1]; 262 obj[entity?.dataKey?.label] = entity?.data[i][1];
263 obj[entity?.dataKey?.label + '|ts'] = entity?.data[0][0]; 263 obj[entity?.dataKey?.label + '|ts'] = entity?.data[0][0];
264 if (entity?.dataKey?.label === 'type') { 264 if (entity?.dataKey?.label === 'type') {
@@ -65,7 +65,6 @@ export class Polyline { @@ -65,7 +65,6 @@ export class Polyline {
65 this.dataSources = dataSources; 65 this.dataSources = dataSources;
66 this.leafletPoly.setLatLngs(locations); 66 this.leafletPoly.setLatLngs(locations);
67 this.leafletPoly.setStyle(this.getPolyStyle(settings)); 67 this.leafletPoly.setStyle(this.getPolyStyle(settings));
68 - // this.setPolylineLatLngs(data);  
69 if (this.polylineDecorator) 68 if (this.polylineDecorator)
70 this.polylineDecorator.setPaths(this.leafletPoly); 69 this.polylineDecorator.setPaths(this.leafletPoly);
71 } 70 }
@@ -92,8 +91,4 @@ export class Polyline { @@ -92,8 +91,4 @@ export class Polyline {
92 getPolylineLatLngs() { 91 getPolylineLatLngs() {
93 return this.leafletPoly.getLatLngs(); 92 return this.leafletPoly.getLatLngs();
94 } 93 }
95 -  
96 - setPolylineLatLngs(latLngs) {  
97 - this.leafletPoly.setLatLngs(latLngs);  
98 - }  
99 } 94 }
@@ -56,6 +56,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -56,6 +56,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
56 historicalData: FormattedData[][]; 56 historicalData: FormattedData[][];
57 normalizationStep: number; 57 normalizationStep: number;
58 interpolatedTimeData = []; 58 interpolatedTimeData = [];
  59 + intervals = [];
59 widgetConfig: WidgetConfig; 60 widgetConfig: WidgetConfig;
60 settings; 61 settings;
61 mainTooltip = ''; 62 mainTooltip = '';
@@ -68,6 +69,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -68,6 +69,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
68 maxTimeFormat: string; 69 maxTimeFormat: string;
69 anchors: number[] = []; 70 anchors: number[] = [];
70 useAnchors: boolean; 71 useAnchors: boolean;
  72 + currentTime: number;
71 73
72 static getSettingsSchema(): JsonSettingsSchema { 74 static getSettingsSchema(): JsonSettingsSchema {
73 const schema = initSchema(); 75 const schema = initSchema();
@@ -99,15 +101,15 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -99,15 +101,15 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
99 this.settings.fitMapBounds = true; 101 this.settings.fitMapBounds = true;
100 this.normalizationStep = this.settings.normalizationStep; 102 this.normalizationStep = this.settings.normalizationStep;
101 const subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]]; 103 const subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]];
102 - if (subscription) {  
103 - subscription.callbacks.onDataUpdated = () => {  
104 - this.historicalData = parseArray(this.ctx.data); 104 + if (subscription) subscription.callbacks.onDataUpdated = () => {
  105 + this.historicalData = parseArray(this.ctx.data).filter(arr => arr.length);
  106 + if (this.historicalData.length) {
105 this.activeTrip = this.historicalData[0][0]; 107 this.activeTrip = this.historicalData[0][0];
106 this.calculateIntervals(); 108 this.calculateIntervals();
107 this.timeUpdated(this.minTime); 109 this.timeUpdated(this.minTime);
108 - this.mapWidget.map.map?.invalidateSize();  
109 - this.cd.detectChanges();  
110 } 110 }
  111 + this.mapWidget.map.map?.invalidateSize();
  112 + this.cd.detectChanges();
111 } 113 }
112 } 114 }
113 115
@@ -117,8 +119,16 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -117,8 +119,16 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
117 } 119 }
118 120
119 timeUpdated(time: number) { 121 timeUpdated(time: number) {
120 - const currentPosition = this.interpolatedTimeData.map(dataSource => dataSource[time]);  
121 - if(isUndefined(currentPosition[0])){ 122 + this.currentTime = time;
  123 + const currentPosition = this.interpolatedTimeData
  124 + .map(dataSource => dataSource[time])
  125 + .filter(ds => ds)
  126 + .map(ds => {
  127 + ds.minTime = this.minTimeFormat;
  128 + ds.maxTime = this.maxTimeFormat;
  129 + return ds;
  130 + });
  131 + if (isUndefined(currentPosition[0])) {
122 const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10)); 132 const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10));
123 for (let i = 1; i < timePoints.length; i++) { 133 for (let i = 1; i < timePoints.length; i++) {
124 if (timePoints[i - 1] < time && timePoints[i] > time) { 134 if (timePoints[i - 1] < time && timePoints[i] > time) {
@@ -134,7 +144,6 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -134,7 +144,6 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
134 } 144 }
135 } 145 }
136 } 146 }
137 - this.activeTrip = currentPosition[0];  
138 this.calcLabel(); 147 this.calcLabel();
139 this.calcTooltip(); 148 this.calcTooltip();
140 if (this.mapWidget) { 149 if (this.mapWidget) {
@@ -145,7 +154,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -145,7 +154,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
145 if (this.settings.showPoints) { 154 if (this.settings.showPoints) {
146 this.mapWidget.map.updatePoints(_.values(_.union(this.interpolatedTimeData)[0]), this.calcTooltip); 155 this.mapWidget.map.updatePoints(_.values(_.union(this.interpolatedTimeData)[0]), this.calcTooltip);
147 } 156 }
148 - this.mapWidget.map.updateMarkers(currentPosition); 157 + this.mapWidget.map.updateMarkers(currentPosition, (trip) => {
  158 + this.activeTrip = trip;
  159 + this.timeUpdated(this.currentTime)
  160 + });
149 } 161 }
150 } 162 }
151 163
@@ -185,6 +197,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -185,6 +197,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
185 SecurityContext.HTML, tooltipText); 197 SecurityContext.HTML, tooltipText);
186 this.cd.detectChanges(); 198 this.cd.detectChanges();
187 } 199 }
  200 + this.activeTrip = point;
188 return tooltipText; 201 return tooltipText;
189 } 202 }
190 203
@@ -212,7 +225,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { @@ -212,7 +225,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
212 }; 225 };
213 } 226 }
214 const timeStamp = Object.keys(result); 227 const timeStamp = Object.keys(result);
215 - for(let i = 0; i < timeStamp.length - 1; i++){ 228 + for (let i = 0; i < timeStamp.length - 1; i++) {
216 result[timeStamp[i]].rotationAngle += findAngle(result[timeStamp[i]], result[timeStamp[i + 1]], latKeyName, lngKeyName) 229 result[timeStamp[i]].rotationAngle += findAngle(result[timeStamp[i]], result[timeStamp[i + 1]], latKeyName, lngKeyName)
217 } 230 }
218 return result; 231 return result;