首页 前端知识 使用ucharts和echarts制作仪表盘

使用ucharts和echarts制作仪表盘

2024-04-29 11:04:56 前端知识 前端哥 91 434 我要收藏

起因:

之前使用uniapp + vue3 + js重构项目, 由于之前做的pc项目使用一直是echarts,所以这次我起先也毫不犹豫的选择使用echarts来做仪表盘

用echarts完成之后,想着uniapp + vue3可以一套代码可以多端使用,所以尝试将其运行到微信小程序,发现报错

报错的原因是echarts在获取dom容器时,只能使用document.querySelect(),但是小程序要想获取dom元素只能使用uni.createSelectorQuery(),最后查uniapp官网得知echarts不支持多端使用,要想使用多端使用可以选择ucharts

最后使用echarts和ucharts制作的仪表盘效果如下:
在这里插入图片描述

echarts仪表盘

echarts和ucharts制作仪表盘的本质都是通过不同图表类型拼接而成, 由于echarts配置项较多,大多数时候我会选择通过一些echarts demo 网站选择自己想要的表格,然后在进行修改, 此次使用通过demo网站找的的仪表图demo放这里了

最终将echarts deom 封装成组件, echarts-gauge.vue 代码如下:

<template>
	<view :id="pid" :style="style"></view>
</template>

<script setup>
	import useResizeChart from '@/utils/useResizeChart.js'
	import echarts from '@/utils/echarts.js'
	import {
		nextTick,
		watch
	} from 'vue'
	import {
		onLoad
	} from '@dcloudio/uni-app';
	const props = defineProps({
		pid: {
			type: String,
			required: true
		},
		data: {
			type: Number,
			required: true
		},
		title: {
			type: String
		},
		max: {
			type: Number,
			required: true
		},
		colors: {
			type: Object,
			// default: ,
			default: function() {
				return {
					// 内部进度条-刻度和刻度值之间的半圆 && 内部进度条--最里面的一层半圆
					outsideColor: '#22B95E',
					// 环形渐变圆
					shadowColor1: 'rgba(45,230,150,0)',
					shadowColor2: 'rgba(45,230,150,0.2)',
					shadowColor3: 'rgba(45,230,150,1)',
					// 渐变环形圆上面一层颜色较深的圆
					insideColor: '#30DBBA'

				}
			}
		},
		style: {
			type: Object,
			default: function() {
				return {
					height: '520rpx',
					width: '100%'
				}
			}
		}
	});

	var color1 = {
		type: "linear",
		x: 0,
		y: 0,
		x2: 1,
		y2: 1,
		colorStops: [{
				offset: 0,
				color: "rgba(0,0,0,0.1)"
			},
			{
				offset: 1,
				color: "rgba(0,0,0,0.3)"
			}
		],
		global: false
	}
	var color2 = {
		type: "linear",
		x: 0,
		y: 0,
		x2: 1,
		y2: 1,
		colorStops: [{
				offset: 0,
				color: "#30DBBA"
			},
			{
				offset: 1,
				color: "#2DE696"
			}
		],
		global: false
	}
	// dom元素
	let container = null;
	// echarts实例
	let myChart = null;

	let option = {
		// backgroundColor: 'pink',
		// tooltip: {
		//     formatter: "{a} <br/>{b} : {c}%"
		// },
		series: [{
				name: "内部进度条-刻度和刻度值之间的半圆",
				type: "gauge",
				// center: ['20%', '50%'],
				radius: '78%',
				splitNumber: 10,
				axisLine: {
					// 刻度和刻度值之间的半圆颜色
					lineStyle: {
						color: [
							[props.data / props.max, props.colors.outsideColor],
							[1, props.colors.outsideColor]
						],
						width: 2
					}
				},
				axisLabel: {
					show: false,
				},
				axisTick: {
					show: false,

				},
				splitLine: {
					show: false,
				},
				itemStyle: {
					// 指针外部颜色
					color: "#000",
				},
				detail: {
					show: false,
					offsetCenter: [0, 67],
					padding: [0, 0, 0, 0],
					fontSize: 18,
					fontWeight: '700',
					color: '#fff'
				},
				//标题
				title: {
					show: false,
					// x, y,单位px
					offsetCenter: [0, 46],
					color: "#ffffff",
					// 表盘上的标题文字大小
					fontSize: 14,
					fontFamily: 'PingFangSC'
				},
				data: [{
					name: "",
					// value: props.data,
					value: (props.data / props.max) * 100,
				}],
				pointer: {
					show: true,
					length: '70%',
					radius: '20%',
					//指针粗细
					width: 3

				},
				animationDuration: 4000,
			},
			{
				// 阴影部分的半圆
				name: "内部阴影-渐变阴影部分的环形圆",
				type: "gauge",
				radius: '56%',
				splitNumber: 10,
				axisLine: {
					lineStyle: {
						color: [
							[props.data / props.max, new echarts.graphic.LinearGradient(
								0, 1, 0, 0, [{
										offset: 0,
										color: props.colors.shadowColor1,
									}, {
										offset: 0.5,
										color: props.colors.shadowColor2,
									},
									{
										offset: 1,
										color: props.colors.shadowColor3,
									}
								]
							)],
							[
								1, 'rgba(28,128,245,0)'
							]
						],
						width: 45

					},
				},
				axisLabel: {
					show: false,
				},
				axisTick: {
					show: false,

				},
				splitLine: {
					show: false,
				},
				itemStyle: {
					show: false,
				},

			},
			{
				name: "渐变环形半圆上面一层半圆",
				type: "gauge",
				radius: '60%',

				splitNumber: 10,
				axisLine: {
					lineStyle: {
						color: [
							[props.data / props.max, props.colors.insideColor],
							[1, "rgba(0,0,0,0)"]
						],
						width: 5
					}
				},
				axisLabel: {
					show: false,
				},
				axisTick: {
					show: false,

				},
				splitLine: {
					show: false,
				},
				itemStyle: {
					show: false,
				},
			},
			{
				name: '外部刻度',
				type: 'gauge',
				//  center: ['20%', '50%'],
				radius: '76%',
				//最小刻度
				min: 0,
				//最大刻度
				max: props.max,
				//刻度数量
				splitNumber: 5,
				startAngle: 225,
				endAngle: -45,
				axisLine: {
					show: true,
					lineStyle: {
						width: 1,
						color: [
							[1, 'rgba(0,0,0,0)']
						]
					}
				},
				//仪表盘轴线
				axisLabel: {
					show: true,
					// 仪表刻度值颜色
					color: '#000',
					fontSize: 14,
					fontFamily: 'SourceHanSansSC-Regular',
					fontWeight: 'bold',
					// position: "top",
					distance: -20,

				},
				//刻度标签。
				axisTick: {
					show: true,
					splitNumber: 3,
					lineStyle: {
						//用颜色渐变函数不起作用
						color: color1,
						width: 1,
					},
					// 刻度的长度
					length: -6
				},
				//刻度样式
				splitLine: {
					show: true,
					length: -11,
					lineStyle: {
						//用颜色渐变函数不起作用
						color: color1,
					}
				}, //分隔线样式
				detail: {
					show: false
				}
			},
			{
				name: "内部进度条--最里面的一层半圆",
				type: "gauge",
				// center: ['20%', '50%'],
				radius: '20%',
				splitNumber: 10,
				axisLine: {
					lineStyle: {
						color: [
							[props.data / props.max, props.colors.outsideColor],
							[1, props.colors.outsideColor]
						],
						width: 1
					}
				},
				axisLabel: {
					show: false,
				},
				axisTick: {
					show: false,

				},
				splitLine: {
					show: false,
				},
				itemStyle: {
					color: "#000"
				},
				detail: {
					formatter: function(value) {
						if (props.max === 100) {
							if (value !== 0) {
								var num = Math.round(value);
								return parseInt(num).toFixed(0) + "%";
							} else {
								return 0;
							}
						} else {
							return value / 100
						}
					},
					offsetCenter: [0, 67],
					padding: [0, 0, 0, 0],
					fontSize: 18,
					// value 字体颜色
					color: "#000"
					// }
				},
				// 标题
				title: {
					show: true,
					// x, y,单位px
					offsetCenter: [0, 46],
					// name: 颜色
					color: "#000",
					//表盘上的标题文字大小
					fontSize: 14,
					fontWeight: 400,
					fontFamily: 'MicrosoftYaHei'
					// }
				},
				data: [{
					name: props.title,
					value: (props.data / props.max) * 100,
					itemStyle: {
						// 指针内部颜色
						color: "#000",
						fontFamily: "MicrosoftYaHei",
						fontSize: 14
					}
				}],
				pointer: {
					show: true,
					length: '70%',
					radius: '20%',
					//指针粗细
					width: 3

				},
				animationDuration: 4000,
			},
			{ //指针上的圆
				type: 'pie',
				tooltip: {
					show: false
				},
				// hoverAnimation: false,
				legendHoverLink: false,
				radius: ['0%', '4%'],
				center: ['50%', '50%'],
				label: {
					show: false
				},
				labelLine: {
					show: false
				},
				data: [{
					value: 120,
					itemStyle: {
						// 指针上的圆,颜色
						color: "#000",
					}
				}]
			},

		]
	};

	function renderChart() {
		if (container) {
			myChart = echarts.init(container)
			myChart.setOption(option)
			useResizeChart(container, myChart)
		}
	}
	nextTick(() => {
		container = document.querySelector('#' + props.pid)
		renderChart()

	})


	watch(() => props, () => {
		option = initOption();
		renderChart();
	}, {
		deep: true,
	}, )

	function exportImg() {
		const src = (myChart).getDataURL({
			pixelRatio: 2,
			backgroundColor: '#fff',
		});
		const a = document.createElement('a');
		a.href = src;
		a.download = 'chart-img';
		a.click();
	};

	defineExpose({
		exportImg,
	});
