正确设置Canvas尺寸是绑制清晰图形的前提。很多初学者在这里踩坑,导致图形变形或模糊。
<canvas id="canvas" width="400" height="300"></canvas>
这是推荐的方式,直接设置画布的绑制分辨率。
const canvas = document.getElementById('canvas')
canvas.width = 400
canvas.height = 300
canvas {
width: 400px;
height: 300px;
}
注意:CSS只改变显示大小,不改变绑制分辨率。
| 方式 | 影响绑制分辨率 | 影响显示大小 |
|---|---|---|
| HTML属性 | 是 | 是 |
| JavaScript属性 | 是 | 是 |
| CSS样式 | 否 | 是 |
<!-- 画布绑制分辨率:300x150(默认值) -->
<!-- 显示大小:400x300(CSS设置) -->
<canvas id="canvas" style="width: 400px; height: 300px;"></canvas>
<script>
const ctx = canvas.getContext('2d')
ctx.fillRect(0, 0, 100, 100) // 图形会被拉伸变形
</script>
效果:一个正方形被拉伸成了长方形。
<canvas id="canvas" width="400" height="300"></canvas>
const canvas = document.getElementById('canvas')
canvas.width = 400
canvas.height = 300
function resizeCanvas(canvas, width, height) {
canvas.width = width
canvas.height = height
}
// 根据容器大小设置
const container = document.getElementById('container')
const canvas = document.getElementById('canvas')
resizeCanvas(canvas, container.clientWidth, container.clientHeight)
让Canvas跟随窗口大小变化:
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
function resize() {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
// 重新绑制内容
draw()
}
window.addEventListener('resize', resize)
resize() // 初始化
let resizeTimer
window.addEventListener('resize', function() {
clearTimeout(resizeTimer)
resizeTimer = setTimeout(function() {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
draw()
}, 100)
})
高清屏(Retina)上,一个CSS像素对应多个物理像素,导致Canvas模糊。
// CSS像素:400x300
// 物理像素(2倍屏):800x600
// 画布分辨率:400x300
// 结果:400个像素点拉伸到800个物理像素,模糊
function setupHiDPICanvas(canvas, width, height) {
const dpr = window.devicePixelRatio || 1
// 设置画布分辨率
canvas.width = width * dpr
canvas.height = height * dpr
// 设置显示大小
canvas.style.width = width + 'px'
canvas.style.height = height + 'px'
// 缩放上下文
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
return ctx
}
// 使用
const canvas = document.getElementById('canvas')
const ctx = setupHiDPICanvas(canvas, 400, 300)
// 之后绑制时使用CSS像素坐标
ctx.fillRect(0, 0, 100, 100) // 不需要考虑dpr
const CanvasUtil = {
setup(canvas, options = {}) {
const dpr = window.devicePixelRatio || 1
const width = options.width || canvas.clientWidth
const height = options.height || canvas.clientHeight
canvas.width = width * dpr
canvas.height = height * dpr
canvas.style.width = width + 'px'
canvas.style.height = height + 'px'
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
return { ctx, width, height, dpr }
}
}
const canvas = document.getElementById('canvas')
// 获取绑制分辨率
console.log(canvas.width, canvas.height)
// 获取显示大小(CSS)
console.log(canvas.clientWidth, canvas.clientHeight)
// 错误
canvas.style.width = '400px'
canvas.style.height = '300px'
// 此时 canvas.width 和 canvas.height 还是默认值
// 正确
canvas.width = 400
canvas.height = 300
// 错误
canvas.width = 800 // 这会清空画布内容!
// 之前绑制的内容消失了
// 正确
canvas.width = 800
draw() // 重新绑制
// 在高清屏上会模糊
canvas.width = 400
canvas.height = 300
// 正确处理高清屏
const dpr = window.devicePixelRatio || 1
canvas.width = 400 * dpr
canvas.height = 300 * dpr
canvas.style.width = '400px'
canvas.style.height = '300px'
ctx.scale(dpr, dpr)