diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 3804fad..f1d2576 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -15,6 +15,7 @@ import {MatInputModule} from "@angular/material"; import {PermissionsComponent} from "./permissions/permissions.component"; import {AngularFireModule} from "@angular/fire"; import {AngularFirestoreModule} from "@angular/fire/firestore"; +import {ToolbarComponent} from "./map/toolbar/toolbar.component"; @NgModule({ declarations: [ @@ -22,7 +23,8 @@ import {AngularFirestoreModule} from "@angular/fire/firestore"; CalibrateComponent, HomeComponent, MapComponent, - PermissionsComponent + PermissionsComponent, + ToolbarComponent ], imports: [ AgmCoreModule.forRoot({apiKey: 'AIzaSyDFtvCY6nH_HUoTBNf_5b-E8nRweSLYtxE'}), diff --git a/src/app/map/calibrate/calibrate.component.html b/src/app/map/calibrate/calibrate.component.html index 5f97f7c..3408351 100644 --- a/src/app/map/calibrate/calibrate.component.html +++ b/src/app/map/calibrate/calibrate.component.html @@ -1,5 +1,5 @@
-
+
Shift +/- diff --git a/src/app/map/map.component.html b/src/app/map/map.component.html index 7e0c85a..e6bdceb 100644 --- a/src/app/map/map.component.html +++ b/src/app/map/map.component.html @@ -1,32 +1,10 @@ - - - {{version}} -
- - - - - - - - - - - - - - -
-
- + + - + -
No GPS diff --git a/src/app/map/map.component.scss b/src/app/map/map.component.scss index 52fd867..5d1c9c7 100644 --- a/src/app/map/map.component.scss +++ b/src/app/map/map.component.scss @@ -1,5 +1,5 @@ -mat-toolbar { - height: 40px !important; +.map { + height: calc(100vh - 40px); } .info { @@ -16,11 +16,3 @@ mat-toolbar { bottom: 15px; right: 15px; } - -.map { - height: calc(100vh - 40px); -} - -.selected { - background-color: #cccccc; -} diff --git a/src/app/map/map.component.ts b/src/app/map/map.component.ts index 64ed801..5175bc7 100644 --- a/src/app/map/map.component.ts +++ b/src/app/map/map.component.ts @@ -1,10 +1,11 @@ import {Component} from "@angular/core"; import {PhysicsService} from "../physics/physics.service"; -import {debounceTime, filter, map} from "rxjs/operators"; -import {BreakpointObserver, Breakpoints} from "@angular/cdk/layout"; +import {filter, skip, take} from "rxjs/operators"; import {MatBottomSheet, MatSnackBar} from "@angular/material"; import {CalibrateComponent} from "./calibrate/calibrate.component"; -import {version} from "../../../package.json"; +import {ToolbarItem} from "./toolbar/toolbarItem"; +import {BehaviorSubject} from "rxjs"; +import {LatLngLiteral} from "@agm/core"; declare const google; @@ -16,19 +17,26 @@ declare const google; export class MapComponent { drawListener = []; mapApi: any; - markers = []; - mobile = false; - mode: 'marker' | 'circle' | 'square' | 'draw'; + mapClick = new BehaviorSubject(null); position: any; - remove = false; - style: 'satellite' | 'terrain' | 'roadmap' | 'hybrid' = 'terrain'; - version = version; - - Infinity = Infinity; + style = 'terrain'; isNaN = isNaN; - constructor(private bpObserver: BreakpointObserver, public physicsService: PhysicsService, private snackBar: MatSnackBar, private bottomSheet: MatBottomSheet) { - bpObserver.observe([Breakpoints.Handset]).subscribe(results => this.mobile = results.matches); + menu: ToolbarItem[][] = [[ + {name: 'compass', icon: 'explore', click: () => this.calibrate(), hidden: true}, + ], [ + {name: 'marker', icon: 'room', toggle: true, individualToggle: true, click: () => this.addMarker()}, + {name: 'draw', icon: 'create', toggle: true, individualToggle: true, onEnabled: () => this.startDraw(), onDisabled: () => this.endDraw()}, + {name: 'measure', icon: 'straighten', toggle: true, individualToggle: true, click: () => this.measure()}, + {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: 'messages', icon: 'chat', hidden: true}, + {name: 'identity', icon: 'perm_identity', hidden: true}, + {name: 'settings', icon: 'settings', hidden: true} + ]]; + + constructor(public physicsService: PhysicsService, private snackBar: MatSnackBar, private bottomSheet: MatBottomSheet) { physicsService.info.pipe(filter(coord => !!coord)).subscribe(pos => { if(this.mapApi) { if(!this.position) this.center(pos); @@ -49,8 +57,79 @@ export class MapComponent { }); } - mapReady(map) { - this.mapApi = map; + addMarker() { + this.mapClick.pipe(skip(1), take(1)).subscribe(coords => { + this.menu[1][0].enabled = false; + 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() { + let deg2rad = (deg) => deg * (Math.PI/180); + + let distanceInM = (lat1, lon1, lat2, lon2) => { + const R = 6371; // Radius of the earth in km + let dLat = deg2rad(lat2-lat1); // deg2rad below + let dLon = deg2rad(lon2-lon1); + let a = + Math.sin(dLat/2) * Math.sin(dLat/2) + + 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 + }; + + let first; + this.mapClick.pipe(skip(1), take(2)).subscribe(coords => { + if(!first) { + first = coords; + } else { + this.menu[1][2].enabled = false; + + let line = new google.maps.Polyline({ + map: this.mapApi, + path: [first, coords], + strokeColor: '#f00', + icons: [{ + icon: {path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW}, + offset: '0%' + }, { + icon: {path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW}, + offset: '100%' + }] + }); + + let distance = distanceInM(first.lat, first.lng, coords.lat, coords.lng); + + let marker = new google.maps.Marker({ + map: this.mapApi, + icon: null, + position: {lat: (first.lat + coords.lat) / 2, lng: (first.lng + coords.lng) / 2}, + label: distance >= 1000 ? `${Math.round(distance / 100) / 10} km` : `${Math.round(distance)} m` + }); + + google.maps.event.addListener(line, 'click', () => { + if(this.menu[1][3].enabled) { + line.setMap(null); + marker.setMap(null); + } + }) + + google.maps.event.addListener(marker, 'click', () => { + if(this.menu[1][3].enabled) { + line.setMap(null); + marker.setMap(null); + } + }) + } + }) } calibrate() { @@ -65,40 +144,33 @@ export class MapComponent { this.mapApi.setCenter({lat: pos.latitude, lng: pos.longitude}); } - clicked(type: 'single' | 'double' | 'right', event) { - if(this.mode == 'marker') { - this.markers.push({latitude: event.coords.lat, longitude: event.coords.lng}); - this.mode = null; - } + startDraw() { + this.mapApi.setOptions({draggable: false}); + + let drawHander = () => { + let poly = new google.maps.Polyline({map: this.mapApi, clickable: true}); + google.maps.event.addListener(poly, 'click', () => { + if(this.menu[1][3].enabled) poly.setMap(null); + }); + 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)) + ]; + google.maps.event.addListener(this.mapApi, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); + google.maps.event.addListener(this.mapApi, 'mouseup', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); + google.maps.event.addListener(poly, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); + 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) + ]; } - draw() { - if(!this.drawListener.length) { - this.mapApi.setOptions({draggable: false}); - - let drawHander = () => { - let poly = new google.maps.Polyline({map: this.mapApi, clickable: true}); - google.maps.event.addListener(poly, 'click', () => { - if(this.remove) poly.setMap(null); - }); - 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)) - ]; - google.maps.event.addListener(this.mapApi, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); - google.maps.event.addListener(this.mapApi, 'mouseup', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); - google.maps.event.addListener(poly, 'touchend', () => moveListener.forEach(listener => google.maps.event.removeListener(listener))); - 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) - ] - } else { - this.mapApi.setOptions({draggable: true}); - this.drawListener.forEach(listener => google.maps.event.removeListener(listener)); - this.drawListener = []; - } + endDraw() { + this.mapApi.setOptions({draggable: true}); + this.drawListener.forEach(listener => google.maps.event.removeListener(listener)); + this.drawListener = []; } } diff --git a/src/app/map/toolbar/toolbar.component.html b/src/app/map/toolbar/toolbar.component.html new file mode 100644 index 0000000..af50384 --- /dev/null +++ b/src/app/map/toolbar/toolbar.component.html @@ -0,0 +1,15 @@ + + + {{version}} +
+
+ + + +
+
+
diff --git a/src/app/map/toolbar/toolbar.component.scss b/src/app/map/toolbar/toolbar.component.scss new file mode 100644 index 0000000..a8f2353 --- /dev/null +++ b/src/app/map/toolbar/toolbar.component.scss @@ -0,0 +1,7 @@ +mat-toolbar { + height: 40px !important; +} + +.selected { + background-color: #cccccc; +} diff --git a/src/app/map/toolbar/toolbar.component.ts b/src/app/map/toolbar/toolbar.component.ts new file mode 100644 index 0000000..fc0b333 --- /dev/null +++ b/src/app/map/toolbar/toolbar.component.ts @@ -0,0 +1,39 @@ +import {Component, EventEmitter, Input, Output} from "@angular/core"; +import {ToolbarItem} from "./toolbarItem"; +import {version} from '../../../../package.json'; + +@Component({ + selector: 'toolbar', + templateUrl: 'toolbar.component.html', + styleUrls: ['toolbar.component.scss'] +}) +export class ToolbarComponent { + @Input() menu: ToolbarItem[][]; + + @Output() menuChange = new EventEmitter(); + + readonly version = version; + + constructor() { } + + clickWrapper(item: ToolbarItem) { + if(item.toggle) { + if (item.individualToggle) { + this.menu.forEach(menu => menu.filter(i2 => item.name != i2.name && i2.individualToggle).forEach(item => { + item.enabled = false; + if (item.onDisabled) item.onDisabled(); + })); + } + + item.enabled = !item.enabled; + this.menuChange.emit(this.menu); + + if(item.enabled) { + if(item.onEnabled) item.onEnabled(); + } else { + if(item.onDisabled) item.onDisabled(); + } + } + if(item.click) item.click(); + } +} diff --git a/src/app/map/toolbar/toolbarItem.ts b/src/app/map/toolbar/toolbarItem.ts new file mode 100644 index 0000000..d621973 --- /dev/null +++ b/src/app/map/toolbar/toolbarItem.ts @@ -0,0 +1,11 @@ +export interface ToolbarItem { + name: string; + icon: string; + hidden?: boolean; + toggle?: boolean; + individualToggle?: boolean; + click?: () => void; + enabled?: boolean; + onEnabled?: () => void; + onDisabled?: () => void; +} diff --git a/src/app/physics/physics.service.ts b/src/app/physics/physics.service.ts index 4974051..c191fa5 100644 --- a/src/app/physics/physics.service.ts +++ b/src/app/physics/physics.service.ts @@ -40,11 +40,8 @@ export class PhysicsService { this.motionTimestamp = currentTime; }); - this.orientation.subscribe(() => console.log('orientation')); - // Combine data into one nice package combineLatest(this.position, this.orientation, this.calibrate, this.speed).subscribe(data => { - console.log('combine'); if(!data[0]) return; let info = {