Line Chart
d3.line() builds the SVG d attribute from data arrays. The stroke-dashoffset reveal trick: set stroke-dasharray and stroke-dashoffset to the path’s total length, then tween stroke-dashoffset to 0. d3.curveMonotoneX produces smooth monotone curves.
d3.line()이 데이터 배열에서 SVG d 속성을 생성합니다. stroke-dashoffset 리빌 트릭: stroke-dasharray와 stroke-dashoffset을 경로의 전체 길이로 설정한 뒤 stroke-dashoffset을 0으로 트윈합니다. d3.curveMonotoneX는 부드러운 단조 곡선을 만듭니다.
Source Code script.js
const data = [
{ week: 'W1', temp: 3 },
{ week: 'W2', temp: 5 },
{ week: 'W3', temp: 2 },
{ week: 'W4', temp: 8 },
{ week: 'W5', temp: 12 },
{ week: 'W6', temp: 15 },
{ week: 'W7', temp: 18 },
{ week: 'W8', temp: 22 },
{ week: 'W9', temp: 19 },
{ week: 'W10', temp: 24 },
];
const margin = { top: 20, right: 20, bottom: 40, left: 50 };
const chartEl = document.getElementById('chart');
const totalWidth = chartEl.clientWidth || 720;
const width = totalWidth - margin.left - margin.right;
const height = 360 - margin.top - margin.bottom;
const svg = d3.select('#chart')
.append('svg')
.attr('width', totalWidth)
.attr('height', 360)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
const x = d3.scalePoint()
.domain(data.map(d => d.week))
.range([0, width])
.padding(0.5);
const maxTemp = d3.max(data, d => d.temp);
const y = d3.scaleLinear()
.domain([0, maxTemp + 5])
.range([height, 0]);
// Horizontal grid lines
svg.append('g')
.attr('class', 'grid')
.call(
d3.axisLeft(y)
.tickSize(-width)
.tickFormat('')
);
// X axis
svg.append('g')
.attr('class', 'axis axis--x')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x).tickSizeOuter(0));
// Y axis
svg.append('g')
.attr('class', 'axis axis--y')
.call(
d3.axisLeft(y)
.ticks(6)
.tickSizeOuter(0)
.tickFormat(d => `${d}°C`)
);
// Area generator
const areaGen = d3.area()
.x(d => x(d.week))
.y0(height)
.y1(d => y(d.temp))
.curve(d3.curveCatmullRom);
// Line generator
const lineGen = d3.line()
.x(d => x(d.week))
.y(d => y(d.temp))
.curve(d3.curveCatmullRom);
// Area path (no animation needed — reveals with line)
svg.append('path')
.datum(data)
.attr('class', 'area')
.attr('d', areaGen);
// Line path
const linePath = svg.append('path')
.datum(data)
.attr('class', 'line')
.attr('d', lineGen);
// Animate line using stroke-dashoffset trick
const totalLength = linePath.node().getTotalLength();
linePath
.attr('stroke-dasharray', totalLength)
.attr('stroke-dashoffset', totalLength)
.transition()
.duration(1200)
.ease(d3.easeInOut)
.attr('stroke-dashoffset', 0);
// Tooltip
const tooltip = d3.select('#tooltip');
// Dots at each data point
svg.selectAll('.dot')
.data(data)
.join('circle')
.attr('class', 'dot')
.attr('cx', d => x(d.week))
.attr('cy', d => y(d.temp))
.attr('r', 4)
.on('mouseover', function (event, d) {
tooltip
.style('opacity', 1)
.html(`${d.week} · ${d.temp}°C`);
})
.on('mousemove', function (event) {
tooltip
.style('left', `${event.pageX + 12}px`)
.style('top', `${event.pageY - 28}px`);
})
.on('mouseout', function () {
tooltip.style('opacity', 0);
});