Merge pull request #2808 from ArtemHalushko/map/3.0

Map/3.0
This commit is contained in:
Igor Kulikov 2020-05-22 10:39:48 +03:00 committed by GitHub
commit c7ec88cc13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 53 deletions

View File

@ -389,6 +389,9 @@ export default abstract class LeafletMap {
const poly = this.polylines.get(name); const poly = this.polylines.get(name);
if (poly) { if (poly) {
this.map.removeLayer(poly.leafletPoly); this.map.removeLayer(poly.leafletPoly);
if (poly.polylineDecorator) {
this.map.removeLayer(poly.polylineDecorator);
}
this.polylines.delete(name); this.polylines.delete(name);
} }
} }

View File

@ -26,7 +26,7 @@ import {
export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
export type GetTooltip= (point: FormattedData, setTooltip?: boolean) => string; export type GetTooltip = (point: FormattedData, setTooltip?: boolean) => string;
export type MapSettings = { export type MapSettings = {
draggableMarker: boolean; draggableMarker: boolean;
@ -164,9 +164,23 @@ export interface HistorySelectSettings {
} }
export type TripAnimationSettings = { export type TripAnimationSettings = {
showPoints: boolean;
pointColor: string; pointColor: string;
pointSize: number; pointSize: number;
pointTooltipOnRightPanel: boolean; pointTooltipOnRightPanel: boolean;
usePointAsAnchor: boolean;
normalizationStep: number;
showPolygon: boolean;
latKeyName: string;
lngKeyName: string;
rotationAngle: number;
label: string;
tooltipPattern: string;
useTooltipFunction :boolean;
useLabelFunction:boolean;
pointAsAnchorFunction: GenericFunction;
tooltipFunction: GenericFunction;
labelFunction: GenericFunction;
} }
export type actionsHandler = ($event: Event, datasource: Datasource) => void; export type actionsHandler = ($event: Event, datasource: Datasource) => void;

View File

@ -17,12 +17,12 @@
import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models'; import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models';
import LeafletMap from './leaflet-map'; import LeafletMap from './leaflet-map';
import { import {
commonMapSettingsSchema, commonMapSettingsSchema,
mapPolygonSchema, mapPolygonSchema,
mapProviderSchema, mapProviderSchema,
markerClusteringSettingsSchema, markerClusteringSettingsSchema,
markerClusteringSettingsSchemaLeaflet, markerClusteringSettingsSchemaLeaflet,
routeMapSettingsSchema routeMapSettingsSchema
} from './schemes'; } from './schemes';
import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface';
import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils'; import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils';
@ -30,17 +30,18 @@ import { of, Subject } from 'rxjs';
import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { WidgetContext } from '@app/modules/home/models/widget-component.models';
import { getDefCenterPosition, parseArray, parseData, parseFunction, parseWithTranslation } from './maps-utils'; import { getDefCenterPosition, parseArray, parseData, parseFunction, parseWithTranslation } from './maps-utils';
import { import {
Datasource, Datasource,
DatasourceType, DatasourceType,
JsonSettingsSchema, JsonSettingsSchema,
WidgetActionDescriptor, WidgetActionDescriptor,
widgetType widgetType
} from '@shared/models/widget.models'; } from '@shared/models/widget.models';
import { EntityId } from '@shared/models/id/entity-id'; import { EntityId } from '@shared/models/id/entity-id';
import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
import { AttributeService } from '@core/http/attribute.service'; import { AttributeService } from '@core/http/attribute.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
import _ from 'lodash';
// @dynamic // @dynamic
export class MapWidgetController implements MapWidgetInterface { export class MapWidgetController implements MapWidgetInterface {
@ -90,9 +91,9 @@ export class MapWidgetController implements MapWidgetInterface {
} }
public static getProvidersSchema(mapProvider: MapProviders, ignoreImageMap = false) { public static getProvidersSchema(mapProvider: MapProviders, ignoreImageMap = false) {
const providerSchema = _.cloneDeep(mapProviderSchema);
if (mapProvider) if (mapProvider)
mapProviderSchema.schema.properties.provider.default = mapProvider; providerSchema.schema.properties.provider.default = mapProvider;
const providerSchema = mapProviderSchema;
if (ignoreImageMap) { if (ignoreImageMap) {
providerSchema.form[0].items = providerSchema.form[0]?.items.filter(item => item.value !== 'image-map'); providerSchema.form[0].items = providerSchema.form[0]?.items.filter(item => item.value !== 'image-map');
} }

View File

@ -19,7 +19,7 @@ import tinycolor from 'tinycolor2';
import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, SecurityContext, ViewChild } from '@angular/core'; import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, SecurityContext, ViewChild } from '@angular/core';
import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2'; import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2';
import { FormattedData, MapProviders } from '../lib/maps/map-models'; import { FormattedData, MapProviders, TripAnimationSettings } from '../lib/maps/map-models';
import { addCondition, addGroupInfo, addToSchema, initSchema } from '@app/core/schema-utils'; import { addCondition, addGroupInfo, addToSchema, initSchema } from '@app/core/schema-utils';
import { mapPolygonSchema, pathSchema, pointSchema, tripAnimationSchema } from '../lib/maps/schemes'; import { mapPolygonSchema, pathSchema, pointSchema, tripAnimationSchema } from '../lib/maps/schemes';
import { DomSanitizer } from '@angular/platform-browser'; import { DomSanitizer } from '@angular/platform-browser';
@ -56,17 +56,14 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
historicalData: FormattedData[][]; historicalData: FormattedData[][];
normalizationStep: number; normalizationStep: number;
interpolatedTimeData = []; interpolatedTimeData = [];
intervals = [];
widgetConfig: WidgetConfig; widgetConfig: WidgetConfig;
settings; settings: TripAnimationSettings;
mainTooltip = ''; mainTooltip = '';
visibleTooltip = false; visibleTooltip = false;
activeTrip: FormattedData; activeTrip: FormattedData;
label; label;
minTime: number; minTime: number;
minTimeFormat: string;
maxTime: number; maxTime: number;
maxTimeFormat: string;
anchors: number[] = []; anchors: number[] = [];
useAnchors: boolean; useAnchors: boolean;
currentTime: number; currentTime: number;
@ -98,15 +95,15 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
this.settings = { ...settings, ...this.ctx.settings }; this.settings = { ...settings, ...this.ctx.settings };
this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor; this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor;
this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']); this.settings.pointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']);
this.settings.fitMapBounds = true; this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
this.settings.labelFunction = parseFunction(this.settings.labelFunction, ['data', 'dsData', 'dsIndex']);
this.normalizationStep = this.settings.normalizationStep; this.normalizationStep = this.settings.normalizationStep;
const subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]]; const subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]];
if (subscription) subscription.callbacks.onDataUpdated = () => { if (subscription) subscription.callbacks.onDataUpdated = () => {
this.historicalData = parseArray(this.ctx.data).filter(arr => arr.length); this.historicalData = parseArray(this.ctx.data).filter(arr => arr.length);
if (this.historicalData.length) { if (this.historicalData.length) {
this.activeTrip = this.historicalData[0][0];
this.calculateIntervals(); this.calculateIntervals();
this.timeUpdated(this.minTime); this.timeUpdated(this.currentTime && this.currentTime > this.minTime ? this.currentTime : this.minTime);
} }
this.mapWidget.map.map?.invalidateSize(); this.mapWidget.map.map?.invalidateSize();
this.cd.detectChanges(); this.cd.detectChanges();
@ -122,12 +119,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
this.currentTime = time; this.currentTime = time;
const currentPosition = this.interpolatedTimeData const currentPosition = this.interpolatedTimeData
.map(dataSource => dataSource[time]) .map(dataSource => dataSource[time])
.filter(ds => ds) .filter(ds => ds);
.map(ds => {
ds.minTime = this.minTimeFormat;
ds.maxTime = this.maxTimeFormat;
return ds;
});
if (isUndefined(currentPosition[0])) { if (isUndefined(currentPosition[0])) {
const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10)); const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10));
for (let i = 1; i < timePoints.length; i++) { for (let i = 1; i < timePoints.length; i++) {
@ -145,7 +137,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
} }
} }
this.calcLabel(); this.calcLabel();
this.calcTooltip(); this.calcTooltip(currentPosition.find(position => position.entityName === this.activeTrip.entityName));
if (this.mapWidget) { if (this.mapWidget) {
this.mapWidget.map.updatePolylines(this.interpolatedTimeData.map(ds => _.values(ds)), this.activeTrip); this.mapWidget.map.updatePolylines(this.interpolatedTimeData.map(ds => _.values(ds)), this.activeTrip);
if (this.settings.showPolygon) { if (this.settings.showPolygon) {
@ -167,11 +159,14 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
calculateIntervals() { calculateIntervals() {
this.historicalData.forEach((dataSource, index) => { this.historicalData.forEach((dataSource, index) => {
this.minTime = dataSource[0]?.time || Infinity; this.minTime = dataSource[0]?.time || Infinity;
this.minTimeFormat = this.minTime !== Infinity ? moment(this.minTime).format('YYYY-MM-DD HH:mm:ss') : ''; const minTimeFormat = this.minTime !== Infinity ? moment(this.minTime).format('YYYY-MM-DD HH:mm:ss') : '';
this.maxTime = dataSource[dataSource.length - 1]?.time || -Infinity; this.maxTime = dataSource[dataSource.length - 1]?.time || -Infinity;
this.maxTimeFormat = this.maxTime !== -Infinity ? moment(this.maxTime).format('YYYY-MM-DD HH:mm:ss') : ''; const maxTimeFormat = this.maxTime !== -Infinity ? moment(this.maxTime).format('YYYY-MM-DD HH:mm:ss') : '';
this.interpolatedTimeData[index] = this.interpolateArray(dataSource); this.interpolatedTimeData[index] = this.interpolateArray(dataSource, minTimeFormat, maxTimeFormat);
}); });
if(!this.activeTrip){
this.activeTrip = this.interpolatedTimeData.map(dataSource => dataSource[this.minTime]).filter(ds => ds)[0];
}
if (this.useAnchors) { if (this.useAnchors) {
const anchorDate = Object.entries(_.union(this.interpolatedTimeData)[0]); const anchorDate = Object.entries(_.union(this.interpolatedTimeData)[0]);
this.anchors = anchorDate this.anchors = anchorDate
@ -180,39 +175,26 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
} }
} }
calcTooltip = (point?: FormattedData, setTooltip = true) => { calcTooltip = (point?: FormattedData) => {
if (!point) { const data = point ? point : this.activeTrip;
point = this.activeTrip;
}
const data = {
...this.activeTrip,
maxTime: this.maxTimeFormat,
minTime: this.minTimeFormat
}
const tooltipPattern: string = this.settings.useTooltipFunction ? const tooltipPattern: string = this.settings.useTooltipFunction ?
safeExecute(this.settings.tooolTipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern; safeExecute(this.settings.tooltipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern;
const tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true); const tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true);
if (setTooltip) { this.mainTooltip = this.sanitizer.sanitize(
this.mainTooltip = this.sanitizer.sanitize( SecurityContext.HTML, tooltipText);
SecurityContext.HTML, tooltipText); this.cd.detectChanges();
this.cd.detectChanges();
}
this.activeTrip = point; this.activeTrip = point;
return tooltipText; return tooltipText;
} }
calcLabel() { calcLabel() {
const data = { const data = this.activeTrip;
...this.activeTrip,
maxTime: this.maxTimeFormat,
minTime: this.minTimeFormat
}
const labelText: string = this.settings.useLabelFunction ? const labelText: string = this.settings.useLabelFunction ?
safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label;
this.label = (parseWithTranslation.parseTemplate(labelText, data, true)); this.label = (parseWithTranslation.parseTemplate(labelText, data, true));
} }
interpolateArray(originData: FormattedData[]) { interpolateArray(originData: FormattedData[], minTimeFormat?: string, maxTimeFormat?: string) {
const result = {}; const result = {};
const latKeyName = this.settings.latKeyName; const latKeyName = this.settings.latKeyName;
const lngKeyName = this.settings.lngKeyName; const lngKeyName = this.settings.lngKeyName;
@ -221,6 +203,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
const normalizeTime = this.minTime + Math.ceil((currentTime - this.minTime) / this.normalizationStep) * this.normalizationStep; const normalizeTime = this.minTime + Math.ceil((currentTime - this.minTime) / this.normalizationStep) * this.normalizationStep;
result[normalizeTime] = { result[normalizeTime] = {
...data, ...data,
minTime: minTimeFormat,
maxTime: maxTimeFormat,
rotationAngle: this.settings.rotationAngle rotationAngle: this.settings.rotationAngle
}; };
} }