묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결단 2주간 키운 블로그로 월 80만원 용돈 벌기
완강후 질문
완강했습니다. woojin0413@gmail.com 혹시 블로그 스킨이나 메뉴관련해서 꿀팁도 받을 수 있을까요? 그리고 제가 기존에 운영하던 블로그가 있는데 그건 엄마 아이디였어서 이번엔 제 아이디로 하려고 생각하고 있는데 제꺼는 개설된지는 너무 오래되었어요 한 8년~10년? 다시 살려도 문제 없을까요?
-
미해결스프링 핵심 원리 - 기본편
너무 햇갈려서 질문하겠습니다..
안녕하세요 강사님 스프링 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 → 사용 → 소멸 전 콜백 → 스프링 종료 초기화 콜백 : 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출 소멸전 콜백 : 빈이 소멸되기 직전에 호출 뒤죽박죽인걸 감안해주시고 어이없는 질문이라도 양해좀 부타드립니다 ㅠ 1) 빈 라이프사이클이 아래 메서드 자체가 빈 라이프사이클을 도는것인지, 이 메서드 내부 라이프사이클을 도는것인지 잘모르겟습니다. @Bean public NetworkClient NetworkClient(){ NetworkClient networkClient = new NetworkClient(); networkClient.setUrl(" "); return networkClient } 2) NetworkClient networkClient = new NetworkClient(); 를 인스턴스화후 생성자가 호출되는 시점까지는 라이프사이클중 어느시점이죠...? 3)지금 여기서 networkClient.setUrl() 이것이 빈의 의존관계 주입단계인건가요?, 이부분만 몇일째 듣고있는데 머리속에 적립이안되서요
-
미해결[개정판 2023-11-27] Spring Boot 3.x 를 이용한 RESTful Web Services 개발
Snapshot 은 어떤 의미인가요?
일부 스프링 부트 버전은 스냅샷 이라고 괄호에 나와 있는데 snapshot은 lts 같은 의미인가요?
-
미해결
XD 플러그인 중에서 Icons 4 Design 저작권
XD 플러그인 중에서 Icons 4 Design 저작권이 있나요?
-
미해결UX/UI 시작하기 : Figma 입문 (Inflearn Original)
ios 14 beta 버전 다운로드
피그마에 파일 불러오기 수업 듣고 있는데요, 애플 디자인 소스가서 'ios 14 beta 버전'이 없습니다. 그래서 ios 14 스케치키트를 다운받으려고 하니 스케치 프로그램이 없어서 그런가 프로그램이 열리지 않습니다. 스케치 프로그램을 다운 받아야 하나요?
-
미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
시퀄라이즈 모델명 질문
기존의 hashtag모델을 Comment모델로 바꾸는 시도를 했는데요, Object.assign(options, _.omit(source.options, ['hooks'])); ^ TypeError: Cannot assign to read only property 'name' of function 'class Comment extends Sequelize.Model { static init(sequelize) { return super.init( { c...<omitted>... }' at Function.assign (<anonymous>) at Function.hasMany (C:\Users\DAAE\OneDrive - Chonnam National University\2021-1\Project\collusic\implement\collusic\backend\node_modules\sequelize\lib\associations\mixin.js:27:12) at Function.associate (C:\Users\DAAE\OneDrive - Chonnam National University\2021-1\Project\collusic\implement\collusic\backend\models\user.js:49:13) at Object.<anonymous> (C:\Users\DAAE\OneDrive - Chonnam National University\2021-1\Project\collusic\implement\collusic\backend\models\index.js:25:6) 이러한 에러가 나옵니다. post와 user 테이블도 바꿨었는데 hashtag모델을 바꾸니 문제가 생기네요.. 기존의 databases는 mysql에서 drop 한 상태에서 실습중입니다! //models/user.js const Sequelize = require("sequelize"); //db 테이블과 sequelize 연동을 위한 코드 module.exports = class User extends Sequelize.Model { static init(sequelize) { return super.init( { email: { type: Sequelize.STRING(40), allowNull: true, unique: true, }, nick: { type: Sequelize.STRING(15), allowNull: false, }, password: { type: Sequelize.STRING(100), allowNull: true, }, provider: { //로그인 제공자 type: Sequelize.STRING(10), allowNull: false, defaultValue: "local", }, introduce: { type: Sequelize.TEXT, allowNull: true, }, imagePath: { type: Sequelize.STRING(100), allowNull: true, }, }, { sequelize, timestamps: true, //생성일 수정일 삭제일이 기록 underscored: false, modelName: "User", tableName: "users", paranoid: true, charset: "utf8", collate: "utf8_general_ci", //한글 지원 } ); } static associate(db) { db.User.hasMany(db.Post, db.Comment, { foreignKey: "uid", targetKey: "id", }); } }; //models/post.js const Sequelize = require("sequelize"); module.exports = class Post extends Sequelize.Model { static init(sequelize) { return super.init( { title: { //id 생략. -> sequlize에서는 id가 생략될 수 있음. type: Sequelize.STRING(140), allowNull: false, }, description: { type: Sequelize.TEXT, allowNull: true, }, audioFile: { type: Sequelize.STRING(140), allowNull: false, }, state: { type: Sequelize.BOOLEAN, allowNull: false, }, field_free: { type: Sequelize.BOOLEAN, allowNull: false, }, lyrics_text: { type: Sequelize.TEXT, allowNull: true, }, genre: { type: Sequelize.STRING(140), allowNull: true, }, mood: { type: Sequelize.STRING(140), allowNull: true, }, music_field: { type: Sequelize.BOOLEAN, allowNull: true, }, lyrics_field: { type: Sequelize.BOOLEAN, allowNull: true, }, instrument_field: { type: Sequelize.BOOLEAN, allowNull: true, }, }, { sequelize, timestamps: true, underscored: false, modelName: "Post", tableName: "posts", paranoid: false, //deleted at false -> 게시글 삭제시 완전 삭제 charset: "utf8mb4", //이모티콘 collate: "utf8mb4_general_ci", } ); } static associate(db) { db.Post.belongsTo(db.User, { foreignKey: "uid", sourceKey: "id" }); db.Post.hasMany(db.Comment, { foreignKey: "pid", targetKey: "id" }); } }; //models/comment.js const Sequelize = require("sequelize"); module.exports = class Comment extends Sequelize.Model { static init(sequelize) { return super.init( { c_description: { type: Sequelize.TEXT, allowNull: false, }, c_audioFile: { type: Sequelize.STRING(140), allowNull: false, }, c_lyrics_text: { type: Sequelize.TEXT, allowNull: true, }, selected_status: { type: Sequelize.BOOLEAN, allowNull: false, }, }, { sequelize, timestamps: true, underscored: false, modelName: "Comment", tableName: "comment", paranoid: false, charset: "utf8mb4", collate: "utf8mb4_general_ci", } ); } static associate(db) { db.Comment.belongsTo(db.Post, { foreignKey: "pid", sourceKey: "id" }); db.Comment.belongsTo(db.User, { foreignKey: "uid", sourceKey: "id" }); } }; //requestid 외래키 //uid 외래키 //models/index.js const Sequelize = require("sequelize"); const env = process.env.NODE_ENV || "development"; //config.json의 development 가져오기 const config = require("../config/config")[env]; //config.json의 development 가져오기 const User = require("./user"); const Post = require("./post"); const Comment = require("./comment"); const db = {}; const sequelize = new Sequelize( config.database, config.username, config.password, config ); db.sequelize = sequelize; db.User = User; db.Post = Post; db.Comment = Comment; //사람과 게시글은 1:1관계, 게시글과 해시태그는 1:N 관계 User.init(sequelize); Post.init(sequelize); Comment.init(sequelize); User.associate(db); Post.associate(db); Comment.associate(db); module.exports = db;
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
제어자 static의 의미
안녕하세요 실습 진행중에 'ItemRepository'클래스에서 선생님께서 멤버변수를 만드실 때 제어자를 'static'으로 사용하셨는데 왜 'static'을 사용하신거죠? 의미를 설명해주셨는데도 이해가 잘 안가서요!
-
해결됨딥러닝 CNN 완벽 가이드 - TFKeras 버전
안녕하세요 교수님 이미지 제너레이터 관련 질문드립니다.
이전 강의들에서는 이미지를 증강 할 때, data_generator.fit(image_batch) data_gen_iter = data_generator.flow(image_batch) aug_image_batch = next(data_gen_iter) 제너레이터에 fit을 하고 flow으로 이터레이터를 생성하고 next로 조금 씩가져오는 것으로 이해하였습니다. 하지만 이번 강의에서는 왜 제너레이터에 fit과 next를 하지 않으시는지 궁금합니다... 또한 제너레이터가 이미지를 생성하는 것이 아니라 flow를 만들어 주고, next로 랜덤하게 적용해서 가져와 주는 것으로 이해하는 것이 맞는지요..? 감사합니다.
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
톰캣서버
안녕하세요 강의너무잘듣고있습니다.!! 강의자료그림에 보면 내장된 톰캣이 웹브라우저에서 url을 받아올때 실행되는것으로 나오는데, 프론트에서 was로 넘어올때 실행되는것인가요? 아니면 웹브라우저에서 프론트로 넘어올때도 실행되는 것인가요??? 톰캣이 was역할을 하는 것으로 알고있는데 제가 생각한 그림이 맞는지 궁금합니다.
-
미해결UX/UI 시작하기 : Figma 입문 (Inflearn Original)
[커뮤니티 베타 가입하기]
안녕하세요, 선생님. - 피그마 사용시 주의사항에서 '커뮤니티 베타 가입'을 할려는데 업데이트가 많이 되어서 그런지 선생님이 영상에 보여지는 내용, 이미지들이 많이 다릅니다. 현 저의 프로필에서 resources에 'join beta'처럼 안적혀있고 'explore'로 적혀있습니다 선생님처럼 가입을 하려면 어떻게 해야 하나요?
-
해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part2: 자료구조와 알고리즘
Tail = newRoom; 질문 드립니다
구문중에 36줄 Tail = newRoom; 이 부분 질문입니다. 첨부한 그림을 보시면 제가 이해한 방식인데요.(마우스 우버튼ㅡ새 탭에서 이미지 열기ㅡ로 크게 보실수 있습니다)제가 Tail.Next와 newRoom.Prev를 연결하여 연결포탈을 만드는것까지는 이해를 하였는데요. 최종적으로 Tail에 newRoom의 주소를 덮어쓰는(?) 부분이 이해가 어렵군요. 왜냐면 Tail은 newRoom이 추가되기 전 마지막 방의 주소인데, Tail에 newRoom의 주소를 넣게 되면(덮어쓰기?) 새로운 방이 추가되는 것이 아니라 기존 마지막방 주소를 새로운 방의 주소로 덮어쓰는 느낌이 드는데 제가 잘못 생각한 것인지요? 아니면, 우리가 A와 B의 값을 교환할때의 방식처럼X = A;A = B;B = X;기존 Tail주소에 다른 이름을 붙여주고 나서, Tail을 newRoom의 주소로 새롭게 정의하는 것이 맞지 않나 하는 생각이 들어서요.
-
미해결스프링 핵심 원리 - 기본편
SingletonWithPrototype에서 Provider 대신 프록시 사용
이전 강의에 싱클톤 빈(ClientBean)안에 PrototypeBean이 있는 예제에서 프로바이더 대신 프록시로 해봤는데, 프로토타입빈의 addCount()메소드를 타지 않아 count가 계속 0으로 나오더라구요 프록시로 해결할 수 있는 경우가 있고 ObjectProvider로 해결해야하는 경우가 따로 있나요?
-
미해결실전 프로젝트로 배우는 타입스크립트
esLinttrc.js 에서 에러 확인이 힘듭니다.
.eslintrc.js파일에서 복붙을한 상태에서 강의 순서대로 진행을 했습니다. 근데 특이하게 세미콜론쪽 에러가 계속 나와서, esLint가 적용되지 않는거 같아서요. 혹시 이런 현상이 있으셨나요?
-
미해결애플 웹사이트 인터랙션 클론!
video section 영역을 2개 이상 추가 했더니 첫번째 두번째 영역은 나오는데 3번째 영역부터 이미지가 그려지지 않습니다.
안녕하세요 좋은 강의 감사합니다. 예제 샘플을 이용해서 한가지 해보고 싶은게 있어 테스트 중에 있습니다. scroll section-0, scroll section-2 구간에 video-canvas-0, video-canvas-1을 main-js 샘플을 만들어 주신것처럼 똑같이 만들었습니다. 추후에 scroll-section-4를 추가 하고 video-canvas-2를 만들어 1,2와 같이 동일하게 만들었는데 3번째 영역이 보여지질 않습니다 ㅜㅜ 어떤 문제가 있는지 알고 싶습니다. index.html <!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>IKEA</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="main.css"> </head> <body> <div class="container"> <section class="scroll-section" id="scroll-section-0"> <div class="sticky-elem stick-elem-canvas"> <canvas id="video-canvas-0" width="1920" height="1080"></canvas> </div> </section> <section class="scroll-section" id="scroll-section-1"> <p class="description"> <strong>재료소개</strong> 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 </p> </section> <section class="scroll-section" id="scroll-section-2"> <div class="sticky-elem stick-elem-canvas"> <canvas id="video-canvas-1" width="1920" height="1080"></canvas> </div> </section> <section class="scroll-section" id="scroll-section-3"> <p class="description"> <strong>재료소개</strong> 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 </p> </section> <section class="scroll-section" id="scroll-section-4"> <div class="sticky-elem stick-elem-canvas"> <canvas id="video-canvas-2" width="1920" height="1080"></canvas> </div> </section> <section class="scroll-section" id="scroll-section-5"> <p class="description"> <strong>재료소개</strong> 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 재료소개 <br/><br/><br/><br/><br/><br/><br/> </p> </section> </div> <script src="js/main.js"></script> </body> </html> main.css #show-scene-0 #scroll-section-0 .sticky-elem, #show-scene-1 #scroll-section-1 .sticky-elem, #show-scene-2 #scroll-section-2 .sticky-elem, #show-scene-3 #scroll-section-3 .sticky-elem, #show-scene-4 #scroll-section-4 .sticky-elem, #show-scene-5 #scroll-section-5 .sticky-elem { display: block; will-change: transform, opacity; } main.js (() => { let yOffset = 0; //window.pageYoffset 대신 쓸 변수 let prevScrollHeight = 0; //현재 스크롤 위치(yOffset)보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합 let currentScene = 0; //현재 활성화된(눈 앞에 보고있는) 씬(scroll-section) let enterNewScene = false; //새로운 scene이 시작된 순간 true let acc = 0.1; let delayedYOffset = 0; let rafId; let rafState; const sceneInfo = [ { // 0 type : 'sticky', heightNum : 8, // 브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight : 0, objs: { container : document.querySelector('#scroll-section-0'), canvas : document.querySelector('#video-canvas-0'), context : document.querySelector('#video-canvas-0').getContext('2d'), videoImages : [] }, values : { videoImageCount : 314, imageSequence : [0, 313], canvas_opacity : [1, 0, {start: 0.9, end: 1}], } }, { // 1 type : 'normal', // heightNum : 5, // 브라우저 높이의 5배로 scrollHeight 세팅 (normal에서는 필요없음) scrollHeight : 0, objs: { container : document.querySelector('#scroll-section-1') } }, { // 2 type : 'sticky', heightNum : 8, // 브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight : 0, objs: { container: document.querySelector('#scroll-section-2'), canvas : document.querySelector('#video-canvas-1'), context : document.querySelector('#video-canvas-1').getContext('2d'), videoImages : [] }, values: { videoImageCount : 471, imageSequence : [0, 470], canvas_opacity_in : [0, 1, {start: 0, end: 0.1}], canvas_opacity_out : [1, 0, {start: 0.95, end: 1}], } }, { // 3 type : 'normal', // heightNum : 5, // 브라우저 높이의 5배로 scrollHeight 세팅 (normal에서는 필요없음) scrollHeight : 0, objs: { container : document.querySelector('#scroll-section-3') } }, { // 4 type : 'sticky', heightNum : 8, // 브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight : 0, objs: { container: document.querySelector('#scroll-section-4'), canvas : document.querySelector('#video-canvas-2'), context : document.querySelector('#video-canvas-2').getContext('2d'), videoImages : [] }, values: { videoImageCount : 338, imageSequence : [0, 337], canvas_opacity_in : [0, 1, {start: 0, end: 0.1}], canvas_opacity_out : [1, 0, {start: 0.95, end: 1}], } }, { // 5 type : 'normal', // heightNum : 5, // 브라우저 높이의 5배로 scrollHeight 세팅 (normal에서는 필요없음) scrollHeight : 0, objs: { container : document.querySelector('#scroll-section-5') } }, ]; function setCanvasImages() { let imgElem1; for (let i = 1; i < sceneInfo[0].values.videoImageCount; i++) { let filenameNumber = i; let filename = ''; if ( filenameNumber < 10) { filename = '000' + filenameNumber; } else if ( filenameNumber < 100) { filename = '00' + filenameNumber; } else if (filenameNumber >= 100 && filenameNumber < 1000) { filename = '0' + filenameNumber; } else { filename = String(filenameNumber); } imgElem1 = new Image(); imgElem1.src = `./video/chapter1/img_${filename}.jpg`; sceneInfo[0].objs.videoImages.push(imgElem1); // 24프레임 } let imgElem2; for (let i = 1; i < sceneInfo[2].values.videoImageCount; i++) { let filenameNumber = i; let filename = ''; if ( filenameNumber < 10) { filename = '000' + filenameNumber; } else if ( filenameNumber < 100) { filename = '00' + filenameNumber; } else if (filenameNumber >= 100 && filenameNumber < 1000) { filename = '0' + filenameNumber; } else { filename = String(filenameNumber); } imgElem2 = new Image(); imgElem2.src = `./video/chapter2/img_${filename}.jpg`; sceneInfo[2].objs.videoImages.push(imgElem2); // 24프레임 } let imgElem3; for (let i = 1; i < sceneInfo[4].values.videoImageCount; i++) { let filenameNumber = i; let filename = ''; if ( filenameNumber < 10) { filename = '000' + filenameNumber; } else if ( filenameNumber < 100) { filename = '00' + filenameNumber; } else if (filenameNumber >= 100 && filenameNumber < 1000) { filename = '0' + filenameNumber; } else { filename = String(filenameNumber); } imgElem3 = new Image(); imgElem3.src = `./video/chapter3/img_${filename}.jpg`; sceneInfo[4].objs.videoImages.push(imgElem3); // 24프레임 } } function setLayout() { // 각 스크롤 섹션의 높이 세팅 for (let i = 0; i < sceneInfo.length; i++) { if (sceneInfo[i].type === 'sticky') { sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight; //각섹션 스크롤 총 높이 = hightnum * 뷰포트 높이 } 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 = 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[0].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`; sceneInfo[2].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`; sceneInfo[4].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`; } function calcValues(values, currentYOffset) { let rv; // 현재 씬 (스크롤섹션)에서 스크롤된 범위를 비율로 구하기 const scrollHeight = sceneInfo[currentScene].scrollHeight; let 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; //섹션에 현재 yoffset 값 const scrollHeight = sceneInfo[currentScene].scrollHeight; const scrollRatio = currentYOffset / scrollHeight; switch (currentScene) { case 0 : // let sequence = Math.round(calcValues(values.imageSequence, currentYOffset)); //math 반올림 처리 // objs.context.drawImage(objs.videoImages[sequence], 0, 0); objs.canvas.style.opacity = calcValues(values.canvas_opacity, currentYOffset); break; case 1 : break; case 2 : // let sequence2 = Math.round(calcValues(values.imageSequence, currentYOffset)); //math 반올림 처리 // objs.context.drawImage(objs.videoImages[sequence2], 0, 0); if (scrollRatio <= 0.3) { // in objs.canvas.style.opacity = calcValues(values.canvas_opacity_in, currentYOffset); } else { // out objs.canvas.style.opacity = calcValues(values.canvas_opacity_out, currentYOffset); } break; case 3 : break; case 4 : // let sequence4 = Math.round(calcValues(values.imageSequence, currentYOffset)); //math 반올림 처리 // objs.context.drawImage(objs.videoImages[sequence4], 0, 0); if (scrollRatio <= 0.3) { // in objs.canvas.style.opacity = calcValues(values.canvas_opacity_in, currentYOffset); } else { // out objs.canvas.style.opacity = calcValues(values.canvas_opacity_out, currentYOffset); } break; case 5 : break; } } function scrollLoop() { enterNewScene = false; prevScrollHeight = 0; for (let i = 0; i < currentScene; i++) { prevScrollHeight += sceneInfo[i].scrollHeight; } if (delayedYOffset < prevScrollHeight + sceneInfo[currentScene].scrollHeight) { document.body.classList.remove('scroll-effect-end'); } if (delayedYOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) { enterNewScene = true; if (currentScene === sceneInfo.length - 1) { document.body.classList.add('scroll-effect-end'); } if (currentScene < sceneInfo.length - 1) { currentScene++; } document.body.setAttribute('id', `show-scene-${currentScene}`); } if (delayedYOffset < prevScrollHeight) { enterNewScene = true; // 브라우저 바운스 효과로 인해 마이너스가 되는 것을 방지(모바일) if (currentScene === 0) return; currentScene--; document.body.setAttribute('id', `show-scene-${currentScene}`); } if (enterNewScene) return; playAnimation(); } function loop() { delayedYOffset = delayedYOffset + (yOffset - delayedYOffset) * acc; if (!enterNewScene) { if (currentScene === 0 || currentScene === 2 || currentScene === 4) { const currentYOffset = delayedYOffset - prevScrollHeight; const objs = sceneInfo[currentScene].objs; const values = sceneInfo[currentScene].values; let sequence = Math.round(calcValues(values.imageSequence, currentYOffset)); if (objs.videoImages[sequence]) { objs.context.drawImage(objs.videoImages[sequence], 0, 0); } } } // 일부 기기에서 페이지 끝으로 고속 이동하면 body id가 제대로 인식 안되는 경우를 해결 // 페이지 맨 위로 갈 경우: scrollLoop와 첫 scene의 기본 캔버스 그리기 수행 if (delayedYOffset < 1) { scrollLoop(); sceneInfo[0].objs.canvas.style.opacity = 1; sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImages[0], 0, 0); } // 페이지 맨 아래로 갈 경우: 마지막 섹션은 스크롤 계산으로 위치 및 크기를 결정해야할 요소들이 많아서 1픽셀을 움직여주는 것으로 해결 if ((document.body.offsetHeight - window.innerHeight) - delayedYOffset < 1) { let tempYOffset = yOffset; scrollTo(0, tempYOffset - 1); } rafId = requestAnimationFrame(loop); if (Math.abs(yOffset - delayedYOffset) < 1) { cancelAnimationFrame(rafId); rafState = false; } } // 페이지 로드 됐을때 // window.addEventListener('DOMContentLoaded', setLayout); window.addEventListener('load', () => { setLayout(); // 중간에 새로고침 시, 콘텐츠 양에 따라 높이 계산에 오차가 발생하는 경우를 방지하기 위해 before-load 클래스 제거 전에도 확실하게 높이를 세팅하도록 한번 더 실행 // document.body.classList.remove('before-load'); setLayout(); sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImages[0], 0, 0); // 중간에서 새로고침 했을 경우 자동 스크롤로 제대로 그려주기 let tempYOffset = yOffset; let tempScrollCount = 0; if (tempYOffset > 0) { let siId = setInterval(() => { scrollTo(0, tempYOffset); tempYOffset += 5; if (tempScrollCount > 20) { clearInterval(siId); } tempScrollCount++; }, 20); } // 스크롤 했을때 window.addEventListener('scroll', () => { yOffset = window.pageYOffset; scrollLoop(); // checkMenu(); if (!rafState) { rafId = requestAnimationFrame(loop); rafState = true; } }); window.addEventListener('resize', () => { if (window.innerWidth > 900) { window.location.reload(); } }); window.addEventListener('orientationchange', () => { scrollTo(0, 0); setTimeout(() => { window.location.reload(); }, 500); }); // document.querySelector('.loading').addEventListener('transitionend', (e) => { // document.body.removeChild(e.currentTarget); // }); }); setCanvasImages(); })(); 소스는 다음과 같습니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
test오류나요
삭제된 글입니다
-
미해결
교안 및 예제파일이 없네요
-쉽고 빠르게 익히는 Access 2016 수강중입니다 . 강의중에 말씀하시는 교안과 예제파일이 따로 있다고 안내되어 있는데 찾을 수가 없네요 ~~
-
미해결실전 HTML & CSS 강좌
브라우저 보기
비주얼 스튜디오 2019 사용 중인데 파일-브라우저 보기 가 안됩니다
-
미해결Vue.js 중급 강좌 - 웹앱 제작으로 배워보는 Vue.js, ES6, Vuex
Github 권한 요청드립니다.
인프런 아이디 : dudrbs10400@gmail.com 인프런 이메일: dudrbs10400@gmail.com 깃헙 아이디: dudrbs10400@gmail.com 깃헙 Username : MrFabulous00
-
해결됨모든 개발자를 위한 HTTP 웹 기본 지식
중복 주문 방지를 클라이언트 차원에서 할 수 있는 방법이 궁금합니다.
안녕하세요. 7분14초 경에 나오는 설명 중, 중복 주문 방지를 클라이언트 차원에서 할 수 있는 방법이 무엇인지 궁금합니다. 아래 흐름으로 이해하였는데 맞게 이해한 것인가요?? 아래 적은 내용은 서버 차원에서 중복 주문을 방지하는 방법인가요?? - 클라이언트에서 POST 요청 - 서버에서 300대 상태 코드로 리다이렉트 - 클라이언트는 리다이렉트 된 URL로 이동하여 다시 GET 요청 - 완료 좋은 강의 정말 감사드립니다. :)
-
미해결Vue.js 중급 강좌 - 웹앱 제작으로 배워보는 Vue.js, ES6, Vuex
Github 권한 요청드립니다.
인프런 아이디 : andrew.park@lgcns.com 인프런 이메일 : andrew.park@lgcns.com 깃헙 아이디 : izttotio@hanmail.net 깃헙 Username : daekyungpark