From a093fb65a89f0067e2f215689496c2bfb11f5205 Mon Sep 17 00:00:00 2001 From: netil Date: Mon, 14 Oct 2024 19:00:15 +0900 Subject: [PATCH] feat(legend): Pass visibility state to legend item's event callback Pass visibility state argument to event callbacks Ref #3897 --- src/ChartInternal/internals/legend.ts | 15 ++++++++-- src/config/Options/common/legend.ts | 9 ++++-- test/internals/legend-spec.ts | 42 +++++++++++++++++++++++---- types/options.d.ts | 6 ++-- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/ChartInternal/internals/legend.ts b/src/ChartInternal/internals/legend.ts index afd57188e..5cce9eea0 100644 --- a/src/ChartInternal/internals/legend.ts +++ b/src/ChartInternal/internals/legend.ts @@ -462,7 +462,10 @@ export default { .on(interaction.dblclick ? "dblclick" : "click", interaction || isFunction(config.legend_item_onclick) ? function(event, id) { - if (!callFn(config.legend_item_onclick, api, id)) { + if ( + !callFn(config.legend_item_onclick, api, id, + !state.hiddenTargetIds.includes(id)) + ) { const {altKey, target, type} = event; if (type === "dblclick" || altKey) { @@ -493,7 +496,10 @@ export default { !isTouch && item .on("mouseout", interaction || isFunction(config.legend_item_onout) ? function(event, id) { - if (!callFn(config.legend_item_onout, api, id)) { + if ( + !callFn(config.legend_item_onout, api, id, + !state.hiddenTargetIds.includes(id)) + ) { d3Select(this).classed($FOCUS.legendItemFocused, false); if (hasGauge) { @@ -506,7 +512,10 @@ export default { null) .on("mouseover", interaction || isFunction(config.legend_item_onover) ? function(event, id) { - if (!callFn(config.legend_item_onover, api, id)) { + if ( + !callFn(config.legend_item_onover, api, id, + !state.hiddenTargetIds.includes(id)) + ) { d3Select(this).classed($FOCUS.legendItemFocused, true); if (hasGauge) { diff --git a/src/config/Options/common/legend.ts b/src/config/Options/common/legend.ts index af0ac5530..4253bb5c3 100644 --- a/src/config/Options/common/legend.ts +++ b/src/config/Options/common/legend.ts @@ -118,9 +118,12 @@ export default { * } * * // when set below callback, will disable corresponding default interactions - * onclick: function(id) { ... }, - * onover: function(id) { ... }, - * onout: function(id) { ... }, + * onclick: function(id, visible) { + * // toggle based on the data visibility + * this[visible ? "hide" : "show"](id); + * }, + * onover: function(id, visible) { ... }, + * onout: function(id, visible) { ... }, * * // set tile's size * tile: { diff --git a/test/internals/legend-spec.ts b/test/internals/legend-spec.ts index 0f5aa1023..920148bdd 100644 --- a/test/internals/legend-spec.ts +++ b/test/internals/legend-spec.ts @@ -815,7 +815,7 @@ describe("LEGEND", () => { }); it("set options: legend.item.onclick", () => { - args.legend.item.onclick = () => {}; + args.legend.item.onclick = sinon.spy(() => {}); }); it("should only 'click' event lister bound", () => { @@ -826,14 +826,24 @@ describe("LEGEND", () => { expect(item.on("mouseover mouseout")).to.be.undefined; expect(item.on("click")).to.not.be.undefined; - expect(item.style("cursor")).to.be.equal("pointer"); + + id === "data1" && chart.hide(id); + + fireEvent(item.node(), "click", { + clientX: 2, + clientY: 2 + }, chart); }); + + // given visible state argguments? + expect(args.legend.item.onclick.args) + .to.be.deep.equal(chart.data().map(({id}) => [id, id === "data1" ? false : true])); }); it("set options: legend.item.onover", () => { delete args.legend.item.onclick; - args.legend.item.onover = () => {}; + args.legend.item.onover = sinon.spy(() => {}); }); it("should only 'mouseover' event lister bound", () => { @@ -844,14 +854,24 @@ describe("LEGEND", () => { expect(item.on("click mouseout")).to.be.undefined; expect(item.on("mouseover")).to.not.be.undefined; - expect(item.style("cursor")).to.be.equal("pointer"); + + id === "data2" && chart.hide(id); + + fireEvent(item.node(), "mouseover", { + clientX: 2, + clientY: 2 + }, chart); }); + + // given visible state argguments? + expect(args.legend.item.onover.args) + .to.be.deep.equal(chart.data().map(({id}) => [id, id === "data2" ? false : true])); }); it("set options: legend.item.onout", () => { delete args.legend.item.onover; - args.legend.item.onout = () => {}; + args.legend.item.onout = sinon.spy(() => {}); }); it("should only 'mouseout' event lister bound", () => { @@ -862,9 +882,19 @@ describe("LEGEND", () => { expect(item.on("click mouseover")).to.be.undefined; expect(item.on("mouseout")).to.not.be.undefined; - expect(item.style("cursor")).to.be.equal("pointer"); + + id === "data1" && chart.hide(id); + + fireEvent(item.node(), "mouseout", { + clientX: 2, + clientY: 2 + }, chart); }); + + // given visible state argguments? + expect(args.legend.item.onout.args) + .to.be.deep.equal(chart.data().map(({id}) => [id, id === "data1" ? false : true])); }); it("set options: legend.item.interaction.dblclik=true", () => { diff --git a/types/options.d.ts b/types/options.d.ts index e84d7fc72..a7ec2d74e 100644 --- a/types/options.d.ts +++ b/types/options.d.ts @@ -517,19 +517,19 @@ export interface LegendOptions { * - When set, default `click` interaction will be disabled. * - When `interaction.dblclick=true` is set, will be called on double click. */ - onclick?(this: Chart, id: string): void; + onclick?(this: Chart, id: string, visible: boolean): void; /** * Set mouseover event handler to the legend item. * - **NOTE:** When set, default `mouseover` interaction will be disabled. */ - onover?(this: Chart, id: string): void; + onover?(this: Chart, id: string, visible: boolean): void; /** * Set mouseout event handler to the legend item. * - **NOTE:** When set, default `mouseout` interaction will be disabled. */ - onout?(this: Chart, id: string): void; + onout?(this: Chart, id: string, visible: boolean): void; }; /**