From 78d3f5667245f3f7ced0db22afa4a59fd9bb5c2e Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Tue, 12 Nov 2024 00:32:53 +0100 Subject: [PATCH] Adjust perspective origin if viewport is near vertical edges If the origin is set to the center of the screen for a small 3d element that's near the top or bottom, then it looks out of place and can't be scrolled to fit nicely in view. Adjust the origin to stay inside the bounds of the viewport when scrolled to the edge of the screen in this case. --- web/viewport.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/web/viewport.js b/web/viewport.js index 29030d5..5bf20e5 100644 --- a/web/viewport.js +++ b/web/viewport.js @@ -2,12 +2,28 @@ 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; - const rect = viewport.getBoundingClientRect(); - if (rect.top > windowHeight || rect.bottom < 0) { + const viewportRect = viewport.getBoundingClientRect(); + if (viewportRect.top > windowHeight || viewportRect.bottom < 0) { return; } - const yOffset = windowHeight / 2 - rect.top; - viewport.style.setProperty('--y-offset', yOffset+"px"); + 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"); } const viewports = document.querySelectorAll(".viewport");