remember pinch to zoom state when re-opening board

This commit is contained in:
marlon-erler
2026-09-24 16:15:35 +02:00
parent 8c699575cf
commit 49da609b5a
3 changed files with 37 additions and 35 deletions
+33 -34
View File
@@ -227,16 +227,18 @@ export function localeCompare(a: string, b: string): number {
} }
// ui // ui
export function implementPinchZoom(canvas: HTMLElement) { export interface PinchToZoomData {
zoom: number;
x: number;
y: number;
}
export function implementPinchZoom(canvas: HTMLElement, data: React.State<PinchToZoomData>) {
let pinching = false; let pinching = false;
let dragging = false; let dragging = false;
let lastElement: HTMLElement | undefined = undefined; let lastElement: HTMLElement | undefined = undefined;
let initialDistance: number, let initialDistance: number,
currentZoom: number,
initialZoom: number, initialZoom: number,
currentX: number,
currentY: number,
initialX: number, initialX: number,
initialY: number, initialY: number,
initialTouchX: number, initialTouchX: number,
@@ -245,11 +247,8 @@ export function implementPinchZoom(canvas: HTMLElement) {
function reset() { function reset() {
initialDistance = 0; initialDistance = 0;
currentZoom = 1;
initialZoom = 1; initialZoom = 1;
currentX = 0;
currentY = 0;
initialX = 0; initialX = 0;
initialY = 0; initialY = 0;
initialTouchX = 0; initialTouchX = 0;
@@ -272,41 +271,41 @@ export function implementPinchZoom(canvas: HTMLElement) {
const midpoint = (e: TouchEvent, direction: "x" | "y") => const midpoint = (e: TouchEvent, direction: "x" | "y") =>
(point(e, direction, 0) + point(e, direction, 1)) / 2; (point(e, direction, 0) + point(e, direction, 1)) / 2;
function apply(factor: number, _offset?: [number, number]) { function apply(zoom: number, _offset?: [number, number]) {
if (zoom < MIN) return apply(MIN, _offset);
if (zoom > MAX) return apply(5, _offset);
let {x, y} = data.value;
if (_offset) [x, y] = _offset;
data.value = {
zoom, x, y
}
}
data.subscribe((data) => {
const el = element(); const el = element();
if (!el) return; if (!el) return;
if (factor < MIN) return apply(MIN, _offset); el.style.transform = `scale(${data.zoom.toString()}) translate(${data.x}px, ${data.y}px)`;
if (factor > MAX) return apply(5, _offset); })
let x: number, y: number;
if (_offset) [x, y] = _offset;
else {
x = currentX;
y = currentY;
}
el.style.transform = `scale(${factor.toString()}) translate(${x}px, ${y}px)`;
currentX = x;
currentY = y;
currentZoom = factor;
}
canvas.addEventListener("wheel", (event: WheelEvent) => { canvas.addEventListener("wheel", (event: WheelEvent) => {
event.preventDefault(); event.preventDefault();
initialZoom = currentZoom; initialZoom = data.value.zoom;
initialX = currentX; initialX = data.value.x;
initialY = currentY; initialY = data.value.y;
apply(currentZoom - event.deltaY * 0.005); apply(data.value.zoom - event.deltaY * 0.005);
}); });
canvas.addEventListener("scroll", (event: Event) => { canvas.addEventListener("scroll", (event: Event) => {
event.preventDefault(); event.preventDefault();
}); });
canvas.addEventListener("mousedown", (event: MouseEvent) => { canvas.addEventListener("mousedown", (event: MouseEvent) => {
initialZoom = currentZoom; initialZoom = data.value.zoom;
initialX = currentX; initialX = data.value.x;
initialY = currentY; initialY = data.value.y;
initialTouchX = event.clientX; initialTouchX = event.clientX;
initialTouchY = event.clientY; initialTouchY = event.clientY;
dragging = true; dragging = true;
@@ -316,7 +315,7 @@ export function implementPinchZoom(canvas: HTMLElement) {
}) })
canvas.addEventListener("mousemove", (event: MouseEvent) => { canvas.addEventListener("mousemove", (event: MouseEvent) => {
if (!dragging) return; if (!dragging) return;
apply(currentZoom, [ apply(data.value.zoom, [
initialX + initialX +
(event.clientX - initialTouchX) / initialZoom, (event.clientX - initialTouchX) / initialZoom,
initialY + initialY +
@@ -332,9 +331,9 @@ export function implementPinchZoom(canvas: HTMLElement) {
if (lastElement != undefined && lastElement != el) reset(); if (lastElement != undefined && lastElement != el) reset();
lastElement = el; lastElement = el;
initialZoom = currentZoom; initialZoom = data.value.zoom;
initialX = currentX; initialX = data.value.x;
initialY = currentY; initialY = data.value.y;
if (event.touches.length != 2) { if (event.touches.length != 2) {
pinching = false; pinching = false;
@@ -350,7 +349,7 @@ export function implementPinchZoom(canvas: HTMLElement) {
}); });
canvas.addEventListener("touchmove", (event: TouchEvent) => { canvas.addEventListener("touchmove", (event: TouchEvent) => {
if (!pinching) { if (!pinching) {
apply(currentZoom, [ apply(data.value.zoom, [
initialX + initialX +
(event.touches[0].clientX - initialTouchX) / initialZoom, (event.touches[0].clientX - initialTouchX) / initialZoom,
initialY + initialY +
+1 -1
View File
@@ -48,7 +48,7 @@ export function BoardPage(
const wrapper = ( const wrapper = (
<div class="content main-content" children:set={pages}></div> <div class="content main-content" children:set={pages}></div>
); );
Utility.implementPinchZoom(wrapper); Utility.implementPinchZoom(wrapper, boardViewModel.pinchToZoomData);
// task modal // task modal
const taskSettingsModal = React.createProxyState( const taskSettingsModal = React.createProxyState(
+3
View File
@@ -11,6 +11,7 @@ import BoardsAndTasksModel, {
BoardInfoFileContent, BoardInfoFileContent,
TaskFileContent, TaskFileContent,
} from "../../Model/Files/boardsAndTasksModel"; } from "../../Model/Files/boardsAndTasksModel";
import {PinchToZoomData} from "../../Model/Utility/utility";
export default class BoardViewModel extends TaskContainingPageViewModel { export default class BoardViewModel extends TaskContainingPageViewModel {
// state // state
@@ -33,6 +34,8 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
new React.ListState(); new React.ListState();
isFilterActive: React.State<boolean>; isFilterActive: React.State<boolean>;
pinchToZoomData: React.State<PinchToZoomData> = new React.State({zoom: 1, x: 0, y: 0});
// paths // paths
getBasePath = (): string[] => { getBasePath = (): string[] => {
return [ return [