inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

첫번째 스크롤 섹션 마무리

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

313

김창규

작성한 질문수 6

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);
  });
})()

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

답변 1

0

1분코딩

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

0

김창규

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

이미지 배경 문의

0

82

1

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

0

124

1

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

0

131

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

208

1

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

0

329

2

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

0

531

2

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

1

500

1

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

0

464

2

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

0

461

2

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

0

444

1

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

0

540

1

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

0

606

2

라이브러리 질문

1

421

2

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

0

416

1

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

0

607

2

scrollLoop 함수 질문

0

483

2

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

0

1242

2

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

0

513

2