import { useCallback, useRef, useEffect } from 'react' import { useAppStore } from '@/store' export function useCanvas() { const canvasRef = useRef(null) const contextRef = useRef(null) useEffect(() => { if (canvasRef.current) { contextRef.current = canvasRef.current.getContext('2d', { willReadFrequently: true }) } }, []) const drawImage = useCallback((imageData: ImageData) => { const ctx = contextRef.current const canvas = canvasRef.current if (!ctx || !canvas) return canvas.width = imageData.width canvas.height = imageData.height ctx.putImageData(imageData, 0, 0) }, []) const drawImageScaled = useCallback( (imageData: ImageData, scale: number, offsetX: number, offsetY: number) => { const ctx = contextRef.current const canvas = canvasRef.current if (!ctx || !canvas) return const displayWidth = Math.round(imageData.width * scale) const displayHeight = Math.round(imageData.height * scale) canvas.width = displayWidth canvas.height = displayHeight ctx.imageSmoothingEnabled = false ctx.drawImage( createImageBitmapFromImageData(imageData), 0, 0, imageData.width, imageData.height, offsetX, offsetY, displayWidth, displayHeight ) }, [] ) const clear = useCallback(() => { const ctx = contextRef.current const canvas = canvasRef.current if (!ctx || !canvas) return ctx.clearRect(0, 0, canvas.width, canvas.height) }, []) const getCanvas = useCallback(() => canvasRef.current, []) const getContext = useCallback(() => contextRef.current, []) return { canvasRef, drawImage, drawImageScaled, clear, getCanvas, getContext, } } function createImageBitmapFromImageData(imageData: ImageData): ImageBitmap { const canvas = document.createElement('canvas') canvas.width = imageData.width canvas.height = imageData.height const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Failed to create canvas context') ctx.putImageData(imageData, 0, 0) // Note: createImageBitmap is async, this is a synchronous fallback return canvas as unknown as ImageBitmap } export function useZoomPan() { const { settings, setZoomLevel, setPanOffset } = useAppStore() const zoomRef = useRef(settings.zoomLevel) const panRef = useRef(settings.panOffset) useEffect(() => { zoomRef.current = settings.zoomLevel panRef.current = settings.panOffset }, [settings.zoomLevel, settings.panOffset]) const zoomIn = useCallback(() => { const newZoom = Math.min(zoomRef.current * 1.2, 20) setZoomLevel(newZoom) }, [setZoomLevel]) const zoomOut = useCallback(() => { const newZoom = Math.max(zoomRef.current / 1.2, 0.1) setZoomLevel(newZoom) }, [setZoomLevel]) const resetZoom = useCallback(() => { setZoomLevel(1) setPanOffset({ x: 0, y: 0 }) }, [setZoomLevel, setPanOffset]) const setZoom = useCallback( (zoom: number) => { setZoomLevel(Math.max(0.1, Math.min(20, zoom))) }, [setZoomLevel] ) const pan = useCallback( (deltaX: number, deltaY: number) => { const newPan = { x: panRef.current.x + deltaX, y: panRef.current.y + deltaY, } setPanOffset(newPan) }, [setPanOffset] ) const panTo = useCallback( (x: number, y: number) => { setPanOffset({ x, y }) }, [setPanOffset] ) return { zoom: settings.zoomLevel, panOffset: settings.panOffset, zoomIn, zoomOut, resetZoom, setZoom, pan, panTo, } }