{
const svg = d3
.create('svg')
.attr('viewBox', [0, 0, width * 2, height * 2])
.attr('width', width * 2)
.attr('height', height * 2);
const chart = svg
.append('g')
.attr("transform", `translate(${width * 0.75}, ${height})`);
const radius = Math.min(width, height) / 2;
const arc = d3
.arc()
.innerRadius(0)
.outerRadius(radius);
chart
.selectAll(null)
.data(pieData)
.enter()
.append('path')
.attr('d', datum => arc(datum))
.attr('fill', datum => colorSeq(datum.index))
.attr("stroke", "gray")
.style("stroke-width", "1px");
const arcTarget = d3
.arc()
.innerRadius(radius * 0.8)
.outerRadius(radius);
pieData.forEach(x => {
const centroid = arcTarget.centroid(x);
x.midAngle = (x.startAngle + x.endAngle) / 2;
x.centroid = centroid;
x.centroidX = centroid[0];
x.centroidY = centroid[1];
});
const sortedPieData = pieData
.sort((a, b) => ssInvOp(arcTarget.centroidX, arcTarget.centroidX))
.map((x, i) => {
x.xOrder = i + 1;
return x;
});
const calcLineRadical = d => {
const firstAngle = d.midAngle;
const firstRadius =
(d.xOrder * 30) / Math.abs(Math.cos(Math.PI - firstAngle));
const xpos = radius * 1.5 - d.centroidX;
const secondAngle =
Math.PI + Math.atan(xpos / (firstRadius * Math.cos(firstAngle)));
const secondRadius = Math.abs(xpos / Math.sin(secondAngle));
const fixedSecondAngle =
secondAngle < Math.PI ? secondAngle : secondAngle - Math.PI;
return [
[0, 0],
[firstAngle, firstRadius],
[fixedSecondAngle, secondRadius]
];
};
const line = d3.lineRadial();
chart
.selectAll(null)
.data(sortedPieData)
.enter()
.append('path')
.attr('d', datum => line(calcLineRadical(datum)))
.attr('transform', datum => `translate(${datum.centroid})`)
.attr('fill', 'none')
.attr('stroke', 'black')
.style('stroke-width', '1px');
const calcLabelY = d => {
const center = arcTarget.centroid(d);
const sign = Math.sign(Math.cos(d.midAngle));
return center[1] - sign * d.xOrder * 30 + 10;
};
chart
.selectAll(null)
.data(sortedPieData)
.enter()
.append('text')
.text(datum => datum.data.key)
.attr('x', radius * 1.5 + 10)
.attr('y', calcLabelY)
.style("font-size", 20);
return svg.node();
}