Add support of latest values for timeseries map widgets
This commit is contained in:
parent
1b95f32b19
commit
c35d60abd9
File diff suppressed because one or more lines are too long
@ -471,6 +471,19 @@ export function flatFormattedData(input: FormattedData[]): FormattedData {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mergeFormattedData(first: FormattedData[], second: FormattedData[]): FormattedData[] {
|
||||||
|
const merged = first.concat(second);
|
||||||
|
return _(merged).groupBy(el => el.$datasource)
|
||||||
|
.values().value().map((formattedDataArray, i) => {
|
||||||
|
let res = formattedDataArray[0];
|
||||||
|
if (formattedDataArray.length > 1) {
|
||||||
|
const toMerge = formattedDataArray[1];
|
||||||
|
res = {...res, ...toMerge};
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function processDataPattern(pattern: string, data: FormattedData): Array<ReplaceInfo> {
|
export function processDataPattern(pattern: string, data: FormattedData): Array<ReplaceInfo> {
|
||||||
const replaceInfo: Array<ReplaceInfo> = [];
|
const replaceInfo: Array<ReplaceInfo> = [];
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -48,7 +48,7 @@ import {
|
|||||||
formattedDataFormDatasourceData,
|
formattedDataFormDatasourceData,
|
||||||
isDefinedAndNotNull,
|
isDefinedAndNotNull,
|
||||||
isNotEmptyStr,
|
isNotEmptyStr,
|
||||||
isString, safeExecute
|
isString, mergeFormattedData, safeExecute
|
||||||
} from '@core/utils';
|
} from '@core/utils';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import {
|
import {
|
||||||
@ -644,13 +644,25 @@ export default abstract class LeafletMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateData(drawRoutes: boolean, showPolygon: boolean) {
|
updateData(drawRoutes: boolean, showPolygon: boolean) {
|
||||||
|
const data = this.ctx.data;
|
||||||
|
let formattedData = formattedDataFormDatasourceData(data);
|
||||||
|
if (this.ctx.latestData && this.ctx.latestData.length) {
|
||||||
|
const formattedLatestData = formattedDataFormDatasourceData(this.ctx.latestData);
|
||||||
|
formattedData = mergeFormattedData(formattedData, formattedLatestData);
|
||||||
|
}
|
||||||
|
let polyData: FormattedData[][] = null;
|
||||||
|
if (drawRoutes) {
|
||||||
|
polyData = formattedDataArrayFromDatasourceData(data);
|
||||||
|
}
|
||||||
|
this.updateFromData(drawRoutes, showPolygon, formattedData, polyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromData(drawRoutes: boolean, showPolygon: boolean, formattedData: FormattedData[],
|
||||||
|
polyData: FormattedData[][], markerClickCallback?: any) {
|
||||||
this.drawRoutes = drawRoutes;
|
this.drawRoutes = drawRoutes;
|
||||||
this.showPolygon = showPolygon;
|
this.showPolygon = showPolygon;
|
||||||
if (this.map) {
|
if (this.map) {
|
||||||
const data = this.ctx.data;
|
|
||||||
const formattedData = formattedDataFormDatasourceData(data);
|
|
||||||
if (drawRoutes) {
|
if (drawRoutes) {
|
||||||
const polyData = formattedDataArrayFromDatasourceData(data);
|
|
||||||
this.updatePolylines(polyData, formattedData, false);
|
this.updatePolylines(polyData, formattedData, false);
|
||||||
}
|
}
|
||||||
if (showPolygon) {
|
if (showPolygon) {
|
||||||
@ -659,7 +671,7 @@ export default abstract class LeafletMap {
|
|||||||
if (this.options.showCircle) {
|
if (this.options.showCircle) {
|
||||||
this.updateCircle(formattedData, false);
|
this.updateCircle(formattedData, false);
|
||||||
}
|
}
|
||||||
this.updateMarkers(formattedData, false);
|
this.updateMarkers(formattedData, false, markerClickCallback);
|
||||||
this.updateBoundsInternal();
|
this.updateBoundsInternal();
|
||||||
if (this.options.draggableMarker || this.editPolygons || this.editCircle) {
|
if (this.options.draggableMarker || this.editPolygons || this.editCircle) {
|
||||||
let foundEntityWithLocation = false;
|
let foundEntityWithLocation = false;
|
||||||
|
|||||||
@ -221,7 +221,7 @@ export interface MapImage {
|
|||||||
update?: boolean;
|
update?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TripAnimationSettings extends PolygonSettings {
|
export interface TripAnimationSettings extends PolygonSettings, CircleSettings {
|
||||||
showPoints: boolean;
|
showPoints: boolean;
|
||||||
pointColor: string;
|
pointColor: string;
|
||||||
pointSize: number;
|
pointSize: number;
|
||||||
|
|||||||
@ -226,8 +226,12 @@ export class MapWidgetController implements MapWidgetInterface {
|
|||||||
id: e.$datasource.entityId
|
id: e.$datasource.entityId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let dataKeys = e.$datasource.dataKeys;
|
||||||
|
if (e.$datasource.latestDataKeys) {
|
||||||
|
dataKeys = dataKeys.concat(e.$datasource.latestDataKeys);
|
||||||
|
}
|
||||||
for (const dataKeyName of Object.keys(values)) {
|
for (const dataKeyName of Object.keys(values)) {
|
||||||
for (const key of e.$datasource.dataKeys) {
|
for (const key of dataKeys) {
|
||||||
if (dataKeyName === key.name) {
|
if (dataKeyName === key.name) {
|
||||||
const value = {
|
const value = {
|
||||||
key: key.name,
|
key: key.name,
|
||||||
@ -317,6 +321,10 @@ export class MapWidgetController implements MapWidgetInterface {
|
|||||||
this.map.setLoading(false);
|
this.map.setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
latestDataUpdate() {
|
||||||
|
this.map.updateData(this.drawRoutes, this.settings.showPolygon);
|
||||||
|
}
|
||||||
|
|
||||||
resize() {
|
resize() {
|
||||||
this.map.onResize();
|
this.map.onResize();
|
||||||
this.map?.invalidateSize();
|
this.map?.invalidateSize();
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import {
|
|||||||
import { MapProviders, TripAnimationSettings } from '@home/components/widget/lib/maps/map-models';
|
import { MapProviders, TripAnimationSettings } from '@home/components/widget/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 {
|
import {
|
||||||
|
mapCircleSchema,
|
||||||
mapPolygonSchema,
|
mapPolygonSchema,
|
||||||
pathSchema,
|
pathSchema,
|
||||||
pointSchema,
|
pointSchema,
|
||||||
@ -48,9 +49,9 @@ import { FormattedData, JsonSettingsSchema, WidgetConfig } from '@shared/models/
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
deepClone,
|
deepClone,
|
||||||
formattedDataArrayFromDatasourceData,
|
formattedDataArrayFromDatasourceData, formattedDataFormDatasourceData,
|
||||||
isDefined,
|
isDefined,
|
||||||
isUndefined,
|
isUndefined, mergeFormattedData,
|
||||||
parseFunction,
|
parseFunction,
|
||||||
safeExecute
|
safeExecute
|
||||||
} from '@core/utils';
|
} from '@core/utils';
|
||||||
@ -82,6 +83,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
normalizationStep: number;
|
normalizationStep: number;
|
||||||
interpolatedTimeData: {[time: number]: FormattedData}[] = [];
|
interpolatedTimeData: {[time: number]: FormattedData}[] = [];
|
||||||
formattedInterpolatedTimeData: FormattedData[][] = [];
|
formattedInterpolatedTimeData: FormattedData[][] = [];
|
||||||
|
formattedCurrentPosition: FormattedData[] = [];
|
||||||
|
formattedLatestData: FormattedData[] = [];
|
||||||
widgetConfig: WidgetConfig;
|
widgetConfig: WidgetConfig;
|
||||||
settings: TripAnimationSettings;
|
settings: TripAnimationSettings;
|
||||||
mainTooltips = [];
|
mainTooltips = [];
|
||||||
@ -104,11 +107,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
addGroupInfo(schema, 'Path Settings');
|
addGroupInfo(schema, 'Path Settings');
|
||||||
addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints']));
|
addToSchema(schema, addCondition(pointSchema, 'model.showPoints === true', ['showPoints']));
|
||||||
addGroupInfo(schema, 'Path Points Settings');
|
addGroupInfo(schema, 'Path Points Settings');
|
||||||
const mapPolygonSchemaWithoutEdit = deepClone(mapPolygonSchema);
|
addToSchema(schema, addCondition(mapPolygonSchema, 'model.showPolygon === true', ['showPolygon']));
|
||||||
delete mapPolygonSchemaWithoutEdit.schema.properties.editablePolygon;
|
|
||||||
mapPolygonSchemaWithoutEdit.form.splice(mapPolygonSchemaWithoutEdit.form.indexOf('editablePolygon'), 1);
|
|
||||||
addToSchema(schema, addCondition(mapPolygonSchemaWithoutEdit, 'model.showPolygon === true', ['showPolygon']));
|
|
||||||
addGroupInfo(schema, 'Polygon Settings');
|
addGroupInfo(schema, 'Polygon Settings');
|
||||||
|
addToSchema(schema, addCondition(mapCircleSchema, 'model.showCircle === true', ['showCircle']));
|
||||||
|
addGroupInfo(schema, 'Circle Settings');
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +124,6 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
rotationAngle: 0
|
rotationAngle: 0
|
||||||
};
|
};
|
||||||
this.settings = { ...settings, ...this.ctx.settings };
|
this.settings = { ...settings, ...this.ctx.settings };
|
||||||
this.settings.editablePolygon = false;
|
|
||||||
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.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
|
this.settings.tooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
|
||||||
@ -148,6 +149,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
this.mapWidget.map.setLoading(false);
|
this.mapWidget.map.setLoading(false);
|
||||||
this.cd.detectChanges();
|
this.cd.detectChanges();
|
||||||
};
|
};
|
||||||
|
subscription.callbacks.onLatestDataUpdated = () => {
|
||||||
|
this.formattedLatestData = formattedDataFormDatasourceData(this.ctx.latestData);
|
||||||
|
this.updateCurrentData();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
@ -171,17 +176,17 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
timeUpdated(time: number) {
|
timeUpdated(time: number) {
|
||||||
this.currentTime = time;
|
this.currentTime = time;
|
||||||
// get point for each datasource associated with time
|
// get point for each datasource associated with time
|
||||||
const currentPosition = this.interpolatedTimeData
|
this.formattedCurrentPosition = this.interpolatedTimeData
|
||||||
.map(dataSource => dataSource[time]);
|
.map(dataSource => dataSource[time]);
|
||||||
for (let j = 0; j < this.interpolatedTimeData.length; j++) {
|
for (let j = 0; j < this.interpolatedTimeData.length; j++) {
|
||||||
if (isUndefined(currentPosition[j])) {
|
if (isUndefined(this.formattedCurrentPosition[j])) {
|
||||||
const timePoints = Object.keys(this.interpolatedTimeData[j]).map(item => parseInt(item, 10));
|
const timePoints = Object.keys(this.interpolatedTimeData[j]).map(item => parseInt(item, 10));
|
||||||
for (let i = 1; i < timePoints.length; i++) {
|
for (let i = 1; i < timePoints.length; i++) {
|
||||||
if (timePoints[i - 1] < time && timePoints[i] > time) {
|
if (timePoints[i - 1] < time && timePoints[i] > time) {
|
||||||
const beforePosition = this.interpolatedTimeData[j][timePoints[i - 1]];
|
const beforePosition = this.interpolatedTimeData[j][timePoints[i - 1]];
|
||||||
const afterPosition = this.interpolatedTimeData[j][timePoints[i]];
|
const afterPosition = this.interpolatedTimeData[j][timePoints[i]];
|
||||||
const ratio = getRatio(timePoints[i - 1], timePoints[i], time);
|
const ratio = getRatio(timePoints[i - 1], timePoints[i], time);
|
||||||
currentPosition[j] = {
|
this.formattedCurrentPosition[j] = {
|
||||||
...beforePosition,
|
...beforePosition,
|
||||||
time,
|
time,
|
||||||
...interpolateOnLineSegment(beforePosition, afterPosition, this.settings.latKeyName, this.settings.lngKeyName, ratio)
|
...interpolateOnLineSegment(beforePosition, afterPosition, this.settings.latKeyName, this.settings.lngKeyName, ratio)
|
||||||
@ -192,25 +197,29 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let j = 0; j < this.interpolatedTimeData.length; j++) {
|
for (let j = 0; j < this.interpolatedTimeData.length; j++) {
|
||||||
if (isUndefined(currentPosition[j])) {
|
if (isUndefined(this.formattedCurrentPosition[j])) {
|
||||||
currentPosition[j] = this.calculateLastPoints(this.interpolatedTimeData[j], time);
|
this.formattedCurrentPosition[j] = this.calculateLastPoints(this.interpolatedTimeData[j], time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.updateCurrentData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateCurrentData() {
|
||||||
|
let currentPosition = this.formattedCurrentPosition;
|
||||||
|
if (this.formattedLatestData.length) {
|
||||||
|
currentPosition = mergeFormattedData(this.formattedCurrentPosition, this.formattedLatestData);
|
||||||
|
}
|
||||||
this.calcLabel(currentPosition);
|
this.calcLabel(currentPosition);
|
||||||
this.calcMainTooltip(currentPosition);
|
this.calcMainTooltip(currentPosition);
|
||||||
if (this.mapWidget && this.mapWidget.map && this.mapWidget.map.map) {
|
if (this.mapWidget && this.mapWidget.map && this.mapWidget.map.map) {
|
||||||
this.mapWidget.map.updatePolylines(this.formattedInterpolatedTimeData, currentPosition, true);
|
this.mapWidget.map.updateFromData(true, this.settings.showPolygon, currentPosition, this.formattedInterpolatedTimeData, (trip) => {
|
||||||
if (this.settings.showPolygon) {
|
|
||||||
this.mapWidget.map.updatePolygons(currentPosition);
|
|
||||||
}
|
|
||||||
if (this.settings.showPoints) {
|
|
||||||
this.mapWidget.map.updatePoints(this.formattedInterpolatedTimeData, this.calcTooltip);
|
|
||||||
}
|
|
||||||
this.mapWidget.map.updateMarkers(currentPosition, true, (trip) => {
|
|
||||||
this.activeTrip = trip;
|
this.activeTrip = trip;
|
||||||
this.timeUpdated(this.currentTime);
|
this.timeUpdated(this.currentTime);
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
if (this.settings.showPoints) {
|
||||||
|
this.mapWidget.map.updatePoints(this.formattedInterpolatedTimeData, this.calcTooltip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user