canvas实现有递增动画的环形进度条
哈?标题不知道啥意思?
老规矩,直接看图!
效果如下:
高清大图!
码农多年,老眼昏花,动图看不清?!那就看静态截图!!!
不同分值效果如下:
看完了卖家秀,我们来看产品的制作过程吧!
canvas绘制圆环
1、vue中,<template lang="pug">里的代码如下:
canvas#baseCanvas是底部的灰色圆环
canvas#myCanvas是上边的彩色圆环
需要用css样式帮助我们把彩色圆环盖到灰色圆环上边。
2、css样式:
3、js-canvas的样式绘制代码
这段代码也很简单,看canvas的api即可
3-1、vue组件中,script标签顶部定义需要用的变量
3-2、vue的methos对象中,定义方法三个:
以下是三个方法的代码:
上边三个方法里边的代码,几乎都是对canvas API的应用,看教程即可。
只有draoClrCanvas方法中,canvas圆形的绘制时,arc的参数里关于开始值、结束值的设置。
开始值决定了圆环的起始绘制位置,结束值决定了结束的位置(我好像说了一句废话,但是冥思苦想后的思想描述文字,不想删掉哈哈哈)
这个结束值的计算,对于我来说还是比较麻烦的。
count变量为什么要这么计算,我也忘了我是怎么鼓捣出来的了。
this.grade是100以内的正整数,表示分值。被定义在data中,默认是0分。
所以一开始彩色圆环就看不见,因为起始点和结束点都是0点。
如果更改grade的值,从0-100,canvas彩色圆环的值也就会更改。
这样,只要我们逐渐修改grade的值,重新绘制,彩色圆环就会逐渐递增,实现动画效果。
圆环动画效果
由于我这里需求特殊,需要用户每次翻到canvas所在swiper时,才会触发动画(后来更麻烦一点需要柱状图和canvas部分有个入场效果后,动画才开始。效果就是上图中最长的那张gif动画那样)。
所以我得借助swiper才能实现。在swiper切换的回调函数中,从0开始不停递增grade分数,并重新触发彩色圆环的绘制,进而实现动画效果。
vue中我用的swiper是'vue-awesome-swiper'。她的用法我在其他文章中写过步骤【点击进入传送门】。
swiper在vue-data中的配置里,有一个on对象。在on对象中的slideChange函数,就是每次翻页swiper时会触发的回调函数。
这里我说一下几个比较特殊的点:
(1)vm:是我早就在vue的script中存储的变量,初始化为null,然后在mounted中,将其赋值为vue实例对象。
初始化数据、绘制灰色圆环
通过这种方法,我在vue实例对象 - data - swiper - 回调函数中去拿vue实例对象 - data中的grade和gradeTarget属性值,并对其进行修改。
ps:我也不知道这么做是不是很傻的一种做法,当时做到这里时是我遇到的一个难题,不知道怎么在swiper的on回调中获取vue实例。于是就有了这么曲线救国的方法。如果看官有更好的解决方案,希望可以给我提供一个新的思路,感激不尽哦亲
(2) (this.activeIndex == 2 && vm.isStar) || (this.activeIndex == 1 && !vm.isStar)
这里是因为业务,才这么判断,可以忽略。
this在swiperChange函数中指向swiper对象。this.activeIndex是swiper实例的属性,用官方的话说“返回当前活动块(激活块)的索引。”可以理解他指的是当前翻到的是哪一页,就是当前你所看的swiper-slide的下标。
我因为用户的身份,会判断性的决定当前canvas所在swiper前一页是否展示。 如果不展示就根本不会绘制前一页,那么相应的当前页的swiper的下标就会变成(index-1)。
总而言之,当满足条件、用户翻到canvas所在swiper页面后,我就要触发if里边的圆环绘制逻辑。否则就走到else里初始化数据页面的状态、清除定时器暂停动画、并把彩色圆环清空
(3)vm.aniShow
在我上篇《纯css绘制柱状图》里边说了,柱状图的动画要跟canvas的动画一起说。因为他们的动画实现需要配合swiper的切换。说的就是这里的代码:
vue - data - aniShow属性变为true时,div.row就会添加ani这个class类名:
同样,aniShow为true,progress的高度就会附上自己的目标值,也就是这个progress的实际高度经过百分制转化后被赋予给了style属性的height。(具体换算规则还是见上篇《纯css绘制柱状图》)
此时,因为progress的transition监听了height变化,就开始有了高度渐增的柱状图递增动画了。
而ani类名下,progress的transition-delay实现了其高度错开递增效果。
可能只看文字描述很晦涩,再看一眼效果:
(4)彩色圆环绘制代码部分
gradeTarget是实际分值,是最终要绘制到的结果。
grade从0开始,自增到gradeTarget的大小。
这里我没有直接++vm.grade,我也不知道自己当时咋想的。
if判断,如果grade递增到了目标值gradeTarget或者大于目标值,就停止递增,并让grade=gradeTarget。属于临界值的判断。在运动功能中,又算碰撞检测。
反之,不到目标的话,就清除上一次绘制的canvas画布,在grade递增变化后重新绘制新的彩色圆环。
(5)所有这些放到setTimeout中,暂停500毫秒再执行,是为了等柱图和环图入场后,在开始绘制圆环的递增效果。
其实上边代码都是很简单的逻辑处理,看官们读一遍代码应该就差不离了。
新想法:
这个效果是我很久以前做的,今天在整理制作方法的时候,我想到自己代码的一种优化方案:
其实没必要在定时器里重新调用彩色圆环绘制方法。我们直接改的是this.grade属性,监听这个属性的改变就好了其实。这样此属性在定时器中被修改,圆环方法就会自动执行。
这还是一个想法,还需要我的实践。
中间文字的递增效果:
因为grade是每次递增的分数,所以利用vue的双向数据绑定,直接把grade当作分数值绑定到对应dom视图处即可。
最后,圆环和上边柱状图的动画结合,就是animation控制一下动画延迟即可。很简单的。
index.vue源码:
(注,源码稍作整理,单独提取。为了完整性也为了保护其他业务代码,部分变量名做了修改,可能会和之前截图中略微不同)
<template lang='pug'>
.indexs#Indexs.app-bg
transition(name="fade")
swiper#swiperBox(:options="swiperOption" ref="mySwiper")
swiper-slide.swiper-slide1
.container
.up
swiper-slide.swiper-slide2(v-if="isShow")
.my-shark
.up
swiper-slide.swiper-slide3
.container
.data-cont
.data.data01
.data01-charts
.row(v-for='item,index in Data' :key="index" :class='aniShow ? "ani":""')
.data-txt {{item.grade > 0 ? item.grade : '无数据'}}
.progress(:class='item.grade == 0 ? "nodata" : ""' :style="'height: ' + (aniShow ? (item.grade >= 100 ? (100 * 1.5) / 100 : item.grade == 0 ? 0.04 : item.grade * 1.5 / 100) : 0) +'rem'")
span.pg-data
.week {{item.week}}
.data.data02
.data02-charts
.canvas-box
//- baseCanvas
canvas#baseCanvas.my-canvas(ref="baseCanvas" width="174" height="174")
//- canvas
canvas#myCanvas.my-canvas.clr-canvas(ref="myCanvas" width="174" height="174")
.canvas-data #[span.num {{grade}}]分 </template>
<script>
var vm = null,
timer1 = null,
/* canvas基础值 */
c = null, //document.getElementById("myCanvas");
ctx = null, //canvas-2d画布
x = 161 / 2 + 1, //圆心坐标
r = (161 - 10) / 2; //半径大小 /* swiper组件 */
import { swiper, swiperSlide } from "vue-awesome-swiper";
import { getData } from "../io/getData"; export default {
name: "Indexs",
components: {
swiper,
swiperSlide
},
data() {
return {
grade: 0, //圆环图分数
gradeTarget: 78.54, //实际得分数,可ajax请求数据后修改
isShow: true,//是否展示第二页swiper
aniShow: false,//是否开启柱图动画
Data:[{
week: "第一周",
grade: 0
},
{
week: "第二周",
grade: 30
},
{
week: "第三周",
grade: 99.99
},
{
week: "第四周",
grade: 76.98
},
{
week: "第五周",
grade: 100
}], swiperOption: {
//swiper参数
notNextTick: true,
direction: "vertical",
grabCursor: true,
setWrapperSize: true,
autoHeight: true,
slidesPerView: 1,
mousewheel: false,
mousewheelControl: false,
height: window.innerHeight, // 高度设置,占满设备高度
resistanceRatio: 0,
observeParents: true,
initialSlide: 2 - 1, //设置初始化时,swiper的默认展示页面,从零开始
on: {
slideChange() {
if (
(this.activeIndex == 2 && vm.isShow) ||
(this.activeIndex == 1 && !vm.isShow)
) {
console.log(this.activeIndex, vm.isShow, "绘制动画");
setTimeout(function() {
// 配合展示柱状图动画
vm.aniShow = true;
// 定时器不断触发绘制彩色圆环,实现圆环动画效果
timer1 = setInterval(function() {
// 中间分数文案更改
var num = vm.grade;
num++;
if (num >= vm.gradeTarget) {
vm.grade = vm.gradeTarget;
clearInterval(timer1);
} else {
vm.grade = num;
}
vm.clearCanvas();
vm.drawClrCanvas();
}, 1000 / 60);
}, 500);
} else {
// 翻页后,初始化数据页面的状态、清除定时器暂停动画、并把彩色圆环清空
console.log("其他页");
clearInterval(timer1);
vm.grade = 0;
vm.aniShow = false;
vm.clearCanvas();
}
}
}
}
};
},
computed: {},
mounted() {
// 初始化数据、绘制灰色圆环
vm = this;
c = this.$refs.myCanvas;
ctx = c.getContext("2d");
this.drawBaseCanvas();
},
methods: {
drawBaseCanvas() {
// canvas绘制
/* 基础值 */
var c = this.$refs.baseCanvas, //document.getElementById("myCanvas");
// debugger;
ctx = c.getContext("2d"),
o = x,
randius = r;
/* 默认灰色圆圈 */
ctx.strokeStyle = "#eee";
ctx.lineWidth = 10;
ctx.beginPath();
ctx.arc(o, o, randius, 0, 2 * Math.PI);
ctx.stroke();
},
clearCanvas() {
// 清除画布
ctx.clearRect(0, 0, 200, 200);
},
drawClrCanvas() {
var gradient = ctx.createLinearGradient(75, 50, 5, 90);
gradient.addColorStop("0", "#C88EFF");
gradient.addColorStop("1.0", "#7E5CFF");
ctx.strokeStyle = gradient; // 用渐变进行填充
ctx.lineWidth = 10;
ctx.lineCap = "round";
ctx.shadowColor = "rgba(191,142,255, 0.36)";
ctx.shadowBlur = 8;
ctx.shadowOffsetY = 8;
ctx.beginPath();
var count = this.grade / (100 / 2) + 1;
ctx.arc(x, x, r, Math.PI, Math.PI * count, false);
ctx.stroke();
}
}
};
</script>
<style lang='scss'>
// 柱图
.row {
position: relative;
z-index: 1;
width: 0.61rem;
margin-bottom: -0.28 - 0.08 - 0.38rem;
text-align: center;
} .data-txt {
font-size: 0.2rem;
line-height: 0.2rem;
margin-bottom: 0.09rem;
} .progress {
height: 0rem;
transition: height 0.5s ease-in-out;
} .ani {
@for $i from 1 to 6 {
&:nth-of-type(#{$i}) {
.progress {
transition-delay: #{$i * 0.15}s;
}
}
}
// &:nth-of-type(1) {
// .progress {
// transition-delay: .4s;
// }
// } // &:nth-of-type(2) {
// .progress {
// transition-delay: .8s;
// }
// } // &:nth-of-type(3) {
// .progress {
// transition-delay: 1s;
// }
// } // &:nth-of-type(4) {
// .progress {
// transition-delay: 1.4s;
// }
// } // &:nth-of-type(5) {
// .progress {
// transition-delay: 1.8s;
// }
// }
} .pg-data {
display: block;
width: 0.12rem;
height: 100%;
margin: 0 auto;
background: linear-gradient(0deg, #c88eff 0%, #7e5cff 100%);
box-shadow: 0 -0.04rem 0.14rem 0 rgba(129, 93, 255, 0.4);
border-radius: 0.05rem 0.05rem 0 0;
} // 0分展示规则
.nodata {
.pg-data {
border-radius: 0;
background: #e7e7e7;
box-shadow: none;
}
} .week {
font-size: 0.2rem;
line-height: 0.2rem;
margin-top: 0.08rem;
color: #666;
}
// 环图 - data02数据部分
.data02-charts {
margin-top: 0.32rem;
height: 1.61rem;
} .canvas-box {
position: relative;
float: left;
width: 1.61rem;
height: 1.61rem;
margin-left: 0.92rem;
} .my-canvas {
width: 1.61rem;
height: 1.61rem;
}
.clr-canvas {
position: absolute;
top: 0;
left: 0;
} .canvas-data {
position: absolute;
top: 0.56rem;
left: 0;
right: 0;
margin: auto;
margin-left: -0.1rem;
text-align: center;
font-size: 0.24rem; .num {
font-size: 0.32rem;
font-weight: 600;
}
}
</style>
canvas实现有递增动画的环形进度条的更多相关文章
- iOS带动画的环形进度条(进度条和数字同步)
本篇写的是实现环形进度条,并带动画效果,要实现这些,仅能通过自己画一个 方法直接看代码 为了方便多次调用,用继承UIView的方式 .m文件 #import <UIKit/UIKit.h> ...
- 环形进度条的实现方法总结和动态时钟绘制(CSS3、SVG、Canvas)
缘由: 在某一个游戏公司的笔试中,最后一道大题是,“用CSS3实现根据动态显示时间和环形进度[效果如下图所示],且每个圆环的颜色不一样,不需要考虑IE6~8的兼容性”.当时第一想法是用SVG,因为SV ...
- canvas绘制环形进度条
<!DOCTYPE html> <html > <head> <meta http-equiv="content-type" conten ...
- canvas实现半圆环形进度条
html部分 <canvas id="canvas" width="150" height="150"> <p>抱歉 ...
- 用初中数学知识撸一个canvas环形进度条
周末好,今天给大家带来一款接地气的环形进度条组件vue-awesome-progress.近日被设计小姐姐要求实现这么一个环形进度条效果,大体由四部分组成,分别是底色圆环,进度弧,环内文字,进度圆点. ...
- canvas环形进度条
<style> canvas { border: 1px solid red; margin: 100px; }</style> <canvas id="rin ...
- html5 canvas绘制环形进度条,环形渐变色仪表图
html5 canvas绘制环形进度条,环形渐变色仪表图 在绘制圆环前,我们需要知道canvas arc() 方 ...
- Canvas实现环形进度条
Canvas实现环形进度条 直接上代码: <canvas width="200" height="200" >60%</canvas> ...
- Android简易实战教程--第十七话《自定义彩色环形进度条》
转载请注明出处:http://blog.csdn.net/qq_32059827/article/details/52203533 点击打开链接 在Android初级教程里面,介绍了shape用法 ...
随机推荐
- MFC中获取App,MainFrame,Doc和View类等指针的方法
From: http://hi.baidu.com/wxnxs/item/156a68f5b3b4ed18e3e3bd03 MFC中获取App,MainFrame,Doc和View类等指针的方法 ...
- Dijkstra含权图最短路径;审判,不要错过枚举退款保证不会重复;国际象棋八皇后问题
求两节点的最短通路.对于无权图,能够通过图的广度优先遍历求解.含权图一般通过Dijkstra算法求解. import java.util.ArrayList; import java.util.Has ...
- sql 循环 随机数创建数据
--循环 WHILE @i<40 BEGIN …… end --随机数 SET @money=rand()*100000 例子: DECLARE @i INT DECLARE @money MO ...
- 使用aws和tomcat搭建服务器过程中的一些坑.
在国外没啥事做, 考前也不愿意复习, 看到aws能免费试用一年, 于是就试着搞了搞, 就准备搭建个个人网站玩玩. aws的注册与创建实例 首先个人感觉这个东西使用起来还是很方便的, 一开始注册完验证完 ...
- XF 进度条和指示器
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http:/ ...
- Delphi 10.2可以开发Linux桌面应用了
原始地址 https://community.embarcadero.com/blogs/entry/firemonkey-on-linux Delphi Linux编译器已经发布,现在无需等待 ...
- nprogress.js 头部进度条使用方法
nprogress.js 头部进度条 引入CSS\JS <link rel="stylesheet" type="text/css" href=" ...
- 简单的Windows Webcam应用:Barcode Reader
原文:简单的Windows Webcam应用:Barcode Reader 在Windows上用WinForm创建一个Webcam应用需要用到DirectShow.DirectShow没有提供C#的接 ...
- MyCat的初步了解
MyCat 1 开源数据库中间件 MyCat 如今随着互联网的发展,数据的量级也是撑指数的增长,从GB到TB到PB.对数据的各种操作也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据 ...
- 谷歌推出全新Android开发语言Sky:让App更流畅
土豆网同步更新:http://www.tudou.com/plcover/VHNh6ZopQ4E/ 使用HTML 创建Mac OS App 视频教程. 官方QQ群: (1)App实践出真知 434 ...