Skip to content

Commit

Permalink
feat(axis): Intent to ship axis.y2.tick.rotate
Browse files Browse the repository at this point in the history
- Implement axis.y2.tick.rotate, to make consistent aligned as x and y tick.rotate
- Add missing data type for axis.padding
- Remove unused & undocumented axis.y.padding.ratio

Fix #1157
Fix #1158
  • Loading branch information
netil committed Dec 19, 2019
1 parent e69275b commit 98992f3
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 31 deletions.
52 changes: 50 additions & 2 deletions spec/internals/axis-spec.js
Expand Up @@ -886,7 +886,7 @@ describe("AXIS", function() {
});

describe("axis.y.tick.rotate", () => {
describe("not rotated", () => {
describe("y Axis", () => {
before(() => {
args = {
data: {
Expand Down Expand Up @@ -915,7 +915,7 @@ describe("AXIS", function() {
const transform = text.attr("transform");

transform &&
expect(Math.round(transform.replace(/[A-z()]/g, ""))).to.be.closeTo(45, 5);
expect(Math.round(transform.replace(/[A-z()]/g, ""))).to.be.equal(args.axis.y.tick.rotate);

expect(text.attr("y")).to.be.equal("4");
expect(parseFloat(tspan.attr("dx"))).to.be.closeTo(5.6, 0.5);
Expand All @@ -931,6 +931,54 @@ describe("AXIS", function() {

expect(box.width).to.be.closeTo(590, 1);
});
});

describe("y2 Axis", () => {
before(() => {
args = {
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250, 100, 600],
["data2", 50, 20, 10, 40, 15, 25],
]
},
axis: {
rotated: true,
y2: {
show: true,
tick: {
rotate: 45
}
}
}
};
});

it("should rotate tick texts", done => {
setTimeout(() => {
chart.$.main.selectAll(`.${CLASS.axisY2} g.tick`).each(function() {
const tick = d3Select(this);
const text = tick.select("text");
const tspan = text.select("tspan");
const transform = text.attr("transform");

transform &&
expect(Math.round(transform.replace(/[A-z()]/g, ""))).to.be.equal(args.axis.y2.tick.rotate);

expect(+text.attr("y")).to.be.closeTo(-13, 0.5);
expect(parseFloat(tspan.attr("dx"))).to.be.closeTo(-5.6, 0.5);
});

done();
}, 1000);
});

it("should have automatically calculated y axis width", () => {
const box = chart.$.main.select(`.${CLASS.axisY2}`)
.node().getBoundingClientRect();

expect(box.width).to.be.closeTo(602, 1);
});

});
});
Expand Down
9 changes: 2 additions & 7 deletions src/axis/Axis.js
Expand Up @@ -175,7 +175,7 @@ export default class Axis {
const $$ = this.owner;
const config = $$.config;
const isX = /^(x|subX)$/.test(name);
const type = isX ? "x" : "y";
const type = isX ? "x" : name;

const isCategory = isX && $$.isCategorized();
const orient = $$[`${name}Orient`];
Expand Down Expand Up @@ -579,11 +579,6 @@ export default class Axis {
return defaultValue;
}

if (padding.unit === "ratio") {
return padding[key] * domainLength;
}

// assume padding is pixels if unit is not specified
return this.convertPixelsToAxisPadding(p, domainLength);
}

Expand Down Expand Up @@ -662,7 +657,7 @@ export default class Axis {

redraw(transitions, isHidden, isInit) {
const $$ = this.owner;
const opacity = isHidden ? "0" : "1";
const opacity = isHidden ? "0" : "1";

["x", "y", "y2", "subX"].forEach(id => {
const axis = $$[`${id}Axis`];
Expand Down
24 changes: 17 additions & 7 deletions src/axis/AxisRenderer.js
Expand Up @@ -46,7 +46,6 @@ export default class AxisRenderer {
const scale = helperInst.scale;
const orient = config.orient;
const splitTickText = this.splitTickText.bind(this);

const isLeftRight = /^(left|right)$/.test(orient);
const isTopBottom = /^(top|bottom)$/.test(orient);

Expand Down Expand Up @@ -160,8 +159,8 @@ export default class AxisRenderer {
.attr("dx", (() => {
let dx = 0;

if (orient === "bottom" && rotate) {
dx = 8 * Math.sin(Math.PI * (rotate / 180));
if (/(top|bottom)/.test(orient) && rotate) {
dx = 8 * Math.sin(Math.PI * (rotate / 180)) * (orient === "top" ? -1 : 1);
}

return dx + (tickTextPos.x || 0);
Expand Down Expand Up @@ -264,9 +263,19 @@ export default class AxisRenderer {
const {innerTickSize, orient, tickLength, tickOffset} = this.config;
const rotate = this.params.tickTextRotate;

const textAnchorForText = r => (!r ? "middle" : (r > 0 ? "start" : "end"));
const textAnchorForText = r => {
const value = ["start", "end"];

orient === "top" && value.reverse();

return !r ? "middle" : (r > 0 ? value[0] : value[1]);
};
const textTransform = r => (r ? `rotate(${r})` : null);
const yForText = r => (r ? 11.5 - 2.5 * (r / 15) * (r > 0 ? 1 : -1) : tickLength);
const yForText = r => {
const r2 = r / (orient === "bottom" ? 15 : 23);

return r ? 11.5 - 2.5 * r2 * (r > 0 ? 1 : -1) : tickLength;
};

switch (orient) {
case "bottom":
Expand All @@ -288,8 +297,9 @@ export default class AxisRenderer {

textUpdate
.attr("x", 0)
.attr("y", -tickLength * 2)
.style("text-anchor", "middle");
.attr("y", -yForText(rotate) * 2)
.style("text-anchor", textAnchorForText(rotate))
.attr("transform", textTransform(rotate));
break;
case "left":
lineUpdate
Expand Down
64 changes: 55 additions & 9 deletions src/config/Options.js
Expand Up @@ -1292,7 +1292,7 @@ export default class Options {
* @memberof Options
* @type {Object}
* @property {String|Object|Function} [color.onover] Set the color value for each data point when mouse/touch onover event occurs.
* @property {Array} [color.pattern] custom color pattern
* @property {Array} [color.pattern=[]] custom color pattern
* @property {Function} [color.tiles] if defined, allows use svg's patterns to fill data area. It should return an array of [SVGPatternElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGPatternElement).
* - **NOTE:** The pattern element's id will be defined as `bb-colorize-pattern-$COLOR-VALUE`.<br>
* ex. When color pattern value is `['red', '#fff']` and defined 2 patterns,then ids for pattern elements are:<br>
Expand Down Expand Up @@ -1765,8 +1765,9 @@ export default class Options {
axis_x_tick_values: null,

/**
* Rotate x axis tick text.<br>
* If you set negative value, it will rotate to opposite direction.
* Rotate x axis tick text.
* - If you set negative value, it will rotate to opposite direction.
* - Applied when [`axis.rotated`](#.axis%25E2%2580%25A4rotated) option is `false`.
* @name axis鈥鈥ick鈥otate
* @memberof Options
* @type {Number}
Expand Down Expand Up @@ -1910,7 +1911,7 @@ export default class Options {
* ex. the given value `1000*60*60*24`, which is numeric time equivalent of a day, is same as the width of 1 tick width
* @name axis鈥鈥adding
* @memberof Options
* @type {Object}
* @type {Object|Number}
* @default {}
* @example
* axis: {
Expand All @@ -1923,7 +1924,10 @@ export default class Options {
* // when axis type is 'timeseries'
* left: 1000*60*60*24, // set left padding width of equivalent value of a day tick's width
* right: 1000*60*60*12 // set right padding width as half of equivalent value of a day tick's width
* }
* },
*
* // or set both values at once.
* padding: 10
* }
* }
*/
Expand Down Expand Up @@ -2300,6 +2304,24 @@ export default class Options {
* }
*/
axis_y_tick_values: null,

/**
* Rotate y axis tick text.
* - If you set negative value, it will rotate to opposite direction.
* - Applied when [`axis.rotated`](#.axis%25E2%2580%25A4rotated) option is `true`.
* @name axis鈥鈥ick鈥otate
* @memberof Options
* @type {Number}
* @default 0
* @example
* axis: {
* y: {
* tick: {
* rotate: 60
* }
* }
* }
*/
axis_y_tick_rotate: 0,

/**
Expand Down Expand Up @@ -2412,15 +2434,18 @@ export default class Options {
* - **NOTE:** For area and bar type charts, [area.zerobased](#.area) or [bar.zerobased](#.bar) options should be set to 'false` to get padded bottom.
* @name axis鈥鈥adding
* @memberof Options
* @type {Object}
* @type {Object|Number}
* @default {}
* @example
* axis: {
* y: {
* padding: {
* top: 0,
* bottom: 0
* }
* },
*
* // or set both values at once.
* padding: 10
* }
* }
*/
Expand Down Expand Up @@ -2692,6 +2717,25 @@ export default class Options {
*/
axis_y2_tick_values: null,

/**
* Rotate y2 axis tick text.
* - If you set negative value, it will rotate to opposite direction.
* - Applied when [`axis.rotated`](#.axis%25E2%2580%25A4rotated) option is `true`.
* @name axis鈥2鈥ick鈥otate
* @memberof Options
* @type {Number}
* @default 0
* @example
* axis: {
* y2: {
* tick: {
* rotate: 60
* }
* }
* }
*/
axis_y2_tick_rotate: 0,

/**
* Set the number of y2 axis ticks.
* - **NOTE:** This works in the same way as axis.y.tick.count.
Expand Down Expand Up @@ -2775,7 +2819,7 @@ export default class Options {
* - **NOTE:** This works in the same way as axis.y.tick.count.
* @name axis鈥2鈥adding
* @memberof Options
* @type {Object}
* @type {Object|Number}
* @default {}
* @example
* axis: {
Expand All @@ -2784,7 +2828,9 @@ export default class Options {
* top: 100,
* bottom: 100
* }
* }
*
* // or set both values at once.
* padding: 10
* }
*/
axis_y2_padding: {},
Expand Down
9 changes: 6 additions & 3 deletions src/internals/size.js
Expand Up @@ -219,12 +219,15 @@ extend(ChartInternal.prototype, {
return $$.rotated_padding_top;
}

const rotate = config[`axis_${id}_tick_rotate`];

// Calculate x/y axis height when tick rotated
if ((id === "x" && !isRotated && config.axis_x_tick_rotate) ||
(id === "y" && isRotated && config.axis_y_tick_rotate)) {
if (
((id === "x" && !isRotated) || (/y2?/.test(id) && isRotated)) && rotate
) {
h = 30 +
$$.axis.getMaxTickWidth(id) *
Math.cos(Math.PI * (90 - config[`axis_${id}_tick_rotate`]) / 180);
Math.cos(Math.PI * (90 - rotate) / 180);
}

return h +
Expand Down
15 changes: 12 additions & 3 deletions types/axis.d.ts
Expand Up @@ -56,7 +56,7 @@ export interface XAxisConfiguration {
padding?: {
left?: number;
right?: number;
};
} | number;

/**
* Set height of x axis.
Expand Down Expand Up @@ -150,7 +150,7 @@ export interface YAxisConfiguration {
padding?: {
top?: number;
bottom?: number;
};
} | number;

/**
* Set default range of y axis.
Expand Down Expand Up @@ -216,7 +216,9 @@ export interface XTickConfiguration {
values?: number[] | string[];

/**
* Rotate x axis tick text. If you set negative value, it will rotate to opposite direction.
* Rotate x axis tick text.
* - If you set negative value, it will rotate to opposite direction.
* - Applied when 'axis.rotated' option is 'false'.
*/
rotate?: number;

Expand Down Expand Up @@ -274,6 +276,13 @@ export interface YTickConfiguration {
*/
values?: number[];

/**
* Rotate y(or y2) axis tick text.
* - If you set negative value, it will rotate to opposite direction.
* - Applied when 'axis.rotated' option is 'true'.
*/
rotate?: number;

/**
* The number of y axis ticks to show.
* The position of the ticks will be calculated precisely, so the values on the ticks will not be rounded nicely.
Expand Down

0 comments on commit 98992f3

Please sign in to comment.