Merge pull request #3261 from vvlladd28/improvement/map/create-label-tooltip

[3.0] Optimize created marker label and tooltip
This commit is contained in:
Igor Kulikov 2020-08-07 19:46:01 +03:00 committed by GitHub
commit 9b92f67b34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 141 additions and 19 deletions

View File

@ -77,6 +77,10 @@ export function isUndefined(value: any): boolean {
return typeof value === 'undefined'; return typeof value === 'undefined';
} }
export function isUndefinedOrNull(value: any): boolean {
return typeof value === 'undefined' || value === null;
}
export function isDefined(value: any): boolean { export function isDefined(value: any): boolean {
return typeof value !== 'undefined'; return typeof value !== 'undefined';
} }
@ -452,7 +456,7 @@ export function insertVariable(pattern: string, name: string, value: any): strin
const variable = match[0]; const variable = match[0];
const variableName = match[1]; const variableName = match[1];
if (variableName === name) { if (variableName === name) {
result = result.split(variable).join(value); result = result.replace(variable, value);
} }
match = varsRegex.exec(pattern); match = varsRegex.exec(pattern);
} }
@ -469,17 +473,17 @@ export function createLabelFromDatasource(datasource: Datasource, pattern: strin
const variable = match[0]; const variable = match[0];
const variableName = match[1]; const variableName = match[1];
if (variableName === 'dsName') { if (variableName === 'dsName') {
label = label.split(variable).join(datasource.name); label = label.replace(variable, datasource.name);
} else if (variableName === 'entityName') { } else if (variableName === 'entityName') {
label = label.split(variable).join(datasource.entityName); label = label.replace(variable, datasource.entityName);
} else if (variableName === 'deviceName') { } else if (variableName === 'deviceName') {
label = label.split(variable).join(datasource.entityName); label = label.replace(variable, datasource.entityName);
} else if (variableName === 'entityLabel') { } else if (variableName === 'entityLabel') {
label = label.split(variable).join(datasource.entityLabel || datasource.entityName); label = label.replace(variable, datasource.entityLabel || datasource.entityName);
} else if (variableName === 'aliasName') { } else if (variableName === 'aliasName') {
label = label.split(variable).join(datasource.aliasName); label = label.replace(variable, datasource.aliasName);
} else if (variableName === 'entityDescription') { } else if (variableName === 'entityDescription') {
label = label.split(variable).join(datasource.entityDescription); label = label.replace(variable, datasource.entityDescription);
} }
match = varsRegex.exec(pattern); match = varsRegex.exec(pattern);
} }

View File

