Canvas 坐标系统

Canvas坐标系统详解,理解二维坐标系统是绑制图形的基础,包含多个交互式案例 理解坐标系统是使用Canvas绑制图形的基础。Canvas使用的是二维笛卡尔坐标系,但与数学中的坐标系有些不同。

坐标系基础

Canvas坐标系的原点(0, 0)在画布的左上角

(0,0) ────────→ X轴
  │
  │
  │
  ↓
  Y轴

这与数学中的坐标系不同(数学坐标系原点在左下角,Y轴向上)。

案例一:坐标网格可视化

坐标网格(移动鼠标查看坐标)

坐标: (0, 0)

代码实现

<canvas id="myCanvas" width="400" height="250"></canvas>
<p id="coordDisplay">坐标: (0, 0)</p>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
const coordDisplay = document.getElementById('coordDisplay')

const width = canvas.width
const height = canvas.height
const step = 50

function drawGrid() {
  ctx.clearRect(0, 0, width, height)
  
  // 绘制网格线
  ctx.strokeStyle = '#ecf0f1'
  ctx.lineWidth = 1
  
  for (let x = 0; x <= width; x += step) {
    ctx.beginPath()
    ctx.moveTo(x, 0)
    ctx.lineTo(x, height)
    ctx.stroke()
  }
  
  for (let y = 0; y <= height; y += step) {
    ctx.beginPath()
    ctx.moveTo(0, y)
    ctx.lineTo(width, y)
    ctx.stroke()
  }
  
  // 标注刻度
  ctx.fillStyle = '#bdc3c7'
  ctx.font = '10px Arial'
  
  for (let x = 0; x <= width; x += step) {
    ctx.fillText(x, x + 2, 12)
  }
  
  for (let y = step; y <= height; y += step) {
    ctx.fillText(y, 2, y - 2)
  }
}

canvas.addEventListener('mousemove', function(e) {
  const rect = canvas.getBoundingClientRect()
  const x = Math.round(e.clientX - rect.left)
  const y = Math.round(e.clientY - rect.top)
  
  coordDisplay.textContent = `坐标: (${x}, ${y})`
  
  drawGrid()
  
  // 绘制十字线
  ctx.strokeStyle = '#3498db'
  ctx.setLineDash([5, 5])
  
  ctx.beginPath()
  ctx.moveTo(x, 0)
  ctx.lineTo(x, height)
  ctx.stroke()
  
  ctx.beginPath()
  ctx.moveTo(0, y)
  ctx.lineTo(width, y)
  ctx.stroke()
  
  ctx.setLineDash([])
  
  // 绘制当前位置点
  ctx.fillStyle = '#3498db'
  ctx.beginPath()
  ctx.arc(x, y, 6, 0, Math.PI * 2)
  ctx.fill()
})

drawGrid()
</script>

代码解析

方法说明
moveTo(x, y)移动画笔到指定坐标
lineTo(x, y)从当前点画线到指定坐标
setLineDash([5, 5])设置虚线样式
getBoundingClientRect()获取元素在页面中的位置

案例二:坐标与图形绑制

不同位置的图形

代码实现

<canvas id="myCanvas" width="400" height="200"></canvas>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')

// 在(50, 50)位置绑制红色矩形
ctx.fillStyle = '#e74c3c'
ctx.fillRect(50, 50, 60, 60)
ctx.fillStyle = '#333'
ctx.font = '12px Arial'
ctx.fillText('(50, 50)', 50, 130)

// 在(170, 30)位置绑制绿色矩形
ctx.fillStyle = '#2ecc71'
ctx.fillRect(170, 30, 60, 60)
ctx.fillText('(170, 30)', 170, 110)

// 在(290, 70)位置绑制蓝色矩形
ctx.fillStyle = '#3498db'
ctx.fillRect(290, 70, 60, 60)
ctx.fillText('(290, 70)', 290, 150)

