Vẽ đồ họa bằng Canvas trong HTML JavaScript

Javascript căn bản | by Học Javascript

Trong thế giới phát triển web hiện nay, việc tạo và hiển thị đồ họa trực quan đã trở thành một phần quan trọng không thể thiếu trong hầu hết các ứng dụng và trang web. Từ việc vẽ các biểu đồ, hình ảnh động đến xây dựng các trò chơi trực tuyến, khả năng vẽ đồ họa trên web mang lại trải nghiệm người dùng phong phú và thú vị. Một trong những công cụ mạnh mẽ nhất mà HTML cung cấp để thực hiện các tác vụ này chính là thẻ <canvas>.

Thẻ <canvas> trong HTML5 cho phép chúng ta vẽ đồ họa trực tiếp vào trang web bằng JavaScript, tạo ra những hình ảnh động, tương tác hoặc thậm chí là các trò chơi 2D phức tạp. Với khả năng vẽ trên một vùng không gian 2D hoặc 3D, thẻ <canvas> đã mở ra vô vàn cơ hội sáng tạo cho các nhà phát triển web.

Trong bài viết này, chúng ta sẽ tìm hiểu cách sử dụng <canvas> để vẽ đồ họa, từ những thao tác cơ bản như vẽ hình chữ nhật, đường thẳng, đến việc tạo ra các hiệu ứng động và tương tác phức tạp. Cùng với đó, chúng ta sẽ tìm hiểu các phương thức, kỹ thuật nâng cao để tận dụng tối đa khả năng của thẻ <canvas> trong việc xây dựng các ứng dụng đồ họa trên web.

Tìm hiểu về phần tử <canvas> trong JavaScript

Cấu trúc cơ bản của thẻ <canvas>

Thẻ <canvas> là một phần tử HTML5 cho phép vẽ đồ họa trực tiếp trên trang web. Nó không hiển thị gì nếu không có JavaScript để thao tác với nó. Đây là một công cụ mạnh mẽ giúp bạn có thể tạo ra các hình ảnh động, biểu đồ, hoặc trò chơi đơn giản mà không cần phải sử dụng bất kỳ plugin hay thư viện bên ngoài nào.

Cấu trúc cơ bản của thẻ <canvas> như sau:

<canvas id="myCanvas" width="500" height="400"></canvas>
  • id: Dùng để định danh phần tử <canvas>, giúp dễ dàng truy cập từ JavaScript.

  • widthheight: Chỉ định kích thước của vùng vẽ (canvas). Kích thước này được tính bằng pixel và là kích thước của phần tử <canvas> trong HTML.

    • Lưu ý: Kích thước này có thể được thiết lập qua CSS, nhưng khi vẽ lên canvas, kích thước thực tế sẽ được xác định bởi các thuộc tính widthheight của thẻ HTML <canvas>.

Lấy context vẽ

Để bắt đầu vẽ trên canvas, bạn cần lấy "context" vẽ từ phần tử <canvas>. Context chính là đối tượng JavaScript cho phép bạn vẽ và thao tác với nội dung bên trong canvas. Có hai loại context chính:

  • 2D Context: Dùng để vẽ đồ họa 2D, là loại context phổ biến nhất.

  • WebGL Context: Dùng cho đồ họa 3D, giúp bạn làm việc với WebGL, một API JavaScript để render đồ họa 3D trong trình duyệt.

Để lấy context vẽ 2D, bạn sử dụng phương thức getContext() của đối tượng <canvas>, như sau:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

Ở đây:

  • document.getElementById("myCanvas"): Truy cập vào phần tử <canvas> qua ID.

  • getContext("2d"): Lấy context 2D để vẽ đồ họa 2D.

Thuộc tính và các lưu ý

width và height của canvas

  • widthheight quyết định kích thước của không gian vẽ thực tế trên canvas, tức là kích thước mà bạn sẽ vẽ lên. Đây là kích thước của vùng vẽ trên canvas và có đơn vị tính là pixel.

