Add mouse wheel zoom to pattern preview

This commit is contained in:
wuyanwanwu
2026-08-14 02:10:34 +08:00
parent d53f8f4585
commit 4f8d46a523
12 changed files with 69 additions and 14 deletions
+55
View File
@@ -700,6 +700,14 @@ export default function Home() {
const cropDialogCanvasRef = useRef<HTMLCanvasElement | null>(null);
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const patternStageRef = useRef<HTMLDivElement | null>(null);
const zoomRef = useRef(zoom);
const pendingWheelZoomRef = useRef<{
stage: HTMLDivElement;
cursorX: number;
cursorY: number;
canvasX: number;
canvasY: number;
} | null>(null);
const cropDialogStageRef = useRef<HTMLDivElement | null>(null);
const cropSelectionDragRef = useRef<{ pointerId: number; startX: number; startY: number } | null>(null);
const patternDragRef = useRef<{
@@ -959,6 +967,52 @@ export default function Home() {
}
}, [pixels, gridWidth, gridHeight, zoom, selectedCodes, onlySelected, showGrid, showCodes]);
useEffect(() => {
zoomRef.current = zoom;
const pending = pendingWheelZoomRef.current;
if (!pending) return;
pendingWheelZoomRef.current = null;
const frame = window.requestAnimationFrame(() => {
const { stage } = pending;
const canvas = canvasRef.current;
if (!canvas) return;
const stageRect = stage.getBoundingClientRect();
const canvasRect = canvas.getBoundingClientRect();
const anchorX = canvasRect.left + canvasRect.width * pending.canvasX;
const anchorY = canvasRect.top + canvasRect.height * pending.canvasY;
stage.scrollLeft += anchorX - (stageRect.left + pending.cursorX);
stage.scrollTop += anchorY - (stageRect.top + pending.cursorY);
});
return () => window.cancelAnimationFrame(frame);
}, [zoom]);
useEffect(() => {
const stage = patternStageRef.current;
if (!stage) return;
const handleWheel = (event: WheelEvent) => {
if (pixels.length === 0 || event.deltaY === 0) return;
event.preventDefault();
const currentZoom = zoomRef.current;
const nextZoom = Math.max(3, Math.min(42, currentZoom + (event.deltaY < 0 ? 1 : -1)));
if (nextZoom === currentZoom) return;
const rect = stage.getBoundingClientRect();
const canvasRect = canvasRef.current?.getBoundingClientRect();
const cursorX = event.clientX - rect.left;
const cursorY = event.clientY - rect.top;
pendingWheelZoomRef.current = {
stage,
cursorX,
cursorY,
canvasX: canvasRect ? (event.clientX - canvasRect.left) / Math.max(1, canvasRect.width) : 0.5,
canvasY: canvasRect ? (event.clientY - canvasRect.top) / Math.max(1, canvasRect.height) : 0.5,
};
zoomRef.current = nextZoom;
setZoom(nextZoom);
};
stage.addEventListener("wheel", handleWheel, { passive: false });
return () => stage.removeEventListener("wheel", handleWheel);
}, [pixels.length]);
const handleUpload = (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
@@ -1274,6 +1328,7 @@ export default function Home() {
<div
className="canvas-stage"
ref={patternStageRef}
title="鼠标位于预览区时,可滚动滚轮缩放图纸"
>
<div className="canvas-wrap">
<canvas