vue canvas 方法无效_canvas实现有递增动画的环形进度条

效果如下:

f3646c211b2a13f33e973458c0852c50.gif

高清大图!

b2d6acd1e6c89eb4a56779ce3900efdb.gif

不同分值效果如下:

00986e469d6836ebb08ce7e8ecb4f6af.png
828b249592504cb750bf1175abdfc848.png
4f10939209c88b4b427dd790ee1e2a65.png
193774d8a6496d2fd8e74e72fee58532.png
246e6a687449267a81993dcf21db0f79.png

我们来看产品的制作过程吧!

canvas绘制圆环

1、vue中,里的代码如下:

af4e826ae46e160a610943391ae08ef1.png

canvas#baseCanvas是底部的灰色圆环

canvas#myCanvas是上边的彩色圆环

需要用css样式帮助我们把彩色圆环盖到灰色圆环上边。

2、css样式:

e6ddc3fbd67474fcf8d170bec16f5266.png
989fb93b7a94c420c2dda065342d5735.png
e58c78bc1e65f9c10cf5e09a8b4ff3bf.png

3、js-canvas的样式绘制代码

这段代码也很简单,看canvas的api即可

3-1、vue组件中,script标签顶部定义需要用的变量

03e2e20fe64cb6135b45f4a31bcb89a0.png

3-2、vue的methos对象中,定义方法三个:

drawBaseCanvas:用来绘制底部灰色圆环。由于灰色圆环没有动画效果,所以一开始就绘制一个完整的灰色圆环即可。

drawClrCanvas:用来绘制上边的彩色圆环。

clearCanvas:用来清空画布。这是彩色圆环动画需要。

因为我们圆环动画效果的核心就是,每隔一段时间就把彩色圆环清空一下,然后把结束角度值增大、重画,这样连续起来就是动画。

以下是三个方法的代码:

cc1bb6f3ae975385984285cd7356b4f8.png
aeda7af5cf528a6efb81286183293983.png
7d0a22970f3a14bca159d98e4ad0516b.png

上边三个方法里边的代码,几乎都是对canvas API的应用,看教程即可。

只有draoClrCanvas方法中,canvas圆形的绘制时,arc的参数里关于开始值、结束值的设置。

开始值决定了圆环的起始绘制位置,结束值决定了结束的位置,这个结束值的计算,对于我来说还是比较麻烦的。

this.grade是100以内的正整数,表示分值。被定义在data中,默认是0分。

510c7df434fd5880842bd15e214d6306.png

所以一开始彩色圆环就看不见,因为起始点和结束点都是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时会触发的回调函数。

d1775aa1b369813ec4ea99f115f70498.png

这里我说一下几个比较特殊的点:

(1)vm:是我早就在vue的script中存储的变量,初始化为null,然后在mounted中,将其赋值为vue实例对象。

初始化数据、绘制灰色圆环

22470ab653a67ac79bffbad55c9db080.png

通过这种方法,我在vue实例对象 - data - swiper - 回调函数中去拿vue实例对象 - data中的grade和gradeTarget属性值,并对其进行修改。

(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类名:

328d1424c7adb73c1d8be4aa50ebad3e.png

同样,aniShow为true,progress的高度就会附上自己的目标值,也就是这个progress的实际高度经过百分制转化后被赋予给了style属性的height。(具体换算规则还是见上篇《纯css绘制柱状图》)

此时,因为progress的transition监听了height变化,就开始有了高度渐增的柱状图递增动画了。

9669006149f88f8f49ab236ba556a63d.png

而ani类名下,progress的transition-delay实现了其高度错开递增效果。

6f398ea6984c87989131ccc64a4d5b4f.png

可能只看文字描述很晦涩,再看一眼效果:

b3c26951631f8a8d2f69e9f3023fba7d.gif

(4)彩色圆环绘制代码部分

1801052e4a3ff3ab1f8a6b1e5a15245b.png

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源码:

(注,源码稍作整理,单独提取。为了完整性也为了保护其他业务代码,部分变量名做了修改,可能会和之前截图中略微不同)

 1  2 .indexs#Indexs.app-bg 3 transition(name="fade") 4 swiper#swiperBox(:options="swiperOption" ref="mySwiper") 5 swiper-slide.swiper-slide1 6 .container 7 .up 8 swiper-slide.swiper-slide2(v-if="isShow") 9 .my-shark 10 .up 11 swiper-slide.swiper-slide3 12 .container 13 .data-cont 14 .data.data01 15 .data01-charts 16 .row(v-for='item,index in Data' :key="index" :class='aniShow ? "ani":""') 17 .data-txt {{item.grade > 0 ? item.grade : '无数据'}} 18 .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'") 19 span.pg-data 20 .week {{item.week}} 21 .data.data02 22 .data02-charts 23 .canvas-box 24 //- baseCanvas 25 canvas#baseCanvas.my-canvas(ref="baseCanvas"  ) 26 //- canvas 27 canvas#myCanvas.my-canvas.clr-canvas(ref="myCanvas"  ) 28 .canvas-data #[span.num {{grade}}]分 29  30  31 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值