Commit c7ec88cc131de38b7b83d3076f4fb53a6693ab64

Authored by Igor Kulikov
Committed by GitHub
2 parents a70a4b72 c9c0f465

Merge pull request #2808 from ArtemHalushko/map/3.0

Map/3.0
... ... @@ -389,6 +389,9 @@ export default abstract class LeafletMap {
389 389 const poly = this.polylines.get(name);
390 390 if (poly) {
391 391 this.map.removeLayer(poly.leafletPoly);
  392 + if (poly.polylineDecorator) {
  393 + this.map.removeLayer(poly.polylineDecorator);
  394 + }
392 395 this.polylines.delete(name);
393 396 }
394 397 }
... ...
... ... @@ -26,7 +26,7 @@ import {
26 26
27 27 export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
28 28 export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
29   -export type GetTooltip= (point: FormattedData, setTooltip?: boolean) => string;
  29 +export type GetTooltip = (point: FormattedData, setTooltip?: boolean) => string;
30 30
31 31 export type MapSettings = {
32 32 draggableMarker: boolean;
... ... @@ -164,9 +164,23 @@ export interface HistorySelectSettings {
164 164 }
165 165
166 166 export type TripAnimationSettings = {
  167 + showPoints: boolean;
167 168 pointColor: string;
168 169 pointSize: number;
169 170 pointTooltipOnRightPanel: boolean;
  171 + usePointAsAnchor: boolean;
  172 + normalizationStep: number;
  173 + showPolygon: boolean;
  174 + latKeyName: string;
  175 + lngKeyName: string;
  176 + rotationAngle: number;
  177 + label: string;
  178 + tooltipPattern: string;
  179 + useTooltipFunction :boolean;
  180 + useLabelFunction:boolean;
  181 + pointAsAnchorFunction: GenericFunction;
  182 + tooltipFunction: GenericFunction;
  183 + labelFunction: GenericFunction;
170 184 }
171 185
172 186 export type actionsHandler = ($event: Event, datasource: Datasource) => void;
... ...
... ... @@ -17,12 +17,12 @@
17 17 import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models';
18 18 import LeafletMap from './leaflet-map';
19 19 import {
20   - commonMapSettingsSchema,
21   - mapPolygonSchema,
22   - mapProviderSchema,
23   - markerClusteringSettingsSchema,
24   - markerClusteringSettingsSchemaLeaflet,
25   - routeMapSettingsSchema
  20 + commonMapSettingsSchema,
  21 + mapPolygonSchema,
  22 + mapProviderSchema,
  23 + markerClusteringSettingsSchema,
  24 + markerClusteringSettingsSchemaLeaflet,
  25 + routeMapSettingsSchema
26 26 } from './schemes';
27 27 import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface';
28 28 import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils';
... ... @@ -30,17 +30,18 @@ import { of, Subject } from 'rxjs';
30 30 import { WidgetContext } from '@app/modules/home/models/widget-component.models';
31 31 import { getDefCenterPosition, parseArray, parseData, parseFunction, parseWithTranslation } from './maps-utils';
32 32 import {
33   - Datasource,
34   - DatasourceType,
35   - JsonSettingsSchema,
36   - WidgetActionDescriptor,
37   - widgetType
  33 + Datasource,
  34 + DatasourceType,
  35 + JsonSettingsSchema,
  36 + WidgetActionDescriptor,
  37 + widgetType
38 38 } from '@shared/models/widget.models';
39 39 import { EntityId } from '@shared/models/id/entity-id';
40 40 import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
41 41 import { AttributeService } from '@core/http/attribute.service';
42 42 import { TranslateService } from '@ngx-translate/core';
43 43 import { UtilsService } from '@core/services/utils.service';
  44 +import _ from 'lodash';
44 45
45 46 // @dynamic
46 47 export class MapWidgetController implements MapWidgetInterface {
... ... @@ -90,9 +91,9 @@ export class MapWidgetController implements MapWidgetInterface {
90 91 }
91 92
92 93 public static getProvidersSchema(mapProvider: MapProviders, ignoreImageMap = false) {
  94 + const providerSchema = _.cloneDeep(mapProviderSchema);
93 95 if (mapProvider)
94   - mapProviderSchema.schema.properties.provider.default = mapProvider;
95   - const providerSchema = mapProviderSchema;
  96 + providerSchema.schema.properties.provider.default = mapProvider;
96 97 if (ignoreImageMap) {
97 98 providerSchema.form[0].items = providerSchema.form[0]?.items.filter(item => item.value !== 'image-map');
98 99 }
... ...
... ... @@ -19,7 +19,7 @@ import tinycolor from 'tinycolor2';
19 19
20 20 import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, SecurityContext, ViewChild } from '@angular/core';
21 21 import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2';
22   -import { FormattedData, MapProviders } from '../lib/maps/map-models';
  22 +import { FormattedData, MapProviders, TripAnimationSettings } from '../lib/maps/map-models';
23 23 import { addCondition, addGroupInfo, addToSchema, initSchema } from '@app/core/schema-utils';
24 24 import { mapPolygonSchema, pathSchema, pointSchema, tripAnimationSchema } from '../lib/maps/schemes';
25 25 import { DomSanitizer } from '@angular/platform-browser';
... ... @@ -56,17 +56,14 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
56 56 historicalData: FormattedData[][];
57 57 normalizationStep: number;
58 58 interpolatedTimeData = [];
59   - intervals = [];
60 59 widgetConfig: WidgetConfig;
61   - settings;
  60 + settings: TripAnimationSettings;
62 61 mainTooltip = '';
63 62 visibleTooltip = false;
64 63 activeTrip: FormattedData;
65 64 label;
66 65 minTime: number;
67   - minTimeFormat: string;
68 66 maxTime: number;
69   - maxTimeFormat: string;
70 67 anchors: number[] = [];
71 68 useAnchors: boolean;
72 69 currentTime: number;
... ... @@ -98,15 +95,15 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
98 95 this.settings = { ...settings, ...this.ctx.settings };
99 96 this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor;
100 97 this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']);
101   - this.settings.fitMapBounds = true;
  98 + this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
  99 + this.settings.labelFunction = parseFunction(this.settings.labelFunction, ['data', 'dsData', 'dsIndex']);
102 100 this.normalizationStep = this.settings.normalizationStep;
103 101 const subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]];
104 102 if (subscription) subscription.callbacks.onDataUpdated = () => {
105 103 this.historicalData = parseArray(this.ctx.data).filter(arr => arr.length);
106 104 if (this.historicalData.length) {
107   - this.activeTrip = this.historicalData[0][0];
108 105 this.calculateIntervals();
109   - this.timeUpdated(this.minTime);
  106 + this.timeUpdated(this.currentTime && this.currentTime > this.minTime ? this.currentTime : this.minTime);
110 107 }
111 108 this.mapWidget.map.map?.invalidateSize();
112 109 this.cd.detectChanges();
... ... @@ -122,12 +119,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
122 119 this.currentTime = time;
123 120 const currentPosition = this.interpolatedTimeData
124 121 .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   - });
  122 + .filter(ds => ds);
