最近有个挺好玩的需求:需要将分布在全国各地的系统用户数量统计出来,以地图的形式展示出每个地域的用户数量。
此前我一直用的是highcharts,怎奈highcharts不支持地图报表,于是转而使用百度的Echarts,Echarts本身的功能没的说,很赞,API也很详细,但是网上貌似玩的人不多,于是自己动手参照官方demo耍耍。
先展示下最终实现效果,如果诸位看官感觉效果还不错,欢迎继续向下看,如果感觉效果很逊,pls close ~ O(∩_∩)O~
简单的描述下:上述地图中,左侧是展示全国地图(默认选择的是江苏 ps:因为在下目前在江苏 O(∩_∩)O~),右侧是展示的江苏各地市的用户数量,点击左侧的不同省份,右侧地图会随之变化,从而显示不同省市的用户数量。
下面说下具体的实现:
Echarts 官网:http://echarts.baidu.com/
先说下思路:Echarts的样式是很容易在前台jsp定制的,最重要的数据源(如图中的各区域的用户数量)是需要在后台拼装,然后传到前台解析显示的。Echarts页面上获得选择的省名称(如江苏),ajax传入后台,我在数据库中存入的有最新的全国行政区域代码(国家统计局http://www.stats.gov.cn/zjtj/tjbz/xzqhdm/获得),在后台会先通过省名称获得对应的省编码,然后获得其下各市的用户总数量,将这个数量数据拼装然后返回前台解析显示。
代码如下,echarts.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/jquery-1.8.3.min.js"></script> <script type="text/javascript" src="${pageContext.request.contextPath}/file/scripts/echarts/esl.js"></script> </head> <body> <div> <div id="main" style="float:left;height:500px;width:620px;padding:0px;"></div> <div id="pc" style="float:right;height:500px;width:600px;padding:20px;"></div> </div> <%--注意 此段js只能置于此位置 否则echarts无法正常生成 --%> <script type="text/javascript"> var curIndx = 0; var mapType = [ // 23个省 '江苏', '青海', '四川', '海南', '陕西', '甘肃', '云南', '湖南', '湖北', '黑龙江', '贵州', '山东', '江西', '河南', '河北', '山西', '安徽', '福建', '浙江', '广东', '吉林', '辽宁', '台湾', // 5个自治区 '新疆', '广西', '宁夏', '内蒙古', '西藏', // 4个直辖市 '北京', '天津', '上海', '重庆', // 2个特别行政区 '香港', '澳门' ]; var fileLocation = '${pageContext.request.contextPath}/file/scripts/echarts/echarts-map'; require.config({ paths:{ 'echarts': fileLocation, 'echarts/chart/map': fileLocation, } }); var pcChart; var myChart; var colorList; require( [ 'echarts', 'echarts/chart/map' ], function(ec) { colorList = require('zrender/tool/color').getGradientColors( ['red','yellow','lightskyblue'], 10 ); myChart = ec.init(document.getElementById('main')); pcChart = ec.init(document.getElementById('pc')); myChart.setOption(getChinaMapChartOption()); window.onresize = myChart.resize; var ecConfig = require('echarts/config'); myChart.on(ecConfig.EVENT.MAP_SELECTED, mapSelected); mapSelected(true); //初始加载江苏各地市 } ); function getChinaMapChartOption() { var chinaMapChartOption = { title: { text : '全国34个省级行政区', }, tooltip : { trigger: 'item' }, series : [ { tooltip: { trigger: 'item', formatter: '{b}' }, name: '中国', type: 'map', mapType: 'china', mapLocation: { x: 'left', width: 600 }, selectedMode : 'single', itemStyle:{ normal:{label:{show:true}}, emphasis:{label:{show:true}} }, data:[ {name: '江苏', selected:true} ] } ], animation: false }; return chinaMapChartOption; } function mapSelected(param){ var len = mapType.length; var mt = mapType[curIndx % len]; var selected = param.selected; for (var i in selected) { if (selected[i]) { mt = i; while (len--) { if (mapType[len] == mt) { curIndx = len; } } break; } } $.post('${pageContext.request.contextPath}/usermanager!ajaxUserAreaJson.action',{'provinceName':mt}, function(data){ datas = eval('(' + data + ')'); var option = { title: { text : '江苏', }, tooltip : { trigger: 'item', //formatter: '{b}' }, legend: { orient: 'vertical', x:'right', data:['系统用户数量'] }, dataRange: { min: 0, max: 100, //此处由于echarts的bug 默认的max最小值为100且为100的整数倍 color:['orange','yellow'], text:['高','低'], // 文本,默认为数值文本 calculable : true }, toolbox: { show : false, orient : 'vertical', x: 'right', y: 'center', feature : { mark : true, dataView : {readOnly: true}, restore : true, saveAsImage : true } }, series : [ { name: '系统用户数量', type: 'map', mapType: 'china', selectedMode : 'single', itemStyle:{ normal:{label:{show:true}}, emphasis:{label:{show:true}} }, data:datas } ] }; option.tooltip.formatter = '{b}:{c}'; option.series[0].mapType = mt; option.title.text = mt + "-系统用户分布"; pcChart.setOption(option, true); }); } </script> </body> </html>注意:jsp中的post方法,是动态获得数据的关键,以及获得的data数据eval下,在series中的data中设置数据源即可。其他的东东请参考官网。
后台拼装数据:
实际上后台只要获得如
[{name:'南京市',value:13},{name:'无锡市',value:4},{name:'徐州市',value:4},{name:'连云港市',value:1}]
的字符串即可,或者你也可以叫它json,但是要注意name和value是没有引号的,具体拼装代码就不展示了,你可以用各种姿势获得其。O(∩_∩)O~
这里提下,dataRange中的max属性的获取思路,首先将每个区域下用户总数获取到,进行sort排序取最大值,最大值然后传入如下方法处理,获得返回值同dataJson一起返回页面解析显示即可(上述的例子只是简单的写死max=100,具体如何动态化这个max,请自行思考,其实so easy……):
/** * 获得echarts的dataRange的max值 max必须为100的整数倍 * 返回值示例:94则返回100 125则返回200 1240则需要返回1300 * * @param ranMax * @return * @see */ private static int rangeMax(Integer ranMax) { int max = 100; // 小于100 则直接返回100 if (ranMax <= 100) { return 100; } else { // 能被100整除 直接返回 if (ranMax % 100 == 0) { return ranMax; } // 返回比当前值多100的值 else { int m = ranMax / 100; max = (m + 1) * 100; } } return max; }
综上:最主要的就是jsp的写法,和字符串的拼装。如有不明白之处可以给我留言~
PS:附上echarts作者的地址 http://my.oschina.net/kener kener@osc。