Files
html-examples/doc/svg/07_인터랙티브 SVG.md
2025-03-14 13:00:37 +09:00

7.7 KiB

SVG와 JavaScript 이벤트 및 인터랙티브 그래프 제작

SVG는 JavaScript와 결합하여 클릭, 마우스 이동 등 다양한 이벤트를 처리할 수 있어 인터랙티브한 그래픽을 구현하는 데 이상적입니다. 여기에 getBoundingClientRect()를 활용한 좌표 변환, 그래프/차트 제작 기법, 그리고 드래그&드롭 기능을 위한 포인터 이벤트까지 설명하겠습니다.


SVG와 JavaScript 이벤트

SVG 요소는 HTML 요소처럼 DOM 이벤트(click, mouseover, mousemove 등)를 지원합니다. 이를 통해 사용자 상호작용을 감지하고 동적으로 반응할 수 있습니다.

주요 이벤트

이벤트 설명 사용 예시
click 요소를 클릭할 때 발생. 버튼, 토글 기능
mouseover 마우스가 요소 위로 올라갈 때 발생. 호버 효과, 툴팁 표시
mouseout 마우스가 요소를 벗어날 때 발생. 호버 효과 해제
mousemove 마우스가 요소 위에서 움직일 때 발생. 드래그, 실시간 좌표 추적
mousedown 마우스 버튼을 누를 때 발생. 드래그 시작
mouseup 마우스 버튼을 뗄 때 발생. 드래그 종료

예시: 클릭과 호버 이벤트

<svg width="200" height="200">
  <circle id="myCircle" cx="100" cy="100" r="30" fill="blue" />
</svg>
<script>
  const circle = document.getElementById("myCircle");
  circle.addEventListener("click", () => circle.setAttribute("fill", "red"));
  circle.addEventListener("mouseover", () => circle.setAttribute("r", "40"));
  circle.addEventListener("mouseout", () => circle.setAttribute("r", "30"));
</script>
  • 클릭 시 색상이 빨강으로, 호버 시 반지름이 커짐.

getBoundingClientRect()를 활용한 마우스 좌표 변환

SVG는 자체 좌표계를 사용하므로, 브라우저의 클라이언트 좌표(clientX, clientY)를 SVG 좌표로 변환해야 합니다. getBoundingClientRect()getScreenCTM()를 활용하면 이를 쉽게 처리할 수 있습니다.

변환 과정

  1. getBoundingClientRect(): SVG 요소의 뷰포트 내 경계 상자 좌표를 반환.
  2. getScreenCTM(): SVG 좌표계와 화면 좌표계 간 변환 행렬을 반환.
  3. point 객체: SVG 좌표로 변환된 값을 계산.

예시: 마우스 위치에 원 추가

<svg id="svgCanvas" width="400" height="400">
</svg>
<script>
  const svg = document.getElementById("svgCanvas");
  svg.addEventListener("click", (e) => {
    const rect = svg.getBoundingClientRect();
    const matrix = svg.getScreenCTM().inverse();
    const point = svg.createSVGPoint();
    point.x = e.clientX - rect.left;
    point.y = e.clientY - rect.top;
    const svgPoint = point.matrixTransform(matrix);

    const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    circle.setAttribute("cx", svgPoint.x);
    circle.setAttribute("cy", svgPoint.y);
    circle.setAttribute("r", "10");
    circle.setAttribute("fill", "green");
    svg.appendChild(circle);
  });
</script>
  • 클릭한 위치에 녹색 원을 추가. viewBox가 설정된 경우에도 정확한 SVG 좌표로 변환됨.

SVG를 활용한 인터랙티브 그래프 및 차트 제작

SVG는 데이터 시각화(막대그래프, 선그래프 등)에 적합하며, 이벤트와 동적 업데이트를 통해 인터랙티브하게 만들 수 있습니다.

예시: 인터랙티브 막대그래프

