화면 모서리에 부딪히면 bounce하는 png 이미지를 js로 구현해 페이지에 디자인 요소를 추가하고 싶었다.
기술 포스팅에 적절하진 않은 같지만 KPT 회고 방법론을 사용해 볼 것이다.
💡 KEEP
1. 구글링 키워드를 잘 이용했다. (Bouncing, screen saver, js)
2. 잘 정리된 설명을 바탕으로 원하는 애니메이션을 구현할 수 있었다.
https://dev.to/s1mpson/creating-bouncing-logo-with-javascript-4ekg
💡 구현
1. HTML
<div class="fly ironman"></div>
- 내 html 파일의 body는 header, main, footer로 구분되어 있었다.
- 이미지가 body에 부딪혔을 때 bounce되어야 하므로 footer 아래에 코드를 작성하였다.
2. CSS
.fly {
background-size: contain;
background-position: center;
background-repeat: no-repeat;
width: 80px;
height: 80px;
position: fixed;
left: calc(50vw - 40px);
top: calc(50vw - 40px);
z-index: 200;
}
.fly.ironman {
background-image: url("../images/dh/ironman/fly.png");
}
.fly.spiderman {
background-image: url("../images/dh/spiderman/fly.png");
}
.fly.dr-strange {
background-image: url("../images/dh/dr-strange/fly.png");
}
- 이미지 div의 크기를 적용하고, background 속성에 알맞은 값을 준다.
- 스크롤을 따라 이동할 것이므로 position을 fixed로 설정한 후 초기 위치를 화면 중앙으로 설정한다.
3. JAVASCRIPT
const body = document.querySelector("body");
const hero = document.querySelector(".fly");
let FPS = 60;
let width,
height,
velocityX = 1,
velocityY = 1,
pause = true;
- FPS: setInterval 함수의 실행 간격을 조절
- width, height: 스크린 사이즈
- velocity: 이미지 이동 속도
- pause: 이미지의 이동을 정지하는 flag
const reset = () => {
width = window.innerWidth;
height = window.innerHeight;
pause =
width <= hero.getBoundingClientRect().width ||
height <= hero.getBoundingClientRect().height;
hero.style.left = "calc(50vw - 40px)";
hero.style.top = "calc(50vh - 40px)";
};
reset();
window.addEventListener("resize", reset);
- reset 함수는 window resize시에 실행된다.
- width와 height에 window 사이즈를 받아 이미지 보다 페이지 사이즈가 작아지면 pause는 true가 된다.
- 그 후 이미지를 초기 위치로 이동한다.
setInterval(() => {
if (pause) return;
let rect = hero.getBoundingClientRect();
let left = rect.x;
let top = rect.y;
if (left + rect.width >= width || left <= 0) {
velocityX = -velocityX;
}
if (top + rect.height >= height || top <= 0) {
velocityY = -velocityY;
}
hero.style.left = rect.x + velocityX + "px";
hero.style.top = rect.y + velocityY + "px";
if (isHeroCaught) {
pause = true;
if (hero.classList.contains("ironman")) {
hero.style.backgroundImage = "url('../../images/dh/ironman/fly2.png')";
} else if (hero.classList.contains("spiderman")) {
hero.style.backgroundImage = "url('../../images/dh/spiderman/fly2.png')";
} else if (hero.classList.contains("dr-strange")) {
hero.style.backgroundImage = "url('../../images/dh/dr-strange/fly2.png')";
}
}
}, 1000 / FPS);
- 이미지의 left border의 스크린 상 위치를 left, top border의 위치를 top으로 계산한다.
- left와 이미지의 너비 합 (right border의 스크린 상 위치)이 페이지 가로 사이즈를 넘어가거나
- left가 0보다 작아지면 (페이지 왼쪽 벽에 부딪히면) 이미지의 x축 이동 방향을 바꾼다.
- 같은 방법을 y축 이동 방향에도 적용한다.
- 이미지의 left와 top값에 현재 위치와 이동 방향을 더한 값을 적용한다.
- isHeroCaught flag 작동 시 이미지 소스를 바꾼다.
- 해당 함수는 1000 / FPS (1초에 fps번) 마다 실행한다.
let isHeroCaught = false;
hero.addEventListener("mouseover", () => {
isHeroCaught = true;
});
hero.addEventListener("mouseout", () => {
isHeroCaught = false;
pause = false;
if (hero.classList.contains("ironman")) {
hero.style.backgroundImage = "url('../../images/dh/ironman/fly.png')";
} else if (hero.classList.contains("spiderman")) {
hero.style.backgroundImage = "url('../../images/dh/spiderman/fly.png')";
} else if (hero.classList.contains("dr-strange")) {
hero.style.backgroundImage = "url('../../images/dh/dr-strange/fly.png')";
}
});
- 이미지에 mouseover시 isHeroCaught flag를 true로 바꾼다.
- mouseout 시 이미지소스를 원래대로 바꾼다.
🤔 PROBLEM
1. 이미지의 해상도가 높아 로딩이 필요하다.
2. Github 호스팅 페이지에서 이미지의 경로 이슈가 있었다.
3. Moblie 버전에서 이미지가 상, 하단에 도착 직후 스크롤 시 화면 바깥으로 나간 것으로 인식되어 reset이 실행되는 작은 버그가 발생한다.
🚀 TRY
호스팅 서버에서의 버그를 제외하면 의도대로 동작했다?
다른 환경에서 실행해보자.
'Front-end > Design' 카테고리의 다른 글
히어로 등장 애니메이션 (0) | 2024.02.04 |
---|---|
Hero select 디자인 구현 (0) | 2024.02.04 |