canvas动态绘制渐变色环形百分比

canvas动态绘制渐变色环形百分比

项目中需要根据数据动态绘制渐变环形百分比(非线性渐变和放射渐变),代码基于Vue。将100%的渐变环形图设置为Pattern,进行绘制。

// 注册环形百分比组件
Vue.component("v-ratechart", {
	props: {
		rate: Number,
		count: Number,
		imgsrc: String
	},
	data: function() {
		return {
			timer: Number,
			ctx: Object,
			//圆心(x, y)  半径r
			x: 55,
			y: 55,
			r: 50,
			oldRate: Number
		}
	},
	template: "<canvas width='160' height='160' ref='rateCanvas'></canvas>",
	mounted: function() {
		var that = this;
		this.oldRate = this.rate;
		var canvas = this.$refs.rateCanvas,
			ctx = canvas.getContext("2d"); 
		this.ctx = ctx; //拷贝指针
		//绘制灰色轨道
		ctx.lineWidth = 10;
		ctx.lineCap = 'round';
		this.drawTrack(ctx);
		// 加载100%图片
		var img = new Image();
		// IE不兼容脚本引入svg
		var format = '.svg'
		if( window.ActiveXObject || "ActiveXObject" in window ) {
			format = '.png'
		}
		img.src = "/img/sysMonitorCompnt/" + this.imgsrc + format;
		img.onload = function() {
			that.ImageLoadCallBack(ctx, this)
		};
	},
	methods: {
		/**
		* 绘制轨道
		*/
		drawTrack: function(ctx) {
			ctx.save()
			// 绘制环形轨道 
			ctx.beginPath();
			ctx.strokeStyle = 'rgba(0, 0, 0, 0.08)';
			ctx.arc(this.x, this.y, this.r, 20 / 180 * Math.PI, 300 / 180 * Math.PI);
			ctx.stroke();
			ctx.restore()
		},
		/**
		* 图片加载回调
		*/
		ImageLoadCallBack: function(ctx, img) {
			//绘制百分比 渐变填充
			var rateFill = ctx.createPattern(img, 'no-repeat');
			ctx.strokeStyle = rateFill;
			this.drawCircleAndText(ctx, 20, this.rate * 300, 0, this.rate * 10000 / 100, 0, this.count, 1)
		},
		/**
		* 动态绘制渐渐变填充和文本
		* startAngle: 当前变化角度
		* endAngle: 环形变化结束角度
		* startRate: 当前变化百分比
		* endRate: 变化终止百分比
		* startCount: 当前变化系统数量
		* endCount: 变化终止系统数量
		* isIncrease: 是否增长
		*/
		drawCircleAndText: function(ctx, startAngle, endAngle, startRate, endRate, startCount, endCount, isIncrease) {
			var that = this,
				velocity = 3;   //百分比、环形填充动画速度
			//文本通用样式
			ctx.fillStyle = '#fff';
			ctx.textAlign = 'center';
			ctx.textBaseline = 'middle';
			//清空画布
			ctx.clearRect(0, 0, 160, 160);
			//重新绘制轨道
			this.drawTrack(ctx)
			//动态绘制环形填充
			if ( isIncrease >= 0 && startAngle < endAngle && endAngle != 0 ) {
				//角度递增  与百分比速度同步
				startAngle += endAngle * (velocity * 1 / endRate);
				if(startAngle > endAngle) {
					startAngle = endAngle;
				}
			}else if( isIncrease < 0 && startAngle > endAngle){
				//角度递增  与百分比速度同步
				startAngle -= (startAngle - endAngle) * (velocity * 1 / (startRate - endRate != 0 ? startRate - endRate : 1));
				if(startAngle < endAngle) {
					startAngle = endAngle;
				}
			}else if(isIncrease >= 0 && endAngle == 0) {
				// 数据为0,不绘制
				startAngle = 0
			}
	    	ctx.beginPath();
	    	ctx.arc(this.x, this.y, this.r, 0, startAngle / 180 * Math.PI, false);
	    	ctx.stroke();				
	    	//动态绘制系统数量文本
			if( isIncrease > 0 && startCount < endCount ) {
				// 与百分比速度同步
				startCount += endCount * (velocity * 1 / endRate);
				if(startCount > endCount) {
					startCount = endCount;
				}
			}else if( isIncrease < 0 ) {
				startCount -= (startCount - endCount) * (velocity * 1 / (startRate - endRate != 0 ? startRate - endRate : 1));
				if(startCount < endCount) {
					startCount = endCount;
				}
			}
			//绘制系统数量
			ctx.font = '46px PingFangSC-Medium';
			ctx.fillText( Math.round( startCount ), this.x, this.y);
			//动态绘制比率文本
			if( isIncrease > 0 && startRate < endRate ) {
				startRate += velocity;	
				if( startRate > endRate) {
					startRate = endRate;
				}
			}else if( isIncrease < 0 ) {
				startRate -= velocity;
				if( startRate < endRate) {
					startRate = endRate;
				}
			}
			ctx.font = '15px PingFangSC-Medium';
			var rateLoctionX = this.x + this.r * Math.sin(30 / 180 * Math.PI) + 30,
				rateLoctionY = this.y - this.r + 10;
			ctx.fillText( startRate + '%', rateLoctionX, rateLoctionY);
			// 刷新画布
			that.timer = window.requestAnimationFrame(function () {
			    that.drawCircleAndText(ctx, startAngle, endAngle, startRate, endRate, startCount, endCount, isIncrease);
			});
			//所有元素动态绘制完毕,停止刷新
			if( (isIncrease > 0 && startAngle >= endAngle && startRate >= endRate && startCount >= endCount) ||
				(isIncrease < 0 && startAngle <= endAngle && startRate <= endRate && startCount <= endCount)) {
				window.cancelAnimationFrame( that.timer )
			}   
		}
	},
	watch: {
		'count': function(val, oldVal) {
			var isIncrease = val - oldVal;
			// 更新比例绘图
			this.drawCircleAndText(this.ctx, this.oldRate * 300, this.rate * 300, this.oldRate * 10000 / 100, this.rate * 10000 / 100, oldVal, val, isIncrease);
			this.oldRate = this.rate;
		}
	}
});

html直接引入

  <div class="contentRate">
      <v-ratechart :rate=status.SystemNumRate :count=status.SystemNum :imgsrc="statusCardClass[index]"></v-ratechart>
  </div>

最终效果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/PGD_607/article/details/103053806