Added ID's and update times for more accurate map merging during updates.

This commit is contained in:
Zakary Timson 2019-09-08 11:36:48 -04:00
parent 088777d742
commit eceb85569e
16 changed files with 152 additions and 136 deletions

View File

@ -44,6 +44,7 @@
"ng-click-outside": "^5.0.0", "ng-click-outside": "^5.0.0",
"ngx-color-picker": "^8.1.0", "ngx-color-picker": "^8.1.0",
"rxjs": "~6.4.0", "rxjs": "~6.4.0",
"ts-md5": "^1.2.5",
"tslib": "^1.9.0", "tslib": "^1.9.0",
"web-animations-js": "^2.3.2", "web-animations-js": "^2.3.2",
"whatwg-fetch": "^3.0.0", "whatwg-fetch": "^3.0.0",

View File

@ -15,26 +15,24 @@ import {PermissionsComponent} from "./components/permissions/permissions.compone
import {AngularFireModule} from "@angular/fire"; import {AngularFireModule} from "@angular/fire";
import {AngularFirestoreModule} from "@angular/fire/firestore"; import {AngularFirestoreModule} from "@angular/fire/firestore";
import {ToolbarComponent} from "./components/toolbar/toolbar.component"; import {ToolbarComponent} from "./components/toolbar/toolbar.component";
import {PaletteComponent} from "./components/palette/palette.component"; import {PaletteComponent} from "./components/palette/palette.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 {ColorPickerModule} from "ngx-color-picker";
import {ColorPickerDialogComponent} from "./components/colorPickerDialog/colorPickerDialog.component"; import {ColorPickerDialogComponent} from "./components/colorPickerDialog/colorPickerDialog.component";
import {DimensionsDialogComponent} from "./components/dimensionsDialog/dimensionsDialog.component"; import {DimensionsDialogComponent} from "./components/dimensionsDialog/dimensionsDialog.component";
import {EditSymbolComponent} from "./components/editSymbol/editSymbol.component";
@NgModule({ @NgModule({
declarations: [ declarations: [
AnimatedBackgroundComponent, AnimatedBackgroundComponent,
AppComponent, AppComponent,
CalibrateComponent, CalibrateComponent,
CircleComponent,
ColorPickerDialogComponent, ColorPickerDialogComponent,
DimensionsDialogComponent, DimensionsDialogComponent,
EditSymbolComponent,
HomeComponent, HomeComponent,
MapComponent, MapComponent,
MarkerComponent,
PaletteComponent, PaletteComponent,
PermissionsComponent, PermissionsComponent,
ToolbarComponent ToolbarComponent
@ -53,7 +51,7 @@ import {DimensionsDialogComponent} from "./components/dimensionsDialog/dimension
MatInputModule, MatInputModule,
], ],
providers: [], providers: [],
entryComponents: [CalibrateComponent, CircleComponent, ColorPickerDialogComponent, DimensionsDialogComponent, MarkerComponent, PermissionsComponent], entryComponents: [CalibrateComponent, ColorPickerDialogComponent, DimensionsDialogComponent, EditSymbolComponent, PermissionsComponent],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { export class AppModule {

View File

@ -4,7 +4,7 @@
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 600; z-index: 6000;
background-color: black; background-color: black;
} }

View File

@ -1,37 +0,0 @@
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

@ -2,14 +2,14 @@
<div class="row"> <div class="row">
<mat-form-field appearance="fill" class="col-12 col-md-6"> <mat-form-field appearance="fill" class="col-12 col-md-6">
<mat-label>Label</mat-label> <mat-label>Label</mat-label>
<input matInput [(ngModel)]="circle.label"> <input matInput [(ngModel)]="symbol.label">
</mat-form-field> </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 class="ml-auto mt-1 mr-3 rounded-circle border curs-pointer" (click)="colorPicker()" style="width: 46px; height: 46px;" [style.background]="symbol.color"></div>
</div> </div>
<div class="row"> <div class="row">
<mat-form-field appearance="fill" class="col-12"> <mat-form-field appearance="fill" class="col-12">
<mat-label>Notes</mat-label> <mat-label>Notes</mat-label>
<textarea matInput rows="3"></textarea> <textarea matInput rows="3" [(ngModel)]="symbol.notes"></textarea>
</mat-form-field> </mat-form-field>
</div> </div>
<mat-divider></mat-divider> <mat-divider></mat-divider>

View File

@ -0,0 +1,36 @@
import {Component, Inject} from "@angular/core";
import {MatDialog} from "@angular/material/dialog";
import {MapSymbol} from "../../models/mapSymbol";
import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetRef} from "@angular/material/bottom-sheet";
import {ColorPickerDialogComponent} from "../colorPickerDialog/colorPickerDialog.component";
@Component({
selector: 'edit-symbol',
templateUrl: 'editSymbol.component.html'
})
export class EditSymbolComponent {
symbol: MapSymbol;
mapItem;
constructor(private dialog: MatDialog, private ref: MatBottomSheetRef, @Inject(MAT_BOTTOM_SHEET_DATA) data) {
this.symbol = Object.assign({color: '#ff4141'}, data.symbol);
this.mapItem = data.item;
this.mapItem.enableEdit();
this.ref.afterDismissed().subscribe(() => this.mapItem.disableEdit());
}
close() {
let latlng = this.mapItem.getLatLng();
this.symbol.latlng = {lat: latlng.lat, lng: latlng.lng};
if(this.mapItem.getRadius) this.symbol['radius'] = this.mapItem.getRadius();
this.ref.dismiss(this.symbol);
}
colorPicker() {
this.dialog.open(ColorPickerDialogComponent, {data: this.symbol.color, hasBackdrop: false, panelClass: 'p-0'}).afterClosed()
.subscribe(color => {
this.symbol.color = color
});
}
}

View File

@ -1,10 +0,0 @@
<div>
<div class="row">
<mat-form-field appearance="fill" class="col-12 col-md-6">
<mat-label>Label</mat-label>
<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>

View File

@ -1,16 +0,0 @@
import {Component, Inject} from "@angular/core";
import {MatBottomSheetRef} from "@angular/material";
import {MAT_BOTTOM_SHEET_DATA} from "@angular/material/bottom-sheet";
@Component({
selector: 'calibrate',
templateUrl: 'marker.component.html'
})
export class MarkerComponent {
constructor(private bottomSheetRef: MatBottomSheetRef, @Inject(MAT_BOTTOM_SHEET_DATA) public marker) { }
close() {
this.bottomSheetRef.dismiss();
}
}

View File

@ -4,19 +4,21 @@ export interface LatLng {
} }
export interface MapData { export interface MapData {
circles?: Circle[]; circles?: {[key: string]: Circle};
locations?: {[key: string]: Marker}; locations?: {[key: string]: Marker};
markers?: Marker[]; markers?: {[key: string]: Marker};
measurements?: Measurement[]; measurements?: {[key: string]: Measurement};
polygons?: Polygon[]; polygons?: {[key: string]: Polygon};
polylines?: Polyline[]; polylines?: {[key: string]: Polyline};
rectangles?: Rectangle[]; rectangles?: {[key: string]: Rectangle};
} }
export interface MapSymbol { export interface MapSymbol {
deleted?: boolean;
id?: string;
symbol?: any; symbol?: any;
latlng?: LatLng | LatLng[]; latlng?: LatLng | LatLng[];
new?: boolean; noClick?: boolean;
noDelete?: boolean; noDelete?: boolean;
noDeleteTool?: boolean; noDeleteTool?: boolean;
noSelect?: boolean; noSelect?: boolean;
@ -26,6 +28,7 @@ export interface MapSymbol {
interactive?: boolean; interactive?: boolean;
rotationAngle?: number; rotationAngle?: number;
rotationOrigin?: string; rotationOrigin?: string;
updated?: number;
} }
export interface Circle extends MapSymbol { export interface Circle extends MapSymbol {

View File

@ -108,7 +108,7 @@ export class MapService {
newCircle(c: Circle) { newCircle(c: Circle) {
let circle = L.circle(c.latlng, Object.assign({color: '#ff4141'}, c)).addTo(this.map); let circle = L.circle(c.latlng, Object.assign({color: '#ff4141'}, c)).addTo(this.map);
if(c.label) circle.bindTooltip(c.label, {permanent: true, direction: 'center'}); if(c.label) circle.bindTooltip(c.label, {permanent: true, direction: 'center'});
circle.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: c, item: circle})); if(!c.noClick) circle.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: c, item: circle}));
if(!c.noDelete) this.circles.push(circle); if(!c.noDelete) this.circles.push(circle);
return circle; return circle;
} }
@ -116,7 +116,7 @@ export class MapService {
newMarker(m: Marker) { newMarker(m: Marker) {
let marker = L.marker(m.latlng, Object.assign({color: '#ff4141'}, m, {icon: m.icon ? this.getIcon(m.icon) : MARKER})).addTo(this.map); let marker = L.marker(m.latlng, Object.assign({color: '#ff4141'}, m, {icon: m.icon ? this.getIcon(m.icon) : MARKER})).addTo(this.map);
if(m.label) marker.bindTooltip(m.label, {permanent: true, direction: 'bottom'}); if(m.label) marker.bindTooltip(m.label, {permanent: true, direction: 'bottom'});
marker.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: m, item: marker})); if(!m.noClick) marker.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: m, item: marker}));
if(!m.noDelete) this.markers.push(marker); if(!m.noDelete) this.markers.push(marker);
return marker; return marker;
} }
@ -132,20 +132,20 @@ export class MapService {
let distance = latLngDistance(m.latlng, m.latlng2); let distance = latLngDistance(m.latlng, m.latlng2);
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();
line.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: m, item: group})); if(m.noClick) line.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: m, item: group}));
return group; return group;
} }
newPolygon(p: Polygon) { newPolygon(p: Polygon) {
let polygon = new L.Polygon(p.latlng, Object.assign({color: '#ff4141'}, p)).addTo(this.map); let polygon = new L.Polygon(p.latlng, Object.assign({color: '#ff4141'}, p)).addTo(this.map);
polygon.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: p, item: polygon})); if(!p.noClick) polygon.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: p, item: polygon}));
if(!p.noDelete) this.polygons.push(polygon); if(!p.noDelete) this.polygons.push(polygon);
return polygon; return polygon;
} }
newPolyline(p: Polyline) { newPolyline(p: Polyline) {
let polyline = new L.Polyline(p.latlng, Object.assign({color: '#ff4141', weight: 10}, p)).addTo(this.map); let polyline = new L.Polyline(p.latlng, Object.assign({color: '#ff4141', weight: 10}, p)).addTo(this.map);
polyline.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: p, item: polyline})); if(!p.noClick) polyline.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: p, item: polyline}));
if(!p.noDelete) this.polylines.push(polyline); if(!p.noDelete) this.polylines.push(polyline);
return polyline; return polyline;
} }
@ -153,7 +153,7 @@ export class MapService {
newRectangle(r: Rectangle) { newRectangle(r: Rectangle) {
let rect = new L.Rectangle([r.latlng, r.latlng2], Object.assign({color: '#ff4141'}, r)).addTo(this.map); let rect = new L.Rectangle([r.latlng, r.latlng2], Object.assign({color: '#ff4141'}, r)).addTo(this.map);
if(r.label) rect.bindTooltip(r.label, {permanent: true, direction: 'center'}); if(r.label) rect.bindTooltip(r.label, {permanent: true, direction: 'center'});
rect.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: r, item: rect})); if(!r.noClick) rect.on('click', e => this.click.next({latlng: {lat: e.latlng.lat, lng: e.latlng.lng}, symbol: r, item: rect}));
if(!r.noDelete) this.rectangles.push(rect); if(!r.noDelete) this.rectangles.push(rect);
return rect; return rect;
} }

