From 1903583e2639d22fe72f8ae0c07c069152512a75 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 19 May 2021 16:02:51 -0400 Subject: [PATCH 01/12] remove problematic hover filter and adjust tests --- src/components/fx/hover.js | 34 ---------------- test/jasmine/tests/hover_label_test.js | 55 -------------------------- 2 files changed, 89 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index a568c503f8d..925db9915fa 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -708,7 +708,6 @@ function _hover(gd, evt, subplot, noHoverEvent) { } // Remove duplicated hoverData points - // note that d3 also filters identical points in the rendering steps var repeated = {}; hoverData = hoverData.filter(function(hd) { var key = hoverDataKey(hd); @@ -820,9 +819,7 @@ function createHoverText(hoverData, opts, gd) { var xa = c0.xa; var ya = c0.ya; 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; var outerWidth = outerContainerBB.width; @@ -1011,44 +1008,13 @@ function createHoverText(hoverData, opts, gd) { } label.attr('transform', strTranslate(lx, ly)); - - // remove the "close but not quite" points - // because of error bars, only take up to a space - hoverData = filterClosePoints(hoverData); }); - function filterClosePoints(hoverData) { - return hoverData.filter(function(d) { - 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; - }); - } - // Show a single hover label if(helpers.isUnifiedHover(hovermode)) { // Delete leftover hover labels from other hovermodes container.selectAll('g.hovertext').remove(); - // similarly to compare mode, we remove the "close but not quite together" points - if((t0 !== undefined) && (c0.distance <= opts.hoverdistance)) hoverData = filterClosePoints(hoverData); - // Return early if nothing is hovered on if(hoverData.length === 0) return; diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 371c28932c9..c47db8d6cbf 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -1714,40 +1714,6 @@ describe('hover info', function() { }) .then(done, done.fail); }); - - it('should avoid overlaps on *too close* pts are filtered out', function(done) { - Plotly.newPlot(gd, [ - {name: 'A', x: [9, 10], y: [9, 10]}, - {name: 'B', x: [8, 9], y: [9, 10]}, - {name: 'C', x: [9, 10], y: [10, 11]} - ], { - hovermode: 'x', - xaxis: {range: [0, 100]}, - yaxis: {range: [0, 100]}, - width: 700, - height: 450 - }) - .then(function() { _hover(gd, 67, 239); }) - .then(function() { - var nodesA = hoverInfoNodes('A'); - var nodesC = hoverInfoNodes('C'); - - // Ensure layout correct - assertLabelsInsideBoxes(nodesA, 'A'); - assertLabelsInsideBoxes(nodesC, 'C'); - assertSecondaryRightToPrimaryBox(nodesA, 'A'); - assertSecondaryRightToPrimaryBox(nodesC, 'C'); - - // Ensure stacking, finally - var boxA = nodesA.primaryBox.getBoundingClientRect(); - var boxC = nodesC.primaryBox.getBoundingClientRect(); - - // Be robust against floating point arithmetic and subtle future layout changes - expect(calcLineOverlap(boxA.top, boxA.bottom, boxC.top, boxC.bottom)) - .toBeWithin(0, 1); - }) - .then(done, done.fail); - }); }); describe('constraints info graph viewport', function() { @@ -4708,27 +4674,6 @@ describe('hovermode: (x|y)unified', function() { .then(done, done.fail); }); - it('shares filtering logic with compare mode x', function(done) { - var mock = require('@mocks/27.json'); - var mockCopy = Lib.extendDeep({}, mock); - - Plotly.newPlot(gd, mockCopy) - .then(function(gd) { - _hover(gd, { xval: '2002' }); - assertElementCount('g.hovertext', 2); - - return Plotly.relayout(gd, 'hovermode', 'x unified'); - }) - .then(function() { - _hover(gd, { xval: '2002' }); - assertLabel({title: '2002.042', items: [ - 'Market income : 0.5537845', - 'Market incom... : 0.4420997' - ]}); - }) - .then(done, done.fail); - }); - it('case of scatter points on period bars', function(done) { Plotly.newPlot(gd, { data: [ From 969420f3f8a16d35971f0bcae550580d26f358f1 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 19 May 2021 17:01:41 -0400 Subject: [PATCH 02/12] remove period addition hacks now that the filter is gone --- src/components/fx/hover.js | 27 -------------------------- test/jasmine/tests/hover_label_test.js | 9 ++++----- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 925db9915fa..cbb0154fd47 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -14,7 +14,6 @@ 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'); @@ -662,34 +661,8 @@ function _hover(gd, evt, subplot, noHoverEvent) { findHoverPoints(customXVal, customYVal); - // also find start, middle and end point for period var axLetter = hovermode.charAt(0); if(winningPoint.trace[axLetter + 'period']) { - var v = winningPoint[axLetter + 'LabelVal']; - var ax = winningPoint[axLetter + 'a']; - var T = {}; - T[axLetter + 'period'] = winningPoint.trace[axLetter + 'period']; - T[axLetter + 'period0'] = winningPoint.trace[axLetter + 'period0']; - - T[axLetter + 'periodalignment'] = 'start'; - var start = alignPeriod(T, ax, axLetter, [v])[0]; - - T[axLetter + 'periodalignment'] = 'middle'; - var middle = alignPeriod(T, ax, axLetter, [v])[0]; - - T[axLetter + 'periodalignment'] = 'end'; - var end = alignPeriod(T, ax, axLetter, [v])[0]; - - if(axLetter === 'x') { - findHoverPoints(start, customYVal); - findHoverPoints(middle, customYVal); - findHoverPoints(end, customYVal); - } else { - findHoverPoints(customXVal, start); - findHoverPoints(customXVal, middle); - findHoverPoints(customXVal, end); - } - var k; var seen = {}; for(k = 0; k < initLen; k++) { diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index c47db8d6cbf..697d19d5f3c 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -4974,6 +4974,7 @@ describe('hovermode: (x|y)unified', function() { _hover(gd, { xpx: 100, ypx: 200 }); assertLabel({title: 'Jan 1, 2000', items: [ + 'bar : (Dec, 2)', 'scatter : 1.1' ]}); @@ -5051,22 +5052,20 @@ describe('hovermode: (x|y)unified', function() { _hover(gd, { xpx: 40, ypx: 200 }); assertLabel({title: 'Jan', items: [ 'bar : (Jan 1, 2000, 1)', - 'start : 1', - 'end : 1' + 'start : 1' ]}); _hover(gd, { xpx: 100, ypx: 200 }); assertLabel({title: 'Jan 1, 2000', items: [ 'bar : 1', - 'start : (Jan, 1)', - 'end : (Jan, 1)' + 'start : (Jan, 1)' ]}); _hover(gd, { xpx: 360, ypx: 200 }); assertLabel({title: 'Feb 1, 2000', items: [ 'bar : 2', 'start : (Feb, 2)', - 'end : (Feb, 2)' + 'end : (Jan, 1)' ]}); _hover(gd, { xpx: 400, ypx: 200 }); From bb67741d4a0e07891b2b8bbc903806d672df9982 Mon Sep 17 00:00:00 2001 From: archmoj Date: Wed, 19 May 2021 17:30:35 -0400 Subject: [PATCH 03/12] add jasmine test --- test/jasmine/tests/hover_label_test.js | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 697d19d5f3c..28730a9b19f 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -4674,6 +4674,55 @@ describe('hovermode: (x|y)unified', function() { .then(done, done.fail); }); + it('should display hover for scatter and bars at various intervals', function(done) { + Plotly.newPlot(gd, { + data: [{ + name: 'bar', + type: 'bar', + y: [10, 30] + }, { + name: 'scatter', + type: 'scatter', + x: [0, 0.2, 0.4, 0.6, 0.8, 1], + y: [21, 22, 23, 24, 25, 26] + }], + layout: { + hovermode: 'x unified', + showlegend: false, + width: 500, + height: 500, + margin: { + t: 50, + b: 50, + l: 50, + r: 50 + } + } + }) + .then(function() { + _hover(gd, { xpx: 100, ypx: 200 }); + assertLabel({title: '0', items: [ + 'bar : 10', + 'scatter : 21' + ]}); + }) + .then(function() { + _hover(gd, { xpx: 200, ypx: 200 }); + assertLabel({title: '0.6', items: [ + 'bar : (1, 30)', + 'scatter : 24' + ]}); + }) + .then(function() { + _hover(gd, { xpx: 300, ypx: 200 }); + assertLabel({title: '1', items: [ + 'bar : 30', + 'scatter : 26' + ]}); + }) + .then(done, done.fail); + }); + it('case of scatter points on period bars', function(done) { Plotly.newPlot(gd, { data: [ From 3b855345e556b2024401d3cddebdf25bd25d9a77 Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 20 May 2021 14:48:58 -0400 Subject: [PATCH 04/12] unify non-period and period filter --- src/components/fx/hover.js | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index cbb0154fd47..0e8fe0212b4 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -661,22 +661,18 @@ function _hover(gd, evt, subplot, noHoverEvent) { findHoverPoints(customXVal, customYVal); - var axLetter = hovermode.charAt(0); - if(winningPoint.trace[axLetter + 'period']) { - var k; - var seen = {}; - for(k = 0; k < initLen; k++) { - seen[hoverData[k].trace.index] = true; - } + var k; + var seen = {}; + for(k = 0; k < initLen; k++) { + seen[hoverData[k].trace.index] = true; + } - // remove non-period aditions and traces that seen before - for(k = hoverData.length - 1; k >= initLen; k--) { - if( - seen[hoverData[k].trace.index] || - !hoverData[k].trace[axLetter + 'period'] - ) { - hoverData.splice(k, 1); - } + // remove aditions and traces that seen before + for(k = hoverData.length - 1; k >= initLen; k--) { + if( + seen[hoverData[k].trace.index] + ) { + hoverData.splice(k, 1); } } From 658d311cc4e63f8605e7ff3fd7d1745774a24f36 Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 20 May 2021 15:58:55 -0400 Subject: [PATCH 05/12] revise winnig point not to be bar or box --- src/components/fx/hover.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 0e8fe0212b4..d43bf544f69 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -644,8 +644,8 @@ function _hover(gd, evt, subplot, noHoverEvent) { hoverData.sort(function(d1, d2) { return d1.distance - d2.distance; }); - // move period positioned points to the end of list - hoverData = orderPeriod(hoverData, hovermode); + // move period positioned points and box/bar-like traces to the end of the list + hoverData = orderRangePoints(hoverData, hovermode); // If in compare mode, select every point at position if( @@ -1864,7 +1864,7 @@ function plainText(s, len) { }); } -function orderPeriod(hoverData, hovermode) { +function orderRangePoints(hoverData, hovermode) { var axLetter = hovermode.charAt(0); var first = []; @@ -1873,7 +1873,11 @@ function orderPeriod(hoverData, hovermode) { for(var i = 0; i < hoverData.length; i++) { var d = hoverData[i]; - if(d.trace[axLetter + 'period']) { + if( + d.trace[axLetter + 'period'] || + Registry.traceIs(d.trace, 'bar-like') || + Registry.traceIs(d.trace, 'box-violin') + ) { last.push(d); } else { first.push(d); From 93ab1467bf6b2038e21cfd95c398dcf1a33e9a3a Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 20 May 2021 16:21:00 -0400 Subject: [PATCH 06/12] underscore ohlc getClosest function having different args compared to Fx --- src/traces/ohlc/hover.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/traces/ohlc/hover.js b/src/traces/ohlc/hover.js index e189c828733..5800303db40 100644 --- a/src/traces/ohlc/hover.js +++ b/src/traces/ohlc/hover.js @@ -23,7 +23,7 @@ function hoverPoints(pointData, xval, yval, hovermode) { return hoverOnPoints(pointData, xval, yval, hovermode); } -function getClosestPoint(pointData, xval, yval, hovermode) { +function _getClosestPoint(pointData, xval, yval, hovermode) { var cd = pointData.cd; var xa = pointData.xa; var trace = cd[0].trace; @@ -95,7 +95,7 @@ function hoverSplit(pointData, xval, yval, hovermode) { var t = cd[0].t; var closeBoxData = []; - var closestPoint = getClosestPoint(pointData, xval, yval, hovermode); + var closestPoint = _getClosestPoint(pointData, xval, yval, hovermode); // skip the rest (for this trace) if we didn't find a close point if(!closestPoint) return []; @@ -150,7 +150,7 @@ function hoverOnPoints(pointData, xval, yval, hovermode) { var trace = cd[0].trace; var t = cd[0].t; - var closestPoint = getClosestPoint(pointData, xval, yval, hovermode); + var closestPoint = _getClosestPoint(pointData, xval, yval, hovermode); // skip the rest (for this trace) if we didn't find a close point if(!closestPoint) return []; From 266fced96c6738a2dd2db6750d57a6ef4c324821 Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 20 May 2021 16:53:59 -0400 Subject: [PATCH 07/12] avoid infinit hoverdistance to confuse bar hover when picking extra points --- src/components/fx/hover.js | 7 +++++-- src/traces/bar/hover.js | 8 +++++--- src/traces/funnel/hover.js | 4 ++-- src/traces/histogram/hover.js | 4 ++-- src/traces/waterfall/hover.js | 4 ++-- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index d43bf544f69..8c243abfed9 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -490,6 +490,7 @@ function _hover(gd, evt, subplot, noHoverEvent) { if(hoverdistance !== 0) { if(trace._module && trace._module.hoverPoints) { var newPoints = trace._module.hoverPoints(pointData, xval, yval, _mode, { + finiteRange: true, hoverLayer: fullLayout._hoverlayer }); @@ -1868,23 +1869,25 @@ function orderRangePoints(hoverData, hovermode) { var axLetter = hovermode.charAt(0); var first = []; + var second = []; var last = []; for(var i = 0; i < hoverData.length; i++) { var d = hoverData[i]; if( - d.trace[axLetter + 'period'] || Registry.traceIs(d.trace, 'bar-like') || Registry.traceIs(d.trace, 'box-violin') ) { last.push(d); + } else if(d.trace[axLetter + 'period']) { + second.push(d); } else { first.push(d); } } - return first.concat(last); + return first.concat(second).concat(last); } function customVal(axLetter, winningPoint, fullLayout) { diff --git a/src/traces/bar/hover.js b/src/traces/bar/hover.js index 93539145d3e..2c0ba4d86ba 100644 --- a/src/traces/bar/hover.js +++ b/src/traces/bar/hover.js @@ -9,8 +9,8 @@ var getLineWidth = require('./helpers').getLineWidth; var hoverLabelText = require('../../plots/cartesian/axes').hoverLabelText; var BADNUM = require('../../constants/numerical').BADNUM; -function hoverPoints(pointData, xval, yval, hovermode) { - var barPointData = hoverOnBars(pointData, xval, yval, hovermode); +function hoverPoints(pointData, xval, yval, hovermode, opts) { + var barPointData = hoverOnBars(pointData, xval, yval, hovermode, opts); if(barPointData) { var cd = barPointData.cd; @@ -24,7 +24,7 @@ function hoverPoints(pointData, xval, yval, hovermode) { } } -function hoverOnBars(pointData, xval, yval, hovermode) { +function hoverOnBars(pointData, xval, yval, hovermode, opts) { var cd = pointData.cd; var trace = cd[0].trace; var t = cd[0].t; @@ -67,6 +67,8 @@ function hoverOnBars(pointData, xval, yval, hovermode) { }; function inbox(_minPos, _maxPos, maxDistance) { + if(opts.finiteRange) maxDistance = 0; + // add a little to the pseudo-distance for wider bars, so that like scatter, // if you are over two overlapping bars, the narrower one wins. return Fx.inbox(_minPos - posVal, _maxPos - posVal, diff --git a/src/traces/funnel/hover.js b/src/traces/funnel/hover.js index 02687c1921e..21493dcb208 100644 --- a/src/traces/funnel/hover.js +++ b/src/traces/funnel/hover.js @@ -4,8 +4,8 @@ var opacity = require('../../components/color').opacity; var hoverOnBars = require('../bar/hover').hoverOnBars; var formatPercent = require('../../lib').formatPercent; -module.exports = function hoverPoints(pointData, xval, yval, hovermode) { - var point = hoverOnBars(pointData, xval, yval, hovermode); +module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) { + var point = hoverOnBars(pointData, xval, yval, hovermode, opts); if(!point) return; var cd = point.cd; diff --git a/src/traces/histogram/hover.js b/src/traces/histogram/hover.js index 317c632e984..8b3f26e20c1 100644 --- a/src/traces/histogram/hover.js +++ b/src/traces/histogram/hover.js @@ -3,8 +3,8 @@ var barHover = require('../bar/hover').hoverPoints; var hoverLabelText = require('../../plots/cartesian/axes').hoverLabelText; -module.exports = function hoverPoints(pointData, xval, yval, hovermode) { - var pts = barHover(pointData, xval, yval, hovermode); +module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) { + var pts = barHover(pointData, xval, yval, hovermode, opts); if(!pts) return; diff --git a/src/traces/waterfall/hover.js b/src/traces/waterfall/hover.js index 95950200cc4..b7b0ed23444 100644 --- a/src/traces/waterfall/hover.js +++ b/src/traces/waterfall/hover.js @@ -10,8 +10,8 @@ var DIRSYMBOL = { decreasing: delta.DECREASING.SYMBOL }; -module.exports = function hoverPoints(pointData, xval, yval, hovermode) { - var point = hoverOnBars(pointData, xval, yval, hovermode); +module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) { + var point = hoverOnBars(pointData, xval, yval, hovermode, opts); if(!point) return; var cd = point.cd; From c57f717f0308eeab9ca2cfd6eb6eb9361775277c Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 20 May 2021 17:13:00 -0400 Subject: [PATCH 08/12] pass opts to bar-like hoverPoints method --- test/jasmine/tests/bar_test.js | 6 +++--- test/jasmine/tests/funnel_test.js | 2 +- test/jasmine/tests/waterfall_test.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 221fbbf5d8f..62d74d99d71 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -2296,7 +2296,7 @@ describe('bar hover', function() { function _hover(gd, xval, yval, hovermode) { var pointData = getPointData(gd); - var pts = Bar.hoverPoints(pointData, xval, yval, hovermode); + var pts = Bar.hoverPoints(pointData, xval, yval, hovermode, {}); if(!pts) return false; var pt = pts[0]; @@ -2663,8 +2663,8 @@ describe('bar hover', function() { barmode: m }) .then(function() { - var pt0 = Bar.hoverPoints(getPointData(gd, 0), 0, 1, 'x')[0]; - var pt1 = Bar.hoverPoints(getPointData(gd, 1), 0, 1, 'x')[0]; + var pt0 = Bar.hoverPoints(getPointData(gd, 0), 0, 1, 'x', {})[0]; + var pt1 = Bar.hoverPoints(getPointData(gd, 1), 0, 1, 'x', {})[0]; expect(pt0.yLabelVal).toBe(0, 'y label value for data[0]'); expect(pt1.yLabelVal).toBe(1, 'y label value for data[1]'); diff --git a/test/jasmine/tests/funnel_test.js b/test/jasmine/tests/funnel_test.js index 32c076f005e..e318b1706ce 100644 --- a/test/jasmine/tests/funnel_test.js +++ b/test/jasmine/tests/funnel_test.js @@ -1309,7 +1309,7 @@ describe('funnel hover', function() { function _hover(gd, xval, yval, hovermode) { var pointData = getPointData(gd); - var pts = Funnel.hoverPoints(pointData, xval, yval, hovermode); + var pts = Funnel.hoverPoints(pointData, xval, yval, hovermode, {}); if(!pts) return false; var pt = pts[0]; diff --git a/test/jasmine/tests/waterfall_test.js b/test/jasmine/tests/waterfall_test.js index eb675ee6d2f..70952a9db45 100644 --- a/test/jasmine/tests/waterfall_test.js +++ b/test/jasmine/tests/waterfall_test.js @@ -1345,7 +1345,7 @@ describe('waterfall hover', function() { function _hover(gd, xval, yval, hovermode) { var pointData = getPointData(gd); - var pts = Waterfall.hoverPoints(pointData, xval, yval, hovermode); + var pts = Waterfall.hoverPoints(pointData, xval, yval, hovermode, {}); if(!pts) return false; var pt = pts[0]; From c24e12e2b98597ad067a62f2a6895e2c19d2009a Mon Sep 17 00:00:00 2001 From: archmoj Date: Thu, 20 May 2021 18:28:27 -0400 Subject: [PATCH 09/12] add jasmine tests --- test/jasmine/tests/hover_label_test.js | 122 ++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 28730a9b19f..ccbedcf5dbc 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -4674,7 +4674,7 @@ describe('hovermode: (x|y)unified', function() { .then(done, done.fail); }); - it('should display hover for scatter and bars at various intervals', function(done) { + it('should display hover for scatter and bars at various intervals (default hoverdistance)', function(done) { Plotly.newPlot(gd, { data: [{ name: 'bar', @@ -4723,6 +4723,126 @@ describe('hovermode: (x|y)unified', function() { .then(done, done.fail); }); + it('should display hover for scatter and bars at various intervals (case of hoverdistance: -1) tests finitRange', function(done) { + Plotly.newPlot(gd, { + data: [{ + name: 'bar', + type: 'bar', + y: [10, 30] + }, { + name: 'scatter', + type: 'scatter', + x: [0, 0.2, 0.4, 0.6, 0.8, 1], + y: [21, 22, 23, 24, 25, 26] + }], + layout: { + hoverdistance: -1, + hovermode: 'x unified', + showlegend: false, + width: 500, + height: 500, + margin: { + t: 50, + b: 50, + l: 50, + r: 50 + } + } + }) + .then(function() { + _hover(gd, { xpx: 100, ypx: 200 }); + assertLabel({title: '0', items: [ + 'bar : 10', + 'scatter : 21' + ]}); + }) + .then(function() { + _hover(gd, { xpx: 200, ypx: 200 }); + assertLabel({title: '0.6', items: [ + 'bar : (1, 30)', + 'scatter : 24' + ]}); + }) + .then(function() { + _hover(gd, { xpx: 300, ypx: 200 }); + assertLabel({title: '1', items: [ + 'bar : 30', + 'scatter : 26' + ]}); + }) + .then(done, done.fail); + }); + + it('should display hover for two high-res scatter at different various intervals', function(done) { + var x1 = []; + var y1 = []; + var x2 = []; + var y2 = []; + var i, t; + + function r100(v) { + return Math.round(v * 100); + } + + for(i = 0; i <= 1800; i++) { + t = i / 180 * Math.PI; + x1.push(r100(t / 5)); + y1.push(r100(Math.sin(t))); + } + + for(i = 0; i <= 360; i++) { + t = i / 180 * Math.PI; + x2.push(r100(t)); + y2.push(r100(Math.sin(t))); + } + + Plotly.newPlot(gd, { + data: [{ + name: 'high', + x: x1, + y: y1 + }, { + name: 'low', + x: x2, + y: y2 + }], + layout: { + hovermode: 'x unified', + showlegend: false, + width: 500, + height: 500, + margin: { + t: 50, + b: 50, + l: 50, + r: 50 + } + } + }) + .then(function() { + _hover(gd, { xpx: 100, ypx: 200 }); + assertLabel({title: '157', items: [ + 'high : 100', + 'low : 100' + ]}); + }) + .then(function() { + _hover(gd, { xpx: 175, ypx: 200 }); + assertLabel({title: '275', items: [ + 'high : 93', + 'low : (274, 39)' + ]}); + }) + .then(function() { + _hover(gd, { xpx: 350, ypx: 200 }); + assertLabel({title: '550', items: [ + 'high : 68', + 'low : −71' + ]}); + }) + .then(done, done.fail); + }); + it('case of scatter points on period bars', function(done) { Plotly.newPlot(gd, { data: [ From 520dc80ba2e587259f81e2d8bedd3f4fb3012bec Mon Sep 17 00:00:00 2001 From: archmoj Date: Sat, 22 May 2021 11:39:18 -0400 Subject: [PATCH 10/12] use winning point coords to pickup other points --- src/components/fx/hover.js | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 8c243abfed9..0b75e9c8cb3 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -643,10 +643,13 @@ function _hover(gd, evt, subplot, noHoverEvent) { } } - hoverData.sort(function(d1, d2) { return d1.distance - d2.distance; }); + var sortHoverData = function() { + hoverData.sort(function(d1, d2) { return d1.distance - d2.distance; }); - // move period positioned points and box/bar-like traces to the end of the list - hoverData = orderRangePoints(hoverData, hovermode); + // move period positioned points and box/bar-like traces to the end of the list + hoverData = orderRangePoints(hoverData, hovermode); + }; + sortHoverData(); // If in compare mode, select every point at position if( @@ -654,7 +657,6 @@ function _hover(gd, evt, subplot, noHoverEvent) { hoverData[0].length !== 0 && hoverData[0].trace.type !== 'splom' // TODO: add support for splom ) { - var initLen = hoverData.length; var winningPoint = hoverData[0]; var customXVal = customVal('x', winningPoint, fullLayout); @@ -662,30 +664,28 @@ function _hover(gd, evt, subplot, noHoverEvent) { findHoverPoints(customXVal, customYVal); - var k; + var finalPoints = []; var seen = {}; - for(k = 0; k < initLen; k++) { - seen[hoverData[k].trace.index] = true; - } - - // remove aditions and traces that seen before - for(k = hoverData.length - 1; k >= initLen; k--) { - if( - seen[hoverData[k].trace.index] - ) { - hoverData.splice(k, 1); + var insert = function(hd) { + var type = hd.trace.type; + var key = ( + type === 'ohlc' || + type === 'candlestick' + ) ? hoverDataKey(hd) : hd.trace.index; + if(!seen[key]) { + seen[key] = true; + finalPoints.push(hd); } - } + }; - // Remove duplicated hoverData points - var repeated = {}; - hoverData = hoverData.filter(function(hd) { - var key = hoverDataKey(hd); - if(!repeated[key]) { - repeated[key] = true; - return repeated[key]; - } - }); + // insert the winnig point first + insert(winningPoint); + // override from the end + for(var k = hoverData.length - 1; k > 0; k--) { + insert(hoverData[k]); + } + hoverData = finalPoints; + sortHoverData(); } // lastly, emit custom hover/unhover events From 71f75f508aae3c78cb2e0d658f53a5c7393eab08 Mon Sep 17 00:00:00 2001 From: archmoj Date: Sat, 22 May 2021 12:21:08 -0400 Subject: [PATCH 11/12] adjust tests --- src/components/fx/hover.js | 2 ++ test/jasmine/tests/hover_label_test.js | 34 +++++++++++++------------- test/jasmine/tests/violin_test.js | 4 +-- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 0b75e9c8cb3..947285096dd 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -669,6 +669,8 @@ function _hover(gd, evt, subplot, noHoverEvent) { var insert = function(hd) { var type = hd.trace.type; var key = ( + type === 'box' || + type === 'violin' || type === 'ohlc' || type === 'candlestick' ) ? hoverDataKey(hd) : hd.trace.index; diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index ccbedcf5dbc..f1db4bba1d3 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -920,37 +920,37 @@ describe('hover info', function() { fontFamily: 'Arial', fontColor: 'rgb(0, 100, 200)' }, { - bgcolor: 'rgb(255, 127, 14)', + bgcolor: 'rgb(227, 119, 194)', bordercolor: 'rgb(68, 68, 68)', fontSize: 13, fontFamily: 'Arial', fontColor: 'rgb(68, 68, 68)' }, { - bgcolor: 'rgb(0, 200, 0)', + bgcolor: 'rgb(140, 86, 75)', bordercolor: 'rgb(255, 255, 255)', fontSize: 13, fontFamily: 'Arial', fontColor: 'rgb(255, 255, 255)' }, { - bgcolor: 'rgb(150, 0, 0)', + bgcolor: 'rgb(150, 0, 200)', bordercolor: 'rgb(255, 255, 255)', fontSize: 13, fontFamily: 'Arial', fontColor: 'rgb(255, 255, 255)' }, { - bgcolor: 'rgb(150, 0, 200)', + bgcolor: 'rgb(150, 0, 0)', bordercolor: 'rgb(255, 255, 255)', fontSize: 13, fontFamily: 'Arial', fontColor: 'rgb(255, 255, 255)' }, { - bgcolor: 'rgb(140, 86, 75)', + bgcolor: 'rgb(0, 200, 0)', bordercolor: 'rgb(255, 255, 255)', fontSize: 13, fontFamily: 'Arial', fontColor: 'rgb(255, 255, 255)' }, { - bgcolor: 'rgb(227, 119, 194)', + bgcolor: 'rgb(255, 127, 14)', bordercolor: 'rgb(68, 68, 68)', fontSize: 13, fontFamily: 'Arial', @@ -2278,7 +2278,7 @@ describe('hover info on stacked subplots', function() { y: 0 })); - expect(gd._hoverdata[1]).toEqual(jasmine.objectContaining( + expect(gd._hoverdata[2]).toEqual(jasmine.objectContaining( { curveNumber: 1, pointNumber: 0, @@ -2286,7 +2286,7 @@ describe('hover info on stacked subplots', function() { y: 0 })); - expect(gd._hoverdata[2]).toEqual(jasmine.objectContaining( + expect(gd._hoverdata[1]).toEqual(jasmine.objectContaining( { curveNumber: 2, pointNumber: 0, @@ -5225,16 +5225,16 @@ describe('hovermode: (x|y)unified', function() { ]}); _hover(gd, { xpx: 100, ypx: 200 }); - assertLabel({title: 'Jan 1, 2000', items: [ - 'bar : 1', - 'start : (Jan, 1)' + assertLabel({title: 'Jan', items: [ + 'bar : (Jan 1, 2000, 1)', + 'start : 1' ]}); _hover(gd, { xpx: 360, ypx: 200 }); - assertLabel({title: 'Feb 1, 2000', items: [ - 'bar : 2', + assertLabel({title: 'Jan', items: [ + 'bar : (Feb 1, 2000, 2)', 'start : (Feb, 2)', - 'end : (Jan, 1)' + 'end : 1' ]}); _hover(gd, { xpx: 400, ypx: 200 }); @@ -5275,10 +5275,10 @@ describe('hovermode: (x|y)unified', function() { .then(function(gd) { _hover(gd, {curveNumber: 0}); - assertLabel({title: 'Apr 13, 2014, 15:21:11', items: [ + assertLabel({title: 'Apr 13, 2014, 15:21:15', items: [ 'Outdoor (wun... : (Apr 13, 2014, 15:26:12, 69.4)', - '1st Floor (N... : (Apr 13, 2014, 15:21:15, 74.8)', - '2nd Floor (R... : 73.625', + '1st Floor (N... : 74.8', + '2nd Floor (R... : (Apr 13, 2014, 15:21:11, 73.625)', 'Attic (Ardui... : (Apr 13, 2014, 15:26:34, 98.49)' ]}); }) diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js index 4b111891583..a8dbd926bcf 100644 --- a/test/jasmine/tests/violin_test.js +++ b/test/jasmine/tests/violin_test.js @@ -537,8 +537,8 @@ describe('Test violin hover:', function() { name: ['', '', '', '', '', ''], axis: 'Sat', hoverLabelPos: [ - [364, 270], [352, 270], [339, 270], - [346, 270], [349, 270], [387, 270] + [364, 270], [387, 270], [339, 270], + [346, 270], [349, 270], [352, 270] ] }, { desc: 'single horizontal violin', From e18bb61d74c9770725951ebae6276a213e7ba8af Mon Sep 17 00:00:00 2001 From: archmoj Date: Sat, 22 May 2021 12:54:46 -0400 Subject: [PATCH 12/12] add jasmine test --- test/jasmine/tests/hover_label_test.js | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index f1db4bba1d3..9db86bcb2d5 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -4773,6 +4773,78 @@ describe('hovermode: (x|y)unified', function() { .then(done, done.fail); }); + it('should pick the bar which is closest to the winning point no the bar that close to the cursor', function(done) { + Plotly.newPlot(gd, { + data: [{ + name: 'bar', + type: 'bar', + y: [10, 20, 30] + }, { + name: 'scatter', + type: 'scatter', + x: [0, 0.49, 1, 1.51, 2], + y: [21, 22, 23, 24, 25] + }], + layout: { + hoverdistance: -1, + hovermode: 'x unified', + showlegend: false, + width: 500, + height: 500, + margin: { + t: 50, + b: 50, + l: 50, + r: 50 + } + } + }) + .then(function() { + _hover(gd, { xpx: 0, ypx: 200 }); + assertLabel({title: '0', items: [ + 'bar : 10', + 'scatter : 21' + ]}); + + _hover(gd, { xpx: 100, ypx: 200 }); + assertLabel({title: '0.49', items: [ + 'bar : (0, 10)', + 'scatter : 22' + ]}); + + _hover(gd, { xpx: 150, ypx: 200 }); + assertLabel({title: '0.49', items: [ + 'bar : (0, 10)', + 'scatter : 22' + ]}); + + _hover(gd, { xpx: 200, ypx: 200 }); + assertLabel({title: '1', items: [ + 'bar : 20', + 'scatter : 23' + ]}); + + _hover(gd, { xpx: 250, ypx: 200 }); + assertLabel({title: '1.51', items: [ + 'bar : (2, 30)', + 'scatter : 24' + ]}); + + _hover(gd, { xpx: 300, ypx: 200 }); + assertLabel({title: '1.51', items: [ + 'bar : (2, 30)', + 'scatter : 24' + ]}); + + _hover(gd, { xpx: 400, ypx: 200 }); + assertLabel({title: '2', items: [ + 'bar : 30', + 'scatter : 25' + ]}); + }) + .then(done, done.fail); + }); + it('should display hover for two high-res scatter at different various intervals', function(done) { var x1 = []; var y1 = [];