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

대림대님의 프로필 이미지
대림대

작성한 질문수

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

두 가지 에러들 해결방법을 모르겠습니다 ㅜ

작성

·

154

0

안녕하세요. 강의 잘 듣고있습니다 !

그런데 콘솔창에 아래 이미지 처럼 에러가 떠서 질문 드립니다.

스크롤을 내릴때는 뜨지 않다가 전부 다 내리고 다시 올려보면 저렇게 에러가 뜹니다. 작동은 됩니다.. (스크롤 비디오 처리 부분)

혹시 빼먹은게 있나 강의도 여러번 다시 보았는데 해결이 나지 않아서 질문 드립니다 ..ㅜㅜ

-----

그리고 또 한가지가 있는데,  show scene1 에서 show scene2로 넘어갈때 아래 이미지가 잠깐 뜨고 사라집니다.

 

강의에서는 저와 다른 텍스트만 잠깐 뜨고 사라져서 css에서 수정하는것을 보았는데 저의 경우에는 위의 이미지처럼 저 텍스트와 이미지가 잠깐 떴다가 사라져서 이것도 해결책을 잘 모르겠습니다ㅠ

완성본에서는 콘솔창에 에러 뜨는 현상도 전혀 없고 잘 작동 됩니다.

제 코드에 문제가 있는건데 html과 css에는 문제가 없는거 같습니다..  (완성본에 적용해보았습니다)

강의는 두번째 스크롤 비디오 처리까지 들었습니다!

-----

아래는 현재 제 코드입니다.

