From ea5c91e19e55d0f7054ebe365fb8a80f8689e61f Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Fri, 14 Feb 2020 11:46:57 +0100 Subject: [PATCH] Revert "Merge pull request #9565 from dbrnz/v6.0.0-beta.7-branch" This reverts commit 35569a84277854109281946b73d95ba1b0bff5d1, reversing changes made to 29a434314b770a596baa981793b336575a406a6a. --- src/ol/interaction/MouseWheelZoom.js | 85 ++++++++++--- .../ol/interaction/mousewheelzoom.test.js | 112 ++++++++---------- 2 files changed, 122 insertions(+), 75 deletions(-) diff --git a/src/ol/interaction/MouseWheelZoom.js b/src/ol/interaction/MouseWheelZoom.js index 37a4e4022f..1ed762bc17 100644 --- a/src/ol/interaction/MouseWheelZoom.js +++ b/src/ol/interaction/MouseWheelZoom.js @@ -4,7 +4,17 @@ import {always, focus} from '../events/condition.js'; import EventType from '../events/EventType.js'; import {DEVICE_PIXEL_RATIO, FIREFOX} from '../has.js'; -import Interaction from './Interaction.js'; +import Interaction, {zoomByDelta} from './Interaction.js'; +import {clamp} from '../math.js'; + + +/** + * @enum {string} + */ +export const Mode = { + TRACKPAD: 'trackpad', + WHEEL: 'wheel' +}; /** @@ -92,23 +102,35 @@ class MouseWheelZoom extends Interaction { this.startTime_ = undefined; /** - * Events separated by this delay will be considered separate + * @private + * @type {?} + */ + this.timeoutId_; + + /** + * @private + * @type {Mode|undefined} + */ + this.mode_ = undefined; + + /** + * Trackpad events separated by this delay will be considered separate * interactions. * @type {number} */ - this.eventGap_ = 400; + this.trackpadEventGap_ = 400; /** * @type {?} */ - this.timeoutId_; + this.trackpadTimeoutId_; /** * The number of delta values per zoom level * @private * @type {number} */ - this.deltaPerZoom_ = 300; + this.trackpadDeltaPerZoom_ = 300; } @@ -130,7 +152,7 @@ class MouseWheelZoom extends Interaction { * @private */ endInteraction_() { - this.timeoutId_ = undefined; + this.trackpadTimeoutId_ = undefined; const view = this.getMap().getView(); view.endInteraction(undefined, this.lastDelta_ ? (this.lastDelta_ > 0 ? 1 : -1) : 0, this.lastAnchor_); } @@ -184,18 +206,53 @@ class MouseWheelZoom extends Interaction { this.startTime_ = now; } - const view = map.getView(); - if (this.timeoutId_) { - clearTimeout(this.timeoutId_); - } else { - view.beginInteraction(); + if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) { + this.mode_ = Math.abs(delta) < 4 ? + Mode.TRACKPAD : + Mode.WHEEL; } - this.timeoutId_ = setTimeout(this.endInteraction_.bind(this), this.eventGap_); - view.adjustZoom(-delta / this.deltaPerZoom_, this.lastAnchor_); - this.startTime_ = now; + + if (this.mode_ === Mode.TRACKPAD) { + const view = map.getView(); + if (this.trackpadTimeoutId_) { + clearTimeout(this.trackpadTimeoutId_); + } else { + view.beginInteraction(); + } + this.trackpadTimeoutId_ = setTimeout(this.endInteraction_.bind(this), this.trackpadEventGap_); + view.adjustZoom(-delta / this.trackpadDeltaPerZoom_, this.lastAnchor_); + this.startTime_ = now; + return false; + } + + this.totalDelta_ += delta; + + const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0); + + clearTimeout(this.timeoutId_); + this.timeoutId_ = setTimeout(this.handleWheelZoom_.bind(this, map), timeLeft); + return false; } + /** + * @private + * @param {import("../PluggableMap.js").default} map Map. + */ + handleWheelZoom_(map) { + const view = map.getView(); + if (view.getAnimating()) { + view.cancelAnimations(); + } + const delta = clamp(this.totalDelta_, -this.maxDelta_, this.maxDelta_); + zoomByDelta(view, -delta, this.lastAnchor_, this.duration_); + this.mode_ = undefined; + this.totalDelta_ = 0; + this.lastAnchor_ = null; + this.startTime_ = undefined; + this.timeoutId_ = undefined; + } + /** * Enable or disable using the mouse's location as an anchor when zooming * @param {boolean} useAnchor true to zoom to the mouse's location, false diff --git a/test/spec/ol/interaction/mousewheelzoom.test.js b/test/spec/ol/interaction/mousewheelzoom.test.js index 8eea3ea3c3..ee1858bf5d 100644 --- a/test/spec/ol/interaction/mousewheelzoom.test.js +++ b/test/spec/ol/interaction/mousewheelzoom.test.js @@ -3,7 +3,7 @@ import MapBrowserEvent from '../../../../src/ol/MapBrowserEvent.js'; import View from '../../../../src/ol/View.js'; import Event from '../../../../src/ol/events/Event.js'; import {DEVICE_PIXEL_RATIO, FIREFOX} from '../../../../src/ol/has.js'; -import MouseWheelZoom from '../../../../src/ol/interaction/MouseWheelZoom.js'; +import MouseWheelZoom, {Mode} from '../../../../src/ol/interaction/MouseWheelZoom.js'; describe('ol.interaction.MouseWheelZoom', function() { @@ -32,13 +32,13 @@ describe('ol.interaction.MouseWheelZoom', function() { describe('timeout duration', function() { let clock; beforeEach(function() { - sinon.spy(interaction, 'endInteraction_'); + sinon.spy(interaction, 'handleWheelZoom_'); clock = sinon.useFakeTimers(); }); afterEach(function() { clock.restore(); - interaction.endInteraction_.restore(); + interaction.handleWheelZoom_.restore(); }); it('works with the default value', function(done) { @@ -49,12 +49,12 @@ describe('ol.interaction.MouseWheelZoom', function() { }); map.handleMapBrowserEvent(event); - clock.tick(100); - // default timeout is 400 ms, not called yet - expect(interaction.endInteraction_.called).to.be(false); + clock.tick(50); + // default timeout is 80 ms, not called yet + expect(interaction.handleWheelZoom_.called).to.be(false); - clock.tick(300); - expect(interaction.endInteraction_.called).to.be(true); + clock.tick(30); + expect(interaction.handleWheelZoom_.called).to.be(true); done(); }); @@ -63,15 +63,10 @@ describe('ol.interaction.MouseWheelZoom', function() { describe('handleEvent()', function() { - let view; - beforeEach(function() { - view = map.getView(); - }); - if (FIREFOX) { it('works on Firefox in DOM_DELTA_PIXEL mode (trackpad)', function(done) { map.once('postrender', function() { - expect(interaction.lastDelta_).to.be(1); + expect(interaction.mode_).to.be(Mode.TRACKPAD); done(); }); const event = new MapBrowserEvent('wheel', map, { @@ -89,7 +84,7 @@ describe('ol.interaction.MouseWheelZoom', function() { if (!FIREFOX) { it('works in DOM_DELTA_PIXEL mode (trackpad)', function(done) { map.once('postrender', function() { - expect(interaction.lastDelta_).to.be(1); + expect(interaction.mode_).to.be(Mode.TRACKPAD); done(); }); const event = new MapBrowserEvent('wheel', map, { @@ -104,61 +99,56 @@ describe('ol.interaction.MouseWheelZoom', function() { }); } - - it('works in DOM_DELTA_LINE mode (wheel)', function(done) { - map.once('postrender', function() { - expect(view.getResolution()).to.be(2); - expect(view.getCenter()).to.eql([0, 0]); - done(); + describe('spying on view.animateInternal()', function() { + let view; + beforeEach(function() { + view = map.getView(); + sinon.spy(view, 'animateInternal'); }); - const event = new MapBrowserEvent('wheel', map, { - type: 'wheel', - deltaMode: WheelEvent.DOM_DELTA_LINE, - deltaY: 7.5, - target: map.getViewport(), - preventDefault: Event.prototype.preventDefault - }); - event.coordinate = [0, 0]; - - map.handleMapBrowserEvent(event); - }); - - it('works on all browsers (wheel)', function(done) { - map.once('postrender', function() { - expect(view.getResolution()).to.be(2); - expect(view.getCenter()).to.eql([0, 0]); - done(); + afterEach(function() { + view.animateInternal.restore(); }); - const event = new MapBrowserEvent('wheel', map, { - type: 'wheel', - deltaY: 300, // trackpadDeltaPerZoom_ - target: map.getViewport(), - preventDefault: Event.prototype.preventDefault - }); - event.coordinate = [0, 0]; + it('works in DOM_DELTA_LINE mode (wheel)', function(done) { + map.once('postrender', function() { + const call = view.animateInternal.getCall(0); + expect(call.args[0].resolution).to.be(2); + expect(call.args[0].anchor).to.eql([0, 0]); + done(); + }); - map.handleMapBrowserEvent(event); - }); + const event = new MapBrowserEvent('wheel', map, { + type: 'wheel', + deltaMode: WheelEvent.DOM_DELTA_LINE, + deltaY: 3.714599609375, + target: map.getViewport(), + preventDefault: Event.prototype.preventDefault + }); + event.coordinate = [0, 0]; - it('works in DOM_DELTA_LINE mode (wheel)', function(done) { - map.once('postrender', function() { - expect(view.getResolution()).to.be(2); - expect(view.getCenter()).to.eql([0, 0]); - done(); + map.handleMapBrowserEvent(event); }); - const event = new MapBrowserEvent('wheel', map, { - type: 'wheel', - deltaMode: WheelEvent.DOM_DELTA_LINE, - deltaY: 7.5, // trackpadDeltaPerZoom_ / 40 - target: map.getViewport(), - preventDefault: Event.prototype.preventDefault - }); - event.coordinate = [0, 0]; + it('works on all browsers (wheel)', function(done) { + map.once('postrender', function() { + const call = view.animateInternal.getCall(0); + expect(call.args[0].resolution).to.be(2); + expect(call.args[0].anchor).to.eql([0, 0]); + done(); + }); + + const event = new MapBrowserEvent('wheel', map, { + type: 'wheel', + deltaY: 120, + target: map.getViewport(), + preventDefault: Event.prototype.preventDefault + }); + event.coordinate = [0, 0]; + + map.handleMapBrowserEvent(event); + }); - map.handleMapBrowserEvent(event); }); });