Skip to content

Commit

Permalink
feat(data): Intent to ship data.onshown/onhidden
Browse files Browse the repository at this point in the history
Implement data.onshown/onhidden.

Close #2146
  • Loading branch information
netil committed Jun 24, 2021
1 parent e84a4f1 commit af98eb7
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 11 deletions.
16 changes: 13 additions & 3 deletions src/Chart/api/show.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
import {endall} from "../../module/util";
import {callFn, endall} from "../../module/util";

/**
* Show/Hide data series
Expand All @@ -14,6 +14,9 @@ import {endall} from "../../module/util";
function showHide(show: boolean, targetIdsValue: string[], options: any): void {
const $$ = this.internal;
const targetIds = $$.mapToTargetIds(targetIdsValue);
const hiddenIds = $$.state.hiddenTargetIds
.map(v => targetIds.indexOf(v) > -1 && v)
.filter(Boolean);

$$.state.toggling = true;

Expand All @@ -22,13 +25,20 @@ function showHide(show: boolean, targetIdsValue: string[], options: any): void {
const targets = $$.$el.svg.selectAll($$.selectorTargets(targetIds));
const opacity = show ? null : "0";

show && targets.style("display", null);
if (show && hiddenIds.length) {
targets.style("display", null);
callFn($$.config.data_onshown, this, hiddenIds);
}

targets.transition()
.style("opacity", opacity, "important")
.call(endall, () => {
// https://github.com/naver/billboard.js/issues/1758
!show && targets.style("display", "none");
if (!show && hiddenIds.length === 0) {
targets.style("display", "none");
callFn($$.config.data_onhidden, this, targetIds);
}

targets.style("opacity", opacity);
});

Expand Down
49 changes: 41 additions & 8 deletions src/ChartInternal/data/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,20 +464,53 @@ export default {
return sortValue(xs);
},

addHiddenTargetIds(targetIds): void {
this.state.hiddenTargetIds = this.state.hiddenTargetIds.concat(targetIds);
/**
* Add to the state target Ids
* @param {string} type State's prop name
* @param {Array|string} targetIds Target ids array
* @private
*/
addTargetIds(type: string, targetIds: string[] | string): void {
const {state} = this;
const ids = (isArray(targetIds) ? targetIds : [targetIds]) as [];

ids.forEach(v => {
state[type].indexOf(v) < 0 &&
state[type].push(v);
});
},

/**
* Remove from the state target Ids
* @param {string} type State's prop name
* @param {Array|string} targetIds Target ids array
* @private
*/
removeTargetIds(type: string, targetIds: string[] | string): void {
const {state} = this;
const ids = (isArray(targetIds) ? targetIds : [targetIds]) as [];

ids.forEach(v => {
const index = state[type].indexOf(v);

index >= 0 && state[type].splice(index, 1);
});
},

addHiddenTargetIds(targetIds: string[]): void {
this.addTargetIds("hiddenTargetIds", targetIds);
},

removeHiddenTargetIds(targetIds): void {
this.state.hiddenTargetIds = this.state.hiddenTargetIds.filter(id => targetIds.indexOf(id) < 0);
removeHiddenTargetIds(targetIds: string[]): void {
this.removeTargetIds("hiddenTargetIds", targetIds);
},

addHiddenLegendIds(targetIds): void {
this.state.hiddenLegendIds = this.state.hiddenLegendIds.concat(targetIds);
addHiddenLegendIds(targetIds: string[]): void {
this.addTargetIds("hiddenLegendIds", targetIds);
},

removeHiddenLegendIds(targetIds): void {
this.state.hiddenLegendIds = this.state.hiddenLegendIds.filter(id => targetIds.indexOf(id) < 0);
removeHiddenLegendIds(targetIds: string[]): void {
this.removeTargetIds("hiddenLegendIds", targetIds);
},

getValuesAsIdKeyed(targets) {
Expand Down
34 changes: 34 additions & 0 deletions src/config/Options/data/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,40 @@ export default {
*/
data_onout: () => {},

/**
* Set a callback for when data is shown.<br>
* The callback will receive shown data ids in array.
* @name data․onshown
* @memberof Options
* @type {Function}
* @default undefined
* @example
* data: {
* onshown: function(ids) {
* // ids - ["data1", "data2", ...]
* ...
* }
* }
*/
data_onshown: <Function|undefined> undefined,

/**
* Set a callback for when data is hidden.<br>
* The callback will receive hidden data ids in array.
* @name data․onhidden
* @memberof Options
* @type {Function}
* @default undefined
* @example
* data: {
* onhidden: function(ids) {
* // ids - ["data1", "data2", ...]
* ...
* }
* }
*/
data_onhidden: <Function|undefined> undefined,

/**
* Set a callback for minimum data
* - **NOTE:** For 'area-line-range' and 'area-spline-range', `mid` data will be taken for the comparison
Expand Down
119 changes: 119 additions & 0 deletions test/internals/data-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import {expect} from "chai";
import {select as d3Select} from "d3-selection";
import {format as d3Format} from "d3-format";
import sinon from "sinon";
import util from "../assets/util";
import CLASS from "../../src/config/classes";
import {isNumber} from "../../src/module/util";
Expand Down Expand Up @@ -2259,4 +2260,122 @@ describe("DATA", () => {
});
});
});

describe("data.onshown/onhidden", () => {
const spyShown = sinon.spy();
const spyHidden = sinon.spy();

before(() => {
args = {
data: {
columns: [
["data1", 300, 350, 300, 0, 0, 0],
["data2", 130, 100, 140, 200, 150, 50]
],
type: "line",
onshown: spyShown,
onhidden: spyHidden
}
};
});

afterEach(() => {
spyHidden.resetHistory();
spyShown.resetHistory();
});

it("check on continuous .hide()/.show() APIs.", done => {
new Promise((resolve, reject) => {
// hide
chart.hide();

setTimeout(() => {
expect(spyHidden.calledOnce).to.be.true;
expect(spyHidden.args[0][0]).to.deep.equal(chart.data().map(v => v.id));

resolve(true);
}, 300);
}).then(() => {
return new Promise((resolve, reject) => {
// when is called already hidden, do not call onhidden callback
chart.hide();

setTimeout(() => {
expect(spyHidden.callCount).to.be.equal(1);

resolve(true);
}, 300);
});
}).then(() => {
return new Promise((resolve, reject) => {
// show
chart.show();

setTimeout(() => {
expect(spyShown.calledOnce).to.be.true;
expect(spyShown.args[0][0]).to.deep.equal(chart.data().map(v => v.id));

resolve(true);
}, 300);
});
}).then(() => {
// when is called already shown, do not call onshown callback
chart.show();

setTimeout(() => {
expect(spyShown.callCount).to.be.equal(1);

done();
}, 300);
});
});

it("check on continuous .hide()/.show() APIs giving specific data id.", done => {
const id = "data1";

new Promise((resolve, reject) => {
// hide
chart.hide(id);

setTimeout(() => {
expect(spyHidden.calledOnce).to.be.true;
expect(spyHidden.args[0][0]).to.deep.equal([id]);

resolve(true);
}, 300);
}).then(() => {
return new Promise((resolve, reject) => {
// when is called already hidden, do not call onhidden callback
chart.hide(id);

setTimeout(() => {
expect(spyHidden.callCount).to.be.equal(1);

resolve(true);
}, 300);
});
}).then(() => {
return new Promise((resolve, reject) => {
// show
chart.show();

setTimeout(() => {
expect(spyShown.calledOnce).to.be.true;
expect(spyShown.args[0][0]).to.deep.equal([id]);

resolve(true);
}, 300);
});
}).then(() => {
// when is called already shown, do not call onshown callback
chart.show();

setTimeout(() => {
expect(spyShown.callCount).to.be.equal(1);

done();
}, 300);
});
});
});
});
12 changes: 12 additions & 0 deletions types/options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1665,6 +1665,18 @@ export interface Data {
* - NOTE: For 'area-line-range' and 'area-spline-range', mid data will be taken for the comparison
*/
onmax?(this: Chart, d: DataItem[]): void;

/**
* Set a callback for when data is shown.
* The callback will receive shown data ids in array.
*/
onshown?(): void;

/**
* Set a callback for when data is hidden.
* The callback will receive hidden data ids in array.
*/
onhidden?(): void;
}

export type FormatFunction = (
Expand Down

0 comments on commit af98eb7

Please sign in to comment.