一. 绘制逻辑 1,首先创建canvas 2. 开始绘画 2.1 首先先画一个大圆,在画一个小圆,把重叠的部分去掉,把重合的地方填充颜色 2.2 进度条
我们开始吧!!!
1.首先获取canvas 已vue 为例子
<canvas class="canvas" ref="canvas"></canvas> mounted(){ let canvas = this.$refs.canvas // 设置画布大小 canvas.width = 60; canvas.height = 60; // 获得画布的上下文 this.context = canvas.getContext("2d"); this.renderAction() }, methods:{ renderAction() { // 清除上一次的绘制 this.context.clearRect(0, 0, 60, 60); // 绘制整个圆环 this.context.save(); this.context.beginPath(); // 起始一条路径 // 绘制大圆 * 2 = 360度 既 360º = 2π //2π / 360 = π / 180 ≈ 0.0174rad, 即: 度数 * (π / 180) = 弧度 //例如:将30º转为弧度rad // 30º * (π / 180)= 0.523320 rad // Math.PI = π this.context.moveTo(30, 30); // 把路径移动到画布中的指定点,不创建线条 this.context.arc(30,30,30,0,2*Math.PI *2,false) this.context.lineTo(30, 30); // 绘制小圆 this.context.moveTo(30,30) this.context.arc(30,30,25,0, 2*Math.PI *2,false) this.context.closePath() this.context.fillStyle= 'rgba(212, 68, 57, 0.3)' //fill()参数为evenodd 代表 把中间镂空 this.context.fill('evenodd') //把中间镂空 this.context.restore() // 绘制扇形 同样原理 先绘制大扇形在绘制小扇形 减去镂空的部分,剩下重合的部分,就是进度条 this.context.save() this.context.beginPath() this.context.moveTo(30,30) // 开始位置需要设置在 12点钟方法,默认是3点钟方向 但是结束位置需要在开始位置上进行调整 this.context.arc(30,30,30,Math.PI/180 * (-90),Math.PI/180 * (-90) + Math.PI/180 * 360*0.2,false) this.context.lineTo(30,30) this.context.arc(30,30,25,Math.PI/180 * (-90),Math.PI/180 * (-90) + Math.PI/180 * 360*0.2,false) this.context.lineTo(30,30) this.context.closePath() this.context.fillStyle= 'yellow' this.context.fill('evenodd') //把中间镂空 this.context.restore() } }
我们现在现在开始逐行分析吧,分析时会把补充canvas 方法及属性
1.获取画布-> 设置画布大小 -> 设置画布上下文
不能在css中给画布设置宽高,因为设置了大小是对画布进行了拉伸,应该在 js 中操作
2.知识点分析
2.1 this.context.clearRect(0, 0, 60, 60);
在给定的矩形内清除指定的像素 参数为this.context.clearRect(x坐标,y坐标,width,height)
2.2 this.context.save()
保存当前环境的状态
知识点:save() 入栈 ;restore() 出栈
save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。 restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
restore就能还原出上一次的图像
<canvas id="mc" width="200" height="200" style="border:1px solid black"></canvas> var canvas = document.getElementById('mc'); //获取Canvas元素对应的DOM对象 var ctx = canvas.getContext('2d');//获取Canvas上的绘图的CanvasRenderingContext2D对象 ctx.lineWidth=10; //设置笔触线条的宽度 ctx.save(); //保存当前画布的状态,该状态包含了lineWidth=3,translate(100,100),然后其他那些属性为默认值. ctx.strokeStyle='red'; //设置线条颜色为红色 // //坐标系统旋转90° ctx.rotate(Math.PI/2); // // //画第一条直线 ctx.beginPath(); ctx.moveTo(-100,0); ctx.lineTo(100,0); ctx.closePath(); ctx.stroke(); // //恢复之前保存的绘图状态 ctx.restore(); //再画第二条直线 ctx.beginPath(); ctx.moveTo(-100,0); ctx.lineTo(100,0); ctx.closePath(); ctx.stroke();
可以看出save()之前,就值设置了线条的10px宽度,所以第一次入栈就一个 宽高 200px的正方形。开始画第一条红色,将它旋转了90°并做一些其他操作时它竖着。之后restore()第一次出栈,恢复之前保存的绘画状态,就是save()之前只有宽高 200px的正方形。开始绘画第二条线,默认是黑色,第二条线没有旋转等操作,他就是横着的。横着就是因为save() restore(),如果没有 save() restore(),会怎么样的,大家想一下? 对,就是和红色的重合,因为第二条线,开始画的基础是在第一条线的位置继续重新绘制了。看下图更加理解
简而言之 画第一条线时,是将坐标系统旋转了90°,设置了lineStyle="red",故画出来的是垂直的红色线;画第二条线前调用了restore()方法,即恢复为了之前保存的绘图状态,该绘图状态是坐标系统没有经过旋转的,线条颜色也默认为黑色,所以画出来的先就是我们想要得到的水平的黑色线。
2.3 this.context.beginPath()
起始一条路径,或重置当前路径
说到beginPath,就不得不提到closePath,两者是不是有很“紧”的联系呢?答案是几乎没有关系。
beginPath()和closePath()成对出现!因为你如果想通过闭合一段路径来开始新的路径那么开始的路径也不会是新的路径
ctx. beginPath ( ) ; ctx. moveTo ( 100.5 , 20.5 ) ; ctx. lineTo ( 200.5 , 20.5 ) ; ctx. stroke ( ) ; ctx.closePath() // ctx. beginPath ( ) ; ctx. moveTo ( 100.5 , 40.5 ) ; ctx. lineTo ( 200.5 , 40.5 ) ctx. strokeStyle = 'blue' ; ctx. stroke ( ) ;
canvas中的绘制方法(如stroke,fill),都会以“上一次beginPath”之后的所有路径为基础进行绘制。比如上面的代码里面我stroke了两次,其实这两次都是以第一次beginPath后的所有路径为基础画的。也就是说第一条路径我们stroke了两下,第一下是黑的,第二下是红的,所以最终也是红的
1.不管你用moveTo把画笔移动到哪里,只要不beginPath,那你一直都是在画一条路径。 2.fillRect与strokeRect这种直接画出独立区域的函数,也不会打断当前的path.
2.4 this.context.stroke()
方法用于绘制所有moveTo()和lineTo()方法定义的路径。画布stroke()方法的默认颜色是黑色。
2.5 moveTo():绘制线段的起点 参数 x,y 坐标位置;
2.6 arc():参数(x,y,半径,开始弧度,结束弧度,时针方向);
x,y坐标 半径,圆的大小, 开始弧度,一般都是0,结束弧度,一般都是 (0-360)*Math.PI/180, 时针方向,true 逆时针,false 顺时针
2.7 lineTo():绘制线段的领点 参数 x,y 坐标位置 ; (最后一个lineTo就代表终点)线条只能有一个moveTo(),但却可以有很多lineTo()
2.8 rect() 绘制方块,及不带填充色和线框;
2.9 fill() 填充颜***r>2.10 clearRect(x,y,width,height) 清除矩形区域