canvas实现环形进度条效果

 更新时间:2017年03月23日 08:49:37   作者:differ_wy  
本文主要介绍了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不规则增加的问题。

先就这样,之后可能会结合一个上传图片的小功能尝试把它封装成一个组件。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

相关文章

  • 微信小程序wx.request的简单封装

    微信小程序wx.request的简单封装

    这篇文章主要介绍了微信小程序wx.request的简单封装,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • JS中的const命令你真懂它吗

    JS中的const命令你真懂它吗

    这篇文章主要介绍了JS中的const命令你真懂它吗,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 详解JavaScript基于面向对象之创建对象(2)

    详解JavaScript基于面向对象之创建对象(2)

    这篇文章主要介绍了JavaScript基于面向对象之创建对象,详细的分析面向对象的原型方式以及其他综合的方式,感兴趣的小伙伴们可以参考一下
    2015-12-12
  • js判断文本框输入的内容是否为数字

    js判断文本框输入的内容是否为数字

    这篇文章主要介绍了js判断文本框输入的内容是否为数字,本文为大家分享了验证文本框中的内容是否为数字的方法,感兴趣的小伙伴们可以参考一下
    2015-12-12
  • JS实现选项卡实例详解

    JS实现选项卡实例详解

    这篇文章主要介绍了JS实现选项卡的方法,结合实例形式详细讲述了JavaScript实现选项卡的布局与功能实现的完整步骤及相关技巧,需要的朋友可以参考下
    2015-11-11
  • JS中的算法与数据结构之集合(Set)实例详解

    JS中的算法与数据结构之集合(Set)实例详解

    这篇文章主要介绍了JS中的算法与数据结构之集合(Set),结合实例形式详细分析了javascript中集合的概念、原理、定义及相关操作技巧,需要的朋友可以参考下
    2019-08-08
  • 线路分流自动智能跳转代码,自动选择最快镜像网站(js)

    线路分流自动智能跳转代码,自动选择最快镜像网站(js)

    线路分流自动智能跳转代码,自动选择最快镜像网站,自动选择电信或网通线路跳转代码
    2011-10-10
  • js制作网站首页图片轮播特效代码

    js制作网站首页图片轮播特效代码

    这篇文章主要为大家详细介绍了js制作网站首页图片轮播特效代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • js实现开关灯效果

    js实现开关灯效果

    这篇文章主要为大家详细介绍了js实现开关灯效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • Javascript模拟scroll滚动效果脚本

    Javascript模拟scroll滚动效果脚本

    项目需要写了一段模拟Scroll滚动代码,分享的同时,我有些疑问,希望大家能帮忙解决,代码如下
    2008-09-09

最新评论