在相关的后台系统开发中,有一个必不可少的模块就是图表主题分析。通过图表分析,可以更加直观的展示业务的发展状态及各个业务占比情况,更加有利于公司领导做出相应的决策。在开发的最近一个项目中,有用到了Java 的 Echarts 开发其相应的后台图表主题分析模块功能。既然用到了,就概要的说下,希望以后在需要使用或者有其他人需要使用的话,只需要看下教程就可以立即上手操作使用,而不需要重新去看文档花掉很多时间。
序: 在刚开始使用这个图表插件的时候,我一般是首先新建一个页面,然后的话把相应的官网Demo例子全文复制到该新建的页面中,然后运行该页面,观察其是否能够正常运行。如果不能运行的话,找出其相应的原因,总之最后把这个Demo例子先成功运行起来是开始学习的首要且重要的一件事。当你把下载下来的例子成功在你新建的页面中运行起来的时候,然后开始动态赋值,从后台动态加载数据,开始轻微的修改代码,与后台进行交互。做到这一点之后,前后台的数据填充和交互差不多就OK了,然后的话图表主题分析肯定是要有其相应的搜索条件,根据选择的搜索条件去动态的加载图表并重绘。这样的话一步步就差不太多了。(注:因为在项目中,我的饼图和折线图是在一个JSP页面中绘制的,所以的话下面的讲解都是基于一个JSP两个图表的分析)
***********************************************************************************
饼图和折线图:
1,引入JQuery minui 和 Echarts 相关的 js 文件 并绘制相应的JSP图表界面;( JQuery mini 项目中有用到,没有用到可以不用引入 )
<head>
<title></title>
<script src="resource/js/boot.js" type="text/javascript"></script>
</head>
<fieldset id="query_fieldset" style="">
<legend>查询结果</legend>
<div style="width:99%;">
<div class="ct" id="chart1" style="height:100%;width:96%;margin:0 auto;">></div>
</div>
<div style="width:99%;">
<div id="chartContainer" style="height:100%;width:96%;">></div>
</div>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/echarts-all-3.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts-stat/ecStat.min.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/extension/dataTool.min.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/map/js/china.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/map/js/world.js"></script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=ZUONbpqGBsYGXNIYHicvbAbM"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/extension/bmap.min.js"></script>
</fieldset>
2,引入 Echarts 饼图和折线图的 Options 参数并初始化图表;
<script type="text/javascript">
mini.parse();
var chartPie = echarts.init(document.getElementById('chart1'));
var chartCross = echarts.init(document.getElementById('chartContainer'));
var form = new mini.Form("#queryForm");
//=======初始加载 "饼图" 和 "折线图"数据=======
var data = search();
//====================================
var option = {
title: {
text: '业务饼图分析',
subtext: '各类业务申请次数(人次)',
textStyle: {
fontSize: '24',
fontWeight: '900'
},
x: 'center'
},
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: 'vertical',
left: 'left',
textStyle: {
fontSize: '14',
fontWeight: '900'
},
data: data.legendData
},
series: [
{
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: data.seriesData,
normal: {
label:{
show:true,
formatter:'{b} : {c}人次 ({d}%)',
textStyle: {
color: '#000000',
fontSize: '14',
fontWeight: '900'
}
}
},
itemStyle: {
normal: {
label:{
show:true,
formatter:'{b} : {c}人次 ({d}%)',
textStyle: {
color: '#000000',
fontSize: '14',
fontWeight: '900'
}
}
},
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
var options = {
title: {
text: '',
subtext: '',
textStyle: {
fontSize: '24',
fontWeight: '900'
},
x: 'left'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: data.crossLegend,
textStyle: {
fontSize: '14',
fontWeight: '900'
},
},
grid: {
left: '5%',
right: '4%',
bottom: '2%',
containLabel: true
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: data.crossType
}
],
yAxis: [
{
type: 'value'
}
],
series: data.crossSeries
};
function buildChart() {
$('#chart1').removeAttr('_echarts_instance_');
$('#chartContainer').removeAttr('_echarts_instance_');
chartPie.setOption(option,true);
chartCross.setOption(options,true);
}
//buildChart();
//重置
function resetForm() {
form.reset();
}
//查询
function check(){
form.validate();
if (form.isValid() == false) return;
var streetId = mini.get("street").getValue();
//发放日期
var beginDate = mini.get("beginDate").getFormValue();
var endDate = mini.get("endDate").getFormValue();
if(beginDate>endDate){
mini.alert('开始日期不得小于结束日期,请重新选择查询日期!');
}else{
data=search();
chartPie.setOption(option,true);
chartCross.setOption(options,true);
//饼图重新赋值
option = chartPie.getOption();
option.series[0].data=data.seriesData;
//折线图重新赋值
options = chartCross.getOption();
options.xAxis[0].data=data.crossType;
options.series=data.crossSeries;
buildChart();
}
}
function search(){
var legendData = [];
var seriesData = [];
var crossLegend = [];
var crossSeries = [];
var crossType = [];
var data=form.getData(true);
var json=mini.encode(data);
$.ajax({
url: "theme.queryBusAnalysisData.action",
type: "post",
data: { submitData: json },
async: false,
success: function (text) {
var pieData = text.pieData;
for(var i=0;i<pieData.degreeInfo.length;i++){
legendData.push(pieData.legendInfo[i]);
seriesData.push({
name:pieData.degreeInfo[i].NAME,
value:pieData.degreeInfo[i].VALUE
});
}
var crossData = text.crossData;
for(var i=0;i<crossData.legendInfo.length;i++){
crossLegend.push(crossData.legendInfo[i]);
crossSeries.push({
areaStyle:crossData.seriesInfo[i].areaStyle,
data:crossData.seriesInfo[i].data,
name:crossData.seriesInfo[i].name,
stack:crossData.seriesInfo[i].stack,
type:crossData.seriesInfo[i].type
});
}
for(var j=0;j<crossData.typeInfo.length;j++){
crossType.push(crossData.typeInfo[j]);
}
}
});
return {
legendData: legendData,
seriesData: seriesData,
crossLegend: crossLegend,
crossSeries: crossSeries,
crossType: crossType
};
}
</script>
注: 与后台交互通过JSON的形式,所以需要把相应的数据结构给定义好,这是我的后台实体及JSON格式;
public String queryBusAnalysisData() {
List<String> strList = new ArrayList<String>();
String pieJson = "";
String crossJson = "";
DegreeOptionInfo degreeOptionInfo = new DegreeOptionInfo();
String json = getServletRequest().getParameter("submitData");
if (!StringUtil.safeToString(json).equals("")) {
ThemeVo themVo = (ThemeVo) VOUtils.getBeanFromJsonData(json,
ThemeVo.class);
Map<String, List<Map<String, Object>>> busAnalysisMap = themeService
.queryBusAnalysisData(themVo);
// 组装成json
for (String key : busAnalysisMap.keySet()) {
if (key.equals("pieData")) {
List<Map<String, Object>> list = busAnalysisMap.get(key);
for (int i = 0; i < list.size(); i++) {
Map<String, Object> map = list.get(i);
strList.add(map.get("NAME").toString());
}
degreeOptionInfo.setDegreeInfo(list);
degreeOptionInfo.setLegendInfo(strList);
pieJson = VOUtils.getJsonData(degreeOptionInfo);
}
if (key.equals("crossData")) {
CrossData crossData = new CrossData();
List<String> typeList = new ArrayList<String>();
List<CrossTree> seriesList = new ArrayList<CrossTree>();
List<Map<String, Object>> list = busAnalysisMap.get(key);
Map<String, List<String>> tempList = new HashMap<String, List<String>>();
List<String> tkgyList = new ArrayList<String>();
List<String> jwbkList = new ArrayList<String>();
List<String> wbbkList = new ArrayList<String>();
List<String> itemList = new ArrayList<String>();
List<String> ydcjList = new ArrayList<String>();
List<String> individualList = new ArrayList<String>();
List<String> lsjzList = new ArrayList<String>();
for (int j = 0; j < list.size(); j++) {
Map<String, Object> map = list.get(j);
typeList.add(map.get("TYPE").toString()); // 折线图 X轴
tkgyList.add(map.get("F1").toString());
jwbkList.add(map.get("F2").toString());
wbbkList.add(map.get("F3").toString());
itemList.add(map.get("F4").toString());
ydcjList.add(map.get("F5").toString());
individualList.add(map.get("F6").toString());
lsjzList.add(map.get("F7").toString());
tempList.put("f1", tkgyList);
tempList.put("f2", jwbkList);
tempList.put("f3", wbbkList);
tempList.put("f4", itemList);
tempList.put("f5", ydcjList);
tempList.put("f6", individualList);
tempList.put("f7", lsjzList);
}
for (int t = 0; t < strList.size(); t++) {
CrossTree crossTree = new CrossTree();
Map<String, List<String>> map1 = new HashMap<String, List<String>>();
map1.put("normal", new ArrayList<String>());
crossTree.setAreaStyle(map1);
crossTree.setName(strList.get(t));
crossTree.setType("line");
crossTree.setStack("总量");
String keys = ("f" + (t + 1)).toString();
crossTree.setData(tempList.get(keys));
seriesList.add(crossTree);
}
crossData.setLegendInfo(strList); // 折线图标题列
crossData.setTypeInfo(typeList); // 折线图 X轴
crossData.setSeriesInfo(seriesList); // 折线图数据
crossJson = VOUtils.getJsonData(crossData);
LOG.info("Cross折线图格式化的json数据是:=====" + crossJson);
}
}
JSONObject obj = new JSONObject();
obj.put("pieData", pieJson);
obj.put("crossData", crossJson);
createJSonData(obj.toString());
}
return AJAX;
}
@Override
public Map<String, List<Map<String, Object>>> queryBusAnalysisData(
ThemeVo themVo) {
Map<String,List<Map<String,Object>>> busAnalysisMap = new HashMap<String,List<Map<String,Object>>>();
Map<String,Object> param=new HashMap<String,Object>();
param.put("STREET_ID",themVo.getStreet());
param.put("BEGIN_DATE",themVo.getBeginDate());
param.put("END_DATE",themVo.getEndDate());
param.put("TYPE",themVo.getType());
List<Map<String,Object>> pieList = themeDao.queryBusAnalysisPieData(param);
List<Map<String,Object>> crossList = themeDao.queryBusAnalysisCrossData(param);
busAnalysisMap.put("pieData",pieList);
busAnalysisMap.put("crossData",crossList);
return busAnalysisMap;
}
看代码也知道了,Service及Dao 层返回的都是Map和List 之间互相嵌套,而 返回前台的JSON数据结构则是 DegreeOptionInfo 类
public class DegreeOptionInfo {
public List<Map<String,Object>> degreeInfo;
public List<String> legendInfo;
public String seriesName;
public List<String> degreeInfos;
public DegreeOptionInfo(){
this.degreeInfo = new ArrayList<Map<String,Object>>();
this.legendInfo = new ArrayList<String>();
this.degreeInfos = new ArrayList<String>();
}
public List<Map<String, Object>> getDegreeInfo() {
return degreeInfo;
}
public void setDegreeInfo(List<Map<String, Object>> degreeInfo) {
this.degreeInfo = degreeInfo;
}
public List<String> getLegendInfo() {
return legendInfo;
}
public void setLegendInfo(List<String> legendInfo) {
this.legendInfo = legendInfo;
}
public String getSeriesName() {
return seriesName;
}
public void setSeriesName(String seriesName) {
this.seriesName = seriesName;
}
public List<String> getDegreeInfos() {
return degreeInfos;
}
public void setDegreeInfos(List<String> degreeInfos) {
this.degreeInfos = degreeInfos;
}
}
折线图的实体类及JSON数据结构:
public class CrossData {
public List<CrossTree> seriesInfo;
public List<String> legendInfo;
public List<String> typeInfo;
public CrossData(){
this.seriesInfo = new ArrayList<CrossTree>();
this.legendInfo = new ArrayList<String>();
this.typeInfo = new ArrayList<String>();
}
public List<CrossTree> getSeriesInfo() {
return seriesInfo;
}
public void setSeriesInfo(List<CrossTree> seriesInfo) {
this.seriesInfo = seriesInfo;
}
public List<String> getLegendInfo() {
return legendInfo;
}
public void setLegendInfo(List<String> legendInfo) {
this.legendInfo = legendInfo;
}
public List<String> getTypeInfo() {
return typeInfo;
}
public void setTypeInfo(List<String> typeInfo) {
this.typeInfo = typeInfo;
}
}
public class CrossTree {
private String name;
private String type;
private String stack;
private Map<String,List<String>> areaStyle;
private List<String> data;
public CrossTree() {
}
public CrossTree(String name, String type, String stack,
Map<String, List<String>> areaStyle, List<String> data) {
super();
this.name = name;
this.type = type;
this.stack = stack;
this.areaStyle = areaStyle;
this.data = data;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getStack() {
return stack;
}
public void setStack(String stack) {
this.stack = stack;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
public Map<String, List<String>> getAreaStyle() {
return areaStyle;
}
public void setAreaStyle(Map<String, List<String>> areaStyle) {
this.areaStyle = areaStyle;
}
}
最后,看一下相应的JSP效果图吧
******************************************************************************************
参考网址:
饼图数据填充 http://www.cnblogs.com/sillypasserby/p/6185703.html
折线图数据填充 http://www.cnblogs.com/Dreamer-1/p/5530221.html