131 123 if (isUndefined(currentPosition[0])) {
132 124 const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10));
133 125 for (let i = 1; i < timePoints.length; i++) {
... ... @@ -145,7 +137,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
145 137 }
146 138 }
147 139 this.calcLabel();
148   - this.calcTooltip();
  140 + this.calcTooltip(currentPosition.find(position => position.entityName === this.activeTrip.entityName));
149 141 if (this.mapWidget) {
150 142 this.mapWidget.map.updatePolylines(this.interpolatedTimeData.map(ds => _.values(ds)), this.activeTrip);
151 143 if (this.settings.showPolygon) {
... ... @@ -167,11 +159,14 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
167 159 calculateIntervals() {
168 160 this.historicalData.forEach((dataSource, index) => {
169 161 this.minTime = dataSource[0]?.time || Infinity;
170   - this.minTimeFormat = this.minTime !== Infinity ? moment(this.minTime).format('YYYY-MM-DD HH:mm:ss') : '';
  162 + const minTimeFormat = this.minTime !== Infinity ? moment(this.minTime).format('YYYY-MM-DD HH:mm:ss') : '';
171 163 this.maxTime = dataSource[dataSource.length - 1]?.time || -Infinity;
172   - this.maxTimeFormat = this.maxTime !== -Infinity ? moment(this.maxTime).format('YYYY-MM-DD HH:mm:ss') : '';
173   - this.interpolatedTimeData[index] = this.interpolateArray(dataSource);
  164 + const maxTimeFormat = this.maxTime !== -Infinity ? moment(this.maxTime).format('YYYY-MM-DD HH:mm:ss') : '';
  165 + this.interpolatedTimeData[index] = this.interpolateArray(dataSource, minTimeFormat, maxTimeFormat);
174 166 });
  167 + if(!this.activeTrip){
  168 + this.activeTrip = this.interpolatedTimeData.map(dataSource => dataSource[this.minTime]).filter(ds => ds)[0];
  169 + }
175 170 if (this.useAnchors) {
176 171 const anchorDate = Object.entries(_.union(this.interpolatedTimeData)[0]);
177 172 this.anchors = anchorDate
... ... @@ -180,39 +175,26 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
180 175 }
181 176 }
182 177
183   - calcTooltip = (point?: FormattedData, setTooltip = true) => {
184   - if (!point) {
185   - point = this.activeTrip;
186   - }
187   - const data = {
188   - ...this.activeTrip,
189   - maxTime: this.maxTimeFormat,
190   - minTime: this.minTimeFormat
191   - }
  178 + calcTooltip = (point?: FormattedData) => {
  179 + const data = point ? point : this.activeTrip;
192 180 const tooltipPattern: string = this.settings.useTooltipFunction ?
193   - safeExecute(this.settings.tooolTipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern;
  181 + safeExecute(this.settings.tooltipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern;
194 182 const tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true);
195   - if (setTooltip) {
196   - this.mainTooltip = this.sanitizer.sanitize(
197   - SecurityContext.HTML, tooltipText);
198   - this.cd.detectChanges();
199   - }
  183 + this.mainTooltip = this.sanitizer.sanitize(
  184 + SecurityContext.HTML, tooltipText);
  185 + this.cd.detectChanges();
200 186 this.activeTrip = point;
201 187 return tooltipText;
202 188 }
203 189
204 190 calcLabel() {
205   - const data = {
206   - ...this.activeTrip,
207   - maxTime: this.maxTimeFormat,
208   - minTime: this.minTimeFormat
209   - }
  191 + const data = this.activeTrip;
210 192 const labelText: string = this.settings.useLabelFunction ?
211 193 safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label;
212 194 this.label = (parseWithTranslation.parseTemplate(labelText, data, true));
213 195 }
214 196
215   - interpolateArray(originData: FormattedData[]) {
  197 + interpolateArray(originData: FormattedData[], minTimeFormat?: string, maxTimeFormat?: string) {
216 198 const result = {};
217 199 const latKeyName = this.settings.latKeyName;
218 200 const lngKeyName = this.settings.lngKeyName;
... ... @@ -221,6 +203,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
221 203 const normalizeTime = this.minTime + Math.ceil((currentTime - this.minTime) / this.normalizationStep) * this.normalizationStep;
222 204 result[normalizeTime] = {
223 205 ...data,
  206 + minTime: minTimeFormat,
  207 + maxTime: maxTimeFormat,
224 208 rotationAngle: this.settings.rotationAngle
225 209 };
226 210 }
... ...