小程序 2d canvas 尺寸问题
日期:2020-06-26
作者:科技微讯
微信小程序 canvas 2d 官方例子是这样的:
wxml
<canvas type="2d" id="myCanvas"></canvas>
js
Page({
onReady() {
const query = wx.createSelectorQuery()
query
.select("#myCanvas")
.fields({ node: true, size: true })
.exec(res => {
const canvas = res[0].node
const ctx = canvas.getContext("2d")
// 根据 dpr 做相关设置
const dpr = wx.getSystemInfoSync().devicePixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
ctx.fillRect(0, 0, 100, 100)
})
},
})
canvas 组件没有设置 style, 所以默认 style 就是 width: 300px; height 150px
, 在 wxml 中的尺寸都是 css pixel
, 设备会把 css pixel 乘以 devicePixelRatio 转换成 device pixel 再显示在屏幕上. iPhone 6 的屏幕分辨率是 375*667, 这个数字也是 css pixel.
记住, 在 wxml 显示的是 css pixel, 但是在 js 中写的 canvas 代码, 通常是 device pixel 尺寸. 所以上面的例子, 通过 res[0].width
拿到这个 canvas 组件的 css pixel, 然后乘以 dpr 转换成这个 canvas 的 device pixel. 如果不转换, 那整个图片都会被缩小.
canvas.width
和 canvas.style.width
是不同的东西, 前者定义了 canvas 的座标体系, 而后者定义 canvas 实际显示的尺寸. 上面这个例子设置了 canvas.width = canvas.style.width * dpr
, 这样可以保证 canvas 的图片清晰地显示出来. 有时候也可以 Math.round(canvas.width / dpr) = canvas.style.width
ctx.scale(dpr, dpr)
的作用是, 用微信小程序文档的一句话来说, 就是:
在调用后,之后创建的路径其横纵坐标会被缩放。多次调用倍数会相乘.
所以下面这个代码:
ctx.scale(dpr, dpr)
ctx.fillRect(0, 0, 100, 100)
相当于下面这个代码:
ctx.fillRect(0 * dpr, 0 * dpr, 100 * dpr, 100 * dpr)
有时候之所以写 ctx.scale(dpr, dpr)
, 是因为接下来可以用 css pixel 去画这个 canvas, 毕竟 css pixel 是设计师采用的尺寸, 不用每次都乘以 dpr.
drawImage(imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
中, sWidth 和 sHeight 都是图片的 css pixel 尺寸, 如果不确定可以用 wx.getImageInfo()
获取, 后面四个参数都是 canvas 的座标位置, 根据 canvas.width
和 canvas.height
以及 ctx.scale(dpr, dpr)
确定.
wx.canvasToTempFilePath
可以设置这些选项:
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: 50,
height: 50,
destWidth: 100,
destHeight: 100,
canvas: 'myCanvas',
success(res) {
console.log(res.tempFilePath)
}
})
前面四个参数是 canvas 的 css 座标, destWidth 和 destHeight 是最终输出的图片的 css 尺寸, 即 destWidth: 100,
其实相当于在输出的图片添加 image.style.width = 100px
. destWidth 和 destHeight 要不小于 width 和 height, 否则会变模糊.