add overpass poi to file

This commit is contained in:
vcoppe
2024-07-17 23:05:17 +02:00
parent 2b7067a1fb
commit 92a1c600d0
9 changed files with 110 additions and 86 deletions

View File

@@ -1,5 +1,5 @@
export * from './gpx'; export * from './gpx';
export { Coordinates, LineStyleExtension } from './types'; export { Coordinates, LineStyleExtension, WaypointType } from './types';
export { parseGPX, buildGPX } from './io'; export { parseGPX, buildGPX } from './io';
export * from './simplify'; export * from './simplify';

View File

@@ -561,7 +561,7 @@ export const overpassTree: LayerTreeType = {
tourism: { tourism: {
attraction: true, attraction: true,
viewpoint: true, viewpoint: true,
sleep: true, accommodation: true,
summit: true, summit: true,
pass: true, pass: true,
climbing: true, climbing: true,
@@ -645,7 +645,7 @@ export const defaultOverpassQueries: LayerTreeType = {
tourism: { tourism: {
attraction: false, attraction: false,
viewpoint: false, viewpoint: false,
sleep: false, accommodation: false,
summit: false, summit: false,
pass: false, pass: false,
climbing: false climbing: false
@@ -770,30 +770,30 @@ export const defaultOverpassTree: LayerTreeType = {
amenities: { amenities: {
toilets: true, toilets: true,
"water": true, "water": true,
"water-spring": true, "water-spring": false,
shower: true, shower: false,
"fuel-station": false, "fuel-station": false,
parking: false, parking: false,
barrier: false barrier: false
}, },
tourism: { tourism: {
attraction: true, attraction: false,
viewpoint: true, viewpoint: false,
sleep: true, accommodation: true,
summit: true, summit: true,
pass: true, pass: true,
climbing: false climbing: false
}, },
bicycle: { bicycle: {
"bicycle-parking": true, "bicycle-parking": false,
"bicycle-rental": true, "bicycle-rental": false,
"bicycle-shop": true "bicycle-shop": true
}, },
"public-transport": { "public-transport": {
"railway-station": true, "railway-station": true,
"tram-stop": true, "tram-stop": true,
"bus-stop": true, "bus-stop": true,
ferry: true ferry: false
}, },
}, },
}; };
@@ -926,10 +926,10 @@ export const overpassQueryData: Record<string, OverpassQueryData> = {
tourism: "viewpoint" tourism: "viewpoint"
} }
}, },
sleep: { accommodation: {
icon: { icon: {
svg: Bed, svg: Bed,
color: "Green", color: "#e6c100",
}, },
tags: { tags: {
tourism: ["hotel", "hostel", "guest_house", "motel", "camp_site", "alpine_hut", "wilderness_hut"] tourism: ["hotel", "hostel", "guest_house", "motel", "camp_site", "alpine_hut", "wilderness_hut"]

View File

@@ -34,16 +34,15 @@
{/if} {/if}
</div> </div>
{#if $currentPopupWaypoint[0].desc} {#if $currentPopupWaypoint[0].desc}
<span>{$currentPopupWaypoint[0].desc}</span> <span class="whitespace-pre-wrap">{$currentPopupWaypoint[0].desc}</span>
{/if} {/if}
{#if $currentPopupWaypoint[0].cmt && $currentPopupWaypoint[0].cmt !== $currentPopupWaypoint[0].desc} {#if $currentPopupWaypoint[0].cmt && $currentPopupWaypoint[0].cmt !== $currentPopupWaypoint[0].desc}
<span>{$currentPopupWaypoint[0].cmt}</span> <span class="whitespace-pre-wrap">{$currentPopupWaypoint[0].cmt}</span>
{/if} {/if}
{#if $currentTool === Tool.WAYPOINT} {#if $currentTool === Tool.WAYPOINT}
<div class="mt-2">
<Button <Button
class="w-full px-2 py-1 h-6 justify-start" class="mt-2 w-full px-2 py-1 h-8 justify-start"
variant="ghost" variant="outline"
on:click={() => on:click={() =>
deleteWaypoint($currentPopupWaypoint[1], $currentPopupWaypoint[0]._data.index)} deleteWaypoint($currentPopupWaypoint[1], $currentPopupWaypoint[0]._data.index)}
> >
@@ -51,7 +50,6 @@
{$_('menu.delete')} {$_('menu.delete')}
<Shortcut key="" shift={true} click={true} /> <Shortcut key="" shift={true} click={true} />
</Button> </Button>
</div>
{/if} {/if}
</Card.Content> </Card.Content>
</Card.Root> </Card.Root>

View File

@@ -209,10 +209,6 @@
</ScrollArea> </ScrollArea>
</Accordion.Content> </Accordion.Content>
</Accordion.Item> </Accordion.Item>
<Accordion.Item value="pois" class="hidden">
<Accordion.Trigger>{$_('layers.pois')}</Accordion.Trigger>
<Accordion.Content></Accordion.Content>
</Accordion.Item>
<Accordion.Item value="heatmap-color" class="hidden"> <Accordion.Item value="heatmap-color" class="hidden">
<Accordion.Trigger>{$_('layers.heatmap')}</Accordion.Trigger> <Accordion.Trigger>{$_('layers.heatmap')}</Accordion.Trigger>
<Accordion.Content class="overflow-visible"> <Accordion.Content class="overflow-visible">

View File

@@ -90,6 +90,7 @@ export class OverpassLayer {
layout: { layout: {
'icon-image': ['get', 'icon'], 'icon-image': ['get', 'icon'],
'icon-size': 0.25, 'icon-size': 0.25,
'icon-padding': 0,
}, },
}); });
@@ -173,14 +174,13 @@ export class OverpassLayer {
fetch(`${this.overpassUrl}?data=${getQueryForBounds(bounds, queries)}`) fetch(`${this.overpassUrl}?data=${getQueryForBounds(bounds, queries)}`)
.then((response) => { .then((response) => {
if (response.ok) { if (response.ok) {
try {
return response.json(); return response.json();
} catch (e) { }
} }
this.currentQueries.delete(`${x},${y}`); this.currentQueries.delete(`${x},${y}`);
return Promise.reject(); return Promise.reject();
}, () => (this.currentQueries.delete(`${x},${y}`))) }, () => (this.currentQueries.delete(`${x},${y}`)))
.then((data) => this.storeOverpassData(x, y, queries, data)); .then((data) => this.storeOverpassData(x, y, queries, data))
.catch(() => this.currentQueries.delete(`${x},${y}`));
} }
storeOverpassData(x: number, y: number, queries: string[], data: any) { storeOverpassData(x: number, y: number, queries: string[], data: any) {

View File

@@ -2,9 +2,11 @@
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { overpassPopup, overpassPopupPOI } from './OverpassLayer'; import { overpassPopup, overpassPopupPOI } from './OverpassLayer';
import { PencilLine } from 'lucide-svelte'; import { selection } from '$lib/components/file-list/Selection';
import { PencilLine, MapPin } from 'lucide-svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { _ } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import { dbUtils } from '$lib/db';
let popupElement: HTMLDivElement; let popupElement: HTMLDivElement;
@@ -47,9 +49,8 @@
<img src={tags.image ?? tags['image:0']} /> <img src={tags.image ?? tags['image:0']} />
</div> </div>
{/if} {/if}
<Card.Content <Card.Content class="flex flex-col p-0 text-sm mt-1 whitespace-normal break-all">
class="grid grid-cols-[auto_auto] gap-x-3 p-0 text-sm mt-1 whitespace-normal break-all" <div class="grid grid-cols-[auto_auto] gap-x-3">
>
{#each Object.entries(tags) as [key, value]} {#each Object.entries(tags) as [key, value]}
{#if key !== 'name' && !key.includes('image')} {#if key !== 'name' && !key.includes('image')}
<span class="font-mono">{key}</span> <span class="font-mono">{key}</span>
@@ -64,6 +65,29 @@
{/if} {/if}
{/if} {/if}
{/each} {/each}
</div>
<Button
class="mt-2"
variant="outline"
disabled={$selection.size === 0}
on:click={() => {
let desc = Object.entries(tags)
.map(([key, value]) => `${key}: ${value}`)
.join('\n');
dbUtils.addOrUpdateWaypoint({
attributes: {
lat: $overpassPopupPOI.lat,
lon: $overpassPopupPOI.lon
},
name: tags.name ?? '',
desc: desc,
cmt: desc
});
}}
>
<MapPin size="16" class="mr-1" />
{$_('toolbar.waypoint.add')}
</Button>
</Card.Content> </Card.Content>
</Card.Root> </Card.Root>
{/if} {/if}

View File

@@ -102,39 +102,22 @@
} }
latitude = parseFloat(latitude.toFixed(6)); latitude = parseFloat(latitude.toFixed(6));
longitude = parseFloat(longitude.toFixed(6)); longitude = parseFloat(longitude.toFixed(6));
if ($selectedWaypoint) {
dbUtils.applyToFile($selectedWaypoint[1], (file) => { dbUtils.addOrUpdateWaypoint(
let wpt = file.wpt[$selectedWaypoint[0]._data.index]; {
wpt.name = name;
wpt.desc = description;
wpt.cmt = description;
wpt.setCoordinates({
lat: latitude,
lon: longitude
});
wpt.ele =
get(map)?.queryTerrainElevation([longitude, latitude], { exaggerated: false }) ?? 0;
});
} else {
let fileIds = new Set<string>();
$selection.getSelected().forEach((item) => {
fileIds.add(item.getFileId());
});
let waypoint = new Waypoint({
name,
desc: description,
cmt: description,
attributes: { attributes: {
lat: latitude, lat: latitude,
lon: longitude lon: longitude
} },
}); name,
waypoint.ele = desc: description,
get(map)?.queryTerrainElevation([longitude, latitude], { exaggerated: false }) ?? 0; cmt: description
dbUtils.applyToFiles(Array.from(fileIds), (file) => },
file.replaceWaypoints(file.wpt.length, file.wpt.length, [waypoint]) $selectedWaypoint
? new ListWaypointItem($selectedWaypoint[1], $selectedWaypoint[0]._data.index)
: undefined
); );
}
selectedWaypoint.set(undefined); selectedWaypoint.set(undefined);
resetWaypointData(); resetWaypointData();
} }

View File

@@ -1,8 +1,8 @@
import Dexie, { liveQuery } from 'dexie'; import Dexie, { liveQuery } from 'dexie';
import { GPXFile, GPXStatistics, Track, TrackSegment, Waypoint, TrackPoint, type Coordinates, distance, type LineStyleExtension } from 'gpx'; import { GPXFile, GPXStatistics, Track, TrackSegment, Waypoint, TrackPoint, type Coordinates, distance, type LineStyleExtension, type WaypointType } from 'gpx';
import { enableMapSet, enablePatches, applyPatches, type Patch, type WritableDraft, freeze, produceWithPatches } from 'immer'; import { enableMapSet, enablePatches, applyPatches, type Patch, type WritableDraft, freeze, produceWithPatches } from 'immer';
import { writable, get, derived, type Readable, type Writable } from 'svelte/store'; import { writable, get, derived, type Readable, type Writable } from 'svelte/store';
import { gpxStatistics, initTargetMapBounds, splitAs, updateAllHidden, updateTargetMapBounds } from './stores'; import { gpxStatistics, initTargetMapBounds, map, splitAs, updateAllHidden, updateTargetMapBounds } from './stores';
import { defaultBasemap, defaultBasemapTree, defaultOverlayTree, defaultOverlays, type CustomLayer, defaultOpacities, defaultOverpassQueries, defaultOverpassTree } from './assets/layers'; import { defaultBasemap, defaultBasemapTree, defaultOverlayTree, defaultOverlays, type CustomLayer, defaultOpacities, defaultOverpassQueries, defaultOverpassTree } from './assets/layers';
import { applyToOrderedItemsFromFile, applyToOrderedSelectedItemsFromFile, selection } from '$lib/components/file-list/Selection'; import { applyToOrderedItemsFromFile, applyToOrderedSelectedItemsFromFile, selection } from '$lib/components/file-list/Selection';
import { ListFileItem, ListItem, ListTrackItem, ListLevel, ListTrackSegmentItem, ListWaypointItem, ListRootItem } from '$lib/components/file-list/FileList'; import { ListFileItem, ListItem, ListTrackItem, ListLevel, ListTrackSegmentItem, ListWaypointItem, ListRootItem } from '$lib/components/file-list/FileList';
@@ -893,6 +893,29 @@ export const dbUtils = {
}); });
}); });
}, },
addOrUpdateWaypoint: (waypoint: WaypointType, item?: ListWaypointItem) => {
let ele = get(map)?.queryTerrainElevation([waypoint.attributes.lon, waypoint.attributes.lat], { exaggerated: false }) ?? 0;
if (item) {
dbUtils.applyToFile(item.getFileId(), (file) => {
let wpt = file.wpt[item.getWaypointIndex()];
wpt.name = waypoint.name;
wpt.desc = waypoint.desc;
wpt.cmt = waypoint.cmt;
wpt.setCoordinates(waypoint.attributes);
wpt.ele = ele;
});
} else {
let fileIds = new Set<string>();
get(selection).getSelected().forEach((item) => {
fileIds.add(item.getFileId());
});
let wpt = new Waypoint(waypoint);
wpt.ele = ele;
dbUtils.applyToFiles(Array.from(fileIds), (file) =>
file.replaceWaypoints(file.wpt.length, file.wpt.length, [wpt])
);
}
},
setStyleToSelection: (style: LineStyleExtension) => { setStyleToSelection: (style: LineStyleExtension) => {
if (get(selection).size === 0) { if (get(selection).size === 0) {
return; return;

View File

@@ -182,6 +182,7 @@
"longitude": "Longitude", "longitude": "Longitude",
"latitude": "Latitude", "latitude": "Latitude",
"create": "Create point of interest", "create": "Create point of interest",
"add": "Add point of interest to file",
"help": "Fill in the form to create a new point of interest, or click on an existing one to edit it. Click on the map to fill the coordinates, or drag points of interest to move them.", "help": "Fill in the form to create a new point of interest, or click on an existing one to edit it. Click on the map to fill the coordinates, or drag points of interest to move them.",
"help_no_selection": "Select a file item to create or edit points of interest." "help_no_selection": "Select a file item to create or edit points of interest."
}, },
@@ -223,7 +224,6 @@
}, },
"opacity": "Overlay opacity", "opacity": "Overlay opacity",
"heatmap": "Strava Heatmap", "heatmap": "Strava Heatmap",
"pois": "Points of interest",
"label": { "label": {
"basemaps": "Basemaps", "basemaps": "Basemaps",
"overlays": "Overlays", "overlays": "Overlays",
@@ -302,7 +302,7 @@
"tourism": "Tourism", "tourism": "Tourism",
"attraction": "Attraction", "attraction": "Attraction",
"viewpoint": "Viewpoint", "viewpoint": "Viewpoint",
"sleep": "Sleep", "accommodation": "Accommodation",
"summit": "Summit", "summit": "Summit",
"pass": "Pass", "pass": "Pass",
"climbing": "Climbing", "climbing": "Climbing",