5 Commits

Author SHA1 Message Date
vcoppe
117c46341b add utagawaVTT layer 2025-10-19 14:19:44 +02:00
vcoppe
ba1ac69151 start/end & distance markers 2025-10-19 14:15:52 +02:00
vcoppe
a8d3af35de fix gap 2025-10-19 13:55:01 +02:00
vcoppe
307eed86e3 fix export 2025-10-19 13:51:56 +02:00
vcoppe
3f103323c7 fix hiding 2025-10-19 13:45:05 +02:00
15 changed files with 283 additions and 241 deletions

View File

@@ -119,6 +119,7 @@ export const basemaps: { [key: string]: string | StyleSpecification } = {
}, },
], ],
}, },
utagawaVTT: 'https://maps.utagawavtt.com/styles/utagawavtt/style.json',
swisstopoRaster: { swisstopoRaster: {
version: 8, version: 8,
sources: { sources: {
@@ -803,6 +804,7 @@ export const basemapTree: LayerTreeType = {
openTopoMap: true, openTopoMap: true,
openHikingMap: true, openHikingMap: true,
cyclOSM: true, cyclOSM: true,
utagawaVTT: true,
}, },
countries: { countries: {
belgium: { belgium: {
@@ -1023,6 +1025,7 @@ export const defaultBasemapTree: LayerTreeType = {
openTopoMap: true, openTopoMap: true,
openHikingMap: true, openHikingMap: true,
cyclOSM: true, cyclOSM: true,
utagawaVTT: true,
}, },
countries: { countries: {
belgium: { belgium: {

View File

@@ -72,6 +72,7 @@
import { fileStateCollection } from '$lib/logic/file-state'; import { fileStateCollection } from '$lib/logic/file-state';
import { fileActionManager } from '$lib/logic/file-action-manager'; import { fileActionManager } from '$lib/logic/file-action-manager';
import { copied, selection } from '$lib/logic/selection'; import { copied, selection } from '$lib/logic/selection';
import { allHidden } from '$lib/logic/hidden';
const { const {
distanceUnits, distanceUnits,
@@ -229,21 +230,21 @@
</Menubar.Item> </Menubar.Item>
<Menubar.Item <Menubar.Item
onclick={() => { onclick={() => {
// if ($allHidden) { if ($allHidden) {
// fileActions.setHiddenToSelection(false); fileActions.setHiddenToSelection(false);
// } else { } else {
// fileActions.setHiddenToSelection(true); fileActions.setHiddenToSelection(true);
// } }
}} }}
disabled={$selection.size == 0} disabled={$selection.size == 0}
> >
<!-- {#if $allHidden} {#if $allHidden}
<Eye size="16" /> <Eye size="16" />
{i18n._('menu.unhide')} {i18n._('menu.unhide')}
{:else} {:else}
<EyeOff size="16" /> <EyeOff size="16" />
{i18n._('menu.hide')} {i18n._('menu.hide')}
{/if} --> {/if}
<Shortcut key="H" ctrl={true} /> <Shortcut key="H" ctrl={true} />
</Menubar.Item> </Menubar.Item>
{#if $treeFileView} {#if $treeFileView}
@@ -621,11 +622,11 @@
$treeFileView = !$treeFileView; $treeFileView = !$treeFileView;
e.preventDefault(); e.preventDefault();
} else if (e.key === 'h' && (e.metaKey || e.ctrlKey)) { } else if (e.key === 'h' && (e.metaKey || e.ctrlKey)) {
// if ($allHidden) { if ($allHidden) {
// fileActions.setHiddenToSelection(false); fileActions.setHiddenToSelection(false);
// } else { } else {
// fileActions.setHiddenToSelection(true); fileActions.setHiddenToSelection(true);
// } }
e.preventDefault(); e.preventDefault();
} else if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { } else if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
// if ($selection.size > 0) { // if ($selection.size > 0) {

View File

@@ -11,7 +11,6 @@
exportState, exportState,
} from '$lib/components/export/utils.svelte'; } from '$lib/components/export/utils.svelte';
import { currentTool } from '$lib/components/toolbar/tools'; import { currentTool } from '$lib/components/toolbar/tools';
// import { gpxStatistics } from '$lib/stores';
import { import {
Download, Download,
Zap, Zap,
@@ -26,6 +25,8 @@
import { ListRootItem } from '$lib/components/file-list/file-list'; import { ListRootItem } from '$lib/components/file-list/file-list';
import { fileStateCollection } from '$lib/logic/file-state'; import { fileStateCollection } from '$lib/logic/file-state';
import { selection } from '$lib/logic/selection'; import { selection } from '$lib/logic/selection';
import { gpxStatistics } from '$lib/logic/statistics';
import { get } from 'svelte/store';
let open = $derived(exportState.current !== ExportState.NONE); let open = $derived(exportState.current !== ExportState.NONE);
let exportOptions: Record<string, boolean> = $state({ let exportOptions: Record<string, boolean> = $state({
@@ -37,36 +38,7 @@
extensions: false, extensions: false,
}); });
let hide: Record<string, boolean> = $derived.by(() => { let hide: Record<string, boolean> = $derived.by(() => {
// if (exportState.current === ExportState.NONE) { if (exportState.current === ExportState.NONE) {
// return {
// time: false,
// hr: false,
// cad: false,
// atemp: false,
// power: false,
// extensions: false,
// };
// } else {
// let statistics = $gpxStatistics;
// if (exportState.current === ExportState.ALL) {
// statistics = Array.from(fileStateCollection.files.values())
// .map((file) => file.statistics)
// .reduce((acc, cur) => {
// if (cur !== undefined) {
// acc.mergeWith(cur.getStatisticsFor(new ListRootItem()));
// }
// return acc;
// }, new GPXStatistics());
// }
// return {
// time: statistics.global.time.total === 0,
// hr: statistics.global.hr.count === 0,
// cad: statistics.global.cad.count === 0,
// atemp: statistics.global.atemp.count === 0,
// power: statistics.global.power.count === 0,
// extensions: Object.keys(statistics.global.extensions).length === 0,
// };
// }
return { return {
time: false, time: false,
hr: false, hr: false,
@@ -75,6 +47,27 @@
power: false, power: false,
extensions: false, extensions: false,
}; };
} else {
let statistics = $gpxStatistics;
if (exportState.current === ExportState.ALL) {
statistics = Array.from(get(fileStateCollection).values())
.map((file) => file.statistics)
.reduce((acc, cur) => {
if (cur !== undefined) {
acc.mergeWith(cur.getStatisticsFor(new ListRootItem()));
}
return acc;
}, new GPXStatistics());
}
return {
time: statistics.global.time.total === 0,
hr: statistics.global.hr.count === 0,
cad: statistics.global.cad.count === 0,
atemp: statistics.global.atemp.count === 0,
power: statistics.global.power.count === 0,
extensions: Object.keys(statistics.global.extensions).length === 0,
};
}
}); });
let exclude = $derived(Object.keys(exportOptions).filter((key) => !exportOptions[key])); let exclude = $derived(Object.keys(exportOptions).filter((key) => !exportOptions[key]));
@@ -158,15 +151,6 @@
{i18n._('quantities.time')} {i18n._('quantities.time')}
</Label> </Label>
</div> </div>
<div
class="flex flex-row items-center gap-1.5 {hide.extensions ? 'hidden' : ''}"
>
<Checkbox id="export-extensions" bind:checked={exportOptions.extensions} />
<Label for="export-extensions" class="flex flex-row items-center gap-1">
<Earth size="16" />
{i18n._('quantities.osm_extensions')}
</Label>
</div>
<div class="flex flex-row items-center gap-1.5 {hide.hr ? 'hidden' : ''}"> <div class="flex flex-row items-center gap-1.5 {hide.hr ? 'hidden' : ''}">
<Checkbox id="export-heartrate" bind:checked={exportOptions.hr} /> <Checkbox id="export-heartrate" bind:checked={exportOptions.hr} />
<Label for="export-heartrate" class="flex flex-row items-center gap-1"> <Label for="export-heartrate" class="flex flex-row items-center gap-1">
@@ -195,6 +179,15 @@
{i18n._('quantities.power')} {i18n._('quantities.power')}
</Label> </Label>
</div> </div>
<div
class="flex flex-row items-center gap-1.5 {hide.extensions ? 'hidden' : ''}"
>
<Checkbox id="export-extensions" bind:checked={exportOptions.extensions} />
<Label for="export-extensions" class="flex flex-row items-center gap-1">
<Earth size="16" />
{i18n._('quantities.osm_extensions')}
</Label>
</div>
</div> </div>
</div> </div>
</Dialog.Content> </Dialog.Content>

View File

@@ -40,6 +40,7 @@
import { selection, copied, cut } from '$lib/logic/selection'; import { selection, copied, cut } from '$lib/logic/selection';
import { map } from '$lib/components/map/map'; import { map } from '$lib/components/map/map';
import { fileActions, pasteSelection } from '$lib/logic/file-actions'; import { fileActions, pasteSelection } from '$lib/logic/file-actions';
import { allHidden } from '$lib/logic/hidden';
let { let {
node, node,
@@ -240,20 +241,20 @@
{/if} {/if}
<ContextMenu.Item <ContextMenu.Item
onclick={() => { onclick={() => {
// if ($allHidden) { if ($allHidden) {
// dbUtils.setHiddenToSelection(false); fileActions.setHiddenToSelection(false);
// } else { } else {
// dbUtils.setHiddenToSelection(true); fileActions.setHiddenToSelection(true);
// } }
}} }}
> >
<!-- {#if $allHidden} {#if $allHidden}
<Eye size="16" class="mr-1" /> <Eye size="16" class="mr-1" />
{i18n._('menu.unhide')} {i18n._('menu.unhide')}
{:else} {:else}
<EyeOff size="16" class="mr-1" /> <EyeOff size="16" class="mr-1" />
{i18n._('menu.hide')} {i18n._('menu.hide')}
{/if} --> {/if}
<Shortcut key="H" ctrl={true} /> <Shortcut key="H" ctrl={true} />
</ContextMenu.Item> </ContextMenu.Item>
<ContextMenu.Separator /> <ContextMenu.Separator />

View File

@@ -1,41 +1,33 @@
<script lang="ts"> <script lang="ts">
import { gpxLayers } from '$lib/components/map/gpx-layer/gpx-layers'; import { gpxLayers } from '$lib/components/map/gpx-layer/gpx-layers';
import { onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
// import { map, gpxLayers } from '$lib/stores'; // import { map, gpxLayers } from '$lib/stores';
// import { GPXLayer } from './gpx-layer'; // import { GPXLayer } from './gpx-layer';
// import { DistanceMarkers } from './DistanceMarkers'; import { DistanceMarkers } from '$lib/components/map/gpx-layer/distance-markers';
// import { StartEndMarkers } from './StartEndMarkers'; import { StartEndMarkers } from '$lib/components/map/gpx-layer/start-end-markers';
// import { onDestroy } from 'svelte'; // import { onDestroy } from 'svelte';
// import { createPopups, removePopups } from './GPXLayerPopup'; // import { createPopups, removePopups } from './GPXLayerPopup';
// let distanceMarkers = $derived(map.current ? new DistanceMarkers(map.current) : undefined); let distanceMarkers: DistanceMarkers;
// let startEndMarkers = $derived(map.current ? new StartEndMarkers(map.current) : undefined); let startEndMarkers: StartEndMarkers;
// $: if ($map) { // $: if ($map) {
// if (distanceMarkers) {
// distanceMarkers.remove();
// }
// if (startEndMarkers) {
// startEndMarkers.remove();
// }
// createPopups($map); // createPopups($map);
// distanceMarkers = new DistanceMarkers($map);
// startEndMarkers = new StartEndMarkers($map);
// } // }
// onDestroy(() => {
// removePopups();
// if (distanceMarkers) {
// distanceMarkers.remove();
// distanceMarkers = undefined;
// }
// if (startEndMarkers) {
// startEndMarkers.remove();
// startEndMarkers = undefined;
// }
// });
onMount(() => { onMount(() => {
gpxLayers.init(); gpxLayers.init();
startEndMarkers = new StartEndMarkers();
distanceMarkers = new DistanceMarkers();
});
onDestroy(() => {
// removePopups();
if (startEndMarkers) {
startEndMarkers.remove();
}
if (distanceMarkers) {
distanceMarkers.remove();
}
}); });
</script> </script>

View File

@@ -1,6 +1,9 @@
import { settings } from '$lib/logic/settings'; import { settings } from '$lib/logic/settings';
import { gpxStatistics } from '$lib/logic/statistics';
import { getConvertedDistanceToKilometers } from '$lib/units';
import type { GeoJSONSource } from 'mapbox-gl'; import type { GeoJSONSource } from 'mapbox-gl';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { map } from '$lib/components/map/map';
const { distanceMarkers, distanceUnits } = settings; const { distanceMarkers, distanceUnits } = settings;
@@ -14,35 +17,40 @@ const stops = [
]; ];
export class DistanceMarkers { export class DistanceMarkers {
map: mapboxgl.Map;
updateBinded: () => void = this.update.bind(this); updateBinded: () => void = this.update.bind(this);
unsubscribes: (() => void)[] = []; unsubscribes: (() => void)[] = [];
constructor(map: mapboxgl.Map) { constructor() {
this.map = map;
this.unsubscribes.push(gpxStatistics.subscribe(this.updateBinded)); this.unsubscribes.push(gpxStatistics.subscribe(this.updateBinded));
this.unsubscribes.push(distanceMarkers.subscribe(this.updateBinded)); this.unsubscribes.push(distanceMarkers.subscribe(this.updateBinded));
this.unsubscribes.push(distanceUnits.subscribe(this.updateBinded)); this.unsubscribes.push(distanceUnits.subscribe(this.updateBinded));
this.map.on('style.import.load', this.updateBinded); this.unsubscribes.push(
map.subscribe((map_) => {
if (map_) {
map_.on('style.import.load', this.updateBinded);
}
})
);
} }
update() { update() {
const map_ = get(map);
if (!map_) return;
try { try {
if (get(distanceMarkers)) { if (get(distanceMarkers)) {
let distanceSource: GeoJSONSource | undefined = let distanceSource: GeoJSONSource | undefined = map_.getSource('distance-markers');
this.map.getSource('distance-markers');
if (distanceSource) { if (distanceSource) {
distanceSource.setData(this.getDistanceMarkersGeoJSON()); distanceSource.setData(this.getDistanceMarkersGeoJSON());
} else { } else {
this.map.addSource('distance-markers', { map_.addSource('distance-markers', {
type: 'geojson', type: 'geojson',
data: this.getDistanceMarkersGeoJSON(), data: this.getDistanceMarkersGeoJSON(),
}); });
} }
stops.forEach(([d, minzoom, maxzoom]) => { stops.forEach(([d, minzoom, maxzoom]) => {
if (!this.map.getLayer(`distance-markers-${d}`)) { if (!map_.getLayer(`distance-markers-${d}`)) {
this.map.addLayer({ map_.addLayer({
id: `distance-markers-${d}`, id: `distance-markers-${d}`,
type: 'symbol', type: 'symbol',
source: 'distance-markers', source: 'distance-markers',
@@ -68,13 +76,13 @@ export class DistanceMarkers {
}, },
}); });
} else { } else {
this.map.moveLayer(`distance-markers-${d}`); map_.moveLayer(`distance-markers-${d}`);
} }
}); });
} else { } else {
stops.forEach(([d]) => { stops.forEach(([d]) => {
if (this.map.getLayer(`distance-markers-${d}`)) { if (map_.getLayer(`distance-markers-${d}`)) {
this.map.removeLayer(`distance-markers-${d}`); map_.removeLayer(`distance-markers-${d}`);
} }
}); });
} }
@@ -96,7 +104,7 @@ export class DistanceMarkers {
for (let i = 0; i < statistics.local.distance.total.length; i++) { for (let i = 0; i < statistics.local.distance.total.length; i++) {
if ( if (
statistics.local.distance.total[i] >= statistics.local.distance.total[i] >=
currentTargetDistance * (get(distanceUnits) === 'metric' ? 1 : 1.60934) getConvertedDistanceToKilometers(currentTargetDistance)
) { ) {
let distance = currentTargetDistance.toFixed(0); let distance = currentTargetDistance.toFixed(0);
let [level, minzoom] = stops.find(([d]) => currentTargetDistance % d === 0) ?? [ let [level, minzoom] = stops.find(([d]) => currentTargetDistance % d === 0) ?? [

View File

@@ -1,17 +1,16 @@
import { gpxStatistics, slicedGPXStatistics, currentTool, Tool } from '$lib/stores'; import { currentTool, Tool } from '$lib/components/toolbar/tools';
import { gpxStatistics, slicedGPXStatistics } from '$lib/logic/statistics';
import mapboxgl from 'mapbox-gl'; import mapboxgl from 'mapbox-gl';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { map } from '$lib/components/map/map';
export class StartEndMarkers { export class StartEndMarkers {
map: mapboxgl.Map;
start: mapboxgl.Marker; start: mapboxgl.Marker;
end: mapboxgl.Marker; end: mapboxgl.Marker;
updateBinded: () => void = this.update.bind(this); updateBinded: () => void = this.update.bind(this);
unsubscribes: (() => void)[] = []; unsubscribes: (() => void)[] = [];
constructor(map: mapboxgl.Map) { constructor() {
this.map = map;
let startElement = document.createElement('div'); let startElement = document.createElement('div');
let endElement = document.createElement('div'); let endElement = document.createElement('div');
startElement.className = `h-4 w-4 rounded-full bg-green-500 border-2 border-white`; startElement.className = `h-4 w-4 rounded-full bg-green-500 border-2 border-white`;
@@ -28,15 +27,18 @@ export class StartEndMarkers {
} }
update() { update() {
let tool = get(currentTool); const map_ = get(map);
let statistics = get(slicedGPXStatistics)?.[0] ?? get(gpxStatistics); if (!map_) return;
const tool = get(currentTool);
const statistics = get(slicedGPXStatistics)?.[0] ?? get(gpxStatistics);
if (statistics.local.points.length > 0 && tool !== Tool.ROUTING) { if (statistics.local.points.length > 0 && tool !== Tool.ROUTING) {
this.start.setLngLat(statistics.local.points[0].getCoordinates()).addTo(this.map); this.start.setLngLat(statistics.local.points[0].getCoordinates()).addTo(map_);
this.end this.end
.setLngLat( .setLngLat(
statistics.local.points[statistics.local.points.length - 1].getCoordinates() statistics.local.points[statistics.local.points.length - 1].getCoordinates()
) )
.addTo(this.map); .addTo(map_);
} else { } else {
this.start.remove(); this.start.remove();
this.end.remove(); this.end.remove();

View File

@@ -167,7 +167,7 @@
disabled={!canCreate && !$selectedWaypoint} disabled={!canCreate && !$selectedWaypoint}
/> />
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
<div class="grow"> <div class="grow flex flex-col gap-2">
<Label for="latitude">{i18n._('toolbar.waypoint.latitude')}</Label> <Label for="latitude">{i18n._('toolbar.waypoint.latitude')}</Label>
<Input <Input
bind:value={latitude} bind:value={latitude}
@@ -180,7 +180,7 @@
disabled={!canCreate && !$selectedWaypoint} disabled={!canCreate && !$selectedWaypoint}
/> />
</div> </div>
<div class="grow"> <div class="grow flex flex-col gap-2">
<Label for="longitude">{i18n._('toolbar.waypoint.longitude')}</Label> <Label for="longitude">{i18n._('toolbar.waypoint.longitude')}</Label>
<Input <Input
bind:value={longitude} bind:value={longitude}

View File

@@ -747,61 +747,61 @@ export const fileActions = {
); );
}, },
setStyleToSelection: (style: LineStyleExtension) => { setStyleToSelection: (style: LineStyleExtension) => {
// if (get(selection).size === 0) { if (get(selection).size === 0) {
// return; return;
// } }
// applyGlobal((draft) => { fileActionManager.applyGlobal((draft) => {
// applyToOrderedSelectedItemsFromFile((fileId, level, items) => { selection.applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
// let file = draft.get(fileId); let file = draft.get(fileId);
// if (file && (level === ListLevel.FILE || level === ListLevel.TRACK)) { if (file && (level === ListLevel.FILE || level === ListLevel.TRACK)) {
// if (level === ListLevel.FILE) { if (level === ListLevel.FILE) {
// file.setStyle(style); file.setStyle(style);
// } else if (level === ListLevel.TRACK) { } else if (level === ListLevel.TRACK) {
// if (items.length === file.trk.length) { if (items.length === file.trk.length) {
// file.setStyle(style); file.setStyle(style);
// } else { } else {
// for (let item of items) { for (let item of items) {
// let trackIndex = (item as ListTrackItem).getTrackIndex(); let trackIndex = (item as ListTrackItem).getTrackIndex();
// file.trk[trackIndex].setStyle(style); file.trk[trackIndex].setStyle(style);
// } }
// } }
// } }
// } }
// }); });
// }); });
}, },
setHiddenToSelection: (hidden: boolean) => { setHiddenToSelection: (hidden: boolean) => {
// if (get(selection).size === 0) { if (get(selection).size === 0) {
// return; return;
// } }
// applyGlobal((draft) => { fileActionManager.applyGlobal((draft) => {
// applyToOrderedSelectedItemsFromFile((fileId, level, items) => { selection.applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
// let file = draft.get(fileId); let file = draft.get(fileId);
// if (file) { if (file) {
// if (level === ListLevel.FILE) { if (level === ListLevel.FILE) {
// file.setHidden(hidden); file.setHidden(hidden);
// } else if (level === ListLevel.TRACK) { } else if (level === ListLevel.TRACK) {
// let trackIndices = items.map((item) => let trackIndices = items.map((item) =>
// (item as ListTrackItem).getTrackIndex() (item as ListTrackItem).getTrackIndex()
// ); );
// file.setHidden(hidden, trackIndices); file.setHidden(hidden, trackIndices);
// } else if (level === ListLevel.SEGMENT) { } else if (level === ListLevel.SEGMENT) {
// let trackIndices = [(items[0] as ListTrackSegmentItem).getTrackIndex()]; let trackIndices = [(items[0] as ListTrackSegmentItem).getTrackIndex()];
// let segmentIndices = items.map((item) => let segmentIndices = items.map((item) =>
// (item as ListTrackSegmentItem).getSegmentIndex() (item as ListTrackSegmentItem).getSegmentIndex()
// ); );
// file.setHidden(hidden, trackIndices, segmentIndices); file.setHidden(hidden, trackIndices, segmentIndices);
// } else if (level === ListLevel.WAYPOINTS) { } else if (level === ListLevel.WAYPOINTS) {
// file.setHiddenWaypoints(hidden); file.setHiddenWaypoints(hidden);
// } else if (level === ListLevel.WAYPOINT) { } else if (level === ListLevel.WAYPOINT) {
// let waypointIndices = items.map((item) => let waypointIndices = items.map((item) =>
// (item as ListWaypointItem).getWaypointIndex() (item as ListWaypointItem).getWaypointIndex()
// ); );
// file.setHiddenWaypoints(hidden, waypointIndices); file.setHiddenWaypoints(hidden, waypointIndices);
// } }
// } }
// }); });
// }); });
}, },
deleteSelection: () => { deleteSelection: () => {
if (get(selection).size === 0) { if (get(selection).size === 0) {

View File

@@ -31,10 +31,6 @@ export class GPXFileState {
} }
this._file.set({ file, statistics }); this._file.set({ file, statistics });
// if (get(selection).hasAnyChildren(new ListFileItem(id))) {
// updateAllHidden();
// }
} }
}); });
} }

View File

@@ -0,0 +1,67 @@
import { get, writable, type Writable } from 'svelte/store';
import { SelectedGPXFilesObserver, selection } from '$lib/logic/selection';
import { fileStateCollection } from '$lib/logic/file-state';
import {
ListFileItem,
ListTrackItem,
ListTrackSegmentItem,
ListWaypointItem,
ListWaypointsItem,
} from '$lib/components/file-list/file-list';
export class AllHidden {
private _value: Writable<boolean>;
constructor() {
this._value = writable(false);
new SelectedGPXFilesObserver(() => this.update());
}
subscribe(run: (value: boolean) => void, invalidate?: () => void) {
return this._value.subscribe(run, invalidate);
}
update() {
let hidden = true;
selection.applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
let file = fileStateCollection.getFile(fileId);
if (file) {
for (let item of items) {
if (!hidden) {
return;
}
if (item instanceof ListFileItem) {
hidden = hidden && file._data.hidden === true;
} else if (
item instanceof ListTrackItem &&
item.getTrackIndex() < file.trk.length
) {
hidden = hidden && file.trk[item.getTrackIndex()]._data.hidden === true;
} else if (
item instanceof ListTrackSegmentItem &&
item.getTrackIndex() < file.trk.length &&
item.getSegmentIndex() < file.trk[item.getTrackIndex()].trkseg.length
) {
hidden =
hidden &&
file.trk[item.getTrackIndex()].trkseg[item.getSegmentIndex()]._data
.hidden === true;
} else if (item instanceof ListWaypointsItem) {
hidden = hidden && file._data.hiddenWpt === true;
} else if (
item instanceof ListWaypointItem &&
item.getWaypointIndex() < file.wpt.length
) {
hidden = hidden && file.wpt[item.getWaypointIndex()]._data.hidden === true;
}
}
}
});
if (hidden != get(this._value)) {
this._value.set(hidden);
}
}
}
export const allHidden = new AllHidden();

View File

@@ -14,7 +14,6 @@ import { settings } from '$lib/logic/settings';
import type { GPXFile } from 'gpx'; import type { GPXFile } from 'gpx';
import { get, writable, type Readable, type Writable } from 'svelte/store'; import { get, writable, type Readable, type Writable } from 'svelte/store';
import { SelectionTreeType } from '$lib/logic/selection-tree'; import { SelectionTreeType } from '$lib/logic/selection-tree';
import { tick } from 'svelte';
export class Selection { export class Selection {
private _selection: Writable<SelectionTreeType>; private _selection: Writable<SelectionTreeType>;
@@ -254,3 +253,33 @@ export function applyToOrderedItemsFromFile(
} }
}); });
} }
export class SelectedGPXFilesObserver {
private _fileStateCollectionObserver: GPXFileStateCollectionObserver;
private _unsubscribes: Map<string, () => void> = new Map();
constructor(onSelectedFileChange: () => void) {
this._unsubscribes = new Map();
this._fileStateCollectionObserver = new GPXFileStateCollectionObserver(
(fileId, fileState) => {
this._unsubscribes.set(
fileId,
fileState.subscribe(() => {
if (get(selection).hasAnyChildren(new ListFileItem(fileId))) {
onSelectedFileChange();
}
})
);
},
(fileId) => {
this._unsubscribes.get(fileId)?.();
this._unsubscribes.delete(fileId);
},
() => {
this._unsubscribes.forEach((unsubscribe) => unsubscribe());
this._unsubscribes.clear();
}
);
selection.subscribe(() => onSelectedFileChange());
}
}

View File

@@ -1,68 +1,3 @@
// import { writable, get, type Writable } from 'svelte/store'; // import { writable } from 'svelte/store';
// import { GPXFile, parseGPX, GPXStatistics } from 'gpx';
// import { tick } from 'svelte';
// import { i18n } from '$lib/i18n.svelte';
// import type { GPXLayer } from '$lib/components/map/gpx-layer/GPXLayer';
// import { dbUtils, fileObservers, getFile, getStatistics } from '$lib/db';
// import {
// applyToOrderedSelectedItemsFromFile,
// selectFile,
// selection,
// } from '$lib/components/file-list/Selection';
// import {
// ListFileItem,
// ListTrackItem,
// ListTrackSegmentItem,
// ListWaypointItem,
// ListWaypointsItem,
// } from '$lib/components/file-list/FileList';
// import type { RoutingControls } from '$lib/components/toolbar/tools/routing/RoutingControls';
// export const embedding = writable(false); // export const embedding = writable(false);
// export const selectFiles = writable<{ [key: string]: (fileId?: string) => void }>({});
// export const routingControls: Map<string, RoutingControls> = new Map();
// export const allHidden = writable(false);
// export function updateAllHidden() {
// let hidden = true;
// applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
// let file = getFile(fileId);
// if (file) {
// for (let item of items) {
// if (!hidden) {
// return;
// }
// if (item instanceof ListFileItem) {
// hidden = hidden && file._data.hidden === true;
// } else if (
// item instanceof ListTrackItem &&
// item.getTrackIndex() < file.trk.length
// ) {
// hidden = hidden && file.trk[item.getTrackIndex()]._data.hidden === true;
// } else if (
// item instanceof ListTrackSegmentItem &&
// item.getTrackIndex() < file.trk.length &&
// item.getSegmentIndex() < file.trk[item.getTrackIndex()].trkseg.length
// ) {
// hidden =
// hidden &&
// file.trk[item.getTrackIndex()].trkseg[item.getSegmentIndex()]._data
// .hidden === true;
// } else if (item instanceof ListWaypointsItem) {
// hidden = hidden && file._data.hiddenWpt === true;
// } else if (
// item instanceof ListWaypointItem &&
// item.getWaypointIndex() < file.wpt.length
// ) {
// hidden = hidden && file.wpt[item.getWaypointIndex()]._data.hidden === true;
// }
// }
// }
// });
// allHidden.set(hidden);
// }
// selection.subscribe(updateAllHidden);

View File

@@ -178,6 +178,20 @@ export function getConvertedDistance(value: number, targetDistanceUnits = get(di
} }
} }
export function getConvertedDistanceToKilometers(
value: number,
sourceDistanceUnits = get(distanceUnits)
) {
switch (sourceDistanceUnits) {
case 'metric':
return value;
case 'imperial':
return milesToKilometers(value);
case 'nautical':
return nauticalMilesToKilometers(value);
}
}
export function getConvertedElevation(value: number, targetDistanceUnits = get(distanceUnits)) { export function getConvertedElevation(value: number, targetDistanceUnits = get(distanceUnits)) {
switch (targetDistanceUnits) { switch (targetDistanceUnits) {
case 'metric': case 'metric':

View File

@@ -305,6 +305,7 @@
"openTopoMap": "OpenTopoMap", "openTopoMap": "OpenTopoMap",
"openHikingMap": "OpenHikingMap", "openHikingMap": "OpenHikingMap",
"cyclOSM": "CyclOSM", "cyclOSM": "CyclOSM",
"utagawaVTT": "Utagawa MTB",
"linz": "LINZ Topo", "linz": "LINZ Topo",
"linzTopo": "LINZ Topo50", "linzTopo": "LINZ Topo50",
"swisstopoRaster": "swisstopo Raster", "swisstopoRaster": "swisstopo Raster",