80 lines
2.0 KiB
Svelte
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>
|