diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index a8738cf3f6e..088f90f4727 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -14,6 +14,7 @@ var Drawing = require('../drawing'); var Color = require('../color'); var dragElement = require('../dragelement'); var Axes = require('../../plots/cartesian/axes'); +var alignPeriod = require('../../plots/cartesian/align_period'); var Registry = require('../../registry'); var helpers = require('./helpers'); @@ -779,8 +780,9 @@ function createHoverText(hoverData, opts, gd) { var c0 = hoverData[0]; var xa = c0.xa; var ya = c0.ya; - var commonAttr = hovermode.charAt(0) === 'y' ? 'yLabel' : 'xLabel'; - var t0 = c0[commonAttr]; + var axLetter = hovermode.charAt(0); + var v0 = c0[axLetter + 'LabelVal']; + var t0 = c0[axLetter + 'Label']; var t00 = (String(t0) || '').split(' ')[0]; var outerContainerBB = outerContainer.node().getBoundingClientRect(); var outerTop = outerContainerBB.top; @@ -978,8 +980,25 @@ function createHoverText(hoverData, opts, gd) { function filterClosePoints(hoverData) { return hoverData.filter(function(d) { - return (d.zLabelVal !== undefined) || - (d[commonAttr] || '').split(' ')[0] === t00; + if(d.zLabelVal !== undefined) return true; + if((d[axLetter + 'Label'] || '').split(' ')[0] === t00) return true; + if(d.trace[axLetter + 'period']) { + var v = d[axLetter + 'LabelVal']; + var ax = d[axLetter + 'a']; + var trace = {}; + trace[axLetter + 'period'] = d.trace[axLetter + 'period']; + trace[axLetter + 'period0'] = d.trace[axLetter + 'period0']; + + trace[axLetter + 'periodalignment'] = 'start'; + var start = alignPeriod(trace, ax, axLetter, [v])[0]; + + trace[axLetter + 'periodalignment'] = 'end'; + var end = alignPeriod(trace, ax, axLetter, [v])[0]; + + if(v0 >= start && v0 < end) return true; + } + + return false; }); } diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 22aee441ae6..164f0980e8e 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -4749,6 +4749,255 @@ describe('hovermode: (x|y)unified', function() { .then(done, done.fail); }); + it('case of scatter points on period bars', function(done) { + Plotly.newPlot(gd, { + data: [ + { + type: 'bar', + name: 'bar', + x: [ + '2017-04', + '2017-07', + '2017-10', + '2018-01' + ], + xperiod: 'M3', + y: [10, 5, 10, 5] + }, + { + type: 'scatter', + name: 'scatter', + x: [ + '2017-01-01', + '2017-02-01', + '2017-03-01', + '2017-04-01', + '2017-05-01', + '2017-06-01', + '2017-07-01', + '2017-08-01', + '2017-09-01', + '2017-10-01', + '2017-11-01', + '2017-12-01' + ], + y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + } + ], + layout: { + hovermode: 'x unified', + showlegend: false, + width: 500, + height: 500, + margin: { + t: 50, + b: 50, + l: 50, + r: 50 + } + } + }) + .then(function(gd) { + _hover(gd, { xpx: 50, ypx: 250 }); + assertLabel({title: 'Feb 1, 2017', items: [ + 'scatter : 2' + ]}); + + _hover(gd, { xpx: 75, ypx: 250 }); + assertLabel({title: 'Mar 1, 2017', items: [ + 'scatter : 3' + ]}); + + _hover(gd, { xpx: 100, ypx: 250 }); + assertLabel({title: 'Apr 1, 2017', items: [ + 'bar : 10', + 'scatter : 4' + ]}); + + _hover(gd, { xpx: 125, ypx: 250 }); + assertLabel({title: 'May 1, 2017', items: [ + 'bar : (Apr 1, 2017, 10)', + 'scatter : 5' + ]}); + + _hover(gd, { xpx: 150, ypx: 250 }); + assertLabel({title: 'Jun 1, 2017', items: [ + 'bar : (Apr 1, 2017, 10)', + 'scatter : 6' + ]}); + + _hover(gd, { xpx: 175, ypx: 250 }); + assertLabel({title: 'Jul 1, 2017', items: [ + 'bar : 5', + 'scatter : 7' + ]}); + + _hover(gd, { xpx: 200, ypx: 250 }); + assertLabel({title: 'Aug 1, 2017', items: [ + 'bar : (Jul 1, 2017, 5)', + 'scatter : 8' + ]}); + + _hover(gd, { xpx: 225, ypx: 250 }); + assertLabel({title: 'Sep 1, 2017', items: [ + 'bar : (Jul 1, 2017, 5)', + 'scatter : 9' + ]}); + + _hover(gd, { xpx: 250, ypx: 250 }); + assertLabel({title: 'Oct 1, 2017', items: [ + 'bar : 10', + 'scatter : 10' + ]}); + + _hover(gd, { xpx: 275, ypx: 250 }); + assertLabel({title: 'Nov 1, 2017', items: [ + 'bar : (Oct 1, 2017, 10)', + 'scatter : 11' + ]}); + + _hover(gd, { xpx: 300, ypx: 250 }); + assertLabel({title: 'Dec 1, 2017', items: [ + 'bar : (Oct 1, 2017, 10)', + 'scatter : 12' + ]}); + + _hover(gd, { xpx: 350, ypx: 250 }); + assertLabel({title: 'Jan 1, 2018', items: [ + 'bar : 5' + ]}); + }) + .then(done, done.fail); + }); + + it('case of M1 period bars overlaid on M3 period bars', function(done) { + Plotly.newPlot(gd, { + data: [ + { + type: 'bar', + name: 'M3', + xperiod: 'M3', + x: [ + '2017-04', + '2017-07', + '2017-10', + '2018-01' + ], + y: [10, 5, 10, 5] + }, + { + type: 'bar', + name: 'M1', + xperiod: 'M1', + x: [ + '2017-01', + '2017-02', + '2017-03', + '2017-04', + '2017-05', + '2017-06', + '2017-07', + '2017-08', + '2017-09', + '2017-10', + '2017-11', + '2017-12' + ], + y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + } + ], + layout: { + barmode: 'overlay', + hovermode: 'x unified', + showlegend: false, + width: 500, + height: 500, + margin: { + t: 50, + b: 50, + l: 50, + r: 50 + } + } + }) + .then(function(gd) { + _hover(gd, { xpx: 25, ypx: 250 }); + assertLabel({title: 'Jan 1, 2017', items: [ + 'M1 : 1' + ]}); + + _hover(gd, { xpx: 50, ypx: 250 }); + assertLabel({title: 'Feb 1, 2017', items: [ + 'M1 : 2' + ]}); + + _hover(gd, { xpx: 75, ypx: 250 }); + assertLabel({title: 'Mar 1, 2017', items: [ + 'M1 : 3' + ]}); + + _hover(gd, { xpx: 100, ypx: 250 }); + assertLabel({title: 'Apr 1, 2017', items: [ + 'M3 : 10', + 'M1 : 4' + ]}); + + _hover(gd, { xpx: 125, ypx: 250 }); + assertLabel({title: 'May 1, 2017', items: [ + 'M3 : (Apr 1, 2017, 10)', + 'M1 : 5' + ]}); + + _hover(gd, { xpx: 150, ypx: 250 }); + assertLabel({title: 'Jun 1, 2017', items: [ + 'M3 : (Apr 1, 2017, 10)', + 'M1 : 6' + ]}); + + _hover(gd, { xpx: 175, ypx: 250 }); + assertLabel({title: 'Jul 1, 2017', items: [ + 'M3 : 5', + 'M1 : 7' + ]}); + + _hover(gd, { xpx: 200, ypx: 250 }); + assertLabel({title: 'Aug 1, 2017', items: [ + 'M3 : (Jul 1, 2017, 5)', + 'M1 : 8' + ]}); + + _hover(gd, { xpx: 225, ypx: 250 }); + assertLabel({title: 'Sep 1, 2017', items: [ + 'M3 : (Jul 1, 2017, 5)', + 'M1 : 9' + ]}); + + _hover(gd, { xpx: 250, ypx: 250 }); + assertLabel({title: 'Oct 1, 2017', items: [ + 'M3 : 10', + 'M1 : 10' + ]}); + + _hover(gd, { xpx: 275, ypx: 250 }); + assertLabel({title: 'Nov 1, 2017', items: [ + 'M3 : (Oct 1, 2017, 10)', + 'M1 : 11' + ]}); + + _hover(gd, { xpx: 300, ypx: 250 }); + assertLabel({title: 'Dec 1, 2017', items: [ + 'M3 : (Oct 1, 2017, 10)', + 'M1 : 12' + ]}); + + _hover(gd, { xpx: 350, ypx: 250 }); + assertLabel({title: 'Jan 1, 2018', items: [ + 'M3 : 5' + ]}); + }) + .then(done, done.fail); + }); + it('should have the same traceorder as the legend', function(done) { var mock = require('@mocks/stacked_area.json'); var mockCopy = Lib.extendDeep({}, mock);