-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Fix relayout constrained axes + various multi-subplot perf improvements #2628
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
Changes from 5 commits
a12a22b
23964ca
abd4bcf
09d5dd0
5557d7b
73b354b
e69b7dd
c947b2c
6fa8ffd
455ff4d
72b6558
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1689,19 +1689,9 @@ exports.relayout = function relayout(gd, astr, val) { | |
// subroutine of its own so that finalDraw always gets | ||
// executed after drawData | ||
seq.push( | ||
// TODO | ||
// no test fail when commenting out doAutoRangeAndConstraints, | ||
// but I think we do need this (maybe just the enforce part?) | ||
// Am I right? | ||
// More info in: | ||
// https://github.com/plotly/plotly.js/issues/2540 | ||
subroutines.doAutoRangeAndConstraints, | ||
// TODO | ||
// can target specific axes, | ||
// do not have to redraw all axes here | ||
// See: | ||
// https://github.com/plotly/plotly.js/issues/2547 | ||
subroutines.doTicksRelayout, | ||
function(gd) { | ||
return subroutines.doTicksRelayout(gd, specs.rangesAltered); | ||
}, | ||
subroutines.drawData, | ||
subroutines.finalDraw | ||
); | ||
|
@@ -1728,6 +1718,10 @@ exports.relayout = function relayout(gd, astr, val) { | |
}); | ||
}; | ||
|
||
var AX_RANGE_RE = /^[xyz]axis[0-9]*\.range(\[[0|1]\])?$/; | ||
var AX_AUTORANGE_RE = /^[xyz]axis[0-9]*\.autorange$/; | ||
var AX_DOMAIN_RE = /^[xyz]axis[0-9]*\.domain(\[[0|1]\])?$/; | ||
|
||
function _relayout(gd, aobj) { | ||
var layout = gd.layout, | ||
fullLayout = gd._fullLayout, | ||
|
@@ -1806,7 +1800,7 @@ function _relayout(gd, aobj) { | |
var plen = p.parts.length; | ||
// p.parts may end with an index integer if the property is an array | ||
var pend = plen - 1; | ||
while(pend > 0 && typeof p.parts[plen - 1] !== 'string') { pend--; } | ||
while(pend > 0 && typeof p.parts[pend] !== 'string') pend--; | ||
// last property in chain (leaf node) | ||
var pleaf = p.parts[pend]; | ||
// leaf plus immediate parent | ||
|
@@ -1841,11 +1835,11 @@ function _relayout(gd, aobj) { | |
fullLayout[ai] = gd._initialAutoSize[ai]; | ||
} | ||
// check autorange vs range | ||
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.range(\[[0|1]\])?$/)) { | ||
else if(pleafPlus.match(AX_RANGE_RE)) { | ||
recordAlteredAxis(pleafPlus); | ||
Lib.nestedProperty(fullLayout, ptrunk + '._inputRange').set(null); | ||
} | ||
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.autorange$/)) { | ||
else if(pleafPlus.match(AX_AUTORANGE_RE)) { | ||
recordAlteredAxis(pleafPlus); | ||
Lib.nestedProperty(fullLayout, ptrunk + '._inputRange').set(null); | ||
var axFull = Lib.nestedProperty(fullLayout, ptrunk).get(); | ||
|
@@ -1855,7 +1849,7 @@ function _relayout(gd, aobj) { | |
axFull._input.domain = axFull._inputDomain.slice(); | ||
} | ||
} | ||
else if(pleafPlus.match(/^[xyz]axis[0-9]*\.domain(\[[0|1]\])?$/)) { | ||
else if(pleafPlus.match(AX_DOMAIN_RE)) { | ||
Lib.nestedProperty(fullLayout, ptrunk + '._inputDomain').set(null); | ||
} | ||
|
||
|
@@ -2061,6 +2055,7 @@ function _relayout(gd, aobj) { | |
|
||
return { | ||
flags: flags, | ||
rangesAltered: rangesAltered, | ||
undoit: undoit, | ||
redoit: redoit, | ||
eventData: Lib.extendDeep({}, redoit) | ||
|
@@ -2174,8 +2169,9 @@ exports.update = function update(gd, traceUpdate, layoutUpdate, _traces) { | |
if(relayoutFlags.layoutstyle) seq.push(subroutines.layoutStyles); | ||
if(relayoutFlags.axrange) { | ||
seq.push( | ||
subroutines.doAutoRangeAndConstraints, | ||
subroutines.doTicksRelayout, | ||
function(gd) { | ||
return subroutines.doTicksRelayout(gd, relayoutSpecs.rangesAltered); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. N.B. @alexcjohnson I didn't implement per-axis "axrange" edit for |
||
}, | ||
subroutines.drawData, | ||
subroutines.finalDraw | ||
); | ||
|
@@ -2340,7 +2336,6 @@ exports.react = function(gd, data, layout, config) { | |
if(relayoutFlags.layoutstyle) seq.push(subroutines.layoutStyles); | ||
if(relayoutFlags.axrange) { | ||
seq.push( | ||
subroutines.doAutoRangeAndConstraints, | ||
subroutines.doTicksRelayout, | ||
subroutines.drawData, | ||
subroutines.finalDraw | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1456,6 +1456,10 @@ axes.findSubplotsWithAxis = function(subplots, ax) { | |
// makeClipPaths: prepare clipPaths for all single axes and all possible xy pairings | ||
axes.makeClipPaths = function(gd) { | ||
var fullLayout = gd._fullLayout; | ||
|
||
// for more info: https://github.com/plotly/plotly.js/issues/2595 | ||
if(fullLayout._hasOnlyLargeSploms) return; | ||
|
||
var fullWidth = {_offset: 0, _length: fullLayout.width, _id: ''}; | ||
var fullHeight = {_offset: 0, _length: fullLayout.height, _id: ''}; | ||
var xaList = axes.list(gd, 'x', true); | ||
|
@@ -1494,28 +1498,50 @@ axes.makeClipPaths = function(gd) { | |
}); | ||
}; | ||
|
||
// doTicks: draw ticks, grids, and tick labels | ||
// axid: 'x', 'y', 'x2' etc, | ||
// blank to do all, | ||
// 'redraw' to force full redraw, and reset: | ||
// ax._r (stored range for use by zoom/pan) | ||
// ax._rl (stored linearized range for use by zoom/pan) | ||
// or can pass in an axis object directly | ||
axes.doTicks = function(gd, axid, skipTitle) { | ||
/** Main axis drawing routine! | ||
* | ||
* This routine draws axis ticks and much more (... grids, labels, title etc.) | ||
* Supports multiple argument signatures. | ||
* N.B. this thing is async in general (because of MathJax rendering) | ||
* | ||
* @param {DOM element} gd : graph div | ||
* @param {object or string or array of strings} arg : polymorphic argument | ||
* @param {boolean} skipTitle : optional flag to skip axis title draw/update | ||
* @return {promise} | ||
* | ||
* Signature 1: Axes.doTicks(gd, ax) | ||
* where ax is an axis object as in fullLayout | ||
* | ||
* Signature 2: Axes.doTicks(gd, axId) | ||
* where axId is a axis id string | ||
* | ||
* Signature 3: Axes.doTicks(gd, 'redraw') | ||
* use this to clear and redraw all axes on graph | ||
* | ||
* Signature 4: Axes.doTicks(gd, '') | ||
* use this to draw all axes on graph w/o the selectAll().remove() | ||
* of the 'redraw' signature | ||
* | ||
* Signature 5: Axes.doTicks(gd, [axId, axId2, ...]) | ||
* where the items are axis id string, | ||
* use this to update multiple axes in one call | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was already a bit out of control, do we really want to add another signature? Can we perhaps break it into 2 separate functions, one for signatures 1 & 2 and a second for 3, 4, 5? That's how it functions anyway - 3,4,5 just map into a bunch of calls to signature 2 (ignoring There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure that would be nice. But since But if you insist, than I'm thinking of making On |
||
* | ||
* N.B signatures 3, 4 and 5 reset: | ||
* - ax._r (stored range for use by zoom/pan) | ||
* - ax._rl (stored linearized range for use by zoom/pan) | ||
*/ | ||
axes.doTicks = function(gd, arg, skipTitle) { | ||
var fullLayout = gd._fullLayout; | ||
var ax; | ||
var independent = false; | ||
var ax; | ||
|
||
// allow passing an independent axis object instead of id | ||
if(typeof axid === 'object') { | ||
ax = axid; | ||
axid = ax._id; | ||
if(Lib.isPlainObject(arg)) { | ||
ax = arg; | ||
independent = true; | ||
} | ||
else { | ||
ax = axes.getFromId(gd, axid); | ||
} else if(!arg || arg === 'redraw' || Array.isArray(arg)) { | ||
var axList = (!arg || arg === 'redraw') ? axes.listIds(gd) : arg; | ||
|
||
if(axid === 'redraw') { | ||
if(arg === 'redraw') { | ||
fullLayout._paper.selectAll('g.subplot').each(function(subplot) { | ||
var plotinfo = fullLayout._plots[subplot]; | ||
var xa = plotinfo.xaxis; | ||
|
@@ -1530,22 +1556,24 @@ axes.doTicks = function(gd, axid, skipTitle) { | |
}); | ||
} | ||
|
||
if(!axid || axid === 'redraw') { | ||
return Lib.syncOrAsync(axes.list(gd, '', true).map(function(ax) { | ||
return function() { | ||
if(!ax._id) return; | ||
var axDone = axes.doTicks(gd, ax._id); | ||
ax._r = ax.range.slice(); | ||
ax._rl = Lib.simpleMap(ax._r, ax.r2l); | ||
return axDone; | ||
}; | ||
})); | ||
} | ||
return Lib.syncOrAsync(axList.map(function(a) { | ||
return function() { | ||
if(!a) return; | ||
var axDone = axes.doTicks(gd, a); | ||
var ax = axes.getFromId(gd, a); | ||
ax._r = ax.range.slice(); | ||
ax._rl = Lib.simpleMap(ax._r, ax.r2l); | ||
return axDone; | ||
}; | ||
})); | ||
} else { | ||
ax = axes.getFromId(gd, arg); | ||
} | ||
|
||
// set scaling to pixels | ||
ax.setScale(); | ||
|
||
var axid = ax._id; | ||
var axLetter = axid.charAt(0); | ||
var counterLetter = axes.counterLetter(axid); | ||
var vals = ax._vals = axes.calcTicks(ax); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, nice catch!