Skip to content

Commit dca5b1e

Browse files
committed
for x|y hovermodes display spikeline on the winning point
- also adjust scattergl and splom hover label position
1 parent 30f61c8 commit dca5b1e

File tree

2 files changed

+34
-17
lines changed

2 files changed

+34
-17
lines changed

src/components/fx/hover.js

+24-12
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ var multipleHoverPoints = {
4646
candlestick: true
4747
};
4848

49+
var cartesianScatterPoints = {
50+
scatter: true,
51+
scattergl: true,
52+
splom: true
53+
};
54+
4955
// fx.hover: highlight data on hover
5056
// evt can be a mousemove event, or an object with data about what points
5157
// to hover on
@@ -574,12 +580,15 @@ function _hover(gd, evt, subplot, noHoverEvent) {
574580

575581
findHoverPoints();
576582

577-
function selectClosestPoint(pointsData, spikedistance) {
583+
function selectClosestPoint(pointsData, spikedistance, spikeOnWinning) {
578584
var resultPoint = null;
579585
var minDistance = Infinity;
580586
var thisSpikeDistance;
587+
581588
for(var i = 0; i < pointsData.length; i++) {
582589
thisSpikeDistance = pointsData[i].spikeDistance;
590+
if(spikeOnWinning && i === 0) thisSpikeDistance = -Infinity;
591+
583592
if(thisSpikeDistance <= minDistance && thisSpikeDistance <= spikedistance) {
584593
resultPoint = pointsData[i];
585594
minDistance = thisSpikeDistance;
@@ -616,19 +625,30 @@ function _hover(gd, evt, subplot, noHoverEvent) {
616625
};
617626
gd._spikepoints = newspikepoints;
618627

628+
var sortHoverData = function() {
629+
hoverData.sort(function(d1, d2) { return d1.distance - d2.distance; });
630+
631+
// move period positioned points and box/bar-like traces to the end of the list
632+
hoverData = orderRangePoints(hoverData, hovermode);
633+
};
634+
sortHoverData();
635+
636+
var axLetter = hovermode.charAt(0);
637+
var spikeOnWinning = (axLetter === 'x' || axLetter === 'y') && hoverData[0] && cartesianScatterPoints[hoverData[0].trace.type];
638+
619639
// Now if it is not restricted by spikedistance option, set the points to draw the spikelines
620640
if(hasCartesian && (spikedistance !== 0)) {
621641
if(hoverData.length !== 0) {
622642
var tmpHPointData = hoverData.filter(function(point) {
623643
return point.ya.showspikes;
624644
});
625-
var tmpHPoint = selectClosestPoint(tmpHPointData, spikedistance);
645+
var tmpHPoint = selectClosestPoint(tmpHPointData, spikedistance, spikeOnWinning);
626646
spikePoints.hLinePoint = fillSpikePoint(tmpHPoint);
627647

628648
var tmpVPointData = hoverData.filter(function(point) {
629649
return point.xa.showspikes;
630650
});
631-
var tmpVPoint = selectClosestPoint(tmpVPointData, spikedistance);
651+
var tmpVPoint = selectClosestPoint(tmpVPointData, spikedistance, spikeOnWinning);
632652
spikePoints.vLinePoint = fillSpikePoint(tmpVPoint);
633653
}
634654
}
@@ -650,14 +670,6 @@ function _hover(gd, evt, subplot, noHoverEvent) {
650670
}
651671
}
652672

653-
var sortHoverData = function() {
654-
hoverData.sort(function(d1, d2) { return d1.distance - d2.distance; });
655-
656-
// move period positioned points and box/bar-like traces to the end of the list
657-
hoverData = orderRangePoints(hoverData, hovermode);
658-
};
659-
sortHoverData();
660-
661673
if(
662674
helpers.isXYhover(_mode) &&
663675
hoverData[0].length !== 0 &&
@@ -1074,7 +1086,7 @@ function createHoverText(hoverData, opts, gd) {
10741086
var winningPoint = hoverData[0];
10751087

10761088
// When the scatter point wins, it's OK for the hovelabel to occlude the bar and other points.
1077-
var scatterWon = winningPoint.trace.type === 'scatter';
1089+
var scatterWon = cartesianScatterPoints[winningPoint.trace.type];
10781090

10791091
var lyBottom, lyTop;
10801092
if(axLetter === 'y') {

test/jasmine/tests/hover_spikeline_test.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -523,12 +523,17 @@ describe('spikeline hover', function() {
523523
_hover({xpx: 200, ypx: 200});
524524
lines = d3SelectAll('line.spikeline');
525525
expect(lines.size()).toBe(4);
526-
expect(lines[0][1].getAttribute('stroke')).toBe('blue');
526+
expect(lines[0][1].getAttribute('stroke')).toBe('green');
527527

528528
_hover({xpx: 200, ypx: 350});
529529
lines = d3SelectAll('line.spikeline');
530530
expect(lines.size()).toBe(4);
531531
expect(lines[0][1].getAttribute('stroke')).toBe('green');
532+
533+
_hover({xpx: 300, ypx: 350});
534+
lines = d3SelectAll('line.spikeline');
535+
expect(lines.size()).toBe(4);
536+
expect(lines[0][1].getAttribute('stroke')).toBe('blue');
532537
})
533538
.then(done, done.fail);
534539
});
@@ -717,10 +722,10 @@ describe('spikeline hover', function() {
717722
.then(done, done.fail);
718723
});
719724

720-
it('correctly draws lines up to the last point', function(done) {
725+
it('correctly draws lines up to the winning point', function(done) {
721726
Plotly.newPlot(gd, [
722727
{type: 'bar', y: [5, 7, 9, 6, 4, 3]},
723-
{y: [5, 7, 9, 6, 4, 3]},
728+
{y: [5, 7, 9, 6, 4, 3], marker: {color: 'green'}},
724729
{y: [5, 7, 9, 6, 4, 3], marker: {color: 'red'}}
725730
], {
726731
hovermode: 'x',
@@ -735,8 +740,8 @@ describe('spikeline hover', function() {
735740

736741
var lines = d3SelectAll('line.spikeline');
737742
expect(lines.size()).toBe(4);
738-
expect(lines[0][1].getAttribute('stroke')).toBe('red');
739-
expect(lines[0][3].getAttribute('stroke')).toBe('red');
743+
expect(lines[0][1].getAttribute('stroke')).toBe('green');
744+
expect(lines[0][3].getAttribute('stroke')).toBe('green');
740745
})
741746
.then(done, done.fail);
742747
});

0 commit comments

Comments
 (0)