ECharts5 实现掘金数据中心折线图

1,140 阅读5分钟

掘金数据中心上线也有好一阵子了,近来忙里偷闲,试着用 ECharts(5.4版本) 自己实现了如下所示的折线图,在此做个记录与分享。

初识 ECharts

ECharts 全称 Enterprise Charts,意为企业级数据图表,是一个百度团队开源的现在交由 Apache 基金会管理的基于 js 的可视化图表库,它的底层依赖的是 ZRender 图形库。

使用 echarts 制作图表大体分为 3 步:

  1. 定义一个用于展示图表的 DOM 容器,一定要定义高度,宽度可以省略,默认等于父级容器的宽度:
<div id="main" style="height: 400px"></div>
  1. 引入库文件,并通过 echarts.init,传入第 1 步准备好的 DOM 容器,初始化一个 echarts 实例 myChart
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script>
  const myChart = echarts.init(document.getElementById('main'))
</script>

如果想生成深色模式的图表,可以给 init() 传入第 2 个参数 'dark';echarts 默认使用 canvas 绘图,如果想使用 svg 绘图,则需要传入第 3 个参数 { renderer: 'svg' }

const myChart = echarts.init(document.getElementById('main'), 'dark', {
  renderer: 'svg'
})
  1. 通过实例的 setOption 方法传入图表的配置:
myChart.setOption(option)

echarts 上手体验很容易,但它的 option 的配置十分复杂,有诸多的可配置选项,下面将详细介绍如何配置 option 以实现我们想要的的折线图效果。

配置 option

基础配置

我们可以将一个图表内的不同部分看成不同的组件,比如一个折线图有 x 轴,有 y 轴等,而一个配置项就是对一个组件的定义。先看看生成一个基本的折线图,需要哪些配置:

// 代码片段 1
const option = {
  xAxis: {
    data: [
      '23-10-04',
      '23-10-05',
      '23-10-06',
      '23-10-07',
      '23-10-08',
      '23-10-09'
    ]
  },
  yAxis: {},
  series: [
    // 展现数
    {
      type: 'line',
      data: [205, 201, 283, 561, 1098, 1046, 1134]
    },
    // 阅读数
    {
      type: 'line',
      data: [68, 71, 85, 130, 280, 271, 319]
    }
  ]
}
  • xAxis:配置 x 轴。data 用于配置当 x 轴为类目轴时类目的数据,默认就是类目轴,即 xAxis.type = 'category'
  • yAxis:配置 y 轴。看起来我们只是给 yAxis 赋值了一个空对象,但这是必需的,因为其有个默认属性 show,值为 true,表示要显示 y 轴;
  • series:值为一个数组,数组里的每一项最终会映射成一个图形。比如我们想在一个坐标系中生成 2 个折线图,一个用于表示“展现数”,一个用于表示“阅读数”,就给数组添加如代码片段 1 所示的 2 个对象,对象中 type: 'line' 表示是折线图,data 则表示具体数据。

代码片段 1 生成的图表如下: image.png

可以看到初具雏形但与我们的预期效果还有很大差距,接下去我们一步步对各个组件做进一步地配置。

x 轴

对比掘金的内容数据图,发现有几点需要改进:

  1. x 轴轴线应该隐藏;
  2. x 轴中的分隔线不应该显示;
  3. 折线的起点与终点距离 x 轴两端还有一些空间,需要去除;
  4. 刻度标签的样式需要修改,具体为字体颜色要改得淡一些,与 x 轴的距离需要加长,并且第 1 个标签应该左对齐,最后一个标签右对齐,其余的中间对齐:

image.png

通过配置 xAxis 实现修改:

xAxis: {
  axisLine: {
    show: false // 隐藏轴线
  },

  axisTick: {
    show: false // 隐藏分隔线
  },

  boundaryGap: false, // 坐标轴两边不留白

  // 标签文字样式修改
  axisLabel: {
    color: '#9DA5AF',
    margin: 12,
    formatter: (value, index) => {
      if (index === 0) return `{a|${value}}`
      if (index === 6) return `{b|${value}}`
      return value
    },
    rich: {
      a: {
        padding: [0, 0, 0, 40] // 左边距 40
      },
      b: { 
        padding: [0, 40, 0, 0] // 右边距 40
      }
    }
  },
  // ...
},

因为首尾标签的对齐方式和其它标签不同,所以使用 xAxis.axisLabel.formatter 对不同标签做了特殊处理。formatter 的值我这里采用了回调函数的形式,该函数在调用时会传入刻度类目(value)和刻度的索引(index)。{a|${value}} 写法代表的意思是对于 value 值,应用定义于 richa 的样式。注意,这里使用 padding 而不是 align 来修改标签的对齐方式,因为后者会无效,这在 echarts 的 github 的 issues 里有所提及:

image.png

现在效果如下:

image.png

y 轴

