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即可~~)
畫其他指標的堆棧圖也類似做就行了。