Merge pull request #6113 from tschaub/scroll-zoom

Smooth trackpad zooming
This commit is contained in:
Tim Schaub
2016-11-12 15:00:05 -07:00
committed by GitHub
2 changed files with 154 additions and 71 deletions
+132 -54
View File
@@ -1,6 +1,7 @@
goog.provide('ol.interaction.MouseWheelZoom');
goog.require('ol');
goog.require('ol.easing');
goog.require('ol.events.EventType');
goog.require('ol.has');
goog.require('ol.interaction.Interaction');
@@ -66,6 +67,26 @@ ol.interaction.MouseWheelZoom = function(opt_options) {
*/
this.timeoutId_ = undefined;
/**
* @private
* @type {ol.interaction.MouseWheelZoom.Mode|undefined}
*/
this.mode_ = undefined;
/**
* The number of delta values per zoom level
* @private
* @type {number}
*/
this.trackpadDeltaPerZoom_ = 300;
/**
* The zoom factor by which scroll zooming is allowed to exceed the limits.
* @private
* @type {number}
*/
this.trackpadZoomBuffer_ = 1.5;
};
ol.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction);
@@ -74,57 +95,105 @@ ol.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction);
* Handles the {@link ol.MapBrowserEvent map browser event} (if it was a
* mousewheel-event) and eventually zooms the map.
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} `false` to stop event propagation.
* @return {boolean} Allow event propagation.
* @this {ol.interaction.MouseWheelZoom}
* @api
*/
ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) {
var stopEvent = false;
if (mapBrowserEvent.type == ol.events.EventType.WHEEL ||
mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) {
var map = mapBrowserEvent.map;
var wheelEvent = /** @type {WheelEvent} */ (mapBrowserEvent.originalEvent);
if (this.useAnchor_) {
this.lastAnchor_ = mapBrowserEvent.coordinate;
}
// Delta normalisation inspired by
// https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js
//TODO There's more good stuff in there for inspiration to improve this interaction.
var delta;
if (mapBrowserEvent.type == ol.events.EventType.WHEEL) {
delta = wheelEvent.deltaY;
if (ol.has.FIREFOX &&
wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
delta /= ol.has.DEVICE_PIXEL_RATIO;
}
if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) {
delta *= 40;
}
} else if (mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) {
delta = -wheelEvent.wheelDeltaY;
if (ol.has.SAFARI) {
delta /= 3;
}
}
this.delta_ += delta;
if (this.startTime_ === undefined) {
this.startTime_ = Date.now();
}
var timeLeft = Math.max(this.timeout_ - (Date.now() - this.startTime_), 0);
clearTimeout(this.timeoutId_);
this.timeoutId_ = setTimeout(
this.doZoom_.bind(this, map), timeLeft);
mapBrowserEvent.preventDefault();
stopEvent = true;
var type = mapBrowserEvent.type;
if (type !== ol.events.EventType.WHEEL && type !== ol.events.EventType.MOUSEWHEEL) {
return true;
}
return !stopEvent;
mapBrowserEvent.preventDefault();
var map = mapBrowserEvent.map;
var wheelEvent = /** @type {WheelEvent} */ (mapBrowserEvent.originalEvent);
if (this.useAnchor_) {
this.lastAnchor_ = mapBrowserEvent.coordinate;
}
// Delta normalisation inspired by
// https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js
var delta;
if (mapBrowserEvent.type == ol.events.EventType.WHEEL) {
delta = wheelEvent.deltaY;
if (ol.has.FIREFOX &&
wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
delta /= ol.has.DEVICE_PIXEL_RATIO;
}
if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) {
delta *= 40;
}
} else if (mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) {
delta = -wheelEvent.wheelDeltaY;
if (ol.has.SAFARI) {
delta /= 3;
}
}
if (delta === 0) {
return false;
}
var now = Date.now();
if (this.startTime_ === undefined) {
this.startTime_ = now;
}
if (!this.mode_ || now - this.startTime_ > 400) {
this.mode_ = Math.abs(delta) < 4 ?
ol.interaction.MouseWheelZoom.Mode.TRACKPAD :
ol.interaction.MouseWheelZoom.Mode.WHEEL;
}
if (this.mode_ === ol.interaction.MouseWheelZoom.Mode.TRACKPAD) {
var view = map.getView();
var resolution = view.getResolution() * Math.pow(2, delta / this.trackpadDeltaPerZoom_);
var minResolution = view.getMinResolution();
var maxResolution = view.getMaxResolution();
var rebound = 0;
if (resolution < minResolution) {
resolution = Math.max(resolution, minResolution / this.trackpadZoomBuffer_);
rebound = 1;
} else if (resolution > maxResolution) {
resolution = Math.min(resolution, maxResolution * this.trackpadZoomBuffer_);
rebound = -1;
}
if (this.lastAnchor_) {
var center = view.calculateCenterZoom(resolution, this.lastAnchor_);
view.setCenter(center);
}
view.setResolution(resolution);
if (rebound > 0) {
view.animate({
resolution: minResolution,
easing: ol.easing.easeOut,
anchor: this.lastAnchor_,
duration: 500
});
} else if (rebound < 0) {
view.animate({
resolution: maxResolution,
easing: ol.easing.easeOut,
anchor: this.lastAnchor_,
duration: 500
});
}
this.startTime_ = now;
return false;
}
this.delta_ += delta;
var timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
clearTimeout(this.timeoutId_);
this.timeoutId_ = setTimeout(this.handleWheelZoom_.bind(this, map), timeLeft);
return false;
};
@@ -132,16 +201,16 @@ ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) {
* @private
* @param {ol.Map} map Map.
*/
ol.interaction.MouseWheelZoom.prototype.doZoom_ = function(map) {
ol.interaction.MouseWheelZoom.prototype.handleWheelZoom_ = function(map) {
var view = map.getView();
if (!view.getAnimating()) {
var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA;
var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta);
ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_,
this.duration_);
if (view.getAnimating()) {
view.cancelAnimations();
}
var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA;
var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta);
ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_,
this.duration_);
this.mode_ = undefined;
this.delta_ = 0;
this.lastAnchor_ = null;
this.startTime_ = undefined;
@@ -161,3 +230,12 @@ ol.interaction.MouseWheelZoom.prototype.setMouseAnchor = function(useAnchor) {
this.lastAnchor_ = null;
}
};
/**
* @enum {string}
*/
ol.interaction.MouseWheelZoom.Mode = {
TRACKPAD: 'trackpad',
WHEEL: 'wheel'
};