function donutChart(data, {
name = ([x]) => x,
value = ([, y]) => y,
title,
width = 640,
height = 400,
innerRadius = Math.min(width, height) / 3,
outerRadius = Math.min(width, height) / 2,
labelRadius = (innerRadius + outerRadius) / 2,
format = ",",
names,
stroke = innerRadius > 0 ? "none" : "white",
// width of stroke separating wedges
strokeWidth = 1,
// line join of stroke separating wedges
strokeLinejoin = "round",
// angular separation between wedges
padAngle = stroke === "none" ? 1 / outerRadius : 0,
} = {}) {
// Compute values.
const N = d3.map(data, name);
const V = d3.map(data, value);
const I = d3.range(N.length).filter(i => !isNaN(V[i]));
// Unique the names.
if (names === undefined) names = N;
names = new d3.InternSet(names);
// Compute titles.
if (title === undefined) {
const formatValue = d3.format(format);
// variable to store total number of films represented
var totalFilms = 0;
// determine the total films represented
for (let aCount of data) {
totalFilms = totalFilms + aCount.count;
}
// text to display
title = i => `${N[i]}\n${formatValue(V[i])}\n${Math.round(((V[i] * 100) / totalFilms) * 100) / 100}%`;
} else {
const O = d3.map(data, d => d);
const T = title;
title = i => T(O[i], i, data);
}
// Construct arcs.
const arcs = d3.pie().padAngle(padAngle).sort(null).value(i => V[i])(I);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcLabel = d3.arc().innerRadius(labelRadius).outerRadius(labelRadius);
// create svg
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");
// append g
svg.append("g")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-linejoin", strokeLinejoin)
.selectAll("path")
.data(arcs)
.join("path")
.attr("fill", d => mpaaColorCoding(N[d.data]))
.attr("d", arc)
.append("title")
.text(d => title(d.data))
// create legend inside of donut
var legendRectSize = 13;
var legendSpacing = 7;
var legend = svg.selectAll('.legend')
.data(mpaaColorCoding.domain())
.enter()
.append('g')
.attr('class', 'circle-legend')
.attr('transform', function (d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * mpaaColorCoding.domain().length / 2;
var horz = -2 * legendRectSize - 13;
var vert = i * height - offset;
return 'translate(' + horz + ',' + vert + ')';
});
// keys
legend.append('circle')
.style('fill', mpaaColorCoding)
.style('stroke', mpaaColorCoding)
.attr('cx', 0)
.attr('cy', 0)
.attr('r', '.5rem');
// labels
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function (d) {
return d;
});
return Object.assign(svg.node(), {scales: {mpaaColorCoding}});
}