Skip to content

Commit

Permalink
fix(axis): Fix axis label text position
Browse files Browse the repository at this point in the history
- Add condition to handle axis label when tick.rotate option applied
- Refactored axis label position related code

Fix #1270
  • Loading branch information
netil authored Mar 5, 2020
1 parent 8d45075 commit 68b6b86
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 110 deletions.
79 changes: 79 additions & 0 deletions spec/internals/axis-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,85 @@ describe("AXIS", function() {
});
});

describe("axis outer label position", () => {
before(() => {
args = {
data: {
x: "x",
columns: [
["x", "www.site1.com", "www.site2.com", "www.site3.com", "www.site4.com"],
["download", 3000, 2000, 1000, 4000],
],
type: "bar"
},
axis: {
x: {
type: "category",
tick: {
rotate: 70
},
label: {
text: "number",
position: "outer-center"
}
},
y: {
tick: {
rotate: 60
},
label: {
text: "y text",
position: "outer-center"
}
},
y2: {
show: true,
tick: {
rotate: 70
},
label: {
text: "number",
position: "outer-center"
}
}
}
}
});

const checkLabelPos = id => {
const axis = chart.$.main.select(`.${CLASS[`axis${id.toUpperCase()}`]}`);
const tickRect = axis.select(".tick").node().getBoundingClientRect();
const labelRect = axis.select("text").node().getBoundingClientRect();

// label text is positioned below of tick text?
expect(labelRect.y).to.be[id == "y2" ? "below": "above"](tickRect.y + tickRect.height);
}

it("when legend is visible: x Axis label text is positioned below of tick text?", () => {
checkLabelPos("x");
});

it("set option legend.show", () => {
args.legend = {show: false};
});

it("when legend is invisible: x Axis label text is positioned below of tick text?", () => {
checkLabelPos("x");
});

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

it("y Axis label text is positioned below of tick text?", () => {
checkLabelPos("y");
});

it("y2 Axis label text is positioned above of tick text?", () => {
checkLabelPos("y2");
});
});

