/ proof-of-concept / phase-perception
Sign in
proof-of-concept / phase-perception
phase-perception / src / hooks / useCanvas.ts
34 lines · 1.1 KBBlameHistoryRaw
1import { useEffect, useRef } from 'react'
3export type DrawFn = (ctx: CanvasRenderingContext2D, width: number, height: number) => void
5/**
6 * Returns a ref for a <canvas>. The draw callback runs whenever it changes
7 * identity (wrap it in useCallback) and whenever the canvas is resized.
8 * Handles devicePixelRatio so lines stay crisp on high-DPI screens.
9 */
10export function useCanvas(draw: DrawFn) {
11 const ref = useRef<HTMLCanvasElement>(null)
12 useEffect(() => {
13 const canvas = ref.current
14 if (!canvas) return
15 const render = () => {
16 const dpr = window.devicePixelRatio || 1
17 const w = canvas.clientWidth
18 const h = canvas.clientHeight
19 if (w === 0 || h === 0) return
20 canvas.width = Math.round(w * dpr)
21 canvas.height = Math.round(h * dpr)
22 const ctx = canvas.getContext('2d')
23 if (!ctx) return
24 ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
25 ctx.clearRect(0, 0, w, h)
26 draw(ctx, w, h)
27 }
28 render()
29 const ro = new ResizeObserver(render)
30 ro.observe(canvas)
31 return () => ro.disconnect()
32 }, [draw])
33 return ref
↑↓ move↵openescclose