1. ホーム
  2. d3.js

[解決済み] geoJSON オブジェクトを d3 でマップの中央に配置する

2022-05-30 19:46:08

質問

現在d3では、描画しようとするgeoJSONオブジェクトがある場合、それを望みのサイズにするためにスケーリングとトランスレートし、それを中心に置くためにトランスレートする必要があります。これは試行錯誤の非常に退屈な作業で、これらの値を取得するためのより良い方法を知っている人がいれば教えてください。

たとえば、次のようなコードがあるとします。

var path, vis, xy;
xy = d3.geo.mercator().scale(8500).translate([0, -1200]);

path = d3.geo.path().projection(xy);

vis = d3.select("#vis").append("svg:svg").attr("width", 960).attr("height", 600);

d3.json("../../data/ireland2.geojson", function(json) {
  return vis.append("svg:g")
    .attr("class", "tracts")
    .selectAll("path")
    .data(json.features).enter()
    .append("svg:path")
    .attr("d", path)
    .attr("fill", "#85C3C0")
    .attr("stroke", "#222");
});

.scale(8500) と .translate([0, -1200]) を少しずつでなく、一体どうやって取得するのでしょうか?

どうすれば解決するのでしょうか?

以下のようにすると、だいたい希望通りになるようです。スケーリングは大丈夫なようです。私のマップに適用すると、小さなオフセットがあります。この小さなオフセットは、おそらく center コマンドを使用する必要がある一方で、マップを中央に配置するために translate コマンドを使用したために発生したものです。

  1. 投影とd3.geo.pathを作成します。
  2. 現在の投影の境界を計算する
  3. これらの境界を使用して、スケールと平行移動を計算します。
  4. 投影を再作成する

コードでは

  var width  = 300;
  var height = 400;

  var vis = d3.select("#vis").append("svg")
      .attr("width", width).attr("height", height)

  d3.json("nld.json", function(json) {
      // create a first guess for the projection
      var center = d3.geo.centroid(json)
      var scale  = 150;
      var offset = [width/2, height/2];
      var projection = d3.geo.mercator().scale(scale).center(center)
          .translate(offset);

      // create the path
      var path = d3.geo.path().projection(projection);

      // using the path determine the bounds of the current map and use 
      // these to determine better values for the scale and translation
      var bounds  = path.bounds(json);
      var hscale  = scale*width  / (bounds[1][0] - bounds[0][0]);
      var vscale  = scale*height / (bounds[1][1] - bounds[0][1]);
      var scale   = (hscale < vscale) ? hscale : vscale;
      var offset  = [width - (bounds[0][0] + bounds[1][0])/2,
                        height - (bounds[0][1] + bounds[1][1])/2];

      // new projection
      projection = d3.geo.mercator().center(center)
        .scale(scale).translate(offset);
      path = path.projection(projection);

      // add a rectangle to see the bound of the svg
      vis.append("rect").attr('width', width).attr('height', height)
        .style('stroke', 'black').style('fill', 'none');

      vis.selectAll("path").data(json.features).enter().append("path")
        .attr("d", path)
        .style("fill", "red")
        .style("stroke-width", "1")
        .style("stroke", "black")
    });