Commit b86c5e61e1168e5cfa49eaf9350aa211c7b409b4

Authored by Igor Kulikov
1 parent 0206a8ab

Image map fixes and improvements. Fixed state chart subscription.

@@ -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, {