๊ธฐ๋ณธ ์ ๋๋ฉ์ด์
<canvas> ์์๋ JavaScript๋ก ์ ์ดํ๋ ๊ฒ์ด๋ฏ๋ก, ์ ๋๋ฉ์ด์
๋ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ๋ณต์กํ ์ ๋๋ฉ์ด์
์ ๋ง๋๋ ๊ฒ์ ์ถ๊ฐ ์์
์ด ๋ ํ์ํ๊ณ , ์์ผ๋ก ๊ทธ์ ๋ํ ํ์ด์ง๋ ๋จธ์ง ์์ ์ถ๊ฐ๋๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค.
๋ํ์ ํ๋ฒ ๋ง๋ค์ด ๋์ผ๋ฉด ๊ทธ ๋ชจ์ต ๊ทธ๋๋ก ์๋ค๋ ๊ฒ์ด ์ ๋๋ฉ์ด์ ์ ๋ง๋ค ๋์ ๊ฐ์ฅ ํฐ ์ ์ฝ์ผ ๊ฒ์ ๋๋ค. ๊ทธ ๋ํ์ ์์ง์ด๊ณ ์ ํ๋ฉด ๊ทธ ๋ํ๋ฟ๋ง์ด ์๋๋ผ ๊ทธ ๋ํ์ด ๊ทธ๋ ค์ง๊ธฐ ์ ์ ๊ทธ๋ ค์ง ๋ชจ๋ ๊ฒ์ ๋ค์ ๊ทธ๋ ค์ผ ํฉ๋๋ค. ๋ณต์กํ ์ฅ๋ฉด์ ๋ค์ ๊ทธ๋ฆฌ๋ ๊ฒ์ ์๊ฐ๋ ๋ง์ด ๊ฑธ๋ฆฌ๋ฉฐ, ์ฝ๋๋ฅผ ์คํํ๋ ์ปดํจํฐ์ ๋ฅ๋ ฅ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค.
๊ธฐ๋ณธ ์ ๋๋ฉ์ด์ ๋จ๊ณ
ํ ์ฅ๋ฉด์ ๊ทธ๋ฆฌ๋ ค๋ฉด ์๋์ ๊ฐ์ ๋จ๊ณ๋ฅผ ๋ฐ์ต๋๋ค.
- ์บ๋ฒ์ค๋ฅผ ๋น์๋๋ค.
๊ทธ๋ฆฌ๋ ค๋ ๋ํ์ด (๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค ๋์ฒ๋ผ) ์บ๋ฒ์ค๋ฅผ ๊ฐ๋ ์ฑ์ฐ๋ ๊ฒ์ด ์๋๋ผ๋ฉด, ์ด์ ์ ๊ทธ๋ ค์ง ๋ชจ๋ ๋ํ์ ์ง์ธ ํ์๊ฐ ์์ต๋๋ค. ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์
clearRect()๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. - ์บ๋ฒ์ค ์ํ๋ฅผ ์ ์ฅํฉ๋๋ค. ์บ๋ฒ์ค ์ํ์ ์ํฅ์ ์ฃผ๋ (์คํ์ผ ๋ณ๊ฒฝ, ๋ชจ์ ๋ณํ ๋ฑ์) ์ค์ ๊ฐ์ ๋ฐ๊พธ๋ ค๊ณ ํ๊ณ , ๋ฐ๋ ๊ฐ์ ๊ฐ ์ฅ๋ฉด๋ง๋ค ์ฌ์ฉํ๋ ค๊ณ ํ๋ค๋ฉด, ์๋ ์ํ๋ฅผ ์ ์ฅํ ํ์๊ฐ ์์ต๋๋ค.
- ์ ๋๋ฉ์ด์ ํ ๋ํ์ ๊ทธ๋ฆฝ๋๋ค. ์ค์ ์ฅ๋ฉด์ ๊ทธ๋ฆฌ๋ ๋จ๊ณ์ ๋๋ค.
- ์บ๋ฒ์ค ์ํ๋ฅผ ๋ณต์ํฉ๋๋ค. ์๋ก์ด ์ฅ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ ์ ์ ์ ์ฅ๋ ์ํ๋ฅผ ๋ณต์ํฉ๋๋ค.
์ ๋๋ฉ์ด์ ์ ์ดํ๊ธฐ
์บ๋ฒ์ค ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์ฌ์ฉ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์บ๋ฒ์ค์ ๋ํ๋ค์ ๊ทธ๋ฆฝ๋๋ค. ๋ณดํต์ ๊ฒฝ์ฐ์์๋, ์ฝ๋ ์คํ์ด ์๋ฃ๋๋ฉด ์บ๋ฒ์ค์ ๋ํ๋๋ ๊ฒฐ๊ณผ๋ง์ ๋ณด๊ฒ ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, for ๋ฐ๋ณต๋ฌธ ์์์ ์ ๋๋ฉ์ด์
์ ์คํํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
๊ทธ๋์ ์ ํด์ง ์๊ฐ๋ง๋ค ๊ทธ๋ฆฌ๊ธฐ ํจ์๋ฅผ ์คํํ๋ ๋ฐฉ๋ฒ์ด ํ์ํ ๊ฒ์ ๋๋ค. ์๋์ ๊ฐ์ด ์ ๋๋ฉ์ด์ ์ ์ ์ดํ๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
์์ ๋ ๋ณ๊ฒฝ
์ ํด์ง ์๊ฐ๋ง๋ค ํน์ ํจ์๋ฅผ ๋ถ๋ฅผ ๋ ์ฌ์ฉํ ์ ์๋ window.setInterval()๊ณผ window.setTimeout() ํจ์๊ฐ ์์ต๋๋ค.
์ฐธ๊ณ :
์์๋ ๊ฒ: ํ์ฌ๋ ์ ๋๋ฉ์ด์
์ ๋ง๋๋ ๋ฐฉ๋ฒ์ผ๋ก window.requestAnimationFrame() ๋ฉ์๋๋ฅผ ์ถ์ฒํฉ๋๋ค. ์ด์ ๋ํ ํํ ๋ฆฌ์ผ์ ๊ณง ์
๋ฐ์ดํธํ ๊ฒ์
๋๋ค.
setInterval(function, delay)-
delay๋ฐ๋ฆฌ์ธ์ปจ๋(1,000๋ถ์ 1์ด)๋ง๋คfunctionํจ์ ๋ฐ๋ณต ์คํ์ ์์ํฉ๋๋ค. setTimeout(function, delay)-
delay๋ฐ๋ฆฌ์ธ์ปจ๋(1,000๋ถ์ 1์ด) ๊ฒฝ๊ณผํ,functionํจ์๋ฅผ ์คํํฉ๋๋ค.
์ฌ์ฉ์์ ์ ์ด๋ฅผ ํ์๋ก ํ์ง ์๋ ๋ฐ๋ณต ์คํ์๋ setInterval() ํจ์๊ฐ ์๋ง์ ๊ฒ์
๋๋ค.
์ฌ์ฉ์ ์ํธ ์์ฉ ๋ณ๊ฒฝ
์ ๋๋ฉ์ด์
์ ์ ์ดํ๋ ๋๋ฒ์งธ ๋ฐฉ๋ฒ์ ์ฌ์ฉ์ ์
๋ ฅ์
๋๋ค. ๊ฒ์์ ๋ง๋ค๋ ค๊ณ ํ๋ค๋ฉด, ์ ๋๋ฉ์ด์
์ ์ ์ดํ๊ธฐ ์ํด ํค๋ณด๋๋ ๋ง์ฐ์ค ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ ์ ์์ ๊ฒ์
๋๋ค. EventListener๋ฅผ ์ค์ ํ์ฌ, ์ฌ์ฉ์์ ์ํธ ์์ฉํ์ฌ ์ ๋๋ฉ์ด์
ํจ์๋ฅผ ์คํํฉ๋๋ค.
์ฌ์ฉ์ ์ํธ ์์ฉ์ด ํ์ํ๋ค๋ฉด, ์ฐ๋ฆฌ๊ฐ ๋ง๋ ์ ๋๋ฉ์ด์ ์ฉ ํ๋ ์์(framework)์ ์ต์ ๊ธฐ๋ฅ ๋ฒ์ ๋๋ ์ต๋ ๊ธฐ๋ฅ ๋ฒ์ ์ ์ฌ์ฉํ ์ ์์ ๊ฒ์ ๋๋ค.
var myAnimation = new MiniDaemon(null, animateShape, 500, Infinity);
๋๋
var myAnimation = new Daemon(null, animateShape, 500, Infinity);
์๋ ์์ ์์๋, ์ ๋๋ฉ์ด์
์ ์ ์ดํ๊ธฐ ์ํด window.setInterval()์ ์ฌ์ฉํ ๊ฒ์
๋๋ค. ํ์ด์ง ์ ์ผ ์๋์ชฝ์ window.setTimeout()์ ์ฌ์ฉํ ์์ ๋งํฌ๋ ์์ต๋๋ค.
ํ์๊ณ ์ ๋๋ฉ์ด์
์ด ์์ ์์๋ ๋ฌ์ด ์ง๊ตฌ๋ฅผ ๋๊ณ ์ง๊ตฌ๊ฐ ํ์์ ๋๋ ์ ๋๋ฉ์ด์ ์ ๋ง๋ญ๋๋ค.
var sun = new Image();
var moon = new Image();
var earth = new Image();
function init() {
sun.src = "canvas_sun.png";
moon.src = "canvas_moon.png";
earth.src = "canvas_earth.png";
setInterval(draw, 100);
}
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
ctx.globalCompositeOperation = "destination-over";
ctx.clearRect(0, 0, 300, 300); // ์บ๋ฒ์ค๋ฅผ ๋น์ด๋ค
ctx.fillStyle = "rgba(0,0,0,0.4)";
ctx.strokeStyle = "rgba(0,153,255,0.4)";
ctx.save();
ctx.translate(150, 150);
// ์ง๊ตฌ
var time = new Date();
ctx.rotate(
((2 * Math.PI) / 60) * time.getSeconds() +
((2 * Math.PI) / 60000) * time.getMilliseconds(),
);
ctx.translate(105, 0);
ctx.fillRect(0, -12, 50, 24); // Shadow
ctx.drawImage(earth, -12, -12);
// ๋ฌ
ctx.save();
ctx.rotate(
((2 * Math.PI) / 6) * time.getSeconds() +
((2 * Math.PI) / 6000) * time.getMilliseconds(),
);
ctx.translate(0, 28.5);
ctx.drawImage(moon, -3.5, -3.5);
ctx.restore();
ctx.restore();
ctx.beginPath();
ctx.arc(150, 150, 105, 0, Math.PI * 2, false); // ์ง๊ตฌ ๊ถค๋
ctx.stroke();
ctx.drawImage(sun, 0, 0, 300, 300);
}
์๊ณ ์ ๋๋ฉ์ด์
์ด ์์ ์์๋, ํ์ฌ ์๊ฐ์ ๋ณด์ฌ์ฃผ๋ ์์ง์ด๋ ์๊ณ๋ฅผ ๋ง๋ญ๋๋ค.
function init() {
clock();
setInterval(clock, 1000);
}
function clock() {
var now = new Date();
var ctx = document.getElementById("canvas").getContext("2d");
ctx.save();
ctx.clearRect(0, 0, 150, 150);
ctx.translate(75, 75);
ctx.scale(0.4, 0.4);
ctx.rotate(-Math.PI / 2);
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx.lineWidth = 8;
ctx.lineCap = "round";
// ์๊ณํ - ์
ctx.save();
for (var i = 0; i < 12; i++) {
ctx.beginPath();
ctx.rotate(Math.PI / 6);
ctx.moveTo(100, 0);
ctx.lineTo(120, 0);
ctx.stroke();
}
ctx.restore();
// ์๊ณํ - ๋ถ
ctx.save();
ctx.lineWidth = 5;
for (i = 0; i < 60; i++) {
if (i % 5 != 0) {
ctx.beginPath();
ctx.moveTo(117, 0);
ctx.lineTo(120, 0);
ctx.stroke();
}
ctx.rotate(Math.PI / 30);
}
ctx.restore();
var sec = now.getSeconds();
var min = now.getMinutes();
var hr = now.getHours();
hr = hr >= 12 ? hr - 12 : hr;
ctx.fillStyle = "black";
// ์๊ฐ ํ์ - ์
ctx.save();
ctx.rotate(
hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) * sec,
);
ctx.lineWidth = 14;
ctx.beginPath();
ctx.moveTo(-20, 0);
ctx.lineTo(80, 0);
ctx.stroke();
ctx.restore();
// ์๊ฐ ํ์ - ๋ถ
ctx.save();
ctx.rotate((Math.PI / 30) * min + (Math.PI / 1800) * sec);
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(-28, 0);
ctx.lineTo(112, 0);
ctx.stroke();
ctx.restore();
// ์๊ฐ ํ์ - ์ด
ctx.save();
ctx.rotate((sec * Math.PI) / 30);
ctx.strokeStyle = "#D40000";
ctx.fillStyle = "#D40000";
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(-30, 0);
ctx.lineTo(83, 0);
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, 10, 0, Math.PI * 2, true);
ctx.fill();
ctx.beginPath();
ctx.arc(95, 0, 10, 0, Math.PI * 2, true);
ctx.stroke();
ctx.fillStyle = "rgba(0,0,0,0)";
ctx.arc(0, 0, 3, 0, Math.PI * 2, true);
ctx.fill();
ctx.restore();
ctx.beginPath();
ctx.lineWidth = 14;
ctx.strokeStyle = "#325FA2";
ctx.arc(0, 0, 142, 0, Math.PI * 2, true);
ctx.stroke();
ctx.restore();
}
์์ง์ด๋ ํ๋ ธ๋ผ๋ง ์ฌ์ง
์ด ์์ ์์๋, ์์ง์ด๋ ํ๋ ธ๋ผ๋ง ์ฌ์ง์ ๋ง๋ญ๋๋ค. ์ฌ์ฉํ ๊ทธ๋ฆผ์ ์ํคํผ๋์ด(Wikipedia)์์ ๊ตฌํ ์์ธ๋ฏธํฐ ๊ตญ๋ฆฝ๊ณต์์ ๋๋ค. ์บ๋ฒ์ค๋ณด๋ค ํฐ ๊ทธ๋ฆผ์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
var img = new Image();
// ๋ณ์
// ์คํฌ๋กค๋ ์ด๋ฏธ์ง, ๋ฐฉํฅ, ์๋๋ฅผ ๋ฐ๊พธ๋ ค๋ฉด ๋ณ์๊ฐ์ ๋ฐ๊พผ๋ค.
img.src = "capitan_meadows,_yosemite_national_park.jpg";
var CanvasXSize = 800;
var CanvasYSize = 200;
var speed = 30; // ๊ฐ์ด ์์ ์๋ก ๋นจ๋ผ์ง๋ค
var scale = 1.05;
var y = -4.5; // ์์ง ์ต์
// ์ฃผ์ ํ๋ก๊ทธ๋จ
var dx = 0.75;
var imgW;
var imgH;
var x = 0;
var clearX;
var clearY;
var ctx;
img.onload = function () {
imgW = img.width * scale;
imgH = img.height * scale;
if (imgW > CanvasXSize) {
x = CanvasXSize - imgW;
} // ์บ๋ฒ์ค๋ณด๋ค ํฐ ์ด๋ฏธ์ง
if (imgW > CanvasXSize) {
clearX = imgW;
} // ์บ๋ฒ์ค๋ณด๋ค ํฐ ์ด๋ฏธ์ง
else {
clearX = CanvasXSize;
}
if (imgH > CanvasYSize) {
clearY = imgH;
} // ์บ๋ฒ์ค๋ณด๋ค ํฐ ์ด๋ฏธ์ง
else {
clearY = CanvasYSize;
}
// ์บ๋ฒ์ค ์์ ์ป๊ธฐ
ctx = document.getElementById("canvas").getContext("2d");
// ์๋ก ๊ทธ๋ฆฌ๊ธฐ ์๋ ์ค์
return setInterval(draw, speed);
};
function draw() {
// ์บ๋ฒ์ค๋ฅผ ๋น์ด๋ค
ctx.clearRect(0, 0, clearX, clearY);
// ์ด๋ฏธ์ง๊ฐ ์บ๋ฒ์ค๋ณด๋ค ์๊ฑฐ๋ ๊ฐ๋ค๋ฉด (If image is <= Canvas Size)
if (imgW <= CanvasXSize) {
// ์ฌ์ค์ , ์ฒ์๋ถํฐ ์์
if (x > CanvasXSize) {
x = 0;
}
// ์ถ๊ฐ ์ด๋ฏธ์ง ๊ทธ๋ฆฌ๊ธฐ
if (x > CanvasXSize - imgW) {
ctx.drawImage(img, x - CanvasXSize + 1, y, imgW, imgH);
}
}
// ์ด๋ฏธ์ง๊ฐ ์บ๋ฒ์ค๋ณด๋ค ํฌ๋ค๋ฉด (If image is > Canvas Size)
else {
// ์ฌ์ค์ , ์ฒ์๋ถํฐ ์์
if (x > CanvasXSize) {
x = CanvasXSize - imgW;
}
// ์ถ๊ฐ ์ด๋ฏธ์ง ๊ทธ๋ฆฌ๊ธฐ
if (x > CanvasXSize - imgW) {
ctx.drawImage(img, x - imgW + 1, y, imgW, imgH);
}
}
// ์ด๋ฏธ์ง ๊ทธ๋ฆฌ๊ธฐ
ctx.drawImage(img, x, y, imgW, imgH);
// ์์ง์ ์ ๋
x += dx;
}
์์ ์ ์ฌ์ฉ๋ <canvas>์ ํฌ๊ธฐ๋ ์๋์ ๊ฐ๋ค. ์บ๋ฒ์ค์ ๋๋น๊ฐ ๋ณ์ CanvasXSize๊ฐ๊ณผ ๊ฐ๊ณ , ์บ๋ฒ์ค์ ๋์ด๋ ๋ณ์ CanvasYSize๊ฐ๊ณผ ๊ฐ๋ค๋ ๊ฒ์ ์ฃผ๋ชฉํ๋ผ.
<canvas id="canvas" width="800" height="200"></canvas>
Live sample
๋ ๋ค๋ฅธ ์์ ๋ค
- Gartic
-
๋ค์ค ์ฌ์ฉ์ ์ง์ ๊ทธ๋ฆฌ๊ธฐ ๋์ด.
- Canvascape
-
3D ์ด๋๋ฒค์ฒ ๊ฒ์ (1์ธ์นญ ์ํ ).
- A basic ray-caster
-
ํค๋ณด๋๋ฅผ ์ฌ์ฉํ ์ ๋๋ฉ์ด์ ์ ์ด ๋ฐฉ๋ฒ์ ๋ํ ์ข์ ์์ .
- canvas adventure
-
ํค๋ณด๋ ์ ์ด๋ฅผ ์ฌ์ฉํ๋ ๋๋ค๋ฅธ ์ข์ ์์ .
- An interactive Blob
-
๋ฌผ๋ฐฉ์ธ ๊ฐ๊ณ ๋๊ธฐ.
- Flying through a starfield
-
๋ณ, ๋๊ทธ๋ผ๋ฏธ, ๋ค๋ชจ๊ฐ ๋ ๋ค๋๋ ์ฐ์ฃผ๋ฅผ ๋๋ฒผ๋ผ.
- iGrapher
-
์ฃผ์ ์์ฅ ์๋ฃ ์ฐจํธ ์์ .