mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
141 lines
4.0 KiB
TypeScript
141 lines
4.0 KiB
TypeScript
import {Activator} from './activator';
|
|
import {removeElement, raf} from '../../util/dom';
|
|
import {Animation} from '../../animations/animation';
|
|
|
|
|
|
export class RippleActivator extends Activator {
|
|
|
|
constructor(app, config) {
|
|
super(app, config);
|
|
this.ripples = {};
|
|
}
|
|
|
|
downAction(ev, activatableEle, pointerX, pointerY) {
|
|
|
|
if (this.disableActivated(ev)) return;
|
|
|
|
super.downAction(ev, activatableEle, pointerX, pointerY);
|
|
|
|
// create a new ripple element
|
|
let r = activatableEle.getBoundingClientRect();
|
|
|
|
let outerRadius = Math.sqrt(r.width + r.height);
|
|
let radiusDuration = (1000 * Math.sqrt(outerRadius / TOUCH_DOWN_ACCEL) + 0.5);
|
|
|
|
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;
|
|
|
|
let rippleEle = document.createElement('md-ripple');
|
|
let eleStyle = rippleEle.style;
|
|
eleStyle.width = eleStyle.height = size + 'px';
|
|
eleStyle.marginTop = eleStyle.marginLeft = -(size / 2) + 'px';
|
|
eleStyle.left = (pointerX - r.left) + 'px';
|
|
eleStyle.top = (pointerY - r.top) + 'px';
|
|
|
|
activatableEle.appendChild(rippleEle);
|
|
|
|
let ripple = this.ripples[Date.now()] = {
|
|
ele: rippleEle,
|
|
outerRadius: outerRadius,
|
|
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(radiusDuration)
|
|
.playbackRate(DOWN_PLAYBACK_RATE)
|
|
.onFinish(()=> {
|
|
// finished expanding
|
|
ripple.expand && ripple.expand.dispose();
|
|
ripple.expand = null;
|
|
ripple.expanded = true;
|
|
this.next();
|
|
})
|
|
.play();
|
|
|
|
this.next();
|
|
}
|
|
|
|
upAction() {
|
|
this.deactivate();
|
|
|
|
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)
|
|
ripple.expand.remainingTime = (ripple.outerRadius / ripple.radiusDuration) *
|
|
((ripple.radiusDuration / DOWN_PLAYBACK_RATE) - (currentTime));
|
|
}
|
|
|
|
if (!ripple.fade) {
|
|
// ripple has not been let up yet
|
|
// speed up the rate if the animation is still going
|
|
setTimeout(() => {
|
|
ripple.expand && ripple.expand.playbackRate(EXPAND_OUT_PLAYBACK_RATE);
|
|
ripple.fade = new Animation(ripple.ele);
|
|
ripple.fade
|
|
.fadeOut()
|
|
.duration(ripple.epxand && ripple.expand.remaingTime || OPACITY_OUT_DURATION)
|
|
.playbackRate(1)
|
|
.onFinish(() => {
|
|
ripple.fade && ripple.fade.dispose();
|
|
ripple.fade = null;
|
|
ripple.faded = true;
|
|
this.next();
|
|
})
|
|
.play();
|
|
|
|
}, 16);
|
|
}
|
|
}
|
|
|
|
this.next();
|
|
}
|
|
|
|
next(forceComplete) {
|
|
let ripple, rippleEle;
|
|
for (let rippleId in this.ripples) {
|
|
ripple = this.ripples[rippleId];
|
|
|
|
if ((ripple.expanded && ripple.faded && ripple.ele) ||
|
|
forceComplete ||
|
|
parseInt(rippleId) + 5000 < Date.now()) {
|
|
// finished expanding and the user has lifted the pointer
|
|
raf(() => {
|
|
this.remove(rippleId);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
clearState() {
|
|
this.deactivate();
|
|
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];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
const TOUCH_DOWN_ACCEL = 512;
|
|
const OPACITY_OUT_DURATION = 750;
|
|
const EXPAND_OUT_PLAYBACK_RATE = 3.5;
|
|
const DOWN_PLAYBACK_RATE = 0.65;
|