实践demo——“canvas离屏、旋转效果实践——旋转的雪花”html
前几天研究html2Canvas的时候恰好遇上做者发布新版本,发现新版本截屏出来的效果比我对旧版本处理后(画布尺寸都设为2倍)的效果更好。 扒源码的时候发现他们并无直接设为两倍尺寸,而是先获取当前dom结构的scale,用当前dom的scale去设置canvas的画布尺寸比。 我本身手机上测试时打印出来的dom的scale显示为3倍尺寸,因此我设置canvas两倍画布尺寸的时候,其实仍是会模糊的,不过对比1倍尺寸的是要清晰不少了。
问题缘由canvas
查阅canvas的API就能够知道,想要得到精确地线条,必须对线条是如何描绘出来的有所理解。segmentfault
首先要清楚一点:canvas画线时的定位定的是线条中线的位置,根据线条的宽度再向两边延伸,若是延伸出去的线条没有占满1px,不足的部分将会以实际笔触颜色的一半色调来填充。因此最后咱们实际看到的效果就是:1px的线条变宽了,且变模糊了,效果如左图所示:缓存
解决办法dom
根据问题缘由咱们知道:只要从线条中线开始向外延伸部分占满1px,就不会出现线条变宽且模糊的问题了。函数
最简单的办法是画线时根据需求将线条定位移动0.5px,不过这是治标不治本的方法,只能用来验证这个方法是否是正确的。布局
咱们还能够将画布尺寸设为显示尺寸的2倍,这至关于用画图时的两个像素点去填充实际显示的一个像素点,这样就能很好的解决canvas显示模糊的问题了。性能
canvas.setAttribute('width', x * 2); canvas.setAttribute('height', y * 2); canvas.style.width = x + 'px'; canvas.style.height = y + 'px';
用这种方法要记得:各类布局尺寸也要作相应变化。测试
定义离屏canvas,在离屏canvas上设定画布尺寸并绘制canvas图片:字体
var offScreenCanvas = document.createElement('offScreenCanvas'); var offScreenCtx = offScreenCanvas.getContext('2d');
而后将画好的离屏canvas绘制到实际显示的canvas上:
ctx.drawImage(offScreenCanvas, 0, 0, offScreenCanvas.width, offScreenCanvas.height, 0, 0, canvas.width, canvas.height);
好处
一是能够不受限于html标签及实际显示尺寸,画出一个标准尺寸的大图,而后自适应到实际显示的canvas上;
二是离屏canvas的缓存效果能够大大提高canvas的性能(固然像上述那样粗糙的代码,是体现不出这一效果的)。
不足
离屏canvas必定要画好以后才能绘制到实际显示的canvas上,这就致使哪些有延时的元素不方便这样用(如图片、自定义字体等)。针对这一问题,目前我尚未找到好的解决办法。
刚开始画图的时候很纠结的一个问题就是:canvas画png图片时,不一样屏幕尺寸要配多大的图、配几套。后来在解决上述“离屏canvas”的问题后,这个问题也就迎刃而解了:drawImage函数能够设定将图片绘制成多大的,而不限定于图片自己的尺寸。
这个问题解决以后,就只须要一套图片就行了,还可使图片大小自适应屏幕、随显示界面缩放。
canvas中有两个很好用的东西:旋转和保存状态。
以画圆的不一样角度的半径为例,正常状况下咱们要根据圆半径、线的角度和圆心的位置计算得出线的端点坐标P1{x1,y1}、P2{x2,y2},而后画一条P1到P2的线,代码中的计算量不小。不过canvas中咱们有更好的解决办法:
1.定位笔触到圆心位置{x,y}
ctx.translate(x,y)
2.根据线的角度旋转画布angle圈(angle=1时表示顺时针旋转一圈)
ctx.rotate(Math.PI*2 * angle);
3.画一条{0,0}到{r,0}的线便可
ctx.beginPath(); ctx.lineTo(0, 0); ctx.lineTo(r, 0); ctx.stroke();
canvas旋转方式画线步骤解读:
笔触定位至关因而定画布原点的位置,旋转画布则是以原点为圆心顺时针旋转了x/y坐标系,旋转后的效果是将x正半轴与要画的线重合,天然就至关于直接画一条{0,0}到{r,0}的线。
另一定要注意:
修改画布坐标系(定原点、旋转画布)以前必定要保存状态,画完线后必定要重载状态!否则你会很容易被本身改过的坐标系玩死的。