diff --git a/website/src/lib/components/gpx-layer/GPXLayer.ts b/website/src/lib/components/gpx-layer/GPXLayer.ts index c7e1996d..0cad0cc0 100644 --- a/website/src/lib/components/gpx-layer/GPXLayer.ts +++ b/website/src/lib/components/gpx-layer/GPXLayer.ts @@ -7,6 +7,7 @@ import { addSelectItem, selectItem, selection } from "$lib/components/file-list/ import { ListTrackSegmentItem, type ListItem, ListWaypointItem, ListWaypointsItem, ListTrackItem, ListFileItem, ListRootItem } from "$lib/components/file-list/FileList"; import type { Waypoint } from "gpx"; import { produce } from "immer"; +import { resetCursor, setGrabbingCursor, setPointerCursor } from "$lib/utils"; let defaultWeight = 5; let defaultOpacity = 0.6; @@ -121,8 +122,8 @@ export class GPXLayer { }); this.map.on('click', this.fileId, this.selectOnClickBinded); - this.map.on('mouseenter', this.fileId, toPointerCursor); - this.map.on('mouseleave', this.fileId, toDefaultCursor); + this.map.on('mouseenter', this.fileId, setPointerCursor); + this.map.on('mouseleave', this.fileId, resetCursor); } if (get(directionMarkers)) { @@ -194,12 +195,12 @@ export class GPXLayer { e.stopPropagation(); }); marker.on('dragstart', () => { - this.map.getCanvas().style.cursor = 'grabbing'; + setGrabbingCursor(); marker.getElement().style.cursor = 'grabbing'; this.hideWaypointPopup(); }); marker.on('dragend', (e) => { - this.map.getCanvas().style.cursor = ''; + resetCursor(); marker.getElement().style.cursor = ''; dbUtils.applyToFile(this.fileId, (file) => { return produce(file, (draft) => { @@ -229,8 +230,8 @@ export class GPXLayer { remove() { this.map.off('click', this.fileId, this.selectOnClickBinded); - this.map.off('mouseenter', this.fileId, toPointerCursor); - this.map.off('mouseleave', this.fileId, toDefaultCursor); + this.map.off('mouseenter', this.fileId, setPointerCursor); + this.map.off('mouseleave', this.fileId, resetCursor); this.map.off('style.load', this.updateBinded); if (this.map.getLayer(this.fileId + '-direction')) { @@ -345,12 +346,4 @@ export class GPXLayer { } return data; } -} - -function toPointerCursor() { - get(map).getCanvas().style.cursor = 'pointer'; -} - -function toDefaultCursor() { - get(map).getCanvas().style.cursor = ''; -} +} \ No newline at end of file diff --git a/website/src/lib/components/toolbar/tools/routing/RoutingControls.ts b/website/src/lib/components/toolbar/tools/routing/RoutingControls.ts index 364f1396..b3c87ed2 100644 --- a/website/src/lib/components/toolbar/tools/routing/RoutingControls.ts +++ b/website/src/lib/components/toolbar/tools/routing/RoutingControls.ts @@ -11,6 +11,7 @@ import { dbUtils, type GPXFileWithStatistics } from "$lib/db"; import { selection } from "$lib/components/file-list/Selection"; import { ListFileItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList"; import { currentTool, Tool } from "$lib/stores"; +import { resetCursor, setCrosshairCursor, setGrabbingCursor } from "$lib/utils"; export class RoutingControls { active: boolean = false; @@ -78,6 +79,7 @@ export class RoutingControls { this.map.on('move', this.toggleAnchorsForZoomLevelAndBoundsBinded); this.map.on('click', this.appendAnchorBinded); this.map.on('mousemove', this.fileId, this.showTemporaryAnchorBinded); + setCrosshairCursor(); this.fileUnsubscribe = this.file.subscribe(this.updateControls.bind(this)); } @@ -126,6 +128,7 @@ export class RoutingControls { this.map.off('click', this.appendAnchorBinded); this.map.off('mousemove', this.fileId, this.showTemporaryAnchorBinded); this.map.off('mousemove', this.updateTemporaryAnchorBinded); + resetCursor(); this.fileUnsubscribe(); } @@ -152,13 +155,13 @@ export class RoutingControls { let lastDragEvent = 0; marker.on('dragstart', (e) => { lastDragEvent = Date.now(); - this.map.getCanvas().style.cursor = 'grabbing'; + setGrabbingCursor(); element.classList.remove('cursor-pointer'); element.classList.add('cursor-grabbing'); }); marker.on('dragend', (e) => { lastDragEvent = Date.now(); - this.map.getCanvas().style.cursor = ''; + resetCursor(); element.classList.remove('cursor-grabbing'); element.classList.add('cursor-pointer'); this.moveAnchor(anchor); diff --git a/website/src/lib/utils.ts b/website/src/lib/utils.ts index 88712453..89bd6e29 100644 --- a/website/src/lib/utils.ts +++ b/website/src/lib/utils.ts @@ -2,61 +2,91 @@ import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; import { cubicOut } from "svelte/easing"; import type { TransitionConfig } from "svelte/transition"; +import { get } from "svelte/store"; +import { map } from "./stores"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); + return twMerge(clsx(inputs)); } type FlyAndScaleParams = { - y?: number; - x?: number; - start?: number; - duration?: number; + y?: number; + x?: number; + start?: number; + duration?: number; }; export const flyAndScale = ( - node: Element, - params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 } + node: Element, + params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 } ): TransitionConfig => { - const style = getComputedStyle(node); - const transform = style.transform === "none" ? "" : style.transform; + const style = getComputedStyle(node); + const transform = style.transform === "none" ? "" : style.transform; - const scaleConversion = ( - valueA: number, - scaleA: [number, number], - scaleB: [number, number] - ) => { - const [minA, maxA] = scaleA; - const [minB, maxB] = scaleB; + const scaleConversion = ( + valueA: number, + scaleA: [number, number], + scaleB: [number, number] + ) => { + const [minA, maxA] = scaleA; + const [minB, maxB] = scaleB; - const percentage = (valueA - minA) / (maxA - minA); - const valueB = percentage * (maxB - minB) + minB; + const percentage = (valueA - minA) / (maxA - minA); + const valueB = percentage * (maxB - minB) + minB; - return valueB; - }; + return valueB; + }; - const styleToString = ( - style: Record - ): string => { - return Object.keys(style).reduce((str, key) => { - if (style[key] === undefined) return str; - return str + `${key}:${style[key]};`; - }, ""); - }; + const styleToString = ( + style: Record + ): string => { + return Object.keys(style).reduce((str, key) => { + if (style[key] === undefined) return str; + return str + `${key}:${style[key]};`; + }, ""); + }; - return { - duration: params.duration ?? 200, - delay: 0, - css: (t) => { - const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]); - const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]); - const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]); + return { + duration: params.duration ?? 200, + delay: 0, + css: (t) => { + const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]); + const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]); + const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]); - return styleToString({ - transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, - opacity: t - }); - }, - easing: cubicOut - }; -}; \ No newline at end of file + return styleToString({ + transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, + opacity: t + }); + }, + easing: cubicOut + }; +}; + +let previousCursors: string[] = []; +export function setCursor(cursor: string) { + let m = get(map); + if (m) { + previousCursors.push(m.getCanvas().style.cursor); + m.getCanvas().style.cursor = cursor; + } +} + +export function resetCursor() { + let m = get(map); + if (m) { + m.getCanvas().style.cursor = previousCursors.pop() ?? ''; + } +} + +export function setPointerCursor() { + setCursor('pointer'); +} + +export function setGrabbingCursor() { + setCursor('grabbing'); +} + +export function setCrosshairCursor() { + setCursor('crosshair'); +} \ No newline at end of file