Commit b86c5e61e1168e5cfa49eaf9350aa211c7b409b4
1 parent
0206a8ab
Image map fixes and improvements. Fixed state chart subscription.
Showing
9 changed files
with
122 additions
and
89 deletions
@@ -314,7 +314,7 @@ export class DatasourceSubscription { | @@ -314,7 +314,7 @@ export class DatasourceSubscription { | ||
314 | }); | 314 | }); |
315 | stateDataReceived = true; | 315 | stateDataReceived = true; |
316 | } else { | 316 | } else { |
317 | - firstStateData = data; | 317 | + firstStateData = subscriptionUpdate; |
318 | } | 318 | } |
319 | } else { | 319 | } else { |
320 | if (subsTw.aggregation.stateData && !stateDataReceived) { | 320 | if (subsTw.aggregation.stateData && !stateDataReceived) { |
@@ -33,6 +33,7 @@ import { filter } from 'rxjs/operators'; | @@ -33,6 +33,7 @@ import { filter } from 'rxjs/operators'; | ||
33 | import { Polyline } from './polyline'; | 33 | import { Polyline } from './polyline'; |
34 | import { Polygon } from './polygon'; | 34 | import { Polygon } from './polygon'; |
35 | import { createTooltip, safeExecute } from '@home/components/widget/lib/maps/maps-utils'; | 35 | import { createTooltip, safeExecute } from '@home/components/widget/lib/maps/maps-utils'; |
36 | +import { WidgetContext } from '@home/models/widget-component.models'; | ||
36 | 37 | ||
37 | export default abstract class LeafletMap { | 38 | export default abstract class LeafletMap { |
38 | 39 | ||
@@ -49,7 +50,9 @@ export default abstract class LeafletMap { | @@ -49,7 +50,9 @@ export default abstract class LeafletMap { | ||
49 | points: FeatureGroup; | 50 | points: FeatureGroup; |
50 | markersData: FormattedData[] = []; | 51 | markersData: FormattedData[] = []; |
51 | 52 | ||
52 | - protected constructor(public $container: HTMLElement, options: UnitedMapSettings) { | 53 | + protected constructor(public ctx: WidgetContext, |
54 | + public $container: HTMLElement, | ||
55 | + options: UnitedMapSettings) { | ||
53 | this.options = options; | 56 | this.options = options; |
54 | } | 57 | } |
55 | 58 | ||
@@ -341,9 +344,6 @@ export default abstract class LeafletMap { | @@ -341,9 +344,6 @@ export default abstract class LeafletMap { | ||
341 | }); | 344 | }); |
342 | } | 345 | } |
343 | 346 | ||
344 | - setImageAlias(alias: Observable<any>) { | ||
345 | - } | ||
346 | - | ||
347 | // Polyline | 347 | // Polyline |
348 | 348 | ||
349 | updatePolylines(polyData: FormattedData[][], data?: FormattedData) { | 349 | updatePolylines(polyData: FormattedData[][], data?: FormattedData) { |
@@ -165,6 +165,12 @@ export interface HistorySelectSettings { | @@ -165,6 +165,12 @@ export interface HistorySelectSettings { | ||
165 | buttonColor: string; | 165 | buttonColor: string; |
166 | } | 166 | } |
167 | 167 | ||
168 | +export interface MapImage { | ||
169 | + imageUrl: string; | ||
170 | + aspect: number; | ||
171 | + update?: boolean; | ||
172 | +} | ||
173 | + | ||
168 | export type TripAnimationSettings = { | 174 | export type TripAnimationSettings = { |
169 | showPoints: boolean; | 175 | showPoints: boolean; |
170 | pointColor: string; | 176 | pointColor: string; |
@@ -17,26 +17,18 @@ | @@ -17,26 +17,18 @@ | ||
17 | import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models'; | 17 | import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models'; |
18 | import LeafletMap from './leaflet-map'; | 18 | import LeafletMap from './leaflet-map'; |
19 | import { | 19 | import { |
20 | - commonMapSettingsSchema, | ||
21 | - mapPolygonSchema, | ||
22 | - mapProviderSchema, | ||
23 | - markerClusteringSettingsSchema, | ||
24 | - markerClusteringSettingsSchemaLeaflet, | ||
25 | - routeMapSettingsSchema | 20 | + commonMapSettingsSchema, |
21 | + mapPolygonSchema, | ||
22 | + mapProviderSchema, | ||
23 | + markerClusteringSettingsSchema, | ||
24 | + markerClusteringSettingsSchemaLeaflet, | ||
25 | + routeMapSettingsSchema | ||
26 | } from './schemes'; | 26 | } from './schemes'; |
27 | import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; | 27 | import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; |
28 | import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils'; | 28 | import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils'; |
29 | -import { of, Subject } from 'rxjs'; | ||
30 | import { WidgetContext } from '@app/modules/home/models/widget-component.models'; | 29 | import { WidgetContext } from '@app/modules/home/models/widget-component.models'; |
31 | import { getDefCenterPosition, parseArray, parseData, parseFunction, parseWithTranslation } from './maps-utils'; | 30 | import { getDefCenterPosition, parseArray, parseData, parseFunction, parseWithTranslation } from './maps-utils'; |
32 | -import { | ||
33 | - Datasource, | ||
34 | - DatasourceType, | ||
35 | - JsonSettingsSchema, | ||
36 | - WidgetActionDescriptor, | ||
37 | - widgetType, | ||
38 | - DatasourceData | ||
39 | -} from '@shared/models/widget.models'; | 31 | +import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models'; |
40 | import { EntityId } from '@shared/models/id/entity-id'; | 32 | import { EntityId } from '@shared/models/id/entity-id'; |
41 | import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; | 33 | import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; |
42 | import { AttributeService } from '@core/http/attribute.service'; | 34 | import { AttributeService } from '@core/http/attribute.service'; |
@@ -76,8 +68,7 @@ export class MapWidgetController implements MapWidgetInterface { | @@ -76,8 +68,7 @@ export class MapWidgetController implements MapWidgetInterface { | ||
76 | return; | 68 | return; |
77 | } | 69 | } |
78 | parseWithTranslation.setTranslate(this.translate); | 70 | parseWithTranslation.setTranslate(this.translate); |
79 | - this.map = new MapClass($element, this.settings, this.ctx.$injector); | ||
80 | - this.map.setImageAlias(this.subscribeForImageAttribute()); | 71 | + this.map = new MapClass(this.ctx, $element, this.settings, this.ctx.$injector); |
81 | this.map.saveMarkerLocation = this.setMarkerLocation; | 72 | this.map.saveMarkerLocation = this.setMarkerLocation; |
82 | if (this.settings.draggableMarker) { | 73 | if (this.settings.draggableMarker) { |
83 | this.map.setDataSources(parseData(this.data)); | 74 | this.map.setDataSources(parseData(this.data)); |
@@ -263,48 +254,6 @@ export class MapWidgetController implements MapWidgetInterface { | @@ -263,48 +254,6 @@ export class MapWidgetController implements MapWidgetInterface { | ||
263 | this.map.onResize(); | 254 | this.map.onResize(); |
264 | } | 255 | } |
265 | 256 | ||
266 | - subscribeForImageAttribute() { | ||
267 | - const imageEntityAlias = this.settings.imageEntityAlias; | ||
268 | - const imageUrlAttribute = this.settings.imageUrlAttribute; | ||
269 | - if (!imageEntityAlias || !imageUrlAttribute) { | ||
270 | - return of(false); | ||
271 | - } | ||
272 | - const entityAliasId = this.ctx.aliasController.getEntityAliasId(imageEntityAlias); | ||
273 | - if (!entityAliasId) { | ||
274 | - return of(false); | ||
275 | - } | ||
276 | - const datasources = [ | ||
277 | - { | ||
278 | - type: DatasourceType.entity, | ||
279 | - name: imageEntityAlias, | ||
280 | - aliasName: imageEntityAlias, | ||
281 | - entityAliasId, | ||
282 | - dataKeys: [ | ||
283 | - { | ||
284 | - type: DataKeyType.attribute, | ||
285 | - name: imageUrlAttribute, | ||
286 | - label: imageUrlAttribute, | ||
287 | - settings: {}, | ||
288 | - _hash: Math.random() | ||
289 | - } | ||
290 | - ] | ||
291 | - } | ||
292 | - ]; | ||
293 | - const result = new Subject(); | ||
294 | - const imageUrlSubscriptionOptions = { | ||
295 | - datasources, | ||
296 | - useDashboardTimewindow: false, | ||
297 | - type: widgetType.latest, | ||
298 | - callbacks: { | ||
299 | - onDataUpdated: (subscription) => { | ||
300 | - result.next(subscription?.data[0]?.data[0]); | ||
301 | - } | ||
302 | - } | ||
303 | - }; | ||
304 | - this.ctx.subscriptionApi.createSubscription(imageUrlSubscriptionOptions, true).subscribe(() => { }); | ||
305 | - return result; | ||
306 | - } | ||
307 | - | ||
308 | onDestroy() { | 257 | onDestroy() { |
309 | } | 258 | } |
310 | } | 259 | } |
@@ -21,6 +21,7 @@ import { UnitedMapSettings } from '../map-models'; | @@ -21,6 +21,7 @@ import { UnitedMapSettings } from '../map-models'; | ||
21 | import 'leaflet.gridlayer.googlemutant'; | 21 | import 'leaflet.gridlayer.googlemutant'; |
22 | import { ResourcesService } from '@core/services/resources.service'; | 22 | import { ResourcesService } from '@core/services/resources.service'; |
23 | import { Injector } from '@angular/core'; | 23 | import { Injector } from '@angular/core'; |
24 | +import { WidgetContext } from '@home/models/widget-component.models'; | ||
24 | 25 | ||
25 | const gmGlobals: GmGlobal = {}; | 26 | const gmGlobals: GmGlobal = {}; |
26 | 27 | ||
@@ -31,8 +32,8 @@ interface GmGlobal { | @@ -31,8 +32,8 @@ interface GmGlobal { | ||
31 | export class GoogleMap extends LeafletMap { | 32 | export class GoogleMap extends LeafletMap { |
32 | private resource: ResourcesService; | 33 | private resource: ResourcesService; |
33 | 34 | ||
34 | - constructor($container, options: UnitedMapSettings, private injector: Injector) { | ||
35 | - super($container, options); | 35 | + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings, private injector: Injector) { |
36 | + super(ctx, $container, options); | ||
36 | this.resource = injector.get(ResourcesService); | 37 | this.resource = injector.get(ResourcesService); |
37 | this.loadGoogle(() => { | 38 | this.loadGoogle(() => { |
38 | const map = L.map($container, {attributionControl: false}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); | 39 | const map = L.map($container, {attributionControl: false}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); |
@@ -17,10 +17,11 @@ | @@ -17,10 +17,11 @@ | ||
17 | import L from 'leaflet'; | 17 | import L from 'leaflet'; |
18 | import LeafletMap from '../leaflet-map'; | 18 | import LeafletMap from '../leaflet-map'; |
19 | import { UnitedMapSettings } from '../map-models'; | 19 | import { UnitedMapSettings } from '../map-models'; |
20 | +import { WidgetContext } from '@home/models/widget-component.models'; | ||
20 | 21 | ||
21 | export class HEREMap extends LeafletMap { | 22 | export class HEREMap extends LeafletMap { |
22 | - constructor($container, options: UnitedMapSettings) { | ||
23 | - super($container, options); | 23 | + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { |
24 | + super(ctx, $container, options); | ||
24 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); | 25 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); |
25 | const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials); | 26 | const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials); |
26 | tileLayer.addTo(map); | 27 | tileLayer.addTo(map); |
@@ -14,12 +14,16 @@ | @@ -14,12 +14,16 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import L, { LatLngLiteral, LatLngBounds, LatLngTuple } from 'leaflet'; | 17 | +import L, { LatLngBounds, LatLngLiteral, LatLngTuple } from 'leaflet'; |
18 | import LeafletMap from '../leaflet-map'; | 18 | import LeafletMap from '../leaflet-map'; |
19 | -import { UnitedMapSettings, PosFuncton } from '../map-models'; | ||
20 | -import { Observable } from 'rxjs'; | ||
21 | -import { map, filter, switchMap } from 'rxjs/operators'; | 19 | +import { MapImage, PosFuncton, UnitedMapSettings } from '../map-models'; |
20 | +import { Observable, ReplaySubject } from 'rxjs'; | ||
21 | +import { filter, map, mergeMap } from 'rxjs/operators'; | ||
22 | import { aspectCache, calculateNewPointCoordinate, parseFunction } from '@home/components/widget/lib/maps/maps-utils'; | 22 | import { aspectCache, calculateNewPointCoordinate, parseFunction } from '@home/components/widget/lib/maps/maps-utils'; |
23 | +import { WidgetContext } from '@home/models/widget-component.models'; | ||
24 | +import { DataSet, DatasourceType, widgetType } from '@shared/models/widget.models'; | ||
25 | +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; | ||
26 | +import { WidgetSubscriptionOptions } from '@core/api/widget-api.models'; | ||
23 | 27 | ||
24 | const maxZoom = 4;// ? | 28 | const maxZoom = 4;// ? |
25 | 29 | ||
@@ -32,26 +36,96 @@ export class ImageMap extends LeafletMap { | @@ -32,26 +36,96 @@ export class ImageMap extends LeafletMap { | ||
32 | imageUrl: string; | 36 | imageUrl: string; |
33 | posFunction: PosFuncton; | 37 | posFunction: PosFuncton; |
34 | 38 | ||
35 | - constructor($container: HTMLElement, options: UnitedMapSettings) { | ||
36 | - super($container, options); | 39 | + constructor(ctx: WidgetContext, $container: HTMLElement, options: UnitedMapSettings) { |
40 | + super(ctx, $container, options); | ||
37 | this.posFunction = parseFunction(options.posFunction, ['origXPos', 'origYPos']) as PosFuncton; | 41 | this.posFunction = parseFunction(options.posFunction, ['origXPos', 'origYPos']) as PosFuncton; |
38 | - this.imageUrl = options.mapUrl; | ||
39 | - aspectCache(this.imageUrl).subscribe(aspect => { | ||
40 | - this.aspect = aspect; | 42 | + this.mapImage(options).subscribe((mapImage) => { |
43 | + this.imageUrl = mapImage.imageUrl; | ||
44 | + this.aspect = mapImage.aspect; | ||
45 | + if (mapImage.update) { | ||
46 | + this.onResize(true); | ||
47 | + } else { | ||
41 | this.onResize(); | 48 | this.onResize(); |
42 | super.setMap(this.map); | 49 | super.setMap(this.map); |
43 | super.initSettings(options); | 50 | super.initSettings(options); |
51 | + } | ||
44 | }); | 52 | }); |
45 | } | 53 | } |
46 | 54 | ||
47 | - setImageAlias(alias: Observable<any>) { | ||
48 | - alias.pipe(filter(result => result), map(el => el[1]), switchMap(res => { | ||
49 | - this.imageUrl = res; | ||
50 | - return aspectCache(res); | ||
51 | - })).subscribe(aspect => { | ||
52 | - this.aspect = aspect; | ||
53 | - this.onResize(true); | ||
54 | - }); | 55 | + private mapImage(options: UnitedMapSettings): Observable<MapImage> { |
56 | + const imageEntityAlias = options.imageEntityAlias; | ||
57 | + const imageUrlAttribute = options.imageUrlAttribute; | ||
58 | + if (!imageEntityAlias || !imageUrlAttribute) { | ||
59 | + return this.imageFromUrl(options.mapUrl); | ||
60 | + } | ||
61 | + const entityAliasId = this.ctx.aliasController.getEntityAliasId(imageEntityAlias); | ||
62 | + if (!entityAliasId) { | ||
63 | + return this.imageFromUrl(options.mapUrl); | ||
64 | + } | ||
65 | + const datasources = [ | ||
66 | + { | ||
67 | + type: DatasourceType.entity, | ||
68 | + name: imageEntityAlias, | ||
69 | + aliasName: imageEntityAlias, | ||
70 | + entityAliasId, | ||
71 | + dataKeys: [ | ||
72 | + { | ||
73 | + type: DataKeyType.attribute, | ||
74 | + name: imageUrlAttribute, | ||
75 | + label: imageUrlAttribute, | ||
76 | + settings: {}, | ||
77 | + _hash: Math.random() | ||
78 | + } | ||
79 | + ] | ||
80 | + } | ||
81 | + ]; | ||
82 | + const result = new ReplaySubject<[DataSet, boolean]>(); | ||
83 | + let isUpdate = false; | ||
84 | + const imageUrlSubscriptionOptions: WidgetSubscriptionOptions = { | ||
85 | + datasources, | ||
86 | + useDashboardTimewindow: false, | ||
87 | + type: widgetType.latest, | ||
88 | + callbacks: { | ||
89 | + onDataUpdated: (subscription) => { | ||
90 | + result.next([subscription.data[0]?.data, isUpdate]); | ||
91 | + isUpdate = true; | ||
92 | + } | ||
93 | + } | ||
94 | + }; | ||
95 | + this.ctx.subscriptionApi.createSubscription(imageUrlSubscriptionOptions, true).subscribe(() => { }); | ||
96 | + return this.imageFromAlias(result); | ||
97 | + } | ||
98 | + | ||
99 | + private imageFromUrl(url: string): Observable<MapImage> { | ||
100 | + return aspectCache(url).pipe( | ||
101 | + map( aspect => { | ||
102 | + const mapImage: MapImage = { | ||
103 | + imageUrl: url, | ||
104 | + aspect, | ||
105 | + update: false | ||
106 | + }; | ||
107 | + return mapImage; | ||
108 | + } | ||
109 | + )); | ||
110 | + } | ||
111 | + | ||
112 | + private imageFromAlias(alias: Observable<[DataSet, boolean]>): Observable<MapImage> { | ||
113 | + return alias.pipe( | ||
114 | + filter(result => result[0].length > 0), | ||
115 | + mergeMap(res => { | ||
116 | + const mapImage: MapImage = { | ||
117 | + imageUrl: res[0][0][1], | ||
118 | + aspect: null, | ||
119 | + update: res[1] | ||
120 | + }; | ||
121 | + return aspectCache(mapImage.imageUrl).pipe( | ||
122 | + map((aspect) => { | ||
123 | + mapImage.aspect = aspect; | ||
124 | + return mapImage; | ||
125 | + } | ||
126 | + )); | ||
127 | + }) | ||
128 | + ); | ||
55 | } | 129 | } |
56 | 130 | ||
57 | updateBounds(updateImage?: boolean, lastCenterPos?) { | 131 | updateBounds(updateImage?: boolean, lastCenterPos?) { |
@@ -17,10 +17,11 @@ | @@ -17,10 +17,11 @@ | ||
17 | import L from 'leaflet'; | 17 | import L from 'leaflet'; |
18 | import LeafletMap from '../leaflet-map'; | 18 | import LeafletMap from '../leaflet-map'; |
19 | import { UnitedMapSettings } from '../map-models'; | 19 | import { UnitedMapSettings } from '../map-models'; |
20 | +import { WidgetContext } from '@home/models/widget-component.models'; | ||
20 | 21 | ||
21 | export class OpenStreetMap extends LeafletMap { | 22 | export class OpenStreetMap extends LeafletMap { |
22 | - constructor($container, options: UnitedMapSettings) { | ||
23 | - super($container, options); | 23 | + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { |
24 | + super(ctx, $container, options); | ||
24 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); | 25 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); |
25 | let tileLayer; | 26 | let tileLayer; |
26 | if (options.useCustomProvider) | 27 | if (options.useCustomProvider) |
@@ -18,10 +18,11 @@ | @@ -18,10 +18,11 @@ | ||
18 | import L from 'leaflet'; | 18 | import L from 'leaflet'; |
19 | import LeafletMap from '../leaflet-map'; | 19 | import LeafletMap from '../leaflet-map'; |
20 | import { UnitedMapSettings } from '../map-models'; | 20 | import { UnitedMapSettings } from '../map-models'; |
21 | +import { WidgetContext } from '@home/models/widget-component.models'; | ||
21 | 22 | ||
22 | export class TencentMap extends LeafletMap { | 23 | export class TencentMap extends LeafletMap { |
23 | - constructor($container, options: UnitedMapSettings) { | ||
24 | - super($container, options); | 24 | + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { |
25 | + super(ctx, $container, options); | ||
25 | const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; | 26 | const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; |
26 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); | 27 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); |
27 | const txLayer = L.tileLayer(txUrl, { | 28 | const txLayer = L.tileLayer(txUrl, { |