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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add zorder attribute to control stacking order of SVG traces drawn into cartesian subplots #6918

Merged
merged 49 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
df9361c
zindex first pass. scatter and bar traces only
emilykl Mar 9, 2024
176f922
Ensure zindex is compared by trace
Farkites Mar 11, 2024
7a5cdac
Add zindex basic baseline
Farkites Mar 11, 2024
1a24eaa
update plot-schema diff
Farkites Mar 11, 2024
5dcf623
Add zindex to image
Farkites Mar 11, 2024
e17739e
Add zindex to all cartesian traces
Farkites Mar 11, 2024
dbbb0d5
Update schema
Farkites Mar 11, 2024
cc2fc92
Fix scattergl zindex
Farkites Mar 11, 2024
6639de5
Add baseline /zindex-scatter-image.png
Farkites Mar 11, 2024
ac0a2a3
Restore dist
Farkites Mar 11, 2024
497b5f1
Remove scattergl zindex
Farkites Mar 11, 2024
071ac98
Remove coerce zindex from scattergl
Farkites Mar 11, 2024
a141e00
Remove zindex from funnelarea
Farkites Mar 11, 2024
cec8d65
Remove zindex from funnelarea
Farkites Mar 11, 2024
abfd1a8
Add zindex for ohlc
Farkites Mar 11, 2024
c1bfd61
Add mocks for zindex
Farkites Mar 11, 2024
32659ae
Add baselines
Farkites Mar 12, 2024
b758267
Fix zindex_violin_box mock
Farkites Mar 12, 2024
e368849
Add draftlog
Farkites Mar 12, 2024
85edbdf
Define zindex in scatter attributes
Farkites Mar 12, 2024
c422f53
Use Lib.sorterAsc for zindices
Farkites Mar 12, 2024
e5003c6
Handle zindex undefined in sort
Farkites Mar 12, 2024
4edefbd
Update draftlog
Farkites Mar 13, 2024
21a0ac1
Update description
Farkites Mar 13, 2024
ff01eb6
Update zindex-scatter-image mock
Farkites Mar 13, 2024
e92b6cd
Add mocks for zindex in histogram, heatmap, and contour traces
Farkites Mar 13, 2024
9e134e8
Add zindex to histogram traces
Farkites Mar 13, 2024
23368c9
Fix zindex routing in attributes
Farkites Mar 13, 2024
ef4d489
Update zindex description
Farkites Mar 13, 2024
edfefcd
Add baselines for zindex image, contour, heatmap, and histogram mocks
Farkites Mar 13, 2024
1ebbf61
Change zindex editType to 'plot'
Farkites Mar 13, 2024
9c1db37
Add zindex to funnel_axis_with_other_traces mock
Farkites Mar 13, 2024
d4b4c0a
Add new baseline for funnel_axis_with_other_traces
Farkites Mar 13, 2024
fe2f9d1
Update plot-schema
Farkites Mar 13, 2024
f9f7892
Fix funnel_axis_with_other_traces baseline
Farkites Mar 14, 2024
75cfb64
Remove zindex_histogram mock and baseline
Farkites Mar 14, 2024
670b55b
Reduce width and height of zindex mocks
Farkites Mar 14, 2024
c061a92
Update zindex baselines
Farkites Mar 14, 2024
27f51ec
Add Jasmine tests for zindex
Farkites Mar 21, 2024
17ffddb
Merge branch 'master' into trace-zindex
Farkites Mar 21, 2024
b76e894
Add jasmine test for clearing and adding zindex traces
Farkites Mar 22, 2024
c2c268c
Add select tests for zindex traces
Farkites Mar 25, 2024
4a1901c
Change naming of layers with zindex
Farkites Mar 25, 2024
7e2acfb
Remove focus in tests
Farkites Mar 25, 2024
1208283
Add zindex tests for bar traces
Farkites Mar 25, 2024
a9493d4
Fix index of layer names for negative zindex
Farkites Mar 25, 2024
eabedd8
Add overlaying bar traces to zindex_basic mock
Farkites Mar 25, 2024
2391afd
Extend zindex test to waterfall and funnel traces
Farkites Mar 25, 2024
efcd49f
rename zindex to zorder
archmoj Apr 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 72 additions & 72 deletions dist/plotly-cartesian.js
Farkites marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -87391,19 +87391,19 @@ module.exports = $gOPD;
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {

"use strict";
var isBrowser = __webpack_require__(24200)
var hasHover
if (typeof __webpack_require__.g.matchMedia === 'function') {
hasHover = !__webpack_require__.g.matchMedia('(hover: none)').matches
}
else {
hasHover = isBrowser
}
module.exports = hasHover


var isBrowser = __webpack_require__(24200)
var hasHover

if (typeof __webpack_require__.g.matchMedia === 'function') {
hasHover = !__webpack_require__.g.matchMedia('(hover: none)').matches
}
else {
hasHover = isBrowser
}

module.exports = hasHover


/***/ }),
Expand All @@ -87412,30 +87412,30 @@ module.exports = hasHover
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {

"use strict";
var isBrowser = __webpack_require__(24200)
function detect() {
var supported = false
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supported = true
}
})
window.addEventListener('test', null, opts)
window.removeEventListener('test', null, opts)
} catch(e) {
supported = false
}
return supported
}
module.exports = isBrowser && detect()


