当前位置: 首页 > java >正文

封装渐变堆叠柱状图组件附完整代码

在这里插入图片描述

组件功能

这是一个渐变堆叠柱状图组件,主要功能包括:

  1. 在一根柱子上同时显示高、中、低三种危险级别数据
  2. 使用渐变色区分不同危险级别(高危红色、中危橙色、低危蓝色)
  3. 悬停显示详细数据信息(包括总量和各级别数据)
  4. 自适应容器大小变化

使用方法在父组件中引入组件并传入数据

<template><JianbianZhu :warningData="warningData" :warningSevenItem="warningSevenItem" />
</template><script>
export default {data() {return {warningData: {high: [30, 40, 35, 50, 60, 40, 80],    // 高危数据middle: [70, 60, 65, 60, 60, 80, 70],  // 中危数据low: [50, 70, 80, 70, 60, 70, 60]      // 低危数据},warningSevenItem: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] // X轴标签}}
}
</script>

核心代码实现

1. 堆叠柱状图配置

// 核心实现:创建堆叠柱状图,三个系列分别代表低、中、高危
series: [{name: '低危',type: 'bar',stack: '总量',  // 设置堆叠,关键属性data: lowData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#70B2F7' },  // 顶部颜色{ offset: 0.5, color: '#52A2FF' }, // 中间颜色{ offset: 1, color: '#1970C2' }   // 底部颜色])}},{name: '中危',type: 'bar',stack: '总量',data: middleData,// 中危渐变色配置...},{name: '高危',type: 'bar',stack: '总量',data: highData,// 高危渐变色配置...}
]

2. 渐变色实现

// 通过LinearGradient创建渐变效果
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FF2E2E' },  // 顶部颜色(更鲜艳){ offset: 0.5, color: '#FF5252' }, // 中间颜色{ offset: 1, color: '#FF8A8A' }   // 底部颜色(过渡到中危)
]),

3. 数据提示框配置

tooltip: {trigger: 'axis',formatter: function(params) {const index = params[0].dataIndex;const date = xAxisData[index];const total = totalData[index] || 0;let result = `${date}<br/>总数: ${total}<br/>`;// 添加各危险级别数据params.forEach((param) => {let value = param.value || 0;result += `${param.seriesName}: ${value}<br/>`;});return result;}
}

4. 数据变化更新

// 监听数据变化,只在真正变化时更新图表
watch(() => [props.warningData, props.warningSevenItem], ([newWarningData, newWarningSevenItem]) => {const newWarningDataStr = JSON.stringify(newWarningData);const newWarningSevenItemStr = JSON.stringify(newWarningSevenItem);// 检查数据是否有变化const dataChanged = newWarningDataStr !== prevWarningData.value || newWarningSevenItemStr !== prevWarningSevenItem.value;if (dataChanged) {if (chartInstance) {updateChart();} else {initChart();}}
}, { deep: true });

自定义调整

  1. 修改显示顺序:调整series数组中三个对象的顺序即可改变柱状图中高中低危的堆叠顺序

  2. 调整颜色:修改各系列的LinearGradient配置可以改变渐变色效果

  3. 调整圆角:目前顶部系列设置了borderRadius: [2, 2, 0, 0]实现顶部圆角效果

完整组件代码:

<template><div ref="chartContainer" class="chart-container"><div ref="chart" class="chart"></div></div>
</template><script lang="ts">
import { defineComponent, onMounted, ref, watch, onUnmounted } from 'vue';
import * as echarts from 'echarts';export default defineComponent({name: 'JianbianZhu',props: {warningData: {type: Object,required: true},warningSevenItem: {type: Array,required: true}},setup(props) {const chartRef = ref<HTMLElement | null>(null);let chartInstance: echarts.ECharts | null = null;// 保存上一次的数据快照,用于比较数据是否变化const prevWarningData = ref<string>('');const prevWarningSevenItem = ref<string>('');// 处理窗口大小变化const handleResize = () => {if (chartInstance) {chartInstance.resize();}};const initChart = () => {if (!chartRef.value) return;// 创建图表实例chartInstance = echarts.init(chartRef.value);// 准备数据const xAxisData = props.warningSevenItem;const highData = props.warningData.high || [];const middleData = props.warningData.middle || [];const lowData = props.warningData.low || [];// 计算总数据用于展示const totalData = highData.map((val: number, index: number) => {return val + (middleData[index] || 0) + (lowData[index] || 0);});// 更新数据快照prevWarningData.value = JSON.stringify(props.warningData);prevWarningSevenItem.value = JSON.stringify(props.warningSevenItem);// 配置图表选项const option = {tooltip: {trigger: 'axis',axisPointer: {type: 'shadow'},formatter: function(params: any) {const index = params[0].dataIndex;const date = xAxisData[index];const total = totalData[index] || 0;let result = `${date}<br/>总数: ${total}<br/>`;// 按顺序添加高中低危数据params.forEach((param: any) => {let value = param.value || 0;result += `${param.seriesName}: ${value}<br/>`;});return result;}},legend: {data: ['低危', '中危', '高危'],textStyle: {color: 'rgba(255, 255, 255, 0.65)'},right: '5%',top: '0%'},grid: {left: '5%',right: '5%',bottom: '10%',top: '15%',containLabel: true},xAxis: {type: 'category',data: xAxisData,axisLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.2)'}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,interval: 0,rotate: 0},axisTick: {show: false}},yAxis: {type: 'value',name: '',nameTextStyle: {color: 'rgba(255, 255, 255, 0.65)'},min: 0,axisLine: {show: false},axisTick: {show: false},splitLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.1)',type: 'dashed',width: 0.5}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,formatter: function(value: number) {if (value >= 1000) {return Math.floor(value / 1000) + 'k';}return value;}}},series: [{name: '低危',type: 'bar',stack: '总量',data: lowData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#70B2F7' },  // 顶部颜色(与中危底部接近){ offset: 0.5, color: '#52A2FF' }, // 中间颜色{ offset: 1, color: '#1970C2' }   // 底部颜色(更深)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '中危',type: 'bar',stack: '总量',data: middleData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FFA066' },  // 顶部颜色(与高危底部接近){ offset: 0.5, color: '#FFA647' }, // 中间颜色{ offset: 1, color: '#FFD0A1' }   // 底部颜色(过渡到低危)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '高危',type: 'bar',stack: '总量',data: highData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FF2E2E' },  // 顶部颜色(更鲜艳){ offset: 0.5, color: '#FF5252' }, // 中间颜色{ offset: 1, color: '#FF8A8A' }   // 底部颜色(过渡到中危)]),borderRadius: [2, 2, 0, 0] // 只有最上面的柱子需要圆角},emphasis: {itemStyle: {opacity: 0.9}},z: 10},],backgroundColor: 'transparent'};// 设置图表选项chartInstance.setOption(option);// 监听窗口大小变化自动调整图表大小window.addEventListener('resize', handleResize);};// 更新图表,不销毁实例const updateChart = () => {if (!chartInstance || !chartRef.value) return;// 准备数据const xAxisData = props.warningSevenItem;const highData = props.warningData.high || [];const middleData = props.warningData.middle || [];const lowData = props.warningData.low || [];// 计算总数据用于展示const totalData = highData.map((val: number, index: number) => {return val + (middleData[index] || 0) + (lowData[index] || 0);});// 更新数据快照prevWarningData.value = JSON.stringify(props.warningData);prevWarningSevenItem.value = JSON.stringify(props.warningSevenItem);// 解决方案:创建完整的配置,使用true参数强制重置所有配置// 这将确保tooltip格式化器使用最新数据chartInstance.clear();  // 清除当前图表// 完整重新配置图表const option = {tooltip: {trigger: 'axis',axisPointer: {type: 'shadow'},formatter: function(params: any) {const index = params[0].dataIndex;const date = xAxisData[index];const total = totalData[index] || 0;let result = `${date}<br/>总数: ${total}<br/>`;// 按顺序添加高中低危数据params.forEach((param: any) => {let value = param.value || 0;result += `${param.seriesName}: ${value}<br/>`;});return result;}},legend: {data: ['高危', '中危', '低危'],textStyle: {color: 'rgba(255, 255, 255, 0.65)'},right: '5%',top: '0%'},grid: {left: '5%',right: '5%',bottom: '10%',top: '15%',containLabel: true},xAxis: {type: 'category',data: xAxisData,axisLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.2)'}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,interval: 0,rotate: 0},axisTick: {show: false}},yAxis: {type: 'value',name: '',nameTextStyle: {color: 'rgba(255, 255, 255, 0.65)'},min: 0,axisLine: {show: false},axisTick: {show: false},splitLine: {lineStyle: {color: 'rgba(255, 255, 255, 0.1)',type: 'dashed',width: 0.5}},axisLabel: {color: 'rgba(255, 255, 255, 0.65)',fontSize: 12,formatter: function(value: number) {if (value >= 1000) {return Math.floor(value / 1000) + 'k';}return value;}}},series: [{name: '高危',type: 'bar',stack: '总量',data: highData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FF2E2E' },  // 顶部颜色(更鲜艳){ offset: 0.5, color: '#FF5252' }, // 中间颜色{ offset: 1, color: '#FF8A8A' }   // 底部颜色(过渡到中危)]),borderRadius: [2, 2, 0, 0] // 只有最上面的柱子需要圆角},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '中危',type: 'bar',stack: '总量',data: middleData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#FFA066' },  // 顶部颜色(与高危底部接近){ offset: 0.5, color: '#FFA647' }, // 中间颜色{ offset: 1, color: '#FFD0A1' }   // 底部颜色(过渡到低危)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10},{name: '低危',type: 'bar',stack: '总量',data: lowData,barWidth: '20%',itemStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#70B2F7' },  // 顶部颜色(与中危底部接近){ offset: 0.5, color: '#52A2FF' }, // 中间颜色{ offset: 1, color: '#1970C2' }   // 底部颜色(更深)])},emphasis: {itemStyle: {opacity: 0.9}},z: 10}],backgroundColor: 'transparent'};// 使用完整配置重新初始化图表chartInstance.setOption(option);};// 在组件挂载后初始化图表onMounted(() => {initChart();});// 监听数据变化,仅在数据真正变化时更新图表watch(() => [props.warningData, props.warningSevenItem], ([newWarningData, newWarningSevenItem]) => {const newWarningDataStr = JSON.stringify(newWarningData);const newWarningSevenItemStr = JSON.stringify(newWarningSevenItem);// 检查数据是否有变化const dataChanged = newWarningDataStr !== prevWarningData.value || newWarningSevenItemStr !== prevWarningSevenItem.value;if (dataChanged) {// 如果数据有变化,更新图表if (chartInstance) {updateChart();} else {initChart();}}}, { deep: true });// 组件卸载时清理资源onUnmounted(() => {if (chartInstance) {// 移除resize事件监听window.removeEventListener('resize', handleResize);chartInstance.dispose();chartInstance = null;}});return {chart: chartRef};}
});
</script><style scoped>
.chart-container {width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;
}.chart {width: 100%;height: 100%;min-height: 280px;
}
</style>
http://www.xdnf.cn/news/9177.html

相关文章:

  • C语言基础-初识
  • R包安装报错解决案例系列|R包使用及ARM架构解决data.table安装错误问题
  • WPF【11_5】WPF实战-重构与美化(MVVM 实战)
  • 计算机网络学习20250527
  • pycharm终端遇不显示虚拟环境的问题
  • Windows版本的postgres安装插件http
  • java的vscode扩展插件
  • 【】20250527PDF文件拆分成多个pdf(两页一份,用幼儿班级姓名命名文件)
  • CentOS 7 下 Redis 从 5.0 升级至 7.4.3 全流程实践
  • 基线配置管理:为什么它对网络稳定性至关重要
  • RabbitMQ搭建集群
  • Odoo 财务模块全面深度解读(VIP15万字版)
  • xcode手动安装iOS Simulator Runtime
  • 2.4GHz 射频前端芯片AT2401C
  • 【Elasticsearch】PUT` 请求覆盖式更新
  • GitHub push失败解决办法-fatal: unable to access ‘https://github.com/xxx
  • 【node】Express创建服务器
  • leetcode hot100刷题日记——19.买卖股票的最佳时机
  • `sysctl`命令深度剖析:如何优化内核参数以提升服务器网络/IO性能?
  • 百度ocr的简单封装
  • html5视频播放器和微信小程序如何实现视频的自动播放功能
  • 优雅草最新实战项目技术Discuz X3.5电子签约插件开发项目实施方案优雅草·卓伊凡
  • MicroPython 开发ESP32应用教程 之 线程介绍及实例分析
  • Android 启动优化
  • 使用堡塔和XShell
  • C++ STL stack容器使用详解
  • IoT/HCIP实验-1/物联网开发平台实验Part1(快速入门,MQTT.fx对接IoTDA)
  • 大型三甲医院更换HIS系统全流程分析与经验考察(上)
  • 【教程】给Apache服务器装上轻量级的防DDoS模块
  • 【HarmonyOS Next之旅】DevEco Studio使用指南(二十七) -> 开发云函数