ECharts 高级图表

在四大件之上过一遍进阶系列:玫瑰图、平滑面积线、渐变柱、
涟漪散点、热力图、K 线,以及 dataset、dataZoom、富文本标签三大利器。


1. 进阶系列速览

1.1 pie:roseType 南丁格尔玫瑰图

{
  type: 'pie',
  radius: ['15%', '70%'],        // 内外半径
  roseType: 'area',              // 半径映射数值,形成花瓣
  itemStyle: { borderRadius: 6 },
  label: { show: true, formatter: '{b}: {d}%' },
  data: [
    { value: 420, name: '华东' },
    { value: 350, name: '华南' },
    { value: 280, name: '华北' },
    { value: 190, name: '西南' }
  ]
}

{d} 是百分比占位符;{c} 数值、{b} 名称,
formatter 三剑客记住即可。

1.2 line:areaStyle / smooth / markLine / markPoint

{
  type: 'line',
  smooth: true,                        // 平滑曲线
  areaStyle: {                         // 渐变面积
    opacity: 0.25
  },
  markLine: {
    data: [
      { type: 'average', name: '均值' },            // 自动算均线
      { yAxis: 500, name: '目标线',
        lineStyle: { color: '#e74c3c', type: 'dashed' } }
    ]
  },
  markPoint: {
    data: [
      { type: 'max', name: '峰值' },                // 最大值标注
      { type: 'min', name: '谷值' }
    ]
  },
  data: [320, 450, 280, 520, 410, 600]
}

markLine/markPoint 的 type: average/max/min 是免费的分析能力,
不用自己算。

1.3 bar:graphic 线性渐变

{
  type: 'bar',
  barWidth: '45%',
  itemStyle: {
    borderRadius: [6, 6, 0, 0],
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
      { offset: 0, color: '#36a3f7' },   // 顶部亮色
      { offset: 1, color: '#1e88c7' }    // 底部深色
    ])
  },
  data: [320, 450, 280, 520, 410, 600]
}

LinearGradient 参数是 (x0,y0,x1,y1) 归一化坐标——
(0,0,0,1) 表示垂直向下渐变,横向柱改 (0,0,1,0)

1.4 scatter 与 effectScatter:涟漪地标点

series: [
  {                                       // 普通散点:底层数据
    type: 'scatter',
    symbolSize: d => Math.sqrt(d[2]) * 2,
    data: cities
  },
  {                                       // 涟漪特效:重点城市
    type: 'effectScatter',
    rippleEffect: { scale: 3, brushType: 'stroke' },
    symbolSize: 10,
    data: keyCities
  }
]

effectScatter 常用于地图上强调重点城市,与 geo/map 组件配合使用。

1.5 heatmap:需要 visualMap

{
  type: 'heatmap',
  data: [
    // [x索引, y索引, 值]
    [0, 0, 5], [0, 1, 9], [1, 0, 3], [1, 1, 12]
  ]
},
// visualMap 把数值映射成颜色(热力图必需)
visualMap: {
  min: 0,
  max: 20,
  calculable: true,          // 手柄可拖动过滤
  orient: 'horizontal',
  inRange: { color: ['#50a3ba', '#eac736', '#d94e5d'] }
}

没有 visualMap 时热力图没有颜色语义,这是新手常见遗漏。

1.6 boxplot 与 kline

// 箱线图:[min, Q1, median, Q3, max]
{ type: 'boxplot', data: [[20, 45, 68, 80, 95], [30, 50, 62, 75, 90]] }
 
// K 线:[开盘, 收盘, 最低, 最高]
{ type: 'candlestick', data: [
    [2320, 2400, 2290, 2450],
    [2400, 2380, 2350, 2430],
    [2380, 2510, 2360, 2550]
] }

K 线是金融场景核心,完整实战见本章末尾。


2. dataset:维度式数据源

把”数据”与”系列”解耦,一份 source 喂多个 series:

const option = {
  dataset: {
    dimensions: ['月份', '销量', '利润'],
    source: [
      ['一月', 320, 42],
      ['二月', 450, 58],
      ['三月', 280, 36]
    ]
    // 或者 source 直接是二维数组,首行为维度名
  },
  xAxis: { type: 'category' },
  yAxis: { type: 'value' },
  series: [
    { type: 'bar', encode: { x: '月份', y: '销量' } },
    { type: 'line', encode: { x: '月份', y: '利润' } }
  ]
};

优势:

  • 换数据源只改一处,series 配置不动。
  • encode 用维度名绑定轴,可读性远好于列下标。
  • 接口返回的表格数据几乎可以原样塞进 source。

3. 多系列联动 grid 多图

一个 option 里放多个 grid/xAxis/yAxis,实现上下两块绘图区:

grid: [
  { left: 60, right: 20, top: 40, height: '55%' },     // 主图区
  { left: 60, right: 20, top: '72%', height: '18%' }   // 副图区
],
xAxis: [
  { type: 'category', gridIndex: 0, data: months },
  { type: 'category', gridIndex: 1, data: months }
],
yAxis: [
  { type: 'value', gridIndex: 0 },
  { type: 'value', gridIndex: 1, axisLabel: { show: false } }
],
series: [
  { type: 'line', xAxisIndex: 0, yAxisIndex: 0, data: prices },
  { type: 'bar',  xAxisIndex: 1, yAxisIndex: 1, data: volumes,
    itemStyle: {
      // 成交量按涨跌着色
      color: p => p.value >= p.dataIndex ? '#e74c3c' : '#2ecc71'
    } }
]

这套”主图 + 副图”结构就是 K 线 + 成交量联动的骨架。
副图的缩放同步靠下一节的 dataZoom。


