requestAnimationFrame 와 setInterval의 차이점
index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<title> </title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<meta name='Title' content=''>
<meta name='Subject' content=''>
<meta name='Keywords' content=''>
<meta name='Author' content=''>
<meta name='Publisher' content=''>
<meta name='Description' content=''>
<meta name='Author-Date' content=''>
<meta name='Copyright' content=''>
<!-- CSS 리셋 -->
<link href='https://cdn.jsdelivr.net/npm/reset-css@5.0.1/reset.min.css'>
<!-- 제이쿼리 3.7 CDN -->
<script src='https://code.jquery.com/jquery-3.7.0.min.js' crossorigin='anonymous'></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js"></script>
<!-- 로컬 CSS -->
<link rel='stylesheet' href='./css/style.css'/>
<!-- 로컬 js -->
<script src='./js/script.js' defer></script>
<style>
html, body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
filter: url('#gooey');
/*background-color: black;
filter: blur(50px) contrast(50)*/
}
</style>
</head>
<body>
<canvas></canvas>
<svg>
<defs>
<!--재사용 가능한 필터를 정의 할 수 있는 공간-->
<filter id="gooey">
<fegaussianBlur stdDeviation="40" in="SourceFraphic" result="blur1"/>
<feColorMatrix in="blur1" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -23" />
</filter>
</defs>
</svg>
<script type="module" src="./index.js"></script>
</body>
</html>
index.js
const canvas = document.querySelector('canvas')
//HTML 문서 내에서 <canvas> 요소를 찾아서 가져옵니다.
const ctx = canvas.getContext('2d')
//2D 그래픽을 그리기 위한 컨텍스트를 가져옵니다.
const dpr = window.devicePixelRatio
//현재 장치의 픽셀 비율을 가져옵니다. 이 값은 Retina 디스플레이 등 고해상도 디스플레이에서 픽셀 밀도를 조정하는 데 사용됩니다.
let canvasWidth;
let canvasHeight;
let particles;
function init() {
canvasWidth = innerWidth
canvasHeight = innerHeight
//캔버스의 너비와 높이를 지정합니다.
canvas.style.width = canvasWidth + 'px'
canvas.style.height = canvasHeight + 'px'
//CSS 스타일을 사용하여 캔버스의 가로 및 세로 크기를 지정합니다. 이 코드는 캔버스가 화면에 얼마나 큰지를 결정합니다.
canvas.width = canvasWidth * dpr
canvas.height = canvasHeight * dpr
//캔버스의 실제 너비와 높이를 설정합니다. 이 때, 장치의 픽셀 비율을 고려하여 크기를 설정합니다.
ctx.scale(dpr, dpr)
//그리기 컨텍스트에 대한 변환을 적용하여 픽셀 비율에 따라 캔버스에 더 많은 픽셀을 그릴 수 있도록 합니다.
particles = []
const TOTAL = canvasWidth / 10
for (let i = 0; i < TOTAL; i++) {
const x = randomNumBetween(0, canvasWidth)
const y = randomNumBetween(0, canvasHeight)
const radius = randomNumBetween(50, 100)
const vy = randomNumBetween(1, 5)
const particle = new Particle(x, y, radius, vy)
particles.push(particle)
}
}
//파티클 만들기
//파티클 클래스는 각 파티클의 위치, 반지름, 수직 속도를 저장하고, 업데이트 및 그리기 메서드를 정의합니다.
class Particle {
constructor(x, y, radius, vy) {
this.x = x;
this.y = y;
this.radius = radius;
this.vy = vy;
this.acc = 1.03
}
update() {
this.vy *= this.acc;
this.y += this.vy
}
draw() {
// 원형 그리기
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI / 180 * 360)
ctx.fillStyle = 'orange'
ctx.fill()
ctx.closePath()
}
}
//변수 선언과 파티클 생성
//이 부분에서는 파티클의 초기 위치와 반지름을 정의하고, 이 정보를 사용하여 파티클 객체를 생성합니다.
//초기 파티클을 하나 생성합니다.
const x = 100
const y = 100
const radius = 50
const particle = new Particle(x, y, radius)
//여러 개의 파티클 생성
//TOTAL 개수만큼 랜덤한 위치와 반지름, 수직 속도를 가진 파티클을 생성하고, 배열에 추가합니다.
const randomNumBetween = (min, max) => {
return Math.random() * (max - min + 1) + min
}
//60fps 조건으로 애니메이션 프레임 설정
//'interval 변수는 60프레임으로 설정된 애니메이션을 만들기 위해 1초를 60으로 나눈 값을 의미합니다. 그리고 now, delta, then 변수는 애니메이션 프레임 간의 시간 간격을 계산하기 위한 것입니다. then 변수에 현재 시간을 저장합니다.
let interval = 1000 / 60
let now, delta
let then = Date.now()
//애니메이션 함수
function animate() {
window.requestAnimationFrame(animate)
now = Date.now()
delta = now - then
if (delta < interval) return
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
particles.forEach(particle => {
particle.update()
particle.draw()
if (particle.y - particle.radius > canvasHeight) {
// 파티클이 화면을 벗어나면 초기 상태로 되돌립니다.
particle.y = - particle.radius
particle.x = randomNumBetween(0, canvasWidth)
particle.radius = randomNumBetween(50, 100)
particle.vy = randomNumBetween(1, 5)
}
})
then = now - (delta % interval)
}
window.addEventListener('load', () => {
init()
animate()
})
window.addEventListener('resize', () => {
init()
})