Skip to content

Commit b292bec

Browse files
authored
Merge pull request #5647 from plotly/v2-hovermode-default
Default hovermode to closest in plotly.js v2
2 parents d0910dc + cdb8d9e commit b292bec

20 files changed

+110
-148
lines changed

src/components/fx/hovermode_defaults.js

+3-33
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,14 @@
33
var Lib = require('../../lib');
44
var layoutAttributes = require('./layout_attributes');
55

6-
module.exports = function handleHoverModeDefaults(layoutIn, layoutOut, fullData) {
6+
module.exports = function handleHoverModeDefaults(layoutIn, layoutOut) {
77
function coerce(attr, dflt) {
88
// don't coerce if it is already coerced in other place e.g. in cartesian defaults
99
if(layoutOut[attr] !== undefined) return layoutOut[attr];
1010

1111
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
1212
}
1313

14-
var clickmode = coerce('clickmode');
15-
16-
var hovermodeDflt;
17-
if(layoutOut._has('cartesian')) {
18-
if(clickmode.indexOf('select') > -1) {
19-
hovermodeDflt = 'closest';
20-
} else {
21-
// flag for 'horizontal' plots:
22-
// determines the state of the mode bar 'compare' hovermode button
23-
layoutOut._isHoriz = isHoriz(fullData, layoutOut);
24-
hovermodeDflt = layoutOut._isHoriz ? 'y' : 'x';
25-
}
26-
} else hovermodeDflt = 'closest';
27-
28-
return coerce('hovermode', hovermodeDflt);
14+
coerce('clickmode');
15+
return coerce('hovermode');
2916
};
30-
31-
function isHoriz(fullData, fullLayout) {
32-
var stackOpts = fullLayout._scatterStackOpts || {};
33-
34-
for(var i = 0; i < fullData.length; i++) {
35-
var trace = fullData[i];
36-
var subplot = trace.xaxis + trace.yaxis;
37-
var subplotStackOpts = stackOpts[subplot] || {};
38-
var groupOpts = subplotStackOpts[trace.stackgroup] || {};
39-
40-
if(trace.orientation !== 'h' && groupOpts.orientation !== 'h') {
41-
return false;
42-
}
43-
}
44-
45-
return true;
46-
}

src/components/fx/layout_attributes.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ module.exports = {
6060
hovermode: {
6161
valType: 'enumerated',
6262
values: ['x', 'y', 'closest', false, 'x unified', 'y unified'],
63+
dflt: 'closest',
6364
editType: 'modebar',
6465
description: [
6566
'Determines the mode of hover interactions.',
@@ -72,14 +73,7 @@ module.exports = {
7273
'multiple points at the closest x- (or y-) coordinate within the `hoverdistance`',
7374
'with the caveat that no more than one hoverlabel will appear per trace.',
7475
'In this mode, spikelines are enabled by default perpendicular to the specified axis.',
75-
'If false, hover interactions are disabled.',
76-
'If `clickmode` includes the *select* flag,',
77-
'`hovermode` defaults to *closest*.',
78-
'If `clickmode` lacks the *select* flag,',
79-
'it defaults to *x* or *y* (depending on the trace\'s',
80-
'`orientation` value) for plots based on',
81-
'cartesian coordinates. For anything else the default',
82-
'value is *closest*.',
76+
'If false, hover interactions are disabled.'
8377
].join(' ')
8478
},
8579
hoverdistance: {

src/components/fx/layout_defaults.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ var layoutAttributes = require('./layout_attributes');
66
var handleHoverModeDefaults = require('./hovermode_defaults');
77
var handleHoverLabelDefaults = require('./hoverlabel_defaults');
88

9-
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
9+
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
1010
function coerce(attr, dflt) {
1111
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
1212
}
1313

14-
var hoverMode = handleHoverModeDefaults(layoutIn, layoutOut, fullData);
14+
var hoverMode = handleHoverModeDefaults(layoutIn, layoutOut);
1515
if(hoverMode) {
1616
coerce('hoverdistance');
1717
coerce('spikedistance', isUnifiedHover(hoverMode) ? -1 : undefined);

src/plots/cartesian/layout_defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
200200
}
201201
}
202202

203-
var hovermode = handleHoverModeDefaults(layoutIn, layoutOut, fullData);
203+
var hovermode = handleHoverModeDefaults(layoutIn, layoutOut);
204204
var unifiedHover = isUnifiedHover(hovermode);
205205

206206
// first pass creates the containers, determines types, and handles most of the settings

test/jasmine/tests/axes_test.js

+2
Original file line numberDiff line numberDiff line change
@@ -6645,6 +6645,7 @@ describe('Test tickformatstops:', function() {
66456645
beforeEach(function() {
66466646
gd = createGraphDiv();
66476647
mockCopy = Lib.extendDeep({}, mock);
6648+
mockCopy.layout.hovermode = 'x';
66486649
});
66496650

66506651
afterEach(destroyGraphDiv);
@@ -6951,6 +6952,7 @@ describe('category preservation tests on gd passed to Plotly.react()', function(
69516952
x: ['a', 'b', 'c', 'd']
69526953
}],
69536954
layout: {
6955+
hovermode: 'x',
69546956
width: 500,
69556957
height: 500
69566958
}

test/jasmine/tests/bar_test.js

+1
Original file line numberDiff line numberDiff line change
@@ -2416,6 +2416,7 @@ describe('bar hover', function() {
24162416
t.type = 'bar';
24172417
t.hovertemplate = '%{y}<extra></extra>';
24182418
});
2419+
mock.layout.hovermode = 'x';
24192420

24202421
function _hover() {
24212422
var evt = { xpx: 125, ypx: 150 };

test/jasmine/tests/box_test.js

+19-10
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,10 @@ describe('Test box hover:', function() {
739739

740740
[{
741741
desc: 'base',
742+
patch: function(fig) {
743+
fig.layout.hovermode = 'x';
744+
return fig;
745+
},
742746
nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7'],
743747
name: ['radishes', '', '', '', ''],
744748
axis: 'day 1'
@@ -748,6 +752,7 @@ describe('Test box hover:', function() {
748752
fig.data.forEach(function(trace) {
749753
trace.boxmean = true;
750754
});
755+
fig.layout.hovermode = 'x';
751756
return fig;
752757
},
753758
nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', 'mean: 0.45'],
@@ -759,6 +764,7 @@ describe('Test box hover:', function() {
759764
fig.data.forEach(function(trace) {
760765
trace.boxmean = 'sd';
761766
});
767+
fig.layout.hovermode = 'x';
762768
return fig;
763769
},
764770
nums: [
@@ -770,6 +776,10 @@ describe('Test box hover:', function() {
770776
}, {
771777
desc: 'with boxpoints fences',
772778
mock: require('@mocks/boxplots_outliercolordflt.json'),
779+
patch: function(fig) {
780+
fig.layout.hovermode = 'x';
781+
return fig;
782+
},
773783
pos: [350, 200],
774784
nums: [
775785
'median: 8.15', 'min: 0.75', 'q1: 6.8',
@@ -780,6 +790,7 @@ describe('Test box hover:', function() {
780790
}, {
781791
desc: 'with overlaid boxes',
782792
patch: function(fig) {
793+
fig.layout.hovermode = 'x';
783794
fig.layout.boxmode = 'overlay';
784795
return fig;
785796
},
@@ -799,7 +810,6 @@ describe('Test box hover:', function() {
799810
trace.boxpoints = 'all';
800811
trace.hoveron = 'points';
801812
});
802-
fig.layout.hovermode = 'closest';
803813
fig.layout.xaxis = {range: [-0.565, 1.5]};
804814
return fig;
805815
},
@@ -856,7 +866,6 @@ describe('Test box hover:', function() {
856866
trace.hoveron = 'points';
857867
trace.text = trace.y.map(function(v) { return 'look:' + v; });
858868
});
859-
fig.layout.hovermode = 'closest';
860869
fig.layout.xaxis = {range: [-0.565, 1.5]};
861870
return fig;
862871
},
@@ -871,7 +880,6 @@ describe('Test box hover:', function() {
871880
trace.text = trace.y.map(function(v) { return 'look:' + v; });
872881
trace.hoverinfo = 'text';
873882
});
874-
fig.layout.hovermode = 'closest';
875883
fig.layout.xaxis = {range: [-0.565, 1.5]};
876884
return fig;
877885
},
@@ -887,7 +895,6 @@ describe('Test box hover:', function() {
887895
trace.hovertext = trace.y.map(function(v) { return 'look:' + v; });
888896
trace.hoverinfo = 'text';
889897
});
890-
fig.layout.hovermode = 'closest';
891898
fig.layout.xaxis = {range: [-0.565, 1.5]};
892899
return fig;
893900
},
@@ -896,6 +903,10 @@ describe('Test box hover:', function() {
896903
}, {
897904
desc: 'orientation:h | hovermode:y',
898905
mock: require('@mocks/box_grouped_horz.json'),
906+
patch: function(fig) {
907+
fig.layout.hovermode = 'y';
908+
return fig;
909+
},
899910
pos: [430, 130],
900911
nums: [
901912
'max: 1', 'mean ± σ: 0.6833333 ± 0.2409472', 'min: 0.3',
@@ -906,10 +917,6 @@ describe('Test box hover:', function() {
906917
}, {
907918
desc: 'orientation:h | hovermode:closest',
908919
mock: require('@mocks/box_grouped_horz.json'),
909-
patch: function(fig) {
910-
fig.layout.hovermode = 'closest';
911-
return fig;
912-
},
913920
pos: [430, 130],
914921
nums: [
915922
'(max: 1, day 2)', '(mean ± σ: 0.6833333 ± 0.2409472, day 2)', '(min: 0.3, day 2)',
@@ -927,7 +934,6 @@ describe('Test box hover:', function() {
927934
y: [13.1, 14.2, 14, 13, 13.3]
928935
}],
929936
layout: {
930-
hovermode: 'closest',
931937
xaxis: {range: [1.3775, 2.5]}
932938
}
933939
},
@@ -942,7 +948,6 @@ describe('Test box hover:', function() {
942948
trace.hoveron = 'points';
943949
trace.hovertemplate = '%{y}<extra>pt #%{pointNumber}</extra>';
944950
});
945-
fig.layout.hovermode = 'closest';
946951
return fig;
947952
},
948953
nums: '0.6',
@@ -955,6 +960,7 @@ describe('Test box hover:', function() {
955960
y: [1, 2, 2, 3]
956961
}],
957962
layout: {
963+
hovermode: 'x',
958964
yaxis: {range: [1.6, 2.4]},
959965
width: 400,
960966
height: 400
@@ -975,6 +981,7 @@ describe('Test box hover:', function() {
975981
q3: [3]
976982
}],
977983
layout: {
984+
hovermode: 'x',
978985
width: 400,
979986
height: 400
980987
}
@@ -997,6 +1004,7 @@ describe('Test box hover:', function() {
9971004
pointpos: 0
9981005
}],
9991006
layout: {
1007+
hovermode: 'x',
10001008
width: 400,
10011009
height: 400,
10021010
margin: {l: 0, t: 0, b: 0, r: 0}
@@ -1021,6 +1029,7 @@ describe('Test box hover:', function() {
10211029
hovertemplate: '%{x} | %{y}<extra>%{pointNumber[0]} | %{pointNumber[1]}</extra>'
10221030
}],
10231031
layout: {
1032+
hovermode: 'x',
10241033
width: 400,
10251034
height: 400,
10261035
margin: {l: 0, t: 0, b: 0, r: 0}

test/jasmine/tests/cartesian_interact_test.js

+1
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,7 @@ describe('Event data:', function() {
23002300
}
23012301
}
23022302
}], {
2303+
hovermode: 'x',
23032304
width: 500,
23042305
height: 500
23052306
})

test/jasmine/tests/finance_test.js

+1
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,7 @@ describe('finance trace hover via Fx.hover():', function() {
13211321
y: [1, 2, 3, 4],
13221322
type: 'bar'
13231323
}], {
1324+
hovermode: 'x',
13241325
xaxis: { rangeslider: {visible: false} },
13251326
width: 500,
13261327
height: 500

test/jasmine/tests/funnel_test.js

+3
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,7 @@ describe('funnel hover', function() {
14231423
t.orientation = 'v';
14241424
t.hoverinfo = 'all';
14251425
});
1426+
mock.layout.hovermode = 'x';
14261427

14271428
function _hover() {
14281429
var evt = { xpx: 125, ypx: 150 };
@@ -1454,6 +1455,7 @@ describe('funnel hover', function() {
14541455
t.orientation = 'v';
14551456
t.hovertemplate = 'Value: %{y}<br>Total percentage: %{percentTotal}<br>Initial percentage: %{percentInitial}<br>Previous percentage: %{percentPrevious}<extra></extra>';
14561457
});
1458+
mock.layout.hovermode = 'x';
14571459

14581460
function _hover() {
14591461
var evt = { xpx: 125, ypx: 150 };
@@ -1488,6 +1490,7 @@ describe('funnel hover', function() {
14881490
type: 'funnel'
14891491
}],
14901492
layout: {
1493+
hovermode: 'x',
14911494
yaxis: {
14921495
visible: false,
14931496
tickprefix: '$',

test/jasmine/tests/fx_test.js

+5-12
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@ describe('Fx defaults', function() {
2626

2727
it('should default (blank version)', function() {
2828
var layoutOut = _supply().layout;
29-
// we get a blank cartesian subplot that has no traces...
30-
// so all traces are horizontal -> hovermode defaults to y
31-
// we could add a special case to push this back to x, but
32-
// it seems like it has no practical consequence.
33-
expect(layoutOut.hovermode).toBe('y', 'hovermode to y');
29+
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
3430
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
3531
});
3632

@@ -41,9 +37,8 @@ describe('Fx defaults', function() {
4137
}])
4238
.layout;
4339

44-
expect(layoutOut.hovermode).toBe('x', 'hovermode to x');
40+
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
4541
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
46-
expect(layoutOut._isHoriz).toBe(false, 'isHoriz to false');
4742
});
4843

4944
it('should default (cartesian horizontal version)', function() {
@@ -55,9 +50,8 @@ describe('Fx defaults', function() {
5550
}])
5651
.layout;
5752

58-
expect(layoutOut.hovermode).toBe('y', 'hovermode to y');
53+
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
5954
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
60-
expect(layoutOut._isHoriz).toBe(true, 'isHoriz to true');
6155
});
6256

6357
it('should default (cartesian horizontal version, stacked scatter)', function() {
@@ -73,9 +67,8 @@ describe('Fx defaults', function() {
7367
}])
7468
.layout;
7569

76-
expect(layoutOut.hovermode).toBe('y', 'hovermode to y');
70+
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
7771
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
78-
expect(layoutOut._isHoriz).toBe(true, 'isHoriz to true');
7972
});
8073

8174
it('should default (gl3d version)', function() {
@@ -115,7 +108,7 @@ describe('Fx defaults', function() {
115108
}])
116109
.layout;
117110

118-
expect(layoutOut.hovermode).toBe('x', 'hovermode to x');
111+
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
119112
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
120113
});
121114

test/jasmine/tests/gl2d_click_test.js

+1
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ describe('Test hover and click interactions', function() {
416416

417417
it('@gl scattergl should propagate marker colors to hover labels', function(done) {
418418
var _mock = Lib.extendDeep({}, mock0);
419+
_mock.layout.hovermode = 'x';
419420
_mock.layout.width = 800;
420421
_mock.layout.height = 600;
421422

0 commit comments

Comments
 (0)