#ECharts #数据可视化 #前端干货 #需求拆解 #线性渐变
0. 开场 3 连问
- 为什么 Tool 分组要单独一条轴?
答:一条轴上混排了几十种 Tool,用户想一眼看出"哪一段属于哪把 Tool"。 - 为什么非要"渐变色"而不是直接写死颜色?
答:Tool 顺序、数量、颜色全由后端返回,写死就 GG。 - 为什么要在彩虹轴上叠加 dataZoom?
答:彩虹轴 = 导航条,拖动它≈拖动地图的"缩略图",体验才丝滑。
一句话总结:
把"Tool 名"→"颜色"→"渐变"→"可拖动"全自动化,让用户 0 配置就能彩虹导航。
1. 先改数据结构,让"颜色"和"数据"同频共振
老结构的问题:
js
xAxis: ['T1', 'T2', 'T3' ...] // 只存名字
series: [{name: 'T1', data: [...]}, ...] // 颜色靠索引去 externalColors 里硬匹配
新结构(加 2 个字段即可):
js
sitexAxis: ['T1', 'T1', 'T2', 'T3', 'T3', 'T3'] // 每个数据点对应的真实 Tool
colors: ['#FF6B6B','#FF6B6B','#4ECDC4','#45B7D1','#45B7D1','#45B7D1'] // 一一对应
生成逻辑 3 行代码:
js
const colors = [...new Set(sitexAxis)].map(code => {
const idx = filterSites.findIndex(f => f.value === code);
return idx >= 0 ? externalColors[idx] : '#ccc';
});
好处
- 后端顺序随意变,前端不崩。
- 颜色数组直接丢给
makeAxisColor做渐变,无需二次查找。
2. 彩虹轴 = 线性渐变 + 分段色标
ECharts 的 axisLine.lineStyle.color 只认相对位置的色标,格式:
js
new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{offset: 0, color: '#FF6B6B'},
{offset: 0.3, color: '#FF6B6B'},
{offset: 0.3, color: '#4ECDC4'},
{offset: 0.5, color: '#4ECDC4'},
...
])
算法一句话:
"相同 Tool 连续段" = 一个色块,头尾各插 2 个色标,offset = 索引 / 总长。
代码 20 行不到:
js
function makeAxisColor(data, externalColors) {
const total = data.length;
const colorMap = new Map();
let colorIdx = 0;
const stops = [];
let startIdx = 0;
while (startIdx < total) {
const value = data[startIdx];
if (!colorMap.has(value)) {
colorMap.set(value, externalColors[colorIdx++ % externalColors.length]);
}
const color = colorMap.get(value);
const endIdx = data.findIndex((v, i) => i > startIdx && v !== value);
const realEnd = endIdx === -1 ? total : endIdx;
stops.push({ offset: startIdx / total, color });
stops.push({ offset: realEnd / total, color });
startIdx = realEnd;
}
return new echarts.graphic.LinearGradient(0, 0, 1, 0, stops);
}
自测技巧
console.log(stops) 可以看到每段颜色起止,copy 到 colorgradient.dev 一眼验证对不对。
3. 叠加 dataZoom 的 2 个坑
坑 1:彩虹轴是第三条 xAxis ,xAxisIndex 必须对应。
js
dataZoom: [
{
type: 'slider',
xAxisIndex: [0, 1], // 主轴 + 占位轴
...
},
{
type: 'inside',
xAxisIndex: [0, 1],
...
}
]
坑 2:彩虹轴本身不要响应拖动,把它当"导航条"而非"控制条"。
解决:
- 彩虹轴
axisLabel.interval = 0强制全显, - dataZoom 的
xAxisIndex不包含彩虹轴索引(这里是 2), - 这样拖动时彩虹轴不会被裁剪,仅作视觉参考。
4. 最终 10 行伪代码,把 3 步串成 pipeline
js
// 1. 生成 sitexAxis & colors
const sitexAxis = [];
const colors = [...new Set(sitexAxis)].map(...);
// 2. 生成渐变
const axisColor = makeAxisColor(sitexAxis, colors);
// 3. 配置第三条轴 + dataZoom
const chartOptions = {
xAxis: [
{ type: 'category', data: mainX }, // 主轴
{ type: 'category', data: mainX, show: false }, // 占位
{ type: 'category', data: sitexAxis, position: 'bottom', offset: 40,
axisLine: { lineStyle: { color: axisColor, width: 16 } },
axisLabel: { interval: 0, color: '#fff', fontWeight: 600,
formatter: (v, i) => i === 0 || sitexAxis[i] !== sitexAxis[i-1] ? v : '' }
}
],
dataZoom: [
{ type: 'slider', xAxisIndex: [0, 1], bottom: 23, brushSelect: false },
{ type: 'inside', xAxisIndex: [0, 1] }
]
};
5. 上线效果
- 20 把 Tool,彩虹导航条 1 秒生成。
- 拖动底部 zoom,彩虹段实时跟随,0 额外配置。
- 测试小姐姐说"像网易云的歌词渐变条,好酷"。
6. 小结口诀
"数据先对齐,颜色再映射,渐变算断点,zoom 别绑错。"
背下来,下次再遇到"彩虹轴 + 可拖动"需求,直接复制粘贴,提前下班去撸串。
(完)
