-
-
Save bobinska-dev/5fdf2342e989fc39db0521289f824c38 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "@kickstartds/core/lib/container-queries"; | |
import { Component, define } from "@kickstartds/core/lib/core"; | |
import { windowEvents } from "@kickstartds/core/lib/utils"; | |
const desktopImageOffsetAngle = 60; | |
const mobileImageOffsetAngle = 75; | |
const mobileOffsetRotateAngle = 45; | |
const backgroundRotateFactor = -0.25; | |
const maxBlur = 4; | |
const identifier = "enc.wheel"; | |
const rad = Math.PI / 180; | |
class Wheel extends Component { | |
static identifier = identifier; | |
constructor(element) { | |
super(element); | |
const scrollRoot = | |
element.closest('[data-testid="document-panel-scroller"]') || document; // sanity fix | |
const wheel = element.querySelector(".text-media__gallery"); | |
const images = wheel.querySelectorAll(".text-media__media"); | |
let magicFactor; | |
let wheelRadius; | |
let isSmallScreen; | |
let imageOffsetAngle; | |
function getScrollPosition() { | |
const coords = element.getBoundingClientRect(); | |
const height = coords.height - window.innerHeight; | |
return Math.min(1, Math.max(0, (-1 * coords.top) / height)); | |
} | |
function update() { | |
requestAnimationFrame(() => { | |
const scroll = getScrollPosition(); | |
const rotate = -360 * scroll * magicFactor; | |
wheel.style.setProperty( | |
"--c-wheel--rotate", | |
`${rotate * backgroundRotateFactor}deg` | |
); | |
images.forEach((image, index) => { | |
const angle = | |
rotate + | |
imageOffsetAngle * index + | |
(isSmallScreen ? mobileOffsetRotateAngle : 0); | |
const radians = angle * rad; | |
const x = Math.cos(radians) * wheelRadius; | |
const y = Math.sin(radians) * wheelRadius; | |
const scale = Math.max( | |
0, | |
1 - | |
Math.abs(angle - (isSmallScreen ? mobileOffsetRotateAngle : 0)) / | |
180 | |
); | |
image.style.transform = `translate(${x}px, ${y}px) scale(${scale})`; | |
image.style.filter = `blur(${(1 - scale) * maxBlur}px)`; | |
// image.style.zIndex = Math.floor(scale * images.length); | |
}); | |
}); | |
} | |
function init() { | |
isSmallScreen = element.offsetWidth < 640; | |
wheelRadius = isSmallScreen | |
? wheel.clientWidth / 1.5 | |
: wheel.clientWidth / 1.2; | |
imageOffsetAngle = isSmallScreen | |
? mobileImageOffsetAngle | |
: desktopImageOffsetAngle; | |
magicFactor = ((images.length - 1) * imageOffsetAngle) / 360; | |
update(); | |
} | |
let isActive = false; | |
const observer = new IntersectionObserver((entries) => { | |
let inViewport = false; | |
for (const entry of entries) { | |
inViewport = entry.isIntersecting; | |
} | |
if (inViewport && !isActive) { | |
init(); | |
scrollRoot.addEventListener("scroll", update, { | |
passive: true, | |
}); | |
} else if (!inViewport && isActive) { | |
scrollRoot.removeEventListener("scroll", update); | |
} | |
isActive = inViewport; | |
}); | |
observer.observe(element); | |
window.rm.radio.on(windowEvents.resize, init); | |
} | |
} | |
define(identifier, Wheel); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment