做者本人的干货,通常人我不给他看。(开玩笑的)web
canvas是一个很实用的工具,难能够难到头发掉光,简单能够简单到几行代码就能给人眼前一亮的效果。这里是做者在开发canvas的道路上遇过的坑,以及如何用简易地使用canvas作一些平常任务,好比分享图片的自定义,又好比你们喜欢的X炸天的粒子特效(不知道算不算,反正很COOL就是了)。canvas
你们都知道Canvas能够作流畅的动画,功能很强大,可是Canvas中并无像Dom那样能够帮助咱们调试的工具。不过如今mac有一款web inspector(webkit.org/downloads//)能够调试canvas,有兴趣的同窗能够去试一下。api
不过这里还有一种方式能够帮助你们调试Canvas。Canvas其实就是一块绘板,随便你在上面画什么。可是又不像PS那样有辅助线,所以定位很艰辛。数组
所以,手动给Canvas加上网格,不就能够了!这里咱们能够建立一个绘制网格的方法,而后每次render的时候调用,这样就能够对图形的定位有一个直观的感觉了。不再用抓瞎。浏览器
首先咱们要计算好网格的数量,将全部计算好的网线放入一个数组中。虽然咱们也能够动态计算,网格的位置,可是从性能上考虑,canvas中凡是在绘图以前能够确认的位置都提早计算好,这样能够提升性能。这里我留了一点空间给坐标值,所以并非全屏的网格。bash
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]);
})
}
复制代码
注意这里beginPath是一切新开始的意思,也就是当前图和上一个操做已经没有了任何关系。closePath就是结束的意思,一切回到最初开始的地方,就是最早开始的那个点。lineTo就是画线的意思,两个点之间画一条直线。咱们能够搭配moveTo使用,moveTo就是移动到当前点,可是并不绘制任何内容。工具
若是咱们只是绘制图形,并没有其余操做,好比每段路径的颜色不同或者是填充颜色不同,那么moveTo和beiginPath的做用差很少,可是若是是,那么每次都须要beginPath一下,切断与上一个路径的联系,不然会以最后的设置的填充色路径色为主。性能
那么问题来了我直接closePath能够吗?固然不行,你能够说开始就开始,但不能说结束就结束!closePath最大的做用就是链接路径最后一个点和路径最开始的点。动画
由于Canvas是画布,因此每次画面更新时都是擦干净,再画下一幅画,否则就会重叠。你们想一想一下帧动画,就是1s中N幅画划过的动态感,变成了会动的动画。若是是jpg这种不透明的图片还能够一层层覆盖,若是是png透明的图片,一层层就会堆叠在一块儿。因此橡皮擦的功能时必不可少的。
其实就是画一个矩形,矩形所在的地方图像消失。
在线玩耍地址:
See the Pen canvas No.1 by cherryvenus (@cherryvenus) on CodePen.
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
复制代码
咱们的H5在哪里的传播最多?微信啊!咱们常常接到一个功能,让用户保存图片,分享到朋友圈。一般这个图片是用户本身填写内容,而后打印到屏幕上。最后合成,保存的。那么Canvas该如何帮助咱们保存图片呢?
Canvas虽然不能直接保存图片,可是却能够生成Base64的文件。咱们将Base64放入img标签中,用户就能够自由保存了。
代码也很简单canvas.toDataURL('image/jpeg');
。
代码玩耍地址:
See the Pen Canvas No.2 by cherryvenus (@cherryvenus) on CodePen.
Canvas的代码一个不当心就会写好多好多,每次新建一个操做都要写好多内容。这个时候就要看看Canvas的复用操做了,一个是减小操做,还有一个就是减小机器的压力,防止计算量过多。
谈到save&restore,可能你们会有点懵,不知道这个是用来作什么的。也不知道有什么用。咱们假想全部的canvas的配置,如fillSytle,strokeStyle的状态都封装在一个对象之中,而后每次save这个对象,就将这个对象push到一个Cavans状态的数组之中,以后咱们可能改变了其中的一些属性,而后咱们又须要以前的哪一个配置,怎么办?再写一遍属性配置吗?不,这个时候咱们能够用restore,一键切换至上一个状态。也就是当前的配置所有失效。全部属性值回退到以前的一个状态。咱们能够一直restore到默认值,也就是Canvas状态数组空了为止。
代码玩耍地址:
See the Pen Canvas No3 save&restore by cherryvenus (@cherryvenus) on CodePen.
解析图:
我的以为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 Pen Canvas N0.4 by cherryvenus (@cherryvenus) on CodePen.
这个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 Pen canvas No5. COOL by cherryvenus (@cherryvenus) on CodePen.