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 314 });
315 315 stateDataReceived = true;
316 316 } else {
317   - firstStateData = data;
  317 + firstStateData = subscriptionUpdate;
318 318 }
319 319 } else {
320 320 if (subsTw.aggregation.stateData && !stateDataReceived) {
... ...
... ... @@ -33,6 +33,7 @@ import { filter } from 'rxjs/operators';
33 33 import { Polyline } from './polyline';
34 34 import { Polygon } from './polygon';
35 35 import { createTooltip, safeExecute } from '@home/components/widget/lib/maps/maps-utils';
  36 +import { WidgetContext } from '@home/models/widget-component.models';
36 37
37 38 export default abstract class LeafletMap {
38 39
... ... @@ -49,7 +50,9 @@ export default abstract class LeafletMap {
49 50 points: FeatureGroup;
50 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 56 this.options = options;
54 57 }
55 58
... ... @@ -341,9 +344,6 @@ export default abstract class LeafletMap {
341 344 });
342 345 }
343 346
344   - setImageAlias(alias: Observable<any>) {
345   - }
346   -
347 347 // Polyline
348 348
349 349 updatePolylines(polyData: FormattedData[][], data?: FormattedData) {
... ...
... ... @@ -165,6 +165,12 @@ export interface HistorySelectSettings {
165 165 buttonColor: string;
166 166 }
167 167
  168 +export interface MapImage {
  169 + imageUrl: string;
  170 + aspect: number;
  171 + update?: boolean;
  172 +}
  173 +
168 174 export type TripAnimationSettings = {
169 175 showPoints: boolean;
170 176 pointColor: string;
... ...
... ... @@ -17,26 +17,18 @@
17 17 import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models';
18 18 import LeafletMap from './leaflet-map';
19 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 26 } from './schemes';
27 27 import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface';
28 28 import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils';
29   -import { of, Subject } from 'rxjs';
30 29 import { WidgetContext } from '@app/modules/home/models/widget-component.models';
31 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 32 import { EntityId } from '@shared/models/id/entity-id';
41 33 import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
42 34 import { AttributeService } from '@core/http/attribute.service';
... ... @@ -76,8 +68,7 @@ export class MapWidgetController implements MapWidgetInterface {
76 68 return;
77 69 }
78 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 72 this.map.saveMarkerLocation = this.setMarkerLocation;
82 73 if (this.settings.draggableMarker) {
83 74 this.map.setDataSources(parseData(this.data));
... ... @@ -263,48 +254,6 @@ export class MapWidgetController implements MapWidgetInterface {
263 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 257 onDestroy() {
309 258 }
310 259 }
... ...
... ... @@ -21,6 +21,7 @@ import { UnitedMapSettings } from '../map-models';
21 21 import 'leaflet.gridlayer.googlemutant';
22 22 import { ResourcesService } from '@core/services/resources.service';
23 23 import { Injector } from '@angular/core';
  24 +import { WidgetContext } from '@home/models/widget-component.models';
24 25
25 26 const gmGlobals: GmGlobal = {};
26 27
... ... @@ -31,8 +32,8 @@ interface GmGlobal {
31 32 export class GoogleMap extends LeafletMap {
32 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 37 this.resource = injector.get(ResourcesService);
37 38 this.loadGoogle(() => {
38 39 const map = L.map($container, {attributionControl: false}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
... ...
... ... @@ -17,10 +17,11 @@
17 17 import L from 'leaflet';
18 18 import LeafletMap from '../leaflet-map';
19 19 import { UnitedMapSettings } from '../map-models';
  20 +import { WidgetContext } from '@home/models/widget-component.models';
20 21
21 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 25 const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
25 26 const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials);
26 27 tileLayer.addTo(map);
... ...
... ... @@ -14,12 +14,16 @@
14 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 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 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 28 const maxZoom = 4;// ?
25 29
... ... @@ -32,26 +36,96 @@ export class ImageMap extends LeafletMap {
32 36 imageUrl: string;
33 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 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 48 this.onResize();
42 49 super.setMap(this.map);
43 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 131 updateBounds(updateImage?: boolean, lastCenterPos?) {
... ...
... ... @@ -17,10 +17,11 @@
17 17 import L from 'leaflet';
18 18 import LeafletMap from '../leaflet-map';
19 19 import { UnitedMapSettings } from '../map-models';
  20 +import { WidgetContext } from '@home/models/widget-component.models';
20 21
21 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 25 const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
25 26 let tileLayer;
26 27 if (options.useCustomProvider)
... ...
... ... @@ -18,10 +18,11 @@
18 18 import L from 'leaflet';
19 19 import LeafletMap from '../leaflet-map';
20 20 import { UnitedMapSettings } from '../map-models';
  21 +import { WidgetContext } from '@home/models/widget-component.models';
21 22
22 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 26 const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
26 27 const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
27 28 const txLayer = L.tileLayer(txUrl, {
... ...