Browse Source

Updated translation, added helper functions, updated settings

pull/14155/head
LeoMorgan113 11 months ago
parent
commit
e7086616ec
  1. 36
      ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polylines-data-layer.ts
  2. 110
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts
  3. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-row.component.ts
  4. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts
  5. 70
      ui-ngx/src/app/shared/models/widget/maps/map.models.ts
  6. 22
      ui-ngx/src/assets/help/en_US/widget/lib/map/polyline_label_fn.md
  7. 22
      ui-ngx/src/assets/help/en_US/widget/lib/map/polyline_tooltip_fn.md
  8. 15
      ui-ngx/src/assets/locale/locale.constant-en_US.json

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

@ -72,7 +72,7 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
protected create(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): L.Layer {
const polyData = this.dataLayer.extractPolylineCoordinates(data);
const polyConstructor = L.polyline;
this.polyline = polyConstructor(polyData as (TbPolygonRawCoordinates & L.LatLngTuple[]), {
this.polyline = polyConstructor(polyData as (TbPolylineRawCoordinates & L.LatLngTuple[]), {
// noClip: true,
// snapIgnore: !this.dataLayer.isSnappable(),
bubblingMouseEvents: !this.dataLayer.isEditMode()
@ -80,6 +80,7 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
this.dataLayer.getShapeStyle(data, dsData, this.polylineStyleInfo?.patternId).subscribe((styleInfo) => {
this.polylineStyleInfo = styleInfo;
if (this.polyline) {
this.polyline.setStyle(this.polylineStyleInfo.style);
}
@ -107,6 +108,7 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
this.updatePolylineShape(data);
this.updateTooltip(data, dsData);
this.updateLabel(data, dsData);
if (!this.editing || !this.dataLayer.getMap().getMap().pm.globalCutModeEnabled()) {
this.polyline.setStyle(this.polylineStyleInfo.style);
}
@ -143,7 +145,7 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
}
});
this.polyline.on('pm:dragend', () => {
this.savePolygonCoordinates();
this.savePolylineCoordinates();
this.editing = false;
});
}
@ -229,16 +231,16 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
return this.dataLayer.savePolylineCoordinates(this.data, null);
}
// private enablePolygonEditMode() {
// this.polyline.on('pm:markerdragstart', () => this.editing = true);
// this.polyline.on('pm:markerdragend', () => setTimeout(() => {
// this.editing = false;
// }) );
// this.polyline.on('pm:edit', () => this.savePolygonCoordinates());
// this.polyline.pm.enable();
// const map = this.dataLayer.getMap();
// map.getEditToolbar().getButton('remove')?.setDisabled(false);
// }
private enablePolylineEditMode() {
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();
map.getEditToolbar().getButton('remove')?.setDisabled(false);
}
// private disablePolygonEditMode() {
// this.polyline.pm.disable();
@ -337,10 +339,10 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
// rotateButton?.setActive(false);
// }
private savePolygonCoordinates() {
let coordinates: TbPolygonCoordinates = this.polyline.getLatLngs();
private savePolylineCoordinates() {
let coordinates: TbPolylineCoordinates = this.polyline.getLatLngs();
if (coordinates.length === 1) {
coordinates = coordinates[0] as TbPolygonCoordinates;
coordinates = coordinates[0] as TbPolylineCoordinates;
}
if (this.polyline instanceof L.Rectangle && !isCutPolygon(coordinates)) {
const bounds = this.polyline.getBounds();
@ -356,9 +358,11 @@ class TbPolylineDataLayerItem extends TbLatestDataLayerItem<PolylinesDataLayerSe
if (this.editing) {
return;
}
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,
@ -409,7 +413,7 @@ export class TbPolylineDataLayer extends TbShapesDataLayer<PolylinesDataLayerSet
}
);
} else {
console.warn('Unable to place item, layer is not a polygon.');
console.warn('Unable to place item, layer is not a polyline.');
}
}

110
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts

@ -29,7 +29,7 @@ import {
MarkerType,
pathDecoratorSymbols,
pathDecoratorSymbolTranslationMap,
PolygonsDataLayerSettings,
PolygonsDataLayerSettings, PolylinesDataLayerSettings,
ShapeDataLayerSettings, ShapeFillType,
TripsDataLayerSettings,
updateDataKeyToNewDsType
@ -113,6 +113,8 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
return 'widget/lib/map/polygon_label_fn';
case 'circles':
return 'widget/lib/map/circle_label_fn';
case 'polylines':
return 'widget/lib/map/polyline_label_fn';
default:
return 'widget/lib/map/label_fn';
}
@ -128,6 +130,8 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
return 'widget/lib/map/polygon_tooltip_fn';
case 'circles':
return 'widget/lib/map/circle_tooltip_fn';
case 'polylines':
return 'widget/lib/map/polyline_tooltip_fn';
default:
return 'widget/lib/map/tooltip_fn';
}
@ -138,18 +142,21 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
const editEnabledActions: DataLayerEditAction[] =
this.dataLayerFormGroup.get('edit').get('enabledActions').value;
if (editEnabledActions && editEnabledActions.length) {
switch (this.dataLayerType) {
case 'markers':
const xKey: DataKey = this.dataLayerFormGroup.get('xKey').value;
const yKey: DataKey = this.dataLayerFormGroup.get('yKey').value;
return (xKey?.type === DataKeyType.attribute || yKey?.type === DataKeyType.attribute);
case 'polygons':
const polygonKey: DataKey = this.dataLayerFormGroup.get('polygonKey').value;
return polygonKey?.type === DataKeyType.attribute;
case 'circles':
const circleKey: DataKey = this.dataLayerFormGroup.get('circleKey').value;
return circleKey?.type === DataKeyType.attribute;
}
switch (this.dataLayerType) {
case 'markers':
const xKey: DataKey = this.dataLayerFormGroup.get('xKey').value;
const yKey: DataKey = this.dataLayerFormGroup.get('yKey').value;
return (xKey?.type === DataKeyType.attribute || yKey?.type === DataKeyType.attribute);
case 'polygons':
const polygonKey: DataKey = this.dataLayerFormGroup.get('polygonKey').value;
return polygonKey?.type === DataKeyType.attribute;
case 'circles':
const circleKey: DataKey = this.dataLayerFormGroup.get('circleKey').value;
return circleKey?.type === DataKeyType.attribute;
case 'polylines':
const polylineKey: DataKey = this.dataLayerFormGroup.get('polylineKey').value;
return polylineKey?.type === DataKeyType.attribute;
}
} else {
return false;
}
@ -231,11 +238,11 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
this.dataLayerFormGroup.addControl('pointColor', this.fb.control(tripsDataLayer.pointColor, Validators.required));
this.dataLayerFormGroup.addControl('pointTooltip', this.fb.control(tripsDataLayer.pointTooltip));
merge(this.dataLayerFormGroup.get('showMarker').valueChanges,
this.dataLayerFormGroup.get('markerType').valueChanges,
this.dataLayerFormGroup.get('rotateMarker').valueChanges,
this.dataLayerFormGroup.get('showPath').valueChanges,
this.dataLayerFormGroup.get('usePathDecorator').valueChanges,
this.dataLayerFormGroup.get('showPoints').valueChanges).pipe(
this.dataLayerFormGroup.get('markerType').valueChanges,
this.dataLayerFormGroup.get('rotateMarker').valueChanges,
this.dataLayerFormGroup.get('showPath').valueChanges,
this.dataLayerFormGroup.get('usePathDecorator').valueChanges,
this.dataLayerFormGroup.get('showPoints').valueChanges).pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(() =>
this.updateValidators()
@ -291,6 +298,32 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
this.updateValidators()
);
break;
case 'polylines':
this.dataLayerEditActions = dataLayerEditActions;
const polylineShapeDataLayer = this.settings as PolylinesDataLayerSettings;
this.dataLayerFormGroup.addControl('strokeColor', this.fb.control(polylineShapeDataLayer.strokeColor, Validators.required));
this.dataLayerFormGroup.addControl('strokeWeight', this.fb.control(polylineShapeDataLayer.strokeWeight, [Validators.required, Validators.min(0)]));
this.dialogTitle = 'widgets.maps.data-layer.polyline.polyline-configuration';
this.dataLayerEditTitle = 'widgets.maps.data-layer.polyline.edit';
this.dataLayerFormGroup.addControl('polylineKey', this.fb.control(polylineShapeDataLayer.polylineKey, Validators.required));
this.dataLayerFormGroup.addControl('usePathDecorator', this.fb.control(polylineShapeDataLayer.usePathDecorator));
this.dataLayerFormGroup.addControl('pathDecoratorSymbol', this.fb.control(polylineShapeDataLayer.pathDecoratorSymbol, Validators.required));
this.dataLayerFormGroup.addControl('pathDecoratorSymbolSize', this.fb.control(polylineShapeDataLayer.pathDecoratorSymbolSize, [Validators.required, Validators.min(0)]));
this.dataLayerFormGroup.addControl('pathDecoratorSymbolColor', this.fb.control(polylineShapeDataLayer.pathDecoratorSymbolColor));
this.dataLayerFormGroup.addControl('pathDecoratorOffset', this.fb.control(polylineShapeDataLayer.pathDecoratorOffset, [Validators.required, Validators.min(0)]));
this.dataLayerFormGroup.addControl('pathEndDecoratorOffset', this.fb.control(polylineShapeDataLayer.pathEndDecoratorOffset, [Validators.required, Validators.min(0)]));
this.dataLayerFormGroup.addControl('pathDecoratorRepeat', this.fb.control(polylineShapeDataLayer.pathDecoratorRepeat, [Validators.required, Validators.min(0)]));
this.dataLayerFormGroup.addControl('showPoints', this.fb.control(polylineShapeDataLayer.showPoints));
this.dataLayerFormGroup.addControl('pointSize', this.fb.control(polylineShapeDataLayer.pointSize, [Validators.required, Validators.min(0)]));
this.dataLayerFormGroup.addControl('pointColor', this.fb.control(polylineShapeDataLayer.pointColor, Validators.required));
this.dataLayerFormGroup.addControl('pointTooltip', this.fb.control(polylineShapeDataLayer.pointTooltip));
merge(this.dataLayerFormGroup.get('usePathDecorator').valueChanges,
this.dataLayerFormGroup.get('showPoints').valueChanges).pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(() =>
this.updateValidators()
);
break;
}
this.dataLayerFormGroup.get('dsType').valueChanges.pipe(
takeUntilDestroyed(this.destroyRef)
@ -325,6 +358,12 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
this.dataLayerFormGroup.get('circleKey').patchValue(circleKey, {emitEvent: false});
}
break;
case 'polylines':
const polylineKey: DataKey = this.dataLayerFormGroup.get('polylineKey').value;
if (updateDataKeyToNewDsType(polylineKey, newDsType)) {
this.dataLayerFormGroup.get('polylineKey').patchValue(polylineKey, {emitEvent: false});
}
break;
}
const additionalDataKeys: DataKey[] = this.dataLayerFormGroup.get('additionalDataKeys').value;
if (additionalDataKeys?.length) {
@ -433,6 +472,33 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
this.dataLayerFormGroup.get('pointColor').disable({emitEvent: false});
this.dataLayerFormGroup.get('pointTooltip').disable({emitEvent: false});
}
} else if (this.dataLayerType === 'polylines') {
const usePathDecorator: boolean = this.dataLayerFormGroup.get('usePathDecorator').value;
const showPoints: boolean = this.dataLayerFormGroup.get('showPoints').value;
if (usePathDecorator) {
this.dataLayerFormGroup.get('pathDecoratorSymbol').enable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorSymbolSize').enable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorSymbolColor').enable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorOffset').enable({emitEvent: false});
this.dataLayerFormGroup.get('pathEndDecoratorOffset').enable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorRepeat').enable({emitEvent: false});
} else {
this.dataLayerFormGroup.get('pathDecoratorSymbol').disable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorSymbolSize').disable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorSymbolColor').disable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorOffset').disable({emitEvent: false});
this.dataLayerFormGroup.get('pathEndDecoratorOffset').disable({emitEvent: false});
this.dataLayerFormGroup.get('pathDecoratorRepeat').disable({emitEvent: false});
}
if (showPoints) {
this.dataLayerFormGroup.get('pointSize').enable({emitEvent: false});
this.dataLayerFormGroup.get('pointColor').enable({emitEvent: false});
this.dataLayerFormGroup.get('pointTooltip').enable({emitEvent: false});
} else {
this.dataLayerFormGroup.get('pointSize').disable({emitEvent: false});
this.dataLayerFormGroup.get('pointColor').disable({emitEvent: false});
this.dataLayerFormGroup.get('pointTooltip').disable({emitEvent: false});
}
}
}
@ -470,7 +536,7 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
}
}
editKey(keyType: 'xKey' | 'yKey' | 'polygonKey' | 'circleKey') {
editKey(keyType: 'xKey' | 'yKey' | 'polygonKey' | 'circleKey' | 'polylineKey') {
const targetDataKey: DataKey = this.dataLayerFormGroup.get(keyType).value;
this.context.editKey(targetDataKey,
this.dataLayerFormGroup.get('dsDeviceId').value, this.dataLayerFormGroup.get('dsEntityAliasId').value,
@ -511,6 +577,12 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
dataKeys.push(circleKey);
}
break;
case 'polylines':
const polylineKey: DataKey = this.dataLayerFormGroup.get('polylineKey').value;
if (polylineKey) {
dataKeys.push(polylineKey);
}
break;
}
const additionalKeys: DataKey[] = this.dataLayerFormGroup.get('additionalDataKeys').value;
if (additionalKeys) {

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-row.component.ts

@ -151,8 +151,8 @@ export class MapDataLayerRowComponent implements ControlValueAccessor, OnInit {
this.dataLayerFormGroup.addControl('circleKey', this.fb.control(null, Validators.required));
break;
case 'polylines':
this.editDataLayerText = 'widgets.maps.data-layer.polylines.polyline-configuration';
this.removeDataLayerText = 'widgets.maps.data-layer.polylines.remove-polyline';
this.editDataLayerText = 'widgets.maps.data-layer.polyline.polyline-configuration';
this.removeDataLayerText = 'widgets.maps.data-layer.polyline.remove-polyline';
this.dataLayerFormGroup.addControl('polylineKey', this.fb.control(null, Validators.required));
break;
}

6
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts

@ -104,9 +104,9 @@ export class MapDataLayersComponent implements ControlValueAccessor, OnInit, Val
this.addDataLayerText = 'widgets.maps.data-layer.circle.add-circle';
this.noDataLayersText = 'widgets.maps.data-layer.circle.no-circles';
break;
case 'polylines': // todo translation
this.addDataLayerText = 'widgets.maps.data-layer.circle.add-polylines';
this.noDataLayersText = 'widgets.maps.data-layer.circle.no-polylines';
case 'polylines':
this.addDataLayerText = 'widgets.maps.data-layer.polyline.add-polylines';
this.noDataLayersText = 'widgets.maps.data-layer.polyline.no-polylines';
break;
}
this.dataLayersFormGroup = this.fb.group({

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

@ -442,13 +442,7 @@ export const pathDecoratorSymbolTranslationMap = new Map<PathDecoratorSymbol, st
]
);
export interface TripsDataLayerSettings extends MarkersDataLayerSettings {
showMarker: boolean;
rotateMarker: boolean;
offsetAngle: number;
showPath: boolean;
pathStrokeWeight?: number;
pathStrokeColor?: DataLayerColorSettings;
export interface PathDataLayerSettings {
usePathDecorator?: boolean;
pathDecoratorSymbol?: PathDecoratorSymbol;
pathDecoratorSymbolSize?: number;
@ -462,6 +456,15 @@ export interface TripsDataLayerSettings extends MarkersDataLayerSettings {
pointTooltip?: DataLayerTooltipSettings;
}
export interface TripsDataLayerSettings extends MarkersDataLayerSettings, PathDataLayerSettings {
showMarker: boolean;
rotateMarker: boolean;
offsetAngle: number;
showPath: boolean;
pathStrokeWeight?: number;
pathStrokeColor?: DataLayerColorSettings;
}
export const defaultTripsDataLayerSettings = (mapType: MapType, functionsOnly = false): TripsDataLayerSettings => mergeDeep(
defaultMarkersDataSourceSettings(mapType, true, functionsOnly) as TripsDataLayerSettings,
defaultBaseTripsDataLayerSettings(mapType) as TripsDataLayerSettings);
@ -663,7 +666,7 @@ export const defaultBaseCirclesDataLayerSettings = (mapType: MapType): Partial<C
} 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 {
export interface PolylinesDataLayerSettings extends ShapeDataLayerSettings, PathDataLayerSettings {
polylineKey: DataKey;
}
@ -680,37 +683,34 @@ 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)',
// },
// fillImage: {
// type: ShapeFillImageType.image,
// image: '/assets/widget-preview-empty.svg',
// preserveAspectRatio: true,
// opacity: 1,
// angle: 0,
// scale: 1
// },
// fillStripe: {
// weight: 3,
// color: {
// type: DataLayerColorType.constant,
// color: '#8f8f8f'
// },
// spaceWeight: 9,
// spaceColor: {
// type: DataLayerColorType.constant,
// color: 'rgba(143,143,143,0)',
// },
// angle: 45
// },
strokeColor: {
type: DataLayerColorType.constant,
color: '#3388ff',
},
strokeWeight: 3
usePathDecorator: false,
pathDecoratorSymbol: PathDecoratorSymbol.arrowHead,
pathDecoratorSymbolSize: 10,
pathDecoratorSymbolColor: '#307FE5',
pathDecoratorOffset: 20,
pathEndDecoratorOffset: 20,
pathDecoratorRepeat: 20,
showPoints: false,
pointSize: 10,
pointColor: {
type: DataLayerColorType.constant,
color: '#307FE5',
},
pointTooltip: {
show: true,
trigger: DataLayerTooltipTrigger.click,
autoclose: true,
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>End Time:</b> ${maxTime}<br/><b>Start Time:</b> ${minTime}'
: '<b>${entityName}</b><br/><br/><b>X Pos:</b> ${xPos:2}<br/><b>Y Pos:</b> ${yPos:2}<br/><b>End Time:</b> ${maxTime}<br/><b>Start Time:</b> ${minTime}',
offsetX: 0,
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>)

22
ui-ngx/src/assets/help/en_US/widget/lib/map/polyline_label_fn.md

@ -0,0 +1,22 @@
#### Polyline label function
<div class="divider"></div>
<br/>
*function (data, dsData): string*
A JavaScript function used to compute text or HTML code of the polyline label.
**Parameters:**
<ul>
{% include widget/lib/map/map_fn_args %}
</ul>
**Returns:**
Should return string value presenting text or HTML of the polyline label.
<div class="divider"></div>
{% include widget/lib/map/label_fn_examples %}

22
ui-ngx/src/assets/help/en_US/widget/lib/map/polyline_tooltip_fn.md

@ -0,0 +1,22 @@
#### Polyline tooltip function
<div class="divider"></div>
<br/>
*function (data, dsData): string*
A JavaScript function used to compute text or HTML code to be displayed in the polyline tooltip.
**Parameters:**
<ul>
{% include widget/lib/map/map_fn_args %}
</ul>
**Returns:**
Should return string value presenting text or HTML for the polyline tooltip.
<div class="divider"></div>
{% include widget/lib/map/tooltip_fn_examples %}

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

@ -8432,7 +8432,8 @@
"trips": "Trips",
"markers": "Markers",
"polygons": "Polygons",
"circles": "Circles"
"circles": "Circles",
"polylines": "Polylines"
},
"data-layer": {
"source": "Source",
@ -8629,6 +8630,18 @@
"finish-circle-hint-with-entity": "Circle for '{{entityName}}': click to finish and save circle",
"finish-circle-hint": "Circle: click to finish drawing"
},
"polyline": {
"polyline-key": "Polyline key",
"polyline-key-required": "Polyline key required",
"no-polylines": "No polylines configured",
"add-polylines": "Add polyline",
"polyline-configuration": "Polyline configuration",
"remove-polyline": "Remove polyline",
"edit": "Edit polyline",
"remove-polyline-for": "Remove polyline for '{{entityName}}'",
"draw-polyline": "Draw polyline",
"finish-polyline-hint": "Polyline: click to finish drawing"
},
"select-entity": "Select entity",
"select-entity-hint": "Hint: after selection click at the map to set position"
},

Loading…
Cancel
Save