Skip to content

Commit f262dc9

Browse files
committed
Merge branch 'master' into react-autosize
2 parents 9913afe + 3bff26f commit f262dc9

File tree

9 files changed

+278
-2
lines changed

9 files changed

+278
-2
lines changed

src/components/fx/hover.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,7 @@ function alignHoverText(hoverLabels, rotateLabels) {
11261126
offsetY = d.offset;
11271127
if(d.anchor === 'middle') {
11281128
txx -= d.tx2width / 2;
1129-
tx2x -= d.tx2width / 2;
1129+
tx2x += d.txwidth / 2 + HOVERTEXTPAD;
11301130
}
11311131
if(rotateLabels) {
11321132
offsetY *= -YSHIFTY;
@@ -1135,7 +1135,8 @@ function alignHoverText(hoverLabels, rotateLabels) {
11351135

11361136
g.select('path').attr('d', d.anchor === 'middle' ?
11371137
// middle aligned: rect centered on data
1138-
('M-' + (d.bx / 2) + ',-' + (d.by / 2) + 'h' + d.bx + 'v' + d.by + 'h-' + d.bx + 'Z') :
1138+
('M-' + (d.bx / 2 + d.tx2width / 2) + ',-' + (d.by / 2) +
1139+
'h' + d.bx + 'v' + d.by + 'h-' + d.bx + 'Z') :
11391140
// left or right aligned: side rect with arrow to data
11401141
('M0,0L' + (horzSign * HOVERARROWSIZE + offsetX) + ',' + (HOVERARROWSIZE + offsetY) +
11411142
'v' + (d.by / 2 - HOVERARROWSIZE) +

src/plots/cartesian/axes.js

+28
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var MINUS_SIGN = constants.MINUS_SIGN;
3131
var BADNUM = constants.BADNUM;
3232

3333
var MID_SHIFT = require('../../constants/alignment').MID_SHIFT;
34+
var LINE_SPACING = require('../../constants/alignment').LINE_SPACING;
3435

3536
var axes = module.exports = {};
3637

@@ -1756,6 +1757,26 @@ axes.doTicks = function(gd, axid, skipTitle) {
17561757
});
17571758
}
17581759

1760+
// How much to shift a multi-line label to center it vertically.
1761+
function getAnchorHeight(lineCount, lineHeight, angle) {
1762+
var h = (lineCount - 1) * lineHeight;
1763+
if(axLetter === 'x') {
1764+
if(angle < -60 || 60 < angle) {
1765+
return -0.5 * h;
1766+
} else if(axside === 'top') {
1767+
return -h;
1768+
}
1769+
} else {
1770+
angle *= axside === 'left' ? 1 : -1;
1771+
if(angle < -30) {
1772+
return -h;
1773+
} else if(angle < 30) {
1774+
return -0.5 * h;
1775+
}
1776+
}
1777+
return 0;
1778+
}
1779+
17591780
function positionLabels(s, angle) {
17601781
s.each(function(d) {
17611782
var anchor = labelanchor(angle, d);
@@ -1766,6 +1787,13 @@ axes.doTicks = function(gd, axid, skipTitle) {
17661787
(' rotate(' + angle + ',' + labelx(d) + ',' +
17671788
(labely(d) - d.fontSize / 2) + ')') :
17681789
'');
1790+
var anchorHeight = getAnchorHeight(
1791+
svgTextUtils.lineCount(thisLabel),
1792+
LINE_SPACING * d.fontSize,
1793+
isNumeric(angle) ? +angle : 0);
1794+
if(anchorHeight) {
1795+
transform += ' translate(0, ' + anchorHeight + ')';
1796+
}
17691797
if(mathjaxGroup.empty()) {
17701798
thisLabel.select('text').attr({
17711799
transform: transform,
71.2 KB
Loading

test/image/baselines/benchmarks.png

-65 Bytes
Loading
348 Bytes
Loading
101 Bytes
Loading

test/image/baselines/world-cals.png

322 Bytes
Loading
+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
{
2+
"data":[
3+
{
4+
"type": "bar",
5+
"x":["x 1","multiple<br>lines","one<br >two<BR>three"],
6+
"y":["y 1","multiple<br>lines","one<br >two<BR>three"]
7+
},
8+
{
9+
"type": "bar",
10+
"x":["x 2","multiple<br>lines","one<br>two<br>three"],
11+
"y":["y 2","multiple<br>lines","one<br>two<br>three"],
12+
"xaxis": "x2",
13+
"yaxis": "y2"
14+
},
15+
{
16+
"type": "bar",
17+
"x":["x 3","multiple<br>lines","one<br>two<br>three"],
18+
"y":["y 3","multiple<br>lines","one<br>two<br>three"],
19+
"xaxis": "x3",
20+
"yaxis": "y3"
21+
},
22+
{
23+
"type": "bar",
24+
"x":["x 4","multiple<br>lines","one<br>two<br>three"],
25+
"y":["y 4","multiple<br>lines","one<br>two<br>three"],
26+
"xaxis": "x4",
27+
"yaxis": "y4"
28+
},
29+
{
30+
"type": "bar",
31+
"orientation": "h",
32+
"x":["x 5","multiple<br>lines","one<br>two<br>three"],
33+
"y":["y 5","multiple<br>lines","one<br>two<br>three"],
34+
"xaxis": "x5",
35+
"yaxis": "y5"
36+
},
37+
{
38+
"type": "bar",
39+
"orientation": "h",
40+
"x":["x 6","multiple<br>lines","one<br>two<br>three"],
41+
"y":["y 6","multiple<br>lines","one<br>two<br>three"],
42+
"xaxis": "x6",
43+
"yaxis": "y6"
44+
},
45+
{
46+
"type": "scatter",
47+
"x":["x 7","multiple<br>lines","one<br>two<br>three"],
48+
"y":["y 7","multiple<br>lines","one<br>two<br>three"],
49+
"xaxis": "x7",
50+
"yaxis": "y7"
51+
},
52+
{
53+
"type": "scatter",
54+
"x":["x 8","multiple<br>lines","one<br>two<br>three"],
55+
"y":["y 8","multiple<br>lines","one<br>two<br>three"],
56+
"xaxis": "x8",
57+
"yaxis": "y8"
58+
}
59+
],
60+
"layout":{
61+
"showlegend": false,
62+
"xaxis": {
63+
"ticks": "outside",
64+
"domain": [0, 0.4]
65+
},
66+
"yaxis": {
67+
"ticks": "outside",
68+
"domain": [0, 0.4]
69+
},
70+
"xaxis2": {
71+
"ticks": "outside",
72+
"domain": [0, 0.4],
73+
"side": "top",
74+
"anchor": "y2",
75+
"tickangle": 90
76+
},
77+
"yaxis2": {
78+
"ticks": "outside",
79+
"domain": [0, 0.4],
80+
"side": "right",
81+
"tickangle": 90
82+
},
83+
"xaxis3": {
84+
"ticks": "outside",
85+
"domain": [0.6, 1],
86+
"tickangle": 90
87+
},
88+
"yaxis3": {
89+
"ticks": "outside",
90+
"domain": [0, 0.4],
91+
"anchor": "x3",
92+
"tickangle": 90
93+
},
94+
"xaxis4": {
95+
"ticks": "outside",
96+
"domain": [0.6, 1],
97+
"side": "top"
98+
},
99+
"yaxis4": {
100+
"ticks": "outside",
101+
"domain": [0, 0.4],
102+
"side": "right",
103+
"anchor": "x4"
104+
},
105+
"xaxis5": {
106+
"ticks": "outside",
107+
"domain": [0, 0.4],
108+
"anchor": "y5",
109+
"tickangle": 45
110+
},
111+
"yaxis5": {
112+
"ticks": "outside",
113+
"domain": [0.6, 1],
114+
"anchor": "x5",
115+
"tickangle": 45
116+
},
117+
"xaxis6": {
118+
"ticks": "outside",
119+
"domain": [0, 0.4],
120+
"side": "top",
121+
"anchor": "y6",
122+
"tickangle": -90
123+
},
124+
"yaxis6": {
125+
"ticks": "outside",
126+
"domain": [0.6, 1],
127+
"anchor": "x6",
128+
"side": "right",
129+
"tickangle": -90
130+
},
131+
"xaxis7": {
132+
"ticks": "outside",
133+
"domain": [0.6, 1],
134+
"anchor": "y7",
135+
"tickangle": -90
136+
},
137+
"yaxis7": {
138+
"ticks": "outside",
139+
"domain": [0.6, 1],
140+
"anchor": "x7",
141+
"tickangle": -90
142+
},
143+
"xaxis8": {
144+
"ticks": "outside",
145+
"domain": [0.6, 1],
146+
"side": "top",
147+
"anchor": "y8",
148+
"tickangle": -45
149+
},
150+
"yaxis8": {
151+
"ticks": "outside",
152+
"domain": [0.6, 1],
153+
"side": "right",
154+
"anchor": "x8",
155+
"tickangle": 45
156+
},
157+
"legend": "none",
158+
"height":800,
159+
"width":800
160+
}
161+
}

test/jasmine/tests/hover_label_test.js

+86
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,92 @@ describe('hover info', function() {
11091109
});
11101110

11111111
});
1112+
1113+
describe('centered', function() {
1114+
var trace1 = {
1115+
x: ['giraffes'],
1116+
y: [5],
1117+
name: 'LA Zoo',
1118+
type: 'bar',
1119+
text: ['Way too long hover info!']
1120+
};
1121+
var trace2 = {
1122+
x: ['giraffes'],
1123+
y: [5],
1124+
name: 'SF Zoo',
1125+
type: 'bar',
1126+
text: ['San Francisco']
1127+
};
1128+
var data = [trace1, trace2];
1129+
var layout = {width: 600, height: 300, barmode: 'stack'};
1130+
1131+
var gd;
1132+
1133+
beforeEach(function(done) {
1134+
gd = createGraphDiv();
1135+
Plotly.plot(gd, data, layout).then(done);
1136+
});
1137+
1138+
function centeredHoverInfoNodes() {
1139+
var g = d3.selectAll('g.hoverlayer g.hovertext').filter(function() {
1140+
return !d3.select(this).select('[data-unformatted="LA Zoo"]').empty();
1141+
});
1142+
1143+
return {
1144+
primaryText: g.select('text:not([data-unformatted="LA Zoo"])').node(),
1145+
primaryBox: g.select('path').node(),
1146+
secondaryText: g.select('[data-unformatted="LA Zoo"]').node(),
1147+
secondaryBox: g.select('rect').node()
1148+
};
1149+
}
1150+
1151+
function ensureCentered(hoverInfoNodes) {
1152+
expect(hoverInfoNodes.primaryText.getAttribute('text-anchor')).toBe('middle');
1153+
expect(hoverInfoNodes.secondaryText.getAttribute('text-anchor')).toBe('middle');
1154+
return hoverInfoNodes;
1155+
}
1156+
1157+
function assertElemInside(elem, container, msg) {
1158+
var elemBB = elem.getBoundingClientRect();
1159+
var contBB = container.getBoundingClientRect();
1160+
expect(contBB.left < elemBB.left &&
1161+
contBB.right > elemBB.right &&
1162+
contBB.top < elemBB.top &&
1163+
contBB.bottom > elemBB.bottom).toBe(true, msg);
1164+
}
1165+
1166+
function assertElemRightTo(elem, refElem, msg) {
1167+
var elemBB = elem.getBoundingClientRect();
1168+
var refElemBB = refElem.getBoundingClientRect();
1169+
expect(elemBB.left >= refElemBB.right).toBe(true, msg);
1170+
}
1171+
1172+
function assertTopsAligned(elem1, elem2, msg) {
1173+
var elem1BB = elem1.getBoundingClientRect();
1174+
var elem2BB = elem2.getBoundingClientRect();
1175+
1176+
// Hint: toBeWithin tolerance is exclusive, hence a
1177+
// diff of exactly 1 would fail the test
1178+
var tolerance = 1.1;
1179+
expect(elem1BB.top - elem2BB.top).toBeWithin(0, tolerance, msg);
1180+
}
1181+
1182+
it('renders labels inside boxes', function() {
1183+
_hover(gd, 300, 150);
1184+
1185+
var nodes = ensureCentered(centeredHoverInfoNodes());
1186+
assertElemInside(nodes.primaryText, nodes.primaryBox, 'Primary text inside box');
1187+
assertElemInside(nodes.secondaryText, nodes.secondaryBox, 'Secondary text inside box');
1188+
});
1189+
1190+
it('renders secondary info box right to primary info box', function() {
1191+
_hover(gd, 300, 150);
1192+
1193+
var nodes = ensureCentered(centeredHoverInfoNodes());
1194+
assertElemRightTo(nodes.secondaryBox, nodes.primaryBox, 'Secondary box right to primary box');
1195+
assertTopsAligned(nodes.secondaryBox, nodes.primaryBox, 'Top edges of primary and secondary boxes aligned');
1196+
});
1197+
});
11121198
});
11131199

11141200
describe('hover info on stacked subplots', function() {

0 commit comments

Comments
 (0)