Showing
12 changed files
with
158 additions
and
67 deletions
... | ... | @@ -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", | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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 | ... | ... |