Switching to leaflet

This commit is contained in:
ztimson 2019-08-22 14:55:37 -04:00
parent 39c87666d8
commit 930bbd15a9
5 changed files with 148 additions and 138 deletions

View File

@ -29,9 +29,13 @@
], ],
"styles": [ "styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"./node_modules/leaflet/dist/leaflet.css",
"src/styles.scss" "src/styles.scss"
], ],
"scripts": [] "scripts": [
"./node_modules/leaflet/dist/leaflet.js",
"./node_modules/esri-leaflet/dist/esri-leaflet.js"
]
}, },
"configurations": { "configurations": {
"production": { "production": {

View File

@ -26,9 +26,12 @@
"@angular/pwa": "^0.800.4", "@angular/pwa": "^0.800.4",
"@angular/router": "~8.0.1", "@angular/router": "~8.0.1",
"@angular/service-worker": "~8.0.1", "@angular/service-worker": "~8.0.1",
"@types/leaflet": "^1.5.1",
"bootstrap-scss": "^4.3.1", "bootstrap-scss": "^4.3.1",
"esri-leaflet": "^2.3.0",
"firebase": "^6.3.0", "firebase": "^6.3.0",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"leaflet": "^1.5.1",
"rxjs": "~6.4.0", "rxjs": "~6.4.0",
"tslib": "^1.9.0", "tslib": "^1.9.0",
"zone.js": "~0.9.1" "zone.js": "~0.9.1"

View File

@ -1,11 +1,5 @@
<toolbar [(menu)]="menu"></toolbar> <toolbar [(menu)]="menu"></toolbar>
<agm-map class="map" [styles]="mapStyle" [mapTypeId]="style" [zoomControl]="false" [streetViewControl]="false" [disableDoubleClickZoom]="true" (mapReady)="mapApi = $event" gestureHandling="greedy" (mapClick)="mapClick.next($event.coords)"> <div id="map"></div>
<ng-container *ngIf="position">
<agm-marker *ngIf="position.heading == null" [markerClickable]="false" [latitude]="position.latitude" [longitude]="position.longitude" [iconUrl]="{url: '/assets/images/dot.png', anchor: {x: 11, y: 10}}"></agm-marker>
<agm-marker *ngIf="position.heading != null" [markerClickable]="false" [latitude]="position.latitude" [longitude]="position.longitude" [iconUrl]="{url: '/assets/images/arrow.png', anchor: {x: 11, y: 13}, rotation: 90}"></agm-marker>
<agm-circle [latitude]="position.latitude" [longitude]="position.longitude" [radius]="position.accuracy" fillColor="#5C95F2" [clickable]="false"></agm-circle>
</ng-container>
</agm-map>
<div *ngIf="showPalette" [@flyInRight] [@flyOutRight] class="palette"> <div *ngIf="showPalette" [@flyInRight] [@flyOutRight] class="palette">
<palette [(selected)]="drawColor"></palette> <palette [(selected)]="drawColor"></palette>
</div> </div>

View File

@ -1,10 +1,10 @@
.map { #map {
height: calc(100vh - 40px); height: calc(100vh - 40px);
} }
.palette { .palette {
position: fixed; position: fixed;
z-index: 100; z-index: 500;
top: 50px; top: 50px;
right: 15px; right: 15px;
} }
@ -12,14 +12,14 @@
.info { .info {
background-color: #00000050; background-color: #00000050;
position: fixed; position: fixed;
z-index: 100; z-index: 500;
bottom: 15px; bottom: 15px;
left: 15px; left: 15px;
} }
.gps { .gps {
position: fixed; position: fixed;
z-index: 100; z-index: 500;
bottom: 15px; bottom: 15px;
right: 15px; right: 15px;
} }

View File

@ -1,4 +1,4 @@
import {Component} from "@angular/core"; import {Component, OnInit} from "@angular/core";
import {PhysicsService} from "../../services/physics/physics.service"; import {PhysicsService} from "../../services/physics/physics.service";
import {filter, skip, take} from "rxjs/operators"; import {filter, skip, take} from "rxjs/operators";
import {MatBottomSheet, MatSnackBar} from "@angular/material"; import {MatBottomSheet, MatSnackBar} from "@angular/material";
@ -8,7 +8,7 @@ import {BehaviorSubject} from "rxjs";
import {LatLngLiteral} from "@agm/core"; import {LatLngLiteral} from "@agm/core";
import {flyInRight, flyOutRight} from "../../animations"; import {flyInRight, flyOutRight} from "../../animations";
declare const google; declare const L;
@Component({ @Component({
selector: 'map', selector: 'map',
@ -16,7 +16,11 @@ declare const google;
styleUrls: ['map.component.scss'], styleUrls: ['map.component.scss'],
animations: [flyInRight, flyOutRight] animations: [flyInRight, flyOutRight]
}) })
export class MapComponent { export class MapComponent implements OnInit {
map;
drawColor: string; drawColor: string;
drawListener = []; drawListener = [];
mapApi: any; mapApi: any;
@ -34,14 +38,14 @@ export class MapComponent {
isNaN = isNaN; isNaN = isNaN;
menu: ToolbarItem[][] = [[ menu: ToolbarItem[][] = [[
{name: 'compass', icon: 'explore', click: () => this.calibrate(), hidden: true}, {name: 'compass', icon: 'explore', hidden: true},
], [ ], [
{name: 'marker', icon: 'room', toggle: true, individualToggle: true, click: () => this.addMarker()}, {name: 'marker', icon: 'room', toggle: true, individualToggle: true},
{name: 'draw', icon: 'create', toggle: true, individualToggle: true, onEnabled: () => this.startDraw(), onDisabled: () => this.endDraw()}, {name: 'draw', icon: 'create', toggle: true, individualToggle: true},
{name: 'measure', icon: 'straighten', toggle: true, individualToggle: true, click: () => this.measure()}, {name: 'measure', icon: 'straighten', toggle: true, individualToggle: true},
{name: 'delete', icon: 'delete', toggle: true, individualToggle: true}, {name: 'delete', icon: 'delete', toggle: true, individualToggle: true},
{name: 'style', icon: 'terrain', enabled: true, toggle: true, onEnabled: () => this.style = 'terrain', onDisabled: () => this.style = 'satellite'}, {name: 'style', icon: 'terrain', enabled: true, toggle: true},
{name: 'compass', icon: 'explore', click: () => this.calibrate()} {name: 'compass', icon: 'explore'}
], [ ], [
{name: 'messages', icon: 'chat', hidden: true}, {name: 'messages', icon: 'chat', hidden: true},
{name: 'identity', icon: 'perm_identity', hidden: true}, {name: 'identity', icon: 'perm_identity', hidden: true},
@ -51,7 +55,7 @@ export class MapComponent {
constructor(public physicsService: PhysicsService, private snackBar: MatSnackBar, private bottomSheet: MatBottomSheet) { constructor(public physicsService: PhysicsService, private snackBar: MatSnackBar, private bottomSheet: MatBottomSheet) {
physicsService.info.pipe(filter(coord => !!coord)).subscribe(pos => { physicsService.info.pipe(filter(coord => !!coord)).subscribe(pos => {
if(this.mapApi) { if(this.mapApi) {
if(!this.position) this.center(pos); // if(!this.position) this.center(pos);
this.position = pos; this.position = pos;
if(this.position.heading != null) { if(this.position.heading != null) {
@ -65,125 +69,130 @@ export class MapComponent {
snackBar.open('Compass requires calibration', 'calibrate', { snackBar.open('Compass requires calibration', 'calibrate', {
duration: 5000, duration: 5000,
panelClass: 'bg-warning,text-white' panelClass: 'bg-warning,text-white'
}).onAction().subscribe(() => this.calibrate()); }).onAction()/*.subscribe(() => this.calibrate());*/
}); });
} }
addMarker() { ngOnInit() {
this.mapClick.pipe(skip(1), take(1)).subscribe(coords => { this.map = L.map('map', {attributionControl: false, zoomControl: false}).setView([37.75, -122.23], 10);
this.menu[1][0].enabled = false; L.esri.basemapLayer('ImageryClarity').addTo(this.map);
let marker = new google.maps.Marker({
map: this.mapApi,
position: {lat: coords.lat, lng: coords.lng}
});
google.maps.event.addListener(marker, 'click', () => {
if(this.menu[1][3].enabled) marker.setMap(null)
});
});
} }
measure() { // addMarker() {
let deg2rad = (deg) => deg * (Math.PI/180); // this.mapClick.pipe(skip(1), take(1)).subscribe(coords => {
// this.menu[1][0].enabled = false;
let distanceInM = (lat1, lon1, lat2, lon2) => { // let marker = new google.maps.Marker({
const R = 6371; // Radius of the earth in km // map: this.mapApi,
let dLat = deg2rad(lat2-lat1); // deg2rad below // position: {lat: coords.lat, lng: coords.lng}
let dLon = deg2rad(lon2-lon1); // });
let a = // google.maps.event.addListener(marker, 'click', () => {
Math.sin(dLat/2) * Math.sin(dLat/2) + // if(this.menu[1][3].enabled) marker.setMap(null)
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * // });
Math.sin(dLon/2) * Math.sin(dLon/2) // });
; // }
let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); //
return R * c * 1000 // measure() {
}; // let deg2rad = (deg) => deg * (Math.PI/180);
//
let first; // let distanceInM = (lat1, lon1, lat2, lon2) => {
this.mapClick.pipe(skip(1), take(2)).subscribe(coords => { // const R = 6371; // Radius of the earth in km
if(!first) { // let dLat = deg2rad(lat2-lat1); // deg2rad below
first = coords; // let dLon = deg2rad(lon2-lon1);
} else { // let a =
this.menu[1][2].enabled = false; // Math.sin(dLat/2) * Math.sin(dLat/2) +
// Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
let line = new google.maps.Polyline({ // Math.sin(dLon/2) * Math.sin(dLon/2)
map: this.mapApi, // ;
path: [first, coords], // let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
strokeColor: '#f00', // return R * c * 1000
icons: [{ // };
icon: {path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW}, //
offset: '0%' // let first;
}, { // this.mapClick.pipe(skip(1), take(2)).subscribe(coords => {
icon: {path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW}, // if(!first) {
offset: '100%' // first = coords;
}] // } else {
}); // this.menu[1][2].enabled = false;
//
let distance = distanceInM(first.lat, first.lng, coords.lat, coords.lng); // let line = new google.maps.Polyline({
// map: this.mapApi,
let info = new google.maps.InfoWindow({ // path: [first, coords],
content: distance >= 1000 ? `${Math.round(distance / 100) / 10} km` : `${Math.round(distance)} m`, // strokeColor: '#f00',
position: {lat: (first.lat + coords.lat) / 2, lng: (first.lng + coords.lng) / 2} // icons: [{
}); // icon: {path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW},
info.open(this.mapApi); // offset: '0%'
// }, {
google.maps.event.addListener(line, 'click', () => { // icon: {path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW},
if(this.menu[1][3].enabled) { // offset: '100%'
line.setMap(null); // }]
info.setMap(null); // });
} //
}); // let distance = distanceInM(first.lat, first.lng, coords.lat, coords.lng);
//
google.maps.event.addListener(info, 'click', () => { // let info = new google.maps.InfoWindow({
if(this.menu[1][3].enabled) { // content: distance >= 1000 ? `${Math.round(distance / 100) / 10} km` : `${Math.round(distance)} m`,
line.setMap(null); // position: {lat: (first.lat + coords.lat) / 2, lng: (first.lng + coords.lng) / 2}
info.setMap(null); // });
} // info.open(this.mapApi);
}); //
} // google.maps.event.addListener(line, 'click', () => {
}) // if(this.menu[1][3].enabled) {
} // line.setMap(null);
// info.setMap(null);
calibrate() { // }
this.bottomSheet.open(CalibrateComponent, { // });
hasBackdrop: false, //
disableClose: true // google.maps.event.addListener(info, 'click', () => {
}); // if(this.menu[1][3].enabled) {
} // line.setMap(null);
// info.setMap(null);
center(pos?) { // }
if(!pos) pos = this.position; // });
this.mapApi.setCenter({lat: pos.latitude, lng: pos.longitude}); // }
} // })
// }
startDraw() { //
this.showPalette = true; // calibrate() {
this.mapApi.setOptions({draggable: false}); // this.bottomSheet.open(CalibrateComponent, {
// hasBackdrop: false,
let drawHander = () => { // disableClose: true
let poly = new google.maps.Polyline({map: this.mapApi, clickable: true, strokeColor: this.drawColor}); // });
google.maps.event.addListener(poly, 'click', () => { // }
if(this.menu[1][3].enabled) poly.setMap(null); //
}); // center(pos?) {
let moveListener = [ // if(!pos) pos = this.position;
google.maps.event.addListener(this.mapApi, 'touchmove', e => poly.getPath().push(e.latLng)), // this.mapApi.setCenter({lat: pos.latitude, lng: pos.longitude});
google.maps.event.addListener(this.mapApi, 'mousemove', e => poly.getPath().push(e.latLng)) // }
]; //
google.maps.event.addListener(this.mapApi, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); // startDraw() {
google.maps.event.addListener(this.mapApi, 'mouseup', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); // this.showPalette = true;
google.maps.event.addListener(poly, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); // this.mapApi.setOptions({draggable: false});
google.maps.event.addListener(poly, 'mouseup', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); //
}; // let drawHander = () => {
// let poly = new google.maps.Polyline({map: this.mapApi, clickable: true, strokeColor: this.drawColor});
this.drawListener = [ // google.maps.event.addListener(poly, 'click', () => {
google.maps.event.addDomListener(this.mapApi.getDiv(), 'touchstart', drawHander), // if(this.menu[1][3].enabled) poly.setMap(null);
google.maps.event.addDomListener(this.mapApi.getDiv(), 'mousedown', drawHander) // });
]; // let moveListener = [
} // google.maps.event.addListener(this.mapApi, 'touchmove', e => poly.getPath().push(e.latLng)),
// google.maps.event.addListener(this.mapApi, 'mousemove', e => poly.getPath().push(e.latLng))
endDraw() { // ];
this.showPalette = false; // google.maps.event.addListener(this.mapApi, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener)));
this.mapApi.setOptions({draggable: true}); // google.maps.event.addListener(this.mapApi, 'mouseup', () => moveListener.forEach(listener => google.maps.event.removeListener(listener)));
this.drawListener.forEach(listener => google.maps.event.removeListener(listener)); // google.maps.event.addListener(poly, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener)));
this.drawListener = []; // google.maps.event.addListener(poly, 'mouseup', () => moveListener.forEach(listener => google.maps.event.removeListener(listener)));
} // };
//
// this.drawListener = [
// google.maps.event.addDomListener(this.mapApi.getDiv(), 'touchstart', drawHander),
// google.maps.event.addDomListener(this.mapApi.getDiv(), 'mousedown', drawHander)
// ];
// }
//
// endDraw() {
// this.showPalette = false;
// this.mapApi.setOptions({draggable: true});
// this.drawListener.forEach(listener => google.maps.event.removeListener(listener));
// this.drawListener = [];
// }
} }