perf(ripple): improve ripple perf

This commit is contained in:
Adam Bradley
2015-11-09 13:55:25 -06:00
parent 8d1370a706
commit e0f18a5de2
4 changed files with 71 additions and 37 deletions

View File

@ -27,7 +27,7 @@ export class Animation {
constructor(ele, opts={}) {
this.reset();
this._opts = extend({
renderDelay: 36
renderDelay: 16
}, opts);
this.elements(ele);
@ -238,15 +238,31 @@ export class Animation {
// stage all animations and child animations at their starting point
self.stage();
// synchronously call all onPlay()'s before play()
self._onPlay();
let resolve;
let promise = new Promise(res => { resolve = res; });
function kickoff() {
// synchronously call all onPlay()'s before play()
self._onPlay();
return new Promise(resolve => {
beginPlay().then(() => {
self._onFinish();
resolve();
});
});
}
if (self._duration > 16) {
// begin each animation when everything is rendered in their starting point
// give the browser some time to render everything in place before starting
setTimeout(kickoff, this._opts.renderDelay);
} else {
// no need to render everything in there place before animating in
// just kick it off immediately to render them in their "to" locations
kickoff();
}
return promise;
}
// this is a child animation, it is told exactly when to
@ -586,11 +602,13 @@ class Animate {
// lock in where the element will stop at
// if the playbackRate is negative then it needs to return
// to its "from" effects
inlineStyle(self.ele, self.rate < 0 ? self.fromEffect : self.toEffect);
if (self.ani) {
inlineStyle(self.ele, self.rate < 0 ? self.fromEffect : self.toEffect);
self.ani = null;
self.ani = self.ani.onfinish = null;
done && done();
done && done();
}
};
}

View File

@ -65,14 +65,15 @@ export class RippleActivator extends Activator {
upAction(forceFadeOut) {
this.deactivate();
let ripple;
for (let rippleId in this.ripples) {
let rippleId, ripple;
for (rippleId in this.ripples) {
ripple = this.ripples[rippleId];
if (!ripple.fade || forceFadeOut) {
// ripple has not been let up yet
// speed up the rate if the animation is still going
setTimeout(() => {
clearTimeout(ripple.fadeStart);
ripple.fadeStart = setTimeout(() => {
// speed up the rate if the animation is still going
ripple.expand && ripple.expand.playbackRate(EXPAND_OUT_PLAYBACK_RATE);
ripple.fade = new Animation(ripple.ele);
ripple.fade
@ -87,7 +88,7 @@ export class RippleActivator extends Activator {
})
.play();
}, 16);
});
}
}
@ -95,15 +96,15 @@ export class RippleActivator extends Activator {
}
next(forceComplete) {
let ripple, rippleEle;
for (let rippleId in this.ripples) {
let rippleId, ripple;
for (rippleId in this.ripples) {
ripple = this.ripples[rippleId];
if ((ripple.expanded && ripple.faded && ripple.ele) ||
forceComplete || parseInt(rippleId) + 5000 < Date.now()) {
if ((ripple.expanded && ripple.faded && ripple.ele) || forceComplete) {
// finished expanding and the user has lifted the pointer
ripple.remove = true;
raf(() => {
this.remove(rippleId);
this.remove();
});
}
}
@ -114,14 +115,17 @@ export class RippleActivator extends Activator {
this.next(true);
}
remove(rippleId) {
let ripple = this.ripples[rippleId];
if (ripple) {
ripple.expand && ripple.expand.dispose();
ripple.fade && ripple.fade.dispose();
removeElement(ripple.ele);
ripple.ele = ripple.expand = ripple.fade = null;
delete this.ripples[rippleId];
remove() {
let rippleId, ripple;
for (rippleId in this.ripples) {
ripple = this.ripples[rippleId];
if (ripple.remove || parseInt(rippleId, 10) + 4000 < Date.now()) {
ripple.expand && ripple.expand.dispose();
ripple.fade && ripple.fade.dispose();
removeElement(ripple.ele);
ripple.ele = ripple.expand = ripple.fade = null;
delete this.ripples[rippleId];
}
}
}

View File

@ -10,7 +10,7 @@ let lastActivated = 0;
let disableNativeClickTime = 0;
let disableNativeClickLimit = 1000;
let activator = null;
let isEnabled = false;
let isTapPolyfill = false;
let app = null;
let config = null;
let win = null;
@ -24,13 +24,15 @@ export function initTapClick(windowInstance, documentInstance, appInstance, conf
config = configInstance;
activator = (config.get('mdRipple') ? new RippleActivator(app, config) : new Activator(app, config));
isEnabled = (config.get('tapPolyfill') !== false);
isTapPolyfill = (config.get('tapPolyfill') === true);
addListener('click', click, true);
addListener('touchstart', touchStart);
addListener('touchend', touchEnd);
addListener('touchcancel', touchCancel);
if (isTapPolyfill) {
addListener('touchstart', touchStart);
addListener('touchend', touchEnd);
addListener('touchcancel', touchCancel);
}
addListener('mousedown', mouseDown, true);
addListener('mouseup', mouseUp, true);
@ -45,7 +47,7 @@ function touchStart(ev) {
function touchEnd(ev) {
touchAction();
if (isEnabled && startCoord && app.isEnabled()) {
if (startCoord && app.isEnabled()) {
let endCoord = pointerCoord(ev);
if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) {
@ -111,8 +113,8 @@ function pointerStart(ev) {
}
function pointerEnd(ev) {
activator.upAction();
moveListeners(false);
activator.upAction();
}
function pointerMove(ev) {
@ -131,16 +133,22 @@ function pointerCancel(ev) {
}
function moveListeners(shouldAdd) {
removeListener('touchmove', pointerMove);
if (isTapPolyfill) {
removeListener('touchmove', pointerMove);
}
removeListener('mousemove', pointerMove);
if (shouldAdd) {
addListener('touchmove', pointerMove);
if (isTapPolyfill) {
addListener('touchmove', pointerMove);
}
addListener('mousemove', pointerMove);
}
}
function setDisableNativeClick() {
disableNativeClickTime = Date.now() + disableNativeClickLimit;
if (isTapPolyfill) {
disableNativeClickTime = Date.now() + disableNativeClickLimit;
}
}
function isDisabledNativeClick() {
@ -161,6 +169,8 @@ function click(ev) {
console.debug('click prevent', preventReason);
ev.preventDefault();
ev.stopPropagation();
} else {
activator.upAction();
}
}

View File

@ -74,10 +74,12 @@ Platform.register({
scrollAssist: function(p) {
return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
},
tapPolyfill: function(p) {
return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
},
keyboardHeight: 290,
hoverCSS: false,
swipeBackEnabled: function(p) {
return true; // TODO: remove me! Force it to always work for iOS mode for now
return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
},
swipeBackThreshold: 40,