Commit 047230a2284ba88e88eccc5050ab701fa36b9ad3

Authored by ArtemHalushko
Committed by GitHub
1 parent a4f5d355

Map/3.0 (#2544)

* add base map infrastructure

* add leaflet css

* add tencent map

* add google maps support

* added image map support

* refactor schemes

* here maps support && WIP on markers

* add simple marker suppor

* data update & polyline support

* map bouds support

* add some settings support

* add map provider select to settings

* labels support

* WIP on trip animation widget

* WIP on history control and route interpolation

* trip-animation map provider & custom markers

* comleted track marker & history controls

* add license headers

* label fix & tooltips support

* WIP on polygons

* marker dropping support

* add polygon support

* add label to trip animation

* WIP on tooltips

* lint anf typed leaflet AddMarker

* some typing and poly improvements

* add typing

* add marker creation

* update proxy

* save position fix

* add bounds padding

* update map widget bendle && bugfixes

* update marker placement widget

* add licenses

* reomove log

* fix sizes

* entity and map fixes

* Fix tile server support  form OSM and zoom level fix

Co-authored-by: Artem Halushko <ahalushko@thingboards.io>
Co-authored-by: Adsumus <artemtv42@gmail.com>
@@ -23,7 +23,7 @@ import 'leaflet.markercluster/dist/leaflet.markercluster' @@ -23,7 +23,7 @@ import 'leaflet.markercluster/dist/leaflet.markercluster'
23 23
24 import { MapSettings, MarkerSettings, FormattedData, UnitedMapSettings, PolygonSettings, PolylineSettings } from './map-models'; 24 import { MapSettings, MarkerSettings, FormattedData, UnitedMapSettings, PolygonSettings, PolylineSettings } from './map-models';
25 import { Marker } from './markers'; 25 import { Marker } from './markers';
26 -import { Observable, of, BehaviorSubject, Subject } from 'rxjs'; 26 +import { Observable, BehaviorSubject } from 'rxjs';
27 import { filter } from 'rxjs/operators'; 27 import { filter } from 'rxjs/operators';
28 import { Polyline } from './polyline'; 28 import { Polyline } from './polyline';
29 import { Polygon } from './polygon'; 29 import { Polygon } from './polygon';
@@ -64,7 +64,7 @@ export default abstract class LeafletMap { @@ -64,7 +64,7 @@ export default abstract class LeafletMap {
64 let mousePositionOnMap: L.LatLng; 64 let mousePositionOnMap: L.LatLng;
65 let addMarker: L.Control; 65 let addMarker: L.Control;
66 this.map.on('mouseup', (e: L.LeafletMouseEvent) => { 66 this.map.on('mouseup', (e: L.LeafletMouseEvent) => {
67 - mousePositionOnMap = e.latlng 67 + mousePositionOnMap = e.latlng;
68 }) 68 })
69 const dragListener = (e: L.DragEndEvent) => { 69 const dragListener = (e: L.DragEndEvent) => {
70 if (e.type === 'dragend' && mousePositionOnMap) { 70 if (e.type === 'dragend' && mousePositionOnMap) {
@@ -164,6 +164,23 @@ export default abstract class LeafletMap { @@ -164,6 +164,23 @@ export default abstract class LeafletMap {
164 return this.map.getCenter(); 164 return this.map.getCenter();
165 } 165 }
166 166
  167 + fitBounds(bounds, useDefaultZoom = false) {
  168 + if (bounds.isValid()) {
  169 + if ((this.options.dontFitMapBounds || useDefaultZoom) && this.options.defaultZoomLevel) {
  170 + this.map.setZoom(this.options.defaultZoomLevel, { animate: false });
  171 + this.map.panTo(bounds.getCenter(), { animate: false });
  172 + } else {
  173 + this.map.once('zoomend', function () {
  174 + if (!this.options.defaultZoomLevel && this.options.map.getZoom() > this.options.minZoomLevel) {
  175 + this.map.setZoom(this.options.minZoomLevel, { animate: false });
  176 + }
  177 + });
  178 + this.map.fitBounds(bounds, { padding: [50, 50], animate: false });
  179 + }
  180 + this.bounds = this.bounds.extend(bounds);
  181 + }
  182 + }
  183 +
167 convertPosition(expression: object): L.LatLng { 184 convertPosition(expression: object): L.LatLng {
168 if (!expression) return null; 185 if (!expression) return null;
169 const lat = expression[this.options.latKeyName]; 186 const lat = expression[this.options.latKeyName];
@@ -185,7 +202,7 @@ export default abstract class LeafletMap { @@ -185,7 +202,7 @@ export default abstract class LeafletMap {
185 updateMarkers(markersData) { 202 updateMarkers(markersData) {
186 markersData.forEach(data => { 203 markersData.forEach(data => {
187 if (this.convertPosition(data)) { 204 if (this.convertPosition(data)) {
188 - if (data.rotationAngle) { 205 + if (data.rotationAngle || data.rotationAngle === 0) {
189 this.options.icon = L.divIcon({ 206 this.options.icon = L.divIcon({
190 html: `<div class="arrow" style="transform: translate(-10px, -10px) rotate(${data.rotationAngle}deg);"><div>` 207 html: `<div class="arrow" style="transform: translate(-10px, -10px) rotate(${data.rotationAngle}deg);"><div>`
191 }) 208 })
@@ -211,8 +228,7 @@ export default abstract class LeafletMap { @@ -211,8 +228,7 @@ export default abstract class LeafletMap {
211 private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, setFocus = true) { 228 private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, setFocus = true) {
212 this.ready$.subscribe(() => { 229 this.ready$.subscribe(() => {
213 const newMarker = new Marker(this.map, this.convertPosition(data), settings, data, dataSources, () => { }, this.dragMarker); 230 const newMarker = new Marker(this.map, this.convertPosition(data), settings, data, dataSources, () => { }, this.dragMarker);
214 - if (setFocus /*&& settings.fitMapBounds*/)  
215 - this.map.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()).pad(0.2)); 231 + this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()), setFocus);
216 this.markers.set(key, newMarker); 232 this.markers.set(key, newMarker);
217 }); 233 });
218 } 234 }
@@ -260,11 +276,8 @@ export default abstract class LeafletMap { @@ -260,11 +276,8 @@ export default abstract class LeafletMap {
260 this.ready$.subscribe(() => { 276 this.ready$.subscribe(() => {
261 const poly = new Polyline(this.map, 277 const poly = new Polyline(this.map,
262 data.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings); 278 data.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings);
263 - const bounds = this.bounds.extend(poly.leafletPoly.getBounds().pad(0.2));  
264 - if (bounds.isValid()) {  
265 - this.map.fitBounds(bounds);  
266 - this.bounds = bounds;  
267 - } 279 + const bounds = this.bounds.extend(poly.leafletPoly.getBounds());
  280 + this.fitBounds(bounds)
268 this.polylines.set(data[0].entityName, poly) 281 this.polylines.set(data[0].entityName, poly)
269 }); 282 });
270 } 283 }
@@ -296,7 +309,7 @@ export default abstract class LeafletMap { @@ -296,7 +309,7 @@ export default abstract class LeafletMap {
296 createPolygon(key: string, data: LatLngTuple[], dataSources: DatasourceData[], settings: PolygonSettings) { 309 createPolygon(key: string, data: LatLngTuple[], dataSources: DatasourceData[], settings: PolygonSettings) {
297 this.ready$.subscribe(() => { 310 this.ready$.subscribe(() => {
298 const polygon = new Polygon(this.map, data, dataSources, settings); 311 const polygon = new Polygon(this.map, data, dataSources, settings);
299 - const bounds = this.bounds.extend(polygon.leafletPoly.getBounds().pad(0.2)); 312 + const bounds = this.bounds.extend(polygon.leafletPoly.getBounds());
300 if (bounds.isValid()) { 313 if (bounds.isValid()) {
301 this.map.fitBounds(bounds); 314 this.map.fitBounds(bounds);
302 this.bounds = bounds; 315 this.bounds = bounds;
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import L from 'leaflet'; 17 +import L, { LatLngLiteral } from 'leaflet';
18 import LeafletMap from '../leaflet-map'; 18 import LeafletMap from '../leaflet-map';
19 import { MapSettings, UnitedMapSettings } from '../map-models'; 19 import { MapSettings, UnitedMapSettings } from '../map-models';
20 import { aspectCache } from '@app/core/utils'; 20 import { aspectCache } from '@app/core/utils';
@@ -93,7 +93,6 @@ export class ImageMap extends LeafletMap { @@ -93,7 +93,6 @@ export class ImageMap extends LeafletMap {
93 lastCenterPos.y /= prevHeight; 93 lastCenterPos.y /= prevHeight;
94 this.updateBounds(updateImage, lastCenterPos); 94 this.updateBounds(updateImage, lastCenterPos);
95 this.map.invalidateSize(true); 95 this.map.invalidateSize(true);
96 - // this.updateMarkers();  
97 } 96 }
98 97
99 } 98 }
@@ -113,7 +112,6 @@ export class ImageMap extends LeafletMap { @@ -113,7 +112,6 @@ export class ImageMap extends LeafletMap {
113 attributionControl: false 112 attributionControl: false
114 }); 113 });
115 this.updateBounds(updateImage); 114 this.updateBounds(updateImage);
116 - // this.updateMarkers();  
117 } 115 }
118 } 116 }
119 117
@@ -127,7 +125,14 @@ export class ImageMap extends LeafletMap { @@ -127,7 +125,14 @@ export class ImageMap extends LeafletMap {
127 return L.CRS.Simple.pointToLatLng({ x, y } as L.PointExpression, maxZoom - 1); 125 return L.CRS.Simple.pointToLatLng({ x, y } as L.PointExpression, maxZoom - 1);
128 } 126 }
129 127
130 - latLngToPoint(latLng) { 128 + latLngToPoint(latLng: LatLngLiteral) {
131 return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1); 129 return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
132 } 130 }
  131 +
  132 + /* convertToCustomFormat(position: L.LatLng): object {
  133 + return {
  134 + [this.options.xPosKeyName]: (position.lng + 180) / 360,
  135 + [this.options.yPosKeyName]: (position.lat + 180) / 360
  136 + }
  137 + }*/
133 } 138 }
@@ -22,7 +22,7 @@ export class OpenStreetMap extends LeafletMap { @@ -22,7 +22,7 @@ export class OpenStreetMap extends LeafletMap {
22 constructor($container, options: UnitedMapSettings) { 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(options.mapProvider || 'OpenStreetMap.Mapnik');
26 tileLayer.addTo(map); 26 tileLayer.addTo(map);
27 super.setMap(map); 27 super.setMap(map);
28 super.initSettings(options); 28 super.initSettings(options);