引言
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: 是否为新增数据。
方法逻辑
- 首先,获取当前数据的长度,即
option.series[0].data数组的长度。 - 调用
setMarkLine方法,将最新的出价数据作为标记线的位置,并决定是否重新渲染图表。 - 根据
isAdd参数的值,判断是新增数据还是更新现有数据。如果是新增数据,则将xAxisItem和seriesItem分别添加到option.xAxis.data和option.series[0].data数组末尾;如果是更新数据,则将seriesItem替换option.series[0].data数组中的最后一个元素。 - 如果页面可见且不处于加载状态,则根据需要进行一些额外的操作。如果是新增数据且当前页数为第一页(即
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 })
}
方法逻辑
- 通过解构赋值,获取
channelObj对象中的formatValue属性。 - 使用
map方法遍历results数组,将每个数据项的时间格式化为指定的格式,并存储在xAxisData数组中。 - 使用
map方法遍历results数组,提取每个数据项的开盘价、收盘价、最低价和最高价,将这些值组成一个数组,并存储在seriesData数组中。 - 调用
resolveData方法,将处理后的xAxisData和seriesData作为参数传递给该方法。
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()
}
方法逻辑
- 将
xAxisData数组中的元素添加到option.xAxis.data数组的开头,实现历史数据的插入。 - 将
seriesData数组中的元素添加到option.series[0].data数组的开头,实现历史数据的插入。 - 如果页面可见且不处于加载状态,则根据当前数据的长度调整数据缩放的位置。如果当前页数为第一页(即
page === 1),则调用changeDataZoomLocation方法调整数据缩放的位置,确保显示最新的数据。否则,使用myChart.dispatchAction方法直接更新数据缩放的位置。 - 最后,使用
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 线图的绘制过程,并在实际项目中得到应用。
参考资料: