在本教程中,我们将看到如何使用d3 的JavaScript库创建世界地图。您可以找到许多与此主题相关的教程,但是在学习完这些教程之后,您会遇到一些未解决的问题,这些问题对于掌握使用d3.js创建地图的技巧非常重要。我假设您熟悉d3.js,SVG和javascript。
实施D3 的JavaScript库
首先,我们需要HTML页面。创建 index.html 文件并加载jQuery, d3.js 和TopoJSON库。
注意:A div 与类 地图 我们要在哪里渲染地图。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>World Map</title>
<style type="text/css">/* Write 的CSS here */</style>
</head>
<body>
<!-- render 地图 -->
<div class="地图"></div>
<!-- render 地图 -->
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/2.2.0/topojson.min.js"></script>
<script> /* Write 的JavaScript Here */</script>
</body>
</html>
使用D3库设置世界地图
关闭body标签之前,请编写以下脚本来代替“在此处编写JavaScript”。
var jMap = $(".map"),
height = jMap.height(),
width = jMap.width(),
地图JsonUrl = '//ucarecdn.com/8e1027ea-dafd-4d6c-bf1e-698d305d4760/world110m2.json',
svg = d3.select(".map").append("svg").attr("width", width).attr("height", height);
高度和宽度
让我们用一个类定义div的高度和宽度 地图 我们要在哪里渲染地图。 地图JsonUrl 是由Mike Bostock使用geoJSON和TopoJSON库生成的世界地图的数据文件。生成该数据文件超出了本文的范围。
svg = d3.select(".map").append("svg").attr("width", width).attr("height", height);
您可以猜到上面的代码行选择带有类的元素 地图 并在SVG元素上附加我们已经计算出的高度和宽度。
加载数据中
d3.json(mapJsonUrl, function (error, worldJson) {
if (error) throw error;
var projection = getProjection();
});
上面的代码块将加载世界TopoJSON文件。真正的动作从现在开始。
设定投影 如您所见 getProjection() 到目前为止,方法尚未定义。定义 getProjection 和 墨卡托界限 功能如下。
var getProjection = function(worldJson) {
var scale = 1,
offset = [ width / 2, height / 2 ],
projection = d3.geoEquirectangular().scale( scale ).rotate( [0,0] ).center([0,5]).translate( offset ),
bounds = 墨卡托界限( projection ),
scaleExtent;
scale = width / (bounds[ 1 ][ 0 ] - bounds[ 0 ][ 0 ]);
scaleExtent = [ scale, 10 * scale ];
projection
.scale( scaleExtent[ 0 ] );
return projection;
},
mercatorBounds = function(projection) {
var maxlat = 83,
yaw = projection.rotate()[ 0 ],
xymax = projection( [ -yaw + 180 - 1e-6, -maxlat ] ),
xymin = projection( [ -yaw - 180 + 1e-6, maxlat ] );
return [ xymin, xymax ];
};
getProjection 方法以worldJson为参数。此参数不过是我们加载的TopoJSON文件。在解释以上方法的作用之前,让我解释一下本教程中将要使用的几个术语。
- 投影: 投影用于将球坐标投影到我们的二维屏幕上。基本上,TopoJSON文件以度为单位提供球坐标,并且投影将其转换为以像素为单位的笛卡尔坐标。
- 中央: projection.center方法将location([lon,lat])作为数组,并将投影的中心设置为指定位置。例如,如果我使用[0,5],则地图将以西0度和北5度为中心。北代表纬度的正值,南代表纬度的负值。
- 翻译: 平移偏移量确定投影中心的像素坐标,然后返回投影。
- 规模: 将投影的比例因子设置为指定值,然后返回投影。
- 旋转: 将投影仪的三轴旋转设置为以度为单位的指定角度λ,φ和γ(经度,纬度和侧倾),然后返回投影。
阅读更多有关官方的预测 文件资料.
getProjection方法
让我们回到方法 getProjection。首先,我们只是在猜测这样的投影
var center = d3.geoCentroid( worldJson ),
scale = 1,
offset = [ width / 2, height / 2 ],
projection = d3.geoEquirectangular().scale( scale ).rotate( [0,0] ).center([0,5]).translate( offset );
墨卡托界限 方法计算当前投影的边界。边界将为我们提供平移和缩放投影的确切值。确定边界后,更新投影比例。计算边界并更新投影将确保您的地图将占据所提供容器的完整尺寸并始终居中。到目前为止,这是在d3中创建地图时最难理解的事情。互联网上的其他教程/文章提供了上述属性的硬编码值,并留下了我上面解释过的最困难的部分。
到目前为止,您还没有在屏幕上看到任何东西。忍受我,我们快完成了。其余部分很容易。
绘制地理
这样定义路径生成器
var path = d3.geoPath().projection( projection );
svg.selectAll( 'path.land' )
.data( topojson.feature( worldJson, worldJson.objects.countries ).features )
.enter().append( 'path' )
.attr( 'class', 'land' )
.attr( 'd', path );
这是按预期绘制世界地图的最终代码段。在这里,我们将国家数据与路径绑定在一起 元素。 topojson.feature(worldJson,worldJson.objects.countries)。此功能可从定义国家/地区的TopoJSON文件中提取数据。
美化
这张地图看起来有点难看。让我们添加一些样式,让世界变得美丽。添加以下样式代替“在此处写CSS”
html {
height: 100%;
}
body {
background: #2c87a9;
height: inherit;
margin: 0;
padding: 0;
}
.map {
height: 100%;
}
.water {
fill: none;
}
.land {
fill: #44ab66;
stroke: #080808;
stroke-width: 0.5px;
}
.land:hover {
fill: #49988d;
stroke: #080808;
stroke-width: 1.5px;
}
看看我们的世界地图看起来如何 这里.