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

Thêm sự kiện click (onClick) cho hình vẽ trên HTML5 Canvas

Canvas vẽ bitmap (pixel) - không có DOM element cho từng hình vẽ (hình tròn, chữ nhật, path...). Để xử lý click trên hình vẽ, bạn phải:

  1. Gắn sự kiện click cho toàn bộ canvas element.
  2. Tính toán tọa độ click tương đối so với canvas.
  3. Kiểm tra xem tọa độ đó có nằm trong vùng hình vẽ nào không (hit testing).

Cơ bản: Gắn sự kiện click cho canvas

var canvas = document.getElementById('myCanvas');
canvas.addEventListener('click', function(event) {
  // Tính tọa độ click tương đối so với canvas
  var rect = canvas.getBoundingClientRect();
  var x = event.clientX - rect.left;
  var y = event.clientY - rect.top;
  
  console.log('Click tại:', x, y);
  // TODO: Kiểm tra hit test cho các hình vẽ
}, false);

Hit Testing - Kiểm tra va chạm

Lưu trữ thông tin hình vẽ (vị trí, kích thước) trong mảng, kiểm tra khi click:

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var rect = canvas.getBoundingClientRect();

// Mảng lưu trữ các hình vẽ
var shapes = [];

// Thêm hình chữ nhật
shapes.push({
  type: 'rect',
  x: 50, y: 50,
  width: 100, height: 80,
  color: '#1C2128',
  id: 'rect1'
});

// Thêm hình tròn
shapes.push({
  type: 'circle',
  x: 200, y: 100,
  radius: 40,
  color: '#e74c3c',
  id: 'circle1'
});

// Vẽ tất cả hình
function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  shapes.forEach(function(shape) {
    ctx.fillStyle = shape.color;
    if (shape.type === 'rect') {
      ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
    } else if (shape.type === 'circle') {
      ctx.beginPath();
      ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
      ctx.fill();
    }
  });
}
render();

// Xử lý click
canvas.addEventListener('click', function(event) {
  var x = event.clientX - rect.left;
  var y = event.clientY - rect.top;
  
  // Kiểm tra ngược từ trên xuống (topmost first)
  for (var i = shapes.length - 1; i >= 0; i--) {
    var shape = shapes[i];
    var hit = false;
    
    if (shape.type === 'rect') {
      hit = x > shape.x && x < shape.x + shape.width &&
            y > shape.y && y < shape.y + shape.height;
    } else if (shape.type === 'circle') {
      var dx = x - shape.x;
      var dy = y - shape.y;
      hit = (dx * dx + dy * dy) < (shape.radius * shape.radius);
    }
    
    if (hit) {
      alert('Clicked on: ' + shape.id);
      break; // Chỉ xử lý hình trên cùng
    }
  }
});

Nâng cao: Sử dụng Path2D (HTML5 Canvas API)

Path2D lưu trữ đường vẽ (path) và hỗ trợ ctx.isPointInPath(path, x, y) cho hit test chính xác cho path phức tạp:

var path1 = new Path2D();
path1.rect(50, 50, 100, 80); // Hình chữ nhật

var path2 = new Path2D();
path2.arc(200, 100, 40, 0, Math.PI * 2); // Hình tròn

// Vẽ
ctx.fillStyle = '#1C2128';
ctx.fill(path1);
ctx.fillStyle = '#e74c3c';
ctx.fill(path2);

// Hit test chính xác theo path
canvas.addEventListener('click', function(e) {
  var x = e.clientX - rect.left;
  var y = e.clientY - rect.top;
  
  if (ctx.isPointInPath(path2, x, y)) { // Kiểm tra hình tròn trước (trên cùng)
    alert('Click hình tròn');
  } else if (ctx.isPointInPath(path1, x, y)) {
    alert('Click hình chữ nhật');
  }
});

Thư viện hỗ trợ (Khuyên dùng cho app phức tạp)

  • Fabric.js - Object model cho canvas, event handling built-in.
  • Konva.js - 2D canvas framework, hiệu năng cao, React/Vue binding.
  • Paper.js - Vector graphics, scene graph.
  • Two.js - API thống nhất cho Canvas, SVG, WebGL.