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 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 84 export function isDefined(value: any): boolean {
81 85 return typeof value !== 'undefined';
82 86 }
... ... @@ -452,7 +456,7 @@ export function insertVariable(pattern: string, name: string, value: any): strin
452 456 const variable = match[0];
453 457 const variableName = match[1];
454 458 if (variableName === name) {
455   - result = result.split(variable).join(value);
  459 + result = result.replace(variable, value);
456 460 }
457 461 match = varsRegex.exec(pattern);
458 462 }
... ... @@ -469,17 +473,17 @@ export function createLabelFromDatasource(datasource: Datasource, pattern: strin
469 473 const variable = match[0];
470 474 const variableName = match[1];
471 475 if (variableName === 'dsName') {
472   - label = label.split(variable).join(datasource.name);
  476 + label = label.replace(variable, datasource.name);
473 477 } else if (variableName === 'entityName') {
474   - label = label.split(variable).join(datasource.entityName);
  478 + label = label.replace(variable, datasource.entityName);
475 479 } else if (variableName === 'deviceName') {
476   - label = label.split(variable).join(datasource.entityName);
  480 + label = label.replace(variable, datasource.entityName);
477 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 483 } else if (variableName === 'aliasName') {
480   - label = label.split(variable).join(datasource.aliasName);
  484 + label = label.replace(variable, datasource.aliasName);
481 485 } else if (variableName === 'entityDescription') {
482   - label = label.split(variable).join(datasource.entityDescription);
  486 + label = label.replace(variable, datasource.entityDescription);
483 487 }
484 488 match = varsRegex.exec(pattern);
485 489 }
... ...
... ... @@ -15,7 +15,8 @@
15 15 ///
16 16
17 17 import L, {
18   - FeatureGroup, Icon,
  18 + FeatureGroup,
  19 + Icon,
19 20 LatLngBounds,
20 21 LatLngTuple,
21 22 markerClusterGroup,
... ... @@ -32,6 +33,7 @@ import {
32 33 MarkerSettings,
33 34 PolygonSettings,
34 35 PolylineSettings,
  36 + ReplaceInfo,
35 37 UnitedMapSettings
36 38 } from './map-models';
37 39 import { Marker } from './markers';
... ... @@ -62,6 +64,10 @@ export default abstract class LeafletMap {
62 64 defaultMarkerIconInfo: { size: number[], icon: Icon };
63 65 loadingDiv: JQuery<HTMLElement>;
64 66 loading = false;
  67 + replaceInfoLabelMarker: Array<ReplaceInfo> = [];
  68 + markerLabelText: string;
  69 + replaceInfoTooltipMarker: Array<ReplaceInfo> = [];
  70 + markerTooltipText: string;
65 71
66 72 protected constructor(public ctx: WidgetContext,
67 73 public $container: HTMLElement,
... ...
... ... @@ -121,6 +121,12 @@ export interface FormattedData {
121 121 [key: string]: any
122 122 }
123 123
  124 +export interface ReplaceInfo {
  125 + variable: string;
  126 + valDec?: number;
  127 + dataKeyName: string
  128 +}
  129 +
124 130 export type PolygonSettings = {
125 131 showPolygon: boolean;
126 132 polygonKeyName: string;
... ...
... ... @@ -15,13 +15,12 @@
15 15 ///
16 16
17 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 19 import { Datasource, DatasourceData } from '@app/shared/models/widget.models';
20 20 import _ from 'lodash';
21 21 import { Observable, Observer, of } from 'rxjs';
22 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 25 export function createTooltip(target: L.Layer,
27 26 settings: MarkerSettings | PolylineSettings | PolygonSettings,
... ... @@ -185,7 +184,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
185 184 } else {
186 185 textValue = value;
187 186 }
188   - template = template.split(variable).join(textValue);
  187 + template = template.replace(variable, textValue);
189 188 match = /\${([^}]*)}/g.exec(template);
190 189 }
191 190
... ... @@ -198,7 +197,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
198 197 while (match !== null) {
199 198 [actionTags, actionName, actionText] = match;
200 199 action = createLinkElement(actionName, actionText);
201   - template = template.split(actionTags).join(action);
  200 + template = template.replace(actionTags, action);
202 201 match = linkActionRegex.exec(template);
203 202 }
204 203
... ... @@ -206,7 +205,7 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
206 205 while (match !== null) {
207 206 [actionTags, actionName, actionText] = match;
208 207 action = createButtonElement(actionName, actionText);
209   - template = template.split(actionTags).join(action);
  208 + template = template.replace(actionTags, action);
210 209 match = buttonActionRegex.exec(template);
211 210 }
212 211
... ... @@ -219,6 +218,94 @@ function parseTemplate(template: string, data: { $datasource?: Datasource, [key:
219 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 309 export const parseWithTranslation = {
223 310
224 311 translateFn: null,
... ... @@ -233,6 +320,9 @@ export const parseWithTranslation = {
233 320 parseTemplate(template: string, data: object, forceTranslate = false): string {
234 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 326 setTranslate(translateFn: TranslateFunc) {
237 327 this.translateFn = translateFn;
238 328 }
... ...
... ... @@ -16,7 +16,15 @@
16 16
17 17 import L, { LeafletMouseEvent } from 'leaflet';
18 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 28 import tinycolor from 'tinycolor2';
21 29 import { isDefined } from '@core/utils';
22 30 import LeafletMap from './leaflet-map';
... ... @@ -74,9 +82,13 @@ export class Marker {
74 82 }
75 83
76 84 updateMarkerTooltip(data: FormattedData) {
  85 + if(!this.map.markerTooltipText || this.settings.useTooltipFunction) {
77 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 92 if (this.tooltip.isOpen() && this.tooltip.getElement()) {
81 93 bindPopupActions(this.tooltip, this.settings, data.$datasource);
82 94 }
... ... @@ -89,9 +101,13 @@ export class Marker {
89 101 updateMarkerLabel(settings: MarkerSettings) {
90 102 this.leafletMarker.unbindTooltip();
91 103 if (settings.showLabel) {
92   - const pattern = settings.useLabelFunction ?
  104 + if(!this.map.markerLabelText || settings.useLabelFunction) {
  105 + const pattern = settings.useLabelFunction ?
93 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 111 this.leafletMarker.bindTooltip(`<div style="color: ${settings.labelColor};"><b>${settings.labelText}</b></div>`,
96 112 { className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.tooltipOffset });
97 113 }
... ...