lint fixes

This commit is contained in:
vcoppe committed 2026-10-28 22:40:48 +01:00
1 parent f5a2db0565
commit 6956c19410
44 files changed
+223 -224

No files matched your search

+3 -3
View File
@@ -107,9 +107,9 @@ impl Apply for Convert {
Err(CommandError::NothingToDo) Err(CommandError::NothingToDo)
}; };
} }
Selection::Empty Selection::Empty | Selection::Waypoints { .. } | Selection::Waypoint { .. } => {
| Selection::Waypoints { .. } return Err(CommandError::NothingToDo);
| Selection::Waypoint { .. } => return Err(CommandError::NothingToDo), }
}; };
let empty = match &next { let empty = match &next {
Selection::Route { rte_ids, .. } => rte_ids.is_empty(), Selection::Route { rte_ids, .. } => rte_ids.is_empty(),
-13
View File
@@ -1,13 +0,0 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
-31
View File
@@ -1,31 +0,0 @@
/** @type { import("eslint").Linter.Config } */
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte'],
},
env: {
browser: true,
es2017: true,
node: true,
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
},
},
],
};
+47
View File
@@ -0,0 +1,47 @@
import js from '@eslint/js';
import ts from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import svelte from 'eslint-plugin-svelte';
import prettier from 'eslint-config-prettier';
import globals from 'globals';
/** @type {import('eslint').Linter.Config[]} */
export default [
{
ignores: ['build/', '.svelte-kit/', 'package/'],
},
js.configs.recommended,
...ts.configs['flat/recommended'],
...svelte.configs['flat/recommended'],
prettier,
...svelte.configs['flat/prettier'],
{
languageOptions: {
globals: { ...globals.browser, ...globals.node },
},
},
{
rules: {
// TypeScript already reports undefined names
'no-undef': 'off',
'no-empty': ['error', { allowEmptyCatch: true }],
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
},
},
{
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
languageOptions: {
parserOptions: {
parser: tsParser,
extraFileExtensions: ['.svelte'],
},
},
rules: {
// $effect dependencies are tracked by reading them
'@typescript-eslint/no-unused-expressions': 'off',
},
},
];
+2 -2
View File
@@ -1,7 +1,7 @@
@import 'tailwindcss'; @import 'tailwindcss';
@import 'tw-animate-css'; @import 'tw-animate-css';
@import "shadcn-svelte/tailwind.css"; @import 'shadcn-svelte/tailwind.css';
@import "@fontsource-variable/inter"; @import '@fontsource-variable/inter';
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@@ -26,7 +26,7 @@
<Tooltip.Root> <Tooltip.Root>
<Tooltip.Trigger> <Tooltip.Trigger>
{#snippet child({ props })} {#snippet child({ props })}
<Button {...props} {variant} class="bg-inherit {className}" {onclick}> <Button {...props} {variant} {disabled} class="bg-inherit {className}" {onclick}>
{@render children()} {@render children()}
</Button> </Button>
{/snippet} {/snippet}
+3 -3
View File
@@ -39,7 +39,7 @@ export function getPreviousGuide(currentGuide: string): string | undefined {
return `${previousGuide}/${guides[previousGuide][guides[previousGuide].length - 1]}`; return `${previousGuide}/${guides[previousGuide][guides[previousGuide].length - 1]}`;
} }
} else { } else {
if (guides.hasOwnProperty(subguides[0])) { if (Object.hasOwn(guides, subguides[0])) {
const subguideIndex = guides[subguides[0]].indexOf(subguides[1]); const subguideIndex = guides[subguides[0]].indexOf(subguides[1]);
if (subguideIndex > 0) { if (subguideIndex > 0) {
return `${subguides[0]}/${guides[subguides[0]][subguideIndex - 1]}`; return `${subguides[0]}/${guides[subguides[0]][subguideIndex - 1]}`;
@@ -56,7 +56,7 @@ export function getNextGuide(currentGuide: string): string | undefined {
const subguides = currentGuide.split('/'); const subguides = currentGuide.split('/');
if (subguides.length === 1) { if (subguides.length === 1) {
if (guides.hasOwnProperty(currentGuide)) { if (Object.hasOwn(guides, currentGuide)) {
if (guides[currentGuide].length === 0) { if (guides[currentGuide].length === 0) {
const keys = Object.keys(guides); const keys = Object.keys(guides);
const index = keys.indexOf(currentGuide); const index = keys.indexOf(currentGuide);
@@ -68,7 +68,7 @@ export function getNextGuide(currentGuide: string): string | undefined {
return undefined; return undefined;
} }
} else { } else {
if (guides.hasOwnProperty(subguides[0])) { if (Object.hasOwn(guides, subguides[0])) {
const subguideIndex = guides[subguides[0]].indexOf(subguides[1]); const subguideIndex = guides[subguides[0]].indexOf(subguides[1]);
if (subguideIndex < guides[subguides[0]].length - 1) { if (subguideIndex < guides[subguides[0]].length - 1) {
return `${subguides[0]}/${guides[subguides[0]][subguideIndex + 1]}`; return `${subguides[0]}/${guides[subguides[0]][subguideIndex + 1]}`;
@@ -148,7 +148,7 @@ export class ElevationProfile {
} }
initialize() { initialize() {
let options: ChartOptions<'line'> = { const options: ChartOptions<'line'> = {
animation: false, animation: false,
parsing: false, parsing: false,
maintainAspectRatio: false, maintainAspectRatio: false,
@@ -199,7 +199,7 @@ export class ElevationProfile {
return ''; return '';
}, },
label: (context: TooltipItem<'line'>) => { label: (context: TooltipItem<'line'>) => {
let point = context.raw as ElevationProfilePoint; const point = context.raw as ElevationProfilePoint;
if (context.datasetIndex === 0) { if (context.datasetIndex === 0) {
this._hoveredPoint.set( this._hoveredPoint.set(
this._dragging this._dragging
@@ -223,16 +223,18 @@ export class ElevationProfile {
} }
}, },
afterBody: (contexts: TooltipItem<'line'>[]) => { afterBody: (contexts: TooltipItem<'line'>[]) => {
let context = contexts.filter((context) => context.datasetIndex === 0); const context = contexts.filter(
(context) => context.datasetIndex === 0
);
if (context.length === 0) return; if (context.length === 0) return;
let point = context[0].raw as ElevationProfilePoint; const point = context[0].raw as ElevationProfilePoint;
// the rest of the data is there once it is read (see `hover`) // the rest of the data is there once it is read (see `hover`)
const hovered = this._hovered; const hovered = this._hovered;
const details = const details =
hovered?.index === point.index ? hovered.point : undefined; hovered?.index === point.index ? hovered.point : undefined;
const elevationFill = get(this._elevationFill); const elevationFill = get(this._elevationFill);
let labels = [ const labels = [
` ${i18n._('quantities.distance')}: ${getDistanceWithUnits(point.x, false)}`, ` ${i18n._('quantities.distance')}: ${getDistanceWithUnits(point.x, false)}`,
]; ];
@@ -250,10 +252,10 @@ export class ElevationProfile {
} }
labels.push(` ${i18n._('quantities.slope')}: ${slope}`); labels.push(` ${i18n._('quantities.slope')}: ${slope}`);
} }
let surface = details.surface ?? 'unknown'; const surface = details.surface ?? 'unknown';
let highway = details.highway ?? 'unknown'; const highway = details.highway ?? 'unknown';
let sacScale = details.sacScale; const sacScale = details.sacScale;
let mtbScale = details.mtbScale; const mtbScale = details.mtbScale;
if (elevationFill === 'surface') { if (elevationFill === 'surface') {
labels.push( labels.push(
@@ -305,7 +307,7 @@ export class ElevationProfile {
enabled: true, enabled: true,
}, },
mode: 'x', mode: 'x',
onZoomStart: ({ chart, event }: { chart: Chart; event: any }) => { onZoomStart: ({ event }: { event: any }) => {
if (!this._chart) { if (!this._chart) {
return false; return false;
} }
@@ -335,7 +337,7 @@ export class ElevationProfile {
}, },
}; };
let datasets: string[] = ['speed', 'hr', 'cad', 'atemp', 'power']; const datasets: string[] = ['speed', 'hr', 'cad', 'atemp', 'power'];
datasets.forEach((id) => { datasets.forEach((id) => {
options.scales![`y${id}`] = { options.scales![`y${id}`] = {
type: 'linear', type: 'linear',
@@ -580,11 +582,11 @@ export class ElevationProfile {
} }
const additionalDatasets = get(this._additionalDatasets); const additionalDatasets = get(this._additionalDatasets);
let includeSpeed = additionalDatasets.includes('speed'); const includeSpeed = additionalDatasets.includes('speed');
let includeHeartRate = additionalDatasets.includes('hr'); const includeHeartRate = additionalDatasets.includes('hr');
let includeCadence = additionalDatasets.includes('cad'); const includeCadence = additionalDatasets.includes('cad');
let includeTemperature = additionalDatasets.includes('atemp'); const includeTemperature = additionalDatasets.includes('atemp');
let includePower = additionalDatasets.includes('power'); const includePower = additionalDatasets.includes('power');
if (this._chart.data.datasets.length == 6) { if (this._chart.data.datasets.length == 6) {
this._chart.data.datasets[1].hidden = !includeSpeed; this._chart.data.datasets[1].hidden = !includeSpeed;
this._chart.data.datasets[2].hidden = !includeHeartRate; this._chart.data.datasets[2].hidden = !includeHeartRate;
@@ -639,21 +641,21 @@ export class ElevationProfile {
const slicedStatistics = get(this._slicedStatistics); const slicedStatistics = get(this._slicedStatistics);
if (slicedStatistics) { if (slicedStatistics) {
let startIndex = slicedStatistics.start; const startIndex = slicedStatistics.start;
let endIndex = slicedStatistics.end; const endIndex = slicedStatistics.end;
// Draw selection rectangle // Draw selection rectangle
let selectionContext = this._overlay.getContext('2d'); const selectionContext = this._overlay.getContext('2d');
if (selectionContext) { if (selectionContext) {
selectionContext.fillStyle = mode.current === 'dark' ? 'white' : 'black'; selectionContext.fillStyle = mode.current === 'dark' ? 'white' : 'black';
selectionContext.globalAlpha = mode.current === 'dark' ? 0.2 : 0.1; selectionContext.globalAlpha = mode.current === 'dark' ? 0.2 : 0.1;
selectionContext.clearRect(0, 0, this._overlay.width, this._overlay.height); selectionContext.clearRect(0, 0, this._overlay.width, this._overlay.height);
const statistics = get(this._statistics); const statistics = get(this._statistics);
let startPixel = this._chart.scales.x.getPixelForValue( const startPixel = this._chart.scales.x.getPixelForValue(
getConvertedDistance(statistics.totalDistance[startIndex] ?? 0) getConvertedDistance(statistics.totalDistance[startIndex] ?? 0)
); );
let endPixel = this._chart.scales.x.getPixelForValue( const endPixel = this._chart.scales.x.getPixelForValue(
getConvertedDistance(statistics.totalDistance[endIndex] ?? 0) getConvertedDistance(statistics.totalDistance[endIndex] ?? 0)
); );
@@ -665,7 +667,7 @@ export class ElevationProfile {
); );
} }
} else if (this._overlay) { } else if (this._overlay) {
let selectionContext = this._overlay.getContext('2d'); const selectionContext = this._overlay.getContext('2d');
if (selectionContext) { if (selectionContext) {
selectionContext.clearRect(0, 0, this._overlay.width, this._overlay.height); selectionContext.clearRect(0, 0, this._overlay.width, this._overlay.height);
} }
@@ -109,7 +109,7 @@ export function getURLForGoogleDriveFile(fileId: string): string {
} }
export function convertOldEmbeddingOptions(options: URLSearchParams): any { export function convertOldEmbeddingOptions(options: URLSearchParams): any {
let newOptions: any = { const newOptions: any = {
key: PUBLIC_MAPTILER_KEY, key: PUBLIC_MAPTILER_KEY,
files: [], files: [],
ids: [], ids: [],
@@ -128,7 +128,7 @@ export function convertOldEmbeddingOptions(options: URLSearchParams): any {
} }
} }
if (options.has('source')) { if (options.has('source')) {
let basemap = options.get('source')!; const basemap = options.get('source')!;
if (basemap === 'satellite') { if (basemap === 'satellite') {
newOptions.basemap = 'libertySatellite'; newOptions.basemap = 'libertySatellite';
} else if (basemap === 'otm') { } else if (basemap === 'otm') {
@@ -132,7 +132,6 @@
<div class="flex flex-col h-full"> <div class="flex flex-col h-full">
<div class="px-2 py-1 text-sm font-semibold shrink-0">{i18n._('menu.explorer')}</div> <div class="px-2 py-1 text-sm font-semibold shrink-0">{i18n._('menu.explorer')}</div>
<ScrollArea class="grow min-h-0"> <ScrollArea class="grow min-h-0">
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<div <div
bind:this={container} bind:this={container}
data-explorer data-explorer
@@ -121,7 +121,6 @@
let isCut = $derived($clipboard?.cut === true && isInClipboard($clipboard, node)); let isCut = $derived($clipboard?.cut === true && isInClipboard($clipboard, node));
</script> </script>
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions --> <!-- svelte-ignore a11y_no_static_element_interactions -->
<ContextMenu.Root <ContextMenu.Root
onOpenChange={(open) => { onOpenChange={(open) => {
@@ -241,9 +241,9 @@ export class SortableFileList {
return; return;
} }
const selection_ = get(engine.selection); const selection_ = get(engine.selection);
for (let id of changed) { for (const id of changed) {
let element = this._elements[id]; const element = this._elements[id];
let node = this.childNode(id); const node = this.childNode(id);
if (element && node) { if (element && node) {
if (isSelected(selection_, node)) { if (isSelected(selection_, node)) {
Sortable.utils.select(element); Sortable.utils.select(element);
@@ -344,7 +344,7 @@ export class SortableFileList {
const files = get(engine.files); const files = get(engine.files);
this._container.childNodes.forEach((element) => { this._container.childNodes.forEach((element) => {
if (element instanceof HTMLElement) { if (element instanceof HTMLElement) {
let attr = element.getAttribute('data-id'); const attr = element.getAttribute('data-id');
if (attr) { if (attr) {
if (this._sortableLevel === 'file' && !files.has(attr)) { if (this._sortableLevel === 'file' && !files.has(attr)) {
this.forget(element); this.forget(element);
@@ -392,12 +392,12 @@ export class SortableFileList {
} }
getChangedIds() { getChangedIds() {
let changed: string[] = []; const changed: string[] = [];
const selection_ = get(engine.selection); const selection_ = get(engine.selection);
Object.entries(this._elements).forEach(([id, element]) => { Object.entries(this._elements).forEach(([id, element]) => {
const node = this.childNode(id); const node = this.childNode(id);
let inSelection = node !== undefined && isSelected(selection_, node); const inSelection = node !== undefined && isSelected(selection_, node);
let isSelectedInList = element.classList.contains('sortable-selected'); const isSelectedInList = element.classList.contains('sortable-selected');
if (inSelection !== isSelectedInList) { if (inSelection !== isSelectedInList) {
changed.push(id); changed.push(id);
} }
@@ -77,9 +77,11 @@
</div> </div>
<ScrollArea class="flex flex-col max-h-[30dvh]"> <ScrollArea class="flex flex-col max-h-[30dvh]">
{#if waypoint.item.desc} {#if waypoint.item.desc}
<!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitized -->
<span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.desc)}</span> <span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.desc)}</span>
{/if} {/if}
{#if waypoint.item.cmt && waypoint.item.cmt !== waypoint.item.desc} {#if waypoint.item.cmt && waypoint.item.cmt !== waypoint.item.desc}
<!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitized -->
<span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.cmt)}</span> <span class="whitespace-pre-wrap">{@html sanitize(waypoint.item.cmt)}</span>
{/if} {/if}
</ScrollArea> </ScrollArea>
@@ -35,7 +35,8 @@ export class DistanceMarkers {
try { try {
if (get(distanceMarkers) && !get(allHidden)) { if (get(distanceMarkers) && !get(allHidden)) {
let distanceSource: GeoJSONSource | undefined = map_.getSource('distance-markers'); const distanceSource: GeoJSONSource | undefined =
map_.getSource('distance-markers');
if (distanceSource) { if (distanceSource) {
distanceSource.setData(this.getDistanceMarkersGeoJSON()); distanceSource.setData(this.getDistanceMarkersGeoJSON());
} else { } else {
@@ -90,7 +91,7 @@ export class DistanceMarkers {
map_.removeLayer('distance-markers'); map_.removeLayer('distance-markers');
} }
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to add sources and layers // No reliable way to check if the map is ready to add sources and layers
return; return;
} }
@@ -104,12 +105,12 @@ export class DistanceMarkers {
// the distance from the start of the selection, and the position, of each trackpoint // the distance from the start of the selection, and the position, of each trackpoint
const { length, totalDistance, lng, lat } = get(engine.statistics); const { length, totalDistance, lng, lat } = get(engine.statistics);
let features: GeoJSON.Feature[] = []; const features: GeoJSON.Feature[] = [];
let currentTargetDistance = 1; let currentTargetDistance = 1;
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
if (totalDistance[i] >= getConvertedDistanceToKilometers(currentTargetDistance)) { if (totalDistance[i] >= getConvertedDistanceToKilometers(currentTargetDistance)) {
let distance = currentTargetDistance.toFixed(0); const distance = currentTargetDistance.toFixed(0);
let level = levels.find((level) => currentTargetDistance % level === 0) || 1; const level = levels.find((level) => currentTargetDistance % level === 0) || 1;
features.push({ features.push({
type: 'Feature', type: 'Feature',
geometry: { geometry: {
@@ -23,7 +23,7 @@ import { mapCursor, MapCursorState } from '$lib/state/map-cursor';
import { ANCHOR_LAYER_KEY } from '$lib/components/map/style'; import { ANCHOR_LAYER_KEY } from '$lib/components/map/style';
export function getSvgForSymbol(symbol?: string | undefined, layerColor?: string | undefined) { export function getSvgForSymbol(symbol?: string | undefined, layerColor?: string | undefined) {
let symbolSvg = symbol ? symbols[symbol]?.iconSvg : undefined; const symbolSvg = symbol ? symbols[symbol]?.iconSvg : undefined;
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
${ ${
layerColor layerColor
@@ -63,7 +63,7 @@ export class GPXLayer {
currentWaypointData: GeoJSON.FeatureCollection | null = null; currentWaypointData: GeoJSON.FeatureCollection | null = null;
draggedWaypointIndex: number | null = null; draggedWaypointIndex: number | null = null;
draggingStartingPosition: Point = new Point(0, 0); draggingStartingPosition: Point = new Point(0, 0);
unsubscribe: Function[] = []; unsubscribe: (() => void)[] = [];
updateBinded: () => void = this.update.bind(this); updateBinded: () => void = this.update.bind(this);
layerOnMouseEnterBinded: (e: any) => void = this.layerOnMouseEnter.bind(this); layerOnMouseEnterBinded: (e: any) => void = this.layerOnMouseEnter.bind(this);
@@ -101,7 +101,7 @@ export class GPXLayer {
this.unsubscribe.push( this.unsubscribe.push(
engine.selection.subscribe(($selection) => { engine.selection.subscribe(($selection) => {
this.selectionState = $selection; this.selectionState = $selection;
let newSelected = hasSelectionWithin($selection, this.fileNode()); const newSelected = hasSelectionWithin($selection, this.fileNode());
if (this.selected || newSelected) { if (this.selected || newSelected) {
this.selected = newSelected; this.selected = newSelected;
this.update(); this.update();
@@ -146,7 +146,7 @@ export class GPXLayer {
this.loadIcons(); this.loadIcons();
try { try {
let source = _map.getSource(this.fileId) as GeoJSONSource | undefined; const source = _map.getSource(this.fileId) as GeoJSONSource | undefined;
if (source) { if (source) {
source.setData(this.getGeoJSON()); source.setData(this.getGeoJSON());
} else { } else {
@@ -234,7 +234,7 @@ export class GPXLayer {
} }
} }
let waypointSource = _map.getSource(this.fileId + '-waypoints') as const waypointSource = _map.getSource(this.fileId + '-waypoints') as
| GeoJSONSource | GeoJSONSource
| undefined; | undefined;
this.currentWaypointData = this.getWaypointsGeoJSON(); this.currentWaypointData = this.getWaypointsGeoJSON();
@@ -301,7 +301,7 @@ export class GPXLayer {
['in', ['get', 'waypointIndex'], ['literal', visibleWaypoints]], ['in', ['get', 'waypointIndex'], ['literal', visibleWaypoints]],
{ validate: false } { validate: false }
); );
} catch (e) { } catch {
// No reliable way to check if the map is ready to add sources and layers // No reliable way to check if the map is ready to add sources and layers
return; return;
} }
@@ -584,7 +584,7 @@ export class GPXLayer {
this.currentWaypointData!.features[this.draggedWaypointIndex].geometry as GeoJSON.Point this.currentWaypointData!.features[this.draggedWaypointIndex].geometry as GeoJSON.Point
).coordinates = [e.lngLat.lng, e.lngLat.lat]; ).coordinates = [e.lngLat.lng, e.lngLat.lat];
let waypointSource = get(map)?.getSource(this.fileId + '-waypoints') as const waypointSource = get(map)?.getSource(this.fileId + '-waypoints') as
| GeoJSONSource | GeoJSONSource
| undefined; | undefined;
if (waypointSource) { if (waypointSource) {
@@ -698,7 +698,7 @@ export class GPXLayer {
return; return;
} }
let symbols = new Set<string | undefined>(); const symbols = new Set<string | undefined>();
get(this.file).waypoints.features.forEach((feature) => { get(this.file).waypoints.features.forEach((feature) => {
symbols.add(getSymbolKey(feature.properties.sym)); symbols.add(getSymbolKey(feature.properties.sym));
}); });
@@ -100,7 +100,7 @@ export class StartEndMarkers {
}); });
} }
let source = map_.getSource('start-end-markers') as GeoJSONSource | undefined; const source = map_.getSource('start-end-markers') as GeoJSONSource | undefined;
if (source) { if (source) {
source.setData(data); source.setData(data);
} else { } else {
@@ -136,7 +136,7 @@
function getLayerId() { function getLayerId() {
for (let id = 0; ; id++) { for (let id = 0; ; id++) {
if (!$customLayers.hasOwnProperty(`custom-${id}`)) { if (!Object.hasOwn($customLayers, `custom-${id}`)) {
return `custom-${id}`; return `custom-${id}`;
} }
} }
@@ -145,7 +145,7 @@
function addLayer(layerId: string) { function addLayer(layerId: string) {
if (layerType === 'basemap') { if (layerType === 'basemap') {
selectedBasemapTree.update(($tree) => { selectedBasemapTree.update(($tree) => {
if (!$tree.basemaps.hasOwnProperty('custom')) { if (!Object.hasOwn($tree.basemaps, 'custom')) {
$tree.basemaps['custom'] = {}; $tree.basemaps['custom'] = {};
} }
$tree.basemaps['custom'][layerId] = true; $tree.basemaps['custom'][layerId] = true;
@@ -161,7 +161,7 @@
} }
} else { } else {
selectedOverlayTree.update(($tree) => { selectedOverlayTree.update(($tree) => {
if (!$tree.overlays.hasOwnProperty('custom')) { if (!Object.hasOwn($tree.overlays, 'custom')) {
$tree.overlays['custom'] = {}; $tree.overlays['custom'] = {};
} }
$tree.overlays['custom'][layerId] = true; $tree.overlays['custom'][layerId] = true;
@@ -169,7 +169,7 @@
}); });
currentOverlays.update(($overlays) => { currentOverlays.update(($overlays) => {
if (!$overlays.overlays.hasOwnProperty('custom')) { if (!Object.hasOwn($overlays.overlays, 'custom')) {
$overlays.overlays['custom'] = {}; $overlays.overlays['custom'] = {};
} }
$overlays.overlays['custom'][layerId] = true; $overlays.overlays['custom'][layerId] = true;
@@ -183,7 +183,7 @@
} }
function tryDeleteLayer(node: any, id: string): any { function tryDeleteLayer(node: any, id: string): any {
if (node.hasOwnProperty(id)) { if (Object.hasOwn(node, id)) {
delete node[id]; delete node[id];
} }
return node; return node;
@@ -365,7 +365,7 @@
<Label for="name">{i18n._('menu.metadata.name')}</Label> <Label for="name">{i18n._('menu.metadata.name')}</Label>
<Input bind:value={name} id="name" class="h-8" /> <Input bind:value={name} id="name" class="h-8" />
<Label for="url">{i18n._('layers.custom_layers.urls')}</Label> <Label for="url">{i18n._('layers.custom_layers.urls')}</Label>
{#each tileUrls as url, i} {#each tileUrls as _, i}
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
<Input <Input
bind:value={tileUrls[i]} bind:value={tileUrls[i]}
@@ -45,7 +45,7 @@
function setOpacityFromSelection() { function setOpacityFromSelection() {
if (selectedOverlay) { if (selectedOverlay) {
if ($opacities.hasOwnProperty(selectedOverlay)) { if (Object.hasOwn($opacities, selectedOverlay)) {
overlayOpacity = $opacities[selectedOverlay]; overlayOpacity = $opacities[selectedOverlay];
} else { } else {
overlayOpacity = 1; overlayOpacity = 1;
@@ -169,7 +169,7 @@
{#if isSelected($selectedOverlayTree, selectedOverlay)} {#if isSelected($selectedOverlayTree, selectedOverlay)}
{#if $isLayerFromExtension(selectedOverlay)} {#if $isLayerFromExtension(selectedOverlay)}
{$getLayerName(selectedOverlay)} {$getLayerName(selectedOverlay)}
{:else if $customLayers.hasOwnProperty(selectedOverlay)} {:else if Object.hasOwn($customLayers, selectedOverlay)}
{$customLayers[selectedOverlay].name} {$customLayers[selectedOverlay].name}
{:else} {:else}
{i18n._(`layers.label.${selectedOverlay}`)} {i18n._(`layers.label.${selectedOverlay}`)}
@@ -218,7 +218,7 @@
if ($map.getLayer(selectedOverlay)) { if ($map.getLayer(selectedOverlay)) {
$map.removeLayer(selectedOverlay); $map.removeLayer(selectedOverlay);
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to remove sources and layers // No reliable way to check if the map is ready to remove sources and layers
} }
} }
@@ -31,7 +31,7 @@
$effect.pre(() => { $effect.pre(() => {
if (checked !== undefined) { if (checked !== undefined) {
Object.keys(node).forEach((id) => { Object.keys(node).forEach((id) => {
if (!checked.hasOwnProperty(id)) { if (!Object.hasOwn(checked, id)) {
if (typeof node[id] == 'boolean') { if (typeof node[id] == 'boolean') {
checked[id] = false; checked[id] = false;
} else { } else {
@@ -72,7 +72,7 @@
/> />
{/if} {/if}
<Label for="{name}-{id}" class="flex flex-row items-center gap-1"> <Label for="{name}-{id}" class="flex flex-row items-center gap-1">
{#if $customLayers.hasOwnProperty(id)} {#if Object.hasOwn($customLayers, id)}
{$customLayers[id].name} {$customLayers[id].name}
{:else if $isLayerFromExtension(id)} {:else if $isLayerFromExtension(id)}
{$getLayerName(id)} {$getLayerName(id)}
@@ -1,7 +1,7 @@
import { settings } from '$lib/state/settings'; import { settings } from '$lib/state/settings';
import { derived, get, writable, type Writable } from 'svelte/store'; import { derived, get, writable, type Writable } from 'svelte/store';
import { isSelected, remove, removeAll } from './utils'; import { isSelected, remove, removeAll } from './utils';
import { overlays, overlayTree } from '$lib/data/layers'; import { overlays, overlayTree, type LayerTreeType } from '$lib/data/layers';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { map } from '$lib/components/map/map'; import { map } from '$lib/components/map/map';
@@ -19,7 +19,7 @@ export class ExtensionAPI {
private _overlays: Writable<Map<string, CustomOverlay>> = writable(new Map()); private _overlays: Writable<Map<string, CustomOverlay>> = writable(new Map());
init() { init() {
if (browser && !window.hasOwnProperty('gpxstudio')) { if (browser && !Object.hasOwn(window, 'gpxstudio')) {
Object.defineProperty(window, 'gpxstudio', { Object.defineProperty(window, 'gpxstudio', {
value: this, value: this,
}); });
@@ -84,14 +84,14 @@ export class ExtensionAPI {
], ],
}; };
if (!overlayTree.overlays.hasOwnProperty(overlay.extensionName)) { if (!Object.hasOwn(overlayTree.overlays as LayerTreeType, overlay.extensionName)) {
overlayTree.overlays[overlay.extensionName] = {}; overlayTree.overlays[overlay.extensionName] = {};
} }
overlayTree.overlays[overlay.extensionName][overlay.id] = true; overlayTree.overlays[overlay.extensionName][overlay.id] = true;
selectedOverlayTree.update((selected) => { selectedOverlayTree.update((selected) => {
if (!selected.overlays.hasOwnProperty(overlay.extensionName)) { if (!Object.hasOwn(selected.overlays, overlay.extensionName)) {
selected.overlays[overlay.extensionName] = {}; selected.overlays[overlay.extensionName] = {};
} }
selected.overlays[overlay.extensionName][overlay.id] = true; selected.overlays[overlay.extensionName][overlay.id] = true;
@@ -104,13 +104,13 @@ export class ExtensionAPI {
show = true; show = true;
try { try {
get(map)?.removeLayer(overlay.id); get(map)?.removeLayer(overlay.id);
} catch (e) { } catch {
// No reliable way to check if the map is ready to remove sources and layers // No reliable way to check if the map is ready to remove sources and layers
} }
} }
currentOverlays.update((current) => { currentOverlays.update((current) => {
if (!current.overlays.hasOwnProperty(overlay.extensionName)) { if (!Object.hasOwn(current.overlays, overlay.extensionName)) {
current.overlays[overlay.extensionName] = {}; current.overlays[overlay.extensionName] = {};
} }
current.overlays[overlay.extensionName][overlay.id] = show; current.overlays[overlay.extensionName][overlay.id] = show;
@@ -155,13 +155,13 @@ export class ExtensionAPI {
updateOverlaysOrder(ids: string[]) { updateOverlaysOrder(ids: string[]) {
ids = ids.map((id) => this.getOverlayId(id)); ids = ids.map((id) => this.getOverlayId(id));
selectedOverlayTree.update((selected) => { selectedOverlayTree.update((selected) => {
let isSelected: Record<string, boolean> = {}; const isSelected: Record<string, boolean> = {};
ids.forEach((id) => { ids.forEach((id) => {
const overlay = get(this._overlays).get(id); const overlay = get(this._overlays).get(id);
if ( if (
overlay && overlay &&
selected.overlays.hasOwnProperty(overlay.extensionName) && Object.hasOwn(selected.overlays, overlay.extensionName) &&
selected.overlays[overlay.extensionName].hasOwnProperty(id) Object.hasOwn(selected.overlays[overlay.extensionName] as LayerTreeType, id)
) { ) {
isSelected[id] = selected.overlays[overlay.extensionName][id]; isSelected[id] = selected.overlays[overlay.extensionName][id];
delete selected.overlays[overlay.extensionName][id]; delete selected.overlays[overlay.extensionName][id];
@@ -86,7 +86,7 @@ export class OverpassLayer {
}; };
try { try {
let source = this.map.getSource('overpass') as GeoJSONSource | undefined; const source = this.map.getSource('overpass') as GeoJSONSource | undefined;
if (source) { if (source) {
source.setData(d); source.setData(d);
} else { } else {
@@ -115,7 +115,7 @@ export class OverpassLayer {
this.layerEventManager.on('mouseenter', 'overpass', this.onHoverBinded); this.layerEventManager.on('mouseenter', 'overpass', this.onHoverBinded);
this.layerEventManager.on('click', 'overpass', this.onHoverBinded); this.layerEventManager.on('click', 'overpass', this.onHoverBinded);
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to add sources and layers // No reliable way to check if the map is ready to add sources and layers
} }
} }
@@ -135,7 +135,7 @@ export class OverpassLayer {
if (this.map.getSource('overpass')) { if (this.map.getSource('overpass')) {
this.map.removeSource('overpass'); this.map.removeSource('overpass');
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to remove sources and layers // No reliable way to check if the map is ready to remove sources and layers
} }
} }
@@ -151,12 +151,12 @@ export class OverpassLayer {
} }
query(bbox: [number, number, number, number]) { query(bbox: [number, number, number, number]) {
let queries = getCurrentQueries(); const queries = getCurrentQueries();
if (queries.length === 0) { if (queries.length === 0) {
return; return;
} }
let tileLimits = mercator.xyz(bbox, this.queryZoom); const tileLimits = mercator.xyz(bbox, this.queryZoom);
for (let x = tileLimits.minX; x <= tileLimits.maxX; x++) { for (let x = tileLimits.minX; x <= tileLimits.maxX; x++) {
for (let y = tileLimits.minY; y <= tileLimits.maxY; y++) { for (let y = tileLimits.minY; y <= tileLimits.maxY; y++) {
@@ -189,8 +189,8 @@ export class OverpassLayer {
} }
this.data.update((updatedData) => { this.data.update((updatedData) => {
for (let element of data.elements) { for (const element of data.elements) {
for (let query of queries) { for (const query of queries) {
if (belongsToQuery(element, query)) { if (belongsToQuery(element, query)) {
updatedData.features.push({ updatedData.features.push({
type: 'Feature', type: 'Feature',
@@ -224,7 +224,7 @@ export class OverpassLayer {
} }
loadIcons() { loadIcons() {
let currentQueries = getCurrentQueries(); const currentQueries = getCurrentQueries();
currentQueries.forEach((query) => { currentQueries.forEach((query) => {
loadSVGIcon( loadSVGIcon(
this.map, this.map,
@@ -257,7 +257,7 @@ function getQuery(query: string) {
} }
function getQueryItem(tags: Record<string, string | string[]>) { function getQueryItem(tags: Record<string, string | string[]>) {
let arrayEntry = Object.entries(tags).find((entry): entry is [string, string[]] => const arrayEntry = Object.entries(tags).find((entry): entry is [string, string[]] =>
Array.isArray(entry[1]) Array.isArray(entry[1])
); );
if (arrayEntry !== undefined) { if (arrayEntry !== undefined) {
@@ -291,12 +291,12 @@ function belongsToQueryItem(element: any, tags: Record<string, string | string[]
} }
function getCurrentQueries() { function getCurrentQueries() {
let currentQueries = get(currentOverpassQueries); const currentQueries = get(currentOverpassQueries);
if (currentQueries === undefined) { if (currentQueries === undefined) {
return []; return [];
} }
return Object.entries(getLayers(currentQueries)) return Object.entries(getLayers(currentQueries))
.filter(([_, selected]) => selected) .filter(([, selected]) => selected)
.map(([query, _]) => query); .map(([query]) => query);
} }
@@ -235,7 +235,7 @@ export class MapLayerEventManager {
private _filterLayersIntersectingBounds(layerIds: string[], bounds: LngLatBounds): string[] { private _filterLayersIntersectingBounds(layerIds: string[], bounds: LngLatBounds): string[] {
const files = get(engine.files); const files = get(engine.files);
let result = layerIds.filter((layerId) => { const result = layerIds.filter((layerId) => {
if (!this._map.getLayer(layerId)) return false; if (!this._map.getLayer(layerId)) return false;
const fileId = layerId.replace('-waypoints', ''); const fileId = layerId.replace('-waypoints', '');
if (fileId === layerId) { if (fileId === layerId) {
+3 -3
View File
@@ -13,7 +13,7 @@ import { MapLayerEventManager } from '$lib/components/map/map-layer-event-manage
const { treeFileView, elevationProfile, bottomPanelSize, rightPanelSize, distanceUnits } = settings; const { treeFileView, elevationProfile, bottomPanelSize, rightPanelSize, distanceUnits } = settings;
let fitBoundsOptions: maplibregl.MapOptions['fitBoundsOptions'] = { const fitBoundsOptions: maplibregl.MapOptions['fitBoundsOptions'] = {
maxZoom: 15, maxZoom: 15,
linear: true, linear: true,
easing: () => 1, easing: () => 1,
@@ -75,7 +75,7 @@ export class MapLibreGLMap {
}) })
); );
if (geocoder) { if (geocoder) {
let geocoder = new MaplibreGeocoder( const geocoder = new MaplibreGeocoder(
{ {
forwardGeocode: async (config) => { forwardGeocode: async (config) => {
const results: MaplibreGeocoderFeatureResults = { const results: MaplibreGeocoderFeatureResults = {
@@ -96,7 +96,7 @@ export class MapLibreGLMap {
place_name: result.display_name, place_name: result.display_name,
}; };
}); });
} catch (e) {} } catch {}
return results; return results;
}, },
}, },
@@ -89,7 +89,7 @@ export class MapillaryLayer {
this.viewer.on('position', async () => { this.viewer.on('position', async () => {
if (this.active) { if (this.active) {
popupOpen.value = true; popupOpen.value = true;
let latLng = await this.viewer.getPosition(); const latLng = await this.viewer.getPosition();
this.marker.setLngLat(latLng).addTo(this.map); this.marker.setLngLat(latLng).addTo(this.map);
if (!this.map.getBounds()?.contains(latLng)) { if (!this.map.getBounds()?.contains(latLng)) {
this.map.panTo(latLng); this.map.panTo(latLng);
+9 -9
View File
@@ -87,7 +87,7 @@ export class StyleManager {
updateBasemap() { updateBasemap() {
const map_ = get(this._map); const map_ = get(this._map);
if (!map_) return; if (!map_) return;
let basemap = get(currentBasemap); const basemap = get(currentBasemap);
this.buildStyle(basemap).then((style) => { this.buildStyle(basemap).then((style) => {
if (get(currentBasemap) === basemap) map_.setStyle(style); if (get(currentBasemap) === basemap) map_.setStyle(style);
}); });
@@ -148,18 +148,18 @@ export class StyleManager {
const overlayOpacities = get(opacities); const overlayOpacities = get(opacities);
try { try {
const layers = getLayers(get(currentOverlays) ?? {}); const layers = getLayers(get(currentOverlays) ?? {});
for (let overlay in layers) { for (const overlay in layers) {
if (!layers[overlay]) { if (!layers[overlay]) {
if (this._pastOverlays.has(overlay)) { if (this._pastOverlays.has(overlay)) {
const overlayInfo = custom[overlay]?.value ?? overlays[overlay]; const overlayInfo = custom[overlay]?.value ?? overlays[overlay];
try { try {
const overlayStyle = await this.get(overlayInfo); const overlayStyle = await this.get(overlayInfo);
for (let layer of overlayStyle.layers ?? []) { for (const layer of overlayStyle.layers ?? []) {
if (map_.getLayer(layer.id)) { if (map_.getLayer(layer.id)) {
map_.removeLayer(layer.id); map_.removeLayer(layer.id);
} }
} }
} catch (e) { } catch {
// Should not happen // Should not happen
} }
this._pastOverlays.delete(overlay); this._pastOverlays.delete(overlay);
@@ -170,13 +170,13 @@ export class StyleManager {
const overlayStyle = await this.get(overlayInfo); const overlayStyle = await this.get(overlayInfo);
const opacity = overlayOpacities[overlay]; const opacity = overlayOpacities[overlay];
for (let sourceId in overlayStyle.sources) { for (const sourceId in overlayStyle.sources) {
if (!map_.getSource(sourceId)) { if (!map_.getSource(sourceId)) {
map_.addSource(sourceId, overlayStyle.sources[sourceId]); map_.addSource(sourceId, overlayStyle.sources[sourceId]);
} }
} }
for (let layer of overlayStyle.layers ?? []) { for (const layer of overlayStyle.layers ?? []) {
if (!map_.getLayer(layer.id)) { if (!map_.getLayer(layer.id)) {
if (opacity !== undefined) { if (opacity !== undefined) {
if (layer.type === 'raster') { if (layer.type === 'raster') {
@@ -200,7 +200,7 @@ export class StyleManager {
} }
} }
} }
} catch (e) {} } catch {}
} }
updateTerrain() { updateTerrain() {
@@ -223,7 +223,7 @@ export class StyleManager {
async get(styleInfo: StyleSpecification | string): Promise<StyleSpecification> { async get(styleInfo: StyleSpecification | string): Promise<StyleSpecification> {
if (typeof styleInfo === 'string') { if (typeof styleInfo === 'string') {
let styleUrl = styleInfo as string; const styleUrl = styleInfo as string;
const response = await fetch(styleUrl, { cache: 'force-cache' }); const response = await fetch(styleUrl, { cache: 'force-cache' });
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error fetching style "${styleInfo}": ${response.status}`); throw new Error(`HTTP error fetching style "${styleInfo}": ${response.status}`);
@@ -238,7 +238,7 @@ export class StyleManager {
merge(style: StyleSpecification, other: StyleSpecification) { merge(style: StyleSpecification, other: StyleSpecification) {
style.sources = { ...style.sources, ...other.sources }; style.sources = { ...style.sources, ...other.sources };
const units = get(distanceUnits); const units = get(distanceUnits);
for (let layer of other.layers ?? []) { for (const layer of other.layers ?? []) {
if ('source' in layer) { if ('source' in layer) {
if (layer.source == 'contours_m' && units === 'imperial') continue; if (layer.source == 'contours_m' && units === 'imperial') continue;
if (layer.source == 'contours_ft' && units !== 'imperial') continue; if (layer.source == 'contours_ft' && units !== 'imperial') continue;
@@ -92,7 +92,7 @@
} }
} }
function onMouseUp(e: any) { function onMouseUp() {
mousedown = false; mousedown = false;
} }
@@ -74,7 +74,7 @@ export class RoutingControls {
listenedFileIds: string[] = []; listenedFileIds: string[] = [];
popup: Popup; popup: Popup;
popupElement: HTMLElement; popupElement: HTMLElement;
unsubscribes: Function[] = []; unsubscribes: (() => void)[] = [];
updateBinded: () => void = this.update.bind(this); updateBinded: () => void = this.update.bind(this);
appendAnchorBinded: (e: MapMouseEvent) => void = this.appendAnchor.bind(this); appendAnchorBinded: (e: MapMouseEvent) => void = this.appendAnchor.bind(this);
@@ -270,7 +270,7 @@ export class RoutingControls {
layerEventManager.on('mousedown', LAYER_ID, this.onMouseDownBinded); layerEventManager.on('mousedown', LAYER_ID, this.onMouseDownBinded);
layerEventManager.on('touchstart', LAYER_ID, this.onTouchStartBinded); layerEventManager.on('touchstart', LAYER_ID, this.onTouchStartBinded);
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to add sources and layers // No reliable way to check if the map is ready to add sources and layers
} }
} }
@@ -303,7 +303,7 @@ export class RoutingControls {
if (map_?.getSource(LAYER_ID)) { if (map_?.getSource(LAYER_ID)) {
map_?.removeSource(LAYER_ID); map_?.removeSource(LAYER_ID);
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to remove sources and layers // No reliable way to check if the map is ready to remove sources and layers
} }
@@ -137,7 +137,7 @@ async function getGraphHopperRoute(
graphHopperProfile: string, graphHopperProfile: string,
privateRoads: boolean privateRoads: boolean
): Promise<RoutedPoints> { ): Promise<RoutedPoints> {
let response = await fetch('https://graphhopper.gpx.studio/route', { const response = await fetch('https://graphhopper.gpx.studio/route', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -222,9 +222,9 @@ async function getBRouterRoute(
points: Coordinates[], points: Coordinates[],
brouterProfile: string brouterProfile: string
): Promise<RoutedPoints> { ): Promise<RoutedPoints> {
let url = `https://brouter.de/brouter?lonlats=${points.map((point) => `${point.lng.toFixed(8)},${point.lat.toFixed(8)}`).join('|')}&profile=${brouterProfile}&format=geojson&alternativeidx=0`; const url = `https://brouter.de/brouter?lonlats=${points.map((point) => `${point.lng.toFixed(8)},${point.lat.toFixed(8)}`).join('|')}&profile=${brouterProfile}&format=geojson&alternativeidx=0`;
let response = await fetch(url); const response = await fetch(url);
if (!response.ok) { if (!response.ok) {
throw brouterError(await response.text()); throw brouterError(await response.text());
@@ -289,11 +289,10 @@ export function parseBRouterRoute(geojson: any): RoutedPoints {
/** The tags of a way, `key=value` separated by spaces, with the `:` of the keys as `_`. */ /** The tags of a way, `key=value` separated by spaces, with the `:` of the keys as `_`. */
export function getTags(message: string): { [key: string]: string } { export function getTags(message: string): { [key: string]: string } {
const fields = message.split(' '); const fields = message.split(' ');
let tags: { [key: string]: string } = {}; const tags: { [key: string]: string } = {};
for (let i = 0; i < fields.length; i++) { for (let i = 0; i < fields.length; i++) {
let [key, value] = fields[i].split('='); const [key, value] = fields[i].split('=');
key = key.replace(/:/g, '_'); tags[key.replace(/:/g, '_')] = value;
tags[key] = value;
} }
return tags; return tags;
} }
@@ -12,7 +12,7 @@ export const SplitType = {
} as const satisfies Record<string, EngineSplitType>; } as const satisfies Record<string, EngineSplitType>;
export type SplitType = (typeof SplitType)[keyof typeof SplitType]; export type SplitType = (typeof SplitType)[keyof typeof SplitType];
export let splitAs: Writable<SplitType> = writable(SplitType.FILES); export const splitAs: Writable<SplitType> = writable(SplitType.FILES);
/** The ids of the segments of the routes of the files of the selection. */ /** The ids of the segments of the routes of the files of the selection. */
export function routeSegmentIds(selection: Selection): Set<string> { export function routeSegmentIds(selection: Selection): Set<string> {
@@ -23,7 +23,7 @@ import {
export class SplitControls { export class SplitControls {
map: Map; map: Map;
layerEventManager: MapLayerEventManager; layerEventManager: MapLayerEventManager;
unsubscribes: Function[] = []; unsubscribes: (() => void)[] = [];
/** What the tool needs from the engine, while it shows the anchors. */ /** What the tool needs from the engine, while it shows the anchors. */
request: StatisticsRequest = engine.requestStatistics(); request: StatisticsRequest = engine.requestStatistics();
selection: Selection = { type: 'empty' }; selection: Selection = { type: 'empty' };
@@ -116,7 +116,7 @@ export class SplitControls {
}; };
try { try {
let source = this.map.getSource('split-controls') as GeoJSONSource | undefined; const source = this.map.getSource('split-controls') as GeoJSONSource | undefined;
if (source) { if (source) {
source.setData(data); source.setData(data);
} else { } else {
@@ -154,7 +154,7 @@ export class SplitControls {
); );
this.layerEventManager.on('click', 'split-controls', this.layerOnClickBinded); this.layerEventManager.on('click', 'split-controls', this.layerOnClickBinded);
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to add sources and layers // No reliable way to check if the map is ready to add sources and layers
} }
} }
@@ -172,12 +172,12 @@ export class SplitControls {
if (this.map.getSource('split-controls')) { if (this.map.getSource('split-controls')) {
this.map.removeSource('split-controls'); this.map.removeSource('split-controls');
} }
} catch (e) { } catch {
// No reliable way to check if the map is ready to remove sources and layers // No reliable way to check if the map is ready to remove sources and layers
} }
} }
layerOnMouseEnter(e: any) { layerOnMouseEnter() {
mapCursor.notify(MapCursorState.SPLIT_CONTROL, true); mapCursor.notify(MapCursorState.SPLIT_CONTROL, true);
} }
@@ -101,10 +101,7 @@
if (typeof hours === 'string') { if (typeof hours === 'string') {
hours = parseInt(hours); hours = parseInt(hours);
} }
if (hours >= 0) { if (hours < 0) {
} else if (hours < 0) {
hours = 0;
} else {
hours = 0; hours = 0;
} }
onChange(); onChange();
@@ -124,12 +121,9 @@
if (typeof minutes === 'string') { if (typeof minutes === 'string') {
minutes = parseInt(minutes); minutes = parseInt(minutes);
} }
if (minutes >= 0 && (minutes <= 59 || !showHours)) { if (showHours && minutes > 59) {
} else if (minutes < 0) {
minutes = 0;
} else if (showHours && minutes > 59) {
minutes = 59; minutes = 59;
} else { } else if (minutes < 0) {
minutes = 0; minutes = 0;
} }
minutes = minutes.toString().padStart(showHours ? 2 : 1, '0'); minutes = minutes.toString().padStart(showHours ? 2 : 1, '0');
@@ -149,12 +143,9 @@
if (typeof seconds === 'string') { if (typeof seconds === 'string') {
seconds = parseInt(seconds); seconds = parseInt(seconds);
} }
if (seconds >= 0 && seconds <= 59) { if (seconds > 59) {
} else if (seconds < 0) {
seconds = 0;
} else if (seconds > 59) {
seconds = 59; seconds = 59;
} else { } else if (seconds < 0) {
seconds = 0; seconds = 0;
} }
seconds = seconds.toString().padStart(2, '0'); seconds = seconds.toString().padStart(2, '0');
+8 -8
View File
@@ -96,10 +96,10 @@ function createPattern(
size: number = 16, size: number = 16,
lineWidth: number = 4 lineWidth: number = 4
) { ) {
let canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
canvas.width = size; canvas.width = size;
canvas.height = size; canvas.height = size;
let ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (ctx) { if (ctx) {
ctx.fillStyle = backgroundColor; ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, size, size); ctx.fillRect(0, 0, size, size);
@@ -139,11 +139,11 @@ export function getHighwayColor(
sacScale: string | undefined, sacScale: string | undefined,
mtbScale: string | undefined mtbScale: string | undefined
) { ) {
let backgroundColor = highwayColors[highway] ? highwayColors[highway] : highwayColors.missing; const backgroundColor = highwayColors[highway] ? highwayColors[highway] : highwayColors.missing;
let sacScaleColor = sacScale ? sacScaleColors[sacScale] : undefined; const sacScaleColor = sacScale ? sacScaleColors[sacScale] : undefined;
let mtbScaleColor = mtbScale ? mtbScaleColors[mtbScale] : undefined; const mtbScaleColor = mtbScale ? mtbScaleColors[mtbScale] : undefined;
if (sacScale || mtbScale) { if (sacScale || mtbScale) {
let patternId = `${backgroundColor}-${[sacScale, mtbScale].filter((x) => x).join('-')}`; const patternId = `${backgroundColor}-${[sacScale, mtbScale].filter((x) => x).join('-')}`;
if (!patterns[patternId]) { if (!patterns[patternId]) {
patterns[patternId] = createPattern(backgroundColor, sacScaleColor, mtbScaleColor); patterns[patternId] = createPattern(backgroundColor, sacScaleColor, mtbScaleColor);
} }
@@ -164,8 +164,8 @@ export function getSlopeColor(slope: number): string {
v = 1 / (1 + Math.exp(-6 * v)); v = 1 / (1 + Math.exp(-6 * v));
v = v - 0.5; v = v - 0.5;
let hue = ((0.5 - v) * 120).toString(10); const hue = ((0.5 - v) * 120).toString(10);
let lightness = 90 - Math.abs(v) * 70; const lightness = 90 - Math.abs(v) * 70;
return `hsl(${hue},70%,${lightness}%)`; return `hsl(${hue},70%,${lightness}%)`;
} }
+1 -1
View File
@@ -1,5 +1,5 @@
import { get, writable, type Readable } from 'svelte/store'; import { get, writable, type Readable } from 'svelte/store';
import { categoryIntervals, type CategoryIntervals } from '$lib/engine/trackpoint-categories'; import type { CategoryIntervals } from '$lib/engine/trackpoint-categories';
import type { Backend } from './backend'; import type { Backend } from './backend';
import { import {
EMPTY_SELECTION_STATISTICS, EMPTY_SELECTION_STATISTICS,
+1 -1
View File
@@ -1,5 +1,5 @@
import type { Readable } from 'svelte/store'; import type { Readable } from 'svelte/store';
import type { Feature, FeatureCollection, LineString, Point } from 'geojson'; import type { FeatureCollection, LineString, Point } from 'geojson';
import type { Visibility } from '$lib/engine/file-visibility'; import type { Visibility } from '$lib/engine/file-visibility';
import type { CategoryIntervals } from '$lib/engine/trackpoint-categories'; import type { CategoryIntervals } from '$lib/engine/trackpoint-categories';
import type { FileStructure, GlobalStatistics, SelectionPoint } from 'gpx-wasm'; import type { FileStructure, GlobalStatistics, SelectionPoint } from 'gpx-wasm';
+3 -3
View File
@@ -19,7 +19,7 @@ export class BoundsManager {
this.fitBoundsOnLoad(Array.from(newFiles.keys())); this.fitBoundsOnLoad(Array.from(newFiles.keys()));
} }
}, },
(fileId) => {}, () => {},
() => {} () => {}
); );
} }
@@ -40,7 +40,7 @@ export class BoundsManager {
} }
}); });
}, },
(fileId) => {}, () => {},
() => {} () => {}
); );
} }
@@ -51,7 +51,7 @@ export class BoundsManager {
this._files.delete(fileId); this._files.delete(fileId);
if (file.statistics.bounds) { if (file.statistics.bounds) {
let bounds = new LngLatBounds([ const bounds = new LngLatBounds([
file.statistics.bounds.west, file.statistics.bounds.west,
file.statistics.bounds.south, file.statistics.bounds.south,
file.statistics.bounds.east, file.statistics.bounds.east,
+2 -2
View File
@@ -36,10 +36,10 @@ export class MapCursor {
constructor() { constructor() {
this._states = writable(new Set()); this._states = writable(new Set());
this._states.subscribe((states) => { this._states.subscribe((states) => {
let state = Array.from(states.values()).reduce((max, value) => { const state = Array.from(states.values()).reduce((max, value) => {
return value > max ? value : max; return value > max ? value : max;
}, MapCursorState.DEFAULT); }, MapCursorState.DEFAULT);
let canvas = get(map)?.getCanvas(); const canvas = get(map)?.getCanvas();
if (canvas) { if (canvas) {
canvas.style.cursor = cursorStyles[state]; canvas.style.cursor = cursorStyles[state];
} }
+1 -1
View File
@@ -126,7 +126,7 @@ export function getArrayValidator<V>(allowed: V[]) {
export function getLayerValidator(allowed: Record<string, any>, fallback: string) { export function getLayerValidator(allowed: Record<string, any>, fallback: string) {
return (layer: string) => return (layer: string) =>
allowed.hasOwnProperty(layer) || Object.hasOwn(allowed, layer) ||
layer.startsWith('custom-') || layer.startsWith('custom-') ||
layer.startsWith('extension-') layer.startsWith('extension-')
? layer ? layer
-1
View File
@@ -10,7 +10,6 @@ import {
defaultTerrainSource, defaultTerrainSource,
overpassTree, overpassTree,
type CustomLayer, type CustomLayer,
type LayerTreeType,
} from '$lib/data/layers'; } from '$lib/data/layers';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import type { DistanceUnits, TemperatureUnits, VelocityUnits } from '$lib/units/conversions'; import type { DistanceUnits, TemperatureUnits, VelocityUnits } from '$lib/units/conversions';
+5 -1
View File
@@ -40,7 +40,11 @@ describe('getURLForLanguage', () => {
describe('cn', () => { describe('cn', () => {
it('merges class names, the last tailwind class winning', () => { it('merges class names, the last tailwind class winning', () => {
assert.equal(cn('p-2', 'p-4'), 'p-4'); assert.equal(cn('p-2', 'p-4'), 'p-4');
assert.equal(cn('text-sm', false && 'hidden', undefined, 'font-bold'), 'text-sm font-bold'); const hidden: boolean = false;
assert.equal(
cn('text-sm', hidden && 'hidden', undefined, 'font-bold'),
'text-sm font-bold'
);
assert.equal(cn(['a', { b: true, c: false }]), 'a b'); assert.equal(cn(['a', { b: true, c: false }]), 'a b');
}); });
}); });
+21 -21
View File
@@ -22,22 +22,22 @@ export function getElevation(
ELEVATION_ZOOM: number = 12, ELEVATION_ZOOM: number = 12,
tileSize = 512 tileSize = 512
): Promise<number[]> { ): Promise<number[]> {
let coordinates = points; const coordinates = points;
let bbox = new LngLatBounds(); const bbox = new LngLatBounds();
coordinates.forEach((coord) => bbox.extend(coord)); coordinates.forEach((coord) => bbox.extend(coord));
let tiles = coordinates.map((coord) => pointToTile(coord.lng, coord.lat, ELEVATION_ZOOM)); const tiles = coordinates.map((coord) => pointToTile(coord.lng, coord.lat, ELEVATION_ZOOM));
let uniqueTiles = Array.from(new Set(tiles.map((tile) => tile.join(',')))).map((tile) => const uniqueTiles = Array.from(new Set(tiles.map((tile) => tile.join(',')))).map((tile) =>
tile.split(',').map((x) => parseInt(x)) tile.split(',').map((x) => parseInt(x))
); );
let images = new Map<string, ImageData>(); const images = new Map<string, ImageData>();
const getPixelFromImageData = (imageData: ImageData, x: number, y: number): number[] => { const getPixelFromImageData = (imageData: ImageData, x: number, y: number): number[] => {
const index = (y * imageData.width + x) * 4; const index = (y * imageData.width + x) * 4;
return [imageData.data[index], imageData.data[index + 1], imageData.data[index + 2]]; return [imageData.data[index], imageData.data[index + 1], imageData.data[index + 2]];
}; };
let promises = uniqueTiles.map((tile) => const promises = uniqueTiles.map((tile) =>
fetch(`https://tiles.gpx.studio/mapterhorn/${ELEVATION_ZOOM}/${tile[0]}/${tile[1]}.webp`, { fetch(`https://tiles.gpx.studio/mapterhorn/${ELEVATION_ZOOM}/${tile[0]}/${tile[1]}.webp`, {
cache: 'force-cache', cache: 'force-cache',
}) })
@@ -71,20 +71,20 @@ export function getElevation(
return Promise.all(promises).then(() => return Promise.all(promises).then(() =>
coordinates.map((coord, index) => { coordinates.map((coord, index) => {
let tile = tiles[index]; const tile = tiles[index];
let imageData = images.get(tile.join(',')); const imageData = images.get(tile.join(','));
if (!imageData) { if (!imageData) {
return 0; return 0;
} }
let tf = pointToTileFraction(coord.lng, coord.lat, ELEVATION_ZOOM); const tf = pointToTileFraction(coord.lng, coord.lat, ELEVATION_ZOOM);
let x = tileSize * (tf[0] - tile[0]); const x = tileSize * (tf[0] - tile[0]);
let y = tileSize * (tf[1] - tile[1]); const y = tileSize * (tf[1] - tile[1]);
let _x = Math.floor(x); const _x = Math.floor(x);
let _y = Math.floor(y); const _y = Math.floor(y);
let dx = x - _x; const dx = x - _x;
let dy = y - _y; const dy = y - _y;
const p00 = getPixelFromImageData(imageData, _x, _y); const p00 = getPixelFromImageData(imageData, _x, _y);
const p01 = getPixelFromImageData(imageData, _x, _y + (_y + 1 == tileSize ? 0 : 1)); const p01 = getPixelFromImageData(imageData, _x, _y + (_y + 1 == tileSize ? 0 : 1));
@@ -95,10 +95,10 @@ export function getElevation(
_y + (_y + 1 == tileSize ? 0 : 1) _y + (_y + 1 == tileSize ? 0 : 1)
); );
let ele00 = -32768 + p00[0] * 256 + p00[1] + p00[2] / 256; const ele00 = -32768 + p00[0] * 256 + p00[1] + p00[2] / 256;
let ele01 = -32768 + p01[0] * 256 + p01[1] + p01[2] / 256; const ele01 = -32768 + p01[0] * 256 + p01[1] + p01[2] / 256;
let ele10 = -32768 + p10[0] * 256 + p10[1] + p10[2] / 256; const ele10 = -32768 + p10[0] * 256 + p10[1] + p10[2] / 256;
let ele11 = -32768 + p11[0] * 256 + p11[1] + p11[2] / 256; const ele11 = -32768 + p11[0] * 256 + p11[1] + p11[2] / 256;
return ( return (
ele00 * (1 - dx) * (1 - dy) + ele00 * (1 - dx) * (1 - dy) +
@@ -112,7 +112,7 @@ export function getElevation(
export function loadSVGIcon(map: MapLibreMap, id: string, svg: string, size: number = 100) { export function loadSVGIcon(map: MapLibreMap, id: string, svg: string, size: number = 100) {
if (!map.hasImage(id)) { if (!map.hasImage(id)) {
let icon = new Image(size, size); const icon = new Image(size, size);
icon.onload = () => { icon.onload = () => {
if (!map.hasImage(id)) { if (!map.hasImage(id)) {
map.addImage(id, icon); map.addImage(id, icon);
@@ -134,7 +134,7 @@ export function getURLForLanguage(lang: string, path: string): string {
let newPath = path.replace(base, ''); let newPath = path.replace(base, '');
let languageInPath = newPath.split('/')[1]; let languageInPath = newPath.split('/')[1];
if (!languages.hasOwnProperty(languageInPath)) { if (!Object.hasOwn(languages, languageInPath)) {
languageInPath = 'en'; languageInPath = 'en';
} }
+2 -2
View File
@@ -15,9 +15,9 @@ export async function load({ params }) {
const { language } = params; const { language } = params;
const guideTitles: Record<string, string> = {}; const guideTitles: Record<string, string> = {};
for (let guide of Object.keys(guides)) { for (const guide of Object.keys(guides)) {
guideTitles[guide] = (await getModule(language, guide)).metadata.title; guideTitles[guide] = (await getModule(language, guide)).metadata.title;
for (let subguide of guides[guide]) { for (const subguide of guides[guide]) {
guideTitles[`${guide}/${subguide}`] = ( guideTitles[`${guide}/${subguide}`] = (
await getModule(language, `${guide}/${subguide}`) await getModule(language, `${guide}/${subguide}`)
).metadata.title; ).metadata.title;
+1 -1
View File
@@ -40,7 +40,7 @@
if (page.params.language) { if (page.params.language) {
let lang = page.params.language.replace('/', ''); let lang = page.params.language.replace('/', '');
if (i18n.lang !== lang) { if (i18n.lang !== lang) {
if (languages.hasOwnProperty(lang)) { if (Object.hasOwn(languages, lang)) {
i18n.lang = lang; i18n.lang = lang;
} else if (browser) { } else if (browser) {
goto(`${base}/404`); goto(`${base}/404`);
+1 -1
View File
@@ -145,7 +145,7 @@
{elevationFill} {elevationFill}
/> />
</div> </div>
<GPXStatistics {statistics} {slicedStatistics} orientation={'horizontal'} /> <GPXStatistics {statistics} {slicedStatistics} orientation="horizontal" />
</div> </div>
</div> </div>
<div class="grid md:grid-rows-subgrid md:row-start-3 md:row-end-5 gap-4"> <div class="grid md:grid-rows-subgrid md:row-start-3 md:row-end-5 gap-4">
@@ -3,14 +3,14 @@ import { guides } from '$lib/components/docs/docs';
import type { EntryGenerator } from './$types'; import type { EntryGenerator } from './$types';
export const entries: EntryGenerator = () => { export const entries: EntryGenerator = () => {
let entries = []; const entries = [];
for (let lang of Object.keys(languages)) { for (const lang of Object.keys(languages)) {
for (let guide of Object.keys(guides)) { for (const guide of Object.keys(guides)) {
entries.push({ entries.push({
language: lang == 'en' ? '' : lang, language: lang == 'en' ? '' : lang,
guide, guide,
}); });
for (let subguide of guides[guide]) { for (const subguide of guides[guide]) {
entries.push({ entries.push({
language: lang == 'en' ? '' : lang, language: lang == 'en' ? '' : lang,
guide: `${guide}/${subguide}`, guide: `${guide}/${subguide}`,