</script>

<style lang="scss" scoped>

</style>

ucharts仪表盘

ucharts相比于echarts,它的配置项没有那么复杂,几乎是将 ucharts官网 demo上的代码粘贴过去就能直接用(前提是安装了啊), 最后更具自己的需要调整图表样式就可以了

使用ucharts我属于新手上路,下面将我在其学的到的知识点几率一下,在po代码

vue3 组合式式获取组件实例

  • vue2 或者 vue3 我们使用的是选项式API (Options API )时, 组件内可以使用this,而this就是组件实例,
  • 但是当vue3使用setup时,我们不能使用this,此时想要获取组件实例我们可以使用getCurrentInstance
	import {  getCurrentInstance } from 'vue'
    const test = getCurrentInstance()
	console.log('组件实例', test)

之所以会获取组件实例, 是因为ucharts有原生和组件两种使用方式, 使用原生会使用到组件实例

仪表盘刻度值浮点数问题

真的,我觉得这个就是ucharts的bug,我找到码云翻到有人提过这个问题, 甚至把解决方案的代码都发出来了,作者都不改,作者说可以用format,结果我用了format根本没用!!! 最后我甚至还提交了issues, 写的时候真的是火大, 最后根据别人提交的issues,修改了u-charts.js,这个问题才被解决, 具体修改方法放在这里
在这里插入图片描述
最后使用ucharts封装的仪表盘组件代码如下:

<template>
	<view class="charts" :style="style">
		<!-- 最外层半圆 -->
		<view class="charts-box-outside">
			<qiun-data-charts type="arcbar" :opts="arcbarOpts" :chartData="arcbarChartData" />
		</view>
		<!-- 深颜色进度条 -->
		<view class="charts-box-Progress">
			<qiun-data-charts type="arcbar" :opts="progressOpts" :chartData="ProgressChartData" />
		</view>
		<!-- 渐变进度条 -->
		<view class="charts-box-color">
			<qiun-data-charts type="arcbar" :opts="colorOpts" :chartData="colorChartData" />
		</view>
		<!--  最内部半圆 -->
		<view class="charts-box-inside">
			<qiun-data-charts type="arcbar" :opts="arcbarOpts" :chartData="arcbarChartData" />
		</view>
		<!-- 仪表盘 -->
		<view class="charts-box">
			<qiun-data-charts type="gauge" :opts="opts" :chartData="chartData" />
		</view>

	</view>
</template>

<script setup>
	import {
		getCurrentInstance,
		ref,
		nextTick
	} from 'vue'
	import uCharts from '@/utils/u-charts.js';
	import {
		onReady
	} from '@dcloudio/uni-app'

	const props = defineProps({
		subtitle: {
			type: String,
		},
		unit: {
			type: String,
			default: ""
		},
		data: {
			type: Number,
			required: true
		},
		max: {
			type: Number,
			default: 100
		},
		style: {
			type: Object,
			default: function() {
				return {
					width: '100%',
					height: '300px'
				}
			}
		},
		colors: {
			type: Object,
			default: function () {
				return {
					sideColor: "#1890FF",
					progressColor: "#00bfff",
					ColorCustom: ["#4ed3ff", "#00bfff"]
				}
			}
			
		}
	})

	const chartData = ref({})
	// 最外层半圆 and 最内部半圆 
	const arcbarChartData = ref({})
	// 渐变进度条
	const colorChartData = ref({})
	const ProgressChartData = ref({})
	// 仪表盘配置
	const opts = ref({
		padding: undefined,
		title: {
			name: props.data + props.unit,
			fontSize: 16,
			color: "#666666",
			offsetY: 100
		},
		subtitle: {
			name: props.subtitle,
			fontSize: 14,
			color: "#666666",
			offsetY: 60
		},
		extra: {
			gauge: {
				type: "default",
				width: 15,
				labelColor: "#000",
				startAngle: 0.75,
				endAngle: 0.25,
				startNumber: 0,
				endNumber: props.max,
				splitLine: {
					fixRadius: 0,
					splitNumber: 5,
					width: 15,
					color: "#000",
					childNumber: 5,
					childWidth: 12,
				},
				labelOffset: -30,
				pointer: {
					width: 10,
					color: "#000000"
				},
				// formatter: (val, index, opts) => {
				// 	console.log('111111111',val, index, opts )
				// 	// return val.toFixed(1)
				// }
			}
		}

	})
	// 进度条配置: 最外层半圆 and 最内部半圆 
	const arcbarOpts = ref({
		padding: undefined,
		title: {
			name: "",
		},
		subtitle: {
			name: "",
		},
		extra: {
			arcbar: {
				type: "default",
				width: 2,
				backgroundColor: "#E9E9E9",
				startAngle: 0.75,
				endAngle: 0.25,
				gap: 2,
				linearType: "none",
				lineCap: "butt"
			}
		}
	})

	// 深颜色进度条配置
	const progressOpts = ref({
		padding: undefined,
		title: {
			name: "",
		},
		subtitle: {
			name: "",
		},
		extra: {
			arcbar: {
				type: "default",
				width: 8,
				backgroundColor: "rgba(0,0,0,0.001)",
				startAngle: 0.75,
				endAngle: 0.25,
				gap: 2,
				linearType: "none",
				lineCap: "butt"
			}
		}
	})


	// 渐变进度条配置
	const colorOpts = ref({
		padding: undefined,
		title: {
			name: "",
			fontSize: 35,
			color: "#2fc25b"
		},
		subtitle: {
			name: "",
			fontSize: 25,
			color: "#666666"
		},
		extra: {
			arcbar: {
				type: "default",
				width: 52,
				backgroundColor: "rgba(0,0,0,0.001)",
				startAngle: 0.75,
				endAngle: 0.25,
				gap: 2,
				linearType: "custom",
				custom: props.colors.ColorCustom,
				lineCap: "butt"
			}
		}
	})


	// 仪表盘数据
	function getChartData() {
		let res = {
			categories: [{
				"value": 0.2,

				"color": "rgba(0,0,0,0.01)"
			}, {
				"value": 0.8,
				"color": "rgba(0,0,0,0.01)"
			}, {
				"value": 1,
				"color": "rgba(0,0,0,0.01)"
			}, ],

			series: [{
				name: "完成率",
				data: props.data / props.max,
			}],
		};
		chartData.value = JSON.parse(JSON.stringify(res));
	}



	// 获取组件实例
	// 在 setup 和其他 Composition API 中没有 this
	// 可通过 getCurrentInstance 获取当前实例
	// 若使用 Options API 可照常使用 this
	// const test = getCurrentInstance()
	// console.log('组件实例', test)
	// 最外层半圆 and 最内部半圆 进度条数据固定
	function getArcbarChartData() {
		let res = {
			series: [{
				name: "最外层半圆 and 最内部半圆",
				color: props.colors.sideColor,
				data: 1
			}]
		};
		arcbarChartData.value = JSON.parse(JSON.stringify(res));
	}

	function getProgressChartData() {
		let res = {
			series: [{
				name: "深颜色进度条",
				color: props.colors.progressColor,
				data: props.data / props.max
			}]
		};
		ProgressChartData.value = JSON.parse(JSON.stringify(res));
	}


	function getColorChartData() {
		let res = {
			series: [{
				name: "渐变进度条",
				color: "#eafcf4",
				data: props.data / props.max
			}]
		};
		colorChartData.value = JSON.parse(JSON.stringify(res));
	}

	nextTick(() => {
		getChartData()
		getArcbarChartData()
		getProgressChartData()
		getColorChartData()
	})
</script>


<style lang="scss">
	.charts {

		position: relative;

		.charts-box-outside {
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			width: 90%;
			height: 90%;
		}

		.charts-box {
			width: 87%;
			height: 87%;
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			// background-color: aquamarine;
		}

		.charts-box-Progress {
			width: 70%;
			height: 70%;
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
		}

		.charts-box-color {
			width: 65%;
			height: 65%;
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
		}

		.charts-box-inside {
			width: 30%;
			height: 30%;
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
		}
	}
</style>
转载请注明出处或者链接地址:https://www.qianduange.cn//article/6204.html
标签
uni app
评论
发布的文章

@JsonCreator和@JsonValue

2024-05-05 22:05:05

Python 字符串转换为 JSON

2024-05-05 22:05:00

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!