Map: handle GPX click

This commit is contained in:
itskovacs 2025-08-23 16:04:56 +02:00
parent 0abb938393
commit 9eae8f9b53
5 changed files with 120 additions and 2 deletions

View File

@ -6,6 +6,11 @@
(closeEmitter)="closePlaceBox()"></app-place-box> (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"> <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" /> <p-button (click)="toggleMarkersList()" text severity="secondary" icon="pi pi-map-marker" />
</div> </div>

View File

@ -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 { CategoryCreateModalComponent } from "../../modals/category-create-modal/category-create-modal.component";
import { AuthService } from "../../services/auth.service"; import { AuthService } from "../../services/auth.service";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { PlaceGPXComponent } from "../../shared/place-gpx/place-gpx.component";
export interface ContextMenuItem { export interface ContextMenuItem {
text: string; text: string;
@ -62,6 +63,7 @@ export interface MarkerOptions extends L.MarkerOptions {
standalone: true, standalone: true,
imports: [ imports: [
PlaceBoxComponent, PlaceBoxComponent,
PlaceGPXComponent,
FormsModule, FormsModule,
SkeletonModule, SkeletonModule,
ToggleSwitchModule, ToggleSwitchModule,
@ -102,6 +104,7 @@ export class DashboardComponent implements OnInit, AfterViewInit {
visiblePlaces: Place[] = []; visiblePlaces: Place[] = [];
selectedPlace?: Place; selectedPlace?: Place;
categories: Category[] = []; categories: Category[] = [];
selectedGPX?: Place;
filter_display_visited = false; filter_display_visited = false;
filter_display_favorite_only = false; filter_display_favorite_only = false;
@ -531,21 +534,24 @@ export class DashboardComponent implements OnInit, AfterViewInit {
} }
displayGPXOnMap(gpx: string) { displayGPXOnMap(gpx: string) {
if (!this.map) return; if (!this.map || !this.selectedPlace) return;
if (!this.gpxLayerGroup) if (!this.gpxLayerGroup)
this.gpxLayerGroup = L.layerGroup().addTo(this.map); this.gpxLayerGroup = L.layerGroup().addTo(this.map);
this.gpxLayerGroup.clearLayers(); this.gpxLayerGroup.clearLayers();
try { try {
const gpxPolyline = gpxToPolyline(gpx); const gpxPolyline = gpxToPolyline(gpx);
const selectedPlaceWithGPX = { ...this.selectedPlace, gpx };
gpxPolyline.on("click", () => { gpxPolyline.on("click", () => {
this.gpxLayerGroup?.removeLayer(gpxPolyline); this.selectedGPX = selectedPlaceWithGPX;
}); });
this.gpxLayerGroup?.addLayer(gpxPolyline); this.gpxLayerGroup?.addLayer(gpxPolyline);
this.map.fitBounds(gpxPolyline.getBounds(), { padding: [20, 20] }); this.map.fitBounds(gpxPolyline.getBounds(), { padding: [20, 20] });
} catch { } catch {
this.utilsService.toast("error", "Error", "Couldn't parse GPX data"); this.utilsService.toast("error", "Error", "Couldn't parse GPX data");
} }
this.closePlaceBox();
} }
getPlaceGPX() { getPlaceGPX() {
@ -816,6 +822,28 @@ export class DashboardComponent implements OnInit, AfterViewInit {
this.selectedPlace = undefined; 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() { toGithub() {
this.utilsService.toGithubTRIP(); this.utilsService.toGithubTRIP();
} }

View 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>
}

View 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%;
}
}

View 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()
}
}