echarts股票分时图
几个注意的地方
要点1.x轴显示固定的时间(一天240条数据)
formatter: function(value, index) {
if (index == 0) {
return '9:30'
} else if (index == 60) {
return '10:30'
} else if (index == 120) {
return '11:30/13:00'
} else if (index == 180) {
return '14:00'
} else if (index == 240) {
return '15:00'
} else {
return
}
}
要点2.缺失某段时间,用下面代码限制x轴数据
function creatX() {
let onehours = ['09', '10', '11', '13', '14']
let min = ''
let timegroup = []
onehours.forEach((item) => {
if (item == '11') {
for (let i = 0; i < 30; i++) {
let str = item + ':' + (i < 10 ? ('0' + i) : i)
// console.log()
timegroup.push(str)
}
} else if (item == '09') {
for (let i = 30; i < 60; i++) {
let str = item + ':' + i
// console.log()
timegroup.push(str)
}
} else {
for (let i = 0; i < 60; i++) {
let str = item + ':' + (i < 10 ? ('0' + i) : i)
timegroup.push(str)
}
}
})
timegroup.push("15:00")
return timegroup
}
y轴左边价格与右边涨跌幅对齐,对两个y轴限定最大值与最小值,并且限定分割段数
min: data.valueMin,
max: data.valueMax,
scale: true,
interval: data.valueInterval,
然后一步一步来
首先是将网格分为上下两部分,上面是折线图,下面是成交量柱形图
grid: [{
left: '15%',
right: '15%',
height: '60%',
bottom: '30%'
},
{
left: '15%',
right: '15%',
bottom: '10%',
height: '20%'
},
],
然后先是上半折线图部分,先来定义x轴和y轴
xAxis: [{//折线图x轴
type: 'category',
data: timegroup,//使用上面定义好的数据
boundaryGap: false,
max: 241,
scale: true,
axisLine: {
onZero: false,
lineStyle: {
color: '#303b49'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: false
},
axisPointer: {
z: 100,
label: {
show: false
}
},
},
//.......
]
yAxis: [{
min: data.valueMin,//左半部分,限定最大最小,按计算分隔坐标轴,与右边坐标轴数据对应对齐
max: data.valueMax,
scale: true,
interval: data.valueInterval,
splitArea: {
show: false
},
splitLine: {
lineStyle: {
color: '#303b49'
}
},
axisTick: {
show: false
},
axisLine: {
show: false
},
axisPointer: {
z: 100,
label: {
backgroundColor: '#ddd',
padding: [2, 3],
color: '#333',
formatter: function(val) {
return parseFloat(val.value).toFixed(2)
}
}
},
axisLabel: {
// show:false
color: '#838D9E',
formatter: function(value) {
// console.log(value)
return value.toFixed(2)
},
textStyle: {
fontSize: fontsizes(1.2),
color: function(value, index) {
// console.log(value+'----'+averLine)
return Math.round(value) > Math.round(averLine) ? '#FF4A4A' : (Math.round(value) < Math.round(averLine) ?
'#3CC864' : 'gray');
}
}
}
},
{//右边涨幅轴
min: data.radioMin,
max: data.radioMax,
interval: data.radioInterval,
gridIndex: 0,
type: 'value',
name: ' ',
scale: true,
splitArea: {
show: false
},
axisPointer: {
z: 100,
label: {
backgroundColor: '#ddd',
padding: [2, 3],
color: '#333',
formatter: function(val) {
return parseFloat(val.value).toFixed(2) + '%'
}
}
},
splitLine: {
show: false,
lineStyle: {
color: '#f5f5f5'
}
},
axisTick: {
show: false
},
axisLine: {
show: false
},
axisLabel: {
fontSize: fontsizes(1.2),
show: true,
// interval: 'auto',//居中显示
textStyle: {
color: function(value, index) {
return value > 0 ? '#FF4A4A' : (value < 0 ? '#3CC864' : 'gray');
}
},
formatter: function(value) {
let text1 = parseFloat(value).toFixed(2) + '%'
if (value > 0 || value == 0) {
text1 = " " + text1;
}
return text1
}
//以百分比显示
},
},
//.....
]
然后给数据,以及线的样式
series: [{
name: '当前价格',
type: 'line',
markLine: {
lineStyle: {
color: 'gray'
},
symbol: "none",
data: [{
name: '昨收线',
yAxis: averLine,
label: {
show: false,
position: 'start',
backgroundColor: "#DDDDDD",
borderRadius: 2,
width: '10%',
padding: [1, 2],
fontSize: fontsizes(1.2),
// formatter:"{@[3]}"
},
},
{
name: '昨收线',
yAxis: averLine,
label: {
show: false,
position: 'end',
backgroundColor: "#DDDDDD",
borderRadius: 2,
width: '10%',
padding: [1, 2],
fontSize: fontsizes(1.2),
formatter: "0.00%"
},
},
]
},
markPoint: {
symbol: 'circle',
symbolSize: 4,
itemStyle: {
borderColor: "#2e91ff",
color: "white"
},
label: {
show: false,
position: "top",
fontSize: fontsizes(1.2),
formatter: function(value) {
}
},
data: [{
type: "max",
valueIndex: 0
}],
animation: true,
animationEasingUpdate: "bounceIn",
animationEasing: "bounceIn"
},
data: data.values,
smooth: true,
symbol: 'none',
lineStyle: {
opacity: 1,
width: fontsizes(0.1),
color: "#1A5C7B" //#50b2f4
},
areaStyle: {
// origin:'start',
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: '#41658177' // 0% 处的颜色
},
{
offset: 0.6,
color: '#41658111' // 100% 处的颜色
},
{
offset: 1,
color: 'transparent' // 100% 处的颜色
}
],
global: false // 缺省为 false
}
}
},
然后数据data从哪来?例如后台给的数据是这种的:
data:[{close: 3592.38,
high: 3593.88,
low: 3590.87,
money: 12686632781.5,
open: 3590.92,
time: "2021-01-21 09:31",
volume: 1010254100}],
perClose:3544.98
然后我们处理一下,转换为我们需要的数据
function splitDataMin(rawData, currClose) {
var values = [];
var volumes = [];
let radios = [];
let zde = [];
let valueMin = parseFloat(currClose).toFixed(2);
let valueMax = parseFloat(currClose).toFixed(2);
let radioMin = 0;
let radioMax = 0;
let valueInterval = 0;
let radioInterval = 0;
// let lastPoint=[];
for (var i = 0; i < rawData.length; i++) {
if ((i - 1 >= 0) && rawData[i].time == rawData[i - 1].time) {
continue
}
let curr = rawData[i].time.split(' ')[1]
curr = curr.split(':')[0] + ':' + curr.split(':')[1]
let indx = timegroup.indexOf(curr)
valueMax = Math.max(valueMax, rawData[i].close)
valueMin = Math.min(valueMin, rawData[i].close)
let zz = (rawData[i].close - currClose).toFixed(2)
let rr = (rawData[i].close - currClose) / currClose
rr = (rr * 100).toFixed(2)
radioMin = Math.min(rr, radioMin)
radioMax = Math.max(rr, radioMax)
values.push([indx, rawData[i].close, rawData[i].time, rawData[i].high, rawData[i].low, rawData[i].money, rawData[i].open,
zz, rr
]); //x,y
volumes.push([indx, rawData[i].volume, rawData[i].close > rawData[i].open ? 1 : -1]);
}
if ((valueMax - currClose > 0) && (currClose - valueMin > 0)) {
let a = valueMax - currClose
let b = currClose - valueMin
}
valueInterval = ((valueMax - valueMin) / 4)
radioInterval = (radioMax - radioMin) / 4
return {
values: values,//曲线数据
volumes: volumes,//成交额数据
valueMax,
valueMin,
radioMax,
radioMin,
valueInterval,
radioInterval,
};
}
先加上成交量的图对应的坐标轴代码
xAxis:[
.....
{
type: 'category',
gridIndex: 1,
data: timegroup,
scale: true,
max: 241,
boundaryGap: false,
axisLine: {
onZero: false,
lineStyle: {
color: "#838D9E"
}
},
axisTick: {
lineStyle: {
width: fontsizes(0.1)
},
// show: false,
interval: (index, value) => {
if (index == 0 || index == 60 || index == 120 || index == 180 || index == 240) {
return true
}
}
},
axisPointer: {
z: 100,
label: {
show: false
}
},
splitLine: {
show: false
},
axisLabel: {
interval: 0,
fontSize: fontsizes(1.2),
color: '#838D9E',
formatter: function(value, index) {
if (index == 0) {
return '9:30'
} else if (index == 60) {
return '10:30'
} else if (index == 120) {
return '11:30/13:00'
} else if (index == 180) {
return '14:00'
} else if (index == 240) {
return '15:00'
} else {
return
}
}
},
},
],
yAxis:[
..........
{
min: data.radioMin,
max: data.radioMax,
interval: data.radioInterval,
gridIndex: 0,
type: 'value',
name: ' ',
scale: true,
splitArea: {
show: false
},
axisPointer: {
z: 100,
label: {
backgroundColor: '#ddd',
padding: [2, 3],
color: '#333',
formatter: function(val) {
return parseFloat(val.value).toFixed(2) + '%'
}
}
},
splitLine: {
show: false,
lineStyle: {
color: '#f5f5f5'
}
},
axisTick: {
show: false
},
axisLine: {
show: false
},
axisLabel: {
fontSize: fontsizes(1.2),
show: true,
// interval: 'auto',//居中显示
textStyle: {
color: function(value, index) {
return value > 0 ? '#FF4A4A' : (value < 0 ? '#3CC864' : 'gray');
}
},
formatter: function(value) {
let text1 = parseFloat(value).toFixed(2) + '%'
if (value > 0 || value == 0) {
text1 = " " + text1;
}
return text1
}
//以百分比显示
},
}
],
series:[
..........
{
name: '成交量',
type: 'bar',
barWidth: fontsizes(0.1),
xAxisIndex: 1,
yAxisIndex: 1,
data: data.volumes
},
]
然后处理鼠标移上的显示问题
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderWidth: 1,
borderColor: '#000',
padding: 10,
textStyle: {
color: '#ddd',
fontSize: fontsizes(1.2)
},
position: function(pos, params, el, elRect, size) {
var obj = {
top: 10
};
obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 30;
return obj;
},
formatter: function(param) {
// console.log(param)
let p1, p2
param.forEach(function(item) {
if (item.seriesType == 'line') {
p1 = item //分时线
} else if (item.seriesType == 'bar') {
p2 = item //成交量
}
})
function priNum(n) {
if (n > 100000000) {
return (n / 100000000).toFixed(2) + '亿'
} else if (n > 10000) {
return (n / 10000).toFixed(2) + '万'
} else {
return n
}
}
return [
'时间:<span style="margin-left:6rem"> ' + p1.data[2] + '</span><hr size=1 style="margin: 3px 0">',
'最新价:<span style="float:right;color:' + (p1.data[1] > averLine ? '#FF4A4A' : '#3CC864') + '">' + parseFloat(p1.data[
1]) + '</span><br/>',
'涨跌额:<span style="float:right;color:' + (Math.ceil(p1.data[7]) > 0 ? '#FF4A4A' : '#3CC864') + '"> ' + p1.data[7] +
'</span><br/>' +
'涨跌幅:<span style="float:right;color:' + (Math.ceil(p1.data[7]) > 0 ? '#FF4A4A' : '#3CC864') + '"> ' + p1.data[8] +
'%</span><br/>' +
'成交额:<span style="float:right;"> ' + priNum(p1.data[5]) + '</span><br/>' +
'成交量:<span style="float:right"> ' + priNum(p2.data[1]) + '</span><br/>',
].join('');
}
// extraCssText: 'width: 170px'
},
axisPointer: {
link: {
xAxisIndex: 'all'
},
label: {
backgroundColor: 'transparent',
fontSize: fontsizes(1.2),
// formatter:function(val){
// }
}
},