A bunch of stuff

This commit is contained in:
Zakary Timson 2019-08-27 19:33:52 -04:00
parent 30b74dd91c
commit cd4f0a53a8
19 changed files with 195 additions and 76 deletions

View File

@ -37,6 +37,7 @@
"leaflet-polylinedecorator": "^1.6.0", "leaflet-polylinedecorator": "^1.6.0",
"leaflet-rotatedmarker": "^0.2.0", "leaflet-rotatedmarker": "^0.2.0",
"ng-click-outside": "^5.0.0", "ng-click-outside": "^5.0.0",
"ngx-color-picker": "^8.1.0",
"rxjs": "~6.4.0", "rxjs": "~6.4.0",
"tslib": "^1.9.0", "tslib": "^1.9.0",
"web-animations-js": "^2.3.2", "web-animations-js": "^2.3.2",

View File

@ -19,12 +19,17 @@ import {PaletteComponent} from "./components/palette/palette.component";
import {MarkerComponent} from "./components/marker/marker.component"; import {MarkerComponent} from "./components/marker/marker.component";
import {AnimatedBackgroundComponent} from "./components/animatedBackground/animatedBackground.component"; import {AnimatedBackgroundComponent} from "./components/animatedBackground/animatedBackground.component";
import {ClickOutsideModule} from "ng-click-outside"; import {ClickOutsideModule} from "ng-click-outside";
import {CircleComponent} from "./components/circle/circle.component";
import {ColorPickerModule} from "ngx-color-picker";
import {ColorPickerDialogComponent} from "./components/colorPickerDialog/colorPickerDialog.component";
@NgModule({ @NgModule({
declarations: [ declarations: [
AnimatedBackgroundComponent, AnimatedBackgroundComponent,
AppComponent, AppComponent,
CalibrateComponent, CalibrateComponent,
CircleComponent,
ColorPickerDialogComponent,
HomeComponent, HomeComponent,
MapComponent, MapComponent,
MarkerComponent, MarkerComponent,
@ -39,13 +44,14 @@ import {ClickOutsideModule} from "ng-click-outside";
BrowserAnimationsModule, BrowserAnimationsModule,
BrowserModule, BrowserModule,
ClickOutsideModule, ClickOutsideModule,
ColorPickerModule,
FormsModule, FormsModule,
MaterialModule, MaterialModule,
ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production}), ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production}),
MatInputModule, MatInputModule,
], ],
providers: [], providers: [],
entryComponents: [CalibrateComponent, MarkerComponent, PermissionsComponent], entryComponents: [CalibrateComponent, CircleComponent, ColorPickerDialogComponent, MarkerComponent, PermissionsComponent],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { export class AppModule {

View File

@ -0,0 +1,17 @@
<div>
<div class="row">
<mat-form-field appearance="fill" class="col-12 col-md-6">
<mat-label>Label</mat-label>
<input matInput [(ngModel)]="circle.label">
</mat-form-field>
<div class="ml-auto mt-1 mr-3 rounded-circle border" (click)="colorPicker()" style="width: 46px; height: 46px;" [style.background]="circle.color"></div>
</div>
<div class="row">
<mat-form-field appearance="fill" class="col-12">
<mat-label>Notes</mat-label>
<textarea matInput rows="3"></textarea>
</mat-form-field>
</div>
<mat-divider></mat-divider>
<button mat-button class="float-right mt-2" (click)="close()">Close</button>
</div>

View File

@ -0,0 +1,37 @@
import {Component, Inject} from "@angular/core";
import {MatBottomSheetRef} from "@angular/material";
import {MAT_BOTTOM_SHEET_DATA} from "@angular/material/bottom-sheet";
import {Circle} from "../../models/mapSymbol";
import {MatDialog} from "@angular/material/dialog";
import {ColorPickerDialogComponent} from "../colorPickerDialog/colorPickerDialog.component";
@Component({
selector: 'calibrate',
templateUrl: 'circle.component.html'
})
export class CircleComponent {
symbol: any;
circle: Circle;
constructor(private dialog: MatDialog, private bottomSheetRef: MatBottomSheetRef, @Inject(MAT_BOTTOM_SHEET_DATA) circle) {
this.symbol = circle;
this.circle = this.symbol.symbol;
this.symbol.enableEdit();
this.bottomSheetRef.afterDismissed().subscribe(() => this.symbol.disableEdit());
}
close() {
this.circle.latlng = this.symbol.getLatLng();
this.circle.radius = this.symbol.getRadius();
this.bottomSheetRef.dismiss(this.symbol);
}
colorPicker() {
this.dialog.open(ColorPickerDialogComponent, {data: this.circle.color, hasBackdrop: false, panelClass: 'p-0'}).afterClosed()
.subscribe(color => {
this.circle.color = color
});
}
}

View File

@ -0,0 +1,7 @@
<div class="d-relative">
<div [(colorPicker)]="color" [cpToggle]="true" [cpCloseClickOutside]="false" cpDialogDisplay="inline"></div>
<div class="text-right p-1">
<button mat-button color="warn" [mat-dialog-close]="originalColor">Cancel</button>
<button mat-button [mat-dialog-close]="color">Ok</button>
</div>
</div>

View File

@ -0,0 +1,14 @@
import {Component, Inject} from "@angular/core";
import {MAT_DIALOG_DATA} from "@angular/material/dialog";
@Component({
selector: '',
templateUrl: `./colorPickerDialog.component.html`
})
export class ColorPickerDialogComponent {
readonly originalColor: string;
constructor(@Inject(MAT_DIALOG_DATA) public color) {
this.originalColor = color;
}
}

View File

@ -5,4 +5,6 @@
<input matInput [(ngModel)]="marker.label"> <input matInput [(ngModel)]="marker.label">
</mat-form-field> </mat-form-field>
</div> </div>
<mat-divider></mat-divider>
<button mat-button class="float-right mt-2" (click)="close()">Close</button>
</div> </div>

View File

@ -9,4 +9,8 @@ import {MAT_BOTTOM_SHEET_DATA} from "@angular/material/bottom-sheet";
export class MarkerComponent { export class MarkerComponent {
constructor(private bottomSheetRef: MatBottomSheetRef, @Inject(MAT_BOTTOM_SHEET_DATA) public marker) { } constructor(private bottomSheetRef: MatBottomSheetRef, @Inject(MAT_BOTTOM_SHEET_DATA) public marker) { }
close() {
this.bottomSheetRef.dismiss();
}
} }

View File

@ -1,6 +0,0 @@
import {LatLng} from "./latlng";
export interface Drawing {
color: string;
path: LatLng[];
}

View File

@ -1,4 +0,0 @@
export interface LatLng {
lat: number;
lng: number;
}

View File

@ -1,12 +1,2 @@
import {Marker} from "./marker";
import {Drawing} from "./drawing";
import {User} from "./user";
import {Message} from "./message";
export interface Map { export interface Map {
drawings: Drawing[];
markers: Marker[];
messages: Message[];
name: string;
users: User[];
} }

View File

@ -0,0 +1,46 @@
export interface LatLng {
lat: number;
lng: number;
}
export interface MapSymbol {
symbol?: any;
latlng?: LatLng | LatLng[];
noDelete?: boolean;
noSelect?: boolean;
label?: string;
color?: string;
notes?: string;
interactive?: boolean;
rotationAngle?: number;
rotationOrigin?: string;
}
export interface Circle extends MapSymbol {
latlng: LatLng;
radius?: number;
}
export interface Square extends MapSymbol {
latlng: LatLng;
latlng2: LatLng;
}
export interface Polyline extends MapSymbol {
latlng: LatLng[];
}
export interface Marker extends MapSymbol {
latlng: LatLng;
icon?: any;
}
export interface Polygon extends MapSymbol {
latlng: LatLng[];
}
export interface Measurement extends MapSymbol {
latlng: LatLng;
latlng2: LatLng;
weight?: number;
}

View File

@ -1,9 +0,0 @@
import {LatLng} from "./latlng";
export interface Marker {
latLng: LatLng;
name: string;
color: string;
notes: string;
icon: string;
}

View File

@ -1,6 +0,0 @@
import {LatLng} from "./latlng";
export interface Measurement {
start: LatLng;
end: LatLng;
}

View File

@ -1,6 +0,0 @@
import {User} from "./user";
export interface Message {
from: User;
text: string;
}

View File

@ -1,7 +0,0 @@
import {LatLng} from "./latlng";
export interface User {
name: string;
icon: string;
latLng: LatLng;
}

View File

@ -1,7 +1,7 @@
import {BehaviorSubject} from "rxjs"; import {BehaviorSubject} from "rxjs";
import {distanceInM} from "../utils"; import {distanceInM} from "../utils";
import {environment} from "../../environments/environment"; import {environment} from "../../environments/environment";
import {LatLng} from "../models/latlng"; import {Circle, LatLng, Marker, Measurement} from "../models/mapSymbol";
declare const L; declare const L;
@ -39,6 +39,8 @@ export class MapService {
this.map = L.map(elementId, {attributionControl: false, editable: true, tap: true, zoomControl: false, maxBoundsViscosity: 1, doubleClickZoom: false}).setView({lat: 0, lng: 0}, 10); this.map = L.map(elementId, {attributionControl: false, editable: true, tap: true, zoomControl: false, maxBoundsViscosity: 1, doubleClickZoom: false}).setView({lat: 0, lng: 0}, 10);
this.map.on('click', (e) => this.click.next({event: e})); this.map.on('click', (e) => this.click.next({event: e}));
this.setMapLayer(); this.setMapLayer();
this.map.on('editable:drag', e => console.log(e));
} }
centerOn(latlng: LatLng, zoom=14) { centerOn(latlng: LatLng, zoom=14) {
@ -115,34 +117,36 @@ export class MapService {
if(this.weatherLayer) this.weatherLayer.layer.addTo(this.map); if(this.weatherLayer) this.weatherLayer.layer.addTo(this.map);
} }
newCircle(latlng: LatLng, radius?: number, opts: any={}) { newCircle(c: Circle) {
if(!radius) radius = 100_000 / this.map.getZoom(); if(!c.radius) c.radius = 10000;
opts.radius = radius; if(!c.color) c.color = '#ff4141';
let circle = L.circle(latlng, opts).addTo(this.map); let circle = L.circle(c.latlng, c).addTo(this.map);
circle.symbol = c;
circle.on('click', e => this.click.next({event: e, symbol: circle})); circle.on('click', e => this.click.next({event: e, symbol: circle}));
return circle; return circle;
} }
newMarker(latlng: LatLng, opts: any={}) { newMarker(m: Marker) {
if(!opts.icon) opts.icon = MARKER; if(!m.icon) m.icon = MARKER;
let marker = L.marker(latlng, opts).addTo(this.map); let marker = L.marker(m.latlng, m).addTo(this.map);
if(opts.label) marker.bindTooltip(opts.label, {permanent: true, direction: 'bottom'}); if(m.label) marker.bindTooltip(m.label, {permanent: true, direction: 'bottom'});
this.markers.push(marker); marker.symbol = m;
marker.on('click', e => this.click.next({event: e, symbol: marker})); marker.on('click', e => this.click.next({event: e, symbol: marker}));
return marker; return marker;
} }
newMeasurement(latlng1: LatLng, latlng2: LatLng) { newMeasurement(m: Measurement) {
let line = L.polyline([latlng1, latlng2], {color: '#ff4141', weight: 10}); if(!m.color) m.color = '#ff4141';
if(!m.weight) m.weight = 8;
let line = L.polyline([m.latlng, m.latlng2], m);
let decoration = L.polylineDecorator(line, {patterns: [ let decoration = L.polylineDecorator(line, {patterns: [
{offset: '100%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 15, polygon: false, headAngle: 180, pathOptions: {color: '#ff4141', weight: 10, stroke: true}})}, {offset: '100%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 10, polygon: false, headAngle: 180, pathOptions: m})},
{offset: '-100%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 15, polygon: false, headAngle: 180, pathOptions: {color: '#ff4141', weight: 10, stroke: true}})} {offset: '-100%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 10, polygon: false, headAngle: 180, pathOptions: m})}
]}); ]});
this.measurements.push({line: line, decoration: decoration}); let group = L.layerGroup([line, decoration]).addTo(this.map);
let distance = distanceInM(latlng1.lat, latlng1.lng, latlng2.lat, latlng2.lng); group.symbol = m;
let group = L.layerGroup([line, decoration]);
line.on('click', e => this.click.next({event: e, symbol: group})); line.on('click', e => this.click.next({event: e, symbol: group}));
group.addTo(this.map); let distance = distanceInM(m.latlng.lat, m.latlng.lng, m.latlng2.lat, m.latlng2.lng);
line.bindPopup(`${distance > 1000 ? Math.round(distance / 100) / 10 : Math.round(distance)} ${distance > 1000 ? 'k' : ''}m`, {autoClose: false, closeOnClick: false}).openPopup(); line.bindPopup(`${distance > 1000 ? Math.round(distance / 100) / 10 : Math.round(distance)} ${distance > 1000 ? 'k' : ''}m`, {autoClose: false, closeOnClick: false}).openPopup();
return group; return group;
} }

View File

@ -11,6 +11,7 @@ import {MarkerComponent} from "../../components/marker/marker.component";
import {MatBottomSheetRef} from "@angular/material/bottom-sheet"; import {MatBottomSheetRef} from "@angular/material/bottom-sheet";
import {copyToClipboard} from "../../utils"; import {copyToClipboard} from "../../utils";
import {ActivatedRoute} from "@angular/router"; import {ActivatedRoute} from "@angular/router";
import {CircleComponent} from "../../components/circle/circle.component";
declare const L; declare const L;
@ -70,17 +71,30 @@ export class MapComponent implements OnInit {
this.map = new MapService('map'); this.map = new MapService('map');
// Handle click actions // Handle click actions
this.map.click.pipe(filter(e => !!e)).subscribe(e => { this.map.click.pipe(filter(e => !!e && e.symbol)).subscribe(e => {
if(!!e.symbol && this.menu[6].enabled) return this.map.delete(e.symbol); let symbol = e.symbol.symbol;
if(e.symbol instanceof L.Marker) this.bottomSheet.open(MarkerComponent, {data: e.symbol}); if(this.menu[6].enabled) {
if(!!symbol && symbol.noDelete) return;
return this.map.delete(e.symbol);
} else if(e.symbol instanceof L.Marker) {
if(symbol.noSelect) return;
/*this.bottomSheet.open(MarkerComponent, {data: e.symbol, hasBackdrop: false, disableClose: true});*/
} else if(e.symbol instanceof L.Circle) {
if(symbol.noSelect) return;
/*this.bottomSheet.open(CircleComponent, {data: e.symbol, hasBackdrop: false, disableClose: true}).afterDismissed().subscribe(c => {
let circle = c['_symbol'];
this.map.delete(c);
this.map.newCircle(circle);
});*/
}
}); });
this.physicsService.info.pipe(filter(coord => !!coord)).subscribe(pos => { this.physicsService.info.pipe(filter(coord => !!coord)).subscribe(pos => {
if(!this.position) this.center({lat: pos.latitude, lng: pos.longitude}); if(!this.position) this.center({lat: pos.latitude, lng: pos.longitude});
if(this.positionMarker.arrow) this.map.delete(this.positionMarker.arrow); if(this.positionMarker.arrow) this.map.delete(this.positionMarker.arrow);
if(this.positionMarker.circle) this.map.delete(this.positionMarker.circle); if(this.positionMarker.circle) this.map.delete(this.positionMarker.circle);
this.positionMarker.arrow = this.map.newMarker({lat: pos.latitude, lng: pos.longitude}, {noDelete: true, icon: ARROW, rotationAngle: pos.heading, rotationOrigin: 'center'}); this.positionMarker.arrow = this.map.newMarker({latlng: {lat: pos.latitude, lng: pos.longitude}, noSelect: true, noDelete: true, icon: ARROW, rotationAngle: pos.heading, rotationOrigin: 'center'});
this.positionMarker.circle = this.map.newCircle({lat: pos.latitude, lng: pos.longitude}, pos.accuracy, {interactive: false}); this.positionMarker.circle = this.map.newCircle({latlng: {lat: pos.latitude, lng: pos.longitude}, color: '#2873d8', radius: pos.accuracy, interactive: false});
this.position = pos; this.position = pos;
}); });
@ -95,14 +109,14 @@ export class MapComponent implements OnInit {
addCircle() { addCircle() {
this.map.click.pipe(skip(1), take(1), filter(() => this.menu[2].enabled)).subscribe(e => { this.map.click.pipe(skip(1), take(1), filter(() => this.menu[2].enabled)).subscribe(e => {
this.menu[2].enabled = false; this.menu[2].enabled = false;
this.map.newCircle(e.event.latlng); this.map.newCircle({latlng: e.event.latlng});
}); });
} }
addMarker() { addMarker() {
this.map.click.pipe(skip(1), take(1), filter(() => this.menu[0].enabled)).subscribe(e => { this.map.click.pipe(skip(1), take(1), filter(() => this.menu[0].enabled)).subscribe(e => {
this.menu[0].enabled = false; this.menu[0].enabled = false;
this.map.newMarker(e.event.latlng); this.map.newMarker({latlng: e.event.latlng});
}); });
} }
@ -147,10 +161,10 @@ export class MapComponent implements OnInit {
startMeasuring() { startMeasuring() {
this.measuringSubscription = this.map.click.pipe(skip(1)).subscribe(e => { this.measuringSubscription = this.map.click.pipe(skip(1)).subscribe(e => {
if(this.lastMeasuringPoint) { if(this.lastMeasuringPoint) {
this.map.newMeasurement(this.lastMeasuringPoint.getLatLng(), e.event.latlng); this.map.newMeasurement({latlng: this.lastMeasuringPoint.getLatLng(), latlng2: e.event.latlng});
this.map.delete(this.lastMeasuringPoint); this.map.delete(this.lastMeasuringPoint);
} }
this.lastMeasuringPoint = this.map.newMarker(e.event.latlng, {icon: MEASURE}); this.lastMeasuringPoint = this.map.newMarker({latlng: e.event.latlng, icon: MEASURE});
}) })
} }

View File

@ -16,3 +16,18 @@ body {
font-family: Roboto, "Helvetica Neue", sans-serif; font-family: Roboto, "Helvetica Neue", sans-serif;
background-color: black; background-color: black;
} }
.d-relative {
position: relative;
}
.overflow-hidden {
overflow: hidden;
}
.cdk-overlay-pane.p-0 {
.mat-dialog-container {
padding: 0;
overflow: hidden;
}
}