Map rectangles support

This commit is contained in:
Igor Kulikov 2021-12-20 17:52:19 +02:00
parent 7072713f12
commit 66d6b8d687
6 changed files with 179 additions and 26 deletions

View File

@ -69,6 +69,8 @@ export default abstract class LeafletMap {
loading = false; loading = false;
replaceInfoLabelMarker: Array<ReplaceInfo> = []; replaceInfoLabelMarker: Array<ReplaceInfo> = [];
markerLabelText: string; markerLabelText: string;
polygonLabelText: string;
replaceInfoLabelPolygon: Array<ReplaceInfo> = [];
replaceInfoTooltipMarker: Array<ReplaceInfo> = []; replaceInfoTooltipMarker: Array<ReplaceInfo> = [];
markerTooltipText: string; markerTooltipText: string;
drawRoutes: boolean; drawRoutes: boolean;
@ -248,8 +250,16 @@ export default abstract class LeafletMap {
this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => { this.saveLocation(this.selectedEntity, this.convertToCustomFormat(e.layer.getLatLng())).subscribe(() => {
}); });
} else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') { } else if (e.shape === 'tbRectangle' || e.shape === 'tbPolygon') {
// @ts-ignore let coordinates;
this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(e.layer.getLatLngs()[0])).subscribe(() => { if (e.shape === 'tbRectangle') {
// @ts-ignore
const bounds: L.LatLngBounds = e.layer.getBounds();
coordinates = [bounds.getNorthWest(), bounds.getSouthEast()];
} else {
// @ts-ignore
coordinates = e.layer.getLatLngs()[0];
}
this.saveLocation(this.selectedEntity, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {
}); });
} }
// @ts-ignore // @ts-ignore
@ -281,7 +291,7 @@ export default abstract class LeafletMap {
result = iterator.next(); result = iterator.next();
} }
this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {}); this.saveLocation(result.value.data, this.convertToCustomFormat(null)).subscribe(() => {});
} else if (e.shape === 'Polygon') { } else if (e.shape === 'Polygon' || e.shape === 'Rectangle') {
const iterator = this.polygons.values(); const iterator = this.polygons.values();
let result = iterator.next(); let result = iterator.next();
while (!result.done && e.layer !== result.value.leafletPoly) { while (!result.done && e.layer !== result.value.leafletPoly) {
@ -333,6 +343,7 @@ export default abstract class LeafletMap {
this.map.scrollWheelZoom.disable(); this.map.scrollWheelZoom.disable();
} }
if (this.options.draggableMarker || this.editPolygons) { if (this.options.draggableMarker || this.editPolygons) {
map.pm.setGlobalOptions({ snappable: false } as L.PM.GlobalOptions);
this.addEditControl(); this.addEditControl();
} else { } else {
this.map.pm.disableDraw(); this.map.pm.disableDraw();
@ -764,6 +775,14 @@ export default abstract class LeafletMap {
if (coordinates.length === 1) { if (coordinates.length === 1) {
coordinates = coordinates[0]; coordinates = coordinates[0];
} }
if (e.shape === 'Rectangle') {
// @ts-ignore
const bounds: L.LatLngBounds = e.layer.getBounds();
const boundsArray = [bounds.getNorthWest(), bounds.getNorthEast(), bounds.getSouthWest(), bounds.getSouthEast()];
if (coordinates.every(point => boundsArray.find(boundPoint => boundPoint.equals(point)) !== undefined)) {
coordinates = [bounds.getNorthWest(), bounds.getSouthEast()];
}
}
this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {}); this.saveLocation(data, this.convertPolygonToCustomFormat(coordinates)).subscribe(() => {});
} }

View File

@ -131,6 +131,11 @@ export type PolygonSettings = {
polygonStrokeWeight: number; polygonStrokeWeight: number;
polygonStrokeColor: string; polygonStrokeColor: string;
polygonColor: string; polygonColor: string;
showPolygonLabel?: boolean;
polygonLabel: string;
polygonLabelColor: string;
polygonLabelText: string;
usePolygonLabelFunction: boolean;
showPolygonTooltip: boolean; showPolygonTooltip: boolean;
autocloseTooltip: boolean; autocloseTooltip: boolean;
showTooltipAction: string; showTooltipAction: string;
@ -139,8 +144,11 @@ export type PolygonSettings = {
usePolygonTooltipFunction: boolean; usePolygonTooltipFunction: boolean;
polygonClick: { [name: string]: actionsHandler }; polygonClick: { [name: string]: actionsHandler };
usePolygonColorFunction: boolean; usePolygonColorFunction: boolean;
usePolygonStrokeColorFunction: boolean;
polygonTooltipFunction: GenericFunction; polygonTooltipFunction: GenericFunction;
polygonColorFunction?: GenericFunction; polygonColorFunction?: GenericFunction;
polygonStrokeColorFunction?: GenericFunction;
polygonLabelFunction?: GenericFunction;
editablePolygon: boolean; editablePolygon: boolean;
}; };
@ -227,8 +235,10 @@ export const defaultSettings: any = {
showPolygon: false, showPolygon: false,
labelColor: '#000000', labelColor: '#000000',
color: '#FE7569', color: '#FE7569',
showPolygonLabel: false,
polygonColor: '#0000ff', polygonColor: '#0000ff',
polygonStrokeColor: '#fe0001', polygonStrokeColor: '#fe0001',
polygonLabelColor: '#000000',
polygonOpacity: 0.5, polygonOpacity: 0.5,
polygonStrokeOpacity: 1, polygonStrokeOpacity: 1,
polygonStrokeWeight: 1, polygonStrokeWeight: 1,

View File

@ -265,10 +265,13 @@ export class MapWidgetController implements MapWidgetInterface {
tooltipFunction: parseFunction(settings.tooltipFunction, functionParams), tooltipFunction: parseFunction(settings.tooltipFunction, functionParams),
colorFunction: parseFunction(settings.colorFunction, functionParams), colorFunction: parseFunction(settings.colorFunction, functionParams),
colorPointFunction: parseFunction(settings.colorPointFunction, functionParams), colorPointFunction: parseFunction(settings.colorPointFunction, functionParams),
polygonLabelFunction: parseFunction(settings.polygonLabelFunction, functionParams),
polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams), polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams),
polygonStrokeColorFunction: parseFunction(settings.polygonStrokeColorFunction, functionParams),
polygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams), polygonTooltipFunction: parseFunction(settings.polygonTooltipFunction, functionParams),
markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']), markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']),
labelColor: this.ctx.widgetConfig.color, labelColor: this.ctx.widgetConfig.color,
polygonLabelColor: this.ctx.widgetConfig.color,
polygonKeyName: settings.polKeyName ? settings.polKeyName : settings.polygonKeyName, polygonKeyName: settings.polKeyName ? settings.polKeyName : settings.polygonKeyName,
tooltipPattern: settings.tooltipPattern || tooltipPattern: settings.tooltipPattern ||
'<b>${entityName}</b><br/><br/><b>Latitude:</b> ${' + '<b>${entityName}</b><br/><br/><b>Latitude:</b> ${' +

