UI: Add JS modules support to map widgets JS functions.
This commit is contained in:
parent
90ef67bf59
commit
a0dcd7cf30
@ -711,21 +711,6 @@ export function safeExecuteTbFunction<T extends GenericFunction>(func: CompiledT
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
export function safeExecute(func: (...args: any[]) => any, params = []) {
|
||||
let res = null;
|
||||
if (func && typeof (func) === 'function') {
|
||||
try {
|
||||
res = func(...params);
|
||||
}
|
||||
catch (err) {
|
||||
console.log('error in external function:', err);
|
||||
res = null;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export function padValue(val: any, dec: number): string {
|
||||
let strVal;
|
||||
let n;
|
||||
|
||||
@ -16,14 +16,11 @@
|
||||
|
||||
import L, { LeafletMouseEvent } from 'leaflet';
|
||||
import { CircleData, WidgetCircleSettings } from '@home/components/widget/lib/maps/map-models';
|
||||
import {
|
||||
functionValueCalculator,
|
||||
parseWithTranslation
|
||||
} from '@home/components/widget/lib/maps/common-maps-utils';
|
||||
import { functionValueCalculator, parseWithTranslation } from '@home/components/widget/lib/maps/common-maps-utils';
|
||||
import LeafletMap from '@home/components/widget/lib/maps/leaflet-map';
|
||||
import { createTooltip } from '@home/components/widget/lib/maps/maps-utils';
|
||||
import { FormattedData } from '@shared/models/widget.models';
|
||||
import { fillDataPattern, processDataPattern, safeExecute } from '@core/utils';
|
||||
import { fillDataPattern, processDataPattern, safeExecuteTbFunction } from '@core/utils';
|
||||
|
||||
export class Circle {
|
||||
|
||||
@ -94,7 +91,7 @@ export class Circle {
|
||||
if (this.settings.showCircleLabel) {
|
||||
if (!this.map.circleLabelText || this.settings.useCircleLabelFunction) {
|
||||
const pattern = this.settings.useCircleLabelFunction ?
|
||||
safeExecute(this.settings.parsedCircleLabelFunction,
|
||||
safeExecuteTbFunction(this.settings.parsedCircleLabelFunction,
|
||||
[this.data, this.dataSources, this.data.dsIndex]) : this.settings.circleLabel;
|
||||
this.map.circleLabelText = parseWithTranslation.prepareProcessPattern(pattern, true);
|
||||
this.map.replaceInfoTooltipCircle = processDataPattern(this.map.circleLabelText, this.data);
|
||||
@ -109,7 +106,7 @@ export class Circle {
|
||||
|
||||
private updateTooltip() {
|
||||
const pattern = this.settings.useCircleTooltipFunction ?
|
||||
safeExecute(this.settings.parsedCircleTooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) :
|
||||
safeExecuteTbFunction(this.settings.parsedCircleTooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) :
|
||||
this.settings.circleTooltipPattern;
|
||||
this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, this.data, true));
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import { map } from 'rxjs/operators';
|
||||
import { FormattedData } from '@shared/models/widget.models';
|
||||
import L from 'leaflet';
|
||||
import { ImagePipe } from '@shared/pipe/image.pipe';
|
||||
import { CompiledTbFunction, GenericFunction } from '@shared/models/js-function.models';
|
||||
|
||||
export function getRatio(firsMoment: number, secondMoment: number, intermediateMoment: number): number {
|
||||
return (intermediateMoment - firsMoment) / (secondMoment - firsMoment);
|
||||
@ -257,11 +258,11 @@ export const parseWithTranslation = {
|
||||
}
|
||||
};
|
||||
|
||||
export function functionValueCalculator<T>(useFunction: boolean, func: (...args: any[]) => any, params = [], defaultValue: T): T {
|
||||
export function functionValueCalculator<T>(useFunction: boolean, func: CompiledTbFunction<GenericFunction>, params = [], defaultValue: T): T {
|
||||
let res: T;
|
||||
if (useFunction && isDefined(func) && isFunction(func)) {
|
||||
try {
|
||||
res = func(...params);
|
||||
res = func.execute(...params);
|
||||
if (!isDefinedAndNotNull(res) || res === '') {
|
||||
res = defaultValue;
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ import {
|
||||
isNotEmptyStr,
|
||||
isString,
|
||||
mergeFormattedData,
|
||||
safeExecute
|
||||
safeExecuteTbFunction
|
||||
} from '@core/utils';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
@ -63,9 +63,9 @@ import {
|
||||
} from '@home/components/widget/lib/maps/dialogs/select-entity-dialog.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { FormattedData, ReplaceInfo } from '@shared/models/widget.models';
|
||||
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
|
||||
import { ImagePipe } from '@shared/pipe/image.pipe';
|
||||
import { take, tap } from 'rxjs/operators';
|
||||
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
|
||||
|
||||
export default abstract class LeafletMap {
|
||||
|
||||
@ -149,7 +149,7 @@ export default abstract class LeafletMap {
|
||||
const childCount = cluster.getChildCount();
|
||||
const formattedData = cluster.getAllChildMarkers().map(clusterMarker => clusterMarker.options.tbMarkerData);
|
||||
const markerColor = markerClusteringSettings.clusterMarkerFunction
|
||||
? safeExecute(markerClusteringSettings.parsedClusterMarkerFunction,
|
||||
? safeExecuteTbFunction(markerClusteringSettings.parsedClusterMarkerFunction,
|
||||
[formattedData, childCount])
|
||||
: null;
|
||||
if (isDefinedAndNotNull(markerColor) && tinycolor(markerColor).isValid()) {
|
||||
@ -899,7 +899,7 @@ export default abstract class LeafletMap {
|
||||
rawMarkers.forEach(data => {
|
||||
if (data.rotationAngle || data.rotationAngle === 0) {
|
||||
const currentImage: MarkerImageInfo = this.options.useMarkerImageFunction ?
|
||||
safeExecute(this.options.parsedMarkerImageFunction,
|
||||
safeExecuteTbFunction(this.options.parsedMarkerImageFunction,
|
||||
[data, this.options.markerImages, markersData, data.dsIndex]) : this.options.currentImage;
|
||||
const imageUrl$ =
|
||||
currentImage
|
||||
@ -1042,7 +1042,7 @@ export default abstract class LeafletMap {
|
||||
if (!!this.extractPosition(pdata)) {
|
||||
const dsData = pointsData.map(ds => ds[tsIndex]);
|
||||
if (this.options.useColorPointFunction) {
|
||||
pointColor = safeExecute(this.options.parsedColorPointFunction, [pdata, dsData, pdata.dsIndex]);
|
||||
pointColor = safeExecuteTbFunction(this.options.parsedColorPointFunction, [pdata, dsData, pdata.dsIndex]);
|
||||
}
|
||||
const point = L.circleMarker(this.convertPosition(pdata, dsData), {
|
||||
color: pointColor,
|
||||
|
||||
@ -18,6 +18,7 @@ import { Datasource, FormattedData } from '@app/shared/models/widget.models';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { BaseIconOptions, Icon } from 'leaflet';
|
||||
import { Observable } from 'rxjs';
|
||||
import { CompiledTbFunction, TbFunction } from '@shared/models/js-function.models';
|
||||
|
||||
export const DEFAULT_MAP_PAGE_SIZE = 16384;
|
||||
export const DEFAULT_ZOOM_LEVEL = 8;
|
||||
@ -273,7 +274,7 @@ export interface TripAnimationCommonSettings {
|
||||
}
|
||||
|
||||
export interface WidgetTripAnimationCommonSettings extends TripAnimationCommonSettings {
|
||||
parsedTooltipFunction: GenericFunction;
|
||||
parsedTooltipFunction: CompiledTbFunction<GenericFunction>;
|
||||
}
|
||||
|
||||
export const defaultTripAnimationCommonSettings: TripAnimationCommonSettings = {
|
||||
@ -305,35 +306,35 @@ export const showTooltipActionTranslationMap = new Map<ShowTooltipAction, string
|
||||
export interface MarkersSettings {
|
||||
markerOffsetX: number;
|
||||
markerOffsetY: number;
|
||||
posFunction?: string;
|
||||
posFunction?: TbFunction;
|
||||
draggableMarker: boolean;
|
||||
showLabel: boolean;
|
||||
useLabelFunction: boolean;
|
||||
label?: string;
|
||||
labelFunction?: string;
|
||||
labelFunction?: TbFunction;
|
||||
showTooltip: boolean;
|
||||
showTooltipAction: ShowTooltipAction;
|
||||
autocloseTooltip: boolean;
|
||||
useTooltipFunction: boolean;
|
||||
tooltipPattern?: string;
|
||||
tooltipFunction?: string;
|
||||
tooltipFunction?: TbFunction;
|
||||
tooltipOffsetX: number;
|
||||
tooltipOffsetY: number;
|
||||
color?: string;
|
||||
useColorFunction: boolean;
|
||||
colorFunction?: string;
|
||||
colorFunction?: TbFunction;
|
||||
useMarkerImageFunction: boolean;
|
||||
markerImage?: string;
|
||||
markerImageSize?: number;
|
||||
markerImageFunction?: string;
|
||||
markerImageFunction?: TbFunction;
|
||||
markerImages?: string[];
|
||||
}
|
||||
|
||||
export interface WidgetMarkersSettings extends MarkersSettings, WidgetToolipSettings {
|
||||
parsedLabelFunction: GenericFunction;
|
||||
parsedTooltipFunction: GenericFunction;
|
||||
parsedColorFunction: GenericFunction;
|
||||
parsedMarkerImageFunction: MarkerImageFunction;
|
||||
parsedLabelFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedTooltipFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedColorFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedMarkerImageFunction: CompiledTbFunction<MarkerImageFunction>;
|
||||
markerClick: { [name: string]: actionsHandler };
|
||||
currentImage: MarkerImageInfo;
|
||||
tinyColor: tinycolor.Instance;
|
||||
@ -382,8 +383,7 @@ export interface TripAnimationMarkerSettings {
|
||||
}
|
||||
|
||||
export interface WidgetTripAnimationMarkerSettings extends TripAnimationMarkerSettings {
|
||||
parsedLabelFunction: GenericFunction;
|
||||
parsedMarkerImageFunction: MarkerImageFunction;
|
||||
parsedLabelFunction: CompiledTbFunction<GenericFunction>;
|
||||
}
|
||||
|
||||
export const defaultTripAnimationMarkersSettings: TripAnimationMarkerSettings = {
|
||||
@ -406,29 +406,29 @@ export interface PolygonSettings {
|
||||
showPolygonLabel: boolean;
|
||||
usePolygonLabelFunction: boolean;
|
||||
polygonLabel?: string;
|
||||
polygonLabelFunction?: string;
|
||||
polygonLabelFunction?: TbFunction;
|
||||
showPolygonTooltip: boolean;
|
||||
showPolygonTooltipAction: ShowTooltipAction;
|
||||
autoClosePolygonTooltip: boolean;
|
||||
usePolygonTooltipFunction: boolean;
|
||||
polygonTooltipPattern?: string;
|
||||
polygonTooltipFunction?: string;
|
||||
polygonTooltipFunction?: TbFunction;
|
||||
polygonColor?: string;
|
||||
polygonOpacity?: number;
|
||||
usePolygonColorFunction: boolean;
|
||||
polygonColorFunction?: string;
|
||||
polygonColorFunction?: TbFunction;
|
||||
polygonStrokeColor?: string;
|
||||
polygonStrokeOpacity?: number;
|
||||
polygonStrokeWeight?: number;
|
||||
usePolygonStrokeColorFunction: boolean;
|
||||
polygonStrokeColorFunction?: string;
|
||||
polygonStrokeColorFunction?: TbFunction;
|
||||
}
|
||||
|
||||
export interface WidgetPolygonSettings extends PolygonSettings, WidgetToolipSettings {
|
||||
parsedPolygonLabelFunction: GenericFunction;
|
||||
parsedPolygonTooltipFunction: GenericFunction;
|
||||
parsedPolygonColorFunction: GenericFunction;
|
||||
parsedPolygonStrokeColorFunction: GenericFunction;
|
||||
parsedPolygonLabelFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedPolygonTooltipFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedPolygonColorFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedPolygonStrokeColorFunction: CompiledTbFunction<GenericFunction>;
|
||||
polygonClick: { [name: string]: actionsHandler };
|
||||
}
|
||||
|
||||
@ -464,29 +464,29 @@ export interface CircleSettings {
|
||||
showCircleLabel: boolean;
|
||||
useCircleLabelFunction: boolean;
|
||||
circleLabel?: string;
|
||||
circleLabelFunction?: string;
|
||||
circleLabelFunction?: TbFunction;
|
||||
showCircleTooltip: boolean;
|
||||
showCircleTooltipAction: ShowTooltipAction;
|
||||
autoCloseCircleTooltip: boolean;
|
||||
useCircleTooltipFunction: boolean;
|
||||
circleTooltipPattern?: string;
|
||||
circleTooltipFunction?: string;
|
||||
circleTooltipFunction?: TbFunction;
|
||||
circleFillColor?: string;
|
||||
circleFillColorOpacity?: number;
|
||||
useCircleFillColorFunction: boolean;
|
||||
circleFillColorFunction?: string;
|
||||
circleFillColorFunction?: TbFunction;
|
||||
circleStrokeColor?: string;
|
||||
circleStrokeOpacity?: number;
|
||||
circleStrokeWeight?: number;
|
||||
useCircleStrokeColorFunction: boolean;
|
||||
circleStrokeColorFunction?: string;
|
||||
circleStrokeColorFunction?: TbFunction;
|
||||
}
|
||||
|
||||
export interface WidgetCircleSettings extends CircleSettings, WidgetToolipSettings {
|
||||
parsedCircleLabelFunction: GenericFunction;
|
||||
parsedCircleTooltipFunction: GenericFunction;
|
||||
parsedCircleFillColorFunction: GenericFunction;
|
||||
parsedCircleStrokeColorFunction: GenericFunction;
|
||||
parsedCircleLabelFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedCircleTooltipFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedCircleFillColorFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedCircleStrokeColorFunction: CompiledTbFunction<GenericFunction>;
|
||||
circleClick: { [name: string]: actionsHandler };
|
||||
}
|
||||
|
||||
@ -530,13 +530,13 @@ export const polylineDecoratorSymbolTranslationMap = new Map<PolylineDecoratorSy
|
||||
export interface PolylineSettings {
|
||||
useStrokeWeightFunction?: boolean;
|
||||
strokeWeight: number;
|
||||
strokeWeightFunction?: string;
|
||||
strokeWeightFunction?: TbFunction;
|
||||
useStrokeOpacityFunction?: boolean;
|
||||
strokeOpacity: number;
|
||||
strokeOpacityFunction?: string;
|
||||
strokeOpacityFunction?: TbFunction;
|
||||
useColorFunction?: boolean;
|
||||
color?: string;
|
||||
colorFunction?: string;
|
||||
colorFunction?: TbFunction;
|
||||
usePolylineDecorator?: boolean;
|
||||
decoratorSymbol?: PolylineDecoratorSymbol;
|
||||
decoratorSymbolSize?: number;
|
||||
@ -548,9 +548,9 @@ export interface PolylineSettings {
|
||||
}
|
||||
|
||||
export interface WidgetPolylineSettings extends PolylineSettings {
|
||||
parsedColorFunction: GenericFunction;
|
||||
parsedStrokeOpacityFunction: GenericFunction;
|
||||
parsedStrokeWeightFunction: GenericFunction;
|
||||
parsedColorFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedStrokeOpacityFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedStrokeWeightFunction: CompiledTbFunction<GenericFunction>;
|
||||
}
|
||||
|
||||
export const defaultRouteMapSettings: PolylineSettings = {
|
||||
@ -578,7 +578,7 @@ export interface PointsSettings {
|
||||
showPoints?: boolean;
|
||||
pointColor?: string;
|
||||
useColorPointFunction?: false;
|
||||
colorPointFunction?: string;
|
||||
colorPointFunction?: TbFunction;
|
||||
pointSize?: number;
|
||||
usePointAsAnchor?: false;
|
||||
pointAsAnchorFunction?: string;
|
||||
@ -586,8 +586,8 @@ export interface PointsSettings {
|
||||
}
|
||||
|
||||
export interface WidgetPointsSettings extends PointsSettings {
|
||||
parsedColorPointFunction: GenericFunction;
|
||||
parsedPointAsAnchorFunction: GenericFunction;
|
||||
parsedColorPointFunction: CompiledTbFunction<GenericFunction>;
|
||||
parsedPointAsAnchorFunction: CompiledTbFunction<GenericFunction>;
|
||||
}
|
||||
|
||||
export const defaultTripAnimationPointSettings: PointsSettings = {
|
||||
@ -612,11 +612,11 @@ export interface MarkerClusteringSettings {
|
||||
chunkedLoading: boolean;
|
||||
removeOutsideVisibleBounds: boolean;
|
||||
useIconCreateFunction: boolean;
|
||||
clusterMarkerFunction?: string;
|
||||
clusterMarkerFunction?: TbFunction;
|
||||
}
|
||||
|
||||
export interface WidgetMarkerClusteringSettings extends MarkerClusteringSettings {
|
||||
parsedClusterMarkerFunction?: GenericFunction;
|
||||
parsedClusterMarkerFunction?: CompiledTbFunction<GenericFunction>;
|
||||
}
|
||||
|
||||
export const defaultMarkerClusteringSettings: MarkerClusteringSettings = {
|
||||
|
||||
@ -30,9 +30,9 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
import { EntityDataPageLink } from '@shared/models/query/query.models';
|
||||
import { providerClass } from '@home/components/widget/lib/maps/providers/public-api';
|
||||
import { isDefined, isDefinedAndNotNull, parseFunction } from '@core/utils';
|
||||
import { isDefined, isDefinedAndNotNull, parseFunction, parseTbFunction } from '@core/utils';
|
||||
import L from 'leaflet';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { firstValueFrom, forkJoin, from, Observable, of } from 'rxjs';
|
||||
import { AttributeService } from '@core/http/attribute.service';
|
||||
import { EntityId } from '@shared/models/id/entity-id';
|
||||
import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
|
||||
@ -40,12 +40,18 @@ import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/tel
|
||||
// @dynamic
|
||||
export class MapWidgetController implements MapWidgetInterface {
|
||||
|
||||
private updatePending = false;
|
||||
private latestUpdatePending = false;
|
||||
private resizePending = false;
|
||||
private destroyed = false;
|
||||
|
||||
constructor(
|
||||
public mapProvider: MapProviders,
|
||||
private drawRoutes: boolean,
|
||||
public ctx: WidgetContext,
|
||||
$element: HTMLElement,
|
||||
isEdit?: boolean
|
||||
isEdit = false,
|
||||
mapLoaded?: (map: LeafletMap) => void
|
||||
) {
|
||||
if (this.map) {
|
||||
this.map.map.remove();
|
||||
@ -56,37 +62,53 @@ export class MapWidgetController implements MapWidgetInterface {
|
||||
if (!$element) {
|
||||
$element = ctx.$container[0];
|
||||
}
|
||||
this.settings = this.initSettings(ctx.settings, isEdit);
|
||||
this.settings.tooltipAction = this.getDescriptors('tooltipAction');
|
||||
this.settings.markerClick = this.getDescriptors('markerClick');
|
||||
this.settings.polygonClick = this.getDescriptors('polygonClick');
|
||||
this.settings.circleClick = this.getDescriptors('circleClick');
|
||||
from(this.initSettings(ctx.settings, isEdit)).subscribe(settings => {
|
||||
if (!this.destroyed) {
|
||||
this.settings = settings;
|
||||
this.settings.tooltipAction = this.getDescriptors('tooltipAction');
|
||||
this.settings.markerClick = this.getDescriptors('markerClick');
|
||||
this.settings.polygonClick = this.getDescriptors('polygonClick');
|
||||
this.settings.circleClick = this.getDescriptors('circleClick');
|
||||
|
||||
const MapClass = providerClass[this.provider];
|
||||
if (!MapClass) {
|
||||
return;
|
||||
}
|
||||
parseWithTranslation.setTranslate(this.translate);
|
||||
this.map = new MapClass(this.ctx, $element, this.settings);
|
||||
(this.ctx as any).mapInstance = this.map;
|
||||
this.map.saveMarkerLocation = this.setMarkerLocation.bind(this);
|
||||
this.map.savePolygonLocation = this.savePolygonLocation.bind(this);
|
||||
this.map.saveLocation = this.saveLocation.bind(this);
|
||||
let pageSize = this.settings.mapPageSize;
|
||||
if (isDefinedAndNotNull(this.ctx.widgetConfig.pageSize)) {
|
||||
pageSize = Math.max(pageSize, this.ctx.widgetConfig.pageSize);
|
||||
}
|
||||
this.pageLink = {
|
||||
page: 0,
|
||||
pageSize,
|
||||
textSearch: null,
|
||||
dynamic: true
|
||||
};
|
||||
this.map.setLoading(true);
|
||||
this.ctx.defaultSubscription.paginatedDataSubscriptionUpdated.subscribe(() => {
|
||||
this.map.resetState();
|
||||
const MapClass = providerClass[this.provider];
|
||||
if (!MapClass) {
|
||||
return;
|
||||
}
|
||||
parseWithTranslation.setTranslate(this.translate);
|
||||
this.map = new MapClass(this.ctx, $element, this.settings);
|
||||
(this.ctx as any).mapInstance = this.map;
|
||||
this.map.saveMarkerLocation = this.setMarkerLocation.bind(this);
|
||||
this.map.savePolygonLocation = this.savePolygonLocation.bind(this);
|
||||
this.map.saveLocation = this.saveLocation.bind(this);
|
||||
let pageSize = this.settings.mapPageSize;
|
||||
if (isDefinedAndNotNull(this.ctx.widgetConfig.pageSize)) {
|
||||
pageSize = Math.max(pageSize, this.ctx.widgetConfig.pageSize);
|
||||
}
|
||||
this.pageLink = {
|
||||
page: 0,
|
||||
pageSize,
|
||||
textSearch: null,
|
||||
dynamic: true
|
||||
};
|
||||
this.map.setLoading(true);
|
||||
this.ctx.defaultSubscription.paginatedDataSubscriptionUpdated.subscribe(() => {
|
||||
this.map.resetState();
|
||||
});
|
||||
this.ctx.defaultSubscription.subscribeAllForPaginatedData(this.pageLink, null);
|
||||
if (this.updatePending) {
|
||||
this.update();
|
||||
}
|
||||
if (this.latestUpdatePending) {
|
||||
this.latestDataUpdate();
|
||||
}
|
||||
if (this.resizePending) {
|
||||
this.resize();
|
||||
}
|
||||
if (mapLoaded) {
|
||||
mapLoaded(this.map);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.ctx.defaultSubscription.subscribeAllForPaginatedData(this.pageLink, null);
|
||||
}
|
||||
|
||||
map: LeafletMap;
|
||||
@ -233,27 +255,27 @@ export class MapWidgetController implements MapWidgetInterface {
|
||||
}
|
||||
}
|
||||
|
||||
initSettings(settings: UnitedMapSettings, isEditMap?: boolean): WidgetUnitedMapSettings {
|
||||
async initSettings(settings: UnitedMapSettings, isEditMap?: boolean): Promise<WidgetUnitedMapSettings> {
|
||||
const functionParams = ['data', 'dsData', 'dsIndex'];
|
||||
this.provider = settings.provider || this.mapProvider;
|
||||
const parsedOptions: Partial<WidgetUnitedMapSettings> = {
|
||||
provider: this.provider,
|
||||
parsedLabelFunction: parseFunction(settings.labelFunction, functionParams),
|
||||
parsedTooltipFunction: parseFunction(settings.tooltipFunction, functionParams),
|
||||
parsedColorFunction: parseFunction(settings.colorFunction, functionParams),
|
||||
parsedColorPointFunction: parseFunction(settings.colorPointFunction, functionParams),
|
||||
parsedStrokeOpacityFunction: parseFunction(settings.strokeOpacityFunction, functionParams),
|
||||
parsedStrokeWeightFunction: parseFunction(settings.strokeWeightFunction, functionParams),
|
||||
parsedPolygonLabelFunction: parseFunction(settings.polygonLabelFunction, functionParams),
|
||||
parsedPolygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams),
|
||||
parsedPolygonStrokeColorFunction: parseFunction(settings.polygonStrokeColorFunction, functionParams),
|
||||
parsedPolygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams),
|
||||
parsedCircleLabelFunction: parseFunction(settings.circleLabelFunction, functionParams),
|
||||
parsedCircleStrokeColorFunction: parseFunction(settings.circleStrokeColorFunction, functionParams),
|
||||
parsedCircleFillColorFunction: parseFunction(settings.circleFillColorFunction, functionParams),
|
||||
parsedCircleTooltipFunction: parseFunction(settings.circleTooltipFunction, functionParams),
|
||||
parsedMarkerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']),
|
||||
parsedClusterMarkerFunction: parseFunction(settings.clusterMarkerFunction, ['data', 'childCount']),
|
||||
parsedLabelFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.labelFunction, functionParams)),
|
||||
parsedTooltipFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.tooltipFunction, functionParams)),
|
||||
parsedColorFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.colorFunction, functionParams)),
|
||||
parsedColorPointFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.colorPointFunction, functionParams)),
|
||||
parsedStrokeOpacityFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.strokeOpacityFunction, functionParams)),
|
||||
parsedStrokeWeightFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.strokeWeightFunction, functionParams)),
|
||||
parsedPolygonLabelFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.polygonLabelFunction, functionParams)),
|
||||
parsedPolygonColorFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.polygonColorFunction, functionParams)),
|
||||
parsedPolygonStrokeColorFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.polygonStrokeColorFunction, functionParams)),
|
||||
parsedPolygonTooltipFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.polygonTooltipFunction, functionParams)),
|
||||
parsedCircleLabelFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.circleLabelFunction, functionParams)),
|
||||
parsedCircleStrokeColorFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.circleStrokeColorFunction, functionParams)),
|
||||
parsedCircleFillColorFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.circleFillColorFunction, functionParams)),
|
||||
parsedCircleTooltipFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.circleTooltipFunction, functionParams)),
|
||||
parsedMarkerImageFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex'])),
|
||||
parsedClusterMarkerFunction: await firstValueFrom(parseTbFunction(this.ctx.http, settings.clusterMarkerFunction, ['data', 'childCount'])),
|
||||
// labelColor: this.ctx.widgetConfig.color,
|
||||
// polygonLabelColor: this.ctx.widgetConfig.color,
|
||||
polygonKeyName: (settings as any).polKeyName ? (settings as any).polKeyName : settings.polygonKeyName,
|
||||
@ -277,20 +299,36 @@ export class MapWidgetController implements MapWidgetInterface {
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this.map) {
|
||||
this.updatePending = false;
|
||||
this.map.updateData(this.drawRoutes);
|
||||
this.map.setLoading(false);
|
||||
} else {
|
||||
this.updatePending = true;
|
||||
}
|
||||
}
|
||||
|
||||
latestDataUpdate() {
|
||||
this.map.updateData(this.drawRoutes);
|
||||
if (this.map) {
|
||||
this.latestUpdatePending = false;
|
||||
this.map.updateData(this.drawRoutes);
|
||||
} else {
|
||||
this.latestUpdatePending = true;
|
||||
}
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.map.onResize();
|
||||
this.map?.invalidateSize();
|
||||
if (this.map) {
|
||||
this.resizePending = false;
|
||||
this.map.onResize();
|
||||
this.map.invalidateSize();
|
||||
} else {
|
||||
this.resizePending = true;
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
if (this.map) {
|
||||
this.map.remove();
|
||||
}
|
||||
|
||||
@ -15,13 +15,11 @@
|
||||
///
|
||||
|
||||
import L from 'leaflet';
|
||||
import {
|
||||
GenericFunction,
|
||||
ShowTooltipAction, WidgetToolipSettings
|
||||
} from './map-models';
|
||||
import { GenericFunction, ShowTooltipAction, WidgetToolipSettings } from './map-models';
|
||||
import { Datasource, FormattedData } from '@app/shared/models/widget.models';
|
||||
import { fillDataPattern, isDefinedAndNotNull, isString, processDataPattern, safeExecute } from '@core/utils';
|
||||
import { fillDataPattern, isDefinedAndNotNull, isString, processDataPattern, safeExecuteTbFunction } from '@core/utils';
|
||||
import { parseWithTranslation } from '@home/components/widget/lib/maps/common-maps-utils';
|
||||
import { CompiledTbFunction } from '@shared/models/js-function.models';
|
||||
|
||||
export function createTooltip(target: L.Layer,
|
||||
settings: Partial<WidgetToolipSettings>,
|
||||
@ -90,7 +88,7 @@ export function isJSON(data: string): boolean {
|
||||
export interface LabelSettings {
|
||||
showLabel: boolean;
|
||||
useLabelFunction: boolean;
|
||||
parsedLabelFunction: GenericFunction;
|
||||
parsedLabelFunction: CompiledTbFunction<GenericFunction>;
|
||||
label: string;
|
||||
}
|
||||
|
||||
@ -98,7 +96,7 @@ export function entitiesParseName(entities: FormattedData[], labelSettings: Labe
|
||||
const div = document.createElement('div');
|
||||
for (const entity of entities) {
|
||||
if (labelSettings?.showLabel) {
|
||||
const pattern = labelSettings.useLabelFunction ? safeExecute(labelSettings.parsedLabelFunction,
|
||||
const pattern = labelSettings.useLabelFunction ? safeExecuteTbFunction(labelSettings.parsedLabelFunction,
|
||||
[entity, entities, entity.dsIndex]) : labelSettings.label;
|
||||
const markerLabelText = parseWithTranslation.prepareProcessPattern(pattern, true);
|
||||
const replaceInfoLabelMarker = processDataPattern(pattern, entity);
|
||||
|
||||
@ -19,7 +19,13 @@ import { MarkerIconInfo, MarkerIconReadyFunction, MarkerImageInfo, WidgetMarkers
|
||||
import { bindPopupActions, createTooltip } from './maps-utils';
|
||||
import { loadImageWithAspect, parseWithTranslation } from './common-maps-utils';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { fillDataPattern, isDefined, isDefinedAndNotNull, processDataPattern, safeExecute } from '@core/utils';
|
||||
import {
|
||||
fillDataPattern,
|
||||
isDefined,
|
||||
isDefinedAndNotNull,
|
||||
processDataPattern,
|
||||
safeExecuteTbFunction
|
||||
} from '@core/utils';
|
||||
import LeafletMap from './leaflet-map';
|
||||
import { FormattedData } from '@shared/models/widget.models';
|
||||
import { ImagePipe } from '@shared/pipe/image.pipe';
|
||||
@ -101,7 +107,7 @@ export class Marker {
|
||||
updateMarkerTooltip(data: FormattedData) {
|
||||
if (!this.map.markerTooltipText || this.settings.useTooltipFunction) {
|
||||
const pattern = this.settings.useTooltipFunction ?
|
||||
safeExecute(this.settings.parsedTooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) : this.settings.tooltipPattern;
|
||||
safeExecuteTbFunction(this.settings.parsedTooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) : this.settings.tooltipPattern;
|
||||
this.map.markerTooltipText = parseWithTranslation.prepareProcessPattern(pattern, true);
|
||||
this.map.replaceInfoTooltipMarker = processDataPattern(this.map.markerTooltipText, data);
|
||||
}
|
||||
@ -123,7 +129,7 @@ export class Marker {
|
||||
if (settings.showLabel) {
|
||||
if (!this.map.markerLabelText || settings.useLabelFunction) {
|
||||
const pattern = settings.useLabelFunction ?
|
||||
safeExecute(settings.parsedLabelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.label;
|
||||
safeExecuteTbFunction(settings.parsedLabelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.label;
|
||||
this.map.markerLabelText = parseWithTranslation.prepareProcessPattern(pattern, true);
|
||||
this.map.replaceInfoLabelMarker = processDataPattern(this.map.markerLabelText, this.data);
|
||||
}
|
||||
@ -165,11 +171,11 @@ export class Marker {
|
||||
return;
|
||||
}
|
||||
const currentImage: MarkerImageInfo = this.settings.useMarkerImageFunction ?
|
||||
safeExecute(this.settings.parsedMarkerImageFunction,
|
||||
safeExecuteTbFunction(this.settings.parsedMarkerImageFunction,
|
||||
[this.data, this.settings.markerImages, this.dataSources, this.data.dsIndex]) : this.settings.currentImage;
|
||||
let currentColor = this.settings.tinyColor;
|
||||
if (this.settings.useColorFunction) {
|
||||
const functionColor = safeExecute(this.settings.parsedColorFunction,
|
||||
const functionColor = safeExecuteTbFunction(this.settings.parsedColorFunction,
|
||||
[this.data, this.dataSources, this.data.dsIndex]);
|
||||
if (isDefinedAndNotNull(functionColor)) {
|
||||
currentColor = tinycolor(functionColor);
|
||||
|
||||
@ -16,13 +16,10 @@
|
||||
|
||||
import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet';
|
||||
import { createTooltip, isCutPolygon } from './maps-utils';
|
||||
import {
|
||||
functionValueCalculator,
|
||||
parseWithTranslation
|
||||
} from './common-maps-utils';
|
||||
import { functionValueCalculator, parseWithTranslation } from './common-maps-utils';
|
||||
import { WidgetPolygonSettings } from './map-models';
|
||||
import { FormattedData } from '@shared/models/widget.models';
|
||||
import { fillDataPattern, processDataPattern, safeExecute } from '@core/utils';
|
||||
import { fillDataPattern, processDataPattern, safeExecuteTbFunction } from '@core/utils';
|
||||
import LeafletMap from '@home/components/widget/lib/maps/leaflet-map';
|
||||
|
||||
export class Polygon {
|
||||
@ -92,7 +89,7 @@ export class Polygon {
|
||||
|
||||
updateTooltip(data: FormattedData) {
|
||||
const pattern = this.settings.usePolygonTooltipFunction ?
|
||||
safeExecute(this.settings.parsedPolygonTooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) :
|
||||
safeExecuteTbFunction(this.settings.parsedPolygonTooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) :
|
||||
this.settings.polygonTooltipPattern;
|
||||
this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true));
|
||||
}
|
||||
@ -102,7 +99,7 @@ export class Polygon {
|
||||
if (settings.showPolygonLabel) {
|
||||
if (!this.map.polygonLabelText || settings.usePolygonLabelFunction) {
|
||||
const pattern = settings.usePolygonLabelFunction ?
|
||||
safeExecute(settings.parsedPolygonLabelFunction,
|
||||
safeExecuteTbFunction(settings.parsedPolygonLabelFunction,
|
||||
[this.data, this.dataSources, this.data.dsIndex]) : settings.polygonLabel;
|
||||
this.map.polygonLabelText = parseWithTranslation.prepareProcessPattern(pattern, true);
|
||||
this.map.replaceInfoLabelPolygon = processDataPattern(this.map.polygonLabelText, this.data);
|
||||
|
||||
@ -23,16 +23,17 @@ import {
|
||||
PosFunction,
|
||||
WidgetUnitedMapSettings
|
||||
} from '../map-models';
|
||||
import { Observable, of, ReplaySubject, switchMap } from 'rxjs';
|
||||
import { forkJoin, Observable, of, ReplaySubject, switchMap } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { calculateNewPointCoordinate, loadImageWithAspect } from '@home/components/widget/lib/maps/common-maps-utils';
|
||||
import { WidgetContext } from '@home/models/widget-component.models';
|
||||
import { DataSet, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models';
|
||||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||
import { WidgetSubscriptionOptions } from '@core/api/widget-api.models';
|
||||
import { isDefinedAndNotNull, isEmptyStr, isNotEmptyStr, parseFunction } from '@core/utils';
|
||||
import { isDefinedAndNotNull, isEmptyStr, isNotEmptyStr, parseFunction, parseTbFunction } from '@core/utils';
|
||||
import { EntityDataPageLink } from '@shared/models/query/query.models';
|
||||
import { ImagePipe } from '@shared/pipe/image.pipe';
|
||||
import { CompiledTbFunction } from '@shared/models/js-function.models';
|
||||
|
||||
const maxZoom = 4; // ?
|
||||
|
||||
@ -43,13 +44,20 @@ export class ImageMap extends LeafletMap {
|
||||
width = 0;
|
||||
height = 0;
|
||||
imageUrl: string;
|
||||
posFunction: PosFunction;
|
||||
posFunction: CompiledTbFunction<PosFunction>;
|
||||
|
||||
constructor(ctx: WidgetContext, $container: HTMLElement, options: WidgetUnitedMapSettings) {
|
||||
super(ctx, $container, options);
|
||||
this.posFunction = parseFunction(options.posFunction,
|
||||
['origXPos', 'origYPos', 'data', 'dsData', 'dsIndex', 'aspect']) as PosFunction;
|
||||
this.mapImage(options).subscribe((mapImage) => {
|
||||
|
||||
const initData = {
|
||||
posFunction: parseTbFunction<PosFunction>(this.ctx.http, options.posFunction,
|
||||
['origXPos', 'origYPos', 'data', 'dsData', 'dsIndex', 'aspect']),
|
||||
mapImage: this.mapImage(options)
|
||||
};
|
||||
|
||||
forkJoin(initData).subscribe(inited => {
|
||||
this.posFunction = inited.posFunction;
|
||||
const mapImage = inited.mapImage;
|
||||
this.imageUrl = mapImage.imageUrl;
|
||||
this.aspect = mapImage.aspect;
|
||||
if (mapImage.update) {
|
||||
@ -272,7 +280,7 @@ export class ImageMap extends LeafletMap {
|
||||
convertPosition(data: FormattedData, dsData: FormattedData[]): L.LatLng {
|
||||
const position = this.extractPosition(data);
|
||||
if (position) {
|
||||
const converted = this.posFunction(position.x, position.y, data, dsData, data.dsIndex, this.aspect) || {x: 0, y: 0};
|
||||
const converted = this.posFunction.execute(position.x, position.y, data, dsData, data.dsIndex, this.aspect) || {x: 0, y: 0};
|
||||
return this.positionToLatLng(converted);
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!circleSettingsFormGroup.get('useCircleLabelFunction').value"
|
||||
formControlName="circleLabelFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.circle-label-function' | translate }}"
|
||||
@ -105,6 +106,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!circleSettingsFormGroup.get('useCircleTooltipFunction').value"
|
||||
formControlName="circleTooltipFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.circle-tooltip-function' | translate }}"
|
||||
@ -140,6 +142,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="circleFillColorFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.circle-fill-color-function' | translate }}"
|
||||
@ -179,6 +182,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="circleStrokeColorFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.circle-stroke-color-function' | translate }}"
|
||||
|
||||
@ -78,6 +78,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="clusterMarkerFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'childCount']"
|
||||
functionTitle="{{ 'widgets.maps.marker-color-function' | translate }}"
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
</section>
|
||||
<tb-js-func [class.!hidden]="provider !== mapProvider.image"
|
||||
formControlName="posFunction"
|
||||
withModules
|
||||
minHeight="100px"
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['origXPos', 'origYPos', 'data', 'dsData', 'dsIndex', 'aspect']"
|
||||
@ -63,6 +64,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!markersSettingsFormGroup.get('useLabelFunction').value"
|
||||
formControlName="labelFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.label-function' | translate }}"
|
||||
@ -106,6 +108,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!markersSettingsFormGroup.get('useTooltipFunction').value"
|
||||
formControlName="tooltipFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.tooltip-function' | translate }}"
|
||||
@ -144,6 +147,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="colorFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.color-function' | translate }}"
|
||||
@ -177,6 +181,7 @@
|
||||
</mat-form-field>
|
||||
<tb-js-func [class.!hidden]="!markersSettingsFormGroup.get('useMarkerImageFunction').value"
|
||||
formControlName="markerImageFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'images', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.marker-image-function' | translate }}"
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!polygonSettingsFormGroup.get('usePolygonLabelFunction').value"
|
||||
formControlName="polygonLabelFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.polygon-label-function' | translate }}"
|
||||
@ -105,6 +106,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!polygonSettingsFormGroup.get('usePolygonTooltipFunction').value"
|
||||
formControlName="polygonTooltipFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.polygon-tooltip-function' | translate }}"
|
||||
@ -140,6 +142,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="polygonColorFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.polygon-color-function' | translate }}"
|
||||
@ -179,6 +182,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="polygonStrokeColorFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.polygon-stroke-color-function' | translate }}"
|
||||
|
||||
@ -81,6 +81,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!tripAnimationCommonSettingsFormGroup.get('useTooltipFunction').value"
|
||||
formControlName="tooltipFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.tooltip-function' | translate }}"
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
</tb-html>
|
||||
<tb-js-func [class.!hidden]="!tripAnimationMarkerSettingsFormGroup.get('useLabelFunction').value"
|
||||
formControlName="labelFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.label-function' | translate }}"
|
||||
@ -78,6 +79,7 @@
|
||||
<input matInput type="number" min="1" formControlName="markerImageSize">
|
||||
</mat-form-field>
|
||||
<tb-js-func [class.!hidden]="!tripAnimationMarkerSettingsFormGroup.get('useMarkerImageFunction').value"
|
||||
withModules
|
||||
formControlName="markerImageFunction"
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'images', 'dsData', 'dsIndex']"
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="colorFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.path-color-function' | translate }}"
|
||||
|
||||
@ -55,6 +55,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="colorPointFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.point-color-function' | translate }}"
|
||||
@ -75,6 +76,7 @@
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<tb-js-func formControlName="pointAsAnchorFunction"
|
||||
withModules
|
||||
[globalVariables]="functionScopeVariables"
|
||||
[functionArgs]="['data', 'dsData', 'dsIndex']"
|
||||
functionTitle="{{ 'widgets.maps.point-as-anchor-function' | translate }}"
|
||||
|
||||
@ -48,10 +48,11 @@ import {
|
||||
isDefined,
|
||||
isUndefined,
|
||||
mergeFormattedData,
|
||||
parseFunction,
|
||||
safeExecute
|
||||
parseTbFunction,
|
||||
safeExecuteTbFunction
|
||||
} from '@core/utils';
|
||||
import { MapWidgetInterface } from '@home/components/widget/lib/maps/map-widget.interface';
|
||||
import { firstValueFrom, from } from 'rxjs';
|
||||
|
||||
interface DataMap {
|
||||
[key: string]: FormattedData;
|
||||
@ -67,6 +68,10 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
|
||||
private mapResize$: ResizeObserver;
|
||||
|
||||
private initialized = false;
|
||||
private updatePending = false;
|
||||
private mapWidgetUpdatePending = false;
|
||||
|
||||
constructor(private cd: ChangeDetectorRef, private sanitizer: DomSanitizer) { }
|
||||
|
||||
@Input() ctx: WidgetContext;
|
||||
@ -100,38 +105,33 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
...this.ctx.settings
|
||||
};
|
||||
this.useAnchors = this.settings.showPoints && this.settings.usePointAsAnchor;
|
||||
this.settings.parsedPointAsAnchorFunction = parseFunction(this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']);
|
||||
this.settings.parsedTooltipFunction = parseFunction(this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']);
|
||||
this.settings.parsedLabelFunction = parseFunction(this.settings.labelFunction, ['data', 'dsData', 'dsIndex']);
|
||||
this.settings.parsedColorPointFunction = parseFunction(this.settings.colorPointFunction, ['data', 'dsData', 'dsIndex']);
|
||||
this.normalizationStep = this.settings.normalizationStep;
|
||||
const subscription = this.ctx.defaultSubscription;
|
||||
subscription.callbacks.onDataUpdated = () => {
|
||||
this.historicalData = formattedDataArrayFromDatasourceData(this.ctx.data).map(
|
||||
item => this.clearIncorrectFirsLastDatapoint(item)).filter(arr => arr.length);
|
||||
this.interpolatedTimeData.length = 0;
|
||||
this.formattedInterpolatedTimeData.length = 0;
|
||||
const prevMinTime = this.minTime;
|
||||
const prevMaxTime = this.maxTime;
|
||||
this.calculateIntervals();
|
||||
const currentTime = this.calculateCurrentTime(prevMinTime, prevMaxTime);
|
||||
if (currentTime !== this.currentTime) {
|
||||
this.timeUpdated(currentTime);
|
||||
}
|
||||
this.mapWidget.map.map?.invalidateSize();
|
||||
this.mapWidget.map.setLoading(false);
|
||||
this.cd.detectChanges();
|
||||
this.update();
|
||||
};
|
||||
subscription.callbacks.onLatestDataUpdated = () => {
|
||||
this.formattedLatestData = formattedDataFormDatasourceData(this.ctx.latestData);
|
||||
this.updateCurrentData();
|
||||
this.latestDataUpdate();
|
||||
};
|
||||
from(this.initializeFunctions()).subscribe(() => {
|
||||
this.initialized = true;
|
||||
if (this.updatePending) {
|
||||
this.updateCurrentData();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
import('@home/components/widget/lib/maps/map-widget2').then(
|
||||
(mod) => {
|
||||
this.mapWidget = new mod.MapWidgetController(MapProviders.openstreet, false, this.ctx, this.mapContainer.nativeElement);
|
||||
this.mapWidget = new mod.MapWidgetController(MapProviders.openstreet, false, this.ctx, this.mapContainer.nativeElement, false,
|
||||
() => {
|
||||
if (this.mapWidgetUpdatePending) {
|
||||
this.updateMapWidget();
|
||||
}
|
||||
}
|
||||
);
|
||||
this.mapResize$ = new ResizeObserver(() => {
|
||||
this.mapWidget.resize();
|
||||
});
|
||||
@ -177,22 +177,65 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
this.updateCurrentData();
|
||||
}
|
||||
|
||||
private updateCurrentData() {
|
||||
let currentPosition = this.formattedCurrentPosition;
|
||||
if (this.formattedLatestData.length) {
|
||||
currentPosition = mergeFormattedData(this.formattedCurrentPosition, this.formattedLatestData);
|
||||
private async initializeFunctions(): Promise<void> {
|
||||
this.settings.parsedPointAsAnchorFunction = await firstValueFrom(parseTbFunction(this.ctx.http, this.settings.pointAsAnchorFunction, ['data', 'dsData', 'dsIndex']));
|
||||
this.settings.parsedTooltipFunction = await firstValueFrom(parseTbFunction(this.ctx.http, this.settings.tooltipFunction, ['data', 'dsData', 'dsIndex']));
|
||||
this.settings.parsedLabelFunction = await firstValueFrom(parseTbFunction(this.ctx.http, this.settings.labelFunction, ['data', 'dsData', 'dsIndex']));
|
||||
this.settings.parsedColorPointFunction = await firstValueFrom(parseTbFunction(this.ctx.http, this.settings.colorPointFunction, ['data', 'dsData', 'dsIndex']));
|
||||
}
|
||||
|
||||
private update() {
|
||||
this.historicalData = formattedDataArrayFromDatasourceData(this.ctx.data).map(
|
||||
item => this.clearIncorrectFirsLastDatapoint(item)).filter(arr => arr.length);
|
||||
this.interpolatedTimeData.length = 0;
|
||||
this.formattedInterpolatedTimeData.length = 0;
|
||||
const prevMinTime = this.minTime;
|
||||
const prevMaxTime = this.maxTime;
|
||||
this.calculateIntervals();
|
||||
const currentTime = this.calculateCurrentTime(prevMinTime, prevMaxTime);
|
||||
if (currentTime !== this.currentTime) {
|
||||
this.timeUpdated(currentTime);
|
||||
}
|
||||
this.calcLabel(currentPosition);
|
||||
this.calcMainTooltip(currentPosition);
|
||||
if (this.mapWidget && this.mapWidget.map && this.mapWidget.map.map) {
|
||||
this.mapWidget.map.updateFromData(true, currentPosition, this.formattedInterpolatedTimeData, (trip) => {
|
||||
this.activeTrip = trip;
|
||||
this.timeUpdated(this.currentTime);
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
if (this.settings.showPoints) {
|
||||
this.mapWidget.map.updatePoints(this.formattedInterpolatedTimeData, this.calcTooltip);
|
||||
this.updateMapWidget();
|
||||
}
|
||||
|
||||
private latestDataUpdate() {
|
||||
this.formattedLatestData = formattedDataFormDatasourceData(this.ctx.latestData);
|
||||
this.updateCurrentData();
|
||||
}
|
||||
|
||||
private updateMapWidget() {
|
||||
if (this.mapWidget?.map) {
|
||||
this.mapWidgetUpdatePending = false;
|
||||
this.mapWidget.map.map?.invalidateSize();
|
||||
this.mapWidget.map.setLoading(false);
|
||||
this.cd.detectChanges();
|
||||
} else {
|
||||
this.mapWidgetUpdatePending = true;
|
||||
}
|
||||
}
|
||||
|
||||
private updateCurrentData() {
|
||||
if (this.initialized) {
|
||||
this.updatePending = false;
|
||||
let currentPosition = this.formattedCurrentPosition;
|
||||
if (this.formattedLatestData.length) {
|
||||
currentPosition = mergeFormattedData(this.formattedCurrentPosition, this.formattedLatestData);
|
||||
}
|
||||
this.calcLabel(currentPosition);
|
||||
this.calcMainTooltip(currentPosition);
|
||||
if (this.mapWidget?.map?.map) {
|
||||
this.mapWidget.map.updateFromData(true, currentPosition, this.formattedInterpolatedTimeData, (trip) => {
|
||||
this.activeTrip = trip;
|
||||
this.timeUpdated(this.currentTime);
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
if (this.settings.showPoints) {
|
||||
this.mapWidget.map.updatePoints(this.formattedInterpolatedTimeData, this.calcTooltip);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.updatePending = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +278,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
if (this.useAnchors) {
|
||||
const anchorDate = Object.entries(_.union(this.interpolatedTimeData)[0]);
|
||||
this.anchors = anchorDate
|
||||
.filter((data: [string, FormattedData], tsIndex) => safeExecute(this.settings.parsedPointAsAnchorFunction, [data[1],
|
||||
.filter((data: [string, FormattedData], tsIndex) => safeExecuteTbFunction(this.settings.parsedPointAsAnchorFunction, [data[1],
|
||||
this.formattedInterpolatedTimeData.map(ds => ds[tsIndex]), data[1].dsIndex]))
|
||||
.map(data => parseInt(data[0], 10));
|
||||
}
|
||||
@ -244,7 +287,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
calcTooltip = (point: FormattedData, points: FormattedData[]): string => {
|
||||
const data = point ? point : this.activeTrip;
|
||||
const tooltipPattern: string = this.settings.useTooltipFunction ?
|
||||
safeExecute(this.settings.parsedTooltipFunction,
|
||||
safeExecuteTbFunction(this.settings.parsedTooltipFunction,
|
||||
[data, points, point.dsIndex]) : this.settings.tooltipPattern;
|
||||
return parseWithTranslation.parseTemplate(tooltipPattern, data, true);
|
||||
}
|
||||
@ -261,7 +304,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
if (this.activeTrip) {
|
||||
const data = points[this.activeTrip.dsIndex];
|
||||
const labelText: string = this.settings.useLabelFunction ?
|
||||
safeExecute(this.settings.parsedLabelFunction, [data, points, data.dsIndex]) : this.settings.label;
|
||||
safeExecuteTbFunction(this.settings.parsedLabelFunction, [data, points, data.dsIndex]) : this.settings.label;
|
||||
this.label = this.sanitizer.bypassSecurityTrustHtml(parseWithTranslation.parseTemplate(labelText, data, true));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user