4. dataZoom 缩放:inside + slider

dataZoom: [
  {                                   // 内置型:滚轮/手势直接缩放
    type: 'inside',
    start: 60,                        // 初始窗口起点(百分比)
    end: 100
  },
  {                                   // 滑条型:底部拖动条
    type: 'slider',
    height: 24,
    bottom: 12
  }
]

要点:

  • 多个 dataZoom 同时生效,一个 option 里通常两个都配。
  • 多图联动缩放:给主副图的 dataZoom 设相同 xAxisIndex
    或用 id + dataZoomId 关联,滑动一个另一个自动跟随。
  • 大数据量时配合 sampling: 'lttb'(见下一章交互篇)。

5. 富文本标签 formatter

formatter 支持字符串模板和回调函数两级:

// 字符串模板
label: { formatter: '{b}\n{c} 万元 ({d}%)' }
 
// 回调函数(类型标注齐全)
tooltip: {
  formatter(params) {
    if (Array.isArray(params)) {           // trigger:'axis' 时是数组
      return params.map(p =>
        `${p.marker}${p.seriesName}:${p.value}`
      ).join('<br/>');
    }
    return `${params.name}<br/>数值:${params.value}`;
  }
}

富文本还能在标签里混排多种样式:

yAxis: {
  axisLabel: {
    formatter: v => `{big|${v}}{unit|万}`,
    rich: {
      big:  { fontSize: 14, fontWeight: 'bold', color: '#333' },
      unit: { fontSize: 10, color: '#999',
              padding: [0, 0, 0, 2] }
    }
  }
}

rich 定义命名样式片段,formatter 里用 {name|文本} 引用,
可以做出”大数字 + 小单位”的精致效果。


6. 实战:K 线图 + 成交量副图联动

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<style>
  body { font-family: sans-serif; margin: 0; padding: 24px; background: #10141a; }
  #kline { width: 100%; height: 560px; background: #10141a; }
</style>
</head>
<body>
 
<div id="kline"></div>
 
<script>
  // 模拟 30 天行情数据:[日期, 开, 收, 低, 高, 成交量]
  const raw = Array.from({ length: 30 }, (_, i) => {
    const base = 100 + i * 0.8;
    const open = base + Math.sin(i) * 4;
    const close = base + Math.sin(i + 1) * 5;
    const low = Math.min(open, close) - Math.random() * 3;
    const high = Math.max(open, close) + Math.random() * 3;
    const volume = Math.round(800 + Math.random() * 600);
    return [`D${i + 1}`,
            +open.toFixed(2), +close.toFixed(2),
            +low.toFixed(2), +high.toFixed(2), volume];
  });
 
  const dates = raw.map(r => r[0]);
  const kdata = raw.map(r => r.slice(1, 5));
  const vols = raw.map((r, i) => ({
    value: r[5],
    itemStyle: {
      color: r[2] >= r[1] ? '#ef4444' : '#22c55e'
    }
  }));
 
  const chart = echarts.init(document.getElementById('kline'), 'dark');
 
  chart.setOption({
    backgroundColor: 'transparent',
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'cross' }
    },
    grid: [
      { left: 70, right: 20, top: 30, height: '58%' },
      { left: 70, right: 20, top: '74%', height: '16%' }
    ],
    xAxis: [
      { type: 'category', gridIndex: 0, data: dates, boundaryGap: true },
      { type: 'category', gridIndex: 1, data: dates }
    ],
    yAxis: [
      { scale: true, gridIndex: 0 },                    // scale 不强制含零
      { gridIndex: 1, axisLabel: { show: false },
        splitLine: { show: false } }
    ],
    // 关键:一个 inside 缩放同时控制两个坐标系的 x 轴
    dataZoom: [
      { type: 'inside',
        xAxisIndex: [0, 1],                             // 联动双图
        start: 40, end: 100 },
      { type: 'slider',
        xAxisIndex: [0, 1],
        bottom: 8, height: 20 }
    ],
    series: [
      {
        name: '日 K',
        type: 'candlestick',
        xAxisIndex: 0, yAxisIndex: 0,
        data: kdata,
        itemStyle: {
          color: '#ef4444',          // 阳线
          color0: '#22c55e',         // 阴线
          borderColor: '#ef4444',
          borderColor0: '#22c55e'
        },
        markLine: {
          symbol: 'none',
          data: [{ type: 'average', name: '均价' }]
        }
      },
      {
        name: '成交量',
        type: 'bar',
        xAxisIndex: 1, yAxisIndex: 1,
        data: vols
      }
    ]
  });
 
  window.addEventListener('resize', () => chart.resize());
</script>
 
</body>
</html>

实现要点回顾:

  1. 双 grid 结构:主图 58% 高度放 K 线,副图放成交量。
  2. dataZoom 的 xAxisIndex 写数组 [0,1]:一次缩放同时驱动
    两张图的窗口——这就是”联动”的全部秘密。
  3. 成交量按阴阳着色:收盘大于开盘红、否则绿,
    通过 itemStyle 回调逐柱设置。
  4. yAxis.scale: true:K 线不强制从零开始,放大波动细节。

小结

  • roseType/markLine/markPoint/graphic 渐变都是 series 级一行配置。
  • visualMap 是热力图的”颜色图例”,缺了它热力没有语义。
  • dataset + encode 把数据与系列解耦,接口表格数据可直塞 source。
  • 多 grid 多轴时,series 用 gridIndex/xAxisIndex 挂载到指定绘图区。
  • dataZoom 的 xAxisIndex 写数组即可实现主副图缩放联动。

下一篇处理交互事件、resize 与大数据量优化:
交互与响应式