Commit f6ca099613fbfe013bb1ab66a3e5c436bf497e24

Authored by Artem Halushko
1 parent 8149d9d4

data update & polyline support

... ... @@ -1897,6 +1897,11 @@
1897 1897 "@types/geojson": "7946.0.7"
1898 1898 }
1899 1899 },
  1900 + "@types/lodash": {
  1901 + "version": "4.14.149",
  1902 + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz",
  1903 + "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ=="
  1904 + },
1900 1905 "@types/minimatch": {
1901 1906 "version": "3.0.3",
1902 1907 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
... ...
... ... @@ -38,6 +38,7 @@
38 38 "@ngx-share/core": "^7.1.4",
39 39 "@ngx-translate/core": "^12.1.1",
40 40 "@ngx-translate/http-loader": "^4.0.0",
  41 + "@types/lodash": "^4.14.149",
41 42 "ace-builds": "^1.4.8",
42 43 "angular-gridster2": "^9.0.1",
43 44 "angular2-hotkeys": "^2.1.5",
... ...
... ... @@ -101,7 +101,7 @@ export function isNumber(value: any): boolean {
101 101 }
102 102
103 103 export function isNumeric(value: any): boolean {
104   - return (value - parseFloat( value ) + 1) >= 0;
  104 + return (value - parseFloat(value) + 1) >= 0;
105 105 }
106 106
107 107 export function isString(value: any): boolean {
... ... @@ -226,9 +226,9 @@ function hashCode(str) {
226 226 var i, char;
227 227 if (str.length == 0) return hash;
228 228 for (i = 0; i < str.length; i++) {
229   - char = str.charCodeAt(i);
230   - hash = ((hash << 5) - hash) + char;
231   - hash = hash & hash; // Convert to 32bit integer
  229 + char = str.charCodeAt(i);
  230 + hash = ((hash << 5) - hash) + char;
  231 + hash = hash & hash; // Convert to 32bit integer
232 232 }
233 233 return hash;
234 234 }
... ... @@ -424,24 +424,24 @@ export function getDescendantProp(obj: any, path: string): any {
424 424 return path.split('.').reduce((acc, part) => acc && acc[part], obj);
425 425 }
426 426
427   -export function imageLoader(imageUrl: string): Observable<HTMLImageElement>{
  427 +export function imageLoader(imageUrl: string): Observable<HTMLImageElement> {
428 428 const image = new Image();
429   - const imageLoad$ = fromEvent(image, 'load').pipe(map(event=>image));
  429 + const imageLoad$ = fromEvent(image, 'load').pipe(map(event => image));
430 430 image.src = imageUrl;
431 431 return imageLoad$;
432 432 }
433 433
434 434 const imageAspectMap = {};
435 435
436   -export function aspectCache(imageUrl: string): Observable<number>{
437   - if(imageUrl?.length){
  436 +export function aspectCache(imageUrl: string): Observable<number> {
  437 + if (imageUrl?.length) {
438 438 const hash = hashCode(imageUrl);
439 439 let aspect = imageAspectMap[hash];
440   - if(aspect){
  440 + if (aspect) {
441 441 return of(aspect);
442 442 }
443   - else return imageLoader(imageUrl).pipe(map(image=>{
444   - aspect = image.width/image.height;
  443 + else return imageLoader(imageUrl).pipe(map(image => {
  444 + aspect = image.width / image.height;
445 445 imageAspectMap[hash] = aspect;
446 446 return aspect;
447 447 }))
... ...
... ... @@ -9,11 +9,13 @@ import { MapOptions, MarkerSettings } from './map-models';
9 9 import { Marker } from './markers';
10 10 import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
11 11 import { filter } from 'rxjs/operators';
  12 +import { Polyline } from './polyline';
12 13
13   -export default class LeafletMap {
  14 +export default abstract class LeafletMap {
14 15
15   - markers = [];
  16 + markers: Map<string, Marker> = new Map();
16 17 tooltips = [];
  18 + poly: Polyline;
17 19 map: L.Map;
18 20 map$: BehaviorSubject<L.Map> = new BehaviorSubject(null);
19 21 ready$: Observable<L.Map> = this.map$.pipe(filter(map => !!map));
... ... @@ -22,6 +24,7 @@ export default class LeafletMap {
22 24
23 25
24 26 constructor($container: HTMLElement, options: MapOptions) {
  27 + console.log("LeafletMap -> constructor -> options", options)
25 28 this.options = options;
26 29 }
27 30
... ... @@ -123,29 +126,69 @@ export default class LeafletMap {
123 126 return this.map.getCenter();
124 127 }
125 128
126   - convertPosition(expression: L.LatLngExpression | { x, y }): L.LatLngExpression {
127   - return expression as L.LatLngExpression;
  129 + convertPosition(expression: any): L.LatLng {
  130 + return L.latLng(expression[this.options.latKeyName], expression[this.options.lngKeyName]) as L.LatLng;
128 131 }
129 132
130 133 ////Markers
  134 + updateMarkers(markersData) {
  135 + markersData.forEach(data => {
  136 + if (this.markers.get(data.aliasName)) {
  137 + this.updateMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings)
  138 + }
  139 + else {
  140 + this.createMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings);
  141 + }
  142 + });
  143 + }
131 144
132   -
133   - createMarker(location, settings: MarkerSettings) {
  145 + private createMarker(key, location, settings: MarkerSettings) {
134 146 this.ready$.subscribe(() => {
135 147 let defaultSettings: MarkerSettings = {
136 148 color: '#FD2785'
137 149 }
138   - this.markers.push(new Marker(this.map, this.convertPosition(location), { ...defaultSettings, ...settings }))
  150 + this.markers.set(key, new Marker(this.map, location, { ...defaultSettings, ...settings }))
139 151 });
140 152 }
141 153
142   - updateMarker() {
  154 + private updateMarker(key, location: L.LatLng, settings: MarkerSettings) {
  155 + const marker: Marker = this.markers.get(key);
  156 + if (!location.equals(marker.location)) {
  157 + marker.updateMarkerPosition(location);
  158 + }
  159 + //other implements later
143 160
144 161 }
145 162
146   - deleteMarker() {
  163 + private deleteMarker() {
147 164
148 165 }
149 166
  167 + //polyline
  168 +
  169 + updatePolylines(polyData) {
  170 + if (this.poly) {
150 171
  172 + }
  173 +
  174 + else {
  175 + this.map$
  176 + this.createPolyline(polyData.map(data => this.convertPosition(data)), this.options);
  177 + }
  178 +
  179 + /* markersData.forEach(data => {
  180 + if (this.markers.get(data.aliasName)) {
  181 + this.updateMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings)
  182 + }
  183 + else {
  184 + this.createMarker(data.aliasName, this.convertPosition(data), this.options as MarkerSettings);
  185 + }
  186 + });*/
  187 + }
  188 +
  189 + createPolyline(locations, settings) {
  190 + this.ready$.subscribe(() =>
  191 + this.poly = new Polyline(this.map, locations, settings)
  192 + )
  193 + }
151 194 }
\ No newline at end of file
... ...
... ... @@ -4,6 +4,10 @@ export interface MapOptions {
4 4 dontFitMapBounds?: boolean,
5 5 disableScrollZooming?: boolean,
6 6 minZoomLevel?: number,
  7 + latKeyName?: string,
  8 + lngKeyName?: string,
  9 + xPosKeyName?: string,
  10 + yPosKeyName?: string,
7 11 mapProvider: MapProviders,
8 12 mapUrl?: string;
9 13 credentials?: any, // declare credentials format
... ... @@ -19,9 +23,9 @@ export enum MapProviders {
19 23 tencent = 'tencent-map'
20 24 }
21 25
22   -export interface MarkerSettings{
  26 +export interface MarkerSettings {
23 27 showLabel?: boolean,
24 28 draggable?: boolean,
25 29 displayTooltip?: boolean,
26   - color: string
  30 + color?: string
27 31 }
\ No newline at end of file
... ...
1 1 export interface MapWidgetInterface {
2 2 resize(),
  3 + update(),
3 4 onInit(),
4 5 onDataUpdated();
5 6 onResize();
... ...
... ... @@ -13,44 +13,21 @@ import {
13 13 } from './schemes';
14 14 import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface';
15 15 import { OpenStreetMap, TencentMap, GoogleMap, HEREMap, ImageMap } from './providers';
16   -
17   -
18   -const providerSets = {
19   - 'openstreet-map': {
20   - MapClass: OpenStreetMap,
21   - schema: openstreetMapSettingsSchema,
22   - name: "Openstreet"
23   - },
24   - 'tencent-map': {
25   - MapClass: TencentMap,
26   - schema: tencentMapSettingsSchema,
27   - name: "Tencent"
28   - },
29   - 'google-map': {
30   - MapClass: GoogleMap,
31   - schema: googleMapSettingsSchema,
32   - name: "Openstreet"
33   - },
34   - 'here': {
35   - MapClass: HEREMap,
36   - schema: hereMapSettingsSchema,
37   - name: "HERE"
38   - },
39   - 'image-map': {
40   - MapClass: ImageMap,
41   - schema: imageMapSettingsSchema
42   - }
43   -}
  16 +import { WidgetSubscription } from '@app/core/public-api';
  17 +import { parseData, parseArray } from './maps-utils';
44 18
45 19 export let TbMapWidgetV2: MapWidgetStaticInterface;
46 20 TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface {
47 21 map: LeafletMap;
48 22 provider: MapProviders;
49 23 schema;
  24 + data;
50 25
51   - constructor(mapProvider: MapProviders, drawRoutes, ctx, $element) {
52   - console.log(ctx.settings);
53   -
  26 + constructor(mapProvider: MapProviders, private drawRoutes, ctx, $element) {
  27 + console.log("TbMapWidgetV2 -> constructor -> ctx", ctx)
  28 + // console.log(ctx.subscriptions, ctx.data, ctx.datasources);
  29 + this.data = ctx.data;
  30 + //this.subsciptions.
54 31 if (!$element) {
55 32 $element = ctx.$container[0];
56 33 }
... ... @@ -71,17 +48,21 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface {
71 48 if (!MapClass) {
72 49 return;
73 50 }
74   - this.map = new MapClass($element, { ...baseOptions, ...ctx.settings })
75   - if(mapProvider !== "image-map")
76   - this.map.createMarker({ lat: 0, lng: 0 }, { color: '#FD2785' })
77   - else
78   - this.map.createMarker({ x: 500, y: 500 }, { color: '#6D2785' });
  51 + this.map = new MapClass($element, { ...baseOptions, ...ctx.settings });
79 52 this.schema = providerSets[mapProvider]?.schema;
80 53 }
81 54
82 55 onInit() {
83 56 }
84 57
  58 + update() {
  59 + console.log(this.data,parseData(this.data) );
  60 +
  61 + if (this.drawRoutes)
  62 + this.map.updatePolylines(parseArray(this.data));
  63 + this.map.updateMarkers(parseData(this.data));
  64 + }
  65 +
85 66 onDataUpdated() {
86 67 }
87 68
... ... @@ -173,4 +154,31 @@ TbMapWidgetV2 = class TbMapWidgetV2 implements MapWidgetInterface {
173 154
174 155 onDestroy() {
175 156 }
  157 +}
  158 +
  159 +const providerSets = {
  160 + 'openstreet-map': {
  161 + MapClass: OpenStreetMap,
  162 + schema: openstreetMapSettingsSchema,
  163 + name: "Openstreet"
  164 + },
  165 + 'tencent-map': {
  166 + MapClass: TencentMap,
  167 + schema: tencentMapSettingsSchema,
  168 + name: "Tencent"
  169 + },
  170 + 'google-map': {
  171 + MapClass: GoogleMap,
  172 + schema: googleMapSettingsSchema,
  173 + name: "Openstreet"
  174 + },
  175 + 'here': {
  176 + MapClass: HEREMap,
  177 + schema: hereMapSettingsSchema,
  178 + name: "HERE"
  179 + },
  180 + 'image-map': {
  181 + MapClass: ImageMap,
  182 + schema: imageMapSettingsSchema
  183 + }
176 184 }
\ No newline at end of file
... ...
1 1 import L from 'leaflet';
  2 +import _ from 'lodash';
2 3
3 4 export function createTooltip(target, settings, targetArgs?) {
4 5 var popup = L.popup();
... ... @@ -19,4 +20,27 @@ export function createTooltip(target, settings, targetArgs?) {
19 20 locationSettings: settings,
20 21 dsIndex: settings.dsIndex
21 22 };
  23 +}
  24 +
  25 +export function parseArray(input: any[]): any[] {
  26 + let alliases: any = _(input).groupBy(el => el?.datasource?.aliasName).values().value();
  27 + return alliases.map(alliasArray =>
  28 + alliasArray[0].data.map((el, i) => {
  29 + const obj = { aliasName: alliasArray[0]?.datasource?.aliasName };
  30 + alliasArray.forEach(el => {
  31 + obj[el?.dataKey?.label] = el?.data[i][1]
  32 + });
  33 + return obj;
  34 + })
  35 + ).flat();
  36 +}
  37 +
  38 +export function parseData(input: any[]): any[] {
  39 + return _(input).groupBy(el => el?.datasource?.aliasName).values().value().map(alliasArray => {
  40 + const obj = { aliasName: alliasArray[0]?.datasource?.aliasName };
  41 + alliasArray.forEach(el => {
  42 + obj[el?.dataKey?.label] = el?.data[0][1]
  43 + });
  44 + return obj;
  45 + });
22 46 }
\ No newline at end of file
... ...
... ... @@ -7,13 +7,14 @@ import { aspectCache } from '@app/core/utils';
7 7 export class Marker {
8 8
9 9 leafletMarker: L.Marker;
10   - // map: L.Map;
11 10
12 11 tooltipOffset;
13 12 tooltip;
  13 + location;
14 14
15 15 constructor(private map: L.Map, location: L.LatLngExpression, settings: MarkerSettings, onClickListener?, markerArgs?, onDragendListener?) {
16 16 //this.map = map;
  17 + this.location = location;
17 18 this.leafletMarker = L.marker(location, {
18 19 draggable: settings.draggable
19 20 });
... ... @@ -43,6 +44,10 @@ export class Marker {
43 44
44 45 }
45 46
  47 + updateMarkerPosition(position: L.LatLngExpression){
  48 + this.leafletMarker.setLatLng(position);
  49 + }
  50 +
46 51 updateMarkerLabel(settings) {
47 52 this.leafletMarker.unbindTooltip();
48 53 if (settings.showLabel)
... ... @@ -56,7 +61,7 @@ export class Marker {
56 61 });
57 62 }
58 63
59   - updateMarkerIcon( settings) {
  64 + updateMarkerIcon(settings) {
60 65 this.createMarkerIcon(settings, (iconInfo) => {
61 66 this.leafletMarker.setIcon(iconInfo.icon);
62 67 if (settings.showLabel) {
... ...
... ... @@ -2,10 +2,9 @@ import L from 'leaflet';
2 2
3 3 export class Polyline {
4 4
5   - map: L.Map;
6 5 leafletPoly: L.Polyline;
7 6
8   - constructor(locations, settings) {
  7 + constructor(private map: L.Map, locations, settings) {
9 8 this.leafletPoly = L.polyline(locations,
10 9 {
11 10 color: settings.color,
... ...
... ... @@ -101,13 +101,13 @@ export class ImageMap extends LeafletMap {
101 101 }
102 102 }
103 103
104   - convertPosition(expression: { x, y }): L.LatLngExpression {
105   - console.log("ImageMap -> expression", expression)
106   - return this.pointToLatLng(expression.x, expression.y) as L.LatLngExpression;
  104 + convertPosition(expression): L.LatLng {
  105 + return this.pointToLatLng(
  106 + expression[this.options.xPosKeyName] * this.width,
  107 + expression[this.options.yPosKeyName] * this.height);
107 108 }
108 109
109   -
110   - pointToLatLng(x, y) {
  110 + pointToLatLng(x, y): L.LatLng {
111 111 return L.CRS.Simple.pointToLatLng({ x, y } as L.PointExpression, maxZoom - 1);
112 112 }
113 113
... ...
... ... @@ -33,6 +33,7 @@
33 33 },
34 34 "lib": [
35 35 "es2018",
  36 + "es2019",
36 37 "dom"
37 38 ]
38 39 }
... ...