如何在 Vue 3 中使用 ECharts 创建饼状图

727 阅读2分钟

如何在 Vue 3 中使用 ECharts 创建饼状图

实现高亮效果与交互

<template>
    <div ref="chart" class="chart"></div>
</template>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import * as echarts from 'echarts';

const chart = ref(null);
let myChart = null;
let highlightInterval;

const data = reactive([{
    name: '第三产业',
    value: 51
}, {
    name: '第二产业',
    value: 29
}, {
    name: '第一产业',
    value: 20,
}])
let color2 = ['rgba(42,142,242,0.5)', 'rgba(101,147,254,0.5)', 'rgba(61,188,191,0.5)'];
let color1 = ['rgba(42,142,242,1)', 'rgba(101,147,254,1)', 'rgba(61,188,191,1)'];

const createBaseData = (data, colors) => {
    let baseData = [];
    for (let i = 0; i < data.length; i++) {
        baseData.push({
            value: data[i].value,
            name: data[i].name,
            itemStyle: {
                normal: {
                    color: colors[i],
                }
            }
        });
    }
    return baseData;
}
onMounted(() => {
    myChart = echarts.init(chart.value);

    let baseData1 = createBaseData(data, color1);
    let baseData2 = createBaseData(data, color2);
    const option = {
        tooltip: {
            show: true,
            trigger: 'item',
            formatter: (params) => {
                const total = data.reduce((sum, current) => sum + current.value, 0);
                params.percent = ((params.value / total) * 100).toFixed(0);
                return `${params.name}\n${params.percent}%`;
            }
        },
        legend: {
            show: true,
            selectedMode: false,
            data: data.map(d => d.name),
            orient: 'vertical',
            right: '5%',
            top: 'center',
            icon: 'roundRect',
            textStyle: {
                fontSize: 14,
                fontFamily: 'Arial',
                rich: {
                    name: {
                        color: '#FFFFFF',
                        fontWeight: 'bold',
                    },
                    value: {
                        color: '#FFF200',
                        fontStyle: 'italic',
                    },
                }
            },
            formatter: function (name) {
                const item = data.find(d => d.name === name);
                if (item) {
                    const total = data.reduce((sum, current) => sum + current.value, 0);
                    const percentage = ((item.value / total) * 100).toFixed(0);
                    return [
                        `{name|${name}}   `,
                        `{value|${percentage}%}`
                    ].join('');
                }
                return name;
            },
        },
        series: [{
            type: 'pie',
            hoverAnimation: false,
            radius: ['70%', '50%'],
            center: ['35%', '50%'],

            itemStyle: {
                borderColor: '#fff',
                borderWidth: 2
            },
            emphasis: {
                itemStyle: {
                    color: 'rgba(255, 0, 0, 1)',
                    borderWidth: 5,
                    borderColor: '#ffffff',
                    shadowBlur: 20,
                    shadowColor: 'rgba(0, 0, 0, 0.5)',
                },
                label: {
                    show: true,
                    fontSize: 20,
                    fontWeight: 'bold',
                    rich: {
                        b: {
                            color: '#ffffff',
                            fontSize: 24,
                        },
                        c: {
                            color: '#ffffff',
                            fontSize: 20,
                        }
                    },
                    formatter: (params) => {
                        const total = data.reduce((sum, current) => sum + current.value, 0);
                        params.percent = ((params.value / total) * 100).toFixed(0);
                        return `{b|${params.percent}%}\n\n{c|${params.name}}`;
                    }
                }
            },
            label: {
                show: false,
                position: 'center'
            },
            data: baseData1
        },
        {
            type: 'pie',
            hoverAnimation: false,
            color: color1,
            radius: ['95%', '71%'],
            center: ['35%', '50%'],
            tooltip: {
                show: false
            },
            itemStyle: {
                borderColor: '#fff',
                borderWidth: 2
            },
            emphasis: {
                itemStyle: {
                    color: 'rgba(255, 0, 0, 1)',
                    borderWidth: 5,
                    borderColor: '#ffffff',
                    shadowBlur: 20,
                    shadowColor: 'rgba(0, 0, 0, 0.5)',
                },
                label: {
                    show: true,
                    fontSize: 20,
                    fontWeight: 'bold',
                    rich: {
                        b: {
                            color: '#ffffff',
                            fontSize: 24,
                        },
                        c: {
                            color: '#ffffff',
                            fontSize: 20,
                        }
                    },
                    formatter: (params) => {
                        const total = data.reduce((sum, current) => sum + current.value, 0);
                        params.percent = ((params.value / total) * 100).toFixed(0);
                        return `{b|${params.percent}%}\n\n{c|${params.name}}`;
                    }
                }
            },
            label: {
                show: false,
                position: 'center'
            },
            data: baseData2
        },
        ]
    };
    myChart.setOption(option);

    let currentIndex = 0;
    const totalItems = data.length;


    const startHighlighting = () => {
        // 立即高亮第一个数据项
        myChart.dispatchAction({
            type: 'highlight',
            seriesIndex: 0,
            dataIndex: currentIndex
        });
        myChart.dispatchAction({
            type: 'highlight',
            seriesIndex: 1,
            dataIndex: currentIndex
        });
        highlightInterval = setInterval(() => {
            myChart.dispatchAction({
                type: 'downplay',
                seriesIndex: 0,
                dataIndex: currentIndex
            });
            myChart.dispatchAction({
                type: 'downplay',
                seriesIndex: 1,
                dataIndex: currentIndex
            });

            currentIndex = (currentIndex + 1) % totalItems;

            myChart.dispatchAction({
                type: 'highlight',
                seriesIndex: 0,
                dataIndex: currentIndex
            });
            myChart.dispatchAction({
                type: 'highlight',
                seriesIndex: 1,
                dataIndex: currentIndex
            });
        }, 5000);
    };

    startHighlighting();

    chart.value.addEventListener('mouseenter', () => {
        clearInterval(highlightInterval);
        myChart.dispatchAction({
            type: 'downplay',
            seriesIndex: 0,
            dataIndex: currentIndex
        });
        myChart.dispatchAction({
            type: 'downplay',
            seriesIndex: 1,
            dataIndex: currentIndex
        });
    });

    chart.value.addEventListener('mouseleave', () => {
        startHighlighting();
    });
});