forked from Dogfalo/materialize
-
-
Notifications
You must be signed in to change notification settings - Fork 106
/
Copy pathwaves.ts
70 lines (61 loc) · 2.31 KB
/
waves.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
type RGBColor = {
r: number,
g: number,
b: number,
}
type Position = {
x: number,
y: number,
}
export class Waves {
private static _offset(el: HTMLElement) {
const box = el.getBoundingClientRect();
const docElem = document.documentElement;
return {
top: box.top + window.pageYOffset - docElem.clientTop,
left: box.left + window.pageXOffset - docElem.clientLeft
};
}
// https://phoenix-dx.com/css-techniques-for-material-ripple-effect/
public static renderWaveEffect(targetElement: HTMLElement, position: Position|null = null, color: RGBColor|null = null): void {
const isCentered = position === null;
const duration = 500;
let animationFrame: number, animationStart: number;
const animationStep = function(timestamp: number) {
if (!animationStart) {
animationStart = timestamp;
}
const frame = timestamp - animationStart;
if (frame < duration) {
const easing = (frame/duration) * (2 - (frame/duration));
const circle = isCentered ? 'circle at 50% 50%' : `circle at ${position.x}px ${position.y}px`;
const waveColor = `rgba(${color?.r || 0}, ${color?.g || 0}, ${color?.b || 0}, ${ 0.3 * (1-easing) })`;
const stop = 90 * easing + "%";
targetElement.style.backgroundImage = "radial-gradient("+circle+", "+waveColor+" "+stop+", transparent "+stop+")";
animationFrame = window.requestAnimationFrame(animationStep);
}
else {
targetElement.style.backgroundImage = 'none';
window.cancelAnimationFrame(animationFrame);
}
};
animationFrame = window.requestAnimationFrame(animationStep);
}
static Init() {
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener('click', e => {
const trigger = <HTMLElement>e.target;
const el = <HTMLElement>trigger.closest('.waves-effect');
if (el && el.contains(trigger)) {
const isCircular = el.classList.contains('waves-circle');
const x = e.pageX - Waves._offset(el).left;
const y = e.pageY - Waves._offset(el).top;
let color = null;
if (el.classList.contains('waves-light'))
color = {r:255, g:255, b:255};
Waves.renderWaveEffect(el, isCircular ? null : {x, y}, color);
}
});
});
}
}