Skip to content

Commit 869e054

Browse files
committed
Fix layout of centered hover info #2154
- Bug: when a tooltip displays a sufficiently long text (also depends on overall plot dimensions), the tooltip isn't rendered right or left but centered. In this case the tooltip text was partly rendered outside the tooltip box and the secondary label (the trace name) was hidden underneath the primary label.
1 parent 12e69c8 commit 869e054

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-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) +

test/jasmine/tests/hover_label_test.js

+90
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,96 @@ 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(done) {
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+
done();
1190+
});
1191+
1192+
it('renders secondary info box right to primary info box', function(done) {
1193+
_hover(gd, 300, 150);
1194+
1195+
var nodes = ensureCentered(centeredHoverInfoNodes());
1196+
assertElemRightTo(nodes.secondaryBox, nodes.primaryBox, 'Secondary box right to primary box');
1197+
assertTopsAligned(nodes.secondaryBox, nodes.primaryBox, 'Top edges of primary and secondary boxes aligned');
1198+
1199+
done();
1200+
});
1201+
});
11121202
});
11131203

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

0 commit comments

Comments
 (0)