feat: add zoom and pan functionality with wheel listener in SimulatorCanvas

pull/10/head
David Montero Crespo 2026-03-07 02:08:20 -03:00
parent 3ace72d0f8
commit 2744b398e3
1 changed files with 23 additions and 1 deletions

View File

@ -96,6 +96,29 @@ export const SimulatorCanvas = () => {
initSimulator(); initSimulator();
}, [initSimulator]); }, [initSimulator]);
// Attach wheel listener as non-passive so preventDefault() works
useEffect(() => {
const el = canvasRef.current;
if (!el) return;
const onWheel = (e: WheelEvent) => {
e.preventDefault();
const rect = el.getBoundingClientRect();
const factor = e.deltaY < 0 ? 1.1 : 0.9;
const newZoom = Math.min(5, Math.max(0.1, zoomRef.current * factor));
const mx = e.clientX - rect.left;
const my = e.clientY - rect.top;
const worldX = (mx - panRef.current.x) / zoomRef.current;
const worldY = (my - panRef.current.y) / zoomRef.current;
const newPan = { x: mx - worldX * newZoom, y: my - worldY * newZoom };
zoomRef.current = newZoom;
panRef.current = newPan;
setZoom(newZoom);
setPan(newPan);
};
el.addEventListener('wheel', onWheel, { passive: false });
return () => el.removeEventListener('wheel', onWheel);
}, []);
// Recalculate wire positions after web components initialize their pinInfo // Recalculate wire positions after web components initialize their pinInfo
useEffect(() => { useEffect(() => {
const timer = setTimeout(() => { const timer = setTimeout(() => {
@ -536,7 +559,6 @@ export const SimulatorCanvas = () => {
onMouseMove={handleCanvasMouseMove} onMouseMove={handleCanvasMouseMove}
onMouseUp={handleCanvasMouseUp} onMouseUp={handleCanvasMouseUp}
onMouseLeave={() => { isPanningRef.current = false; setPan({ ...panRef.current }); setDraggedComponentId(null); }} onMouseLeave={() => { isPanningRef.current = false; setPan({ ...panRef.current }); setDraggedComponentId(null); }}
onWheel={handleWheel}
onContextMenu={(e) => e.preventDefault()} onContextMenu={(e) => e.preventDefault()}
onClick={() => setSelectedComponentId(null)} onClick={() => setSelectedComponentId(null)}
style={{ cursor: isPanningRef.current ? 'grabbing' : wireInProgress ? 'crosshair' : 'default' }} style={{ cursor: isPanningRef.current ? 'grabbing' : wireInProgress ? 'crosshair' : 'default' }}