[interaction] 동영상 스크롤 감응 구현하기/requestAnimationFrame, setInterval 차이점과 장단점

임유정·2022년 12월 8일
0

Interaction

목록 보기
1/1
post-thumbnail
  • 스크롤에 따른 동영상 재생을 구현한다.

  • 옵션에 따라 재생 속도 및 프레임 조절한다.

원리 설명

// 비디오가 위치할 컨테이너와 비디오의 id 값을 전달받는 함수
  const registerVideo = (bound, video) => {
    // 컨테이너 DOM
    bound = document.querySelector(bound);
    // 비디오 DOM
    video = document.querySelector(video);

    const scrollVideo = ()=>{
      // video의 총 재생시간이 존재할 경우에만 이 로직을 실행시키겠다.
      if(video.duration) {
        // 각 영역의 시작지점 위치를 저장하는 변수 
        const distanceFromTop = window.scrollY + bound.getBoundingClientRect().top;
        // 스크롤 된 퍼센트 
        const rawPercentScrolled = (window.scrollY - distanceFromTop) / (bound.scrollHeight - window.innerHeight);
        // 스크롤 된 퍼센트가 최대 1의 값을 가지도록 변수에 저장
        // 영역이 2개 이상인 경우 스크롤 된 퍼센트가 1의 값을 넘어가는데, currentTime에 영상의 총 재생시간을 넘어서도록 할당하면 안되기 때문에 아래와 같은 코드 작성
        // Math.max는 전달한 값 중 가장 큰 값을 반환. Math.min은 전달한 값 중 가장 작은 값을 반환.
        const percentScrolled = Math.min(Math.max(rawPercentScrolled, 0), 1);
        // 비디오 currentTime에 비디오 총 재생시간 * 스크롤 된 퍼센트를 할당하여 비디오를 조작
        video.currentTime = video.duration * percentScrolled;
      }
      // requestAnimationFrame에 함수를 전달하면 프레임 생성에 맞춰서 함수를 실행한다.
      requestAnimationFrame(scrollVideo);
    }
    requestAnimationFrame(scrollVideo);
  }

  registerVideo("#bound-one", "#bound-one video");

  registerVideo("#bound-two", "#bound-two video")

  registerVideo("#bound-three", "#bound-three video")

requestAnimationFrame

requestAnimationFrame은 전달한 함수를 프레임 생성 초기 단계에 맞춰 실행시킵니다.

setInterval이나 setTimeout은 프레임을 신경쓰지 않고 동작하기 때문에, requestAnimationFrame을 사용함으로써 애니메이션을 더 부드럽게 동작시킬 수 있습니다.

requestAnimationFrame의 장점

페이지가 비활성 상태이면 페이지의 화면 그리기 작업도 브라우저에 의해 일시 중지되므로 브라우저를 따르는 requestAnimationFrame도 렌더링을 중지합니다. 이에 따라 CPU 리소스와 배터리 수명을 낭비하지 않게됩니다. (setInterval은 비활성 상태여도 백그라운드에서 계속 실행됨)

브라우저가 언제 업데이트를 할지 알게해줌으로써 프레임(frame) 손실을 방지해줌. 이에 따라 리소스도 균등하게 분배해서 사용할 수 있고, 간격도 균등하게 가져갈 수 있습니다.

옵션에 따른 재생 속도 조절

재생 속도 조절이라는 것은 사용자가 같은 길이의 스크롤을 움직였을 때, 동영상의 재생 속도가 다른 것으로 이해했습니다.

비디오의 컨테이너 height를 어느 정도로 설정하느냐에 따라 사용자가 같은 힘으로 스크롤링을 했을 때, 비디오 재생 속도를 조절할 수 있다고 생각했습니다.

.scroll-bound {
    /* height의 길이가 길어지수록 비디오를 재생하는데 많은 스크롤이 필요하다. */
    height: 200vh;
  }

trial and error 시행착오

  $(function() {
    const vid = $('#cat-vid')[0]; // cat-vid라는 id를 가진 DOM을(=비디오 객체) vid라는 변수에 저장함. (0번째 요소를 돔)

    // setInterval에는 두 개의 값을 전달한다. 첫 번째 값은 주기적으로 실행시킬 함수, 두 번째 값은 주기 시간. 주기 시간은 1000이 1초.
    // 0.023초마다 첫 번째로 전달한 함수를 실행한다.
    setInterval(function() {
      vid.currentTime = window.pageYOffset / 800;
      console.log(window.pageYOffset)

    }, 23);
  });

처음에는 위의 코드처럼 setInterval을 사용하여 문제를 해결하고자 하였습니다.

하지만 이번 기회에 애니메이션을 구현하기 위해서는 프레임 당 호출을 보장하는 requestAnimationFrame api를 사용하는 것이 더 부드러운 애니메이션을 구현하는 방법이라는 점을 알게 되었습니다.

결과

첫 번째 프레임 : 높이 500vh
두 번째 프레임 : 높이 300vh
세 번째 프레임 : 높이 200vh

높이에 따라 스크롤시에 동영상 속도가 달라지는 점을 알 수 있다.

Reference
http://www.donhkoland.com/clients/bluesmart/website/test/videoscroll/
https://velog.io/@0715yk/HTML-requestAnimationFrame
https://codepen.io/Maltsbier/pen/dyYmGGq

profile
console.log(youjung(🌼 , 🍣)); // true

0개의 댓글