从 topojson 获取各个国家的边界​​框

Posted

技术标签:

【中文标题】从 topojson 获取各个国家的边界​​框【英文标题】:Get bounding box of individual countries from topojson 【发布时间】:2017-11-04 20:50:20 【问题描述】:

我想从 topojson 中获取每个国家/地区的边界框,但是当我将它们添加为 svg 矩形时,它们被捆绑在一起朝向 0,0。

我重新阅读了 API 并使用了绑定坐标的顺序,但这并没有改变任何东西!另外,我尝试在国家/地区路径上使用 SVG 方法 getBBox(),但产生了相同的结果。

有什么想法吗?

var width = 700,
  height = 400,
  bboxes = [];

d3.queue()
  .defer(d3.json, "data/world.topojson")
  .await(ready);

//Map projection
var proj = d3.geoMercator()
  .scale(100)
  .center([-0.0018057527730242487, 11.258678472759552]) //projection center
  .translate([width / 2, height / 2]) //translate to center the map in view

//Generate paths based on projection
var myPath = d3.geoPath().projection(proj);

var svg = d3.select("svg"),
  width = +svg.attr("width"),
  height = +svg.attr("height");

//Group for the map features
var map = svg.append("g")
  .attr("class", "map");


function ready(error, geodata) 
  if (error) return console.log(error); //unknown error, check the console

  //Create a path for each map feature in the data
  map.selectAll("path")
    .data(topojson.feature(geodata, geodata.objects.subunits).features) //generate features from TopoJSON
    .enter()
    .append("path")
    .attr("class", "country")
    .attr("id", function(d) 
      return d.id;
    )
    .attr("d", myPath);

    bboxes = boundingExtent(topojson.feature(geodata, geodata.objects.subunits).features);


    svg.selectAll("rect")
    .data(bboxes)
    .enter()
    .append("rect")
    .attr("id", function(d)
      return d.id;
    )
    .attr("class", "bb")
    .attr("x1", function(d) 
      return d.x;
    )
    .attr("y1", function(d) 
      return d.y;
    )
    .attr("width", function(d) 
      return d.width;
    )
    .attr("height", function(d) 
      return d.height;
    )


function boundingExtent(features) 
var bounds= [];
  for (var x in features) 
    var boundObj = ;
    thisBounds = myPath.bounds(features[x]);
    boundObj.id = features[x].id;
    boundObj.x = thisBounds[0][0];
    boundObj.y = thisBounds[0][1];
    boundObj.width = thisBounds[1][0] - thisBounds[0][0];
    boundObj.height = thisBounds[1][1] - thisBounds[0][1];
    boundObj.path = thisBounds;
    bounds.push(boundObj)
  
  return bounds;


function boundExtentBySvg()
  var countries = svg.selectAll(".country")
  countries.each(function(d)
      var box = d3.select(this).node().getBBox();
      bboxes.push(id: d.id, x: box.x, y : box.y, width: box.width, height : box.height)
  )

【问题讨论】:

【参考方案1】:

在这些行中:

.attr("x1", function(d) 
  return d.x;
)
.attr("y1", function(d) 
  return d.y;
)

rect 没有x1y1 的属性,我想你的意思只是xy

这是你正在运行的代码(注意,我关闭了导致轻微代码更改的 topojson 文件):

<!DOCTYPE html>
<html>

  <head>
    <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
    <script data-require="topojson.min.js@3.0.0" data-semver="3.0.0" src="https://unpkg.com/topojson@3.0.0"></script>
  </head>

  <body>
    <svg  ></svg>
    <script>
    var width = 700,
      height = 400,
      bboxes = [];

    d3.queue()
      .defer(d3.json, "https://unpkg.com/world-atlas@1/world/110m.json")
      .await(ready);

    //Map projection
    var proj = d3.geoMercator()
      .scale(100)
      .center([-0.0018057527730242487, 11.258678472759552]) //projection center
      .translate([width / 2, height / 2]) //translate to center the map in view

    //Generate paths based on projection
    var myPath = d3.geoPath().projection(proj);

    var svg = d3.select("svg"),
      width = +svg.attr("width"),
      height = +svg.attr("height");

    //Group for the map features
    var map = svg.append("g")
      .attr("class", "map");


    function ready(error, geodata) 
      
      if (error) return console.log(error); //unknown error, check the console

      //Create a path for each map feature in the data
      map.selectAll("path")
        .data(topojson.feature(geodata, geodata.objects.countries).features) //generate features from TopoJSON
        .enter()
        .append("path")
        .attr("class", "country")
        .attr("id", function(d) 
          return d.id;
        )
        .attr("d", myPath);

      bboxes = boundingExtent(topojson.feature(geodata, geodata.objects.countries).features);


      svg.selectAll("rect")
        .data(bboxes)
        .enter()
        .append("rect")
        .attr("id", function(d) 
          return d.id;
        )
        .attr("class", "bb")
        .attr("x", function(d) 
          return d.x;
        )
        .attr("y", function(d) 
          return d.y;
        )
        .attr("width", function(d) 
          return d.width;
        )
        .attr("height", function(d) 
          return d.height;
        )
        .style("fill", "none")
        .style("stroke", "steelblue");
    

    function boundingExtent(features) 
      var bounds = [];
      for (var x in features) 
        var boundObj = ;
        thisBounds = myPath.bounds(features[x]);
        boundObj.id = features[x].id;
        boundObj.x = thisBounds[0][0];
        boundObj.y = thisBounds[0][1];
        boundObj.width = thisBounds[1][0] - thisBounds[0][0];
        boundObj.height = thisBounds[1][1] - thisBounds[0][1];
        boundObj.path = thisBounds;
        bounds.push(boundObj)
      
      console.log(bounds)
      
      return bounds;
    

    function boundExtentBySvg() 
      var countries = svg.selectAll(".country")
      countries.each(function(d) 
        var box = d3.select(this).node().getBBox();
        bboxes.push(
          id: d.id,
          x: box.x,
          y: box.y,
          width: box.width,
          height: box.height
        )
      )
    
  </script>
  </body>

</html>

【讨论】:

就是它,马克,疲惫的眼睛无法发现它。提醒自己,不要在星期五晚上晚些时候开始新代码!

以上是关于从 topojson 获取各个国家的边界​​框的主要内容,如果未能解决你的问题,请参考以下文章

如何找到全球所有地区的边界框数据?

如何从图像中获取随机边界框? (Python)

从边界框获取对象[对象检测]

从 ggmap 对象获取边界框

如何从R中的州边界获取纬度和经度数据

有啥方法可以从 three.js Object3D 中获取边界框?