하트 모양의 경로를 계산하기 위해 for 루프를 사용하여 h 배열에 노드를 추가합니다. 이 노드는 하트의 수학적 공식을 기반으로 계산됩니다.
while 루프를 사용하여 각 궤적에 대한 입자 배열을 생성합니다. 각 입자는 위치, 속도, 반경, 가속도, 타겟 노드, 방향, 마찰, 색상 등의 속성을 가집니다.
이 함수는 캔버스에 입자를 그립니다. 입자의 색상, 위치 및 크기에 따라 캔버스에 원을 그립니다.
이 함수는 애니메이션의 주요 부분입니다. 캔버스를 지우고, 각 입자의 위치를 업데이트하며, 입자가 하트 경로의 노드에 도달했는지 확인합니다. 입자가 노드에 도달하면 새로운 목표를 설정합니다. 그런 다음 모든 입자를 새 위치에 그립니다.
requestAnimationFrame을 사용하여 loop 함수를 반복적으로 호출합니다. 이는 웹 브라우저에게 애니메이션을 수행하도록 요청하고, 브라우저가 최적화된 방식으로 애니메이션을 수행할 수 있게 합니다.
이 코드를 블로그에 설명할 때는 각 단계를 상세히 설명하고, 코드의 각 부분이 어떻게 함께 작동하는지를 독자가 이해할 수 있도록 해야 합니다. 또한, 코드의 수학적인 부분이나 프로그래밍 개념을 설명할 때는 독자가 기초적인 지식을 가지고 있지 않다고 가정하고 설명하는 것이 좋습니다.
#heart.js
e = [];// trails
h = [];// heart path
O = c.width = innerWidth;
Q = c.height = innerHeight;
v = 32; // num trails, num particles per trail & num nodes in heart path
M = Math;
R = M.random;
C = M.cos;
Y = 6.3;// close to 44/7 or Math.PI * 2 - 6.3 seems is close enough.
for( i = 0; i <Y; i+= .2 ) { // calculate heart nodes, from http://mathworld.wolfram.com/HeartCurve.html
h.push([
O/2 + 180*M.pow(M.sin(i), 3),
Q/2 + 10 * (-(15*C(i) - 5*C(2*i) - 2*C(3*i) - C(4*i)))
])
}
i = 0;
while (i < v ) {
x = R() * O;
y = R() * Q;
//r = R() * 50 + 200;
//b = R() * r;
//g = R() * b;
H = i/v * 80 + 280;
S = R() * 40 + 60;
B = R() * 60 + 20;
f = []; // create new trail
k = 0;
while ( k < v ) {
f[k++] = { // create new particle
x : x, // position
y : y,
X : 0, // velocity
Y : 0,
R : (1 - k/v) + 1, // radius
S : R() + 1, // acceleration
q : ~~(R() * v), // target node on heart path
//D : R()>.5?1:-1,
D : i%2*2-1, // direction around heart path
F : R() * .2 + .7, // friction
//f : "rgba(" + ~~r + "," + ~~g + "," + ~~b + ",.1)"
f : "hsla("+~~H+","+~~S+"%,"+~~B+"%,.1)" // colour
}
}
e[i++] = f; // dots are a 2d array of trails x particles
}
function render(_) { // draw particle
a.fillStyle = _.f;
a.beginPath();
a.arc(_.x, _.y, _.R, 0, Y, 1);
a.closePath();
a.fill();
}
function loop(){
a.fillStyle = "rgba(0,0,0,.2)"; // clear screen
a.fillRect(0,0,O,Q);
i = v;
while (i--) {
f = e[ i ]; // get worm
u = f[ 0 ]; // get 1st particle of worm
q = h[ u.q ]; // get current node on heart path
D = u.x - q[0]; // calc distance
E = u.y - q[1];
G = M.sqrt( (D * D) + (E * E) );
if ( G < 10 ) { // has trail reached target node?
if (R() > .95 ) { // randomly send a trail elsewhere
u.q = ~~(R() * v);
} else {
if ( R() > .99) u.D *= -1; // randomly change direction
u.q += u.D;
u.q %= v;
if ( u.q < 0 ) u.q += v;
}
}
u.X += -D / G * u.S; // calculate velocity
u.Y += -E / G * u.S;
u.x += u.X; // apply velocity
u.y += u.Y;
render(u); // draw the first particle
u.X *= u.F; // apply friction
u.Y *= u.F;
k = 0;
while ( k < v-1 ) { // loop through remaining dots
T = f[ k ]; // this particle
N = f[ ++k ]; // next particle
N.x -= (N.x - T.x) * .7; // use zenos paradox to create trail
N.y -= (N.y - T.y) * .7;
render(N);
}
}
}; // eo loop()
(function doit(){
requestAnimationFrame(doit);
loop();
}());
index.html
<!doctype html>
<html>
<head>
<title>heart</title>
<meta charset="utf-8">
</head>
<body>
<canvas id="c"></canvas>
<script>
var b = document.body;
var c = document.getElementsByTagName('canvas')[0];
var a = c.getContext('2d');
document.body.clientWidth;
</script>
<script src="https://raw.github.com/gist/1579671/7f515ade253afbc860dac1f84e21998d54359d79/rAF.js"></script>
<script src="heart.js"></script>
</body>
</html>
https://www.youtube.com/watch?v=PndFxaz4TnU
Window 크기에 맞게 HTML 5 Canvas 크기 조정하기 (0) | 2021.06.18 |
---|---|
CORS - DOMException: Failed to execute 'texImage2D' on 'WebGL2RenderingContext': Tainted canvases may not be loaded. (0) | 2021.05.11 |
Teachable Machine TensorFlow.js 예제 분석 (2) | 2021.05.10 |
Canvas 객체를 이미지로 AWS S3에 업로드 하기 (0) | 2021.05.10 |
이미지 객체를 Canvas 에 그리기 (0) | 2021.05.04 |
댓글 영역