본문 바로가기
  • search_ _ _ _
  • search_ _ _ _
  • search_ _ _ _
JavaScript &jQuery

[JavaScript] 스크롤 애니메이션 (Apple 제품 페이지)

by 오늘의갈비찜 2024. 6. 13.
728x90

1. html

- canvas 태그 생성

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>canvas test</title>
    </head>
    <body>
        <canvas></canvas>
    </body>
</html>

 

2. css

 

- 스크롤시  호출되는 이미지는 화면의 중앙에 위치 해야하므로 fixed사용

body{
    width: 100vw;
    height: 500vh;
    background-color: #000;
}

canvas{
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    max-width: 50vw;
    max-height: 50vh;
}

 

3. javascript_1

const canvas = document.querySelector("canvas"); 
const context = canvas.getContext("2d"); 
//- HTMLCanvasElement.getContext() 메소드는 캔버스의 드로잉 컨텍스트를 반환


canvas.width=1158;  
canvas.height=770; //canvas 사이즈 지정




let currentFrame = index => (
  `https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`
)
//- toString() 메서드는 문자열로 반환
//- padStart() 메서드는 주어진 길이를 만족하는 새로운 문자열을 반환 
// 0001.jpg, 0002.jpg, 0003.jpg ...


// Draw the first image
let img = new Image() //image객체 생성
img.src = currentFrame(1); //0001.jpg
img.onload=function(){   
  context.drawImage(img, 0, 0);
  //CanvasRenderingContext2D.drawImage() 캔버스에 이미지를 그림
  //drawImage(image, x, y, Width, Height)
}
// 웹 페이지가 로딩되었을 때 원하는 함수, 코드를 호출하는 window.onload 콜백함수
// window.onload = function() { }



//이미지는 미리 로드 하면 좋음(스크롤 이벤트 안에 위치해도 작동됨)
  let frameCount = 148; //총 페이지 수
  let preloadImages = () => {
    for (let i = 1; i < frameCount; i++) { //for문
      const img = new Image();  //로드시 새롭게 객체 생성
      img.src = currentFrame(i);  
    }
  };
  preloadImages();


//스크롤시 
window.addEventListener('scroll', () => {  
  const html = document.documentElement;
  const scrollEvent = html.scrollTop / (html.scrollHeight - window.innerHeight);
  // html.scrollTop : 페이지 최상단 값 (시작점)
  
  // html.scrollHeight - window.innerHeight : 스크롤 포함 전체페이지 높이 - 보이는 화면 높이 = 아래로 스크롤 할 수있는 최대 값
  
  // html.scrollTop / (html.scrollHeight - window.innerHeight) : 아래로 스크롤 할 수있는 최대 값을 시작점으로 나눠 현재 진행 위치



  //해당 스크롤 진행 상황을 이미지 번호 매기기 위해 
  //순서에 해당하는 인덱스 번호로 바꿔야 한다.
  let frameIndex = Math.min( 
  //Math.min() 주어진 숫자들 중 가장 작은 값을 반환 , 프레임 수를 초과방지
    frameCount - 1,            //총페이지 - 처음 시작페이지
    Math.floor(scrollEvent * frameCount)  
  );
  //Math.floor() 반올림 , 현재위치와 페이지값을 곱 = 진행률
  
  
  
  //이미지를 업데이트하기 위해 전달하는 콜백 함수
  let updateImage = index => {
    img.src = currentFrame(index);
    context.drawImage(img, 0, 0);
  }
  
  
  requestAnimationFrame(() => updateImage(frameIndex + 1))
  //스크롤할 때 이미지를 교체
  //window.requestAnimationFrame() 메서드는 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 리페인트 바로 전에 브라우저가 애니메이션을 업데이트할 지정된 함수를 호출하도록 요청이 메서드는 리페인트 이전에 호출할 인수로 콜백을 받습니다.

  //0001.jpg에서 시작하는 동안 스크롤 진행률 계산은 실제로 0에서 시작하기 때문에 1을 더한다.

});

 

 

 

 

 

 

4. javascript_2

 -  img.src = currentFrame(index)에서  updateImag 함수가 인식안되고 무시되는 현상

 -  updateImage 함수 삭제 

const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');

canvas.width=1158;
canvas.height=770;

const currentFrame = index => (
  `https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`
)

// Draw the first image
let img = new Image();
img.src = currentFrame(1);
img.onload = function(){
    context.drawImage(img, 0, 0);
}




let frameCount = 148; 
let images = [];   //-------------임의 배열
let preloadImages = () => {
    for (let i = 1; i < frameCount; i++) {
        images[i] = new Image(); 
        images[i].src = currentFrame(i);
    }
};
preloadImages(); //-------------배열에 객체를 담고 새롭게 그린다.





window.addEventListener('scroll', () => {  
    const html = document.documentElement;
    const scrollEvent = html.scrollTop / (html.scrollHeight - window.innerHeight)
    let frameIndex = Math.min(
        frameCount - 1,
        Math.floor(scrollEvent * frameCount)
    );
   
    requestAnimationFrame(() => context.drawImage(images[frameIndex + 1], 0, 0));
});

 

 

 

비디오 플레이 스크롤 애니메이션:

https://codepen.io/Maltsbier/pen/dyYmGGq

 

Play Video On Scroll

...

codepen.io

 

 

 

 

 

 

 

참고:  

https://odada.me/155

 

Apple 제품 페이지 스크롤 애니메이션

Apple은 제품 페이지의 세련된 애니메이션으로 유명합니다. 예를 들어, 페이지를 아래로 스크롤하면 제품이보기에 들어가고, MacBook은 접 히고 iPhone은 회전하면서 하드웨어를 과시하고 소프트웨

odada.me

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage

 

CanvasRenderingContext2D: drawImage() method - Web APIs | MDN

The CanvasRenderingContext2D.drawImage() method of the Canvas 2D API provides different ways to draw an image onto the canvas.

developer.mozilla.org

 

728x90