目前 y 轴需要修改的有 2 点:

  1. y 坐标轴在坐标系区域中的分隔线样式需要改为虚线;
  2. 标签距离过近:

image.png

通过配置 yAxis 实现修改。对于标签的修改同 x 轴一样,也是修改 axisLabel 属性;对于分隔线的修改则是通过 yAxis.splitLine.lineStyle

yAxis: {
  splitLine: {
    lineStyle: {
      type: 'dashed',
      color: ['#EDEEF1']
    }
  },
  axisLabel: {
    color: '#9DA5AF',
    margin: 20
  }
},

现在折线图如下所示: image.png

折线样式

现在我们通过配置 series 来改变折线的样式,以“展现数”这条折线为例:

series: [
  {
    name: '展现数',
    type: 'line',
    smooth: true, // 平滑
    data: [205, 201, 283, 561, 1098, 1046, 1134],
    itemStyle: {
      color: '#9F54FF' // 改变颜色
    },
    showSymbol: false, // 隐藏标记点
    symbol: 'pin', // 当鼠标悬浮在折线图上出现 tooltip 时,显示的标记类型
    symbolOffset: [0, '75%'], // 标记点的位置
    // 区域填充
    areaStyle: {
      color: {
        type: 'linear', // 线性渐变
        x: 0,
        y: 0,
        x2: 0,
        y2: 1,
        colorStops: [
          {
            offset: 0,
            color: 'rgba(173,102,255,0.1)' // 0% 处的颜色
          },
          {
            offset: 1,
            color: 'rgba(173,102,255,0.01)' // 100% 处的颜色
          }
        ]
      }
    }
  },
]
  • name 属性在 tooltip 组件中会使用到;
  • 通过 smooth: true 让折线的线条变得平滑;
  • 通过 itemStyle.color 让线条以及标记点呈现指定的颜色;
  • 让线条的下部分区域有渐变填充效果则是通过 areaStyle.color 属性,x: 0, y: 0, x2: 0, y2: 1 表明线性渐变的方向是从上到下;

“阅读数”折线也经过对应调整后,折线图样式如下: image.png

提示工具

现在我们通过配置 tooltip 来实现下图所示鼠标悬浮于图表时显示的提示工具:

image.png

tooltip.trigger 设置为 'axis' 表明触发显示提示工具的条件是坐标轴:

tooltip: {
  trigger: 'axis',
}

这样展示的提示组件内部的默认样式,与预期效果稍有不同:

  1. 日期的字体没有加粗;
  2. “展现数”,“阅读数”后面没有冒号;
  3. 数量值字体不需要为粗体;
  4. 每行文字间的间隔比较小:

image.png

所以还需要使用 tooltip.formatter 对提示框浮层内容进行样式修改:

tooltip: {
  // ...
  formatter: params => {
    const title = `<div style="font-weight: bold; margin-bottom: 10px">${params[0].axisValue}</div>`
    let content = ''
    params.forEach(item => {
      content += `
        <div style="margin-bottom: 6px">
          <span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${item.color}"></span>
          <span>${item.seriesName}${item.value}</span>
        </div>
      `
    })
    return title + content
  }
}

formatter 的值使用回调函数,该回调的类型如下,从 params 中可以获取到需要的数据,返回值可以直接是 HTMLElement :

image.png

图例

接着我们来添加图例:

image.png

通过 legend 配置:

legend: {
  bottom: 0,
  itemGap: 30,
  itemWidth: 20,
  icon: 'path://M431.36 652.16L261.76 482.56a48 48 0 1 0-67.84 67.904l203.584 203.648a48 48 0 0 0 71.232-3.648l381.184-381.184a48 48 0 1 0-67.904-67.84l-350.72 350.72zM128 0h768a128 128 0 0 1 128 128v768a128 128 0 0 1-128 128H128a128 128 0 0 1-128-128V128a128 128 0 0 1 128-128z'
}
  • bottom: 0 让图例位于图表的下方,默认会在图表的上方;
  • itemGap 设置图例每项之间的间隔;
  • itemWidth 的设置是为了调整图例的 icon 和文字的间距;
  • icon 用于设置图例中的图标,ECharts 提供的类型只有圆或矩形等,想用自定义图标,我通过使用 'path://路径' 的方式设置,路径则是阿里图标库的“复制 SVG 代码”得到的:

image.png

绘制网格

最后我们来调整下绘制网格的配置,改变 grid 组件离容器左右两侧的距离:

grid: {
  left: '5%',
  right: '1%'
},

至于网格的概念,可参见介绍 canvas 的文章。

响应式

如果想让图表可以根据浏览器窗口的调整自动调整,可以添加个监听窗口缩放的事件,一旦事件触发则执行 resize 方法(为避免频繁触发,我使用了 lodash 的 _.throttle 进行了节流):

const resize = _.throttle(() => {
  myChart.resize()
}, 1000)
window.addEventListener('resize', resize)

感谢.gif 点赞.png