global map cursor logic

This commit is contained in:
vcoppe
2024-06-06 11:58:50 +02:00
parent 192ae7ae0a
commit 8611c9c63d
3 changed files with 86 additions and 60 deletions

View File

@@ -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 { ListTrackSegmentItem, type ListItem, ListWaypointItem, ListWaypointsItem, ListTrackItem, ListFileItem, ListRootItem } from "$lib/components/file-list/FileList";
import type { Waypoint } from "gpx"; import type { Waypoint } from "gpx";
import { produce } from "immer"; import { produce } from "immer";
import { resetCursor, setGrabbingCursor, setPointerCursor } from "$lib/utils";
let defaultWeight = 5; let defaultWeight = 5;
let defaultOpacity = 0.6; let defaultOpacity = 0.6;
@@ -121,8 +122,8 @@ export class GPXLayer {
}); });
this.map.on('click', this.fileId, this.selectOnClickBinded); this.map.on('click', this.fileId, this.selectOnClickBinded);
this.map.on('mouseenter', this.fileId, toPointerCursor); this.map.on('mouseenter', this.fileId, setPointerCursor);
this.map.on('mouseleave', this.fileId, toDefaultCursor); this.map.on('mouseleave', this.fileId, resetCursor);
} }
if (get(directionMarkers)) { if (get(directionMarkers)) {
@@ -194,12 +195,12 @@ export class GPXLayer {
e.stopPropagation(); e.stopPropagation();
}); });
marker.on('dragstart', () => { marker.on('dragstart', () => {
this.map.getCanvas().style.cursor = 'grabbing'; setGrabbingCursor();
marker.getElement().style.cursor = 'grabbing'; marker.getElement().style.cursor = 'grabbing';
this.hideWaypointPopup(); this.hideWaypointPopup();
}); });
marker.on('dragend', (e) => { marker.on('dragend', (e) => {
this.map.getCanvas().style.cursor = ''; resetCursor();
marker.getElement().style.cursor = ''; marker.getElement().style.cursor = '';
dbUtils.applyToFile(this.fileId, (file) => { dbUtils.applyToFile(this.fileId, (file) => {
return produce(file, (draft) => { return produce(file, (draft) => {
@@ -229,8 +230,8 @@ export class GPXLayer {
remove() { remove() {
this.map.off('click', this.fileId, this.selectOnClickBinded); this.map.off('click', this.fileId, this.selectOnClickBinded);
this.map.off('mouseenter', this.fileId, toPointerCursor); this.map.off('mouseenter', this.fileId, setPointerCursor);
this.map.off('mouseleave', this.fileId, toDefaultCursor); this.map.off('mouseleave', this.fileId, resetCursor);
this.map.off('style.load', this.updateBinded); this.map.off('style.load', this.updateBinded);
if (this.map.getLayer(this.fileId + '-direction')) { if (this.map.getLayer(this.fileId + '-direction')) {
@@ -345,12 +346,4 @@ export class GPXLayer {
} }
return data; return data;
} }
} }
function toPointerCursor() {
get(map).getCanvas().style.cursor = 'pointer';
}
function toDefaultCursor() {
get(map).getCanvas().style.cursor = '';
}

View File

@@ -11,6 +11,7 @@ import { dbUtils, type GPXFileWithStatistics } from "$lib/db";
import { selection } from "$lib/components/file-list/Selection"; import { selection } from "$lib/components/file-list/Selection";
import { ListFileItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList"; import { ListFileItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList";
import { currentTool, Tool } from "$lib/stores"; import { currentTool, Tool } from "$lib/stores";
import { resetCursor, setCrosshairCursor, setGrabbingCursor } from "$lib/utils";
export class RoutingControls { export class RoutingControls {
active: boolean = false; active: boolean = false;
@@ -78,6 +79,7 @@ export class RoutingControls {
this.map.on('move', this.toggleAnchorsForZoomLevelAndBoundsBinded); this.map.on('move', this.toggleAnchorsForZoomLevelAndBoundsBinded);
this.map.on('click', this.appendAnchorBinded); this.map.on('click', this.appendAnchorBinded);
this.map.on('mousemove', this.fileId, this.showTemporaryAnchorBinded); this.map.on('mousemove', this.fileId, this.showTemporaryAnchorBinded);
setCrosshairCursor();
this.fileUnsubscribe = this.file.subscribe(this.updateControls.bind(this)); 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('click', this.appendAnchorBinded);
this.map.off('mousemove', this.fileId, this.showTemporaryAnchorBinded); this.map.off('mousemove', this.fileId, this.showTemporaryAnchorBinded);
this.map.off('mousemove', this.updateTemporaryAnchorBinded); this.map.off('mousemove', this.updateTemporaryAnchorBinded);
resetCursor();
this.fileUnsubscribe(); this.fileUnsubscribe();
} }
@@ -152,13 +155,13 @@ export class RoutingControls {
let lastDragEvent = 0; let lastDragEvent = 0;
marker.on('dragstart', (e) => { marker.on('dragstart', (e) => {
lastDragEvent = Date.now(); lastDragEvent = Date.now();
this.map.getCanvas().style.cursor = 'grabbing'; setGrabbingCursor();
element.classList.remove('cursor-pointer'); element.classList.remove('cursor-pointer');
element.classList.add('cursor-grabbing'); element.classList.add('cursor-grabbing');
}); });
marker.on('dragend', (e) => { marker.on('dragend', (e) => {
lastDragEvent = Date.now(); lastDragEvent = Date.now();
this.map.getCanvas().style.cursor = ''; resetCursor();
element.classList.remove('cursor-grabbing'); element.classList.remove('cursor-grabbing');
element.classList.add('cursor-pointer'); element.classList.add('cursor-pointer');
this.moveAnchor(anchor); this.moveAnchor(anchor);

View File

@@ -2,61 +2,91 @@ import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { cubicOut } from "svelte/easing"; import { cubicOut } from "svelte/easing";
import type { TransitionConfig } from "svelte/transition"; import type { TransitionConfig } from "svelte/transition";
import { get } from "svelte/store";
import { map } from "./stores";
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));
} }
type FlyAndScaleParams = { type FlyAndScaleParams = {
y?: number; y?: number;
x?: number; x?: number;
start?: number; start?: number;
duration?: number; duration?: number;
}; };
export const flyAndScale = ( export const flyAndScale = (
node: Element, node: Element,
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 } params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
): TransitionConfig => { ): TransitionConfig => {
const style = getComputedStyle(node); const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform; const transform = style.transform === "none" ? "" : style.transform;
const scaleConversion = ( const scaleConversion = (
valueA: number, valueA: number,
scaleA: [number, number], scaleA: [number, number],
scaleB: [number, number] scaleB: [number, number]
) => { ) => {
const [minA, maxA] = scaleA; const [minA, maxA] = scaleA;
const [minB, maxB] = scaleB; const [minB, maxB] = scaleB;
const percentage = (valueA - minA) / (maxA - minA); const percentage = (valueA - minA) / (maxA - minA);
const valueB = percentage * (maxB - minB) + minB; const valueB = percentage * (maxB - minB) + minB;
return valueB; return valueB;
}; };
const styleToString = ( const styleToString = (
style: Record<string, number | string | undefined> style: Record<string, number | string | undefined>
): string => { ): string => {
return Object.keys(style).reduce((str, key) => { return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined) return str; if (style[key] === undefined) return str;
return str + `${key}:${style[key]};`; return str + `${key}:${style[key]};`;
}, ""); }, "");
}; };
return { return {
duration: params.duration ?? 200, duration: params.duration ?? 200,
delay: 0, delay: 0,
css: (t) => { css: (t) => {
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]); const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]); const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]); const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
return styleToString({ return styleToString({
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
opacity: t opacity: t
}); });
}, },
easing: cubicOut 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');
}