<svg id="chart" width="400" height="200" viewBox="0 0 400 200">
  <g id="bars"></g>
</svg>
<script>
  const data = [50, 100, 80, 120];
  const svg = document.getElementById("chart");
  const barsGroup = document.getElementById("bars");

  data.forEach((value, index) => {
    const bar = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    bar.setAttribute("x", index * 100);
    bar.setAttribute("y", 200 - value);
    bar.setAttribute("width", "80");
    bar.setAttribute("height", value);
    bar.setAttribute("fill", "steelblue");

    bar.addEventListener("mouseover", () => bar.setAttribute("fill", "orange"));
    bar.addEventListener("mouseout", () => bar.setAttribute("fill", "steelblue"));
    bar.addEventListener("click", () => alert(`Value: ${value}`));

    barsGroup.appendChild(bar);
  });
</script>
  • 막대그래프에서 호버 시 색상 변경, 클릭 시 값 표시.

기법

  • 데이터 바인딩: 배열 데이터를 SVG 요소로 변환.
  • 축 추가: <line><text>로 x/y축 렌더링.
  • 툴팁: mouseover로 동적 <text> 요소 표시.
  • 업데이트: 데이터 변경 시 removeChildappendChild로 DOM 갱신.

드래그&드롭 (Pointer Events)

SVG에서 드래그&드롭은 pointerdown, pointermove, pointerup 이벤트를 사용해 구현합니다. 이들은 mousedown 등보다 멀티터치와 스타일러스 입력을 지원해 더 현대적입니다.

예시: 드래그 가능한 원

<svg id="svgCanvas" width="400" height="400">
  <circle id="dragCircle" cx="100" cy="100" r="30" fill="purple" />
</svg>
<script>
  const svg = document.getElementById("svgCanvas");
  const circle = document.getElementById("dragCircle");
  let isDragging = false;

  circle.addEventListener("pointerdown", (e) => {
    isDragging = true;
    circle.setPointerCapture(e.pointerId); // 포인터 캡처 설정
  });

  svg.addEventListener("pointermove", (e) => {
    if (!isDragging) return;
    const rect = svg.getBoundingClientRect();
    const matrix = svg.getScreenCTM().inverse();
    const point = svg.createSVGPoint();
    point.x = e.clientX - rect.left;
    point.y = e.clientY - rect.top;
    const svgPoint = point.matrixTransform(matrix);

    circle.setAttribute("cx", svgPoint.x);
    circle.setAttribute("cy", svgPoint.y);
  });

  svg.addEventListener("pointerup", (e) => {
    isDragging = false;
    circle.releasePointerCapture(e.pointerId); // 포인터 캡처 해제
  });
</script>
  • 원을 클릭해 드래그하면 마우스 위치로 이동.

Pointer Events 주요 속성

  • pointerdown: 드래그 시작.
  • pointermove: 드래그 중 위치 업데이트.
  • pointerup: 드래그 종료.
  • setPointerCapture: 해당 요소가 포인터 이벤트를 독점.
  • releasePointerCapture: 캡처 해제.

추가 팁

  • 제약 조건: Math.min/Math.max로 이동 범위 제한.
  • 스냅 효과: 좌표를 일정 단위로 반올림.

결론

SVG와 JavaScript 이벤트는 클릭, 호버, 드래그 등 다양한 상호작용을 가능하게 하며, getBoundingClientRect()와 좌표 변환으로 정확한 위치 계산을 지원합니다. 이를 활용해 막대그래프 같은 데이터 시각화를 만들고, 포인터 이벤트를 통해 드래그&드롭 기능을 추가할 수 있습니다. 실무에서는 D3.js 같은 라이브러리로 복잡한 차트를 쉽게 구현하거나, 순수 JavaScript로 가볍고 커스터마이징된 인터랙션을 만들 수 있습니다. SVG의 유연성과 이벤트 처리 능력은 웹에서 동적이고 사용자 친화적인 경험을 제공하는 데 큰 강점입니다.