当页面窗口变化或者导航栏缩进展开时echarts图表自适应
主要自适应代码块如下

 // 监听当容器大小变化时随之变化
	let resizeObserver = null;
    resizeObserver = new ResizeObserver((entries) => {
        for (let entry of entries) {
            if (entry.target === chartRef.value) {
                if (chart != null) {
                    chart.resize();
                }
            }
        }
    });
    resizeObserver.observe(chartRef.value);

以下是封装的图表组建
折线图代码示例

<template>
    <div ref="chartRef" class="chart-container"></div>
</template>

<script setup>
import { onMounted, ref, onUnmounted, watch } from 'vue';
import useAppStore from '@/store/modules/app';
import * as echarts from 'echarts';

const appStore = useAppStore();

const chartRef = ref(null);
const props = defineProps({
    color: Array,
    xaxisData: Array,
    legendData: Array,
    dataV: Array,
    unit: String
});

let chart = null;
let resizeObserver = null;

onMounted(() => {
    chart = echarts.init(chartRef.value);
    const render = () => {
        chart.setOption({
            tooltip: { trigger: 'axis' },
            legend: { data: props.legendData, icon: 'stack', right: '28px' },
            grid: { left: '0', right: '4%', bottom: '0', containLabel: true },
            xAxis: { type: 'category', boundaryGap: true, data: props.xaxisData },
            yAxis: { type: 'value', name: props.unit },
            color: props.color,
            series: props.dataV
        }, true);
    };
    render();

    // 监听当容器大小变化时随之变化
    resizeObserver = new ResizeObserver((entries) => {
        for (let entry of entries) {
            if (entry.target === chartRef.value) {
                if (chart != null) {
                    chart.resize();
                }
            }
        }
    });
    resizeObserver.observe(chartRef.value);

    const handleResize = () => chart.resize();

    // 窗口缩放时图表自适应
    // window.addEventListener('resize', handleResize);

    watch(() => props.dataV, render, { deep: true });
    // 监听 Vuex store 中的状态变化
 	watch(
    	() => appStore.sidebar.opened,
    	(opened) => {
      		console.log('Sidebar opened state changed:', opened);
      		// 根据需要更新图表或执行其他操作
      		if (opened) {
       			// 执行某些操作,例如重新渲染图表
        		render();
      		}
    	},
    { immediate: true }
  );
    onUnmounted(() => {
        window.removeEventListener('resize', handleResize);
        chart.dispose();
    });
});
</script>

<style scoped>
.chart-container {
    width: 100%;
    height: calc(100% - 20px);
    position: relative;
}
</style>

如图所示效果
多个环状图一个legend示例

<template>
    <div ref="chartRef" style="width: 100%; height: calc(100% - 20px)"></div>
</template>

<script setup>
import { onMounted, ref, watch, onUnmounted } from 'vue';
import * as echarts from 'echarts';

const chartRef = ref(null);
let resizeObserver = null;
const props = defineProps({
    dataV: Array,
    title: Array
});
// 解析数据并生成 ECharts 配置
const render = (data) => {
    const option = {
        legend: {
            right: '20px'
        },
        tooltip: {},
        title: props.title,
        color: ['#6488FE', '#FF6F6F', '#FEE177', '#2AF0CF', '#FFD700'],
        series: data.map((device, index) => ({
            name: device.deviceName,
            type: 'pie',
            radius: ['35%', '65%'],
            center: [`${index * 25 + 12.5}%`, '50%'],
            avoidLabelOverlap: false,
            padAngle: 4,
            label: {
                show: true,
                position: 'inner',
                color: '#666',
                formatter: '{d}%'
            },
            emphasis: {
                label: {
                    show: true,
                    fontSize: '12',
                    fontWeight: 'bold'
                }
            },
            labelLine: {
                show: false
            },
            itemStyle: {
                shadowBlur: 20,
                shadowColor: 'rgba(100,136,254,0.6)',
                shadowOffsetX: 0,
                shadowOffsetY: 0
            },
            data: device.alarmTypes.map(type => ({
                value: parseFloat(type.proportion),
                name: type.alarmType
            }))
        }))
    };

    return option;
};

onMounted(() => {
    const chart = echarts.init(chartRef.value);
    const option = render(props.dataV);
    chart.setOption(option);

    watch(() => props.dataV, (newData) => {
        chart.setOption(render(newData));
    }, { deep: true });

    // 监听当容器大小变化时随之变化
    resizeObserver = new ResizeObserver((entries) => {
        for (let entry of entries) {
            if (entry.target === chartRef.value) {
                if (chart != null) {
                    chart.resize();
                }
            }
        }
    });
    resizeObserver.observe(chartRef.value);

    const handleResize = () => chart.resize();
    // 窗口变化自适应
    // window.addEventListener('resize', handleResize);

    onUnmounted(() => {
        window.removeEventListener('resize', handleResize);
        chart.dispose();
    });
});
</script>

如图所示效果
柱状图示例

<template>
    <div ref="chartRef" style="width: 100%; height: calc(100% - 32px);"></div>
</template>

<script setup>
import { onMounted, ref, watch, onUnmounted } from 'vue';
import * as echarts from 'echarts';

const chartRef = ref(null);
let resizeObserver = null;//监听页面大小变化

const props = defineProps({
    dataV: Array,
    keyNameMap: Object,
    unit: String
});

// 键名替换映射
// 解析数据并生成 ECharts 配置
const render = (data) => {
    const dates = data.map(item => item.timeNode);
    const categories = data.map(item => item.timeNode);
    const seriesData = Object.keys(props.keyNameMap).reduce((acc, key) => {
        acc[key] = data.map(item => parseFloat(item[key]));
        return acc;
    }, {});
    const option = {
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'shadow'
            }
        },
        legend: {
            data: Object.values(props.keyNameMap),
            right: '20px'
        },
        grid: {
            left: '3%',
            right: '4%',
            bottom: '3%',
            containLabel: true
        },
        xAxis: [
            {
                type: 'category',
                data: dates,
            }
        ],
        yAxis: [
            {
                type: 'value',
                name: props.unit
            }
        ],
        color: ['#478BFE', '#27CEBA'],
        dataZoom: [
            // { // 添加滚动条组件以支持缩放和滚动查看。
            //     type: 'slider', // 这个 dataZoom 组件是滑动条类型。
            //     start: 10,      // 左边在 10% 的位置。
            //     end: 50         // 右边在 50% 的位置。
            // },
            {
                type: 'inside'
            }
        ],
        series: Object.keys(seriesData).map(key => ({
            name: props.keyNameMap[key],
            type: 'bar',
            barMaxWidth: '18px',
            data: seriesData[key],
            emphasis: {
                focus: 'series'
            },
            label: {
                show: false,
                position: 'top',
                textStyle: {
                    color: '#999999'
                }
            }
        }))
    };

    return option;
};

onMounted(() => {
    const chart = echarts.init(chartRef.value);

    // 假设 props.dataV 已经包含了解析好的数据
    const option = render(props.dataV);
    chart.setOption(option);

    watch(() => props.dataV, (newData) => {
        chart.setOption(render(newData));
    }, { deep: true });

    // 监听当容器大小变化时随之变化
    resizeObserver = new ResizeObserver((entries) => {
        for (let entry of entries) {
            if (entry.target === chartRef.value) {
                if (chart != null) {
                    chart.resize();
                }
            }
        }
    });
    resizeObserver.observe(chartRef.value);

    const handleResize = () => chart.resize();
    // window.addEventListener('resize', handleResize);

    onUnmounted(() => {
        window.removeEventListener('resize', handleResize);
        chart.dispose();
    });
});
</script>

如图所示效果
以上记录一下封装的组件

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