/
gradient-text-reveal.js
100 lines (88 loc) · 3.21 KB
/
gradient-text-reveal.js
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Gradient Text Reveal
class TextReveal {
constructor(element) {
this.element = element;
this.child = this.element.firstElementChild;
this.revealValue = 0;
this.opacityValue = 0;
this.canReveal = this.canReveal.bind(this);
this.getRects = this.getRects.bind(this);
this.calculateRevealValue = this.calculateRevealValue.bind(this);
this.handleScroll = this.handleScroll.bind(this);
this.setupReveal = this.setupReveal.bind(this);
this.init();
}
canReveal() {
const { childRect } = this.getRects();
// Returns false if the child container is taller than the viewport.
return childRect.height <= window.innerHeight;
}
getRects() {
return {
rect: this.element.getBoundingClientRect(),
childRect: this.child.getBoundingClientRect()
};
}
calculateRevealValue() {
const { rect, childRect } = this.getRects();
if (!this.canReveal()) return 1;
// Calculate the intersection value based on the provided conditions
if (rect.top <= childRect.top && rect.bottom >= childRect.top) {
const totalHeightDifference = rect.height - childRect.height;
const currentHeightDifference = childRect.top - rect.top;
this.revealValue = currentHeightDifference / totalHeightDifference;
} else if (rect.bottom < childRect.top || Math.abs(childRect.top - rect.bottom) < 0.01) {
this.revealValue = 1;
} else {
this.revealValue = 0;
}
// Clamp the value between 0 and 1
this.revealValue = Math.max(0, Math.min(1, this.revealValue));
return this.revealValue;
}
handleScroll() {
this.revealValue = this.calculateRevealValue();
this.element.style.setProperty('--reveal-value', this.revealValue);
if (this.revealValue >= 0.3 && this.revealValue <= 0.7) {
this.opacityValue = 1;
} else if (this.revealValue >= 0.2 && this.revealValue < 0.3) {
this.opacityValue = 10 * (this.revealValue - 0.2);
} else if (this.revealValue > 0.7 && this.revealValue <= 0.8) {
this.opacityValue = 1 - 10 * (this.revealValue - 0.7);
} else {
this.opacityValue = 0;
}
this.element.style.setProperty('--opacity-value', this.opacityValue);
}
setupReveal() {
if (this.canReveal()) {
this.handleScroll();
window.addEventListener('scroll', this.handleScroll);
// Remove the inline styles if previously set
this.child.style.position = '';
this.child.style.top = '';
this.child.style.left = '';
this.child.style.transform = '';
this.element.style.height = '';
} else {
window.removeEventListener('scroll', this.handleScroll);
this.element.style.setProperty('--reveal-value', 0.5);
this.element.style.setProperty('--opacity-value', 1);
// Set some inline styles if the effect isn't doable
this.child.style.position = 'relative';
this.child.style.top = '0';
this.child.style.left = '0';
this.child.style.transform = 'translate3d(0,0,0)';
this.element.style.height = 'auto';
}
}
init() {
this.setupReveal();
window.addEventListener('resize', this.setupReveal);
}
}
// Init TextReveal
const els = document.querySelectorAll('[data-text-reveal]');
els.forEach((el) => {
new TextReveal(el);
});