d3.js 世界 topojson v4
d3.js world topojson v4
我正在尝试让世界地图显示类似于 U.S。此处提供地图 (U.S. map),但我 运行 遇到了一些问题。目前我的世界地图代码是这样的:
<!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/world-atlas@1/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>
但是,它显示的地图只占据了我 window 的左上部分,看起来不正确。
目前我对我可能做错了什么感到困惑。如果有人有任何见解,我将不胜感激。
谢谢。
编辑:我实际上能够使用此处提供的代码让它工作
<!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/world-atlas@1/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>
我认为我的缩放比例有误,没有正确地投影到地图上。如果有人对我的做法有任何意见,请告诉我。
您引用的美国 json 是一个特殊的 json 文件 - 它不需要使用投影。您的 path
变量使用空投影(默认投影),将 geojson 中的坐标(topojson 转换成的坐标)转换为像素值而不进行转换。
创建此文件可能是为了允许更简单的块通过跳过投影细节来显示 d3 功能,但无论如何它相对独特,因为它是如何投影的。
美国 json 文件中的每个顶点都已从表示 3 维地球上的点的 latitude/longitude 对转换为表示宽度为 960 的平面的笛卡尔 x,y 坐标高度为 500(bl.ock 默认视图的宽度和高度)。您的世界数据仍然包含纬度经度对,因此需要使用投影。
您的数据未投影是因为它是颠倒的,这是在将纬度经度数据转换为 svg 中的像素坐标而没有定义投影的变换时产生的。北极在北纬 90 度,赤道在 0 度。使用 SVG 时,y 坐标为零将位于屏幕顶部,y 坐标为 90 将向下 90 像素。因此,将纬度经度点转换为 x,y svg 点而不进行转换时,北极将位于赤道下方。此外,西半球和南半球的 x and/or y 值为负,因此如果不进行转换,它们将不会出现在您的 svg 中。这就是为什么您在地图上只能看到本初子午线以东和赤道以北的点。
如何解决这个问题?您需要投影数据。您可以使用任何一种投影,我将使用墨卡托,因为它可能比其他投影更容易辨认(尽管在两极附近存在严重的失真问题):
var projection = d3.geoMercator();
var path = d3.geoPath().projection(projection);
就是这样 (see here)。
供参考,墨卡托投影的默认参数旨在显示 960 像素的地球,如果您想专注于特定区域或显示不同尺寸(比例)的地图,则需要设置投影参数。
我正在尝试让世界地图显示类似于 U.S。此处提供地图 (U.S. map),但我 运行 遇到了一些问题。目前我的世界地图代码是这样的:
<!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/world-atlas@1/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>
但是,它显示的地图只占据了我 window 的左上部分,看起来不正确。 目前我对我可能做错了什么感到困惑。如果有人有任何见解,我将不胜感激。
谢谢。
编辑:我实际上能够使用此处提供的代码让它工作
<!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/world-atlas@1/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>
我认为我的缩放比例有误,没有正确地投影到地图上。如果有人对我的做法有任何意见,请告诉我。
您引用的美国 json 是一个特殊的 json 文件 - 它不需要使用投影。您的 path
变量使用空投影(默认投影),将 geojson 中的坐标(topojson 转换成的坐标)转换为像素值而不进行转换。
创建此文件可能是为了允许更简单的块通过跳过投影细节来显示 d3 功能,但无论如何它相对独特,因为它是如何投影的。
美国 json 文件中的每个顶点都已从表示 3 维地球上的点的 latitude/longitude 对转换为表示宽度为 960 的平面的笛卡尔 x,y 坐标高度为 500(bl.ock 默认视图的宽度和高度)。您的世界数据仍然包含纬度经度对,因此需要使用投影。
您的数据未投影是因为它是颠倒的,这是在将纬度经度数据转换为 svg 中的像素坐标而没有定义投影的变换时产生的。北极在北纬 90 度,赤道在 0 度。使用 SVG 时,y 坐标为零将位于屏幕顶部,y 坐标为 90 将向下 90 像素。因此,将纬度经度点转换为 x,y svg 点而不进行转换时,北极将位于赤道下方。此外,西半球和南半球的 x and/or y 值为负,因此如果不进行转换,它们将不会出现在您的 svg 中。这就是为什么您在地图上只能看到本初子午线以东和赤道以北的点。
如何解决这个问题?您需要投影数据。您可以使用任何一种投影,我将使用墨卡托,因为它可能比其他投影更容易辨认(尽管在两极附近存在严重的失真问题):
var projection = d3.geoMercator();
var path = d3.geoPath().projection(projection);
就是这样 (see here)。
供参考,墨卡托投影的默认参数旨在显示 960 像素的地球,如果您想专注于特定区域或显示不同尺寸(比例)的地图,则需要设置投影参数。