Skip to content

Commit 8d79522

Browse files
committed
shift multi-line <tspan> in common hovermode:'y' hover label
... so that each start-of-line is always visible.
1 parent 2c94e5f commit 8d79522

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

src/components/fx/hover.js

+27-10
Original file line numberDiff line numberDiff line change
@@ -772,18 +772,19 @@ function createHoverText(hoverData, opts, gd) {
772772
var commonBgColor = commonLabelOpts.bgcolor || Color.defaultLine;
773773
var commonStroke = commonLabelOpts.bordercolor || Color.contrast(commonBgColor);
774774
var contrastColor = Color.contrast(commonBgColor);
775+
var commonLabelFont = {
776+
family: commonLabelOpts.font.family || fontFamily,
777+
size: commonLabelOpts.font.size || fontSize,
778+
color: commonLabelOpts.font.color || contrastColor
779+
};
775780

776781
lpath.style({
777782
fill: commonBgColor,
778783
stroke: commonStroke
779784
});
780785

781786
ltext.text(t0)
782-
.call(Drawing.font,
783-
commonLabelOpts.font.family || fontFamily,
784-
commonLabelOpts.font.size || fontSize,
785-
commonLabelOpts.font.color || contrastColor
786-
)
787+
.call(Drawing.font, commonLabelFont)
787788
.call(svgTextUtils.positionText, 0, 0)
788789
.call(svgTextUtils.convertToTspans, gd);
789790

@@ -861,23 +862,39 @@ function createHoverText(hoverData, opts, gd) {
861862
'H' + leftsign + HOVERARROWSIZE + 'V-' + HOVERARROWSIZE + 'Z');
862863

863864
var halfHeight = tbb.height / 2;
865+
var lty = outerTop - tbb.top - halfHeight;
864866
var clipId = 'clip' + fullLayout._uid + 'commonlabel' + ya._id;
865867
var clipPath;
866-
var ltx;
867868

868869
if(lx < (tbb.width + 2 * HOVERTEXTPAD + HOVERARROWSIZE)) {
869-
ltx = tbb.width - lx + HOVERTEXTPAD;
870870
clipPath = 'M-' + (HOVERARROWSIZE + HOVERTEXTPAD) + '-' + halfHeight +
871871
'h-' + (tbb.width - HOVERTEXTPAD) +
872872
'V' + halfHeight +
873873
'h' + (tbb.width - HOVERTEXTPAD) + 'Z';
874+
875+
var ltx = tbb.width - lx + HOVERTEXTPAD;
876+
svgTextUtils.positionText(ltext, ltx, lty);
877+
878+
// shift each line (except the longest) so that start-of-line
879+
// is always visible
880+
if(anchor === 'end') {
881+
ltext.selectAll('tspan').each(function() {
882+
var s = d3.select(this);
883+
var dummy = Drawing.tester.append('text')
884+
.text(s.text())
885+
.call(Drawing.font, commonLabelFont);
886+
var dummyBB = dummy.node().getBoundingClientRect();
887+
if(dummyBB.width < tbb.width) {
888+
s.attr('x', ltx - dummyBB.width);
889+
}
890+
dummy.remove();
891+
});
892+
}
874893
} else {
875-
ltx = sgn * (HOVERTEXTPAD + HOVERARROWSIZE);
894+
svgTextUtils.positionText(ltext, sgn * (HOVERTEXTPAD + HOVERARROWSIZE), lty);
876895
clipPath = null;
877896
}
878897

879-
svgTextUtils.positionText(ltext, ltx, outerTop - tbb.top - halfHeight);
880-
881898
var textClip = fullLayout._topclips.selectAll('#' + clipId).data(clipPath ? [0] : []);
882899
textClip.enter().append('clipPath').attr('id', clipId).append('path');
883900
textClip.exit().remove();

test/jasmine/tests/hover_label_test.js

+24
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,18 @@ describe('hover info', function() {
17671767
var clipId = 'clip' + fullLayout._uid + 'commonlabely';
17681768
var clipPath = d3.select('#' + clipId);
17691769
negateIf(exp.clip, expect(clipPath.node())).toBe(null, 'text clip path|' + msg);
1770+
1771+
if(exp.tspanX) {
1772+
var tspans = label.selectAll('tspan');
1773+
if(tspans.size()) {
1774+
tspans.each(function(d, i) {
1775+
var s = d3.select(this);
1776+
expect(s.attr('x')).toBeWithin(exp.tspanX[i], 5, i + '- tspan shift| ' + msg);
1777+
});
1778+
} else {
1779+
fail('fail to generate tspans in hover label');
1780+
}
1781+
}
17701782
} else {
17711783
fail('fail to generate common hover label');
17721784
}
@@ -1790,6 +1802,18 @@ describe('hover info', function() {
17901802
.then(_assert('on way long label', {txt: 'Waay loooong label', clip: true, ltx: 38}))
17911803
.then(_hoverA)
17921804
.then(_assert('on "a" label', {txt: 'a', clip: false, ltx: -9}))
1805+
.then(function() {
1806+
return Plotly.restyle(gd, {
1807+
y: [['Looong label', 'Loooooger label', 'SHORT!<br>Waay loooong label', 'a']]
1808+
});
1809+
})
1810+
.then(_hoverWayLong)
1811+
.then(_assert('on way long label (multi-line case)', {
1812+
txt: 'SHORT!Waay loooong label',
1813+
clip: true,
1814+
ltx: 38,
1815+
tspanX: [-11, 38]
1816+
}))
17931817
.catch(failTest)
17941818
.then(done);
17951819
});

0 commit comments

Comments
 (0)