시간이 벌써 7월이다. canvas를 배워보자 배워보자 생각만 하고 시작을 못했다. MDN 문서를 보고 canvas를 처음부터 전부 다 훑다 보면 포기를 할 것 같아 그냥 내가 원하는 것부터 차근 차근 구현하면서 기능을 알아보기로 했다. 포토샵도 이렇게 배웠으니까 비슷하지 않을까.

Canvas 위에 움직이는 공을 그리기

;
Canvas.tsx
1const Canvas = () => {
2 const containerRef = useRef<HTMLCanvasElement>(null);
3
4 const handleDraw = () => {
5 const canvas = containerRef.current;
6 const position = { x: 60, y: 60 };
7 const velocity = { x: 10, y: 10 };
8 const rad = 30;
9 if (!canvas) return;
10 let innerWidth = canvas.width;
11 let innerHeight = canvas.height;
12 canvas.width = 1000;
13 canvas.height = 500;
14
15 const context = canvas.getContext("2d");
16
17 if (!context) return;
18
19 const draw = () => {
20 context.fillStyle = "#0efccc";
21 context.beginPath();
22 context.arc(position.x, position.y, rad, 0, 2 * Math.PI);
23 context.fill();
24 };
25
26 const update = () => {
27 if (position.x + rad > innerWidth || position.x - rad < 0) {
28 velocity.x = -velocity.x;
29 }
30
31 if (position.y + rad > innerHeight || position.y - rad < 0) {
32 velocity.y = -velocity.y;
33 }
34
35 position.x += velocity.x;
36 position.y += velocity.y;
37 };
38
39 const animate = () => {
40 requestAnimationFrame(animate);
41 context.clearRect(0, 0, innerWidth, innerHeight);
42 draw();
43 update();
44 };
45
46 animate();
47 };
48
49 useEffect(() => {
50 handleDraw();
51 }, []);
52
53 return (
54 <Box>
55 <Container ref={containerRef} />;
56 </Box>
57 );
58};
59
60export default Canvas;

React에서 Canvas를 다루는 것은 생각보다 쉽지 않았다. 상태를 훅으로 관리하고 싶었는데 useState로 position과 velocity를 가지고 있는데 함수 안에서 변화량을 감지하지 못한다. 그래서 함수 내부에 따로 변수를 선언해서 animate라는 곳에서 draw를 계속 호출하게 하였다. 아마도 이렇게 되는 이유는 함수가 선언된 위치와 관계가 있지 않을까? 함수 외부에서는 state가 변하는 것을 볼 수 있지만 draw 함수 내부에서는 이전 값이 계속 들어온다. 클로저와 관계가 있을 것 같은데 정확한 원인은 모르겠다.