给echarts图表添加弧形动画效果

         这里在option中一定要设置animation: false,因为echarts的5.0版本以后执行动画效果会卡顿,不清楚为什么。开启定时器时,定时器的间隔应当设置小一点,不然也会出现卡顿效果,希望echarts5.50版本之后能修复ecahrts执行加载效果卡顿的问题吧......

<template>
	<div class="h-120px" ref="pieChart"></div>
</template>

<script lang="ts" setup>
import { watch, ref, onMounted, onBeforeUnmount } from "vue";
import * as echarts from "echarts";
import { useEcharts } from "@/hooks/useEcharts";
const pieChart = ref();
const props = defineProps({
	data: {
		type: Object,
		default: () => {}
	}
});
watch(
	() => props.data,
	() => {
		initPieChart();
	},
	{
		deep: true
	}
);

/**
 * 制作弧形的动画效果
 */
let angle = 0; //角度,用来做简单的动画效果的
let timer: NodeJS.Timer; // 定时器
// 更新旋转的弧形的开始角度和结束角度
//获取圆上面某点的坐标(s:起始角度,e:结束角度,angle角度)
const getCirclePoint = (s: number, e: number) => {
	return {
		startAngle: ((s + angle) * Math.PI) / 180,
		endAngle: ((e + angle) * Math.PI) / 180
	};
};
const draw = (myChart: echarts.ECharts, option: echarts.EChartsCoreOption) => {
	angle = angle + 3;
	myChart.setOption(option, true);
};
// 鼠标移入echarts图表暂停动画
const stopAnimation = () => {
	clearInterval(timer);
};
// 鼠标移出echarts图表开始动画
const startAnimation = (myChart: echarts.ECharts, option: echarts.EChartsCoreOption) => {
	if (timer) {
		stopAnimation();
	}
    timer = setInterval(() => {
		draw(myChart, option);
	}, 50);
};
// 初始化图表
const initPieChart = () => {
    if (timer) {
		stopAnimation();
	}
	// 判断当前echarts是否存在
	let myChart = echarts.getInstanceByDom(pieChart.value);
	if (myChart == null) {
		myChart = echarts.init(pieChart.value);
	}
	const productList = ["产品1", "产品2", "产品3", "产品4", "产品5", "产品6", "产品7"];
	let totalData = [1.5, 1.3, 1.1, 2.3, 2.4, 2.6, 2.4];
	let totalNumber = 0;
	totalData.forEach(item => {
		totalNumber += item;
	});
	let finalData = [];
	for (let i = 0; i < productList.length; i++) {
		finalData.push({ name: productList[i], value: totalData[i] });
	}

	const option = {
		animation: false,
		tooltip: {
			trigger: "item",
			formatter: "{b} <br/>产能: {c}t"
		},
		legend: {
			type: "plain",
			orient: "vertical",
			height: "88%",
			right: "20",
			top: "center",
			itemWidth: 8,
			itemHeight: 8,
			data: productList,
			//格式化每一项内容
			formatter(name: string) {
				//只接收一个参数,就是类目名称
				let value = 0;
				//使用name去放内容的数组中拿到对应的值
				finalData.forEach(item => {
					if (item.name == name) {
						value = item.value;
					}
				});
				//name, value可以理解为样式标记符,用于在富文本中设置对应的样式
				return name + " " + ((value / totalNumber) * 100).toFixed(2) + "%";
			},
			textStyle: {
				fontSize: 14,
				fontWeight: 400,
				color: "#D1D6DF"
			}
		},
		series: [
			{
				type: "pie",
				radius: ["58%", "88%"],
				center: ["16%", "50%"],
				color: ["#4E7BFE", "#6796FD", "#3CB4FF", "#26D080", "#6B72D4", "#FEC704", "#FF4756"],
				label: {
					normal: {
						show: false
					}
				},
				labelLine: {
					normal: {
						show: false
					}
				},
				data: finalData
			},
			// 内圈阴影
			{
				itemStyle: {
					normal: {
						color: "rgba(8, 58, 84, 1)"
					}
				},
				type: "pie",
				hoverAnimation: false,
				radius: ["50%", "65%"],
				center: ["16%", "50%"],
				label: {
					normal: {
						show: false
					}
				},
				data: [
					{
						value: 1
					}
				],
				z: -1
			},
			// 外圈圆弧
			{
				name: "ring1",
				type: "custom",
				coordinateSystem: "none",
				renderItem: function (params: any, api: any) {
					let point = getCirclePoint(60, 120);
					return {
						type: "arc",
						shape: {
							cx: api.getWidth() * 0.16,
							cy: api.getHeight() / 2,
							r: Math.min(api.getWidth(), api.getHeight()) * 0.48,
							startAngle: point.startAngle,
							endAngle: point.endAngle
						},
						style: {
							stroke: "#FF0351",
							fill: "transparent",
							lineWidth: 1.5
						},
						silent: true
					};
				},
				data: [0]
			},
			{
				name: "ring2",
				type: "custom",
				coordinateSystem: "none",
				renderItem: function (params: any, api: any) {
					let point = getCirclePoint(180, 240);
					return {
						type: "arc",
						shape: {
							cx: api.getWidth() * 0.16,
							cy: api.getHeight() / 2,
							r: Math.min(api.getWidth(), api.getHeight()) * 0.48,
							startAngle: point.startAngle,
							endAngle: point.endAngle
						},
						style: {
							stroke: "#FF0351",
							fill: "transparent",
							lineWidth: 1.5
						},
						silent: true
					};
				},
				data: [0]
			},
			{
				name: "ring3",
				type: "custom",
				coordinateSystem: "none",
				renderItem: function (params: any, api: any) {
					let point = getCirclePoint(300, 360);
					return {
						type: "arc",
						shape: {
							cx: api.getWidth() * 0.16,
							cy: api.getHeight() / 2,
							r: Math.min(api.getWidth(), api.getHeight()) * 0.48,
							startAngle: point.startAngle,
							endAngle: point.endAngle
						},
						style: {
							stroke: "#FF0351",
							fill: "transparent",
							lineWidth: 1.5
						},
						silent: true
					};
				},
				data: [0]
			}
		]
	};

	useEcharts(myChart, option);
	// 开始定时器执行动画效果
	startAnimation(myChart, option);
	// 给echarts图表绑定鼠标移入移除事件
	myChart.on("mouseover", function () {
		stopAnimation();
	});
	myChart.on("mouseout", function () {
		startAnimation(myChart, option);
	});
};
onMounted(() => {
	initPieChart();
});
onBeforeUnmount(() => {
	stopAnimation();
});
</script>

<style lang="scss" scoped></style>

附上自己封装的useEcharts函数:给ecahrts添加响应式

import { onBeforeUnmount, onActivated, onDeactivated } from "vue";
import { useDebounceFn } from "@vueuse/core";
import * as echarts from "echarts";

/**
 * @description 使用Echarts(只是为了添加图表响应式)
 * @param {Element} myChart Echarts实例(必传)
 * @param {Object} options 绘制Echarts的参数(必传)
 * @return void
 * */
export const useEcharts = (myChart: echarts.ECharts, options: echarts.EChartsCoreOption) => {
	if (options && typeof options === "object") {
		myChart.setOption(options);
	}
	const echartsResize = useDebounceFn(() => {
		myChart && myChart.resize();
	}, 100);

	window.addEventListener("resize", echartsResize);

	onBeforeUnmount(() => {
		window.removeEventListener("resize", echartsResize);
	});

	onActivated(() => {
		window.addEventListener("resize", echartsResize);
	});

	onDeactivated(() => {
		window.removeEventListener("resize", echartsResize);
	});
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值