d3.js v5:无法获取要在美国地图上显示的数据点

问题描述 投票:1回答:1

我可以成功获取要渲染的美国地图,但是我的数据点却没有。 (我了解d3.js在v5中进行了一些重大更改,因此请注意,先前询问的类似问题不适用)

$(document).ready(function () {

var us = d3.json('https://unpkg.com/us-atlas@1/us/10m.json');
var meteoriteData = d3.json('https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json');

var svg = d3.select("svg")
    .style("width", "1110px")
    .style("height", "714px");

var path = d3.geoPath();

Promise.all([us, meteoriteData]).then(function (values) {

    var map = values[0];
    console.log("map", map);

    var meteoriteData = values[1];
    console.log("meteoriteData", meteoriteData);

    svg.append("g")
        .attr("fill", "#ccc")
        .selectAll("path")
        .data(topojson.feature(map, map.objects.states).features)
        .enter().append("path")
        .attr("d", path),

        svg.append("path")
            .datum(topojson.mesh(map, map.objects.states, (a, b) => a !== b))
            .attr("fill", "none")
            .attr("stroke", "white")
            .attr("stroke-linejoin", "round")
            .attr("pointer-events", "none")
            .attr("d", path),

        svg.selectAll("circle")
            .data(meteoriteData)
            .enter()
            .append("circle")
            .attr("class", "circles")
            .attr("cx", function (d) { return ([d.geometry.coordinates[0], d.geometry.coordinates[1]])[1]; })
            .attr("cy", function (d) { return ([d.geometry.coordinates[0], d.geometry.coordinates[1]])[0]; })
            .attr("r", "1px");
});

});

并且可以在这里找到工作副本。https://codepen.io/lady-ace/pen/PooORoy

d3.js geojson topojson
1个回答
0
投票

这里有很多问题:

。data传递数组

首先,使用时

svg.selectAll("circle")
   .data(meteoriteData)

selectAll().data()要求您传递函数或数组。在您的情况下,您需要将数据数组传递给它-但是meteoriteData是一个对象。这是一个具有以下结构的geojson要素集合:

{
  "type": "FeatureCollection",
  "features": [
      /* features */
  ]
}

[所有单独的geojson特征都在该对象内部的数组中。要获得一系列特征,在这种情况下代表流星的特征,我们需要使用:

svg.selectAll("circle")
   .data(meteoriteData.features)

现在,我们可以为要素集中的每个要素创建一个圆圈。如果执行此操作,则在检查SVG元素时可以找到圆,但是它们放置不正确。


定位点

如果进行上述更改,您将不会在正确的位置看到圆圈。您在此处未正确放置圆圈:

 .attr("cx", function (d) { return ([d.geometry.coordinates[0], d.geometry.coordinates[1]])[1]; })

与以下相同:

 .attr("cx", function(d) { return d.geometry.coordinates[1]; })

[这里有两个问题:一,geojson是[longitude,latitude][x,y](您在这里得到y坐标,但设置了x值)。

但是,更大的问题是您不打算投影数据。这是来自geoj​​son的原始坐标:

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [
      -113,
      54.21667
    ]
   ...

您正在获取经度并将其直接转换为像素值。但是您的geojson使用3D坐标空间(3D地球上的未投影点),单位为度。如果我们简单地将其转换为像素cx = -113,则您的圆圈将显示在屏幕外SVG的左侧。

使用投影

您需要对数据进行投影,为此,我们将定义一个投影函数,并使用类似的方法:

  .attr("cx", function(d) { return projection(d.geometry.coordinates)[0] })

这将同时获得经度和纬度,并将它们传递给投影函数,然后获取返回的x值并将其设置为cx的值。

[投影在3维空间(地球上的点或长/纬线对上的点)以度为单位的未投影坐标,并在2维空间中以像素为单位返回点。

但是,这现在把我们带到了最困难的部分:

您应该使用哪种投影?

我们需要将点与已经绘制的美国要素对齐,但是您没有为美国各州定义投影-如果您不向d3.geoPath提供投影,则它将使用空投影,接受提供的坐标并将其绘制在SVG上,就好像它们是像素坐标一样。没有转换发生。我知道您的美国地图是投影的,因为阿拉斯加不在原处,topojson中的坐标值在经度上超过+/- 180度,在纬度上超过+/- 90,并且地图看起来像用Albers投影进行投影。

[如果geoPath并未使用d3投影来投影数据,而是像投影一样来绘制数据,则将数据预先投影-此topojson存储已经投影的点。

[我们有投影数据(美国各州)和非投影数据(流星雨),将它们混合始终是一个挑战。

这里的挑战是创建一个投影,该投影复制用于创建美国各州数据集的投影函数。我们可以复制该投影,因为它是一个有问题的文件,会引发很多问题。解释方法here。但这比应该的要复杂得多:混合投影数据和非投影数据是繁重的,不灵活的,并且比需要的还要复杂。

我建议您对美国和流星使用非投影数据:

var projection = d3.geoAlbersUsa();             // create an Albers USA projection
var path = d3.geoPath().projection(projection); // set the projection for the path

[我们可以以相同的方式绘制路径,只要找到美国的未投影topojson / geojson,并且可以使用以下方式放置点:

.attr("cx", function(d) { return projection(d.geometry.coordinates)[0]; })
.attr("cy", function(d) { return projection(d.geometry.coordinates)[1]; })

至于找到一个非计划的美国topojson,here的一个。

这是使用上述方法并投影所有数据的working version(我也过滤了要素以消除没有坐标的要素,因为美国Albers可能会破坏这些要素,因为它是复合投影)。

© www.soinside.com 2019 - 2024. All rights reserved.