Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zorder on overlaying axes #6943

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/plots/cartesian/graph_interact.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ exports.initInteractions = function initInteractions(gd) {
return fullLayout._plots[a].mainplot ? 1 : -1;
});

subplots = subplots.filter(function(subplot) { return !subplot.includes('-over-'); });
subplots.forEach(function(subplot) {
var plotinfo = fullLayout._plots[subplot];
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;

// main and corner draggers need not be repeated for
// overlaid subplots - these draggers drag them all
if(!plotinfo.mainplot) {
if(!plotinfo.mainplot || plotinfo.mainplot === plotinfo.id) {
// main dragger goes over the grids and data, so we use its
// mousemove events for all data hover effects
var maindrag = makeDragBox(gd, plotinfo, xa._offset, ya._offset,
Expand Down
230 changes: 151 additions & 79 deletions src/plots/cartesian/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,8 @@ exports.finalizeSubplots = function(layoutIn, layoutOut) {
*/
exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) {
var fullLayout = gd._fullLayout;
var subplots = fullLayout._subplots.cartesian;
var calcdata = gd.calcdata;
var i;
var i, j;

// Traces is a list of trace indices to (re)plot. If it's not provided,
// then it's a complete replot so we create a new list and add all trace indices
Expand All @@ -141,55 +140,98 @@ exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) {
for(i = 0; i < calcdata.length; i++) traces.push(i);
}

// For each subplot
for(i = 0; i < subplots.length; i++) {
var subplot = subplots[i];
var subplotInfo = fullLayout._plots[subplot];

// Get all calcdata (traces) for this subplot:
var cdSubplot = [];
var pcd;

// For each trace
for(var j = 0; j < calcdata.length; j++) {
var cd = calcdata[j];
var trace = cd[0].trace;

// Skip trace if whitelist provided and it's not whitelisted:
// if (Array.isArray(traces) && traces.indexOf(i) === -1) continue;
if(trace.xaxis + trace.yaxis === subplot) {
// XXX: Should trace carpet dependencies. Only replot all carpet plots if the carpet
// axis has actually changed:
//
// If this trace is specifically requested, add it to the list:
if(traces.indexOf(trace.index) !== -1 || trace.carpet) {
// Okay, so example: traces 0, 1, and 2 have fill = tonext. You animate
// traces 0 and 2. Trace 1 also needs to be updated, otherwise its fill
// is outdated. So this retroactively adds the previous trace if the
// traces are interdependent.
if(
pcd &&
pcd[0].trace.xaxis + pcd[0].trace.yaxis === subplot &&
['tonextx', 'tonexty', 'tonext'].indexOf(trace.fill) !== -1 &&
cdSubplot.indexOf(pcd) === -1
) {
cdSubplot.push(pcd);
var trace;
var subplot;
var subplotZorderGroups = {};
for(var t = 0; t < calcdata.length; t++) {
trace = calcdata[t][0].trace;
var zi = trace.zorder || 0;
subplot = trace.xaxis + trace.yaxis;
if(!subplotZorderGroups[zi]) subplotZorderGroups[zi] = {};
if(!subplotZorderGroups[zi][subplot]) subplotZorderGroups[zi][subplot] = [];
subplotZorderGroups[zi][subplot].push(calcdata[t]);
}
var zindices = Object.keys(subplotZorderGroups)
.map(Number)
.sort(Lib.sorterAsc);

var subplots;
var zindex;
var subplotId;
var newsubplotZorderGroups = {};
var prevSubplots = [];
for(i = 0; i < zindices.length; i++) {
zindex = zindices[i];
subplots = Object.keys(subplotZorderGroups[zindex]);

// For each subplot
for(j = 0; j < subplots.length; j++) {
subplot = subplots[j];
if(prevSubplots.indexOf(subplot) === -1) {
prevSubplots.push(subplot);
subplotId = subplot;
} else {
subplotId = subplot + '-over-' + i;
}
if(!newsubplotZorderGroups[zindex]) newsubplotZorderGroups[zindex] = {};
if(!newsubplotZorderGroups[zindex][subplotId]) newsubplotZorderGroups[zindex][subplotId] = [];
newsubplotZorderGroups[zindex][subplotId].push(subplotZorderGroups[zindex][subplot]);
}
}

var subplotLayerData = {};
for(i = 0; i < zindices.length; i++) {
zindex = zindices[i];
subplots = Object.keys(newsubplotZorderGroups[zindex]);

// For each subplot
for(j = 0; j < subplots.length; j++) {
subplot = subplots[j];
var subplotInfo = fullLayout._plots[subplot];

// Get all calcdata (traces) for this subplot:
var cdSubplot = [];
var pcd;
// For each trace
for(var k = 0; k < newsubplotZorderGroups[zindex][subplot].length; k++) {
var cd = newsubplotZorderGroups[zindex][subplot][k][0];
trace = cd[0].trace;

// Skip trace if whitelist provided and it's not whitelisted:
// if (Array.isArray(traces) && traces.indexOf(i) === -1) continue;
if(trace.xaxis + trace.yaxis === subplot || (subplot.indexOf('-over-') !== -1 && subplot.indexOf(trace.xaxis + trace.yaxis) === 0)) {
// XXX: Should trace carpet dependencies. Only replot all carpet plots if the carpet
// axis has actually changed:
//
// If this trace is specifically requested, add it to the list:
if(traces.indexOf(trace.index) !== -1 || trace.carpet) {
// Okay, so example: traces 0, 1, and 2 have fill = tonext. You animate
// traces 0 and 2. Trace 1 also needs to be updated, otherwise its fill
// is outdated. So this retroactively adds the previous trace if the
// traces are interdependent.
if(
pcd &&
pcd[0].trace.xaxis + pcd[0].trace.yaxis === subplot &&
['tonextx', 'tonexty', 'tonext'].indexOf(trace.fill) !== -1 &&
cdSubplot.indexOf(pcd) === -1
) {
cdSubplot.push(pcd);
}
cdSubplot.push(cd);
}

cdSubplot.push(cd);
// Track the previous trace on this subplot for the retroactive-add step
// above:
pcd = cd;
}

// Track the previous trace on this subplot for the retroactive-add step
// above:
pcd = cd;
}
if(!subplotLayerData[subplot]) subplotLayerData[subplot] = [];
if(subplotInfo) subplotLayerData[subplot] = plotOne(gd, subplotInfo, cdSubplot, transitionOpts, makeOnCompleteCallback, subplotLayerData[subplot]);
}
// Plot the traces for this subplot
plotOne(gd, subplotInfo, cdSubplot, transitionOpts, makeOnCompleteCallback);
}
};

function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback) {
function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback, layerData) {
var traceLayerClasses = constants.traceLayerClasses;
var fullLayout = gd._fullLayout;
var modules = fullLayout._modules;
Expand All @@ -205,7 +247,6 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
traceZorderGroups[zi].push(cdSubplot[t]);
}

var layerData = [];
var zoomScaleQueryParts = [];

// Plot each zorder group in ascending order
Expand Down Expand Up @@ -263,7 +304,6 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
.attr('class', function(d) { return d.className; })
.classed('mlayer', true)
.classed('rangeplot', plotinfo.isRangePlot);

layers.exit().remove();

layers.order();
Expand Down Expand Up @@ -307,6 +347,7 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
plotinfo.zoomScaleTxt = traces.selectAll('.textpoint');
}
}
return layerData;
}

exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
Expand Down Expand Up @@ -392,90 +433,121 @@ exports.drawFramework = function(gd) {
var plotinfo = fullLayout._plots[id];

plotinfo.plotgroup = d3.select(this);
makeSubplotLayer(gd, plotinfo);
makeSubplotLayer(gd, plotinfo, id);

// 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);
if(id.indexOf('over') === -1) plotinfo.draglayer = ensureSingle(fullLayout._draggers, 'g', id);
});
};

exports.rangePlot = function(gd, plotinfo, cdSubplot) {
makeSubplotLayer(gd, plotinfo);
makeSubplotLayer(gd, plotinfo, plotinfo.id);
plotOne(gd, plotinfo, cdSubplot);
Plots.style(gd);
};

function makeSubplotData(gd) {
var fullLayout = gd._fullLayout;
var ids = fullLayout._subplots.cartesian;
var len = ids.length;

var i, j, id, plotinfo, xa, ya;

// split 'regular' and 'overlaying' subplots
var regulars = [];
var overlays = [];

for(i = 0; i < len; i++) {
id = ids[i];
plotinfo = fullLayout._plots[id];
xa = plotinfo.xaxis;
ya = plotinfo.yaxis;
var calcdata = gd.calcdata;

var trace;
var subplot;
var subplotZorderGroups = {};
for(var t = 0; t < calcdata.length; t++) {
trace = calcdata[t][0].trace;
var zi = trace.zorder || 0;
subplot = trace.xaxis + trace.yaxis;
if(!subplotZorderGroups[zi]) subplotZorderGroups[zi] = {};
if(!subplotZorderGroups[zi][subplot]) subplotZorderGroups[zi][subplot] = [];
subplotZorderGroups[zi][subplot].push(calcdata[t]);
}
var zindices = Object.keys(subplotZorderGroups)
.map(Number)
.sort(Lib.sorterAsc);
var len = zindices.length;

var xa2 = xa._mainAxis;
var ya2 = ya._mainAxis;
var mainplot = xa2._id + ya2._id;
var mainplotinfo = fullLayout._plots[mainplot];
plotinfo.overlays = [];

if(mainplot !== id && mainplotinfo) {
plotinfo.mainplot = mainplot;
plotinfo.mainplotinfo = mainplotinfo;
overlays.push(id);
} else {
plotinfo.mainplot = undefined;
plotinfo.mainplotinfo = undefined;
regulars.push(id);
var mainplot;
var mainplotinfo;
for(i = 0; i < len; i++) {
var zindex = subplotZorderGroups[zindices[i]];
ids = Object.keys(zindex);
for(j = 0; j < ids.length; j++) {
id = ids[j];
plotinfo = fullLayout._plots[id];

mainplot = mainplot ? mainplot : id;
mainplotinfo = fullLayout._plots[mainplot];
plotinfo.overlays = [];

if(regulars.indexOf(id) !== -1 || overlays.indexOf(id) !== -1) {
plotinfo.mainplot = mainplot;
plotinfo.mainplotinfo = mainplotinfo;
overlays.push(id + '-over-' + i);
} else if(mainplot !== id) {
plotinfo.mainplot = mainplot;
plotinfo.mainplotinfo = mainplotinfo;
overlays.push(id);
} else {
plotinfo.mainplot = undefined;
plotinfo.mainplotinfo = undefined;
regulars.push(id);
}
}
}

// fill in list of overlaying subplots in 'main plot'
for(i = 0; i < overlays.length; i++) {
id = overlays[i];
plotinfo = fullLayout._plots[id];
plotinfo.mainplotinfo.overlays.push(plotinfo);
if(id.indexOf('-over-') !== -1) {
id = id.split('-over-')[0];
}
var plotinfoCopy = Object.assign({}, fullLayout._plots[id]);
plotinfoCopy.id = overlays[i];
fullLayout._plots[id].mainplotinfo.overlays.push(plotinfoCopy);
}

// put 'regular' subplot data before 'overlaying'
var subplotIds = regulars.concat(overlays);
var subplotData = new Array(len);

for(i = 0; i < len; i++) {
var subplotData = new Array(subplotIds.length);
for(i = 0; i < subplotIds.length; i++) {
id = subplotIds[i];
if(id.indexOf('-over-') !== -1) {
fullLayout._plots[id] = Object.assign({}, fullLayout._plots[id.split('-over-')[0]]);
}
plotinfo = fullLayout._plots[id];
xa = plotinfo.xaxis;
ya = plotinfo.yaxis;

// use info about axis layer and overlaying pattern
// to clean what need to be cleaned up in exit selection
var d = [id, xa.layer, ya.layer, xa.overlaying || '', ya.overlaying || ''];
for(j = 0; j < plotinfo.overlays.length; j++) {
d.push(plotinfo.overlays[j].id);
if(id.indexOf('-over-') !== -1) {
for(j = 0; j < plotinfo.overlays.length; j++) {
d.push(plotinfo.overlays[j].id);
}
}
subplotData[i] = d;
}
return subplotData;
}

function makeSubplotLayer(gd, plotinfo) {
function makeSubplotLayer(gd, plotinfo, id) {
var plotgroup = plotinfo.plotgroup;
var id = plotinfo.id;
var xLayer = constants.layerValue2layerClass[plotinfo.xaxis.layer];
var yLayer = constants.layerValue2layerClass[plotinfo.yaxis.layer];
var hasOnlyLargeSploms = gd._fullLayout._hasOnlyLargeSploms;

if(!plotinfo.mainplot) {
if(!plotinfo.mainplot || plotinfo.mainplot === id) {
if(hasOnlyLargeSploms) {
// TODO could do even better
// - we don't need plot (but we would have to mock it in lsInner
Expand All @@ -486,7 +558,7 @@ function makeSubplotLayer(gd, plotinfo) {
plotinfo.ylines = ensureSingle(plotgroup, 'path', 'ylines-above');
plotinfo.xaxislayer = ensureSingle(plotgroup, 'g', 'xaxislayer-above');
plotinfo.yaxislayer = ensureSingle(plotgroup, 'g', 'yaxislayer-above');
} else {
} else if(id.indexOf('-over-') === -1) {
var backLayer = ensureSingle(plotgroup, 'g', 'layer-subplot');
plotinfo.shapelayer = ensureSingle(backLayer, 'g', 'shapelayer');
plotinfo.imagelayer = ensureSingle(backLayer, 'g', 'imagelayer');
Expand Down