highcharts的堆栈面积图适用于一组对象对同一个指标在一段时间范围内进行走势的展示,同时,在每个时间点可以同时显示出每个对象在这个时间点的值,一目了然。官网上的是这样的:
实际情况中,需要结合后台查询出数据再填充,难点在于数据结构的拼装。而且有时候还不止一个指标,你可能被要求得出若干个指标在这组对象的这段时间的值。
下面,我就来模拟一种情景:
假设有app1,app2, app3三个对象,我需要得出他们在20160301, 20160302, 20160303这3个月的index1,index2,index3这3个指标值,并用趋势图的形式展示出来,首先,模拟查询出来的结果,真实的sql语句肯定是要按app和date来group by的:
我以index1这个指标为例,来画一个堆栈图。难点在于后台数据结构的拼装:
//先用假设据模拟 Map<String, List<Object>> map1 = new HashMap<String, List<Object>>();//模拟index1的map Map<String, List<Object>> map2 = new HashMap<String, List<Object>>();//模拟index2的map Map<String, List<Object>> map3 = new HashMap<String, List<Object>>();//模拟index3的map String[] keys = {"a", "b", "c"};//模拟系统 //模拟查询出的数据 List<Map<String, Object>> data = new ArrayList<Map<String,Object>>(); Map<String, Object> data1 = new HashMap<String, Object>(); data1.put("app", "app1"); data1.put("date", "20160301"); data1.put("index1", 100); data1.put("index2", 0.9); data1.put("index3", 0.34); data.add(data1); Map<String, Object> data2 = new HashMap<String, Object>(); data2.put("app", "app1"); data2.put("date", "20160302"); data2.put("index1", 110); data2.put("index2", 0.88); data2.put("index3", 0.3); data.add(data2); Map<String, Object> data3 = new HashMap<String, Object>(); data3.put("app", "app1"); data3.put("date", "20160303"); data3.put("index1", 101); data3.put("index2", 0.9); data3.put("index3", 0.64); data.add(data3); Map<String, Object> data4 = new HashMap<String, Object>(); data4.put("app", "app2"); data4.put("date", "20160301"); data4.put("index1", 120); data4.put("index2", 0.89); data4.put("index3", 0.94); data.add(data4); Map<String, Object> data5 = new HashMap<String, Object>(); data5.put("app", "app2"); data5.put("date", "20160302"); data5.put("index1", 110); data5.put("index2", 0.88); data5.put("index3", 0.3); data.add(data5); Map<String, Object> data6 = new HashMap<String, Object>(); data6.put("app", "app2"); data6.put("date", "20160303"); data6.put("index1", 201); data6.put("index2", 0.88); data6.put("index3", 0.04); data.add(data6); Map<String, Object> data7 = new HashMap<String, Object>(); data7.put("app", "app3"); data7.put("date", "20160301"); data7.put("index1", 300); data7.put("index2", 0.9); data7.put("index3", 0.34); data.add(data7); Map<String, Object> data8 = new HashMap<String, Object>(); data8.put("app", "app3"); data8.put("date", "20160302"); data8.put("index1", 310); data8.put("index2", 0.88); data8.put("index3", 0.335); data.add(data8); Map<String, Object> data9 = new HashMap<String, Object>(); data9.put("app", "app3"); data9.put("date", "20160303"); data9.put("index1", 401); data9.put("index2", 0.3); data9.put("index3", 0.84); data.add(data9); Set<String> times = new HashSet<String>(); for(int i=0; i<data.size(); i++) { Map<String, Object> dto = data.get(i); String app = (String) dto.get("app"); long index1 = Long.valueOf(dto.get("index1").toString()); double index2 = (double) dto.get("index2"); double index3 = (double) dto.get("index3"); getMapData(map1, app + "|index1", index1); getMapData(map2, app + "|index2", index2); getMapData(map3, app + "|index3", index3); times.add((String)dto.get("date")); } List<String> timess = new ArrayList<String>(times); Collections.sort(timess); System.out.println(times); System.out.println(timess); System.out.println(map1); System.out.println(map2); System.out.println(map3); result.put("map1", map1); result.put("map2", map2); result.put("map3", map3); result.put("times", timess); public static void getMapData(Map<String, List<Object>> map, String key, Object data) { List<Object> list = map.get(key); if(list == null) { list = new ArrayList<Object>(); map.put(key, list); } list.add(data); }
可以看出这段模拟group by查询出的结果打印如下:
times: [20160301, 20160302, 20160303]
指标1的map:{app3|index1=[300, 310, 401], app1|index1=[100, 110, 101], app2|index1=[120, 110, 201]}
指标2的map:{app3|index2=[0.9, 0.88, 0.3], app1|index2=[0.9, 0.88, 0.9], app2|index2=[0.89, 0.88, 0.88]}
指标3的map:{app3|index3=[0.34, 0.335, 0.84], app1|index3=[0.34, 0.3, 0.64], app2|index3=[0.94, 0.3, 0.04]}
即为js需要的数据结构,一个指标的map对应一个图。以指标1(index1)为例,js代码如下:
$.ajax({ async : true, type : "POST", data:dataParam, dataType:"json", url :url, success : function(data) { var times = data.times; var map1= data.map1; var map2= data.map2; var map3= data.map3; //堆栈面积图数据填充 针对指标1,其他指标原理类似 var chart = $('#container').highcharts(); var xAixs = chart.xAxis[0]; xAixs.setCategories(times); var series = chart.series; while(series.length > 0) { series[0].remove(false);//remove这个series之后是否重绘charts } //js里面循环map1的key和value for(var prop in dataMap) { if(dataMap.hasOwnProperty(prop)) { var strs = prop.split("|"); chart.addSeries({ name: strs[0], data: dataMap[prop] }, false); } } chart.redraw(); } } );
这里需要注意如何在js里循环一个map型(后台传过来,前台是一个json格式的对象)的方法。
针对指标1的堆栈面积图,结果如下:(也可以画堆栈折线图,只要你设置chart的type为line即可~~)
画其他指标的堆栈图也类似做就行了。