View File

@ -2,7 +2,7 @@ import {Injectable} from "@angular/core";
import {AngularFirestore, AngularFirestoreDocument} from "@angular/fire/firestore"; import {AngularFirestore, AngularFirestoreDocument} from "@angular/fire/firestore";
import {BehaviorSubject, combineLatest, Subscription} from "rxjs"; import {BehaviorSubject, combineLatest, Subscription} from "rxjs";
import {Circle, MapData, MapSymbol, Marker, Measurement, Polygon, Polyline, Position, Rectangle} from "../models/mapSymbol"; import {Circle, MapData, MapSymbol, Marker, Measurement, Polygon, Polyline, Position, Rectangle} from "../models/mapSymbol";
import * as _ from 'lodash'; import {Md5} from 'ts-md5';
import {filter, map} from "rxjs/operators"; import {filter, map} from "rxjs/operators";
export const LOCATION_COLLECTION = 'Users'; export const LOCATION_COLLECTION = 'Users';
@ -22,6 +22,7 @@ export class SyncService {
private saveInterval: number; private saveInterval: number;
private username: string; private username: string;
freeze = new BehaviorSubject<boolean>(false);
mapData = new BehaviorSubject<MapData>({}); mapData = new BehaviorSubject<MapData>({});
status = new BehaviorSubject<string>(null); status = new BehaviorSubject<string>(null);
@ -39,10 +40,13 @@ export class SyncService {
} }
private addMapSymbol(s: MapSymbol, key: string) { private addMapSymbol(s: MapSymbol, key: string) {
s.new = true;
let map = this.mapData.value; let map = this.mapData.value;
if(!map[key]) map[key] = []; if(!map[key]) map[key] = {};
map[key].push(s); do {
s.updated = new Date().getTime();
s.id = Md5.hashStr(s.updated.toString()).toString();
} while (!!map[key][s.id]);
map[key][s.id] = s;
this.mapData.next(map); this.mapData.next(map);
this.mapChanged = true; this.mapChanged = true;
this.status.next('modified'); this.status.next('modified');
@ -67,8 +71,8 @@ export class SyncService {
addMyLocation(location: Position) { addMyLocation(location: Position) {
location.timestamp = new Date(); location.timestamp = new Date();
let markForSave = this.location == null; let markForSave = this.location == null;
if(!this.locationChanged) this.locationChanged = !_.isEqual(this.location, location); this.locationChanged = true;
if(this.locationChanged) this.location = location; this.location = location;
if(markForSave) return this.save(false, true); if(markForSave) return this.save(false, true);
} }
@ -86,9 +90,7 @@ export class SyncService {
delete(...symbols) { delete(...symbols) {
let map = this.mapData.value; let map = this.mapData.value;
Object.keys(map).filter(key => Array.isArray(map[key])).forEach(key => { Object.keys(map).forEach(key => symbols.filter(s => !!map[key][s.id]).forEach(s => map[key][s.id].deleted = true));
symbols.forEach(s => map[key] = map[key].filter(ss => !_.isEqual(s, ss)))
});
this.mapData.next(map); this.mapData.next(map);
this.mapChanged = true; this.mapChanged = true;
this.status.next('modified'); this.status.next('modified');
@ -105,15 +107,15 @@ export class SyncService {
let aMinuteAgo = new Date(); let aMinuteAgo = new Date();
aMinuteAgo.setMinutes(aMinuteAgo.getMinutes() - 1); aMinuteAgo.setMinutes(aMinuteAgo.getMinutes() - 1);
return ref.where('timestamp', '>=', aMinuteAgo); return ref.where('timestamp', '>=', aMinuteAgo);
}).snapshotChanges()) }).snapshotChanges(), this.freeze)
.pipe(map(data => { .pipe(map(data => {
let newMap = data[0];
let oldMap = this.mapData.value; let oldMap = this.mapData.value;
if(data[2]) return oldMap;
let newMap = data[0] || {};
let mergedMap = this.mergeMaps(newMap, oldMap); let mergedMap = this.mergeMaps(newMap, oldMap);
let locations = data[1].map(doc => ({id: doc.payload.doc.id, data: <Marker>doc.payload.doc.data()})); let locations = data[1].map(doc => ({id: doc.payload.doc.id, data: <Marker>doc.payload.doc.data()}));
locations.filter(l => l.id != username).forEach(l => { locations.filter(l => l.id != username).forEach(l => {
if(!mergedMap.locations) mergedMap.locations = {};
mergedMap.locations[l.id] = l.data; mergedMap.locations[l.id] = l.data;
}); });
@ -127,14 +129,20 @@ export class SyncService {
} }
mergeMaps(newMap: MapData, oldMap: MapData) { mergeMaps(newMap: MapData, oldMap: MapData) {
let map = Object.assign({}, newMap); let map: MapData = {locations: {}};
Object.keys(oldMap).forEach(key => { Object.keys(newMap).forEach(key => {
if(Array.isArray(map[key])) { if(!map[key]) map[key] = {};
if(!map[key]) map[key] = []; Object.keys(newMap[key]).filter(id => !newMap[key][id].deleted)
oldMap[key].filter(s => !_.find(map[key], s) && s.new).forEach(s => map[key].push(s)); .forEach(id => map[key][id] = newMap[key][id]);
} });
Object.keys(oldMap).filter(key => key != 'locations').forEach(key => {
if(!map[key]) map[key] = {};
Object.keys(oldMap[key]).filter(id => {
let newS = map[key][id] || false;
return newS && newS.updated > map[key][id].updated;
}).forEach(id => map[key][id] = oldMap[key][id]);
}); });
if(!map.locations) map.locations = {};
return map; return map;
} }
@ -153,7 +161,6 @@ export class SyncService {
if(map && this.mapDoc && this.mapChanged) { if(map && this.mapDoc && this.mapChanged) {
this.status.next('saving'); this.status.next('saving');
let map = this.mapData.value; let map = this.mapData.value;
Object.values(map).filter(val => Array.isArray(val)).forEach(val => val.filter(s => s.new).forEach(s => delete s.new));
delete map.locations; delete map.locations;
promises.push(this.mapDoc.set(map)); promises.push(this.mapDoc.set(map));
this.mapChanged = false; this.mapChanged = false;

View File

@ -2,7 +2,7 @@
position: absolute; position: absolute;
top: 15%; top: 15%;
left: 50%; left: 50%;
z-index: 500; z-index: 5000;
transform: translateX(-50%); transform: translateX(-50%);
} }
@ -11,7 +11,7 @@
bottom: 15%; bottom: 15%;
left: 50%; left: 50%;
width: 200px; width: 200px;
z-index: 500; z-index: 5000;
transform: translateX(-50%); transform: translateX(-50%);
} }
@ -19,5 +19,5 @@
position: absolute; position: absolute;
bottom: 2%; bottom: 2%;
right: 2%; right: 2%;
z-index: 500; z-index: 5000;
} }

View File

@ -4,14 +4,14 @@
.palette { .palette {
position: fixed; position: fixed;
z-index: 500; z-index: 5000;
top: 60px; top: 60px;
right: 15px; right: 15px;
} }
.share { .share {
position: fixed; position: fixed;
z-index: 500; z-index: 5000;
top: 60px; top: 60px;
right: 15px; right: 15px;
} }
@ -19,14 +19,14 @@
.info { .info {
background-color: #00000050; background-color: #00000050;
position: fixed; position: fixed;
z-index: 500; z-index: 5000;
bottom: 15px; bottom: 15px;
left: 15px; left: 15px;
} }
.gps { .gps {
position: fixed; position: fixed;
z-index: 500; z-index: 5000;
bottom: 15px; bottom: 15px;
right: 15px; right: 15px;
} }
@ -50,7 +50,7 @@
::ng-deep .mat-toolbar { ::ng-deep .mat-toolbar {
position: absolute; position: absolute;
height: 45px !important; height: 45px !important;
z-index: 500; z-index: 5000;
color: rgba(255, 255, 255, 0.54); color: rgba(255, 255, 255, 0.54);
background-color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.8);

View File

@ -12,9 +12,12 @@ import {ActivatedRoute} from "@angular/router";
import {DimensionsDialogComponent} from "../../components/dimensionsDialog/dimensionsDialog.component"; import {DimensionsDialogComponent} from "../../components/dimensionsDialog/dimensionsDialog.component";
import {MatDialog} from "@angular/material/dialog"; import {MatDialog} from "@angular/material/dialog";
import {SyncService} from "../../services/sync.service"; import {SyncService} from "../../services/sync.service";
import {MapData, Marker} from "../../models/mapSymbol"; import {MapData, MapSymbol, Marker} from "../../models/mapSymbol";
import {Adjectives} from "../../adjectives"; import {Adjectives} from "../../adjectives";
import {Nouns} from "../../nounes"; import {Nouns} from "../../nounes";
import {EditSymbolComponent} from "../../components/editSymbol/editSymbol.component";
declare const L;
@Component({ @Component({
selector: 'map', selector: 'map',
@ -95,28 +98,25 @@ export class MapComponent implements OnDestroy, OnInit {
// Setup map repainting on updates // Setup map repainting on updates
this.syncService.mapData.pipe(filter(s => !!s)).subscribe((map: MapData) => { this.syncService.mapData.pipe(filter(s => !!s)).subscribe((map: MapData) => {
this.map.deleteAll(); this.map.deleteAll();
if (map.circles) map.circles.forEach(c => this.map.newCircle(c)); if (map.circles) Object.values(map.circles).filter(c => !c.deleted).forEach(c => this.map.newCircle(c));
if (map.locations) Object.values(map.locations).forEach(l => this.map.newMarker(Object.assign(l, {icon: 'dot'}))); if (map.locations) Object.values(map.locations).forEach(l => this.map.newMarker(Object.assign(l, {icon: 'dot', noDeleteTool: true})));
if (map.markers) map.markers.forEach(m => this.map.newMarker(m)); if (map.markers) Object.values(map.markers).filter(m => !m.deleted).forEach(m => this.map.newMarker(m));
if (map.measurements) map.measurements.forEach(m => this.map.newMeasurement(m)); if (map.measurements) Object.values(map.measurements).filter(m => !m.deleted).forEach(m => this.map.newMeasurement(m));
if (map.polygons) map.polygons.forEach(p => this.map.newPolygon(p)); if (map.polygons) Object.values(map.polygons).filter(p => !p.deleted).forEach(p => this.map.newPolygon(p));
if (map.polylines) map.polylines.forEach(p => this.map.newPolyline(p)); if (map.polylines) Object.values(map.polylines).filter(p => !p.deleted).forEach(p => this.map.newPolyline(p));
if (map.rectangles) map.rectangles.forEach(r => this.map.newRectangle(r)); if (map.rectangles) Object.values(map.rectangles).filter(r => !r.deleted).forEach(r => this.map.newRectangle(r));
}); });
// Handle opening map symbols // Handle opening map symbols
this.map.click.pipe(filter(e => !!e && e.item)).subscribe(ignore => { this.map.click.pipe(filter(e => !!e)).subscribe(e => {
/*if (e.item instanceof L.Marker) { if(this.sub == null && e.symbol) {
if (e.symbol.noSelect) return; this.sub = this.bottomSheet.open(EditSymbolComponent, {data: e, disableClose: true, hasBackdrop: false}).afterDismissed().pipe(finalize(() => this.sub = null)).subscribe(symbol => {
this.bottomSheet.open(MarkerComponent, {data: e.symbol, hasBackdrop: false, disableClose: true}); this.syncService.delete(e.symbol);
} else if (e.item instanceof L.Circle) { if(e.item instanceof L.Circle) {
if (e.symbol.noSelect) return; this.syncService.addCircle(symbol);
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);
}); });
}*/ }
}); });
// Display location information & submit it // Display location information & submit it
@ -172,9 +172,12 @@ export class MapComponent implements OnDestroy, OnInit {
startCalibrating = (menuItem?) => { startCalibrating = (menuItem?) => {
this.calibration = this.bottomSheet.open(CalibrateComponent, {hasBackdrop: false, disableClose: true}); this.calibration = this.bottomSheet.open(CalibrateComponent, {hasBackdrop: false, disableClose: true});
this.sub = this.calibration.afterDismissed().pipe(finalize(() => { this.sub = this.calibration.afterDismissed().pipe(finalize(() => {
menuItem.enabled = false;
})).subscribe(() => {
this.calibration.dismiss(); this.calibration.dismiss();
this.calibration = null; this.calibration = null;
}), filter(menuItem => !!menuItem)).subscribe(() => menuItem.enabled = false); this.sub = null;
});
}; };
startCircle = menuItem => { startCircle = menuItem => {
@ -182,6 +185,7 @@ export class MapComponent implements OnDestroy, OnInit {
let dimensions = await this.dialog.open(DimensionsDialogComponent, {data: ['Radius (m)'], panelClass: 'pb-0'}).afterClosed().toPromise(); let dimensions = await this.dialog.open(DimensionsDialogComponent, {data: ['Radius (m)'], panelClass: 'pb-0'}).afterClosed().toPromise();
if(!dimensions) return; if(!dimensions) return;
menuItem.enabled = false; menuItem.enabled = false;
this.sub = null;
let circle = {latlng: e.latlng, radius: dimensions[0]}; let circle = {latlng: e.latlng, radius: dimensions[0]};
this.syncService.addCircle(circle); this.syncService.addCircle(circle);
}); });
@ -201,7 +205,7 @@ export class MapComponent implements OnDestroy, OnInit {
this.showPalette = false; this.showPalette = false;
this.map.lock(true); this.map.lock(true);
})).subscribe(e => { })).subscribe(e => {
let p = {latlng: [e.latlng], noDelete: true, color: this.drawColor, weight: 8}; let p = {latlng: [e.latlng], noClick: true, noDelete: true, color: this.drawColor, weight: 8};
let polyline = this.map.newPolyline(p); let polyline = this.map.newPolyline(p);
let drawingSub = this.map.touch.pipe(filter(e => e.type == 'move')).subscribe(e => polyline.addLatLng(e.latlng)); let drawingSub = this.map.touch.pipe(filter(e => e.type == 'move')).subscribe(e => polyline.addLatLng(e.latlng));
this.map.touch.pipe(filter(e => e.type == 'end'), take(1)).subscribe(() => { this.map.touch.pipe(filter(e => e.type == 'end'), take(1)).subscribe(() => {
@ -217,12 +221,13 @@ export class MapComponent implements OnDestroy, OnInit {
startMarker = menuItem => { startMarker = menuItem => {
this.sub = this.map.click.pipe(skip(1), take(1)).subscribe(e => { this.sub = this.map.click.pipe(skip(1), take(1)).subscribe(e => {
menuItem.enabled = false; menuItem.enabled = false;
this.sub = null;
let marker: Marker = {latlng: e.latlng}; let marker: Marker = {latlng: e.latlng};
this.syncService.addMarker(marker); this.syncService.addMarker(marker);
}); });
}; };
startMeasuring = menuItem => { startMeasuring = () => {
let lastPoint; let lastPoint;
this.sub = this.map.click.pipe(skip(1), finalize(() => this.map.delete(lastPoint))).subscribe(e => { this.sub = this.map.click.pipe(skip(1), finalize(() => this.map.delete(lastPoint))).subscribe(e => {
if (lastPoint) { if (lastPoint) {
@ -253,6 +258,7 @@ export class MapComponent implements OnDestroy, OnInit {
this.sub = this.map.click.pipe(skip(1), take(2), finalize(() => this.map.delete(lastPoint))).subscribe(e => { this.sub = this.map.click.pipe(skip(1), take(2), finalize(() => this.map.delete(lastPoint))).subscribe(e => {
if (lastPoint) { if (lastPoint) {
menuItem.enabled = false; menuItem.enabled = false;
this.sub = null;
let rect = {latlng: {lat: lastPoint.getLatLng().lat, lng: lastPoint.getLatLng().lng}, latlng2: e.latlng}; let rect = {latlng: {lat: lastPoint.getLatLng().lat, lng: lastPoint.getLatLng().lng}, latlng2: e.latlng};
this.syncService.addRectangle(rect); this.syncService.addRectangle(rect);
return this.map.delete(lastPoint); return this.map.delete(lastPoint);

View File

@ -14,6 +14,10 @@ body {
background-color: black; background-color: black;
} }
.curs-pointer {
cursor: pointer;
}
.d-relative { .d-relative {
position: relative; position: relative;
} }
@ -47,3 +51,22 @@ a[href^="https://maps.google.com/maps"]{display:none !important}
background: none !important; background: none !important;
} }
.cdk-overlay-container {
z-index: 5500 !important;
}
.leaflet-tooltip {
background: rgba(0, 0, 0, 0.6) !important;
border-color: rgba(0, 0, 0, 0.6) !important;
color: white;
}
.leaflet-popup-content-wrapper {
background: rgba(0, 0, 0, 0.6) !important;
color: white !important;
}
.leaflet-popup-tip {
background: rgba(0, 0, 0, 0.6) !important;
}

View File

@ -7621,6 +7621,11 @@ try-require@^1.0.0:
resolved "https://registry.yarnpkg.com/try-require/-/try-require-1.2.1.tgz#34489a2cac0c09c1cc10ed91ba011594d4333be2" resolved "https://registry.yarnpkg.com/try-require/-/try-require-1.2.1.tgz#34489a2cac0c09c1cc10ed91ba011594d4333be2"
integrity sha1-NEiaLKwMCcHMEO2RugEVlNQzO+I= integrity sha1-NEiaLKwMCcHMEO2RugEVlNQzO+I=
ts-md5@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/ts-md5/-/ts-md5-1.2.5.tgz#4cb00ddf687251a2aba09922f95f766bf6486a15"
integrity sha512-0E8UHsfEmK9CICH47YLVIN6/wtGJJ7/8XiAbUBszTHxeucglueTgPn86D8Ec3UG9tYWTICVY/EuUGQ+Xa2iSEA==
ts-node@~7.0.0: ts-node@~7.0.0:
version "7.0.1" version "7.0.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf"