uniapp 绘制环形图

效果图:
在这里插入图片描述

vue页面

<template>
	<view>
		<canvas style="width: 350px; height: 300px;" canvas-id="homeownerCanvas" class="homeowner-canvas_charts"></canvas>
	</view>
</template>

<script>
	// 引入外部 js
	import canvas from '@/static/canvas.js'

	export default {
		data() {
			return {
				
			}
		},
		onReady() {
			let data = [{
					"money": 50 + '万',
					"value": 0.5,
					"color": "#afb4db",
					"title": "口红"
				},
				{
					"money": 20 + '万',
					"value": 0.2,
					"color": "#ffce7b",
					"title": "眼影"
				},
				{
					"money": 10 + '万',
					"value": 0.1,
					"color": "#f8aba6",
					"title": "粉底"
				},
				{
					"money": 20 + '万',
					"value": 0.2,
					"color": "#afdfe4",
					"title": "眉笔"
				}
			];
			
			// 调用外部方法并传入参数
			canvas.canvasGraph('homeownerCanvas', data, 100)
		},

		methods: {

		}
	}
</script>

<style>

</style>

图表封装 canvas.js

// 图表封装
export default {
	canvasGraph(canvasID, data, summation) {
		function PieChart(ctx, radius) {
			//定义起始角度
			let tempAngle = 0;
			//定圆心位置
			let x0 = 182, y0 = 150; //伸出长度
			let outLine = 18;
			PieChart.prototype.init = function(data) {
				this.drawPie(data);
			};
			// 绘画扇形 及中心圆
			PieChart.prototype.drawPie = function(data) {
				for (let i = 0; i < data.length; i++) {
					// 开始一个新路径
					ctx.beginPath();
					// 移动到中心点
					ctx.moveTo(x0, y0);
					//计算当前扇形角度   所占比例*360
					let angle = data[i].value * 360;
					//当前扇形起始绘制弧度   360 = 2π  等于6.28
					let startAngle = tempAngle * Math.PI / 180;
					//当前扇形借结束绘制弧度
					let endAngle = (tempAngle + angle) * Math.PI / 180;
					//绘制扇形  x y中心  半径  开始弧度  结束弧度
					ctx.arc(x0, y0, radius, startAngle, endAngle);
					//填充扇形
					ctx.fillStyle = data[i].color;
					// 填充
					ctx.fill();
					// 调用添加标题解释方法
					this.drawTitle(startAngle, angle, data[i].color, data[i].title + data[i].money)
					//当前扇形结束绘制角度,即下一个扇形开始绘制角度
					tempAngle += angle;
				}
				// 开始一个新路径
				ctx.beginPath();
				// 开始画圆
				ctx.arc(x0, y0, 65, 0, 2 * Math.PI)
				// 填充颜色 白色
				ctx.setFillStyle('white')
				// 调用绘制中心圆文字方法
				this.drawCenterTitle()
			}
			// 伸出线条方法
			PieChart.prototype.drawTitle = function(startAngle, angle, color, title) {
				// 伸出去的长度 斜边长度 等于半径加上定义好的长度  
				let out = radius;
				// 当前弧度的二分之一
				let du = startAngle + (angle / 2) * Math.PI / 180;
				// 计算伸出的点x坐标
				let outX = x0 + out * Math.cos(du);
				// 计算伸出的点y坐标
				let outY = y0 + out * Math.sin(du);
				// 开始一个新路径
				ctx.beginPath();
				// 移动到中心点
				ctx.moveTo(x0, y0);
				// 画出点到伸出点的一条线
				ctx.lineTo(outX, outY);
				// 线条颜色
				ctx.strokeStyle = color;
				//设置标题
				ctx.font = 'bold 14px Microsoft Yahei';
				// 计算出标题文字宽度
				let textWidth = ctx.measureText(title).width;
				// 计算标题样式
				ctx.textBaseline = "bottom";
				// 象限判断
				let optionArr = [{
						quadrant: outX >= x0 && outY <= y0,
						symbol: ['+', '-', 'left']
					},
					{
						quadrant: outX < x0 && outY <= y0,
						symbol: ['-', '-', 'right']
					},
					{
						quadrant: outX < x0 && outY > y0,
						symbol: ['-', '+', 'right']
					},
					{
						quadrant: outX >= x0 && outY > y0,
						symbol: ['+', '+', 'left']
					}
				]
				// 渲染的配置项
				let {symbol} = optionArr.find(el => el.quadrant && el.symbol)
				// 斜线起始点
				let slashState = eval(outX + symbol[0] + outLine)
				// 横线起始点
				let lineState = eval(outX + symbol[0] + textWidth + symbol[0] + outLine)
				// 终点
				let lineEnd = eval(outY + symbol[1] + outLine)
				// 标题文字样式
				ctx.textAlign = symbol[2];
				// 画出伸出的斜线
				ctx.lineTo(slashState, lineEnd);
				// 接上斜线画出标题下面的直线
				ctx.lineTo(lineState, lineEnd);
				// 填充标题
				ctx.fillText(title, slashState, lineEnd);
				// 填充
				ctx.stroke();
			}
			// 绘制中心文字
			PieChart.prototype.drawCenterTitle = function() {
				// 填充
				ctx.fill();
				// 文字大小
				ctx.setFontSize(24)
				// 文字颜色
				ctx.fillStyle = "#333333"
				// 文字位置
				ctx.setTextAlign('center')
				// 插入文字
				ctx.fillText(`${summation}`, x0, y0 + 5)
				// 文字大小
				ctx.setFontSize(14)
				// 合计字体样式
				ctx.font = '14px Microsoft Yahei';
				// 文字颜色
				ctx.fillStyle = "#999999"
				// 插入文字
				ctx.fillText('合计(元)', x0, y0 + 30)
				// 开始画图
				ctx.draw()
			}
		}
		var ctx = uni.createCanvasContext(canvasID)
		var PieChart = new PieChart(ctx, 90)
		PieChart.init(data)
	}

}

