canvas实现环形进度条效果
程序员文章站
2022-06-07 23:39:35
昨下午睡着了,晚上打开手机才发现朋友给我发了一个qq消息,问我这个怎么实现?
这里就选canvas来简单写一下 先上代码,然后在说一说需要注意的点:
<...
昨下午睡着了,晚上打开手机才发现朋友给我发了一个qq消息,问我这个怎么实现?
这里就选canvas来简单写一下 先上代码,然后在说一说需要注意的点:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>canvas环形进度条</title> <style> body{ background-color:#000; text-align: center; } .canvas1{ margin-top: 100px; display: inline-block; background-color: #fff; } </style> </head> <body> <canvas id="circle_process" class="canvas1"></canvas> <script> /* 需求:环形、一周分为10个片段,根据进度去走的一个状态 技术选型:canvas (挑战加熟悉) 思路: 01 首先中间的文字部分不用说,使用canvas的画文字。 02 圆形是个规则图形,那么为了避免画不规则图形,我们可以用圆和矩形来重叠出效果。 a. 大的灰色背景圆 b. 小一圈的白色背景圆 c. 以同心圆的圆心为圆心,小圆为半径为半径复制画10个小的矩形 */ //初始化动画变量 var requestanimationframe = window.requestanimationframe || window.msrequestanimationframe || window.mozrequestanimationframe || window.webkitrequestanimationframe; var cancelanimationframe = window.cancelanimationframe || window.mscancelanimationframe || window.mozcancelanimationframe || window.webkitcancelrequestanimationframe; //初始化当前进度数 var curpercentcount = 0; //获取canvas对象,设置画布大小 var oc = document.queryselector('#circle_process'); oc.width = 300; oc.height = 300; //获取canvas执行上下文 var ctx = oc.getcontext('2d'); //定义小矩形的个数 var minirectcount = 10; //定义圆心位置 var circenter = { x:oc.width/2, y:oc.height/2 }; //定义小矩形的大小rectsize var rectsize = { width:0, height:0 }; //圆对象构造函数 function circle(center,radius){ this.center = center; this.radius = radius; } //小矩形对象构造函数 function minirect(length,width){ this.length = length; this.width = width; } //角度转换成弧度的函数 function d2a(angleint){ return angleint*math.pi / 180; } //百分比转换角度函数(这里减90因为arc0度是从右侧开始的) function percentturn(percentfloat){ return percentfloat * 360 / 100 - 90; } //画当前百分比扇形的方法 function drawfanforpercent(percentfloat){ ctx.beginpath(); ctx.moveto(circenter.x,circenter.y); ctx.lineto(oc.width/2,(oc.height-basecircle.radius*2)/2); ctx.arc(circenter.x,circenter.y,basecircle.radius,d2a(-90),d2a(percentturn(percentfloat))); ctx.fillstyle = 'aqua'; ctx.fill(); ctx.closepath(); } //画圆的函数 function drawarc(center,radius,start,end,type,color){ start = start || 0; end = end || 360; ctx.beginpath(); ctx.arc(center.x,center.y,radius,d2a(start),d2a(end)); ctx.fillstyle = color; ctx.strokestyle = color; if(!!type){ (type === 'fill') && ctx.fill(); (type === 'stroke') && ctx.stroke(); } ctx.closepath(); } //画文字的函数 function drawpercenttext(text,percentint){ ctx.beginpath(); ctx.fillstyle = 'aqua'; ctx.font="italic small-caps bold 40px calibri"; ctx.textalign = 'center'; ctx.filltext(text,circenter.x,circenter.y-18,100); ctx.closepath(); ctx.beginpath(); ctx.fillstyle = 'aqua'; ctx.font="italic small-caps bold 60px calibri"; ctx.textalign = 'center'; ctx.filltext(percentint+'%',circenter.x,circenter.y+40,100); ctx.closepath(); } //画小方块的方法 function drawminirect(startpoint,width,height,axispoint,rotateangle){ /* ctx.beginpath(); //平移,画出第一个 ctx.save(); ctx.translate(startpoint.x,startpoint.y); ctx.fillstyle = '#fff'; ctx.fillrect(0,0,rectsize.width,rectsize.height); ctx.restore(); ctx.closepath(); //这种先平移画出在旋转的思路是错的,画之后就不能转了 ctx.save(); ctx.translate(axispoint.x,axispoint.y); ctx.rotate(rotateangle); ctx.restore(); */ ctx.save(); ctx.translate(axispoint.x,axispoint.y); /*画布平移到圆的中心*/ ctx.rotate(d2a(rotateangle)); /*旋转*/ /*画*/ ctx.beginpath(); ctx.fillstyle = '#fff'; ctx.fillrect(startpoint.x,startpoint.y,rectsize.width,rectsize.height); ctx.closepath(); ctx.restore(); } //画整体 function draw(curpercent){ //底部灰色圆 drawarc(basecircle.center,basecircle.radius,null,null,'fill','#ccc'); //进度扇形 drawfanforpercent(curpercent); //内部白色遮挡圆 drawarc(innercircle.center,innercircle.radius,null,null,'fill','#fff'); //画文字 drawpercenttext('当前进度',curpercent); //十个小的矩形 for(var i=0; i<minirectcount; i++){ drawminirect(startpoint,rectsize.width,rectsize.height,circenter,i*360/minirectcount); } } //实例化底圆和内圆 var basecircle = new circle(circenter,130); var innercircle = new circle(circenter,100); //设置rectsize数值 rectsize.width = 15; rectsize.height = basecircle.radius - innercircle.radius + 5; //设置第一个小矩形的起始点 (这里有误差) // var startpoint = { // x: oc.width /2 - 7.5, // y: (oc.height - basecircle.radius*2) / 2 // }; //由于平移到中心点之后画的位置是在画布外的,所以重新定义 var startpoint = { x:-7.5, y:-basecircle.radius - 2 }; //这里开定时去显示当前是百分之几的进度 var raf = null; var percent = 0; function actprocess(percentfloat){ percentfloat = percentfloat || 100; percent = math.round(percentfloat); console.log(percent); curpercentcount++; raf = requestanimationframe(function(){ actprocess(percentfloat); }); draw(curpercentcount); if(curpercentcount >= percent){ cancelanimationframe(raf); return; } } actprocess(50); // cancelanimationframe(raf); //这里没搞懂为什么percent会加 ? //解: requestanimationframe中方法还是需要有参数,这里就用匿名函数回调的执行体去指定。 /* //setinterval的方式 function actprocess(percentfloat){ if(curpercentcount >= percentfloat){ clearinterval(timer); return; } curpercentcount++; draw(curpercentcount); } clearinterval(timer); var timer = setinterval(function(){ actprocess(50); },16.7); */ //直接画弧形的测试: //drawarc(innercircle.center,innercircle.radius,0,260,'fill','red'); /* 用到的技术点: 01 canvas平移 02 canvas画布状态保存于恢复 03 canvas旋转 04 canvas clearrect配合动画requestanimationframe 05 canvas写文字 */ </script> </body> </html>
接下来说一些注意点和我写的过程中碰到的疑问:
疑问:
01 整体代码没有封装成一个组件,感兴趣的同学可以封装一下。 我这有时间也会封装。
02 画文字的时候只能单独画一行文字么? 怎样进行换行?
03 canvas怎样处理响应式?
注意点:
01 画布平移之后,画布上的点也会被平移,所以我在定义第一个小矩形的起始点的时候才会重新定义一个负值。
02 直接画弧形来控制进度不准确,因为arc会自动closepath(),最终形成这样的一个效果。
03 默认圆的0度起始位置是从3点钟方向开始的(见上图),那么想从12点钟位置开始走进度,需要减去90度的角度。
04 requestanimationframe的回调函数在有参数的情况下还是需要传参数的,需要借助匿名函数回调,在执行体里面去执行想要loop的函数内容(可传参数)。否者会出现注释中写道的pecent不规则增加的问题。
先就这样,之后可能会结合一个上传图片的小功能尝试把它封装成一个组件。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!