Canvas thuần (vanilla) không có hệ thống object/event cho hình vẽ. Để có drag-and-drop, selection, click event trên từng shape, cần thư viện cung cấp Object Model (Scene Graph).
So sánh thư viện phổ biến
| Thư viện | Kích thước | Đặc điểm nổi bật | Phù hợp |
|---|---|---|---|
| Fabric.js | ~120KB | Object model đầy đủ, SVG parsing, serialization, interaction built-in | Editor, design tool, whiteboard |
| Konva.js | ~60KB | Hiệu năng cao, Stage/Layer, React/Vue binding, animation | Game 2D, chart realtime, high-perf |
| Paper.js | ~180KB | Vector-based, Path boolean ops, Svg import/export | Illustration, drawing app |
| Two.js | ~50KB | Unified API: Canvas, SVG, WebGL | Cross-renderer, generative art |
Ví dụ Fabric.js - Drag & Drop đơn giản
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
<style> canvas { border: 1px solid #ccc; } </style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
var canvas = new fabric.Canvas('canvas', {
selection: true // Cho phép chọn nhiều object (drag select)
});
// Tạo hình tròn - KÉO THẢ SẴN CÓ
var circle = new fabric.Circle({
left: 100, top: 100,
radius: 50,
fill: '#e74c3c',
// Tùy chọn interaction
hasControls: true, // Resize/rotate handles
hasBorders: true, // Border khi selected
lockRotation: false,
lockScalingX: false,
lockScalingY: false
});
// Tạo hình chữ nhật
var rect = new fabric.Rect({
left: 250, top: 100,
width: 100, height: 80,
fill: '#3498db',
rx: 10, ry: 10 // Bo góc
});
// Thêm text
var text = new fabric.Textbox('Kéo tôi đi!', {
left: 100, top: 250,
width: 200,
fontSize: 20,
fill: '#2c3e50',
editable: true // Cho phép edit text trực tiếp
});
canvas.add(circle, rect, text);
// Event handlers
canvas.on('object:moving', function(e) {
console.log('Đang kéo:', e.target.type, 'tới', e.target.left, e.target.top);
});
canvas.on('selection:created', function(e) {
console.log('Đã chọn:', e.selected.length, 'đối tượng');
});
// Serialize (lưu trạng thái)
$('#saveBtn').click(function() {
var json = JSON.stringify(canvas.toJSON(['id', 'customProp']));
localStorage.setItem('canvasState', json);
});
// Deserialize (khôi phục)
$('#loadBtn').click(function() {
var json = localStorage.getItem('canvasState');
if (json) canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));
});
</script>
</body>
</html>
Ví dụ Konva.js - Hiệu năng cao
<script src="https://cdn.jsdelivr.net/npm/konva@9.2.0/konva.min.js"></script>
<div id="container"></div>
<script>
var stage = new Konva.Stage({
container: 'container',
width: 600,
height: 400
});
var layer = new Konva.Layer();
var circle = new Konva.Circle({
x: 100, y: 100,
radius: 50,
fill: 'red',
draggable: true // Drag & drop built-in!
});
// Event trên object
circle.on('dragstart', function() {
this.opacity(0.5);
layer.draw();
});
circle.on('dragend', function() {
this.opacity(1);
layer.draw();
});
layer.add(circle);
stage.add(layer);
</script>
Raphaël (Deprecated - Tham khảo lịch sử)
Raphaël dùng SVG/VML (cho IE cũ), không phải Canvas. Đã ngừng phát triển. Không khuyến khích cho dự án mới.
Khuyến nghị chọn thư viện
- Cần SVG import/export, serialization JSON, text editing → Fabric.js.
- Cần hiệu năng cao, 60fps, nhiều object, React/Vue → Konva.js (+ react-konva).
- Cần vector boolean operations (union, subtract, intersect) → Paper.js.
- Đơn giản, nhẹ, cross-renderer → Two.js.