HTML5 Canvas คืออะไร? + วิธีใช้งานเบื้องต้น
HTML5 Canvas เป็นหนึ่งใน feature ที่มีคุณสมบัติทางด้านกราฟฟิคที่มาพร้อมกับ HTML5 โดยส่วนตัวเพิ่งเริ่มสนใจ Canvas ก็ตอนที่ได้ลองหัดทำเกมส์บน Browser นี่แหละครับ เลยไปนั่งอ่านและลองทำความเข้าใจอยู่ซักพัก สุดท้ายก็เลยเขียนและเรียบเรียงตามความเข้าใจของตัวเองไว้
ตัวอย่างนี้เป็นการทดลองและลองเล่น HTML5 Canvas โดยจะนำเสนอและวิธีการใช้งานและวาดรูปทรงต่างๆเบื้องต้น ทั้ง วาดสี่เหลี่ยม วาดวงกลม วาดเส้น แบบง่ายๆ :)
Canvas คืออะไร ?
Canvas เป็น Element หนึ่งใน HTML5 เหมือนอย่าง <img>
หรือ <a>
โดยใน <img>
หรือ <a>
จะมี attributes เช่น src
และ href
แต่ใน <canvas>
จะมีเพียงแค่ 2 attributes คือ width
และ height
(ความกว้างและความสูงของ Canvas) เท่านั้น
Note:
<canvas>
นั้น required closed tag ด้วยไม่เหมือนอย่าง<img>
ฉะนั้นก็อย่าลืมปิดแท็กด้วย</canvas>
นะครับ :)
ตัวอย่างเช่น
<canvas id="tutorial" width="150" height="150"></canvas>
เป็นการประกาศสร้าง Element <canvas>
ขึ้นมาโดยมี id ชื่อ canvas
และมีความกว้างและความสูง 150 pixels
Note: โดยปกติแล้ว
canvas
จะมีความกว้าง 300px และสูง 150px ถึงแม้ว่าเราจะไม่ได้กำหนดขนาดให้มันก็ตาม
ใช้งาน Canvas เบื้องต้น
เริ่มแรกทำการสร้างไฟล์ HTML ขึ้นมา ผมทำการตั้งชื่อว่า index.html
และมี element <canvas>
ดังตัวอย่าง
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>HTML5 Canvas Tutorials</title>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script src="main.js"></script>
</body>
</html>
จากนั้นลิงค์สคริปไปยังไฟล์ JavaScript ของเรา โดยทำการตั้งชื่อว่า main.js
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
จากโค๊ดด้านบน เราทำการเลือก element ที่มีไอดีว่า canvas
ซึ่งก็คือตัว <canvas>
จากนั้นทำการ getContext('2d')
เพื่อทำการใช้ canvas context แบบ 2d (เป็นออปเจ็คที่เอาไว้วาดและสร้างกราฟฟิคต่างๆ)
ระบบ Coordinate System
โดยปกติแล้ว หากได้เรียนคณิตศาสตร์มา จะพบว่าเราจะใช้การกำหนดแกน x, y ด้วยระบบ Cartesian coordinate system ซึ่งกำหนดจุด x, y จากการลากเส้นแกนทั้งสองตัดกันเป็นมุมฉาก
ส่วนระบบของ Canvas coordinate system จะต่างออกไป จะนับจุดบนซ้ายเป็นจุด 0,0 ดังตัวอย่างเปรียบเทียบในภาพด้านล่างครับ
วาดสี่เหลี่ยม
การวาดสี่เหลี่ยม สามารถใช้ฟังค์ชัน fillRect(x, y, width, height)
โดย x คือแกน x, y คือแกน y และ width, height คือความกว้างและความสูง ตามลำดับ
โดยเมื่อเราเลือก Element canvas
และทำการ getContext()
แล้ว เราสามารถวาดสี่เหลี่ยมแบบง่ายๆ ด้วยโค๊ดแบบนี้
// กำหนดสี
context.fillStyle = 'green';
// วาดสี่เหลี่ยม Rectangle (x, y, width, height)
// โดยแกน x,y จะนับจากมุมบนซ้ายเป็นจุด 0, 0
context.fillRect(10, 10, 100, 100);
See the Pen WbyJEV by Chai Phonbopit (@Phonbopit) on CodePen.
นอกจาก fillRect()
แล้ว เรายังสามารถใช้
strokeRect(x, y, width, height)
: เพื่อวาดสี่เหลี่ยมให้มีเฉพาะเส้นขอบclearRect(x, y, width, height)
: วาดสี่เหลี่ยมให้เป็น transparent หรืออีกในหนึ่งก็คือการลบ content อื่นๆ (เหมือนเป็นยางลบ)
เช่น
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.fillStyle = 'green';
context.fillRect(10, 10, 100, 100);
context.strokeStyle = 'red';
context.strokeRect(110, 110, 200, 200);
context.clearRect(35, 35, 50, 50);
See the Pen jEKxGO by Chai Phonbopit (@Phonbopit) on CodePen.
Paths
ให้นึกถึงเวลาคุณจับดินสอวาดรูป Path หนึ่งก็เหมือนกับการจิ้มดินสอลงบนกระดาษ เวลาคุณวาดรูป คุณก็จะมีการยกดินสอขึ้น และเลื่อนไปยังอีกตำแหน่งเพื่อวาดภาพต่อๆมา (ลองนึกว่าให้คุณวาดรูปแมวโดยไม่ยกดินสอซิ เปรียบเสมือนใช้ Canvas แค่ Path เดียว)
ฉะนั้น Path จะมีด้วยกัน 2 เมธอดคือ (ให้นึกถึงการใช้ดินสอวาดรูปเหมือนเดิม)
moveTo(x, y)
: หมายถึงเลื่อนดินสอไปยังตำแหน่งที่ต้องการ (จุดเริ่มต้น)lineTo(x, y)
: หมายถึงว่าลากเส้นไปถึงตำแหน่งไหน (จุดสุดท้ายที่ยกมือ)
เช่น
context.moveTo(0, 100);
context.lineTo(200, 100);
แต่ว่ายังไม่มีอะไรเกิดขึ้น เนื่องจากว่าดินสอเราไส้หมดครับ ต้องเดิมไส้ใหม่ พอดีใช้ดินสอกด :)
context.strokeStyle = 'black';
context.stroke();
วาดวงกลม
การวาดวงกลมจะใช้ context.arc()
ดังนี้ context.arc(x, y, radius, startAngle, endAngle, anticlockwise)
โดย
- x,y คือ แกน x และ y
- radius: รัศมีของวงกลม
- startAngle, endAngle คือ เรเดียน
- anticlockwise : ทวนเข็มหรือตามเข็มนาฬิกา (true/false)
เช่นตัวอย่าง จะทำการวาดวงกลม 2 วง วงแรกขนาดรัศมี 40 ตรงตำแหน่ง 50, 50 โดยวาดเฉพาะเส้นรอบวง และวงที่สองขนาดเท่ากัน ที่ตำแหน่ง 120, 120 และวาดทั้งวงกลม จะได้ดังนี้
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.beginPath();
context.strokeStyle = 'black';
context.lineWidth = 5;
context.arc(50, 50, 40, 0, Math.PI * 2, false);
context.stroke();
context.closePath();
context.beginPath();
context.fillStyle = '#dd0343';
context.arc(120, 120, 40, 0, Math.PI * 2);
context.fill();
context.closePath();
See the Pen GgGdOw by Chai Phonbopit (@Phonbopit) on CodePen.
วาดเส้น
การวาดเส้นบน Canvas
เราจะใช้ร่วมกับการใช้ Path โดยมีฟังค์ชันที่สำคัญดังนี้
context.beginPath()
: สำหรับกำหนด pathcontext.moveTo(x, y)
: ตำแหน่งเริ่มต้นในการวาดcontext.lineTo(x, y)
: ตำแหน่งสิ้นสุดการวาดcontext.lineWidth
: เอาไว้กำหนดขนาดของเส้นcontext.strokeStyle
: เอาไว้กำหนดสีของเส้นcontext.lineCap
: กำหนดรูปแบบของเส้น เช่นround
,square
หรือbutt
ตัวอย่าง เช่น
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.beginPath();
context.strokeStyle = '#3984dd';
context.lineWidth = 10;
context.moveTo(50, 50);
context.lineTo(50, 200);
context.stroke();
context.beginPath();
context.strokeStyle = '#dd0343';
context.lineWidth = 10;
context.lineCap = 'round';
context.moveTo(100, 50);
context.lineTo(100, 200);
context.stroke();
context.beginPath();
context.strokeStyle = '#06f3d2';
context.lineWidth = 10;
context.lineCap = 'butt';
context.moveTo(150, 50);
context.lineTo(150, 200);
context.stroke();
See the Pen ZYRorp by Chai Phonbopit (@Phonbopit) on CodePen.
วาด Text
การวาด Text จะมีด้วยกัน 2 เมธอดคือ
fillText(text, x, y)
: คือการแสดง Text แบบปกติstrokeText(text, x, y)
: วาดแต่เส้นขอบของ Text
และเมธอดสำคัญๆ อื่นๆด้วย เช่น
font
: ทำการกำหนดขนาดและฟ้อนที่ต้องการใช้fillStyle
: ไว้กำหนดสีของ Text แบบเดียวกันกับการวาดสี่เหลี่ยม วงกลม เส้นtextAlign
: สามารถกำหนดtext-align
ได้
ดังเช่นตัวอย่าง
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.beginPath();
context.font = '50px Open Sans sans-serif';
context.fillStyle = '#f36';
context.fillText('Hello HTML5 Canvas', 50, 50);
See the Pen EaRLEX by Chai Phonbopit (@Phonbopit) on CodePen.
ประยุกต์ใช้ Canvas แบบง่ายๆ
ตัวอย่างผมจะลองสร้าง ลูกบอล จากนั้นก็ให้มันเด้ง อยู่ภายใน canvas
เริ่มแรกผมสร้างลูกบอลขึ้นมา โดยกำหนด x, y, radius, speedX, speedY ต่างๆ เพื่อกำหนดตำแหน่งลูกบอล รัศมี ความเร็วบอลในแกน x,y ดังนี้
var ball = {
x: 20,
y: 200,
radius: 20,
speedX: 2,
speedY: 4
};
จากนั้นก็ใช้ฟังค์ชั่น context.arc()
เพื่อวาดวงกลมลงไป แต่มันจะไม่ขยับ ก็เลยต้องใช้ setInterval()
เพื่อให้มัน refresh ทุกๆ 1000/60 millisec (60 FPS)
setInterval(functino() {
update();
render();
}, 1000 / 60);
จากนั้นผมสร้างฟังค์ชัน update()
เพื่อเอาไว้วาดวงกลมทุกๆครั้งที่ถูกรีเฟรซ จุดประสงค์คือทุกครั้งที่รีเฟรซก็จะทำการขยับตำแหน่ง ball จะได้ดังนี้
ball.x += ball.speedX;
ball.y += ball.speedY;
เมื่อลองรันดูจะพบผลลัพธ์ดังนี้ (ลูกบอลทั้งหมดไม่ถูกลบ แต่จะซ้อนทับกันไปเรื่อยๆ)
See the Pen MYXGBj by Chai Phonbopit (@Phonbopit) on CodePen.
ฉะนั้นก็เลยต้องทำการเคลียร์ canvas
ก่อนทุกครั้ง
canvas.width = canvas.width; // reset canvas
ball.x += ball.speedX;
ball.y += ball.speedY;
Note: Clear Canvas ง่ายๆด้วย
canvas.width = canvas.width;
ซึ่งจริงๆจะใช้clearRect(0, 0, canvas.width, canvas.height)
ก็ได้
ต่อมา render()
ผมเอาไว้แสดงผลลูกบอล (update()
เอาไว้เปลี่ยนแปลง x,y เฉยๆ ไม่ได้วาด)
function render() {
context.fillStyle = '#2634dd';
context.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
context.fill();
}
สุดท้ายกำหนดเงื่อนไข ถ้าลูกบอลเด้งไปโดนขอบ แต่ละด้าน ให้มันเด้งกลับ (ใช้ speed *= -1
)
ดังนี้
if (ball.x > canvas.width - ball.radius || ball.x < ball.radius) {
ball.speedX *= -1;
}
if (ball.y > canvas.height - ball.radius || ball.y < ball.radius) {
ball.speedY *= -1;
}
ball.x += ball.speedX;
ball.y += ball.speedY;
สุดท้ายโค๊ดทั้งหมด และตัวอย่างเดโม่
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var ball = {
x: 20,
y: 200,
radius: 20,
speedX: 2,
speedY: 4
};
start();
function start() {
setInterval(function () {
update();
render();
}, 1000 / 60);
}
function update() {
canvas.width = canvas.width; // reset canvas
if (ball.x > canvas.width - ball.radius || ball.x < ball.radius) {
ball.speedX *= -1;
}
if (ball.y > canvas.height - ball.radius || ball.y < ball.radius) {
ball.speedY *= -1;
}
ball.x += ball.speedX;
ball.y += ball.speedY;
}
function render() {
context.fillStyle = '#2634dd';
context.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
context.fill();
}
See the Pen RNJyJq by Chai Phonbopit (@Phonbopit) on CodePen.
สรุป
บทความนี้ก็เป็นการนำเสนอ HTML5 Canvas แบบง่ายๆสำหรับผู้เริ่มต้น ในแบบฉบับของผมนะครับ ซึ่งผมก็เพิ่งจะนั่งศึกษา นั่งอ่าน ตามเว็บและบล็อกดังที่แนบไว้ใน References หากผิดพลาดไปบ้าง ก็ขออภัยด้วยครับ
สุดท้ายรายชื่อด้านล่างก็เป็นรายการที่ผมลิสท์ไว้ ดูแล้วน่าสนใจ ว่าจะเอาไว้อ่านต่อ และ Reference ทั้งๆหมดที่ใช้อ้างอิง หากใครสนใจอ่านเพิ่มเติมก็สามารถเข้าไปดูได้ครับ
References
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit