canvas实现环形进度条效果


Posted in Javascript onMarch 23, 2017

昨下午睡着了,晚上打开手机才发现朋友给我发了一个QQ消息,问我这个怎么实现?

canvas实现环形进度条效果

这里就选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(),最终形成这样的一个效果。

canvas实现环形进度条效果

03 默认圆的0度起始位置是从3点钟方向开始的(见上图),那么想从12点钟位置开始走进度,需要减去90度的角度。

04 requestAnimationFrame的回调函数在有参数的情况下还是需要传参数的,需要借助匿名函数回调,在执行体里面去执行想要loop的函数内容(可传参数)。否者会出现注释中写道的pecent不规则增加的问题。

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

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

Javascript 相关文章推荐
Javascript 汉字字节判断
Aug 01 Javascript
JS 的应用开发初探(mootools)
Dec 19 Javascript
纯js简单日历实现代码
Oct 05 Javascript
js在IE与firefox的差异集锦
Nov 11 Javascript
JS实现向表格行添加新单元格的方法
Mar 30 Javascript
JS使用oumousemove和oumouseout动态改变图片显示的方法
Mar 31 Javascript
js控制文本框输入的字符类型方法汇总
Jun 19 Javascript
JavaScript前端开发之实现二进制读写操作
Nov 04 Javascript
JS鼠标3次点击事件实现代码及扩展思路
Sep 12 Javascript
Javascript 严格模式use strict详解
Sep 16 Javascript
Jquery实现无缝向上循环滚动列表的特效
Feb 13 jQuery
js实现直播点击飘心效果
Aug 19 Javascript
Javascript实现登录记住用户名和密码功能
Mar 22 #Javascript
jquery实现图片平滑滚动详解
Mar 22 #jQuery
JavaScript中在光标处插入添加文本标签节点的详细方法
Mar 22 #Javascript
jQuery轻松实现无缝轮播效果
Mar 22 #jQuery
JavaScript登录记住密码操作(超简单代码)
Mar 22 #Javascript
原生JS京东轮播图代码
Mar 22 #Javascript
10道典型的JavaScript面试题
Mar 22 #Javascript
You might like
跟我学小偷程序之成功偷取首页(第三天)
2006/10/09 PHP
PHP的伪随机数与真随机数详解
2015/05/27 PHP
3种php生成唯一id的方法
2015/11/23 PHP
PHP实现的redis主从数据库状态检测功能示例
2017/07/20 PHP
PHP实现的Redis多库选择功能单例类
2017/07/27 PHP
解决laravel5中auth用户登录其他页面获取不到登录信息的问题
2019/10/08 PHP
javascript实现仿银行密码输入框效果的代码
2007/12/13 Javascript
基于jquery+thickbox仿校内登录注册框
2010/06/07 Javascript
面向对象Javascript核心支持代码分享
2012/05/23 Javascript
javascript加号&quot;+&quot;的二义性说明
2013/03/04 Javascript
Js操作Select大全(取值、设置选中等等)
2013/10/29 Javascript
jQuery中noconflict函数的实现原理分解
2015/02/03 Javascript
Vue from-validate 表单验证的示例代码
2017/09/26 Javascript
vue实现验证码按钮倒计时功能
2018/04/10 Javascript
基于React Native 0.52实现轮播图效果
2020/08/25 Javascript
vue鼠标悬停事件实例详解
2019/04/01 Javascript
微信小程序中如何使用flyio封装网络请求
2019/07/03 Javascript
vue fetch中的.then()的正确使用方法
2020/04/17 Javascript
解决vuecli3中img src 的引入问题
2020/08/04 Javascript
详解python中的文件与目录操作
2017/07/11 Python
python如何在循环引用中管理内存
2018/03/20 Python
在Django中输出matplotlib生成的图片方法
2018/05/24 Python
python实现给scatter设置颜色渐变条colorbar的方法
2018/12/13 Python
浅谈Python采集网页时正则表达式匹配换行符的问题
2018/12/20 Python
解决Python列表字符不区分大小写的问题
2019/12/19 Python
python脚本后台执行方式
2019/12/21 Python
DRF框架API版本管理实现方法解析
2020/08/21 Python
同程旅游英文网站:LY.com
2018/11/13 全球购物
英国女性时尚品牌:Apricot
2018/12/04 全球购物
中学生运动会通讯稿大全
2014/09/18 职场文书
党员干部四风问题整改措施思想汇报
2014/10/12 职场文书
银行求职信怎么写
2019/06/20 职场文书
Pytorch distributed 多卡并行载入模型操作
2021/06/05 Python
Django Paginator分页器的使用示例
2021/06/23 Python
Python 数据可视化之Matplotlib详解
2021/11/02 Python
微信告警的zabbix监控系统 监控整个NGINX集群
2022/04/18 Servers