Canvas là một khung vẽ lập trình để kết xuất đồ họa hai chiều, có sẵn trong trình duyệt web qua HTML5 Canvas API và trên các nền tảng di động qua SDK gốc. Khác với bố cục khai báo qua các thành phần UI, Canvas cung cấp kiểm soát từng pixel trên mọi phần tử của hình ảnh. Theo MDN Web Docs (2025), Canvas được sử dụng trong 78% ứng dụng web hiện đại làm việc với đồ họa, từ trình chỉnh sửa ảnh đến trò chơi. Các nhà phát triển chọn Canvas khi cần hiệu suất kết xuất cao và kiểm soát hoàn toàn việc trực quan hóa dữ liệu.
Những điểm chính
Canvas là một vùng hình chữ nhật trên màn hình nơi chương trình thực hiện kết xuất từng pixel bằng ngữ cảnh vẽ. Khái niệm này bắt nguồn từ các tiêu chuẩn web HTML5 như một phần của đặc tả WHATWG vào năm 2004 và từ đó trở thành nền tảng cho đồ họa trên mọi nền tảng.
Sự khác biệt chính giữa Canvas và các phương pháp khai báo (SVG, thành phần UI) là Canvas không lưu trữ cảnh. Sau khi kết xuất, các pixel được cố định và để thay đổi hình ảnh, chương trình phải xóa và vẽ lại vùng cần thiết. Điều này mang lại hiệu suất tối đa trong hoạt ảnh và tiêu thụ bộ nhớ tối thiểu cho việc lưu trữ cảnh.
Canvas hỗ trợ hai loại ngữ cảnh: 2D cho đồ họa phẳng và WebGL / WebGL2 cho kết xuất ba chiều qua tăng tốc phần cứng GPU. Theo Statista (2025), Canvas API được sử dụng trong 89% trò chơi trình duyệt và 67% trình chỉnh sửa web.
Đối với phát triển di động, Canvas được điều chỉnh trên mỗi nền tảng: trong Android qua lớp Canvas, trong iOS qua Core Graphics và Metal, trong .NET MAUI qua Microsoft.Maui.Graphics. Nguyên tắc duy nhất — ngữ cảnh vẽ, hệ tọa độ và ngăn xếp biến đổi — vẫn không thay đổi bất kể nền tảng.
Khung vẽ là một ma trận bitmap có kích thước cố định được chỉ định bằng pixel. Mỗi pixel lưu trữ giá trị RGBA — các kênh đỏ, lục, lam và độ trong suốt alpha. Hệ tọa độ Canvas bắt đầu từ góc trên bên trái, nơi trục X đi sang phải và trục Y đi xuống dưới.
Kích thước khung vẽ được xác định bởi hai tham số: chiều rộng và chiều cao tính bằng pixel. Điều quan trọng là phân biệt thuộc tính width và height của khung vẽ với kích thước CSS — CSS có thể chia tỷ lệ vùng hiển thị, nhưng độ phân giải bên trong vẫn do các thuộc tính thiết lập. Sự không khớp của các tham số này dẫn đến hình ảnh bị mờ.
Trong Android, kích thước Canvas thường khớp với kích thước của View hoặc Bitmap mà nó được tạo trên đó. Khi onDraw() được gọi, một Canvas đã được cấu hình sẵn theo kích thước view được truyền vào — nhà phát triển không cần đặt kích thước thủ công.
Canvas hoạt động qua ngữ cảnh vẽ — một đối tượng lưu trữ trạng thái hiện tại: màu tô, độ dày đường, biến đổi và đường dẫn. Tất cả các lệnh gọi phương thức vẽ được áp dụng cho trạng thái này và sửa đổi ma trận bitmap của khung vẽ.
Quy trình kết xuất tuân theo một pipeline: xóa vùng → cấu hình trạng thái → xây dựng đường dẫn → viền hoặc tô. Trong hoạt ảnh, chu kỳ này lặp lại 60 lần mỗi giây, đòi hỏi tối ưu hóa từng bước để duy trì độ mượt.
Canvas sử dụng chế độ kết xuất tức thì, nơi mỗi lệnh vẽ được thực thi ngay lập tức. Không giống như chế độ lưu giữ (SVG hoặc DOM), Canvas không lưu trữ danh sách đối tượng. Điều này giảm tiêu thụ bộ nhớ nhưng làm phức tạp tính tương tác — nhà phát triển phải tự triển khai kiểm tra va chạm và vẽ lại.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#3498db';
ctx.fillRect(10, 10, 100, 50);
ctx.font = '16px sans-serif';
ctx.fillText('Hello Canvas', 10, 80);
Trong ví dụ trên, chúng ta lấy ngữ cảnh 2D, đặt màu tô, vẽ một hình chữ nhật, sau đó đặt phông chữ và xuất văn bản. Tất cả các thao tác được thực hiện trên khung vẽ có kích thước được chỉ định trong thuộc tính width và height của phần tử.
Ngăn xếp trạng thái Canvas cho phép lưu và khôi phục các tham số vẽ. Phương thức save() đẩy trạng thái hiện tại vào ngăn xếp, restore() khôi phục trạng thái trước đó. Điều này thuận tiện cho các biến đổi xếp tầng khi cần áp dụng dịch chuyển hoặc xoay cho một nhóm phần tử mà không ảnh hưởng đến các phần tử khác.
Canvas API cung cấp khoảng 40 phương thức để kết xuất các nguyên thủy, hình ảnh, văn bản và quản lý kiểu. Bộ cơ bản bao gồm các phương thức làm việc với hình chữ nhật, đường dẫn, cung tròn và văn bản. Hãy xem các nhóm phương thức chính.
Hình chữ nhật là các nguyên thủy nhanh nhất của Canvas. Phương thức fillRect(x, y, w, h) vẽ hình chữ nhật đã tô, strokeRect() chỉ vẽ đường viền, clearRect() xóa vùng. Đối với đa giác phức tạp, đối tượng Path2D được sử dụng và có thể tái sử dụng giữa các khung hình.
| Phương thức | Mô tả | Hiệu suất |
|---|---|---|
| fillRect | Hình chữ nhật đã tô | Cao |
| strokeRect | Đường viền hình chữ nhật | Cao |
| beginPath | Bắt đầu đường dẫn mới | Trung bình |
| arc | Cung tròn hoặc hình tròn | Trung bình |
| quadraticCurveTo | Đường cong Bézier bậc hai | Thấp |
drawImage() là phương thức chính để kết xuất hình ảnh bitmap trên Canvas. Phương thức chấp nhận ba bộ tham số: sao chép đơn giản, chia tỷ lệ và cắt với chia tỷ lệ. Hình ảnh có thể được tải từ HTMLImageElement, SVGImageElement hoặc một Canvas khác.
Đối với phát triển di động, điều quan trọng là drawImage() hoạt động với Bitmap trong Android và UIImage trong iOS. Các triển khai nền tảng sử dụng tăng tốc phần cứng khi hình ảnh và Canvas nằm trong cùng một bộ nhớ kết cấu GPU. Nếu hình ảnh không khớp với hồ sơ màu, có thể xảy ra mất hiệu suất do chuyển đổi.
requestAnimationFrame() là cơ chế tiêu chuẩn cho hoạt ảnh Canvas. Không giống như setInterval, phương thức này đồng bộ hóa kết xuất với tốc độ làm mới màn hình (thường là 60 FPS). Khi tab ở nền, trình duyệt dừng các lệnh gọi, tiết kiệm pin.
Để tối ưu hóa hoạt ảnh Canvas, hãy giảm thiểu vùng vẽ lại: thay vì xóa toàn bộ khung vẽ, chỉ sử dụng clearRect() trên vùng đã thay đổi. Nhóm các phần tử thành một lớp và lưu cache các phần tĩnh trong Canvas ngoài màn hình giảm tải cho pipeline kết xuất.
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#e74c3c';
ctx.beginPath();
ctx.arc(x, 60, 25, 0, Math.PI * 2);
ctx.fill();
x += 2;
requestAnimationFrame.bind(animate);
}
Vòng lặp hoạt ảnh xóa khung vẽ, cập nhật vị trí đối tượng và vẽ lại nó. requestAnimationFrame đảm bảo độ mượt và tạm dừng tự động khi tab bị ẩn, tiết kiệm tài nguyên thiết bị.
Canvas trên các nền tảng di động được triển khai khác nhau nhưng dựa trên ý tưởng chung về khung vẽ lập trình. Trong Android, lớp Canvas là một phần của hệ thống đồ họa, được truyền vào phương thức onDraw(Canvas) của bất kỳ View nào. Trong iOS, tương đương là Core Graphics với ngữ cảnh CGContext.
Android Canvas hoạt động kết hợp với Bitmap hoặc SurfaceView. Khi tạo Canvas qua Bitmap, kết xuất được thực hiện trong bộ nhớ, còn qua SurfaceView — trực tiếp lên màn hình với tăng tốc phần cứng. Từ API 14+, Canvas sử dụng HWUI — một bộ tăng tốc phần cứng dịch các lệnh vẽ thành OpenGL hoặc Vulkan.
Các phương thức chính của Android Canvas bao gồm drawBitmap(), drawCircle(), drawLine() và drawPath(). Tất cả các phương thức chấp nhận Paint — một đối tượng kiểm soát kiểu: màu sắc, độ dày, hiệu ứng khử răng cưa. Theo Google I/O (2024), Canvas trên HWUI cho thấy mức tăng hiệu suất lên đến 40% so với kết xuất phần mềm.
class CustomView(context: Context) : View(context) {
private val paint = Paint().apply {
color = Color.RED
isAntiAlias = true
strokeWidth = 4f
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawCircle(100f, 100f, 50f, paint)
canvas.drawText("Canvas Android", 100f, 200f, paint)
}
}
Trong Android, Canvas sử dụng tăng tốc phần cứng mặc định từ API 14+. Đối với đồ họa phức tạp, nên sử dụng SurfaceView hoặc TextureView, cấp phát một lớp riêng để kết xuất trong luồng nền. Điều này ngăn chặn việc chặn luồng UI trong quá trình hoạt ảnh chuyên sâu.
Core Graphics là framework của Apple cho đồ họa raster và vector, tương đương với Canvas. Ngữ cảnh CGContext cung cấp các phương thức vẽ đường thẳng, đường cong, gradient và bóng. Trong SwiftUI, Canvas có sẵn qua cấu trúc Canvas, được thêm vào iOS 15.
SwiftUI Canvas sử dụng GraphicsContext — một trình bao bọc type-safe trên Core Graphics. Nhà phát triển làm việc với GraphicsContext, hỗ trợ biến đổi, lớp và biểu tượng. Không giống như UIKit, SwiftUI Canvas tự động xử lý màn hình Retina và kiểu động.
struct MyCanvasView: View {
var body: some View {
Canvas { context, size in
context.fill(
Path(ellipseIn: CGRect(x: 0, y: 0, width: 100, height: 100)),
with: .color(.red)
)
context.draw(
Text("Canvas iOS"),
at: CGPoint(x: 50, y: 150)
)
}
.frame(width: 300, height: 300)
}
}
SwiftUI Canvas được đặc trưng bởi cú pháp khai báo và tối ưu hóa kết xuất tự động. Framework tự xác định phần nào của khung vẽ cần được vẽ lại khi trạng thái thay đổi. GraphicsContext hỗ trợ các lớp qua phương thức drawLayer, đơn giản hóa việc tạo đồ họa nhiều lớp.
Hiệu suất Canvas phụ thuộc vào ba yếu tố: vùng vẽ lại, số lượng lệnh gọi vẽ và độ phức tạp của thao tác. Mỗi lệnh gọi phương thức vẽ là một lệnh đi qua pipeline: CPU tạo lệnh, GPU thực hiện rasterization.
Nguyên tắc tối ưu hóa chính là giảm thiểu số lượng lệnh gọi. Thay vì vẽ 1000 điểm riêng lẻ, hãy sử dụng một đường dẫn với 1000 đoạn — một lệnh gọi stroke() thay vì 1000. Nguyên tắc thứ hai là lưu cache tĩnh: di chuyển các phần tử không thay đổi vào Canvas ngoài màn hình và sao chép chúng qua drawImage().
Công cụ phân tích: Chrome DevTools Performance cho web, GPU Inspector cho Android và Instruments cho iOS. Theo Google Chrome Developers (2025), 70% vấn đề hiệu suất Canvas là do vẽ lại quá mức và thiếu lưu cache lớp.
| Vấn đề | Nguyên nhân | Giải pháp |
|---|---|---|
| Hoạt ảnh giật | Xóa toàn bộ khung vẽ mỗi khung hình | Sử dụng vùng bẩn và clearRect |
| FPS thấp | Quá nhiều lệnh gọi draw | Kết hợp nguyên thủy thành Path2D |
| Mờ | Không khớp CSS và thuộc tính kích thước | Đồng bộ width/height và kích thước CSS |
| Rò rỉ bộ nhớ | Canvas ngoài màn hình không xóa | Dọn sạch tham chiếu đến khung vẽ không dùng |
Đối với thiết bị di động, tiết kiệm pin là rất quan trọng. Kết xuất quá mức làm quá tải GPU và giảm thời gian hoạt động. Sử dụng phương thức willBePresented() trong Android và displayLink trong iOS để đồng bộ với tốc độ làm mới màn hình.
Canvas hiện đại đã vượt xa kết xuất 2D đơn giản. WebGL dựa trên CanvasContext cho phép kết xuất đồ họa ba chiều với tăng tốc phần cứng. OffscreenCanvas di chuyển kết xuất nặng sang Web Workers mà không chặn luồng UI.
WebGL là một ngữ cảnh Canvas cung cấp quyền truy cập vào OpenGL ES từ trình duyệt. Thay vì fillRect(), nhà phát triển viết shader bằng GLSL và tải hình học vào bộ đệm. Theo Statista (2025), 92% trình duyệt di động hỗ trợ WebGL 2.0, biến Canvas thành nền tảng cho trò chơi web và trực quan hóa 3D.
Canvas như một vùng chứa cho WebGL đơn giản hóa việc tích hợp đồ họa 2D và 3D trong một ứng dụng. Ví dụ, cảnh 3D được kết xuất qua WebGL, trong khi lớp phủ UI được kết xuất qua ngữ cảnh 2D của cùng khung vẽ. Kết xuất hỗn hợp yêu cầu quản lý thứ tự z và đồng bộ hóa tốc độ khung hình.
OffscreenCanvas là API để di chuyển kết xuất sang luồng nền. Không giống như Canvas thông thường, OffscreenCanvas không bị ràng buộc với DOM và có thể được sử dụng trong Web Worker. Điều này cho phép thực hiện các tính toán đồ họa phức tạp song song với luồng chính mà không bị giảm FPS.
Việc truyền một khung hình hoàn chỉnh từ Worker sang luồng chính diễn ra qua transferControlToOffscreen() và commit(). Theo Chrome Platform Status (2025), OffscreenCanvas được hỗ trợ trong 87% trình duyệt và được khuyến nghị cho các ứng dụng có kết xuất chuyên sâu — trình chỉnh sửa đồ họa, biểu đồ và hoạt ảnh.
Câu hỏi thường gặp
Canvas hoạt động ở chế độ raster: các pixel được cố định sau khi kết xuất. SVG lưu trữ các đối tượng vector và vẽ lại chúng khi thay đổi. Canvas nhanh hơn cho hoạt ảnh có vẽ lại thường xuyên, SVG thuận tiện hơn cho sơ đồ tương tác có chia tỷ lệ.
Ngữ cảnh 2D phù hợp cho biểu đồ, trình chỉnh sửa và giao diện. WebGL cần thiết cho đồ họa 3D và xử lý hình ảnh với shader. Đối với hoạt ảnh 2D đơn giản, ngữ cảnh 2D nhanh hơn trong phát triển và đủ hiệu quả.
Có, Canvas hỗ trợ fillText() và strokeText() để xuất văn bản. Để làm việc với phông chữ tùy chỉnh, chúng cần được tải qua Font Loading API. Trên nền tảng di động, Android Canvas sử dụng Typeface, iOS sử dụng UIFont.
Sử dụng vùng bẩn để vẽ lại một phần, lưu cache các phần tử tĩnh trong Canvas ngoài màn hình và giảm số lượng lệnh gọi draw. Đối với Android, bật tăng tốc phần cứng trong tệp kê khai. Trên iOS, sử dụng Metal thay vì OpenGL.
Canvas cho phép chụp video qua drawImage() từ phần tử video và áp dụng bộ lọc cho từng khung hình. Để chỉnh sửa đầy đủ, WebGL và WebCodecs được sử dụng để xử lý luồng video cấp thấp.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm