diff --git a/ui-ngx/src/app/core/api/datasource-subcription.ts b/ui-ngx/src/app/core/api/datasource-subcription.ts index ccc69f863c..c3d182595d 100644 --- a/ui-ngx/src/app/core/api/datasource-subcription.ts +++ b/ui-ngx/src/app/core/api/datasource-subcription.ts @@ -314,7 +314,7 @@ export class DatasourceSubscription { }); stateDataReceived = true; } else { - firstStateData = data; + firstStateData = subscriptionUpdate; } } else { if (subsTw.aggregation.stateData && !stateDataReceived) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 68e967c29b..3d11b704c0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -33,6 +33,7 @@ import { filter } from 'rxjs/operators'; import { Polyline } from './polyline'; import { Polygon } from './polygon'; import { createTooltip, safeExecute } from '@home/components/widget/lib/maps/maps-utils'; +import { WidgetContext } from '@home/models/widget-component.models'; export default abstract class LeafletMap { @@ -49,7 +50,9 @@ export default abstract class LeafletMap { points: FeatureGroup; markersData: FormattedData[] = []; - protected constructor(public $container: HTMLElement, options: UnitedMapSettings) { + protected constructor(public ctx: WidgetContext, + public $container: HTMLElement, + options: UnitedMapSettings) { this.options = options; } @@ -341,9 +344,6 @@ export default abstract class LeafletMap { }); } - setImageAlias(alias: Observable) { - } - // Polyline updatePolylines(polyData: FormattedData[][], data?: FormattedData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index 32e6049a4b..7bf1b8fb21 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -165,6 +165,12 @@ export interface HistorySelectSettings { buttonColor: string; } +export interface MapImage { + imageUrl: string; + aspect: number; + update?: boolean; +} + export type TripAnimationSettings = { showPoints: boolean; pointColor: string; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 557631609c..58b1140e93 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -17,26 +17,18 @@ import { defaultSettings, hereProviders, MapProviders, providerSets, UnitedMapSettings } from './map-models'; import LeafletMap from './leaflet-map'; import { - commonMapSettingsSchema, - mapPolygonSchema, - mapProviderSchema, - markerClusteringSettingsSchema, - markerClusteringSettingsSchemaLeaflet, - routeMapSettingsSchema + commonMapSettingsSchema, + mapPolygonSchema, + mapProviderSchema, + markerClusteringSettingsSchema, + markerClusteringSettingsSchemaLeaflet, + routeMapSettingsSchema } from './schemes'; import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface'; import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils'; -import { of, Subject } from 'rxjs'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { getDefCenterPosition, parseArray, parseData, parseFunction, parseWithTranslation } from './maps-utils'; -import { - Datasource, - DatasourceType, - JsonSettingsSchema, - WidgetActionDescriptor, - widgetType, - DatasourceData -} from '@shared/models/widget.models'; +import { Datasource, DatasourceData, JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models'; import { EntityId } from '@shared/models/id/entity-id'; import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; import { AttributeService } from '@core/http/attribute.service'; @@ -76,8 +68,7 @@ export class MapWidgetController implements MapWidgetInterface { return; } parseWithTranslation.setTranslate(this.translate); - this.map = new MapClass($element, this.settings, this.ctx.$injector); - this.map.setImageAlias(this.subscribeForImageAttribute()); + this.map = new MapClass(this.ctx, $element, this.settings, this.ctx.$injector); this.map.saveMarkerLocation = this.setMarkerLocation; if (this.settings.draggableMarker) { this.map.setDataSources(parseData(this.data)); @@ -263,48 +254,6 @@ export class MapWidgetController implements MapWidgetInterface { this.map.onResize(); } - subscribeForImageAttribute() { - const imageEntityAlias = this.settings.imageEntityAlias; - const imageUrlAttribute = this.settings.imageUrlAttribute; - if (!imageEntityAlias || !imageUrlAttribute) { - return of(false); - } - const entityAliasId = this.ctx.aliasController.getEntityAliasId(imageEntityAlias); - if (!entityAliasId) { - return of(false); - } - const datasources = [ - { - type: DatasourceType.entity, - name: imageEntityAlias, - aliasName: imageEntityAlias, - entityAliasId, - dataKeys: [ - { - type: DataKeyType.attribute, - name: imageUrlAttribute, - label: imageUrlAttribute, - settings: {}, - _hash: Math.random() - } - ] - } - ]; - const result = new Subject(); - const imageUrlSubscriptionOptions = { - datasources, - useDashboardTimewindow: false, - type: widgetType.latest, - callbacks: { - onDataUpdated: (subscription) => { - result.next(subscription?.data[0]?.data[0]); - } - } - }; - this.ctx.subscriptionApi.createSubscription(imageUrlSubscriptionOptions, true).subscribe(() => { }); - return result; - } - onDestroy() { } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts index 2a06f5c056..b0653483c9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/google-map.ts @@ -21,6 +21,7 @@ import { UnitedMapSettings } from '../map-models'; import 'leaflet.gridlayer.googlemutant'; import { ResourcesService } from '@core/services/resources.service'; import { Injector } from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; const gmGlobals: GmGlobal = {}; @@ -31,8 +32,8 @@ interface GmGlobal { export class GoogleMap extends LeafletMap { private resource: ResourcesService; - constructor($container, options: UnitedMapSettings, private injector: Injector) { - super($container, options); + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings, private injector: Injector) { + super(ctx, $container, options); this.resource = injector.get(ResourcesService); this.loadGoogle(() => { const map = L.map($container, {attributionControl: false}).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts index 9ad0d7b160..17a8f61801 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/here-map.ts @@ -17,10 +17,11 @@ import L from 'leaflet'; import LeafletMap from '../leaflet-map'; import { UnitedMapSettings } from '../map-models'; +import { WidgetContext } from '@home/models/widget-component.models'; export class HEREMap extends LeafletMap { - constructor($container, options: UnitedMapSettings) { - super($container, options); + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { + super(ctx, $container, options); const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); const tileLayer = (L.tileLayer as any).provider(options.mapProviderHere || 'HERE.normalDay', options.credentials); tileLayer.addTo(map); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index 095bff401d..7d38477f14 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -14,12 +14,16 @@ /// limitations under the License. /// -import L, { LatLngLiteral, LatLngBounds, LatLngTuple } from 'leaflet'; +import L, { LatLngBounds, LatLngLiteral, LatLngTuple } from 'leaflet'; import LeafletMap from '../leaflet-map'; -import { UnitedMapSettings, PosFuncton } from '../map-models'; -import { Observable } from 'rxjs'; -import { map, filter, switchMap } from 'rxjs/operators'; +import { MapImage, PosFuncton, UnitedMapSettings } from '../map-models'; +import { Observable, ReplaySubject } from 'rxjs'; +import { filter, map, mergeMap } from 'rxjs/operators'; import { aspectCache, calculateNewPointCoordinate, parseFunction } from '@home/components/widget/lib/maps/maps-utils'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { DataSet, DatasourceType, widgetType } from '@shared/models/widget.models'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { WidgetSubscriptionOptions } from '@core/api/widget-api.models'; const maxZoom = 4;// ? @@ -32,26 +36,96 @@ export class ImageMap extends LeafletMap { imageUrl: string; posFunction: PosFuncton; - constructor($container: HTMLElement, options: UnitedMapSettings) { - super($container, options); + constructor(ctx: WidgetContext, $container: HTMLElement, options: UnitedMapSettings) { + super(ctx, $container, options); this.posFunction = parseFunction(options.posFunction, ['origXPos', 'origYPos']) as PosFuncton; - this.imageUrl = options.mapUrl; - aspectCache(this.imageUrl).subscribe(aspect => { - this.aspect = aspect; + this.mapImage(options).subscribe((mapImage) => { + this.imageUrl = mapImage.imageUrl; + this.aspect = mapImage.aspect; + if (mapImage.update) { + this.onResize(true); + } else { this.onResize(); super.setMap(this.map); super.initSettings(options); + } }); } - setImageAlias(alias: Observable) { - alias.pipe(filter(result => result), map(el => el[1]), switchMap(res => { - this.imageUrl = res; - return aspectCache(res); - })).subscribe(aspect => { - this.aspect = aspect; - this.onResize(true); - }); + private mapImage(options: UnitedMapSettings): Observable { + const imageEntityAlias = options.imageEntityAlias; + const imageUrlAttribute = options.imageUrlAttribute; + if (!imageEntityAlias || !imageUrlAttribute) { + return this.imageFromUrl(options.mapUrl); + } + const entityAliasId = this.ctx.aliasController.getEntityAliasId(imageEntityAlias); + if (!entityAliasId) { + return this.imageFromUrl(options.mapUrl); + } + const datasources = [ + { + type: DatasourceType.entity, + name: imageEntityAlias, + aliasName: imageEntityAlias, + entityAliasId, + dataKeys: [ + { + type: DataKeyType.attribute, + name: imageUrlAttribute, + label: imageUrlAttribute, + settings: {}, + _hash: Math.random() + } + ] + } + ]; + const result = new ReplaySubject<[DataSet, boolean]>(); + let isUpdate = false; + const imageUrlSubscriptionOptions: WidgetSubscriptionOptions = { + datasources, + useDashboardTimewindow: false, + type: widgetType.latest, + callbacks: { + onDataUpdated: (subscription) => { + result.next([subscription.data[0]?.data, isUpdate]); + isUpdate = true; + } + } + }; + this.ctx.subscriptionApi.createSubscription(imageUrlSubscriptionOptions, true).subscribe(() => { }); + return this.imageFromAlias(result); + } + + private imageFromUrl(url: string): Observable { + return aspectCache(url).pipe( + map( aspect => { + const mapImage: MapImage = { + imageUrl: url, + aspect, + update: false + }; + return mapImage; + } + )); + } + + private imageFromAlias(alias: Observable<[DataSet, boolean]>): Observable { + return alias.pipe( + filter(result => result[0].length > 0), + mergeMap(res => { + const mapImage: MapImage = { + imageUrl: res[0][0][1], + aspect: null, + update: res[1] + }; + return aspectCache(mapImage.imageUrl).pipe( + map((aspect) => { + mapImage.aspect = aspect; + return mapImage; + } + )); + }) + ); } updateBounds(updateImage?: boolean, lastCenterPos?) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts index 443e565e61..d1e2379dbd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/openstreet-map.ts @@ -17,10 +17,11 @@ import L from 'leaflet'; import LeafletMap from '../leaflet-map'; import { UnitedMapSettings } from '../map-models'; +import { WidgetContext } from '@home/models/widget-component.models'; export class OpenStreetMap extends LeafletMap { - constructor($container, options: UnitedMapSettings) { - super($container, options); + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { + super(ctx, $container, options); const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); let tileLayer; if (options.useCustomProvider) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts index 598bd7f357..a615de883a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/tencent-map.ts @@ -18,10 +18,11 @@ import L from 'leaflet'; import LeafletMap from '../leaflet-map'; import { UnitedMapSettings } from '../map-models'; +import { WidgetContext } from '@home/models/widget-component.models'; export class TencentMap extends LeafletMap { - constructor($container, options: UnitedMapSettings) { - super($container, options); + constructor(ctx: WidgetContext, $container, options: UnitedMapSettings) { + super(ctx, $container, options); const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); const txLayer = L.tileLayer(txUrl, {