зеркало из https://github.com/mozilla/pjs.git
Improve kinetic panning and add constants to customise behaviour.
Increase the number of considered motion events and add some constants to control the kinetic panning behaviour. This should make it a lot less glitchy.
This commit is contained in:
Родитель
1d0e5f50ae
Коммит
3bb845b883
|
@ -7,6 +7,24 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
|
||||
// The ratio of velocity that is retained every ms.
|
||||
const kPanDeceleration = 0.999;
|
||||
|
||||
// The number of ms to consider events over for a swipe gesture.
|
||||
const kSwipeLength = 1000;
|
||||
|
||||
// Minimum speed to move during kinetic panning. 0.015 pixels/ms is roughly
|
||||
// equivalent to a pixel every 4 frames at 60fps.
|
||||
const kMinKineticSpeed = 0.015;
|
||||
|
||||
// Maximum kinetic panning speed. 3 pixels/ms is equivalent to 50 pixels per
|
||||
// frame at 60fps.
|
||||
const kMaxKineticSpeed = 3;
|
||||
|
||||
// The maximum magnitude of disparity allowed between axes acceleration. If
|
||||
// it's larger than this, lock the slow-moving axis.
|
||||
const kAxisLockRatio = 5;
|
||||
|
||||
function dump(a) {
|
||||
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(a);
|
||||
}
|
||||
|
@ -319,9 +337,6 @@ Tab.prototype = {
|
|||
|
||||
var BrowserEventHandler = {
|
||||
init: function init() {
|
||||
this.motionBuffer = [];
|
||||
this._updateLastPosition(0, 0, 0, 0);
|
||||
|
||||
window.addEventListener("click", this, true);
|
||||
window.addEventListener("mousedown", this, true);
|
||||
window.addEventListener("mouseup", this, true);
|
||||
|
@ -406,14 +421,12 @@ var BrowserEventHandler = {
|
|||
this.firstMovement = true;
|
||||
this.firstXMovement = 0;
|
||||
this.firstYMovement = 0;
|
||||
|
||||
|
||||
this.motionBuffer = [];
|
||||
this._updateLastPosition(aEvent.clientX, aEvent.clientY, 0, 0);
|
||||
this.panElement = this._findScrollableElement(aEvent.originalTarget,
|
||||
true);
|
||||
|
||||
// Set panning to true *after* calling updateLastPosition, so
|
||||
// that it can clear the motion buffer the first time we call
|
||||
// it.
|
||||
if (this.panElement)
|
||||
this.panning = true;
|
||||
|
||||
|
@ -486,19 +499,18 @@ var BrowserEventHandler = {
|
|||
this.blockClick = true;
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
|
||||
if (isDrag &&
|
||||
(this.motionBuffer[4].time - this.motionBuffer[0].time) < 1000) {
|
||||
// We've exceeded the scroll threshold, start kinetic pan
|
||||
|
||||
// Find the average velocity over the last few motion events
|
||||
this.panLastTime = window.mozAnimationStartTime;
|
||||
this.panX = 0;
|
||||
this.panY = 0;
|
||||
let nEvents = 0;
|
||||
for (let i = 1; i < 5; i++) {
|
||||
for (let i = 0; i < this.motionBuffer.length - 1; i++) {
|
||||
if (this.motionBuffer[i].time < this.panLastTime - kSwipeLength)
|
||||
break;
|
||||
|
||||
let timeDelta = this.motionBuffer[i].time -
|
||||
this.motionBuffer[i - 1].time;
|
||||
this.motionBuffer[i + 1].time;
|
||||
if (timeDelta <= 0)
|
||||
continue;
|
||||
|
||||
|
@ -506,11 +518,19 @@ var BrowserEventHandler = {
|
|||
this.panY += this.motionBuffer[i].dy / timeDelta;
|
||||
nEvents ++;
|
||||
}
|
||||
if (nEvents == 0)
|
||||
break;
|
||||
|
||||
this.panX /= nEvents;
|
||||
this.panY /= nEvents;
|
||||
if (Math.abs(this.panX) > kMaxKineticSpeed)
|
||||
this.panX = (this.panX > 0) ? kMaxKineticSpeed : -kMaxKineticSpeed;
|
||||
if (Math.abs(this.panY) > kMaxKineticSpeed)
|
||||
this.panY = (this.panY > 0) ? kMaxKineticSpeed : -kMaxKineticSpeed;
|
||||
|
||||
// If we have zero acceleration, bail out.
|
||||
if (this.panX == 0 && this.panY == 0)
|
||||
// If we have (near) zero acceleration, bail out.
|
||||
if (Math.abs(this.panX) < kMinKineticSpeed &&
|
||||
Math.abs(this.panY) < kMinKineticSpeed)
|
||||
break;
|
||||
|
||||
// Check if this element can scroll - if not, let's bail out.
|
||||
|
@ -522,10 +542,8 @@ var BrowserEventHandler = {
|
|||
this._scrollElementBy(this.panElement, -this.panX, -this.panY);
|
||||
|
||||
// TODO: Use the kinetic scrolling prefs
|
||||
this.panDeceleration = 0.999;
|
||||
this.panAccumulatedDeltaX = 0;
|
||||
this.panAccumulatedDeltaY = 0;
|
||||
this.panLastTime = window.mozAnimationStartTime;
|
||||
|
||||
let self = this;
|
||||
let panElement = this.panElement;
|
||||
|
@ -538,8 +556,8 @@ var BrowserEventHandler = {
|
|||
self.panLastTime = timeStamp;
|
||||
|
||||
// Adjust deceleration
|
||||
self.panX *= Math.pow(self.panDeceleration, timeDelta);
|
||||
self.panY *= Math.pow(self.panDeceleration, timeDelta);
|
||||
self.panX *= Math.pow(kPanDeceleration, timeDelta);
|
||||
self.panY *= Math.pow(kPanDeceleration, timeDelta);
|
||||
|
||||
// Calculate panning motion
|
||||
let dx = self.panX * timeDelta;
|
||||
|
@ -566,20 +584,16 @@ var BrowserEventHandler = {
|
|||
|
||||
self._scrollElementBy(panElement, -dx, -dy);
|
||||
|
||||
// If we're moving at a rate slower than 0.015
|
||||
// pixels/ms, stop requesting frames.
|
||||
// This is roughly equivalent to a pixel every
|
||||
// 4 frames at 60fps.
|
||||
if (Math.abs(self.panX) >= 0.015 || Math.abs(self.panY) >= 0.015)
|
||||
if (Math.abs(self.panX) >= kMinKineticSpeed ||
|
||||
Math.abs(self.panY) >= kMinKineticSpeed)
|
||||
window.mozRequestAnimationFrame(this);
|
||||
}
|
||||
};
|
||||
|
||||
// If one axis is moving more than five times faster than
|
||||
// the other, lock to that axis.
|
||||
if (Math.abs(this.panX) < Math.abs(this.panY) / 5)
|
||||
// If one axis is moving a lot slower than the other, lock it.
|
||||
if (Math.abs(this.panX) < Math.abs(this.panY) / kAxisLockRatio)
|
||||
this.panX = 0;
|
||||
else if (Math.abs(this.panY) < Math.abs(this.panX) / 5)
|
||||
else if (Math.abs(this.panY) < Math.abs(this.panX) / kAxisLockRatio)
|
||||
this.panY = 0;
|
||||
|
||||
// Start the panning animation
|
||||
|
@ -611,16 +625,7 @@ var BrowserEventHandler = {
|
|||
this.lastY = y;
|
||||
this.lastTime = Date.now();
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (this.panning) {
|
||||
this.motionBuffer[i] = this.motionBuffer[i + 1];
|
||||
} else {
|
||||
this.motionBuffer[i] = { dx: 0, dy: 0, time: this.lastTime };
|
||||
}
|
||||
}
|
||||
|
||||
this.motionBuffer[4] =
|
||||
{ dx: dx, dy: dy, time: this.lastTime };
|
||||
this.motionBuffer.unshift({ dx: dx, dy: dy, time: this.lastTime });
|
||||
},
|
||||
|
||||
_findScrollableElement: function(elem, checkElem) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче