import { Controller } from "@hotwired/stimulus"; import * as d3 from "d3"; // Connects to data-controller="pie-chart" export default class extends Controller { static values = { data: Array, total: String, label: String, }; #d3SvgMemo = null; #d3GroupMemo = null; #d3ContentMemo = null; #d3ViewboxWidth = 200; #d3ViewboxHeight = 200; connect() { this.#draw(); document.addEventListener("turbo:load", this.#redraw); } disconnect() { this.#teardown(); document.removeEventListener("turbo:load", this.#redraw); } #redraw = () => { this.#teardown(); this.#draw(); }; #teardown() { this.#d3SvgMemo = null; this.#d3GroupMemo = null; this.#d3ContentMemo = null; this.#d3Container.selectAll("*").remove(); } #draw() { this.#d3Container.attr("class", "relative"); this.#d3Content.html(this.#contentSummaryTemplate()); const pie = d3 .pie() .value((d) => d.percent_of_total) .padAngle(0.06); const arc = d3 .arc() .innerRadius(this.#radius - 8) .outerRadius(this.#radius) .cornerRadius(2); const arcs = this.#d3Group .selectAll("arc") .data(pie(this.dataValue)) .enter() .append("g") .attr("class", "arc"); const paths = arcs .append("path") .attr("class", (d) => d.data.fill_color) .attr("d", arc); paths .on("mouseover", (event) => { this.#d3Svg.selectAll(".arc path").attr("class", "fill-gray-200"); d3.select(event.target).attr("class", (d) => d.data.fill_color); this.#d3ContentMemo.html( this.#contentDetailTemplate(d3.select(event.target).datum().data), ); }) .on("mouseout", () => { this.#d3Svg .selectAll(".arc path") .attr("class", (d) => d.data.fill_color); this.#d3ContentMemo.html(this.#contentSummaryTemplate()); }); } #contentSummaryTemplate() { return `${this.totalValue} ${this.labelValue}`; } #contentDetailTemplate(datum) { return ` ${datum.formatted_value}