2024-08-10 00:00:26 +02:00
|
|
|
function setViewportOffset(viewport) {
|
|
|
|
// Calculate the distance from the top of the element to the center of the screen.
|
|
|
|
// This is an accurate rendering, but we might want to change it for artistic effects.
|
|
|
|
const windowHeight = window.innerHeight;
|
2024-11-12 00:32:53 +01:00
|
|
|
const viewportRect = viewport.getBoundingClientRect();
|
|
|
|
if (viewportRect.top > windowHeight || viewportRect.bottom < 0) {
|
2024-08-10 00:00:26 +02:00
|
|
|
return;
|
|
|
|
}
|
2024-11-12 00:32:53 +01:00
|
|
|
const documentRect = document.documentElement.getBoundingClientRect();
|
|
|
|
/*
|
|
|
|
If the the bounds of a viewport element is close to the top or bottom
|
|
|
|
of the page the perspective origin is adjusted so that it is still
|
|
|
|
contained inside of the bounds of the element to not look out of place.
|
|
|
|
This controls how much into the bounds the perspective origin should be
|
|
|
|
pushed when the screen in scrolled all the way to the top/bottom.
|
|
|
|
*/
|
|
|
|
const endOffset = viewportRect.height * 0.25;
|
|
|
|
const origin = Math.min(
|
|
|
|
(viewportRect.bottom - documentRect.top) - endOffset,
|
|
|
|
Math.max(
|
|
|
|
windowHeight / 2,
|
|
|
|
windowHeight - (documentRect.bottom - viewportRect.top) + endOffset,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
const yOffset = origin - viewportRect.top;
|
|
|
|
viewport.style.setProperty('--y-offset', yOffset + "px");
|
2024-08-10 00:00:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const viewports = document.querySelectorAll(".viewport");
|
|
|
|
function updateViewports() {
|
|
|
|
for (const viewport of viewports) {
|
|
|
|
setViewportOffset(viewport);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
window.addEventListener("scroll", updateViewports, { passive: true });
|
|
|
|
window.addEventListener("resize", updateViewports, { passive: true });
|
|
|
|
updateViewports();
|