Added ID's and update times for more accurate map merging during updates.
This commit is contained in:
		@@ -15,26 +15,24 @@ import {PermissionsComponent} from "./components/permissions/permissions.compone
 | 
			
		||||
import {AngularFireModule} from "@angular/fire";
 | 
			
		||||
import {AngularFirestoreModule} from "@angular/fire/firestore";
 | 
			
		||||
import {ToolbarComponent} from "./components/toolbar/toolbar.component";
 | 
			
		||||
import {PaletteComponent} from "./components/palette/palette.component";
 | 
			
		||||
import {MarkerComponent} from "./components/marker/marker.component";
 | 
			
		||||
import {PaletteComponent} from "./components/palette/palette.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";
 | 
			
		||||
import {DimensionsDialogComponent} from "./components/dimensionsDialog/dimensionsDialog.component";
 | 
			
		||||
import {EditSymbolComponent} from "./components/editSymbol/editSymbol.component";
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AnimatedBackgroundComponent,
 | 
			
		||||
        AppComponent,
 | 
			
		||||
        CalibrateComponent,
 | 
			
		||||
        CircleComponent,
 | 
			
		||||
        ColorPickerDialogComponent,
 | 
			
		||||
        DimensionsDialogComponent,
 | 
			
		||||
        EditSymbolComponent,
 | 
			
		||||
        HomeComponent,
 | 
			
		||||
        MapComponent,
 | 
			
		||||
        MarkerComponent,
 | 
			
		||||
        PaletteComponent,
 | 
			
		||||
        PermissionsComponent,
 | 
			
		||||
        ToolbarComponent
 | 
			
		||||
@@ -53,7 +51,7 @@ import {DimensionsDialogComponent} from "./components/dimensionsDialog/dimension
 | 
			
		||||
        MatInputModule,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [],
 | 
			
		||||
    entryComponents: [CalibrateComponent, CircleComponent, ColorPickerDialogComponent, DimensionsDialogComponent, MarkerComponent, PermissionsComponent],
 | 
			
		||||
    entryComponents: [CalibrateComponent, ColorPickerDialogComponent, DimensionsDialogComponent, EditSymbolComponent, PermissionsComponent],
 | 
			
		||||
    bootstrap: [AppComponent]
 | 
			
		||||
})
 | 
			
		||||
export class AppModule {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  z-index: 600;
 | 
			
		||||
  z-index: 6000;
 | 
			
		||||
  background-color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,14 +2,14 @@
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <mat-form-field appearance="fill" class="col-12 col-md-6">
 | 
			
		||||
            <mat-label>Label</mat-label>
 | 
			
		||||
            <input matInput [(ngModel)]="circle.label">
 | 
			
		||||
            <input matInput [(ngModel)]="symbol.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 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 class="row">
 | 
			
		||||
        <mat-form-field appearance="fill" class="col-12">
 | 
			
		||||
            <mat-label>Notes</mat-label>
 | 
			
		||||
            <textarea matInput rows="3"></textarea>
 | 
			
		||||
            <textarea matInput rows="3" [(ngModel)]="symbol.notes"></textarea>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
    </div>
 | 
			
		||||
    <mat-divider></mat-divider>
 | 
			
		||||
							
								
								
									
										36
									
								
								src/app/components/editSymbol/editSymbol.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/app/components/editSymbol/editSymbol.component.ts
									
									
									
									
									
