Pie Chart
d3.pie() computes arc start/end angles from values. d3.arc() generates the path d attribute for each slice. On enter, arcs tween from zero-angle via attrTween('d', ...) using an interpolated arc function. An inner radius > 0 creates the donut hole.
d3.pie()가 값에서 호의 시작/끝 각도를 계산합니다. d3.arc()가 각 슬라이스의 경로 d 속성을 생성합니다. 진입 시 attrTween('d', ...)과 보간된 arc 함수로 0각도에서 트윈합니다. 내부 반지름이 0보다 크면 도넛 구멍이 생깁니다.
Source Code script.js
const data = [
{ label: 'Chrome', value: 65.1 },
{ label: 'Safari', value: 18.7 },
{ label: 'Edge', value: 5.3 },
{ label: 'Firefox', value: 4.0 },
{ label: 'Other', value: 6.9 },
];
// Monochrome shades from dark to light
const colors = ['#222', '#444', '#666', '#888', '#aaa'];
const size = 280;
const radius = 120;
const innerRadius = 70;
const tooltip = d3.select('#tooltip');
// Build SVG
const svg = d3.select('#chart')
.append('svg')
.attr('width', size)
.attr('height', size);
const g = svg.append('g')
.attr('transform', `translate(${size / 2}, ${size / 2})`);
// Pie layout
const pie = d3.pie()
.sort(null)
.value(d => d.value);
// Arc generator
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(radius);
const arcs = pie(data);
// Draw arcs with animation
const arcGroups = g.selectAll('.arc')
.data(arcs)
.enter()
.append('g')
.attr('class', 'arc');
arcGroups.append('path')
.attr('fill', (d, i) => colors[i])
.transition()
.duration(800)
.delay((d, i) => i * 60)
.attrTween('d', function(d) {
const interpolate = d3.interpolate({ startAngle: 0, endAngle: 0 }, d);
return function(t) {
return arc(interpolate(t));
};
});
// Tooltip interactions on the group element
arcGroups
.style('cursor', 'pointer')
.on('mouseover', function(event, d) {
tooltip
.style('opacity', 1)
.html(`${d.data.label} ${d.data.value}%`);
})
.on('mousemove', function(event) {
tooltip
.style('left', (event.clientX + 14) + 'px')
.style('top', (event.clientY - 28) + 'px');
})
.on('mouseout', function() {
tooltip.style('opacity', 0);
});
// Legend
const legend = d3.select('#legend');
data.forEach((d, i) => {
const item = legend.append('div').attr('class', 'legend-item');
item.append('div')
.attr('class', 'legend-swatch')
.style('background', colors[i]);
item.append('span')
.attr('class', 'legend-label')
.text(`${d.label} (${d.value}%)`);
});