ECharts K 线图
看过股市的朋友们对 K线图 这个图形肯定都不陌生。K线又称“阴阳烛”、“蜡烛线”,是反映价格走势的一种图线,其特色在于线段内记录了多项讯息,相当易读易懂且实用有效,广泛用于股票、期货、贵金属、数字货币等行情的技术分析,称为K线分析。
解释
K 线图又称蜡烛图,最初起源于日本德川幕府时期,被用于记录米市的行情与价格波动,后被引入股票与证券交易市场,现如今已经在金融交易活动中大范围使用。K 线图在形态上很像柱状图与折线图的组合,但每个数据节点能够表达出更多的信息。在股票交易中,k 线图通常包含四个维度,即开盘价、收盘价、最高价、最低价的涨跌变化状况,典型的 k 线图如下图所示:
包含三个部分:
K 线图在 ECharts 中通过 series.type = k
或 series.type = candlestick
配置,示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
< charset="utf-8" />
< http-equiv="X-UA-Compatible" content="IE=edge" />
< name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Echarts Example</title>
</head>
<body>
<div id="main" style="width: px;height: px"></div>
<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
<script type="text/javascript">
const myChart = echarts.init(document.getElementById('main'));
const option = {
tool@R_229_2@: { feature: { saveAsImage: {} } },
xAxis: { type: 'category', data: ['2017-10-24', '2017-10-25', '2017-10-26', '2017-10-27'] },
yAxis: { type: 'value' },
series: [
{
data: [
// 开盘价、收盘价、最高价、最低价
[, , , ],
[, , , ],
[, , , ],
[, , , ],
],
type: 'k',
},
],
};
myChart.setOption(option);
</script>
</body>
</html>
@H_249_@
示例:
k 线图是一种基于直角坐标系的图表,可以通过 xAxis
、yAxis
、grid
项声明坐标系。
k 线图的 series.data
项是长度为 4 的数组,按次序分别对应 k 线图的开盘价、收盘价、最高价、最低价。
K 线图通过实体颜色表达数据涨、跌,不同国家或地区对于 K 线图的颜色定义不一样,可能是红涨绿跌或红涨蓝跌(如台湾、日本、韩国等),可能是绿涨红跌(如西方国家、香港、新加坡等),也可能是有色/无色等表示。认配置项是红涨蓝跌,可通过如下配置项更改:
下例通过 itemStyle
, k 线图的颜色:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
< charset="utf-8" />
< http-equiv="X-UA-Compatible" content="IE=edge" />
< name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Echarts Example</title>
</head>
<body>
<div id="main" style="width: px;height: px"></div>
<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
<script type="text/javascript">
const myChart = echarts.init(document.getElementById('main'));
const option = {
tool@R_229_2@: { feature: { saveAsImage: {} } },
xAxis: { type: 'category', data: ['2017-10-24', '2017-10-25', '2017-10-26', '2017-10-27'] },
yAxis: { type: 'value' },
series: [
{
data: [
// 开盘价、收盘价、最高价、最低价
[, , , ],
[, , , ],
[, , , ],
[, , , ],
],
itemStyle: {
color: '#d87c7c',
color0: '#919e8b',
borderColor: '#d87c7c',
borderColor0: '#919e8b',
},
type: 'k',
},
],
};
myChart.setOption(option);
</script>
</body>
</html>
@H_249_@
示例:
与柱状图、折线图等其他直角坐标图表不同,在坐标系中无论存在多少个 k 线图,认都会被处理为红涨蓝跌,此时必须通过 itemStyle
阴阳线的色值,详见下一节。
由于 k 线图的数据项只能通过这种 4 位数组的格式定义,这会导致 k 线图与折线图、柱状图、散点图等其他直角坐标图表有些许不同:
当序列上只有 k 线图时,问题不大,但若要在同一坐标系上渲染多个 k 线图时,则需要对数据做一些额外的处理。比如,假设要展示下述四种蔬果的价格变化:
[
{
sku: '小台农芒果',
data: [
['2020-3-4', , , , ],
['2020-3-6', , , , ],
['2020-3-9', , , , ],
['2020-3-12', , , , ],
['2020-3-14', , , , ],
['2020-3-16', , , , ],
['2020-3-19', , , , ],
['2020-3-21', , , , ],
['2020-3-23', , , , ],
['2020-3-25', , , , ],
],
},
{
sku: '阿克苏苹果',
data: [
['2020-3-3', , , , ],
['2020-3-6', , , , ],
['2020-3-8', , , , ],
['2020-3-9', , , , ],
['2020-3-10', , , , ],
['2020-3-11', , , , ],
['2020-3-12', , , , ],
['2020-3-15', , , , ],
['2020-3-17', , , , ],
['2020-3-19', , , , ],
],
},
{
sku: '海南西州蜜瓜',
data: [
['2020-3-1', , , , ],
['2020-3-2', , , , ],
['2020-3-4', , , , ],
['2020-3-7', , , , ],
['2020-3-9', , , , ],
['2020-3-12', , , , ],
['2020-3-14', , , , ],
['2020-3-17', , , , ],
['2020-3-19', , , , ],
['2020-3-21', , , , ],
],
},
{
sku: '泰国椰青',
data: [
['2020-3-2', , , , ],
['2020-3-3', , , , ],
['2020-3-4', , , , ],
['2020-3-6', , , , ],
['2020-3-7', , , , ],
['2020-3-9', , , , ],
['2020-3-11', , , , ],
['2020-3-13', , , , ],
['2020-3-16', , , , ],
['2020-3-18', , , , ],
],
},
];
@H_249_@
注意,四个系列的时间不同,由于 k 线图无法推算类目轴的类别数据,所以第一步需要收集所有类目值:
function retriveDates(series) {
const categories = [];
const len = series.length;
for (let i = ; i < len; i++) {
// 找出尚未收集的时间值
const dates = series[i].data
.map(([date]) => date)
.filter((date) => categories.findIndex((cat) => cat === date) < );
// 批量插入
categories.splice(categories.length, , ...dates);
}
return categories;
}
@H_249_@
第二步,需要根据应用场景对收集到的类目值进行排序,本例中为简便起见,将借助 库进行时间排序:
function sort(categories) {
const format = 'YYYY-MM-DD';
return categories.sort((d1, d2) => moment(d1, format) - moment(d2, format));
}
@H_249_@
第三步,有了类目数据之后,还需要整理系列数据的顺序,使得数据与其对应的类目能够一一对应:
function reschedule(series, categories) {
return series.map(({ sku, data }) => {
return {
name: sku,
data: categories.map((cat) => {
const index = data.findIndex((c) => c === cat);
return index >= ? data[index].slice() : null;
}),
};
});
}
@H_249_@
经过上述步骤就可以得到所有类目值及调整后的系列数据,完整:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
< charset="utf-8" />
< http-equiv="X-UA-Compatible" content="IE=edge" />
< name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Echarts Example</title>
</head>
<body>
<div id="main" style="width: px;height: px"></div>
<script src="//cdn.bootcss.com/axios/0.19.2/axios.min.js"></script>
<script src="//cdn.bootcss.com/moment.js/2.24.0/moment.min.js"></script>
<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
<script type="text/javascript">
// 解析系列中的类目数据
function retriveDates(series) {
const categories = [];
const len = series.length;
for (let i = ; i < len; i++) {
// 找出尚未收集的时间值
const dates = series[i].data
.map(([date]) => date)
.filter((date) => categories.findIndex((cat) => cat === date) < );
// 批量插入
categories.splice(categories.length, , ...dates);
}
return categories;
}
// 借助 moment.js 为时间值排序
function sort(categories) {
const format = 'YYYY-MM-DD';
return categories.sort((d1, d2) => moment(d1, format) - moment(d2, format));
}
// 根据类目序列,调整系列数值的位置
function reschedule(series, categories) {
return series.map(({ sku, data }, index) => {
return {
name: sku,
type: 'k',
data: categories.map((cat) => {
const index = data.findIndex(([c]) => c === cat);
return index >= ? data[index].slice() : [];
}),
};
});
}
async function run() {
const myChart = echarts.init(document.getElementById('main'));
const { data: statics } = await axios.get('./statics.json');
const dates = retriveDates(statics);
const sortedDates = sort(dates);
const themeColors = ['#d87c7c', '#919e8b', '#d7ab82', '#6e7074'];
const series = reschedule(statics, sortedDates)
// 为系列设置不同的色值
.map((serie, index) => {
const color = themeColors[index];
const liftColor = echarts.color.lift(color, );
return {
...serie,
itemStyle: {
color: color,
color0: liftColor,
borderColor: color,
borderColor0: liftColor,
},
};
});
const option = {
tool@R_229_2@: { feature: { saveAsImage: {} } },
xAxis: { type: 'category', data: sortedDates },
yAxis: { type: 'value' },
legend: { data: series.map((s) => s.name) },
series,
};
myChart.setOption(option);
}
run();
</script>
</body>
</html>
@H_249_@
示例: