묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결
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 적용후