해결된 질문
작성
·
269
0
검은 박스가 밖에서 안으로 들어오려는거 같은데 원인을 알 수 있을까요?
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;
답변 5
1
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;
}
이 부분에서 end만 있고 start 파트가 빠져있네요~
start를 아래와같이 넣어주니 정상 동작합니다^^
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].start = (window.innerHeight / 2) / scrollHeight;
values.rect2X[2].start = (window.innerHeight / 2) / scrollHeight;
values.rect1X[2].end = values.rectStartY / scrollHeight;
values.rect2X[2].end = values.rectStartY / scrollHeight;
}
0
저도 안되는 부분이 있어 댓글남깁니다. 제 코드는 이렇습니다.
(() => {
let yOffset = 0;
let prevScrollHeight = 0; //current scroll yOffset previous scroll sections sum of heights
let currentScene = 0;// currently activated scene in front of our eye
let enterNewScene = false; //whne new scene set, starts true
const sceneInfo = [
{
type: 'sticky',
scrollHeight: 0,
heightNum: 5,// browser's height times 5 to set scrollHeight
objs:{
container: document.querySelector('#scroll-section-0'),
messageA: document.querySelector('#scroll-section-0 .main-message.a'),
messageB: document.querySelector('#scroll-section-0 .main-message.b'),
messageC: document.querySelector('#scroll-section-0 .main-message.c'),
messageD : document.querySelector('#scroll-section-0 .main-message.d'),
canvas: document.querySelector('#video-canvas-0'),
context: document.querySelector('#video-canvas-0').getContext('2d'),
videoImages: [],
},
values: {
// in
messageA_opacity: [0,1, {start: 0.1, end:0.2}],
messageA_translateY_in: [20, 0, {start:0.1, end:0.2}],
messageB_opacity: [0,1, {start: 0.3, end:0.4}],
messageB_translateY_in: [20, 0, {start:0.3, end:0.4}],
messageC_opacity: [0,1, {start: 0.5, end:0.6}],
messageC_translateY_in: [20, 0, {start:0.5, end:0.6}],
messageD_opacity: [0,1, {start: 0.7, end:0.8}],
messageD_translateY_in: [20, 0, {start:0.7, end:0.8}],
// out
messageA_opacity_out: [1,0,{start:0.25, end:0.3}],
messageA_translateY_out: [0, -20, {start:0.25, end:0.3}],
messageB_opacity_out: [1,0,{start:0.45, end:0.5}],
messageB_translateY_out: [0, -20, {start:0.45, end:0.5}],
messageC_opacity_out: [1,0,{start:0.65, end:0.7}],
messageC_translateY_out: [0, -20, {start:0.65, end:0.7}],
messageD_opacity_out: [1,0,{start:0.85, end:0.9}],
messageD_translateY_out: [0, -20, {start:0.85, end:0.9}],
// images
videoIMageCount: 300,
imageSequence: [0, 299],
//canvas
canvas_opacity: [1,0,{start:0.9,end:1}]
}
},
{
type: 'normal',
scrollHeight: 0,
heightNum: 5,// browser's height times 5 to set scrollHeight,
objs:{
container: document.querySelector('#scroll-section-1')
}
},
{
type: 'sticky',
scrollHeight: 0,// for compatibility purposes
heightNum: 5,// browser's height times 5 to set scrollHeight
objs:{
container: document.querySelector('#scroll-section-2'),
messageA: document.querySelector('#scroll-section-2 .a'),
messageB: document.querySelector('#scroll-section-2 .b'),
messageC: document.querySelector('#scroll-section-2 .c'),
pinB: document.querySelector('#scroll-section-2 .b .pin'),
pinC: document.querySelector('#scroll-section-2 .c .pin'),
canvas: document.querySelector('#video-canvas-1'),
context: document.querySelector('#video-canvas-1').getContext('2d'),
videoImages: [],
},
values:{
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: [0,1,{start:0.15, end:0.2}],
messageB_opacity: [0,1,{start:0.5, end:0.55}],
messageC_opacity: [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: [0,1,{start:0.5, end:0.55}],
pinC_opacity: [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}],
// images
videoIMageCount: 960,
imageSequence: [0, 959],
//canvas
canvas_opacity: [0,1,{start:0,end:0.1}],
canvas_opacity_out: [1,0,{start: 0.95, end:1}]
}
},
{
type: 'sticky',
scrollHeight: 0,
heightNum: 5,// browser's height times 5 to set scrollHeight
objs:{
container: document.querySelector('#scroll-section-3'),
canvasCaption: document.querySelector('.canvas-caption'),
canvas: document.querySelector('.image-blend-canvas'),
context: document.querySelector('.image-blend-canvas').getContext('2d'),
imagesPath: [
'./images/blend-image-1.jpg',
'./images/blend-image-2.jpg',
],
images:[]
},
values: {
rect1X: [0,0,{start:0, end:0}],
rect2X: [0,0,{start:0, end:0}],
rectStartY: 0,
}
},
]
function setCanvasImages(){
let imgElem;
for(let i =0; i < sceneInfo[0].values.videoIMageCount; i++){
imgElem = document.createElement('img');
// imgElem = new Image()
imgElem.src = `./video/001/IMG_${6726+i}.JPG`;
sceneInfo[0].objs.videoImages.push(imgElem);
}
let imgElem2;
for(let i =0; i < sceneInfo[2].values.videoIMageCount; i++){
imgElem2 = document.createElement('img');
// imgElem = new Image()
imgElem2.src = `./video/002/IMG_${7027+i}.JPG`;
sceneInfo[2].objs.videoImages.push(imgElem2);
}
let imgElem3;
for(let i =0; i< sceneInfo[3].objs.imagesPath.length; i++){
imgElem3 = new Image();
imgElem3.src = sceneInfo[3].objs.imagesPath[i];
sceneInfo[3].objs.images.push(imgElem3)
}
}
// store images into array
setCanvasImages();
function setLayout(){
// each scroll section's height set
for(let i =0; i < sceneInfo.length; i++){
// however, when type is normal, we set to contents height because no need to animation
if(sceneInfo[i].type==='sticky'){
sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight;
sceneInfo[i].objs.container.style.height = `${sceneInfo[i].scrollHeight}px`
}else{
sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.offsetHeight;
}
sceneInfo[i].objs.container.style.height = `${sceneInfo[i].scrollHeight}px`;
}
yOffset = 0;
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;
// multiply window ratio to the current browser's height
sceneInfo[0].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`;
sceneInfo[2].objs.canvas.style.transform = `translate3d(-50%, -50%, 0) scale(${heightRatio})`;
}
// the ratio of current scrolled values in terms of Y offset
function calcValues(values, currentYOffset){
let rv;
const scrollHeight = sceneInfo[currentScene].scrollHeight;
// current Scene, scrolled section need to be factored
let scrollRatio = currentYOffset / sceneInfo[currentScene].scrollHeight;
// specific start ~ specific end animation activated
if(values.length ===3){
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;
//current scene's ratio current height
const scrollRatio = currentYOffset / sceneInfo[currentScene].scrollHeight;
switch(currentScene){
case 0:
// getting the sequence and scrolls of it
let sequence = Math.round(calcValues(values.imageSequence, currentYOffset));
objs.context.drawImage(objs.videoImages[sequence], 0, 0);
objs.canvas.style.opacity = calcValues(values.canvas_opacity, currentYOffset);
// scrolling and interaction with texts
if (scrollRatio <= 0.22){
objs.messageA.style.opacity = calcValues(values.messageA_opacity, currentYOffset);
objs.messageA.style.transform = `translateY(${calcValues(values.messageA_translateY_in, currentYOffset)}%)`;
}else{
objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset);
objs.messageA.style.transform = `translateY(${calcValues(values.messageA_translateY_out, currentYOffset)}%)`;
}
if(scrollRatio <= 0.42){
objs.messageB.style.opacity = calcValues(values.messageB_opacity, currentYOffset);
objs.messageB.style.transform = `translateY(${calcValues(values.messageB_translateY_in, currentYOffset)}%)`;
}
else{
objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
objs.messageB.style.transform = `translateY(${calcValues(values.messageB_translateY_out, currentYOffset)}%)`;
}
if(scrollRatio <= 0.62){
objs.messageC.style.opacity = calcValues(values.messageC_opacity, currentYOffset);
objs.messageC.style.transform = `translateY(${calcValues(values.messageC_translateY_in, currentYOffset)}%)`;
}
else{
objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
objs.messageC.style.transform = `translateY(${calcValues(values.messageC_translateY_out, currentYOffset)}%)`;
}
if(scrollRatio <= 0.82){
objs.messageD.style.opacity = calcValues(values.messageD_opacity, currentYOffset);
objs.messageD.style.transform = `translateY(${calcValues(values.messageD_translateY_in, currentYOffset)}%)`;
}
else{
objs.messageD.style.opacity = calcValues(values.messageD_opacity_out, currentYOffset);
objs.messageD.style.transform = `translateY(${calcValues(values.messageD_translateY_out, currentYOffset)}%)`;
}
//css
break;
case 1:
break;
case 2:
// getting the sequence and scrolls of it
let sequence2 = Math.round(calcValues(values.imageSequence, currentYOffset));
objs.context.drawImage(objs.videoImages[sequence2], 0, 0);
objs.canvas.style.opacity = calcValues(values.canvas_opacity, currentYOffset);
// this is only for canvas opacity
if(scrollRatio <= 0.5){
//in
objs.canvas.style.opacity = calcValues(values.canvas_opacity, currentYOffset);
}else{
//out
objs.canvas.style.opacity = calcValues(values.canvas_opacity_out, currentYOffset);
}
if (scrollRatio <= 0.22){
objs.messageA.style.opacity = calcValues(values.messageA_opacity, currentYOffset);
objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`;
}else{
objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset);
objs.messageA.style.transform = `translateY(${calcValues(values.messageA_translateY_out, currentYOffset)}%)`;
}
if(scrollRatio <= 0.57){
objs.messageB.style.opacity = calcValues(values.messageB_opacity, currentYOffset);
objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`;
objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`;
}
else{
objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
objs.messageB.style.transform = `translateY(${calcValues(values.messageB_translateY_out, currentYOffset)}%)`;
}
if(scrollRatio <= 0.79){
objs.messageC.style.opacity = calcValues(values.messageC_opacity, currentYOffset);
objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`;
objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
}
else{
objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
objs.messageC.style.transform = `translateY(${calcValues(values.messageC_translateY_out, currentYOffset)}%)`;
objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
}
break;
case 3:
// fill out the height and cross
console.log('in case 3')
// these ratios are required for getting the width and height ratio
// const widthRatio = window.innerWidth / objs.canvas.width;
const widthRatio = window.innerWidth / objs.canvas.width;
const heightRatio = window.innerHeight / objs.canvas.height;
// const heightRatio = window.innerHeight / objs.canvas.height;
let canvasScaleRatio;
if(widthRatio <= heightRatio){
//when brwoser is thinner than canvas
canvasScaleRatio = heightRatio;
console.log('height Ratio has been decided');
}else{
// when browser is fatter than canvas
canvasScaleRatio = widthRatio;
console.log('widthRatio decided')
}
objs.canvas.style.transform = `scale(${canvasScaleRatio})`;
// objs.canvas.style.height = String(canvasScaleRatio * 1080);
// objs.canvas.style.width = String(canvasScaleRatio * 1920);
objs.context.drawImage(objs.images[0],0,0);
// fit to canvas size, innerwidth and innerHeight
const recalculatedInnerWidth = window.innerWidth / 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 / sceneInfo[3].scrollHeight;
values.rect2X[2].end = values.rectStartY / sceneInfo[3].scrollHeight;
}
console.log(values.rect2X[2])
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;
// left right white box drawing
objs.context.fillRect(
parseInt(calcValues(values.rect1X, currentYOffset)),
0,
parseInt(whiteRectWidth),
objs.canvas.height
);
console.log(parseInt(calcValues(values.rect2X, currentYOffset)),'should inccrease', currentYOffset)
objs.context.fillRect(
parseInt(calcValues(values.rect2X, currentYOffset)),
0,
parseInt(whiteRectWidth),
objs.canvas.height
);
// objs.context.fillRect(values.rect2X[0],0, parseInt(whiteRectWidth), recalculatedInnerHeight);
break;
}
}
//increase the current scene and calculate prevScrollHeight of current scene
function scrollLoop(){
enterNewScene = false;
prevScrollHeight = 0
for(let i =0; i < currentScene; i++){
prevScrollHeight += sceneInfo[i].scrollHeight;
}
if(yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight && currentScene < sceneInfo.length-1){
currentScene ++;
enterNewScene = true;
document.body.setAttribute('id', `show-scene-${currentScene}`);
}
if(yOffset < prevScrollHeight){
if(currentScene===0) return;
currentScene --;
enterNewScene = true;
document.body.setAttribute('id', `show-scene-${currentScene}`);
}
if(enterNewScene) return;
playAnimation();
}
//whenever browser resizes
window.addEventListener('scroll', () => {
// call necessary function in here
yOffset = window.pageYOffset;
scrollLoop();
})
// window.addEventListener('DOMContentLoaded', setLayout);
window.addEventListener('load',() => {
setLayout();
sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImages[0],0,0);
})
window.addEventListener('resize', setLayout);
})();
0
(() => {
let yOffset = 0; // window.pageYOffset 대신 사용할 변수
let prevScrollHeight = 0; // 현재 스크롤 위치(yOffset)보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합
let currentScene = 0; // 현재 활성화된(뷰포트) 씬(scroll-section)
let enterNewScene = false; // 새로운 씬이 시작되는 순간 true
const sceneInfo = [{
// 0
type: 'sticky',
heightNum: 5, // 브라우저 높이의 5배로 scrollHeight 세팅
scrollHeight: 0,
objs: {
container: document.querySelector('#scroll-section-0'),
messageA: document.querySelector('#scroll-section-0 .main-message.a'),
messageB: document.querySelector('#scroll-section-0 .main-message.b'),
messageC: document.querySelector('#scroll-section-0 .main-message.c'),
messageD: document.querySelector('#scroll-section-0 .main-message.d'),
canvas: document.querySelector('#video-canvas-0'),
context: document.querySelector('#video-canvas-0').getContext('2d'),
videoImages: []
},
values: {
videoImageCount: 300, // 이미지가 300장
imageSequence: [0, 299], // 이미지 인덱스
canvas_opacity: [1, 0, { start: 0.9, end: 1 }],
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 }]
}
},
{
// 1
type: 'normal',
// heightNum: 5, // type normal에서는 필요 없음
scrollHeight: 0,
objs: {
container: document.querySelector('#scroll-section-1')
}
},
{
// 2
type: 'sticky',
heightNum: 5,
scrollHeight: 0,
objs: {
container: document.querySelector('#scroll-section-2'),
messageA: document.querySelector('#scroll-section-2 .a'),
messageB: document.querySelector('#scroll-section-2 .b'),
messageC: document.querySelector('#scroll-section-2 .c'),
pinB: document.querySelector('#scroll-section-2 .b .pin'),
pinC: document.querySelector('#scroll-section-2 .c .pin'),
canvas: document.querySelector('#video-canvas-1'),
context: document.querySelector('#video-canvas-1').getContext('2d'),
videoImages: []
},
values: {
videoImageCount: 960,
imageSequence: [0, 959],
canvas_opacity_in: [0, 1, { start: 0, end: 0.1 }],
canvas_opacity_out: [1, 0, { start: 0.95, end: 1 }],
messageA_translateY_in: [20, 0, { start: 0.15, end: 0.2 }],
messageB_translateY_in: [30, 0, { start: 0.6, end: 0.65 }],
messageC_translateY_in: [30, 0, { start: 0.87, end: 0.92 }],
messageA_opacity_in: [0, 1, { start: 0.25, end: 0.3 }],
messageB_opacity_in: [0, 1, { start: 0.6, end: 0.65 }],
messageC_opacity_in: [0, 1, { start: 0.87, end: 0.92 }],
messageA_translateY_out: [0, -20, { start: 0.4, end: 0.45 }],
messageB_translateY_out: [0, -20, { start: 0.68, end: 0.73 }],
messageC_translateY_out: [0, -20, { start: 0.95, end: 1 }],
messageA_opacity_out: [1, 0, { start: 0.4, end: 0.45 }],
messageB_opacity_out: [1, 0, { start: 0.68, end: 0.73 }],
messageC_opacity_out: [1, 0, { start: 0.95, end: 1 }],
pinB_scaleY: [0.5, 1, { start: 0.6, end: 0.65 }],
pinC_scaleY: [0.5, 1, { start: 0.87, end: 0.92 }]
}
},
{
// 3
type: 'sticky',
heightNum: 5,
scrollHeight: 0,
objs: {
container: document.querySelector('#scroll-section-3'),
canvasCaption: document.querySelector('.canvas-caption'),
canvas: document.querySelector('.image-blend-canvas'),
context: document.querySelector('.image-blend-canvas').getContext('2d'),
imagePath: [
'./images/blend-image-1.jpg',
'./images/blend-image-2.jpg'
],
images: []
},
values: {
rect1X: [0, 0, { sctart: 0, end: 0 }],
rect2X: [0, 0, { sctart: 0, end: 0 }],
rectStartY: 0
}
}
];
function setCanvasImages() {
let imgElem;
for (let i = 0; i < sceneInfo[0].values.videoImageCount; i++) {
imgElem = new Image();
imgElem.src = `./video/001/IMG_${6726 + i}.JPG`;
sceneInfo[0].objs.videoImages.push(imgElem);
}
let imgElem2;
for (let i = 0; i < sceneInfo[2].values.videoImageCount; i++) {
imgElem2 = new Image();
imgElem2.src = `./video/002/IMG_${7027 + i}.JPG`;
sceneInfo[2].objs.videoImages.push(imgElem2);
}
let imgElem3;
for (let i = 0; i < sceneInfo[3].objs.imagePath.length; i++) {
imgElem3 = new Image();
imgElem3.src = sceneInfo[3].objs.imagePath[i];
sceneInfo[3].objs.images.push(imgElem3);
}
}
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') {
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})`;
}
function calcValues(values, currentYOffset) {
let rv;
// 현재 씬(스크롤섹션)에서 스크롤된 범위를 비율로 구하기
const scrollHeight = sceneInfo[currentScene].scrollHeight;
const scrollRatio = currentYOffset / scrollHeight;
if (values.length === 3) {
// start ~ end 사이에 애니메이션 실행
const partScrollStart = values[2].start * scrollHeight;
const partScrollEnd = values[2].end * scrollHeight;
const partScrollHeight = partScrollEnd - partScrollStart;
if (currentYOffset >= partScrollStart && currentYOffset <= partScrollEnd) {
rv = (currentYOffset - partScrollStart) / partScrollHeight * (values[1] - values[0]) + values[0];
} else if (currentYOffset < partScrollStart) {
rv = values[0];
} else if (currentYOffset > partScrollEnd) {
rv = values[1];
}
} else {
rv = scrollRatio * (values[1] - values[0]) + values[0];
}
return rv;
}
function playAnimation() {
const objs = sceneInfo[currentScene].objs;
const values = sceneInfo[currentScene].values;
const currentYOffset = yOffset - prevScrollHeight;
const scrollHeight = sceneInfo[currentScene].scrollHeight;
const scrollRatio = currentYOffset / scrollHeight;
switch (currentScene) {
case 0:
let sequence = Math.round(calcValues(values.imageSequence, currentYOffset));
objs.context.drawImage(objs.videoImages[sequence], 0, 0);
objs.canvas.style.opacity = calcValues(values.canvas_opacity, currentYOffset);
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:
let sequence2 = Math.round(calcValues(values.imageSequence, currentYOffset));
objs.context.drawImage(objs.videoImages[sequence2], 0, 0);
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.32) {
// 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.67) {
// 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.93) {
// 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:
// 가로, 세로 모두 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;
}
}
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}`);
}
if (yOffset < prevScrollHeight) {
if (currentScene === 0) return; // 브라우저 바운스 효과로 인해 마이너스가 되는 것을 방지(모바일)
enterNewScene = true;
currentScene--;
document.body.setAttribute("id", `show-scene-${currentScene}`);
}
if (enterNewScene) return;
playAnimation();
}
window.addEventListener("scroll", () => {
yOffset = window.pageYOffset;
scrollLoop();
});
// window.addEventListener("DOMContentLoadded", setLayout);
window.addEventListener("load", () => {
setLayout();
sceneInfo[0].objs.context.drawImage(sceneInfo[0].objs.videoImages[0], 0, 0);
});
window.addEventListener("resize", setLayout);
})();
0
박스2개가 아주 미미하게 움직이고있고, 디버깅을 해보는데, 도무지 원인을 찾을수가 없네요. 혹시 한번 확인해주시겠어요?