Skip to content

Commit bb02281

Browse files
committed
speed up doModeBar subroutines for cartesian subplots
- split minimal updateFx part out of initInteractions - set maindrag cursor class (which depends only on layout.dragmode) on <g .draglayer> instead of inner <rect> to update it for all subplots in < 1ms (that's a > 600ms improvement on 50x50 grids) - use gd._fullLayout instead of scoped fullLayout in initInteractions and makeDragBox to ensure correct reference after doModeBar()
1 parent 3ad1eaa commit bb02281

File tree

6 files changed

+37
-24
lines changed

6 files changed

+37
-24
lines changed

src/plot_api/plot_api.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ var Registry = require('../registry');
2222
var PlotSchema = require('./plot_schema');
2323
var Plots = require('../plots/plots');
2424
var Polar = require('../plots/polar/legacy');
25-
var initInteractions = require('../plots/cartesian/graph_interact');
2625

2726
var Axes = require('../plots/cartesian/axes');
2827
var Drawing = require('../components/drawing');
2928
var Color = require('../components/color');
29+
var initInteractions = require('../plots/cartesian/graph_interact').initInteractions;
3030
var xmlnsNamespaces = require('../constants/xmlns_namespaces');
3131
var svgTextUtils = require('../lib/svg_text_utils');
3232

src/plot_api/subroutines.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ var Color = require('../components/color');
1919
var Drawing = require('../components/drawing');
2020
var Titles = require('../components/titles');
2121
var ModeBar = require('../components/modebar');
22+
2223
var Axes = require('../plots/cartesian/axes');
23-
var initInteractions = require('../plots/cartesian/graph_interact');
2424
var cartesianConstants = require('../plots/cartesian/constants');
2525
var alignmentConstants = require('../constants/alignment');
2626
var axisConstraints = require('../plots/cartesian/constraints');
@@ -465,7 +465,6 @@ exports.doModeBar = function(gd) {
465465
var fullLayout = gd._fullLayout;
466466

467467
ModeBar.manage(gd);
468-
initInteractions(gd);
469468

470469
for(var i = 0; i < fullLayout._basePlotModules.length; i++) {
471470
var updateFx = fullLayout._basePlotModules[i].updateFx;

src/plots/cartesian/dragbox.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
5555
// within DBLCLICKDELAY so we can check for click or doubleclick events
5656
// dragged stores whether a drag has occurred, so we don't have to
5757
// redraw unnecessarily, ie if no move bigger than MINDRAG or MINZOOM px
58-
var fullLayout = gd._fullLayout;
5958
var zoomlayer = gd._fullLayout._zoomlayer;
6059
var isMainDrag = (ns + ew === 'nsew');
6160
var singleEnd = (ns + ew).length === 1;
@@ -111,6 +110,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
111110

112111
recomputeAxisLists();
113112

113+
var cursor = getDragCursor(yActive + xActive, gd._fullLayout.dragmode, isMainDrag);
114114
var dragger = makeRectDragger(plotinfo, ns + ew + 'drag', cursor, x, y, w, h);
115115

116116
var allFixedRanges = !yActive && !xActive;
@@ -131,6 +131,8 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
131131
prepFn: function(e, startX, startY) {
132132
var dragModeNow = gd._fullLayout.dragmode;
133133

134+
recomputeAxisLists();
135+
134136
if(!allFixedRanges) {
135137
if(isMainDrag) {
136138
// main dragger handles all drag modes, and changes
@@ -204,7 +206,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
204206
.call(svgTextUtils.makeEditable, {
205207
gd: gd,
206208
immediate: true,
207-
background: fullLayout.paper_bgcolor,
209+
background: gd._fullLayout.paper_bgcolor,
208210
text: String(initialText),
209211
fill: ax.tickfont ? ax.tickfont.color : '#444',
210212
horizontalAlign: hAlign,
@@ -354,7 +356,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
354356
// deactivate mousewheel scrolling on embedded graphs
355357
// devs can override this with layout._enablescrollzoom,
356358
// but _ ensures this setting won't leave their page
357-
if(!gd._context.scrollZoom && !fullLayout._enablescrollzoom) {
359+
if(!gd._context.scrollZoom && !gd._fullLayout._enablescrollzoom) {
358360
return;
359361
}
360362

@@ -456,8 +458,6 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
456458
return;
457459
}
458460

459-
recomputeAxisLists();
460-
461461
if(xActive === 'ew' || yActive === 'ns') {
462462
if(xActive) dragAxList(xa, dx);
463463
if(yActive) dragAxList(ya, dy);
@@ -584,9 +584,9 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
584584
// annotations and shapes 'draw' method is slow,
585585
// use the finer-grained 'drawOne' method instead
586586

587-
redrawObjs(fullLayout.annotations || [], Registry.getComponentMethod('annotations', 'drawOne'));
588-
redrawObjs(fullLayout.shapes || [], Registry.getComponentMethod('shapes', 'drawOne'));
589-
redrawObjs(fullLayout.images || [], Registry.getComponentMethod('images', 'draw'), true);
587+
redrawObjs(gd._fullLayout.annotations || [], Registry.getComponentMethod('annotations', 'drawOne'));
588+
redrawObjs(gd._fullLayout.shapes || [], Registry.getComponentMethod('shapes', 'drawOne'));
589+
redrawObjs(gd._fullLayout.images || [], Registry.getComponentMethod('images', 'draw'), true);
590590
}
591591

592592
function doubleClick() {
@@ -892,9 +892,12 @@ function dZoom(d) {
892892
1 / (1 / Math.max(d, -0.3) + 3.222));
893893
}
894894

895-
function getDragCursor(nsew, dragmode) {
895+
function getDragCursor(nsew, dragmode, isMainDrag) {
896896
if(!nsew) return 'pointer';
897897
if(nsew === 'nsew') {
898+
// in this case here, clear cursor and
899+
// use the cursor style set on <g .draglayer>
900+
if(isMainDrag) return '';
898901
if(dragmode === 'pan') return 'move';
899902
return 'crosshair';
900903
}

src/plots/cartesian/graph_interact.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ var d3 = require('d3');
1313

1414
var Fx = require('../../components/fx');
1515
var dragElement = require('../../components/dragelement');
16+
var setCursor = require('../../lib/setcursor');
1617

17-
var constants = require('./constants');
1818
var makeDragBox = require('./dragbox').makeDragBox;
19+
var DRAGGERSIZE = require('./constants').DRAGGERSIZE;
1920

20-
module.exports = function initInteractions(gd) {
21+
exports.initInteractions = function initInteractions(gd) {
2122
var fullLayout = gd._fullLayout;
2223

2324
if(gd._context.staticPlot) {
@@ -43,12 +44,9 @@ module.exports = function initInteractions(gd) {
4344

4445
subplots.forEach(function(subplot) {
4546
var plotinfo = fullLayout._plots[subplot];
46-
4747
var xa = plotinfo.xaxis;
4848
var ya = plotinfo.yaxis;
4949

50-
var DRAGGERSIZE = constants.DRAGGERSIZE;
51-
5250
// main and corner draggers need not be repeated for
5351
// overlaid subplots - these draggers drag them all
5452
if(!plotinfo.mainplot) {
@@ -139,17 +137,29 @@ module.exports = function initInteractions(gd) {
139137
var hoverLayer = fullLayout._hoverlayer.node();
140138

141139
hoverLayer.onmousemove = function(evt) {
142-
evt.target = fullLayout._lasthover;
140+
evt.target = gd._fullLayout._lasthover;
143141
Fx.hover(gd, evt, fullLayout._hoversubplot);
144142
};
145143

146144
hoverLayer.onclick = function(evt) {
147-
evt.target = fullLayout._lasthover;
145+
evt.target = gd._fullLayout._lasthover;
148146
Fx.click(gd, evt);
149147
};
150148

151149
// also delegate mousedowns... TODO: does this actually work?
152150
hoverLayer.onmousedown = function(evt) {
153-
fullLayout._lasthover.onmousedown(evt);
151+
gd._fullLayout._lasthover.onmousedown(evt);
154152
};
153+
154+
exports.updateFx(fullLayout);
155+
};
156+
157+
// Minimal set of update needed on 'modebar' edits.
158+
// We only need to update the <g .draglayer> cursor style.
159+
//
160+
// Note that changing the axis configuration and/or the fixedrange attribute
161+
// should trigger a full initInteractions.
162+
exports.updateFx = function(fullLayout) {
163+
var cursor = fullLayout.dragmode === 'pan' ? 'move' : 'crosshair';
164+
setCursor(fullLayout._draggers, cursor);
155165
};

src/plots/cartesian/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,5 @@ exports.toSVG = function(gd) {
548548

549549
canvases.each(canvasToImage);
550550
};
551+
552+
exports.updateFx = require('./graph_interact').updateFx;

test/jasmine/tests/fx_test.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,12 @@ describe('relayout', function() {
201201
afterEach(destroyGraphDiv);
202202

203203
it('should update main drag with correct', function(done) {
204-
205204
function assertMainDrag(cursor, isActive) {
206205
expect(d3.selectAll('rect.nsewdrag').size()).toEqual(1, 'number of nodes');
207-
var mainDrag = d3.select('rect.nsewdrag'),
208-
node = mainDrag.node();
206+
var mainDrag = d3.select('rect.nsewdrag');
207+
var node = mainDrag.node();
209208

210-
expect(mainDrag.classed('cursor-' + cursor)).toBe(true, 'cursor ' + cursor);
209+
expect(window.getComputedStyle(node).cursor).toBe(cursor, 'cursor ' + cursor);
211210
expect(node.style.pointerEvents).toEqual('all', 'pointer event');
212211
expect(!!node.onmousedown).toBe(isActive, 'mousedown handler');
213212
}

0 commit comments

Comments
 (0)