mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-01 08:12:32 +00:00
waypoint popup info
This commit is contained in:
@@ -557,6 +557,14 @@ export class Waypoint {
|
|||||||
this.attributes = coordinates;
|
this.attributes = coordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLatitude(): number {
|
||||||
|
return this.attributes.lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLongitude(): number {
|
||||||
|
return this.attributes.lon;
|
||||||
|
}
|
||||||
|
|
||||||
clone(): Waypoint {
|
clone(): Waypoint {
|
||||||
return new Waypoint({
|
return new Waypoint({
|
||||||
attributes: cloneJSON(this.attributes),
|
attributes: cloneJSON(this.attributes),
|
||||||
|
@@ -17,38 +17,40 @@
|
|||||||
const { distanceUnits, velocityUnits, temperatureUnits } = settings;
|
const { distanceUnits, velocityUnits, temperatureUnits } = settings;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if type === 'distance'}
|
<span class={$$props.class}>
|
||||||
{#if $distanceUnits === 'metric'}
|
{#if type === 'distance'}
|
||||||
{value.toFixed(2)} {showUnits ? $_('units.kilometers') : ''}
|
{#if $distanceUnits === 'metric'}
|
||||||
{:else}
|
{value.toFixed(2)} {showUnits ? $_('units.kilometers') : ''}
|
||||||
{kilometersToMiles(value).toFixed(2)} {showUnits ? $_('units.miles') : ''}
|
|
||||||
{/if}
|
|
||||||
{:else if type === 'elevation'}
|
|
||||||
{#if $distanceUnits === 'metric'}
|
|
||||||
{value.toFixed(0)} {showUnits ? $_('units.meters') : ''}
|
|
||||||
{:else}
|
|
||||||
{metersToFeet(value).toFixed(0)} {showUnits ? $_('units.feet') : ''}
|
|
||||||
{/if}
|
|
||||||
{:else if type === 'speed'}
|
|
||||||
{#if $distanceUnits === 'metric'}
|
|
||||||
{#if $velocityUnits === 'speed'}
|
|
||||||
{value.toFixed(2)} {showUnits ? $_('units.kilometers_per_hour') : ''}
|
|
||||||
{:else}
|
{:else}
|
||||||
{secondsToHHMMSS(distancePerHourToSecondsPerDistance(value))}
|
{kilometersToMiles(value).toFixed(2)} {showUnits ? $_('units.miles') : ''}
|
||||||
{showUnits ? $_('units.minutes_per_kilometer') : ''}
|
|
||||||
{/if}
|
{/if}
|
||||||
{:else if $velocityUnits === 'speed'}
|
{:else if type === 'elevation'}
|
||||||
{kilometersToMiles(value).toFixed(2)} {showUnits ? $_('units.miles_per_hour') : ''}
|
{#if $distanceUnits === 'metric'}
|
||||||
{:else}
|
{value.toFixed(0)} {showUnits ? $_('units.meters') : ''}
|
||||||
{secondsToHHMMSS(distancePerHourToSecondsPerDistance(kilometersToMiles(value)))}
|
{:else}
|
||||||
{showUnits ? $_('units.minutes_per_mile') : ''}
|
{metersToFeet(value).toFixed(0)} {showUnits ? $_('units.feet') : ''}
|
||||||
|
{/if}
|
||||||
|
{:else if type === 'speed'}
|
||||||
|
{#if $distanceUnits === 'metric'}
|
||||||
|
{#if $velocityUnits === 'speed'}
|
||||||
|
{value.toFixed(2)} {showUnits ? $_('units.kilometers_per_hour') : ''}
|
||||||
|
{:else}
|
||||||
|
{secondsToHHMMSS(distancePerHourToSecondsPerDistance(value))}
|
||||||
|
{showUnits ? $_('units.minutes_per_kilometer') : ''}
|
||||||
|
{/if}
|
||||||
|
{:else if $velocityUnits === 'speed'}
|
||||||
|
{kilometersToMiles(value).toFixed(2)} {showUnits ? $_('units.miles_per_hour') : ''}
|
||||||
|
{:else}
|
||||||
|
{secondsToHHMMSS(distancePerHourToSecondsPerDistance(kilometersToMiles(value)))}
|
||||||
|
{showUnits ? $_('units.minutes_per_mile') : ''}
|
||||||
|
{/if}
|
||||||
|
{:else if type === 'temperature'}
|
||||||
|
{#if $temperatureUnits === 'celsius'}
|
||||||
|
{value} {showUnits ? $_('units.celsius') : ''}
|
||||||
|
{:else}
|
||||||
|
{celsiusToFahrenheit(value)} {showUnits ? $_('units.fahrenheit') : ''}
|
||||||
|
{/if}
|
||||||
|
{:else if type === 'time'}
|
||||||
|
{secondsToHHMMSS(value)}
|
||||||
{/if}
|
{/if}
|
||||||
{:else if type === 'temperature'}
|
</span>
|
||||||
{#if $temperatureUnits === 'celsius'}
|
|
||||||
{value} {showUnits ? $_('units.celsius') : ''}
|
|
||||||
{:else}
|
|
||||||
{celsiusToFahrenheit(value)} {showUnits ? $_('units.fahrenheit') : ''}
|
|
||||||
{/if}
|
|
||||||
{:else if type === 'time'}
|
|
||||||
{secondsToHHMMSS(value)}
|
|
||||||
{/if}
|
|
||||||
|
@@ -2,6 +2,7 @@ import { map, selectFiles, currentTool, Tool } from "$lib/stores";
|
|||||||
import { settings, type GPXFileWithStatistics } from "$lib/db";
|
import { settings, type GPXFileWithStatistics } from "$lib/db";
|
||||||
import { get, type Readable } from "svelte/store";
|
import { get, type Readable } from "svelte/store";
|
||||||
import mapboxgl from "mapbox-gl";
|
import mapboxgl from "mapbox-gl";
|
||||||
|
import { currentWaypoint, waypointPopup } from "./WaypointPopup";
|
||||||
|
|
||||||
let defaultWeight = 6;
|
let defaultWeight = 6;
|
||||||
let defaultOpacity = 1;
|
let defaultOpacity = 1;
|
||||||
@@ -43,21 +44,17 @@ export class GPXLayer {
|
|||||||
fileId: string;
|
fileId: string;
|
||||||
file: Readable<GPXFileWithStatistics | undefined>;
|
file: Readable<GPXFileWithStatistics | undefined>;
|
||||||
layerColor: string;
|
layerColor: string;
|
||||||
popup: mapboxgl.Popup;
|
|
||||||
popupElement: HTMLElement;
|
|
||||||
markers: mapboxgl.Marker[] = [];
|
markers: mapboxgl.Marker[] = [];
|
||||||
unsubscribe: Function[] = [];
|
unsubscribe: Function[] = [];
|
||||||
|
|
||||||
updateBinded: () => void = this.update.bind(this);
|
updateBinded: () => void = this.update.bind(this);
|
||||||
selectOnClickBinded: (e: any) => void = this.selectOnClick.bind(this);
|
selectOnClickBinded: (e: any) => void = this.selectOnClick.bind(this);
|
||||||
|
|
||||||
constructor(map: mapboxgl.Map, fileId: string, file: Readable<GPXFileWithStatistics | undefined>, popup: mapboxgl.Popup, popupElement: HTMLElement) {
|
constructor(map: mapboxgl.Map, fileId: string, file: Readable<GPXFileWithStatistics | undefined>) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
this.fileId = fileId;
|
this.fileId = fileId;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.layerColor = getColor();
|
this.layerColor = getColor();
|
||||||
this.popup = popup;
|
|
||||||
this.popupElement = popupElement;
|
|
||||||
this.unsubscribe.push(file.subscribe(this.updateBinded));
|
this.unsubscribe.push(file.subscribe(this.updateBinded));
|
||||||
this.unsubscribe.push(directionMarkers.subscribe(this.updateBinded));
|
this.unsubscribe.push(directionMarkers.subscribe(this.updateBinded));
|
||||||
this.unsubscribe.push(distanceMarkers.subscribe(this.updateBinded));
|
this.unsubscribe.push(distanceMarkers.subscribe(this.updateBinded));
|
||||||
@@ -182,11 +179,15 @@ export class GPXLayer {
|
|||||||
this.markers[markerIndex].setLngLat(waypoint.getCoordinates());
|
this.markers[markerIndex].setLngLat(waypoint.getCoordinates());
|
||||||
} else {
|
} else {
|
||||||
let marker = new mapboxgl.Marker().setLngLat(waypoint.getCoordinates());
|
let marker = new mapboxgl.Marker().setLngLat(waypoint.getCoordinates());
|
||||||
marker.getElement().addEventListener('click', (e) => {
|
marker.getElement().addEventListener('mouseover', (e) => {
|
||||||
marker.setPopup(this.popup);
|
currentWaypoint.set(waypoint);
|
||||||
|
marker.setPopup(waypointPopup);
|
||||||
marker.togglePopup();
|
marker.togglePopup();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
marker.getElement().addEventListener('mouseout', () => {
|
||||||
|
marker.togglePopup();
|
||||||
|
});
|
||||||
|
|
||||||
this.markers.push(marker);
|
this.markers.push(marker);
|
||||||
}
|
}
|
||||||
|
@@ -2,14 +2,9 @@
|
|||||||
import { map, selectedFiles, gpxLayers } from '$lib/stores';
|
import { map, selectedFiles, gpxLayers } from '$lib/stores';
|
||||||
import { GPXLayer } from './GPXLayer';
|
import { GPXLayer } from './GPXLayer';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
import { onMount } from 'svelte';
|
|
||||||
import mapboxgl from 'mapbox-gl';
|
|
||||||
import WaypointPopup from './WaypointPopup.svelte';
|
import WaypointPopup from './WaypointPopup.svelte';
|
||||||
import { fileObservers } from '$lib/db';
|
import { fileObservers } from '$lib/db';
|
||||||
|
|
||||||
let popupElement: HTMLElement;
|
|
||||||
let popup: mapboxgl.Popup | null = null;
|
|
||||||
|
|
||||||
$: if ($map && $fileObservers) {
|
$: if ($map && $fileObservers) {
|
||||||
gpxLayers.update(($layers) => {
|
gpxLayers.update(($layers) => {
|
||||||
// remove layers for deleted files
|
// remove layers for deleted files
|
||||||
@@ -22,7 +17,7 @@
|
|||||||
// add layers for new files
|
// add layers for new files
|
||||||
$fileObservers.forEach((file, fileId) => {
|
$fileObservers.forEach((file, fileId) => {
|
||||||
if (!$layers.has(fileId)) {
|
if (!$layers.has(fileId)) {
|
||||||
$layers.set(fileId, new GPXLayer(get(map), fileId, file, popup, popupElement));
|
$layers.set(fileId, new GPXLayer(get(map), fileId, file));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return $layers;
|
return $layers;
|
||||||
@@ -34,15 +29,6 @@
|
|||||||
$gpxLayers.get(fileId)?.moveToFront();
|
$gpxLayers.get(fileId)?.moveToFront();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
popup = new mapboxgl.Popup({
|
|
||||||
closeButton: false,
|
|
||||||
maxWidth: undefined
|
|
||||||
});
|
|
||||||
popup.setDOMContent(popupElement);
|
|
||||||
popupElement.classList.remove('hidden');
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<WaypointPopup bind:element={popupElement} />
|
<WaypointPopup />
|
||||||
|
@@ -1,13 +1,43 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as Card from '$lib/components/ui/card';
|
import * as Card from '$lib/components/ui/card';
|
||||||
|
import { waypointPopup, currentWaypoint } from './WaypointPopup';
|
||||||
|
import WithUnits from '$lib/components/WithUnits.svelte';
|
||||||
|
import { Dot } from 'lucide-svelte';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
import { _ } from 'svelte-i18n';
|
import { _ } from 'svelte-i18n';
|
||||||
|
|
||||||
export let element: HTMLElement;
|
let popupElement: HTMLDivElement;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
waypointPopup.setDOMContent(popupElement);
|
||||||
|
popupElement.classList.remove('hidden');
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={element} class="hidden">
|
<div bind:this={popupElement} class="hidden">
|
||||||
<Card.Root class="border-none shadow-md text-base">
|
{#if $currentWaypoint}
|
||||||
<Card.Content class="flex flex-col p-1">Waypoint info (TODO)</Card.Content>
|
<Card.Root class="border-none shadow-md text-base max-w-72 p-2">
|
||||||
</Card.Root>
|
<Card.Header class="p-0">
|
||||||
|
<Card.Title class="text-md">{$currentWaypoint.name}</Card.Title>
|
||||||
|
</Card.Header>
|
||||||
|
<Card.Content class="flex flex-col p-0 text-sm">
|
||||||
|
<div class="flex flex-row items-center text-muted-foreground">
|
||||||
|
{$currentWaypoint.getLatitude().toFixed(6)}° {$currentWaypoint
|
||||||
|
.getLongitude()
|
||||||
|
.toFixed(6)}°
|
||||||
|
{#if $currentWaypoint.ele !== undefined}
|
||||||
|
<Dot size="16" />
|
||||||
|
<WithUnits value={$currentWaypoint.ele} type="elevation" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if $currentWaypoint.desc}
|
||||||
|
<span>{$currentWaypoint.desc}</span>
|
||||||
|
{/if}
|
||||||
|
{#if $currentWaypoint.cmt}
|
||||||
|
<span>{$currentWaypoint.cmt}</span>
|
||||||
|
{/if}
|
||||||
|
</Card.Content>
|
||||||
|
</Card.Root>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
10
website/src/lib/components/gpx-layer/WaypointPopup.ts
Normal file
10
website/src/lib/components/gpx-layer/WaypointPopup.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import type { Waypoint } from "gpx";
|
||||||
|
import mapboxgl from "mapbox-gl";
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const currentWaypoint = writable<Waypoint | null>(null);
|
||||||
|
|
||||||
|
export const waypointPopup = new mapboxgl.Popup({
|
||||||
|
closeButton: false,
|
||||||
|
maxWidth: undefined
|
||||||
|
});
|
Reference in New Issue
Block a user