canvas使用小记

Canvas 想必前端er都不陌生,它是 HTML5 新增的「画布」元素,允许我们使用 JavaScript 来绘制图形。目前,所有的主流浏览器都支持 Canvas。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

获取 canvas 上下文

1
2
3
4
5
6
7
8
// html
<canvas id="myCanvas" style="width:375px;height:667px;"></canvas>
// js
var myCanvas = document.getElementById('myCanvas')
// 设置canvas真实宽高,不然会出现拉伸问题
myCanvas.width = 750
myCanvas.height = 1334
var ctx = c.getContext('2d')

绘制图片

  1. 创建 Img 元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function loadImg(url) {
    return new Promise(function(resolve, reject) {
    let img = new Image()
    img.setAttribute('crossOrigin','Anonymous')
    img.src = url
    img.onload = function() {
    resolve(img)
    }
    img.onerror = function(e) {
    reject(e)
    }
    })
    }
  2. 绘制图片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 绘制一张图片
    loadImg(this.painting.playbill_bg).then(res => {
    const playbill_bg = res
    ctx.drawImage(playbill_bg, 0, 0, 375, 667)
    })
    // 绘制多张图片
    Promise.all([loadImg(this.painting.playbill_bg), loadImg(this.painting.avatar), loadImg(this.painting.qrcodePath)]).then(images => {
    const [playbill_bg, avatar, qrcodePath] = images
    ctx.drawImage(playbill_bg, 0, 0, 375, 667)
    // do something ...
    const dataURL = myCanvas.toDataURL()
    console.log(dataURL)
    })

canvas 导出生成图片

把当前画布指定区域的内容导出生成指定大小的图片。

生成base64文件

相关文档MDN:HTMLCanvasElement.toDataURL()

1
2
var dataURL = myCanvas.toDataURL();
console.log(dataURL);

生成blob文件

相关文档MDN:HTMLCanvasElement.toBlob()

1
2
3
4
5
6
7
8
9
10
11
// 导出并本地预览文件
myCanvas.toBlob(function(blob) {
var newImg = document.createElement("img"),
url = URL.createObjectURL(blob);
newImg.onload = function() {
// no longer need to read the blob so it's revoked
URL.revokeObjectURL(url);
};
newImg.src = url;
document.body.appendChild(newImg);
});

Tips

canvas 宽高设置不当产生的拉伸或缩放问题

原因:canvas标签里的宽高是相当于定义画布的大小(默认宽300px,高150px)。在定义了画布之后,canvas就相当于一张图片了,类似于img,所以这个时候再设置宽高,就会把canvas拉伸成style里设置的宽高了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Canvas元素默认宽 300px, 高 150px, 设置其宽高可以使用如下方法:
方法一:
<canvas id="myCanvas" width="375" height="667" />您的浏览器不支持canvas</canvas>
方法二:使用HTML5 Canvas API操作
var myCanvas = document.getElementById('myCanvas');
myCanvas.width = 375;
myCanvas.width = 667;

若通过如下方法设置宽高,那么Canvas元素将由原来大小被拉伸到所设置的宽高:
方法一:使用CSS 会被拉伸
#myCanvas{
width:375px;
height:667px;
}

也包含了行间样式中的 style="" 。也就是上面的例子,也会产生拉伸的情况。
方法二:使用HTML5 Canvas API操作 会被拉伸
var myCanvas = document.getElementById('myCanvas');
myCanvas.style.width = "375px";
myCanvas.style.height = "667px";

其它:canvas的width和height也不能用百分比表示。canvas会将百分值当成数值显示

类似下面这样在style上,css中

清除画布的方法

1.重设 canvas 的 width 或 height 属性,会清空整个画布

1
myCanvas.height = 300

2.clearRect() 用于擦除指定矩形区域内的所有内容(所有像素变成透明)

1
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)

3.fillRect() 用于绘制填充矩形,使用某一特定颜色填充,达到清除的视觉效果

1
2
ctx.fillStyle = "#ffffff"
ctx.fillRect(0, 0, myCanvas.width, myCanvas.height)

canvas 的saverestore方法的作用

  1. save()

用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作

  1. restore()

用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响

一般结合使用,save是入栈,restore是出栈。

drawImage方法 跨平台差异

  • web 端 canvas 的drawImage第一个参数对象image 是 image 或者 canvas 对象
  • 小程序端 canvas 的drawImage第一个参数对象image 是图片地址

    图片跨域处理!!

1.给要使用的img上设置crossOrigin属性

1
2
3

2.设置允许跨域的响应头
- 图片所在服务器需要设置允许跨域的响应头
// 这是一个例子:不同后端语言的写法可能不一样
response.setHeader("Access-Control-Allow-Origin", "*")
```

请注意,少了第一步会报这个错 Tainted canvases may not be exported 画布被污染的意思。

性能优化小结

相关文档MDN:canvas 的优化建议

  • 避免浮点数的坐标点,用整数取而代之
  • 不要频繁设置绘图上下文的 font 属性
  • 通过计算和判断,避免无谓的绘制操作
  • 将固定的内容预先绘制在离屏 Canvas 上以提高性能