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的画布:
超出范围的绑制会被裁剪,不会报错:
// 这个矩形部分在画布外,只显示可见部分
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坐标系统的要点: