Echarts在h5画实时k线,支持左滑加载更多以及实时填充蜡烛

1,428 阅读6分钟

引言

K 线图是一种常用的股票市场数据可视化方式,通过绘制开盘价、最高价、最低价和收盘价等数据,可以直观地展示股票价格的波动情况。在本文中,我们将详细分析使用 ECharts 库绘制实时 K 线图的相关 JavaScript 方法以及对数据的处理过程。

Echarts 版本为 5.4.2。

ECharts 配置

我们定义了一个配置对象 option,其中包含了图表的各种配置项,如动画、提示框、网格、坐标轴、数据缩放和系列等。通过调用 setOption 方法,将配置应用到图表实例上。

const chartEl = document.getElementById('chart-container')
const myChart = echarts.init(chartEl, null, {
    renderer: 'canvas',
    useDirtyRect: false
})
const barCount = 40 // 每页柱子的个数
const upColor = '#24B267'
const upBorderColor = '#24B267'
const downColor = '#FC6767'
const downBorderColor = '#FC6767'
const option = {
    animation: false,
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'cross',
        label: {
          formatter: ({ value }) => toThousands(value, 2)
        }
      },
      confine: true,
      valueFormatter: (value) => {
        if (typeof value === 'object') return value
        return toThousands(value, 2)
      }
    },
    grid: {
      show: false,
      containLabel: true,
      top: '2%',
      left: 10,
      right: '6%',
      bottom: '2%'
    },
    xAxis: {
      type: 'category',
      data: [],
      axisLine: { onZero: false },
      splitLine: {
        show: true,
        lineStyle: {
          color: '#E5E5E5',
          type: 'dashed'
        }
      },
      axisLabel: {
        color: '#666666',
        fontSize: 10
      },
    },
    yAxis: {
      scale: true,
      axisLine: { onZero: false },
      position: 'right',
      splitLine: {
        lineStyle: {
          color: '#E5E5E5',
          type: 'dashed'
        }
      },
      axisLabel: {
        color: '#666666',
        fontSize: 10,
        verticalAlign: 'middle',
        backgroundColor: '#fff',
        formatter: (value) => toThousands(value, 2)
      }
    },
    dataZoom: [
      {
        type: 'inside',
        zoomLock: false,
        start: 0,
        end: 100,
        maxValueSpan: barCount
      },
    ],
    series: [
      {
        name: '当前价格',
        type: 'candlestick',
        data: [],
        itemStyle: {
          color: upColor,
          color0: downColor,
          borderColor: upBorderColor,
          borderColor0: downBorderColor
        },
        markLine: {
          symbol: ['none', 'none'],
          label: {
            position: 'end',
            color: '#fff',
            backgroundColor: '#CC9B52',
            fontSize: 10,
            padding: [4, 6],
            borderRadius: 2,
            formatter: ({ value }) => toThousands(value, 2)
          },
          lineStyle: {
            color: '#CC9B52'
          },
          data: [
            {
              yAxis: ''
            }
          ]
        }
      }
    ]
}

Echarts 事件的监听

1.1. dataZoom 和数据区间的变化

在下述代码中,我们可以看到 dataZoom 是用于控制数据区间和缩放的关键属性之一。通过监听数据区间变化事件,我们可以根据变化的起始和结束位置调用 changeDataZoomLocation 方法来更新数据缩放区域的位置。

myChart.on('datazoom', (params) => {
    const start = params.start || params.batch[0].start
    const end = params.end || params.batch[0].end
    // 更新数据缩放区域的位置 左滑加载数据后固定当前位置
    changeDataZoomLocation(start, end)
    if (start === 0) {
      // 加载数据
      ...
    }
    // 500ms 之后隐藏tooltip
    debounce(hideToolTip, 500)()
})

const changeDataZoomLocation = (start, end) => {
    option.dataZoom.forEach(item => {
      item.start = start
      item.end = end
    })
}

1.2. Tooltip 和标记线的设置

我们调用 hideToolTip 方法来隐藏 tooltip 并更新指示线的位置。

const hideToolTip = () => {
    myChart.dispatchAction({
      type: 'hideTip'
    })
    myChart.dispatchAction({
      type: 'updateAxisPointer',
      currTrigger: 'leave',
    })
}

数据的处理

在实时K线图的开发中,数据的处理和更新是非常关键的部分。

// 变量的声明
const isIos = isIOS()
let loading = true
let page = 0 // 页数
let isPageVisible = true // 页面是否可见,跳转到二级页面调用setOption返回会导致页面重绘

2.1. resolveLastData 方法

resolveLastData方法用于处理最新的数据,并更新实时K线图的显示。以下是该方法的代码实现:

const resolveLastData = ({
    bid,
    seriesItem,
    xAxisItem,
    isAdd
}) => {
    const dataLength = option.series[0].data.length
    setMarkLine(bid, false)
    if (isAdd) {
      option.xAxis.data.push(xAxisItem)
      option.series[0].data.push(seriesItem)
    } else {
      option.series[0].data[dataLength - 1] = seriesItem
    }
    if (isPageVisible && !loading) {
      if (isAdd && page === 1) {
        const barWidth = 100 / option.xAxis.data.length
        const end = 100
        const start = end - barWidth * barCount
        changeDataZoomLocation(start, end)
      }
      isAdd && hideToolTip()
      myChart.setOption(option)
    }
}

