2017-07-10 163 views
0

我想获得一张世界地图,显示类似于这里提供的美国地图(U.S. map),但我遇到了一些问题。目前,这是我迄今为止我的世界地图代码:d3.js world topojson v4

<!DOCTYPE html> 
<style> 

</style> 
<svg width="960" height="600"></svg> 
<script src="https://d3js.org/d3.v4.min.js"></script> 
<script src="https://d3js.org/topojson.v2.min.js"></script> 
<script> 

var svg = d3.select("svg"); 

var path = d3.geoPath(); 

d3.json("https://unpkg.com/[email protected]/world/50m.json", function(error, world) 
{ 
    if (error) throw error; 

    svg.append("g") 
     .selectAll("path") 
     .data(topojson.feature(world, world.objects.countries).features) 
     .enter().append("path") 
      .attr("d", path); 

}); 

</script> 

然而,它显示只占用了我的窗口的左上部分,而且似乎看不正确的地图。 目前我对我可能做错了什么感到困惑。如果有人有任何见解,我将不胜感激。

谢谢。

编辑:实际上,我是能够得到它提供的代码在这里工作

<!DOCTYPE html> 
<style> 

    .countries :hover 
    { 
     fill: red; 
    } 

    .country-borders 
    { 
     fill: none; 
     stroke: #FFF; 
     stroke-width: 0.5px; 
     stroke-linejoin: round; 
     stroke-linecap: round; 
     cursor: pointer; 

    } 

</style> 
<meta charset="utf-8"> 
<body> 
<script src="http://d3js.org/d3.v4.min.js"></script> 
<script src="http://d3js.org/topojson.v1.min.js"></script> 
<script> 
var format = d3.format(","); 


var margin = {top: 0, right: 0, bottom: 0, left: 0}, 
      width = 1200 - margin.left - margin.right, 
      height = 900 - margin.top - margin.bottom; 


var path = d3.geoPath(); 

var svg = d3.select("body") 
      .append("svg") 
      .attr("width", width) 
      .attr("height", height) 
      .append('g') 
      .attr('class', 'map'); 

var projection = d3.geoMercator() 
        .scale(170) 
        .translate([width/2, height/1.5]); 

var path = d3.geoPath().projection(projection); 


d3.json("https://unpkg.com/[email protected]/world/50m.json", function(error, world) 
{ 
    svg.append("g") 
     .attr("class", "countries") 
    .selectAll("path") 
     .data(topojson.feature(world, world.objects.countries).features) 
    .enter().append("path") 
     .attr("d", path); 


    svg.append("path") 
     .attr("class", "country-borders") 
     .attr("d", path(topojson.mesh(world, world.objects.countries, function(a, b) 
     { 
      return a !== b; 
     }))); 
}); 

</script> 
</body> 
</html> 

我相信我在做我的缩放错误,不能正确地做投影到地图上。如果有人对我的做法有任何意见,请让我知道。

回答

1

您引用的美国json是一个特殊的json文件 - 它不需要使用投影。您的path变量使用空投影(默认投影),将geojson中的坐标(topojson转换到的坐标)转换为像素值而不进行转换。

此文件可能已创建,允许通过跳过投影细节来显示d3功能的更简单的块,但无论如何由于其投影方式而相对独特。

该美国json文件中的每个顶点已经从表示三维地球上一个点的纬度/经度对转换为笛卡尔x,y坐标,表示宽度为960,高度为500的平面bl.ock默认视图的宽度和高度)。你的世界数据仍然包含纬度经度对,因此需要使用投影。

A给出你的数据未被投影的是它是颠倒的,这是在没有定义投影的变换的情况下将纬度经度数据转换为svg中的像素坐标时的结果。北极北纬90度,赤道0度。使用SVG时,y坐标为零将位于屏幕顶部,90的y坐标将向下90像素。因此,将纬度经度点转换为x,y svg点时,北极将位于赤道以下,且不会转换。此外,西半球和南半球的x值和/或y值都是负数,所以它们不会在没有变换的情况下出现在你的svg中。这就是为什么你只能看到地图上主要子午线以东和赤道以北的点。

如何解决这个问题?你需要投影你的数据。你可以使用任何一个预测,我会用墨卡托,因为它很可能比其他人更容易识别(尽管两极附近主要失真的问题):

var projection = d3.geoMercator(); 
var path = d3.geoPath().projection(projection); 

这就是它(see here)。

作为参考,墨卡托投影的默认参数旨在显示960像素的地球,如果您想要专注于特定区域或以不同大小(比例)显示地图,则需要设置投影参数。