A bunch of stuff
This commit is contained in:
parent
30b74dd91c
commit
cd4f0a53a8
@ -37,6 +37,7 @@
|
||||
"leaflet-polylinedecorator": "^1.6.0",
|
||||
"leaflet-rotatedmarker": "^0.2.0",
|
||||
"ng-click-outside": "^5.0.0",
|
||||
"ngx-color-picker": "^8.1.0",
|
||||
"rxjs": "~6.4.0",
|
||||
"tslib": "^1.9.0",
|
||||
"web-animations-js": "^2.3.2",
|
||||
|
@ -19,12 +19,17 @@ import {PaletteComponent} from "./components/palette/palette.component";
|
||||
import {MarkerComponent} from "./components/marker/marker.component";
|
||||
import {AnimatedBackgroundComponent} from "./components/animatedBackground/animatedBackground.component";
|
||||
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({
|
||||
declarations: [
|
||||
AnimatedBackgroundComponent,
|
||||
AppComponent,
|
||||
CalibrateComponent,
|
||||
CircleComponent,
|
||||
ColorPickerDialogComponent,
|
||||
HomeComponent,
|
||||
MapComponent,
|
||||
MarkerComponent,
|
||||
@ -39,13 +44,14 @@ import {ClickOutsideModule} from "ng-click-outside";
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
ClickOutsideModule,
|
||||
ColorPickerModule,
|
||||
FormsModule,
|
||||
MaterialModule,
|
||||
ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production}),
|
||||
MatInputModule,
|
||||
],
|
||||
providers: [],
|
||||
entryComponents: [CalibrateComponent, MarkerComponent, PermissionsComponent],
|
||||
entryComponents: [CalibrateComponent, CircleComponent, ColorPickerDialogComponent, MarkerComponent, PermissionsComponent],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
|
17
src/app/components/circle/circle.component.html
Normal file
17
src/app/components/circle/circle.component.html
Normal 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>
|
37
src/app/components/circle/circle.component.ts
Normal file
37
src/app/components/circle/circle.component.ts
Normal 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
|
||||
});
|
||||
}
|
||||
}
|
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
@ -5,4 +5,6 @@
|
||||
<input matInput [(ngModel)]="marker.label">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<button mat-button class="float-right mt-2" (click)="close()">Close</button>
|
||||
</div>
|
||||
|
@ -9,4 +9,8 @@ import {MAT_BOTTOM_SHEET_DATA} from "@angular/material/bottom-sheet";
|
||||
export class MarkerComponent {
|
||||
|
||||
constructor(private bottomSheetRef: MatBottomSheetRef, @Inject(MAT_BOTTOM_SHEET_DATA) public marker) { }
|
||||
|
||||
close() {
|
||||
this.bottomSheetRef.dismiss();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
import {LatLng} from "./latlng";
|
||||
|
||||
export interface Drawing {
|
||||
color: string;
|
||||
path: LatLng[];
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
export interface LatLng {
|
||||
lat: number;
|
||||
lng: number;
|
||||
}
|
@ -1,12 +1,2 @@
|
||||
import {Marker} from "./marker";
|
||||
import {Drawing} from "./drawing";
|
||||
import {User} from "./user";
|
||||
import {Message} from "./message";
|
||||
|
||||
export interface Map {
|
||||
drawings: Drawing[];
|
||||
markers: Marker[];
|
||||
messages: Message[];
|
||||
name: string;
|
||||
users: User[];
|
||||
}
|
||||
|
46
src/app/models/mapSymbol.ts
Normal file
46
src/app/models/mapSymbol.ts
Normal 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;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import {LatLng} from "./latlng";
|
||||
|
||||
export interface Marker {
|
||||
latLng: LatLng;
|
||||
name: string;
|
||||
color: string;
|
||||
notes: string;
|
||||
icon: string;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import {LatLng} from "./latlng";
|
||||
|
||||
export interface Measurement {
|
||||
start: LatLng;
|
||||
end: LatLng;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import {User} from "./user";
|
||||
|
||||
export interface Message {
|
||||
from: User;
|
||||
text: string;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import {LatLng} from "./latlng";
|
||||
|
||||
export interface User {
|
||||
name: string;
|
||||
icon: string;
|
||||
latLng: LatLng;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import {BehaviorSubject} from "rxjs";
|
||||
import {distanceInM} from "../utils";
|
||||
import {environment} from "../../environments/environment";
|
||||
import {LatLng} from "../models/latlng";
|
||||
import {Circle, LatLng, Marker, Measurement} from "../models/mapSymbol";
|
||||
|
||||
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.on('click', (e) => this.click.next({event: e}));
|
||||
this.setMapLayer();
|
||||
|
||||
this.map.on('editable:drag', e => console.log(e));
|
||||
}
|
||||
|
||||
centerOn(latlng: LatLng, zoom=14) {
|
||||
@ -115,34 +117,36 @@ export class MapService {
|
||||
if(this.weatherLayer) this.weatherLayer.layer.addTo(this.map);
|
||||
}
|
||||
|
||||
newCircle(latlng: LatLng, radius?: number, opts: any={}) {
|
||||
if(!radius) radius = 100_000 / this.map.getZoom();
|
||||
opts.radius = radius;
|
||||
let circle = L.circle(latlng, opts).addTo(this.map);
|
||||
newCircle(c: Circle) {
|
||||
if(!c.radius) c.radius = 10000;
|
||||
if(!c.color) c.color = '#ff4141';
|
||||
let circle = L.circle(c.latlng, c).addTo(this.map);
|
||||
circle.symbol = c;
|
||||
circle.on('click', e => this.click.next({event: e, symbol: circle}));
|
||||
return circle;
|
||||
}
|
||||
|
||||
newMarker(latlng: LatLng, opts: any={}) {
|
||||
if(!opts.icon) opts.icon = MARKER;
|
||||
let marker = L.marker(latlng, opts).addTo(this.map);
|
||||
if(opts.label) marker.bindTooltip(opts.label, {permanent: true, direction: 'bottom'});
|
||||
this.markers.push(marker);
|
||||
newMarker(m: Marker) {
|
||||
if(!m.icon) m.icon = MARKER;
|
||||
let marker = L.marker(m.latlng, m).addTo(this.map);
|
||||
if(m.label) marker.bindTooltip(m.label, {permanent: true, direction: 'bottom'});
|
||||
marker.symbol = m;
|
||||
marker.on('click', e => this.click.next({event: e, symbol: marker}));
|
||||
return marker;
|
||||
}
|
||||
|
||||
newMeasurement(latlng1: LatLng, latlng2: LatLng) {
|
||||
let line = L.polyline([latlng1, latlng2], {color: '#ff4141', weight: 10});
|
||||
newMeasurement(m: Measurement) {
|
||||
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: [
|
||||
{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: 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: 10, polygon: false, headAngle: 180, pathOptions: m})}
|
||||
]});
|
||||
this.measurements.push({line: line, decoration: decoration});
|
||||
let distance = distanceInM(latlng1.lat, latlng1.lng, latlng2.lat, latlng2.lng);
|
||||
let group = L.layerGroup([line, decoration]);
|
||||
let group = L.layerGroup([line, decoration]).addTo(this.map);
|
||||
group.symbol = m;
|
||||
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();
|
||||
return group;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import {MarkerComponent} from "../../components/marker/marker.component";
|
||||
import {MatBottomSheetRef} from "@angular/material/bottom-sheet";
|
||||
import {copyToClipboard} from "../../utils";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {CircleComponent} from "../../components/circle/circle.component";
|
||||
|
||||
declare const L;
|
||||
|
||||
@ -70,17 +71,30 @@ export class MapComponent implements OnInit {
|
||||
this.map = new MapService('map');
|
||||
|
||||
// Handle click actions
|
||||
this.map.click.pipe(filter(e => !!e)).subscribe(e => {
|
||||
if(!!e.symbol && this.menu[6].enabled) return this.map.delete(e.symbol);
|
||||
if(e.symbol instanceof L.Marker) this.bottomSheet.open(MarkerComponent, {data: e.symbol});
|
||||
this.map.click.pipe(filter(e => !!e && e.symbol)).subscribe(e => {
|
||||
let symbol = e.symbol.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 => {
|
||||
if(!this.position) this.center({lat: pos.latitude, lng: pos.longitude});
|
||||
if(this.positionMarker.arrow) this.map.delete(this.positionMarker.arrow);
|
||||
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.circle = this.map.newCircle({lat: pos.latitude, lng: pos.longitude}, pos.accuracy, {interactive: false});
|
||||
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({latlng: {lat: pos.latitude, lng: pos.longitude}, color: '#2873d8', radius: pos.accuracy, interactive: false});
|
||||
this.position = pos;
|
||||
});
|
||||
|
||||
@ -95,14 +109,14 @@ export class MapComponent implements OnInit {
|
||||
addCircle() {
|
||||
this.map.click.pipe(skip(1), take(1), filter(() => this.menu[2].enabled)).subscribe(e => {
|
||||
this.menu[2].enabled = false;
|
||||
this.map.newCircle(e.event.latlng);
|
||||
this.map.newCircle({latlng: e.event.latlng});
|
||||
});
|
||||
}
|
||||
|
||||
addMarker() {
|
||||
this.map.click.pipe(skip(1), take(1), filter(() => this.menu[0].enabled)).subscribe(e => {
|
||||
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() {
|
||||
this.measuringSubscription = this.map.click.pipe(skip(1)).subscribe(e => {
|
||||
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.lastMeasuringPoint = this.map.newMarker(e.event.latlng, {icon: MEASURE});
|
||||
this.lastMeasuringPoint = this.map.newMarker({latlng: e.event.latlng, icon: MEASURE});
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -16,3 +16,18 @@ body {
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.d-relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.overflow-hidden {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cdk-overlay-pane.p-0 {
|
||||
.mat-dialog-container {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user