本例中,我们要做的是,
在原有echart表格的基础上,添加新的数据显示。
【大致思想】
分析原有表格中某项数据的显示原理,根据此原理,将我们所需要的数据展现出来。
即,最关键的就是分析数据库的数据,是通过一个怎样的过程,以图表的形式展现的。
第一步、分析
这一步,我们直到最后做出来,才刚刚搞清楚我们需要的原理。也即是说,这一步其实是最重要的。
接下来我们首先叙述下分析原理过程中的问题,然后再解释原理。
【问题】
我们依样画葫芦试着做的时候,遇到一个比较大的问题是,页面不停的刷新,刷新了一下午也刷不出最后的结果。
这里的原因可能有两点,
一者,
js错误,即,JSP页面不显示的原因,是JSP页面的代码出错了。
显而易见,显示的部分应当是不会出错的。因为我们根本就不需要动这部分。
JSP代码中的另一部分,js是我们改过的,所以,分析可能是这里出错。
二者,
后台出错,即,Controller中的某部分代码出错了。因为我们改了这部分里的一些代码。
【分析问题】
以上两个可能的问题,我们需要确定是哪一个。
我们首先需要知道,
前者js错误需要在F12控制台选项的js菜单中观察,我们怀疑js出错的时候,往往要到这里看有没有报错。
后者Controller代码报错,是在Eclipse的控制台中报错的。
最后我们分析得知,是js报错,但根本原因还是Controller中的代码错了。所以是二者都有错!
但js的报错信息,告诉我们哪里错了,我们从报错的地方追溯回去,才发现了问题所在。
【原理】
因为我们做的这个例子,是要在图表中显示新加的数据。新加的,我们要做的事情有人已经做过了。
我们要做的,要分析已经实现的部分的原理。
【数据流】
这里提出一个私人定义的概念,数据流。
即分析,我们看到的东西是从哪里来的。将这条路线画出来。正向推,反向推都是可以的。
接下来我们采用反向推!
以最接近我们要求的注册量为例:
{
/* 注册量 */
name : chart_line_names[i][0],
type : 'line',
data : data.list[i].data[0],
markPoint : {
data : [ {
type : 'max',
name : '最大值'
}, {
type : 'min',
name : '最小值'
} ]
},
markLine : {
data : [ {
type : 'average',
name : '平均值'
} ]
}
},
这里涉及到ECharts的知识。我们发现,图中的这条数据线的显示,所需的数据来自data。
即
data : data.list[i].data[0]再分析,data中的data是哪里来的
function base_member_regist_cnt_doChart(data){来自于这里,画图的js函数doChart所需的数据都来自于这个方法传进来的参数data
再分析,这个data是哪里来的
var jsonObj= data.chartDatas;来自于jsonObj,jsonObj又来自于data.chartDatas
base_member_regist_cnt_doChart(jsonObj);
分析这里的data是哪儿的。【注意:我们分析数据来源时,只分析源,不需要管data.balabala里的balabala这些东西】
$.getJSON(base_member_regist_cnt_url, paramdata, function (data) {我们发现data是通过访问链接得到的JSON数据。
分析下paramdata是哪里来的。
function base_member_regist_cnt_genJson(paramdata){
var $form = $(form);var paramdata = $form.serializeArray();base_member_regist_cnt_genJson(paramdata);我们发现paramdata来自于form。
<form id="form1" action="chart/base_member_regist_cnt.html" method="get" onsubmit="return base_member_regist_cnt_submit(this);">也即是,来自于表单的提交。
<div class='ichartjs_details' style="margin-left:200px;margin-bottom:10px">
日期:<input type="text" id="base_member_regist_cnt_startDate" name="startDate" class="date" minDate="2010-07-15" value="" maxDate="{%y}-%M-{%d}" />
与
<input type="text" id="base_member_regist_cnt_compareDate" name="compareDate" class="date" minDate="2010-07-15" value="" maxDate="{%y}-%M-{%d}" />
与 前<select name="intervalDay" id="base_member_regist_cnt_intervalDay">
<option value="3" >3日</option>
<option value="7" >7日</option>
<option value="30">1个月</option>
</select>平均值
<button type="submit">比较</button><br />
</div>
</form>
我们如果想得到这个JSON数据,就需要传递paramdata,才能够得到。
@RequestMapping("/base_member_regist_cnt.json")我们找到了要访问的链接。而且这个链接的确是返回了一个jsonView。
public String base_member_regist_cnt(String startDate,String compareDate, String intervalDay, ModelMap modelMap) throws MyException, ParseException {
也就是说,这个名为base_member_regist_cnt的方法中,在jsonView中装入了数据。
我们接下来就是要分析,它是怎么在这个方法里取得数据并把它装入jsonView的。
该方法的精简版方法体如下
if(startDate == null || startDate.trim().length() == 0) {根据以上方法体的代码, 我们依然反向来推!
startDate=dateUtil.getString(new Date(), "yyyy-MM-dd");
}
if(intervalDay == null || intervalDay.trim().length() == 0) {
intervalDay="7";
}
if(compareDate == null || compareDate.trim().length() == 0) {
Date date=dateUtil.addDay(new Date(), -Integer.valueOf(intervalDay));
compareDate=dateUtil.getString(date, "yyyy-MM-dd");
}
ParamMap paramMap=new ParamMap();
paramMap.put("startDate", startDate);
paramMap.put("compareDate", compareDate);
paramMap.put("intervalDay", intervalDay);
EChartsData eChartsData=new EChartsData(paramMap);
String sqlStr;
String[] hoursLabels = LabelUtil.getLabelByIntBegin_00(24);
ECharts eCharts2 = new ECharts(hoursLabels);
//当日注册数
List<Map<String,Object>> list2;
sqlStr = stringUtil.formatMsg(
"select DATE_FORMAT(b.CREATED_DATE,'%H') as label,count(MEMBER_ID) as STARTDATE_COUNT from moyoyo_member.BASE_INFO b where DATE_FORMAT(b.CREATED_DATE,'%Y-%m-%d') = '{0}' group by DATE_FORMAT(b.CREATED_DATE,'%H')",
new Object[]{startDate});
list2 = chartDataService.getChartList(sqlStr);
eCharts2.add(LabelUtil.getValue(list2, hoursLabels,"label","STARTDATE_COUNT"));
List<Map<String,Object>> list21;
sqlStr = stringUtil.formatMsg(
"select DATE_FORMAT(b.CREATED_DATE,'%H') as label,count(MEMBER_ID) as COMPAREDATE_COUNT from moyoyo_member.BASE_INFO b where DATE_FORMAT(b.CREATED_DATE,'%Y-%m-%d') = '{0}' group by DATE_FORMAT(b.CREATED_DATE,'%H')",
new Object[]{compareDate});
list21 = chartDataService.getChartList(sqlStr);
eCharts2.add(LabelUtil.getValue(list21, hoursLabels,"label","COMPAREDATE_COUNT"));
Date date=dateUtil.getDateObj(startDate);
date=dateUtil.addDay(date, -Integer.valueOf(intervalDay));
String compareStartDate=dateUtil.getString(date, "yyyy-MM-dd");
List<Map<String,Object>> list22;
sqlStr = stringUtil.formatMsg("select DATE_FORMAT(b.CREATED_DATE,'%H') as label,round(count(MEMBER_ID)/{0},0) as AVG_COUNT from moyoyo_member.BASE_INFO b where b.CREATED_DATE >= '{1}' and b.CREATED_DATE<'{2}' group by DATE_FORMAT(b.CREATED_DATE,'%H')"
, new Object[]{intervalDay,compareStartDate,startDate});
list22 = chartDataService.getChartList(sqlStr);
eCharts2.add(LabelUtil.getValue(list22, hoursLabels,"label","AVG_COUNT"));
eChartsData.add(eCharts2);
modelMap.addAttribute("chartDatas", eChartsData);
return "jsonView";
}
jsonView 的数据肯定是来自于modelMap
modelMap.addAttribute("chartDatas", eChartsData);
modelMap中的数据来自于eChartsData。
eChartsData中的又装入了eCharts2。
eChartsData.add(eCharts2);而eCharts2中的数据又是eCharts2 add了三次得到的。
eCharts2.add(LabelUtil.getValue(list2, hoursLabels,"label","STARTDATE_COUNT"));
eCharts2.add(LabelUtil.getValue(list21, hoursLabels,"label","COMPAREDATE_COUNT"));
eCharts2.add(LabelUtil.getValue(list22, hoursLabels,"label","AVG_COUNT"));而add的内容中又包含了list2,list21,list22三个list。
list2 = chartDataService.getChartList(sqlStr);
list21 = chartDataService.getChartList(sqlStr);
list22 = chartDataService.getChartList(sqlStr);而每个list又是通过sqlStr取得的数据。
这样看来,
方法这种不变的东西,如果重复了很多遍,我们只需要分析一次就可以,我们需要找的,是这一个方法追溯到最后,
不一样的那个参数,而这个参数绝对是很明显的那种。
sqlStr = stringUtil.formatMsg(就像这样!而这里就是我们得到数据的地方。SQL从数据库中取得数据。
"select DATE_FORMAT(b.CREATED_DATE,'%H') as label,count(MEMBER_ID) as STARTDATE_COUNT from moyoyo_member.BASE_INFO b where DATE_FORMAT(b.CREATED_DATE,'%Y-%m-%d') = '{0}' group by DATE_FORMAT(b.CREATED_DATE,'%H')",
new Object[]{startDate});
至此,我们要分析的原理,其实就是数据流已经分析完成了。
我们看到了数据从哪里来,到哪里去。
我们要注意的是,没有分析到最明显的参数那一步时,就不算分析完,因为还没有找到数据的源头。
【知识】
JSON格式的数据。什么是JSON数据?
我们在分析代码的时候,怀疑过为什么直接return一个jsonView就可以返回数据呢?
这个JSONVIEW到底是什么东西。经过研究,我们可以知道:
json是一种轻量级的数据交换格式。可以是一堆键值对,也可以是一堆数组。这里我们没有分析出它是什么?
但是没有关系,只需要知道json数据就是可以封装一大堆数据的数据对象。
否则,我们在JSP中画图的时候为什么总是传递JSON对象呢?23333333333
第二步、搭建框架
我们从需求就可以知道,我们要改动的关键地方就是SQL。
我们需要增加多少个数据,就按原理分析的来,增加多少个一样的部分。
这些一样的部分!是体力活!最后我们才专注于改动SQL。
第三步、改动SQL
这里的SQL又涉及到了联表查询。又是我们比较头疼的这种联表查询。
本例中,其实我们实际做的时候是很快就把SQL写好了,只是一直不太确定是不是正确的。
这里如何判断是否SQL正确呢?
一个最好用且最常用的办法,【我们也是今天才明确这个东西的作用】
使用Navicat的查询功能。
我们看下Navicat的界面,发现查询选项是在某个数据库的菜单下的,这个数据库中有很多的表。
我们要做的联表查询,肯定是在一个数据库中做的。
所以我们活用这个查询功能。
这里再提出一个私人的定义。
【SQL调试器】
我们可以把Navicat的查询功能当做一个SQL的调试器,我们不确定写出来的SQL是不是对的,
换句话说,就是它能不能够取到数据,取到的数据是否正确,这些东西,
查询之后,是可以直接在界面中看到的。如果有错,选择不到我们需要的数据,随时修改就可以。
而且这样做还有一个好处,Navicat中有美化SQL格式的功能。
我们可以更加清晰的看到SQL的语法,如果哪里需要修改,也很清晰明了。
最终我们用来联表查询的SQL例子如下:
SELECT发现其实意外的简单。其它几个SQL,只要照猫画虎,按照原来的SQL来写就可以啦。
DATE_FORMAT(b.CREATED_DATE, '%H') AS label,
count(d.MEMBER_ID) AS STARTDATE_COUNT
FROM
moyoyo_member.BASE_INFO b
LEFT JOIN moyoyo_member.DETAIL_INFO d ON b.MEMBER_ID = d.MEMBER_ID
WHERE
DATE_FORMAT(b.CREATED_DATE, '%Y-%m-%d') = '{0}'
AND d.CHANNEL_TYPE = 1
GROUP BY
DATE_FORMAT(b.CREATED_DATE, '%H')
第四步、画图
接下来,到了最为关键的一步。画图!
我们拿到了数据,并且传回来了。怎么来画这个图呢?
还是分析原来已经画好的图的原理。
function base_member_regist_cnt_doChart(data){画图主要靠这个js函数,doChart来完成。
$("input#base_member_regist_cnt_startDate").val(data.paramMap['startDate']);
$("input#base_member_regist_cnt_compareDate").val(data.paramMap['compareDate']);
$("#base_member_regist_cnt_intervalDay").val(data.paramMap['intervalDay']);
chart_titles = ['用户注册情况','当日注册数量比较'];
chart_line_names = [
['总数'],
[data.paramMap['startDate']+' 注册量',
data.paramMap['startDate']+' WAP 注册量',
data.paramMap['startDate']+' WEB 注册量',
data.paramMap['startDate']+' APP 注册量',
data.paramMap['startDate']+' SDK 注册量',
data.paramMap['compareDate']+' 注册量',
data.paramMap['compareDate']+' WAP 注册量',
data.paramMap['compareDate']+' WEB 注册量',
data.paramMap['compareDate']+' APP 注册量',
data.paramMap['compareDate']+' SDK 注册量',
'前'+data.paramMap['intervalDay']+'天平均注册量',
'前'+data.paramMap['intervalDay']+'天 WAP 平均注册量',
'前'+data.paramMap['intervalDay']+'天 WEB 平均注册量',
'前'+data.paramMap['intervalDay']+'天 APP 平均注册量',
'前'+data.paramMap['intervalDay']+'天 SDK 平均注册量',
]
];
先定义了一堆title和图例的名字。。。。
接下来,要画图的data传递进来了,这个函数是如何处理这个data的呢?
i = 1到这一步,完全就是ECharts的知识了。
if(data.list[i].data[0].length==0){
chart_div = document.getElementById('base_member_regist_cnt_canvasDiv' + i)
html = '';
html+='<div style="font-size: 14px;text-align: center; width: 100%;height:100%;color:red">'
html+= data.paramMap["startDate"]+ chart_titles[i] + ' 暂时没有数据'
html+= '</div>'
chart_div.innerHTML=html;
}
if(data.list[i].data[0].length>0){
echarts.init(document.getElementById('base_member_regist_cnt_canvasDiv' + i)).setOption({
title : {
text : data.paramMap["startDate"]+ chart_titles[i],
x : "center"
},
tooltip : {
trigger : 'axis'
},
legend : {
data : chart_line_names[i],
y : 'bottom'
},
toolbox : {
show : true,
feature : {
dataView : {
show : true,
readOnly : false
},
magicType : {
show : true,
type : [ 'line', 'bar' ]
},
restore : {
show : true
},
saveAsImage : {
show : true
}
}
},
calculable : true,
xAxis : [ {
type : 'category',
data : data.list[i].labels
} ],
yAxis : [ {
type : 'value',
scale : true,
name : '注册数量',
axisLabel : {
formatter : '{value} 个'
}
} ],
series : [
{
/* 注册量 */
name : chart_line_names[i][0],
type : 'line',
data : data.list[i].data[0],
markPoint : {
data : [ {
type : 'max',
name : '最大值'
}, {
type : 'min',
name : '最小值'
} ]
},
markLine : {
data : [ {
type : 'average',
name : '平均值'
} ]
}
},
如何定义坐标轴,如何定义图例,如何定义标题等等等等。
这些东西都已经写好了,我们只需要添加新的数据进去就可以了。
经过分析,我们可以知道,series里面是一条一条的数据。我们新添加一项数据,就是在这里添加。
根据特定的格式添加就去就好了,很简单!
【图例问题】
图画出来以后,我们发现有个问题,图例过于混乱了,
如何整理这个图例呢?
【图例相关的修改】
要整理图例,要修改的是-------图例相关代码!
legend : {在整理这个图例的过程中,我们主要修改了legend(英文意思就是传奇、图例)
data : chart_line_names[i],
textStyle:{fontSize:12},
//x:'left',
//y:'50px',
//orient:'vertical',
y : '365px',
},
中的x、y,即图例的位置。因为图例最开始与图表重合了,我们将图例向下移动,即调整y的坐标,最终发现y的坐标为365px比较合适。
这个365px是图例与图表顶端的距离。
后来发现怎么修改都不合适,只能调整图例字体的大小,
textStyle:{fontSize:12},才调整到了一个比价合适的状态,如下!
另一种方法,其实可以不用修改字体的大小,转而修改字的多少,把图例简化,如:
2015-11-23注册量改为11-23,就可以节省不少空间。该例中,图例不合适的原因就是太多,占的空间也太多了!
修改的过程中,我们用到了js取子字符串的知识。
【js取子字符串】
data.paramMap['startDate'].substr(5,5),即substr函数,表示从第几位开始,取几位数!
【js检测数据的传送】
这个问题我们之前就说过,这里又用到了,但是没有想起来用,所以再重申一遍。
alert()的用法。相当于Java代码中的System.out.println,相当于Python代码中的print。
加了alert(),我们刷新页面的时候,就会自动跳出包含了数据信息的提示框。
【ECharts表格的默认选中或默认不选中】
接下来我们要实现另一个效果,即,刚刷出页面的时候,需要只显示前五条记录。其它的数据默认不显示。
我们从ECharts的官方网站例子中了解到应当在legend的selected中进行设置。
option = {其中,将'降水量'这一项设置为false,刷新页面的时候降水量这一项就会默认不选中。
legend: {
orient: 'horizontal', // 'vertical'
x: 'right', // 'center' | 'left' | {number},
y: 'top', // 'center' | 'bottom' | {number}
backgroundColor: '#eee',
borderColor: 'rgba(178,34,34,0.8)',
borderWidth: 4,
padding: 10, // [5, 10, 15, 20]
itemGap: 20,
textStyle: {color: 'red'},
selected: {
'降水量' : false
},
data: [
{
name:'蒸发量',
icon : 'image://../asset/ico/favicon.png',
textStyle:{fontWeight:'bold', color:'green'}
},
'降水量','最高气温', '最低气温'
]
},
本例中,我们的图例很多,而且图例的名字不是死的,而是由每天的日期与其它字符串组成的。
chart_line_names = [官方的例子中,这种效果实现时,图例名字是死的,直接写出来。
['总数'],
[data.paramMap['startDate'].substr(5,5),
data.paramMap['startDate'].substr(5,5)+' WAP',
data.paramMap['startDate'].substr(5,5)+' WEB',
data.paramMap['startDate'].substr(5,5)+' APP',
data.paramMap['startDate'].substr(5,5)+' SDK',
<pre name="code" class="javascript"> data.paramMap['compareDate'].substr(5,5),
<pre name="code" class="javascript"> data.paramMap['compareDate'].substr(5,5)+' WAP',
data.paramMap['compareDate'].substr(5,5)+' WEB',
data.paramMap['compareDate'].substr(5,5)+' APP',
data.paramMap['compareDate'].substr(5,5)+' SDK',
'前'+data.paramMap['intervalDay']+'天平均',
'前'+data.paramMap['intervalDay']+'天 WAP 平均',
'前'+data.paramMap['intervalDay']+'天 WEB 平均',
'前'+data.paramMap['intervalDay']+'天 APP 平均',
'前'+data.paramMap['intervalDay']+'天 SDK 平均',
]
];
这里如果我们直接传参数进去,
if(data.list[i].data[0].length>0){<pre name="code" class="javascript">echarts.init(document.getElementById('base_member_regist_cnt_canvasDiv' + i)).setOption({这种写法,没有达到我们想要的效果。
title : {
text : data.paramMap["startDate"]+ chart_titles[i],
x : "center"
},
tooltip : {
trigger : 'axis'
},
legend : {
data : chart_line_names[i],
textStyle:{fontSize:12},
//x:'left',
//y:'50px',
//orient:'vertical',
y : '365px',
selected:{
chart_line_names[1][0]:false
}
},
});
即,
官方的写法只适用于图例名字死的时候,
如果图例名字为变量,这样写是不行的,因为这个变量的值,传不到legend中的selected中去。
最终,我们只能改变代码的结构来达到目的。如下:
先定义一个option
option= {
title : {
text : data.paramMap["startDate"]+ chart_titles[i],
x : "center"
},
tooltip : {
trigger : 'axis'
},
legend : {
data : chart_line_names[i],
textStyle:{fontSize:12},
//x:'left',
//y:'50px',
//orient:'vertical',
y : '365px',
selected:{}
},
option.legend.selected[chart_line_names[1][5]] = false;option.legend.selected[chart_line_names[1][6]] = false;option.legend.selected[chart_line_names[1][7]] = false;option.legend.selected[chart_line_names[1][8]] = false;option.legend.selected[chart_line_names[1][9]] = false;option.legend.selected[chart_line_names[1][10]] = false;option.legend.selected[chart_line_names[1][11]] = false;option.legend.selected[chart_line_names[1][12]] = false;option.legend.selected[chart_line_names[1][13]] = false;option.legend.selected[chart_line_names[1][14]] = false;echarts.init(document.getElementById('base_member_regist_cnt_canvasDiv' + i)).setOption(option);}即先定义好option,然后再定义option中的legend中的selected属性。
这样最终可以达到我们想要的效果。
【注意】
这样的修改,代码结构发生了变化。还有一个地方需要注意,
我们要在option定义完后再修改legend中的selected属性值,需要现在option中声明一下有selected这么个属性。
legend : {否则会js报错,option.legend.selected没有被定义。
data : chart_line_names[i],
textStyle:{fontSize:12},
//x:'left',
//y:'50px',
//orient:'vertical',
y : '365px',
selected:{}
},
修改过这个图例以后的效果如下:
接下来我们要做的另外一件事情,是自定义tooltip,我们现在的代码中,
tooltip是默认样式的,
tooltip : {即跟着图例走。
trigger : 'axis'
},
我们想定义我们想要的悬浮框,就需要自己来写!
【自定义ECharts悬浮框样式】
实现这个自定义的悬浮框,我们参考的是ECharts官方的例子代码,最终成功实现!
官方的代码如下:
option = {这个代码例子乍看很复杂,我们这里再提出一个私人的定义。
tooltip : { // Option config. Can be overwrited by series or data
trigger: 'axis',
//show: true, //default true
showDelay: 0,
hideDelay: 50,
transitionDuration:0,
backgroundColor : 'rgba(255,0,255,0.7)',
borderColor : '#f50',
borderRadius : 8,
borderWidth: 2,
padding: 10, // [5, 10, 15, 20]
position : function(p) {
// 位置回调
// console.log && console.log(p);
return [p[0] + 10, p[1] - 10];
},
textStyle : {
color: 'yellow',
decoration: 'none',
fontFamily: 'Verdana, sans-serif',
fontSize: 15,
fontStyle: 'italic',
fontWeight: 'bold'
},
formatter: function (params,ticket,callback) {
console.log(params)
var res = 'Function formatter : <br/>' + params[0].name;
for (var i = 0, l = params.length; i < l; i++) {
res += '<br/>' + params[i].seriesName + ' : ' + params[i].value;
}
setTimeout(function (){
// 仅为了模拟异步回调
callback(ticket, res);
}, 1000)
return 'loading';
}
//formatter: "Template formatter: <br/>{b}<br/>{a}:{c}<br/>{a1}:{c1}"
},
toolbox: {
show : true,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
magicType : {show: true, type: ['line', 'bar', 'stack', 'tiled']},
restore : {show: true},
saveAsImage : {show: true}
}
},
calculable : true,
xAxis : {
data : ['周一','周二','周三','周四','周五','周六','周日']
},
yAxis : {
type : 'value'
},
series : [
{
name:'坐标轴触发1',
type:'bar',
data:[
{value:320, extra:'Hello~'},
332, 301, 334, 390, 330, 320
]
},
{
name:'坐标轴触发2',
type:'bar',
data:[862, 1018, 964, 1026, 1679, 1600, 157]
},
{
name:'数据项触发1',
type:'bar',
tooltip : { // Series config.
trigger: 'item',
backgroundColor: 'black',
position : [0, 0],
formatter: "Series formatter: <br/>{a}<br/>{b}:{c}"
},
stack: '数据项',
data:[
120, 132,
{
value: 301,
itemStyle: {normal: {color: 'red'}},
tooltip : { // Data config.
backgroundColor: 'blue',
formatter: "Data formatter: <br/>{a}<br/>{b}:{c}"
}
},
134, 90,
{
value: 230,
tooltip: {show: false}
},
210
]
},
{
name:'数据项触发2',
type:'bar',
tooltip : {
show : false,
trigger: 'item'
},
stack: '数据项',
data:[150, 232, 201, 154, 190, 330, 410]
}
]
};
【代码简化法则】
有一个需求,我们需要编程来实现功能会有以下几种情况:
一者,从头开始写,这个时候我们需要寻找例子来参考,官方的或是私人的,有可能是比较复杂的例子;
二者,一部分有人已经做过了,本例就是这样。
这个时候我们需要做的就是理清楚逻辑。
看清楚代码的逻辑,我们要做的就是把代码简化到只剩逻辑!这就是简化!
比如以上这个自定义悬浮框的例子代码,我们可以去掉很多东西。
比如悬浮框的样式定制,字体定制,模拟异步回调等等。这些都是无关紧要的东西,我们可以去掉。
知道最后我们可以清楚的看到自定义悬浮框的核心代码,tooltip部分。
tooltip : {这部分代码的意思是:
trigger : 'axis',
formatter: function (s) {
var res = 'Formatter:<br/>'+s[0].name;
for (var i = 0, l = s.length; i < l; i++) {
res += '<br/>' + s[i].seriesName + ' 注册量 : ' + s[i].value;
}
return res;
}
},
当鼠标移到光标时,会有数据传回来,装入参数s中,
然后这个function会执行下面的代码,实现对tooltip的定制。
这里的这个参数s,可以随意起名字,比如params等等。
这个参数之所以可以这样使用,我们可以类比AJAX的数据回调,function(data)这个data就可以随意起名字,
参数名字只不过是传回来的数据的一个容器,AJAX中不过是习惯性的起名为data而已。
最终我们的效果图如下!
截图快捷键:ctrl+alt+a