(()=>{

    let yOffset = 0// window.pageYOffset 대신 쓸 변수
    let prevScrollHeight = 0// 현재 스크롤 위치(yoffset)보다 이전에 위치한 스크롤 섹션들의 스크롤 높이 값의 합
    let currentScene = 0// 현재 활성화된(눈 앞에 보고 있는) 씬(scroll-section)

    const sceneInfo = [
        {
            // 0
            type: 'sticky',
            heightNum: 5// 브라우저 높이의 5배로 scrollHeight 세팅
            scrollHeight: 0,
            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'),
                videoImages: []
            },
            values: {
                videoImagesCount: 300,
                imageSequence: [0299],
                canvas_opacity: [10, { start: 0.9, end: 1}],
                messageA_opacity_in: [01, { start: 0.1, end: 0.2 }],
                messageB_opacity_in: [01, { start: 0.3, end: 0.4 }],
                messageC_opacity_in: [01, { start: 0.5, end: 0.6 }],
                messageD_opacity_in: [01, { start: 0.7, end: 0.8 }],
                messageA_translateY_in: [200, { start: 0.1, end: 0.2 }],
                messageB_translateY_in: [200, { start: 0.3, end: 0.4 }],
                messageC_translateY_in: [200, { start: 0.5, end: 0.6 }],
                messageD_translateY_in: [200, { start: 0.7, end: 0.8 }],
                messageA_opacity_out: [10, { start: 0.25, end: 0.3 }],
                messageB_opacity_out: [10, { start: 0.45, end: 0.5 }],
                messageC_opacity_out: [10, { start: 0.65, end: 0.7 }],
                messageD_opacity_out: [10, { start: 0.85, end: 0.9 }],
                messageA_translateY_out: [0-20, { start: 0.25, end: 0.3 }],
                messageB_translateY_out: [0-20, { start: 0.45, end: 0.5 }],
                messageC_translateY_out: [0-20, { start: 0.65, end: 0.7 }],
                messageD_translateY_out: [0-20, { start: 0.85, end: 0.9 }]
            }
        },
        {
            // 1
            type: 'normal',
            // heightNum: 5, // type normal에서는 필요 없음
            scrollHeight: 0,
            objs: {
                container: document.querySelector('#scroll-section-1')
            }
        },
        {
            // 2
            type: 'sticky',
            heightNum: 5,
            scrollHeight: 0,
            objs: {
                container: document.querySelector('#scroll-section-2'),
                messageA: document.querySelector('#scroll-section-2 .a'),
                messageB: document.querySelector('#scroll-section-2 .b'),
                messageC: document.querySelector('#scroll-section-2 .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'),
                videoImages: []
            },
            values: {
                videoImagesCount: 960,
                imageSequence: [0959],
                canvas_opacity_in: [01, { start: 0, end: 0.1 }],
                canvas_opacity_out: [10, { start: 0.95, end: 1 }],
                messageA_translateY_in: [200, { start: 0.15, end: 0.2 }],
                messageB_translateY_in: [300, { start: 0.6, end: 0.65 }],
                messageC_translateY_in: [300, { start: 0.87, end: 0.92 }],
                messageA_opacity_in: [01, { start: 0.25, end: 0.3 }],
                messageB_opacity_in: [01, { start: 0.6, end: 0.65 }],
                messageC_opacity_in: [01, { start: 0.87, end: 0.92 }],
                messageA_translateY_out: [0-20, { start: 0.4, end: 0.45 }],
                messageB_translateY_out: [0-20, { start: 0.68, end: 0.73 }],
                messageC_translateY_out: [0-20, { start: 0.95, end: 1 }],
                messageA_opacity_out: [10, { start: 0.4, end: 0.45 }],
                messageB_opacity_out: [10, { start: 0.68, end: 0.73 }],
                messageC_opacity_out: [10, { start: 0.95, end: 1 }],
                pinB_scaleY: [0.51, { start: 0.6, end: 0.65 }],
                pinC_scaleY: [0.51, { start: 0.87, end: 0.92 }]
            }
        },
        {
            // 3
            type: 'sticky',
            heightNum: 5,
            scrollHeight: 0,
            objs: {
                container: document.querySelector('#scroll-section-3'),
                canvasCaption: document.querySelector('.canvas-caption')
            },
            values: {
    
            }
        }
    ];

    function setCanvasImages() {
        let imgElem;
        for ( let i = 0i < sceneInfo[0].values.videoImagesCounti++) {
            imgElem = new Image();
            // = imgElems = document.createElement('img');
            imgElem.src = `./video/001/IMG_${6726 + i}.JPG`;
            sceneInfo[0].objs.videoImages.push(imgElem);
        }

        let imgElem2;
        for ( let i = 0i < sceneInfo[2].values.videoImagesCounti++) {
            imgElem2 = new Image();
            // = imgElems = document.createElement('img');
            imgElem2.src = `./video/002/IMG_${7027 + i}.JPG`;
            sceneInfo[2].objs.videoImages.push(imgElem2);
        }
        // console.log(sceneInfo[0].objs.videoImages);
    }
    setCanvasImages();

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

        yOffset = window.pageYOffset;

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

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

        // console.log(sceneInfo);
    }

    function calcValues(values, currentYOffset) {
        let rv;
        // 현재 씬 (스크롤섹션)에서 스크롤된 범위를 비율로 구하기
        const scrollHeight = sceneInfo[currentScene].scrollHeight;
        const scrollRatio = currentYOffset / scrollHeight;
        
        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 = sceneInfo[currentScene].objs;
        const values = sceneInfo[currentScene].values;
        const currentYOffset = yOffset - prevScrollHeight;
        const scrollHeight = sceneInfo[currentScene].scrollHeight;
        const scrollRatio = currentYOffset / scrollHeight;
    
        switch (currentScene) {
            case 0:
                // console.log('0 play');

                let sequence = Math.round(calcValues(values.imageSequencecurrentYOffset));
                // console.log(sequence);
                objs.context.drawImage(objs.videoImages[sequence], 00);
                objs.canvas.style.opacity = calcValues(values.canvas_opacitycurrentYOffset);

                if (scrollRatio <= 0.22) {
                    // in
                    objs.messageA.style.opacity = calcValues(values.messageA_opacity_incurrentYOffset);
                    objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_incurrentYOffset)}%, 0)`;
                } else {
                    // out
                    objs.messageA.style.opacity = calcValues(values.messageA_opacity_outcurrentYOffset);
                    objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_outcurrentYOffset)}%, 0)`;
                }
    
                if (scrollRatio <= 0.42) {
                    // in
                    objs.messageB.style.opacity = calcValues(values.messageB_opacity_incurrentYOffset);
                    objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_incurrentYOffset)}%, 0)`;
                } else {
                    // out
                    objs.messageB.style.opacity = calcValues(values.messageB_opacity_outcurrentYOffset);
                    objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_outcurrentYOffset)}%, 0)`;
                }
    
                if (scrollRatio <= 0.62) {
                    // in
                    objs.messageC.style.opacity = calcValues(values.messageC_opacity_incurrentYOffset);
                    objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_incurrentYOffset)}%, 0)`;
                } else {
                    // out
                    objs.messageC.style.opacity = calcValues(values.messageC_opacity_outcurrentYOffset);
                    objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_outcurrentYOffset)}%, 0)`;
                }
    
                if (scrollRatio <= 0.82) {
                    // in
                    objs.messageD.style.opacity = calcValues(values.messageD_opacity_incurrentYOffset);
                    objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_incurrentYOffset)}%, 0)`;
                } else {
                    // out
                    objs.messageD.style.opacity = calcValues(values.messageD_opacity_outcurrentYOffset);
                    objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_outcurrentYOffset)}%, 0)`;
                }
    
                break;
    
            case 2:
                // console.log('2 play');
                let sequence2 = Math.round(calcValues(values.imageSequencecurrentYOffset));
                objs.context.drawImage(objs.videoImages[sequence2], 00);

                if (scrollRatio <= 0.5) {
                    objs.canvas.style.opacity = calcValues(values.canvas_opacity_incurrentYOffset);
                } else {
                    objs.canvas.style.opacity = calcValues(values.canvas_opacity_outcurrentYOffset);
                }

                if (scrollRatio <= 0.32) {
                    // in
                    objs.messageA.style.opacity = calcValues(values.messageA_opacity_incurrentYOffset);
                    objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_incurrentYOffset)}%, 0)`;
                } else {
                    // out
                    objs.messageA.style.opacity = calcValues(values.messageA_opacity_outcurrentYOffset);
                    objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_outcurrentYOffset)}%, 0)`;
                }
    
                if (scrollRatio <= 0.67) {
                    // in
                    objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_incurrentYOffset)}%, 0)`;
                    objs.messageB.style.opacity = calcValues(values.messageB_opacity_incurrentYOffset);
                    objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleYcurrentYOffset)})`;
                } else {
                    // out
                    objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_outcurrentYOffset)}%, 0)`;
                    objs.messageB.style.opacity = calcValues(values.messageB_opacity_outcurrentYOffset);
                    objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleYcurrentYOffset)})`;
                }
    
                if (scrollRatio <= 0.93) {
                    // in
                    objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_incurrentYOffset)}%, 0)`;
                    objs.messageC.style.opacity = calcValues(values.messageC_opacity_incurrentYOffset);
                    objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleYcurrentYOffset)})`;
                } else {
                    // out
                    objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_outcurrentYOffset)}%, 0)`;
                    objs.messageC.style.opacity = calcValues(values.messageC_opacity_outcurrentYOffset);
                    objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleYcurrentYOffset)})`;
                }
    
                break;
    
            case 3:
                // console.log('3 play');
                break;
        }
    }

    function scrollLoop() {
        prevScrollHeight = 0;
        for (let i = 0i < currentScenei++) {
            prevScrollHeight = prevScrollHeight + sceneInfo[i].scrollHeight// +=를 사용하고 뒤에 prevScrollHeight 지워도 동일
        }

        if(yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) {
            currentScene++;
            document.body.setAttribute('id'`show-scene-${currentScene}`);
        }

        if(yOffset < prevScrollHeight) {
            if (currentScene === 0return// 브라우저 바운스 효과로 인해 마이너스가 되는것을 방지
            currentScene--;
            document.body.setAttribute('id'`show-scene-${currentScene}`);
        }
        playAnimation();
    }

    window.addEventListener('scroll', () => {
        yOffset = window.pageYOffset;
        scrollLoop();
    });

    window.addEventListener('load', () => {
        setLayout();
        sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImages[0], 00);
    });
    window.addEventListener('resize'setLayout);
    setLayout();

})();


