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

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

学习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。

这是d3实践的特别篇,代码不是我写的,是从PornHub网站中copy出来,进行了简化、美化处理,并加上了一些注释。


早上看到了一则微博:



我想很多人对PornHub会有所认识,这是全球三大色情网站之一,内容可是相当丰富的哟。咳咳,跑题了...

微博里面提到的地图目测是d3.js的应用,所以想看看具体的代码。但是PornHub在国内是无法访问的(就连搜索这个关键字都不能....),于是使用vpn登录,可以正常访问PornHub网站,哇,里面好多资源呀!这网站不被墙真是没天理了!我收回心,毕竟我不是来看片的,我是来学习技术的呀!


我找到了交互式地图,网址为:http://www.pornhub.com/infographic/longest

从地图上可以看到,全球范围内的网民观看成人视频的平均时长。同时,可以切换到美国地图。除了根据国家形式查看,还可以转到城市级别,这时会在地图上标出全球的主要城市,当鼠标移动到城市的图标上去可以看到城市名字跟观看时长等数据。地图可以放大缩小。


看了下代码,js文件就两个:


data.min.js 是数据(包括了国家级别、城市级别的数据)

main.js 是绘制地图还有交互用的

usa.json 是美国的geoJson数据

world.json 则是世界地图数据


为了大家访问查看效果,我将地图部署到了d3lesson的项目中,有兴趣的朋友可以在git中导出项目然后运行。

通过这个例子,可以学习到地图的切换、缩放、小图标在大地图缩放是的处理方法(因为地图放大后,图标也会跟着放大,这样的话,不够美观)等。

具体的代码可以再git中查看(我都加了注释的),在这里主要讲一下里面绘图方法:

var m, //svg对象
		r, //放置地图的 g 集合
		u, //坐标转换器
		n,	//path
		a,	//zoom元素
		e;	//地图块数据
    var o, l;
	
    //绘制地图
    function j() {
        o = $("#map").width();      //得到大地图宽度
        l = $("#map").height();     //得到大地图高度
        d3.json($("body").data("base-url") + c.mapScope + ".json",
        function(w) {
            m = d3.select("#map").append("svg").attr("width", o).attr("height", l);
            $("#map").css("background", c.mapOptions[c.mapDisplayMode].mapBackgroundColor).css("cursor", "move");
            r = m.append("g");
            if (c.mapScope == "world") {
                u = d3.geo.mercator().translate([0, 0]).scale(1).rotate([ - 11.5, 0])
            } else {
                u = d3.geo.albersUsa().translate([0, 0]).scale(1)
            }
            e = topojson.feature(w, w.objects[(c.mapScope == "world") ? "collection": "usa"]);
            e.features = e.features.filter(function(x) {
                return x.id !== 11;
            });
            var g = r.selectAll(".country").data(e.features);
            n = d3.geo.path().projection(u);
            q();       //完成地图的位移,不然页面时显示不出地图的
            if (c.mapDisplayMode == "cities") {
                r.append("path").datum(topojson.merge(w, w.objects[(c.mapScope == "world") ? "collection": "usa"].geometries.filter(function(x) {
                    return x.id !== 11
                }))).attr("class", "dropshadow").attr("d", n).style("fill", "#5e8fa7").attr("width", o).attr("height", l).attr("transform", "translate(0,5)")
            }
            g.enter().append("path").attr("class", "country").attr("d", n).attr("id",
            function(y, x) {
                return "c" + y.id
            });
			
            d3.selectAll("path.country").attr("class", "country")
				//给地图块上色,函数的z参数,就是对应元素的data对象(由之前调用data()函数分配)
				.style("fill",function(z) {
					if (c.mapDisplayMode == "countries") {
						//或者具体的时间长, 数据结构在  data.min.js
						var y = mapTimeData[c.mapScope][c.mapDisplayMode][z.id].t;
						var x = d(y);   //判断颜色级别
						return x
					} else {
						return c.mapOptions[c.mapDisplayMode].mapItemsColor
					}
				})
				.style("stroke-width", 1).style("stroke", c.mapOptions[c.mapDisplayMode].strokeColor);
            p();         //创建qtip的提示
            
			/*
			一下的3行代码是设置svg的滚轮放大效果
			*/
			d3.behavior.zoom();
            a = d3.behavior.zoom().scaleExtent([c.minZoomLevel, c.maxZoomLevel]).on("zoom", k);
            m.call(a).call(a.event)
        });
    }

再来几张效果图:






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