Skip to content

Commit

Permalink
Merge pull request #3422 from plotly/scrollzoom-flaglist
Browse files Browse the repository at this point in the history
Make scrollZoom config option a flaglist
  • Loading branch information
etpinard committed Jan 16, 2019
2 parents f9cfadb + 09f1af5 commit ceac510
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 35 deletions.
19 changes: 19 additions & 0 deletions src/plot_api/plot_api.js
Expand Up @@ -507,6 +507,25 @@ function setPlotContext(gd, config) {
// Check if gd has a specified widht/height to begin with
context._hasZeroHeight = context._hasZeroHeight || gd.clientHeight === 0;
context._hasZeroWidth = context._hasZeroWidth || gd.clientWidth === 0;

// fill context._scrollZoom helper to help manage scrollZoom flaglist
var szIn = context.scrollZoom;
var szOut = context._scrollZoom = {};
if(szIn === true) {
szOut.cartesian = 1;
szOut.gl3d = 1;
szOut.geo = 1;
szOut.mapbox = 1;
} else if(typeof szIn === 'string') {
var parts = szIn.split('+');
for(i = 0; i < parts.length; i++) {
szOut[parts[i]] = 1;
}
} else if(szIn !== false) {
szOut.gl3d = 1;
szOut.geo = 1;
szOut.mapbox = 1;
}
}

