Browse Source

Added logic to create and edit polylines

pull/14155/head
LeoMorgan113 11 months ago
parent
commit
e8b2066fb6
  1. 22
      ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/map-data-layer.ts
  2. 19
      ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polygons-data-layer.ts
  3. 97
      ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polylines-data-layer.ts
  4. 27
      ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/shapes-data-layer.ts
  5. 31
      ui-ngx/src/app/modules/home/components/widget/lib/maps/geo-map.ts
  6. 3
      ui-ngx/src/app/modules/home/components/widget/lib/maps/image-map.ts
  7. 322
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts
  8. 6
      ui-ngx/src/app/shared/models/widget.models.ts
  9. 61
      ui-ngx/src/app/shared/models/widget/maps/map.models.ts
  10. 5
      ui-ngx/src/assets/locale/locale.constant-en_US.json

22
ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/map-data-layer.ts

@ -28,7 +28,6 @@ import {
} from '@shared/models/widget/maps/map.models';
import {
createLabelFromPattern,
guid,
isDefined,
isDefinedAndNotNull,
isNumber,
@ -53,7 +52,8 @@ export class DataLayerPatternProcessor {
private pattern: string;
constructor(private dataLayer: TbMapDataLayer,
private settings: DataLayerPatternSettings) {}
private settings: DataLayerPatternSettings) {
}
public setup(): Observable<void> {
if (this.settings.type === DataLayerPatternType.function) {
@ -91,7 +91,8 @@ export class DataLayerColorProcessor {
private range: ColorRange[];
constructor(private dataLayer: TbMapDataLayer,
private settings: DataLayerColorSettings) {}
private settings: DataLayerColorSettings) {
}
public setup(): Observable<void> {
this.color = this.settings.color;
@ -150,7 +151,8 @@ export abstract class TbDataLayerItem<S extends MapDataLayerSettings = MapDataLa
protected layer: L;
protected constructor(protected settings: S,
protected dataLayer: D) {}
protected dataLayer: D) {
}
public getLayer(): L {
return this.layer;
@ -178,7 +180,7 @@ export abstract class TbMapDataLayer<S extends MapDataLayerSettings = MapDataLay
protected layerItems = new Map<string, I>();
protected groupsState: {[group: string]: boolean} = {};
protected groupsState: { [group: string]: boolean } = {};
protected enabled = true;
@ -197,7 +199,7 @@ export abstract class TbMapDataLayer<S extends MapDataLayerSettings = MapDataLay
}
this.dataLayerContainer = this.createDataLayerContainer();
this.dataLayerLabelProcessor = this.settings.label.show ? new DataLayerPatternProcessor(this, this.settings.label) : null;
this.dataLayerTooltipProcessor = this.settings.tooltip.show ? new DataLayerPatternProcessor(this, this.settings.tooltip): null;
this.dataLayerTooltipProcessor = this.settings.tooltip.show ? new DataLayerPatternProcessor(this, this.settings.tooltip) : null;
this.map.getMap().addLayer(this.dataLayerContainer);
}
@ -298,7 +300,7 @@ export abstract class TbMapDataLayer<S extends MapDataLayerSettings = MapDataLay
protected calculateDataKeys(): DataKey[] {
const dataKeys = this.settings.additionalDataKeys ? [...this.settings.additionalDataKeys] : [];
const colorRangeKeys = this.allColorSettings().filter(settings => settings.type === DataLayerColorType.range && settings.rangeKey)
.map(settings => settings.rangeKey);
.map(settings => settings.rangeKey);
dataKeys.push(...colorRangeKeys);
dataKeys.push(...this.getDataKeys());
return dataKeys;
@ -316,9 +318,11 @@ export abstract class TbMapDataLayer<S extends MapDataLayerSettings = MapDataLay
return [];
}
protected onDataLayerEnabled(): void {}
protected onDataLayerEnabled(): void {
}
protected onDataLayerDisabled(): void {}
protected onDataLayerDisabled(): void {
}
public abstract dataLayerType(): MapDataLayerType;

19
ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polygons-data-layer.ts

@ -91,7 +91,7 @@ class TbPolygonDataLayerItem extends TbLatestDataLayerItem<PolygonsDataLayerSett
protected bindLabel(content: L.Content): void {
this.polygonContainer.bindTooltip(content, {className: 'tb-polygon-label', permanent: true, direction: 'center'})
.openTooltip(this.polygonContainer.getBounds().getCenter());
.openTooltip(this.polygonContainer.getBounds().getCenter());
}
protected doUpdate(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): void {
@ -148,7 +148,7 @@ class TbPolygonDataLayerItem extends TbLatestDataLayerItem<PolygonsDataLayerSett
}
protected onSelected(): L.TB.ToolbarButtonOptions[] {
const buttons: L.TB.ToolbarButtonOptions[] = [];
const buttons: L.TB.ToolbarButtonOptions[] = [];
if (this.dataLayer.isEditEnabled()) {
this.enablePolygonEditMode();
buttons.push(
@ -190,9 +190,9 @@ class TbPolygonDataLayerItem extends TbLatestDataLayerItem<PolygonsDataLayerSett
protected onDeselected(): void {
if (this.dataLayer.isEditEnabled()) {
this.disablePolygonEditMode();
this.disablePolygonCutMode();
this.disablePolygonRotateMode();
this.disablePolygonEditMode();
this.disablePolygonCutMode();
this.disablePolygonRotateMode();
}
}
@ -226,7 +226,7 @@ class TbPolygonDataLayerItem extends TbLatestDataLayerItem<PolygonsDataLayerSett
this.polygon.on('pm:markerdragstart', () => this.editing = true);
this.polygon.on('pm:markerdragend', () => setTimeout(() => {
this.editing = false;
}) );
}));
this.polygon.on('pm:edit', () => this.savePolygonCoordinates());
this.polygon.pm.enable();
const map = this.dataLayer.getMap();
@ -246,8 +246,10 @@ class TbPolygonDataLayerItem extends TbLatestDataLayerItem<PolygonsDataLayerSett
this.polygonContainer.closePopup();
this.editing = true;
this.polygon.options.bubblingMouseEvents = true;
this.polygon.setStyle({...this.polygonStyleInfo.style, dashArray: '5 5', weight: 3,
color: '#3388ff', opacity: 1, fillColor: '#3388ff', fillOpacity: 0.2});
this.polygon.setStyle({
...this.polygonStyleInfo.style, dashArray: '5 5', weight: 3,
color: '#3388ff', opacity: 1, fillColor: '#3388ff', fillOpacity: 0.2
});
this.addItemClass('tb-cut-mode');
this.polygon.once('pm:cut', (e) => {
if (e.layer instanceof L.Polygon) {
@ -365,6 +367,7 @@ class TbPolygonDataLayerItem extends TbLatestDataLayerItem<PolygonsDataLayerSett
this.polygon.setLatLngs(polyData);
}
} else if (polyData.length === 2) {
const bounds = new L.LatLngBounds(polyData as L.LatLngTuple[]);
(this.polygon as L.Rectangle).setBounds(bounds);
}

97
ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polylines-data-layer.ts

@ -15,17 +15,14 @@
///
import {
defaultBasePolygonsDataLayerSettings,
defaultBasePolylinesDataLayerSettings,
isCutPolygon,
isJSON,
MapDataLayerType,
PolygonsDataLayerSettings,
PolylinesDataLayerSettings,
TbMapDatasource,
TbPolyData,
TbPolygonCoordinates,
TbPolygonRawCoordinates,
TbPolylineCoordinates, TbPolylineData,
TbPolylineCoordinates,
TbPolylineData,
TbPolylineRawCoordinates
} from '@shared/models/widget/maps/map.models';
import L from 'leaflet';
@ -98,7 +95,7 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
protected bindLabel(content: L.Content): void {
this.polylineContainer.bindTooltip(content, {className: 'tb-polyline-label', permanent: true, direction: 'center'})
.openTooltip(this.polylineContainer.getBounds().getCenter());
.openTooltip(this.polylineContainer.getBounds().getCenter());
}
protected doUpdate(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): void {
@ -156,27 +153,13 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
}
protected onSelected(): L.TB.ToolbarButtonOptions[] {
const buttons: L.TB.ToolbarButtonOptions[] = [];
const buttons: L.TB.ToolbarButtonOptions[] = [];
if (this.dataLayer.isEditEnabled()) {
this.enablePolylineEditMode();
buttons.push(
// {
// id: 'cut',
// title: this.getDataLayer().getCtx().translate.instant('widgets.maps.data-layer.polygon.cut'),
// iconClass: 'tb-cut',
// click: (e, button) => {
// const map = this.dataLayer.getMap().getMap();
// if (!map.pm.globalCutModeEnabled()) {
// this.disablePolylineRotateMode();
// this.disablePolylineEditMode();
// } else {
// this.enablePolylineEditMode();
// }
// }
// },
{
id: 'rotate',
title: this.getDataLayer().getCtx().translate.instant('widgets.maps.data-layer.polygon.rotate'),
title: this.getDataLayer().getCtx().translate.instant('widgets.maps.data-layer.polyline.rotate'),
iconClass: 'tb-rotate',
click: (e, button) => {
if (!this.polyline.pm.rotateEnabled()) {
@ -195,8 +178,8 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
protected onDeselected(): void {
if (this.dataLayer.isEditEnabled()) {
this.disablePolylineEditMode();
this.disablePolylineRotateMode();
this.disablePolylineEditMode();
this.disablePolylineRotateMode();
}
}
@ -213,7 +196,7 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
}
protected removeDataItemTitle(): string {
return this.dataLayer.getCtx().translate.instant('widgets.maps.data-layer.polygon.remove-polygon-for', {entityName: this.data.entityName});
return this.dataLayer.getCtx().translate.instant('widgets.maps.data-layer.polyline.remove-polyline-for', {entityName: this.data.entityName});
}
protected removeDataItem(): Observable<any> {
@ -224,7 +207,7 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
this.polyline.on('pm:markerdragstart', () => this.editing = true);
this.polyline.on('pm:markerdragend', () => setTimeout(() => {
this.editing = false;
}) );
}));
this.polyline.on('pm:edit', () => this.savePolylineCoordinates());
this.polyline.pm.enable();
const map = this.dataLayer.getMap();
@ -267,13 +250,6 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
if (coordinates.length === 1) {
coordinates = coordinates[0] as TbPolylineCoordinates;
}
if (this.polyline instanceof L.Rectangle && !isCutPolygon(coordinates)) {
const bounds = this.polyline.getBounds();
const boundsArray = [bounds.getNorthWest(), bounds.getNorthEast(), bounds.getSouthWest(), bounds.getSouthEast()];
if (coordinates.every(point => boundsArray.find(boundPoint => boundPoint.equals(point as L.LatLng)) !== undefined)) {
coordinates = [bounds.getNorthWest(), bounds.getSouthEast()];
}
}
this.dataLayer.savePolylineCoordinates(this.data, coordinates).subscribe();
}
@ -283,24 +259,24 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
}
const polyData = this.dataLayer.extractPolylineCoordinates(data) as TbPolylineData;
if (isCutPolygon(polyData) || polyData.length !== 2) {
// if (this.polyline instanceof L.Rectangle) {
//
// this.polylineContainer.removeLayer(this.polyline);
// this.polyline = L.polyline(polyData, {
// ...this.polylineStyleInfo.style,
// snapIgnore: !this.dataLayer.isSnappable(),
// bubblingMouseEvents: !this.dataLayer.isEditMode(),
// noClip: true
// });
// this.polyline.addTo(this.polylineContainer);
// this.editModeUpdated();
// } else {
this.polyline.setLatLngs(polyData);
// }
} else if (polyData.length === 2) {
if (this.polyline instanceof L.Polyline && !(this.polyline instanceof L.Rectangle)) {
this.polyline.setLatLngs(polyData as L.LatLngExpression[] | L.LatLngExpression[][]);
} else if (this.polyline instanceof L.Rectangle && polyData.length === 2) {
const bounds = new L.LatLngBounds(polyData as L.LatLngTuple[]);
// (this.polyline as L.Rectangle).setBounds(bounds);
this.polyline.setBounds(bounds);
} else {
this.polylineContainer.removeLayer(this.polyline);
if (polyData.length === 2 && isCutPolygon(polyData)) {
this.polyline = L.polyline(polyData as L.LatLngExpression[] | L.LatLngExpression[][], {
...this.polylineStyleInfo.style,
snapIgnore: !this.dataLayer.isSnappable(),
bubblingMouseEvents: !this.dataLayer.isEditMode(),
noClip: true
});
}
this.polyline.addTo(this.polylineContainer);
this.editModeUpdated();
}
}
@ -318,16 +294,11 @@ export class TbPolylineDataLayer extends TbShapesDataLayer<PolylinesDataLayerSet
}
public placeItem(item: UnplacedMapDataItem, layer: L.Layer): void {
if (layer instanceof L.Polygon) {
if (layer instanceof L.Polyline) {
let coordinates: TbPolylineCoordinates;
if (layer instanceof L.Rectangle) {
const bounds = layer.getBounds();
coordinates = [bounds.getNorthWest(), bounds.getSouthEast()];
} else {
coordinates = layer.getLatLngs();
if (coordinates.length === 1) {
coordinates = coordinates[0] as TbPolygonCoordinates;
}
coordinates = layer.getLatLngs();
if (coordinates.length === 1) {
coordinates = coordinates[0] as TbPolylineCoordinates;
}
this.savePolylineCoordinates(item.entity, coordinates).subscribe(
(converted) => {
@ -340,7 +311,7 @@ export class TbPolylineDataLayer extends TbShapesDataLayer<PolylinesDataLayerSet
}
}
public extractPolylineCoordinates(data: FormattedData<TbMapDatasource>): TbPolygonRawCoordinates {
public extractPolylineCoordinates(data: FormattedData<TbMapDatasource>): TbPolylineRawCoordinates {
let rawPolyData = data[this.settings.polylineKey.label];
if (isString(rawPolyData)) {
rawPolyData = JSON.parse(rawPolyData);
@ -349,7 +320,7 @@ export class TbPolylineDataLayer extends TbShapesDataLayer<PolylinesDataLayerSet
}
public savePolylineCoordinates(data: FormattedData<TbMapDatasource>, coordinates: TbPolylineCoordinates): Observable<TbPolylineRawCoordinates> {
const converted = coordinates ? this.map.coordinatesToPolygonData(coordinates) : null;
const converted = coordinates ? this.map.coordinatesToPolylineData(coordinates) : null;
const polylineData = [
{
dataKey: this.settings.polylineKey,
@ -366,7 +337,7 @@ export class TbPolylineDataLayer extends TbShapesDataLayer<PolylinesDataLayerSet
}
protected defaultBaseSettings(map: TbMap<any>): Partial<PolylinesDataLayerSettings> {
return defaultBasePolygonsDataLayerSettings(map.type());
return defaultBasePolylinesDataLayerSettings(map.type());
}
protected doSetup(): Observable<any> {

27
ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/shapes-data-layer.ts

@ -37,10 +37,12 @@ import { isDefinedAndNotNull, objectHashCode, parseTbFunction, safeExecuteTbFunc
import { CompiledTbFunction } from '@shared/models/js-function.models';
import { ImagePipe } from '@shared/pipe/image.pipe';
export type ShapePatternStorage = {[id: string]: {
pattern: L.TB.Pattern;
refCount: number;
}};
export type ShapePatternStorage = {
[id: string]: {
pattern: L.TB.Pattern;
refCount: number;
}
};
interface ShapePatternInfo {
type: ShapeFillType;
@ -88,7 +90,8 @@ abstract class ShapePatternProcessor<S = any> {
}
protected constructor(protected dataLayer: TbMapDataLayer,
protected settings: S) {}
protected settings: S) {
}
public abstract setup(): Observable<any>;
@ -119,8 +122,10 @@ abstract class ShapePatternProcessor<S = any> {
let pattern: L.TB.Pattern;
if (patternInfo.type === ShapeFillType.color) {
pattern = new L.TB.Pattern({width: 1, height: 1});
const fillRect = new L.TB.PatternRect({x: 0, y: 0, width: 1, height: 1,
fillOpacity: 1, stroke: false, fill: true, fillColor: patternInfo.fillColor});
const fillRect = new L.TB.PatternRect({
x: 0, y: 0, width: 1, height: 1,
fillOpacity: 1, stroke: false, fill: true, fillColor: patternInfo.fillColor
});
pattern.addElement(fillRect);
} else if (patternInfo.type === ShapeFillType.image) {
const patternOptions: L.TB.PatternOptions = {
@ -128,7 +133,7 @@ abstract class ShapePatternProcessor<S = any> {
height: 1,
patternUnits: 'objectBoundingBox',
patternContentUnits: 'objectBoundingBox',
viewBox: [0,0,patternInfo.fillImage.width,patternInfo.fillImage.height]
viewBox: [0, 0, patternInfo.fillImage.width, patternInfo.fillImage.height]
};
if (patternInfo.fillImage.preserveAspectRatio) {
patternOptions.preserveAspectRatioAlign = 'xMidYMid';
@ -301,7 +306,7 @@ class ShapeStripePatternProcessor extends ShapePatternProcessor<ShapeFillStripeS
}
export abstract class TbShapesDataLayer<S extends ShapeDataLayerSettings, L extends TbLatestMapDataLayer<S,L>> extends TbLatestMapDataLayer<S, L> {
export abstract class TbShapesDataLayer<S extends ShapeDataLayerSettings, L extends TbLatestMapDataLayer<S, L>> extends TbLatestMapDataLayer<S, L> {
private shapePatternProcessor: ShapePatternProcessor;
private strokeColorProcessor: DataLayerColorProcessor;
@ -349,7 +354,7 @@ export abstract class TbShapesDataLayer<S extends ShapeDataLayerSettings, L exte
}
protected allColorSettings(): DataLayerColorSettings[] {
const colorSettings: DataLayerColorSettings[] = [this.settings.strokeColor];
const colorSettings: DataLayerColorSettings[] = [this.settings.strokeColor];
if (this.settings.fillType === ShapeFillType.color) {
colorSettings.push(this.settings.fillColor)
} else if (this.settings.fillType === ShapeFillType.stripe) {
@ -366,7 +371,7 @@ export abstract class TbShapesDataLayer<S extends ShapeDataLayerSettings, L exte
protected doSetup(): Observable<any> {
this.shapePatternProcessor = ShapePatternProcessor.fromSettings(this, this.settings);
this.strokeColorProcessor = new DataLayerColorProcessor(this, this.settings.strokeColor);
return forkJoin([this.shapePatternProcessor.setup(), this.strokeColorProcessor.setup()]);
return forkJoin([this.shapePatternProcessor ? this.shapePatternProcessor.setup() : of([]), this.strokeColorProcessor.setup()]);
}
}

31
ui-ngx/src/app/modules/home/components/widget/lib/maps/geo-map.ts

@ -61,16 +61,16 @@ export class TbGeoMap extends TbMap<GeoMapSettings> {
return of(map);
}
protected onResize(): void {}
protected onResize(): void {
}
protected fitBounds(bounds: L.LatLngBounds) {
if (bounds.isValid()) {
if (!this.settings.fitMapBounds && this.settings.defaultZoomLevel) {
this.map.setZoom(this.settings.defaultZoomLevel, { animate: false });
this.map.setZoom(this.settings.defaultZoomLevel, {animate: false});
if (this.settings.useDefaultCenterPosition) {
this.map.panTo(this.defaultCenterPosition, { animate: false });
}
else {
this.map.panTo(this.defaultCenterPosition, {animate: false});
} else {
this.map.panTo(bounds.getCenter());
}
} else {
@ -80,13 +80,13 @@ export class TbGeoMap extends TbMap<GeoMapSettings> {
minZoom = Math.max(minZoom, this.settings.defaultZoomLevel);
}
if (this.map.getZoom() > minZoom) {
this.map.setZoom(minZoom, { animate: false });
this.map.setZoom(minZoom, {animate: false});
}
});
if (this.settings.useDefaultCenterPosition) {
bounds = bounds.extend(this.defaultCenterPosition);
}
this.map.fitBounds(bounds, { padding: [50, 50], animate: false });
this.map.fitBounds(bounds, {padding: [50, 50], animate: false});
this.map.invalidateSize();
}
}
@ -125,12 +125,15 @@ export class TbGeoMap extends TbMap<GeoMapSettings> {
);
}
public locationDataToLatLng(position: {x: number; y: number}): L.LatLng {
public locationDataToLatLng(position: { x: number; y: number }): L.LatLng {
return L.latLng(position.x, position.y) as L.LatLng;
}
public latLngToLocationData(position: L.LatLng): {x: number; y: number} {
position = position ? latLngPointToBounds(position, this.southWest, this.northEast, 0) : {lat: null, lng: null} as L.LatLng;
public latLngToLocationData(position: L.LatLng): { x: number; y: number } {
position = position ? latLngPointToBounds(position, this.southWest, this.northEast, 0) : {
lat: null,
lng: null
} as L.LatLng;
return {
x: position.lat,
y: position.lng
@ -187,11 +190,9 @@ export class TbGeoMap extends TbMap<GeoMapSettings> {
return (expression).map((el: TbPolylineRawCoordinate) => {
if (!Array.isArray(el[0]) && !Array.isArray(el[1]) && el.length === 2) {
return el;
}
// else if (Array.isArray(el) && el.length) {
// return this.polylineDataToCoordinates(el as TbPolylineRawCoordinates) as TbPolylineRawCoordinates;
// }
else {
} else if (Array.isArray(el) && el.length) {
return this.polylineDataToCoordinates(el as TbPolylineRawCoordinates) as TbPolylineRawCoordinate;
} else {
return null;
}
}).filter(el => !!el);

3
ui-ngx/src/app/modules/home/components/widget/lib/maps/image-map.ts

@ -352,8 +352,7 @@ export class TbImageMap extends TbMap<ImageMapSettings> {
el[1] * this.height
);
return [latLng.lat, latLng.lng] as TbPolylineRawCoordinate;
}
else if (Array.isArray(el) && el.length) {
} else if (Array.isArray(el) && el.length) {
return this.polylineDataToCoordinates(el as TbPolylineRawCoordinates) as TbPolylineRawCoordinate;
}
else {

322
ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts

@ -27,7 +27,9 @@ import {
TbCircleData,
TbMapDatasource,
TbPolygonCoordinates,
TbPolygonRawCoordinates, TbPolylineCoordinates, TbPolylineRawCoordinates
TbPolygonRawCoordinates,
TbPolylineCoordinates,
TbPolylineRawCoordinates
} from '@shared/models/widget/maps/map.models';
import { WidgetContext } from '@home/models/widget-component.models';
import {
@ -80,12 +82,12 @@ import { TbTripsDataLayer } from '@home/components/widget/lib/maps/data-layer/tr
import { CompiledTbFunction } from '@shared/models/js-function.models';
import { TbMapDataLayer } from '@home/components/widget/lib/maps/data-layer/map-data-layer';
import { EntityType } from '@shared/models/entity-type.models';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import TooltipPositioningSide = JQueryTooltipster.TooltipPositioningSide;
import { ShapePatternStorage } from '@home/components/widget/lib/maps/data-layer/shapes-data-layer';
import { TbPolylineDataLayer } from '@home/components/widget/lib/maps/data-layer/polylines-data-layer';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import TooltipPositioningSide = JQueryTooltipster.TooltipPositioningSide;
type TooltipInstancesData = {root: HTMLElement, instances: ITooltipsterInstance[]};
type TooltipInstancesData = { root: HTMLElement, instances: ITooltipsterInstance[] };
export abstract class TbMap<S extends BaseMapSettings> {
@ -327,7 +329,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
let datasources: TbMapDatasource[];
for (const layerType of mapDataLayerTypes) {
const typeDatasources = this.latestDataLayers.filter(dl => dl.dataLayerType() === layerType)
.map(dl => dl.getDataSources()).flat();
.map(dl => dl.getDataSources()).flat();
if (!datasources) {
datasources = typeDatasources;
} else {
@ -427,100 +429,100 @@ export abstract class TbMap<S extends BaseMapSettings> {
private setupEditMode() {
this.editToolbar = L.TB.bottomToolbar({
mapElement: $(this.mapElement),
closeTitle: this.ctx.translate.instant('action.cancel'),
onClose: () => {
return this.deselectItem(true);
}
});
this.map.on('click', () => {
this.deselectItem();
});
if (this.latestDataLayers.some(dl => dl.isEditable())) {
this.map.pm.setGlobalOptions({ snappable: false });
this.map.pm.applyGlobalOptions();
}
const dragSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isDragEnabled());
const showDragModeButton = this.settings.dragModeButton && dragSupportedDataLayers.length;
const addSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isAddEnabled());
if (showDragModeButton || addSupportedDataLayers.length) {
const drawToolbar = L.TB.toolbar({
position: this.settings.controlsPosition
}).addTo(this.map);
if (showDragModeButton) {
this.dragModeButton = drawToolbar.toolbarButton({
id: 'dragMode',
title: this.ctx.translate.instant('widgets.maps.data-layer.drag-drop-mode'),
iconClass: 'tb-drag-mode',
click: (e, button) => {
this.toggleDragMode(e, button);
}
});
}
this.addMarkerDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'markers');
if (this.addMarkerDataLayers.length) {
this.addMarkerButton = drawToolbar.toolbarButton({
id: 'addMarker',
title: this.ctx.translate.instant('widgets.maps.data-layer.marker.place-marker'),
iconClass: 'tb-place-marker',
click: (e, button) => {
this.placeMarker(e, button);
}
});
this.addMarkerButton.setDisabled(true);
this.setPlaceMarkerStyle();
}
this.addPolygonDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'polygons');
if (this.addPolygonDataLayers.length) {
this.addRectangleButton = drawToolbar.toolbarButton({
id: 'addRectangle',
title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-rectangle'),
iconClass: 'tb-draw-rectangle',
click: (e, button) => {
this.drawRectangle(e, button);
}
});
this.addRectangleButton.setDisabled(true);
this.addPolygonButton = drawToolbar.toolbarButton({
id: 'addPolygon',
title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-polygon'),
iconClass: 'tb-draw-polygon',
click: (e, button) => {
this.drawPolygon(e, button);
}
});
this.addPolygonButton.setDisabled(true);
}
this.addCircleDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'circles');
if (this.addCircleDataLayers.length) {
this.addCircleButton = drawToolbar.toolbarButton({
id: 'addCircle',
title: this.ctx.translate.instant('widgets.maps.data-layer.circle.draw-circle'),
iconClass: 'tb-draw-circle',
click: (e, button) => {
this.drawCircle(e, button);
}
});
this.addCircleButton.setDisabled(true);
}
this.addPolylineDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'polylines');
if (this.addPolylineDataLayers.length) {
this.addPolylineButton = drawToolbar.toolbarButton({
id: 'addPolyline',
title: this.ctx.translate.instant('widgets.maps.data-layer.polyline.draw-polyline'),
iconClass: 'tb-draw-polyline',
click: (e, button) => {
this.drawPolyline(e, button);
}
});
this.addPolylineButton.setDisabled(true);
}
}
this.editToolbar = L.TB.bottomToolbar({
mapElement: $(this.mapElement),
closeTitle: this.ctx.translate.instant('action.cancel'),
onClose: () => {
return this.deselectItem(true);
}
});
this.map.on('click', () => {
this.deselectItem();
});
if (this.latestDataLayers.some(dl => dl.isEditable())) {
this.map.pm.setGlobalOptions({snappable: false});
this.map.pm.applyGlobalOptions();
}
const dragSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isDragEnabled());
const showDragModeButton = this.settings.dragModeButton && dragSupportedDataLayers.length;
const addSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isAddEnabled());
if (showDragModeButton || addSupportedDataLayers.length) {
const drawToolbar = L.TB.toolbar({
position: this.settings.controlsPosition
}).addTo(this.map);
if (showDragModeButton) {
this.dragModeButton = drawToolbar.toolbarButton({
id: 'dragMode',
title: this.ctx.translate.instant('widgets.maps.data-layer.drag-drop-mode'),
iconClass: 'tb-drag-mode',
click: (e, button) => {
this.toggleDragMode(e, button);
}
});
}
this.addMarkerDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'markers');
if (this.addMarkerDataLayers.length) {
this.addMarkerButton = drawToolbar.toolbarButton({
id: 'addMarker',
title: this.ctx.translate.instant('widgets.maps.data-layer.marker.place-marker'),
iconClass: 'tb-place-marker',
click: (e, button) => {
this.placeMarker(e, button);
}
});
this.addMarkerButton.setDisabled(true);
this.setPlaceMarkerStyle();
}
this.addPolygonDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'polygons');
if (this.addPolygonDataLayers.length) {
this.addRectangleButton = drawToolbar.toolbarButton({
id: 'addRectangle',
title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-rectangle'),
iconClass: 'tb-draw-rectangle',
click: (e, button) => {
this.drawRectangle(e, button);
}
});
this.addRectangleButton.setDisabled(true);
this.addPolygonButton = drawToolbar.toolbarButton({
id: 'addPolygon',
title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-polygon'),
iconClass: 'tb-draw-polygon',
click: (e, button) => {
this.drawPolygon(e, button);
}
});
this.addPolygonButton.setDisabled(true);
}
this.addCircleDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'circles');
if (this.addCircleDataLayers.length) {
this.addCircleButton = drawToolbar.toolbarButton({
id: 'addCircle',
title: this.ctx.translate.instant('widgets.maps.data-layer.circle.draw-circle'),
iconClass: 'tb-draw-circle',
click: (e, button) => {
this.drawCircle(e, button);
}
});
this.addCircleButton.setDisabled(true);
}
this.addPolylineDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'polylines');
if (this.addPolylineDataLayers.length) {
this.addPolylineButton = drawToolbar.toolbarButton({
id: 'addPolyline',
title: this.ctx.translate.instant('widgets.maps.data-layer.polyline.draw-polyline'),
iconClass: 'tb-draw-polyline',
click: (e, button) => {
this.drawPolyline(e, button);
}
});
this.addPolylineButton.setDisabled(true);
}
}
}
private toggleDragMode(_e: MouseEvent, button: L.TB.ToolbarButton): void {
@ -578,9 +580,9 @@ export abstract class TbMap<S extends BaseMapSettings> {
}
private drawPolyline(e: MouseEvent, button: L.TB.ToolbarButton): void {
this.placeItem(e, button, this.addCircleDataLayers, (entity) => this.prepareDrawMode('Polyline', {
firstVertex: this.ctx.translate.instant('widgets.maps.data-layer.polyline.polyline-place-first-point-hint-with-entity', {entityName: entity.entity.entityDisplayName}),
continueLine: this.ctx.translate.instant('widgets.maps.data-layer.polyline.continue-polyline-hint-with-entity', {entityName: entity.entity.entityDisplayName}),
this.placeItem(e, button, this.addPolylineDataLayers, (entity) => this.prepareDrawMode('Line', {
startPolyline: this.ctx.translate.instant('widgets.maps.data-layer.polyline.polyline-place-first-point-hint-with-entity', {entityName: entity.entity.entityDisplayName}),
finishPolyline: this.ctx.translate.instant('widgets.maps.data-layer.polyline.finish-polyline-hint', {entityName: entity.entity.entityDisplayName}),
}));
}
@ -706,7 +708,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
this.createCircle(actionData);
break;
case MapItemType.polyline:
// this.createPolyline(actionData); // TODO
this.createPolyline(actionData);
break;
}
}
@ -755,6 +757,17 @@ export abstract class TbMap<S extends BaseMapSettings> {
}));
}
private createPolyline(actionData: PlaceMapItemActionData): void {
this.createItem(actionData, () => this.prepareDrawMode('Line', {
startPolyline: actionData.action.mapItemTooltips.startPolyline
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.startPolyline)
: this.ctx.translate.instant(mapItemTooltipsTranslation.startPolyline),
finishPolyline: actionData.action.mapItemTooltips.finishPolyline
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.finishPolyline)
: this.ctx.translate.instant(mapItemTooltipsTranslation.finishPolyline),
}));
}
private createItem(actionData: PlaceMapItemActionData, prepareDrawMode: () => void) {
const actionId = 'id' in actionData.action ? actionData.action.id : 'map-button';
if (this.createMapItemActionId === actionId) {
@ -795,7 +808,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
this.createMapItemActionId = actionId;
const convertLayerToCoordinates = (type: MapItemType, layer: L.Layer): {x: number; y: number} | TbPolygonRawCoordinates | TbCircleData => {
const convertLayerToCoordinates = (type: MapItemType, layer: L.Layer): { x: number; y: number } | TbPolygonRawCoordinates | TbCircleData => {
switch (type) {
case MapItemType.marker:
if (layer instanceof L.Marker) {
@ -852,8 +865,8 @@ export abstract class TbMap<S extends BaseMapSettings> {
this.editToolbar.close();
}
private prepareDrawMode(shape: 'Marker' | 'Rectangle' | 'Polygon' | 'Circle' | 'Polyline', tooltipsTranslation: Record<string, string>) {
this.map.pm.setLang('en', { tooltips: tooltipsTranslation }, 'en');
private prepareDrawMode(shape: 'Marker' | 'Rectangle' | 'Polygon' | 'Circle' | 'Line', tooltipsTranslation: Record<string, string>) {
this.map.pm.setLang('en', {tooltips: tooltipsTranslation}, 'en');
this.map.pm.enableDraw(shape);
// @ts-ignore
L.DomUtil.addClass(this.map.pm.Draw[shape]._hintMarker.getTooltip()._container, 'tb-place-item-label');
@ -887,46 +900,46 @@ export abstract class TbMap<S extends BaseMapSettings> {
tooltipData.instances = [];
}
$(root)
.find('a[role="button"]:not(.leaflet-pm-action)')
.each((_index, element) => {
let title: string;
if (element.title) {
title = element.title;
$(element).removeAttr('title');
} else if (element.parentElement.title) {
title = element.parentElement.title;
$(element).parent().removeAttr('title');
}
const tooltip = $(element).tooltipster(
{
content: title,
theme: 'tooltipster-shadow',
delay: 10,
triggerClose: {
click: true,
tap: true,
scroll: true,
mouseleave: true
},
side,
distance: 2,
trackOrigin: true,
functionBefore: (_instance, helper) => {
if (helper.origin.ariaDisabled === 'true' || helper.origin.parentElement.classList.contains('active')) {
return false;
}
},
}
);
const instance = tooltip.tooltipster('instance');
tooltipData.instances.push(instance);
instance.on('destroyed', () => {
const index = tooltipData.instances.indexOf(instance);
if (index > -1) {
tooltipData.instances.splice(index, 1);
.find('a[role="button"]:not(.leaflet-pm-action)')
.each((_index, element) => {
let title: string;
if (element.title) {
title = element.title;
$(element).removeAttr('title');
} else if (element.parentElement.title) {
title = element.parentElement.title;
$(element).parent().removeAttr('title');
}
const tooltip = $(element).tooltipster(
{
content: title,
theme: 'tooltipster-shadow',
delay: 10,
triggerClose: {
click: true,
tap: true,
scroll: true,
mouseleave: true
},
side,
distance: 2,
trackOrigin: true,
functionBefore: (_instance, helper) => {
if (helper.origin.ariaDisabled === 'true' || helper.origin.parentElement.classList.contains('active')) {
return false;
}
},
}
);
const instance = tooltip.tooltipster('instance');
tooltipData.instances.push(instance);
instance.on('destroyed', () => {
const index = tooltipData.instances.indexOf(instance);
if (index > -1) {
tooltipData.instances.splice(index, 1);
}
});
});
});
});
}
@ -938,6 +951,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
this.updateTripsAnchors();
this.updateBounds();
this.updateEditButtonsStates();
}
private updateTrips(subscription: IWidgetSubscription) {
@ -982,6 +996,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
private updateTripsAppearance() {
this.tripDataLayers.forEach(dl => dl.updateAppearance());
}
private updateTripsTime() {
this.tripDataLayers.forEach(dl => dl.updateCurrentTime());
}
@ -1034,8 +1049,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
(!this.bounds || !this.bounds.isValid() || (!this.bounds.equals(bounds) || force) && this.settings.fitMapBounds)
&& !mapBounds.contains(bounds)
)
)
{
) {
this.bounds = bounds;
if (!this.ignoreUpdateBounds && !this.isPlacingItem) {
this.fitBounds(bounds);
@ -1062,6 +1076,9 @@ export abstract class TbMap<S extends BaseMapSettings> {
if (this.addCircleButton && this.addCircleButton !== this.currentEditButton) {
this.addCircleButton.setDisabled(true);
}
if (this.addPolylineButton && this.addPolylineButton !== this.currentEditButton) {
this.addPolylineButton.setDisabled(true);
}
this.customActionsToolbar?.setDisabled(true);
} else {
if (this.dragModeButton) {
@ -1079,7 +1096,9 @@ export abstract class TbMap<S extends BaseMapSettings> {
if (this.addCircleButton) {
this.addCircleButton.setDisabled(!this.addCircleDataLayers.some(dl => dl.isEnabled() && dl.hasUnplacedItems()));
}
// TODO
if (this.addPolylineButton) {
this.addPolylineButton.setDisabled(!this.addPolylineDataLayers.some(dl => dl.isEnabled() && dl.hasUnplacedItems()));
}
this.customActionsToolbar?.setDisabled(false);
}
}
@ -1190,7 +1209,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
$event.preventDefault();
$event.stopPropagation();
}
const { entityId, entityName, entityLabel, entityType } = data.$datasource;
const {entityId, entityName, entityLabel, entityType} = data.$datasource;
this.ctx.actionsApi.handleWidgetAction($event, action, {
entityType,
id: entityId
@ -1259,7 +1278,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
}
}
public saveLocation(data: FormattedData<TbMapDatasource>, values: {[key: string]: any}): Observable<any> {
public saveLocation(data: FormattedData<TbMapDatasource>, values: { [key: string]: any }): Observable<any> {
const datasource = data.$datasource;
let dataKeys = datasource.dataKeys;
if (datasource.latestDataKeys) {
@ -1369,9 +1388,9 @@ export abstract class TbMap<S extends BaseMapSettings> {
}
}
public abstract locationDataToLatLng(position: {x: number; y: number}): L.LatLng;
public abstract locationDataToLatLng(position: { x: number; y: number }): L.LatLng;
public abstract latLngToLocationData(position: L.LatLng): {x: number; y: number};
public abstract latLngToLocationData(position: L.LatLng): { x: number; y: number };
public abstract polygonDataToCoordinates(coordinates: TbPolygonRawCoordinates): TbPolygonRawCoordinates;
@ -1386,5 +1405,4 @@ export abstract class TbMap<S extends BaseMapSettings> {
public abstract coordinatesToCircleData(center: L.LatLng, radius: number): TbCircleData;
}

6
ui-ngx/src/app/shared/models/widget.models.ts

@ -827,6 +827,8 @@ export interface MapItemTooltips {
finishRect?: string;
startCircle?: string;
finishCircle?: string;
startPolyline?: string;
finishPolyline?: string;
}
export const mapItemTooltipsTranslation: Required<MapItemTooltips> = Object.freeze({
@ -837,7 +839,9 @@ export const mapItemTooltipsTranslation: Required<MapItemTooltips> = Object.free
startRect: 'widgets.maps.data-layer.polygon.rectangle-place-first-point-hint',
finishRect: 'widgets.maps.data-layer.polygon.finish-rectangle-hint',
startCircle: 'widgets.maps.data-layer.circle.place-circle-center-hint',
finishCircle: 'widgets.maps.data-layer.circle.finish-circle-hint'
finishCircle: 'widgets.maps.data-layer.circle.finish-circle-hint',
startPolyline: 'widgets.maps.data-layer.polyline.polyline-place-first-point-hint',
finishPolyline: 'widgets.maps.data-layer.polyline.finish-polyline-hint'
})
export interface WidgetActionDescriptor extends WidgetAction {

61
ui-ngx/src/app/shared/models/widget/maps/map.models.ts

@ -79,7 +79,7 @@ export const mapDataSourceSettingsToDatasource = (settings: MapDataSourceSetting
};
const mapDataLayerDatasourceDataKeys = (settings: MapDataLayerSettings,
dataLayerType: MapDataLayerType): DataKey[] => {
dataLayerType: MapDataLayerType): DataKey[] => {
const dataKeys = settings.additionalDataKeys?.length ? deepClone(settings.additionalDataKeys) : [];
switch (dataLayerType) {
case 'trips':
@ -169,7 +169,7 @@ export interface MapDataLayerSettings extends MapDataSourceSettings {
tooltip: DataLayerTooltipSettings;
click: WidgetAction;
groups?: string[];
edit: DataLayerEditSettings;
edit: DataLayerEditSettings;
}
export const defaultBaseDataLayerSettings = (mapType: MapType): Partial<MapDataLayerSettings> => ({
@ -185,7 +185,7 @@ export const defaultBaseDataLayerSettings = (mapType: MapType): Partial<MapDataL
type: DataLayerPatternType.pattern,
pattern: mapType === MapType.geoMap ?
'<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><b>Temperature:</b> ${temperature} °C<br/><small>See tooltip settings for details</small>'
: '<b>${entityName}</b><br/><br/><b>X Pos:</b> ${xPos:2}<br/><b>Y Pos:</b> ${yPos:2}<br/><b>Temperature:</b> ${temperature} °C<br/><small>See tooltip settings for details</small>',
: '<b>${entityName}</b><br/><br/><b>X Pos:</b> ${xPos:2}<br/><b>Y Pos:</b> ${yPos:2}<br/><b>Temperature:</b> ${temperature} °C<br/><small>See tooltip settings for details</small>',
offsetX: 0,
offsetY: -1
},
@ -225,7 +225,7 @@ export const mapDataLayerValid = (dataLayer: MapDataLayerSettings, type: MapData
case 'markers':
const markersDataLayer = dataLayer as MarkersDataLayerSettings;
if (!markersDataLayer.xKey?.type || !markersDataLayer.xKey?.name ||
!markersDataLayer.yKey?.type || !markersDataLayer.xKey?.name) {
!markersDataLayer.yKey?.type || !markersDataLayer.xKey?.name) {
return false;
}
break;
@ -309,6 +309,7 @@ export interface MarkerIconSettings extends BaseMarkerShapeSettings {
iconContainer?: MarkerIconContainer;
icon: string;
}
export interface MarkerClusteringSettings {
enable: boolean;
zoomOnClick: boolean;
@ -612,8 +613,11 @@ export const defaultBasePolygonsDataLayerSettings = (mapType: MapType): Partial<
color: '#3388ff',
},
strokeWeight: 3
} as Partial<PolygonsDataLayerSettings>, defaultBaseDataLayerSettings(mapType),
{label: {show: false}, tooltip: {show: false, pattern: '<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}'}} as Partial<PolygonsDataLayerSettings>)
} as Partial<PolygonsDataLayerSettings>, defaultBaseDataLayerSettings(mapType),
{
label: {show: false},
tooltip: {show: false, pattern: '<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}'}
} as Partial<PolygonsDataLayerSettings>)
export interface CirclesDataLayerSettings extends ShapeDataLayerSettings {
circleKey: DataKey;
@ -663,8 +667,11 @@ export const defaultBaseCirclesDataLayerSettings = (mapType: MapType): Partial<C
color: '#3388ff',
},
strokeWeight: 3
} as Partial<CirclesDataLayerSettings>, defaultBaseDataLayerSettings(mapType),
{label: {show: false}, tooltip: {show: false, pattern: '<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}'}} as Partial<CirclesDataLayerSettings>)
} as Partial<CirclesDataLayerSettings>, defaultBaseDataLayerSettings(mapType),
{
label: {show: false},
tooltip: {show: false, pattern: '<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}'}
} as Partial<CirclesDataLayerSettings>)
export interface PolylinesDataLayerSettings extends ShapeDataLayerSettings, PathDataLayerSettings {
polylineKey: DataKey;
@ -683,6 +690,11 @@ export const defaultPolylinesDataLayerSettings = (mapType: MapType, functionsOnl
} as PolylinesDataLayerSettings, defaultBasePolylinesDataLayerSettings(mapType) as PolylinesDataLayerSettings);
export const defaultBasePolylinesDataLayerSettings = (mapType: MapType): Partial<PolylinesDataLayerSettings> => mergeDeep({
fillType: ShapeFillType.color,
fillColor: {
type: DataLayerColorType.constant,
color: 'rgba(51,136,255,0.2)',
},
strokeColor: {
type: DataLayerColorType.constant,
color: '#3388ff',
@ -713,7 +725,10 @@ export const defaultBasePolylinesDataLayerSettings = (mapType: MapType): Partial
offsetY: -1
},
} as Partial<PolylinesDataLayerSettings>, defaultBaseDataLayerSettings(mapType),
{label: {show: false}, tooltip: {show: false, pattern: '<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}'}} as Partial<PolylinesDataLayerSettings>)
{
label: {show: false},
tooltip: {show: false, pattern: '<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}'}
} as Partial<PolylinesDataLayerSettings>)
export const defaultMapDataLayerSettings = (mapType: MapType, dataLayerType: MapDataLayerType, functionsOnly = false): MapDataLayerSettings => {
@ -793,13 +808,13 @@ export const additionalMapDataSourceValid = (dataSource: AdditionalMapDataSource
};
export const additionalMapDataSourceValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
const dataSource: AdditionalMapDataSourceSettings = control.value;
if (!additionalMapDataSourceValid(dataSource)) {
return {
dataSource: true
};
}
return null;
const dataSource: AdditionalMapDataSourceSettings = control.value;
if (!additionalMapDataSourceValid(dataSource)) {
return {
dataSource: true
};
}
return null;
};
export const defaultAdditionalMapDataSourceSettings = (functionsOnly = false): AdditionalMapDataSourceSettings => {
@ -922,7 +937,7 @@ export const defaultBaseMapSettings: BaseMapSettings = {
tripTimeline: {
showTimelineControl: false,
timeStep: 1000,
speedOptions: [1,5,10,15,25],
speedOptions: [1, 5, 10, 15, 25],
showTimestamp: true,
timestampFormat: simpleDateFormat('yyyy-MM-dd HH:mm:ss'),
snapToRealLocation: false,
@ -1294,7 +1309,7 @@ export type MapStringFunction = (data: FormattedData<TbMapDatasource>,
dsData: FormattedData<TbMapDatasource>[]) => string;
export type MapBooleanFunction = (data: FormattedData<TbMapDatasource>,
dsData: FormattedData<TbMapDatasource>[]) => boolean;
dsData: FormattedData<TbMapDatasource>[]) => boolean;
export type MarkerImageFunction = (data: FormattedData<TbMapDatasource>, markerImages: string[],
dsData: FormattedData<TbMapDatasource>[]) => MarkerImageInfo;
@ -1316,7 +1331,7 @@ export type TbPolygonCoordinates = TbPolygonCoordinate[];
export type TbPolylineRawCoordinate = L.LatLngTuple | L.LatLngTuple[] | L.LatLngTuple[][];
export type TbPolylineRawCoordinates = TbPolylineRawCoordinate[];
export type TbPolylineData = L.LatLngTuple[] | L.LatLngTuple[][];
export type TbPolylineData = L.LatLngTuple[] | L.LatLngTuple[][] | L.LatLngTuple[][][];
export type TbPolylineCoordinate = L.LatLng | L.LatLng[] | L.LatLng[][];
export type TbPolylineCoordinates = TbPolylineCoordinate[];
@ -1354,7 +1369,7 @@ export const isValidLatLng = (latitude: any, longitude: any): boolean =>
isValidLatitude(latitude) && isValidLongitude(longitude);
export const isCutPolygon = (data: TbPolygonCoordinates | TbPolygonRawCoordinates): boolean => {
return data.length > 1 && Array.isArray(data[0]) && (Array.isArray(data[0][0]) || (isNumber((data[0][0] as any).lat) && isNumber((data[0][0] as any).lng)) );
return data.length > 1 && Array.isArray(data[0]) && (Array.isArray(data[0][0]) || (isNumber((data[0][0] as any).lat) && isNumber((data[0][0] as any).lng)));
}
export const parseCenterPosition = (position: string | [number, number]): [number, number] => {
@ -1438,7 +1453,7 @@ const mergeMapDatasource = (target: TbMapDatasource, source: TbMapDatasource): T
return target;
}
const imageAspectMap: {[key: string]: ImageWithAspect} = {};
const imageAspectMap: { [key: string]: ImageWithAspect } = {};
const imageLoader = (imageUrl: string): Observable<HTMLImageElement> => new Observable((observer: Observer<HTMLImageElement>) => {
const image = document.createElement('img'); // support IE
@ -1485,7 +1500,7 @@ export const loadImageWithAspect = (imagePipe: ImagePipe, imageUrl: string): Obs
url,
width: size[0],
height: size[1],
aspect: size[0]/size[1]
aspect: size[0] / size[1]
};
imageAspectMap[hash] = imageWithAspect;
return imageWithAspect;
@ -1563,7 +1578,7 @@ export const latLngPointToBounds = (point: L.LatLng, southWest: L.LatLng, northE
return point;
}
export type TripRouteData = {[time: number]: FormattedData<TbMapDatasource>};
export type TripRouteData = { [time: number]: FormattedData<TbMapDatasource> };
export const calculateInterpolationRatio = (firsMoment: number, secondMoment: number, intermediateMoment: number): number => {
return (intermediateMoment - firsMoment) / (secondMoment - firsMoment);

5
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -8638,11 +8638,12 @@
"polyline-configuration": "Polyline configuration",
"remove-polyline": "Remove polyline",
"edit": "Edit polyline",
"rotate": "Rotate polyline",
"remove-polyline-for": "Remove polyline for '{{entityName}}'",
"draw-polyline": "Draw polyline",
"polyline-place-first-point-hint-with-entity": "Polyline for '{{entityName}}': click to place first point",
"polyline-place-first-point-hint": "Polyline: click to place first point",
"continue-polyline-hint-with-entity": "Polyline for '{{entityName}}': click to continue drawing",
"finish-polyline-hint": "Polyline: click to finish drawing"
"finish-polyline-hint": "Polyline for '{{entityName}}': click to finish drawing"
},
"select-entity": "Select entity",
"select-entity-hint": "Hint: after selection click at the map to set position"

Loading…
Cancel
Save