进步一点是一点,做报表大多都使用
echarts
,很多时候并不是简简单单的的做一个折线图、柱状图就可以的,需要一些特别的处理,如下图,需要对每个柱状图添加一个标准线,比如每天最低销售额等。费了老大劲了,查了很多资料,最后结合echarts
的瀑布图实现,对于 baseline ,可以使用两个柱状叠加在一起,底下柱状颜色设置透明,上面柱子设置高度为 0.1 即可形成一条线。
series
配置数据系列的样式和行为,例如名称、类型、数据、柱状图宽度、标签样式等。其中,该对象包含了三个数据系列,分别是销售额(Sale)、基准线(baseLine)和基准线的横线(baseLine1)。z:1
(Sale)、z:2
(baseLine/baseLine1),之所以这样设置,就是为了防止Sale高亮时遮挡住baseLine1的标准线。getEchartsInstance
方法获取了图表实例,监听了图例的 legendselectchanged
事件,并在事件处理函数中使用 setOption
方法重新设置了另一个图表的 legend
以隐藏或显示对应的图例,因为 baseLine 是透明的,不做处理的话,就会出现当图例全都隐藏时,图表还会有莫名的坐标。import React, { useRef, useEffect, useState } from "react";
import * as echarts from "echarts";
import ReactECharts from "echarts-for-react";
function BarChartBaseLine() {
const chartRef = useRef(null);
const [echartsOptions, setEchartsOptions] = useState({});
useEffect(() => {
getInfo();
// 通过 getEchartsInstance 方法获取了图表实例
const chart = chartRef.current.getEchartsInstance();
// 监听了图例的 legendselectchanged 事件,
// 并在事件处理函数中使用 setOption 方法重新设置了另一个图表的 legend 以隐藏或显示对应的图例
chart.on("legendselectchanged", handleLegendSelectChanged);
return () => {
if (chart) {
chart.off("legendselectchanged", handleLegendSelectChanged);
}
};
}, []);
const handleLegendSelectChanged = (params) => {
const chart = chartRef.current.getEchartsInstance();
if (params.name === "baseLine") {
if (!params.selected.baseLine) {
chart.setOption({
legend: {
selected: {
baseLine1: false,
},
},
});
} else {
chart.setOption({
legend: {
selected: {
baseLine1: true,
},
},
});
}
}
};
const getInfo = () => {
initEcharts();
};
const initEcharts = () => {
let dataList = [
{
value: Math.floor(Math.random() * 90 + 10),
name: "Mon",
base: Math.floor(Math.random() * 80 + 10),
},
{
value: Math.floor(Math.random() * 90 + 10),
name: "Tue",
base: Math.floor(Math.random() * 80 + 10),
},
{
value: Math.floor(Math.random() * 90 + 10),
name: "Web",
base: Math.floor(Math.random() * 80 + 10),
},
{
value: Math.floor(Math.random() * 90 + 10),
name: "Thu",
base: Math.floor(Math.random() * 80 + 10),
},
{
value: Math.floor(Math.random() * 90 + 10),
name: "Fri",
base: Math.floor(Math.random() * 80 + 10),
},
{
value: Math.floor(Math.random() * 90 + 10),
name: "Sat",
base: Math.floor(Math.random() * 80 + 10),
},
{
value: Math.floor(Math.random() * 90 + 10),
name: "Sun",
base: Math.floor(Math.random() * 80 + 10),
},
];
let option = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
axis: "y",
Z: 10,
},
formatter: function (params) {
var relVal = '' + params[0].name + "";
params.forEach((item) => {
// 不显示baseLine1 tooltip
if (item.seriesName !== "baseLine1") {
relVal +=
'
' +
item.seriesName +
': ' +
item.value +
"";
}
});
return relVal;
},
backgroundColor: "#fff",
padding: [5, 10],
},
legend: {
data: [
{
name: "Sale",
icon: "image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAvCAIAAAD7B9ruAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAAEXRFWHRTb2Z0d2FyZQBTbmlwYXN0ZV0Xzt0AAAGeSURBVGiB7Zohb4NAGEA/mrXNsqQJommWjJmmas0EZmSpRsAPQCGxVcXPtwqLRPEDQKArmEEsTFWyZMkqkEvbJczeAc3EuCM97slPwHsJXEj4hKIooEv02hagDQ+ucjiQ12iGw8/fqlf149MJogiiCLZbyDLY7xsREuDMefEiNHL98c1YGkmL+4U6VdWp2u/1axxqDq0sg80GHKcRCexmhINRlk/L1fNKGkmleeWRTlOwbRK1lHFeHTuy06+0NK8Euy74PiUpwvjvvpu4pSEeHATgefSMyOO9ecEuQCd4cBhCnlM1Ikz+nYe7EJ0gwccjxDFtI/LEH1gUElwUkCS0dciTfGJRSPBwSNulDfinJevwYNbhwazDg1mHB7MOD2YdHsw6PJh1eDDr8GDW4cGs0+Xgy/nx/R+QYEEAWW7PhBTyLRaFBA8GoCi0dcij3GFR+DusaSCKVHUII16L2kxDJ3iwroNpUjUijPlo6jMdnVROacsCw6BnRBLjwbBkqzSsbPHM57Bew2Ry6Wse55Za6rZ4oGtrS0zT5S+tbvALPvJySV+miIUAAAAASUVORK5CYII=",
},
{
name: "baseLine",
icon: "image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGIAAAA5CAIAAABCjmltAAAACXBIWXMAAB2HAAAdhwGP5fFlAAAAEXRFWHRTb2Z0d2FyZQBTbmlwYXN0ZV0Xzt0AAACaSURBVHic7drBCcAwDACxpHT/lZ0Rer8SkCYwh3/2npnFl+fvAe4gUyJTIlMiUyJTIlMiUyJTIlMiUyJTIlMiUyJTIlMiUyJTIlMiUyJTIlMiUyJTIlOy3XwL25TIlMiUyJS8y+NOYJsSmRKZEpkSmRKZEpkSmRKZEpkSmRKZEpkSmRKZEpkSmRKZEpkSmRKZEpkSmRKZEpmSA40hBm2PYOIHAAAAAElFTkSuQmCC",
itemStyle: {
color: "red",
},
},
],
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: {
type: "value",
boundaryGap: [0, 0.01],
},
yAxis: [
{
type: "category",
data: dataList.map((item) => item.name),
},
{
type: "category",
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
axisPointer: {
type: "none",
},
splitArea: {
show: false,
},
splitLine: {
show: false,
},
data: dataList.map((item) => item.name),
},
],
series: [
{
name: "Sale",
type: "bar",
// z 属性来调整柱状图的层级
z: 1,
data: dataList.map((item) => {
let cor = "blue";
if (item.value < item.base) {
cor = "red";
} else if (item.value > item.base) {
cor = "green";
} else {
cor = "blue";
}
return {
...item,
itemStyle: {
normal: {
color: cor,
},
},
};
}),
barWidth: 20,
},
// 设置透明,主要是为了占位
{
name: "baseLine",
stack: "baseLineGroup" /*数据组,需要设置才能将两个bar堆积在一起*/,
type: "bar",
// z 属性来调整柱状图的层级,防止 name: "Sale"高量时baseline被遮盖
z: 2,
yAxisIndex: 1,
barWidth: 30,
itemStyle: {
normal: {
color: "transparent" /*设置bar为隐藏,撑起下面横线*/,
},
},
data: dataList.map((item) => item.base),
},
{
/*这个bar是横线的显示*/
name: "baseLine1",
stack: "baseLineGroup" /*数据组,需要设置才能将两个bar堆积在一起*/,
type: "bar",
// z 属性来调整柱状图的层级,防止 name: "Sale"高量时baseline被遮盖
z: 2,
yAxisIndex: 1,
barWidth: 30,
itemStyle: {
normal: {
borderColor: "red",
borderWidth: 1,
borderType: "dotted",
color: "red",
},
},
data: Array(dataList.length).fill(0.1),
},
],
};
setEchartsOptions(option);
};
return (
<>
<ReactECharts
ref={chartRef}
option={echartsOptions}
style={{ height: "400px", width: "100%" }}
echarts={echarts}
/>
</>
);
}
export default BarChartBaseLine;