										Normal 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
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,19 +4,21 @@ export interface LatLng {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MapData {
 | 
			
		||||
    circles?: Circle[];
 | 
			
		||||
    circles?: {[key: string]: Circle};
 | 
			
		||||
    locations?: {[key: string]: Marker};
 | 
			
		||||
    markers?: Marker[];
 | 
			
		||||
    measurements?: Measurement[];
 | 
			
		||||
    polygons?: Polygon[];
 | 
			
		||||
    polylines?: Polyline[];
 | 
			
		||||
    rectangles?: Rectangle[];
 | 
			
		||||
    markers?: {[key: string]: Marker};
 | 
			
		||||
    measurements?: {[key: string]: Measurement};
 | 
			
		||||
    polygons?: {[key: string]: Polygon};
 | 
			
		||||
    polylines?: {[key: string]: Polyline};
 | 
			
		||||
    rectangles?: {[key: string]: Rectangle};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MapSymbol {
 | 
			
		||||
    deleted?: boolean;
 | 
			
		||||
    id?: string;
 | 
			
		||||
    symbol?: any;
 | 
			
		||||
    latlng?: LatLng | LatLng[];
 | 
			
		||||
    new?: boolean;
 | 
			
		||||
    noClick?: boolean;
 | 
			
		||||
    noDelete?: boolean;
 | 
			
		||||
    noDeleteTool?: boolean;
 | 
			
		||||
    noSelect?: boolean;
 | 
			
		||||
@@ -26,6 +28,7 @@ export interface MapSymbol {
 | 
			
		||||
    interactive?: boolean;
 | 
			
		||||
    rotationAngle?: number;
 | 
			
		||||
    rotationOrigin?: string;
 | 
			
		||||
    updated?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Circle extends MapSymbol {
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ export class MapService {
 | 
			
		||||
    newCircle(c: Circle) {
 | 
			
		||||
        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'});
 | 
			
		||||
        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);
 | 
			
		||||
        return circle;
 | 
			
		||||
    }
 | 
			
		||||
@@ -116,7 +116,7 @@ export class MapService {
 | 
			
		||||
    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);
 | 
			
		||||
        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);
 | 
			
		||||
        return marker;
 | 
			
		||||
    }
 | 
			
		||||
@@ -132,20 +132,20 @@ export class MapService {
 | 
			
		||||
 | 
			
		||||
        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.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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    newPolygon(p: Polygon) {
 | 
			
		||||
        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);
 | 
			
		||||
        return polygon;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    newPolyline(p: Polyline) {
 | 
			
		||||
        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);
 | 
			
		||||
        return polyline;
 | 
			
		||||
    }
 | 
			
		||||
@@ -153,7 +153,7 @@ export class MapService {
 | 
			
		||||
    newRectangle(r: Rectangle) {
 | 
			
		||||
        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'});
 | 
			
		||||
        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);
 | 
			
		||||
        return rect;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import {Injectable} from "@angular/core";
 | 
			
		||||
import {AngularFirestore, AngularFirestoreDocument} from "@angular/fire/firestore";
 | 
			
		||||
import {BehaviorSubject, combineLatest, Subscription} from "rxjs";
 | 
			
		||||
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";
 | 
			
		||||
 | 
			
		||||
export const LOCATION_COLLECTION = 'Users';
 | 
			
		||||
@@ -22,6 +22,7 @@ export class SyncService {
 | 
			
		||||
    private saveInterval: number;
 | 
			
		||||
    private username: string;
 | 
			
		||||
 | 
			
		||||
    freeze = new BehaviorSubject<boolean>(false);
 | 
			
		||||
    mapData = new BehaviorSubject<MapData>({});
 | 
			
		||||
    status = new BehaviorSubject<string>(null);
 | 
			
		||||
 | 
			
		||||
@@ -39,10 +40,13 @@ export class SyncService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private addMapSymbol(s: MapSymbol, key: string) {
 | 
			
		||||
        s.new = true;
 | 
			
		||||
        let map = this.mapData.value;
 | 
			
		||||
        if(!map[key]) map[key] = [];
 | 
			
		||||
        map[key].push(s);
 | 
			
		||||
        if(!map[key]) map[key] = {};
 | 
			
		||||
        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.mapChanged = true;
 | 
			
		||||
        this.status.next('modified');
 | 
			
		||||
@@ -67,8 +71,8 @@ export class SyncService {
 | 
			
		||||
    addMyLocation(location: Position) {
 | 
			
		||||
        location.timestamp = new Date();
 | 
			
		||||
        let markForSave = this.location == null;
 | 
			
		||||
        if(!this.locationChanged) this.locationChanged = !_.isEqual(this.location, location);
 | 
			
		||||
        if(this.locationChanged) this.location = location;
 | 
			
		||||
        this.locationChanged = true;
 | 
			
		||||
        this.location = location;
 | 
			
		||||
        if(markForSave) return this.save(false, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -86,9 +90,7 @@ export class SyncService {
 | 
			
		||||
 | 
			
		||||
    delete(...symbols) {
 | 
			
		||||
        let map = this.mapData.value;
 | 
			
		||||
        Object.keys(map).filter(key => Array.isArray(map[key])).forEach(key => {
 | 
			
		||||
            symbols.forEach(s => map[key] = map[key].filter(ss => !_.isEqual(s, ss)))
 | 
			
		||||
        });
 | 
			
		||||
        Object.keys(map).forEach(key => symbols.filter(s => !!map[key][s.id]).forEach(s => map[key][s.id].deleted = true));
 | 
			
		||||
        this.mapData.next(map);
 | 
			
		||||
        this.mapChanged = true;
 | 
			
		||||
        this.status.next('modified');
 | 
			
		||||
@@ -105,15 +107,15 @@ export class SyncService {
 | 
			
		||||
            let aMinuteAgo = new Date();
 | 
			
		||||
            aMinuteAgo.setMinutes(aMinuteAgo.getMinutes() - 1);
 | 
			
		||||
            return ref.where('timestamp', '>=', aMinuteAgo);
 | 
			
		||||
        }).snapshotChanges())
 | 
			
		||||
        }).snapshotChanges(), this.freeze)
 | 
			
		||||
            .pipe(map(data => {
 | 
			
		||||
                let newMap = data[0];
 | 
			
		||||
                let oldMap = this.mapData.value;
 | 
			
		||||
                if(data[2]) return oldMap;
 | 
			
		||||
                let newMap = data[0] || {};
 | 
			
		||||
                let mergedMap = this.mergeMaps(newMap, oldMap);
 | 
			
		||||
 | 
			
		||||
                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 => {
 | 
			
		||||
                    if(!mergedMap.locations) mergedMap.locations = {};
 | 
			
		||||
                    mergedMap.locations[l.id] = l.data;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
@@ -127,14 +129,20 @@ export class SyncService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mergeMaps(newMap: MapData, oldMap: MapData) {
 | 
			
		||||
        let map = Object.assign({}, newMap);
 | 
			
		||||
        Object.keys(oldMap).forEach(key => {
 | 
			
		||||
            if(Array.isArray(map[key])) {
 | 
			
		||||
                if(!map[key]) map[key] = [];
 | 
			
		||||
                oldMap[key].filter(s => !_.find(map[key], s) && s.new).forEach(s => map[key].push(s));
 | 
			
		||||
            }
 | 
			
		||||
        let map: MapData = {locations: {}};
 | 
			
		||||
        Object.keys(newMap).forEach(key => {
 | 
			
		||||
            if(!map[key]) map[key] = {};
 | 
			
		||||
            Object.keys(newMap[key]).filter(id => !newMap[key][id].deleted)
 | 
			
		||||
                .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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -153,7 +161,6 @@ export class SyncService {
 | 
			
		||||
        if(map && this.mapDoc && this.mapChanged) {
 | 
			
		||||
            this.status.next('saving');
 | 
			
		||||
            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;
 | 
			
		||||
            promises.push(this.mapDoc.set(map));
 | 
			
		||||
            this.mapChanged = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 15%;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
  transform: translateX(-50%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
  bottom: 15%;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  width: 200px;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
  transform: translateX(-50%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -19,5 +19,5 @@
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  bottom: 2%;
 | 
			
		||||
  right: 2%;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,14 @@
 | 
			
		||||
 | 
			
		||||
.palette {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
  top: 60px;
 | 
			
		||||
  right: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.share {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
  top: 60px;
 | 
			
		||||
  right: 15px;
 | 
			
		||||
}
 | 
			
		||||
@@ -19,14 +19,14 @@
 | 
			
		||||
.info {
 | 
			
		||||
  background-color: #00000050;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
  bottom: 15px;
 | 
			
		||||
  left: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gps {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
  bottom: 15px;
 | 
			
		||||
  right: 15px;
 | 
			
		||||
}
 | 
			
		||||
@@ -50,7 +50,7 @@
 | 
			
		||||
::ng-deep .mat-toolbar {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  height: 45px !important;
 | 
			
		||||
  z-index: 500;
 | 
			
		||||
  z-index: 5000;
 | 
			
		||||
  color: rgba(255, 255, 255, 0.54);
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.8);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,12 @@ import {ActivatedRoute} from "@angular/router";
 | 
			
		||||
import {DimensionsDialogComponent} from "../../components/dimensionsDialog/dimensionsDialog.component";
 | 
			
		||||
import {MatDialog} from "@angular/material/dialog";
 | 
			
		||||
import {SyncService} from "../../services/sync.service";
 | 
			
		||||
import {MapData, Marker} from "../../models/mapSymbol";
 | 
			
		||||
import {MapData, MapSymbol, Marker} from "../../models/mapSymbol";
 | 
			
		||||
import {Adjectives} from "../../adjectives";
 | 
			
		||||
import {Nouns} from "../../nounes";
 | 
			
		||||
import {EditSymbolComponent} from "../../components/editSymbol/editSymbol.component";
 | 
			
		||||
 | 
			
		||||
declare const L;
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'map',
 | 
			
		||||
@@ -95,28 +98,25 @@ export class MapComponent implements OnDestroy, OnInit {
 | 
			
		||||
        // Setup map repainting on updates
 | 
			
		||||
        this.syncService.mapData.pipe(filter(s => !!s)).subscribe((map: MapData) => {
 | 
			
		||||
            this.map.deleteAll();
 | 
			
		||||
            if (map.circles) map.circles.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.markers) map.markers.forEach(m => this.map.newMarker(m));
 | 
			
		||||
            if (map.measurements) map.measurements.forEach(m => this.map.newMeasurement(m));
 | 
			
		||||
            if (map.polygons) map.polygons.forEach(p => this.map.newPolygon(p));
 | 
			
		||||
            if (map.polylines) map.polylines.forEach(p => this.map.newPolyline(p));
 | 
			
		||||
            if (map.rectangles) map.rectangles.forEach(r => this.map.newRectangle(r));
 | 
			
		||||
            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', noDeleteTool: true})));
 | 
			
		||||
            if (map.markers) Object.values(map.markers).filter(m => !m.deleted).forEach(m => this.map.newMarker(m));
 | 
			
		||||
            if (map.measurements) Object.values(map.measurements).filter(m => !m.deleted).forEach(m => this.map.newMeasurement(m));
 | 
			
		||||
            if (map.polygons) Object.values(map.polygons).filter(p => !p.deleted).forEach(p => this.map.newPolygon(p));
 | 
			
		||||
            if (map.polylines) Object.values(map.polylines).filter(p => !p.deleted).forEach(p => this.map.newPolyline(p));
 | 
			
		||||
            if (map.rectangles) Object.values(map.rectangles).filter(r => !r.deleted).forEach(r => this.map.newRectangle(r));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Handle opening map symbols
 | 
			
		||||
        this.map.click.pipe(filter(e => !!e && e.item)).subscribe(ignore => {
 | 
			
		||||
            /*if (e.item instanceof L.Marker) {
 | 
			
		||||
                if (e.symbol.noSelect) return;
 | 
			
		||||
                this.bottomSheet.open(MarkerComponent, {data: e.symbol, hasBackdrop: false, disableClose: true});
 | 
			
		||||
            } else if (e.item instanceof L.Circle) {
 | 
			
		||||
                if (e.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.map.click.pipe(filter(e => !!e)).subscribe(e => {
 | 
			
		||||
            if(this.sub == null && e.symbol) {
 | 
			
		||||
                this.sub = this.bottomSheet.open(EditSymbolComponent, {data: e, disableClose: true, hasBackdrop: false}).afterDismissed().pipe(finalize(() => this.sub = null)).subscribe(symbol => {
 | 
			
		||||
                    this.syncService.delete(e.symbol);
 | 
			
		||||
                    if(e.item instanceof L.Circle) {
 | 
			
		||||
                        this.syncService.addCircle(symbol);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }*/
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Display location information & submit it
 | 
			
		||||
@@ -172,9 +172,12 @@ export class MapComponent implements OnDestroy, OnInit {
 | 
			
		||||
    startCalibrating = (menuItem?) => {
 | 
			
		||||
        this.calibration = this.bottomSheet.open(CalibrateComponent, {hasBackdrop: false, disableClose: true});
 | 
			
		||||
        this.sub = this.calibration.afterDismissed().pipe(finalize(() => {
 | 
			
		||||
            menuItem.enabled = false;
 | 
			
		||||
        })).subscribe(() => {
 | 
			
		||||
            this.calibration.dismiss();
 | 
			
		||||
            this.calibration = null;
 | 
			
		||||
        }), filter(menuItem => !!menuItem)).subscribe(() => menuItem.enabled = false);
 | 
			
		||||
            this.sub = null;
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    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();
 | 
			
		||||
            if(!dimensions) return;
 | 
			
		||||
            menuItem.enabled = false;
 | 
			
		||||
            this.sub = null;
 | 
			
		||||
            let circle = {latlng: e.latlng, radius: dimensions[0]};
 | 
			
		||||
            this.syncService.addCircle(circle);
 | 
			
		||||
        });
 | 
			
		||||
@@ -201,7 +205,7 @@ export class MapComponent implements OnDestroy, OnInit {
 | 
			
		||||
            this.showPalette = false;
 | 
			
		||||
            this.map.lock(true);
 | 
			
		||||
        })).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 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(() => {
 | 
			
		||||
@@ -217,12 +221,13 @@ export class MapComponent implements OnDestroy, OnInit {
 | 
			
		||||
    startMarker = menuItem => {
 | 
			
		||||
        this.sub = this.map.click.pipe(skip(1), take(1)).subscribe(e => {
 | 
			
		||||
            menuItem.enabled = false;
 | 
			
		||||
            this.sub = null;
 | 
			
		||||
            let marker: Marker = {latlng: e.latlng};
 | 
			
		||||
            this.syncService.addMarker(marker);
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    startMeasuring = menuItem => {
 | 
			
		||||
    startMeasuring = () => {
 | 
			
		||||
        let lastPoint;
 | 
			
		||||
        this.sub = this.map.click.pipe(skip(1), finalize(() => this.map.delete(lastPoint))).subscribe(e => {
 | 
			
		||||
            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 => {
 | 
			
		||||
            if (lastPoint) {
 | 
			
		||||
                menuItem.enabled = false;
 | 
			
		||||
                this.sub = null;
 | 
			
		||||
                let rect = {latlng: {lat: lastPoint.getLatLng().lat, lng: lastPoint.getLatLng().lng}, latlng2: e.latlng};
 | 
			
		||||
                this.syncService.addRectangle(rect);
 | 
			
		||||
                return this.map.delete(lastPoint);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,10 @@ body {
 | 
			
		||||
  background-color: black;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.curs-pointer {
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.d-relative {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
@@ -47,3 +51,22 @@ a[href^="https://maps.google.com/maps"]{display: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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user