Skip to content

Commit 315272b

Browse files
authored
Merge pull request #2414 from plotly/bar-hover-width
push hover labels in to the bar group extent in compare mode
2 parents 36b8483 + 47cfe32 commit 315272b

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

src/traces/bar/hover.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,9 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
128128
pointData[sizeLetter + '0'] = pointData[sizeLetter + '1'] = sa.c2p(di[sizeLetter], true);
129129
pointData[sizeLetter + 'LabelVal'] = size;
130130

131-
pointData[posLetter + '0'] = pa.c2p(minPos(di), true);
132-
pointData[posLetter + '1'] = pa.c2p(maxPos(di), true);
131+
var extent = t.extents[t.extents.round(di.p)];
132+
pointData[posLetter + '0'] = pa.c2p(isClosest ? minPos(di) : extent[0], true);
133+
pointData[posLetter + '1'] = pa.c2p(isClosest ? maxPos(di) : extent[1], true);
133134
pointData[posLetter + 'LabelVal'] = di.p;
134135

135136
// spikelines always want "closest" distance regardless of hovermode

src/traces/bar/set_positions.js

+53
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ function setGroupPositions(gd, pa, sa, calcTraces) {
105105
setGroupPositionsInOverlayMode(gd, pa, sa, excluded);
106106
}
107107
}
108+
109+
collectExtents(calcTraces, pa);
108110
}
109111

110112

@@ -596,3 +598,54 @@ function normalizeBars(gd, sa, sieve) {
596598
function getAxisLetter(ax) {
597599
return ax._id.charAt(0);
598600
}
601+
602+
// find the full position span of bars at each position
603+
// for use by hover, to ensure labels move in if bars are
604+
// narrower than the space they're in.
605+
// run once per trace group (subplot & direction) and
606+
// the same mapping is attached to all calcdata traces
607+
function collectExtents(calcTraces, pa) {
608+
var posLetter = pa._id.charAt(0);
609+
var extents = {};
610+
var pMin = Infinity;
611+
var pMax = -Infinity;
612+
613+
var i, j, cd;
614+
for(i = 0; i < calcTraces.length; i++) {
615+
cd = calcTraces[i];
616+
for(j = 0; j < cd.length; j++) {
617+
var p = cd[j].p;
618+
if(isNumeric(p)) {
619+
pMin = Math.min(pMin, p);
620+
pMax = Math.max(pMax, p);
621+
}
622+
}
623+
}
624+
625+
// this is just for positioning of hover labels, and nobody will care if
626+
// the label is 1px too far out; so round positions to 1/10K in case
627+
// position values don't exactly match from trace to trace
628+
var roundFactor = 10000 / (pMax - pMin);
629+
var round = extents.round = function(p) {
630+
return String(Math.round(roundFactor * (p - pMin)));
631+
};
632+
633+
for(i = 0; i < calcTraces.length; i++) {
634+
cd = calcTraces[i];
635+
cd[0].t.extents = extents;
636+
for(j = 0; j < cd.length; j++) {
637+
var di = cd[j];
638+
var p0 = di[posLetter] - di.w / 2;
639+
if(isNumeric(p0)) {
640+
var p1 = di[posLetter] + di.w / 2;
641+
var pVal = round(di.p);
642+
if(extents[pVal]) {
643+
extents[pVal] = [Math.min(p0, extents[pVal][0]), Math.max(p1, extents[pVal][1])];
644+
}
645+
else {
646+
extents[pVal] = [p0, p1];
647+
}
648+
}
649+
}
650+
}
651+
}

test/jasmine/tests/bar_test.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -1508,7 +1508,37 @@ describe('bar hover', function() {
15081508
out = _hover(gd, 125, 0.8, 'x');
15091509

15101510
expect(out.style).toEqual([1, 'red', 200, 1]);
1511-
assertPos(out.pos, [203, 304, 168, 168]);
1511+
assertPos(out.pos, [222, 280, 168, 168]);
1512+
})
1513+
.catch(fail)
1514+
.then(done);
1515+
});
1516+
1517+
it('positions labels correctly w.r.t. narrow bars', function(done) {
1518+
Plotly.newPlot(gd, [{
1519+
x: [0, 10, 20],
1520+
y: [1, 3, 2],
1521+
type: 'bar',
1522+
width: 1
1523+
}], {
1524+
width: 500,
1525+
height: 500,
1526+
margin: {l: 100, r: 100, t: 100, b: 100}
1527+
})
1528+
.then(function() {
1529+
// you can still hover over the gap (14) but the label will
1530+
// get pushed in to the bar
1531+
var out = _hover(gd, 14, 2, 'x');
1532+
assertPos(out.pos, [145, 155, 15, 15]);
1533+
1534+
// in closest mode you must be over the bar though
1535+
out = _hover(gd, 14, 2, 'closest');
1536+
expect(out).toBe(false);
1537+
1538+
// now for a single bar trace, closest and compare modes give the same
1539+
// positioning of hover labels
1540+
out = _hover(gd, 10, 2, 'closest');
1541+
assertPos(out.pos, [145, 155, 15, 15]);
15121542
})
15131543
.catch(fail)
15141544
.then(done);

0 commit comments

Comments
 (0)