chart = {
const svg = d3.create("svg")
.attr("font-size", "10pt")
.attr("cursor", "default")
.attr("viewBox", [0, 0, width, height]);
svg.append("g").call(g => drawGuidelines(g, chartData.map(d => d.year),
d => d3.line()([[x(d) + hx, margin.top],[x(d) + hx, height - margin.bottom]]))
);
svg.append("g").call(g => drawGuidelines(g, y.ticks().reverse().slice(1),
d => d3.line()([[margin.left, y(d)],[width - margin.left - margin.right, y(d)]]))
);
const g = svg.selectAll(".pie")
.data(chartData)
.join("g")
.attr("class", "pie")
.attr("transform", d => `translate(${x(d.year) + hx},${y(d.total)})`)
.call(g => g.append("text")
.attr("dy", "1em")
.attr("text-anchor", "middle")
.attr("transform", d => `translate(0,${r(d.total)})`)
.text(d => toCurrency(d.total)));
const pg = g.selectAll("g")
.data(d => d3.pie()(d.values).map(p => ({pie: p, total: d.total})))
.join("g")
.call(g => g.append("title")
.text((d, i) => `${territories[i]}\n${toCurrency(d.pie.value)} (${(d.pie.value / d.total * 100).toFixed(1)}%)`));
const slice = pg.append("path")
.attr("d", d => pie(d)())
.attr("opacity", 1)
.attr("fill", (d, i) => color(territories[i]));
const pct = pg.append("text")
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("transform", (d, i) => {
const c = pie(d).centroid(d.pie.value);
return `translate(${c[0]},${c[1]})`;
})
.attr("opacity", "0")
.text(d => (d.pie.value / d.total * 100).toFixed(1) + "%");
svg.append("g").call(g => drawAxis(g, margin.left, 0, d3.axisLeft(y).ticks(height / 100, "s")));
svg.append("g").call(g => drawAxis(g, 0, height - margin.bottom, d3.axisBottom(x)));
svg.append("g").call(drawLegend);
return svg.node();
var legend;
function drawLegend(g) {
legend = g.attr("transform", `translate(${width - margin.right},0)`)
.selectAll("g")
.data(territories)
.join("g")
.attr("transform", (d, i) => `translate(0,${i * 20})`)
.call(g => g.append("rect")
.attr("rx", 3).attr("ry", 3)
.attr("width", 20).attr("height", 15)
.attr("fill", d => color(d)))
.call(g => g.append("text").attr("dx", 25).attr("alignment-baseline", "hanging").text(d => d))
.on("mouseover", e => highlight(e))
.on("mouseout", () => highlight());
}
function highlight(e) {
const i = e ? legend.nodes().indexOf(e.currentTarget) : -1;
slice.transition().duration(500).attr("opacity", (d, j) => i === -1 || j === i ? 1 : 0.3);
pct.transition().duration(500)
.attr("opacity", function(d, j) {
if (j === i) {
this.parentNode.parentNode.appendChild(this.parentNode);
return 1;
}
else return 0;
});
}
}