mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-12-03 18:32:12 +00:00
Compare commits
5 Commits
05df3ca064
...
117c46341b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
117c46341b | ||
|
|
ba1ac69151 | ||
|
|
a8d3af35de | ||
|
|
307eed86e3 | ||
|
|
3f103323c7 |
@@ -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: {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,44 +38,36 @@
|
|||||||
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 {
|
return {
|
||||||
// time: false,
|
time: false,
|
||||||
// hr: false,
|
hr: false,
|
||||||
// cad: false,
|
cad: false,
|
||||||
// atemp: false,
|
atemp: false,
|
||||||
// power: false,
|
power: false,
|
||||||
// extensions: false,
|
extensions: false,
|
||||||
// };
|
};
|
||||||
// } else {
|
} else {
|
||||||
// let statistics = $gpxStatistics;
|
let statistics = $gpxStatistics;
|
||||||
// if (exportState.current === ExportState.ALL) {
|
if (exportState.current === ExportState.ALL) {
|
||||||
// statistics = Array.from(fileStateCollection.files.values())
|
statistics = Array.from(get(fileStateCollection).values())
|
||||||
// .map((file) => file.statistics)
|
.map((file) => file.statistics)
|
||||||
// .reduce((acc, cur) => {
|
.reduce((acc, cur) => {
|
||||||
// if (cur !== undefined) {
|
if (cur !== undefined) {
|
||||||
// acc.mergeWith(cur.getStatisticsFor(new ListRootItem()));
|
acc.mergeWith(cur.getStatisticsFor(new ListRootItem()));
|
||||||
// }
|
}
|
||||||
// return acc;
|
return acc;
|
||||||
// }, new GPXStatistics());
|
}, new GPXStatistics());
|
||||||
// }
|
}
|
||||||
// return {
|
return {
|
||||||
// time: statistics.global.time.total === 0,
|
time: statistics.global.time.total === 0,
|
||||||
// hr: statistics.global.hr.count === 0,
|
hr: statistics.global.hr.count === 0,
|
||||||
// cad: statistics.global.cad.count === 0,
|
cad: statistics.global.cad.count === 0,
|
||||||
// atemp: statistics.global.atemp.count === 0,
|
atemp: statistics.global.atemp.count === 0,
|
||||||
// power: statistics.global.power.count === 0,
|
power: statistics.global.power.count === 0,
|
||||||
// extensions: Object.keys(statistics.global.extensions).length === 0,
|
extensions: Object.keys(statistics.global.extensions).length === 0,
|
||||||
// };
|
};
|
||||||
// }
|
}
|
||||||
return {
|
|
||||||
time: false,
|
|
||||||
hr: false,
|
|
||||||
cad: false,
|
|
||||||
atemp: false,
|
|
||||||
power: false,
|
|
||||||
extensions: false,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
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>
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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) ?? [
|
||||||
@@ -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();
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
67
website/src/lib/logic/hidden.ts
Normal file
67
website/src/lib/logic/hidden.ts
Normal 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();
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
|
|||||||
@@ -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':
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user