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

Get bounding box of individual countries from topojson

我想从 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})
  })
}

在这些行中:

.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 width="700" height="400"></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>