클릭 시 Point 컴포넌트를 배치하는 것 + 반응형 구현을 용이하게 하려고 canvas를 사용하지 않고 일반 div를 사용하기로 했다.
클릭했을때 (잘 안보이지만) Point 컴포넌트가 호출되고, 그 내부에서 input에 title을 입력한다.
▼ Point 컴포넌트
더보기
import { ChangeEvent, useEffect, useRef } from "react";
const Point = ({
x,
y,
title,
onChange,
}: {
x: number;
y: number;
title: string;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
}) => {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return (
<div
style={{
position: "absolute",
width: "4px",
height: "4px",
color: "blue",
top: `${y}px`,
left: `${x}px`,
borderRadius: "50%",
}}
>
<input type="text" value={title} ref={inputRef} onChange={onChange} />
</div>
);
};
export default Point;
▼ Graph 컴포넌트
더보기
import { ChangeEvent, MouseEvent, useState } from "react";
import "./graph.scss";
import Point from "./Point";
interface PointData {
id: number;
x: number;
y: number;
title: string;
}
const Graph = () => {
const [points, setPoints] = useState<PointData[]>([]);
const handleClick = (e: MouseEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setPoints((prev) => [...prev, { id: Date.now(), x, y, title: "" }]); // 클릭한 좌표 저장
};
const handleChange = (e: ChangeEvent<HTMLInputElement>, id: number) => {
setPoints((prev) => prev.map((point) => (point.id === id ? { ...point, title: e.target.value } : point)));
};
return (
<div className="graph-container" onClick={handleClick}>
{points.map((point) => (
<Point key={point.id} x={point.x} y={point.y} title={point.title} onChange={(e) => handleChange(e, point.id)} />
))}
<div className="graph-upper"></div>
<div className="graph-below"></div>
</div>
);
};
export default Graph;
input에 입력한 값을 상위에서 관리하기 위해 points 에 id, title 필드가 추가되었고, handleChange를 prop으로 내려준다.
처음에 클릭했을때는 좌표 데이터를 받고, title은 빈 값""으로 저장한다.
id로는 uuid 를 써도되지만 생성한 시간으로 설정하는 것도 좋은것같다
이전에 작성한 input을 수정하고싶은데 click 이벤트가 발동되어서 새로운 Point 컴포넌트가 생성된다.
Point 내부의 ref를 밖으로 빼고 forwardRef 로 감싸줘야겠다.
Point 내부에서 input 요소에 onClick={(e)=>e.stopPropagation()} 하면 해결된다.
상위로 뺀 ref는 유지하기로 했다. 나중에 요소를 삭제하거나 이동할때 상위에서 관리하는게 낫지않을까?해서
'개발개발 > LifeGraph_인생그래프' 카테고리의 다른 글
[인생 그래프] 클릭 이벤트 핸들러 뜯어보기 (0) | 2025.02.11 |
---|---|
[인생 그래프] 그래프가 이상하다 (0) | 2025.02.10 |
[인생 그래프] 클릭 데이터 전역상태로 관리하기 (0) | 2025.02.10 |
[인생 그래프] <canvas>로 그래프 그리기 (1) | 2025.02.10 |
[인생 그래프] 개인 프로젝트 시작하기 (0) | 2025.02.10 |