콘텐츠로 이동

HTML5+JS

효과는 HTML5 캔버스 요소에서 바닐라 JavaScript를 사용하여 만들어집니다. 이 섹션에서는 도형 그리기, 반복으로 그리기, 모션 추가의 기초를 다룹니다.

이 튜토리얼에서는 일반적인 Lightscript 템플릿을 사용합니다:

<head>
<meta description="Template"/>
<meta publisher="WhirlwindFX" />
</head>
<body style="margin: 0; padding: 0;">
<canvas id="exCanvas" width="320" height="200"></canvas>
</body>
<script>
// Get the canvas element from the DOM
var c = document.getElementById("exCanvas");
var ctx = c.getContext("2d");
var width = 320;
var height = 200;
var hue = 0;
function update() {
// Code goes here
window.requestAnimationFrame(update);
}
window.requestAnimationFrame(update);
</script>

선을 하나 그리든 여러 개 그리든 과정은 동일합니다.

  1. **ctx.beginPath()**로 도형을 시작합니다.
  2. **ctx.moveTo(x, y)**로 첫 번째 점을 설정합니다.
  3. **ctx.lineTo(x, y)**로 다음 점을 설정하고 첫 번째 점으로 이어지는 선을 만듭니다. 더 큰 도형을 그리려면 lineTo를 여러 번 사용하십시오.
  4. ctx.strokeStyle 및/또는 ctx.fillStyle을 설정합니다(도형이 닫혀 있는 경우).
  5. **ctx.stroke()**로 선을 그리고, **ctx.fill()**로 닫힌 도형을 채웁니다. 이 명령이 실행되기 전까지는 모든 것이 가상 상태임을 주의하십시오.

선을 사용하는 세 가지 예시입니다:

function update() {
// One Line
ctx.beginPath();
ctx.moveTo(30, 30);
ctx.lineTo(30, 170);
ctx.strokeStyle = "blue";
ctx.stroke();
// L
ctx.beginPath();
ctx.moveTo(80, 30);
ctx.lineTo(80, 100);
ctx.lineTo(120, 100);
ctx.strokeStyle = "blue";
ctx.stroke();
// Filled Triangle
ctx.beginPath();
ctx.moveTo(130, 30);
ctx.lineTo(130, 100);
ctx.lineTo(170, 100);
ctx.lineTo(130, 30);
ctx.fillStyle = "red";
ctx.strokeStyle = "blue";
ctx.fill();
ctx.stroke();
window.requestAnimationFrame(update);
}

여기서 그리기 순서에 주의하십시오: 채워진 삼각형이 마지막에 그려지므로 같은 위치에 있었다면 다른 두 도형을 덮었을 것입니다. 또한 삼각형의 획은 채우기 후에 그려집니다. 이 단계를 반대로 하면 획의 안쪽 절반이 빨간색 채우기로 덮힐 것입니다.

직사각형은 단순하고 유용하며, 특히 RGB 키보드의 평균 해상도에 적합합니다. 선 그리기와 과정이 유사합니다. moveTolineTo 명령을 **rect(x, y, width, height)**로 대체하기만 하면 됩니다.

function update() {
// Basic Square
ctx.beginPath();
ctx.rect(30, 30, 75, 75);
ctx.strokeStyle = "blue";
ctx.stroke();
// Filled Rectangle
ctx.beginPath();
ctx.rect(125, 30, 125, 100);
ctx.fillStyle = "red";
ctx.strokeStyle = "blue";
ctx.fill();
ctx.stroke();
window.requestAnimationFrame(update);
}

호는 중심점을 기준으로 외부 점을 회전시켜 그리며, 완전한 을 만드는 데 사용할 수 있습니다. 호 명령은 **ctx.arc(x, y, 반지름, 시작 각도, 끝 각도)**이며, 두 각도는 모두 라디안으로 지정합니다. 직사각형과 달리 호는 도형의 원점 (x, y)이 호의 중심에 위치합니다.

function update() {
// Half-circle
ctx.beginPath();
ctx.arc(70, 100, 30, 0, Math.PI);
ctx.strokeStyle = "blue";
ctx.stroke();
// 3/4 circle
ctx.beginPath();
ctx.arc(140, 100, 30, 0, Math.PI * (3/2));
ctx.strokeStyle = "blue";
ctx.stroke();
// Full circle
ctx.beginPath();
ctx.arc(210, 100, 30, 0, Math.PI * 2);
ctx.strokeStyle = "blue";
ctx.stroke();
ctx.fillStyle = "red";
ctx.fill();
window.requestAnimationFrame(update);
}