// 绘制圆形
ctx.strokeStyle = '#9b59b6'
ctx.lineWidth = 3
ctx.beginPath()
ctx.arc(110, 150, 25, 0, Math.PI * 2)
ctx.stroke()

// 标记原点
ctx.fillStyle = '#e74c3c'
ctx.beginPath()
ctx.arc(0, 0, 5, 0, Math.PI * 2)
ctx.fill()
</script>

代码解析

参数说明
fillRect(x, y, w, h)x,y是左上角坐标
arc(x, y, r, start, end)x,y是圆心坐标
fillText(text, x, y)x,y是文本左下角坐标

案例三:获取鼠标坐标

点击画布获取坐标

代码实现

<canvas id="myCanvas" width="400" height="200"></canvas>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')

const points = []

canvas.addEventListener('click', function(e) {
  // 获取鼠标在Canvas中的坐标
  const rect = canvas.getBoundingClientRect()
  const x = Math.round(e.clientX - rect.left)
  const y = Math.round(e.clientY - rect.top)
  
  points.push({ x, y })
  
  // 重绘所有点
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  
  points.forEach((point, index) => {
    // 绘制点
    ctx.fillStyle = '#3498db'
    ctx.beginPath()
    ctx.arc(point.x, point.y, 8, 0, Math.PI * 2)
    ctx.fill()
    
    // 显示坐标
    ctx.fillStyle = '#333'
    ctx.font = '11px Arial'
    ctx.textAlign = 'center'
    ctx.fillText(`(${point.x},${point.y})`, point.x, point.y - 15)
  })
  
  // 连接最后两个点并显示距离
  if (points.length > 1) {
    const last = points[points.length - 1]
    const prev = points[points.length - 2]
    
    ctx.strokeStyle = '#e74c3c'
    ctx.lineWidth = 2
    ctx.beginPath()
    ctx.moveTo(prev.x, prev.y)
    ctx.lineTo(last.x, last.y)
    ctx.stroke()
    
    // 计算距离
    const dx = last.x - prev.x
    const dy = last.y - prev.y
    const dist = Math.sqrt(dx * dx + dy * dy).toFixed(1)
    
    const midX = (prev.x + last.x) / 2
    const midY = (prev.y + last.y) / 2
    
    ctx.fillStyle = '#e74c3c'
    ctx.fillText(`距离: ${dist}px`, midX, midY - 10)
  }
})
</script>

代码解析

方法说明
getBoundingClientRect()获取元素相对于视口的位置
clientX - rect.left计算鼠标在元素内的X坐标
clientY - rect.top计算鼠标在元素内的Y坐标
Math.sqrt(dx*dx + dy*dy)计算两点间距离(勾股定理)

坐标值含义

参数含义
x水平位置,向右递增
y垂直位置,向下递增

坐标与画布尺寸的关系

对于400x300的画布:

  • x的有效范围:0 ~ 399
  • y的有效范围:0 ~ 299
  • 右下角坐标:(399, 299)

超出范围的绑制会被裁剪,不会报错:

// 这个矩形部分在画布外,只显示可见部分
ctx.fillRect(350, 250, 100, 100)

坐标变换的影响

Canvas支持坐标变换,变换会影响后续所有绑制:

// 平移坐标原点
ctx.translate(100, 100)

// 现在原点在原来的(100, 100)位置
// 这里的(0, 0)实际显示在画布的(100, 100)
ctx.fillRect(0, 0, 50, 50)

// 旋转(弧度)
ctx.rotate(Math.PI / 4)  // 旋转45度

// 缩放
ctx.scale(2, 2)  // 放大2倍

坐标变换的内容在后续章节详细讲解。

小结

Canvas坐标系统的要点:

  • 原点(0, 0)在左上角
  • X轴向右递增,Y轴向下递增
  • 坐标单位是像素
  • 超出画布范围会被裁剪
  • 获取鼠标坐标需要减去画布偏移