专注于D3.js地图中的geojson

姆沙班

我正在尝试查看(城市建筑物的)topojson 文件中的对象,但出现以下错误:

Error: <path> attribute d: Expected number, "MNaN,NaNLNaN,NaNL…".

这是我的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.land {
  fill: #e5e5e5;
  stroke: #000;   
  stroke-width: 0.2;
  stroke-opacity: 0.8;
}
.states {
  fill: none;
  stroke: #fff;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/queue.v1.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script>
<script>
    var width = 800;
    var height = 600;
var projection = d3.geo.mercator()
    .center([30, 30])
        .scale(500)
    .translate([width / 2, height / 2]);
var path = d3.geo.path().projection(projection);
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);
queue()
    .defer(d3.json, "cairomonuments.json")
    .await(ready);
function ready(error, cairo) {
  if (error) throw error;

      // Refine projection
      var b, s, t;
      projection.scale(1).translate([0, 0]);
      var b = path.bounds(cairo);
      var s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height);
      var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
      projection.scale(s).translate(t); 

  svg.selectAll("path")
      .data(topojson.feature(cairo, cairo.objects.monuments).features)
        .enter()
        .append('path')
        .attr('class', 'land')
        .attr('d', path);
}
</script>
</body>

我只想将地图放在我的 geojson 文件中,然后将其侧向翻转。我错过了什么?

topojson 文件在这里

安德鲁·里德(Andrew Reid)

问题

据我所知,主要问题是这一行:

var b = path.bounds(cairo);

path.bounds不会产生具有特征集合(例如您的图层)的预期结果。相反它

计算指定特征的投影边界框(以像素为单位)。边界框由一个二维数组表示: [[left, top], [right, bottom]] ,与 GIS geo.bounds 的约定不同。

另外,你不是传递geojson,而是传递topojson。如果您想使用特定功能的范围,您的代码将更像:

var b = path.bounds(topojson.feature(cairo, cairo.objects.monuments).features[0]);

即使您以正确的格式将单一特征传递给它,它仍然无法正确投影,因为您在定义投影时将比例定义为 500 - 这将在动态重新计算比例时扭曲计算。

可能的解决方案(保留 d3.js v3)

Topojson 一般都有一个bbox属性。您可以使用它来获取居中坐标:

var x = (cairo.bbox[0] + cairo.bbox[2]) / 2; // get middle x coordinate
var y = (cairo.bbox[1] + cairo.bbox[3]) / 2; // get middle y coordinate

请注意,geojson 或 topojson 边界框的顺序是:左、下、右、上

所以我们现在可以轻松地将地图居中于图层中心:

projection.center([x,y])projection.rotate([-x,0]).center([0,y])projection.rotate([-x,-y])

现在剩下的就是计算比例(将其设置为 1 开始)。

如果path.bounds返回左上角和右下角坐标的两个坐标数组([min x, min y],[max x, max y],在 SVG 坐标空间中),那么我们可以使用 topojson.bbox 生成一个等效数组:

var b = [ projection([cairo.bbox[0],cairo.bbox[3]]),projection([cairo.bbox[2],cairo.bbox[1]]) ];

这里有点棘手,因为 SVG 坐标空间的 y 坐标从顶部的零开始(与地理特征相反),并且边界中的坐标顺序是:左上右下(同样,不同于地理特征)。

这给我们留下了您已经进行的计算:

var s = 0.95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height);

这完全给了我们:

规模初步声明:

var projection = d3.geo.mercator()
    .scale(1)
    .translate([width / 2, height / 2]);

基于数据层的尺度和中心细化:

var x = (cairo.bbox[0] + cairo.bbox[2]) / 2;
var y = (cairo.bbox[1] + cairo.bbox[3]) / 2; 
projection.rotate([-x,-y]);

var b = [ projection([cairo.bbox[0],cairo.bbox[3]]),projection([cairo.bbox[2],cairo.bbox[1]]) ];
var s = 0.95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height);
projection.scale(s);

这是一个块块,展示了这一切。

翻转地图

投影旋转中有一个很少使用的参数可以让您实现这一点。在上面的 bl.ock 和上面的代码块中,我使用旋转来使地图投影居中。通过添加第三个参数,我可以相对于视口旋转地图:

projection.rotate([-x,-y,90]);

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章