地图中的圆圈在 D3 V4 中显示的位置不正确

IT技术 javascript d3.js svg geo map-projections
2021-02-21 09:41:32

我正在使用教程来学习如何在 D3.v3 中生成地图,但我使用的是 D3.v4。我只是想让一些圆圈出现在地图上(见下文)。该代码有效,只是圆圈在内华达州上空并且应该在湾区。我想这是地图投影和投影坐标之间的不匹配。我不确定地图所在的投影,但我试图将其强制为 albersUsa(请参阅我生成路径的注释命令),但这会导致整个地图消失。任何帮助,将不胜感激!

<!DOCTYPE html>

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>

var w = 960,
    h = 600;
var projection = d3.geoAlbersUsa();
var path = d3.geoPath()
             //.projection(projection)

d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {
  if (error) throw error;

  var svg = d3.select("body").append("svg")
    		.attr("width", w)
    		.attr("height", h);

  svg.selectAll("path")
     .data(topojson.feature(us, us.objects.states).features)
     .enter().append("path")
	 .attr("class", "states")
     .attr("d", path);

   svg.append("path")
      .attr("class", "state-borders")
      .attr("d", path(topojson.mesh(us, us.objects.states)))

   svg.append("path")
      .attr("class", "county-borders")
      .attr("d", path(topojson.mesh(us, us.objects.counties)));

      aa = [-122.490402, 37.786453];
  	  bb = [-122.389809, 37.72728];

   svg.selectAll("circle")
      .data([aa,bb]).enter()
      .append("circle")
      .attr("cx", function (d) { return projection(d)[0]; })
      .attr("cy", function (d) { return projection(d)[1]; })
      .attr("r", "8px")
      .attr("fill", "red")
    });

</script>

1个回答

你的美国 json 已经被投影了,为了显示它,你使用了一个空投影:

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

如果没有定义投影,您的 topojson/geojson 坐标将被转换为直线像素坐标。碰巧这个特定的 topojson 文件的像素坐标在 [0,0] 和 [960,600] 之间,几乎与默认的 bl.ock 视图大小相同。在不知道所使用的投影也创建该文件的情况下,您无法复制该投影以将地理要素与您的数据对齐。除非您直接使用像素值放置特征并完全跳过投影(对于不在可识别地标附近或精度很重要的点没有用)。

使用 a 进行投影时,您的 US topojson 特征会消失,geoUsaAlbers()因为您在平面上获取像素坐标并将它们转换为 svg 坐标,就好像它们是三维地球上的点一样(d3 投影需要纬度经度对)。

相反,请使用未投影的 topojson 或 geojson。也就是说,它包含纬度/经度对,并将该数据与您的点一起投影。有关使用您的代码(但将投影分配给的美国未投影(纬度/经度对)json 的示例,请参阅此bl.ockpath

要检查您是否有纬度/经度对,您可以轻松地在 geojson 文件中查看这些要素的几何形状,并查看这些值是否是有效的长纬度点。对于topojson,topojson 库将要素转换为geojson,因此您可以查看转换后的几何图形。

这是美国未投影的 topojson:https ://bl.ocks.org/mbostock/raw/4090846/us.json


假设您确实想使用相同的 topojson 文件,我们可能可以推断出它使用的投影。首先,我将展示您的投影点(通过使用美国的未投影轮廓)和已经投影的 topojson(未投影的 topojsond3.geoAlbersUsa()与空投影投影)之间的差异

在此处输入图片说明

很有可能 d3.geoAlbersUsa 投影针对 bl.ocks.org 默认视口 960x500 进行了优化。未投影的数据集有一个大约 960x600 的边界框,所以也许如果我们将比例增加 600/500 并调整平移,我们可以在 960x600 的 svg 中对齐我们的特征:

var projection = d3.geoAlbersUsa();
var scale = projection.scale() * 600 / 500;
projection.scale(scale).translate([960/2,600/2])
var projectedPath = d3.geoPath().projection(projection);

而且,这似乎很好地对齐,我看不出两者之间的区别:

在此处输入图片说明

这是一个显示对齐特征

但正如我在评论中提到的,即使您可以对齐特征: 任何缩放或居中都会有问题,因为您需要对已投影的数据使用 geoTransform,但对原始地理数据使用 geoProjection。使用所有(均匀)投影数据或所有未投影数据使生活更简单。

谢谢(你的)信息。非常感激!
2021-04-23 09:41:32
一般的投影类型是已知的,它是复合USA Albers;但是,参数未知。鉴于其尺寸,它似乎针对 bl.ocks 进行了优化。它也经常是关于 SO 的问题的来源。由于确切的参数未知,因此在叠加地理点时使用起来很困难。即使您知道使用的所有投影参数 - 任何缩放或居中都会有问题,因为您需要对已经投影的数据使用 geoTransform 而对原始地理数据使用 geoProjection。使用所有(均匀)投影数据或所有未投影数据使生活更简单。
2021-04-29 09:41:32
谢谢!这就说得通了。只是为了让我正确理解你:d3.js 美国地图集有一个未知的投影?
2021-05-03 09:41:32
谢谢。您知道未投影的高分辨率 geoJSON(或 topoJSON)数据的来源吗?我知道有用于 shapefiles --> json 的转换器,但我发现最好从我的脚本中下载文件(如上所述)。
2021-05-10 09:41:32
您正在使用的文件的来源可能与此相同:bl.ocks.org/mbostock/raw/4090846/us.json(这是未投影的);但是,我知道没有明确的 geojson/topojson 来源。高分辨率 geojson、topojson(或更常见的 shapefile,请参阅 mapshaper.org 以方便转换)通常可从政府来源公开获得。对于可以在浏览器中合理显示的内容,文件大小将是您的主要限制,因此能够剪辑、简化、平铺或修改文件可能是其他可以发挥作用的东西。
2021-05-14 09:41:32