d3.js карта диаграммы нарисовать прямоугольник - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь нарисовать карту для эмиратов ОАЭ, используя geojson.

Геойсон действителен и проверен на geojson.io, результат отображается вместо прямоугольника карты, написанный код здесь:

var width = 20,
height = 20;
var scal = (1 << 10) / 2 / Math.PI; 

//Define map projection 
var projection = d3.geo.mercator();
      projection
        .scale(scal)///3.5
        .translate([width/2, height/2]);

//Define path generator
var path = d3.geo.path().projection(projection);

d3.json("http://localhost/data/uae-em.json", function(error,json) {

    if(error) alert("error fetching data");
    var svg = d3.select("article")
        .append("svg")
        .attr("width",width)
        .attr("height",height);
    //draw map
    var map = svg.selectAll("path")
        .data(json.features)
        .enter()
        .append("path")
        .attr("d", path)
        .style("fill", "#3498db"); 
    });

Данные JSON находятся здесь: https://files.fm/f/ndsz3v85

А вот пример функции из геойсона:

{"type":"Feature","id":"4","properties":{"name":"UmmAlQwain"},"geometry":{"type":"Polygon","coordinates":[[[55.2350748,25.5700834],[55.4229709,25.3989174],[55.4236655,25.3981583],[55.423986,25.3978339],[55.4254059,25.3960785],[55.4272991,25.3935724],[55.4570596,25.3762406],[55.4577152,25.375909],[55.4915399,25.3593419],[55.4926741,25.3588472],[55.4954455,25.35793],[55.5013237,25.3571279],[55.5031779,25.3570031],[55.5390972,25.3630675],[55.5909015,25.3679027],[55.5918297,25.3680754],[55.5927443,25.3683591],[55.5935906,25.3688154],[55.5943278,25.3693581],[55.5952833,25.3702339],[55.6010034,25.3768825],[55.6044809,25.3808245],[55.6295136,25.4095735],[55.630044,25.4101151],[55.6303207,25.4106671],[55.6302516,25.411542],[55.6299137,25.4123589],[55.6293946,25.413368],[55.6287288,25.4144586],[55.6280518,25.4152536],[55.6211794,25.4201663],[55.6196221,25.4209307],[55.6177489,25.4214301],[55.605742,25.4232035],[55.6024463,25.4237462],[55.5975759,25.4244245],[55.5956543,25.4249531],[55.5919637,25.4262723],[55.554199,25.4399865],[55.5518752,25.4408552],[55.5505241,25.4414505],[55.5490758,25.4421533],[55.5473004,25.4425344],[55.5456819,25.4430884],[55.5370397,25.4462406],[55.5358338,25.4466226],[55.5349558,25.4467468],[55.5337817,25.4467659],[55.523193,25.4459922],[55.5198927,25.4460304],[55.5162327,25.4457248],[55.513895,25.4454286],[55.4882538,25.4420186],[55.4870268,25.4419613],[55.4857574,25.4421332],[55.4843188,25.4426681],[55.4771469,25.4472339],[55.4709611,25.4516781],[55.324428,25.6230138],[55.3205286,25.6184125],[55.3117729,25.6106044],[55.3015804,25.5994214],[55.2892555,25.5829995],[55.2795994,25.5665793],[55.2730684,25.5680481],[55.2385191,25.570346],[55.2350748,25.5700834]]]}}

1 Ответ

0 голосов
/ 06 сентября 2018

Здесь есть несколько вопросов.

Во-первых, причина, по которой вы получаете прямоугольник, заключается в порядке намотки. D3 не включает в себя порядок намотки спецификации Geojson - он следует порядку намотки шейп-файлов. Это довольно странно, потому что D3 - единственная структура, которая приходит на ум, где порядок намотки имеет значение с точки зрения рисования, потому что он использует сферическую геометрию, а не плоскую. В вашем случае вы рисуете все, кроме ОАЭ:

enter image description here

