这里在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);
});
};