# 引言
项目中需要画一幅收益概览图,研究了一下 Highcharts 的用法。特此收录方便以后再次使用时查阅。
# 代码
//x 轴时间集合 | |
var chartXAxisDateTimes = ['2022-01-01 00:00:00', '2022-02-01 00:00:00', '2022-03-01 00:00:00', '2022-04-01 00:00:00', '2022-05-01 00:00:00'] | |
//y 轴数据集合 | |
var chartYAxisDatas = [ | |
{ | |
title: '累计收益', | |
name: '我的策略累计收益', | |
type: 'spline', | |
unit: '%', | |
valueDecimals: 3, | |
height: '28%', | |
yAxisIndex: 0, //y 轴分区 index(从上到下,默认从 0 开始) | |
data: [{ | |
x: new Date('2022-01-01 00:00:00').getTime(), | |
y: 1, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-02-01 00:00:00').getTime(), | |
y: 2, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-03-01 00:00:00').getTime(), | |
y: 3, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-04-01 00:00:00').getTime(), | |
y: 4, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-05-01 00:00:00').getTime(), | |
y: 5, | |
color: '' | |
}] | |
}, | |
{ | |
title: '每月盈亏', | |
name: '当月盈利', | |
type: 'column', | |
unit: 'k', | |
valueDecimals: 0, | |
top: '34%', | |
height: '28%', | |
yAxisIndex: 1, //y 轴分区 index(从上到下,默认从 0 开始) | |
formatter: function () { | |
return this.value < 0 ? (-this.value) + 'k' : this.value + 'k' | |
}, | |
data: [{ | |
x: new Date('2022-01-01 00:00:00').getTime(), | |
y: 1, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-02-01 00:00:00').getTime(), | |
y: 2, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-03-01 00:00:00').getTime(), | |
y: 3, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-04-01 00:00:00').getTime(), | |
y: 4, | |
color: '' | |
}, | |
{ | |
x: new Date('2022-05-01 00:00:00').getTime(), | |
y: 5, | |
color: '' | |
}] | |
}, | |
{ | |
title: '成交记录', | |
name: '当月买入', | |
type: 'column', | |
unit: 'k', | |
valueDecimals: 0, | |
top: '68%', | |
height: '28%', | |
yAxisIndex: 2, //y 轴分区 index(从上到下,默认从 0 开始) | |
data: [{ | |
x: new Date('2022-01-01 00:00:00').getTime(), | |
y: 1, | |
color: 'red' | |
}, | |
{ | |
x: new Date('2022-02-01 00:00:00').getTime(), | |
y: 2, | |
color: 'red' | |
}, | |
{ | |
x: new Date('2022-03-01 00:00:00').getTime(), | |
y: 3, | |
color: 'red' | |
}, | |
{ | |
x: new Date('2022-04-01 00:00:00').getTime(), | |
y: 4, | |
color: 'red' | |
}, | |
{ | |
x: new Date('2022-05-01 00:00:00').getTime(), | |
y: 5, | |
color: 'red' | |
}] | |
}, | |
{ | |
title: '成交记录', | |
name: '当月卖出', | |
type: 'column', | |
unit: 'k', | |
valueDecimals: 0, | |
top: '68%', | |
height: '28%', | |
yAxisIndex: 2, //y 轴分区 index(从上到下,默认从 0 开始) | |
data: [{ | |
x: new Date('2022-01-01 00:00:00').getTime(), | |
y: 1, | |
color: 'green' | |
}, | |
{ | |
x: new Date('2022-02-01 00:00:00').getTime(), | |
y: 2, | |
color: 'green' | |
}, | |
{ | |
x: new Date('2022-03-01 00:00:00').getTime(), | |
y: 3, | |
color: 'green' | |
}, | |
{ | |
x: new Date('2022-04-01 00:00:00').getTime(), | |
y: 4, | |
color: 'green' | |
}, | |
{ | |
x: new Date('2022-05-01 00:00:00').getTime(), | |
y: 5, | |
color: 'green' | |
}] | |
} | |
] | |
// 最大回测范围 | |
var plotBandScope = [new Date('2022-02-01 00:00:00').getTime(), new Date('2022-04-01 00:00:00').getTime()] | |
// 图表配置 | |
var option = { | |
chart: { | |
height: 600, | |
type: 'spline' // 指定图表的类型,默认是折线图(line) | |
}, | |
plotOptions: { | |
spline: { | |
borderWidth: 0, | |
lineWidth: 1, | |
states: { | |
hover: { | |
lineWidth: 2 | |
} | |
}, | |
//pointWidth: 4, // 柱子内宽度容 | |
dataLabels: { | |
style: { | |
fontSize: 11 | |
}, | |
enabled: false | |
}, | |
showInLegend: true | |
}, | |
column: { | |
borderWidth: 0, | |
pointWidth: 4, // 柱子内宽度容 | |
dataLabels: { | |
style: { | |
fontSize: 11 | |
}, | |
enabled: false | |
}, | |
showInLegend: true, | |
grouping: true | |
} | |
}, | |
rangeSelector: { | |
enabled: false | |
}, | |
credits: { | |
enabled: false | |
}, | |
// legend: { | |
// enabled: true, | |
// verticalAlign: 'top' | |
// }, | |
navigator: { // 导航器样式 | |
enabled: true, | |
height: 20 | |
}, | |
scrollbar: { // 滚动条样式 | |
barBackgroundColor: 'rgb(209, 218, 237)', | |
barBorderRadius: 0, | |
barBorderWidth: 0, | |
buttonBackgroundColor: 'rgb(242, 242, 242)', | |
buttonBorderWidth: 0, | |
buttonBorderRadius: 0, | |
trackBackgroundColor: 'none', | |
trackBorderWidth: 1, | |
trackBorderRadius: 0, | |
trackBorderColor: '#CCC' | |
}, | |
xAxis: { | |
lineWidth: 1, | |
type: 'datetime', | |
categories: [], | |
dateTimeLabelFormats: { | |
// millisecond: '%H:%M:%S.%L', | |
// second: '%H:%M:%S', | |
// minute: '%H:%M', | |
// hour: '%m-%d %H:%M', | |
day: '%m-%d', | |
week: '%m-%d', | |
month: '%Y-%m', | |
year: '%Y' | |
}, | |
gridLineWidth: 1 | |
}, | |
yAxis: [], | |
tooltip: { | |
xDateFormat: '%Y-%m-%d %H:%M:%S', | |
style: { | |
fontSize: 16, | |
fontFamily: '微软雅黑', | |
fontWeight: 'normal', | |
color: '#666', | |
padding: 10, | |
borderWidth: 0, | |
backgroundColor: '#ddd' | |
}, | |
shared: true, | |
useHTML: true, | |
headerFormat: '<small style="font-size: 12px">{point.key}</small><table>', // 标题格式, | |
pointFormat: '<tr><td><li style="color:{series.color};padding:0px">{series.name}: </li>' + | |
'<div style="float: right;">{point.y} {series.tooltip.valueDecimals}</div></td></tr>', | |
footerFormat: '</table>', | |
shadow: true, | |
followPointer: true // 跟随鼠标 | |
}, | |
series: [] | |
} | |
// 根据最大回测范围修改图表配置 | |
if (plotBandScope && plotBandScope.length === 2) { | |
option.xAxis.plotBands = [{ | |
from: plotBandScope[0], | |
to: plotBandScope[1], | |
color: '#FCFFC5', | |
label: { | |
text: '最大回测区间', | |
align: 'center', | |
verticalAlign: 'top', | |
y: 14 | |
} | |
}] | |
} | |
// 根据 x 轴时间集合修改图表配置 | |
if (chartXAxisDateTimes && chartXAxisDateTimes.length > 0) { | |
option.categories = chartXAxisDateTimes | |
} | |
// 根据 y 轴数据集合修改图表配置 | |
if (chartYAxisDatas && chartYAxisDatas.length > 0) { | |
chartYAxisDatas.forEach(function (item, i) { | |
if (item.type === 'spline' || item.type === 'line') { | |
option.yAxis.push({ | |
plotLines: [{ | |
color: 'black', // 线的颜色,定义为红色 | |
dashStyle: 'solid', // 默认值,这里定义为实线 | |
value: 0, // 定义在那个值上显示标示线,这里是在 x 轴上刻度为 3 的值处垂直化一条线 | |
width: 2 // 标示线的宽度,2px | |
}], | |
tickAmount: 4, // 规定坐标轴上的刻度总数 | |
gridLineColor: '#ddd', | |
gridLineDashStyle: 'Solid', | |
labels: { // 坐标轴上刻度的样式及单位 | |
align: 'right', | |
x: 6, | |
style: { | |
color: '#999999', | |
fontSize: 12 | |
}, | |
format: '{value}' + item.unit // 坐标轴上的单位 | |
}, | |
title: { | |
text: item.title, | |
margin: 20, | |
style: { | |
color: '#999999', | |
fontSize: 12, | |
align: 'middle' // 坐标轴对齐方式(相对于坐标轴的值) 默认是:middle 居中对齐 | |
} | |
}, | |
height: item.height, | |
lineWidth: 0 | |
}) | |
option.series.push({ | |
name: item.name, | |
data: item.data, | |
type: item.type, | |
color: 'rgb(170, 70, 67)', | |
tooltip: { | |
valueSuffix: item.unit, // 数值后缀 | |
valueDecimals: item.valueDecimals // 提示框数据精度 (保留小数点后 3 位) | |
}, | |
yAxis: item.yAxisIndex, | |
showInNavigator: false | |
}) | |
} else if (item.type === 'column') { | |
option.yAxis.push({ | |
type: item.type, | |
tickAmount: 4, // 规定坐标轴上的刻度总数 | |
startOnTick: true, | |
reversed: false, //y 轴刻度反转 | |
showFirstLabel: false, | |
showLastLabel: true, | |
gridLineColor: '#ddd', | |
gridLineDashStyle: 'Solid', | |
labels: { | |
align: 'right', | |
x: 12, | |
style: { | |
color: '#999999', | |
fontSize: 12 | |
}, | |
formatter: item.formatter, | |
format: '{value}' + item.unit // 坐标轴上的单位 | |
}, | |
title: { | |
text: item.title, | |
margin: 20, | |
style: { | |
color: '#999999', | |
fontSize: 12, | |
align: 'middle' // 坐标轴对齐方式(相对于坐标轴的值) 默认是:middle 居中对齐 | |
} | |
}, | |
top: item.top, | |
height: item.height, | |
offset: 0, | |
lineWidth: 0 | |
}) | |
option.series.push({ | |
name: item.name, | |
type: item.type, | |
data: item.data, | |
tooltip: { | |
pointFormatter: function () { | |
return '<tr><td><li style="color: ' + this.color + ';padding:0px;"></span> ' + item.name + | |
': </li><div style="float: right;">' + this.y.toFixed(item.valueDecimals) + item.unit + '</div></td></tr>' | |
} | |
}, | |
yAxis: item.yAxisIndex, | |
showInNavigator: false | |
}) | |
} | |
}) | |
} | |
// 画图(container 为 div 的 id) | |
Highcharts.stockChart('container', option) |