View File

@ -29,6 +29,15 @@
box-shadow: none; box-shadow: none;
} }
.tb-polygon-label {
border: none;
background: none;
box-shadow: none;
&:before {
content: none;
}
}
.leaflet-container { .leaflet-container {
background-color: white; background-color: white;
} }

View File

@ -16,8 +16,14 @@
import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet'; import L, { LatLngExpression, LeafletMouseEvent } from 'leaflet';
import { createTooltip } from './maps-utils'; import { createTooltip } from './maps-utils';
import { functionValueCalculator, parseWithTranslation, safeExecute } from './common-maps-utils'; import {
import { FormattedData, PolygonSettings } from './map-models'; fillPattern,
functionValueCalculator,
parseWithTranslation,
processPattern,
safeExecute
} from './common-maps-utils';
import { FormattedData, MarkerSettings, PolygonSettings } from './map-models';
export class Polygon { export class Polygon {
@ -26,38 +32,47 @@ export class Polygon {
data: FormattedData; data: FormattedData;
dataSources: FormattedData[]; dataSources: FormattedData[];
constructor(public map, polyData: FormattedData, dataSources: FormattedData[], private settings: PolygonSettings, onDragendListener?) { constructor(public map, data: FormattedData, dataSources: FormattedData[], private settings: PolygonSettings,
private onDragendListener?) {
this.dataSources = dataSources; this.dataSources = dataSources;
this.data = polyData; this.data = data;
const polygonColor = this.getPolygonColor(settings); const polygonColor = this.getPolygonColor(settings);
this.leafletPoly = L.polygon(polyData[this.settings.polygonKeyName], { const polygonStrokeColor = this.getPolygonStrokeColor(settings);
const polyData = data[this.settings.polygonKeyName];
const polyConstructor = polyData.length > 2 ? L.polygon : L.rectangle;
this.leafletPoly = polyConstructor(polyData, {
fill: true, fill: true,
fillColor: polygonColor, fillColor: polygonColor,
color: settings.polygonStrokeColor, color: polygonStrokeColor,
weight: settings.polygonStrokeWeight, weight: settings.polygonStrokeWeight,
fillOpacity: settings.polygonOpacity, fillOpacity: settings.polygonOpacity,
opacity: settings.polygonStrokeOpacity, opacity: settings.polygonStrokeOpacity,
pmIgnore: !settings.editablePolygon pmIgnore: !settings.editablePolygon
}).addTo(this.map); }).addTo(this.map);
if (settings.editablePolygon && onDragendListener) { this.updateLabel(settings);
this.leafletPoly.on('pm:edit', (e) => onDragendListener(e, this.data));
}
if (settings.showPolygonTooltip) { if (settings.showPolygonTooltip) {
this.tooltip = createTooltip(this.leafletPoly, settings, polyData.$datasource); this.tooltip = createTooltip(this.leafletPoly, settings, data.$datasource);
this.updateTooltip(polyData); this.updateTooltip(data);
}
if (settings.polygonClick) {
this.leafletPoly.on('click', (event: LeafletMouseEvent) => {
for (const action in this.settings.polygonClick) {
if (typeof (this.settings.polygonClick[action]) === 'function') {
this.settings.polygonClick[action](event.originalEvent, polyData.$datasource);
}
}
});
} }
this.createEventListeners();
}
private createEventListeners() {
if (this.settings.editablePolygon && this.onDragendListener) {
this.leafletPoly.on('pm:edit', (e) => this.onDragendListener(e, this.data));
}
if (this.settings.polygonClick) {
this.leafletPoly.on('click', (event: LeafletMouseEvent) => {
for (const action in this.settings.polygonClick) {
if (typeof (this.settings.polygonClick[action]) === 'function') {
this.settings.polygonClick[action](event.originalEvent, this.data.$datasource);
}
}
});
}
} }
updateTooltip(data: FormattedData) { updateTooltip(data: FormattedData) {
@ -67,13 +82,54 @@ export class Polygon {
this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true)); this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true));
} }
updateLabel(settings: PolygonSettings) {
this.leafletPoly.unbindTooltip();
if (settings.showPolygonLabel) {
if (!this.map.polygonLabelText || settings.usePolygonLabelFunction) {
const pattern = settings.usePolygonLabelFunction ?
safeExecute(settings.polygonLabelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.polygonLabel;
this.map.polygonLabelText = parseWithTranslation.prepareProcessPattern(pattern, true);
this.map.replaceInfoLabelPolygon = processPattern(this.map.polygonLabelText, this.data);
}
settings.polygonLabelText = fillPattern(this.map.polygonLabelText, this.map.replaceInfoLabelPolygon, this.data);
this.leafletPoly.bindTooltip(`<div style="color: ${settings.polygonLabelColor};"><b>${settings.polygonLabelText}</b></div>`,
{ className: 'tb-polygon-label', permanent: true, sticky: true, direction: 'center' })
.openTooltip(this.leafletPoly.getBounds().getCenter());
}
}
updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) { updatePolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
this.data = data; this.data = data;
this.dataSources = dataSources; this.dataSources = dataSources;
this.leafletPoly.setLatLngs(data[this.settings.polygonKeyName]); const polyData = data[this.settings.polygonKeyName];
if (polyData.length > 2) {
if (this.leafletPoly instanceof L.Rectangle) {
this.map.removeLayer(this.leafletPoly);
const polygonColor = this.getPolygonColor(settings);
const polygonStrokeColor = this.getPolygonStrokeColor(settings);
this.leafletPoly = L.polygon(polyData, {
fill: true,
fillColor: polygonColor,
color: polygonStrokeColor,
weight: settings.polygonStrokeWeight,
fillOpacity: settings.polygonOpacity,
opacity: settings.polygonStrokeOpacity,
pmIgnore: !settings.editablePolygon
}).addTo(this.map);
} else {
this.leafletPoly.setLatLngs(polyData);
}
} else if (polyData.length === 2) {
const bounds = new L.LatLngBounds(polyData);
// @ts-ignore
this.leafletPoly.setBounds(bounds);
}
if (settings.showPolygonTooltip) { if (settings.showPolygonTooltip) {
this.updateTooltip(this.data); this.updateTooltip(this.data);
} }
if (settings.showPolygonLabel) {
this.updateLabel(settings);
}
this.updatePolygonColor(settings); this.updatePolygonColor(settings);
} }
@ -83,10 +139,11 @@ export class Polygon {
updatePolygonColor(settings: PolygonSettings) { updatePolygonColor(settings: PolygonSettings) {
const polygonColor = this.getPolygonColor(settings); const polygonColor = this.getPolygonColor(settings);
const polygonStrokeColor = this.getPolygonStrokeColor(settings);
const style: L.PathOptions = { const style: L.PathOptions = {
fill: true, fill: true,
fillColor: polygonColor, fillColor: polygonColor,
color: settings.polygonStrokeColor, color: polygonStrokeColor,
weight: settings.polygonStrokeWeight, weight: settings.polygonStrokeWeight,
fillOpacity: settings.polygonOpacity, fillOpacity: settings.polygonOpacity,
opacity: settings.polygonStrokeOpacity opacity: settings.polygonStrokeOpacity
@ -107,4 +164,9 @@ export class Polygon {
return functionValueCalculator(settings.usePolygonColorFunction, settings.polygonColorFunction, return functionValueCalculator(settings.usePolygonColorFunction, settings.polygonColorFunction,
[this.data, this.dataSources, this.data.dsIndex], settings.polygonColor); [this.data, this.dataSources, this.data.dsIndex], settings.polygonColor);
} }
private getPolygonStrokeColor(settings: PolygonSettings): string | null {
return functionValueCalculator(settings.usePolygonStrokeColorFunction, settings.polygonStrokeColorFunction,
[this.data, this.dataSources, this.data.dsIndex], settings.polygonStrokeColor);
}
} }

View File

@ -556,6 +556,25 @@ export const mapPolygonSchema =
type: 'boolean', type: 'boolean',
default: false default: false
}, },
showPolygonLabel: {
title: 'Show polygon label',
type: 'boolean',
default: false
},
polygonLabel: {
title: 'Polygon label (pattern examples: \'${entityName}\', \'${entityName}: (Text ${keyName} units.)\' )',
type: 'string',
default: '${entityName}'
},
usePolygonLabelFunction: {
title: 'Use polygon label function',
type: 'boolean',
default: false
},
polygonLabelFunction: {
title: 'Polygon label function: f(data, dsData, dsIndex)',
type: 'string'
},
polygonColor: { polygonColor: {
title: 'Polygon color', title: 'Polygon color',
type: 'string' type: 'string'
@ -607,6 +626,15 @@ export const mapPolygonSchema =
title: 'Polygon Color function: f(data, dsData, dsIndex)', title: 'Polygon Color function: f(data, dsData, dsIndex)',
type: 'string' type: 'string'
}, },
usePolygonStrokeColorFunction: {
title: 'Use polygon stroke color function',
type: 'boolean',
default: false
},
polygonStrokeColorFunction: {
title: 'Polygon Stroke Color function: f(data, dsData, dsIndex)',
type: 'string'
}
}, },
required: [] required: []
}, },
@ -614,6 +642,21 @@ export const mapPolygonSchema =
'showPolygon', 'showPolygon',
'polygonKeyName', 'polygonKeyName',
'editablePolygon', 'editablePolygon',
'showPolygonLabel',
{
key: 'usePolygonLabelFunction',
condition: 'model.showPolygonLabel === true'
},
{
key: 'polygonLabel',
condition: 'model.showPolygonLabel === true && model.usePolygonLabelFunction !== true'
},
{
key: 'polygonLabelFunction',
type: 'javascript',
helpId: 'widget/lib/map/label_fn',
condition: 'model.showPolygonLabel === true && model.usePolygonLabelFunction === true'
},
{ {
key: 'polygonColor', key: 'polygonColor',
type: 'color' type: 'color'
@ -630,6 +673,13 @@ export const mapPolygonSchema =
key: 'polygonStrokeColor', key: 'polygonStrokeColor',
type: 'color' type: 'color'
}, },
'usePolygonStrokeColorFunction',
{
key: 'polygonStrokeColorFunction',
helpId: 'widget/lib/map/polygon_color_fn',
type: 'javascript',
condition: 'model.usePolygonStrokeColorFunction === true'
},
'polygonStrokeOpacity', 'polygonStrokeOpacity',
'polygonStrokeWeight', 'polygonStrokeWeight',
'showPolygonTooltip', 'showPolygonTooltip',