From 9d10ab330926d85f422552e5b7ea89ddc653a60b Mon Sep 17 00:00:00 2001 From: Xing Hong <39619359+xingxing21@users.noreply.github.com> Date: Sun, 26 Apr 2026 16:32:20 +0900 Subject: [PATCH] Fix budget donut chart hiding center content on segment hover (#1551) * Fix budget donut chart hiding center content on segment hover * Preserve segment hover in center unless leaving the unused arc The unused arc has no interactive link in its center template, so moving from it into the center content should restore default content(including the Edit Budget link) immediately. All other segments have a DS::Link in their center template that must remain clickable after the cursor moves from the arc into the center. Pass the D3 datum into the mouseleave handler to read d.data.id, then clear hover when either (a) the departing segment is the unused arc, or (b) the cursor is not heading into contentContainerTarget. --- app/javascript/controllers/donut_chart_controller.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/javascript/controllers/donut_chart_controller.js b/app/javascript/controllers/donut_chart_controller.js index 216e7d9d6..933c7f2b0 100644 --- a/app/javascript/controllers/donut_chart_controller.js +++ b/app/javascript/controllers/donut_chart_controller.js @@ -26,12 +26,14 @@ export default class extends Controller { this.#draw(); document.addEventListener("turbo:load", this.#redraw); this.element.addEventListener("mouseleave", this.#clearSegmentHover); + this.contentContainerTarget.addEventListener("mouseleave", this.#clearSegmentHover); } disconnect() { this.#teardown(); document.removeEventListener("turbo:load", this.#redraw); this.element.removeEventListener("mouseleave", this.#clearSegmentHover); + this.contentContainerTarget.removeEventListener("mouseleave", this.#clearSegmentHover); } get #data() { @@ -151,8 +153,12 @@ export default class extends Controller { this.#handleSegmentHover(event); }, 10); }) - .on("mouseleave", () => { + .on("mouseleave", (event, d) => { clearTimeout(hoverTimeout); + const leavingUnused = d.data.id === this.unusedSegmentIdValue; + if (leavingUnused || !this.contentContainerTarget.contains(event.relatedTarget)) { + this.#clearSegmentHover(); + } }) .on("click", (event, d) => { if (this.enableClickValue) {