diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js
index 4e1556f119e..287fe2c5662 100644
--- a/src/plots/cartesian/axes.js
+++ b/src/plots/cartesian/axes.js
@@ -32,6 +32,7 @@ var MINUS_SIGN = constants.MINUS_SIGN;
var BADNUM = constants.BADNUM;
var MID_SHIFT = require('../../constants/alignment').MID_SHIFT;
+var LINE_SPACING = require('../../constants/alignment').LINE_SPACING;
var axes = module.exports = {};
@@ -2039,6 +2040,26 @@ axes.doTicks = function(gd, axid, skipTitle) {
});
}
+ // How much to shift a multi-line label to center it vertically.
+ function getAnchorHeight(lineCount, lineHeight, angle) {
+ var h = (lineCount - 1) * lineHeight;
+ if(axLetter === 'x') {
+ if(angle < -60 || 60 < angle) {
+ return -0.5 * h;
+ } else if(axside === 'top') {
+ return -h;
+ }
+ } else {
+ angle *= axside === 'left' ? 1 : -1;
+ if(angle < -30) {
+ return -h;
+ } else if(angle < 30) {
+ return -0.5 * h;
+ }
+ }
+ return 0;
+ }
+
function positionLabels(s, angle) {
s.each(function(d) {
var anchor = labelanchor(angle, d);
@@ -2049,6 +2070,13 @@ axes.doTicks = function(gd, axid, skipTitle) {
(' rotate(' + angle + ',' + labelx(d) + ',' +
(labely(d) - d.fontSize / 2) + ')') :
'');
+ var anchorHeight = getAnchorHeight(
+ svgTextUtils.lineCount(thisLabel),
+ LINE_SPACING * d.fontSize,
+ isNumeric(angle) ? +angle : 0);
+ if(anchorHeight) {
+ transform += ' translate(0, ' + anchorHeight + ')';
+ }
if(mathjaxGroup.empty()) {
thisLabel.select('text').attr({
transform: transform,
diff --git a/test/image/baselines/bar_multiline_labels.png b/test/image/baselines/bar_multiline_labels.png
new file mode 100644
index 00000000000..7788b298bd8
Binary files /dev/null and b/test/image/baselines/bar_multiline_labels.png differ
diff --git a/test/image/baselines/benchmarks.png b/test/image/baselines/benchmarks.png
index c04e854f6f0..c2186f5ed1f 100644
Binary files a/test/image/baselines/benchmarks.png and b/test/image/baselines/benchmarks.png differ
diff --git a/test/image/baselines/cliponaxis_false-dates-log.png b/test/image/baselines/cliponaxis_false-dates-log.png
index 12979eb1763..37af1d51d69 100644
Binary files a/test/image/baselines/cliponaxis_false-dates-log.png and b/test/image/baselines/cliponaxis_false-dates-log.png differ
diff --git a/test/image/baselines/gl2d_date_axes.png b/test/image/baselines/gl2d_date_axes.png
index 35a016d6f19..072cbe9d151 100644
Binary files a/test/image/baselines/gl2d_date_axes.png and b/test/image/baselines/gl2d_date_axes.png differ
diff --git a/test/image/baselines/world-cals.png b/test/image/baselines/world-cals.png
index 200ed69241a..cb846f1df20 100644
Binary files a/test/image/baselines/world-cals.png and b/test/image/baselines/world-cals.png differ
diff --git a/test/image/mocks/bar_multiline_labels.json b/test/image/mocks/bar_multiline_labels.json
new file mode 100644
index 00000000000..aa9744a0236
--- /dev/null
+++ b/test/image/mocks/bar_multiline_labels.json
@@ -0,0 +1,161 @@
+{
+ "data":[
+ {
+ "type": "bar",
+ "x":["x 1","multiple
lines","one
two
three"],
+ "y":["y 1","multiple
lines","one
two
three"]
+ },
+ {
+ "type": "bar",
+ "x":["x 2","multiple
lines","one
two
three"],
+ "y":["y 2","multiple
lines","one
two
three"],
+ "xaxis": "x2",
+ "yaxis": "y2"
+ },
+ {
+ "type": "bar",
+ "x":["x 3","multiple
lines","one
two
three"],
+ "y":["y 3","multiple
lines","one
two
three"],
+ "xaxis": "x3",
+ "yaxis": "y3"
+ },
+ {
+ "type": "bar",
+ "x":["x 4","multiple
lines","one
two
three"],
+ "y":["y 4","multiple
lines","one
two
three"],
+ "xaxis": "x4",
+ "yaxis": "y4"
+ },
+ {
+ "type": "bar",
+ "orientation": "h",
+ "x":["x 5","multiple
lines","one
two
three"],
+ "y":["y 5","multiple
lines","one
two
three"],
+ "xaxis": "x5",
+ "yaxis": "y5"
+ },
+ {
+ "type": "bar",
+ "orientation": "h",
+ "x":["x 6","multiple
lines","one
two
three"],
+ "y":["y 6","multiple
lines","one
two
three"],
+ "xaxis": "x6",
+ "yaxis": "y6"
+ },
+ {
+ "type": "scatter",
+ "x":["x 7","multiple
lines","one
two
three"],
+ "y":["y 7","multiple
lines","one
two
three"],
+ "xaxis": "x7",
+ "yaxis": "y7"
+ },
+ {
+ "type": "scatter",
+ "x":["x 8","multiple
lines","one
two
three"],
+ "y":["y 8","multiple
lines","one
two
three"],
+ "xaxis": "x8",
+ "yaxis": "y8"
+ }
+ ],
+ "layout":{
+ "showlegend": false,
+ "xaxis": {
+ "ticks": "outside",
+ "domain": [0, 0.4]
+ },
+ "yaxis": {
+ "ticks": "outside",
+ "domain": [0, 0.4]
+ },
+ "xaxis2": {
+ "ticks": "outside",
+ "domain": [0, 0.4],
+ "side": "top",
+ "anchor": "y2",
+ "tickangle": 90
+ },
+ "yaxis2": {
+ "ticks": "outside",
+ "domain": [0, 0.4],
+ "side": "right",
+ "tickangle": 90
+ },
+ "xaxis3": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "tickangle": 90
+ },
+ "yaxis3": {
+ "ticks": "outside",
+ "domain": [0, 0.4],
+ "anchor": "x3",
+ "tickangle": 90
+ },
+ "xaxis4": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "side": "top"
+ },
+ "yaxis4": {
+ "ticks": "outside",
+ "domain": [0, 0.4],
+ "side": "right",
+ "anchor": "x4"
+ },
+ "xaxis5": {
+ "ticks": "outside",
+ "domain": [0, 0.4],
+ "anchor": "y5",
+ "tickangle": 45
+ },
+ "yaxis5": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "anchor": "x5",
+ "tickangle": 45
+ },
+ "xaxis6": {
+ "ticks": "outside",
+ "domain": [0, 0.4],
+ "side": "top",
+ "anchor": "y6",
+ "tickangle": -90
+ },
+ "yaxis6": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "anchor": "x6",
+ "side": "right",
+ "tickangle": -90
+ },
+ "xaxis7": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "anchor": "y7",
+ "tickangle": -90
+ },
+ "yaxis7": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "anchor": "x7",
+ "tickangle": -90
+ },
+ "xaxis8": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "side": "top",
+ "anchor": "y8",
+ "tickangle": -45
+ },
+ "yaxis8": {
+ "ticks": "outside",
+ "domain": [0.6, 1],
+ "side": "right",
+ "anchor": "x8",
+ "tickangle": 45
+ },
+ "legend": "none",
+ "height":800,
+ "width":800
+ }
+}