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 while语句和do while语句的区别分析
Dec 08 Javascript
jquery 图片 上一张 下一张 链接效果(续篇)
Apr 20 Javascript
国外大牛IE版本检测!现在IE都到9了,IE检测代码
Jan 04 Javascript
javascript 星级评分效果(手写)
Dec 24 Javascript
jquery实现效果比较好的table选中行颜色
Mar 25 Javascript
完美兼容各大浏览器的jQuery仿新浪图文淡入淡出间歇滚动特效
Nov 12 Javascript
JavaScript声明变量名的语法规则
Jul 10 Javascript
JavaScript实现获得所有兄弟节点的方法
Jul 23 Javascript
微信小程序调用PHP后台接口 解析纯html文本
Jun 13 Javascript
什么是Vue.js框架 为什么选择它?
Oct 17 Javascript
JavaScript实现的3D旋转魔方动画效果实例代码
Jul 31 Javascript
JS插件amCharts实现绘制柱形图默认显示数值功能示例
Nov 26 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
php文件上传的简单实例
2013/10/19 PHP
php传值方式和ajax的验证功能
2017/03/27 PHP
搜索附近的人PHP实现代码
2018/02/11 PHP
php判断目录存在的简单方法
2019/09/26 PHP
Nigma vs Alliance BO5 第五场2.14
2021/03/10 DOTA
永不消失的title提示代码
2007/02/15 Javascript
读jQuery之十 事件模块概述
2011/06/27 Javascript
JavaScript中的eval()函数详解
2013/08/22 Javascript
JS 屏蔽按键效果与改变按键效果的示例代码
2013/12/24 Javascript
JQuery中使文本框获得焦点的方法实例分析
2015/02/28 Javascript
基于javascript如何传递特殊字符
2015/11/30 Javascript
jquery插件autocomplete用法示例
2016/07/01 Javascript
angular使用post、get向后台传参的问题实例
2017/05/27 Javascript
AngularJs实现聊天列表实时刷新功能
2017/06/15 Javascript
jQuery 中msgTips 顶部弹窗效果实现代码
2017/08/14 jQuery
Angular实现类似博客评论的递归显示及获取回复评论的数据
2017/11/06 Javascript
MockJs结合json-server模拟后台数据
2020/08/26 Javascript
原生javascript的ajax请求及后台PHP响应操作示例
2020/02/24 Javascript
Openlayers绘制聚合标注
2020/09/28 Javascript
深入学习Python中的装饰器使用
2016/06/20 Python
python将文本中的空格替换为换行的方法
2018/03/19 Python
python 处理dataframe中的时间字段方法
2018/04/10 Python
Python之NumPy(axis=0 与axis=1)区分详解
2019/05/27 Python
python flask几分钟实现web服务的例子
2019/07/26 Python
python datetime中strptime用法详解
2019/08/29 Python
Myprotein法国官网:欧洲第一运动营养品牌
2019/03/26 全球购物
波兰多品牌运动商店:StreetStyle24.pl
2020/09/22 全球购物
static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
2015/02/22 面试题
如何客观的进行自我评价
2013/12/17 职场文书
《骆驼和羊》教学反思
2014/02/27 职场文书
平安校园建设方案
2014/05/02 职场文书
优秀家长自荐材料
2014/08/26 职场文书
公司离职证明标准格式
2014/11/18 职场文书
办公室卫生管理制度
2015/08/04 职场文书
一文了解JavaScript用Element Traversal新属性遍历子元素
2021/11/27 Javascript
vue实现列表垂直无缝滚动
2022/04/08 Vue.js