d3 v4 geo绘制边界倒置

Posted

技术标签:

【中文标题】d3 v4 geo绘制边界倒置【英文标题】:d3 v4 geo draws boundary inverted 【发布时间】:2018-04-24 09:25:13 【问题描述】:

当我在 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>

我做错了什么?

【问题讨论】:

【参考方案1】:

让我们改变一下:

[
    [-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:

球形多边形也需要一个缠绕顺序约定来确定多边形的哪一侧是内侧:小于半球的多边形的外环必须顺时针,而大于半球的多边形的外环半球必须是逆时针的。 (强调我的)

另外,这是 Bostock(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>

【讨论】:

我想我可以补充一下,d3 在这方面是比较独特的。如果您未能在传单、openlayers 或 qgis 等中遵循右手规则,则不会产生任何后果。大多数工具都不在乎,有些工具甚至给出了不使用右手规则(草皮)的geojson——甚至验证器也没有预料到倒置多边形的情况。 D3 的实现在按规定实现geojson 标准方面是独一无二的,这个答案是唯一可能的,因为d3 对geojson 使用球面几何,这就是d3 非常适合制作地图的原因。任何其他图书馆都没有关系,很好的答案。【参考方案2】:

如果有人会看到类似的问题,我创建了一个工具,可以帮助您倒带或反转 geojson

它帮助我在一些 geoJson 文件中进行更改,没有太多麻烦

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

您可以在下面以 sn-p 的形式运行它

<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>

【讨论】:

非常感谢您分享此链接!!!它为我节省了很多痛苦!我希望我能不止一次地为你投票!

以上是关于d3 v4 geo绘制边界倒置的主要内容,如果未能解决你的问题,请参考以下文章

如何在 KonvaJS 中的图层上绘制倒置元素

如何在 Android Canvas 中使用“倒置”绘画进行绘制?

使用 d3-geo 在球体的一部分上绘制具有公制尺寸的多多边形

我曾想深入了解的:依赖倒置控制反转依赖注入

将旧geo适配到D3 v5,如何表达一个Promise的队列?

线条未正确显示d3.js geo和google地图