Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default hovermode to closest in plotly.js v2 #5647

Merged
merged 2 commits into from
May 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 3 additions & 33 deletions src/components/fx/hovermode_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,14 @@
var Lib = require('../../lib');
var layoutAttributes = require('./layout_attributes');

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

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

var clickmode = coerce('clickmode');

var hovermodeDflt;
if(layoutOut._has('cartesian')) {
if(clickmode.indexOf('select') > -1) {
hovermodeDflt = 'closest';
} else {
// flag for 'horizontal' plots:
// determines the state of the mode bar 'compare' hovermode button
layoutOut._isHoriz = isHoriz(fullData, layoutOut);
hovermodeDflt = layoutOut._isHoriz ? 'y' : 'x';
}
} else hovermodeDflt = 'closest';

return coerce('hovermode', hovermodeDflt);
coerce('clickmode');
return coerce('hovermode');
};

function isHoriz(fullData, fullLayout) {
var stackOpts = fullLayout._scatterStackOpts || {};

for(var i = 0; i < fullData.length; i++) {
var trace = fullData[i];
var subplot = trace.xaxis + trace.yaxis;
var subplotStackOpts = stackOpts[subplot] || {};
var groupOpts = subplotStackOpts[trace.stackgroup] || {};

if(trace.orientation !== 'h' && groupOpts.orientation !== 'h') {
return false;
}
}

return true;
}
10 changes: 2 additions & 8 deletions src/components/fx/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ module.exports = {
hovermode: {
valType: 'enumerated',
values: ['x', 'y', 'closest', false, 'x unified', 'y unified'],
dflt: 'closest',
editType: 'modebar',
description: [
'Determines the mode of hover interactions.',
Expand All @@ -72,14 +73,7 @@ module.exports = {
'multiple points at the closest x- (or y-) coordinate within the `hoverdistance`',
'with the caveat that no more than one hoverlabel will appear per trace.',
'In this mode, spikelines are enabled by default perpendicular to the specified axis.',
'If false, hover interactions are disabled.',
'If `clickmode` includes the *select* flag,',
'`hovermode` defaults to *closest*.',
'If `clickmode` lacks the *select* flag,',
'it defaults to *x* or *y* (depending on the trace\'s',
'`orientation` value) for plots based on',
'cartesian coordinates. For anything else the default',
'value is *closest*.',
'If false, hover interactions are disabled.'
].join(' ')
},
hoverdistance: {
Expand Down
4 changes: 2 additions & 2 deletions src/components/fx/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ var layoutAttributes = require('./layout_attributes');
var handleHoverModeDefaults = require('./hovermode_defaults');
var handleHoverLabelDefaults = require('./hoverlabel_defaults');

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}

var hoverMode = handleHoverModeDefaults(layoutIn, layoutOut, fullData);
var hoverMode = handleHoverModeDefaults(layoutIn, layoutOut);
if(hoverMode) {
coerce('hoverdistance');
coerce('spikedistance', isUnifiedHover(hoverMode) ? -1 : undefined);
Expand Down
2 changes: 1 addition & 1 deletion src/plots/cartesian/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
}
}

var hovermode = handleHoverModeDefaults(layoutIn, layoutOut, fullData);
var hovermode = handleHoverModeDefaults(layoutIn, layoutOut);
var unifiedHover = isUnifiedHover(hovermode);

// first pass creates the containers, determines types, and handles most of the settings
Expand Down
2 changes: 2 additions & 0 deletions test/jasmine/tests/axes_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6645,6 +6645,7 @@ describe('Test tickformatstops:', function() {
beforeEach(function() {
gd = createGraphDiv();
mockCopy = Lib.extendDeep({}, mock);
mockCopy.layout.hovermode = 'x';
});

afterEach(destroyGraphDiv);
Expand Down Expand Up @@ -6951,6 +6952,7 @@ describe('category preservation tests on gd passed to Plotly.react()', function(
x: ['a', 'b', 'c', 'd']
}],
layout: {
hovermode: 'x',
width: 500,
height: 500
}
Expand Down
1 change: 1 addition & 0 deletions test/jasmine/tests/bar_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2416,6 +2416,7 @@ describe('bar hover', function() {
t.type = 'bar';
t.hovertemplate = '%{y}<extra></extra>';
});
mock.layout.hovermode = 'x';

function _hover() {
var evt = { xpx: 125, ypx: 150 };
Expand Down
29 changes: 19 additions & 10 deletions test/jasmine/tests/box_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,10 @@ describe('Test box hover:', function() {

[{
desc: 'base',
patch: function(fig) {
fig.layout.hovermode = 'x';
return fig;
},
nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7'],
name: ['radishes', '', '', '', ''],
axis: 'day 1'
Expand All @@ -748,6 +752,7 @@ describe('Test box hover:', function() {
fig.data.forEach(function(trace) {
trace.boxmean = true;
});
fig.layout.hovermode = 'x';
return fig;
},
nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', 'mean: 0.45'],
Expand All @@ -759,6 +764,7 @@ describe('Test box hover:', function() {
fig.data.forEach(function(trace) {
trace.boxmean = 'sd';
});
fig.layout.hovermode = 'x';
return fig;
},
nums: [
Expand All @@ -770,6 +776,10 @@ describe('Test box hover:', function() {
}, {
desc: 'with boxpoints fences',
mock: require('@mocks/boxplots_outliercolordflt.json'),
patch: function(fig) {
fig.layout.hovermode = 'x';
return fig;
},
pos: [350, 200],
nums: [
'median: 8.15', 'min: 0.75', 'q1: 6.8',
Expand All @@ -780,6 +790,7 @@ describe('Test box hover:', function() {
}, {
desc: 'with overlaid boxes',
patch: function(fig) {
fig.layout.hovermode = 'x';
fig.layout.boxmode = 'overlay';
return fig;
},
Expand All @@ -799,7 +810,6 @@ describe('Test box hover:', function() {
trace.boxpoints = 'all';
trace.hoveron = 'points';
});
fig.layout.hovermode = 'closest';
fig.layout.xaxis = {range: [-0.565, 1.5]};
return fig;
},
Expand Down Expand Up @@ -856,7 +866,6 @@ describe('Test box hover:', function() {
trace.hoveron = 'points';
trace.text = trace.y.map(function(v) { return 'look:' + v; });
});
fig.layout.hovermode = 'closest';
fig.layout.xaxis = {range: [-0.565, 1.5]};
return fig;
},
Expand All @@ -871,7 +880,6 @@ describe('Test box hover:', function() {
trace.text = trace.y.map(function(v) { return 'look:' + v; });
trace.hoverinfo = 'text';
});
fig.layout.hovermode = 'closest';
fig.layout.xaxis = {range: [-0.565, 1.5]};
return fig;
},
Expand All @@ -887,7 +895,6 @@ describe('Test box hover:', function() {
trace.hovertext = trace.y.map(function(v) { return 'look:' + v; });
trace.hoverinfo = 'text';
});
fig.layout.hovermode = 'closest';
fig.layout.xaxis = {range: [-0.565, 1.5]};
return fig;
},
Expand All @@ -896,6 +903,10 @@ describe('Test box hover:', function() {
}, {
desc: 'orientation:h | hovermode:y',
mock: require('@mocks/box_grouped_horz.json'),
patch: function(fig) {
fig.layout.hovermode = 'y';
return fig;
},
pos: [430, 130],
nums: [
'max: 1', 'mean ± σ: 0.6833333 ± 0.2409472', 'min: 0.3',
Expand All @@ -906,10 +917,6 @@ describe('Test box hover:', function() {
}, {
desc: 'orientation:h | hovermode:closest',
mock: require('@mocks/box_grouped_horz.json'),
patch: function(fig) {
fig.layout.hovermode = 'closest';
return fig;
},
pos: [430, 130],
nums: [
'(max: 1, day 2)', '(mean ± σ: 0.6833333 ± 0.2409472, day 2)', '(min: 0.3, day 2)',
Expand All @@ -927,7 +934,6 @@ describe('Test box hover:', function() {
y: [13.1, 14.2, 14, 13, 13.3]
}],
layout: {
hovermode: 'closest',
xaxis: {range: [1.3775, 2.5]}
}
},
Expand All @@ -942,7 +948,6 @@ describe('Test box hover:', function() {
trace.hoveron = 'points';
trace.hovertemplate = '%{y}<extra>pt #%{pointNumber}</extra>';
});
fig.layout.hovermode = 'closest';
return fig;
},
nums: '0.6',
Expand All @@ -955,6 +960,7 @@ describe('Test box hover:', function() {
y: [1, 2, 2, 3]
}],
layout: {
hovermode: 'x',
yaxis: {range: [1.6, 2.4]},
width: 400,
height: 400
Expand All @@ -975,6 +981,7 @@ describe('Test box hover:', function() {
q3: [3]
}],
layout: {
hovermode: 'x',
width: 400,
height: 400
}
Expand All @@ -997,6 +1004,7 @@ describe('Test box hover:', function() {
pointpos: 0
}],
layout: {
hovermode: 'x',
width: 400,
height: 400,
margin: {l: 0, t: 0, b: 0, r: 0}
Expand All @@ -1021,6 +1029,7 @@ describe('Test box hover:', function() {
hovertemplate: '%{x} | %{y}<extra>%{pointNumber[0]} | %{pointNumber[1]}</extra>'
}],
layout: {
hovermode: 'x',
width: 400,
height: 400,
margin: {l: 0, t: 0, b: 0, r: 0}
Expand Down
1 change: 1 addition & 0 deletions test/jasmine/tests/cartesian_interact_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2300,6 +2300,7 @@ describe('Event data:', function() {
}
}
}], {
hovermode: 'x',
width: 500,
height: 500
})
Expand Down
1 change: 1 addition & 0 deletions test/jasmine/tests/finance_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,7 @@ describe('finance trace hover via Fx.hover():', function() {
y: [1, 2, 3, 4],
type: 'bar'
}], {
hovermode: 'x',
xaxis: { rangeslider: {visible: false} },
width: 500,
height: 500
Expand Down
3 changes: 3 additions & 0 deletions test/jasmine/tests/funnel_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,7 @@ describe('funnel hover', function() {
t.orientation = 'v';
t.hoverinfo = 'all';
});
mock.layout.hovermode = 'x';

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

function _hover() {
var evt = { xpx: 125, ypx: 150 };
Expand Down Expand Up @@ -1488,6 +1490,7 @@ describe('funnel hover', function() {
type: 'funnel'
}],
layout: {
hovermode: 'x',
yaxis: {
visible: false,
tickprefix: '$',
Expand Down
17 changes: 5 additions & 12 deletions test/jasmine/tests/fx_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ describe('Fx defaults', function() {

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

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

expect(layoutOut.hovermode).toBe('x', 'hovermode to x');
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
expect(layoutOut._isHoriz).toBe(false, 'isHoriz to false');
});

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

expect(layoutOut.hovermode).toBe('y', 'hovermode to y');
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
expect(layoutOut._isHoriz).toBe(true, 'isHoriz to true');
});

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

expect(layoutOut.hovermode).toBe('y', 'hovermode to y');
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
expect(layoutOut._isHoriz).toBe(true, 'isHoriz to true');
});

it('should default (gl3d version)', function() {
Expand Down Expand Up @@ -115,7 +108,7 @@ describe('Fx defaults', function() {
}])
.layout;

expect(layoutOut.hovermode).toBe('x', 'hovermode to x');
expect(layoutOut.hovermode).toBe('closest', 'hovermode to closest');
expect(layoutOut.dragmode).toBe('zoom', 'dragmode to zoom');
});

Expand Down
1 change: 1 addition & 0 deletions test/jasmine/tests/gl2d_click_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ describe('Test hover and click interactions', function() {

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

Expand Down
Loading