묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결애플 웹사이트 인터랙션 클론!
이미지가 안보입니다...ㅠ(도움이 필요합니다!! 꼭 봐주세요!)
안녕하세요 선생님 강의 잘 듣고 있습니다! 다름이 아니라 밑에 수강생분 처럼 저도 이미지가 안보이고 Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)'. 이런 에러가 계속 뜨는데.. 어떻게 해야할지 모르겠습니다..ㅠㅠㅠ 분명 계속 이미지 경로도 확인하고 문제가 없는거같은데...대체 뭐가 문제인지 도움이 필요합니다..!! 너무 해결이 안되니까 꼭...해결하고싶습니다.. 잘되던 텍스트 애니메이션도 작동이 안됩니다. 보니까 playanimaion함수에서 sequence도 console.log에 찍으면 undefined로 찍히는데 도저히 뭐가 잘못 됐는지 모르겠습니다. 선생님이 주신 완성 코드를 대입해도 안뜨네요ㅠㅠㅠ (() => { let yOffset = 0; // window.pageYOffset대신 쓸 변수 let prevScrollHeight = 0; //현재 스크롤 위치(yOffset)보다 이전에 위치한 스크롤 섹션들의 높이값의 합 let currentScene = 0; //현재 활성화된(눈 앞에 보고있는) 씬(scroll-section) // sceneInfo는 애니메이션을 처리하는 정보를 담아놓는 변수 let enterNewScene = false;//새로운 scene이 시작되는 순간 true로 바뀜 const sceneInfo = [ { //0 type: 'sticky', heightNum:5,//브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight: 0, // 애니메이션을 조작할 오브젝트를 objs에 담음 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객체의 메서드인 getContext를 인자 2d를 넣어 호출해 그림을 그려주는 기초를 연다. context: document.querySelector('#video-canvas-0').getContext('2d'), //비디오 이미지를 배열에 넣을 예정이다. videoImages: [] }, //오브젝트를 어느시점에 보이고 안보이게 할지를 담을 곳 css제어 //시작값 :0 끝값 :1 values: { videoImageCount: 300, //스크롤에 따른 이미지 순서의 [초기값,최종값] messageA와 다르게 섹션의 부분에서 실행될 이미지가 아닌 한스크롤에서 쭉 이어지므로 start,end구간이 필요없다 imageSequence:[0 , 299], messageA_opacity_in: [0, 1, { start: 0.1, end: 0.2 }], messageB_opacity_in: [0, 1, { start: 0.3, end: 0.4 }], //30%~ 40% messageC_opacity_in: [0, 1, { start: 0.5, end: 0.6 }], messageD_opacity_in: [0, 1, { start: 0.7, end: 0.8 }], // 글자를 20%에서 0으로 가는건데 %는 css에 나중에 작업할 예정 세번째 인수에는 타이밍이 들어간다(=어느 타이밍에 효과를 줄것인가) messageA_translateY_in: [20, 0, { start: 0.1, end: 0.2 }], messageB_translateY_in: [20, 0, { start: 0.3, end: 0.4 }], messageC_translateY_in: [20, 0, { start: 0.5, end: 0.6 }], messageD_translateY_in: [20, 0, { start: 0.7, end: 0.8 }], messageA_opacity_out: [1, 0, { start: 0.25, end: 0.3 }], messageB_opacity_out: [1, 0, { start: 0.45, end: 0.5 }], messageC_opacity_out: [1, 0, { start: 0.65, end: 0.7 }], messageD_opacity_out: [1, 0, { 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 }] // messageA_opacity:[200,900] } }, { //1 type: 'normal', //heightNum은 scrollHeight를 결정할 때 innerheight의 몇배로 할지 정해주는 수 였는데 normal은 원래 본인 default높이로 설정하므로 필요가 없다 // heightNum:5, 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') }, values: { messageA_translateY_in: [20, 0, { start: 0.15, end: 0.2 }], messageB_translateY_in: [30, 0, { start: 0.5, end: 0.55 }], messageC_translateY_in: [30, 0, { start: 0.72, end: 0.77 }], messageA_opacity_in: [0, 1, { start: 0.15, end: 0.2 }], messageB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }], messageC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }], messageA_translateY_out: [0, -20, { start: 0.3, end: 0.35 }], messageB_translateY_out: [0, -20, { start: 0.58, end: 0.63 }], messageC_translateY_out: [0, -20, { start: 0.85, end: 0.9 }], messageA_opacity_out: [1, 0, { start: 0.3, end: 0.35 }], messageB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }], messageC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }], pinB_scaleY: [0.5, 1, { start: 0.5, end: 0.55 }], pinC_scaleY: [0.5, 1, { start: 0.72, end: 0.77 }], pinB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }], pinC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }], pinB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }], pinC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }] } }, { //3 type: 'sticky', heightNum:5, scrollHeight: 0, objs:{ container: document.querySelector('#scroll-section-3') } } ]; function setCanvasImages() { let imgElem; for (let i = 0; i < sceneInfo[0].values.videoImageCount; i++){ //이미지 객체가 만들어짐 new Image(); 대신에 document.createElement('img')랑 같은말이다. imgElem = new Image(); imgElem.src = `./video/001/IMG_${6726 + i}.JPG`; sceneInfo[0].objs.videoImages.push(imgElem); } } setCanvasImages(); function setLayout() { //각 스크롤 섹션의 높이 세팅 for (let i = 0; i < sceneInfo.length; i++){ if (sceneInfo[i].type === 'sticky') { sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight; } else if (sceneInfo[i].type === 'normal') { //container본연의 높이로 가져와서 그 크기만큼으로만 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 = 0; i < sceneInfo.length; i++){ totalScrollHeight += sceneInfo[i].scrollHeight; if (totalScrollHeight >= yOffset) { currentScene = i; break; } } // 변수랑 문자열이 섞여있으면 ``을 써야한다. document.body.setAttribute('id', `show-scene-${currentScene}`); // console.log(sceneInfo); //초기화 할 때 실행되는 setLayout은 currentScene이 정해지지 않은 상태에서 currentScene을 구하는 것이고, // 스크롤 할 때마다 실행되는 scrollLoop는 현재 활성화된 currentScene 까지의 스크롤양(prevScrollHeight)을 기준으로 일정량의 스크롤이 지나갔을 때 currentScene을 +1 또는 -1 하는 것이랍니다. } function calcValues(values, currentYOffset) { //여기서 인자 currentYOffset은 현재 씬에서 얼마나 스크롤 됐는지 //현재 섹션에서 얼마나 스크롤 되었는지를 비율로 구한다 스클로의 비율을 0~1사이로 정한다. 비율을 구해서 그 값을 css값에 대입해준다. //yoffset변수는 전체 레이아웃에서 스크롤이 어디 위치해있는지 알려주는 변수이다. 현재 씬에서 스크롤이 얼마나됐는지는 알 수 없다. let rv; const scrollHeight = sceneInfo[currentScene].scrollHeight; //현재 씬(스크롤섹션)에서 스크롤된 범위를 비율로 구하기 ==>let scrollRation = 현재 씬에서 스크롤된 값 / 현재 씬 전체 const scrollRatio = currentYOffset / sceneInfo[currentScene].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) { //스크롤섹션에서 스크롤이 start에 도달하지 못했을 때 rv = values[0]; //opacity가 0이라는 뜻 } else if (currentYOffset > partScrollEnd) { //스크롤섹션에서 스크롤이 end를 완전히 벗어났을 때 rv = values[1]; //opacity가 1이라는 뜻 } else { rv = scrollRatio * (values[1] - values[0]) + values[0]; } // rv = parseInt(scrollRatio * (values[1] - values[0]) + values[0]); return rv; } } //애니메이션 함수 function playAnimation() { // 모든 섹션에 애니메이션을 주는 것은 비효율적이므로 switch문을 이용해서 현재 보고있는 섹션의 요소에만 애니메이션을 준다 const objs = sceneInfo[currentScene].objs; const values = sceneInfo[currentScene].values; const currentYOffset = yOffset - prevScrollHeight; const scrollHeight = sceneInfo[currentScene].scrollHeight; const scrollRatio = currentYOffset / sceneInfo[currentScene].scrollHeight; switch (currentScene) { case 0: let sequence = calcValues(values.imageSequence, currentYOffset); objs.context.drawImage(objs.videoImages[sequence], 0, 0); console.log(sequence); if (scrollRatio <= 0.22) { // in objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.42) { // in objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset); objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset); objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.62) { // in objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset); objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset); objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.82) { // in objs.messageD.style.opacity = calcValues(values.messageD_opacity_in, currentYOffset); objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageD.style.opacity = calcValues(values.messageD_opacity_out, currentYOffset); objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_out, currentYOffset)}%, 0)`; } break; case 2: // console.log('2 play'); if (scrollRatio <= 0.25) { // in objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.57) { // in objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`; objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset); objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`; } else { // out objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`; objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset); objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`; } if (scrollRatio <= 0.83) { // in objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`; objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset); objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`; } else { // out objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`; objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset); objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`; } break; case 3: // console.log('3 play'); break; } } // keyframe이란: 애니메이션이 진행중에 변화가 있는 지점을 keyframe이라고 한다. function scrollLoop() { enterNewScene = false; prevScrollHeight = 0;//누적을 막기 위해서 // 현재 보고잇는 section이 몇번째 section인지 판별하려고함 for (let i = 0; i < currentScene; i++){ prevScrollHeight = prevScrollHeight + sceneInfo[i].scrollHeight; } // console.log(prevScrollHeight); if (yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) { enterNewScene = true; currentScene++; document.body.setAttribute('id', `show-scene-${currentScene}`); // setLayout함수에서 이미 id값이 정해져있지만 스크롤에 변함에 따라 체크하는 방식으로 쓴다 } if (yOffset < prevScrollHeight) { if (currentScene === 0) return;//브라우저 바운스 효과로 인해 마이너스가 되는 것을 방지(모바일) enterNewScene = true; currentScene--; document.body.setAttribute('id', `show-scene-${currentScene}`); } // console.log(currentScene); // enterNewScene이 참이라는것은 씬이 바뀌는순간인 것이고 참일때 return, 즉 playAnimation함수를 한타임 실행하지 않는다는것으로 음수값이 무시되고 다시 playAnimation함수가 실행된다. if (enterNewScene) return; playAnimation(); } window.addEventListener('scroll', () => { yOffset = window.pageYOffset; scrollLoop(); }); window.addEventListener('load', setLayout); // window의 모든 문서(html, 이미지, 동영상..)가 완료되고 나서 // 레이아웃 잡는 setLayout함수를 실행한다 // window.addEventListener('DOMContentLoaded', setLayout); //반대로 window의 html구조들만 완료되면 반대로 이미지는 로드되지않아도 setlayout함수를 실행하는것 //인데 load보다는 빨리 setlayout을 실행한다. window.addEventListener('resize', setLayout); // 윈도우가 리사이즈 되었을 때 setLayout을 호출한다 })(); <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>AirMug Pro</title> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;900&display=swap" rel="stylesheet"> <link rel="stylesheet" href="css/default.css"> <link rel="stylesheet" href="css/main.css"> <script defer src="js/main.js"></script> </head> <body> <div class="container"> <nav class="global-nav"> <div class="global-nav-links"> <a href="#" class="global-nav-item">Rooms</a> <a href="#" class="global-nav-item">Ideas</a> <a href="#" class="global-nav-item">Stores</a> <a href="#" class="global-nav-item">Contact</a> </div> </nav> <nav class="local-nav"> <div class="local-nav-links"> <a href="#" class="product-name">AirMug Pro</a> <a href="#">개요</a> <a href="#">제품사양</a> <a href="#">구입하기</a> </div> </nav> <section class="scroll-section" id="scroll-section-0"> <h1>AirMug Pro</h1> <!-- p태그의 값들을 sticky, 즉 스티커처럼 고정해놓고 스트롤의 값에 따라 보여지도록 p태그를 감싸고 있는 div에 class를 준다. --> <div class="sticky-elem sticky-elem-canvas"> <canvas id ="video-canvas-0" width="1920px" height="1080px"></canvas> </div> <div class="sticky-elem main-message a"> <p>온전히 빠져들게 하는<br>최고급 세라믹</p></div> <div class="sticky-elem main-message b"> <p>주변 맛을 느끼게 해주는<br>주변 맛 허용 모드</p> </div> <div class="sticky-elem main-message c"> <p>온종일 편안한<br>맞춤형 손잡이</p> </div> <div class="sticky-elem main-message d"> <p>새롭게 입가를<br>찾아온 매혹</p> </div> </section> <section class="scroll-section" id="scroll-section-1"> <p class="description"> <strong>보통 스크롤 영역</strong> Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas minus praesentium incidunt tempora repellendus? Laudantium sed excepturi quo nemo quisquam totam, cumque nam sit incidunt, corrupti libero temporibus obcaecati enim facilis dolore itaque minima dolorem sequi explicabo. Modi alias in ullam labore, minima voluptates ipsa ex laborum deleniti tempora incidunt architecto iure aut, molestias ab! Fugiat aliquam veritatis ad voluptatibus, quaerat officia doloribus aliquid nulla repellat quidem rem magni perferendis labore similique reprehenderit aut. Cum quis omnis ex iusto natus iste nisi magnam, nesciunt fugit aspernatur ullam? Temporibus, dolores ipsa. Odit odio aliquam sunt error corporis ab facere, illum sequi! Explicabo nulla, ipsum necessitatibus laboriosam eligendi aspernatur quam nostrum. Debitis est ad, vel in corrupti voluptas laboriosam quo, reiciendis quos quas culpa, atque voluptate tempora tempore quam accusamus ipsa asperiores voluptatibus adipisci non vero aspernatur eum nesciunt quis. A cum, molestiae eaque repellat similique esse eligendi reprehenderit amet omnis minus quae voluptatum delectus dolores repudiandae? Distinctio aut aspernatur, iure nemo, eum soluta error necessitatibus minus voluptatum laborum rem dignissimos quae. Error ut recusandae ullam magnam quas molestiae repellat culpa. Ab nihil sint voluptatum in? Enim suscipit debitis earum culpa sint maxime hic, repudiandae nulla ad error voluptatem fugiat blanditiis odit! </p> </section> <section class="scroll-section" id="scroll-section-2"> <div class="sticky-elem main-message a"> <p> <small>편안한 촉감</small> 입과 하나 되다 </p> </div> <div class="sticky-elem desc-message b"> <p> 편안한 목넘김을 완성하는 디테일한 여러 구성 요소들, 우리는 이를 하나하나 새롭게 살피고 재구성하는 과정을 거쳐 새로운 수준의 머그, AirMug Pro를 만들었습니다. 입에 뭔가 댔다는 감각은 어느새 사라지고 오롯이 당신과 음료만 남게 되죠. </p> <div class="pin"></div> </div> <div class="sticky-elem desc-message c"> <p> 디자인 앤 퀄리티 오브 스웨덴,<br>메이드 인 차이나 </p> <div class="pin"></div> </div> </section> <section class="scroll-section" id="scroll-section-3"> <p class="mid-message"> <strong>Retina 머그</strong><br> 아이디어를 광활하게 펼칠<br> 아름답고 부드러운 음료 공간. </p> <p class="canvas-caption"> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Eveniet at fuga quae perspiciatis veniam impedit et, ratione est optio porro. Incidunt aperiam nemo voluptas odit quisquam harum in mollitia. Incidunt minima iusto in corporis, dolores velit. Autem, sit dolorum inventore a rerum distinctio vero illo magni possimus temporibus dolores neque adipisci, repudiandae repellat. Ducimus accusamus similique quas earum laborum. Autem tempora repellendus asperiores illum ex! Velit ea corporis odit? Ea, incidunt delectus. Sapiente rerum neque error deleniti quis, et, quibusdam, est autem voluptate rem voluptas. Ratione soluta similique harum nihil vel. Quas inventore perferendis iusto explicabo animi eos ratione obcaecati. </p> </section> <footer class="footer"> 2020, 1분코딩 </footer> </div> </body> </html>
-
미해결인터랙티브 웹 개발 제대로 시작하기
오늘부터 인터렉티브 공부 시작합니다
평소에도 인터랙티브 강의에 관심ㅇ 있었는데 마침 세일하길래 몽땅 사버렸습니다 오늘부터 천천히 공부를 시작해보겠습니다~~~
-
미해결애플 웹사이트 인터랙션 클론!
공간을 넘어가요!
공간을 넘어가서 lorem 값이 나오는데 왜 이러는지 알 수 있을까요...?! padding 값이 문제일까요 ??? 문제는 없는 것 같은데 원래 넘어갈 수 밖에 없는 건지 궁금합니다.
-
미해결웹게임을 만들며 배우는 인터렉티브웹! JAVASCRIPT
캐릭터가 점프하면서 앞으로 나아가게 만들고있습니다
점프하면 앞으로 나가게는 만들었는데 방향이 left인 상태에서 점프를 up하면 right을 향한채로 뒤로 점프하게 됩니다. 계속 생각해보다가 도무지 모르겠어서 질문드립니다..! up에서 기본으로 방향이 right으로 향하는거 같은데 어떻게 해결해야할까요 if (key.keyDown["right"] && key.keyDown["up"]) { this.el.classList.add("jump_run"); this.el.classList.remove("run"); this.el.classList.remove("jump"); this.el.classList.remove("flip"); this.direction = "right"; this.moveY = this.moveY - this.jump; this.moveX = this.moveX + this.speed; setTimeout(() => { this.el.classList.remove("jump_run"); this.el.classList.add("run"); }, 300); } else if (key.keyDown["left"] && key.keyDown["up"]) { this.el.classList.add("jump_run_back"); this.el.classList.add("flip"); this.el.classList.remove("run"); this.el.classList.remove("jump"); this.direction = "left"; this.moveY = this.moveY - this.jump; this.moveX = this.moveX - this.speed; setTimeout(() => { this.el.classList.remove("jump_run_back"); }, 300); ////// 이하 CSS .hero_box .hero.flip { transform: rotateY(180deg); } .hero_box .hero.jump { animation: hero_jump 0.5s 1; } .hero_box .hero.jump_run { animation: hero_jump_run 0.5s 1; } .hero_box .hero.jump_run_back { background-size: 1498px 182px; animation: hero_jump_run_back 0.5s 1; } @keyframes hero_jump_run_back { 0% { transform: translate(0, 0); } 50% { transform: translate(-25px, -150px); } 100% { transform: translate(-40px, 0); } } @keyframes hero_jump_run_back_flip { 0% { transform: rotateY(180deg); } 50% { transform: rotateY(180deg); } 100% { transform: rotateY(180deg); } }
-
해결됨몇 줄로 끝내는 인터랙티브 웹 개발 노하우 [초급편]
저도 loop함수만 실행하면 오류가떠요!
안녕하세요! 저도 스크립트에서 loop(); 만 실행하면 스크롤 하게되면 강아지있는 사진이 붕 뜨는데 뭐가 문제일까요ㅠㅠ 혹시 코드 봐주실수 있나요!! let x = 0; let y = 0; let mx = 0; let my = 0; let speed = 0.03; let scrollTop = 0; let parallax_0, parallax_1, parallax_2, parallax_3, parallax_4, parallax_5, parallax_6; window.onload = function () { progressBar = document.getElementsByClassName("progressBar")[0]; parallax_0 = document.getElementById("parallax_0"); parallax_1 = document.getElementById("parallax_1"); parallax_2 = document.getElementById("parallax_2"); parallax_3 = document.getElementById("parallax_3"); parallax_4 = document.getElementById("parallax_4"); parallax_5 = document.getElementById("parallax_5"); parallax_6 = document.getElementById("parallax_6"); window.addEventListener('resize', stageResize, false); window.addEventListener('mousemove', mouseMove, false); window.addEventListener('scroll', scrollFunc, false); stageResize(); loop(); } function scrollFunc(e) { scrollTop = document.documentElement.scrollTop; let per = Math.ceil(scrollTop / (_documentHum - _windowHNum) * 100); progressBar.style.width = per + '%'; parallax_0.style.transform = "translate3d(0px," + scrollTop * .03 + "px, 0px)"; parallax_1.style.transform = "translate3d(0px," + -scrollTop * .03 + "px, 0px)"; parallax_2.style.transform = "translate3d(0px," + -scrollTop * .12 + "px, 0px)"; parallax_3.style.transform = "translate3d(0px," + -scrollTop * .16 + "px, 0px)"; parallax_4.style.transform = "translate3d(0px," + -scrollTop * .22 + "px, 0px)"; parallax_5.style.transform = "translate3d(0px," + -scrollTop * .25 + "px, 0px)"; } function stageResize(){ _documentHum = document.body.offsetHeight; _windowHNum = window.outerHeight; } function loop(){ mx += (x - mx) * speed; my += (y - my) * speed; parallax_4.style.transform = "translate3d(" + mx / 140 + "px ," + -scrollTop * 22 + "px, 0px)"; parallax_5.style.transform = "scale(1.1) translate(" + mx / 50 + "px," + -scrollTop * 25 + "px)"; parallax_6.style.transform = "scale(1.2) translate(" + -mx / 20 + "px," + -my / 20 + "px)"; window.requestAnimationFrame(loop); } function mouseMove(e){ x = (e.clientX - window.innerWidth / 2); y = (e.clientY - window.innerHeight / 2); }
-
미해결웹게임을 만들며 배우는 인터렉티브웹! JAVASCRIPT
기초적인 질문이라 부끄럽지만 질문 드립니다
안녕하세요, html, css는 잘 알지만 javascript는 이 강의로 처음 접해보기에 강의 진행에 어려움을 느껴 질문 드립니다. 강의 중 const windowEvent = () => { // 코드 내용 }; 위와 같은 형태가 나오는데요, 이게 함수를 만드는 문법인건가요? function 함수이름() { } 과 같은 형태는 자주 봤는데 처음 보는 형태라 질문 드립니다. 더불어 제가 쓰는 에디터에서 자꾸 노란줄이 생기는데요 (visual studio code 사용중입니다) 이것과 관련해 초기에 세팅 작업이 필요한건가요? 또 7강 진행 도중 this.el.parentNode.style.transform = 'translateX(${this.movex}px)' 부분이 동작하지 않아 this.el.parentNode.style.transform = 'translateX('+this.movex+'px)'; 위와 같이 바꿨더니 동작하는데, ${}가 어떤 것인지 설명 부탁드립니다. 좋은 강의에 부족한 실력이지만 열심히 따라가려고 노력하고 있습니다. 답변 기다리겠습니다. 감사합니다.
-
미해결인터랙티브 웹 개발 제대로 시작하기
firefox에서 backface-visibility: hidden; 이 이상하게 먹힙니다.
안녕하세요. firefox에서 카드에 마우스 호버시 F의 글자가 남아 B와 겹칩니다. 아래 사진 첨부합니다. ie용으로 만든 파일은 정상 작동을 하나, 사파리에서 해결했던 것과 같이 밴더프리픽스만 먹였을 때는 해결이 안되는 것으로 보입니다. https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style 와 https://developer.mozilla.org/ko/docs/Web/CSS/backface-visibility 에서 브라우저 호환성을 확인했을 때 firefox에서 preserve-3d, backface-visibility 두 가지 모두 사용할 수 있는 속성으로 나와있는데 왜 안되는걸까요??
-
미해결애플 웹사이트 인터랙션 클론!
main-add.js 코드 오류 있습니다. 이거 보고 수정하세요
main-add.js 내용 적용했는데 section-2 부분의 messageC부분이 section3까지 넘어가서 뭔가 이상하다고 생각했습니다. 실제로, 강의 영상에 나온 것이랑 값이 차이나서 수정한 부분 올립니다. sceneInfo의 section2부분의 value만 변경해주시면 됩니다. values: { messageA_translateY_in: [20, 0, { start: 0.15, end: 0.2 }], messageB_translateY_in: [30, 0, { start: 0.5, end: 0.55 }], messageC_translateY_in: [30, 0, { start: 0.72, end: 0.77 }], messageA_opacity_in: [0, 1, { start: 0.15, end: 0.2 }], messageB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }], messageC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }], messageA_translateY_out: [0, -20, { start: 0.3, end: 0.35 }], messageB_translateY_out: [0, -20, { start: 0.58, end: 0.63 }], messageC_translateY_out: [0, -20, { start: 0.85, end: 0.9 }], messageA_opacity_out: [1, 0, { start: 0.3, end: 0.35 }], messageB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }], messageC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }], pinB_scaleY: [0.5, 1, { start: 0.5, end: 0.55 }], pinC_scaleY: [0.5, 1, { start: 0.72, end: 0.77 }], pinB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }], pinC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }], pinB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }], pinC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }], },
-
미해결BBC 인터랙티브 페이지 "코로나19가 바꿀 사무실의 미래" 클론
actions 함수 관련 질문
질좋은 강의 무료로 올려주심에 만세 3창 드립니다. 다름이 아니라요 선생님 트위터 새 모션을 설정하는 함수에서 위 사진 상으로 4번째 줄 가운데 ('[data-index = "2"].bird')에서 대괄호와 .bird를 붙이면 이렇게 오류가 나는데 대괄호와 .bird를 띄우면 잘 작동합니다... 자바스크립트를 공부한지 얼마 되지 않아 왜 저런 차이가 있는지 궁금합니다
-
미해결인터랙티브 웹 개발 제대로 시작하기
이 강의를 초보자가 들어도 괜찮을까요?
안녕하세요 선생님. 현재 자바스크립트를 입문해 기초문법을 어느정도 습득한 상태입니다(변수, 연산, 함수, 반복문, 제어문, 객체, 배열) html은 태그의 의미를 이해하는 수준이며(모르면 구글링..) css는 기본적인 문법만 아는상태입니다.(무언가 만들어본적은 아직 없습니다) 이런 상태에서 이 수업을 들어도 괜찮을까요? 아니면 사전에 다른 공부를 준비를해야할까요?
-
해결됨애플 웹사이트 인터랙션 클론!
캔버스 크기 관련 질문
안녕하세요. 질문이 있는데요 저는 캔버스 화면을 애플 공홈처럼 꽉 채우고 싶은데 innerHeight에 맞춰서 그런가 이런 식으로 나오네요(1920*1080 모니터 기준) outHeight나 그 외 다른 height 값들을 대신 넣으면 화면이 꽉 차는 대신 화면이 안 예쁘게 늘어납니다. f11하면 제가 원하는대로 1920*1080 풀사이즈 정확하게 나오고요. 어떻게 수정해야 할까요? const heightRatio = window.innerHeight / 1080; sceneInfo[1].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`;
-
해결됨인터랙티브 웹 개발 제대로 시작하기
안녕하세요 질문 있습니다
영상을 여러 번 돌려봤는데 너무 헷갈려서요 제가 제대로 이해한 게 맞는지 확인해주셨으면 합니다. 제가 정리한 내용은 다음과 같습니다. ㅡㅡ 현재 스크롤 상태를 나타내는 scrollState의 기본값은 false이다. 스크롤 이벤트가 실행되면 clearTimeout이 먼저 작동한다. clearTimeout은 setTimeout의 반환값을 매개변수로 하여 setTimeout을 취소시키는 함수이다. 지금은 setTimeout이 실행되지 않았으니 건너뛰고 다음 if문으로 가자. "!(self.scrollState=false)= true", 즉 if(true){} 이므로 if문이 실행된다. running 클래스가 붙어 이제 애니메이션이 작동된다. 다음으로 setTimeout 함수로 가보자. setTimeout은 항상 숫자를 리턴하기 때문에 scrollState는 값을 가지게 되어 true가 된다. setTimeout 안의 내용들은 0.5초 후에 실행되는데 실행되기도 전에 스크롤 이벤트 갱신과 함께 clearTimeout으로 인해 실행되지 못한다. 이제 if문으로 넘어가는데 scrollState가 true이므로 if(!true), 즉, if(false)가 되어 if 문이 실행되지 않는다. 그리고 setTimeout으로 넘어가면 마찬가지로 리턴값을 받아 여전히 true이고, settimeout은 실행되지 않는다. 이렇게 반복되다가 마지막 스크롤일 때 setTimeout이 드디어 실행된다. 왜냐하면 더 이상 스크롤 이벤트가 일어나지 않아 clearTimeout이 동작하지 않기 때문이다. 비로소 scrollstate는 false가 되고 running 클래스는 제거된다.
-
해결됨애플 웹사이트 인터랙션 클론!
switch(currentScene) case2번 질문드려요!
쌤 코드 기준으로 질문드려여 :> case 0: 일 경우, 동영상이 밑의 사진처럼 로드시 drawImage 처리를 해줘야 스크롤 처리가 없어도 한번에 뜨는 반면에, case2:일 경우는 동영상이 로드 시의 처리 없이도 바로 뜨는데 이게 왜그런지 궁금하네유
-
해결됨애플 웹사이트 인터랙션 클론!
클린코드(8:02부분)
강의 8:02에 .local-nav-links .product-name을 하여 .local-nav-links a보다 우선순위를 올려 주셨는데 앞서 작성하신 .local-nav-links a:not(.product-name)에 fontr-size를 정해주고 .porduct-name에 굵기, 크기를 조절해준다면 더 클린한 코드 아닌가요? 사실 크게 상관 없을거 같은데 궁금해서 질의 합니다. 8:02부분과 이 코드를 비교하시면 제질문이 이해되기 쉬울거 같습니다. .product-name { margin-right: auto; font-size: 1.2rem; font-weight: bold; } .local-nav-links a:not(.product-name) { margin-left: 2em; font-size: 0.8rem; }
-
해결됨인터랙티브 웹 개발 제대로 시작하기
zMove에 1000이나 950곱하는것
안녕하세요 선생님 궁금한게 생겨서 질문드려요! const zMove=pageYOffset/maxScrollValue*1000-490; houseElem.style.transform='translateZ('+zMove+'vw)'; 여기에서 zMove에 1000을 곱할때 pageYOffset/maxScrollValue가 너무 작아서라고 이해했는데 다시듣다보니 의문이 생겨서요 .wall-left, .wall-right의 width가 1000vw인것과 관련있는건가요? 스크롤이 끝까지 가지않게 950을 곱해주시는걸 보고 든 생각인데 이게 맞는건지 궁금해요
-
해결됨애플 웹사이트 인터랙션 클론!
블로킹
이미지 경로의 문제가 있는건가요???
-
해결됨애플 웹사이트 인터랙션 클론!
오류
검은 박스가 밖에서 안으로 들어오려는거 같은데 원인을 알 수 있을까요? case 3: // 가로, 세로 모두 100%로 채우기 위한 세팅(계산 필요) const widthRatio = window.innerWidth / objs.canvas.width; const heightRatio = window.innerHeight / objs.canvas.height; let canvasScaleRatio; if (widthRatio <= heightRatio) { // 브라우저 width < 캔버스 width인 경우 canvasScaleRatio = heightRatio; } else { // 브라우저 height < 캔버스 height 경우 canvasScaleRatio = widthRatio; } objs.canvas.style.transform = `scale(${canvasScaleRatio})`; objs.context.drawImage(objs.images[0], 0, 0); // 캔버스 사이즈에 맞춰 가정한 innerWdth와 innerHeight const recalculatedInnerWidth = document.body.offsetWidth / canvasScaleRatio; const recalculatedInnerHeight = window.innerHeight / canvasScaleRatio; if (!values.rectStartY) { // values.rectStartY = objs.canvas.getBoundingClientRect().top; values.rectStartY = objs.canvas.offsetTop + (objs.canvas.height - objs.canvas.height * canvasScaleRatio) / 2; values.rect1X[2].end = values.rectStartY / scrollHeight; values.rect2X[2].end = values.rectStartY / scrollHeight; } const whiteRectWidth = recalculatedInnerWidth * 0.15; values.rect1X[0] = (objs.canvas.width - recalculatedInnerWidth) / 2; values.rect1X[1] = values.rect1X[0] - whiteRectWidth; values.rect2X[0] = values.rect1X[0] + recalculatedInnerWidth - whiteRectWidth; values.rect2X[1] = values.rect2X[0] + whiteRectWidth; // 좌우 화이트박스 그리기 // objs.context.fillRect(values.rect1X[0], 0, parseInt(whiteRectWidth), objs.canvas.height); // objs.context.fillRect(values.rect2X[0], 0, parseInt(whiteRectWidth), objs.canvas.height); objs.context.fillRect( parseInt(calcValues(values.rect1X, currentYOffset)), 0, parseInt(whiteRectWidth), objs.canvas.height ); objs.context.fillRect( parseInt(calcValues(values.rect2X, currentYOffset)), 0, parseInt(whiteRectWidth), objs.canvas.height ); break;