개인노트-인강
개인 노트 정리) Canvas - 1-08. 캔버스 resize 다루기
roroism
2023. 6. 1. 19:55
인터랙티브 웹 개발 Canvas 인강 정리
# 캔버스 resize 다루기
- 캔버스 사이즈를 첫 로딩할때 웹 브라우저 크기만큼 적용된 뒤로는 바뀌지 않기 때문에 웹 브라우저 크기를 조절해도 캔버스 크기는 달라지지 않고 고정되어 있습니다.
- 그래서 window가 리사이즈 될 때마다 다시 캔버스 width 변수 값과 캔버스 height 변수 값을 할당해주면 해결할 수 있습니다.
## 코드 수정 하기
1. 캔버스 사이즈를 정의하는 코드 부분을 init 함수로 묶어줍니다.
// ...
let canvasWidth;
let canvasHeight;
function init() {
canvasWidth = innerWidth;
canvasHeight = innerHeight;
canvas.style.width = canvasWidth + "px";
canvas.style.height = canvasHeight + "px";
// 2. dpr 값을 canvas의 width와 height에 곱해줍니다.
canvas.width = canvasWidth * dpr;
canvas.height = canvasHeight * dpr;
ctx.scale(dpr, dpr); // 3. 그리려는 객체에도 가로와 세로에 dpr값을 각각 곱해줍니다.
}
// ...
2. 모든 파티클의 위치값들을 정의하는 부분도 init 함수 안으로 넣어줍니다.
// ...
let canvasWidth;
let canvasHeight;
let particles;
function init() {
canvasWidth = innerWidth;
canvasHeight = innerHeight;
canvas.style.width = canvasWidth + "px";
canvas.style.height = canvasHeight + "px";
// 2. dpr 값을 canvas의 width와 height에 곱해줍니다.
canvas.width = canvasWidth * dpr;
canvas.height = canvasHeight * dpr;
ctx.scale(dpr, dpr); // 3. 그리려는 객체에도 가로와 세로에 dpr값을 각각 곱해줍니다.
particles = [];
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);
}
}
// ...
3. window에 event를 추가해줍니다.
// ...
window.addEventListener("load", () => {
init();
animate();
});
window.addEventListener("resize", () => {
init();
});
## 화면 사이즈에 따라 파티클 갯수 변경하기
파티클의 갯수를 정의하는 코드를 init안으로 옮기고 canvasWidth 값을 이용하여 파티클의 갯수를 정해줍니다.
이제 화면 사이즈가 바뀌어도 파티클의 밀도값은 항상 같습니다.
let canvasWidth;
let canvasHeight;
let particles;
function init() {
canvasWidth = innerWidth;
canvasHeight = innerHeight;
canvas.style.width = canvasWidth + "px";
canvas.style.height = canvasHeight + "px";
// 2. dpr 값을 canvas의 width와 height에 곱해줍니다.
canvas.width = canvasWidth * dpr;
canvas.height = canvasHeight * dpr;
ctx.scale(dpr, dpr); // 3. 그리려는 객체에도 가로와 세로에 dpr값을 각각 곱해줍니다.
particles = [];
const TOTAL = canvasWidth / 60;
console.log("TOTAL : ", TOTAL);
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);
}
}
## 배운 코드 전체
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio; // 1. devicePixelRatio 값을 구한 뒤,
let canvasWidth;
let canvasHeight;
let particles;
function init() {
canvasWidth = innerWidth;
canvasHeight = innerHeight;
canvas.style.width = canvasWidth + "px";
canvas.style.height = canvasHeight + "px";
// 2. dpr 값을 canvas의 width와 height에 곱해줍니다.
canvas.width = canvasWidth * dpr;
canvas.height = canvasHeight * dpr;
ctx.scale(dpr, dpr); // 3. 그리려는 객체에도 가로와 세로에 dpr값을 각각 곱해줍니다.
particles = [];
const TOTAL = canvasWidth / 60;
console.log("TOTAL : ", TOTAL);
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);
}
}
// ctx.fillRect(10, 10, 50, 50);
/*
ctx.beginPath();
ctx.arc(100, 100, 50, 0, (Math.PI / 180) * 360);
ctx.fillStyle = "red";
ctx.fill(); // 안에 색상을 채워줍니다.
// ctx.stroke(); // 선을 그립니다.
ctx.closePath(); // 100, 100 위치에 반지름이 50인 원이 그려지게 됩니다.
*/
const feGaussianBlur = document.querySelector("feGaussianBlur");
const feColorMatrix = document.querySelector("feColorMatrix");
// 1. datGUI 컨트롤 패널안에서 변화를 주기 위한 값들을 먼저 정의를 해주어야합니다.
// 함수의 인스턴스 값에 담아서 만들어주도록 합니다.
const controls = new (function () {
// dat GUI 메소드에서 사용되어야할 값들을 여기서 this로 가져오기 때문에 변수명 앞에 this를 붙입니다.
this.blurValue = 40;
this.alphaChannel = 100;
this.alphaOffset = -23;
this.acc = 1.03;
})();
// 2. datGUI 가져오기
let gui = new dat.GUI();
const f1 = gui.addFolder("gooey Effect");
f1.open();
// 첫번째 인자 : controls
// 두번째 인자 : controls에서 사용한 변수 이름의 string 형태
// 세번째 인자 : 최소값 범위
// 네번째 인자 : 최대값 범위
// onChange : 값이 바뀌었을 때 어떻게 동작시킬지 정의
// value : 바뀐 값을 return 해줍니다.
f1.add(controls, "blurValue", 0, 100).onChange((value) => {
feGaussianBlur.setAttribute("stdDeviation", value);
});
f1.add(controls, "alphaChannel", 1, 200).onChange((value) => {
feColorMatrix.setAttribute(
"values",
`1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${value} ${controls.alphaOffset}`
);
});
f1.add(controls, "alphaOffset", -40, 40).onChange((value) => {
feColorMatrix.setAttribute(
"values",
`1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${controls.alphaChannel} ${value}`
);
});
const f2 = gui.addFolder("Particle Property");
// 5번째 인자는 소수점 두번째 자리까지 출력하기 때문에 0.01로 세팅
f2.add(controls, "acc", 1, 1.5, 0.01).onChange((value) => {
// 현재 생성되어 있는 파티클들 모두 값을 세팅해주어야 하기 때문에 particle들을 foreach로 돌아야 합니다.
particles.forEach((particle) => (particle.acc = value));
});
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 randomNumBetween = (min, max) => {
return Math.random() * (max - min + 1) + min;
};
console.log(particles);
// 1초에 60frame으로 동작
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();
});