画布尺寸设置

正确设置Canvas尺寸是绑制清晰图形的前提。很多初学者在这里踩坑,导致图形变形或模糊。

两种设置方式

HTML属性设置

<canvas id="canvas" width="400" height="300"></canvas>

这是推荐的方式,直接设置画布的绑制分辨率。

JavaScript设置

const canvas = document.getElementById('canvas')
canvas.width = 400
canvas.height = 300

CSS样式设置(不推荐)

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>

效果:一个正方形被拉伸成了长方形。

正确的设置方法

方法1:HTML属性

<canvas id="canvas" width="400" height="300"></canvas>

方法2:JavaScript

const canvas = document.getElementById('canvas')
canvas.width = 400
canvas.height = 300

方法3:动态设置

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)

常见错误

错误1:用CSS设置尺寸

// 错误
canvas.style.width = '400px'
canvas.style.height = '300px'
// 此时 canvas.width 和 canvas.height 还是默认值

// 正确
canvas.width = 400
canvas.height = 300

错误2:修改尺寸后不重绘

// 错误
canvas.width = 800  // 这会清空画布内容!
// 之前绑制的内容消失了

// 正确
canvas.width = 800
draw()  // 重新绑制

错误3:忽略高清屏

// 在高清屏上会模糊
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)