chart = {
const height = width;
const innerRadius = 70;
const outerRadius = Math.min(width, height) * 0.37;
const series = d3.stack()
.keys(d3.union(data.map(d => d.category)))
.value(([, D], key) => D.get(key).value)
(d3.index(data, d => d.state, d => d.category));
const arc = d3.arc()
.innerRadius(d => y(d[0]))
.outerRadius(d => y(d[1]))
.startAngle(d => x(d.data[0]))
.endAngle(d => x(d.data[0]) + x.bandwidth())
.padAngle(1 / innerRadius)
.padRadius(innerRadius);
const x = d3.scaleBand()
.domain(d3.groupSort(data, D => -d3.sum(D, d => d.value), d => d.state))
.range([0, 2 * Math.PI])
.align(0);
const y = d3.scaleRadial()
.domain([0, d3.max(series, d => d3.max(d, d => d[1]))])
.range([innerRadius, outerRadius]);
const color = d3.scaleOrdinal()
.domain(series.map(d => d.key))
.range(WRPcolours)
.unknown("#ccc");
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height /2, width, height])
.attr("style", "width: 100%; height: 800px; font: 10px sans-serif; background-color: white;");
// A group for each series, and a rect for each element in the series
svg.append("g")
.selectAll()
.data(series)
.join("g")
.attr("fill", d => color(d.key))
.selectAll("path")
.data(D => D.map(d => (d.key = D.key, d)))
.join("path")
.attr("d", arc)
// When the mouse moves over an item, quickly fade its colour to black
.on('mouseover', function(e, d) {
d3.select(this)
.transition()
.duration(100)
.style('fill', 'black')
})
// When the mouse leaves an item, slowly fade its colour back to its original colour
.on('mouseout', function(e, d) {
d3.select(this)
.transition()
.duration(100)
.style('fill', d => color(d.key))
})
.append("title")
.text(d => `${d.data[1].get(d.key).value} / ${d.data[1].get(d.key).state} / ${d.data[1].get(d.key).category}`);
// x axis
svg.append("g")
.selectAll()
.data(x.domain())
.join("g")
.attr("transform", d => `
rotate(${((x(d) + x.bandwidth() / 2) * 180 / Math.PI - 90)})
translate(${outerRadius},0)
`)
.call(g => g.append("text")
.attr("transform", d => (x(d) + x.bandwidth() / 2 + Math.PI / 1) % (2 * Math.PI) < Math.PI
? "rotate(180) translate(-2,2)"
: "translate(2,2)")
.attr("text-anchor", d => (x(d) + x.bandwidth() / 2 + Math.PI / 1) % (2 * Math.PI) < Math.PI
? "end"
: "start")
.text(d => d));
// y axis
svg.append("g")
.attr("text-anchor", "end")
.call(g => g.selectAll("g")
.data(y.ticks(10).slice(1))
.join("g")
.attr("fill", "none")
.call(g => g.append("circle")
.attr("stroke", "#000")
.attr("stroke-width", "0.05em")
.attr("stroke-opacity", 0.1)
.attr("r", y))
);
// color legend
svg.append("g")
.selectAll()
.data(color.domain())
.join("g")
.attr("transform", (d, i, nodes) => `translate(-40,${(nodes.length / 2 - i - 1) * 20})`)
.call(g => g.append("rect")
.attr("width", 18)
.attr("height", 18)
.attr("fill", color))
.call(g => g.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", "0.35em")
.text(d => d));
// Zoom on mouse scroll
svg.call(d3.zoom()
.extent([[-width / 2, -height /2], [width, height]])
.scaleExtent([1, 5])
.on("zoom", zoomed))
.on("mousedown.zoom", null);
function zoomed({transform}) {
svg.attr("transform", transform);
};
return svg.node();
}