묻고 답해요
148만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
[공유] State 패턴 강의 최종본 커밋에서 누락된 부분이 존재
git commit 으로 공유된 State 패턴 완성본 커밋 에서 강의 마지막 부분 (23:50) 과 달라서 해당 부분을 사용하시는 분들은 정상으로 동작하지 않을 수 있습니다.그래서 해당 공유합니다.강의 시작 부분 23:50코드 export class ChromeGrimpanMenu extends GrimpanMenu { onClickPen() { const command = new PenSelectCommand(this.grimpan); this.executeCommand(command); // { name: 'pen' }; // this.grimpan.setMode('pen'); // 변경, 해당 부분은 강의에도 나와있지는 않지만 pen 모드일때 변경이안되어서 자체적으로 추가함 this.grimpan.history.stack.push(command); } onClickEraser() { // this.executeCommand(new EraserSelectCommand(this.grimpan)); // { name: 'eraser' }; // 기존 this.grimpan.setMode('eraser'); // 변경 } onClickCircle() { // this.executeCommand(new CircleSelectCommand(this.grimpan)); // { name: 'eraser' }; this.grimpan.setMode('circle'); // 변경 } onClickRectangle() { // this.executeCommand(new RectangleSelectCommand(this.grimpan)); // { name: 'eraser' }; this.grimpan.setMode('rectangle'); // 변경 } onClickPipette() { // this.executeCommand(new PipetteSelectCommand(this.grimpan)); // { name: 'eraser' }; this.grimpan.setMode('pipette'); // 변경 }
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
팩토리 메서드에 대해서 궁금증이 생겨서 질문드려봅니다!
심플 팩토리에서 chrome, safari 등등 if문을 통해서 브라우저환경에 맞는 그림판 인스턴스를 가져올 수 있도록 한 코드가 있었는데, 팩토리 메서드가 그 역할을 대신한다고 이해했습니다. 궁금한점은 결국 크롬이든 사파리든 브라우저환경을 알아내서 main함수에 넘겨줄 수 있어야하는데 그 분기는 어디서 해야하는걸까요?function clientCode(creator: Creator) { creator.someOperation() } clientCode(new ConcreteCreator1())아래의 코드라면 new ConcreteCreator1()를 판단할 수 있는 조건 분기를 결국 어디서는 해야하지 않는가에 대한 고민입니다!
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
.
.
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
[섹션1/사전에 알아두면 좋은 TS/JS 지식]영상 재생 관련 질문 드립니다.
현재 [섹션 1/사전에 알아두면 좋은 TS/JS 지식] 영상이 검은 화면에 음성만 재생되는데 확인 부탁드립니다.감사합니다!
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
[12강] 선언식 + bind vs arrow function 어떤거 선호하시나요?
class의 메서드는 선언식으로 쓰는걸 좋아하는데bind는 쓰기 싫어서 bind 필요한것만 arrow function 쓰면 클래스 메서드가 선언식이랑 표현식 섞인게 뭔가 일관성이 없어보이더라구요.. (섞어쓰면 나중에 이거 bind 필요한 메서드였나? arrow function으로 했었나? 헷갈릴것같기도 하고?)
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
싱글톤 강의
싱글통 강의에서 숙제에 대한 답변도 볼 수있는 곳이 있을까요?
-
미해결TS/JS 디자인 패턴 with Canvas: 제로초에게 제대로 배우기
리스코프 치환원칙은 반,공변성과 같은 원리인가요?
class Parents { // 좁은 파라미터 method(name: string, test: string) { // 넓은 반환 타입 return { key: "" }; } } class Child extends Parents { // 넓은 파라미터 override method(name: string) { // 좁은 반환 타입 return { key: "", name: "" }; } } 안녕하세요,리스코프 치환원칙을 보니 반,공변성의 원칙과 같이매개변수는 반공변성을 리턴은 공변성을 가지는 것 같은데, T<child> -> T<parents> 개념이 되는 타입의 정의 원칙을 리스코프 치환 원칙이라 하는 것일까요?
-
미해결
canvas의 도형에 원하는 이미지들을 넣고 싶습니다.
const COLORS = [ "#394fb8", "#554fb8", "#605ac7", "#2a91a8", "#2e9ab2", "#32a5bf", "#81b144", "#85b944", "#8fc549", "#e0af27", "#eeba2a", "#fec72e", "#bf342d", "#ca3931", "#d7423a", ]; export class Polygon { constructor(x, y, radius, sides) { this.x = x; this.y = y; this.radius = radius; this.sides = sides; this.rotate = 0; } animate(ctx, moveX) { ctx.save(); const angle = PI2 / this.sides; const angle2 = PI2 / 4; ctx.translate(this.x, this.y); this.rotate += moveX * 0.008; ctx.rotate(this.rotate); for (let i = 0; i < this.sides; i++) { const x = this.radius * Math.cos(angle * i); const y = this.radius * Math.sin(angle * i); i == 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); ctx.save(); ctx.fillStyle=COLORS[i] ctx.translate(x, y); ctx.rotate((((360 / this.sides) * i + 45) * Math.PI) / 180); ctx.beginPath(); for (let j = 0; j < 4; j++) { const x2 = 160 * Math.cos(angle2 * j); const y2 = 160 * Math.sin(angle2 * j); j == 0 ? ctx.moveTo(x2, y2) : ctx.lineTo(x2, y2); } ctx.fill(); ctx.closePath(); ctx.restore(); } ctx.restore(); } }지금은 COLORS 배열을 이용해 fillstyle의 색을 넣었는데, 색상 대신 특정 이미지들을 넣고싶습니다. ctx.fillstyle = colors[i] 를 어떤 식으로 바꿔야할까요..?
-
미해결애플 웹사이트 인터랙션 클론!
canvas 너비를 화면 꽉 차게 하려면 어떻게 해야 할까요?
위의 사진과 같이 2000px 혹은 그 이상의 넓은 화면에서 보면 양 옆에 보기 싫게 흰 너비가 생기게 됩니다. 이걸 어떻게 하면 없앨 수 있을까요? 아예 동영상을 렌더링 할 시 넓게 해봤더니 여전히 안되더군요.
-
해결됨애플 웹사이트 인터랙션 클론!
canvas에 사진이 출력되지 않습니다
해당 강의를 바탕으로 따로 페이지 하나를 제작하고 있는데 사진은 지정이 되지만 사진이 출력되지 않네요 ㅠ 그리고 Uncaught TypeError : Cannot read properties of undefined (reading @@@) 에러가 length랑 style에 뜨는데 원인과 해결방법을 알 수 있을까요? -> 이 부분은 해결했습니다. main.js 코드입니다 + canvas를 통해 (머그컵과 같은) video 모션 이미지들이 들어가는 곳은 section 2,3,4 입니다. (() => { // 변수 모음 let yOffset = 0; // window.pageYOffset 대신 쓸 변수 let prevScrollHeight; // 현재 스크롤 위치 이전의 섹션들의 높이 합 let currentScene = 0; // 현재 보고 있는 씬 scroll-section 몇 번째인지 let enterNewScene = false; // 새로운 세션 시작된 순간 true const sceneInfo = [ { // section 0 - 인트로 type: "sticky", heightNum: 5, // 브라우저 높이의 5배로 세팅 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"), }, values: { // 타이밍 구간 지정 // 나타나는 타이밍 조절 messageA_opacity_in: [0, 1, { start: 0.1, end: 0.2 }], messageB_opacity_in: [0, 1, { start: 0.3, end: 0.4 }], messageC_opacity_in: [0, 1, { start: 0.5, end: 0.6 }], messageD_opacity_in: [0, 1, { start: 0.7, end: 0.8 }], // 위치 변화 타이밍 조절 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 }], }, }, { // section 1 - 서비스 리스트 type: "normal", // heightNum: 5, // type normal에서는 필요 없음 scrollHeight: 0, objs: { container: document.querySelector("#scroll-section-1"), content: document.querySelector("#scroll-section-1 .description"), }, }, { // section 2 - 공개행정 type: "sticky", heightNum: 5, scrollHeight: 0, objs: { container: document.querySelector("#scroll-section-2"), // messageABCD canvas: document.querySelector("#video-canvas-2"), context: document.querySelector("#video-canvas-2").getContext("2d"), videoImages: [], }, values: { videoImageCount: 14, imageSequence: [0, 13], canvas_opacity: [1, 0, { start: 0.9, end: 1 }], canvas_opacity_out: [1, 0, { start: 0.95, end: 1 }], // ,assage opacity, translate }, }, { // section 3 - 참여행정 type: "sticky", heightNum: 5, scrollHeight: 0, objs: { container: document.querySelector("#scroll-section-3"), // messageABCD canvas: document.querySelector("#video-canvas-3"), //content: document.querySelector("#scroll-section-3 .description"), context: document.querySelector("#video-canvas-3").getContext("2d"), videoImages: [], }, values: { videoImageCount: 15, imageSequence: [0, 14], canvas_opacity: [1, 0, { start: 0.9, end: 1 }], canvas_opacity_out: [1, 0, { start: 0.95, end: 1 }], // ,assage opacity, translate }, }, { // section 4 - 능률행정 type: "sticky", heightNum: 5, scrollHeight: 0, objs: { container: document.querySelector("#scroll-section-4"), // messageABCD canvas: document.querySelector("#video-canvas-4"), //content: document.querySelector("#scroll-section-4 .description"), //context: document.querySelector("#video-canvas-4").getContext("2d"), videoImages: [], }, values: { videoImageCount: 12, imageSequence: [0, 11], canvas_opacity: [1, 0, { start: 0.9, end: 1 }], canvas_opacity_out: [1, 0, { start: 0.95, end: 1 }], // ,assage opacity, translate }, }, { // section 5 - 마무리 type: "sticky", heightNum: 5, // 브라우저 높이의 5배로 세팅 scrollHeight: 0, objs: { container: document.querySelector("#scroll-section-5"), messageA: document.querySelector("#scroll-section-5 .main-message.a"), messageB: document.querySelector("#scroll-section-5 .main-message.b"), messageC: document.querySelector("#scroll-section-5 .main-message.c"), messageD: document.querySelector("#scroll-section-5 .main-message.d"), }, values: { // 타이밍 구간 지정 // 나타나는 타이밍 조절 messageA_opacity_in: [0, 1, { start: 0.1, end: 0.2 }], messageB_opacity_in: [0, 1, { start: 0.3, end: 0.4 }], messageC_opacity_in: [0, 1, { start: 0.5, end: 0.6 }], messageD_opacity_in: [0, 1, { start: 0.7, end: 0.8 }], // 위치 변화 타이밍 조절 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 }], }, }, ]; function setCanvasImages() { let imgElem1; for (let i = 0; i < sceneInfo[2].values.videoImageCount; i++) { imgElem1 = new Image(); imgElem1.src = `./video/section2_file/section2IMG_${i}.JPG`; sceneInfo[2].objs.videoImages.push(imgElem1); } let imgElem2; for (let i = 0; i < sceneInfo[3].values.videoImageCount; i++) { imgElem2 = new Image(); imgElem2.src = `./video/section3_file/section3IMG_${i}.JPG`; sceneInfo[3].objs.videoImages.push(imgElem2); } let imgElem3; for (let i = 0; i < sceneInfo[4].values.videoImageCount; i++) { imgElem3 = new Image(); imgElem3.src = `./video/section4_file/section4IMG_${i}.JPG`; sceneInfo[4].objs.videoImages.push(imgElem3); } } 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") { sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.offsetHeight; } // 섹션의 높이를 html에 세팅 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}`); const heightRatio = window.innerHeight / 1080; sceneInfo[2].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`; } // 값이 변화되는 걸 계산 // currentYOffset - 현재 섹션에서 얼마나 scroll되었는지 비율 계산 function calcValues(values, currentYOffset) { let rv; // return value 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]; // 0~1 -> 범위 확장 return rv; } 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; //console.log(currentScene, currentYOffset); switch (currentScene) { case 0: // 인트로 // console.log('0 play'); // let sequence = Math.round(calcValues(values.imageSequence, currentYOffset)); // objs.context.drawImage(objs.videoImages[sequence], 0, 0); 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 1: // 리스트 break; case 2: // 공개행정 objs.canvas.style.opacity = calcValues( values.canvas_opacity, currentYOffset ); if (scrollRatio <= 0.5) { // in objs.canvas.style.opacity = calcValues( values.canvas_opacity_in, currentYOffset ); } else { // out objs.canvas.style.opacity = calcValues( values.canvas_opacity_out, currentYOffset ); } 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: // 참여행정 objs.canvas.style.opacity = calcValues( values.canvas_opacity, currentYOffset ); 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 4: // 능률 행정 objs.canvas.style.opacity = calcValues( values.canvas_opacity, currentYOffset ); 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 5: // 마무리 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; } } // "현재 활성시킬 스크롤 씬(세션) 결정하기" // 몇 번째 스크롤 섹션 진행중인지 check // 앞파트 스크롤 섹션의 height 합으로 계산 가능 function scrollLoop() { enterNewScene = false; prevScrollHeight = 0; // 값 누적 방지용 초기화 for (let i = 0; i < currentScene; i++) { prevScrollHeight += sceneInfo[i].scrollHeight; } if (yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) { enterNewScene = true; currentScene++; document.body.setAttribute("id", `show-scene-${currentScene}`); // currentScene에 맞춰서 body에 하나씩 세팅된다 } if (yOffset < prevScrollHeight) { enterNewScene = true; if (currentScene == 0) return; // 브라우저 바운스 효과로 음수 에러 방지 currentScene--; document.body.setAttribute("id", `show-scene-${currentScene}`); // currentScene에 맞춰서 body에 하나씩 세팅된다 } if (enterNewScene) return; playAnimation(); //console.log(currentScene); // 몇 번째 섹션인지 } //window.addEventListener("resize", setLayout); // height에러 check window.addEventListener("scroll", () => { yOffset = window.pageYOffset; //console.log(yOffset); // 스크롤 페이지 값 scrollLoop(); }); // 새로고침 window.addEventListener("load", setLayout); window.addEventListener("resize", setLayout); setLayout(); setCanvasImages(); })();
-
미해결애플 웹사이트 인터랙션 클론!
canvas.context.transform 적용 시 다른 요소를 가리는 현상
안녕하세요! 강의 열심히 따라가고 있습니다 :) 제가 중간에 놓친 부분이 있는지, canvas.context.transform 으로 scrollHeight에 따라서 canvas 사이즈 조절 시에 일분이가 커지면서 뒤에 글씨를 가리고 있는데, 어떤 부분을 놓쳤을까요 ? 뭔가 css 일 것 같은데,css를 잘 몰라서 어떤 부분을 봐야할지모르겠습니다 ㅠㅠ ps. 사용중인 디스플레이가 지금 높이 1440px 인데요, 1080px보다 작은 화면에서는 정상적으로 표시되는것을 보아하니.. canvasScaleRatio가 1보다 클 경우에 문제가 되는 것 같아보입니다 :) transform 적용해제 (개발자도구로 제거) transform 적용후