vue 스크롤 애니메이션

해적왕·2023년 5월 28일
0
post-custom-banner

https://www.youtube.com/watch?v=Ud_hP2raTmk&t=935s
이미지 출처

<template>
  <div id="main">
    <div id="page" ref="page">
      <canvas ref="canvas"> </canvas>
    </div>
    <div id="page1">page 1</div>
    <div id="page2">page 2</div>
    <div id="page3">page 3</div>
  </div>
</template>
<script setup>
import { onMounted, ref } from "vue";

const page = ref(null);
const canvas = ref(null);
const frameCount = 300;
const img = new Image();
const currentFrame = (index) =>
  `../images/male${String(index + 1).padStart(4, "0")}.png`;

const updateImage = (context, index) => {
  img.src = currentFrame(index);
  img.onload = () => {
    const canvasWidth = canvas.value.width;
    const canvasHeight = canvas.value.height;
    const imageAspectRatio = img.width / img.height;
    const canvasAspectRatio = canvasWidth / canvasHeight;
    let drawWidth, drawHeight, drawX, drawY;

    if (imageAspectRatio > canvasAspectRatio) {
      drawWidth = canvasWidth;
      drawHeight = drawWidth / imageAspectRatio;
      drawX = 0;
      drawY = (canvasHeight - drawHeight) / 2;
    } else {
      drawHeight = canvasHeight;
      drawWidth = drawHeight * imageAspectRatio;
      drawX = (canvasWidth - drawWidth) / 2;
      drawY = 0;
    }

    context.clearRect(0, 0, canvasWidth, canvasHeight);
    context.drawImage(img, drawX, drawY, drawWidth, drawHeight);
  };
};

const resizeCanvas = (page) => {
  const canvasWidth = page.value.clientWidth;
  const imageAspectRatio = img.width / img.height;
  const canvasHeight = canvasWidth / imageAspectRatio;
  canvas.value.width = canvasWidth;
  canvas.value.height = canvasHeight;
};

onMounted(() => {
  const html = document.documentElement;
  const context = canvas.value.getContext("2d");

  updateImage(context,1)
  resizeCanvas(page);

  window.addEventListener("scroll", () => {
    const scrollTop = html.scrollTop;
    const maxScrollTop = html.scrollHeight - window.innerHeight;
    const scrollFraction = scrollTop / maxScrollTop;
    const frameIndex = Math.min(
      frameCount - 1,
      Math.ceil(scrollFraction * frameCount)
    );

    requestAnimationFrame(() => updateImage(context, frameIndex));
  });

  window.addEventListener("resize", function () {
    var delay = 300;
    var timer = null;
    clearTimeout(timer);
    timer = setTimeout(function () {
      const scrollTop = html.scrollTop;
      const maxScrollTop = html.scrollHeight - window.innerHeight;
      const scrollFraction = scrollTop / maxScrollTop;
      const frameIndex = Math.min(
      frameCount - 1,
      Math.ceil(scrollFraction * frameCount)
    );
    resizeCanvas(page);
    updateImage(context,frameIndex)
    }, delay);
  });
});
</script>
<style scoped>
#main {
  position: relative;
  width: 100%;
}

#page {
  position: relative;
  height: 100vh;
  width: 100%;
  background-color: #f1f1f1;
}

#page canvas{
  position: fixed;
  bottom:0;
  left: 0;
  height:auto;
  width:100%;
  z-index: 9999;
}

#page1 {
  position: relative;
  height: 100vh;
  width: 100vw;
  background-color: #f1f1f1;
}

#page2 {
  position: relative;
  height: 100vh;
  width: 100vw;
  background-color: #f1f1f1;
}

#page3 {
  position: relative;
  height: 100vh;
  width: 100vw;
  background-color: #f1f1f1;
}
</style>
profile
프론트엔드
post-custom-banner

0개의 댓글