Commit 9b92f67b34d6b6d17bc6c1afe1ae2be4cbce36f6

Authored by Igor Kulikov
Committed by GitHub
2 parents 6a4cd0d5 c4ae2779

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

[3.0] Optimize created marker label and tooltip
@@ -77,6 +77,10 @@ export function isUndefined(value: any): boolean { @@ -77,6 +77,10 @@ export function isUndefined(value: any): boolean {
77 return typeof value === 'undefined'; 77 return typeof value === 'undefined';
78 } 78 }
79 79
  80 +export function isUndefinedOrNull(value: any): boolean {
  81 + return typeof value === 'undefined' || value === null;
  82 +}
  83 +
80 export function isDefined(value: any): boolean { 84 export function isDefined(value: any): boolean {
81 return typeof value !== 'undefined'; 85 return typeof value !== 'undefined';
82 } 86 }
@@ -452,7 +456,7 @@ export function insertVariable(pattern: string, name: string, value: any): strin @@ -452,7 +456,7 @@ export function insertVariable(pattern: string, name: string, value: any): strin
452 const variable = match[0]; 456 const variable = match[0];
453 const variableName = match[1]; 457 const variableName = match[1];
454 if (variableName === name) { 458 if (variableName === name) {
455 - result = result.split(variable).join(value); 459 + result = result.replace(variable, value);
456 } 460 }
457 match = varsRegex.exec(pattern); 461 match = varsRegex.exec(pattern);
458 } 462 }
@@ -469,17 +473,17 @@ export function createLabelFromDatasource(datasource: Datasource, pattern: strin @@ -469,17 +473,17 @@ export function createLabelFromDatasource(datasource: Datasource, pattern: strin
469 const variable = match[0]; 473 const variable = match[0];
470 const variableName = match[1]; 474 const variableName = match[1];
471 if (variableName === 'dsName') { 475 if (variableName === 'dsName') {
472 - label = label.split(variable).join(datasource.name); 476 + label = label.replace(variable, datasource.name);
473 } else if (variableName === 'entityName') { 477 } else if (variableName === 'entityName') {
474 - label = label.split(variable).join(datasource.entityName); 478 + label = label.replace(variable, datasource.entityName);
475 } else if (variableName === 'deviceName') { 479 } else if (variableName === 'deviceName') {
476 - label = label.split(variable).join(datasource.entityName); 480 + label = label.replace(variable, datasource.entityName);
477 } else if (variableName === 'entityLabel') { 481 } else if (variableName === 'entityLabel') {
478 - label = label.split(variable).join(datasource.entityLabel || datasource.entityName); 482 + label = label.replace(variable, datasource.entityLabel || datasource.entityName);
479 } else if (variableName === 'aliasName') { 483 } else if (variableName === 'aliasName') {
480 - label = label.split(variable).join(datasource.aliasName); 484 + label = label.replace(variable, datasource.aliasName);
481 } else if (variableName === 'entityDescription') { 485 } else if (variableName === 'entityDescription') {
482 - label = label.split(variable).join(datasource.entityDescription); 486 + label = label.replace(variable, datasource.entityDescription);
483 } 487 }
484 match = varsRegex.exec(pattern); 488 match = varsRegex.exec(pattern);
485 } 489 }
@@ -15,7 +15,8 @@ @@ -15,7 +15,8 @@
15 /// 15 ///
16 16
17 import L, { 17 import L, {
18 - FeatureGroup, Icon, 18 + FeatureGroup,
  19 + Icon,
19 LatLngBounds, 20 LatLngBounds,
20 LatLngTuple, 21 LatLngTuple,
21 markerClusterGroup, 22 markerClusterGroup,
@@ -32,6 +33,7 @@ import { @@ -32,6 +33,7 @@ import {
32 MarkerSettings, 33 MarkerSettings,
33 PolygonSettings, 34 PolygonSettings,
34 PolylineSettings, 35 PolylineSettings,
  36 + ReplaceInfo,
35 UnitedMapSettings 37 UnitedMapSettings
36 } from './map-models'; 38 } from './map-models';
37 import { Marker } from './markers'; 39 import { Marker } from './markers';
@@ -62,6 +64,10 @@ export default abstract class LeafletMap { @@ -62,6 +64,10 @@ export default abstract class LeafletMap {
62 defaultMarkerIconInfo: { size: number[], icon: Icon }; 64 defaultMarkerIconInfo: { size: number[], icon: Icon };
63 loadingDiv: JQuery<HTMLElement>; 65 loadingDiv: JQuery<HTMLElement>;
64 loading = false; 66 loading = false;
  67 + replaceInfoLabelMarker: Array<ReplaceInfo> = [];
  68 + markerLabelText: string;
  69 + replaceInfoTooltipMarker: Array<ReplaceInfo> = [];
  70 + markerTooltipText: string;
65 71
66 protected constructor(public ctx: WidgetContext, 72 protected constructor(public ctx: WidgetContext,
67 public $container: HTMLElement, 73 public $container: HTMLElement,
@@ -121,6 +121,12 @@ export interface FormattedData { @@ -121,6 +121,12 @@ export interface FormattedData {
121 [key: string]: any 121 [key: string]: any
122 } 122 }
123 123
  124 +export interface ReplaceInfo {
  125 + variable: string;
  126 + valDec?: number;
  127 + dataKeyName: string
  128 +}
  129 +
124 export type PolygonSettings = { 130 export type PolygonSettings = {
125 showPolygon: boolean; 131 showPolygon: boolean;
126 polygonKeyName: string; 132 polygonKeyName: string;
@@ -15,13 +15,12 @@ @@ -15,13 +15,12 @@
15 /// 15 ///
16 16
17 import L from 'leaflet'; 17 import L from 'leaflet';
18 -import { FormattedData, MarkerSettings, PolygonSettings, PolylineSettings } from './map-models'; 18 +import { FormattedData, MarkerSettings, PolygonSettings, PolylineSettings, ReplaceInfo } from './map-models';
19 import { Datasource, DatasourceData } from '@app/shared/models/widget.models'; 19 import { Datasource, DatasourceData } from '@app/shared/models/widget.models';
20 import _ from 'lodash'; 20 import _ from 'lodash';
21 import { Observable, Observer, of } from 'rxjs'; 21 import { Observable, Observer, of } from 'rxjs';
22 import { map } from 'rxjs/operators'; 22 import { map } from 'rxjs/operators';
23 -import { createLabelFromDatasource, hashCode, isNumber, isUndefined, padValue } from '@core/utils';  
24 -import { Form } from '@angular/forms'; 23 +import { createLabelFromDatasource, hashCode, isDefinedAndNotNull, isNumber, isUndefined, padValue } from '@core/utils';
25 24
26 export function createTooltip(target: L.Layer, 25 export function createTooltip(target: L.Layer,
27 settings: MarkerSettings | PolylineSettings | PolygonSettings, 26 settings: MarkerSettings | PolylineSettings | PolygonSettings,
@@ -185,7 +184,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key: @@ -185,7 +184,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
185 } else { 184 } else {
186 textValue = value; 185 textValue = value;
187 } 186 }
188 - template = template.split(variable).join(textValue); 187 + template = template.replace(variable, textValue);
189 match = /\${([^}]*)}/g.exec(template); 188 match = /\${([^}]*)}/g.exec(template);
190 } 189 }
191 190
@@ -198,7 +197,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key: @@ -198,7 +197,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
198 while (match !== null) { 197 while (match !== null) {
199 [actionTags, actionName, actionText] = match; 198 [actionTags, actionName, actionText] = match;
200 action = createLinkElement(actionName, actionText); 199 action = createLinkElement(actionName, actionText);
201 - template = template.split(actionTags).join(action); 200 + template = template.replace(actionTags, action);
202 match = linkActionRegex.exec(template); 201 match = linkActionRegex.exec(template);
203 } 202 }
204 203
@@ -206,7 +205,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key: @@ -206,7 +205,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
206 while (match !== null) { 205 while (match !== null) {
207 [actionTags, actionName, actionText] = match; 206 [actionTags, actionName, actionText] = match;
208 action = createButtonElement(actionName, actionText); 207 action = createButtonElement(actionName, actionText);
209 - template = template.split(actionTags).join(action); 208 + template = template.replace(actionTags, action);
210 match = buttonActionRegex.exec(template); 209 match = buttonActionRegex.exec(template);
211 } 210 }
212 211
@@ -219,6 +218,94 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key: @@ -219,6 +218,94 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
219 return res; 218 return res;
220 } 219 }
221 220
  221 +export function processPattern(template: string, data: { $datasource?: Datasource, [key: string]: any }): Array<ReplaceInfo> {
  222 + const replaceInfo = [];
  223 + try {
  224 + const reg = /\${([^}]*)}/g;
  225 + let match = reg.exec(template);
  226 + while (match !== null) {
  227 + const variableInfo: ReplaceInfo = {
  228 + dataKeyName: '',
  229 + valDec: 2,
  230 + variable: ''
  231 + };
  232 + const variable = match[0];
  233 + let label = match[1];
  234 + let valDec = 2;
  235 + const splitValues = label.split(':');
  236 + if (splitValues.length > 1) {
  237 + label = splitValues[0];
  238 + valDec = parseFloat(splitValues[1]);
  239 + }
  240 +
  241 + variableInfo.variable = variable;
  242 + variableInfo.valDec = valDec;
  243 +
  244 + if (label.startsWith('#')) {
  245 + const keyIndexStr = label.substring(1);
  246 + const n = Math.floor(Number(keyIndexStr));
  247 + if (String(n) === keyIndexStr && n >= 0) {
  248 + variableInfo.dataKeyName = data.$datasource.dataKeys[n].label;
  249 + }
  250 + } else {
  251 + variableInfo.dataKeyName = label;
  252 + }
  253 + replaceInfo.push(variableInfo);
  254 +
  255 + match = reg.exec(template);
  256 + }
  257 + } catch (ex) {
  258 + console.log(ex, template)
  259 + }
  260 + return replaceInfo;
  261 +}
  262 +
  263 +export function fillPattern(markerLabelText: string, replaceInfoLabelMarker: Array<ReplaceInfo>, data: FormattedData) {
  264 + let text = createLabelFromDatasource(data.$datasource, markerLabelText);
  265 + if (replaceInfoLabelMarker) {
  266 + for(const variableInfo of replaceInfoLabelMarker) {
  267 + let txtVal = '';
  268 + if (variableInfo.dataKeyName && isDefinedAndNotNull(data[variableInfo.dataKeyName])) {
  269 + const varData = data[variableInfo.dataKeyName];
  270 + if (isNumber(varData)) {
  271 + txtVal = padValue(varData, variableInfo.valDec);
  272 + } else {
  273 + txtVal = varData;
  274 + }
  275 + }
  276 + text = text.replace(variableInfo.variable, txtVal);
  277 + }
  278 + }
  279 + return text;
  280 +}
  281 +
  282 +function prepareProcessPattern(template: string, translateFn?: TranslateFunc): string {
  283 + if (translateFn) {
  284 + template = translateFn(template);
  285 + }
  286 + let actionTags: string;
  287 + let actionText: string;
  288 + let actionName: string;
  289 + let action: string;
  290 +
  291 + let match = linkActionRegex.exec(template);
  292 + while (match !== null) {
  293 + [actionTags, actionName, actionText] = match;
  294 + action = createLinkElement(actionName, actionText);
  295 + template = template.replace(actionTags, action);
  296 + match = linkActionRegex.exec(template);
  297 + }
  298 +
  299 + match = buttonActionRegex.exec(template);
  300 + while (match !== null) {
  301 + [actionTags, actionName, actionText] = match;
  302 + action = createButtonElement(actionName, actionText);
  303 + template = template.replace(actionTags, action);
  304 + match = buttonActionRegex.exec(template);
  305 + }
  306 + return template;
  307 +}
  308 +
222 export const parseWithTranslation = { 309 export const parseWithTranslation = {
223 310
224 translateFn: null, 311 translateFn: null,
@@ -233,6 +320,9 @@ export const parseWithTranslation = { @@ -233,6 +320,9 @@ export const parseWithTranslation = {
233 parseTemplate(template: string, data: object, forceTranslate = false): string { 320 parseTemplate(template: string, data: object, forceTranslate = false): string {
234 return parseTemplate(forceTranslate ? this.translate(template) : template, data, this.translate.bind(this)); 321 return parseTemplate(forceTranslate ? this.translate(template) : template, data, this.translate.bind(this));
235 }, 322 },
  323 + prepareProcessPattern(template: string, forceTranslate = false): string {
  324 + return prepareProcessPattern(forceTranslate ? this.translate(template) : template, this.translate.bind(this));
  325 + },
236 setTranslate(translateFn: TranslateFunc) { 326 setTranslate(translateFn: TranslateFunc) {
237 this.translateFn = translateFn; 327 this.translateFn = translateFn;
238 } 328 }
@@ -16,7 +16,15 @@ @@ -16,7 +16,15 @@
16 16
17 import L, { LeafletMouseEvent } from 'leaflet'; 17 import L, { LeafletMouseEvent } from 'leaflet';
18 import { FormattedData, MarkerSettings } from './map-models'; 18 import { FormattedData, MarkerSettings } from './map-models';
19 -import { aspectCache, bindPopupActions, createTooltip, parseWithTranslation, safeExecute } from './maps-utils'; 19 +import {
  20 + aspectCache,
  21 + bindPopupActions,
  22 + createTooltip,
  23 + fillPattern,
  24 + parseWithTranslation,
  25 + processPattern,
  26 + safeExecute
  27 +} from './maps-utils';
20 import tinycolor from 'tinycolor2'; 28 import tinycolor from 'tinycolor2';
21 import { isDefined } from '@core/utils'; 29 import { isDefined } from '@core/utils';
22 import LeafletMap from './leaflet-map'; 30 import LeafletMap from './leaflet-map';
@@ -74,9 +82,13 @@ export class Marker { @@ -74,9 +82,13 @@ export class Marker {
74 } 82 }
75 83
76 updateMarkerTooltip(data: FormattedData) { 84 updateMarkerTooltip(data: FormattedData) {
  85 + if(!this.map.markerTooltipText || this.settings.useTooltipFunction) {
77 const pattern = this.settings.useTooltipFunction ? 86 const pattern = this.settings.useTooltipFunction ?
78 - safeExecute(this.settings.tooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) : this.settings.tooltipPattern;  
79 - this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true)); 87 + safeExecute(this.settings.tooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) : this.settings.tooltipPattern;
  88 + this.map.markerTooltipText = parseWithTranslation.prepareProcessPattern(pattern, true);
  89 + this.map.replaceInfoTooltipMarker = processPattern(this.map.markerTooltipText, data);
  90 + }
  91 + this.tooltip.setContent(fillPattern(this.map.markerTooltipText, this.map.replaceInfoTooltipMarker, data));
80 if (this.tooltip.isOpen() && this.tooltip.getElement()) { 92 if (this.tooltip.isOpen() && this.tooltip.getElement()) {
81 bindPopupActions(this.tooltip, this.settings, data.$datasource); 93 bindPopupActions(this.tooltip, this.settings, data.$datasource);
82 } 94 }
@@ -89,9 +101,13 @@ export class Marker { @@ -89,9 +101,13 @@ export class Marker {
89 updateMarkerLabel(settings: MarkerSettings) { 101 updateMarkerLabel(settings: MarkerSettings) {
90 this.leafletMarker.unbindTooltip(); 102 this.leafletMarker.unbindTooltip();
91 if (settings.showLabel) { 103 if (settings.showLabel) {
92 - const pattern = settings.useLabelFunction ? 104 + if(!this.map.markerLabelText || settings.useLabelFunction) {
  105 + const pattern = settings.useLabelFunction ?
93 safeExecute(settings.labelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.label; 106 safeExecute(settings.labelFunction, [this.data, this.dataSources, this.data.dsIndex]) : settings.label;
94 - settings.labelText = parseWithTranslation.parseTemplate(pattern, this.data, true); 107 + this.map.markerLabelText = parseWithTranslation.prepareProcessPattern(pattern, true);
  108 + this.map.replaceInfoLabelMarker = processPattern(this.map.markerLabelText, this.data);
  109 + }
  110 + settings.labelText = fillPattern(this.map.markerLabelText, this.map.replaceInfoLabelMarker, this.data);
95 this.leafletMarker.bindTooltip(`<div style="color: ${settings.labelColor};"><b>${settings.labelText}</b></div>`, 111 this.leafletMarker.bindTooltip(`<div style="color: ${settings.labelColor};"><b>${settings.labelText}</b></div>`,
96 { className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.tooltipOffset }); 112 { className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.tooltipOffset });
97 } 113 }