【d3.js实践教程02】基于中国地图的高考一本录取率排行

学习d3.js(以下都简称d3)也有一段时间了,运行d3做了几个项目。我发现中文的d3教程很少,国外资料多但要求有一定的英文阅读能力(推荐网址:http://bl.ocks.org/mbostock),于是就萌发了写一个d3实际运用系列文章的想法,现在开始付之行动。在系列中,我会用d3+html5 canvas实现一些实际效果(如统计结果展示,地图数据展示等),希望可以跟大家共同学习交流。

代码我公布在git.cschina.com上,大家可以clone到本地运行,地址是:http://git.oschina.net/0604hx/d3lesson

运行环境是java 7+,tomcat 7.0.47+(以后会用到websocket,所以需要javaee7 跟 tomcat 7+的支持),IDE 是IntelliJ IDEA 13, 项目的视图使用了freemarker。

这一章讲的是在中国地图上展示2013年大陆各省份高考一本录取率的排行。

准备数据

首先需要有录取率的相关数据,我从网上复制出来了一份统计数据:

2013年一本录取率排名
1	 天津	 6.3	 1.5447	 24.52%
2	 北京	 7.27	 1.7686	 24.33%
3	 上海	 5.3	 1.2	 22.64%
4	 青海	 3.6733	 0.6837	 18.61%
5	 山东	 50.9	 9.351	 18.37%
6	 宁夏	 5.87	 1.001	 17.05%
7	 吉林	 15.5	 2.2435	 14.47%
8	 福建	 25.5	 3.6186	 14.19%
9	 贵州	 24.78	 3.4369	 13.87%
10	 浙江	 31.3	 4.1887	 13.38%
11	 陕西	 36.65	 4.8422	 13.21%
12	 新疆	 15.87	 2.05	 12.92%
13	 云南	 23.6	 3.0179	 12.79%
14	 海南	 5.6	 0.6396	 11.42%
15	 内蒙古	 19.3	 2.163	 11.21%
16	 甘肃	 28.3	 2.9598	 10.46%
17	 安徽	 51.1	 5.1692	 10.12%
18	 江苏	 45.1	 4.5085	 10.00%
19	 湖南	  37.3	 3.5789	 9.59%
20	 黑龙江	 20.8	 1.9931	 9.58%
21	 重庆	 23.5	 2.195	 9.34%
22	 江西	 27.43	 2.4891	 9.07%
23	 河北	 44.98	 4.0602	 9.03%
24	 湖北	 43.8	 3.5923	 8.20%
25	 广西	 29.8	 2.3	 7.72%
26	 河南	 71.63	 4.8655	 6.79%
27	 广东	 72.7	 4.3092	 5.93%
28	 山西	 35.8	 2.1091	 5.89%
29	 辽宁	 25.4	 1.4583	 5.74%
30	 四川	 54	 	 2.849   5.28%
31	 西藏	 1.89	 0.0904	 4.78%

这个文件可以在d3lesson中找到

对于有规则的txt数据(如一行一个对象),我写了一个转换工具,可以转成json(json格式在网页中使用较为方便),具体可见:org.nerve.d3lesson.common.tools.impl.TxtToJSONImporter 这个类。

最终效果图

最终的效果图如下(当鼠标移动到省份可以看到具体的信息)

(根据录取率排行,颜色深的代表录取率越高)

(根据高考人数排行,颜色深的代表高考人数越多)

如何实现?

1. 画出中国地图

整个地图是用svg的path绘制,那么需要有相应的数据。中国地图的json数据在 /web/data/china.json 中,我们可以用d3的json()方法加载这个json,然后绘制出地图。

加载方法:

d3.json("{json路径}", function(data){
	//这里是回调函数,如果加载成功,data就是json对象
	//执行drawChina方法绘制地图

});

绘制函数(这里使用过的是墨卡托投影, projection 的调整我暂时没弄透彻,反正是对着屏幕调到满意的位置就好了,如果有朋友知道欢迎解答,万分感谢!)

在绘制过程中,给每个省份对应的path加一个唯一的id,方便以后调用(如修改颜色就是通过id获取path来完成)

// Project from latlng to pixel coords
//使用墨卡托投影
var projection = d3.geo.mercator()
        .scale(width/2)                                   //对地图进行缩放
        .translate([width / 2, height / 2])                 //将地图平移到屏幕中间
        .rotate([-110, 0])
        .center([0, 37.5])                                  //设置中心点,调整到屏幕中心
;

// Draw geojson to svg path using the projection
var path = d3.geo.path().projection(projection);

//画出中国地图
function drawChina(ds){
    if(!chinaG)
        chinaG = container.append("g");
    chinaG.selectAll("path")
            .data(ds.features)
            .enter()
            .insert("path")
            .attr("id", function(d){
                return d.id;
            })
            .attr("fill", "#000000")
            .attr("d", path)
            .attr('stroke',setting.strokeColor)
            .attr('stroke-width','0.7px')
    ;
}

这样下来,就得到这样的一个地图

看看dom中都创建了什么?

2. 根据排行对省份进行颜色分配

接着,就要根据排序规则对省份上色了。先看看统计数据是怎么样的(就是第一步中转换过来的json数据):

{
    "_title": "2013年一本录取率排名",
    "datas": [
        {
            "enter": 1.5447,
            "id": "TIANJIN",
            "index": 1,
            "province": "天津",
            "rate": "24.52%",
            "total": 6.3
        },
        {
            "enter": 1.7686,
            "id": "BEIJING",
            "index": 2,
            "province": "北京",
            "rate": "24.33%",
            "total": 7.27
        },
        {
            "enter": 1.2,
            "id": "SHANGHAI",
            "index": 3,
            "province": "上海",
            "rate": "22.64%",
            "total": 5.3
        },
        //.....
        //剩下的就不列出来了

同样的,我们用d3.json() 方法加载这些数据,然后排序其中的datas数组。

这里要说一下过度颜色,我是这样定义的:

 //创建过度颜色,注意上一步的排序是从大到小,那么颜色应该是从深到浅
        var rateColors = d3.scale.linear()
                .domain([1, 340])
                .range([d3.rgb(20, 120, 140),d3.rgb(180, 230, 255)]);

那么可以这样得到一个颜色值: rateColors(index); 传进去的index应该是 1 到 340 之间(当然你传更大或更小的也可以),那么就得到d3.rgb(20, 120, 140),d3.rgb(180, 230, 255) 之间相对应的一个颜色。 如index=1 就得到 d3.rgb(20, 120, 140), index = 340 就得到d3.rgb(180, 230, 255), index=170 就得到两个端点颜色的中间颜色。

最后就是对数据排序,然后更新对应省份的颜色了:

/**
 * 根据录取率排序
 */
function sortByRate(){
    //首先我们需要对数据进行录取率从大到小的排序
    //因为rate 是 xx.xx% 的格式,所以在对比前需要进行parseFloat 的操作
    var data = gkData.datas.sort(function(d1,d2){
        return parseFloat(d2.rate) - parseFloat(d1.rate);
    });

    //创建过度颜色,注意上一步的排序是从大到小,那么颜色应该是从深到浅
    var rateColors = d3.scale.linear()
                .domain([1, 340])
                .range([d3.rgb(130, 140, 20),d3.rgb(255, 255, 180)]);
    /*
    遍历上一步得到是数组
    forEach 参数中的 d 就是遍历到的某个数据, i 就是该对象的下标序号,从0开始
    */
    data.forEach(function(d,i){
        d.sort = i+1;
        //通过d.id 来获取中国地图上对应的省份,因为地图中的省份块是根据省份拼音命名的
        d3.select("#"+ d.id)
                .transition()
                .duration(duration)
                .delay(10*i)
                .attr("fill", rateColors((i+1)*10))
        ;
    });

    buildTip(data);
    showOnTable(data);
}

/**
 * 根据参加高考人数排序
 */
function sortByTotal(){
    //首先我们需要对数据进行录取率从大到小的排序
    //因为rate 是 xx.xx% 的格式,所以在对比前需要进行parseFloat 的操作
    var data = gkData.datas.sort(function(d1,d2){
        return d2.total - d1.total;
    });

    //创建过度颜色,注意上一步的排序是从大到小,那么颜色应该是从深到浅
    var rateColors = d3.scale.linear()
            .domain([1, 340])
            .range([d3.rgb(20, 120, 140),d3.rgb(180, 230, 255)]);
//                .range([d3.rgb(30, 40, 160),d3.rgb(180, 160, 255)]);
    /*
    遍历上一步得到是数组
    forEach 参数中的 d 就是遍历到的某个数据, i 就是该对象的下标序号,从0开始
    */
    data.forEach(function(d,i){
        d.sort = i+1;
        //通过d.id 来获取中国地图上对应的省份,因为地图中的省份块是根据省份拼音命名的
        d3.select("#"+ d.id)
                .transition()
                .duration(duration)
                .delay(10*i)
                .attr("fill", rateColors((i+1)*10))
        ;
    });

    buildTip(data);
    showOnTable(data);
}

3. 创建提示

鼠标移动到省份上,可以显示具体的信息(这个功能是很实用的!客户绝对是需要的)

首先,先定义好用来显示提示的div元素

<!--div提示框-->
<div id="tooltip" class="hidden box">
    <p>
        <strong class="dataHolder" name="province"></strong>
        排名:<span class="dataHolder" name="sort"></span>
    </p>
    <div>
        高考人数:<span class="dataHolder" name="total"></span>万 
        录取率:<span class="dataHolder" name="rate"></span>
    </div>
</div>

然后用d3填充数据

/**
 * 创建提示条
 * 提示的创建大致有3种方式
 * 1: 给svg元素里面增加一个title元素,
 *     var t = d3.select(id).append("title").text("我是提示条");
 *      这种方法效果不大理想,而且提示单调
 *
 * 2: 给需要提示的元素添加mouseover, mouseout 事件,当鼠标在该元素上移动时,就显示提示条(动态创建的svg元素),如:
 *      var t = d3.select(id);
 *      t.on('mouseover',function(){
 *          //创建提示条
            svg.append("text")
              .attr("id", "tooltip")
              .attr("x", d3.event.x)
              .attr("y", d3.event.y)
              .attr("text-anchor", "middle")
              .attr("font-family", "sans-serif")
              .attr("font-size", "11px")
              .attr("font-weight", "bold")
              .attr("?ll", "black")
              .text("我是svg的提示条");
            })
 *      });
 *
 * 3: 类似方法2,但是提示条不是svg元素,而是普通的html元素(如div),动态修改提示框里面的内容跟提示框的x,y坐标
 *      达到提示的效果,总体来说这个方法较好,较为灵活,而且可以使用css3,同时不用担心提示框超出svg范围的问题
 *
 *      所以,在教程中,都是使用这个方法
 */
function buildTip(data){
    var t = "#tooltip";
    chinaG.selectAll("path")
            .data(data, function(d){
                return d.id;
            })
            .on("mouseover",function(d){
                d3.select(t)
                        .style("left", d3.event.x + "px")
                        .style("top", d3.event.y + "px")
                        .classed("hidden", false)
                        .selectAll(".dataHolder")[0]
                        .forEach(function(h){
                            h = d3.select(h);
                            h.html(d[h.attr('name')]);
                        })
                ;
                d3.select(this)
                        .attr("opacity", 0.8);
            })
            .on("mouseout",function(){
                d3.select(t).classed("hidden", true);
                d3.select(this)
                        .attr("opacity", 1);
            })
    ;
}

详细的代码请到:http://git.oschina.net/0604hx/d3lesson

时间: 2024-08-04 15:42:25

【d3.js实践教程02】基于中国地图的高考一本录取率排行的相关文章

【d3.js实践教程特别篇】PornHub发布基于d3的网民观看成人视频时长分布交互式地图

学习d3.js(以下都简称d3)也有一段时间了,运行d3做了几个项目.我发现中文的d3教程很少,国外资料多但要求有一定的英文阅读能力(推荐网址:http://bl.ocks.org/mbostock),于是就萌发了写一个d3实际运用系列文章的想法,现在开始付之行动.在系列中,我会用d3+html5 canvas实现一些实际效果(如统计结果展示,地图数据展示等),希望可以跟大家共同学习交流. 代码我公布在git.cschina.com上,大家可以clone到本地运行,地址是:http://git.

【d3.js实践教程01】d3基本操作

学习d3.js(以下都简称d3)也有一段时间了,运行d3做了几个项目.我发现中文的d3教程很少,国外资料多但要求有一定的英文阅读能力(推荐网址:http://bl.ocks.org/mbostock),于是就萌发了写一个d3实际运用系列文章的想法,现在开始付之行动.在系列中,我会用d3+html5 canvas实现一些实际效果(如统计结果展示,地图数据展示等),希望可以跟大家共同学习交流. 代码我公布在git.cschina.com上,大家可以clone到本地运行,地址是:http://git.

vue.js初级教程--02.环境搭建

node.js 如何安装 官方网址  https://nodejs.org/en/ 如何验证node.js安装成功 node -v 能够解决什么问题 相较于其他服务器框架,它给系统性能能提升所带来的好处? node.js特性 javascript运行环境 依赖Chrome v8引擎进行代码解释 事件驱动 非阻塞I/O 轻量/可伸缩的 实时交互的应用面比较广(I/O密集型的服务器模型里面性能比较好) 单进程.单线程 解决的问题 并发连接数 案例 利用node.js http模块 我们监听端口888

利用d3.js绘制中国地图

d3.js是一个比较强的数据可视化js工具.利用它画了一幅中国地图,如下图所示: 源码如下: <!DOCTYPE html> <html> <head> <script type="text/javascript" src="d3.js"></script> <script type="text/javascript" src="d3.csv.js">&l

D3.js的v5版本入门教程(第十二章)—— D3.js中各种精美的图形

D3.js的v5版本入门教程(第十二章) D3中提供了各种制作常见图形的函数,在d3的v3版本中叫布局,通过d3.layout.xxx,来新建,但是到了v5,新建一个d3中基本的图形的方式变了(我也并不知道是不是还叫布局,我觉得也可以这么叫,反正布局指的也是一个绘图函数) 下面是d3中一些常见的部分图形 bubble —— 泡泡图 packing —— 打包图 bundling —— 捆图 force —— 力导向图 chord —— 弦图 pie——饼状图 tree——树状图 中国地图 我们利

Javascript实战开发:教你使用raphael.js绘制中国地图

最近的数据统计项目中要用到中国地图,也就是在地图上动态的显示某个时间段某个省份地区的统计数据,我们不需要flash,仅仅依靠raphael.js以及SVG图像就可以完成地图的交互操作.在本文中,我给大家分享如何使用js来完成地图交互. 先简单介绍下raphael.js,raphael.js是一个很小的javascript库,它可以在网页中实现绘制各种矢量图.各类图表.以及图像裁剪.旋转.运动动画等等功能.此外raphael.js还跨浏览器兼容,而且还兼容老掉牙的IE6啊.raphael.js的官

【 D3.js 入门系列 --- 10 】 地图的绘制

本人的个人博客为:www.ourd3js.com csdn博客为:blog.csdn.net/lzhlzz 转载请注明出处,谢谢. 地图的制作在 D3 中可以说是最重要的一环.因为在进行数据可视化时,很多情况都会和地图联系在一起,如中国各省的人口多少,GDP多少等,都可以和地图联系在一起. D3 中制作地图所需要的文件问 JSON 文件.JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.关于 JSON 的语法格式,可以在: http://www.w3s

基于VUE+TS中引用ECharts的中国地图和世界地图密度表

首先先附上官网 http://echarts.baidu.com/option.html#series-line.label 以及密度表对应geo配置文档 http://echarts.baidu.com/option.html#geo 以下仅是个人在开发中逐步摸索出来的.demo目前没出问题.如果有错误地方请留言指出  (若转载请标注出处) 直接上效果图,对应代码在效果图下面 安装: 1. npm install echarts --save2. npm install --save @typ

PHP+Mysql+jQuery实现中国地图区域数据统计(raphael.js)

使用过百度统计或者cnzz统计的童鞋应该知道,后台有一个地图统计,不同访问量的省份显示的颜色也不一样,今天我将带领大家开发一个这样的案例.上一篇<使用raphael.js绘制中国地图>文章中,我给大家介绍了如何使用raphael.js绘制中国地图,今天我要给大家介绍在实际应用中,如何把数据载入到地图中.本文结合实例,使用PHP+Mysql+jQuery实现中国地图各省份数据统计效果. 本例以统计某产品在各省份的活跃用户数为背景,数据来源于mysql数据库,根据各省份的活跃用户数,分成不同等级,