인프런 커뮤니티 질문&답변

김창규님의 프로필 이미지
김창규

작성한 질문수

애플 웹사이트 인터랙션 클론!

첫번째 스크롤 섹션 마무리

강의에서 잠깐 나오는 desc 메시지 와 다르게 캔버스가 잠깐 보입니다..

작성

·

246

0

현제 제가 section-1에서 2로 넘어갈때 위 처럼 캔버스와 main텍스트가 번쩍 하고 보입니다. 둘다 opacity를 줘도 해결되지 않고 자바스크립트 문제인 것 같은데 어디가 문제인지 도저히 모르겠습니다.. 아래에 제 자바스크립트 코드입니다.

(() => {
  let yoffset = 0;//현재 스크롤된 높이
  let prevScrollHeight = 0; // 이전 씬의 총 높이
  let currentScene = 0;//현재 활성화된 씬
  const sceneInfo=[
    //0
    {
      type: 'sticky',
      scrollHeight: 0,
      heightNum: 5,
      objs: {
        container : document.querySelector('#scroll-section-0'),
        messageA: document.querySelector('#scroll-section-0 .main-message.a'),
        messageB: document.querySelector('#scroll-section-0 .main-message.b'),
        messageC: document.querySelector('#scroll-section-0 .main-message.c'),
        messageD: document.querySelector('#scroll-section-0 .main-message.d'),
        canvas: document.querySelector('#video-canvas-0'),
        context: document.querySelector('#video-canvas-0').getContext('2d'),
        videoImage: []
      },
      //모든 애니메이션 정보를 담음
      values:{
        //이미지의 갯수
        videoImageCount : 300,
        imageSequence: [0,299],
        //message A
        messageA_opacity_in : [0,1,{ start : 0.1, end: 0.2 }],
        messageA_opacity_out : [1,0,{ start : 0.25, end: 0.3 }],
        messageA_translate_in: [20,0, { start: 0.1,end: 0.2 }],
        messageA_translate_out: [0,-20, { start: 0.25,end: 0.3 }],
        //message B
        messageB_opacity_in : [0,1,{ start : 0.3, end: 0.4 }],
        messageB_opacity_out : [1,0,{ start : 0.45, end: 0.5 }],
        messageB_translate_in: [20,0, { start: 0.3,end: 0.4 }],
        messageB_translate_out: [0,-20, { start: 0.45,end: 0.5 }],
        //message C
        messageC_opacity_in : [0,1,{ start : 0.5, end: 0.6 }],
        messageC_opacity_out : [1,0,{ start : 0.65, end: 0.7 }],
        messageC_translate_in: [20,0, { start: 0.5,end: 0.6 }],
        messageC_translate_out: [0,-20, { start: 0.65,end: 0.7 }],
        //message D
        messageD_opacity_in : [0,1,{ start : 0.7, end: 0.8 }],
        messageD_opacity_out : [1,0,{ start : 0.85, end: 0.9 }],
        messageD_translate_in: [20,0, { start: 0.7,end: 0.8 }],
        messageD_translate_out: [0,-20, { start: 0.85,end: 0.9 }],
        //canvas_Opacity
        canvas_opacity : [1,0,{ start:0.9, end: 1 }],
      }
    },
    //1
    {
      type: 'normal',
      scrollHeight: 0,
      objs: {
        container : document.querySelector('#scroll-section-1'),
      }
    },
    //2
    {
      type: 'sticky',
      scrollHeight: 0,
      heightNum: 5,
      objs: {
        container : document.querySelector('#scroll-section-2'),
        messageA: document.querySelector('#scroll-section-2 .main-message.a'),
        messageB: document.querySelector('#scroll-section-2 .desc-message.b'),
        messageC: document.querySelector('#scroll-section-2 .desc-message.c'),
        pinB: document.querySelector('#scroll-section-2 .b .pin'),
        pinC: document.querySelector('#scroll-section-2 .c .pin'),
        canvas: document.querySelector('#video-canvas-1'),
        context: document.querySelector('#video-canvas-1').getContext('2d'),
        videoImage: []
      },
      values: {
        //이미지의 갯수
        videoImageCount : 960,
        imageSequence: [0,959],
        //messageA
        messageA_opacity_in: [0,1,{ start: 0.25, end: 0.3 }],
        messageA_opacity_out: [1,0,{ start: 0.4, end: 0.45 }],
        messageA_translate_in: [20,0,{ start: 0.15, end: 0.2 }],
        messageA_translate_out: [0,-20,{ start: 0.4, end: 0.45 }],
        //messageB
        messageB_opacity_in: [0,1,{ start: 0.6, end: 0.65 }],
        messageB_opacity_out: [1,0,{ start: 0.68, end: 0.73 }],
        messageB_translate_in: [30,0,{ start: 0.6, end: 0.65 }],
        messageB_translate_out: [0,-20,{ start: 0.68, end: 0.73 }],
        //messageC
        messageC_opacity_in: [0,1,{ start: 0.87, end: 0.92 }],
        messageC_opacity_out: [1,0,{ start: 0.95, end: 1 }],
        messageC_translate_in: [30,0,{ start: 0.87, end: 0.92 }],
        messageC_translate_out: [0,-20,{ start: 0.95, end: 1 }],
        //pin
        pinB_scaleY: [0.5, 1, { start: 0.6, end: 0.65 }],
        pinC_scaleY: [0.5, 1, { start: 0.87, end: 0.92 }],
        //canvas_Opacity
        canvas_opacity_in: [0, 1, { start: 0, end: 0.1 }],
				canvas_opacity_out: [1, 0, { start: 0.95, end: 1 }],
      },
    },
    //3
    {
      type: 'sticky',
      scrollHeight: 0,
      heightNum: 5,
      objs: {
        container : document.querySelector('#scroll-section-3'),
      }
    },
  ]

  function setCanvasImages(){
    let imgElem;
    let imgElem2;
    for(let i =0; i < sceneInfo[0].values.videoImageCount; i++){
      //이미지 객체 새성
      imgElem = new Image;
      imgElem.src = `./video/001/IMG_${6726 + i}.JPG`;
      sceneInfo[0].objs.videoImage.push(imgElem);
    }

    for(let i =0; i < sceneInfo[2].values.videoImageCount; i++){
        //이미지 객체 새성
        imgElem2 = new Image;
        imgElem2.src = `./video/002/IMG_${7027 + i}.JPG`;
        sceneInfo[2].objs.videoImage.push(imgElem2);
    }
  }
  setCanvasImages();

  function setLayout(){
    const heightRatio = window.innerHeight / 1080;
    
    //각 스크롤 섹션의 높이 세팅
    for(let i =0; i < sceneInfo.length; i++){
      if( sceneInfo[i].type === 'sticky' ){
        sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight;
      }else{
        sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.offsetHeight;
      }
      sceneInfo[i].objs.container.style.height = `${sceneInfo[i].scrollHeight}px`;
    }

    let totalScrollHeight = 0;
    yoffset = window.pageYOffset;

    for(let i =0; i < sceneInfo.length; i++){
      totalScrollHeight += sceneInfo[i].scrollHeight;
      if( totalScrollHeight >= yoffset ){
        currentScene = i;
        break;
      }
    }
    document.querySelector('body').id = `show-scene-${currentScene}`


    sceneInfo[0].objs.canvas.style.transform = `translate3d(-50%,-50%,0) scale(${heightRatio})`;
    sceneInfo[2].objs.canvas.style.transform = `translate3d(-50%,-50%,0) scale(${heightRatio})`;
  }


//values = 값 변화의 시작과 끝, 현재 씬의 높이 비율 currentYoffset = 현재 씬의 스크롤한 높이
//scrollRatio = 현재 씬의 스크롤 비율
  function calcValues(values,currnetYoffset){
    let rv;
    const scrollHeight = sceneInfo[currentScene].scrollHeight;
    let scrollRatio = currnetYoffset / scrollHeight;
    //start와 end의 원소가 있는 배열의 적용
    if( values.length === 3 ){
      const partScrollStart = values[2].start * scrollHeight;
      const partScrollEnd = values[2].end * scrollHeight;
      const partScrollHeight = partScrollEnd - partScrollStart;
      if( currnetYoffset >= partScrollStart && currnetYoffset <= partScrollEnd ){
        rv =  (currnetYoffset - partScrollStart)  / partScrollHeight * (values[1] - values[0]) + values[0];
      }else if( currnetYoffset < partScrollStart ){
        rv = values[0];
      }else if(currnetYoffset > partScrollEnd){
        rv = values[1];
      }
    }else{
      rv =  scrollRatio * (values[1] - values[0]) + values[0];
    }
    return rv;
  }


  function playAnimation(){
    const values = sceneInfo[currentScene].values;
    const objs = sceneInfo[currentScene].objs;
    const currnetYoffset = yoffset - prevScrollHeight;
    const scrollHeight = sceneInfo[currentScene].scrollHeight;
    const scrollRatio = currnetYoffset / scrollHeight;

    
    if( currnetYoffset < 0 ) return;
    switch (currentScene){
      case 0:
        let sequence = parseInt(calcValues(values.imageSequence,currnetYoffset));
        objs.context.drawImage(objs.videoImage[sequence],0,0);
        objs.canvas.style.opacity = calcValues(values.canvas_opacity,currnetYoffset);
        if( scrollRatio <= 0.22 ){
          objs.messageA.style.opacity = calcValues(values.messageA_opacity_in,currnetYoffset);
          objs.messageA.style.transform = `translateY(${calcValues(values.messageA_translate_in,currnetYoffset)}%)`;
        }else{
          objs.messageA.style.opacity = calcValues(values.messageA_opacity_out,currnetYoffset);
          objs.messageA.style.transform = `translateY(${calcValues(values.messageA_translate_out,currnetYoffset)}%)`;
        }

        if( scrollRatio <= 0.42 ){
          objs.messageB.style.opacity = calcValues(values.messageB_opacity_in,currnetYoffset);
          objs.messageB.style.transform = `translateY(${calcValues(values.messageB_translate_in,currnetYoffset)}%)`;
        }else{
          objs.messageB.style.opacity = calcValues(values.messageB_opacity_out,currnetYoffset);
          objs.messageB.style.transform = `translateY(${calcValues(values.messageB_translate_out,currnetYoffset)}%)`;
        }

        if( scrollRatio <= 0.62 ){
          objs.messageC.style.opacity = calcValues(values.messageC_opacity_in,currnetYoffset);
          objs.messageC.style.transform = `translateY(${calcValues(values.messageC_translate_in,currnetYoffset)}%)`;
        }else{
          objs.messageC.style.opacity = calcValues(values.messageC_opacity_out,currnetYoffset);
          objs.messageC.style.transform = `translateY(${calcValues(values.messageC_translate_out,currnetYoffset)}%)`;
        }

        if( scrollRatio <= 0.82 ){
          objs.messageD.style.opacity = calcValues(values.messageD_opacity_in,currnetYoffset);
          objs.messageD.style.transform = `translateY(${calcValues(values.messageD_translate_in,currnetYoffset)}%)`;
        }else{
          objs.messageD.style.opacity = calcValues(values.messageD_opacity_out,currnetYoffset);
          objs.messageD.style.transform = `translateY(${calcValues(values.messageD_translate_out,currnetYoffset)}%)`;
        }
        
        break;
      case 1:
        break;
      case 2:
        let sequence2 = parseInt(calcValues(values.imageSequence,currnetYoffset));
        objs.context.drawImage(objs.videoImage[sequence2],0,0);

				if (scrollRatio <= 0.5) {
					// in
					objs.canvas.style.opacity = calcValues(values.canvas_opacity_in, currnetYoffset);
				} else {
					// out
					objs.canvas.style.opacity = calcValues(values.canvas_opacity_out, currnetYoffset);
				}


        if( scrollRatio <= 0.32 ){
          objs.messageA.style.opacity = calcValues(values.messageA_opacity_in,currnetYoffset);
          objs.messageA.style.transform = `translateY(${calcValues(values.messageA_translate_in,currnetYoffset)}%)`;
        }else{
          objs.messageA.style.opacity = calcValues(values.messageA_opacity_out,currnetYoffset);
          objs.messageA.style.transform = `translateY(${calcValues(values.messageA_translate_out,currnetYoffset)}%)`;
        }

        if( scrollRatio <= 0.67 ){
          objs.messageB.style.opacity = calcValues(values.messageB_opacity_in,currnetYoffset);
          objs.messageB.style.transform = `translateY(${calcValues(values.messageB_translate_in,currnetYoffset)}%)`;
        }else{
          objs.messageB.style.opacity = calcValues(values.messageB_opacity_out,currnetYoffset);
          objs.messageB.style.transform = `translateY(${calcValues(values.messageB_translate_out,currnetYoffset)}%)`;
        }

        if( scrollRatio <= 0.93 ){
          objs.messageC.style.opacity = calcValues(values.messageC_opacity_in,currnetYoffset);
          objs.messageC.style.transform = `translateY(${calcValues(values.messageC_translate_in,currnetYoffset)}%)`;
        }else{
          objs.messageC.style.opacity = calcValues(values.messageC_opacity_out,currnetYoffset);
          objs.messageC.style.transform = `translateY(${calcValues(values.messageC_translate_out,currnetYoffset)}%)`;
        }
        break;
      case 3:

        break;
    }
  }

  function scrollLoop(){
    prevScrollHeight = 0;
      for(let i=0; i < currentScene; i++){
        prevScrollHeight += sceneInfo[i].scrollHeight; 
      }
      if( yoffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight){
        currentScene++;
        document.querySelector('body').id = `show-scene-${currentScene}`
      }
      if( yoffset < prevScrollHeight ){
        if( currentScene === 0 ) return;
        currentScene--;
        document.querySelector('body').id = `show-scene-${currentScene}`
      }
      
  }
//윈도우의 창 사이즈 변경시 다시 높이를 세팅함
  window.addEventListener('scroll',() => {
    yoffset = window.pageYOffset;
    scrollLoop();
    playAnimation();
  });
  window.addEventListener('resize',setLayout);
  window.addEventListener('load',  () => {
    setLayout();
    sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImage[0],0,0);
  });
})()

답변 1

0

1분코딩님의 프로필 이미지
1분코딩
지식공유자

씬이 바뀌는 순간 잠깐의 찰나에 계산이 적용이 안되는 부분때문에 그런건데요,
이후에 그 부분을 해결하는게 나온답니다. 강의를 정주행하다 보면 보실 수 있을거에요~

김창규님의 프로필 이미지
김창규
질문자

넵 계속 정주행 해보겠습니다!

김창규님의 프로필 이미지
김창규

작성한 질문수

질문하기