✨ Map: handle GPX click
This commit is contained in:
parent
0abb938393
commit
9eae8f9b53
@ -6,6 +6,11 @@
|
||||
(closeEmitter)="closePlaceBox()"></app-place-box>
|
||||
}
|
||||
|
||||
@if (selectedGPX) {
|
||||
<app-place-gpx [selectedPlace]="selectedGPX" (downloadEmitter)="downloadGPX()" (removeEmitter)="removeGPX()"
|
||||
(closeEmitter)="closePlaceGPX()"></app-place-gpx>
|
||||
}
|
||||
|
||||
<div class="absolute z-30 top-2 right-2 p-2 bg-white shadow rounded dark:bg-surface-900">
|
||||
<p-button (click)="toggleMarkersList()" text severity="secondary" icon="pi pi-map-marker" />
|
||||
</div>
|
||||
|
||||
@ -41,6 +41,7 @@ import { YesNoModalComponent } from "../../modals/yes-no-modal/yes-no-modal.comp
|
||||
import { CategoryCreateModalComponent } from "../../modals/category-create-modal/category-create-modal.component";
|
||||
import { AuthService } from "../../services/auth.service";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { PlaceGPXComponent } from "../../shared/place-gpx/place-gpx.component";
|
||||
|
||||
export interface ContextMenuItem {
|
||||
text: string;
|
||||
@ -62,6 +63,7 @@ export interface MarkerOptions extends L.MarkerOptions {
|
||||
standalone: true,
|
||||
imports: [
|
||||
PlaceBoxComponent,
|
||||
PlaceGPXComponent,
|
||||
FormsModule,
|
||||
SkeletonModule,
|
||||
ToggleSwitchModule,
|
||||
@ -102,6 +104,7 @@ export class DashboardComponent implements OnInit, AfterViewInit {
|
||||
visiblePlaces: Place[] = [];
|
||||
selectedPlace?: Place;
|
||||
categories: Category[] = [];
|
||||
selectedGPX?: Place;
|
||||
|
||||
filter_display_visited = false;
|
||||
filter_display_favorite_only = false;
|
||||
@ -531,21 +534,24 @@ export class DashboardComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
displayGPXOnMap(gpx: string) {
|
||||
if (!this.map) return;
|
||||
if (!this.map || !this.selectedPlace) return;
|
||||
if (!this.gpxLayerGroup)
|
||||
this.gpxLayerGroup = L.layerGroup().addTo(this.map);
|
||||
this.gpxLayerGroup.clearLayers();
|
||||
|
||||
try {
|
||||
const gpxPolyline = gpxToPolyline(gpx);
|
||||
const selectedPlaceWithGPX = { ...this.selectedPlace, gpx };
|
||||
|
||||
gpxPolyline.on("click", () => {
|
||||
this.gpxLayerGroup?.removeLayer(gpxPolyline);
|
||||
this.selectedGPX = selectedPlaceWithGPX;
|
||||
});
|
||||
this.gpxLayerGroup?.addLayer(gpxPolyline);
|
||||
this.map.fitBounds(gpxPolyline.getBounds(), { padding: [20, 20] });
|
||||
} catch {
|
||||
this.utilsService.toast("error", "Error", "Couldn't parse GPX data");
|
||||
}
|
||||
this.closePlaceBox();
|
||||
}
|
||||
|
||||
getPlaceGPX() {
|
||||
@ -816,6 +822,28 @@ export class DashboardComponent implements OnInit, AfterViewInit {
|
||||
this.selectedPlace = undefined;
|
||||
}
|
||||
|
||||
closePlaceGPX() {
|
||||
this.selectedGPX = undefined;
|
||||
}
|
||||
|
||||
downloadGPX() {
|
||||
if (!this.selectedGPX?.gpx) return;
|
||||
const dataBlob = new Blob([this.selectedGPX.gpx]);
|
||||
const downloadURL = URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadURL;
|
||||
link.download = `TRIP_${this.selectedGPX.name}.gpx`;
|
||||
link.click();
|
||||
link.remove();
|
||||
URL.revokeObjectURL(downloadURL);
|
||||
}
|
||||
|
||||
removeGPX() {
|
||||
if (!this.gpxLayerGroup) return;
|
||||
this.gpxLayerGroup.clearLayers();
|
||||
this.closePlaceGPX();
|
||||
}
|
||||
|
||||
toGithub() {
|
||||
this.utilsService.toGithubTRIP();
|
||||
}
|
||||
|
||||
22
src/src/app/shared/place-gpx/place-gpx.component.html
Normal file
22
src/src/app/shared/place-gpx/place-gpx.component.html
Normal file
@ -0,0 +1,22 @@
|
||||
@if (selectedPlace) {
|
||||
<div class="place-box-dialog">
|
||||
<div class="place-box-dialog-content">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center gap-4 w-full max-w-full">
|
||||
<img [src]="selectedPlace.image || selectedPlace.category.image"
|
||||
class="object-cover rounded-full size-16">
|
||||
<div class="flex grow min-w-0">
|
||||
<h1 class="text-gray-800 font-bold mb-0 truncate">Trace of {{ selectedPlace.name }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<p-button (click)="downloadTrace()" text icon="pi pi-download" />
|
||||
<p-button (click)="removeTrace()" text icon="pi pi-eraser" />
|
||||
<div class="border-l border-solid border-gray-700 h-4"></div>
|
||||
<p-button (click)="close()" text icon="pi pi-times" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
25
src/src/app/shared/place-gpx/place-gpx.component.scss
Normal file
25
src/src/app/shared/place-gpx/place-gpx.component.scss
Normal file
@ -0,0 +1,25 @@
|
||||
.place-box-dialog {
|
||||
animation: slideYcenteredX 0.3s both;
|
||||
z-index: 999;
|
||||
min-height: 100px;
|
||||
max-height: 800px;
|
||||
width: 95%;
|
||||
max-width: 1200px;
|
||||
background-color: #fff;
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
transition: none;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
&-content {
|
||||
position: relative;
|
||||
padding: 2rem;
|
||||
border-radius: 8px 8px 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
38
src/src/app/shared/place-gpx/place-gpx.component.ts
Normal file
38
src/src/app/shared/place-gpx/place-gpx.component.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
} from "@angular/core";
|
||||
import { ButtonModule } from "primeng/button";
|
||||
import { Place } from "../../types/poi";
|
||||
|
||||
@Component({
|
||||
selector: "app-place-gpx",
|
||||
standalone: true,
|
||||
imports: [ButtonModule],
|
||||
templateUrl: "./place-gpx.component.html",
|
||||
styleUrls: ["./place-gpx.component.scss"],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PlaceGPXComponent {
|
||||
@Input() selectedPlace: Place | undefined = undefined;
|
||||
@Output() closeEmitter = new EventEmitter<void>();
|
||||
@Output() removeEmitter = new EventEmitter<void>();
|
||||
@Output() downloadEmitter = new EventEmitter<void>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
close() {
|
||||
this.closeEmitter.emit();
|
||||
}
|
||||
|
||||
removeTrace() {
|
||||
this.removeEmitter.emit();
|
||||
}
|
||||
|
||||
downloadTrace() {
|
||||
this.downloadEmitter.emit()
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user