Commit 11db772ea2d753f178faa14e6eee0e2ac830b424
Committed by
GitHub
1 parent
c6cf5c43
bugfixes (#2705)
Showing
10 changed files
with
112 additions
and
73 deletions
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | import { AliasInfo, IAliasController, StateControllerHolder, StateEntityInfo } from '@core/api/widget-api.models'; | 17 | import { AliasInfo, IAliasController, StateControllerHolder, StateEntityInfo } from '@core/api/widget-api.models'; |
18 | import { forkJoin, Observable, of, ReplaySubject, Subject } from 'rxjs'; | 18 | import { forkJoin, Observable, of, ReplaySubject, Subject } from 'rxjs'; |
19 | import { DataKey, Datasource, DatasourceType } from '@app/shared/models/widget.models'; | 19 | import { DataKey, Datasource, DatasourceType } from '@app/shared/models/widget.models'; |
20 | -import { deepClone, isEqual } from '@core/utils'; | 20 | +import { deepClone, isEqual, createLabelFromDatasource } from '@core/utils'; |
21 | import { EntityService } from '@core/http/entity.service'; | 21 | import { EntityService } from '@core/http/entity.service'; |
22 | import { UtilsService } from '@core/services/utils.service'; | 22 | import { UtilsService } from '@core/services/utils.service'; |
23 | import { EntityAliases } from '@shared/models/alias.models'; | 23 | import { EntityAliases } from '@shared/models/alias.models'; |
@@ -329,7 +329,7 @@ export class AliasController implements IAliasController { | @@ -329,7 +329,7 @@ export class AliasController implements IAliasController { | ||
329 | if (!dataKey.pattern) { | 329 | if (!dataKey.pattern) { |
330 | dataKey.pattern = deepClone(dataKey.label); | 330 | dataKey.pattern = deepClone(dataKey.label); |
331 | } | 331 | } |
332 | - dataKey.label = this.utils.createLabelFromDatasource(datasource, dataKey.pattern); | 332 | + dataKey.label = createLabelFromDatasource(datasource, dataKey.pattern); |
333 | } | 333 | } |
334 | 334 | ||
335 | getInstantAliasInfo(aliasId: string): AliasInfo { | 335 | getInstantAliasInfo(aliasId: string): AliasInfo { |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | import { Inject, Injectable, NgZone } from '@angular/core'; | 20 | import { Inject, Injectable, NgZone } from '@angular/core'; |
21 | import { WINDOW } from '@core/services/window.service'; | 21 | import { WINDOW } from '@core/services/window.service'; |
22 | import { ExceptionData } from '@app/shared/models/error.models'; | 22 | import { ExceptionData } from '@app/shared/models/error.models'; |
23 | -import { deepClone, deleteNullProperties, guid, isDefined, isDefinedAndNotNull, isUndefined } from '@core/utils'; | 23 | +import { deepClone, deleteNullProperties, guid, isDefined, isDefinedAndNotNull, isUndefined, createLabelFromDatasource } from '@core/utils'; |
24 | import { WindowMessage } from '@shared/models/window-message.model'; | 24 | import { WindowMessage } from '@shared/models/window-message.model'; |
25 | import { TranslateService } from '@ngx-translate/core'; | 25 | import { TranslateService } from '@ngx-translate/core'; |
26 | import { customTranslationsPrefix } from '@app/shared/models/constants'; | 26 | import { customTranslationsPrefix } from '@app/shared/models/constants'; |
@@ -36,7 +36,7 @@ import { Observable, of, ReplaySubject } from 'rxjs'; | @@ -36,7 +36,7 @@ import { Observable, of, ReplaySubject } from 'rxjs'; | ||
36 | 36 | ||
37 | const varsRegex = /\$\{([^}]*)\}/g; | 37 | const varsRegex = /\$\{([^}]*)\}/g; |
38 | 38 | ||
39 | -const predefinedFunctions: {[func: string]: string} = { | 39 | +const predefinedFunctions: { [func: string]: string } = { |
40 | Sin: 'return Math.round(1000*Math.sin(time/5000));', | 40 | Sin: 'return Math.round(1000*Math.sin(time/5000));', |
41 | Cos: 'return Math.round(1000*Math.cos(time/5000));', | 41 | Cos: 'return Math.round(1000*Math.cos(time/5000));', |
42 | Random: 'var value = prevValue + Math.random() * 100 - 50;\n' + | 42 | Random: 'var value = prevValue + Math.random() * 100 - 50;\n' + |
@@ -63,12 +63,12 @@ const defaultAlarmFields: Array<string> = [ | @@ -63,12 +63,12 @@ const defaultAlarmFields: Array<string> = [ | ||
63 | alarmFields.status.keyName | 63 | alarmFields.status.keyName |
64 | ]; | 64 | ]; |
65 | 65 | ||
66 | -const commonMaterialIcons: Array<string> = [ 'more_horiz', 'more_vert', 'open_in_new', | 66 | +const commonMaterialIcons: Array<string> = ['more_horiz', 'more_vert', 'open_in_new', |
67 | 'visibility', 'play_arrow', 'arrow_back', 'arrow_downward', | 67 | 'visibility', 'play_arrow', 'arrow_back', 'arrow_downward', |
68 | 'arrow_forward', 'arrow_upwards', 'close', 'refresh', 'menu', 'show_chart', 'multiline_chart', 'pie_chart', 'insert_chart', 'people', | 68 | 'arrow_forward', 'arrow_upwards', 'close', 'refresh', 'menu', 'show_chart', 'multiline_chart', 'pie_chart', 'insert_chart', 'people', |
69 | 'person', 'domain', 'devices_other', 'now_widgets', 'dashboards', 'map', 'pin_drop', 'my_location', 'extension', 'search', | 69 | 'person', 'domain', 'devices_other', 'now_widgets', 'dashboards', 'map', 'pin_drop', 'my_location', 'extension', 'search', |
70 | 'settings', 'notifications', 'notifications_active', 'info', 'info_outline', 'warning', 'list', 'file_download', 'import_export', | 70 | 'settings', 'notifications', 'notifications_active', 'info', 'info_outline', 'warning', 'list', 'file_download', 'import_export', |
71 | - 'share', 'add', 'edit', 'done' ]; | 71 | + 'share', 'add', 'edit', 'done']; |
72 | 72 | ||
73 | // @dynamic | 73 | // @dynamic |
74 | @Injectable({ | 74 | @Injectable({ |
@@ -101,8 +101,8 @@ export class UtilsService { | @@ -101,8 +101,8 @@ export class UtilsService { | ||
101 | materialIcons: Array<string> = []; | 101 | materialIcons: Array<string> = []; |
102 | 102 | ||
103 | constructor(@Inject(WINDOW) private window: Window, | 103 | constructor(@Inject(WINDOW) private window: Window, |
104 | - private zone: NgZone, | ||
105 | - private translate: TranslateService) { | 104 | + private zone: NgZone, |
105 | + private translate: TranslateService) { | ||
106 | let frame: Element = null; | 106 | let frame: Element = null; |
107 | try { | 107 | try { |
108 | frame = window.frameElement; | 108 | frame = window.frameElement; |
@@ -302,10 +302,10 @@ export class UtilsService { | @@ -302,10 +302,10 @@ export class UtilsService { | ||
302 | .split('\n') | 302 | .split('\n') |
303 | .filter((codepoint) => codepoint && codepoint.length); | 303 | .filter((codepoint) => codepoint && codepoint.length); |
304 | codepointsArray.forEach((codepoint) => { | 304 | codepointsArray.forEach((codepoint) => { |
305 | - const values = codepoint.split(' '); | ||
306 | - if (values && values.length === 2) { | ||
307 | - this.materialIcons.push(values[0]); | ||
308 | - } | 305 | + const values = codepoint.split(' '); |
306 | + if (values && values.length === 2) { | ||
307 | + this.materialIcons.push(values[0]); | ||
308 | + } | ||
309 | }); | 309 | }); |
310 | materialIconsSubject.next(this.materialIcons); | 310 | materialIconsSubject.next(this.materialIcons); |
311 | }); | 311 | }); |
@@ -360,12 +360,12 @@ export class UtilsService { | @@ -360,12 +360,12 @@ export class UtilsService { | ||
360 | } | 360 | } |
361 | 361 | ||
362 | public createAdditionalDataKey(dataKey: DataKey, datasource: Datasource, timeUnit: string, | 362 | public createAdditionalDataKey(dataKey: DataKey, datasource: Datasource, timeUnit: string, |
363 | - datasources: Datasource[], additionalKeysNumber: number): DataKey { | 363 | + datasources: Datasource[], additionalKeysNumber: number): DataKey { |
364 | const additionalDataKey = deepClone(dataKey); | 364 | const additionalDataKey = deepClone(dataKey); |
365 | if (dataKey.settings.comparisonSettings.comparisonValuesLabel) { | 365 | if (dataKey.settings.comparisonSettings.comparisonValuesLabel) { |
366 | - additionalDataKey.label = this.createLabelFromDatasource(datasource, dataKey.settings.comparisonSettings.comparisonValuesLabel); | 366 | + additionalDataKey.label = createLabelFromDatasource(datasource, dataKey.settings.comparisonSettings.comparisonValuesLabel); |
367 | } else { | 367 | } else { |
368 | - additionalDataKey.label = dataKey.label + ' ' + this.translate.instant('legend.comparison-time-ago.'+timeUnit); | 368 | + additionalDataKey.label = dataKey.label + ' ' + this.translate.instant('legend.comparison-time-ago.' + timeUnit); |
369 | } | 369 | } |
370 | additionalDataKey.pattern = additionalDataKey.label; | 370 | additionalDataKey.pattern = additionalDataKey.label; |
371 | if (dataKey.settings.comparisonSettings.color) { | 371 | if (dataKey.settings.comparisonSettings.color) { |
@@ -380,30 +380,7 @@ export class UtilsService { | @@ -380,30 +380,7 @@ export class UtilsService { | ||
380 | } | 380 | } |
381 | 381 | ||
382 | public createLabelFromDatasource(datasource: Datasource, pattern: string) { | 382 | public createLabelFromDatasource(datasource: Datasource, pattern: string) { |
383 | - let label = pattern; | ||
384 | - if (!datasource) { | ||
385 | - return label; | ||
386 | - } | ||
387 | - let match = varsRegex.exec(pattern); | ||
388 | - while (match !== null) { | ||
389 | - const variable = match[0]; | ||
390 | - const variableName = match[1]; | ||
391 | - if (variableName === 'dsName') { | ||
392 | - label = label.split(variable).join(datasource.name); | ||
393 | - } else if (variableName === 'entityName') { | ||
394 | - label = label.split(variable).join(datasource.entityName); | ||
395 | - } else if (variableName === 'deviceName') { | ||
396 | - label = label.split(variable).join(datasource.entityName); | ||
397 | - } else if (variableName === 'entityLabel') { | ||
398 | - label = label.split(variable).join(datasource.entityLabel || datasource.entityName); | ||
399 | - } else if (variableName === 'aliasName') { | ||
400 | - label = label.split(variable).join(datasource.aliasName); | ||
401 | - } else if (variableName === 'entityDescription') { | ||
402 | - label = label.split(variable).join(datasource.entityDescription); | ||
403 | - } | ||
404 | - match = varsRegex.exec(pattern); | ||
405 | - } | ||
406 | - return label; | 383 | + return createLabelFromDatasource(datasource, pattern); |
407 | } | 384 | } |
408 | 385 | ||
409 | public generateColors(datasources: Array<Datasource>) { | 386 | public generateColors(datasources: Array<Datasource>) { |
@@ -456,7 +433,7 @@ export class UtilsService { | @@ -456,7 +433,7 @@ export class UtilsService { | ||
456 | params = urlQueryString + '&' + newParam; | 433 | params = urlQueryString + '&' + newParam; |
457 | } | 434 | } |
458 | } else if (newParam) { | 435 | } else if (newParam) { |
459 | - params = '?' + newParam; | 436 | + params = '?' + newParam; |
460 | } | 437 | } |
461 | this.window.history.replaceState({}, '', baseUrl + params); | 438 | this.window.history.replaceState({}, '', baseUrl + params); |
462 | } | 439 | } |
@@ -18,6 +18,7 @@ import _ from 'lodash'; | @@ -18,6 +18,7 @@ import _ from 'lodash'; | ||
18 | import { Observable, Subject, fromEvent, of } from 'rxjs'; | 18 | import { Observable, Subject, fromEvent, of } from 'rxjs'; |
19 | import { finalize, share, map } from 'rxjs/operators'; | 19 | import { finalize, share, map } from 'rxjs/operators'; |
20 | import base64js from 'base64-js'; | 20 | import base64js from 'base64-js'; |
21 | +import { Datasource } from '@app/shared/models/widget.models'; | ||
21 | 22 | ||
22 | export function onParentScrollOrWindowResize(el: Node): Observable<Event> { | 23 | export function onParentScrollOrWindowResize(el: Node): Observable<Event> { |
23 | const scrollSubject = new Subject<Event>(); | 24 | const scrollSubject = new Subject<Event>(); |
@@ -435,6 +436,34 @@ export function imageLoader(imageUrl: string): Observable<HTMLImageElement> { | @@ -435,6 +436,34 @@ export function imageLoader(imageUrl: string): Observable<HTMLImageElement> { | ||
435 | return imageLoad$; | 436 | return imageLoad$; |
436 | } | 437 | } |
437 | 438 | ||
439 | +export function createLabelFromDatasource(datasource: Datasource, pattern: string) { | ||
440 | + const varsRegex = /\$\{([^}]*)\}/g; | ||
441 | + let label = pattern; | ||
442 | + if (!datasource) { | ||
443 | + return label; | ||
444 | + } | ||
445 | + let match = varsRegex.exec(pattern); | ||
446 | + while (match !== null) { | ||
447 | + const variable = match[0]; | ||
448 | + const variableName = match[1]; | ||
449 | + if (variableName === 'dsName') { | ||
450 | + label = label.split(variable).join(datasource.name); | ||
451 | + } else if (variableName === 'entityName') { | ||
452 | + label = label.split(variable).join(datasource.entityName); | ||
453 | + } else if (variableName === 'deviceName') { | ||
454 | + label = label.split(variable).join(datasource.entityName); | ||
455 | + } else if (variableName === 'entityLabel') { | ||
456 | + label = label.split(variable).join(datasource.entityLabel || datasource.entityName); | ||
457 | + } else if (variableName === 'aliasName') { | ||
458 | + label = label.split(variable).join(datasource.aliasName); | ||
459 | + } else if (variableName === 'entityDescription') { | ||
460 | + label = label.split(variable).join(datasource.entityDescription); | ||
461 | + } | ||
462 | + match = varsRegex.exec(pattern); | ||
463 | + } | ||
464 | + return label; | ||
465 | +} | ||
466 | + | ||
438 | const imageAspectMap = {}; | 467 | const imageAspectMap = {}; |
439 | 468 | ||
440 | export function aspectCache(imageUrl: string): Observable<number> { | 469 | export function aspectCache(imageUrl: string): Observable<number> { |
@@ -452,7 +481,6 @@ export function aspectCache(imageUrl: string): Observable<number> { | @@ -452,7 +481,6 @@ export function aspectCache(imageUrl: string): Observable<number> { | ||
452 | } | 481 | } |
453 | } | 482 | } |
454 | 483 | ||
455 | - | ||
456 | export function parseArray(input: any[]): any[] { | 484 | export function parseArray(input: any[]): any[] { |
457 | return _(input).groupBy(el => el?.datasource?.entityName) | 485 | return _(input).groupBy(el => el?.datasource?.entityName) |
458 | .values().value().map((entityArray, dsIndex) => | 486 | .values().value().map((entityArray, dsIndex) => |
@@ -523,15 +551,18 @@ export function parseFunction(source: any, params: string[] = ['def']): Function | @@ -523,15 +551,18 @@ export function parseFunction(source: any, params: string[] = ['def']): Function | ||
523 | return res; | 551 | return res; |
524 | } | 552 | } |
525 | 553 | ||
526 | -export function parseTemplate(template: string, data: object, translateFn?: (key: string) => string) { | 554 | +export function parseTemplate(template: string, data: { $datasource?: Datasource, [key: string]: any }, |
555 | + translateFn?: (key: string) => string) { | ||
527 | let res = ''; | 556 | let res = ''; |
528 | try { | 557 | try { |
529 | if (template.match(/<link-act/g)) { | 558 | if (template.match(/<link-act/g)) { |
530 | - template = template.replace(/<link-act/g, '<a').replace(/link-act>/g, 'a>').replace(/name=(\'|")(.*?)(\'|")/g, `class='tb-custom-action' id='$2'`); | 559 | + template = template.replace(/<link-act/g, '<a').replace(/link-act>/g, 'a>') |
560 | + .replace(/name=(\'|")(.*?)(\'|")/g, `class='tb-custom-action' id='$2'`); | ||
531 | } | 561 | } |
532 | if (translateFn) { | 562 | if (translateFn) { |
533 | template = translateFn(template); | 563 | template = translateFn(template); |
534 | } | 564 | } |
565 | + template = createLabelFromDatasource(data.$datasource, template); | ||
535 | const formatted = template.match(/\$\{([^}]*)\:\d*\}/g); | 566 | const formatted = template.match(/\$\{([^}]*)\:\d*\}/g); |
536 | if (formatted) | 567 | if (formatted) |
537 | formatted.forEach(value => { | 568 | formatted.forEach(value => { |
@@ -33,7 +33,7 @@ import { Datasource, WidgetActionDescriptor, WidgetConfig } from '@shared/models | @@ -33,7 +33,7 @@ import { Datasource, WidgetActionDescriptor, WidgetConfig } from '@shared/models | ||
33 | import { IWidgetSubscription } from '@core/api/widget-api.models'; | 33 | import { IWidgetSubscription } from '@core/api/widget-api.models'; |
34 | import { UtilsService } from '@core/services/utils.service'; | 34 | import { UtilsService } from '@core/services/utils.service'; |
35 | import { TranslateService } from '@ngx-translate/core'; | 35 | import { TranslateService } from '@ngx-translate/core'; |
36 | -import { deepClone, isDefined, isNumber } from '@core/utils'; | 36 | +import { deepClone, isDefined, isNumber, createLabelFromDatasource } from '@core/utils'; |
37 | import cssjs from '@core/css/css'; | 37 | import cssjs from '@core/css/css'; |
38 | import { PageLink } from '@shared/models/page/page-link'; | 38 | import { PageLink } from '@shared/models/page/page-link'; |
39 | import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order'; | 39 | import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order'; |
@@ -282,7 +282,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, | @@ -282,7 +282,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, | ||
282 | alarmsTitle = this.translate.instant('alarm.alarms'); | 282 | alarmsTitle = this.translate.instant('alarm.alarms'); |
283 | } | 283 | } |
284 | 284 | ||
285 | - this.ctx.widgetTitle = this.utils.createLabelFromDatasource(this.alarmSource, alarmsTitle); | 285 | + this.ctx.widgetTitle = createLabelFromDatasource(this.alarmSource, alarmsTitle); |
286 | 286 | ||
287 | this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : true; | 287 | this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : true; |
288 | if (!this.allowAcknowledgment && !this.allowClear) { | 288 | if (!this.allowAcknowledgment && !this.allowClear) { |
@@ -39,7 +39,7 @@ import { | @@ -39,7 +39,7 @@ import { | ||
39 | import { IWidgetSubscription } from '@core/api/widget-api.models'; | 39 | import { IWidgetSubscription } from '@core/api/widget-api.models'; |
40 | import { UtilsService } from '@core/services/utils.service'; | 40 | import { UtilsService } from '@core/services/utils.service'; |
41 | import { TranslateService } from '@ngx-translate/core'; | 41 | import { TranslateService } from '@ngx-translate/core'; |
42 | -import { deepClone, isDefined, isNumber } from '@core/utils'; | 42 | +import { deepClone, isDefined, isNumber, createLabelFromDatasource } from '@core/utils'; |
43 | import cssjs from '@core/css/css'; | 43 | import cssjs from '@core/css/css'; |
44 | import { PageLink } from '@shared/models/page/page-link'; | 44 | import { PageLink } from '@shared/models/page/page-link'; |
45 | import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order'; | 45 | import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order'; |
@@ -210,7 +210,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni | @@ -210,7 +210,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni | ||
210 | } | 210 | } |
211 | 211 | ||
212 | const datasource = this.subscription.datasources[0]; | 212 | const datasource = this.subscription.datasources[0]; |
213 | - this.ctx.widgetTitle = this.utils.createLabelFromDatasource(datasource, entitiesTitle); | 213 | + this.ctx.widgetTitle = createLabelFromDatasource(datasource, entitiesTitle); |
214 | 214 | ||
215 | this.searchAction.show = isDefined(this.settings.enableSearch) ? this.settings.enableSearch : true; | 215 | this.searchAction.show = isDefined(this.settings.enableSearch) ? this.settings.enableSearch : true; |
216 | this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true; | 216 | this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true; |
@@ -26,6 +26,7 @@ import { filter } from 'rxjs/operators'; | @@ -26,6 +26,7 @@ import { filter } from 'rxjs/operators'; | ||
26 | import { Polyline } from './polyline'; | 26 | import { Polyline } from './polyline'; |
27 | import { Polygon } from './polygon'; | 27 | import { Polygon } from './polygon'; |
28 | import { DatasourceData } from '@app/shared/models/widget.models'; | 28 | import { DatasourceData } from '@app/shared/models/widget.models'; |
29 | +import { safeExecute } from '@app/core/utils'; | ||
29 | 30 | ||
30 | export default abstract class LeafletMap { | 31 | export default abstract class LeafletMap { |
31 | 32 | ||
@@ -87,12 +88,14 @@ export default abstract class LeafletMap { | @@ -87,12 +88,14 @@ export default abstract class LeafletMap { | ||
87 | if (this.options.draggableMarker) { | 88 | if (this.options.draggableMarker) { |
88 | let mousePositionOnMap: L.LatLng; | 89 | let mousePositionOnMap: L.LatLng; |
89 | let addMarker: L.Control; | 90 | let addMarker: L.Control; |
90 | - this.map.on('mouseup', (e: L.LeafletMouseEvent) => { | 91 | + this.map.on('mousemove', (e: L.LeafletMouseEvent) => { |
91 | mousePositionOnMap = e.latlng; | 92 | mousePositionOnMap = e.latlng; |
92 | }); | 93 | }); |
93 | const dragListener = (e: L.DragEndEvent) => { | 94 | const dragListener = (e: L.DragEndEvent) => { |
94 | if (e.type === 'dragend' && mousePositionOnMap) { | 95 | if (e.type === 'dragend' && mousePositionOnMap) { |
95 | - const newMarker = L.marker(mousePositionOnMap).addTo(this.map); | 96 | + const icon = new L.Icon.Default(); |
97 | + icon.options.shadowSize = [0, 0]; | ||
98 | + const newMarker = L.marker(mousePositionOnMap, { icon }).addTo(this.map); | ||
96 | const datasourcesList = document.createElement('div'); | 99 | const datasourcesList = document.createElement('div'); |
97 | const customLatLng = this.convertToCustomFormat(mousePositionOnMap); | 100 | const customLatLng = this.convertToCustomFormat(mousePositionOnMap); |
98 | this.datasources.forEach(ds => { | 101 | this.datasources.forEach(ds => { |
@@ -195,15 +198,18 @@ export default abstract class LeafletMap { | @@ -195,15 +198,18 @@ export default abstract class LeafletMap { | ||
195 | 198 | ||
196 | fitBounds(bounds: LatLngBounds, useDefaultZoom = false, padding?: LatLngTuple) { | 199 | fitBounds(bounds: LatLngBounds, useDefaultZoom = false, padding?: LatLngTuple) { |
197 | if (bounds.isValid()) { | 200 | if (bounds.isValid()) { |
198 | - if ((!this.options.fitMapBounds || useDefaultZoom) && this.options.defaultZoomLevel) { | 201 | + if ((!this.options.fitMapBounds || this.options.useDefaultCenterPosition) && this.options.defaultZoomLevel) { |
199 | this.map.setZoom(this.options.defaultZoomLevel, { animate: false }); | 202 | this.map.setZoom(this.options.defaultZoomLevel, { animate: false }); |
200 | - this.map.panTo(bounds.getCenter(), { animate: false }); | 203 | + this.map.panTo(this.options.defaultCenterPosition, { animate: false }); |
201 | } else { | 204 | } else { |
202 | this.map.once('zoomend', () => { | 205 | this.map.once('zoomend', () => { |
203 | if (!this.options.defaultZoomLevel && this.map.getZoom() > this.options.minZoomLevel) { | 206 | if (!this.options.defaultZoomLevel && this.map.getZoom() > this.options.minZoomLevel) { |
204 | this.map.setZoom(this.options.minZoomLevel, { animate: false }); | 207 | this.map.setZoom(this.options.minZoomLevel, { animate: false }); |
205 | } | 208 | } |
206 | }); | 209 | }); |
210 | + if (this.options.useDefaultCenterPosition) { | ||
211 | + bounds = bounds.extend(this.options.defaultCenterPosition); | ||
212 | + } | ||
207 | this.map.fitBounds(bounds, { padding: padding || [50, 50], animate: false }); | 213 | this.map.fitBounds(bounds, { padding: padding || [50, 50], animate: false }); |
208 | } | 214 | } |
209 | this.bounds = bounds; | 215 | this.bounds = bounds; |
@@ -231,8 +237,16 @@ export default abstract class LeafletMap { | @@ -231,8 +237,16 @@ export default abstract class LeafletMap { | ||
231 | updateMarkers(markersData) { | 237 | updateMarkers(markersData) { |
232 | markersData.filter(mdata => !!this.convertPosition(mdata)).forEach(data => { | 238 | markersData.filter(mdata => !!this.convertPosition(mdata)).forEach(data => { |
233 | if (data.rotationAngle || data.rotationAngle === 0) { | 239 | if (data.rotationAngle || data.rotationAngle === 0) { |
240 | + const currentImage = this.options.useMarkerImageFunction ? | ||
241 | + safeExecute(this.options.markerImageFunction, | ||
242 | + [data, this.options.markerImages, markersData, data.dsIndex]) : this.options.currentImage; | ||
243 | + const style = currentImage ? 'background-image: url(' + currentImage.url + ');' : ''; | ||
234 | this.options.icon = L.divIcon({ | 244 | this.options.icon = L.divIcon({ |
235 | - html: `<div class="arrow" style="transform: translate(-10px, -10px) rotate(${data.rotationAngle}deg);"><div>` | 245 | + html: `<div class="arrow" |
246 | + style="transform: translate(-10px, -10px); | ||
247 | + ${style} | ||
248 | + rotate(${data.rotationAngle}deg); | ||
249 | + "><div>` | ||
236 | }) | 250 | }) |
237 | } | 251 | } |
238 | else { | 252 | else { |
@@ -335,31 +349,28 @@ export default abstract class LeafletMap { | @@ -335,31 +349,28 @@ export default abstract class LeafletMap { | ||
335 | data.data = JSON.parse(data.data[0][1]) as LatLngTuple[]; | 349 | data.data = JSON.parse(data.data[0][1]) as LatLngTuple[]; |
336 | } | 350 | } |
337 | if (this.polygons.get(data.datasource.entityName)) { | 351 | if (this.polygons.get(data.datasource.entityName)) { |
338 | - this.updatePolygon(data.datasource.entityName, data.data, polyData, this.options); | 352 | + this.updatePolygon(data, polyData, this.options); |
339 | } | 353 | } |
340 | else { | 354 | else { |
341 | - this.createPolygon(data.datasource.entityName, data.data, polyData, this.options); | 355 | + this.createPolygon(data, polyData, this.options); |
342 | } | 356 | } |
343 | } | 357 | } |
344 | }); | 358 | }); |
345 | } | 359 | } |
346 | 360 | ||
347 | - createPolygon(key: string, data: LatLngTuple[], dataSources: DatasourceData[], settings: PolygonSettings) { | 361 | + createPolygon(polyData: DatasourceData, dataSources: DatasourceData[], settings: PolygonSettings) { |
348 | this.ready$.subscribe(() => { | 362 | this.ready$.subscribe(() => { |
349 | - const polygon = new Polygon(this.map, data, dataSources, settings); | 363 | + const polygon = new Polygon(this.map, polyData, dataSources, settings); |
350 | const bounds = this.bounds.extend(polygon.leafletPoly.getBounds()); | 364 | const bounds = this.bounds.extend(polygon.leafletPoly.getBounds()); |
351 | - if (bounds.isValid()) { | ||
352 | - this.map.fitBounds(bounds); | ||
353 | - this.bounds = bounds; | ||
354 | - } | ||
355 | - this.polygons.set(key, polygon); | 365 | + this.fitBounds(bounds); |
366 | + this.polygons.set(polyData.datasource.entityName, polygon); | ||
356 | }); | 367 | }); |
357 | } | 368 | } |
358 | 369 | ||
359 | - updatePolygon(key: string, data: LatLngTuple[], dataSources: DatasourceData[], settings: PolygonSettings) { | 370 | + updatePolygon(polyData: DatasourceData, dataSources: DatasourceData[], settings: PolygonSettings) { |
360 | this.ready$.subscribe(() => { | 371 | this.ready$.subscribe(() => { |
361 | - const poly = this.polygons.get(key); | ||
362 | - poly.updatePolygon(data, dataSources, settings); | 372 | + const poly = this.polygons.get(polyData.datasource.entityName); |
373 | + poly.updatePolygon(polyData.data, dataSources, settings); | ||
363 | this.fitBounds(poly.leafletPoly.getBounds()); | 374 | this.fitBounds(poly.leafletPoly.getBounds()); |
364 | }); | 375 | }); |
365 | } | 376 | } |
@@ -111,9 +111,13 @@ export type PolygonSettings = { | @@ -111,9 +111,13 @@ export type PolygonSettings = { | ||
111 | polygonStrokeWeight: number; | 111 | polygonStrokeWeight: number; |
112 | polygonStrokeColor: string; | 112 | polygonStrokeColor: string; |
113 | polygonColor: string; | 113 | polygonColor: string; |
114 | + showPolygonTooltip: boolean; | ||
114 | autocloseTooltip: boolean; | 115 | autocloseTooltip: boolean; |
116 | + tooltipFunction: GenericFunction; | ||
115 | showTooltipAction: string; | 117 | showTooltipAction: string; |
116 | tooltipAction: object; | 118 | tooltipAction: object; |
119 | + tooltipPattern: string; | ||
120 | + useTooltipFunction: boolean; | ||
117 | polygonClick: { [name: string]: actionsHandler }; | 121 | polygonClick: { [name: string]: actionsHandler }; |
118 | polygonColorFunction?: GenericFunction; | 122 | polygonColorFunction?: GenericFunction; |
119 | } | 123 | } |
@@ -16,8 +16,9 @@ | @@ -16,8 +16,9 @@ | ||
16 | 16 | ||
17 | import L, { LatLngExpression, LatLngTuple } from 'leaflet'; | 17 | import L, { LatLngExpression, LatLngTuple } from 'leaflet'; |
18 | import { createTooltip } from './maps-utils'; | 18 | import { createTooltip } from './maps-utils'; |
19 | -import { PolygonSettings } from './map-models'; | 19 | +import { PolygonSettings, FormattedData } from './map-models'; |
20 | import { DatasourceData } from '@app/shared/models/widget.models'; | 20 | import { DatasourceData } from '@app/shared/models/widget.models'; |
21 | +import { safeExecute, parseWithTranslation } from '@app/core/utils'; | ||
21 | 22 | ||
22 | export class Polygon { | 23 | export class Polygon { |
23 | 24 | ||
@@ -26,8 +27,8 @@ export class Polygon { | @@ -26,8 +27,8 @@ export class Polygon { | ||
26 | data; | 27 | data; |
27 | dataSources; | 28 | dataSources; |
28 | 29 | ||
29 | - constructor(public map, coordinates, dataSources, settings: PolygonSettings, onClickListener?) { | ||
30 | - this.leafletPoly = L.polygon(coordinates, { | 30 | + constructor(public map, polyData: DatasourceData, dataSources, private settings: PolygonSettings, onClickListener?) { |
31 | + this.leafletPoly = L.polygon(polyData.data, { | ||
31 | fill: true, | 32 | fill: true, |
32 | fillColor: settings.polygonColor, | 33 | fillColor: settings.polygonColor, |
33 | color: settings.polygonStrokeColor, | 34 | color: settings.polygonStrokeColor, |
@@ -35,19 +36,29 @@ export class Polygon { | @@ -35,19 +36,29 @@ export class Polygon { | ||
35 | fillOpacity: settings.polygonOpacity, | 36 | fillOpacity: settings.polygonOpacity, |
36 | opacity: settings.polygonStrokeOpacity | 37 | opacity: settings.polygonStrokeOpacity |
37 | }).addTo(this.map); | 38 | }).addTo(this.map); |
38 | - | ||
39 | - if (settings.showTooltip) { | 39 | + this.dataSources = dataSources; |
40 | + this.data = polyData; | ||
41 | + if (settings.showPolygonTooltip) { | ||
40 | this.tooltip = createTooltip(this.leafletPoly, settings); | 42 | this.tooltip = createTooltip(this.leafletPoly, settings); |
43 | + this.updateTooltip(polyData); | ||
41 | } | 44 | } |
42 | if (onClickListener) { | 45 | if (onClickListener) { |
43 | this.leafletPoly.on('click', onClickListener); | 46 | this.leafletPoly.on('click', onClickListener); |
44 | } | 47 | } |
45 | } | 48 | } |
46 | 49 | ||
50 | + updateTooltip(data: DatasourceData) { | ||
51 | + const pattern = this.settings.useTooltipFunction ? | ||
52 | + safeExecute(this.settings.tooltipFunction, [this.data, this.dataSources, this.data.dsIndex]) : this.settings.tooltipPattern; | ||
53 | + this.tooltip.setContent(parseWithTranslation.parseTemplate(pattern, data, true)); | ||
54 | + } | ||
55 | + | ||
47 | updatePolygon(data: LatLngTuple[], dataSources: DatasourceData[], settings: PolygonSettings) { | 56 | updatePolygon(data: LatLngTuple[], dataSources: DatasourceData[], settings: PolygonSettings) { |
48 | this.data = data; | 57 | this.data = data; |
49 | this.dataSources = dataSources; | 58 | this.dataSources = dataSources; |
50 | this.leafletPoly.setLatLngs(data); | 59 | this.leafletPoly.setLatLngs(data); |
60 | + if (settings.showPolygonTooltip) | ||
61 | + this.updateTooltip(this.data); | ||
51 | this.updatePolygonColor(settings); | 62 | this.updatePolygonColor(settings); |
52 | } | 63 | } |
53 | 64 |
@@ -477,6 +477,11 @@ export const mapPolygonSchema = | @@ -477,6 +477,11 @@ export const mapPolygonSchema = | ||
477 | type: 'number', | 477 | type: 'number', |
478 | default: 1 | 478 | default: 1 |
479 | }, | 479 | }, |
480 | + showPolygonTooltip: { | ||
481 | + title: 'Show polygon tooltip', | ||
482 | + type: 'boolean', | ||
483 | + default: false | ||
484 | + }, | ||
480 | usePolygonColorFunction: { | 485 | usePolygonColorFunction: { |
481 | title: 'Use polygon color function', | 486 | title: 'Use polygon color function', |
482 | type: 'boolean', | 487 | type: 'boolean', |
@@ -501,7 +506,7 @@ export const mapPolygonSchema = | @@ -501,7 +506,7 @@ export const mapPolygonSchema = | ||
501 | key: 'polygonStrokeColor', | 506 | key: 'polygonStrokeColor', |
502 | type: 'color' | 507 | type: 'color' |
503 | }, | 508 | }, |
504 | - 'polygonStrokeOpacity', 'polygonStrokeWeight', 'usePolygonColorFunction', | 509 | + 'polygonStrokeOpacity', 'polygonStrokeWeight', 'usePolygonColorFunction', 'showPolygonTooltip', |
505 | { | 510 | { |
506 | key: 'polygonColorFunction', | 511 | key: 'polygonColorFunction', |
507 | type: 'javascript' | 512 | type: 'javascript' |
@@ -1137,7 +1142,7 @@ export const tripAnimationSchema = { | @@ -1137,7 +1142,7 @@ export const tripAnimationSchema = { | ||
1137 | rotationAngle: { | 1142 | rotationAngle: { |
1138 | title: 'Set additional rotation angle for marker (deg)', | 1143 | title: 'Set additional rotation angle for marker (deg)', |
1139 | type: 'number', | 1144 | type: 'number', |
1140 | - default: 180 | 1145 | + default: 0 |
1141 | }, | 1146 | }, |
1142 | useMarkerImageFunction: { | 1147 | useMarkerImageFunction: { |
1143 | title: 'Use marker image function', | 1148 | title: 'Use marker image function', |
@@ -24,7 +24,7 @@ import { UtilsService } from '@core/services/utils.service'; | @@ -24,7 +24,7 @@ import { UtilsService } from '@core/services/utils.service'; | ||
24 | import { TranslateService } from '@ngx-translate/core'; | 24 | import { TranslateService } from '@ngx-translate/core'; |
25 | import { DataKey, Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models'; | 25 | import { DataKey, Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models'; |
26 | import { IWidgetSubscription } from '@core/api/widget-api.models'; | 26 | import { IWidgetSubscription } from '@core/api/widget-api.models'; |
27 | -import { isDefined, isEqual, isUndefined } from '@core/utils'; | 27 | +import { isDefined, isEqual, isUndefined, createLabelFromDatasource } from '@core/utils'; |
28 | import { EntityType } from '@shared/models/entity-type.models'; | 28 | import { EntityType } from '@shared/models/entity-type.models'; |
29 | import * as _moment from 'moment'; | 29 | import * as _moment from 'moment'; |
30 | import { FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; | 30 | import { FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; |
@@ -331,7 +331,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni | @@ -331,7 +331,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni | ||
331 | } | 331 | } |
332 | 332 | ||
333 | public getGroupTitle(datasource: Datasource): string { | 333 | public getGroupTitle(datasource: Datasource): string { |
334 | - return this.utils.createLabelFromDatasource(datasource, this.settings.groupTitle); | 334 | + return createLabelFromDatasource(datasource, this.settings.groupTitle); |
335 | } | 335 | } |
336 | 336 | ||
337 | public visibleKeys(source: MultipleInputWidgetSource): MultipleInputWidgetDataKey[] { | 337 | public visibleKeys(source: MultipleInputWidgetSource): MultipleInputWidgetDataKey[] { |