From f6ca099613fbfe013bb1ab66a3e5c436bf497e24 Mon Sep 17 00:00:00 2001 From: Artem Halushko Date: Tue, 3 Mar 2020 19:24:58 +0200 Subject: [PATCH] data update & polyline support --- ui-ngx/package-lock.json | 5 ++ ui-ngx/package.json | 1 + ui-ngx/src/app/core/utils.ts | 22 ++--- .../components/widget/lib/maps/leaflet-map.ts | 61 +++++++++++--- .../components/widget/lib/maps/map-models.ts | 8 +- .../widget/lib/maps/map-widget.interface.ts | 1 + .../components/widget/lib/maps/map-widget2.ts | 80 ++++++++++--------- .../components/widget/lib/maps/maps-utils.ts | 24 ++++++ .../components/widget/lib/maps/markers.ts | 9 ++- .../components/widget/lib/maps/polyline.ts | 3 +- .../widget/lib/maps/providers/image-map.ts | 10 +-- ui-ngx/tsconfig.json | 1 + 12 files changed, 158 insertions(+), 67 deletions(-) diff --git a/ui-ngx/package-lock.json b/ui-ngx/package-lock.json index e30dce7982..a5565bb937 100644 --- a/ui-ngx/package-lock.json +++ b/ui-ngx/package-lock.json @@ -1897,6 +1897,11 @@ "@types/geojson": "7946.0.7" } }, + "@types/lodash": { + "version": "4.14.149", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", + "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==" + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 0ea3547ac6..76c4cb9753 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -38,6 +38,7 @@ "@ngx-share/core": "^7.1.4", "@ngx-translate/core": "^12.1.1", "@ngx-translate/http-loader": "^4.0.0", + "@types/lodash": "^4.14.149", "ace-builds": "^1.4.8", "angular-gridster2": "^9.0.1", "angular2-hotkeys": "^2.1.5", diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index d46b190206..74e62515be 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -101,7 +101,7 @@ export function isNumber(value: any): boolean { } export function isNumeric(value: any): boolean { - return (value - parseFloat( value ) + 1) >= 0; + return (value - parseFloat(value) + 1) >= 0; } export function isString(value: any): boolean { @@ -226,9 +226,9 @@ function hashCode(str) { var i, char; if (str.length == 0) return hash; for (i = 0; i < str.length; i++) { - char = str.charCodeAt(i); - hash = ((hash << 5) - hash) + char; - hash = hash & hash; // Convert to 32bit integer + char = str.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; // Convert to 32bit integer } return hash; } @@ -424,24 +424,24 @@ export function getDescendantProp(obj: any, path: string): any { return path.split('.').reduce((acc, part) => acc && acc[part], obj); } -export function imageLoader(imageUrl: string): Observable{ +export function imageLoader(imageUrl: string): Observable { const image = new Image(); - const imageLoad$ = fromEvent(image, 'load').pipe(map(event=>image)); + const imageLoad$ = fromEvent(image, 'load').pipe(map(event => image)); image.src = imageUrl; return imageLoad$; } const imageAspectMap = {}; -export function aspectCache(imageUrl: string): Observable{ - if(imageUrl?.length){ +export function aspectCache(imageUrl: string): Observable { + if (imageUrl?.length) { const hash = hashCode(imageUrl); let aspect = imageAspectMap[hash]; - if(aspect){ + if (aspect) { return of(aspect); } - else return imageLoader(imageUrl).pipe(map(image=>{ - aspect = image.width/image.height; + else return imageLoader(imageUrl).pipe(map(image => { + aspect = image.width / image.height; imageAspectMap[hash] = aspect; return aspect; })) 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 0c7a42374e..4cc0d52ab8 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 @@ -9,11 +9,13 @@ import { MapOptions, MarkerSettings } from './map-models'; import { Marker } from './markers'; import { Observable, of, BehaviorSubject, Subject } from 'rxjs'; import { filter } from 'rxjs/operators'; +import { Polyline } from './polyline'; -export default class LeafletMap { +export default abstract class LeafletMap { - markers = []; + markers: Map = new Map(); tooltips = []; + poly: Polyline; map: L.Map; map$: BehaviorSubject = new BehaviorSubject(null); ready$: Observable = this.map$.pipe(filter(map => !!map)); @@ -22,6 +24,7 @@ export default class LeafletMap { constructor($container: HTMLElement, options: MapOptions) { + console.log("LeafletMap -> constructor -> options", options) this.options = options; } @@ -123,29 +126,69 @@ export default class LeafletMap { return this.map.getCenter(); } - convertPosition(expression: L.LatLngExpression | { x, y }): L.LatLngExpression { - return expression as L.LatLngExpression; + convertPosition(expression: any): L.LatLng { + return L.latLng(expression[this.options.latKeyName], expression[this.options.lngKeyName]) as L.LatLng; } ////Markers + updateMarkers(markersData) { + markersData.forEach(data => { + if (this.markers.get(data.aliasName)) { + this.updateMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings) + } + else { + this.createMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings); + } + }); + } - - createMarker(location, settings: MarkerSettings) { + private createMarker(key, location, settings: MarkerSettings) { this.ready$.subscribe(() => { let defaultSettings: MarkerSettings = { color: '#FD2785' } - this.markers.push(new Marker(this.map, this.convertPosition(location), { ...defaultSettings, ...settings })) + this.markers.set(key, new Marker(this.map, location, { ...defaultSettings, ...settings })) }); } - updateMarker() { + private updateMarker(key, location: L.LatLng, settings: MarkerSettings) { + const marker: Marker = this.markers.get(key); + if (!location.equals(marker.location)) { + marker.updateMarkerPosition(location); + } + //other implements later } - deleteMarker() { + private deleteMarker() { } + //polyline + + updatePolylines(polyData) { + if (this.poly) { + } + + else { + this.map$ + this.createPolyline(polyData.map(data => this.convertPosition(data)), this.options); + } + + /* markersData.forEach(data => { + if (this.markers.get(data.aliasName)) { + this.updateMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings) + } + else { + this.createMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings); + } + });*/ + } + + createPolyline(locations, settings) { + this.ready$.subscribe(() => + this.poly = new Polyline(this.map, locations, settings) + ) + } } \ No newline at end of file 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 5b3da8bb47..985a6be965 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 @@ -4,6 +4,10 @@ export interface MapOptions { dontFitMapBounds?: boolean, disableScrollZooming?: boolean, minZoomLevel?: number, + latKeyName?: string, + lngKeyName?: string, + xPosKeyName?: string, + yPosKeyName?: string, mapProvider: MapProviders, mapUrl?: string; credentials?: any, // declare credentials format @@ -19,9 +23,9 @@ export enum MapProviders { tencent = 'tencent-map' } -export interface MarkerSettings{ +export interface MarkerSettings { showLabel?: boolean, draggable?: boolean, displayTooltip?: boolean, - color: string + color?: string } \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts index 9fb2e1c944..48464e3b73 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts @@ -1,5 +1,6 @@ export interface MapWidgetInterface { resize(), + update(), onInit(), onDataUpdated(); onResize(); 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 d501fbc2db..bda59af95d 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 @@ -13,44 +13,21 @@ import { } from './schemes'; import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface'; import { OpenStreetMap, TencentMap, GoogleMap, HEREMap, ImageMap } from './providers'; - - -const providerSets = { - 'openstreet-map': { - MapClass: OpenStreetMap, - schema: openstreetMapSettingsSchema, - name: "Openstreet" - }, - 'tencent-map': { - MapClass: TencentMap, - schema: tencentMapSettingsSchema, - name: "Tencent" - }, - 'google-map': { - MapClass: GoogleMap, - schema: googleMapSettingsSchema, - name: "Openstreet" - }, - 'here': { - MapClass: HEREMap, - schema: hereMapSettingsSchema, - name: "HERE" - }, - 'image-map': { - MapClass: ImageMap, - schema: imageMapSettingsSchema - } -} +import { WidgetSubscription } from '@app/core/public-api'; +import { parseData, parseArray } from './maps-utils'; export let TbMapWidgetV2: MapWidgetStaticInterface; TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface { map: LeafletMap; provider: MapProviders; schema; + data; - constructor(mapProvider: MapProviders, drawRoutes, ctx, $element) { - console.log(ctx.settings); - + constructor(mapProvider: MapProviders, private drawRoutes, ctx, $element) { + console.log("TbMapWidgetV2 -> constructor -> ctx", ctx) + // console.log(ctx.subscriptions, ctx.data, ctx.datasources); + this.data = ctx.data; + //this.subsciptions. if (!$element) { $element = ctx.$container[0]; } @@ -71,17 +48,21 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface { if (!MapClass) { return; } - this.map = new MapClass($element, { ...baseOptions, ...ctx.settings }) - if(mapProvider !== "image-map") - this.map.createMarker({ lat: 0, lng: 0 }, { color: '#FD2785' }) - else - this.map.createMarker({ x: 500, y: 500 }, { color: '#6D2785' }); + this.map = new MapClass($element, { ...baseOptions, ...ctx.settings }); this.schema = providerSets[mapProvider]?.schema; } onInit() { } + update() { + console.log(this.data,parseData(this.data) ); + + if (this.drawRoutes) + this.map.updatePolylines(parseArray(this.data)); + this.map.updateMarkers(parseData(this.data)); + } + onDataUpdated() { } @@ -173,4 +154,31 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface { onDestroy() { } +} + +const providerSets = { + 'openstreet-map': { + MapClass: OpenStreetMap, + schema: openstreetMapSettingsSchema, + name: "Openstreet" + }, + 'tencent-map': { + MapClass: TencentMap, + schema: tencentMapSettingsSchema, + name: "Tencent" + }, + 'google-map': { + MapClass: GoogleMap, + schema: googleMapSettingsSchema, + name: "Openstreet" + }, + 'here': { + MapClass: HEREMap, + schema: hereMapSettingsSchema, + name: "HERE" + }, + 'image-map': { + MapClass: ImageMap, + schema: imageMapSettingsSchema + } } \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts index 71552c4357..1400d99558 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts @@ -1,4 +1,5 @@ import L from 'leaflet'; +import _ from 'lodash'; export function createTooltip(target, settings, targetArgs?) { var popup = L.popup(); @@ -19,4 +20,27 @@ export function createTooltip(target, settings, targetArgs?) { locationSettings: settings, dsIndex: settings.dsIndex }; +} + +export function parseArray(input: any[]): any[] { + let alliases: any = _(input).groupBy(el => el?.datasource?.aliasName).values().value(); + return alliases.map(alliasArray => + alliasArray[0].data.map((el, i) => { + const obj = { aliasName: alliasArray[0]?.datasource?.aliasName }; + alliasArray.forEach(el => { + obj[el?.dataKey?.label] = el?.data[i][1] + }); + return obj; + }) + ).flat(); +} + +export function parseData(input: any[]): any[] { + return _(input).groupBy(el => el?.datasource?.aliasName).values().value().map(alliasArray => { + const obj = { aliasName: alliasArray[0]?.datasource?.aliasName }; + alliasArray.forEach(el => { + obj[el?.dataKey?.label] = el?.data[0][1] + }); + return obj; + }); } \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index 0a26edd30d..3a93ccbc92 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -7,13 +7,14 @@ import { aspectCache } from '@app/core/utils'; export class Marker { leafletMarker: L.Marker; - // map: L.Map; tooltipOffset; tooltip; + location; constructor(private map: L.Map, location: L.LatLngExpression, settings: MarkerSettings, onClickListener?, markerArgs?, onDragendListener?) { //this.map = map; + this.location = location; this.leafletMarker = L.marker(location, { draggable: settings.draggable }); @@ -43,6 +44,10 @@ export class Marker { } + updateMarkerPosition(position: L.LatLngExpression){ + this.leafletMarker.setLatLng(position); + } + updateMarkerLabel(settings) { this.leafletMarker.unbindTooltip(); if (settings.showLabel) @@ -56,7 +61,7 @@ export class Marker { }); } - updateMarkerIcon( settings) { + updateMarkerIcon(settings) { this.createMarkerIcon(settings, (iconInfo) => { this.leafletMarker.setIcon(iconInfo.icon); if (settings.showLabel) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts index 045f51dfba..dd7c7d029a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts @@ -2,10 +2,9 @@ import L from 'leaflet'; export class Polyline { - map: L.Map; leafletPoly: L.Polyline; - constructor(locations, settings) { + constructor(private map: L.Map, locations, settings) { this.leafletPoly = L.polyline(locations, { color: settings.color, 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 7d4714456d..aea8ec39e6 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 @@ -101,13 +101,13 @@ export class ImageMap extends LeafletMap { } } - convertPosition(expression: { x, y }): L.LatLngExpression { - console.log("ImageMap -> expression", expression) - return this.pointToLatLng(expression.x, expression.y) as L.LatLngExpression; + convertPosition(expression): L.LatLng { + return this.pointToLatLng( + expression[this.options.xPosKeyName] * this.width, + expression[this.options.yPosKeyName] * this.height); } - - pointToLatLng(x, y) { + pointToLatLng(x, y): L.LatLng { return L.CRS.Simple.pointToLatLng({ x, y } as L.PointExpression, maxZoom - 1); } diff --git a/ui-ngx/tsconfig.json b/ui-ngx/tsconfig.json index a35b8a413f..bfc3436509 100644 --- a/ui-ngx/tsconfig.json +++ b/ui-ngx/tsconfig.json @@ -33,6 +33,7 @@ }, "lib": [ "es2018", + "es2019", "dom" ] }