var isBrowser = __webpack_require__(24200)

function detect() {
var supported = false

try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supported = true
}
})

window.addEventListener('test', null, opts)
window.removeEventListener('test', null, opts)
} catch(e) {
supported = false
}

return supported
}

module.exports = isBrowser && detect()


/***/ }),
Expand Down Expand Up @@ -88021,41 +88021,41 @@ module.exports = function shimNumberIsNaN() {
/***/ (function(module) {

"use strict";
/**
* Is this string all whitespace?
* This solution kind of makes my brain hurt, but it's significantly faster
* than !str.trim() or any other solution I could find.
*
* whitespace codes from: http://en.wikipedia.org/wiki/Whitespace_character
* and verified with:
*
* for(var i = 0; i < 65536; i++) {
* var s = String.fromCharCode(i);
* if(+s===0 && !s.trim()) console.log(i, s);
* }
*
* which counts a couple of these as *not* whitespace, but finds nothing else
* that *is* whitespace. Note that charCodeAt stops at 16 bits, but it appears
* that there are no whitespace characters above this, and code points above
* this do not map onto white space characters.
*/
module.exports = function(str){
var l = str.length,
a;
for(var i = 0; i < l; i++) {
a = str.charCodeAt(i);
if((a < 9 || a > 13) && (a !== 32) && (a !== 133) && (a !== 160) &&
(a !== 5760) && (a !== 6158) && (a < 8192 || a > 8205) &&
(a !== 8232) && (a !== 8233) && (a !== 8239) && (a !== 8287) &&
(a !== 8288) && (a !== 12288) && (a !== 65279)) {
return false;
}
}
return true;
}


/**
* Is this string all whitespace?
* This solution kind of makes my brain hurt, but it's significantly faster
* than !str.trim() or any other solution I could find.
*
* whitespace codes from: http://en.wikipedia.org/wiki/Whitespace_character
* and verified with:
*
* for(var i = 0; i < 65536; i++) {
* var s = String.fromCharCode(i);
* if(+s===0 && !s.trim()) console.log(i, s);
* }
*
* which counts a couple of these as *not* whitespace, but finds nothing else
* that *is* whitespace. Note that charCodeAt stops at 16 bits, but it appears
* that there are no whitespace characters above this, and code points above
* this do not map onto white space characters.
*/

module.exports = function(str){
var l = str.length,
a;
for(var i = 0; i < l; i++) {
a = str.charCodeAt(i);
if((a < 9 || a > 13) && (a !== 32) && (a !== 133) && (a !== 160) &&
(a !== 5760) && (a !== 6158) && (a < 8192 || a > 8205) &&
(a !== 8232) && (a !== 8233) && (a !== 8239) && (a !== 8287) &&
(a !== 8288) && (a !== 12288) && (a !== 65279)) {
return false;
}
}
return true;
}


/***/ }),
Expand Down
86 changes: 55 additions & 31 deletions src/plots/cartesian/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,27 @@ exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) {
var calcdata = gd.calcdata;
var i;

// 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
// which are in calcdata.

if(!Array.isArray(traces)) {
// If traces is not provided, then it's a complete replot and missing
// traces are removed
traces = [];
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 for this 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;
Expand Down Expand Up @@ -178,7 +184,7 @@ exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) {
pcd = cd;
}
}