CSS vs. thuộc tính HTML: Mặc dù bạn có thể thay đổi kích thước của phần tử canvas qua CSS, nhưng điều này chỉ ảnh hưởng đến giao diện của canvas (kích thước hiển thị trên trang web). Kích thước vẽ thực sự của canvas (kích thước thực tế khi bạn vẽ lên) vẫn được xác định bởi thuộc tính widthheight của thẻ <canvas> trong HTML.

<canvas id="myCanvas" width="800" height="600"></canvas>

Khi bạn sử dụng CSS để thay đổi kích thước:

#myCanvas {
  width: 400px;
  height: 300px;
}

Thực tế, mặc dù kích thước hiển thị trên trang web là 400x300px, nhưng không gian vẽ của canvas vẫn là 800x600px, nếu bạn không thay đổi thuộc tính widthheight trong HTML.

Lưu ý khi thay đổi kích thước

Khi bạn thay đổi kích thước của canvas, toàn bộ nội dung đã vẽ trên canvas sẽ bị xóa và không thể khôi phục lại. Điều này xảy ra vì khi thay đổi kích thước canvas, tất cả các pixel vẽ sẽ bị reset lại. Do đó, khi thay đổi kích thước canvas trong khi làm việc với đồ họa, bạn cần đảm bảo rằng bạn không mất dữ liệu quan trọng hoặc bạn phải vẽ lại các đối tượng sau khi thay đổi kích thước.

Ví dụ:

<canvas id="myCanvas" width="500" height="400"></canvas>

Nếu bạn thay đổi kích thước của canvas trong JavaScript sau khi đã vẽ nội dung lên nó:

canvas.width = 800;  // Kích thước vẽ thực sẽ được reset, toàn bộ nội dung bị mất

Điều này sẽ làm mất tất cả nội dung đã vẽ trên canvas. Do đó, nếu cần thay đổi kích thước, bạn nên xử lý vẽ lại hoặc lưu trữ nội dung trước khi thay đổi kích thước.

Các thao tác vẽ cơ bản với Canvas JavaScript

Canvas API cung cấp nhiều phương thức để vẽ các hình dạng cơ bản, tô màu, vẽ văn bản và tạo các hiệu ứng đồ họa. Dưới đây là các thao tác cơ bản nhất mà bạn có thể sử dụng khi làm việc với Canvas.

Các lệnh vẽ hình cơ bản

Hình chữ nhật

  • fillRect(x, y, width, height): Vẽ một hình chữ nhật có màu nền (fill) tại vị trí (x, y) với chiều rộng width và chiều cao height.

ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 200, 100);  // Vẽ hình chữ nhật màu xanh

strokeRect(x, y, width, height): Vẽ một hình chữ nhật chỉ với viền (stroke), không có màu nền. Các thông số cũng giống như fillRect.

ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
ctx.strokeRect(50, 50, 200, 100);  // Vẽ hình chữ nhật chỉ có viền đỏ

Đường thẳng

  • moveTo(x, y): Di chuyển con trỏ vẽ đến vị trí (x, y) mà không vẽ gì.

ctx.moveTo(50, 50);  // Di chuyển đến điểm (50, 50)

lineTo(x, y): Vẽ một đường thẳng từ vị trí hiện tại đến vị trí (x, y).

ctx.lineTo(250, 50); // Vẽ một đường thẳng đến (250, 50)
stroke(): Kết thúc việc vẽ đường thẳng và vẽ đường viền.
ctx.stroke(); // Vẽ đường viền

Hình tròn/ellipse

arc(x, y, radius, startAngle, endAngle, anticlockwise): Vẽ một hình tròn (hoặc cung tròn) với tâm tại (x, y) và bán kính radius, góc bắt đầu và kết thúc được xác định bằng startAngleendAngle (thường tính theo radian).