Я добавил штрих, мы можем видеть край света (+/- 180 градусов восток-запад, а не вершину, потому что Меркатор растягивается до бесконечности по оси Y, и даже если он закруглен или отрезан, пределы находятся за пределами SVG), мы также можем увидеть схему ОАЭ (или его часть, по крайней мере). Поэтому нам нужно изменить порядок намотки, это означает, что нужно поменять местами массивы, содержащие координаты, которые определяют каждое кольцо в многоугольнике.

Для этого мы можем использовать turf.js, либо для предварительной подготовки данных, либо для вызова его каждый раз, когда мы загружаем данные:

json.features.forEach(function(feature) {
  feature.geometry = turf.rewind(feature.geometry, {reverse:true});
})

Теперь, когда у нас есть данные в правильном порядке, мы получаем:

enter image description here

Функция выглядит больше, потому что мы можем видеть все объекты, на первом изображении действительно видна только последняя нарисованная функция: она охватывает остальные функции.

Теперь у нас другая проблема, я отобразил вашу карту в кадре 960x500 пикселей (используя ваш код ( fiddle )). Если бы мы использовали кадр 20x20 и ваш начальный масштаб, мы ничего не видим. Карта центрирована в [0,0], в Атлантике у побережья Африки:

enter image description here

Квадрат очерчивает грубую область вашей карты, показанную в версии 20x20, используя ваш масштаб и перевод. Я добавил карту мира и увеличил размер до 200x200, чтобы придать некоторый визуальный контекст тому, что мы ищем в версии 20 пикселей


Если цель - показать весь мир, нам нужен правильный масштаб. Цилиндрическая проекция типа Меркатора (если цилиндр ориентирован на север / юг) занимает 360 градусов вокруг Земли (вдоль экватора) и растягивает ее на определенное расстояние в единицах карты. В d3 масштаб является этим коэффициентом преобразования, по умолчанию предполагается, что на карте отображается 960 пикселей по всей планете, а вокруг Земли - 2π радиана, поэтому значение масштаба составляет 960 / 2π (960 пикселей на 2π радиана). Итак, мы можем установить вашу шкалу на width/Math.PI/2:

enter image description here

Это приведет к новой проблеме: ОАЭ имеет ширину около 5 градусов, мир вокруг - 360 градусов, что составляет около 1% мировой «ширины». Это немного проблематично при отображении вашей карты в формате SVG размером 20 на 20 пикселей: ширина ОАЭ составляет около 0,2 пикселя, что не очень хорошо рендерится. Единственным вариантом будет увеличение размера карты или центрирование карты в ОАЭ и увеличение масштаба.

Автоматическое центрирование карты было рассмотрено много раз, и я бы не стал отдавать должное предыдущим превосходным объяснениям, повторяя его снова (все, что я могу сказать, это v4 / 5, предлагающий отличный метод fitSize / fitExtent, но информация центрирования v3 может быть нашел в этом вопрос ). Однако для демонстрации я вручную центрирую ОАЭ ниже.

Центр тяжести в ОАЭ составляет около 24 N, 54E (от здесь ).

Если мы предположим, что ОАЭ шире, чем высоки, и предположим, что число составляет около 5 градусов в поперечнике, и мы хотим отобразить эти пять градусов над 20 пикселями, то мы знаем, что мир имеет ширину около 1440 пикселей (mapWidthPixels * earthWidthDegrees / mapWidthDegrees = 20 * 360/5). Масштаб 1440/2 / π, округляя его немного, чтобы получить дополнительный запас: 200.

Итак, используя:

var width = 20;
var height = 20;
var scale = 200;
var center = [54,24];

Мы можем получить это:

enter image description here

Все еще небольшой, но с вышеупомянутыми принципами, легко расширяется.

скрипка .

Я добавил границу к SVG с 20px выше, чтобы обеспечить границу для SVG, учитывая небольшой размер и отсутствие различия в том, где края SVG

...