Changed a bunch of stuff
This commit is contained in:
		| @@ -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'}), | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <div> | ||||
|     <div class="row"> | ||||
|     <div class="row mt-2"> | ||||
|         <div class="col-5 pr-0"> | ||||
|             <mat-form-field appearance="fill" class="w-100"> | ||||
|                 <mat-label>Shift +/-</mat-label> | ||||
|   | ||||
| @@ -1,32 +1,10 @@ | ||||
| <mat-toolbar> | ||||
|     <button mat-icon-button routerLink="/"> | ||||
|         <img src="/assets/images/logo.png" height="35px" width="auto"> | ||||
|     </button> | ||||
|     <small class="ml-1 text-muted">{{version}}</small> | ||||
|     <div class="ml-auto"> | ||||
|         <button mat-icon-button (click)="mode = 'marker'" [ngClass]="{'selected': mode == 'marker'}"><mat-icon>room</mat-icon></button> | ||||
|         <button mat-icon-button (click)="draw()" [ngClass]="{'selected': drawListener.length}"><mat-icon>create</mat-icon></button> | ||||
|         <button mat-icon-button><mat-icon>straighten</mat-icon></button> | ||||
|         <button mat-icon-button (click)="remove = !remove" [ngClass]="{'selected': remove}"><mat-icon>delete</mat-icon></button> | ||||
|         <button *ngIf="position?.heading != Infinity" mat-icon-button (click)="calibrate()"><mat-icon>explore</mat-icon></button> | ||||
|         <button mat-icon-button [matMenuTriggerFor]="styleMenu"><mat-icon>layers</mat-icon></button> | ||||
|         <mat-menu #styleMenu="matMenu"> | ||||
|             <button mat-menu-item (click)="style = 'satellite'" [ngClass]="{'selected': style == 'satellite'}">Satellite</button> | ||||
|             <button mat-menu-item (click)="style = 'terrain'" [ngClass]="{'selected': style == 'terrain'}">Terrain</button> | ||||
|             <button mat-menu-item (click)="style = 'roadmap'" [ngClass]="{'selected': style == 'roadmap'}">Road</button> | ||||
|             <button mat-menu-item (click)="style = 'hybrid'" [ngClass]="{'selected': style == 'hybrid'}">Hybrid</button> | ||||
|         </mat-menu> | ||||
|         <!--<button mat-icon-button><mat-icon>chat</mat-icon></button>--> | ||||
|         <button mat-icon-button><mat-icon>perm_identity</mat-icon></button> | ||||
|     </div> | ||||
| </mat-toolbar> | ||||
| <agm-map class="map" [mapTypeId]="style" [zoomControl]="false" [streetViewControl]="false" [disableDoubleClickZoom]="true" (mapReady)="mapReady($event)" gestureHandling="greedy" (mapClick)="clicked('single', $event)"> | ||||
| <toolbar [(menu)]="menu"></toolbar> | ||||
| <agm-map class="map" [mapTypeId]="style" [zoomControl]="false" [streetViewControl]="false" [disableDoubleClickZoom]="true" (mapReady)="mapApi = $event" gestureHandling="greedy" (mapClick)="mapClick.next($event.coords)"> | ||||
|     <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"></agm-circle> | ||||
|         <agm-circle [latitude]="position.latitude" [longitude]="position.longitude" [radius]="position.accuracy" fillColor="#5C95F2" [clickable]="false"></agm-circle> | ||||
|     </ng-container> | ||||
|     <agm-marker *ngFor="let m of markers" [latitude]="m.latitude" [longitude]="m.longitude"></agm-marker> | ||||
| </agm-map> | ||||
| <div class="info p-2"> | ||||
|     <span *ngIf="!position" class="text-danger">No GPS</span> | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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<LatLngLiteral>(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 = []; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										15
									
								
								src/app/map/toolbar/toolbar.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/app/map/toolbar/toolbar.component.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <mat-toolbar> | ||||
|     <button mat-icon-button routerLink="/"> | ||||
|         <img src="/assets/images/logo.png" height="35px" width="auto"> | ||||
|     </button> | ||||
|     <small class="ml-1 text-muted">{{version}}</small> | ||||
|     <div class="ml-auto"> | ||||
|         <div *ngFor="let section of menu" class="d-inline ml-4"> | ||||
|             <ng-container *ngFor="let item of section"> | ||||
|                 <button *ngIf="!item.hidden" mat-icon-button [ngClass]="{'selected': item.enabled}" class="ml-1" (click)="clickWrapper(item)"> | ||||
|                     <mat-icon>{{item.icon}}</mat-icon> | ||||
|                 </button> | ||||
|             </ng-container> | ||||
|         </div> | ||||
|     </div> | ||||
| </mat-toolbar> | ||||
							
								
								
									
										7
									
								
								src/app/map/toolbar/toolbar.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/app/map/toolbar/toolbar.component.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| mat-toolbar { | ||||
|   height: 40px !important; | ||||
| } | ||||
|  | ||||
| .selected { | ||||
|   background-color: #cccccc; | ||||
| } | ||||
							
								
								
									
										39
									
								
								src/app/map/toolbar/toolbar.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/app/map/toolbar/toolbar.component.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -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<ToolbarItem[][]>(); | ||||
|  | ||||
|     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(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/app/map/toolbar/toolbarItem.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/app/map/toolbar/toolbarItem.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
| @@ -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 = { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user