EchoForum/src/comp/fx/perspectivefx.svelte
2024-05-11 00:59:50 +03:00

80 lines
2.0 KiB
Svelte

<script>
/**
* @type {number}
*/
export let maxRotation = 1.5;
/**
* @type {number}
*/
export let translateZ = 5;
/** @type {Element} */
let element;
let mouseX = 0;
let mouseY = 0;
function updateMousePosition() {
const rect = element.getBoundingClientRect();
const y = mouseY - rect.top;
const x = mouseX - rect.left;
const mulForX = Math.max(rect.height / rect.width, 1.0);
const mulForY = Math.max(rect.width / rect.height, 1.0);
const bound = Math.max(rect.height, rect.width);
const rotation = maxRotation / bound * 200;
element.setAttribute('style', `--max-rotation: ${maxRotation}; --translate-z: ${translateZ}px; --cur-x: ${(-x / rect.width + 0.5) * rotation * mulForX}deg; --cur-y: ${(y / rect.height - 0.5) * rotation * mulForY}deg;`)
}
function mouseEnterRegion(/** @type {MouseEvent} */ event) {
element.setAttribute('transform', '');
}
function mouseMove(/** @type {MouseEvent} */ event) {
mouseX = event.clientX;
mouseY = event.clientY;
updateMousePosition();
}
function mouseLeaveRegion(/** @type {MouseEvent} */ event) {
element.removeAttribute('transform');
}
</script>
<style>
.perspectiveFx {
position: relative;
transform: perspective(180px) translateZ(0px);
transition: 0.2s;
transition-property: transform;
& > .subPerspectiveFx {
transform: perspective(180px) rotateX(0deg) rotateY(0deg);
}
&[transform] {
transform: perspective(180px) translateZ(var(--translate-z));
& > .subPerspectiveFx {
transform: perspective(180px) rotateX(var(--cur-y)) rotateY(var(--cur-x));
}
}
}
</style>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="perspectiveFx" bind:this={element} on:mouseenter={mouseEnterRegion} on:mousemove={mouseMove} on:mouseleave={mouseLeaveRegion} {...$$restProps}>
<div class="subPerspectiveFx">
<slot />
</div>
</div>
<svelte:window on:resize={updateMousePosition}></svelte:window>