Skip to content

Commit

Permalink
feat(axis): Intent to ship y/y2 axis culling
Browse files Browse the repository at this point in the history
- Implement y/y2 axes culling
- Fix .sortValue() being falsy when treating 0

Fix #915
  • Loading branch information
netil committed Jul 31, 2019
1 parent e1fc0d4 commit 44c6c4c
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 97 deletions.
31 changes: 31 additions & 0 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,37 @@ var demos = {
}
}
},
YAxisTickCulling: {
options: {
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250, 200, 100, 400, 150, 250],
["data2", 130, 100, 200, 250, 250, 150, 230, 300, 200, 300, 250, 150, 330, 100, 200, 100, 350, 50, 100, 200, 300, 250, 150]
],
axes: {
data2: "y2"
},
types: {
data1: "bar"
}
},
axis: {
y: {
tick: {
culling: {
max: 3
}
}
},
y2: {
show: true,
tick: {
culling: true
}
}
}
}
},
YAxisTickFormat: {
options: {
data: {
Expand Down
67 changes: 67 additions & 0 deletions spec/internals/axis-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1528,4 +1528,71 @@ describe("AXIS", function() {
);
});
});

describe("Axes tick culling", () => {
before(() => {
args = {
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250, 200, 100, 400, 150, 250],
["data2", 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250, 30, 200, 100, 400, 150, 250, 200, 100, 400, 150, 250]
],
axes: {
data2: "y2"
}
},
axis: {
x: {
tick: {
culling: {
max: 4
}
}
},
y: {
tick: {
culling: {
max: 3
}
}
},
y2: {
show: true,
tick: {
culling: true
}
}
}
};
});

const checkTickValues = () => {
const expected = {
x: [0, 6, 12, 18],
y: [0, 200, 400],
y2: [0, 100, 200, 300, 400]
};

["x", "y", "y2"].forEach(v => {
const data = chart.internal.axes[v]
.selectAll(".tick text").filter(function() {
return this.style.display === "block";
}).data();

expect(data).to.be.deep.equal(expected[v]);
});
}

it("check tick values are culled", () => {
checkTickValues();
});

it("set options axis.rotated=true", () => {
args.axis.rotated = true;
});

it("check tick values are culled when axis is rotated", () => {
checkTickValues();
});
});
});
114 changes: 113 additions & 1 deletion src/axis/Axis.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
axisRight as d3AxisRight
} from "d3-axis";
import CLASS from "../config/classes";
import {capitalize, isArray, isFunction, isString, isValue, isEmpty, isNumber, isObjectType} from "../internals/util";
import {capitalize, isArray, isFunction, isString, isValue, isEmpty, isNumber, isObjectType, sortValue} from "../internals/util";
import AxisRenderer from "./AxisRenderer";

const isHorizontal = ($$, forHorizontal) => {
Expand Down Expand Up @@ -665,4 +665,116 @@ export default class Axis {

this.updateAxes();
}

/**
* Redraw axis
* @param {Object} targetsToShow targets data to be shown
* @param {Object} wth
* @param {Ojbect} transitions
* @param {Object} flow
* @private
*/
redrawAxis(targetsToShow, wth, transitions, flow, isInit) {
const $$ = this.owner;
const config = $$.config;
const hasZoom = !!$$.zoomScale;
let xDomainForZoom;

if (!hasZoom && $$.isCategorized() && targetsToShow.length === 0) {
$$.x.domain([0, $$.axes.x.selectAll(".tick").size()]);
}

if ($$.x && targetsToShow.length) {
!hasZoom &&
$$.updateXDomain(targetsToShow, wth.UpdateXDomain, wth.UpdateOrgXDomain, wth.TrimXDomain);

if (!config.axis_x_tick_values) {
this.updateXAxisTickValues(targetsToShow);
}
} else if ($$.xAxis) {
$$.xAxis.tickValues([]);
$$.subXAxis.tickValues([]);
}

if (config.zoom_rescale && !flow) {
xDomainForZoom = $$.x.orgDomain();
}

["y", "y2"].forEach(key => {
const axis = $$[key];

if (axis) {
const tickValues = config[`axis_${key}_tick_values`];
const tickCount = config[`axis_${key}_tick_count`];

axis.domain($$.getYDomain(targetsToShow, key, xDomainForZoom));

if (!tickValues && tickCount) {
const domain = axis.domain();

$$[`${key}Axis`].tickValues(
this.generateTickValues(
domain,
domain.every(v => v === 0) ? 1 : tickCount,
$$.isTimeSeriesY()
)
);
}
}
});

// axes
this.redraw(transitions, $$.hasArcType(), isInit);

// Update axis label
this.updateLabels(wth.Transition);

// show/hide if manual culling needed
if ((wth.UpdateXDomain || wth.UpdateXAxis) && targetsToShow.length) {
this.setCulling();
}

// Update sub domain
if (wth.Y) {
$$.subY && $$.subY.domain($$.getYDomain(targetsToShow, "y"));
$$.subY2 && $$.subY2.domain($$.getYDomain(targetsToShow, "y2"));
}
}

/**
* Set manual culling
* @private
*/
setCulling() {
const $$ = this.owner;
const config = $$.config;

["x", "y", "y2"].forEach(type => {
const axis = $$.axes[type];
const toCull = config[`axis_${type}_tick_culling`];

if (axis && toCull) {
const tickText = axis.selectAll(".tick text");
const tickValues = sortValue(tickText.data());
const tickSize = tickValues.length;
const cullingMax = config[`axis_${type}_tick_culling_max`];
let intervalForCulling;

if (tickSize) {
for (let i = 1; i < tickSize; i++) {
if (tickSize / i < cullingMax) {
intervalForCulling = i;
break;
}
}

tickText.each(function(d) {
this.style.display = tickValues.indexOf(d) % intervalForCulling ? "none" : "block";
});
} else {
tickText.style("display", "block");
}
}
});
}
}
76 changes: 76 additions & 0 deletions src/config/Options.js
Original file line number Diff line number Diff line change
Expand Up @@ -2166,6 +2166,44 @@ export default class Options {
*/
axis_y_tick_format: undefined,

/**
* Setting for culling ticks.<br><br>
* If true is set, the ticks will be culled, then only limitted tick text will be shown. This option does not hide the tick lines. If false is set, all of ticks will be shown.<br><br>
* We can change the number of ticks to be shown by axis.y.tick.culling.max.
* @name axis鈥鈥ick鈥ulling
* @memberof Options
* @type {Boolean}
* @default false
* @example
* axis: {
* y: {
* tick: {
* culling: false
* }
* }
* }
*/
axis_y_tick_culling: false,

/**
* The number of tick texts will be adjusted to less than this value.
* @name axis鈥鈥ick鈥ulling鈥ax
* @memberof Options
* @type {Number}
* @default 5
* @example
* axis: {
* y: {
* tick: {
* culling: {
* max: 5
* }
* }
* }
* }
*/
axis_y_tick_culling_max: 5,

/**
* Show y axis outer tick.
* @name axis鈥鈥ick鈥uter
Expand Down Expand Up @@ -2511,6 +2549,44 @@ export default class Options {
*/
axis_y2_tick_format: undefined,

/**
* Setting for culling ticks.<br><br>
* If true is set, the ticks will be culled, then only limitted tick text will be shown. This option does not hide the tick lines. If false is set, all of ticks will be shown.<br><br>
* We can change the number of ticks to be shown by axis.y.tick.culling.max.
* @name axis鈥2鈥ick鈥ulling
* @memberof Options
* @type {Boolean}
* @default false
* @example
* axis: {
* y2: {
* tick: {
* culling: false
* }
* }
* }
*/
axis_y2_tick_culling: false,

/**
* The number of tick texts will be adjusted to less than this value.
* @name axis鈥2鈥ick鈥ulling鈥ax
* @memberof Options
* @type {Number}
* @default 5
* @example
* axis: {
* y2: {
* tick: {
* culling: {
* max: 5
* }
* }
* }
* }
*/
axis_y2_tick_culling_max: 5,

/**
* Show or hide y2 axis outer tick.
* @name axis鈥2鈥ick鈥uter
Expand Down
Loading

0 comments on commit 44c6c4c

Please sign in to comment.