canvas实践笔记
对canvas使用有过好几次了,曾经用基于canvas的createjs写过一个俄罗斯方块的游戏,毕业设计做的是多人在线绘图网站,自然也是canvas实现的。
最近工作需要,需要在h5端调用canvas API实现生成一张带有数据图的图片,“传送给native端”,所以对canvas的使用做一个总结。[2016-08-27更正:生成图片需要走http传输协议,app内与native通信走file传输协议,协议不同,不能直接通信,所以不能完成直接传送给native,只能传送给server端。]
由简到难,本文首先简单介绍canvas几个常用API,然后给出图片预加载的代码,最后会列举绘制过程中的多个坑。
SVG绘制图形是通过构建一棵XML树来实现,canvas来绘制图形是通过调用它提供的方法。所以在canvas中移除相应的元素需要先将当前的相应元素擦除,然后重新绘制。
业务实现效果图,制作过程3.5天,踩了不少坑,下面进行详细讲解。
图形绘制一些简单的API
canvas标签在html文档流中存放,标签内的区域都是画布,所以可以在标签上直接设置画布的长宽。
1 |
|
前面已经说过,canvas需要调用API来绘制图形,大部分API需要调用一个上下文对象来实现,所以需要getContext('2d')
方法(传参2d)来获取这个CanvasRenderingContext2D对象,使用这个对象来实现在画布上绘制二维图形。注意
每个canvas元素只有一个上下文对象
1 |
|
1 |
|
实践过程中发现context.fill()有个坑,特别是在给矩形填充颜色的时候,context的指向会出现问题,可能会将之前已经填充的内容重新填充。
简易使用context.fillRect()这个属性来填充矩形。
如果不可避免需要使用context.fill()这个属性,尽量提前使用,不要影响到后面的内容。
插入图片
1 |
|
[业务需求]:将切图展示在画布的指定位置,设置图片大小
canvas绘图阻塞浏览器,按顺序执行,画图之前需要图片全部加载成功,作者编写了图片预加载功能,在完全加载完成后进行绘制。
1 |
|
imgList存储图片源文件,newImgList存储加载完成的图片,只有当两个list长度相等时,图片完全加载完成,可以进行画布绘制,另外加载图片的过程是浏览器的异步行为,newImgList中的图片顺序和imgList不一定相同,所以需要根据名字查询图片信息。(在附录的链接中作者给出了完整的实现)
缩小图片并剪裁成圆形
[业务需求]:展示用户的圆形小头像,后端返回的是一定尺寸的大头像,所以我需要先等比例缩放,然后进行圆形裁剪。
需要注意的是,arc+clip的方法只对绘制的图形产生效果,对图片不起作用。
所以只能用填充的方法,设置一个填充pattern(ctx.createPattern(image, repetition)),但是填充的效果是图片的原像素尺寸,如果原图是一张超大图,很有可能填充的只是黑色的一个小角,所以在填充之前需要对原图进行等比例缩小。
有个CanvasPattern.setTransform(matrix)的方法,matrix是SVG的缩放方式,OMG!难道写canvas还要和SVG合用吗?好吧,尝试之后遇到了更难过的结果,连亲爱的chrome都不支持!那就别说其他浏览器了。
换种思路,能不能用别的方式缩小图片呢?还是老大厉害,鼓励我尝试了先将图片绘制在另一个canvas上下文中,然后将新的canvas调整到我所需要的尺寸,然后将新的canvas作为填充pattern填充到老canvas的fill中,尝试结果,完美实现填充!
1 |
|
状态堆栈
画布API允许保存当前画布的状态,采用的是堆栈的方式,采用save和restore方法,相当于push和pop,恢复堆栈中的状态。也可以理解为PS的一个图层,作者实践过程中在使用context.scale()这个属性的时候一定需要调用pop和restore。
1 |
|
toDataURL时间上的坑
业务需求需要先向后端请求数据,然后进行绘制,我在做这个需求的时候遇到两个坑。
第一个坑:toDataURL后发现ajax请求的数据还没有返回,所以canvas没有画完。因为ajax请求是异步的,无法判断精确data的返回时间,所以只能在请求成功的回调中进行绘制方法的调用。(附录代码段中作者封装了多个请求执行完毕后处理绘图)
第二个坑:需要在图片预加载结束后画图,然后toDataURL,本地运行时图片加载时间可以忽略不计,而生产环境时加载图片是需要一定时间的,所以判断加载完成的js语句根本没有执行。解决方法是每加载一次图片时进行图片加载判断,即有100张图片就需要执行100次判断,直到第100次判断图片加载完全执行完毕,调用绘图方法进行绘制。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!