需求是展示11个指标数据的折线图,也就是11条折线,但是其实这是3组数据,值域的分布差别有点大,一组数据值域是0到0.1,一组数据的值域达到了10万,如果强行在同一个坐标系,导致数据趋势不能在图表上展示,于是,就有了显示的要求,要求三组数据分组显示,但是要在同一个X轴,也就是Y轴分组。我选择了EChart来实现。
最终实现的思路是 xAxis、yAxis和grid生成三组,xAxis和yAxis引用gridIndex,其中X轴的数据是相同的,grid设置到不同的区域,纵向排布,series设置时把相应的yAxisIndex、xAxisIndex分别设置到对应的区域,还有一个关键的交互,要求在鼠标移动时三个坐标系要同步显示标线并且tooltip展示所有的数据,代码如下
// 过滤掉 fma he sma 为 0 的数据
data = data.filter((item: any) => item['fma'] !== 0 && item['sma'] !== 0)
// 获取日期数组
const dates = data.map((item: any) => dayjs(item.timestamp).utc().format('MM-DD HH:mm:ss'));
// 获取三组数据
const group1 = ['market_price_ask', 'market_price_bid', 'market_price_mid', 'sma', 'fma'];
const group2 = ['most_of_vol', 'realtime_vol'];
const group3 = ['rs', 'rsa', 'rsd', 'rsm'];
const series = [
...group1.map(symbol => ({
name: symbol,
type: 'line',
showSymbol: false,
color: getColor(symbol),
data: data.map((item: any) => item[symbol]),
yAxisIndex: 0,
xAxisIndex: 0,
lineStyle: {
width: 1
},
})),
...group2.map(symbol => ({
name: symbol,
type: 'line',
showSymbol: false,
color: getColor(symbol),
data: data.map((item: any) => item[symbol]),
yAxisIndex: 1,
xAxisIndex: 1,
lineStyle: {
width: 1
},
})),
...group3.map(symbol => ({
name: symbol,
type: 'line',
showSymbol: false,
color: getColor(symbol),
data: data.map((item: any) => item[symbol]),
yAxisIndex: 2,
xAxisIndex: 2,
lineStyle: {
width: 1
},
})),
];
if (data.length > 0) {
chartRef.current?.setOption({
title: {
text: 'Price Analysis',
},
// 核心配置:强制所有坐标系联动
axisPointer: {
type: 'line', // 显示纵向指示线
link: [{ xAxisIndex: [0, 1, 2] }], // 联动所有 x 轴
label: { show: false } // 隐藏默认标签
},
tooltip: {
trigger: 'axis',
// 自定义 Tooltip 内容
formatter: (params: any) => {
const date = params[0].axisValue; // 获取当前时间点
const allValues = data.find((d: any) => dayjs(d.timestamp).utc().format('MM-DD HH:mm:ss') === date); // 找到完整数据
// 按分组组织内容
return `
<div style="padding: 8px 12px;">
<div style="margin-bottom: 8px;font-weight: 500;">${date}</div>
<div style="margin: 8px 0; color: #666;">Market Data:</div>
${['market_price_ask', 'market_price_bid', 'market_price_mid', 'sma', 'fma']
.map(symbol => `
<div style="display: flex; align-items: center; margin: 4px 0;">
<span style="display: inline-block; width: 8px; height: 8px;
background: ${getColor(symbol)}; margin-right: 8px;"></span>
${symbol}: ${allValues[symbol].toFixed(4)}
</div>
`).join('')}
<div style="margin: 8px 0; color: #666;">Volatility:</div>
${['most_of_vol', 'realtime_vol']
.map(symbol => `
<div style="display: flex; align-items: center; margin: 4px 0;">
<span style="display: inline-block; width: 8px; height: 8px;
background: ${getColor(symbol)}; margin-right: 8px;"></span>
${symbol}: ${allValues[symbol].toFixed(4)}
</div>
`).join('')}
<div style="margin: 8px 0; color: #666;">PDS:</div>
${['rs', 'rsa', 'rsd', 'rsm']
.map(symbol => `
<div style="display: flex; align-items: center; margin: 4px 0;">
<span style="display: inline-block; width: 8px; height: 8px;
background: ${getColor(symbol)}; margin-right: 8px;"></span>
${symbol}: ${allValues[symbol].toFixed(4)}
</div>
`).join('')}
</div>
`;
}
},
grid: [
{ // 第一组坐标系
top: '5%',
height: '30%',
left: '10%',
right: '10%'
},
{ // 第二组坐标系
top: '40%',
height: '25%',
left: '10%',
right: '10%'
},
{ // 第三组坐标系
top: '70%',
height: '20%',
left: '10%',
right: '10%'
}
],
legend: {
data: [...group1, ...group2, ...group3],
},
xAxis: [
{ // 主 X 轴(共享)
type: 'category',
data: dates,
gridIndex: 0, // 关联第一个 grid
show: false,
},
{ // 隐藏的副 X 轴(用于对齐)
type: 'category',
gridIndex: 1,
show: false,
data: dates,
axisPointer: { show: true }
},
{ // 隐藏的副 X 轴(用于对齐)
type: 'category',
gridIndex: 2,
axisLabel: { show: true },
data: dates,
axisPointer: { show: true }
}
],
yAxis: [
{
type: 'value',
name: 'Market Data',
position: 'left',
scale: true,
gridIndex: 0,
},
{
type: 'value',
name: 'Volatility',
position: 'left',
scale: true,
gridIndex: 1,
},
{
type: 'value',
name: 'PDS',
position: 'left',
scale: true,
gridIndex: 2,
}
],
series: series,
}, true)
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。