From db44a5bd5e0e4d9ae688ca22c30e2033bdada687 Mon Sep 17 00:00:00 2001 From: John Soklaski Date: Mon, 29 Feb 2016 13:01:25 -0800 Subject: [PATCH 1/5] Add support for multiple subplots to fx.hover() --- src/plots/cartesian/graph_interact.js | 41 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index c418bcdce6c..082be6e2742 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -313,9 +313,15 @@ function hover(gd, evt, subplot){ var fullLayout = gd._fullLayout, plotinfo = fullLayout._plots[subplot], + //If the user passed in an array of subplots, use those instead of finding overlayed plots + subplots = (Object.prototype.toString.call(subplot) == "[object Array]") ? + subplot : + + subplots = [subplot].concat(plotinfo.overlays + .map(function(pi){ return pi.id; })), + // list of all overlaid subplots to look at - subplots = [subplot].concat(plotinfo.overlays - .map(function(pi){ return pi.id; })), + xaArray = subplots.map(function(spId) { return Plotly.Axes.getFromId(gd, spId, 'x'); }), @@ -533,7 +539,7 @@ function hover(gd, evt, subplot){ }; var hoverLabels = createHoverText(hoverData, labelOpts); - hoverAvoidOverlaps(hoverData, rotateLabels ? xaArray[0] : yaArray[0]); + hoverAvoidOverlaps(hoverData, rotateLabels ? "xa" : "ya"); alignHoverText(hoverLabels, rotateLabels); @@ -866,7 +872,7 @@ function createHoverText(hoverData, opts) { // first create the objects var hoverLabels = container.selectAll('g.hovertext') .data(hoverData,function(d){ - return [d.trace.index,d.index,d.x0,d.y0,d.name,d.attr||''].join(','); + return [d.trace.index,d.index,d.x0,d.y0,d.name,d.attr,d.xa,d.ya ||''].join(','); }); hoverLabels.enter().append('g') .classed('hovertext',true) @@ -969,8 +975,8 @@ function createHoverText(hoverData, opts) { g.select('path') .style({fill:traceColor, stroke:contrastColor}); var tbb = tx.node().getBoundingClientRect(), - htx = xa._offset+(d.x0+d.x1)/2, - hty = ya._offset+(d.y0+d.y1)/2, + htx = d.xa._offset+(d.x0+d.x1)/2, + hty = d.ya._offset+(d.y0+d.y1)/2, dx = Math.abs(d.x1-d.x0), dy = Math.abs(d.y1-d.y0), txTotalWidth = tbb.width+HOVERARROWSIZE+HOVERTEXTPAD+tx2width, @@ -1033,18 +1039,19 @@ function createHoverText(hoverData, opts) { // information then. function hoverAvoidOverlaps(hoverData, ax) { var nummoves = 0, - pmin = ax._offset, - pmax = ax._offset+ax._length, // make groups of touching points pointgroups = hoverData .map(function(d,i){ + var axis = d[ax]; return [{ i: i, dp: 0, pos: d.pos, posref: d.posref, - size: d.by*(ax._id.charAt(0)==='x' ? YFACTOR : 1)/2 + size: d.by*(axis._id.charAt(0)==='x' ? YFACTOR : 1)/2, + pmin: axis._offset, + pmax: axis._offset+axis._length }]; }) .sort(function(a,b){ return a[0].posref-b[0].posref; }), @@ -1060,10 +1067,10 @@ function hoverAvoidOverlaps(hoverData, ax) { maxPt = grp[grp.length-1]; // overlap with the top - positive vals are overlaps - topOverlap = pmin-minPt.pos-minPt.dp+minPt.size; + topOverlap = minPt.pmin-minPt.pos-minPt.dp+minPt.size; // overlap with the bottom - positive vals are overlaps - bottomOverlap = maxPt.pos+maxPt.dp+maxPt.size-pmax; + bottomOverlap = maxPt.pos+maxPt.dp+maxPt.size-minPt.pmax; // check for min overlap first, so that we always // see the largest labels @@ -1087,7 +1094,7 @@ function hoverAvoidOverlaps(hoverData, ax) { var deleteCount = 0; for(i=0; ipmax) deleteCount++; + if(pti.pos+pti.dp+pti.size>minPt.pmax) deleteCount++; } // start by deleting points whose data is off screen @@ -1097,7 +1104,7 @@ function hoverAvoidOverlaps(hoverData, ax) { // pos has already been constrained to [pmin,pmax] // so look for points close to that to delete - if(pti.pos>pmax-1) { + if(pti.pos>minPt.pmax-1) { pti.del = true; deleteCount--; } @@ -1108,7 +1115,7 @@ function hoverAvoidOverlaps(hoverData, ax) { // pos has already been constrained to [pmin,pmax] // so look for points close to that to delete - if(pti.pos=0; i--) { if(deleteCount<=0) break; pti = grp[i]; - if(pti.pos+pti.dp+pti.size>pmax) { + if(pti.pos+pti.dp+pti.size>minPt.pmax) { pti.del = true; deleteCount--; } @@ -1149,7 +1156,9 @@ function hoverAvoidOverlaps(hoverData, ax) { p0 = g0[g0.length-1], p1 = g1[0]; topOverlap = p0.pos+p0.dp+p0.size-p1.pos-p1.dp+p1.size; - if(topOverlap>0.01) { + + //Only group points that lie on the same axes + if(topOverlap>0.01 && (p0.pmin == p1.pmin) && (p0.pmax == p1.pmax)) { // push the new point(s) added to this group out of the way for(j=g1.length-1; j>=0; j--) g1[j].dp += topOverlap; From 7e55391ca98b30c2ad872e6201ed6a8e86feb8c1 Mon Sep 17 00:00:00 2001 From: John Soklaski Date: Tue, 1 Mar 2016 10:37:06 -0800 Subject: [PATCH 2/5] Switch to use Array.isArray to check subplot argument. Cleanup to satisfy linting rules. --- src/plots/cartesian/graph_interact.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 082be6e2742..aeb45d8286a 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -314,14 +314,12 @@ function hover(gd, evt, subplot){ var fullLayout = gd._fullLayout, plotinfo = fullLayout._plots[subplot], //If the user passed in an array of subplots, use those instead of finding overlayed plots - subplots = (Object.prototype.toString.call(subplot) == "[object Array]") ? + subplots = Array.isArray(subplot) ? subplot : - - subplots = [subplot].concat(plotinfo.overlays + // list of all overlaid subplots to look at + [subplot].concat(plotinfo.overlays .map(function(pi){ return pi.id; })), - // list of all overlaid subplots to look at - xaArray = subplots.map(function(spId) { return Plotly.Axes.getFromId(gd, spId, 'x'); }), @@ -539,7 +537,7 @@ function hover(gd, evt, subplot){ }; var hoverLabels = createHoverText(hoverData, labelOpts); - hoverAvoidOverlaps(hoverData, rotateLabels ? "xa" : "ya"); + hoverAvoidOverlaps(hoverData, rotateLabels ? 'xa' : 'ya'); alignHoverText(hoverLabels, rotateLabels); @@ -1156,9 +1154,9 @@ function hoverAvoidOverlaps(hoverData, ax) { p0 = g0[g0.length-1], p1 = g1[0]; topOverlap = p0.pos+p0.dp+p0.size-p1.pos-p1.dp+p1.size; - + //Only group points that lie on the same axes - if(topOverlap>0.01 && (p0.pmin == p1.pmin) && (p0.pmax == p1.pmax)) { + if(topOverlap>0.01 && (p0.pmin === p1.pmin) && (p0.pmax === p1.pmax)) { // push the new point(s) added to this group out of the way for(j=g1.length-1; j>=0; j--) g1[j].dp += topOverlap; From cddba4e5d42b50bba303debf71f1aabd5625549c Mon Sep 17 00:00:00 2001 From: John Soklaski Date: Tue, 1 Mar 2016 11:02:58 -0800 Subject: [PATCH 3/5] Some more formatting fixups for lint --- src/plots/cartesian/graph_interact.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 3d4c5eb70c6..5a7c917341b 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -319,7 +319,7 @@ function hover(gd, evt, subplot) { subplot : // list of all overlaid subplots to look at [subplot].concat(plotinfo.overlays - .map(function(pi){ return pi.id; })), + .map(function(pi) { return pi.id; })), xaArray = subplots.map(function(spId) { return Plotly.Axes.getFromId(gd, spId, 'x'); @@ -876,7 +876,7 @@ function createHoverText(hoverData, opts) { // first create the objects var hoverLabels = container.selectAll('g.hovertext') - .data(hoverData,function(d){ + .data(hoverData,function(d) { return [d.trace.index,d.index,d.x0,d.y0,d.name,d.attr,d.xa,d.ya ||''].join(','); }); hoverLabels.enter().append('g') @@ -1050,7 +1050,7 @@ function hoverAvoidOverlaps(hoverData, ax) { // make groups of touching points pointgroups = hoverData - .map(function(d,i){ + .map(function(d,i) { var axis = d[ax]; return [{ i: i, From 57d669d3e0e3ccfd579b50c9fec43a5f660a28d3 Mon Sep 17 00:00:00 2001 From: John Soklaski Date: Fri, 4 Mar 2016 17:23:31 -0800 Subject: [PATCH 4/5] Add unit tests for stacked subplots with both shared x and y axes --- .../mocks/stacked_subplots_shared_yaxis.json | 47 ++++++++ test/jasmine/tests/hover_label_test.js | 104 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 test/image/mocks/stacked_subplots_shared_yaxis.json diff --git a/test/image/mocks/stacked_subplots_shared_yaxis.json b/test/image/mocks/stacked_subplots_shared_yaxis.json new file mode 100644 index 00000000000..4ba82cc407d --- /dev/null +++ b/test/image/mocks/stacked_subplots_shared_yaxis.json @@ -0,0 +1,47 @@ +{ + "data": [ + { + "x": [ + 1, + 2, + 3 + ] + }, + { + "x": [ + 2.1, + 2 + ], + "xaxis": "x2" + }, + { + "x": [ + 3, + 2, + 1 + ], + "xaxis": "x3" + } + ], + "layout": { + "xaxis": { + "domain": [ + 0, + 0.3 + ] + }, + "xaxis2": { + "domain": [ + 0.35, + 0.65 + ] + }, + "xaxis3": { + "domain": [ + 0.7, + 1 + ] + }, + "hovermode": "y" + } +} \ No newline at end of file diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index ee1395464ba..150d429eaca 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -282,3 +282,107 @@ describe('hover info', function() { }); }); }); + +describe('hover info on stacked subplots', function() { + 'use strict'; + + afterEach(destroyGraphDiv); + + describe('hover info on stacked subplots with shared x-axis', function() { + var mock = require('@mocks/stacked_coupled_subplots.json'); + + beforeEach(function(done) { + Plotly.plot(createGraphDiv(), mock.data, mock.layout).then(done); + }); + + it('responds to hover', function() { + var gd = document.getElementById('graph'); + Plotly.Fx.hover(gd, {xval: 3}, ['xy','xy2','xy3']); + + expect(gd._hoverdata.length).toEqual(2); + + expect(gd._hoverdata[0]).toEqual(jasmine.objectContaining( + { + curveNumber: 1, + pointNumber: 1, + x: 3, + y: 110 + })); + + expect(gd._hoverdata[1]).toEqual(jasmine.objectContaining( + { + curveNumber: 2, + pointNumber: 0, + x: 3, + y: 1000 + })); + + //There should be a single label on the x-axis with the shared x value, 3. + expect(d3.selectAll('g.axistext').size()).toEqual(1); + expect(d3.selectAll('g.axistext').select('text').html()).toEqual('3'); + + //There should be two points being hovered over, in two different traces, one in each plot. + expect(d3.selectAll('g.hovertext').size()).toEqual(2); + var textNodes = d3.selectAll('g.hovertext').selectAll('text'); + + expect(textNodes[0][0].innerHTML).toEqual('trace 1'); + expect(textNodes[0][1].innerHTML).toEqual('110'); + expect(textNodes[1][0].innerHTML).toEqual('trace 2'); + expect(textNodes[1][1].innerHTML).toEqual('1000'); + }); + }); + + describe('hover info on stacked subplots with shared y-axis', function() { + var mock = require('@mocks/stacked_subplots_shared_yaxis.json'); + + beforeEach(function(done) { + Plotly.plot(createGraphDiv(), mock.data, mock.layout).then(done); + }); + + it('responds to hover', function() { + var gd = document.getElementById('graph'); + Plotly.Fx.hover(gd, {yval: 0}, ['xy', 'x2y', 'x3y']); + + expect(gd._hoverdata.length).toEqual(3); + + expect(gd._hoverdata[0]).toEqual(jasmine.objectContaining( + { + curveNumber: 0, + pointNumber: 0, + x: 1, + y: 0 + })); + + expect(gd._hoverdata[1]).toEqual(jasmine.objectContaining( + { + curveNumber: 1, + pointNumber: 0, + x: 2.1, + y: 0 + })); + + expect(gd._hoverdata[2]).toEqual(jasmine.objectContaining( + { + curveNumber: 2, + pointNumber: 0, + x: 3, + y: 0 + })); + + //There should be a single label on the y-axis with the shared y value, 0. + expect(d3.selectAll('g.axistext').size()).toEqual(1); + expect(d3.selectAll('g.axistext').select('text').html()).toEqual('0'); + + //There should be three points being hovered over, in three different traces, one in each plot. + expect(d3.selectAll('g.hovertext').size()).toEqual(3); + var textNodes = d3.selectAll('g.hovertext').selectAll('text'); + + expect(textNodes[0][0].innerHTML).toEqual('trace 0'); + expect(textNodes[0][1].innerHTML).toEqual('1'); + expect(textNodes[1][0].innerHTML).toEqual('trace 1'); + expect(textNodes[1][1].innerHTML).toEqual('2.1'); + expect(textNodes[2][0].innerHTML).toEqual('trace 2'); + expect(textNodes[2][1].innerHTML).toEqual('3'); + }); + }); +}); \ No newline at end of file From a2164e4f58054a8bbadd1ad6b99553f048f0c987 Mon Sep 17 00:00:00 2001 From: John Soklaski Date: Mon, 7 Mar 2016 16:09:21 -0800 Subject: [PATCH 5/5] Add baseline image for stacked_subplots_shared_yaxis.json --- .../baselines/stacked_subplots_shared_yaxis.png | Bin 0 -> 34869 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/image/baselines/stacked_subplots_shared_yaxis.png diff --git a/test/image/baselines/stacked_subplots_shared_yaxis.png b/test/image/baselines/stacked_subplots_shared_yaxis.png new file mode 100644 index 0000000000000000000000000000000000000000..70a3beea37478d20df928fbfee452d248099188d GIT binary patch literal 34869 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