inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

캔버스 드로우 애니메이션 2

검은색 영역 애니메이션이 움직이지 않습니다.

261

김창규

작성한 질문수 6

0

안녕하세요 강의 잘 듣고 있습니다. 제가 강의를 보면서 따라하던 도중 이상하게 검은색 박스는 생기지만 옆으로 움직이면서 서서히 사라지는 부분이 안 됌니다. 그런데 아무리 찾아보아도 문제의 원인을 모르겠습니다.(제가 변수의 이름을 제가 알기 쉽게 바꾼게 몇개 존재합니다.)

(() => {
  let yoffset = 0;
  let prevScrollHeight = 0;//이전 스크롤 섹션의 높이를 담음
  let currentScene = 0 //현재 활성화된 씬
  let enterScene = false;
  const sectionInfo = [
    //0
    {
      type : 'sticky',
      heightNum : 5,
      height : 0,
      objs : {
        section : document.querySelector('#scroll-section-1'),
        MessageA : document.querySelector('#scroll-section-1 .main-message.a'),
        MessageB : document.querySelector('#scroll-section-1 .main-message.b'),
        MessageC : document.querySelector('#scroll-section-1 .main-message.c'),
        MessageD : document.querySelector('#scroll-section-1 .main-message.d'),
        canvas : document.querySelector('#scroll-section-1 #first_canvas'),
        ctx : document.querySelector('#scroll-section-1 #first_canvas').getContext('2d'),
      },
      values : {
        //비디오 정보
        img_values : 300,
        img_obj : [],
        imgeSequence : [0,300],
        canvas_opacity : [1,0,{start : 0.9, end : 1}],
        //투명도 조절
        messageA_fade_in : [0,1,{start : 0.1, end : 0.2}],
        messageB_fade_in : [0,1,{start : 0.3, end : 0.4}],
        messageC_fade_in : [0,1,{start : 0.5, end : 0.6}],
        messageA_fade_out : [1,0,{start : 0.25, end : 0.3}],
        messageB_fade_out : [1,0,{start : 0.45, end : 0.5}],
        messageC_fade_out : [1,0,{start : 0.65, end : 0.7}],
        //transform 조절
        messageA_transform_in : [20,0,{start: 0.1, end : 0.2}],
        messageB_transform_in : [20,0,{start: 0.3, end : 0.4}],
        messageC_transform_in : [20,0,{start: 0.5, end : 0.6}],
        messageA_transform_out : [0,-20,{start: 0.25, end : 0.3}],
        messageB_transform_out : [0,-20,{start: 0.45, end : 0.5}],
        messageC_transform_out : [0,-20,{start: 0.65, end : 0.7}],
      }
    },
    //1
    {
      type : 'normal',
      heightNum : 5,
      height : 0,
      objs : {
        section : document.querySelector('#scroll-section-2'),
      },
      values : {

      }
    },
    //2
    {
      type : 'sticky',
      heightNum : 5,
      height : 0,
      objs : {
        section : document.querySelector('#scroll-section-3'),
        desc_messageA: document.querySelector('#scroll-section-3 .desc-message.a'),
        desc_messageB : document.querySelector('#scroll-section-3 .desc-message.b'),
        desc_messageC : document.querySelector('#scroll-section-3 .desc-message.c'),
        canvas : document.querySelector('#scroll-section-3 #second_canvas'),
        ctx : document.querySelector('#scroll-section-3 #second_canvas').getContext('2d'),
      },
      values : {
        img_values : 960,
        img_obj : [],
        imgeSequence : [0,960],
        canvas_fade_in : [0,1, {start : 0.05, end : 0.1}],
        canvas_fade_out : [1,0, {start : 0.9, end : 1}],
        //투명도
        desc_messageA_fade_in : [0 , 1, {start : 0.1, end : 0.2}],
        desc_messageB_fade_in : [0 , 1, {start : 0.3, end : 0.4}],
        desc_messageC_fade_in : [0 , 1, {start : 0.5, end : 0.6}],
        desc_messageA_fade_out : [1 , 0, {start : 0.25, end : 0.3}],
        desc_messageB_fade_out : [1 , 0, {start : 0.45, end : 0.5}],
        desc_messageC_fade_out : [1 , 0, {start : 0.65, end : 0.7}],
        //transform 조절
        desc_messageA_transform_in : [20,0,{start : 0.1, end : 0.2}],
        desc_messageB_transform_in : [20,0,{start : 0.3, end : 0.4}],
        desc_messageC_transform_in : [20,0,{start : 0.5, end : 0.6}],
        desc_messageA_transform_out : [0,-20,{start : 0.25, end : 0.3}],
        desc_messageB_transform_out : [0,-20,{start : 0.45, end : 0.5}],
        desc_messageC_transform_out : [0,-20,{start : 0.65, end : 0.7}],
      }
    },
    //3
    {
      type : 'sticky',
      heightNum : 5,
      height : 0,
      objs : {
        section : document.querySelector('#scroll-section-4'),
        mainMessageA : document.querySelector('mid-message.a'),
        canvas : document.querySelector('#third_canvas'),
        ctx : document.querySelector('#third_canvas').getContext('2d'),
      },
      values : {
        imgsrc : [
          './images/blend-image-1.jpg',
          './images/blend-image-2.jpg'
        ],
        discrimination : 0,
        img_obj : [],
        recet1X : [0,0, {start: 0, end: 0}],
        recet2X : [0,0, {start: 0, end: 0}],
        rectscrollY : 0,
      }
    }
  ]
  function setHeight() {
    yoffset = window.pageYOffset;
    let totalHeight = 0; //각 섹션별 높이를 전부 담는 변수
    const canvasRatio = window.innerHeight / 1080; //마지막 캔버스를 제외한 나머지 캔버스의 비율
    for(let i = 0; i < sectionInfo.length; i++){
      let sectionNum = sectionInfo[i];
      let calcHeight = 0;
      if( sectionNum.type === 'sticky' ){
        calcHeight = window.innerHeight *  sectionNum.heightNum;
        sectionNum.height = calcHeight;
        sectionNum.objs.section.style.height = `${calcHeight}px`
      }else{
        calcHeight = sectionInfo[i].objs.section.offsetHeight;
        sectionNum.height = calcHeight;
      }
      sectionNum.objs.section.style.height = `${calcHeight}px`
    }

    for(let i = 0; i < sectionInfo.length; i++){
      totalHeight += sectionInfo[i].height;
      if( totalHeight >=  window.pageYOffset){
        currentScene = i;
        break;
      }
    }
    

    sectionInfo[0].objs.canvas.style.transform = `translate3d(-50%,-50%,0) scale(${canvasRatio})`;
    sectionInfo[2].objs.canvas.style.transform = `translate3d(-50%,-50%,0) scale(${canvasRatio})`;
    document.body.id = `show-scene-${currentScene}`;
  }

  function setCanvasImage() {
    let imgElem;
    let imgElem2;
    let imgElem3;
    for (let i = 0; i < sectionInfo[0].values.img_values; i++){
      imgElem = new Image();
      imgElem.src = `./video/001/IMG_${6726 + i}.jpg`;
      sectionInfo[0].values.img_obj.push(imgElem);
    }

    for (let i = 0; i < sectionInfo[2].values.img_values; i++){
      imgElem2 = new Image();
      imgElem2.src = `./video/002/IMG_${7027 + i}.jpg`;
      sectionInfo[2].values.img_obj.push(imgElem2);
    }

    for (let i = 0; i < sectionInfo[3].values.imgsrc.length; i++){
      imgElem3 = new Image();
      imgElem3.src = sectionInfo[3].values.imgsrc[i];
      sectionInfo[3].values.img_obj.push(imgElem3);
    }
  } 
  setCanvasImage();


  function scrollLoop() {
    enterScene = false;
    prevScrollHeight = 0;
    for(let i = 0; i < currentScene; i++){
      prevScrollHeight += sectionInfo[i].height;
    }

    if(yoffset > prevScrollHeight + sectionInfo[currentScene].height){
      enterScene = true;
      currentScene++;
      document.body.id = `show-scene-${currentScene}`;
    }
    if ( yoffset < prevScrollHeight ){
      if(yoffset < 0) return;
      enterScene = true;
      currentScene--;
      document.body.id = `show-scene-${currentScene}`;
    }
    if ( enterScene ) return;
    playAnimation();
  }


  //애니메이션 처리 값과 현재 씬에서의 스크롤 비율을 넘겨받음
  function calcValues(values,currentYoffset){
    let rv;//값을 계산해 리턴해줄 변수
    const scrollHeight = sectionInfo[currentScene].height;
    const scrollRatio = currentYoffset / sectionInfo[currentScene].height;//현재씬의 스크롤 비율
    
    if ( values.length === 3 ){
      //start ~ end 사이의 애니메이션 실행
      const partScrollStart = values[2].start * scrollHeight;
      const partScrollEnd = values[2].end * scrollHeight;
      const partScrollHeight = partScrollEnd - partScrollStart;
      if( currentYoffset >= partScrollStart && currentYoffset <= partScrollEnd ){
        rv = (currentYoffset - partScrollStart) / partScrollHeight * (values[1] - values[0] ) + values[0];
      }else if(currentYoffset < partScrollStart){
        rv = values[0]
      }
      else if ( currentYoffset > partScrollEnd ){
        rv = values[1];
      }
    }else{
      rv = scrollRatio * (values[1] - values[0] ) + values[0];
    }



    return rv;
  }

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

    switch(currentScene){
      case 0:
       if ( scrollRatio <= 0.22 ){
        objs.MessageA.style.opacity = calcValues(values.messageA_fade_in,currentYoffset);
        objs.MessageA.style.transform = `translateY(${calcValues(values.messageA_transform_in,currentYoffset)}%)`;
       }
       else{
         objs.MessageA.style.opacity = calcValues(values.messageA_fade_out,currentYoffset);
         objs.MessageA.style.transform = `translateY(${calcValues(values.messageA_transform_out,currentYoffset)}%)`;
       }
       if(scrollRatio < 0.43){
          objs.MessageB.style.opacity = calcValues(values.messageB_fade_in,currentYoffset);
          objs.MessageB.style.transform = `translateY(${calcValues(values.messageB_transform_in,currentYoffset)}%)`;
       }else{
          objs.MessageB.style.opacity = calcValues(values.messageB_fade_out,currentYoffset);
          objs.MessageB.style.transform = `translateY(${calcValues(values.messageB_transform_out,currentYoffset)}%)`;
       }
       if( scrollRatio < 0.63 ){
          objs.MessageC.style.opacity = calcValues(values.messageC_fade_in,currentYoffset);
          objs.MessageC.style.transform = `translateY(${calcValues(values.messageC_transform_in,currentYoffset)}%)`;
       }else{
          objs.MessageC.style.opacity = calcValues(values.messageC_fade_out,currentYoffset);
          objs.MessageC.style.transform = `translateY(${calcValues(values.messageC_transform_out,currentYoffset)}%)`;
       }
       let imgeSequence = Math.floor(calcValues(sectionInfo[0].values.imgeSequence,currentYoffset));
       objs.ctx.drawImage(values.img_obj[imgeSequence],0,0);
       objs.canvas.style.opacity = calcValues(values.canvas_opacity,currentYoffset);
        break;
      case 1:
        break;
      case 2:
        if( scrollRatio <=  0.22 ){
         objs.desc_messageA.style.opacity = calcValues(values.desc_messageA_fade_in,currentYoffset);
         objs.desc_messageA.style.transform = `translate3d(-50%, ${calcValues(values.desc_messageA_transform_in,currentYoffset)}%, 0)`;
        }
        else{
          objs.desc_messageA.style.opacity = calcValues(values.desc_messageA_fade_out,currentYoffset);
          objs.desc_messageA.style.transform = `translate3d(-50%, ${calcValues(values.desc_messageA_transform_out,currentYoffset)}%, 0)`;
        }
        if ( scrollRatio < 0.42 ){
          objs.desc_messageB.style.opacity = calcValues(values.desc_messageB_fade_in,currentYoffset);
          objs.desc_messageB.style.transform = `translate3d(-50%, ${calcValues(values.desc_messageB_transform_in,currentYoffset)}%, 0)`;
        }else{
          objs.desc_messageB.style.opacity = calcValues(values.desc_messageB_fade_out,currentYoffset);
          objs.desc_messageB.style.transform = `translate3d(-50%, ${calcValues(values.desc_messageB_transform_out,currentYoffset)}%, 0)`;
        }
        if ( scrollRatio < 0.62 ){
          objs.desc_messageC.style.opacity = calcValues(values.desc_messageC_fade_in,currentYoffset);
          objs.desc_messageC.style.transform = `translate3d(-50%, ${calcValues(values.desc_messageC_transform_in,currentYoffset)}%, 0)`;
        }else{
          objs.desc_messageC.style.opacity = calcValues(values.desc_messageC_fade_out,currentYoffset);
          objs.desc_messageC.style.transform = `translate3d(-50%, ${calcValues(values.desc_messageC_transform_out,currentYoffset)}%, 0)`;
        }
        if(scrollRatio < 0.5){
          objs.canvas.style.opacity = calcValues(values.canvas_fade_in,currentYoffset);
        }else{
          objs.canvas.style.opacity = calcValues(values.canvas_fade_out,currentYoffset);
        }
        let imageSequence2 = Math.floor(calcValues(values.imgeSequence,currentYoffset));
        objs.ctx.drawImage(values.img_obj[imageSequence2],0,0);
        break;
      case 3:
        const widthRatio = window.innerWidth / objs.canvas.width;
        const heightRatio = window.innerHeight / objs.canvas.height;
        if ( widthRatio <= heightRatio ){
          objs.canvas.style.transform = `scale(${heightRatio})`;
        }else{
          objs.canvas.style.transform = `scale(${widthRatio})`;
        }
        const newWidth = document.body.offsetWidth / widthRatio//안쪽의 content영역의 width값을 구하기 위한 계산
        const newheight = window.innerHeight / heightRatio//안쪽의 content영역의 높이를 구하기 위한 계산
        const blockArea = newWidth * 0.15;
        values.recet1X[0] = (objs.canvas.width - newWidth) / 2; // 애니메이션 시작 지점을 계산
        values.recet1X[1] = values.recet1X[0] - blockArea;//애니메이션 끝 지점을 계산
        values.recet2X[0] = (values.recet1X[0] + newWidth) - blockArea; // 오른쪽 블록의 애니메이션 시작지점을 계산
        values.recet2X[1] = values.recet2X[1] + blockArea//오른쪽 애니메이션의 끝 지점을 지정
        if(!values.rectscrollY){
          values.rectscrollY = objs.canvas.getBoundingClientRect().top;
          values.recet1X[2].end = values.rectscrollY / scrollHeight;
          values.recet2X[2].end = values.rectscrollY / scrollHeight;
        }
        objs.ctx.fillRect(
					parseInt(calcValues(values.recet1X, currentYoffset)),
					0,
					parseInt(blockArea),
					objs.canvas.height
				);
				objs.ctx.fillRect(
					parseInt(calcValues(values.recet2X, currentYoffset)),
					0,
					parseInt(blockArea),
					objs.canvas.height
				);
        break;
    }
  }

  window.addEventListener('resize',setHeight);
  window.addEventListener('scroll',() => {
    yoffset = window.pageYOffset;
    scrollLoop()
  });
  window.addEventListener('load',() => {
    setHeight();
    sectionInfo[0].objs.ctx.drawImage(sectionInfo[0].values.img_obj[0],0,0);
    sectionInfo[3].objs.ctx.drawImage(sectionInfo[3].values.img_obj[0],0,0);
  });
})();

인터랙티브-웹 svg HTML/CSS javascript 웹 디자인 클론코딩

답변 0

이미지 배경 문의

0

81

1

[크로스브라우징] safari에서 동영상 영역 미노출

0

123

1

항상 궁금했는데 크림슨 컬러 선택하셨을때 활용했던 사이트 좀 알려주세요~

0

130

2

vue강의는안하시나요?!

0

125

1

스크롤 속도에 따른 messageA_opacity_out

0

130

1

drawImage(objs.videoImages[sequence], 0, 0); error

0

94

1

선생님 캔버스 width 크기는 이미지 크기에맞게 해줘야하나요?

0

138

0

선생님 안녕하세요. 혹시 메인개발(?)분야가 뭔지 궁금합니다.

0

219

1

React에서 load 상태를 어떻게 감지할 수 있을까요?

0

699

1

[섹션7-3: 버그수정 2] tempYOffset 오류

0

207

1

스크롤할 때 캔버스로 하신 이유가 있으신가요? 그냥 성능 떄문에 캔버스로 하신건가요?

0

327

2

게속 오류떠서 글 작성해봐요....

0

531

2

Vanilla JavaScript로 SPA 만드는 자료 혹은 선택 기준을 추천해주실 수 있으신가요?

1

500

1

특정 타이밍 스크롤 애니메이션 적용하기 섹션 수강중입니다.

0

464

2

[#svg, #이미지프레임과 텍스트 싱크] 스크롤 값에 움직이는 svg path, 이미지프레임과 텍스트 싱크 맞추는 것, 2가지 질문이 있습니다.

0

460

2

페이지가 처음 로딩 되었을 때 애니메이션 처리가 되지 않는 느낌입니다

0

444

1

섹션2 번째, opacity=0 되지 않고 잔상이 남습니다.

0

539

1

원래 쿼리셀렉터에서는 띄워쓰기 하면안되나요?

0

605

2

라이브러리 질문

1

419

2

translateY대신 애플에서 사용한 것 처럼 matrix로 scale의 크기를 주려고 하는데

0

416

1

[스크롤 높이 세팅] scrollHeight값이 3990아닌 4645로만 나오는데 뭐가 문제일까요? ㅠㅠ

0

607

2

scrollLoop 함수 질문

0

483

2

도메인 웹호스팅시 이미지가 안 뜨는데 누가 좀 알려주세요ㅠㅜ

0

1242

2

load 이벤트시 첫 비디오 이미지가 뜨네요.

0

512

2