diff --git a/draftlogs/6989_fix.md b/draftlogs/6989_fix.md new file mode 100644 index 00000000000..7e28efa12c9 --- /dev/null +++ b/draftlogs/6989_fix.md @@ -0,0 +1 @@ + - Add support for xref and yref "paper" for shapes with layer "between" [[#6989](https://github.com/plotly/plotly.js/pull/6989)] \ No newline at end of file diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index 3f9049070e8..da87679683e 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -504,7 +504,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) { var plotinfo = { id: id, - plotgroup: plotgroup, + plotgroup: [undefined, plotgroup], // ragenslider has no background layer xaxis: xa, yaxis: ya, isRangePlot: true diff --git a/src/components/shapes/draw.js b/src/components/shapes/draw.js index 4cc75dc920e..a6a74b6901a 100644 --- a/src/components/shapes/draw.js +++ b/src/components/shapes/draw.js @@ -93,10 +93,10 @@ function drawOne(gd, index) { if(options.layer === 'above') { drawShape(gd._fullLayout._shapeUpperLayer); + } else if(options.layer === 'between') { + drawShape(gd._fullLayout._shapeLayerBetween); } else if(options.xref === 'paper' || options.yref === 'paper') { drawShape(gd._fullLayout._shapeLowerLayer); - } else if(options.layer === 'between') { - drawShape(plotinfo.shapelayerBetween); } else { if(plotinfo._hadPlotinfo) { var mainPlot = plotinfo.mainplotinfo || plotinfo; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 39f9bc93496..7cb790b5c37 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -3731,8 +3731,11 @@ function makePlotFramework(gd) { .classed('shapelayer', true); // single cartesian layer for the whole plot - fullLayout._cartesianlayer = fullLayout._paper.append('g').classed('cartesianlayer', true); - + fullLayout._cartesianlayerBelow = fullLayout._paper.append('g').classed('cartesianlayer-below', true); + var layerBetween = fullLayout._paper.append('g').classed('layer-between', true); + fullLayout._imageLayerBetween = layerBetween.append('g').classed('imagelayer', true); + fullLayout._shapeLayerBetween = layerBetween.append('g').classed('shapelayer', true); + fullLayout._cartesianlayerAbove = fullLayout._paper.append('g').classed('cartesianlayer', true); // single polar layer for the whole plot fullLayout._polarlayer = fullLayout._paper.append('g').classed('polarlayer', true); diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index cd5e890d01c..2c885c872d9 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -133,7 +133,7 @@ function lsInner(gd) { } else { var xDomain = plotinfo.xaxis.domain; var yDomain = plotinfo.yaxis.domain; - var plotgroup = plotinfo.plotgroup; + var plotgroup = plotinfo.plotgroup[0]; if(overlappingDomain(xDomain, yDomain, lowerDomains) && subplot.indexOf(zindexSeparator) === -1) { var pgNode = plotgroup.node(); diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js index 07863ebbdf1..1820bc27a4e 100644 --- a/src/plots/cartesian/index.js +++ b/src/plots/cartesian/index.js @@ -159,7 +159,7 @@ exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) { idWithZ += zindexSeparator + (z + 1); subplotInfo = Lib.extendFlat({}, subplotInfo, { id: idWithZ, - plot: fullLayout._cartesianlayer.selectAll('.subplot').select('.' + idWithZ) + plot: fullLayout._cartesianlayerAbove.selectAll('.subplot').select('.' + idWithZ) }); } @@ -331,7 +331,11 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) if(oldFullLayout._hasOnlyLargeSploms && !newFullLayout._hasOnlyLargeSploms) { for(k in oldPlots) { plotinfo = oldPlots[k]; - if(plotinfo.plotgroup) plotinfo.plotgroup.remove(); + if(plotinfo.plotgroup) { + for(var idx = plotinfo.plotgroup.length - 1; idx >= 0; idx--) { + plotinfo.plotgroup[idx].remove(); + } + } } } @@ -362,8 +366,8 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) if(hadCartesian && !hasCartesian) { // if we've gotten rid of all cartesian traces, remove all the subplot svg items - - purgeSubplotLayers(oldFullLayout._cartesianlayer.selectAll('.subplot'), oldFullLayout); + purgeSubplotLayers(oldFullLayout._cartesianlayerBelow.selectAll('.subplot'), oldFullLayout); + purgeSubplotLayers(oldFullLayout._cartesianlayerAbove.selectAll('.subplot'), oldFullLayout); oldFullLayout._defs.selectAll('.axesclip').remove(); delete oldFullLayout._axisConstraintGroups; delete oldFullLayout._axisMatchGroups; @@ -378,7 +382,8 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) if(!newPlots[oldSubplotId]) { var selector = '.' + oldSubplotId + ',.' + oldSubplotId + '-x,.' + oldSubplotId + '-y'; - oldFullLayout._cartesianlayer.selectAll(selector).remove(); + oldFullLayout._cartesianlayerAbove.selectAll(selector).remove(); + oldFullLayout._cartesianlayerBelow.selectAll(selector).remove(); removeSubplotExtras(oldSubplotId, oldFullLayout); } } @@ -427,19 +432,36 @@ exports.drawFramework = function(gd) { subplotData = subplotData.concat(newSubplotData); } - var subplotLayers = fullLayout._cartesianlayer.selectAll('.subplot') + var subplotLayersAbove = fullLayout._cartesianlayerAbove.selectAll('.subplot') .data(subplotData, String); - - subplotLayers.enter().append('g') + subplotLayersAbove.enter().append('g') .attr('class', function(d) { return 'subplot ' + d[0]; }); + subplotLayersAbove.order(); + subplotLayersAbove.exit() + .call(purgeSubplotLayers, fullLayout); - subplotLayers.order(); - - subplotLayers.exit() + var subplotLayersBelow = fullLayout._cartesianlayerBelow.selectAll('.subplot') + .data(initialSubplotData, String); + subplotLayersBelow.enter().append('g') + .attr('class', function(d) { return 'subplot ' + d[0] + '-below'; }); + subplotLayersBelow.order(); + subplotLayersBelow.exit() .call(purgeSubplotLayers, fullLayout); - subplotLayers.each(function(d) { + subplotLayersBelow.each(function(d) { + var id = d[0]; + var plotinfo = fullLayout._plots[id]; + + plotinfo.plotgroup = [d3.select(this)]; + makeSubplotLayerBelow(gd, plotinfo); + + // make separate drag layers for each subplot, + // but append them to paper rather than the plot groups, + // so they end up on top of the rest + plotinfo.draglayer = ensureSingle(fullLayout._draggers, 'g', id); + }); + subplotLayersAbove.each(function(d) { var id = d[0]; var posZ = id.indexOf(zindexSeparator); var hasZ = posZ !== -1; @@ -448,19 +470,21 @@ exports.drawFramework = function(gd) { id; var plotinfo = fullLayout._plots[id]; - if(!plotinfo) { + if(plotinfo) { + plotinfo.plotgroup = plotinfo.plotgroup.concat([d3.select(this)]); + } else { // repurpose plotinfo from plot without z plotinfo = Lib.extendFlat({}, fullLayout._plots[idWithoutZ]); if(plotinfo) { plotinfo.id = id; fullLayout._plots[id] = plotinfo; fullLayout._subplots.cartesian.push(id); + plotinfo.plotgroup[1] = d3.select(this); } } if(plotinfo) { - plotinfo.plotgroup = d3.select(this); - makeSubplotLayer(gd, plotinfo); + makeSubplotLayerAbove(gd, plotinfo); if(!hasZ) { // make separate drag layers for each subplot, @@ -473,7 +497,7 @@ exports.drawFramework = function(gd) { }; exports.rangePlot = function(gd, plotinfo, cdSubplot) { - makeSubplotLayer(gd, plotinfo); + makeSubplotLayerAbove(gd, plotinfo); plotOne(gd, plotinfo, cdSubplot); Plots.style(gd); }; @@ -556,9 +580,65 @@ function makeSubplotData(gd) { return subplotData; } -function makeSubplotLayer(gd, plotinfo) { +function makeSubplotLayerBelow(gd, plotinfo) { var fullLayout = gd._fullLayout; - var plotgroup = plotinfo.plotgroup; + var plotgroup = plotinfo.plotgroup[0]; + var id = plotinfo.id; + var posZ = id.indexOf(zindexSeparator); + var hasZ = posZ !== -1; + var hasMultipleZ = fullLayout._zindices.length > 1; + var hasOnlyLargeSploms = fullLayout._hasOnlyLargeSploms; + var mainplotinfo = plotinfo.mainplotinfo; + + if(!plotinfo.mainplot || hasMultipleZ) { + if (!hasOnlyLargeSploms && !hasZ) { + var backLayer = ensureSingle(plotgroup, 'g', 'layer-subplot'); + plotinfo.shapelayer = ensureSingle(backLayer, 'g', 'shapelayer'); + plotinfo.imagelayer = ensureSingle(backLayer, 'g', 'imagelayer'); + + if(mainplotinfo && hasMultipleZ) { + plotinfo.minorGridlayer = mainplotinfo.minorGridlayer; + plotinfo.gridlayer = mainplotinfo.gridlayer; + plotinfo.zerolinelayer = mainplotinfo.zerolinelayer; + } else { + plotinfo.minorGridlayer = ensureSingle(plotgroup, 'g', 'minor-gridlayer'); + plotinfo.gridlayer = ensureSingle(plotgroup, 'g', 'gridlayer'); + plotinfo.zerolinelayer = ensureSingle(plotgroup, 'g', 'zerolinelayer'); + } + } + } else { + // now make the components of overlaid subplots + // overlays don't have backgrounds, and append all + // their other components to the corresponding + // extra groups of their main plots. + + plotinfo.minorGridlayer = mainplotinfo.minorGridlayer; + plotinfo.gridlayer = mainplotinfo.gridlayer; + plotinfo.zerolinelayer = mainplotinfo.zerolinelayer; + } + + // common attributes for all subplots, overlays or not + if(!hasZ) { + if(!hasOnlyLargeSploms) { + ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.xaxis._id); + ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.yaxis._id); + plotinfo.minorGridlayer.selectAll('g') + .map(function(d) { return d[0]; }) + .sort(axisIds.idSort); + + ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.xaxis._id); + ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.yaxis._id); + plotinfo.gridlayer.selectAll('g') + .map(function(d) { return d[0]; }) + .sort(axisIds.idSort); + } + } +} + +function makeSubplotLayerAbove(gd, plotinfo) { + var fullLayout = gd._fullLayout; + var plotgroup = plotinfo.plotgroup; + var plotgroup = plotinfo.plotgroup[1]; var id = plotinfo.id; var posZ = id.indexOf(zindexSeparator); @@ -584,24 +664,6 @@ function makeSubplotLayer(gd, plotinfo) { plotinfo.yaxislayer = ensureSingle(plotgroup, 'g', 'yaxislayer-above'); } else { if(!hasZ) { - var backLayer = ensureSingle(plotgroup, 'g', 'layer-subplot'); - plotinfo.shapelayer = ensureSingle(backLayer, 'g', 'shapelayer'); - plotinfo.imagelayer = ensureSingle(backLayer, 'g', 'imagelayer'); - - if(mainplotinfo && hasMultipleZ) { - plotinfo.minorGridlayer = mainplotinfo.minorGridlayer; - plotinfo.gridlayer = mainplotinfo.gridlayer; - plotinfo.zerolinelayer = mainplotinfo.zerolinelayer; - } else { - plotinfo.minorGridlayer = ensureSingle(plotgroup, 'g', 'minor-gridlayer'); - plotinfo.gridlayer = ensureSingle(plotgroup, 'g', 'gridlayer'); - plotinfo.zerolinelayer = ensureSingle(plotgroup, 'g', 'zerolinelayer'); - } - - var betweenLayer = ensureSingle(plotgroup, 'g', 'layer-between'); - plotinfo.shapelayerBetween = ensureSingle(betweenLayer, 'g', 'shapelayer'); - plotinfo.imagelayerBetween = ensureSingle(betweenLayer, 'g', 'imagelayer'); - ensureSingle(plotgroup, 'path', 'xlines-below'); ensureSingle(plotgroup, 'path', 'ylines-below'); plotinfo.overlinesBelow = ensureSingle(plotgroup, 'g', 'overlines-below'); @@ -631,7 +693,8 @@ function makeSubplotLayer(gd, plotinfo) { } } } else { - var mainplotgroup = mainplotinfo.plotgroup; + var mainplotinfo = plotinfo.mainplotinfo; + var mainplotgroup = mainplotinfo.plotgroup[1]; var xId = id + '-x'; var yId = id + '-y'; @@ -640,10 +703,6 @@ function makeSubplotLayer(gd, plotinfo) { // their other components to the corresponding // extra groups of their main plots. - plotinfo.minorGridlayer = mainplotinfo.minorGridlayer; - plotinfo.gridlayer = mainplotinfo.gridlayer; - plotinfo.zerolinelayer = mainplotinfo.zerolinelayer; - ensureSingle(mainplotinfo.overlinesBelow, 'path', xId); ensureSingle(mainplotinfo.overlinesBelow, 'path', yId); ensureSingle(mainplotinfo.overaxesBelow, 'g', xId); @@ -666,20 +725,6 @@ function makeSubplotLayer(gd, plotinfo) { if(!hasZ) { // common attributes for all subplots, overlays or not - if(!hasOnlyLargeSploms) { - ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.xaxis._id); - ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.yaxis._id); - plotinfo.minorGridlayer.selectAll('g') - .map(function(d) { return d[0]; }) - .sort(axisIds.idSort); - - ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.xaxis._id); - ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.yaxis._id); - plotinfo.gridlayer.selectAll('g') - .map(function(d) { return d[0]; }) - .sort(axisIds.idSort); - } - plotinfo.xlines .style('fill', 'none') .classed('crisp', true); diff --git a/test/image/baselines/zz_shapes_layer_between_xref_paper.png b/test/image/baselines/zz_shapes_layer_between_xref_paper.png new file mode 100644 index 00000000000..480e71cc96a Binary files /dev/null and b/test/image/baselines/zz_shapes_layer_between_xref_paper.png differ diff --git a/test/image/mocks/zz_shapes_layer_between_xref_paper.json b/test/image/mocks/zz_shapes_layer_between_xref_paper.json new file mode 100644 index 00000000000..b538ecdb432 --- /dev/null +++ b/test/image/mocks/zz_shapes_layer_between_xref_paper.json @@ -0,0 +1,36 @@ +{ + "data": [ + { + "x": [ + 1, 2, 3, 4, 5, 6, 7 + ], + "y": [ + -1000, 0, 1000, 2000, 3000, 4000, 5000 + ] + } + ], + "layout": { + "shapes": [ + + { + "layer": "between", + "name": "my zeroline y2", + "line": { + "color": "yellow", + "width": 3.0 + }, + "x0": 0, + "x1": 1, + "xref": "paper", + "y0": 0, + "y1": 0, + "yref": "y" + } + ], + "yaxis": { + "ticklabelposition": "inside top", + "zeroline": false + } + + } +} diff --git a/test/jasmine/tests/cartesian_test.js b/test/jasmine/tests/cartesian_test.js index 617726c202c..b5942ef26b0 100644 --- a/test/jasmine/tests/cartesian_test.js +++ b/test/jasmine/tests/cartesian_test.js @@ -436,7 +436,7 @@ describe('subplot creation / deletion:', function() { function checkBGLayers(behindCount, x2y2Count, subplots) { expect(gd.querySelectorAll('.bglayer rect.bg').length).toBe(behindCount); - expect(gd.querySelectorAll('.subplot.x2y2 rect.bg').length).toBe(x2y2Count); + expect(gd.querySelectorAll('.subplot.x2y2-below rect.bg').length).toBe(x2y2Count); // xy is the first subplot, so it never gets put in front of others expect(gd.querySelectorAll('.subplot.xy rect.bg').length).toBe(0); @@ -445,7 +445,7 @@ describe('subplot creation / deletion:', function() { expect(gd.querySelectorAll('.subplot.xy3 rect.bg').length).toBe(0); // verify that these are *all* the subplots and backgrounds we have - expect(gd.querySelectorAll('.subplot').length).toBe(subplots.length); + expect(gd.querySelectorAll('.subplot').length).toBe(subplots.length * 2); subplots.forEach(function(subplot) { expect(gd.querySelectorAll('.subplot.' + subplot).length).toBe(1); }); @@ -791,14 +791,15 @@ describe('subplot creation / deletion:', function() { it('clear axis ticks, labels and title when relayout an axis to `*visible:false*', function(done) { function _assert(xaxis, yaxis) { var g = d3Select('.subplot.xy'); + var gBelow = d3Select('.subplot.xy-below'); var info = d3Select('.infolayer'); expect(g.selectAll('.xtick').size()).toBe(xaxis[0], 'x tick cnt'); - expect(g.selectAll('.gridlayer .xgrid').size()).toBe(xaxis[1], 'x gridline cnt'); + expect(gBelow.selectAll('.gridlayer .xgrid').size()).toBe(xaxis[1], 'x gridline cnt'); expect(info.selectAll('.g-xtitle').size()).toBe(xaxis[2], 'x title cnt'); expect(g.selectAll('.ytick').size()).toBe(yaxis[0], 'y tick cnt'); - expect(g.selectAll('.gridlayer .ygrid').size()).toBe(yaxis[1], 'y gridline cnt'); + expect(gBelow.selectAll('.gridlayer .ygrid').size()).toBe(yaxis[1], 'y gridline cnt'); expect(info.selectAll('.g-ytitle').size()).toBe(yaxis[2], 'y title cnt'); } diff --git a/test/jasmine/tests/plot_interact_test.js b/test/jasmine/tests/plot_interact_test.js index e091148b807..5ed4754495c 100644 --- a/test/jasmine/tests/plot_interact_test.js +++ b/test/jasmine/tests/plot_interact_test.js @@ -25,10 +25,12 @@ describe('Test plot structure', function() { afterEach(destroyGraphDiv); describe('cartesian plots', function() { - function countSubplots() { - return d3SelectAll('g.subplot').size(); + function countSubplotsBackground() { + return d3SelectAll('g.cartesianlayer-below g.subplot').size(); + } + function countSubplotsForeground() { + return d3SelectAll('g.cartesianlayer g.subplot').size(); } - function countScatterTraces() { return d3SelectAll('g.trace.scatter').size(); } @@ -58,8 +60,9 @@ describe('Test plot structure', function() { Plotly.newPlot(gd, mockData, mockLayout).then(done); }); - it('has one *subplot xy* node', function() { - expect(countSubplots()).toEqual(1); + it('has one *subplot xy* node each in background and foreground', function() { + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); }); it('has four clip paths', function() { @@ -101,19 +104,22 @@ describe('Test plot structure', function() { it('should be able to get deleted', function(done) { expect(countScatterTraces()).toEqual(mock.data.length); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); Plotly.deleteTraces(gd, [0]).then(function() { expect(countScatterTraces()).toEqual(0); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(countClipPaths()).toEqual(4); expect(countDraggers()).toEqual(1); return Plotly.relayout(gd, {xaxis: null, yaxis: null}); }).then(function() { expect(countScatterTraces()).toEqual(0); - // we still make one empty cartesian subplot if no other subplots are described - expect(countSubplots()).toEqual(1); + // we still make two empty cartesian subplots (bg and fg) if no other subplots are described + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(countClipPaths()).toEqual(4); expect(countDraggers()).toEqual(1); }) @@ -122,40 +128,46 @@ describe('Test plot structure', function() { it('should restore layout axes when they get deleted', function(done) { expect(countScatterTraces()).toEqual(mock.data.length); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); Plotly.relayout(gd, {xaxis: null, yaxis: null}) .then(function() { expect(countScatterTraces()).toEqual(1); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4); expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4); return Plotly.relayout(gd, 'xaxis', null); }).then(function() { expect(countScatterTraces()).toEqual(1); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4); expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4); return Plotly.relayout(gd, 'xaxis', {}); }).then(function() { expect(countScatterTraces()).toEqual(1); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4); expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4); return Plotly.relayout(gd, 'yaxis', null); }).then(function() { expect(countScatterTraces()).toEqual(1); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4); expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4); return Plotly.relayout(gd, 'yaxis', {}); }).then(function() { expect(countScatterTraces()).toEqual(1); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4); expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4); }) @@ -203,7 +215,8 @@ describe('Test plot structure', function() { }); it('has four *subplot* nodes', function() { - expect(countSubplots()).toEqual(4); + expect(countSubplotsBackground()).toEqual(4); + expect(countSubplotsForeground()).toEqual(4); expect(countClipPaths()).toEqual(12); expect(countDraggers()).toEqual(4); }); @@ -245,8 +258,9 @@ describe('Test plot structure', function() { .then(done); }); - it('has four *subplot* nodes', function() { - expect(countSubplots()).toEqual(4); + it('has 4 *subplot* nodes', function() { + expect(countSubplotsBackground()).toEqual(4); + expect(countSubplotsForeground()).toEqual(4); expect(countClipPaths()).toEqual(12); expect(countDraggers()).toEqual(4); }); @@ -285,7 +299,8 @@ describe('Test plot structure', function() { } it('should be removed of traces in sequence', function(done) { - expect(countSubplots()).toEqual(4); + expect(countSubplotsBackground()).toEqual(4); + expect(countSubplotsForeground()).toEqual(4); assertHeatmapNodes(4); assertContourNodes(2); expect(countColorBars()).toEqual(1); @@ -298,7 +313,8 @@ describe('Test plot structure', function() { }); Plotly.deleteTraces(gd, [0]).then(function() { - expect(countSubplots()).toEqual(3); + expect(countSubplotsBackground()).toEqual(3); + expect(countSubplotsForeground()).toEqual(3); expect(countClipPaths()).toEqual(11); expect(countDraggers()).toEqual(3); assertHeatmapNodes(3); @@ -314,7 +330,8 @@ describe('Test plot structure', function() { return Plotly.deleteTraces(gd, [0]); }).then(function() { - expect(countSubplots()).toEqual(2); + expect(countSubplotsBackground()).toEqual(2); + expect(countSubplotsForeground()).toEqual(2); expect(countClipPaths()).toEqual(7); expect(countDraggers()).toEqual(2); assertHeatmapNodes(2); @@ -330,7 +347,8 @@ describe('Test plot structure', function() { return Plotly.deleteTraces(gd, [0]); }).then(function() { - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(countClipPaths()).toEqual(4); expect(countDraggers()).toEqual(1); assertHeatmapNodes(1); @@ -346,7 +364,8 @@ describe('Test plot structure', function() { return Plotly.deleteTraces(gd, [0]); }).then(function() { - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(countClipPaths()).toEqual(4); expect(countDraggers()).toEqual(1); assertHeatmapNodes(0); @@ -369,7 +388,8 @@ describe('Test plot structure', function() { return Plotly.relayout(gd, update); }).then(function() { - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); expect(countClipPaths()).toEqual(4); expect(countDraggers()).toEqual(1); assertHeatmapNodes(0); @@ -434,11 +454,13 @@ describe('Test plot structure', function() { it('should be able to get deleted', function(done) { expect(countPieTraces()).toEqual(1); - expect(countSubplots()).toEqual(0); + expect(countSubplotsBackground()).toEqual(0); + expect(countSubplotsForeground()).toEqual(0); Plotly.deleteTraces(gd, [0]).then(function() { expect(countPieTraces()).toEqual(0); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); }) .then(done, done.fail); }); @@ -446,18 +468,21 @@ describe('Test plot structure', function() { it('should be able to be restyled to a bar chart and back', function(done) { expect(countPieTraces()).toEqual(1); expect(countBarTraces()).toEqual(0); - expect(countSubplots()).toEqual(0); + expect(countSubplotsBackground()).toEqual(0); + expect(countSubplotsForeground()).toEqual(0); Plotly.restyle(gd, 'type', 'bar').then(function() { expect(countPieTraces()).toEqual(0); expect(countBarTraces()).toEqual(1); - expect(countSubplots()).toEqual(1); + expect(countSubplotsBackground()).toEqual(1); + expect(countSubplotsForeground()).toEqual(1); return Plotly.restyle(gd, 'type', 'pie'); }).then(function() { expect(countPieTraces()).toEqual(1); expect(countBarTraces()).toEqual(0); - expect(countSubplots()).toEqual(0); + expect(countSubplotsBackground()).toEqual(0); + expect(countSubplotsForeground()).toEqual(0); }) .then(done, done.fail); }); diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 44cede6e3fe..1bdc9c9646b 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -740,17 +740,27 @@ describe('Test splom interactions:', function() { var msg = ' - call #' + cnt; var gd3 = d3Select(gd); var subplots = gd3.selectAll('g.cartesianlayer > g.subplot'); + var subplotsBelow = gd3.selectAll('g.cartesianlayer-below > g.subplot'); var bgs = gd3.selectAll('.bglayer > rect.bg'); expect(subplots.size()) - .toBe(exp.subplotCnt, '# of ' + msg); + .toBe(exp.subplotCnt, '# of ' + msg); var failedSubplots = []; subplots.each(function(d, i) { var actual = this.children.length; var expected = typeof exp.innerSubplotNodeCnt === 'function' ? - exp.innerSubplotNodeCnt(d[0], i) : - exp.innerSubplotNodeCnt; + exp.innerSubplotNodeCnt(d[0], i) : + exp.innerSubplotNodeCnt; + if(actual !== expected) { + failedSubplots.push([d, actual, 'vs', expected].join(' ')); + } + }); + subplotsBelow.each(function(d, i) { + var actual = this.children.length; + var expected = typeof exp.innerSubplotNodeCntBelow === 'function' ? + exp.innerSubplotNodeCntBelow(d[0], i) : + exp.innerSubplotNodeCntBelow; if(actual !== expected) { failedSubplots.push([d, actual, 'vs', expected].join(' ')); } @@ -769,6 +779,7 @@ describe('Test splom interactions:', function() { _newPlot(gd, figLarge).then(function() { _assert({ subplotCnt: 400, + innerSubplotNodeCntBelow: 0, innerSubplotNodeCnt: 4, hasSplomGrid: true, bgCnt: 0 @@ -779,6 +790,7 @@ describe('Test splom interactions:', function() { .then(function() { _assert({ subplotCnt: 400, + innerSubplotNodeCntBelow: 0, innerSubplotNodeCnt: 4, hasSplomGrid: true, bgCnt: 400 @@ -789,6 +801,7 @@ describe('Test splom interactions:', function() { .then(function() { _assert({ subplotCnt: 400, + innerSubplotNodeCntBelow: 0, innerSubplotNodeCnt: 4, hasSplomGrid: true, bgCnt: 0 @@ -799,28 +812,12 @@ describe('Test splom interactions:', function() { .then(function() { _assert({ subplotCnt: 25, - innerSubplotNodeCnt: 18, + innerSubplotNodeCntBelow: 4, + innerSubplotNodeCnt: 13, hasSplomGrid: false, bgCnt: 0 }); - // make sure 'new' subplot layers are in order - var gridIndex = -1; - var xaxisIndex = -1; - var subplot0 = d3Select('g.cartesianlayer > g.subplot').node(); - for(var i in subplot0.children) { - var cl = subplot0.children[i].classList; - if(cl) { - if(cl.contains('gridlayer')) gridIndex = +i; - else if(cl.contains('xaxislayer-above')) xaxisIndex = +i; - } - } - // from large -> small splom: - // grid layer would be above xaxis layer, - // if we didn't clear subplot children. - expect(gridIndex).toBe(2, ' index'); - expect(xaxisIndex).toBe(15, ' index'); - return Plotly.restyle(gd, 'dimensions', [dimsLarge]); }) .then(function() { @@ -829,9 +826,13 @@ describe('Test splom interactions:', function() { // from small -> large splom: // no need to clear subplots children in existing subplots, // new subplots though have reduced number of children. + innerSubplotNodeCntBelow: function(d) { + var p = d.match(SUBPLOT_PATTERN); + return (p[1] > 5 || p[2] > 5) ? 0 : 4; + }, innerSubplotNodeCnt: function(d) { var p = d.match(SUBPLOT_PATTERN); - return (p[1] > 5 || p[2] > 5) ? 4 : 18; + return (p[1] > 5 || p[2] > 5) ? 4 : 13; }, hasSplomGrid: true, bgCnt: 0