Showing
14 changed files
with
209 additions
and
137 deletions
@@ -21,7 +21,7 @@ import 'leaflet.markercluster/dist/MarkerCluster.css' | @@ -21,7 +21,7 @@ import 'leaflet.markercluster/dist/MarkerCluster.css' | ||
21 | import 'leaflet.markercluster/dist/MarkerCluster.Default.css' | 21 | import 'leaflet.markercluster/dist/MarkerCluster.Default.css' |
22 | import 'leaflet.markercluster/dist/leaflet.markercluster' | 22 | import 'leaflet.markercluster/dist/leaflet.markercluster' |
23 | 23 | ||
24 | -import { MapOptions, MarkerSettings } from './map-models'; | 24 | +import { MapSettings, MarkerSettings, FormattedData } from './map-models'; |
25 | import { Marker } from './markers'; | 25 | import { Marker } from './markers'; |
26 | import { Observable, of, BehaviorSubject, Subject } from 'rxjs'; | 26 | import { Observable, of, BehaviorSubject, Subject } from 'rxjs'; |
27 | import { filter } from 'rxjs/operators'; | 27 | import { filter } from 'rxjs/operators'; |
@@ -38,15 +38,15 @@ export default abstract class LeafletMap { | @@ -38,15 +38,15 @@ export default abstract class LeafletMap { | ||
38 | map: L.Map; | 38 | map: L.Map; |
39 | map$: BehaviorSubject<L.Map> = new BehaviorSubject(null); | 39 | map$: BehaviorSubject<L.Map> = new BehaviorSubject(null); |
40 | ready$: Observable<L.Map> = this.map$.pipe(filter(map => !!map)); | 40 | ready$: Observable<L.Map> = this.map$.pipe(filter(map => !!map)); |
41 | - options: MapOptions; | 41 | + options: MapSettings & MarkerSettings; |
42 | isMarketCluster: boolean; | 42 | isMarketCluster: boolean; |
43 | bounds: L.LatLngBounds; | 43 | bounds: L.LatLngBounds; |
44 | 44 | ||
45 | - constructor($container: HTMLElement, options: MapOptions) { | 45 | + constructor($container: HTMLElement, options: MapSettings & MarkerSettings) { |
46 | this.options = options; | 46 | this.options = options; |
47 | } | 47 | } |
48 | 48 | ||
49 | - public initSettings(options: MapOptions) { | 49 | + public initSettings(options: MapSettings) { |
50 | const { initCallback, | 50 | const { initCallback, |
51 | defaultZoomLevel, | 51 | defaultZoomLevel, |
52 | dontFitMapBounds, | 52 | dontFitMapBounds, |
@@ -56,7 +56,7 @@ export default abstract class LeafletMap { | @@ -56,7 +56,7 @@ export default abstract class LeafletMap { | ||
56 | credentials, | 56 | credentials, |
57 | defaultCenterPosition, | 57 | defaultCenterPosition, |
58 | draggebleMarker, | 58 | draggebleMarker, |
59 | - markerClusteringSetting }: MapOptions = options; | 59 | + markerClusteringSetting }: MapSettings = options; |
60 | if (disableScrollZooming) { | 60 | if (disableScrollZooming) { |
61 | this.map.scrollWheelZoom.disable(); | 61 | this.map.scrollWheelZoom.disable(); |
62 | } | 62 | } |
@@ -86,16 +86,12 @@ export default abstract class LeafletMap { | @@ -86,16 +86,12 @@ export default abstract class LeafletMap { | ||
86 | } | 86 | } |
87 | } as any); | 87 | } as any); |
88 | 88 | ||
89 | - L.control.addMarker = function (opts) { | 89 | + L.control.addMarker = (opts) => { |
90 | return new L.Control.AddMarker(opts); | 90 | return new L.Control.AddMarker(opts); |
91 | } | 91 | } |
92 | L.control.addMarker({ position: 'topright' }).addTo(this.map); | 92 | L.control.addMarker({ position: 'topright' }).addTo(this.map); |
93 | } | 93 | } |
94 | 94 | ||
95 | - /*inited() {/// !!!! | ||
96 | - return !!this.map; | ||
97 | - }*/ | ||
98 | - | ||
99 | public setMap(map: L.Map) { | 95 | public setMap(map: L.Map) { |
100 | this.map = map; | 96 | this.map = map; |
101 | if (this.options.useDefaultCenterPosition) { | 97 | if (this.options.useDefaultCenterPosition) { |
@@ -117,10 +113,6 @@ export default abstract class LeafletMap { | @@ -117,10 +113,6 @@ export default abstract class LeafletMap { | ||
117 | 113 | ||
118 | } | 114 | } |
119 | 115 | ||
120 | - getContainer() { | ||
121 | - return this.map; | ||
122 | - } | ||
123 | - | ||
124 | createLatLng(lat: number, lng: number): L.LatLng { | 116 | createLatLng(lat: number, lng: number): L.LatLng { |
125 | return L.latLng(lat, lng); | 117 | return L.latLng(lat, lng); |
126 | } | 118 | } |
@@ -147,8 +139,13 @@ export default abstract class LeafletMap { | @@ -147,8 +139,13 @@ export default abstract class LeafletMap { | ||
147 | return this.map.getCenter(); | 139 | return this.map.getCenter(); |
148 | } | 140 | } |
149 | 141 | ||
150 | - convertPosition(expression: any): L.LatLng { | ||
151 | - return L.latLng(expression[this.options.latKeyName], expression[this.options.lngKeyName]) as L.LatLng; | 142 | + convertPosition(expression: object): L.LatLng { |
143 | + const lat = expression[this.options.latKeyName]; | ||
144 | + const lng = expression[this.options.lngKeyName]; | ||
145 | + if (isNaN(lat) || isNaN(lng)) | ||
146 | + return null; | ||
147 | + else | ||
148 | + return L.latLng(lat, lng) as L.LatLng; | ||
152 | } | 149 | } |
153 | 150 | ||
154 | convertToCustomFormat(position: L.LatLng): object { | 151 | convertToCustomFormat(position: L.LatLng): object { |
@@ -161,24 +158,26 @@ export default abstract class LeafletMap { | @@ -161,24 +158,26 @@ export default abstract class LeafletMap { | ||
161 | // Markers | 158 | // Markers |
162 | updateMarkers(markersData) { | 159 | updateMarkers(markersData) { |
163 | markersData.forEach(data => { | 160 | markersData.forEach(data => { |
164 | - if (data.rotationAngle) { | ||
165 | - this.options.icon = L.divIcon({ | ||
166 | - html: `<div class="arrow" style="transform: rotate(${data.rotationAngle}deg)"><div>` | ||
167 | - }) | ||
168 | - } | ||
169 | - else { | ||
170 | - this.options.icon = null; | ||
171 | - } | ||
172 | - if (this.markers.get(data.aliasName)) { | ||
173 | - this.updateMarker(data.aliasName, data, markersData, this.options as MarkerSettings) | ||
174 | - } | ||
175 | - else { | ||
176 | - this.createMarker(data.aliasName, data, markersData, this.options as MarkerSettings); | 161 | + if (this.convertPosition(data)) { |
162 | + if (data.rotationAngle) { | ||
163 | + this.options.icon = L.divIcon({ | ||
164 | + html: `<div class="arrow" style="transform: rotate(${data.rotationAngle}deg)"><div>` | ||
165 | + }) | ||
166 | + } | ||
167 | + else { | ||
168 | + this.options.icon = null; | ||
169 | + } | ||
170 | + if (this.markers.get(data.aliasName)) { | ||
171 | + this.updateMarker(data.aliasName, data, markersData, this.options) | ||
172 | + } | ||
173 | + else { | ||
174 | + this.createMarker(data.aliasName, data, markersData, this.options as MarkerSettings); | ||
175 | + } | ||
177 | } | 176 | } |
178 | }); | 177 | }); |
179 | } | 178 | } |
180 | 179 | ||
181 | - private createMarker(key, data, dataSources, settings: MarkerSettings) { | 180 | + private createMarker(key, data: FormattedData, dataSources, settings: MarkerSettings) { |
182 | this.ready$.subscribe(() => { | 181 | this.ready$.subscribe(() => { |
183 | const newMarker = new Marker(this.map, this.convertPosition(data), settings, data, dataSources); | 182 | const newMarker = new Marker(this.map, this.convertPosition(data), settings, data, dataSources); |
184 | this.map.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng())); | 183 | this.map.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng())); |
@@ -219,10 +218,11 @@ export default abstract class LeafletMap { | @@ -219,10 +218,11 @@ export default abstract class LeafletMap { | ||
219 | }) | 218 | }) |
220 | } | 219 | } |
221 | 220 | ||
222 | - createPolyline(data, dataSources, settings) { | 221 | + createPolyline(data: any[], dataSources, settings) { |
223 | if (data.length) | 222 | if (data.length) |
224 | this.ready$.subscribe(() => { | 223 | this.ready$.subscribe(() => { |
225 | - this.poly = new Polyline(this.map, data.map(data => this.convertPosition(data)), data, dataSources, settings); | 224 | + this.poly = new Polyline(this.map, |
225 | + data.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); | ||
226 | const bounds = this.bounds.extend(this.poly.leafletPoly.getBounds()); | 226 | const bounds = this.bounds.extend(this.poly.leafletPoly.getBounds()); |
227 | if (bounds.isValid()) { | 227 | if (bounds.isValid()) { |
228 | this.map.fitBounds(bounds); | 228 | this.map.fitBounds(bounds); |
@@ -237,7 +237,7 @@ export default abstract class LeafletMap { | @@ -237,7 +237,7 @@ export default abstract class LeafletMap { | ||
237 | }); | 237 | }); |
238 | } | 238 | } |
239 | 239 | ||
240 | - // polygon | 240 | + // Polygon |
241 | 241 | ||
242 | updatePolygons(polyData: Array<Array<any>>) { | 242 | updatePolygons(polyData: Array<Array<any>>) { |
243 | polyData.forEach((data: any) => { | 243 | polyData.forEach((data: any) => { |
@@ -268,7 +268,7 @@ export default abstract class LeafletMap { | @@ -268,7 +268,7 @@ export default abstract class LeafletMap { | ||
268 | 268 | ||
269 | updatePolygon(data, dataSources, settings) { | 269 | updatePolygon(data, dataSources, settings) { |
270 | this.ready$.subscribe(() => { | 270 | this.ready$.subscribe(() => { |
271 | - // this.polygon.updatePolygon(settings, data, dataSources); | 271 | + // this.polygon.updatePolygon(settings, data, dataSources); |
272 | }); | 272 | }); |
273 | } | 273 | } |
274 | } | 274 | } |
1 | /// | 1 | /// |
2 | /// Copyright © 2016-2020 The Thingsboard Authors | 2 | /// Copyright © 2016-2020 The Thingsboard Authors |
3 | /// | 3 | /// |
4 | -/// Licensed under the Apache License, Version 2.0 (the "License"); | 4 | +/// Licensed under the Apache License; Version 2.0 (the "License"); |
5 | /// you may not use this file except in compliance with the License. | 5 | /// you may not use this file except in compliance with the License. |
6 | /// You may obtain a copy of the License at | 6 | /// You may obtain a copy of the License at |
7 | /// | 7 | /// |
8 | /// http://www.apache.org/licenses/LICENSE-2.0 | 8 | /// http://www.apache.org/licenses/LICENSE-2.0 |
9 | /// | 9 | /// |
10 | -/// Unless required by applicable law or agreed to in writing, software | ||
11 | -/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 10 | +/// Unless required by applicable law or agreed to in writing; software |
11 | +/// distributed under the License is distributed on an "AS IS" BASIS; | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND; either express or implied. | ||
13 | /// See the License for the specific language governing permissions and | 13 | /// See the License for the specific language governing permissions and |
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { LatLngExpression, LatLngTuple } from 'leaflet'; | 17 | +import { LatLngTuple } from 'leaflet'; |
18 | 18 | ||
19 | -export interface MapOptions { | 19 | +export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; |
20 | +export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string; | ||
21 | + | ||
22 | +export type MapSettings = { | ||
20 | polygonKeyName: any; | 23 | polygonKeyName: any; |
21 | draggebleMarker: any; | 24 | draggebleMarker: any; |
22 | - initCallback?: Function, | ||
23 | - defaultZoomLevel?: number, | ||
24 | - dontFitMapBounds?: boolean, | ||
25 | - disableScrollZooming?: boolean, | ||
26 | - minZoomLevel?: number, | ||
27 | - latKeyName?: string, | ||
28 | - lngKeyName?: string, | ||
29 | - xPosKeyName?: string, | ||
30 | - yPosKeyName?: string, | ||
31 | - mapProvider: MapProviders, | 25 | + initCallback?: () => any; |
26 | + defaultZoomLevel?: number; | ||
27 | + dontFitMapBounds?: boolean; | ||
28 | + disableScrollZooming?: boolean; | ||
29 | + minZoomLevel?: number; | ||
30 | + latKeyName?: string; | ||
31 | + lngKeyName?: string; | ||
32 | + xPosKeyName?: string; | ||
33 | + yPosKeyName?: string; | ||
34 | + mapProvider: MapProviders; | ||
32 | mapUrl?: string; | 35 | mapUrl?: string; |
33 | - credentials?: any, // declare credentials format | ||
34 | - defaultCenterPosition?: LatLngTuple, | ||
35 | - markerClusteringSetting?, | ||
36 | - useDefaultCenterPosition?: boolean, | ||
37 | - gmDefaultMapType?: string, | 36 | + credentials?: any; // declare credentials format |
37 | + defaultCenterPosition?: LatLngTuple; | ||
38 | + markerClusteringSetting?; | ||
39 | + useDefaultCenterPosition?: boolean; | ||
40 | + gmDefaultMapType?: string; | ||
38 | useLabelFunction: string; | 41 | useLabelFunction: string; |
39 | icon?: any; | 42 | icon?: any; |
40 | } | 43 | } |
@@ -47,15 +50,73 @@ export enum MapProviders { | @@ -47,15 +50,73 @@ export enum MapProviders { | ||
47 | tencent = 'tencent-map' | 50 | tencent = 'tencent-map' |
48 | } | 51 | } |
49 | 52 | ||
50 | -export interface MarkerSettings extends MapOptions { | 53 | +export type MarkerSettings = { |
51 | tooltipPattern?: any; | 54 | tooltipPattern?: any; |
52 | icon?: any; | 55 | icon?: any; |
53 | - showLabel?: boolean, | ||
54 | - draggable?: boolean, | ||
55 | - showTooltip?: boolean, | ||
56 | - color?: string, | 56 | + showLabel?: boolean; |
57 | + label: string; | ||
58 | + labelColor: string; | ||
59 | + labelText: string; | ||
60 | + useLabelFunction: boolean; | ||
61 | + draggable?: boolean; | ||
62 | + showTooltip?: boolean; | ||
63 | + color?: string; | ||
64 | + autocloseTooltip: boolean; | ||
65 | + displayTooltipAction: string; | ||
57 | currentImage?: string; | 66 | currentImage?: string; |
58 | - useMarkerImageFunction?: boolean, | ||
59 | - markerImages?: string[], | ||
60 | - markerImageFunction?: Function; | ||
61 | -} | ||
67 | + useMarkerImageFunction?: boolean; | ||
68 | + markerImages?: string[]; | ||
69 | + | ||
70 | + labelFunction: GenericFunction; | ||
71 | + markerImageFunction?: MarkerImageFunction; | ||
72 | +} | ||
73 | + | ||
74 | +export interface FormattedData { | ||
75 | + aliasName: string; | ||
76 | + entityName: string; | ||
77 | + $datasource: string; | ||
78 | + dsIndex: number; | ||
79 | + deviceType: string | ||
80 | +} | ||
81 | + | ||
82 | +export type PolygonSettings = { | ||
83 | + showPolygon: boolean; | ||
84 | + showTooltip: any; | ||
85 | + polygonStrokeOpacity: number; | ||
86 | + polygonOpacity: number; | ||
87 | + polygonStrokeWeight: number; | ||
88 | + polygonStrokeColor: string; | ||
89 | + polygonColor: string; | ||
90 | + autocloseTooltip: boolean; | ||
91 | + displayTooltipAction: string; | ||
92 | +} | ||
93 | + | ||
94 | +export type PolylineSettings = { | ||
95 | + usePolylineDecorator: any; | ||
96 | + autocloseTooltip: boolean; | ||
97 | + displayTooltipAction: string; | ||
98 | + useColorFunction: any; | ||
99 | + color: string; | ||
100 | + useStrokeOpacityFunction: any; | ||
101 | + strokeOpacity: number; | ||
102 | + useStrokeWeightFunction: any; | ||
103 | + strokeWeight: number; | ||
104 | + decoratorOffset: string | number; | ||
105 | + endDecoratorOffset: string | number; | ||
106 | + decoratorRepeat: string | number; | ||
107 | + decoratorSymbol: any; | ||
108 | + decoratorSymbolSize: any; | ||
109 | + useDecoratorCustomColor: any; | ||
110 | + decoratorCustomColor: any; | ||
111 | + | ||
112 | + | ||
113 | + colorFunction(colorFunction: any, arg1: any[]): string; | ||
114 | + strokeOpacityFunction(strokeOpacityFunction: any, arg1: any[]): number; | ||
115 | + strokeWeightFunction(strokeWeightFunction: any, arg1: any[]): number; | ||
116 | +} | ||
117 | + | ||
118 | +export interface HistorySelectSettings { | ||
119 | + buttonColor: string; | ||
120 | +} | ||
121 | + | ||
122 | +export type UnitedMapSettings = MapSettings & PolygonSettings & MarkerSettings & PolygonSettings; |
@@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { MapProviders, MapOptions } from './map-models'; | 17 | +import { MapProviders, MapSettings, MarkerSettings, PolygonSettings, UnitedMapSettings } from './map-models'; |
18 | import LeafletMap from './leaflet-map'; | 18 | import LeafletMap from './leaflet-map'; |
19 | import { | 19 | import { |
20 | openstreetMapSettingsSchema, | 20 | openstreetMapSettingsSchema, |
@@ -63,7 +63,7 @@ export class MapWidgetController implements MapWidgetInterface { | @@ -63,7 +63,7 @@ export class MapWidgetController implements MapWidgetInterface { | ||
63 | provider: MapProviders; | 63 | provider: MapProviders; |
64 | schema; | 64 | schema; |
65 | data; | 65 | data; |
66 | - settings; | 66 | + settings:UnitedMapSettings; |
67 | 67 | ||
68 | public static dataKeySettingsSchema(): Object { | 68 | public static dataKeySettingsSchema(): Object { |
69 | return {}; | 69 | return {}; |
@@ -16,12 +16,13 @@ | @@ -16,12 +16,13 @@ | ||
16 | 16 | ||
17 | import L from 'leaflet'; | 17 | import L from 'leaflet'; |
18 | import _ from 'lodash'; | 18 | import _ from 'lodash'; |
19 | +import { MarkerSettings, PolylineSettings, PolygonSettings } from './map-models'; | ||
19 | 20 | ||
20 | -export function createTooltip(target: L.Layer, settings): L.Popup { | 21 | +export function createTooltip(target: L.Layer, settings: MarkerSettings | PolylineSettings | PolygonSettings): L.Popup { |
21 | const popup = L.popup(); | 22 | const popup = L.popup(); |
22 | popup.setContent(''); | 23 | popup.setContent(''); |
23 | target.bindPopup(popup, { autoClose: settings.autocloseTooltip, closeOnClick: false }); | 24 | target.bindPopup(popup, { autoClose: settings.autocloseTooltip, closeOnClick: false }); |
24 | - if (settings.displayTooltipAction == 'hover') { | 25 | + if (settings.displayTooltipAction === 'hover') { |
25 | target.off('click'); | 26 | target.off('click'); |
26 | target.on('mouseover', function () { | 27 | target.on('mouseover', function () { |
27 | this.openPopup(); | 28 | this.openPopup(); |
@@ -40,6 +41,6 @@ export function getRatio(firsMoment: number, secondMoment: number, intermediateM | @@ -40,6 +41,6 @@ export function getRatio(firsMoment: number, secondMoment: number, intermediateM | ||
40 | export function findAngle(startPoint, endPoint) { | 41 | export function findAngle(startPoint, endPoint) { |
41 | let angle = -Math.atan2(endPoint.latitude - startPoint.latitude, endPoint.longitude - startPoint.longitude); | 42 | let angle = -Math.atan2(endPoint.latitude - startPoint.latitude, endPoint.longitude - startPoint.longitude); |
42 | angle = angle * 180 / Math.PI; | 43 | angle = angle * 180 / Math.PI; |
43 | - return parseInt(angle.toFixed(2)); | 44 | + return parseInt(angle.toFixed(2), 10); |
44 | } | 45 | } |
45 | 46 |
@@ -15,23 +15,20 @@ | @@ -15,23 +15,20 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import L from 'leaflet'; | 17 | import L from 'leaflet'; |
18 | -import { MarkerSettings } from './map-models'; | 18 | +import { MarkerSettings, FormattedData } from './map-models'; |
19 | import { aspectCache, safeExecute, parseTemplate } from '@app/core/utils'; | 19 | import { aspectCache, safeExecute, parseTemplate } from '@app/core/utils'; |
20 | import { createTooltip } from './maps-utils'; | 20 | import { createTooltip } from './maps-utils'; |
21 | 21 | ||
22 | export class Marker { | 22 | export class Marker { |
23 | 23 | ||
24 | leafletMarker: L.Marker; | 24 | leafletMarker: L.Marker; |
25 | - | ||
26 | - tooltipOffset; | ||
27 | - tooltip; | ||
28 | - location; | ||
29 | - data; | ||
30 | - dataSources; | 25 | + tooltipOffset: [number, number]; |
26 | + tooltip: L.Popup; | ||
27 | + location: L.LatLngExpression; | ||
28 | + data: FormattedData; | ||
29 | + dataSources: FormattedData[]; | ||
31 | 30 | ||
32 | constructor(private map: L.Map, location: L.LatLngExpression, public settings: MarkerSettings, data?, dataSources?, onClickListener?, onDragendListener?) { | 31 | constructor(private map: L.Map, location: L.LatLngExpression, public settings: MarkerSettings, data?, dataSources?, onClickListener?, onDragendListener?) { |
33 | - // this.map = map; | ||
34 | - this.location = location; | ||
35 | this.setDataSources(data, dataSources); | 32 | this.setDataSources(data, dataSources); |
36 | this.leafletMarker = L.marker(location, { | 33 | this.leafletMarker = L.marker(location, { |
37 | draggable: settings.draggable | 34 | draggable: settings.draggable |
@@ -58,12 +55,12 @@ export class Marker { | @@ -58,12 +55,12 @@ export class Marker { | ||
58 | } | 55 | } |
59 | } | 56 | } |
60 | 57 | ||
61 | - setDataSources(data, dataSources) { | 58 | + setDataSources(data: FormattedData, dataSources: FormattedData[]) { |
62 | this.data = data; | 59 | this.data = data; |
63 | this.dataSources = dataSources; | 60 | this.dataSources = dataSources; |
64 | } | 61 | } |
65 | 62 | ||
66 | - updateMarkerTooltip(data) { | 63 | + updateMarkerTooltip(data: FormattedData) { |
67 | this.tooltip.setContent(parseTemplate(this.settings.tooltipPattern, data)); | 64 | this.tooltip.setContent(parseTemplate(this.settings.tooltipPattern, data)); |
68 | } | 65 | } |
69 | 66 | ||
@@ -71,7 +68,7 @@ export class Marker { | @@ -71,7 +68,7 @@ export class Marker { | ||
71 | this.leafletMarker.setLatLng(position); | 68 | this.leafletMarker.setLatLng(position); |
72 | } | 69 | } |
73 | 70 | ||
74 | - updateMarkerLabel(settings) { | 71 | + updateMarkerLabel(settings: MarkerSettings) { |
75 | this.leafletMarker.unbindTooltip(); | 72 | this.leafletMarker.unbindTooltip(); |
76 | 73 | ||
77 | if (settings.showLabel) { | 74 | if (settings.showLabel) { |
@@ -90,7 +87,7 @@ export class Marker { | @@ -90,7 +87,7 @@ export class Marker { | ||
90 | }); | 87 | }); |
91 | } | 88 | } |
92 | 89 | ||
93 | - updateMarkerIcon(settings) { | 90 | + updateMarkerIcon(settings: MarkerSettings) { |
94 | this.createMarkerIcon((iconInfo) => { | 91 | this.createMarkerIcon((iconInfo) => { |
95 | this.leafletMarker.setIcon(iconInfo.icon); | 92 | this.leafletMarker.setIcon(iconInfo.icon); |
96 | this.tooltipOffset = [0, -iconInfo.size[1] + 10]; | 93 | this.tooltipOffset = [0, -iconInfo.size[1] + 10]; |
@@ -14,15 +14,16 @@ | @@ -14,15 +14,16 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import L from 'leaflet'; | 17 | +import L, { LatLngExpression } from 'leaflet'; |
18 | import { createTooltip } from './maps-utils'; | 18 | import { createTooltip } from './maps-utils'; |
19 | +import { PolygonSettings } from './map-models'; | ||
19 | 20 | ||
20 | export class Polygon { | 21 | export class Polygon { |
21 | 22 | ||
22 | leafletPoly: L.Polygon; | 23 | leafletPoly: L.Polygon; |
23 | tooltip; | 24 | tooltip; |
24 | 25 | ||
25 | - constructor(public map, coordinates, dataSources, settings, onClickListener?) { | 26 | + constructor(public map, coordinates, dataSources, settings: PolygonSettings, onClickListener?) { |
26 | this.leafletPoly = L.polygon(coordinates, { | 27 | this.leafletPoly = L.polygon(coordinates, { |
27 | fill: true, | 28 | fill: true, |
28 | fillColor: settings.polygonColor, | 29 | fillColor: settings.polygonColor, |
@@ -33,7 +34,7 @@ export class Polygon { | @@ -33,7 +34,7 @@ export class Polygon { | ||
33 | }).addTo(this.map); | 34 | }).addTo(this.map); |
34 | 35 | ||
35 | if (settings.showTooltip) { | 36 | if (settings.showTooltip) { |
36 | - this.tooltip = createTooltip(this.leafletPoly, settings); | 37 | + this.tooltip = createTooltip(this.leafletPoly, settings); |
37 | } | 38 | } |
38 | if (onClickListener) { | 39 | if (onClickListener) { |
39 | this.leafletPoly.on('click', onClickListener); | 40 | this.leafletPoly.on('click', onClickListener); |
@@ -44,11 +45,13 @@ export class Polygon { | @@ -44,11 +45,13 @@ export class Polygon { | ||
44 | this.map.removeLayer(this.leafletPoly); | 45 | this.map.removeLayer(this.leafletPoly); |
45 | } | 46 | } |
46 | 47 | ||
47 | - updatePolygonColor(settings, color) { | ||
48 | - const style = { | 48 | + updatePolygonColor(settings) { |
49 | + console.log('Polygon -> updatePolygonColor -> settings', settings) | ||
50 | + const style: L.PathOptions = { | ||
51 | + | ||
49 | fill: true, | 52 | fill: true, |
50 | - fillColor: color, | ||
51 | - color, | 53 | + fillColor: settings.color, |
54 | + color: settings.color, | ||
52 | weight: settings.polygonStrokeWeight, | 55 | weight: settings.polygonStrokeWeight, |
53 | fillOpacity: settings.polygonOpacity, | 56 | fillOpacity: settings.polygonOpacity, |
54 | opacity: settings.polygonStrokeOpacity | 57 | opacity: settings.polygonStrokeOpacity |
@@ -60,7 +63,7 @@ export class Polygon { | @@ -60,7 +63,7 @@ export class Polygon { | ||
60 | return this.leafletPoly.getLatLngs(); | 63 | return this.leafletPoly.getLatLngs(); |
61 | } | 64 | } |
62 | 65 | ||
63 | - setPolygonLatLngs(latLngs) { | 66 | + setPolygonLatLngs(latLngs: LatLngExpression[]) { |
64 | this.leafletPoly.setLatLngs(latLngs); | 67 | this.leafletPoly.setLatLngs(latLngs); |
65 | this.leafletPoly.redraw(); | 68 | this.leafletPoly.redraw(); |
66 | } | 69 | } |
@@ -18,51 +18,62 @@ import L, { PolylineDecoratorOptions } from 'leaflet'; | @@ -18,51 +18,62 @@ import L, { PolylineDecoratorOptions } from 'leaflet'; | ||
18 | import 'leaflet-polylinedecorator'; | 18 | import 'leaflet-polylinedecorator'; |
19 | 19 | ||
20 | import { safeExecute } from '@app/core/utils'; | 20 | import { safeExecute } from '@app/core/utils'; |
21 | +import { PolylineSettings, PolygonSettings } from './map-models'; | ||
21 | 22 | ||
22 | export class Polyline { | 23 | export class Polyline { |
23 | 24 | ||
24 | leafletPoly: L.Polyline; | 25 | leafletPoly: L.Polyline; |
26 | + polylineDecorator: L.PolylineDecorator; | ||
25 | dataSources; | 27 | dataSources; |
26 | data; | 28 | data; |
27 | 29 | ||
28 | - constructor(private map: L.Map, locations, data, dataSources, settings) { | 30 | + constructor(private map: L.Map, locations, data, dataSources, settings: PolylineSettings) { |
29 | this.dataSources = dataSources; | 31 | this.dataSources = dataSources; |
30 | this.data = data; | 32 | this.data = data; |
31 | 33 | ||
32 | this.leafletPoly = L.polyline(locations, | 34 | this.leafletPoly = L.polyline(locations, |
33 | - this.getPolyStyle(settings, data, dataSources) | 35 | + this.getPolyStyle(settings) |
34 | ).addTo(this.map); | 36 | ).addTo(this.map); |
35 | if (settings.usePolylineDecorator) { | 37 | if (settings.usePolylineDecorator) { |
36 | - L.polylineDecorator(this.leafletPoly, { | ||
37 | - patterns: [ | ||
38 | - { | ||
39 | - offset: settings.decoratorOffset, | ||
40 | - endOffset: settings.endDecoratorOffset, | ||
41 | - repeat: settings.decoratorRepeat, | ||
42 | - symbol: L.Symbol[settings.decoratorSymbol]({ | ||
43 | - pixelSize: settings.decoratorSymbolSize, | ||
44 | - polygon: false, | ||
45 | - pathOptions: { | ||
46 | - color: settings.useDecoratorCustomColor ? settings.decoratorCustomColor : this.getPolyStyle(settings, data, dataSources).color, | ||
47 | - stroke: true | ||
48 | - } | ||
49 | - }) | ||
50 | - } | ||
51 | - ], | ||
52 | - interactive: false, | ||
53 | - } as PolylineDecoratorOptions).addTo(this.map); | 38 | + this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map); |
54 | } | 39 | } |
55 | } | 40 | } |
56 | 41 | ||
42 | + getDecoratorSettings(settings: PolylineSettings): PolylineDecoratorOptions { | ||
43 | + return { | ||
44 | + patterns: [ | ||
45 | + { | ||
46 | + offset: settings.decoratorOffset, | ||
47 | + endOffset: settings.endDecoratorOffset, | ||
48 | + repeat: settings.decoratorRepeat, | ||
49 | + symbol: L.Symbol[settings.decoratorSymbol]({ | ||
50 | + pixelSize: settings.decoratorSymbolSize, | ||
51 | + polygon: false, | ||
52 | + pathOptions: { | ||
53 | + color: settings.useDecoratorCustomColor ? settings.decoratorCustomColor : this.getPolyStyle(settings).color, | ||
54 | + stroke: true | ||
55 | + } | ||
56 | + }) | ||
57 | + } | ||
58 | + ], | ||
59 | + interactive: false, | ||
60 | + } as PolylineDecoratorOptions | ||
61 | + } | ||
62 | + | ||
57 | updatePolyline(settings, data, dataSources) { | 63 | updatePolyline(settings, data, dataSources) { |
58 | - this.leafletPoly.setStyle(this.getPolyStyle(settings, data, dataSources)); | 64 | + this.leafletPoly.setStyle(this.getPolyStyle(settings)); |
65 | + this.setPolylineLatLngs(data); | ||
66 | + this.polylineDecorator.setPaths(this.leafletPoly); | ||
59 | } | 67 | } |
60 | 68 | ||
61 | - getPolyStyle(settings, data, dataSources): L.PolylineOptions { | 69 | + getPolyStyle(settings: PolylineSettings): L.PolylineOptions { |
62 | return { | 70 | return { |
63 | - color: settings.useColorFunction ? safeExecute(settings.colorFunction, [data, dataSources, data[0]?.dsIndex]) : settings.color, | ||
64 | - opacity: settings.useStrokeOpacityFunction ? safeExecute(settings.strokeOpacityFunction, [data, dataSources, data[0]?.dsIndex]) : settings.strokeOpacity, | ||
65 | - weight: settings.useStrokeWeightFunction ? safeExecute(settings.strokeWeightFunction, [data, dataSources, data[0]?.dsIndex]) : settings.strokeWeight, | 71 | + color: settings.useColorFunction ? |
72 | + safeExecute(settings.colorFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.color, | ||
73 | + opacity: settings.useStrokeOpacityFunction ? | ||
74 | + safeExecute(settings.strokeOpacityFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.strokeOpacity, | ||
75 | + weight: settings.useStrokeWeightFunction ? | ||
76 | + safeExecute(settings.strokeWeightFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.strokeWeight, | ||
66 | } | 77 | } |
67 | } | 78 | } |
68 | 79 |
@@ -17,14 +17,14 @@ | @@ -17,14 +17,14 @@ | ||
17 | 17 | ||
18 | import L from 'leaflet'; | 18 | import L from 'leaflet'; |
19 | import LeafletMap from '../leaflet-map'; | 19 | import LeafletMap from '../leaflet-map'; |
20 | -import { MapOptions } from '../map-models'; | 20 | +import { MapSettings, UnitedMapSettings } from '../map-models'; |
21 | import 'leaflet.gridlayer.googlemutant'; | 21 | import 'leaflet.gridlayer.googlemutant'; |
22 | 22 | ||
23 | let googleLoaded = false; | 23 | let googleLoaded = false; |
24 | 24 | ||
25 | 25 | ||
26 | export class GoogleMap extends LeafletMap { | 26 | export class GoogleMap extends LeafletMap { |
27 | - constructor($container, options: MapOptions) { | 27 | + constructor($container, options: UnitedMapSettings) { |
28 | 28 | ||
29 | super($container, options); | 29 | super($container, options); |
30 | this.loadGoogle(() => { | 30 | this.loadGoogle(() => { |
@@ -16,11 +16,10 @@ | @@ -16,11 +16,10 @@ | ||
16 | 16 | ||
17 | import L from 'leaflet'; | 17 | import L from 'leaflet'; |
18 | import LeafletMap from '../leaflet-map'; | 18 | import LeafletMap from '../leaflet-map'; |
19 | -import { MapOptions } from '../map-models'; | 19 | +import { MapSettings, UnitedMapSettings } from '../map-models'; |
20 | 20 | ||
21 | export class HEREMap extends LeafletMap { | 21 | export class HEREMap extends LeafletMap { |
22 | - constructor($container, options: MapOptions) { | ||
23 | - console.log('HEREMap -> constructor -> options', options) | 22 | + constructor($container, options: UnitedMapSettings) { |
24 | const defaultCredentials = | 23 | const defaultCredentials = |
25 | { | 24 | { |
26 | app_id: 'AhM6TzD9ThyK78CT3ptx', | 25 | app_id: 'AhM6TzD9ThyK78CT3ptx', |
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | 16 | ||
17 | import L from 'leaflet'; | 17 | import L from 'leaflet'; |
18 | import LeafletMap from '../leaflet-map'; | 18 | import LeafletMap from '../leaflet-map'; |
19 | -import { MapOptions } from '../map-models'; | 19 | +import { MapSettings, UnitedMapSettings } from '../map-models'; |
20 | import { aspectCache } from '@app/core/utils'; | 20 | import { aspectCache } from '@app/core/utils'; |
21 | 21 | ||
22 | const maxZoom = 4;// ? | 22 | const maxZoom = 4;// ? |
@@ -28,7 +28,7 @@ export class ImageMap extends LeafletMap { | @@ -28,7 +28,7 @@ export class ImageMap extends LeafletMap { | ||
28 | width = 0; | 28 | width = 0; |
29 | height = 0; | 29 | height = 0; |
30 | 30 | ||
31 | - constructor(private $container: HTMLElement, options: MapOptions) { | 31 | + constructor(private $container: HTMLElement, options: UnitedMapSettings) { |
32 | super($container, options); | 32 | super($container, options); |
33 | aspectCache(options.mapUrl).subscribe(aspect => { | 33 | aspectCache(options.mapUrl).subscribe(aspect => { |
34 | this.aspect = aspect; | 34 | this.aspect = aspect; |
@@ -16,10 +16,10 @@ | @@ -16,10 +16,10 @@ | ||
16 | 16 | ||
17 | import L from 'leaflet'; | 17 | import L from 'leaflet'; |
18 | import LeafletMap from '../leaflet-map'; | 18 | import LeafletMap from '../leaflet-map'; |
19 | -import { MapOptions } from '../map-models'; | 19 | +import { MapSettings, UnitedMapSettings } from '../map-models'; |
20 | 20 | ||
21 | export class OpenStreetMap extends LeafletMap { | 21 | export class OpenStreetMap extends LeafletMap { |
22 | - constructor($container, options: MapOptions) { | 22 | + constructor($container, options: UnitedMapSettings) { |
23 | super($container, options); | 23 | super($container, options); |
24 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); | 24 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); |
25 | const tileLayer = (L.tileLayer as any).provider('OpenStreetMap.Mapnik'); | 25 | const tileLayer = (L.tileLayer as any).provider('OpenStreetMap.Mapnik'); |
@@ -17,10 +17,10 @@ | @@ -17,10 +17,10 @@ | ||
17 | 17 | ||
18 | import L from 'leaflet'; | 18 | import L from 'leaflet'; |
19 | import LeafletMap from '../leaflet-map'; | 19 | import LeafletMap from '../leaflet-map'; |
20 | -import { MapOptions } from '../map-models'; | 20 | +import { MapSettings, UnitedMapSettings } from '../map-models'; |
21 | 21 | ||
22 | export class TencentMap extends LeafletMap { | 22 | export class TencentMap extends LeafletMap { |
23 | - constructor($container, options: MapOptions) { | 23 | + constructor($container, options: UnitedMapSettings) { |
24 | super($container, options); | 24 | super($container, options); |
25 | const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; | 25 | const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0'; |
26 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); | 26 | const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel); |
@@ -97,7 +97,6 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | @@ -97,7 +97,6 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | ||
97 | timeUpdated(time: number) { | 97 | timeUpdated(time: number) { |
98 | const currentPosition = this.interpolatedData.map(dataSource => dataSource[time]); | 98 | const currentPosition = this.interpolatedData.map(dataSource => dataSource[time]); |
99 | this.activeTrip = currentPosition[0]; | 99 | this.activeTrip = currentPosition[0]; |
100 | - console.log("TripAnimationComponent -> timeUpdated -> this.interpolatedData", this.interpolatedData) | ||
101 | if (this.settings.showPolygon) { | 100 | if (this.settings.showPolygon) { |
102 | this.mapWidget.map.updatePolygons(this.interpolatedData); | 101 | this.mapWidget.map.updatePolygons(this.interpolatedData); |
103 | } | 102 | } |
@@ -120,11 +119,11 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | @@ -120,11 +119,11 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | ||
120 | } | 119 | } |
121 | 120 | ||
122 | showHideTooltip() { | 121 | showHideTooltip() { |
123 | - const tooltipText: string = this.settings.useTooltipFunction ? safeExecute(this.settings.tooolTipFunction, [this.activeTrip, this.historicalData, 0]) | 122 | + const tooltipText: string = this.settings.useTooltipFunction ? |
123 | + safeExecute(this.settings.tooolTipFunction, [this.activeTrip, this.historicalData, 0]) | ||
124 | : this.settings.tooltipPattern; | 124 | : this.settings.tooltipPattern; |
125 | 125 | ||
126 | this.mainTooltip = this.sanitizer.sanitize(SecurityContext.HTML, parseTemplate(tooltipText, this.activeTrip)) | 126 | this.mainTooltip = this.sanitizer.sanitize(SecurityContext.HTML, parseTemplate(tooltipText, this.activeTrip)) |
127 | - console.log("TripAnimationComponent -> showHideTooltip -> this.mainTooltip", this.mainTooltip) | ||
128 | this.visibleTooltip = !this.visibleTooltip; | 127 | this.visibleTooltip = !this.visibleTooltip; |
129 | } | 128 | } |
130 | 129 | ||
@@ -132,7 +131,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | @@ -132,7 +131,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { | ||
132 | 131 | ||
133 | const result = {}; | 132 | const result = {}; |
134 | 133 | ||
135 | - for (let i = 1, j = 0; i < originData.length, j < interpolatedIntervals.length;) { | 134 | + for (let i = 1, j = 0; i < originData.length && j < interpolatedIntervals.length;) { |
136 | const currentTime = interpolatedIntervals[j]; | 135 | const currentTime = interpolatedIntervals[j]; |
137 | while (originData[i].time < currentTime) i++; | 136 | while (originData[i].time < currentTime) i++; |
138 | const before = originData[i - 1]; | 137 | const before = originData[i - 1]; |
@@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
17 | import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; | 17 | import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; |
18 | import { interval, Subscription, Subscriber, SubscriptionLike, Observer } from 'rxjs'; | 18 | import { interval, Subscription, Subscriber, SubscriptionLike, Observer } from 'rxjs'; |
19 | import { filter, tap } from 'rxjs/operators'; | 19 | import { filter, tap } from 'rxjs/operators'; |
20 | +import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/maps/map-models'; | ||
20 | 21 | ||
21 | @Component({ | 22 | @Component({ |
22 | selector: 'tb-history-selector', | 23 | selector: 'tb-history-selector', |
@@ -25,10 +26,10 @@ import { filter, tap } from 'rxjs/operators'; | @@ -25,10 +26,10 @@ import { filter, tap } from 'rxjs/operators'; | ||
25 | }) | 26 | }) |
26 | export class HistorySelectorComponent implements OnInit, OnChanges { | 27 | export class HistorySelectorComponent implements OnInit, OnChanges { |
27 | 28 | ||
28 | - @Input() settings | 29 | + @Input() settings: HistorySelectSettings |
29 | @Input() intervals = []; | 30 | @Input() intervals = []; |
30 | 31 | ||
31 | - @Output() onTimeUpdated: EventEmitter<number> = new EventEmitter(); | 32 | + @Output() timeUpdated: EventEmitter<number> = new EventEmitter(); |
32 | 33 | ||
33 | animationTime; | 34 | animationTime; |
34 | minTimeIndex = 0; | 35 | minTimeIndex = 0; |
@@ -58,7 +59,7 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | @@ -58,7 +59,7 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | ||
58 | tap(() => this.index++)).subscribe(() => { | 59 | tap(() => this.index++)).subscribe(() => { |
59 | if (this.index < this.maxTimeIndex) { | 60 | if (this.index < this.maxTimeIndex) { |
60 | this.cd.detectChanges(); | 61 | this.cd.detectChanges(); |
61 | - this.onTimeUpdated.emit(this.intervals[this.index]); | 62 | + this.timeUpdated.emit(this.intervals[this.index]); |
62 | } | 63 | } |
63 | else { | 64 | else { |
64 | this.interval.complete(); | 65 | this.interval.complete(); |
@@ -70,12 +71,12 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | @@ -70,12 +71,12 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | ||
70 | this.playing = false; | 71 | this.playing = false; |
71 | this.interval = null; | 72 | this.interval = null; |
72 | this.cd.detectChanges(); | 73 | this.cd.detectChanges(); |
73 | - }); | 74 | + }); |
74 | } | 75 | } |
75 | 76 | ||
76 | reeneble() { | 77 | reeneble() { |
77 | if (this.playing) { | 78 | if (this.playing) { |
78 | - let position = this.index; | 79 | + const position = this.index; |
79 | this.interval.complete(); | 80 | this.interval.complete(); |
80 | this.index = position; | 81 | this.index = position; |
81 | this.play(); | 82 | this.play(); |
@@ -85,7 +86,7 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | @@ -85,7 +86,7 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | ||
85 | pause() { | 86 | pause() { |
86 | this.playing = false; | 87 | this.playing = false; |
87 | this.cd.detectChanges(); | 88 | this.cd.detectChanges(); |
88 | - this.onTimeUpdated.emit(this.intervals[this.index]); | 89 | + this.timeUpdated.emit(this.intervals[this.index]); |
89 | } | 90 | } |
90 | 91 | ||
91 | moveNext() { | 92 | moveNext() { |
@@ -113,6 +114,6 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | @@ -113,6 +114,6 @@ export class HistorySelectorComponent implements OnInit, OnChanges { | ||
113 | } | 114 | } |
114 | 115 | ||
115 | changeIndex() { | 116 | changeIndex() { |
116 | - this.onTimeUpdated.emit(this.intervals[this.index]); | 117 | + this.timeUpdated.emit(this.intervals[this.index]); |
117 | } | 118 | } |
118 | } | 119 | } |