// Plot the traces for this subplot
plotOne(gd, subplotInfo, cdSubplot, transitionOpts, makeOnCompleteCallback);
}
};
Expand All @@ -189,41 +195,60 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
var modules = fullLayout._modules;
var _module, cdModuleAndOthers, cdModule;

// Separate traces by zindex and plot each zindex group separately
// TODO: Performance
archmoj marked this conversation as resolved.
Show resolved Hide resolved
var traceZindexGroups = {};
for(var t = 0; t < cdSubplot.length; t++) {
var trace = cdSubplot[t][0].trace;
var zi = trace.zindex || 0;
if(!traceZindexGroups[zi]) traceZindexGroups[zi] = [];
traceZindexGroups[zi].push(cdSubplot[t]);
}

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

for(var i = 0; i < modules.length; i++) {
_module = modules[i];
var name = _module.name;
var categories = Registry.modules[name].categories;

if(categories.svg) {
var className = (_module.layerName || name + 'layer');
var plotMethod = _module.plot;

// plot all visible traces of this type on this subplot at once
cdModuleAndOthers = getModuleCalcData(cdSubplot, plotMethod);
cdModule = cdModuleAndOthers[0];
// don't need to search the found traces again - in fact we need to NOT
// so that if two modules share the same plotter we don't double-plot
cdSubplot = cdModuleAndOthers[1];

if(cdModule.length) {
layerData.push({
i: traceLayerClasses.indexOf(className),
className: className,
plotMethod: plotMethod,
cdModule: cdModule
});
}
// Plot each zindex group in ascending order
var zindices = Object.keys(traceZindexGroups)
.map(Number)
archmoj marked this conversation as resolved.
Show resolved Hide resolved
.sort(function(a, b) { return a - b; });
Farkites marked this conversation as resolved.
Show resolved Hide resolved
for(var z = 0; z < zindices.length; z++) {
var zindex = zindices[z];
// For each "module" (trace type)
for(var i = 0; i < modules.length; i++) {
_module = modules[i];
var name = _module.name;
var categories = Registry.modules[name].categories;

if(categories.svg) {
var className = (_module.layerName || name + 'layer') + (zindex ? '-' + z : '');
Farkites marked this conversation as resolved.
Show resolved Hide resolved
var plotMethod = _module.plot;

// plot all visible traces of this type on this subplot at once
cdModuleAndOthers = getModuleCalcData(cdSubplot, plotMethod, zindex);
cdModule = cdModuleAndOthers[0];
// don't need to search the found traces again - in fact we need to NOT
// so that if two modules share the same plotter we don't double-plot
cdSubplot = cdModuleAndOthers[1];

if(cdModule.length) {
layerData.push({
i: traceLayerClasses.indexOf(className),
zindex: z,
className: className,
plotMethod: plotMethod,
cdModule: cdModule
});
}

if(categories.zoomScale) {
zoomScaleQueryParts.push('.' + className);
if(categories.zoomScale) {
zoomScaleQueryParts.push('.' + className);
}
}
}
}

layerData.sort(function(a, b) { return a.i - b.i; });
// Sort the layers primarily by z, then by i
layerData.sort(function(a, b) { return a.zindex - b.zindex || a.i - b.i; });
archmoj marked this conversation as resolved.
Show resolved Hide resolved

var layers = plotinfo.plot.selectAll('g.mlayer')
.data(layerData, function(d) { return d.className; });
Expand Down Expand Up @@ -434,7 +459,6 @@ function makeSubplotData(gd) {
}
subplotData[i] = d;
}

return subplotData;
}

Expand Down
8 changes: 5 additions & 3 deletions src/plots/get_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ exports.getSubplotCalcData = function(calcData, type, subplotId) {
* @param {array} calcdata: as in gd.calcdata
* @param {object|string|fn} arg1:
* the plotting module, or its name, or its plot method
*
* @param {int} arg2: (optional) zindex to filter on
* @return {array[array]} [foundCalcdata, remainingCalcdata]
*/
exports.getModuleCalcData = function(calcdata, arg1) {
exports.getModuleCalcData = function(calcdata, arg1, arg2) {
var moduleCalcData = [];
var remainingCalcData = [];

Expand All @@ -57,10 +57,12 @@ exports.getModuleCalcData = function(calcdata, arg1) {
if(!plotMethod) {
return [moduleCalcData, calcdata];
}
var zindex = arg2;

for(var i = 0; i < calcdata.length; i++) {
var cd = calcdata[i];
var trace = cd[0].trace;
var filterByZ = (trace.zindex !== undefined);
// N.B.
// - 'legendonly' traces do not make it past here
// - skip over 'visible' traces that got trimmed completely during calc transforms
Expand All @@ -70,7 +72,7 @@ exports.getModuleCalcData = function(calcdata, arg1) {
// would suggest), but by 'module plot method' so that if some traces
// share the same module plot method (e.g. bar and histogram), we
// only call it one!
if(trace._module && trace._module.plot === plotMethod) {
if(trace._module && trace._module.plot === plotMethod && (!filterByZ || trace.zindex === zindex)) {
moduleCalcData.push(cd);
} else {
remainingCalcData.push(cd);
Expand Down
1 change: 1 addition & 0 deletions src/traces/bar/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ module.exports = {
textfont: scatterAttrs.unselected.textfont,
editType: 'style'
},
zindex: scatterAttrs.zindex,

_deprecated: {
bardir: {
Expand Down
2 changes: 2 additions & 0 deletions src/traces/bar/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
coerce('xhoverformat');
coerce('yhoverformat');

coerce('zindex');

coerce('orientation', (traceOut.x && !traceOut.y) ? 'h' : 'v');
coerce('base');
coerce('offset');
Expand Down
2 changes: 1 addition & 1 deletion src/traces/bar/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var attributeOutsideTextFont = attributes.outsidetextfont;
var helpers = require('./helpers');

function style(gd) {
var s = d3.select(gd).selectAll('g.barlayer').selectAll('g.trace');
var s = d3.select(gd).selectAll('g[class^="barlayer"]').selectAll('g.trace');
archmoj marked this conversation as resolved.
Show resolved Hide resolved
resizeText(gd, s, 'bar');

var barcount = s.size();
Expand Down
12 changes: 11 additions & 1 deletion src/traces/image/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,15 @@ module.exports = extendFlat({
keys: ['z', 'color', 'colormodel']
}),

transforms: undefined
transforms: undefined,
zindex: {
valType: 'integer',
dflt: 0,
editType: 'calc',
description: [
'Sets the layer on which this trace is displayed, relative to ',
'other traces on the same axes. Traces with higher `zindex` ',
'appear in front of those with lower `zindex`.'
].join(' ')
}
});
2 changes: 2 additions & 0 deletions src/traces/image/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ module.exports = function supplyDefaults(traceIn, traceOut) {
coerce('hovertemplate');

traceOut._length = null;

coerce('zindex');
};
10 changes: 10 additions & 0 deletions src/traces/scatter/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -686,4 +686,14 @@ module.exports = {
arrayOk: true,
description: 'Sets the text font.'
}),
zindex: {
Farkites marked this conversation as resolved.
Show resolved Hide resolved
valType: 'integer',
dflt: 0,
editType: 'calc',
Farkites marked this conversation as resolved.
Show resolved Hide resolved
description: [
'Sets the layer on which this trace is displayed, relative to ',
'other traces on the same axes. Traces with higher `zindex` ',
Farkites marked this conversation as resolved.
Show resolved Hide resolved
'appear in front of those with lower `zindex`.'
].join(' ')
}
};
Loading