Learning
레슨 3 / 8·20분

도형과 트랜지션

SVG 기본 도형

D3는 SVG 요소를 직접 조작하므로 SVG의 기본 도형을 이해하는 것이 중요합니다. rect(사각형), circle(원), line(직선), path(경로) 등을 데이터 바인딩과 함께 사용합니다.

javascript
const svg = d3.select('#chart')
  .append('svg')
  .attr('width', 500)
  .attr('height', 300);

// 사각형 (rect)
svg.append('rect')
  .attr('x', 10).attr('y', 10)
  .attr('width', 100).attr('height', 60)
  .attr('fill', '#3b82f6')
  .attr('rx', 8);  // 둥근 모서리

// 원 (circle)
svg.append('circle')
  .attr('cx', 200).attr('cy', 40)
  .attr('r', 30)
  .attr('fill', '#ef4444');

// 직선 (line)
svg.append('line')
  .attr('x1', 280).attr('y1', 10)
  .attr('x2', 400).attr('y2', 70)
  .attr('stroke', '#10b981')
  .attr('stroke-width', 3);

선 생성기(Line Generator)로 꺾은선 그래프 만들기

javascript
const data = [
  { date: '01/01', value: 30 },
  { date: '01/02', value: 50 },
  { date: '01/03', value: 45 },
  { date: '01/04', value: 70 },
  { date: '01/05', value: 60 },
];

const x = d3.scalePoint()
  .domain(data.map(d => d.date))
  .range([50, 450]);

const y = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.value)])
  .range([250, 20]);

// d3.line()으로 path의 d 속성 문자열 생성
const lineGenerator = d3.line()
  .x(d => x(d.date))
  .y(d => y(d.value))
  .curve(d3.curveMonotoneX);  // 부드러운 곡선

svg.append('path')
  .datum(data)
  .attr('d', lineGenerator)
  .attr('fill', 'none')
  .attr('stroke', '#6366f1')
  .attr('stroke-width', 2.5);

트랜지션(Transition)

D3의 트랜지션은 속성 값의 변화를 부드러운 애니메이션으로 보간합니다. .transition()을 체인에 추가하면 이후의 .attr()이나 .style() 변경이 점진적으로 적용됩니다.

javascript
// 막대가 아래에서 올라오는 애니메이션
svg.selectAll('rect')
  .data(data)
  .join('rect')
    .attr('x', (d, i) => xScale(d.label))
    .attr('width', xScale.bandwidth())
    .attr('y', innerHeight)       // 시작: 바닥
    .attr('height', 0)             // 시작: 높이 0
    .attr('fill', '#6366f1')
  .transition()
    .duration(800)                 // 800ms 동안
    .delay((d, i) => i * 100)     // 각 막대 100ms씩 지연
    .ease(d3.easeBackOut)          // 이징 함수
    .attr('y', d => yScale(d.value))          // 끝: 데이터 위치
    .attr('height', d => innerHeight - yScale(d.value)); // 끝: 데이터 높이

외부 데이터 로드

javascript
// CSV 파일 로드 (자동으로 파싱)
const csvData = await d3.csv('/data/sales.csv', (d) => ({
  month: d.month,
  revenue: +d.revenue,  // 문자열 → 숫자 변환
}));

// JSON 파일 로드
const jsonData = await d3.json('/data/countries.json');

// 로드한 데이터로 시각화
console.log(csvData);  // [{month: "1월", revenue: 150}, ...]
  • .transition() — 이후 속성 변경을 애니메이션으로 처리
  • .duration(ms) — 애니메이션 지속 시간
  • .delay(ms | fn) — 시작 전 지연 시간 (함수로 각 요소별 지연 가능)
  • .ease(fn) — d3.easeLinear, d3.easeBounce, d3.easeBackOut 등
  • d3.csv(url, row) — CSV 로드 및 행 변환 함수 적용
  • d3.json(url) — JSON 데이터 비동기 로드
💡

D3의 .join() 메서드(v5.8+)는 enter/update/exit 패턴을 간결하게 처리합니다. .data(newData).join("rect")만으로 추가/갱신/제거가 자동 처리됩니다.