This commit is contained in:
marlon-erler
2026-09-24 15:47:15 +02:00
parent ffb56b8843
commit f3896c497b
+122 -90
View File
@@ -229,6 +229,8 @@ export function localeCompare(a: string, b: string): number {
// ui // ui
export function implementPinchZoom(canvas: HTMLElement) { export function implementPinchZoom(canvas: HTMLElement) {
let pinching = false; let pinching = false;
let dragging = false;
let scrolling = false;
let lastElement: HTMLElement | undefined = undefined; let lastElement: HTMLElement | undefined = undefined;
let initialDistance: number, let initialDistance: number,
@@ -292,68 +294,98 @@ export function implementPinchZoom(canvas: HTMLElement) {
canvas.addEventListener("wheel", (event: WheelEvent) => { canvas.addEventListener("wheel", (event: WheelEvent) => {
event.preventDefault(); event.preventDefault();
if (!scrolling) {
initialZoom = currentZoom; initialZoom = currentZoom;
initialX = currentX; initialX = currentX;
initialY = currentY; initialY = currentY;
scrolling = true
}
if (!event.shiftKey) { const canvasWidth = canvas.offsetWidth;
apply(currentZoom, [ const canvasHeight = canvas.offsetHeight;
currentX - event.deltaX, const initialWidth = canvasWidth * initialZoom;
currentY - event.deltaY, const initialHeight = canvasHeight * initialZoom;
]); const currentWidth = canvasWidth * currentZoom;
return; const currentHeight = canvasHeight * currentZoom;
}
apply(currentZoom - event.deltaY * 0.01); const differenceWidth = currentWidth - initialWidth;
const differenceHeight = currentHeight - initialHeight;
apply(currentZoom - event.deltaY * 0.005, [initialX - differenceWidth, initialY - differenceHeight]);
}); });
canvas.addEventListener("scrollend", () => {
scrolling = false;
})
canvas.addEventListener("scroll", (event: Event) => { canvas.addEventListener("scroll", (event: Event) => {
event.preventDefault(); event.preventDefault();
}); });
canvas.addEventListener("mousedown", (event: MouseEvent) => {
initialZoom = currentZoom;
initialX = currentX;
initialY = currentY;
initialTouchX = event.clientX;
initialTouchY = event.clientY;
dragging = true;
})
canvas.addEventListener("mouseup", () => {
dragging = false;
})
canvas.addEventListener("mousemove", (event: MouseEvent) => {
if (!dragging) return;
apply(currentZoom, [
initialX +
(event.clientX - initialTouchX) / initialZoom,
initialY +
(event.clientY - initialTouchY) / initialZoom,
]);
})
canvas.addEventListener("touchstart", (event: TouchEvent) => { canvas.addEventListener("touchstart", (event: TouchEvent) => {
(document.activeElement as HTMLElement).blur(); (document.activeElement as HTMLElement)?.blur();
const el = element(); const el = element();
if (!el) return; if (!el) return;
if (lastElement != undefined && lastElement != el) reset(); if (lastElement != undefined && lastElement != el) reset();
lastElement = el; lastElement = el;
initialZoom = currentZoom; initialZoom = currentZoom;
initialX = currentX; initialX = currentX;
initialY = currentY; initialY = currentY;
if (event.touches.length != 2) { if (event.touches.length != 2) {
pinching = false; pinching = false;
initialTouchX = event.touches[0].clientX; initialTouchX = event.touches[0].clientX;
initialTouchY = event.touches[0].clientY; initialTouchY = event.touches[0].clientY;
return; return;
} }
pinching = true; pinching = true;
initialDistance = distance(event); initialDistance = distance(event);
initialTouchX = midpoint(event, "x"); initialTouchX = midpoint(event, "x");
initialTouchY = midpoint(event, "y"); initialTouchY = midpoint(event, "y");
}); });
canvas.addEventListener("touchmove", (event: TouchEvent) => { canvas.addEventListener("touchmove", (event: TouchEvent) => {
if (!pinching) { if (!pinching) {
apply(currentZoom, [ apply(currentZoom, [
initialX + initialX +
(event.touches[0].clientX - initialTouchX) / initialZoom, (event.touches[0].clientX - initialTouchX) / initialZoom,
initialY + initialY +
(event.touches[0].clientY - initialTouchY) / initialZoom, (event.touches[0].clientY - initialTouchY) / initialZoom,
]); ]);
return; return;
} }
if (event.touches.length < 2) return; if (event.touches.length < 2) return;
event.preventDefault(); event.preventDefault();
const currentDistance = distance(event); const currentDistance = distance(event);
const midX = midpoint(event, "x"); const midX = midpoint(event, "x");
const midY = midpoint(event, "y"); const midY = midpoint(event, "y");
const ratio = currentDistance / initialDistance; const ratio = currentDistance / initialDistance;
const difference = currentDistance - initialDistance; const difference = currentDistance - initialDistance;
apply(initialZoom * ratio, [ apply(initialZoom * ratio, [
initialX + (midX - difference - initialTouchX) / initialZoom, initialX + (midX - difference - initialTouchX) / initialZoom,
initialY + (midY - difference - initialTouchY) / initialZoom, initialY + (midY - difference - initialTouchY) / initialZoom,
]); ]);
}); });
} }
@@ -366,12 +398,12 @@ export function collectObjectValuesForKey<T>(
const values: Set<string> = new Set(); const values: Set<string> = new Set();
for (const object of objects) { for (const object of objects) {
const stringEntryObject: StringEntryObject = converter(object); const stringEntryObject: StringEntryObject = converter(object);
const stringEntryObjectValue: Stringifiable | undefined = const stringEntryObjectValue: Stringifiable | undefined =
stringEntryObject[key]; stringEntryObject[key];
if (stringEntryObjectValue == undefined) continue; if (stringEntryObjectValue == undefined) continue;
values.add(stringEntryObjectValue.toString()); values.add(stringEntryObjectValue.toString());
} }
return [...values.values()]; return [...values.values()];
@@ -384,50 +416,50 @@ export function checkDoesObjectMatchReference(
explicitEmptyValue: boolean = false, explicitEmptyValue: boolean = false,
): boolean { ): boolean {
reference_entry_loop: for (const referenceEntry of Object.entries( reference_entry_loop: for (const referenceEntry of Object.entries(
reference, reference,
)) { )) {
const [referenceKey, referenceValue] = referenceEntry; const [referenceKey, referenceValue] = referenceEntry;
const stringEntryObjectValue: Stringifiable | undefined = const stringEntryObjectValue: Stringifiable | undefined =
stringEntryObject[referenceKey]; stringEntryObject[referenceKey];
if (referenceValue == undefined) return false; if (referenceValue == undefined) return false;
if (referenceValue[0] == "-") { if (referenceValue[0] == "-") {
const strippedReferenceValue: string = referenceValue const strippedReferenceValue: string = referenceValue
.toString() .toString()
.substring(1); .substring(1);
// property may not exist // property may not exist
if ( if (
strippedReferenceValue == "" && strippedReferenceValue == "" &&
stringEntryObjectValue != undefined && stringEntryObjectValue != undefined &&
stringEntryObjectValue != "" stringEntryObjectValue != ""
) { ) {
return false; return false;
} }
// property may not match // property may not match
if (stringEntryObjectValue == strippedReferenceValue) { if (stringEntryObjectValue == strippedReferenceValue) {
return false; return false;
} }
} else { } else {
if (explicitEmptyValue == false) { if (explicitEmptyValue == false) {
// property must exist but be anything // property must exist but be anything
if ( if (
referenceValue == "" && referenceValue == "" &&
(stringEntryObjectValue == undefined || (stringEntryObjectValue == undefined ||
stringEntryObjectValue == "") stringEntryObjectValue == "")
) { ) {
return false; return false;
} else if (referenceValue == "") { } else if (referenceValue == "") {
continue reference_entry_loop; continue reference_entry_loop;
} }
} }
// property must match // property must match
if (stringEntryObjectValue != referenceValue) { if (stringEntryObjectValue != referenceValue) {
return false; return false;
} }
} }
} }
return true; return true;
} }