d3.js v5: невозможно получить точки данных для отображения на карте США - PullRequest
2 голосов
/ 31 октября 2019

Я могу успешно получить карту США для рендеринга, однако мои данные не позволяют. (Я понимаю, что 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

1 Ответ

0 голосов
/ 31 октября 2019

Здесь есть ряд проблем:

Передача .data в массив

Сначала при использовании

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

selectAll().data() требуется передать вам функцию илимассив. В вашем случае вам нужно передать ему массив данных - однако, meteoriteData - это объект. Это коллекция объектов геойсона со следующей структурой:

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

Все отдельные объекты геоджона находятся в массиве внутри этого объекта. Чтобы получить массив объектов, в данном случае, объектов, представляющих метеоры, нам нужно использовать:

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]; })

Здесь есть два вопроса: один, геойсон равен [longitude,latitude] или [x,y] (здесь вы получаете координату y, но устанавливаете значение x).

Но, более серьезное беспокойство вызывает то, что вы не проецируете свои данные. Это необработанная координата вашего геойсона:

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

Вы берете долготу и напрямую переводите ее в значение в пикселях. Но ваш геойсон использует трехмерное координатное пространство (непроецированные точки на трехмерном шаре) с единицами измерения в градусах. Если мы просто конвертируем это в пиксели, cx = -113, ваш круг появится за пределами экрана слева от SVG.

Использование проекции

Для этого вам необходимо спроецировать ваши данныемы бы определили функцию проекции и использовали бы что-то вроде:

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

Она получает долготу и широту и передает их в функцию проекции, а затем получает возвращенное значение x и устанавливает его в качестве значения для cx.

Проекция принимает непроецированную координату в 3-мерном пространстве (точки на глобусе или пары long / lat) с единицами измерения в градусах и возвращает точку в 2-мерном пространстве с единицами измерения в пикселях.

Но теперь это приводит нас к самой сложной части:

Какую проекцию вы должны использовать?

Нам необходимо согласовать наши точки с американскими функциями, которые ужебыли нарисованы, но вы не определяете проекцию для штатов США - если вы не предоставляете проекцию для d3.geoPath, она использует нулевую проекцию, она принимает предоставленные координаты и отображает их в SVG, как если бы они были пиксельными координатами,Преобразование не происходит. Я знаю, что ваши американские объекты проецируются, потому что Аляска находится не там, где она должна быть, значения координат в топойсоне превышают +/- 180 градусов по долготе, +/- 90 по широте, и карта выглядит такпроецируется с проекцией Альберса.

Если geoPath не проецирует данные с проекцией d3, но данные отрисовываются, как если бы они были спроецированы, данные предварительно проецируются - этот топойсон хранит уже спроецированные точки.

Мы имеемПроецируемые данные (штаты США) и непрогнозируемые данные (удары метеоритов), их смешивание всегда является проблемой.

Задача здесь состоит в создании проекции, которая копирует функцию проекции, используемую для создания набора данных штатов США. Мы можем воспроизвести этот прогноз, так как это проблемный файл, который приводит ко многим вопросам. Как это сделать, объяснено здесь . Но это сложнее, чем должно быть: смешивание проецируемых и непроецированных данных является обременительным, негибким и более сложным, чем необходимо.

Я бы посоветовал вам использовать непроецированные данные как для США, так и для метеоров:

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

Мы можем нарисовать пути одинаково, если найдем не спроецированный топойсон / геойсон США. , и мы можем поставить точки с:

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

Что касается поиска непроецированного топойсона США, здесь 's one.

А вот рабочая версия , использующая описанный выше подход и проецирующая все данные (я также отфильтрую функции, чтобы избавиться от тех, у которых нет координат, которые могут быть разбиты Альберами США, поскольку они составныепроекция).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...