d3 v4 geo рисует границу перевернутой

Когда я рисую Бермудский треугольник в элементе SVG, масштаб не такой, как я ожидал (треугольник должен простираться до краев блока), а заливка обратная (вместо рисования треугольника он рисует квадрат с вырезанным треугольником).

var geojson = {
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "Bermuda Triangle",
        "area": 1150180
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [-64.73, 32.31],
            [-80.19, 25.76],
            [-66.09, 18.43],
            [-64.73, 32.31]
          ]
        ]
      }
    }
  ],
  "type":"FeatureCollection"
};

var width = 480;
var height = 480;

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)
  .attr("style", "border: 2px solid black");

var projection = d3.geoMercator().fitSize([width, height], geojson);
var path = d3.geoPath().projection(projection);

svg.selectAll('path')
  .data(geojson.features)
  .enter()
  .append('path')
  .attr('d', path)
  .style("fill", "red")
  .style("stroke-width", "1")
  .style("stroke", "black");
<script src="//d3js.org/d3.v4.js"></script>

Что я делаю не так?


person gregjhogan    schedule 11.11.2017    source источник


Ответы (2)


Давайте изменим это:

[
    [-64.73, 32.31],
    [-80.19, 25.76],
    [-66.09, 18.43],
    [-64.73, 32.31]
]

К этому:

[
    [-64.73, 32.31],
    [-66.09, 18.43],
    [-80.19, 25.76],
    [-64.73, 32.31]
]

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

Согласно API:

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

Кроме того, это интересные блоки, сделанные Бостоком (создателем D3), дидактически объясняющие вашу проблему: https://bl.ocks.org/mbostock/a7bdfeb041e850799a8d3dce4d8c50c8

Вот ваш код с этим изменением (и удалением fitSize):

var geojson = {
  "features": [{
    "type": "Feature",
    "properties": {
      "name": "Bermuda Triangle",
      "area": 1150180
    },
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [-64.73, 32.31],
          [-66.09, 18.43],
          [-80.19, 25.76],
          [-64.73, 32.31]
        ]
      ]
    }
  }],
  "type": "FeatureCollection"
};

var width = 480;
var height = 480;

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)
  .attr("style", "border: 2px solid black");

var projection = d3.geoMercator();
var path = d3.geoPath().projection(projection);

svg.selectAll('path')
  .data(geojson.features)
  .enter()
  .append('path')
  .attr('d', path)
  .style("fill", "red")
  .style("stroke-width", "1")
  .style("stroke", "black");
<script src="//d3js.org/d3.v4.js"></script>

person Gerardo Furtado    schedule 11.11.2017
comment
Думаю, я мог бы добавить, что d3 относительно уникален в этом отношении. Если вы не будете следовать правилу правой руки в листовках, openlayers, qgis и т. д., никаких последствий не будет. Большинству инструментов все равно, а некоторые инструменты даже дают geojson, который не использует правило правой руки (дерн) - даже валидаторы не предвидят ситуацию с перевернутым полигоном. Реализация D3 уникальна в реализации стандарта geojson, как указано, этот ответ возможен только потому, что d3 использует сферическую геометрию для geojson, и поэтому d3 отлично подходит для создания карт. Любая другая библиотека, это не имеет значения, отличный ответ. - person Andrew Reid; 12.11.2017

Если кто-то увидит подобную проблему, я создал инструмент, который поможет вам перемотать или реверсировать geojson

Это помогло мне внести изменения в некоторые файлы geoJson без особых хлопот.

https://observablehq.com/@bumbeishvili/rewind-geojson

Вы можете запустить его как фрагмент ниже

<div class="notebook-content">
  
</div>

<script type="module"> 

import notebook from "https://api.observablehq.com/@bumbeishvili/rewind-geojson.js";  //  "download code" url

document.querySelector('.notebook-content').innerHTML =notebook.modules[0].variables
.filter(d=>d)
.map((d,i)=>` <div class=" observable-wrapper div-number-${i}"></div>`)
.join('')
.concat('<div style="display:none" class="hidden"></div>')


import {Inspector, Runtime} from "https://unpkg.com/@observablehq/runtime@3/dist/runtime.js"; 
let i=1;
Runtime.load(notebook, (variable) => { 
if(i==4 ){i++;  return new Inspector(document.querySelector(`.hidden`));}
if(i==13)return;
return new Inspector(document.querySelector(`.observable-wrapper:nth-child(${i++})`));
 }); 


</script>

person bumbeishvili    schedule 02.09.2019
comment
большое спасибо, что поделились этой ссылкой!!! Это избавило меня от многих страданий! Хотел бы я проголосовать за вас больше одного раза! - person Jacob Philpott; 13.02.2021