Commit 9b92f67b34d6b6d17bc6c1afe1ae2be4cbce36f6
Committed by
GitHub
Merge pull request #3261 from vvlladd28/improvement/map/create-label-tooltip
[3.0] Optimize created marker label and tooltip
Showing
5 changed files
with
141 additions
and
19 deletions
... | ... | @@ -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 | } | ... | ... |