@ -15,7 +15,8 @@
/// ///
import L, { import L, {
FeatureGroup, Icon, FeatureGroup,
Icon,
LatLngBounds, LatLngBounds,
LatLngTuple, LatLngTuple,
markerClusterGroup, markerClusterGroup,
@ -32,6 +33,7 @@ import {
MarkerSettings, MarkerSettings,
PolygonSettings, PolygonSettings,
PolylineSettings, PolylineSettings,
ReplaceInfo,
UnitedMapSettings UnitedMapSettings
} from './map-models'; } from './map-models';
import { Marker } from './markers'; import { Marker } from './markers';
@ -62,6 +64,10 @@ export default abstract class LeafletMap {
defaultMarkerIconInfo: { size: number[], icon: Icon }; defaultMarkerIconInfo: { size: number[], icon: Icon };
loadingDiv: JQuery<HTMLElement>; loadingDiv: JQuery<HTMLElement>;
loading = false; loading = false;
replaceInfoLabelMarker: Array<ReplaceInfo> = [];
markerLabelText: string;
replaceInfoTooltipMarker: Array<ReplaceInfo> = [];
markerTooltipText: string;
protected constructor(public ctx: WidgetContext, protected constructor(public ctx: WidgetContext,
public $container: HTMLElement, public $container: HTMLElement,

View File

@ -121,6 +121,12 @@ export interface FormattedData {
[key: string]: any [key: string]: any
} }
export interface ReplaceInfo {
variable: string;
valDec?: number;
dataKeyName: string
}
export type PolygonSettings = { export type PolygonSettings = {
showPolygon: boolean; showPolygon: boolean;
polygonKeyName: string; polygonKeyName: string;

View File

@ -15,13 +15,12 @@
/// ///
import L from 'leaflet'; import L from 'leaflet';
import { FormattedData, MarkerSettings, PolygonSettings, PolylineSettings } from './map-models'; import { FormattedData, MarkerSettings, PolygonSettings, PolylineSettings, ReplaceInfo } from './map-models';
import { Datasource, DatasourceData } from '@app/shared/models/widget.models'; import { Datasource, DatasourceData } from '@app/shared/models/widget.models';
import _ from 'lodash'; import _ from 'lodash';
import { Observable, Observer, of } from 'rxjs'; import { Observable, Observer, of } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { createLabelFromDatasource, hashCode, isNumber, isUndefined, padValue } from '@core/utils'; import { createLabelFromDatasource, hashCode, isDefinedAndNotNull, isNumber, isUndefined, padValue } from '@core/utils';
import { Form } from '@angular/forms';
export function createTooltip(target: L.Layer, export function createTooltip(target: L.Layer,
settings: MarkerSettings | PolylineSettings | PolygonSettings, settings: MarkerSettings | PolylineSettings | PolygonSettings,
@ -185,7 +184,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
} else { } else {
textValue = value; textValue = value;
} }
template = template.split(variable).join(textValue); template = template.replace(variable, textValue);
match = /\${([^}]*)}/g.exec(template); match = /\${([^}]*)}/g.exec(template);
} }
@ -198,7 +197,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
while (match !== null) { while (match !== null) {
[actionTags, actionName, actionText] = match; [actionTags, actionName, actionText] = match;
action = createLinkElement(actionName, actionText); action = createLinkElement(actionName, actionText);
template = template.split(actionTags).join(action); template = template.replace(actionTags, action);
match = linkActionRegex.exec(template); match = linkActionRegex.exec(template);
} }
@ -206,7 +205,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
while (match !== null) { while (match !== null) {
[actionTags, actionName, actionText] = match; [actionTags, actionName, actionText] = match;
action = createButtonElement(actionName, actionText); action = createButtonElement(actionName, actionText);
template = template.split(actionTags).join(action); template = template.replace(actionTags, action);
match = buttonActionRegex.exec(template); match = buttonActionRegex.exec(template);
} }
@ -219,6 +218,94 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
return res; return res;
} }
export function processPattern(template: string, data: { $datasource?: Datasource, [key: string]: any }): Array<ReplaceInfo> {
const replaceInfo = [];
try {
const reg = /\${([^}]*)}/g;
let match = reg.exec(template);
while (match !== null) {
const variableInfo: ReplaceInfo = {
dataKeyName: '',
valDec: 2,
variable: ''
};
const variable = match[0];
let label = match[1];
let valDec = 2;
const splitValues = label.split(':');
if (splitValues.length > 1) {
label = splitValues[0];
valDec = parseFloat(splitValues[1]);
}
variableInfo.variable = variable;
variableInfo.valDec = valDec;
if (label.startsWith('#')) {
const keyIndexStr = label.substring(1);
const n = Math.floor(Number(keyIndexStr));
if (String(n) === keyIndexStr && n >= 0) {
variableInfo.dataKeyName = data.$datasource.dataKeys[n].label;
}
} else {
variableInfo.dataKeyName = label;
}
replaceInfo.push(variableInfo);
match = reg.exec(template);
}
} catch (ex) {
console.log(ex, template)
}
return replaceInfo;
}
export function fillPattern(markerLabelText: string, replaceInfoLabelMarker: Array<ReplaceInfo>, data: FormattedData) {
let text = createLabelFromDatasource(data.$datasource, markerLabelText);
if (replaceInfoLabelMarker) {
for(const variableInfo of replaceInfoLabelMarker) {
let txtVal = '';
if (variableInfo.dataKeyName && isDefinedAndNotNull(data[variableInfo.dataKeyName])) {
const varData = data[variableInfo.dataKeyName];
if (isNumber(varData)) {
txtVal = padValue(varData, variableInfo.valDec);
} else {
txtVal = varData;
}
}
text = text.replace(variableInfo.variable, txtVal);
}
}
return text;
}
function prepareProcessPattern(template: string, translateFn?: TranslateFunc): string {
if (translateFn) {
template = translateFn(template);
}
let actionTags: string;
let actionText: string;
let actionName: string;
let action: string;
let match = linkActionRegex.exec(template);
while (match !== null) {
[actionTags, actionName, actionText] = match;
action = createLinkElement(actionName, actionText);
template = template.replace(actionTags, action);
match = linkActionRegex.exec(template);
}
match = buttonActionRegex.exec(template);
while (match !== null) {
[actionTags, actionName, actionText] = match;
action = createButtonElement(actionName, actionText);
template = template.replace(actionTags, action);
match = buttonActionRegex.exec(template);
}
return template;
}
export const parseWithTranslation = { export const parseWithTranslation = {
translateFn: null, translateFn: null,
@ -233,6 +320,9 @@ export const parseWithTranslation = {
parseTemplate(template: string, data: object, forceTranslate = false): string { parseTemplate(template: string, data: object, forceTranslate = false): string {
return parseTemplate(forceTranslate ? this.translate(template) : template, data, this.translate.bind(this)); return parseTemplate(forceTranslate ? this.translate(template) : template, data, this.translate.bind(this));
}, },
prepareProcessPattern(template: string, forceTranslate = false): string {
return prepareProcessPattern(forceTranslate ? this.translate(template) : template, this.translate.bind(this));
},
setTranslate(translateFn: TranslateFunc) { setTranslate(translateFn: TranslateFunc) {
this.translateFn = translateFn; this.translateFn = translateFn;
} }

View File

@ -16,7 +16,15 @@
import L, { LeafletMouseEvent } from 'leaflet'; import L, { LeafletMouseEvent } from 'leaflet';
import { FormattedData, MarkerSettings } from './map-models'; import { FormattedData, MarkerSettings } from './map-models';
import { aspectCache, bindPopupActions, createTooltip, parseWithTranslation, safeExecute } from './maps-utils'; import {
aspectCache,
bindPopupActions,
createTooltip,
fillPattern,
parseWithTranslation,
processPattern,
safeExecute
} from './maps-utils';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { isDefined } from '@core/utils'; import { isDefined } from '@core/utils';
import LeafletMap from './leaflet-map'; import LeafletMap from './leaflet-map';
@ -74,9 +82,13 @@ export class Marker {
} }
updateMarkerTooltip(data: FormattedData) { updateMarkerTooltip(data: FormattedData) {
if(!this.map.markerTooltipText || this.settings.useTooltipFunction) {
const pattern = this.settings.useTooltipFunction ? const pattern = this.settings.useTooltipFunction ?
safeExecute(this.settings.tooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) : this.settings.tooltipPattern; safeExecute(this.settings.tooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) : this.settings.tooltipPattern;
this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true)); this.map.markerTooltipText = parseWithTranslation.prepareProcessPattern(pattern, true);
this.map.replaceInfoTooltipMarker = processPattern(this.map.markerTooltipText, data);
}
this.tooltip.setContent(fillPattern(this.map.markerTooltipText, this.map.replaceInfoTooltipMarker, data));
if (this.tooltip.isOpen() && this.tooltip.getElement()) { if (this.tooltip.isOpen() && this.tooltip.getElement()) {
bindPopupActions(this.tooltip, this.settings, data.$datasource); bindPopupActions(this.tooltip, this.settings, data.$datasource);
} }
@ -89,9 +101,13 @@ export class Marker {
updateMarkerLabel(settings: MarkerSettings) { updateMarkerLabel(settings: MarkerSettings) {
this.leafletMarker.unbindTooltip(); this.leafletMarker.unbindTooltip();
if (settings.showLabel) { if (settings.showLabel) {
if(!this.map.markerLabelText || settings.useLabelFunction) {
const pattern = settings.useLabelFunction ? const pattern = settings.useLabelFunction ?
safeExecute(settings.labelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.label; safeExecute(settings.labelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.label;
settings.labelText = parseWithTranslation.parseTemplate(pattern, this.data, true); this.map.markerLabelText = parseWithTranslation.prepareProcessPattern(pattern, true);
this.map.replaceInfoLabelMarker = processPattern(this.map.markerLabelText, this.data);
}
settings.labelText = fillPattern(this.map.markerLabelText, this.map.replaceInfoLabelMarker, this.data);
this.leafletMarker.bindTooltip(`<div style="color: ${settings.labelColor};"><b>${settings.labelText}</b></div>`, this.leafletMarker.bindTooltip(`<div style="color: ${settings.labelColor};"><b>${settings.labelText}</b></div>`,
{ className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.tooltipOffset }); { className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.tooltipOffset });
} }