보시다시피 호는 기본적으로 시계 방향으로 그려집니다. 시작 각도보다 작은 끝 각도를 사용하거나 ctx.arc() 메서드의 마지막 인수로 “true”를 추가하면 반시계 방향으로 변경할 수 있습니다.

도형 세 개를 직접 그리는 데 쉽게 스무 줄의 코드가 필요할 수 있으므로, 백 개의 도형을 그려야 한다면 더 효율적인 방법이 필요합니다. JavaScript의 루프는 작업을 반복하는 간단한 방법이며 그리기에도 적용할 수 있습니다.

for 루프를 사용하여 체크무늬 정사각형 행을 그리는 예시입니다:

function update() {
for(let i = 0; i < 8; i++){
// 1. Create rectangle path and draw the stroke for each.
ctx.beginPath();
ctx.rect(i * 20, 20, 20, 20);
ctx.strokeStyle = "black";
ctx.stroke();
// 2. If 'i' is even, the fillStyle is black. Otherwise it's white.
if(i % 2 == 0){
ctx.fillStyle = "black";
} else {
ctx.fillStyle = "white";
}
// 3. Fill the shape after setting the fillStyle.
ctx.fill();
}
window.requestAnimationFrame(update);
}

체크무늬 격자를 그리는 while 루프 예시입니다. 템플릿 리터럴을 사용하여 각 반복에서 검정 정사각형의 밝기와 흰색 정사각형의 색조를 약간씩 변경합니다.

function update() {
var i = 0;
while(i < 16){
// 1. X and Y calculations with 'row' and 'column'
var iRow = Math.floor(i / 4);
var iCol = i % 4;
var ix = iCol * 20;
var iy = iRow * 20;
// 2. Path and stroke
ctx.beginPath();
ctx.rect(ix, iy, 20, 20);
ctx.strokeStyle = "black";
ctx.stroke();
// 3. Fill based on row/column parity
if(iRow % 2 == 0){
if(i % 2 == 0){
ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)`
} else {
ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`;
}
} else {
if(i % 2 == 0){
ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`;
} else {
ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)`
}
}
ctx.fill();
i++;
}
window.requestAnimationFrame(update);
}

캔버스 애니메이션은 여러분의 상상력과 수학 지식에 의해서만 제한됩니다. 삼각법이나 기하학이 불안하다면 실력을 한 단계 높이기 위해 가벼운 자료를 찾아보는 것을 권장합니다. 다음 몇 가지 예시에서 정적인 원에 단순한 진동 모션을 사용하여 가능한 모든 변수를 연결합니다.

진동(규칙적인 앞뒤 운동)의 황금 표준은 타이머의 sin() 또는 **코사인()**을 취하는 것입니다. 두 연산 모두 ANY 값이 전달되더라도 -1에서 1 사이의 값을 반환합니다. 두 연산의 유일한 차이점은 약간 동기화되어 있지 않다는 것입니다. cos가 0일 때 sin은 -1 또는 1이고, 반대로도 마찬가지입니다. 이를 이 애니메이션에서 활용할 수 있습니다:

function update() {
// Find current time in milliseconds, then divide to slow down the animation speed
let time = Date.now() / 100;
// Draw a background so the old shapes don't stick around
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 320,200);
ctx.beginPath();
//USE ONE EXAMPLE AT A TIME
// 1st example - side to side, y is constant
ctx.arc(15 * Math.cos(time) + 160, 100, 30, 0, Math.PI * 2);
// 2nd example - up and down, x is constant
ctx.arc(160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2);
// 3rd example - circle, x and y are variable
ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2);
ctx.fillStyle = "black";
ctx.fill();
window.requestAnimationFrame(update);
}

이제 시간에 따라 변경할 수 있는 몇 가지 속성이 더 남았습니다: 원 반지름, 채우기, 획. 도형을 단순하게 유지하기 위해 호 각도는 그대로 두겠습니다. 나머지는 꽤 화려해질 것입니다.

function update() {
let time = Date.now() / 100;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 320,200);
ctx.beginPath();
ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30 + 15 * Math.sin(time), 0, Math.PI * 2);
ctx.fillStyle = `hsl(${180 + 180 * Math.cos(time)}, 100%, 50%)`;
ctx.fill();
ctx.strokeStyle = `hsl(${180 + 180 * Math.sin(time)}, 100%, 50%)`;
ctx.stroke();
window.requestAnimationFrame(update);
}

지금까지 만든 모든 도형의 모든 속성을 시간에 따라 변경할 수 있으며, 제가 만드는 모든 애니메이션은 위의 기술을 조합한 것입니다. 재사용 가능하고 효율적인 애니메이션 제작에 대한 자세한 내용은 콜백 페이지를 확인하십시오!