这里增加一篇介绍下进度条动画效果如何添加,前几篇的进度值被修改后,切换效果比较生硬。另外也在第四篇基础上,对图形略作修改。在查看uniapp文档时,没有发现重绘执行函数,小程序中有Canvas.requestAnimationFrame;所以在uniapp这里,我们使用setInterval来实现,完成后运行也很流畅。
添加动画后效果如下图:
一、创建对应页面
1.1 创建charts.js文件
/**
* 图表 - 圆环进度条添加动画效果
*/
export class CircleBox {
//构造函数
constructor(_context){
}
//绘制带动画效果图表
drawAniCircle(_percent){
}
//绘制图表
drawCircle(){
}
}
1.2 创建vue页面
<template>
<view class="wrap-box">
<view class="echart-box chart01">
<view class="title">图表:重新赋值实现增长或减少动画效果</view>
<view class="content">
<canvas canvas-id="chartBox5" id="chartBox5" class="chart"></canvas>
<view class="btn-box">
<button type="default" class="btn" @click="mulEvent()">减小</button>
<button type="default" class="btn" @click="addEvent">增加</button>
</view>
</view>
</view>
</view>
</template>
<script>
import { CircleBox } from './charts.js';
export default {
data() {
return {
cbox1: null, //画布实例对象
percent: 0, //当前进度值
step: .1 //每次修改递增或递减值
}
},
mounted() {
this.initCircle1();
},
methods: {
mulEvent(){
//递减
this.percent = this.percent - this.step <= 0 ? 0 : this.percent - this.step;
//开始绘制
this.cbox1.drawAniCircle(this.percent);
},
addEvent(){
//递增
this.percent = this.percent + this.step >= 1 ? 1 : this.percent + this.step;
this.cbox1.drawAniCircle(this.percent);
},
initCircle1(){
//实例对象
this.cbox1 = new CircleBox(uni.createCanvasContext('chartBox5'));
//开始绘制
this.cbox1.drawAniCircle(this.percent);
}
}
}
</script>
<style lang="scss">
@import '../index.scss';
</style>
1.3 创建scss样式文件
略(同前几篇一样)
二、实现chart.js图表
2.1 构造函数定义相应变量
构造函数中这次需要添加一个控制手柄,随时控制定时器的开始和结束。
//构造函数
constructor(_context){
this.ctx = _context;
//刻度数
this.number = 50;
//直径
this.radius = uni.upx2px(300);
//内填充
this.padding = uni.upx2px(20);
//线宽
this.lineWidth = uni.upx2px(20);
//刻度宽度
this.scaleWidth = uni.upx2px(10);
//刻度高度
this.scaleHeight = uni.upx2px(8);
//线颜色
this.lineColor = "#D7EAFF";
//占比
this.percent = 0;
//百分比颜色
this.percentColor = "#297DFE";
//字体大小
this.fontSize = uni.upx2px(42);
//字段颜色
this.fontColor = '#297DFE';
//计时控制手柄
this.handle = null;
}
2.2 绘制圆环进度条
这里代码和第4篇charts.js实现基本一样,只是将刻度向内移动了,多了线宽+内填充的距离;原padding*2,这里padding*4+lineWidth*2,这样刻度就向内移动了。
另外,增加了起始位圆点和勾字符号添加。
drawCircle()函数定义好后,可以进行图表绘制了,只是修改值后,切换效果比较生硬。
//绘制图表
drawCircle(){
//清空画布
this.ctx.clearRect(0, 0, this.radius, this.radius);
//计算实际直径(减掉四周内填充)
let _radius = this.radius/2-this.padding*2;
//开始绘制圆环
this.ctx.beginPath();
this.ctx.arc(this.radius/2,this.radius/2, _radius,0,Math.PI*2, false);
this.ctx.lineWidth = this.lineWidth;
this.ctx.strokeStyle = this.lineColor;
this.ctx.stroke();
//计算角度值(倾斜平均值)
let _depth = Math.PI*2/this.number;
//绘制时刻底色
//计算刻度直径(减去四周内填充 + 圆环内与刻度间的内填充、外部圆环的线宽 )
let _scaleRadius = this.radius - this.lineWidth * 2 - this.padding * 4;
//开始底色部分绘制
this.ctx.beginPath();
this.ctx.strokeStyle = this.lineColor;
this.ctx.lineCap = 'round';
//循环绘制刻度
for(var i=0;i<this.number;i++){
this.ctx.save();
this.ctx.lineWidth=this.scaleHeight;
//把基点设置为圆心
this.ctx.translate(this.radius/2,this.radius/2);
this.ctx.rotate(_depth*i);
this.ctx.moveTo(_scaleRadius/2 ,0);
this.ctx.lineTo(_scaleRadius/2-this.scaleWidth,0);
this.ctx.stroke();
this.ctx.restore();
}
//绘制高亮进度条
this.ctx.beginPath();
this.ctx.lineCap = 'round';
this.ctx.arc(this.radius/2,this.radius/2, _radius,-(Math.PI / 2), ((Math.PI * 2) * this.percent) - Math.PI / 2, false);
this.ctx.strokeStyle = this.percentColor;
this.ctx.stroke();
//恢复之前保存的绘图上下文
this.ctx.restore();
// 绘制高亮刻度
this.ctx.beginPath();
this.ctx.strokeStyle = this.percentColor;
//四舍五入,获取高亮刻度数
let _highNumber = Math.ceil(parseFloat(this.number*this.percent).toFixed(2));
for(var i=0;i<_highNumber;i++){
this.ctx.save();
this.ctx.lineWidth= this.scaleHeight;
//把基点设置为圆心
this.ctx.translate(this.radius/2,this.radius/2);
this.ctx.rotate(
_depth*i-(_depth*Math.ceil(this.number/4))
);
this.ctx.moveTo(_scaleRadius/2 ,0);
this.ctx.lineTo(_scaleRadius/2-this.scaleWidth,0);
this.ctx.stroke();
this.ctx.restore();
}
//绘制文字
this.ctx.font = 'bold '+this.fontSize+'px sans-serif';
this.ctx.setFillStyle(this.fontColor);
this.ctx.setTextAlign('center');
this.ctx.fillText(Math.round(this.percent*100)+'%', this.radius/2+(this.lineWidth/2), this.radius/2+(this.lineWidth/2), this.radius);
//绘制圆点
let _circleRadius = this.lineWidth; //圆点半径
this.ctx.beginPath();
this.ctx.save();
this.ctx.lineWidth = 1;
this.ctx.arc(this.radius/2, this.padding + this.lineWidth, this.lineWidth, 0, Math.PI*2, false);
this.ctx.setFillStyle(this.percentColor);
this.ctx.fill();
this.ctx.restore();
//绘制对号
this.ctx.font = 'bold '+uni.upx2px(20)+'px sans-serif';
this.ctx.setFillStyle('#FFFFFF');
this.ctx.fillText('√', this.radius/2, this.padding + this.lineWidth * 1.4);
//绘制到画布上
this.ctx.draw();
}
2.3 动画添加
我们再添加另一个函数drawAniCircle(),通过Interval进行重绘动作,来实现动画效果。代码如下:
//绘制带动画效果图表
drawAniCircle(_percent){
//每次进入清除一下,以防上次动作未处理完
clearInterval(this.handle);
/**
* 这几篇我们一直是他用百分比小数进行传递
* 所以动画每帧移动步伐为 0.01
*/
let _step = .01,
/**
* 判断当前值是增加还是减少
*/
_type = _percent>this.percent ? 1 : -1;
this.handle = setInterval(() => {
switch(_type){
//增加情况,每帧追加 0.01
case 1:
this.percent += _step;
if(this.percent>=_percent){
this.percent = Math.round(_percent * 100) / 100;
clearInterval(this.handle);
}
break;
//减少情况,每帧减少 0.01
case -1:
this.percent -= _step;
if(this.percent<=_percent){
this.percent = Math.round(_percent * 100) / 100;
clearInterval(this.handle);
}
break;
}
this.drawCircle();
}, 50);
}
把原来的drawCircle()修改为drawAniCircle()函数来执行,并且进度值是通过drawAniCircle()进行传递的。代码如下:
this.cbox1.drawAniCircle(this.percent);
图形如下:
在uniapp中通过canvas进行绘制圆环类图表,这篇算是完结了。通过这几个案例,由㳀入沉,不断学习中沉淀,总结先前经验,吸取更好方法,相信你的开发道路会走的更稳、更远。