mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-11-01 12:17:18 +00:00
lint fixes
This commit is contained in:
1 parent
f5a2db0565
commit
6956c19410
44 files changed
+223
-224
No files matched your search
@@ -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(),
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -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
@@ -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}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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,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,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';
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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
@@ -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';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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`);
|
||||||
|
|||||||
@@ -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}`,
|
||||||
|
|||||||
Reference in new issue
Block a user