본문 바로가기
개발개발/LifeGraph_인생그래프

[인생 그래프] <canvas>로 그래프 그리기

by yelimu 2025. 2. 10.

내가 생각한 구현 방식

 

x축, y축이 존재하는 Graph 컴포넌트

클릭 이벤트를 받아서 x,y 좌표 배열을 받는다

각 좌표에 Point 컴포넌트가 추가된다

입력을 멈추고 그래프 생성하기 버튼을 누르면 각 점을 부드럽게 잇는 그래프가 그려진다 

+ 가능하다면 점의 위치를 드래그앤드롭으로 이동하거나 삭제한다. 

 

일단 클릭 받아서 그래프 만드는거까지만 MVP로 만들어보기


 

처음으로 <canvas>라는 태그가 있다는걸 알게 됐다.

 

canvas로 좌표를 그렸다가, 단순히 좌표만 보여주는 역할이라면 div 에 border 로 충분하려나? 했는데

클릭 이벤트를 받아서 그래프를 그려주기 위해 어떤게 더 효율적일지 몰라서 canvas에 대해 좀더 알아보는 중이다.

 

https://velog.io/@thdrldud369/posts?tag=canvas

 

thdrldud369 (송기영개발잘하고싶다) / 작성글 - velog

 

velog.io

블로그 포스팅을 단계별로 해주셔서 유익하다.

나도 이렇게 보기 좋으면서, 도움이 되는 포스팅을 할 수 있다면 좋을텐데 하는 생각이,,

 

https://yozm.wishket.com/magazine/detail/2268/

 

Canvas API로 가을을 표현해 본다면? | 요즘IT

내가 처음 개발자가 되기로 마음먹은 것은 웹 화면에 내 생각을 그대로 옮겨놓을 수 있다는 점 때문이었다. 우연히 유튜브에서 한 영상을 보게 되었는데, 바로 Canvas API를 활용해 만든 인터랙티

yozm.wishket.com


어떤 방식으로 그래프를 구현할지 고민이 돼서 브랜치를 파서 두 가지 버전 다 해보기로 했다. 

 

[canvas 를 이용한 방식]

우선 gpt가 알려준 코드대로 만들어보니까 그래프를 그려주긴 한다.

그런데 수정이나 삭제 기능을 염두에 두기도 했고, 개별 Point 컴포넌트를 포지셔닝 하고싶어서 div 로 그래프를 구현하는게 좋을것같다.

더보기
import { useEffect, useRef, useState } from "react";

const Graph = () => {
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const [points, setPoints] = useState<{ x: number; y: number }[]>([]);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    // 캔버스 크기 가져오기
    const width = canvas.width;
    const height = canvas.height;

    // 캔버스 초기화
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // 배경 색상 설정
    ctx.fillStyle = "transparent";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // x, y 축 그리기
    ctx.strokeStyle = "#000";
    ctx.lineWidth = 2;

    // x축 (가운데로 설정)
    const centerY = height / 2;

    // x축 (가로)
    ctx.beginPath();
    ctx.moveTo(0, centerY);
    ctx.lineTo(width, centerY);
    ctx.stroke();

    // y축 (세로)
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(0, height);
    ctx.stroke();

    // 저장된 좌표들 그리기
    ctx.fillStyle = "blue";
    ctx.strokeStyle = "blue";
    ctx.lineWidth = 2;

    points.forEach((point, index) => {
      ctx.beginPath();
      ctx.arc(point.x, point.y, 5, 0, Math.PI * 2);
      ctx.fill();

      if (index > 0) {
        ctx.beginPath();
        ctx.moveTo(points[index - 1].x, points[index - 1].y);
        ctx.lineTo(point.x, point.y);
        ctx.stroke();
      }
    });
  }, [points]);

  const handleClick = (event: React.MouseEvent<HTMLCanvasElement>) => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const rect = canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    setPoints((prev) => [...prev, { x, y }]); // 클릭한 좌표 저장
  };

  return (
    <div className="graph-container">
      <canvas ref={canvasRef} width={500} height={500} onClick={handleClick}>
        캔버스를 지원하지 않는 브라우저입니다.
      </canvas>
    </div>
  );
};

export default Graph;

이미지를 누르면 사이트로 이동합니다.