如上图所示,前端时间做了个期权交易项目,涉及到该分时图的实现,没有在网上找到现成的配置,后面自己写了个,是用echarts(版本4.1.0)实现的,我会将相关配置项代码贴在下方:
let interval;//用作y轴的坐标轴分割间隔的值
let min;//当前实时数据,价格最低
let max;//当前实时数据,价格最高
let judgePrice;//昨日行权价格,用来作为今日的涨跌判断基准值
let responseData;//后台获取的实时行情买卖数据,属性i为数据时间(如:10:30:20),p为数据买卖价格,v为数据当次交易量
let baseNumber = Math.max(Math.abs(max - junglePrice), Math.abs(min - junglePrice));
interval = (baseNumber / 2).toFixed(4);
let option = {
backgroundColor: '#1f2025',
animation: false,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
showContent: false
},
axisPointer: {
link: {xAxisIndex: 'all'},
label: {
backgroundColor: '#777'
}
},
visualMap: {
show: false,
seriesIndex: 4,
dimension: 2,
pieces: [{
value: 1,
color: 'red'
}, {
value: -1,
color: 'green'
},
{
value: 0,
color: '#ffffff'
}
]
},
grid: [
{
top: '5%',
left: '15%',
width:'35%',
height: '50%'
},
{
top: '5%',
left: '50%',
width:'35%',
height: '50%'
},
{
left: '15%',
right: '8%',
top: '72%',
height: '20%'
}
],
xAxis: [
{
type: 'time',
boundaryGap: true,
axisLine: {
onZero: false,
lineStyle: {
color: '#666'
}
},
axisLabel: {
formatter: function (val,index) {
if(index === 2){
return ''
}
return moment(val).format('HH:mm');
}
},
splitLine: {
show: true,
lineStyle: {
color: '#666'
}
},
splitArea: {
areaStyle: {
color: '#1f2025'
}
},
// splitNumber: 5,
min: 946690200000,
max: 946697400000,
interval: 3600000,
axisTick: {show: false},
axisPointer: {
z: 100,
label: {
formatter: function (params) {
return moment(params.value).format('HH:mm');
}
}
}
},
{
type: 'time',
gridIndex: 1,
boundaryGap: true,
axisLine: {
onZero: false,
lineStyle: {
color: '#666'
}
},
axisLabel: {
formatter: function (val,index) {
if(index === 0){
return '11:30/13:00'
}
return moment(val).format('HH:mm');
}
},
splitLine: {
show: true,
lineStyle: {
color: '#666'
}
},
splitArea: {
areaStyle: {
color: '#1f2025'
}
},
// splitNumber: 5,
min: 946702800000,
max: 946710000000,
interval: 3600000,
axisTick: {show: false},
axisPointer: {
z: 100,
label: {
formatter: function (params) {
return moment(params.value).format('HH:mm');
}
}
}
},
{
type: 'category',
gridIndex: 2,
data: responseData.map(item => item.i),
// scale: true,
boundaryGap: true,
axisLine: {onZero: false},
axisTick: {show: false},
splitLine: {
show: true,
lineStyle: {
color: '#666'
}
},
splitArea: {
areaStyle: {
color: '#1f2025'
}
},
axisLabel: {show: false},
splitNumber: 20,
min: 'dataMin',
max: 'dataMax'
}
],
yAxis: [
{
min: function (val) {
return (parseFloat(junglePrice) - 2 * parseFloat(interval)).toFixed(4);
},
max: function (val) {
return (parseFloat(junglePrice) + 2 * parseFloat(interval)).toFixed(4);
},
interval: Math.abs(interval),
axisLabel: {
formatter: function (val) {
return val.toFixed(4);
},
color:function (value) {
return value-junglePrice === 0?'#cccccc':value-junglePrice > 0 ? 'red' : 'green';
}
},
axisPointer: {
show: true,
label: {
formatter: function (params) {
return (params.value).toFixed(4);
}
}
},
axisLine: {
lineStyle: {
color: '#666'
}
},
axisTick: {show: false},
splitLine: {
lineStyle: {
color: '#666'
}
},
splitArea: {
areaStyle: {
color: '#1f2025'
}
},
},
{
gridIndex: 1,
position:'right',
min: function (val) {
return (parseFloat(junglePrice) - 2 * parseFloat(interval)).toFixed(4);
},
max: function (val) {
return (parseFloat(junglePrice) + 2 * parseFloat(interval)).toFixed(4);
},
interval: Math.abs(interval),
axisLabel: {
formatter: function (val) {
let data = (val - junglePrice)/junglePrice*100;
return data.toFixed(2)+'%';
},
color:function (value) {
return value-junglePrice === 0?'#cccccc':value-junglePrice > 0 ? 'red' : 'green';
}
},
axisPointer: {
show: true,
label: {
formatter: function (params) {
return (params.value).toFixed(4);
}
}
},
axisLine: {
lineStyle: {
color: '#666'
}
},
axisTick: {show: false},
splitLine: {
lineStyle: {
color: '#666'
}
},
splitArea: {
areaStyle: {
color: '#1f2025'
}
},
},
{
min: 'dataMin',
max: 'dataMax',
gridIndex: 2,
splitNumber: 1,
interval: 10000,
showMinLabel: true,
showMaxLabel: true,
axisLabel: {
formatter: function (value, index) {
if (index === 0) {
return '张'
} else {
return value;
}
},
},
axisPointer: {
show: true,
label: {
formatter: function (params) {
return (params.value).toFixed(0);
}
}
},
axisTick: {show: false},
axisLine: {
lineStyle: {
color: '#666'
}
},
splitLine: {
lineStyle: {
color: '#666'
}
},
splitArea: {
areaStyle: {
color: '#1f2025'
}
},
}
],
series: [
{
name: '当前价',
type: 'line',
data: responseData.map(item => {
let date = '2000-01-01' + ' ' + item.i;
let dateNumber = Date.parse(new Date(date));
return [dateNumber, item.p];
}),
smooth: true,
symbol: 'none',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgb(2,228,253)'
}, {
offset: 1,
color: 'transparent'
}])
},
lineStyle: {
color: 'rgb(2,228,253)',
width: 1
}
},
{
name: '当前价',
type: 'line',
xAxisIndex: 1,
yAxisIndex: 1,
data: responseData.map(item => {
let date = '2000-01-01' + ' ' + item.i;
let dateNumber = Date.parse(new Date(date));
return [dateNumber, item.p];
}),
smooth: true,
symbol: 'none',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgb(2,228,253)'
}, {
offset: 1,
color: 'transparent'
}])
},
lineStyle: {
color: 'rgb(2,228,253)',
width: 1
}
},
{
name: '行权价',
type: 'line',
data: responseData.map(item => {
let date = '2000-01-01' + ' ' + item.i;
let dateNumber = Date.parse(new Date(date));
return [dateNumber, judgePrice];
}),
smooth: true,
symbol: 'none',
lineStyle: {
color: 'rgb(248,185,0)',
width: 1
}
},
{
name: '行权价',
type: 'line',
xAxisIndex: 1,
yAxisIndex: 1,
data: responseData.map(item => {
let date = '2000-01-01' + ' ' + item.i;
let dateNumber = Date.parse(new Date(date));
return [dateNumber, judgePrice];
}),
smooth: true,
symbol: 'none',
lineStyle: {
color: 'rgb(248,185,0)',
width: 1
}
},
{
name: '买卖量',
type: 'bar',
xAxisIndex: 2,
yAxisIndex: 2,
itemStyle: {
normal: {
color: 'green',
color0: 'red',
borderColor: null,
borderColor0: null
}
},
data: responseData.map((item, index, arr) => {
let judge = item.p === junglePrice ? 0 : item.p > junglePrice ? 1 : -1;
if (index === 0) {
judge = item.p === junglePrice ? 0 : item.p > junglePrice ? 1 : -1;
} else {
judge = item.p === arr[index - 1].p ? 0 : item.p > arr[index - 1].p ? 1 : -1;
}
return [index, item.v, judge];
})
}
]
};
由于分时图的特殊性,只关注9:30到下午15:00间的实时交易数据,并且中午11:30到下午13:00之间是暂停交易时间,所以该分时图实现的难点一是x轴的实现,二是y轴的价格区间必须得是实时的当日最高价格和当日最高价格以行权价为基准计算,以最高价和最低价与行权价相减值大的为基准值,然后除2得到y轴的分割间隔值。
上面的配置中,涨我用的颜色是red,跌用的green,具体色值根据实际项目需要调整。上图实际将图表渲染层分为三块,用grid调整相应布局。由于横坐标需要用时间戳来计算interval,所以我都是用2000-01-01加相应时间获取到的时间戳,好用于设置x轴的min和max,并且将interval设置为3600000,那么x轴的间隔刚好是一小时,并且09:30到11:30和13:00到15:00用两个单独的grid配置,组合为实际想要的一整个分时图。
responseData为后台获取数据,由于从新浪期权抓取的数据,属性名依照接口返回的有相应的v(交易量),i(时间),p(价格)几个属性,大家在实际使用该配置时,还是得根据自己得后台接口做相应调整。min和max根据自己接口获取得值设置,若接口未提供该值,就需要前端从实时数据中遍历获取实时得min和max值。
综上,我为大家提供了现成得配置,具体实现还得实际在项目中进行调试,有什么问题可以在评论中提问或者私信我,我会及时回答。走过路过,记得帮忙点个赞哟