ctx.beginPath();
ctx.arc(150, 150, 100, 0, Math.PI, false);  // Vẽ một cung tròn bán kính 100 từ 0 đến π
ctx.stroke();  // Vẽ đường viền

ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise): Vẽ một hình elip với các bán kính khác nhau cho trục X và Y. Tương tự như arc nhưng có thể thay đổi tỷ lệ bán kính.

Đường cong

quadraticCurveTo(cp1x, cp1y, x, y): Vẽ một đường cong bậc hai (quadratic Bézier curve), nơi (cp1x, cp1y) là điểm kiểm soát và (x, y) là điểm kết thúc.

ctx.beginPath();
ctx.moveTo(50, 150);
ctx.quadraticCurveTo(150, 50, 250, 150);  // Đường cong từ (50, 150) qua (150, 50) đến (250, 150)
ctx.stroke();

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y): Vẽ một đường cong bậc ba (cubic Bézier curve), với hai điểm kiểm soát (cp1x, cp1y)(cp2x, cp2y) và điểm kết thúc (x, y).

ctx.beginPath();
ctx.moveTo(50, 150);
ctx.bezierCurveTo(150, 50, 200, 250, 250, 150);  // Đường cong bậc ba
ctx.stroke();

Tô màu và nét vẽ

a fillStylestrokeStyle

fillStyle: Thuộc tính dùng để chỉ định màu sắc, gradient hoặc mẫu hình ảnh sẽ được sử dụng khi tô màu các hình vẽ (fill).

ctx.fillStyle = 'green';  // Đặt màu nền là xanh lá cây
ctx.fillRect(100, 100, 200, 100);  // Vẽ hình chữ nhật có màu nền

strokeStyle: Thuộc tính dùng để chỉ định màu sắc hoặc gradient của đường viền.

ctx.strokeStyle = 'red';  // Đặt màu viền là đỏ
ctx.lineWidth = 5;
ctx.strokeRect(100, 100, 200, 100);  // Vẽ hình chữ nhật với viền đỏ

lineWidth

lineWidth: Thuộc tính xác định độ dày của đường viền khi vẽ.

ctx.lineWidth = 10;  // Đặt độ dày đường viền là 10px
ctx.strokeRect(50, 50, 200, 100);  // Vẽ hình chữ nhật với đường viền dày

Hệ màu

Bạn có thể sử dụng nhiều cách khác nhau để chỉ định màu sắc:

  • Tên màu: red, blue, green, ...

  • Mã màu Hex: #ff0000 (màu đỏ), #0000ff (màu xanh dương).

  • Mã màu RGB: rgb(255, 0, 0) (màu đỏ).

  • Mã màu RGBA: rgba(255, 0, 0, 0.5) (màu đỏ với độ trong suốt 50%).

ctx.fillStyle = 'rgb(255, 0, 0)';  // Màu đỏ
ctx.fillRect(100, 100, 200, 100);

Text

Vẽ văn bản là một trong những tính năng mạnh mẽ của Canvas. Bạn có thể vẽ chữ và tùy chỉnh các thuộc tính của văn bản như font, căn chỉnh, v.v.

fillText() và strokeText()

  • fillText(text, x, y): Vẽ văn bản với màu sắc (fill) tại vị trí (x, y).

ctx.font = '30px Arial';
ctx.fillStyle = 'black';
ctx.fillText('Hello Canvas', 50, 50);  // Vẽ chữ "Hello Canvas" tại vị trí (50, 50)

strokeText(text, x, y): Vẽ văn bản với đường viền (stroke).

ctx.strokeStyle = 'blue';
ctx.lineWidth = 2;
ctx.strokeText('Hello Canvas', 50, 100);  // Vẽ chữ "Hello Canvas" với viền màu xanh

Căn chỉnh văn bản

  • textAlign: Thuộc tính xác định cách căn chỉnh văn bản (left, center, right).

ctx.textAlign = 'center';  // Căn giữa văn bản
ctx.fillText('Centered Text', 250, 150);  // Vẽ văn bản căn giữa

textBaseline: Thuộc tính xác định căn chỉnh theo chiều dọc (top, middle, bottom).