function plotLegacyPolar(gd, data, layout) {
Expand Down
13 changes: 9 additions & 4 deletions src/plot_api/plot_config.js
Expand Up @@ -145,11 +145,16 @@ var configAttributes = {
},

scrollZoom: {
valType: 'boolean',
dflt: false,
valType: 'flaglist',
flags: ['cartesian', 'gl3d', 'geo', 'mapbox'],
extras: [true, false],
dflt: 'gl3d+geo+mapbox',
description: [
'Determines whether mouse wheel or two-finger scroll zooms is',
'enable. Has an effect only on cartesian subplots.'
'Determines whether mouse wheel or two-finger scroll zooms is enable.',
'Turned on by default for gl3d, geo and mapbox subplots',
'(as these subplot types do not have zoombox via pan),',
'but turned off by default for cartesian subplots.',
'Set `scrollZoom` to *false* to disable scrolling for all subplots.'
].join(' ')
},
doubleClick: {
Expand Down
2 changes: 1 addition & 1 deletion src/plots/cartesian/dragbox.js
Expand Up @@ -417,7 +417,7 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
// deactivate mousewheel scrolling on embedded graphs
// devs can override this with layout._enablescrollzoom,
// but _ ensures this setting won't leave their page
if(!gd._context.scrollZoom && !gd._fullLayout._enablescrollzoom) {
if(!gd._context._scrollZoom.cartesian && !gd._fullLayout._enablescrollzoom) {
return;
}

Expand Down
3 changes: 3 additions & 0 deletions src/plots/geo/geo.js
Expand Up @@ -420,6 +420,9 @@ proto.updateFx = function(fullLayout, geoLayout) {
bgRect.node().onmousedown = null;
bgRect.call(createGeoZoom(_this, geoLayout));
bgRect.on('dblclick.zoom', zoomReset);
if(!gd._context._scrollZoom.geo) {
bgRect.on('wheel.zoom', null);
}
}
else if(dragMode === 'select' || dragMode === 'lasso') {
bgRect.on('.zoom', null);
Expand Down
2 changes: 1 addition & 1 deletion src/plots/gl2d/scene2d.js
Expand Up @@ -38,7 +38,7 @@ function Scene2D(options, fullLayout) {
this.pixelRatio = options.plotGlPixelRatio || window.devicePixelRatio;
this.id = options.id;
this.staticPlot = !!options.staticPlot;
this.scrollZoom = this.graphDiv._context.scrollZoom;
this.scrollZoom = this.graphDiv._context._scrollZoom.cartesian;

this.fullData = null;
this.updateRefs(fullLayout);
Expand Down
3 changes: 3 additions & 0 deletions src/plots/gl3d/camera.js
Expand Up @@ -48,6 +48,7 @@ function createCamera(element, options) {

var camera = {
keyBindingMode: 'rotate',
enableWheel: true,
view: view,
element: element,
delay: options.delay || 16,
Expand Down Expand Up @@ -257,7 +258,9 @@ function createCamera(element, options) {
}

camera.wheelListener = mouseWheel(element, function(dx, dy) {
// TODO remove now that we can disable scroll via scrollZoom?
if(camera.keyBindingMode === false) return;
if(!camera.enableWheel) return;

var flipX = camera.flipX ? 1 : -1;
var flipY = camera.flipY ? 1 : -1;
Expand Down
14 changes: 10 additions & 4 deletions src/plots/gl3d/scene.js
Expand Up @@ -227,8 +227,15 @@ function initializeGLPlot(scene, canvas, gl) {
scene.graphDiv.emit('plotly_relayout', update);
};

scene.glplot.canvas.addEventListener('mouseup', relayoutCallback.bind(null, scene));
scene.glplot.canvas.addEventListener('wheel', relayoutCallback.bind(null, scene), passiveSupported ? {passive: false} : false);
scene.glplot.canvas.addEventListener('mouseup', function() {
relayoutCallback(scene);
});

scene.glplot.canvas.addEventListener('wheel', function() {
if(gd._context._scrollZoom.gl3d) {
relayoutCallback(scene);
}
}, passiveSupported ? {passive: false} : false);

if(!scene.staticMode) {
scene.glplot.canvas.addEventListener('webglcontextlost', function(event) {
Expand Down Expand Up @@ -385,7 +392,6 @@ function computeTraceBounds(scene, trace, bounds) {
}

proto.plot = function(sceneData, fullLayout, layout) {

// Save parameters
this.plotArgs = [sceneData, fullLayout, layout];

Expand All @@ -412,6 +418,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
// Update camera and camera mode
this.setCamera(fullSceneLayout.camera);
this.updateFx(fullSceneLayout.dragmode, fullSceneLayout.hovermode);
this.camera.enableWheel = this.graphDiv._context._scrollZoom.gl3d;

// Update scene
this.glplot.update({});
Expand Down Expand Up @@ -776,7 +783,6 @@ proto.updateFx = function(dragmode, hovermode) {
fullCamera.up = zUp;
Lib.nestedProperty(layout, attr).set(zUp);
} else {

// none rotation modes [pan or zoom]
camera.keyBindingMode = dragmode;
}
Expand Down
6 changes: 6 additions & 0 deletions src/plots/mapbox/mapbox.js
Expand Up @@ -258,6 +258,12 @@ proto.updateMap = function(calcData, fullLayout, resolve, reject) {
self.updateLayout(fullLayout);
self.resolveOnRender(resolve);
}

if(this.gd._context._scrollZoom.mapbox) {
map.scrollZoom.enable();
} else {
map.scrollZoom.disable();
}
};

proto.updateData = function(calcData) {
Expand Down
59 changes: 59 additions & 0 deletions test/jasmine/tests/config_test.js
Expand Up @@ -760,4 +760,63 @@ describe('config argument', function() {
.then(done);
});
});

describe('scrollZoom:', function() {
var gd;

beforeEach(function() { gd = createGraphDiv(); });

afterEach(destroyGraphDiv);

function plot(config) {
return Plotly.plot(gd, [], {}, config);
}

it('should fill in scrollZoom default', function(done) {
plot(undefined).then(function() {
expect(gd._context.scrollZoom).toBe('gl3d+geo+mapbox');
expect(gd._context._scrollZoom).toEqual({gl3d: 1, geo: 1, mapbox: 1});
expect(gd._context._scrollZoom.cartesian).toBe(undefined, 'no cartesian!');
})
.catch(failTest)
.then(done);
});

it('should fill in blank scrollZoom value', function(done) {
plot({scrollZoom: null}).then(function() {
expect(gd._context.scrollZoom).toBe(null);
expect(gd._context._scrollZoom).toEqual({gl3d: 1, geo: 1, mapbox: 1});
expect(gd._context._scrollZoom.cartesian).toBe(undefined, 'no cartesian!');
})
.catch(failTest)
.then(done);
});

it('should honor scrollZoom:true', function(done) {
plot({scrollZoom: true}).then(function() {
expect(gd._context.scrollZoom).toBe(true);
expect(gd._context._scrollZoom).toEqual({gl3d: 1, geo: 1, cartesian: 1, mapbox: 1});
})
.catch(failTest)
.then(done);
});

it('should honor scrollZoom:false', function(done) {
plot({scrollZoom: false}).then(function() {
expect(gd._context.scrollZoom).toBe(false);
expect(gd._context._scrollZoom).toEqual({});
})
.catch(failTest)
.then(done);
});

it('should honor scrollZoom flaglist', function(done) {
plot({scrollZoom: 'mapbox+cartesian'}).then(function() {
expect(gd._context.scrollZoom).toBe('mapbox+cartesian');
expect(gd._context._scrollZoom).toEqual({mapbox: 1, cartesian: 1});
})
.catch(failTest)
.then(done);
});
});
});
48 changes: 48 additions & 0 deletions test/jasmine/tests/geo_test.js
Expand Up @@ -1961,4 +1961,52 @@ describe('Test geo zoom/pan/drag interactions:', function() {
.catch(failTest)
.then(done);
});

it('should respect scrollZoom config option', function(done) {
var fig = Lib.extendDeep({}, require('@mocks/geo_winkel-tripel'));
fig.layout.width = 700;
fig.layout.height = 500;
fig.layout.dragmode = 'pan';

function _assert(step, attr, proj, eventKeys) {
var msg = '[' + step + '] ';

var geoLayout = gd._fullLayout.geo;
var scale = geoLayout.projection.scale;
expect(scale).toBeCloseTo(attr[0], 1, msg + 'zoom');

var geo = geoLayout._subplot;
var _scale = geo.projection.scale();
expect(_scale).toBeCloseTo(proj[0], 0, msg + 'scale');

assertEventData(msg, eventKeys);
}

plot(fig)
.then(function() {
_assert('base', [1], [101.9], undefined);
})
.then(function() { return scroll([200, 250], [-200, -200]); })
.then(function() {
_assert('with scroll enable (by default)',
[1.3], [134.4],
['geo.projection.rotation.lon', 'geo.center.lon', 'geo.center.lat', 'geo.projection.scale']
);
})
.then(function() { return Plotly.plot(gd, [], {}, {scrollZoom: false}); })
.then(function() { return scroll([200, 250], [-200, -200]); })
.then(function() {
_assert('with scrollZoom:false', [1.3], [134.4], undefined);
})
.then(function() { return Plotly.plot(gd, [], {}, {scrollZoom: 'geo'}); })
.then(function() { return scroll([200, 250], [-200, -200]); })
.then(function() {
_assert('with scrollZoom:geo',
[1.74], [177.34],
['geo.projection.rotation.lon', 'geo.center.lon', 'geo.center.lat', 'geo.projection.scale']
);
})
.catch(failTest)
.then(done);
});
});
59 changes: 34 additions & 25 deletions test/jasmine/tests/gl3d_plot_interact_test.js
Expand Up @@ -1097,6 +1097,11 @@ describe('Test gl3d drag and wheel interactions', function() {
}
};

function _assertAndReset(cnt) {
expect(relayoutCallback).toHaveBeenCalledTimes(cnt);
relayoutCallback.calls.reset();
}

Plotly.plot(gd, mock)
.then(function() {
relayoutCallback = jasmine.createSpy('relayoutCallback');
Expand All @@ -1115,48 +1120,32 @@ describe('Test gl3d drag and wheel interactions', function() {
return scroll(sceneTarget);
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(1);
relayoutCallback.calls.reset();

_assertAndReset(1);
return scroll(sceneTarget2);
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(1);
relayoutCallback.calls.reset();

_assertAndReset(1);
return drag(sceneTarget2, [0, 0], [100, 100]);
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(1);
relayoutCallback.calls.reset();

_assertAndReset(1);
return drag(sceneTarget, [0, 0], [100, 100]);
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(1);
relayoutCallback.calls.reset();

return Plotly.relayout(gd, {
'scene.dragmode': false,
'scene2.dragmode': false
});
_assertAndReset(1);
return Plotly.relayout(gd, {'scene.dragmode': false, 'scene2.dragmode': false});
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(1);
relayoutCallback.calls.reset();

_assertAndReset(1);
return drag(sceneTarget, [0, 0], [100, 100]);
})
.then(function() {
return drag(sceneTarget2, [0, 0], [100, 100]);
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(0);
_assertAndReset(0);

return Plotly.relayout(gd, {
'scene.dragmode': 'orbit',
'scene2.dragmode': 'turntable'
});
return Plotly.relayout(gd, {'scene.dragmode': 'orbit', 'scene2.dragmode': 'turntable'});
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(1);
Expand All @@ -1168,7 +1157,27 @@ describe('Test gl3d drag and wheel interactions', function() {
return drag(sceneTarget2, [0, 0], [100, 100]);
})
.then(function() {
expect(relayoutCallback).toHaveBeenCalledTimes(2);
_assertAndReset(2);
return Plotly.plot(gd, [], {}, {scrollZoom: false});
})
.then(function() {
return scroll(sceneTarget);
})
.then(function() {
return scroll(sceneTarget2);
})
.then(function() {
_assertAndReset(0);
return Plotly.plot(gd, [], {}, {scrollZoom: 'gl3d'});
})
.then(function() {
return scroll(sceneTarget);
})
.then(function() {
return scroll(sceneTarget2);
})
.then(function() {
_assertAndReset(2);
})
.catch(failTest)
.then(done);
Expand Down

0 comments on commit ceac510

Please sign in to comment.