D3.js Карта с проекцией Альберса: как ее повернуть?

#javascript #d3.js #topojson #map-projections

#javascript #d3.js #topojson #карта-проекции

Вопрос:

Я создаю карту Филиппин с d3.js и по странной причине карта выглядит повернутой влево, так что страна выглядит не такой, какая она есть на самом деле. Я пытался изменить поле projection.rotate, но, похоже, это не линия коррекции.

     var width = 1060,
    height = 860;

    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        .style("overflow", "auto");

    d3.json("ph.json", function(error, ph) {
      if (error) return console.error(error);

      var subunits = topojson.feature(ph, ph.objects.ph_subunits);

      var projection = d3.geo.albers();
      projection.rotate([-4 ,0]);
      projection.scale(3000);
      projection.center([122.427150, 12.499176]);
      projection.parallels([10, 15])
      projection.translate([width / 2, height / 2]);

      var path = d3.geo.path()
           .projection(projection)
           .pointRadius(2);
      svg.append("path")
        .datum(subunits)
        .attr("d", path);

    });
  

Это код.

Любая помощь была бы отличной!

Спасибо!

Ответ №1:

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

Стандартные параллели

Это проекция Альберса, для параллелей которой установлены значения 10 и 15 .parallels([10,15]) , как в вашем вопросе, и масштаб 100 (а для поворота и центра установлено значение [0,0]):

Базовый Альберс

Такая форма обусловлена конической природой проекции. Если выбраны южные параллели, вогнутость меняется на противоположную. Более экстремальные широты / параллели приведут к большему изгибу.

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

Поворот

Если бы мы хотели сказать, сосредоточьтесь на Австралии (я сохраню параллели такими же, как на изображении выше, для демонстрации):

Австралия клип

Мы могли бы просто использовать географический центр Австралии в качестве центра проекции .projection.center([x,y]) и масштабировать до соответствующего уровня .projection.scale(1000) :

Австралия

Единственное изменение заключается в том, что Австралия больше, она по-прежнему так же искажена, как когда она была в углу карты, и меньше. Она была сдвинута вверх / вниз и влево / вправо, а затем увеличена без каких-либо других преобразований.

Как следует из вашего вопроса, вращение — это решение проблемы отображения областей, расположенных не вблизи нулевого меридиана.

Если мы повернем первую карту (которая совпадает со второй картой) на 100 градусов долготы .projection.rotate([100,0]) , мы получим:

Альберс 100 градусов

Мир развернулся на 100 градусов, и воображаемая линия, проведенная вертикально через центр карты, совпадает с меридианом на -100 градусов долготы или 100 градусов западной долготы.

Центрирование

Если наша область интересов — Центральная Америка (для которой параллели, которые вы использовали — и я продолжаю использовать — будут работать), то следующим шагом будет смещение центра карты вверх и вниз вдоль центрального меридиана проекции. Для Центральной Америки этот сдвиг может составлять 20 градусов : .projection.center([0,20]) . При соответствующем масштабе, скажем, 1000, результат будет выглядеть так:

Финал

Филиппины

Итак, для Филиппин, используя вашу центральную координату [122.427150, 12.499176] и параллели, идеальная проекция Альберса может выглядеть так:

         projection.rotate([-122.427150,0])
              .center([0,12.499176])
              .scale(1200)
              .parallels([10,15]);
  

Что для меня дало:
Финал

Краткие сведения

Для Альберса:

 projection.parellels([a,b])
  .rotate([-x,0])
  .center([0,y])
  .translate([w/2,h/2])
  

Где a и b — параллели, пересекающие интересующую область, y центральная параллель и x центральный меридиан.

При использовании метода ( projeciton.fitSize / projection.fitExtent ) для автоматического центрирования и масштабирования объекта вам не нужно использовать методы center и rotate, но вы все равно должны сначала установить параллели и поворот.