代码出处:https://www.cnblogs.com/gongliying/p/11461508.html#top



使用 v-for 动态渲染 canvas 的时候要注意,先等待canvas组件渲染完成,再调用方法进行绘画,否则只有空白页面。

<template>
	<view>
		<block v-for="(item,index) in dataList" :key="index">
			<view style="margin: 50rpx;">{{item.subjectContent}}</view>
			<canvas :canvas-id="'id'+index" class="homeowner-canvas_charts" style="width: 350px; height: 300px;" ></canvas>
		</block>
	</view>
</template>

<script>
	// 引入外部 js
	import canvas from '@/static/canvas.js'

	export default {
		data() {
			return {
				baseUrl: '',
				dataList: []
			}
		},
		onReady() {
			// 获取全局变量 baseUrl
			this.baseUrl = getApp().globalData.baseUrl;
			// 调用方法
			this.getData()
		},

		methods: {
			//从后端获取数据
			getData() {
				uni.request({
					url: this.baseUrl + 'queryByGroup',
					method: "GET",
					data: {},
					success: (res) => {
						//console.log(res)
						let arr = res.data
						this.dataList = arr
						
						uni.showToast({
							title: '数据加载中...', //显示的文字
							duration: 1000, //显示多少时间,默认1500毫秒
							icon: "loading" //自定义显示的图标,默认成功success,错误error,加载loading,不显示图标是none
						})
						
						// 延迟1秒等待canvas组件渲染完成,再调用方法绘画,否则绘画不成功
						setTimeout(function(){
							for (let x in arr) {
								// 调用外部方法并传入参数:canvas-id,数组,总数量
								canvas.canvasGraph('id'+x, arr[x].list, arr[x].list[0].total)
							}
						},1000)
						
					},
					fail: (err) => {
						uni.showToast({
							title: "网络请求失败!",
							icon: 'none',
							duration: 2000
						})
					}
				})
			}
		}
	}
</script>

<style>
</style>

效果图

在这里插入图片描述

后端返回的数据格式

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值