2023. 6. 1. 19:13ㆍ개인노트-인강
인터랙티브 웹 개발 Canvas 인강 정리
# dat GUI 활용하기
- 수기로 하나하나 값을 변경해가며 마음에 드는 수치를 찾지 못하는 단점을 보완하기 위해서, dat GUI 라이브러리를 사용하여 값을 쉽게 테스트할 수 있는 환경을 구성해보겠습니다.
- dat GUI 를 통하여 SVG Blur 값과 alpha, contrast 값 뿐만 아니라 엑셀러레이션 값도 함께 바꿔주면서 우리가 원하는 이상적인 애니메이션 효과를 함께 찾아보도록 하겠습니다.
## cdn을 이용하여 라이브러리 가져오기
1. https://cdnjs.com/libraries/dat-gui
2. 최신버전 & min 버전으로 가져와서 html 상단 head 태그 안에 넣기.
3. index.js에서 dat.GUI 가져오기.
여기까지하면 html 화면에 작은 패널이 한 개 생깁니다.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script
src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js"
integrity="sha512-WoO4Ih0CDOSLYafy22wZD/mcJ7k0ESLqtQsFa6zFKnEUrbtuGU+GkLtVhgt93xa2qewG5gKEC6CWlN8OaCTSVg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<title>Document</title>
<style>
html,
body {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
filter: url("#gooey");
/* filter: blur(10px) contrast(10);
background-color: #f1f1f1; */
}
</style>
</head>
...
index.js
// ...
ctx.scale(dpr, dpr); // 3. 그리려는 객체에도 가로와 세로에 dpr값을 각각 곱해줍니다.
// 1. datGUI 컨트롤 패널안에서 변화를 주기 위한 값들을 먼저 정의를 해주어야합니다.
// 함수의 인스턴스 값에 담아서 만들어주도록 합니다.
const controls = new (function () {
// dat GUI 메소드에서 사용되어야할 값들을 여기서 this로 가져오기 때문에 변수명 앞에 this를 붙입니다.
this.blurValue = 40;
this.alphaChannel = 100;
this.alphaOffset = -23;
})();
// 2. datGUI 가져오기
let gui = new dat.GUI();
class Particle {
// ...
## datGUI 패널에 옵션 추가하기
화면에 생긴 패널 안에 옵션을 추가하려면 index.js에 add로 추가해 줄 수 있습니다.
const feGaussianBlur = document.querySelector("feGaussianBlur");
// 1. datGUI 컨트롤 패널안에서 변화를 주기 위한 값들을 먼저 정의를 해주어야합니다.
// 함수의 인스턴스 값에 담아서 만들어주도록 합니다.
const controls = new (function () {
// dat GUI 메소드에서 사용되어야할 값들을 여기서 this로 가져오기 때문에 변수명 앞에 this를 붙입니다.
this.blurValue = 40;
this.alphaChannel = 100;
this.alphaOffset = -23;
})();
// 2. datGUI 가져오기
let gui = new dat.GUI();
// 첫번째 인자 : controls
// 두번째 인자 : controls에서 사용한 변수 이름의 string 형태
// 세번째 인자 : 최소값 범위
// 네번째 인자 : 최대값 범위
// onChange : 값이 바뀌었을 때 어떻게 동작시킬지 정의
// value : 바뀐 값을 return 해줍니다.
gui.add(controls, "blurValue", 0, 100).onChange((value) => {
feGaussianBlur.setAttribute("stdDeviation", value);
});

Blur 값이 간단하게 Test 될 수 있는 환경이 되었습니다.
## Alpha 채널 바꾸기
// ...
const feColorMatrix = document.querySelector("feColorMatrix");
// ...
gui.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} 0`);
});
// ...
## Alpha offset 바꾸기
// ...
gui.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 1 ${value}`
);
});
// ...
## 여기까지 주의할 점
values라는 하나의 attribute 안에서 두 값을 동시에 바꾸고 있기 때문에 아래처럼 하게 되면..
// 잘못된 동작
gui.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} 0`
);
});
gui.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 1 ${value}`
);
});
한 값은 다시 원래의 값으로 초기화가 되어버립니다.
그래서 아래처럼 바꿔주면..
gui.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}`
);
});
gui.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}`
);
});
여기까지 gooey 관련된 변수들을 테스트를 해봤습니다.
## js안의 다른 값들도 바꿔보기
이제 파티클 class 내의 자체적인 속성값들도 바꿔보겠습니다.
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;
}
// ...
예를 들어 this.acc = 1.03; 을 바꿔보겠습니다.
1. 먼저 controls 안에 원래 쓰던 값을 담아줍니다.
const controls = new (function () {
// dat GUI 메소드에서 사용되어야할 값들을 여기서 this로 가져오기 때문에 변수명 앞에 this를 붙입니다.
this.blurValue = 40;
this.alphaChannel = 100;
this.alphaOffset = -23;
this.acc = 1.03;
})();
2. gui로 정의.
// 5번째 인자는 소수점 두번째 자리까지 출력하기 때문에 0.01로 세팅
gui.add(controls, 'acc', 1, 1.5, 0.01).onChange(value => {
//현재 생성되어 있는 파티클들 모두 값을 세팅해주어야 하기 때문에 particle들을 foreach로 돌아야 합니다.
particles.forEach(particle => particle.acc = value)
});
## 폴더로 관련있는 컨트롤끼리 나누기

위 3개는 gooey 관련 패널입니다. 폴더로 관련있는 컨트롤끼리 묶을 수 있습니다.
gui.addfolder 메소드를 사용하면 됩니다.
// ...
let gui = new dat.GUI();
const f1 = gui.addFolder('gooey Effect');
// gui 대신에 f1로 바꿔줍니다.
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");
f2.add(controls, "acc", 1, 1.5, 0.01).onChange((value) => {
particles.forEach((particle) => (particle.acc = value));
});
// ...

폴더가 열린채로 화면에 보이게 하려면 아래처럼 open() 메소드를 사용합니다.
const f1 = gui.addFolder("gooey Effect");
f1.open();
## 공부한 코드(전체)
index.js
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio; // 1. devicePixelRatio 값을 구한 뒤,
// const canvasWidth = 300;
// const canvasHeight = 300;
const canvasWidth = innerWidth;
const 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값을 각각 곱해줍니다.
// 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 TOTAL = 20;
const randomNumBetween = (min, max) => {
return Math.random() * (max - min + 1) + min;
};
let 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);
}
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);
}
animate();
'개인노트-인강' 카테고리의 다른 글
개인 노트 정리) Canvas - 2-01. 보일러 플레이트 두가지 방법 (0) | 2023.06.04 |
---|---|
개인 노트 정리) Canvas - 1-08. 캔버스 resize 다루기 (0) | 2023.06.01 |
개인 노트 정리) Node.js 백엔드 part 1-5 require와 모듈, 모듈의 레졸루션 (0) | 2023.05.25 |
개인 노트 정리) Canvas - 1-06. SVG 필터 입히기 (0) | 2023.05.23 |
개인 노트 정리) Canvas - 1-05. 파티클에 가속도 주기 (0) | 2023.05.23 |