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={}) { constructor(ele, opts={}) {
this.reset(); this.reset();
this._opts = extend({ this._opts = extend({
renderDelay: 36 renderDelay: 16
}, opts); }, opts);
this.elements(ele); this.elements(ele);
@ -238,15 +238,31 @@ export class Animation {
// stage all animations and child animations at their starting point // stage all animations and child animations at their starting point
self.stage(); self.stage();
// synchronously call all onPlay()'s before play() let resolve;
self._onPlay(); let promise = new Promise(res => { resolve = res; });
function kickoff() {
// synchronously call all onPlay()'s before play()
self._onPlay();
return new Promise(resolve => {
beginPlay().then(() => { beginPlay().then(() => {
self._onFinish(); self._onFinish();
resolve(); 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 // 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 // lock in where the element will stop at
// if the playbackRate is negative then it needs to return // if the playbackRate is negative then it needs to return
// to its "from" effects // 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) { upAction(forceFadeOut) {
this.deactivate(); this.deactivate();
let ripple; let rippleId, ripple;
for (let rippleId in this.ripples) { for (rippleId in this.ripples) {
ripple = this.ripples[rippleId]; ripple = this.ripples[rippleId];
if (!ripple.fade || forceFadeOut) { if (!ripple.fade || forceFadeOut) {
// ripple has not been let up yet // ripple has not been let up yet
// speed up the rate if the animation is still going clearTimeout(ripple.fadeStart);
setTimeout(() => { ripple.fadeStart = setTimeout(() => {
// speed up the rate if the animation is still going
ripple.expand && ripple.expand.playbackRate(EXPAND_OUT_PLAYBACK_RATE); ripple.expand && ripple.expand.playbackRate(EXPAND_OUT_PLAYBACK_RATE);
ripple.fade = new Animation(ripple.ele); ripple.fade = new Animation(ripple.ele);
ripple.fade ripple.fade
@ -87,7 +88,7 @@ export class RippleActivator extends Activator {
}) })
.play(); .play();
}, 16); });
} }
} }
@ -95,15 +96,15 @@ export class RippleActivator extends Activator {
} }
next(forceComplete) { next(forceComplete) {
let ripple, rippleEle; let rippleId, ripple;
for (let rippleId in this.ripples) { for (rippleId in this.ripples) {
ripple = this.ripples[rippleId]; ripple = this.ripples[rippleId];
if ((ripple.expanded && ripple.faded && ripple.ele) || if ((ripple.expanded && ripple.faded && ripple.ele) || forceComplete) {
forceComplete || parseInt(rippleId) + 5000 < Date.now()) {
// finished expanding and the user has lifted the pointer // finished expanding and the user has lifted the pointer
ripple.remove = true;
raf(() => { raf(() => {
this.remove(rippleId); this.remove();
}); });
} }
} }
@ -114,14 +115,17 @@ export class RippleActivator extends Activator {
this.next(true); this.next(true);
} }
remove(rippleId) { remove() {
let ripple = this.ripples[rippleId]; let rippleId, ripple;
if (ripple) { for (rippleId in this.ripples) {
ripple.expand && ripple.expand.dispose(); ripple = this.ripples[rippleId];
ripple.fade && ripple.fade.dispose(); if (ripple.remove || parseInt(rippleId, 10) + 4000 < Date.now()) {
removeElement(ripple.ele); ripple.expand && ripple.expand.dispose();
ripple.ele = ripple.expand = ripple.fade = null; ripple.fade && ripple.fade.dispose();
delete this.ripples[rippleId]; 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 disableNativeClickTime = 0;
let disableNativeClickLimit = 1000; let disableNativeClickLimit = 1000;
let activator = null; let activator = null;
let isEnabled = false; let isTapPolyfill = false;
let app = null; let app = null;
let config = null; let config = null;
let win = null; let win = null;
@ -24,13 +24,15 @@ export function initTapClick(windowInstance, documentInstance, appInstance, conf
config = configInstance; config = configInstance;
activator = (config.get('mdRipple') ? new RippleActivator(app, config) : new Activator(app, config)); 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('click', click, true);
addListener('touchstart', touchStart); if (isTapPolyfill) {
addListener('touchend', touchEnd); addListener('touchstart', touchStart);
addListener('touchcancel', touchCancel); addListener('touchend', touchEnd);
addListener('touchcancel', touchCancel);
}
addListener('mousedown', mouseDown, true); addListener('mousedown', mouseDown, true);
addListener('mouseup', mouseUp, true); addListener('mouseup', mouseUp, true);
@ -45,7 +47,7 @@ function touchStart(ev) {
function touchEnd(ev) { function touchEnd(ev) {
touchAction(); touchAction();
if (isEnabled && startCoord && app.isEnabled()) { if (startCoord && app.isEnabled()) {
let endCoord = pointerCoord(ev); let endCoord = pointerCoord(ev);
if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) { if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) {
@ -111,8 +113,8 @@ function pointerStart(ev) {
} }
function pointerEnd(ev) { function pointerEnd(ev) {
activator.upAction();
moveListeners(false); moveListeners(false);
activator.upAction();
} }
function pointerMove(ev) { function pointerMove(ev) {
@ -131,16 +133,22 @@ function pointerCancel(ev) {
} }
function moveListeners(shouldAdd) { function moveListeners(shouldAdd) {
removeListener('touchmove', pointerMove); if (isTapPolyfill) {
removeListener('touchmove', pointerMove);
}
removeListener('mousemove', pointerMove); removeListener('mousemove', pointerMove);
if (shouldAdd) { if (shouldAdd) {
addListener('touchmove', pointerMove); if (isTapPolyfill) {
addListener('touchmove', pointerMove);
}
addListener('mousemove', pointerMove); addListener('mousemove', pointerMove);
} }
} }
function setDisableNativeClick() { function setDisableNativeClick() {
disableNativeClickTime = Date.now() + disableNativeClickLimit; if (isTapPolyfill) {
disableNativeClickTime = Date.now() + disableNativeClickLimit;
}
} }
function isDisabledNativeClick() { function isDisabledNativeClick() {
@ -161,6 +169,8 @@ function click(ev) {
console.debug('click prevent', preventReason); console.debug('click prevent', preventReason);
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
} else {
activator.upAction();
} }
} }

View File

@ -74,10 +74,12 @@ Platform.register({
scrollAssist: function(p) { scrollAssist: function(p) {
return /iphone|ipad|ipod/i.test(p.navigatorPlatform()); return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
}, },
tapPolyfill: function(p) {
return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
},
keyboardHeight: 290, keyboardHeight: 290,
hoverCSS: false, hoverCSS: false,
swipeBackEnabled: function(p) { 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()); return /iphone|ipad|ipod/i.test(p.navigatorPlatform());
}, },
swipeBackThreshold: 40, swipeBackThreshold: 40,