답변 2

1

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

두가지 버그 모두, 진도를 더 나가시면 자연스럽게 해결될 에러들인데요,
일단 첫번째 에러의 경우 drawImage에서 그릴 이미지 소스에 데이터가 제대로 안들어갈 경우에 이런 에러가 발생합니다.
스크롤 값에 따라 계산되는 맨 끝 인덱스에 오차가 있는 경우가 있어서 발생하는 현상인데, 아래처럼 그려줄 이미지가 있을 경우에만 실행하도록 해주시면 예방할 수 있습니다.

objs.context.drawImage(objs.videoImages[sequence], 0, 0);
// 이 부분과

objs.context.drawImage(objs.videoImages[sequence2], 0, 0);
// 이 부분을
// 각각 아래처럼 바꾸어 주세요

if (objs.videoImages[sequence]) {
	objs.context.drawImage(objs.videoImages[sequence], 0, 0);
}

if (objs.videoImages[sequence2]) {
	objs.context.drawImage(objs.videoImages[sequence2], 0, 0);
}

씬이 바뀌는 중간에 잠깐 이미지가 나타나는 문제 역시, 스크롤값 기반으로 계산하다보니 씬이 바뀌는 순간 발생하는 버그인데
진도 나가다보면 해결하는 부분이 나온답니다. enterNewScene이라는 변수를 두고, 새로운 씬으로 진입 시에는 그려주지 않도록 하는 식으로 처리하고 있습니다^^

0

대림대님의 프로필 이미지
대림대
질문자

아하 뒤에 나와있었군요 하하;;;;;; 감사합니다!! ^^

대림대님의 프로필 이미지
대림대

작성한 질문수

질문하기