内容简介:作者本人的干货,一般人我不给他看。(开玩笑的)canvas是一个很实用的工具,难可以难到头发掉光,简单可以简单到几行代码就能给人眼前一亮的效果。这里是作者在开发canvas的道路上遇过的坑,以及如何用简易地使用canvas做一些日常任务,比如分享图片的自定义,又比如大家喜欢的X炸天的粒子特效(不知道算不算,反正很COOL就是了)。大家都知道Canvas可以做流畅的动画,功能很强大,但是Canvas中并没有像Dom那样可以帮助我们调试的工具。不过现在mac有一款web inspector(
作者本人的干货,一般人我不给他看。(开玩笑的)
canvas是一个很实用的工具,难可以难到头发掉光,简单可以简单到几行代码就能给人眼前一亮的效果。这里是作者在开发canvas的道路上遇过的坑,以及如何用简易地使用canvas做一些日常任务,比如分享图片的自定义,又比如大家喜欢的X炸天的粒子特效(不知道算不算,反正很COOL就是了)。
No.1 Canvas的正确打开方式
大家都知道Canvas可以做流畅的动画,功能很强大,但是Canvas中并没有像Dom那样可以帮助我们调试的工具。不过现在mac有一款web inspector( webkit.org/downloads// )可以调试canvas,有兴趣的同学可以去试一下。
不过这里还有一种方式可以帮助大家调试Canvas。Canvas其实就是一块绘板,随便你在上面画什么。但是又不像PS那样有辅助线,因此定位很艰辛。
创建网格
- mark api:
- context.fillStyle
- context.textAlign
- context.font
- context.textBaseline
- context.fillRect
- context.fillText
因此,手动给Canvas加上网格,不就可以了!这里我们可以创建一个绘制网格的方法,然后每次render的时候调用,这样就可以对图形的定位有一个直观的感受了。再也不用抓瞎。
首先我们要计算好网格的数量,将所有计算好的网线放入一个数组中。虽然我们也可以动态计算,网格的位置,但是从性能上考虑,canvas中凡是在绘图之前可以确认的位置都提前计算好,这样可以提高性能。这里我留了一点空间给坐标值,因此并不是全屏的网格。
let Grids=[] function initGrid(cap,width,height,lineWidth){ const colNum=Math.ceil(width/cap)-1 const rowNum=Math.ceil(height/cap)-1 for(let i=1;i<=colNum;i++){ Grids.push([[cap*i-1, 0,lineWidth,colNum*cap],[i*cap,cap*i-1,colNum*cap+5,"top"]]) } for(let i=1;i<=rowNum;i++){ Grids.push([[ 0,cap*i-1,rowNum*cap,lineWidth],[i*cap,rowNum*cap+5,cap*i-1,"middle"]]) } } initGrid(cap,canvasWidth,canvasHeight,lineWidth); 复制代码
计算并保存好信息之后,我们就要开始画线了。对于线的宽度最好是双数,然后位置偏1px,然线居中,因为.5px在有些机子上性能不好,比如四舍五入一类的,容易有偏差。
function createGrid(){ context.fillStyle = 'green'; context.textAlign="center" context.font="24px Arial" Grids.forEach((grid)=>{ context.textBaseline=grid[1][3] context.fillRect( grid[0][0],grid[0][1], grid[0][2], grid[0][3]) context.fillText (grid[1][0],grid[1][1], grid[1][2]); }) } 复制代码
画一个几何图形
- mark api:
- context.beginPath();
- context.moveTo (50, 50);
- context.lineTo (450, 450);
- context.closePath()
注意这里beginPath是一切新开始的意思,也就是当前图和上一个操作已经没有了任何关系。closePath就是结束的意思,一切回到最初开始的地方,就是最先开始的那个点。lineTo就是画线的意思,两个点之间画一条直线。我们可以搭配moveTo使用,moveTo就是移动到当前点,但是并不绘制任何内容。
如果我们只是绘制图形,并无其他操作,比如每段路径的颜色不一样或者是填充颜色不一样,那么moveTo和beiginPath的作用差不多,但是如果是,那么每次都需要beginPath一下,切断与上一个路径的联系,否则会以最后的设置的填充色路径色为主。
那么问题来了我直接closePath可以吗?当然不行,你可以说开始就开始,但不能说结束就结束!closePath最大的作用就是连接路径最后一个点和路径最开始的点。
橡皮擦
因为Canvas是画布,所以每次画面更新时都是擦干净,再画下一幅画,不然就会重叠。大家想想一下帧动画,就是1s中N幅画划过的动态感,变成了会动的动画。如果是jpg这种不透明的图片还可以一层层覆盖,如果是png透明的图片,一层层就会堆叠在一起。所以橡皮擦的功能时必不可少的。
- mark api:
- context.clearRect (x,y,width,height);
其实就是画一个矩形,矩形所在的地方图像消失。
在线玩耍地址:
See the Pencanvas No.1 by cherryvenus (@cherryvenus) onCodePen.
No.2 Canvas的实用工具
Canvas中有几个小知识点,非常的实用,而且应该是日常开发中基本上都要使用的。
Canvas的像素点
首先就是像素的问题,大家有没有遇到过Canvas模糊的问题,尤其是手机,这个现象尤为明显。那么有没有解决方案呢?答案是当然有!而且并不复杂,一个属性就可以搞定!
Canvas的尺寸其实又两个,不知道大家有没有发现。一个时Canvas的大小,一个是Canvas的样式大小。
canvas.width=cWidth canvas.height=cHeight canvas.style.width=cWidth canvas.style.height=cHeight 复制代码
那么这就好解决的。我们的图片如果1:1放在手机上肯定是模的,但是我们会将图片的样式宽度减少一半以上,这样就不模糊了!Canvas也是同理,只要样式大小小于Canvas大小即可。那么小多少呢?有没有一个标准?这个时候就要借用 window.devicePixelRatio
这个参数了,告诉我们屏幕的像素比,如果没有就2,一般来说像素比是2的情况下,Canvas就不会模糊。
const dpr=window.devicePixelRatio||2 canvas.width=cWidth*dpr canvas.height=cHeight*dpr canvas.style.width=cWidth canvas.style.height=cHeight 复制代码
论如何保存Canvas的图像
我们的H5在哪里的传播最多?微信啊!我们经常接到一个功能,让用户保存图片,分享到朋友圈。通常这个图片是用户自己填写内容,然后打印到屏幕上。最后合成,保存的。那么Canvas该如何帮助我们保存图片呢?
Canvas虽然不能直接保存图片,但是却可以生成Base64的文件。我们将Base64放入img标签中,用户就可以自由保存了。
代码也很简单 canvas.toDataURL('image/jpeg');
。
代码玩耍地址:
See the PenCanvas No.2 by cherryvenus (@cherryvenus) onCodePen.
No.3 save&restore,Canvas的回退功能
Canvas的代码一个不小心就会写好多好多,每次新建一个操作都要写好多内容。这个时候就要看看Canvas的复用操作了,一个是减少操作,还有一个就是减少机器的压力,防止计算量过多。
谈到save&restore,可能大家会有点懵,不知道这个是用来做什么的。也不知道有什么用。我们假想所有的canvas的配置,如fillSytle,strokeStyle的状态都封装在一个对象之中,然后每次save这个对象,就将这个对象push到一个Cavans状态的数组之中,之后我们可能改变了其中的一些属性,然后我们又需要之前的哪个配置,怎么办?再写一遍属性配置吗?不,这个时候我们可以用restore,一键切换至上一个状态。也就是当前的配置全部失效。所有属性值回退到之前的一个状态。我们可以一直restore到默认值,也就是Canvas状态数组空了为止。
代码玩耍地址:
See the Pen Canvas No3 save&restore by cherryvenus (@cherryvenus) onCodePen.
No.4 最常用的drawImage全方位解读
解析图:
个人觉得Canvas中最头疼的就是图片的绘制了,drawImage这个一个方法,就可以帮助我们完成拉伸,剪切,放大,缩小的功能。
drawImage的总参数有9个,但是平时我们可以简写。
第一个参数一定是image,也就是我们的图片对象。其余的几个参数,容易搞混。我们来详细地看下。
参数 | 作用 |
---|---|
dx,dy | 这个最好理解,这里是指图片开始绘制的位置,如果设置这两个参数,就是从这个(dx,dy)点开始绘制原始完整的图片 |
dx,dy,dwidth,dheight | 这里除了开始点(dx,dy),还有图片在画布上呈现的大小,这边需要注意,虽然会画完整的图片,但是会按照dwidth和dheight的尺寸来,因此就会产生图片变形的情况。 |
sx,sy,swidth,sheight,dx,dy,dwidth,dheight | 这个比较难以理解,前四个是对原始图片的操作,也就获取原始图片的区域,后四个参数就是图片需要绘制在画布上的位置和大小。也就是图片的所选区域放入画布的所选区域。 |
玩耍地址:
See the PenCanvas N0.4 by cherryvenus (@cherryvenus) onCodePen.
No5. X炸天的特效
- mark api:
- context.getImageData 获取图像信息
这个api是最amazing的方法,因为他帮助我们获取了画布的颜色信息,通过这个信息,我们可以重新创造新的图片。这个方法除了体积大,没啥毛病。因为他的data长度是按照 width(宽)*height(高)*4(rgba四个颜色信息)
组成的。
let info=context.getImageData(x,y,width,height) //返回 data width height 复制代码
这里要避免遍历data( data.forEach
),来处理图片信息,因为很大,浏览器容易卡顿。最好按照定位信息,获取当前坐标的颜色信息。
至于最开始的那个特效,我是借助了matter.js这个库,才能完成的。如果是手写特效的话,不如这个库来的生动有趣。
play地址:
See the Pencanvas No5. COOL by cherryvenus (@cherryvenus) onCodePen.
以上所述就是小编给大家介绍的《看完这本攻略,Canvas新手小白也可以创建惊人特效》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
RGB转16进制工具
RGB HEX 互转工具
MD5 加密
MD5 加密工具