const setMarkLine = (bid, isRender = false) => {
    option.series[0].markLine.data[0].yAxis = bid
    isRender && myChart.setOption(option)
}

方法参数

  • bid: 最新的出价数据。
  • seriesItem: 要更新的系列数据。
  • xAxisItem: 要更新的X轴数据。
  • isAdd: 是否为新增数据。

方法逻辑

  1. 首先,获取当前数据的长度,即option.series[0].data数组的长度。
  2. 调用 setMarkLine 方法,将最新的出价数据作为标记线的位置,并决定是否重新渲染图表。
  3. 根据 isAdd 参数的值,判断是新增数据还是更新现有数据。如果是新增数据,则将 xAxisItemseriesItem 分别添加到 option.xAxis.dataoption.series[0].data 数组末尾;如果是更新数据,则将 seriesItem 替换 option.series[0].data 数组中的最后一个元素。
  4. 如果页面可见且不处于加载状态,则根据需要进行一些额外的操作。如果是新增数据且当前页数为第一页(即 page === 1),则根据当前数据的长度调整数据缩放的位置,确保显示最新的数据。然后调用 hideToolTip 方法隐藏提示框。最后,使用 myChart.setOption 方法更新图表的配置。

总结起来,resolveLastData 方法主要负责将最新的数据添加到图表的数据数组中,并根据需要进行一些额外的操作,以确保实时K线图的显示始终保持最新和合理的状态。

2.2 handleHistoryData 方法

const handleHistoryData = (results) => {
  const { formatValue } = channelObj
  const xAxisData = results.map(item => {
    return dayjs(item.time * 1000).format(formatValue)
  })
  const seriesData = results.map(item => [
    item.open,
    item.close,
    item.low,
    item.high
  ])

  resolveData({ xAxisData, seriesData })
}

方法逻辑

  1. 通过解构赋值,获取 channelObj 对象中的 formatValue 属性。
  2. 使用 map 方法遍历 results 数组,将每个数据项的时间格式化为指定的格式,并存储在 xAxisData 数组中。
  3. 使用 map 方法遍历 results 数组,提取每个数据项的开盘价、收盘价、最低价和最高价,将这些值组成一个数组,并存储在 seriesData 数组中。
  4. 调用 resolveData 方法,将处理后的 xAxisDataseriesData 作为参数传递给该方法。

2.3. resolveData 方法

resolveData 方法用于处理历史数据的更新,将历史数据添加到图表的数据数组中,并根据需要进行数据缩放的调整。以下是该方法的代码实现:

const resolveData = ({ xAxisData, seriesData }) => {
    loading = true
    page++
    option.xAxis.data.unshift(...xAxisData)
    option.series[0].data.unshift(...seriesData)
    const { length: zoomLength } = option.xAxis.data
    const barWidth = 100 / zoomLength
    const end = page === 1 ? 100 : 100 - (zoomLength - xAxisData.length) * barWidth
    const start = end - barWidth * barCount
    changeDataZoomLocation(start, end)
    isPageVisible && myChart.setOption(option)
    loading = false
}

const resetData = () => {
    loading = true
    page = 0
    option.xAxis.data = []
    option.series[0].data = []
    hideToolTip()
}

方法逻辑

  1. xAxisData 数组中的元素添加到 option.xAxis.data 数组的开头,实现历史数据的插入。
  2. seriesData 数组中的元素添加到 option.series[0].data 数组的开头,实现历史数据的插入。
  3. 如果页面可见且不处于加载状态,则根据当前数据的长度调整数据缩放的位置。如果当前页数为第一页(即 page === 1),则调用 changeDataZoomLocation 方法调整数据缩放的位置,确保显示最新的数据。否则,使用 myChart.dispatchAction 方法直接更新数据缩放的位置。
  4. 最后,使用 myChart.setOption 方法更新图表的配置。

页面可见性和恢复方法

在代码中,我们使用 document.visibilitychange 事件来监听页面的可见性变化。通过判断页面是否可见,我们能够在用户切换到其他页面或锁屏时暂停一些操作,并在用户切回页面时恢复相应的操作。
因为安卓退出后台会暂停 js 的运行,所以需要增加定时器。

// 退出后台或者锁屏后
let timerVisible = null
document.addEventListener("visibilitychange", () => {
    isPageVisible = document.visibilityState === 'visible'
    if (isIos) return

    if (isPageVisible) {
      clearInterval(timerVisible)
    } else {
      timerVisible = setInterval(resume, 2000)
    }
})
function resume() {
    isPageVisible = document.visibilityState === 'visible'
}

结论

通过上述介绍,我们详细分析了使用 ECharts 绘制实时 K 线图的相关 JavaScript 方法以及对数据的处理过程。了解了 ECharts 的初始化和配置过程,以及处理最新数据和历史数据的方法。同时,还提供了重置数据的方法,以便重新加载数据时使用。

通过灵活运用这些方法,我们能够实现实时 K 线图的绘制和数据更新,展示股票价格的变动趋势。希望能够帮助读者深入理解实时 K 线图的绘制过程,并在实际项目中得到应用。

参考资料: