-
Notifications
You must be signed in to change notification settings - Fork 48
Expand file tree
/
Copy pathhero-glass.js
More file actions
101 lines (88 loc) · 2.76 KB
/
Copy pathhero-glass.js
File metadata and controls
101 lines (88 loc) · 2.76 KB
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
const root = document.documentElement;
const hero = document.querySelector("#hero");
const tiltTargets = document.querySelectorAll("[data-tilt]");
const floaters = document.querySelectorAll("[data-float]");
let frame;
let heroInView = true;
let heroRect = null;
let heroRectDirty = true;
const pointer = {
x: window.innerWidth / 2,
y: window.innerHeight / 2,
};
const scheduleUpdateScene = () => {
if (!frame) {
frame = requestAnimationFrame(updateScene);
}
};
const refreshHeroRect = () => {
if (!hero || !heroInView) return;
heroRect = hero.getBoundingClientRect();
heroRectDirty = false;
};
const updateScene = () => {
root.style.setProperty("--cursor-x", `${pointer.x}px`);
root.style.setProperty("--cursor-y", `${pointer.y}px`);
if (!hero || !heroInView) {
frame = null;
return;
}
if (heroRectDirty || !heroRect) {
refreshHeroRect();
}
const relX = (pointer.x - heroRect.left) / heroRect.width - 0.5;
const relY = (pointer.y - heroRect.top) / heroRect.height - 0.5;
hero.style.setProperty("--tilt-x", `${(-relY * 7).toFixed(2)}deg`);
hero.style.setProperty("--tilt-y", `${(relX * 9).toFixed(2)}deg`);
tiltTargets.forEach((target) => {
const rect = target.getBoundingClientRect();
const relX = (pointer.x - rect.left) / rect.width - 0.5;
const relY = (pointer.y - rect.top) / rect.height - 0.5;
target.style.setProperty("--tilt-x", `${(-relY * 6).toFixed(2)}deg`);
target.style.setProperty("--tilt-y", `${(relX * 6).toFixed(2)}deg`);
});
frame = null;
};
const handlePointer = (event) => {
pointer.x = event.clientX;
pointer.y = event.clientY;
heroInView && scheduleUpdateScene();
};
window.addEventListener("pointermove", handlePointer, { passive: true });
window.addEventListener("pointerdown", handlePointer, { passive: true });
window.addEventListener("pointerleave", () => {
pointer.x = window.innerWidth / 2;
pointer.y = window.innerHeight / 2;
scheduleUpdateScene();
});
window.addEventListener("resize", () => {
pointer.x = window.innerWidth / 2;
pointer.y = window.innerHeight / 2;
heroRectDirty = true;
scheduleUpdateScene();
}, { passive: true });
window.addEventListener("scroll", () => {
heroRectDirty = true;
}, { passive: true });
if(hero){
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
heroInView = entry.isIntersecting;
if (!heroInView) {
hero.style.setProperty("--tilt-x", "0deg");
hero.style.setProperty("--tilt-y", "0deg");
heroRect = null;
} else {
heroRectDirty = true;
}
scheduleUpdateScene();
});
},
{ threshold: 0.2 },
);
observer.observe(hero);
}
floaters.forEach((item, index) => {
item.style.animationDelay = `${index * -2.5}s`;
});