diff --git a/draftlogs/7269_add.md b/draftlogs/7269_add.md new file mode 100644 index 00000000000..8e772141a9a --- /dev/null +++ b/draftlogs/7269_add.md @@ -0,0 +1 @@ + - Add property `zerolinelayer` to cartesian axes to allow drawing zeroline above traces [[#7269](https://github.com/plotly/plotly.js/pull/7269)] diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 84ebe5b3bb1..c293d99b564 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2365,6 +2365,7 @@ axes.draw = function(gd, arg, opts) { if(plotinfo.minorGridlayer) plotinfo.minorGridlayer.selectAll('path').remove(); if(plotinfo.gridlayer) plotinfo.gridlayer.selectAll('path').remove(); if(plotinfo.zerolinelayer) plotinfo.zerolinelayer.selectAll('path').remove(); + if(plotinfo.zerolinelayerAbove) plotinfo.zerolinelayerAbove.selectAll('path').remove(); fullLayout._infolayer.select('.g-' + xa._id + 'title').remove(); fullLayout._infolayer.select('.g-' + ya._id + 'title').remove(); @@ -2462,6 +2463,7 @@ axes.drawOne = function(gd, ax, opts) { var axLetter = axId.charAt(0); var counterLetter = axes.counterLetter(axId); var mainPlotinfo = fullLayout._plots[ax._mainSubplot]; + var zerolineIsAbove = ax.zerolinelayer === 'above traces'; // this happens when updating matched group with 'missing' axes if(!mainPlotinfo) return; @@ -2576,7 +2578,7 @@ axes.drawOne = function(gd, ax, opts) { }); axes.drawZeroLine(gd, ax, { counterAxis: counterAxis, - layer: plotinfo.zerolinelayer, + layer: zerolineIsAbove ? plotinfo.zerolinelayerAbove : plotinfo.zerolinelayer, path: gridPath, transFn: transTickFn }); @@ -3555,6 +3557,7 @@ axes.drawLabels = function(gd, ax, opts) { var fullLayout = gd._fullLayout; var axId = ax._id; + var zerolineIsAbove = ax.zerolinelayer === 'above traces'; var cls = opts.cls || axId + 'tick'; var vals = opts.vals.filter(function(d) { return d.text; }); @@ -3763,8 +3766,10 @@ axes.drawLabels = function(gd, ax, opts) { var mainPlotinfo = fullLayout._plots[ax._mainSubplot]; var sel; - if(e.K === ZERO_PATH.K) sel = mainPlotinfo.zerolinelayer.selectAll('.' + ax._id + 'zl'); - else if(e.K === MINORGRID_PATH.K) sel = mainPlotinfo.minorGridlayer.selectAll('.' + ax._id); + if(e.K === ZERO_PATH.K) { + var zerolineLayer = zerolineIsAbove ? mainPlotinfo.zerolinelayerAbove : mainPlotinfo.zerolinelayer; + sel = zerolineLayer.selectAll('.' + ax._id + 'zl'); + } else if(e.K === MINORGRID_PATH.K) sel = mainPlotinfo.minorGridlayer.selectAll('.' + ax._id); else if(e.K === GRID_PATH.K) sel = mainPlotinfo.gridlayer.selectAll('.' + ax._id); else sel = mainPlotinfo[ax._id.charAt(0) + 'axislayer']; diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js index 07863ebbdf1..71eeb5b1a9e 100644 --- a/src/plots/cartesian/index.js +++ b/src/plots/cartesian/index.js @@ -614,6 +614,12 @@ function makeSubplotLayer(gd, plotinfo) { plotinfo.overplot = ensureSingle(plotgroup, 'g', 'overplot'); plotinfo.plot = ensureSingle(plotinfo.overplot, 'g', id); + if(mainplotinfo && hasMultipleZ) { + plotinfo.zerolinelayerAbove = mainplotinfo.zerolinelayerAbove; + } else { + plotinfo.zerolinelayerAbove = ensureSingle(plotgroup, 'g', 'zerolinelayer-above'); + } + if(!hasZ) { plotinfo.xlines = ensureSingle(plotgroup, 'path', 'xlines-above'); plotinfo.ylines = ensureSingle(plotgroup, 'path', 'ylines-above'); @@ -643,6 +649,7 @@ function makeSubplotLayer(gd, plotinfo) { plotinfo.minorGridlayer = mainplotinfo.minorGridlayer; plotinfo.gridlayer = mainplotinfo.gridlayer; plotinfo.zerolinelayer = mainplotinfo.zerolinelayer; + plotinfo.zerolinelayerAbove = mainplotinfo.zerolinelayerAbove; ensureSingle(mainplotinfo.overlinesBelow, 'path', xId); ensureSingle(mainplotinfo.overlinesBelow, 'path', yId); diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 32afc99457a..978f545e53e 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -1016,6 +1016,19 @@ module.exports = { editType: 'ticks', description: 'Sets the line color of the zero line.' }, + zerolinelayer: { + valType: 'enumerated', + values: ['above traces', 'below traces'], + dflt: 'below traces', + editType: 'plot', + description: [ + 'Sets the layer on which this zeroline is displayed.', + 'If *above traces*, this zeroline is displayed above all the subplot\'s traces', + 'If *below traces*, this zeroline is displayed below all the subplot\'s traces,', + 'but above the grid lines. Limitation: *zerolinelayer* currently has no effect', + 'if the *zorder* property is set on any trace.' + ].join(' ') + }, zerolinewidth: { valType: 'number', dflt: 1, diff --git a/src/plots/cartesian/line_grid_defaults.js b/src/plots/cartesian/line_grid_defaults.js index 062c5f2493c..8808c31f7dd 100644 --- a/src/plots/cartesian/line_grid_defaults.js +++ b/src/plots/cartesian/line_grid_defaults.js @@ -67,11 +67,13 @@ module.exports = function handleLineGridDefaults(containerIn, containerOut, coer } if(!opts.noZeroLine) { + var zeroLineLayer = coerce2('zerolinelayer'); var zeroLineColor = coerce2('zerolinecolor', dfltColor); var zeroLineWidth = coerce2('zerolinewidth'); var showZeroLine = coerce('zeroline', opts.showGrid || !!zeroLineColor || !!zeroLineWidth); if(!showZeroLine) { + delete containerOut.zerolinelayer; delete containerOut.zerolinecolor; delete containerOut.zerolinewidth; } diff --git a/test/image/baselines/zzz_zerolinelayer_above.png b/test/image/baselines/zzz_zerolinelayer_above.png new file mode 100644 index 00000000000..485700eec31 Binary files /dev/null and b/test/image/baselines/zzz_zerolinelayer_above.png differ diff --git a/test/image/baselines/zzz_zerolinelayer_below.png b/test/image/baselines/zzz_zerolinelayer_below.png new file mode 100644 index 00000000000..a287931572d Binary files /dev/null and b/test/image/baselines/zzz_zerolinelayer_below.png differ diff --git a/test/image/mocks/zzz_zerolinelayer_above.json b/test/image/mocks/zzz_zerolinelayer_above.json new file mode 100644 index 00000000000..ac9adfd45bc --- /dev/null +++ b/test/image/mocks/zzz_zerolinelayer_above.json @@ -0,0 +1,58 @@ +{ + "data": [ + { + "type": "bar", + "x": [-1, 0, 2, 3], + "y": [-1, 2, -3, 4], + "name": "xy" + }, + { + "line": { + "width": 10 + }, + "mode": "lines", + "x": [-1, 0, 2, 3], + "y": [-3, 1, -1, 2], + "xaxis": "x2", + "yaxis": "y2", + "name": "x2y2" + } + ], + "layout": { + "title": { + "text": "All zerolines above traces (x/x2: pink, y/y2: black)" + }, + "width": 600, + "height": 400, + "xaxis": { + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "pink", + "zerolinelayer": "above traces" + }, + "xaxis2": { + "overlaying": "x", + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "pink", + "zerolinelayer": "above traces", + "side": "top" + }, + "yaxis": { + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "black", + "zerolinelayer": "above traces", + "range": [-1, 4] + }, + "yaxis2": { + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "black", + "zerolinelayer": "above traces", + "range": [-3, 2], + "overlaying": "y", + "side": "right" + } + } +} diff --git a/test/image/mocks/zzz_zerolinelayer_below.json b/test/image/mocks/zzz_zerolinelayer_below.json new file mode 100644 index 00000000000..0f555541057 --- /dev/null +++ b/test/image/mocks/zzz_zerolinelayer_below.json @@ -0,0 +1,58 @@ +{ + "data": [ + { + "type": "bar", + "x": [-1, 0, 2, 3], + "y": [-1, 2, -3, 4], + "name": "xy" + }, + { + "line": { + "width": 10 + }, + "mode": "lines", + "x": [-1, 0, 2, 3], + "y": [-3, 1, -1, 2], + "xaxis": "x2", + "yaxis": "y2", + "name": "x2y2" + } + ], + "layout": { + "title": { + "text": "All zerolines below traces (x/x2: pink, y/y2: black)" + }, + "width": 600, + "height": 400, + "xaxis": { + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "pink", + "zerolinelayer": "below traces" + }, + "xaxis2": { + "overlaying": "x", + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "pink", + "zerolinelayer": "below traces", + "side": "top" + }, + "yaxis": { + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "black", + "zerolinelayer": "below traces", + "range": [-1, 4] + }, + "yaxis2": { + "zeroline": true, + "zerolinewidth": 5, + "zerolinecolor": "black", + "zerolinelayer": "below traces", + "range": [-3, 2], + "overlaying": "y", + "side": "right" + } + } +} diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 44cede6e3fe..69560d7d5bd 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -799,7 +799,7 @@ describe('Test splom interactions:', function() { .then(function() { _assert({ subplotCnt: 25, - innerSubplotNodeCnt: 18, + innerSubplotNodeCnt: 19, hasSplomGrid: false, bgCnt: 0 }); @@ -819,7 +819,7 @@ describe('Test splom interactions:', function() { // grid layer would be above xaxis layer, // if we didn't clear subplot children. expect(gridIndex).toBe(2, ' index'); - expect(xaxisIndex).toBe(15, ' index'); + expect(xaxisIndex).toBe(16, ' index'); return Plotly.restyle(gd, 'dimensions', [dimsLarge]); }) @@ -831,7 +831,7 @@ describe('Test splom interactions:', function() { // new subplots though have reduced number of children. 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 : 19; }, hasSplomGrid: true, bgCnt: 0 diff --git a/test/plot-schema.json b/test/plot-schema.json index 6aa77cf3338..96c230c26ca 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -14959,6 +14959,16 @@ "editType": "ticks", "valType": "color" }, + "zerolinelayer": { + "description": "Sets the layer on which this zeroline is displayed. If *above traces*, this zeroline is displayed above all the subplot's traces If *below traces*, this zeroline is displayed below all the subplot's traces, but above the grid lines. Limitation: *zerolinelayer* currently has no effect if the *zorder* property is set on any trace.", + "dflt": "below traces", + "editType": "plot", + "valType": "enumerated", + "values": [ + "above traces", + "below traces" + ] + }, "zerolinewidth": { "description": "Sets the width (in px) of the zero line.", "dflt": 1, @@ -16193,6 +16203,16 @@ "editType": "ticks", "valType": "color" }, + "zerolinelayer": { + "description": "Sets the layer on which this zeroline is displayed. If *above traces*, this zeroline is displayed above all the subplot's traces If *below traces*, this zeroline is displayed below all the subplot's traces, but above the grid lines. Limitation: *zerolinelayer* currently has no effect if the *zorder* property is set on any trace.", + "dflt": "below traces", + "editType": "plot", + "valType": "enumerated", + "values": [ + "above traces", + "below traces" + ] + }, "zerolinewidth": { "description": "Sets the width (in px) of the zero line.", "dflt": 1,