describe("axis y timeseries", () => {
before(() => {
args = {
Expand Down
165 changes: 57 additions & 108 deletions src/axis/Axis.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ export default class Axis {

target.forEach(v => {
const classAxis = getAxisClassName(v);
const axisId = v.toUpperCase();
const classLabel = CLASS[`axis${axisId}Label`];
const classLabel = CLASS[`axis${v.toUpperCase()}Label`];

$$.axes[v] = main.append("g")
.attr("class", classAxis)
Expand All @@ -63,7 +62,7 @@ export default class Axis {
.attr("transform", ["rotate(-90)", null][
v === "x" ? +!isRotated : +isRotated
])
.style("text-anchor", this[`textAnchorFor${axisId}AxisLabel`].bind(this));
.style("text-anchor", () => this.textAnchorForAxisLabel(v));

this.generateAxes(v);
});
Expand Down Expand Up @@ -345,39 +344,20 @@ export default class Axis {
};
}

getXAxisLabelPosition() {
return this.getLabelPosition("x", ["inner-top", "inner-right"]);
}

getYAxisLabelPosition() {
return this.getLabelPosition("y", ["inner-right", "inner-top"]);
}

getY2AxisLabelPosition() {
return this.getLabelPosition("y2", ["inner-right", "inner-top"]);
getAxisLabelPosition(id) {
return this.getLabelPosition(id, id === "x" ? ["inner-top", "inner-right"] : ["inner-right", "inner-top"]);
}

getLabelPositionById(id) {
return this[`get${id.toUpperCase()}AxisLabelPosition`]();
}

textForXAxisLabel() {
return this.getLabelText("x");
return this.getAxisLabelPosition(id);
}

textForYAxisLabel() {
return this.getLabelText("y");
}

textForY2AxisLabel() {
return this.getLabelText("y2");
}

xForAxisLabel(position, forHorizontal = true) {
xForAxisLabel(id) {
const $$ = this.owner;
const position = this.getAxisLabelPosition(id);
let x = position.isMiddle ? -$$.height / 2 : 0;

if (isHorizontal($$, forHorizontal)) {
if (isHorizontal($$, id !== "x")) {
x = position.isLeft ? 0 : (
position.isCenter ? $$.width / 2 : $$.width
);
Expand All @@ -388,11 +368,12 @@ export default class Axis {
return x;
}

dxForAxisLabel(position, forHorizontal = true) {
dxForAxisLabel(id) {
const $$ = this.owner;
const position = this.getAxisLabelPosition(id);
let dx = position.isBottom ? "0.5em" : "0";

if (isHorizontal($$, forHorizontal)) {
if (isHorizontal($$, id !== "x")) {
dx = position.isLeft ? "0.5em" : (
position.isRight ? "-0.5em" : "0"
);
Expand All @@ -403,11 +384,12 @@ export default class Axis {
return dx;
}

textAnchorForAxisLabel(position, forHorizontal = true) {
textAnchorForAxisLabel(id) {
const $$ = this.owner;
const position = this.getAxisLabelPosition(id);
let anchor = position.isMiddle ? "middle" : "end";

if (isHorizontal($$, forHorizontal)) {
if (isHorizontal($$, id !== "x")) {
anchor = position.isLeft ? "start" : (
position.isCenter ? "middle" : "end"
);
Expand All @@ -418,81 +400,49 @@ export default class Axis {
return anchor;
}

xForXAxisLabel() {
return this.xForAxisLabel(this.getXAxisLabelPosition(), false);
}

xForYAxisLabel() {
return this.xForAxisLabel(this.getYAxisLabelPosition());
}

xForY2AxisLabel() {
return this.xForAxisLabel(this.getY2AxisLabelPosition());
}

dxForXAxisLabel() {
return this.dxForAxisLabel(this.getXAxisLabelPosition(), false);
}

dxForYAxisLabel() {
return this.dxForAxisLabel(this.getYAxisLabelPosition());
}

dxForY2AxisLabel() {
return this.dxForAxisLabel(this.getY2AxisLabelPosition());
}

dyForXAxisLabel() {
dyForAxisLabel(id) {
const $$ = this.owner;
const config = $$.config;
const isInner = this.getXAxisLabelPosition().isInner;
const xHeight = config.axis_x_height;

if (config.axis_rotated) {
return isInner ? "1.2em" : -25 - this.getMaxTickWidth("x");
} else if (isInner) {
return "-0.5em";
} else if (xHeight) {
return xHeight - 10;
} else {
return "3em";
}
}

dyForYAxisLabel() {
const $$ = this.owner;
const isInner = this.getYAxisLabelPosition().isInner;

if ($$.config.axis_rotated) {
return isInner ? "-0.5em" : "3em";
} else {
return isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : (this.getMaxTickWidth("y") + 10));
}
}

dyForY2AxisLabel() {
const $$ = this.owner;
const isInner = this.getY2AxisLabelPosition().isInner;
const isRotated = config.axis_rotated;
const isInner = this.getAxisLabelPosition(id).isInner;

if ($$.config.axis_rotated) {
return isInner ? "1.2em" : "-2.2em";
if (id === "x") {
const xHeight = config.axis_x_height;

if (isRotated) {
return isInner ? "1.2em" : -25 - this.getMaxTickWidth(id);
} else if (isInner) {
return "-0.5em";
} else if (xHeight) {
return xHeight - 10;
} else if (config.axis_x_tick_rotate) {
return $$.getHorizontalAxisHeight(id) - 10;
} else {
return "3em";
}
} else {
return isInner ? "-0.5em" : 15 + ($$.config.axis_y2_inner ? 0 : (this.getMaxTickWidth("y2") + 15));
const dy = {
y: ["-0.5em", 10, "3em", "1.2em", 10],
y2: ["1.2em", -20, "-2.2em", "-0.5em", 15]
}[id];

if (isRotated) {
if (isInner) {
return dy[0];
} else if ($$.config[`axis_${id}_tick_rotate`]) {
return $$.getHorizontalAxisHeight(id) * (id === "y2" ? -1 : 1) - dy[1];
} else {
return dy[2];
}
} else {
return isInner ?
dy[3] : dy[4] + (
$$.config[`axis_${id}_inner`] ? 0 : (this.getMaxTickWidth(id) + dy[4])
) * (id === "y" ? -1 : 1);
}
}
}

textAnchorForXAxisLabel() {
return this.textAnchorForAxisLabel(this.getXAxisLabelPosition(), false);
}

textAnchorForYAxisLabel() {
return this.textAnchorForAxisLabel(this.getYAxisLabelPosition());
}

textAnchorForY2AxisLabel() {
return this.textAnchorForAxisLabel(this.getY2AxisLabelPosition());
}

getMaxTickWidth(id, withoutRecompute) {
const $$ = this.owner;
const config = $$.config;
Expand Down Expand Up @@ -561,21 +511,20 @@ export default class Axis {
updateLabels(withTransition) {
const $$ = this.owner;
const labels = {
X: $$.main.select(`.${CLASS.axisX} .${CLASS.axisXLabel}`),
Y: $$.main.select(`.${CLASS.axisY} .${CLASS.axisYLabel}`),
Y2: $$.main.select(`.${CLASS.axisY2} .${CLASS.axisY2Label}`)
x: $$.main.select(`.${CLASS.axisX} .${CLASS.axisXLabel}`),
y: $$.main.select(`.${CLASS.axisY} .${CLASS.axisYLabel}`),
y2: $$.main.select(`.${CLASS.axisY2} .${CLASS.axisY2Label}`)
};

Object.keys(labels).filter(id => !labels[id].empty())
.forEach(v => {
const node = labels[v];
const axisLabel = `${v}AxisLabel`;

(withTransition ? node.transition() : node)
.attr("x", this[`xFor${axisLabel}`].bind(this))
.attr("dx", this[`dxFor${axisLabel}`].bind(this))
.attr("dy", this[`dyFor${axisLabel}`].bind(this))
.text(this[`textFor${axisLabel}`].bind(this));
.attr("x", () => this.xForAxisLabel(v))
.attr("dx", () => this.dxForAxisLabel(v))
.attr("dy", () => this.dyForAxisLabel(v))
.text(() => this.getLabelText(v));
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/internals/size.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ extend(ChartInternal.prototype, {
padding = !config.axis_x_show ?
1 : Math.max(ceil10(axisWidth), 40);
} else if (!config.axis_y_show || config.axis_y_inner) { // && !config.axis_rotated
padding = $$.axis.getYAxisLabelPosition().isOuter ? 30 : 1;
padding = $$.axis.getAxisLabelPosition("y").isOuter ? 30 : 1;
} else {
padding = ceil10(axisWidth);
}
Expand All @@ -119,7 +119,7 @@ extend(ChartInternal.prototype, {
padding = defaultPadding + legendWidthOnRight;
} else if (!config.axis_y2_show || config.axis_y2_inner) { // && !config.axis_rotated
padding = 2 + legendWidthOnRight +
($$.axis.getY2AxisLabelPosition().isOuter ? 20 : 0);
($$.axis.getAxisLabelPosition("y2").isOuter ? 20 : 0);
} else {
padding = ceil10(axisWidth) + legendWidthOnRight;
}
Expand Down

0 comments on commit 68b6b86

Please sign in to comment.