如上圖所示,前端時(shí)間做了個(gè)期權(quán)交易項(xiàng)目,涉及到該分時(shí)圖的實(shí)現(xiàn)锉罐,沒(méi)有在網(wǎng)上找到現(xiàn)成的配置号涯,后面自己寫(xiě)了個(gè),是用echarts(版本4.1.0)實(shí)現(xiàn)的青扔,我會(huì)將相關(guān)配置項(xiàng)代碼貼在下方:
let interval;//用作y軸的坐標(biāo)軸分割間隔的值
let min;//當(dāng)前實(shí)時(shí)數(shù)據(jù)源织,價(jià)格最低
let max;//當(dāng)前實(shí)時(shí)數(shù)據(jù),價(jià)格最高
let judgePrice;//昨日行權(quán)價(jià)格微猖,用來(lái)作為今日的漲跌判斷基準(zhǔn)值
let responseData;//后臺(tái)獲取的實(shí)時(shí)行情買賣數(shù)據(jù)谈息,屬性i為數(shù)據(jù)時(shí)間(如:10:30:20),p為數(shù)據(jù)買賣價(jià)格凛剥,v為數(shù)據(jù)當(dāng)次交易量
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: '當(dāng)前價(jià)',
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: '當(dāng)前價(jià)',
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: '行權(quán)價(jià)',
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: '行權(quán)價(jià)',
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];
})
}
]
};
由于分時(shí)圖的特殊性侠仇,只關(guān)注9:30到下午15:00間的實(shí)時(shí)交易數(shù)據(jù),并且中午11:30到下午13:00之間是暫停交易時(shí)間犁珠,所以該分時(shí)圖實(shí)現(xiàn)的難點(diǎn)一是x軸的實(shí)現(xiàn)逻炊,二是y軸的價(jià)格區(qū)間必須得是實(shí)時(shí)的當(dāng)日最高價(jià)格和當(dāng)日最高價(jià)格以行權(quán)價(jià)為基準(zhǔn)計(jì)算,以最高價(jià)和最低價(jià)與行權(quán)價(jià)相減值大的為基準(zhǔn)值犁享,然后除2得到y(tǒng)軸的分割間隔值余素。
上面的配置中,漲我用的顏色是red炊昆,跌用的green桨吊,具體色值根據(jù)實(shí)際項(xiàng)目需要調(diào)整。上圖實(shí)際將圖表渲染層分為三塊凤巨,用grid調(diào)整相應(yīng)布局视乐。由于橫坐標(biāo)需要用時(shí)間戳來(lái)計(jì)算interval,所以我都是用2000-01-01加相應(yīng)時(shí)間獲取到的時(shí)間戳敢茁,好用于設(shè)置x軸的min和max佑淀,并且將interval設(shè)置為3600000,那么x軸的間隔剛好是一小時(shí)卷要,并且09:30到11:30和13:00到15:00用兩個(gè)單獨(dú)的grid配置渣聚,組合為實(shí)際想要的一整個(gè)分時(shí)圖。
responseData為后臺(tái)獲取數(shù)據(jù)僧叉,由于從新浪期權(quán)抓取的數(shù)據(jù)奕枝,屬性名依照接口返回的有相應(yīng)的v(交易量),i(時(shí)間),p(價(jià)格)幾個(gè)屬性,大家在實(shí)際使用該配置時(shí)瓶堕,還是得根據(jù)自己得后臺(tái)接口做相應(yīng)調(diào)整隘道。min和max根據(jù)自己接口獲取得值設(shè)置,若接口未提供該值,就需要前端從實(shí)時(shí)數(shù)據(jù)中遍歷獲取實(shí)時(shí)得min和max值谭梗。
綜上忘晤,我為大家提供了現(xiàn)成得配置,具體實(shí)現(xiàn)還得實(shí)際在項(xiàng)目中進(jìn)行調(diào)試激捏,有什么問(wèn)題可以在評(píng)論中提問(wèn)或者私信我设塔,我會(huì)及時(shí)回答。走過(guò)路過(guò)远舅,記得幫忙點(diǎn)個(gè)贊喲