Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> HTML

HTML5 Canvas drag-and-drop, select với thư viện JS (Fabric.js, Konva.js)

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ệnKích thướcĐặc điểm nổi bậtPhù hợp
Fabric.js~120KBObject model đầy đủ, SVG parsing, serialization, interaction built-inEditor, design tool, whiteboard
Konva.js~60KBHiệu năng cao, Stage/Layer, React/Vue binding, animationGame 2D, chart realtime, high-perf
Paper.js~180KBVector-based, Path boolean ops, Svg import/exportIllustration, drawing app
Two.js~50KBUnified API: Canvas, SVG, WebGLCross-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.