ctx.textBaseline = 'middle';  // Căn chỉnh theo chiều dọc giữa
ctx.fillText('Middle-aligned', 250, 150);

Font

  • font: Thuộc tính xác định kiểu chữ và kích thước văn bản.

ctx.font = '30px Arial';  // Đặt font là Arial với kích thước 30px
ctx.fillText('Styled Text', 50, 200);

Các thao tác trên giúp bạn tạo ra những hình ảnh, biểu đồ, hoặc các đối tượng đồ họa động phức tạp khi kết hợp với các kỹ thuật vẽ khác trong Canvas API.

Tương tác và thao tác nâng cao JavaScript

Trong Canvas API, bạn có thể tạo ra các tương tác nâng cao với người dùng thông qua việc xử lý các sự kiện chuột, giúp tạo ra các ứng dụng vẽ hoặc trò chơi trực quan. Phần này sẽ giải thích cách bắt sự kiện chuột, lấy tọa độ chuột, và tạo ứng dụng vẽ đơn giản (paint app) cơ bản.

Xử lý chuột

Để xử lý các sự kiện chuột trong Canvas, bạn có thể sử dụng các sự kiện JavaScript như mousedown, mousemove, và mouseup. Các sự kiện này sẽ cho phép bạn nhận diện khi nào người dùng nhấn chuột, di chuyển chuột, và nhả chuột trên Canvas.

Bắt sự kiện chuột

  • mousedown: Sự kiện này được kích hoạt khi người dùng nhấn nút chuột.

  • mousemove: Sự kiện này được kích hoạt khi người dùng di chuyển chuột.

  • mouseup: Sự kiện này được kích hoạt khi người dùng thả nút chuột.

Để bắt các sự kiện này, bạn cần sử dụng addEventListener() để lắng nghe các sự kiện và thực hiện hành động khi chúng xảy ra.

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
let isDrawing = false;

// Lắng nghe sự kiện mousedown (nhấn chuột)
canvas.addEventListener('mousedown', (e) => {
  isDrawing = true;
  ctx.beginPath();  // Bắt đầu một đường vẽ mới
  ctx.moveTo(getMousePosition(e).x, getMousePosition(e).y);  // Di chuyển con trỏ đến vị trí chuột
});

// Lắng nghe sự kiện mousemove (di chuyển chuột)
canvas.addEventListener('mousemove', (e) => {
  if (isDrawing) {
    const mousePos = getMousePosition(e);
    ctx.lineTo(mousePos.x, mousePos.y);  // Vẽ đường thẳng đến vị trí chuột
    ctx.stroke();  // Vẽ đường viền
  }
});

// Lắng nghe sự kiện mouseup (thả chuột)
canvas.addEventListener('mouseup', () => {
  isDrawing = false;  // Dừng vẽ khi thả chuột
});

// Lấy tọa độ chuột trong canvas
function getMousePosition(e) {
  const rect = canvas.getBoundingClientRect();
  return {
    x: e.clientX - rect.left,
    y: e.clientY - rect.top
  };
}

Trong ví dụ trên:

  • mousedown bắt đầu một đường vẽ mới khi người dùng nhấn chuột.

  • mousemove vẽ đường liên tục khi người dùng di chuyển chuột.

  • mouseup kết thúc quá trình vẽ khi người dùng thả chuột.

Lấy tọa độ chuột trên canvas

Để lấy tọa độ chuột trên canvas, bạn cần tính toán vị trí của chuột trong canvas so với vị trí của cửa sổ trình duyệt. Để làm điều này, bạn có thể sử dụng phương thức getBoundingClientRect() của Canvas để xác định vị trí và kích thước của phần tử trên trang, sau đó tính toán tọa độ thực tế của chuột.

function getMousePosition(e) {
  const rect = canvas.getBoundingClientRect();
  return {
    x: e.clientX - rect.left,  // Tính toán vị trí X
    y: e.clientY - rect.top    // Tính toán vị trí Y
  };
}

Với hàm getMousePosition(), bạn sẽ nhận được tọa độ (x, y) của chuột trong không gian của Canvas.

Vẽ tự do (Paint App cơ bản)

Ứng dụng vẽ cơ bản cho phép người dùng sử dụng chuột để vẽ các đường tự do trên Canvas. Bạn có thể cung cấp các chức năng như chọn màu vẽ, thay đổi kích thước nét vẽ, và xóa phần vẽ.

Chức năng vẽ tự do

Người dùng có thể vẽ trên canvas bằng cách giữ chuột và di chuyển chuột. Mỗi khi người dùng di chuyển chuột, ứng dụng sẽ vẽ một đường liền mạch từ điểm hiện tại đến vị trí chuột.

let isDrawing = false;
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const clearButton = document.getElementById('clearButton');
const colorPicker = document.getElementById('colorPicker');
const sizePicker = document.getElementById('sizePicker');

let currentColor = 'black';  // Màu mặc định
let currentSize = 5;  // Kích thước nét vẽ mặc định

// Lắng nghe sự kiện nhấn chuột để bắt đầu vẽ
canvas.addEventListener('mousedown', (e) => {
  isDrawing = true;
  ctx.beginPath();
  ctx.moveTo(getMousePosition(e).x, getMousePosition(e).y);
});

// Lắng nghe sự kiện di chuyển chuột để vẽ đường
canvas.addEventListener('mousemove', (e) => {
  if (isDrawing) {
    const mousePos = getMousePosition(e);
    ctx.lineTo(mousePos.x, mousePos.y);
    ctx.stroke();
  }
});

// Lắng nghe sự kiện thả chuột để kết thúc vẽ
canvas.addEventListener('mouseup', () => {
  isDrawing = false;
});

// Xóa canvas
clearButton.addEventListener('click', () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);  // Xóa toàn bộ nội dung canvas
});

// Chọn màu
colorPicker.addEventListener('input', (e) => {
  currentColor = e.target.value;  // Cập nhật màu sắc khi người dùng chọn
  ctx.strokeStyle = currentColor;
  ctx.fillStyle = currentColor;
});

// Chọn kích thước nét vẽ
sizePicker.addEventListener('input', (e) => {
  currentSize = e.target.value;  // Cập nhật kích thước nét vẽ
  ctx.lineWidth = currentSize;
});

Trong ví dụ trên:

  • Người dùng có thể vẽ tự do trên canvas bằng chuột.

  • clearButton cho phép người dùng xóa toàn bộ nội dung vẽ trên canvas.

  • colorPicker cho phép người dùng chọn màu vẽ từ một bảng màu.

  • sizePicker cho phép người dùng thay đổi kích thước nét vẽ.

Chức năng lưu ảnh hoặc xóa nội dung

Bạn có thể thêm một nút để lưu nội dung vẽ thành một bức ảnh và một nút để xóa toàn bộ nội dung canvas.

// Lưu ảnh vẽ
function saveDrawing() {
  const dataURL = canvas.toDataURL();  // Chuyển canvas thành chuỗi hình ảnh (data URL)
  const link = document.createElement('a');
  link.href = dataURL;
  link.download = 'drawing.png';  // Tải xuống hình ảnh
  link.click();
}

const saveButton = document.getElementById('saveButton');
saveButton.addEventListener('click', saveDrawing);  // Lắng nghe sự kiện nhấn nút lưu

Lưu ý: canvas.toDataURL() sẽ chuyển nội dung của canvas thành chuỗi base64, có thể dùng để tải xuống như một file ảnh.

Hiệu ứng nâng cao với Canvas JavaScript

Canvas không chỉ giúp vẽ các hình dạng cơ bản mà còn hỗ trợ các hiệu ứng nâng cao như gradient, pattern, xử lý ảnh và tạo hoạt ảnh. Những hiệu ứng này có thể giúp bạn tạo ra các ứng dụng đồ họa phong phú hơn, bao gồm cả game 2D và ứng dụng xử lý ảnh. Phần này sẽ đi sâu vào cách tạo gradient, pattern, làm việc với ảnh, và sử dụng requestAnimationFrame() để tạo hiệu ứng hoạt ảnh.

Gradient và Pattern

GradientPattern là các kỹ thuật phổ biến để tạo ra các hiệu ứng màu sắc phong phú và đẹp mắt. Canvas API cung cấp các phương thức để tạo gradient tuyến tính và radial, cũng như để vẽ pattern từ hình ảnh.

Gradient

  • createLinearGradient(): Tạo ra gradient tuyến tính, nơi màu sắc thay đổi theo một hướng cụ thể.

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// Tạo gradient tuyến tính
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'blue');

// Sử dụng gradient làm màu tô
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
  • createRadialGradient(): Tạo ra gradient hình tròn, với màu sắc thay đổi từ một điểm trung tâm ra ngoài.

const gradientRadial = ctx.createRadialGradient(canvas.width / 2, canvas.height / 2, 10, canvas.width / 2, canvas.height / 2, canvas.width / 2);
gradientRadial.addColorStop(0, 'yellow');
gradientRadial.addColorStop(1, 'green');

ctx.fillStyle = gradientRadial;
ctx.fillRect(0, 0, canvas.width, canvas.height);

Pattern

  • createPattern(): Tạo một pattern từ hình ảnh hoặc một phần của canvas, có thể lặp lại hoặc thay đổi kích thước.

const image = new Image();
image.src = 'path_to_image.jpg';  // Đảm bảo hình ảnh đã tải trước khi vẽ

image.onload = function() {
  const pattern = ctx.createPattern(image, 'repeat');  // Lặp lại hình ảnh
  ctx.fillStyle = pattern;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
};

Trong ví dụ trên, createPattern() cho phép bạn tạo pattern từ hình ảnh và vẽ nó trên canvas.

Làm việc với ảnh

Canvas API cung cấp các phương thức để vẽ và thao tác với hình ảnh, chẳng hạn như chèn ảnh, cắt ảnh, phóng to hoặc thu nhỏ ảnh.

Chèn ảnh với drawImage()

  • drawImage(): Phương thức này dùng để vẽ ảnh lên canvas. Bạn có thể vẽ ảnh từ một đối tượng <img>, hoặc vẽ một phần của ảnh.

const image = new Image();
image.src = 'path_to_image.jpg';

image.onload = function() {
  ctx.drawImage(image, 50, 50, 200, 150);  // Vẽ ảnh tại (50, 50) với kích thước 200x150
};

Cắt ảnh

Bạn có thể cắt một phần của ảnh và chỉ vẽ phần đó lên canvas.

const image = new Image();
image.src = 'path_to_image.jpg';

image.onload = function() {
  ctx.drawImage(image, 0, 0, 100, 100, 50, 50, 200, 200);  // Cắt và vẽ một phần ảnh
};

Trong ví dụ trên, phương thức drawImage() được sử dụng để cắt một phần của ảnh và vẽ nó vào một vùng khác của canvas.

Phóng to, thu nhỏ ảnh

Phương thức drawImage() có thể được sử dụng để phóng to hoặc thu nhỏ ảnh bằng cách thay đổi kích thước mà bạn muốn vẽ.

const image = new Image();
image.src = 'path_to_image.jpg';

image.onload = function() {
  ctx.drawImage(image, 0, 0, image.width / 2, image.height / 2);  // Phóng to ảnh
};

Hoạt ảnh với requestAnimationFrame() JavaScript

requestAnimationFrame() là một phương thức giúp tạo ra các hoạt ảnh mượt mà bằng cách yêu cầu trình duyệt gọi lại một hàm vẽ vào mỗi khung hình (frame). Phương thức này giúp tối ưu hóa hiệu suất và tránh các hiện tượng giật hình khi tạo hoạt ảnh.

Tạo hiệu ứng chuyển động

Dưới đây là một ví dụ về cách sử dụng requestAnimationFrame() để tạo hiệu ứng chuyển động cho một đối tượng.

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

let x = 0;  // Vị trí ban đầu của đối tượng
const speed = 2;  // Tốc độ di chuyển

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);  // Xóa canvas
  ctx.beginPath();
  ctx.arc(x, canvas.height / 2, 30, 0, Math.PI * 2);  // Vẽ hình tròn
  ctx.fillStyle = 'red';
  ctx.fill();
  
  x += speed;  // Cập nhật vị trí
  if (x > canvas.width) {
    x = 0;  // Nếu ra ngoài canvas, quay lại vị trí ban đầu
  }
  
  requestAnimationFrame(animate);  // Gọi lại hàm animate để vẽ lại khung hình tiếp theo
}

animate();  // Bắt đầu hoạt ảnh

Trong ví dụ trên:

  • Một hình tròn di chuyển từ trái sang phải trên canvas.

  • requestAnimationFrame(animate) giúp hàm animate() được gọi liên tục để tạo hoạt ảnh mượt mà.

Di chuyển đối tượng

Tương tự như ví dụ trên, bạn có thể sử dụng requestAnimationFrame() để di chuyển bất kỳ đối tượng nào trên canvas, chẳng hạn như hình vuông, hình chữ nhật hoặc các đối tượng phức tạp hơn.

c. Làm game 2D

Với requestAnimationFrame(), bạn có thể tạo ra một trò chơi 2D đơn giản. Ví dụ, bạn có thể tạo một trò chơi tránh vật cản, nơi người chơi điều khiển một đối tượng và phải tránh các chướng ngại vật di chuyển.

Quản lý đối tượng đồ họa trong JavaScript

Khi phát triển các ứng dụng đồ họa phức tạp, việc quản lý đối tượng đồ họa trở nên rất quan trọng. Một trong những cách tiếp cận phổ biến là sử dụng cấu trúc hướng đối tượng. Bằng cách này, mỗi đối tượng đồ họa như hình tròn, hình chữ nhật, hoặc các đối tượng phức tạp khác sẽ được thể hiện dưới dạng các lớp (classes), giúp bạn dễ dàng quản lý và cập nhật nhiều đối tượng cùng lúc.

Vẽ theo cấu trúc hướng đối tượng

Hướng đối tượng giúp tổ chức mã nguồn và dễ dàng bảo trì, đặc biệt khi bạn cần vẽ và cập nhật nhiều đối tượng cùng lúc.

Tạo lớp Shape

Lớp Shape sẽ là lớp cha (base class) cho các đối tượng đồ họa khác. Lớp này sẽ định nghĩa các thuộc tính và phương thức chung như vị trí, kích thước và phương thức vẽ.

class Shape {
  constructor(x, y, color) {
    this.x = x;
    this.y = y;
    this.color = color || 'black';
  }

  draw(ctx) {
    // Được kế thừa và triển khai ở lớp con
  }
}

Tạo lớp Circle

Lớp Circle kế thừa từ lớp Shape, và có thêm thuộc tính bán kính (radius). Phương thức draw() sẽ vẽ hình tròn lên canvas.

class Circle extends Shape {
  constructor(x, y, radius, color) {
    super(x, y, color);
    this.radius = radius;
  }

  draw(ctx) {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();
  }
}

Tạo lớp Rectangle

Tương tự như Circle, lớp Rectangle kế thừa từ Shape và có thêm thuộc tính chiều rộng (width) và chiều cao (height).

class Rectangle extends Shape {
  constructor(x, y, width, height, color) {
    super(x, y, color);
    this.width = width;
    this.height = height;
  }

  draw(ctx) {
    ctx.fillStyle = this.color;
    ctx.fillRect(this.x, this.y, this.width, this.height);
  }
}

Quản lý và cập nhật nhiều hình đồng thời

Để quản lý và vẽ nhiều đối tượng trên canvas, bạn có thể sử dụng một mảng hoặc danh sách để lưu trữ tất cả các đối tượng đồ họa, sau đó lặp qua danh sách này và vẽ từng đối tượng lên canvas.

const shapes = [
  new Circle(100, 100, 50, 'red'),
  new Rectangle(200, 200, 150, 100, 'blue')
];

function drawShapes(ctx) {
  shapes.forEach(shape => shape.draw(ctx));
}

Mỗi đối tượng sẽ tự quản lý hành vi vẽ của mình, giúp dễ dàng mở rộng và duy trì mã nguồn.

Ứng dụng thực tế trong JavaScript

Sau khi đã nắm vững các phương pháp vẽ và quản lý đối tượng đồ họa, bạn có thể xây dựng nhiều ứng dụng thú vị. Dưới đây là một số ví dụ về các ứng dụng thực tế có thể tạo ra với Canvas.

Ứng dụng vẽ tay online

Ứng dụng vẽ tay online cho phép người dùng vẽ các hình tự do trên canvas bằng chuột. Bạn có thể cung cấp các công cụ để thay đổi màu sắc, độ dày nét vẽ, và thậm chí lưu lại bản vẽ dưới dạng ảnh.

  • Tính năng: Vẽ tự do, thay đổi màu sắc, độ dày nét vẽ, xóa nội dung.

  • Công nghệ sử dụng: HTML5 Canvas API kết hợp với các sự kiện chuột và thao tác nâng cao như undo, redo.

// Thêm sự kiện để vẽ khi người dùng di chuột trên canvas
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);

Game nhỏ (bóng nảy, rắn săn mồi)

Canvas rất hữu ích cho việc phát triển các game 2D đơn giản như bóng nảy hoặc rắn săn mồi. Bạn có thể sử dụng các đối tượng đồ họa như hình vuông, hình tròn để tạo các đối tượng trong game và quản lý chúng qua các lớp.

  • Game bóng nảy: Bóng nảy trên màn hình, người dùng có thể điều khiển thanh gạt để bắt bóng.

  • Game rắn săn mồi: Rắn di chuyển, ăn thức ăn để lớn lên, và người chơi phải tránh va vào tường hoặc chính mình.

// Game bóng nảy cơ bản với Canvas
function animateBall() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ball.move(); // Di chuyển bóng
  ball.draw(ctx); // Vẽ bóng lên canvas
  requestAnimationFrame(animateBall); // Gọi lại hàm để tạo hoạt ảnh
}

Kết bài

Tóm lại, Canvas trong HTML5 là một công cụ mạnh mẽ và linh hoạt cho việc tạo ra các ứng dụng đồ họa trực tuyến. Với khả năng vẽ và thao tác trên pixel, nó giúp chúng ta xây dựng các ứng dụng đồ họa 2D đơn giản như công cụ vẽ tay, game 2D, đồng hồ, biểu đồ động, cũng như các mô phỏng phức tạp hơn. Dù có một số hạn chế như không hỗ trợ trực tiếp việc nhóm đối tượng hoặc tính năng undo, nhưng với sự kết hợp các phương pháp quản lý đối tượng và kỹ thuật xử lý thông minh, chúng ta hoàn toàn có thể vượt qua những rào cản đó để tạo ra những ứng dụng đồ họa sống động và hiệu quả.

Với sự phát triển không ngừng của các thư viện hỗ trợ như p5.js, Fabric.js hay PixiJS, việc phát triển các ứng dụng đồ họa trở nên dễ dàng hơn bao giờ hết. Việc hiểu và sử dụng Canvas không chỉ giúp cải thiện kỹ năng lập trình mà còn mở ra vô số cơ hội sáng tạo cho những người yêu thích đồ họa và phát triển web. Cùng với sự ra đời của các thư viện đồ họa mạnh mẽ, Canvas không chỉ là một công cụ hữu ích mà còn là một phần quan trọng trong việc xây dựng các ứng dụng web hiện đại.

Bài viết liên quan