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

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

View File

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

View File

@@ -209,10 +209,6 @@
</ScrollArea>
</Accordion.Content>
</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.Trigger>{$_('layers.heatmap')}</Accordion.Trigger>
<Accordion.Content class="overflow-visible">

View File

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

View File

@@ -2,9 +2,11 @@
import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button';
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 { _ } from 'svelte-i18n';
import { dbUtils } from '$lib/db';
let popupElement: HTMLDivElement;
@@ -47,23 +49,45 @@
<img src={tags.image ?? tags['image:0']} />
</div>
{/if}
<Card.Content
class="grid grid-cols-[auto_auto] gap-x-3 p-0 text-sm mt-1 whitespace-normal break-all"
>
{#each Object.entries(tags) as [key, value]}
{#if key !== 'name' && !key.includes('image')}
<span class="font-mono">{key}</span>
{#if key === 'website' || key === 'contact:website' || key === 'contact:facebook' || key === 'contact:instagram' || key === 'contact:twitter'}
<a href={value} target="_blank" class="text-blue-500 underline">{value}</a>
{:else if key === 'phone' || key === 'contact:phone'}
<a href={'tel:' + value} class="text-blue-500 underline">{value}</a>
{:else if key === 'email' || key === 'contact:email'}
<a href={'mailto:' + value} class="text-blue-500 underline">{value}</a>
{:else}
<span>{value}</span>
<Card.Content class="flex flex-col 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]}
{#if key !== 'name' && !key.includes('image')}
<span class="font-mono">{key}</span>
{#if key === 'website' || key === 'contact:website' || key === 'contact:facebook' || key === 'contact:instagram' || key === 'contact:twitter'}
<a href={value} target="_blank" class="text-blue-500 underline">{value}</a>
{:else if key === 'phone' || key === 'contact:phone'}
<a href={'tel:' + value} class="text-blue-500 underline">{value}</a>
{:else if key === 'email' || key === 'contact:email'}
<a href={'mailto:' + value} class="text-blue-500 underline">{value}</a>
{:else}
<span>{value}</span>
{/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.Root>
{/if}

View File

@@ -102,39 +102,22 @@
}
latitude = parseFloat(latitude.toFixed(6));
longitude = parseFloat(longitude.toFixed(6));
if ($selectedWaypoint) {
dbUtils.applyToFile($selectedWaypoint[1], (file) => {
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,
dbUtils.addOrUpdateWaypoint(
{
attributes: {
lat: latitude,
lon: longitude
}
});
waypoint.ele =
get(map)?.queryTerrainElevation([longitude, latitude], { exaggerated: false }) ?? 0;
dbUtils.applyToFiles(Array.from(fileIds), (file) =>
file.replaceWaypoints(file.wpt.length, file.wpt.length, [waypoint])
);
}
},
name,
desc: description,
cmt: description
},
$selectedWaypoint
? new ListWaypointItem($selectedWaypoint[1], $selectedWaypoint[0]._data.index)
: undefined
);
selectedWaypoint.set(undefined);
resetWaypointData();
}

View File

@@ -1,8 +1,8 @@
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 { 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 { applyToOrderedItemsFromFile, applyToOrderedSelectedItemsFromFile, selection } from '$lib/components/file-list/Selection';
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) => {
if (get(selection).size === 0) {
return;

View File

@@ -182,6 +182,7 @@
"longitude": "Longitude",
"latitude": "Latitude",
"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_no_selection": "Select a file item to create or edit points of interest."
},
@@ -223,7 +224,6 @@
},
"opacity": "Overlay opacity",
"heatmap": "Strava Heatmap",
"pois": "Points of interest",
"label": {
"basemaps": "Basemaps",
"overlays": "Overlays",
@@ -302,7 +302,7 @@
"tourism": "Tourism",
"attraction": "Attraction",
"viewpoint": "Viewpoint",
"sleep": "Sleep",
"accommodation": "Accommodation",
"summit": "Summit",
"pass": "Pass",
"climbing": "Climbing",