使用百度echarts仿雪球分时图(四)
这章节来收拾一下一些小BUG,顺便把各个小提示信息也补上,分时图也就完成了。
上章节末尾提到的一个bug,就是第一个grid跟第三个grid之间是断开的,折线并没有连在一起,所以先来收拾这个问题。没有连着一起的原因主要是第一个grid的最后一条数据的值,跟第三个grid的第一条数据不一样,而且grid之间是不会帮你把这两个点连接起来的,所以会出现一上一下的断崖。知道了是什么原因,那就知道该怎么办了。在遍历数据的时候,我们先往grid3Data数据里加一条数据,这条数据的值是grid1Data的最后一条数据,也就是11:30的那条数据,这样第一个grid的最后一条数据跟第三个grid的第一条数据就一样了,这样就可以连起来了。但是还会有个问题,因为第三个grid跟第四个grid的x轴类型是 ‘time’类型,但是第一条数据是11:30,第二条数据是13:00,如果继续使用'time'类型的话,第三个grid会有很长一条直线,就是11:30到13:00之间这一段会很平的,所以第三第四个grid不能使用'time'类型了,改用'category'类目类型。改用'category'类型后,要新建两个数组来存放x轴的时间,分别是grid3DateData,grid4DateData,然后grid3Data和grid4Data存放的不再是数组,而是数值。
遍历数据的代码稍微修改一下。下午数据的部分修改为
if(data.data.items[i].current > priceMax){
priceMax = data.data.items[i].current;
}
if(data.data.items[i].current < priceMin || priceMin == 0){
priceMin = data.data.items[i].current;
}
// 第三grid的数据先添加一条数据
if(grid3Data.length == 0){
grid3Data.push(data.data.items[i-1].current);
grid3DateData.push(data.data.items[i-1].timestamp);
}
// 右上方折线图
grid3Data.push(data.data.items[i].current);
grid3DateData.push(data.data.items[i].timestamp); if(data.data.items[i].volume > volumeMax){
volumeMax = data.data.items[i].volume;
}
if(data.data.items[i].volume < volumeMin){
volumeMin = data.data.items[i].volume;
} if(data.data.items[i].current >= data.data.items[i-1].current){
volumeColor2.push(UP_COLOR);
}else{
volumeColor2.push(DOWN_COLOR);
} // 第四grid的数据先添加一条数据
if(grid4Data.length == 0){
grid4Data.push(data.data.items[i-1].volume);
grid4DateData.push(data.data.items[i-1].timestamp);
}
// 右下方柱状图
grid4Data.push(data.data.items[i].volume);
grid4DateData.push(data.data.items[i].timestamp);
然后第三第四个grid的x 轴配置中,data分别设置成grid3DateData和grid4DateData。然后又出现新的问题,x轴的坐标轴线分布不均匀,因为我们用的是 category 的类型,而且我们x轴的数据很多,echarts为了保证能够显示足够的x轴的文字,所以会出现跳跃性的线条,显得分布不均匀。还好,echarts中是有属性可以自定义去显示哪条x轴坐标轴线。就是xAxis.splitLine.interval这个属性,可以设置数字,也可以是回调方法,interval这个属性很熟悉了,就是线条的间隔,所以接下来使用回调方法的方式来显示需要显示的线条。第三第四个grid的xAxis.splitLine.interval属性都是这样写的
interval:function(index,value){
// 第一条第二条线是不需要显示的,第一条是11:30的,第一个grid已经有这条数据了,所以不需要显示
// 第二条显示的话,在中间部分会出现2条线,所以也不要显示
if(index == 0 || index == 1){
return false;
}
// 这里的意思是第一条数据后,每30分钟显示一条线
if((index - 1) % 30 == 0){
return true;
}
return false;
}
这么一改,不连接的问题就解决了。
接下来把各个提示信息调整出来。首先要把指示器axisPointer这个属性配置一下,axisPointer有分为公共配置和各个坐标轴的单独配置。公共配置是配置一些公共的属性,各个坐标轴的配置则是配置不同坐标轴的样式,以及文字的格式化。这里我们两者都需要进行配置。
公共配置部分
axisPointer.show默认是false的,我们设置成true,指示器就出来了,但是会发现,线条也是断开的,只会显示其中的一个grid的线条,这里需要配置一下axisPointer.link属性来联动。link属性的介绍:不同轴的 axisPointer 可以进行联动,在这里设置。联动表示轴能同步一起活动。轴依据他们的 axisPointer 当前对应的值来联动,link 是一个数组,其中每一项表示一个 link group,一个 group 中的坐标轴互相联动。这里我们属性link的xAxisIndex和yAxisIndex属性,这两个属性是数组类型,里面值是数值,也就是grid的下标。重新看一下分时图,我们放鼠标在左上方的的区域,我们希望的是x轴是第一个第二个grid联动,y轴则是第一个第三个联动;放在右上方边的区域的话,x轴是第三个第四个grid联动,y轴还是第一个第三个联动。以此类推出左下方右下方的联动,得到的代码是这样的
axisPointer:{
show:true,
// 配置线条风格为虚线风格
lineStyle:{
type:'dashed'
},
link:[
{
xAxisIndex:[0,1],
},{
xAxisIndex:[2,3],
},{
yAxisIndex:[0,2]
},{
yAxisIndex:[1,3]
}
]
},
再看一下雪球的分时图,发现分时图有指示器的地方分别是第一个第二个第三个grid的y轴,第二个第四个grid的x轴,那么接下来要单独配置一下各个坐标轴的指示器。
所有指示器的show属性都设置成true,显示与否则通过label.show属性来控制。第一个第二个第三个grid的y轴的指示器的 label.show属性我们都设置成true,第四个则设置成false。第二个第四个grid的x轴的指示器的label.show属性设置成true,第一个第三个grid的x轴的指示器设置成false。设置完成后,成功的只显示了需要显示的指示器,但是默认的样式却不是我们想看到的样式。接下来美化一下
1.字体太大了,把label.fontSize调成10。
2.内边距太大了,把label.padding调成2即可。
3.阴影效果也不需要了,把label.shadowBlur调成0。
4.字体颜色也改成深色的,设置label.color即可。
经过调整后,样式已经达到我们的要求,但是指示器上的文字还没达到要求,那么就使用label.formatter的回调函数进行格式化,不同的坐标轴的格式化方式不一样,这里不花太大篇幅去讲解。
第一个第三个grid的x轴指示器配置
axisPointer:{
show:true,
label:{
show:false
}
}
第一个grid的y轴指示器配置
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:-44,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){ return data.value.toFixed(2);
}
},
}
第三个grid的y轴指示器配置
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:-34,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
var persent = (data.value - lastPrice) / lastPrice;
persent = (persent < 0) ? persent * -1 : persent;
persent = persent * 100; return persent.toFixed(2) + '%';
}
},
}
第二个grid的x轴指示器配置
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:0,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
return echarts.format.formatTime('hh:mm', parseFloat(data.value))
}
},
}
第二个grid的y轴指示器配置
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
if(data.value > 1000000){
return parseFloat(data.value / 1000000).toFixed(2)+"万手";
}
return data.value;
}
},
}
第四个grid的x轴指示器配置
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:0,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
return echarts.format.formatTime('hh:mm', parseFloat(data.value));
}
},
}
第四个grid的y轴指示器配置
axisPointer:{
show:true,
label:{
show:false
}
}
到这里,所有坐标轴的指示器都设置完成了,效果也如预期那样。最后还有一个悬浮的提示框需要配置,配置完后我们的分时图就完成了。
配置悬浮的提示框主要是配置根属性的tooltip属性。tooltip有个一个trigger的触发类型属性,item:数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用;axis:坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用;none:什么都不触发。因为默认是item,这里把触发类型改成 axis ,提示框就会出来了。但是提示框的位置还有样式,都不是我们想要的,又要再给它美化一下。首先我们先对它的位置进行固定,使用position属性进行配置,position可以是字符串,数组,回调函数,要高度自定义的话,显然回调函数比较合适,回调函数返回一个对象,这个对象与CSS的position属性类型,对象里面是使用top,right,bottom,left属性来控制位置的,我们可以根据回调函数里的5个回调参数来进行相应的配置,这5个回调参数分别是:
point: 鼠标位置,如 [20, 40]。
params: 同 formatter 的参数相同。
dom: tooltip 的 dom 对象。
rect: 只有鼠标在图形上时有效,是一个用x
, y
, width
, height
四个属性表达的图形包围盒。
size: 包括 dom 的尺寸和 echarts 容器的当前尺寸,例如:{contentSize: [width, height], viewSize: [width, height]}
。
point属性是鼠标当前的x值和y值;params跟formatter的参数相同,但是我们不需要格式化的相关配置,所以这个可以不用;dom对象,这个先保留;rect这个属性是鼠标放在提示框上才会有效,否则就是undefined,要想鼠标能放到提示框上,要配置enterable属性为true,但是我们不需要放鼠标上去,所以不需要;size属性,里面的contentSize属性指的是提示框的宽高,viewSize则是整个图表的大小,我们需要size的viewSize结合point鼠标位置属性来对提示框进行一个位置的定位。
我们要做的效果是鼠标在左边图表的时候,提示框在右边,鼠标在右侧图表的的时候,提示框在左边,那么就要对返回对象的left值或者right值进行配置了。判断鼠标是在左边还是在右边很简单,只需要判断鼠标的x值是否大于第一个第二个grid的宽度即可,因为左右两边的宽度是相等的,所以第一个第二个grid的宽度就是viewSize[width] / 2,只要鼠标位置的x值大于这个值,那就是鼠标在右边,小于这个值那就是在左边;同时我们要固定在头部,所以要把top值也设置一下。
position:function(point, params, dom, rect, size){
var obj ={
top:10
} if(point[0] > size.viewSize[0] / 2){
obj["left"] = 70;
}else{
obj["right"] = 70;
} return obj;
}
位置调整好后,开始整理样式。
1.文字的颜色通过textStyle.color属性设置成黑色
2.设置边框,borderWidth:1,borderColor:'#ECEEF2'
3.设置背景色为白色半透明,backgroundColor:'rgba(255,255,255,0.9)'
4.动画效果也不要了,直接设置动画时长为0,transitionDuration:0
样式调整好后,提示框的文字也需要进行一次格式化,在formatter的回调函数中进行配置。因为提示框的渲染方式renderMode,默认是html,所以回调函数里面我们可以配合CSS来编写我们自己的html。formatter的回调参数有3个,分别是:
1.params,这是提示框里面展示的数据的数据集。
2.ticket,这是异步回调的标识,数据格式跟params是一样的,一般配合第三个参数callback使用
3.callback,异步回调,与第二个参数ticket配合进行异步的数据展示。例如提示框中需要进行数据获取的请求时,可以用到这个组合。
这里我们不需要异步请求数据,所以直接使用params的数据进行展示。首先我们要遍历params数据集,拿到里面的数据,再通过数据集的数据名称seriesName进行判断是什么数据,对数据进行格式化,最后拼接成一段html用于渲染。(注:seriesName可以在series中,对数据进行命名)
命名数据
// 第一个图表的数据
{
name:"最新1",
// 平滑曲线
smooth:true,
// 是否显示折线上的圆点
symbol:'none',
// 线条颜色
lineStyle:{
color:"#0481F8",
width:1
},
xAxisIndex:0,
yAxisIndex:0,
data: grid1Data,
type: 'line',
z:3,
areaStyle:{
color:"#F8FAFF"
}
},
formatter回调函数
formatter:function(params,ticket,callback){
var html = '';
var x,j,c; for(var d in params){
if(params[d].seriesName == '成交量1' || params[d].seriesName == '成交量2' ){
c = params[d];
}
if(params[d].seriesName == '最新1' || params[d].seriesName == '最新2' ){
x = params[d];
} } if(!c.axisValue){
return;
} html += '<div class="tooltips-item"><span class="name">时间</span><span class="value">'+ echarts.format.formatTime('MM-dd hh:mm',parseFloat(c.axisValue)) +'</span></div>';
html += '<div class="tooltips-item"><span class="name">最新</span><span class="value '+ colorCls((typeof x.data == 'number' ? x.data : x.data[1])) +'">'+ (typeof x.data == 'number' ? x.data : x.data[1]) +'</span></div>';
html += '<div class="tooltips-item"><span class="name">涨跌幅</span><span class="value '+ colorCls((typeof x.data == 'number' ? x.data : x.data[1])) +'">'+ ((((typeof x.data == 'number' ? x.data : x.data[1]) - lastPrice)/ lastPrice * 100).toFixed(2)) +'%</span></div>';
html += '<div class="tooltips-item"><span class="name">涨跌额</span><span class="value '+ colorCls((typeof x.data == 'number' ? x.data : x.data[1])) +'">'+ ((typeof x.data == 'number' ? x.data : x.data[1])- lastPrice).toFixed(2) +'</span></div>';
html += '<div class="tooltips-item"><span class="name">成交量</span><span class="value">'+ (typeof c.data == 'number' ? (c.data / 1000000).toFixed(2) : (c.data[1] / 1000000).toFixed(2)) +'万手</span></div>'; return html;
}
部分CSS
#charts{
/*折线图的宽度*/
width:640px;
/*折线图的高度*/
height:390px;
}
.tooltips-item{
display:flex;
display:-webkit-flex;
justify-content: space-between;
color:#33333c;
font-size:10px;
width:120px;
}
.green{
color:#009933
}
.red{
color:#E24528
}
到这里,提示框的配置也完成了。仿分时图系列就结束了。
最终效果图如下
完整的代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>分时图</title>
<script type="text/javascript" src="js/jQuery.js" ></script>
<script type="text/javascript" src="js/echarts.min.js" ></script>
<style>
#charts{
/*折线图的宽度*/
width:640px;
/*折线图的高度*/
height:390px;
}
.tooltips-item{
display:flex;
display:-webkit-flex;
justify-content: space-between;
color:#33333c;
font-size:10px;
width:120px;
}
.green{
color:#009933
}
.red{
color:#E24528
}
</style>
</head>
<body>
<div id="charts"> </div>
<script type="text/javascript">
// 雪球json数据 到雪球网站获取 https://stock.xueqiu.com/v5/stock/chart/minute.json?symbol=SH000001&period=1d
var jsonData = '';
var data = JSON.parse(jsonData); // 第一个grid的数据(折线图)
var grid1Data = [];
// 第二个grid的数据(柱状图)
var grid2Data = [];
// 第三个grid数据(折线图)
var grid3Data = [];
var grid3DateData = [];
// 第四个grid数据(柱状图)
var grid4Data = [];
var grid4DateData = []; // 柱状图的颜色
// 柱状图的红绿规则比较麻烦,所以本次采用的规则则是根据价格的涨跌来区分
var volumeColor1 = [];
var volumeColor2 = []; var UP_COLOR = "#E24528";
var DOWN_COLOR = "#009933";
var NORMAL_COLOR = "#33353C"; var priceMax = 0,priceMin = 0,priceInterval = 0,volumeMax = 0,volumeMin = 0,volumeInterval = 0;
var lastPrice = data.data.last_close; initData(); function colorCls(num){
if(num > lastPrice){
return "red";
}else if(num == lastPrice){
return "";
}
return "green";
} function initData(){ for(var i in data.data.items){
// 上午的数据
if(i < 121){
if(data.data.items[i].current > priceMax){
priceMax = data.data.items[i].current;
}
if(data.data.items[i].current < priceMin || priceMin == 0){
priceMin = data.data.items[i].current;
}
// 左上方折线图
grid1Data.push([data.data.items[i].timestamp,data.data.items[i].current]); if(data.data.items[i].volume > volumeMax){
volumeMax = data.data.items[i].volume;
}
if(data.data.items[i].volume < volumeMin ){
volumeMin = data.data.items[i].volume;
} if(i == 0){ if(data.data.items[i].current >= lastPrice){
volumeColor1.push(UP_COLOR);
}else{
volumeColor1.push(DOWN_COLOR);
} }else{
if(data.data.items[i].current >= data.data.items[i-1].current){
volumeColor1.push(UP_COLOR);
}else{
volumeColor1.push(DOWN_COLOR);
} } // 左下方柱状图
grid2Data.push([data.data.items[i].timestamp,data.data.items[i].volume]); }else{// 下午的数据 if(data.data.items[i].current > priceMax){
priceMax = data.data.items[i].current;
}
if(data.data.items[i].current < priceMin || priceMin == 0){
priceMin = data.data.items[i].current;
}
// 第三grid的数据先添加一条数据
if(grid3Data.length == 0){
grid3Data.push(data.data.items[i-1].current);
grid3DateData.push(data.data.items[i-1].timestamp);
}
// 右上方折线图
grid3Data.push(data.data.items[i].current);
grid3DateData.push(data.data.items[i].timestamp); if(data.data.items[i].volume > volumeMax){
volumeMax = data.data.items[i].volume;
}
if(data.data.items[i].volume < volumeMin){
volumeMin = data.data.items[i].volume;
} if(data.data.items[i].current >= data.data.items[i-1].current){
volumeColor2.push(UP_COLOR);
}else{
volumeColor2.push(DOWN_COLOR);
} // 第四grid的数据先添加一条数据
if(grid4Data.length == 0){
grid4Data.push(data.data.items[i-1].volume);
grid4DateData.push(data.data.items[i-1].timestamp);
}
// 右下方柱状图
grid4Data.push(data.data.items[i].volume);
grid4DateData.push(data.data.items[i].timestamp); }
} // 重新计算价格的最大最小值,以达到对称的效果
if((lastPrice - priceMax) * -1 > (lastPrice - priceMin)){
priceMin = (lastPrice - ((lastPrice - priceMax)* -1));
}else{
priceMax =(lastPrice + (lastPrice - priceMin));
} priceInterval = (priceMax - lastPrice) / 4;
volumeInterval = volumeMax / 2; setOptions();
} function setOptions(){ var nowDate; // 初始化一个echarts的对象
var chart = echarts.init(document.getElementById('charts')); // echarts折线图的配置项
var option = {
animation:false,
//坐标轴指示器
axisPointer:{
show:true,
// 配置线条风格为虚线风格
lineStyle:{
type:'dashed'
},
link:[
{
xAxisIndex:[0,1],
},{
xAxisIndex:[2,3],
},{
yAxisIndex:[0,2]
},{
yAxisIndex:[1,3]
}
]
},
// 悬浮框
tooltip:{
trigger:'axis',
position:function(point, params, dom, rect, size){
var obj ={
top:10
} console.log(size); if(point[0] > size.viewSize[0] / 2){
obj["left"] = 70;
}else{
obj["right"] = 70;
} return obj;
},
formatter:function(params,ticket,callback){
var html = '';
var x,j,c; for(var d in params){
if(params[d].seriesName == '成交量1' || params[d].seriesName == '成交量2' ){
c = params[d];
}
if(params[d].seriesName == '最新1' || params[d].seriesName == '最新2' ){
x = params[d];
} } if(!c.axisValue){
return;
} html += '<div class="tooltips-item"><span class="name">时间</span><span class="value">'+ echarts.format.formatTime('MM-dd hh:mm',parseFloat(c.axisValue)) +'</span></div>';
html += '<div class="tooltips-item"><span class="name">最新</span><span class="value '+ colorCls((typeof x.data == 'number' ? x.data : x.data[1])) +'">'+ (typeof x.data == 'number' ? x.data : x.data[1]) +'</span></div>';
html += '<div class="tooltips-item"><span class="name">涨跌幅</span><span class="value '+ colorCls((typeof x.data == 'number' ? x.data : x.data[1])) +'">'+ ((((typeof x.data == 'number' ? x.data : x.data[1]) - lastPrice)/ lastPrice * 100).toFixed(2)) +'%</span></div>';
html += '<div class="tooltips-item"><span class="name">涨跌额</span><span class="value '+ colorCls((typeof x.data == 'number' ? x.data : x.data[1])) +'">'+ ((typeof x.data == 'number' ? x.data : x.data[1])- lastPrice).toFixed(2) +'</span></div>';
html += '<div class="tooltips-item"><span class="name">成交量</span><span class="value">'+ (typeof c.data == 'number' ? (c.data / 1000000).toFixed(2) : (c.data[1] / 1000000).toFixed(2)) +'万手</span></div>'; return html;
},
textStyle:{
color:"#000"
},
borderWidth:1,
borderColor:"#ECEEF2",
backgroundColor:"rgba(255,255,255,0.9)",
transitionDuration:0,
axisPointer:{
animation:false,
type:"cross"
}
},
// grid
grid:[
// 第一个grid
{
top:10,// 图表的外边距
height:240,// 图表的高度
left:'5%',
width:'45%',//因为是左右各一个图表,使用百分比的方式显得更方便,
},
// 第二个grid,第二个图表是在第一个图表的下方,所以要把它定位到底部
{
top:280,//设置上方的外边距是第一个图表的高度再加10,使用top是方便我们调整下方grid的高度
left:'5%',
width:'45%',// 宽度与第一个图表一个大
height:80,
},
// 第三个grid,第三个图表是在第一个图表的右方,所以要把它定位到右方
{
top:10,// 图表的外边距
left:'50%',//设置右边图表的左边距是第一个图表的大小,达到定位右边的效果
width:'45%',// 宽度与第一个图表一个大
height:240,
},
// 第四个grid,第四个图表是在第三个图表的下方,所以要把它定位到底部
{
top:280,//设置上方的外边距是第三个图表的高度再加10,使用top是方便我们调整下方grid的高度
left:'50%',//设置右边图表的左边距是第三个图表的大小,达到定位右边的效果
width:'45%',// 宽度与第一个图表一个大
height:80,
}
],
// 多个图表则会存在对个x轴y轴,所以这里的配置我们也换成数组的方式
// x轴配置,
xAxis:[
// 第一个grid的x轴属性
{ // 告诉echarts,这个第一个grid的x轴
gridIndex:0,
// 坐标轴是否留白
boundaryGap:false,
// x轴的刻度
axisTick:{show:false},
// x轴的刻度值
axisLabel:{show:false},
max:'dataMax',
min:'dataMin',
type: 'time',
axisPointer:{
show:true,
label:{
show:false
}
},
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
splitLine:{
lineStyle:{
color:"#ECEEF2",
type:"solid"
}
},
},
// 第二个grid的x轴属性
{
// 告诉echarts,这个第一个grid的x轴
gridIndex:1,
// 坐标轴是否留白
boundaryGap:false,
// x轴的刻度
axisTick:{show:false},
max:'dataMax',
min:"dataMin",
type: 'time',
axisLabel: {
fontSize:12,
show: true,
color:'#888',
formatter: function (value) {
var a = echarts.format.formatTime('hh:mm', value);
if(a == "11:30"){
return "11:30/13:00";
}
if(a == "09:30"){
return " 09:30";
}
return a;
}
},
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
splitLine:{
lineStyle:{
color:"#ECEEF2",
type:"solid"
}
},
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:0,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
return echarts.format.formatTime('hh:mm', parseFloat(data.value))
}
},
},
},
// 第三个grid的x轴属性
{
// 告诉echarts,这个第一个grid的x轴
gridIndex:2,
// 坐标轴是否留白
boundaryGap:false,
// x轴的刻度
axisTick:{show:false},
// x轴的刻度值
axisLabel:{show:false},
type: 'category',
data:grid3DateData,
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
max:"dataMax",
min:"dataMin",
axisPointer:{
show:true,
label:{
show:false
}
},
splitLine:{
show:true,
lineStyle:{
color:"#ECEEF2",
type:"solid"
},
interval:function(index,value){
if(index == 0 || index == 1){
return false;
} if((index - 1) % 30 == 0){
return true;
}
return false;
},
},
},
// 第四个grid的x轴属性
{
// 告诉echarts,这个第一个grid的x轴
gridIndex:3,
// 坐标轴是否留白
boundaryGap:false,
// x轴的刻度
axisTick:{
show:false
},
type: 'category',
max:"dataMax",
min:"dataMin",
data:grid4DateData,
axisLabel: {
fontSize:12,
show: true,
showMinLabel:false,
color:'#888',
interval:function(index,value){ if((index - 1) % 30 == 0){
return true;
}
return false;
},
formatter: function (value) {
var a = echarts.format.formatTime('hh:mm', parseFloat(value));
if(a == "15:00"){
return "15:00 ";
}
return a;
}
},
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
splitLine:{
show:true,
lineStyle:{
color:"#ECEEF2",
type:"solid"
},
interval:function(index,value){
// 第一条第二条线是不需要显示的,第一条是11:30的,第一个grid已经有这条数据了,所以不需要显示
// 第二条显示的话,在中间部分会出现2条线,所以也不要显示
if(index == 0 || index == 1){
return false;
}
// 这里的意思是第一条数据后,每30分钟显示一条线
if((index - 1) % 30 == 0){
return true;
}
return false;
},
},
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:0,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
return echarts.format.formatTime('hh:mm', parseFloat(data.value));
}
},
},
}
],
// y轴配置
yAxis: [
// 第一个grid的y轴属性
{
// 去掉刻度值旁边的指示线
axisTick:{show:false},
splitNumber:9,
gridIndex:0,
interval:priceInterval,
max:priceMax,
min:priceMin,
splitLine:{
lineStyle:{
color:"#ECEEF2",
type:"solid",
}
},
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
axisLabel:{
fontSize:10,
margin:0,
// y轴的数值向内显示
align:"left",
formatter: function (value, index) {
return value.toFixed(2);
},
color: function (value, index) { // 中间基准线的数值为黑色
if(parseFloat(value).toFixed(2) == lastPrice){
return NORMAL_COLOR;
} // 上涨区域的数字为红色
if(value > lastPrice){
return UP_COLOR;
} // 下方下跌的数值为绿色
if(value < lastPrice){
return DOWN_COLOR;
} }
},
z:3,
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:-44,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){ return data.value.toFixed(2);
}
},
},
},
// 第二个grid的y轴属性
{
// 去掉刻度值旁边的指示线
axisTick:{show:false},
splitNumber:3,
gridIndex:1,
interval:volumeInterval,
max:volumeMax,
min:0,
splitLine:{
lineStyle:{
color:"#ECEEF2",
type:"solid"
}
},
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
if(data.value > 1000000){
return parseFloat(data.value / 1000000).toFixed(2)+"万手";
}
return data.value;
}
},
},
axisLabel:{
align:"left",
verticalAlign:"top",
//设置显示坐标轴的数值为不显示
show:true,
fontSize:10,
margin:0,
showMaxLabel:true,
showMinLabel:false,
color:"#33353C",
formatter: function (value, index) {
// 格式化成月/日,只在第一个刻度显示年份
if(value == volumeMax){
// 方便演示
if(value > 1000000){
value = parseFloat(value / 1000000).toFixed(2)+"万手"
} return value;
}
return "";
}
},
},
// 第三个grid的y轴属性
{
// 去掉刻度值旁边的指示线
axisTick:{show:false},
splitNumber:9,
position:'right',
gridIndex:2,
interval:priceInterval,
max:priceMax,
min:priceMin,
splitLine:{
lineStyle:{
color:"#ECEEF2",
type:"solid"
}
},
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
axisLabel:{
fontSize:10,
margin:0,
// y轴的数值向内显示
align:"right",
formatter: function (value, index) {
var persent = (value - lastPrice) / lastPrice;
persent = (persent < 0) ? persent * -1 : persent;
persent = persent * 100; return persent.toFixed(2) + '%';
},
color: function (value, index) { // 中间基准线的数值为黑色
if(parseFloat(value).toFixed(2) == lastPrice){
return NORMAL_COLOR;
} // 上涨区域的数字为红色
if(value > lastPrice){
return UP_COLOR;
} // 下方下跌的数值为绿色
if(value < lastPrice){
return DOWN_COLOR;
} }
},
z:3,
axisPointer:{
show:true,
type:"line",
label:{
show:true,
fontSize:10,
margin:-34,
padding:2,
shadowBlur:0,
color:"#33353C",
formatter:function(data){
var persent = (data.value - lastPrice) / lastPrice;
persent = (persent < 0) ? persent * -1 : persent;
persent = persent * 100; return persent.toFixed(2) + '%';
}
},
},
},
// 第四个grid的y轴属性
{
// 去掉刻度值旁边的指示线
axisTick:{show:false},
splitNumber:3,
position:'right',
gridIndex:3,
interval:volumeInterval,
max:volumeMax,
min:0,
axisLabel:{
//设置显示坐标轴的数值为不显示
show:false
},
splitLine:{
lineStyle:{
color:"#ECEEF2",
type:"solid"
}
},
axisPointer:{
show:true,
label:{
show:false
}
},
axisLine:{
lineStyle:{
color:"#ECEEF2"
}
},
}
],
// 数据可以通过xAxisIndex,yAxisIndex属性,来指定是哪个grid的数据
series: [
// 第一个图表的数据
{
name:"最新1",
// 平滑曲线
smooth:true,
// 是否显示折线上的圆点
symbol:'none',
// 线条颜色
lineStyle:{
color:"#0481F8",
width:1
},
xAxisIndex:0,
yAxisIndex:0,
data: grid1Data,
type: 'line',
z:3,
areaStyle:{
color:"#F8FAFF"
}
},
// 第二个图表的数据
{
name:"成交量1",
xAxisIndex:1,
yAxisIndex:1,
// 柱状图柱子宽度
barWidth:1,
data: grid2Data,
type: 'bar',
// 设置柱状图颜色
itemStyle:{
normal: {
color: function (params) {
return volumeColor1[params.dataIndex];
}
}
}
},
// 第三个图表的数据
{
name:"最新2",
// 平滑曲线
smooth:true,
// 是否显示折线上的圆点
symbol:'none',
// 线条颜色
lineStyle:{
color:"#0481F8",
width:1
},
z:3,
xAxisIndex:2,
yAxisIndex:2,
data: grid3Data,
type: 'line',
areaStyle:{
color:"#F8FAFF"
}
},
// 第四个图表的数据
{
name:"成交量2",
xAxisIndex:3,
yAxisIndex:3,
// 柱状图柱子宽度
barWidth:1,
data: grid4Data,
type: 'bar',
// 设置柱状图颜色
itemStyle:{
normal: {
color: function (params) {
return volumeColor2[params.dataIndex];
}
}
}
}
]
}; chart.setOption(option); } </script>
</body>
</html>
总结:一开始做分时图的时候我也不懂从哪开始做,慢慢观察后才发现其实可以由折线图跟柱状图来拼接而成。知道拼接可以达到效果后,就开始写代码,期间也是遇到了很多问题,最开始是用两个echarts来组合,发现效果很丑,去查了一下文档,发现可以用grid来解决,接着就拆成了上下两个grid;然后上下午时间段这个问题,由于不是连续的,所以一个折线图解决不了,再次拆图表,把上下方的图表再一拆为二,拆成了两个后折线图出现了断崖式的效果,经过很多尝试后,把x轴的type修改成category属性,再对下午数据进行一些修改才解决了这个问题。做复杂的图表时,可以先分析一下这个图表可以由哪些图表来组成,然后再根据需求来对各个图表进行修改。echarts这个框架还是很好用的,图表类型丰富,文档全,能够高度自定义,重要还是免费的...
使用百度echarts仿雪球分时图(四)的更多相关文章
- 使用百度echarts仿雪球分时图(三)
这章节将完成我们的分时图,并使用真实的数据来进行展示分时图. 一天的交易时间段分为上午的09:30~11:30,下午的13:00~15:00两个时间段,因为分时间段的关系,数据是不连续的,所以会先分为 ...
- 使用百度echarts仿雪球分时图(一)
第一次写技术博客,有不足的地方希望大家指证出来,我再加以改正,谢谢大家. 之前一直没有找到一个合适的分时图项目,所以决定自己动手撸一个.接触的图表框架不多,在网上看到不少人推荐使用echarts,看了 ...
- 使用百度echarts仿雪球分时图(二)
上一章简单的介绍了一下分时图的构成,其实就是折线图跟柱状图的组成.本来这章打算是把分时图做完,然后再写一章来进行美化和总结,但是仔细观察了一下,发现其实东西还是有点多的.分时图的图表做完后,还要去美化 ...
- 使用百度Echarts制作力导向图
最近项目需求制作一个力导向图来展示企业的画像等关系信息,故想到了百度Echarts的关系图,在这使用Echarts3.0版本来实现.先上效果图,再看代吗 哎,本来想整个工程扔出来,发现好像没地方上传附 ...
- WPF仿百度Echarts人口迁移图
GitHub地址:https://github.com/ptddqr/wpf-echarts-map/tree/master 关于大名鼎鼎的百度Echarts我就不多说了 不了解的朋友直接看官方的例子 ...
- C#+JQuery+.Ashx+百度Echarts实现全国省市地图和饼状图动态数据图形报表的统计
在目前的一个项目中,需要用到报表表现数据,这些数据有多个维度,需要同时表现出来,同时可能会有大量数据呈现的需求,经过几轮挑选,最终选择了百度的echarts作为报表基础类库.echarts功能强大,界 ...
- 手把手教你画AndroidK线分时图及指标
先废话一下:来到公司之前.项目是由外包公司做的,面试初,没有接触过分时图k线这块,认为好难,我能搞定不.可是一段时间之后,发现之前做的那是一片稀烂,可是这货是主功能啊.迟早的自己操刀,痛下决心,开搞, ...
- html5--项目实战-仿360囧图
html5--项目实战-仿360囧图 实例: 代码 <!doctype html> <html> <head> <meta charset="utf ...
- Python socket编程之四:模拟分时图
建立 socket,先运行服务器,再运行客户端,建立连接后服务器从本地数据库调数据一截一截地发送给客户端,客户端接受数据绘图模拟分时图 1.socket # -*- coding: utf-8 -*- ...
随机推荐
- Android与JS交互,json传参问题
一.JS调用Android的方法 JS调用安卓的方法,并且传递的参数为json格式的字符串(JSONObject.toString()), 例如: var json = {"name&quo ...
- jpa 总结
转:http://blog.csdn.net/linzhiqiang0316/article/details/52639265 先来介绍一下JPA中一些常用的查询操作: //And --- 等价于 S ...
- 阶段5 3.微服务项目【学成在线】_day04 页面静态化_05-freemarker基础-List指令
controller填充数据 @RequestMapping("/freemarker") @Controller public class FreemarkerControlle ...
- python图论包networks(最短路,最小生成树带包)
官方文档: https://networkx.github.io/documentation/networkx-1.10/reference/algorithms.html 最短路和最小生成树: im ...
- thymeleaf中img标签图片src路径问题
转载自:解决java - Thymeleaf conditional img src 正确写法. <img class="layui-nav-img" th:src=&quo ...
- 【ML】seq2seq原理
最近要做分享,重温seq2seq原理,这篇文章讲的挺清楚: https://zhuanlan.zhihu.com/p/40920384 https://www.jianshu.com/p/b2b95f ...
- k8s install kubeadm网络原因访问不了谷哥and gpg: no valid OpenPGP data found. 解决办法
gpg: no valid OpenPGP data found. 解决办法 待做.................................... 卡助在这curl -s https://pa ...
- golang web框架设计3:controller设计
继续学习golang web框架设计 controller作用 MVC设计模式里面的这个C,控制器. Model是后台返回的数据: View是渲染页面,通常是HTML的模板页面: Controller ...
- jmeter操作—从redis中获取token
嗨,大家好,我是叶子 背景:某APP项目中需要进行各接口的性能测试,比如:测试商品的搜索功能.店铺查询功能等接口,测试时需要保持登录状态,所以需要获取到登录账号的token,方便之后的接口测试. 准备 ...
- webdriver(处理select下拉框元素)
"""处理下拉框""" from selenium import webdriver from selenium.webdriver.com ...