Skip to content

Commit

Permalink
fix(subchart): Correct subchart extent option
Browse files Browse the repository at this point in the history
- Correct extent to work properly
- Improved to be called once during init & window resizing

Fix #142
Close #805
  • Loading branch information
netil authored Mar 14, 2019
1 parent c73c436 commit eac3e65
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 56 deletions.
94 changes: 78 additions & 16 deletions spec/interactions/subchart-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ describe("SUBCHART", () => {
chart = util.generate(args);
});

// do mouse drag selection
const doDrag = (from = {clientX: 100, clientY: 100}, to = {clientX: 200, clientY: 200}) => {
const overlay = chart.$.svg.select(".overlay").node();

util.fireEvent(overlay, "mousedown", from, chart);
util.fireEvent(overlay, "mousemove", to, chart);
util.fireEvent(overlay, "mouseup", from, chart);
};

describe("generate subchart", () => {
before(() => {
args = {
Expand Down Expand Up @@ -150,24 +159,10 @@ describe("SUBCHART", () => {

const checkSelection = done => {
const selection = chart.$.svg.select(".selection");
const overlay = chart.$.svg.select(".overlay").node();
const baseWidth = 100;

// do mouse selection
util.fireEvent(overlay, "mousedown", {
clientX: 100,
clientY: 100
}, chart);

util.fireEvent(overlay, "mousemove", {
clientX: 200,
clientY: 200
}, chart);

util.fireEvent(overlay, "mouseup", {
clientX: 200,
clientY: 200
}, chart);
// mouse drag selection on subchart
doDrag();

expect(+selection.attr("width")).to.be.equal(baseWidth);

Expand Down Expand Up @@ -195,4 +190,71 @@ describe("SUBCHART", () => {

it("should be select subchart area for category type x axis", checkSelection);
});

describe("the extent", () => {
before(() => {
args = {
data: {
x: "x",
columns: [
['x', '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05'],
["data1", 10, 5, 3, 8, 7]
]
},
subchart: {
show: true
},
axis: {
x: {
type: "timeseries",
tick: {
format: "%Y-%m-%d"
},
extent: [0, 100]
}
}
};
});

it("should be limiting selection area", () => {
const selection = chart.$.svg.select(".selection");

// mouse drag selection on subchart
doDrag( {clientX: 0, clientY: 0}, {clientX: 300, clientY: 300});

// selection shouldn't over pass
expect(Math.floor(selection.attr("width"))).to.be.equal(args.axis.x.extent[1]);
});

it("set options axis.x.extent=datetime", () => {
args.axis.x.extent = ["2019-01-01", "2019-01-02"];
});

it("should be limiting selection area for datetime extent", () => {
const selection = chart.$.svg.select(".selection");
const range = args.axis.x.extent
.map(v => chart.internal.subX(new Date(v)))
.reduce((a, c) => Math.abs(a - c));

// mouse drag selection on subchart
doDrag( {clientX: 0, clientY: 0}, {clientX: 300, clientY: 300});

// selection shouldn't over pass
expect(+selection.attr("width")).to.be.closeTo(range, 10);
});

it("set options axis.x.extent=[0, 100]", () => {
args.axis.x.extent = (domain, scale) => [0, 100];
});

it("should be limiting selection area", () => {
const selection = chart.$.svg.select(".selection");

// mouse drag selection on subchart
doDrag( {clientX: 0, clientY: 0}, {clientX: 300, clientY: 300});

// selection shouldn't over pass
expect(Math.floor(selection.attr("width"))).to.be.equal(args.axis.x.extent()[1]);
});
});
});
12 changes: 5 additions & 7 deletions src/api/api.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,13 @@ extend(Chart.prototype, {
}

domain = [baseValue.x - diff, baseValue.x];
$$.updateXDomain(null, true, true, false, domain);
} else if (orgDataCount === 1) {
if ($$.isTimeSeries()) {
diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
$$.updateXDomain(null, true, true, false, domain);
}
} else if (orgDataCount === 1 && $$.isTimeSeries()) {
diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
}

domain && $$.updateXDomain(null, true, true, false, domain);

// Set targets
$$.updateTargets($$.data.targets);

Expand Down
23 changes: 17 additions & 6 deletions src/config/Options.js
Original file line number Diff line number Diff line change
Expand Up @@ -1815,16 +1815,27 @@ export default class Options {
* Set default extent for subchart and zoom. This can be an array or function that returns an array.
* @name axis․x․extent
* @memberof Options
* @type {Array}
* @type {Array|Function}
* @default undefined
* @example
* axis: {
* x: {
* // [[x0, y0], [x1, y1]], where [x0, y0] is the top-left corner and [x1, y1] is the bottom-right corner
* // https://github.com/d3/d3-brush/blob/master/src/brush.js#L521
* extent: [
* [0, 0], [200, 60]
* ]
* // extent range as a pixel value
* extent: [0, 200],
*
* // when axis is 'timeseries', parsable datetime string
* extent: ["2019-03-01", "2019-03-05"],
*
* // return extent value
* extent: function(domain, scale) {
* var extent = domain.map(function(v) {
* return scale(v);
* });
*
* // it should return a format of array
* // ex) [0, 584]
* return extent;
* }
* }
* }
*/
Expand Down
49 changes: 30 additions & 19 deletions src/interactions/subchart.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from "d3-brush";
import ChartInternal from "../internals/ChartInternal";
import CLASS from "../config/classes";
import {extend, brushEmpty, capitalize, isFunction, getRandom} from "../internals/util";
import {extend, brushEmpty, capitalize, isArray, isFunction, getRandom} from "../internals/util";

extend(ChartInternal.prototype, {
/**
Expand All @@ -32,6 +32,17 @@ extend(ChartInternal.prototype, {
const brushHandler = () => {
$$.redrawForBrush();
};
const getBrushSize = () => {
const brush = $$.svg.select(`.${CLASS.brush} .overlay`);
const brushSize = {width: 0, height: 0};

if (brush.size()) {
brushSize.width = +brush.attr("width");
brushSize.height = +brush.attr("height");
}

return brushSize[isRotated ? "width" : "height"];
};

let lastDomain;
let timeout;
Expand Down Expand Up @@ -67,21 +78,19 @@ extend(ChartInternal.prototype, {
};

// set the brush extent
$$.brush.scale = function(scale, height) {
const extent = [[0, 0]];

if (scale.range) {
extent.push([
scale.range()[1],
height || config.subchart_size_height
]);
} else if (scale.constructor === Array) {
extent.push(scale);
$$.brush.scale = function(scale) {
const h = config.subchart_size_height || getBrushSize();
let extent = $$.getExtent();

if (!extent && scale.range) {
extent = [[0, 0], [scale.range()[1], h]];
} else if (isArray(extent)) {
extent = extent.map((v, i) => [v, i > 0 ? h : i]);
}

// [[x0, y0], [x1, y1]], where [x0, y0] is the top-left corner and [x1, y1] is the bottom-right corner
isRotated && extent[1].reverse();
this.extent(config.axis_x_extent || extent);
this.extent(extent);

// when extent updates, brush selection also be re-applied
// https://github.com/d3/d3/issues/2918
Expand Down Expand Up @@ -411,18 +420,20 @@ extend(ChartInternal.prototype, {
},

/**
* Get default extent
* Get extent value
* @private
* @returns {Array} default extent
*/
getDefaultExtent() {
getExtent() {
const $$ = this;
const config = $$.config;
let extent = isFunction(config.axis_x_extent) ?
config.axis_x_extent($$.getXDomain($$.data.targets)) : config.axis_x_extent;
let extent = $$.config.axis_x_extent;

if ($$.isTimeSeries()) {
extent = [$$.parseDate(extent[0]), $$.parseDate(extent[1])];
if (extent) {
if (isFunction(extent)) {
extent = extent($$.getXDomain($$.data.targets), $$.subX);
} else if ($$.isTimeSeries() && extent.every(isNaN)) {
extent = extent.map(v => $$.subX($$.parseDate(v)));
}
}

return extent;
Expand Down
7 changes: 0 additions & 7 deletions src/internals/ChartInternal.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,6 @@ export default class ChartInternal {
.style("opacity", "0")
.on("dblclick.zoom", null);

// Set default extent if defined
config.axis_x_extent &&
$$.brush.scale($$.getDefaultExtent());

// Add Axis here, when clipPath is 'true'
config.clipPath && $$.axis.init();

Expand Down Expand Up @@ -1095,7 +1091,6 @@ export default class ChartInternal {

updateSvgSize() {
const $$ = this;
const isRotated = $$.config.axis_rotated;
const brush = $$.svg.select(`.${CLASS.brush} .overlay`);
const brushSize = {width: 0, height: 0};

Expand Down Expand Up @@ -1135,8 +1130,6 @@ export default class ChartInternal {
$$.svg.select(`.${CLASS.zoomRect}`)
.attr("width", $$.width)
.attr("height", $$.height);

$$.brush && $$.brush.scale($$.subX, brushSize[isRotated ? "width" : "height"]);
}

updateDimension(withoutAxis) {
Expand Down
7 changes: 6 additions & 1 deletion types/axis.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ export interface XAxisConfiguration {
* Set default extent for subchart and zoom.
* This can be an array or function that returns an array.
*/
extent?: number[] | (() => number[]);
extent?: number[] | string[] | (
(
domain: Date|string|number[],
scale: (value: any) => number
) => number[]
);

/**
* Set label on x axis.
Expand Down

0 comments on commit eac3e65

Please sign in to comment.