Skip to content

Commit 3ad1eaa

Browse files
committed
add 'axrange' editType
- this represents the minimal sequence for '(x|y)axis.range' relayout calls which are pretty common (e.g. on zoom/pan mouseup). - by bypassing drawFramework, lsInner and initInteraction, this can save ~1000ms on 50x50 subplot grids.
1 parent 02ed2eb commit 3ad1eaa

File tree

5 files changed

+86
-6
lines changed

5 files changed

+86
-6
lines changed

src/plot_api/edit_types.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ var layoutOpts = {
3535
valType: 'flaglist',
3636
extras: ['none'],
3737
flags: [
38-
'calc', 'calcIfAutorange', 'plot', 'legend', 'ticks', 'margins',
38+
'calc', 'calcIfAutorange', 'plot', 'legend', 'ticks', 'axrange', 'margins',
3939
'layoutstyle', 'modebar', 'camera', 'arraydraw'
4040
],
4141
description: [
@@ -48,6 +48,7 @@ var layoutOpts = {
4848
'*legend* only redraws the legend.',
4949
'*ticks* only redraws axis ticks, labels, and gridlines.',
5050
'*margins* recomputes ticklabel automargins.',
51+
'*axrange* minimal sequence when updating axis ranges.',
5152
'*layoutstyle* reapplies global and SVG cartesian axis styles.',
5253
'*modebar* just updates the modebar.',
5354
'*camera* just updates the camera settings for gl3d scenes.',

src/plot_api/plot_api.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,26 @@ exports.relayout = function relayout(gd, astr, val) {
16831683

16841684
if(flags.legend) seq.push(subroutines.doLegend);
16851685
if(flags.layoutstyle) seq.push(subroutines.layoutStyles);
1686+
1687+
if(flags.axrange) {
1688+
// N.B. leave as sequence of subroutines (for now) instead of
1689+
// subroutine of its own so that finalDraw always gets
1690+
// executed after drawData
1691+
seq.push(
1692+
// TODO
1693+
// no test fail when commenting out doAutoRangeAndConstraints,
1694+
// but I think we do need this (maybe just the enforce part?)
1695+
// Am I right?
1696+
subroutines.doAutoRangeAndConstraints,
1697+
// TODO
1698+
// can target specific axes,
1699+
// do not have to redraw all axes here
1700+
subroutines.doTicksRelayout,
1701+
subroutines.drawData,
1702+
subroutines.finalDraw
1703+
);
1704+
}
1705+
16861706
if(flags.ticks) seq.push(subroutines.doTicksRelayout);
16871707
if(flags.modebar) seq.push(subroutines.doModeBar);
16881708
if(flags.camera) seq.push(subroutines.doCamera);
@@ -2147,6 +2167,14 @@ exports.update = function update(gd, traceUpdate, layoutUpdate, _traces) {
21472167
if(restyleFlags.colorbars) seq.push(subroutines.doColorBars);
21482168
if(relayoutFlags.legend) seq.push(subroutines.doLegend);
21492169
if(relayoutFlags.layoutstyle) seq.push(subroutines.layoutStyles);
2170+
if(relayoutFlags.axrange) {
2171+
seq.push(
2172+
subroutines.doAutoRangeAndConstraints,
2173+
subroutines.doTicksRelayout,
2174+
subroutines.drawData,
2175+
subroutines.finalDraw
2176+
);
2177+
}
21502178
if(relayoutFlags.ticks) seq.push(subroutines.doTicksRelayout);
21512179
if(relayoutFlags.modebar) seq.push(subroutines.doModeBar);
21522180
if(relayoutFlags.camera) seq.push(subroutines.doCamera);
@@ -2299,6 +2327,14 @@ exports.react = function(gd, data, layout, config) {
22992327
if(restyleFlags.colorbars) seq.push(subroutines.doColorBars);
23002328
if(relayoutFlags.legend) seq.push(subroutines.doLegend);
23012329
if(relayoutFlags.layoutstyle) seq.push(subroutines.layoutStyles);
2330+
if(relayoutFlags.axrange) {
2331+
seq.push(
2332+
subroutines.doAutoRangeAndConstraints,
2333+
subroutines.doTicksRelayout,
2334+
subroutines.drawData,
2335+
subroutines.finalDraw
2336+
);
2337+
}
23022338
if(relayoutFlags.ticks) seq.push(subroutines.doTicksRelayout);
23032339
if(relayoutFlags.modebar) seq.push(subroutines.doModeBar);
23042340
if(relayoutFlags.camera) seq.push(subroutines.doCamera);

src/plots/cartesian/axes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2188,7 +2188,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
21882188
}
21892189
drawTicks(mainPlotinfo[axLetter + 'axislayer'], tickpath);
21902190

2191-
tickSubplots = Object.keys(ax._linepositions);
2191+
tickSubplots = Object.keys(ax._linepositions || {});
21922192
}
21932193

21942194
tickSubplots.map(function(subplot) {

src/plots/cartesian/layout_attributes.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ module.exports = {
100100
valType: 'info_array',
101101
role: 'info',
102102
items: [
103-
{valType: 'any', editType: 'plot+margins', impliedEdits: {'^autorange': false}},
104-
{valType: 'any', editType: 'plot+margins', impliedEdits: {'^autorange': false}}
103+
{valType: 'any', editType: 'axrange+margins', impliedEdits: {'^autorange': false}},
104+
{valType: 'any', editType: 'axrange+margins', impliedEdits: {'^autorange': false}}
105105
],
106-
editType: 'plot+margins',
106+
editType: 'axrange+margins',
107107
impliedEdits: {'autorange': false},
108108
description: [
109109
'Sets the range of this axis.',

test/jasmine/tests/plot_api_test.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,10 @@ describe('Test plot api', function() {
504504
'layoutStyles',
505505
'doTicksRelayout',
506506
'doModeBar',
507-
'doCamera'
507+
'doCamera',
508+
'doAutoRangeAndConstraints',
509+
'drawData',
510+
'finalDraw'
508511
];
509512

510513
var gd;
@@ -613,6 +616,46 @@ describe('Test plot api', function() {
613616
expectReplot(attr);
614617
}
615618
});
619+
620+
it('should trigger minimal sequence for cartesian axis range updates', function() {
621+
var seq = ['doAutoRangeAndConstraints', 'doTicksRelayout', 'drawData', 'finalDraw'];
622+
623+
function _assert(msg) {
624+
expect(gd.calcdata).toBeDefined();
625+
mockedMethods.forEach(function(m) {
626+
expect(subroutines[m].calls.count()).toBe(
627+
seq.indexOf(m) === -1 ? 0 : 1,
628+
'# of ' + m + ' calls - ' + msg
629+
);
630+
});
631+
}
632+
633+
var trace = {y: [1, 2, 1]};
634+
635+
var specs = [
636+
['relayout', ['xaxis.range[0]', 0]],
637+
['relayout', ['xaxis.range[1]', 3]],
638+
['relayout', ['xaxis.range', [-1, 5]]],
639+
['update', [{}, {'xaxis.range': [-1, 10]}]],
640+
['react', [[trace], {xaxis: {range: [0, 1]}}]]
641+
];
642+
643+
specs.forEach(function(s) {
644+
// create 'real' div for Plotly.react to work
645+
gd = createGraphDiv();
646+
Plotly.plot(gd, [trace], {xaxis: {range: [1, 2]}});
647+
mock(gd);
648+
649+
Plotly[s[0]](gd, s[1][0], s[1][1]);
650+
651+
_assert([
652+
'Plotly.', s[0],
653+
'(gd, ', JSON.stringify(s[1][0]), ', ', JSON.stringify(s[1][1]), ')'
654+
].join(''));
655+
656+
destroyGraphDiv();
657+
});
658+
});
616659
});
617660

618661
describe('Plotly.restyle subroutines switchboard', function() {

0 commit comments

Comments
 (0)