echarts股票分时图

2,271 阅读4分钟

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){

				// }

			}
		},