mihirmithani
Add Kernel Convolution Visualizer - Phase 1 complete
80bcac8
Raw History Blame Contribute Delete
3.12 kB
'use client'
import { useRef, useEffect, useCallback } from 'react'
import { useAppStore } from '@/store'
import { cn } from '@/utils/helpers'
interface ImageCanvasProps {
imageData: ImageData | null
title: string
width?: number
height?: number
className?: string
onWheel?: (e: React.WheelEvent) => void
onMouseDown?: (e: React.MouseEvent) => void
onMouseMove?: (e: React.MouseEvent) => void
onMouseUp?: (e: React.MouseEvent) => void
}
export function ImageCanvas({
imageData,
title,
width = 400,
height = 300,
className,
onWheel,
onMouseDown,
onMouseMove,
onMouseUp,
}: ImageCanvasProps) {
const canvasRef = useRef<HTMLCanvasElement>(null)
const { settings } = useAppStore()
const drawCanvas = useCallback(() => {
const canvas = canvasRef.current
const ctx = canvas?.getContext('2d', { willReadFrequently: true })
if (!canvas || !ctx || !imageData) return
const { zoomLevel, panOffset } = settings
const displayWidth = Math.round(imageData.width * zoomLevel)
const displayHeight = Math.round(imageData.height * zoomLevel)
canvas.width = displayWidth
canvas.height = displayHeight
ctx.clearRect(0, 0, displayWidth, displayHeight)
ctx.imageSmoothingEnabled = zoomLevel < 2
const tempCanvas = document.createElement('canvas')
tempCanvas.width = imageData.width
tempCanvas.height = imageData.height
const tempCtx = tempCanvas.getContext('2d')
if (tempCtx) {
tempCtx.putImageData(imageData, 0, 0)
ctx.drawImage(
tempCanvas,
0,
0,
imageData.width,
imageData.height,
panOffset.x,
panOffset.y,
displayWidth,
displayHeight
)
}
// Draw grid at high zoom
if (zoomLevel >= 4) {
drawGrid(ctx, imageData.width, imageData.height, zoomLevel, panOffset)
}
}, [imageData, settings.zoomLevel, settings.panOffset])
useEffect(() => {
drawCanvas()
}, [drawCanvas])
return (
<div className={cn('relative bg-gray-100 dark:bg-gray-900 rounded-lg overflow-hidden', className)}>
<div className="absolute top-2 left-2 z-10 px-2 py-1 bg-black/50 text-white text-xs rounded">
{title}
</div>
<canvas
ref={canvasRef}
width={width}
height={height}
className="block cursor-grab active:cursor-grabbing"
style={{ touchAction: 'none' }}
onWheel={onWheel}
onMouseDown={onMouseDown}
onMouseMove={onMouseMove}
onMouseUp={onMouseUp}
/>
</div>
)
}
function drawGrid(
ctx: CanvasRenderingContext2D,
imgWidth: number,
imgHeight: number,
zoom: number,
pan: { x: number; y: number }
) {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'
ctx.lineWidth = 0.5
for (let x = 0; x <= imgWidth; x++) {
const px = pan.x + x * zoom
ctx.beginPath()
ctx.moveTo(px, 0)
ctx.lineTo(px, imgHeight * zoom)
ctx.stroke()
}
for (let y = 0; y <= imgHeight; y++) {
const py = pan.y + y * zoom
ctx.beginPath()
ctx.moveTo(0, py)
ctx.lineTo(imgWidth * zoom, py)
ctx.stroke()
}
}