事件处理

Canvas事件处理教程,掌握鼠标、触摸、键盘等交互事件的处理方法。事件处理是Canvas交互的核心,通过监听和响应各种用户输入事件,实现丰富的交互体验。

什么是事件处理

事件处理是指监听用户的输入操作(鼠标、触摸、键盘等),并做出相应响应的过程。

Canvas事件特点

特点说明
单一元素Canvas本身是一个DOM元素
内部检测需要自己检测点击了哪个图形
无内置事件图形没有内置的事件系统
手动管理需要手动管理交互状态

事件类型

鼠标事件

canvas.addEventListener('click', (e) => {
  console.log('点击位置:', e.offsetX, e.offsetY)
})

canvas.addEventListener('mousemove', (e) => {
  console.log('鼠标移动:', e.offsetX, e.offsetY)
})

canvas.addEventListener('mousedown', (e) => {
  console.log('鼠标按下, 按钮:', e.button)
})

canvas.addEventListener('mouseup', (e) => {
  console.log('鼠标释放')
})

触摸事件

canvas.addEventListener('touchstart', (e) => {
  e.preventDefault()
  const touch = e.touches[0]
  const rect = canvas.getBoundingClientRect()
  console.log('触摸开始:', touch.clientX - rect.left, touch.clientY - rect.top)
})

canvas.addEventListener('touchmove', (e) => {
  e.preventDefault()
  const touch = e.touches[0]
  console.log('触摸移动')
})

canvas.addEventListener('touchend', (e) => {
  console.log('触摸结束')
})

键盘事件

document.addEventListener('keydown', (e) => {
  console.log('按键:', e.key, 'keyCode:', e.keyCode)
})

document.addEventListener('keyup', (e) => {
  console.log('按键释放:', e.key)
})

基本演示

Canvas事件演示

事件处理流程

class EventHandler {
  constructor(canvas) {
    this.canvas = canvas
    this.shapes = []
    this.hoveredShape = null
    this.draggingShape = null
    
    this.bindEvents()
  }
  
  bindEvents() {
    this.canvas.addEventListener('mousemove', this.onMouseMove.bind(this))
    this.canvas.addEventListener('mousedown', this.onMouseDown.bind(this))
    this.canvas.addEventListener('mouseup', this.onMouseUp.bind(this))
    this.canvas.addEventListener('click', this.onClick.bind(this))
  }
  
  getMousePos(e) {
    const rect = this.canvas.getBoundingClientRect()
    return {
      x: e.clientX - rect.left,
      y: e.clientY - rect.top
    }
  }
  
  findShapeAt(x, y) {
    for (let i = this.shapes.length - 1; i >= 0; i--) {
      if (this.shapes[i].containsPoint(x, y)) {
        return this.shapes[i]
      }
    }
    return null
  }
  
  onMouseMove(e) {
    const pos = this.getMousePos(e)
    const shape = this.findShapeAt(pos.x, pos.y)
    
    if (shape !== this.hoveredShape) {
      if (this.hoveredShape) {
        this.hoveredShape.onMouseLeave()
      }
      this.hoveredShape = shape
      if (shape) {
        shape.onMouseEnter()
      }
    }
    
    if (this.draggingShape) {
      this.draggingShape.onDrag(pos.x, pos.y)
    }
  }
  
  onMouseDown(e) {
    const pos = this.getMousePos(e)
    const shape = this.findShapeAt(pos.x, pos.y)
    
    if (shape) {
      this.draggingShape = shape
      shape.onMouseDown(pos.x, pos.y)
    }
  }
  
  onMouseUp(e) {
    if (this.draggingShape) {
      const pos = this.getMousePos(e)
      this.draggingShape.onMouseUp(pos.x, pos.y)
      this.draggingShape = null
    }
  }
  
  onClick(e) {
    const pos = this.getMousePos(e)
    const shape = this.findShapeAt(pos.x, pos.y)
    
    if (shape) {
      shape.onClick(pos.x, pos.y)
    }
  }
}

章节导航

本章节包含以下内容:

学习建议

理解事件模型

了解DOM事件模型和Canvas的事件处理特点。

坐标转换

掌握屏幕坐标到Canvas坐标的转换方法。

性能考虑

事件处理要高效,避免不必要的重绘。

兼容性

考虑不同设备的输入方式(鼠标、触摸、手柄等)。