diff --git a/ionic/animations/animation.ts b/ionic/animations/animation.ts index 4a0bd81689..1549353008 100644 --- a/ionic/animations/animation.ts +++ b/ionic/animations/animation.ts @@ -408,6 +408,21 @@ export class Animation { } } + /** + * Get the current time of the first animation + * in the list. To get a specific time of an animation, call + * subAnimationInstance.getCurrentTime() + */ + getCurrentTime() { + if(this._chld.length > 0) { + return this._chld[0].getCurrentTime(); + } + if(this._ani.length > 0) { + return this._ani[0].getCurrentTime(); + } + return 0; + } + progressEnd(shouldComplete, rate=3) { let promises = []; @@ -604,6 +619,10 @@ class Animate { } } + getCurrentTime() { + return this.ani.currentTime; + } + playbackRate(value) { this.rate = value; if (this.ani) { diff --git a/ionic/components/tap-click/ripple.ts b/ionic/components/tap-click/ripple.ts index afdc03ec16..240de2d71a 100644 --- a/ionic/components/tap-click/ripple.ts +++ b/ionic/components/tap-click/ripple.ts @@ -4,6 +4,16 @@ import {Animation} from '../../animations/animation'; export class RippleActivator extends Activator { + static TOUCH_DOWN_ACCEL = 512; + static TOUCH_UP_ACCEL = 1024; + static OPACITY_DECAY_VEL = 1.6; + static OUTER_OPACITY_VEL = 1.2; + + static OPACITY_OUT_DURATION = 750; + + static EXPAND_OUT_PLAYBACK_RATE = 2; + static DOWN_PLAYBACK_RATE = 0.45; + static OPACITY_OUT_PLAYBACK_RATE = 1; constructor(app, config) { super(app, config); @@ -17,6 +27,18 @@ export class RippleActivator extends Activator { // create a new ripple element let r = targetEle.getBoundingClientRect(); + let w = r.width; + let h = r.height; + + let halfW = w/2; + let halfH = h/2; + let outerRadius = Math.sqrt(halfW * halfW + halfH * halfH); + + let radiusDuration = (1000 * Math.sqrt(outerRadius / RippleActivator.TOUCH_DOWN_ACCEL) + 0.5); + let outerDuration = 1000 * (1/RippleActivator.OUTER_OPACITY_VEL); + + //console.log('Rippling', radiusDuration); + let x = Math.max(Math.abs(r.width - pointerX), pointerX) * 2; let y = Math.max(Math.abs(r.height - pointerY), pointerY) * 2; let size = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))) - 10; @@ -33,14 +55,16 @@ export class RippleActivator extends Activator { targetEle.appendChild(rippleEle); let ripple = this.ripples[Date.now()] = { ele: rippleEle }; + ripple.outerRadius = outerRadius; + ripple.radiusDuration = radiusDuration; // expand the circle from the users starting point // start slow, and when they let up, then speed up the animation ripple.expand = new Animation(rippleEle, {renderDelay: 0}); ripple.expand .fromTo('scale', '0.001', '1') - .duration(300) - .playbackRate(0.35) + .duration(radiusDuration) + .playbackRate(RippleActivator.DOWN_PLAYBACK_RATE) .onFinish(()=> { // finished expanding ripple.expand && ripple.expand.dispose(); @@ -59,16 +83,26 @@ export class RippleActivator extends Activator { let ripple; for (let rippleId in this.ripples) { ripple = this.ripples[rippleId]; + if(ripple.expand) { + let currentTime = ripple.expand.getCurrentTime(); + + // How much more time do we need to finish the radius animation? + // Math: (radius/second) * ((total_radius_time) - current_time) + let remainingTime = (ripple.outerRadius / ripple.radiusDuration) * + ((ripple.radiusDuration / RippleActivator.DOWN_PLAYBACK_RATE)- (currentTime)); + ripple.expand.remainingTime = remainingTime; + } if (!ripple.fade) { // ripple has not been let up yet // spped up the rate if the animation is still going setTimeout(() => { - ripple.expand && ripple.expand.playbackRate(1); + ripple.expand && ripple.expand.playbackRate(RippleActivator.EXPAND_OUT_PLAYBACK_RATE); ripple.fade = new Animation(ripple.ele); ripple.fade .fadeOut() - .duration(750) + .duration(ripple.epxand && ripple.expand.remaingTime || RippleActivator.OPACITY_OUT_DURATION) + .playbackRate(RippleActivator.OPACITY_OUT_PLAYBACK_RATE) .onFinish(() => { ripple.fade && ripple.fade.dispose(); ripple.fade = null;