cli*_*oid 133 geojson d3.js topojson
目前在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]),而一点一点去?
mbo*_*ock 165
我的答案接近Jan van der Laan,但你可以稍微简化一下,因为你不需要计算地理质心; 你只需要边界框.并且,通过使用未缩放的,未翻译的单位投影,您可以简化数学运算.
代码的重要部分是:
// Create a unit projection.
var projection = d3.geo.albers()
    .scale(1)
    .translate([0, 0]);
// Create a path generator.
var path = d3.geo.path()
    .projection(projection);
// Compute the bounds of a feature of interest, then derive scale & translate.
var b = path.bounds(state),
    s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
    t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
// Update the projection to use computed scale & translate.
projection
    .scale(s)
    .translate(t);
在单位投影中对要素的边界框进行复合后,可以通过比较边界框(和)的纵横比与画布(和)的纵横比来计算适当的比例.在这种情况下,我还将边界框缩放到95%的画布,而不是100%,因此在笔迹和周围特征或填充的边缘上有一点额外的空间.b[1][0] - b[0][0]b[1][1] - b[0][1]widthheight
然后你就可以计算转换使用边界框(中心(b[1][0] + b[0][0]) / 2和(b[1][1] + b[0][1]) / 2)和画布(中央width / 2和height / 2).请注意,由于边界框位于单位投影的坐标中,因此必须乘以scale(s).
有一个相关的问题,其中它是如何放大到一个特定的功能集合在无需调整投影,即,投影用几何变换组合以放大和缩小.它使用与上述相同的原理,但数学略有不同,因为几何变换(SVG"变换"属性)与地理投影相结合.
Jan*_*aan 126
以下似乎大概做了你想要的.缩放似乎没问题.将它应用到我的地图时会有一个小的偏移量.这个小偏移可能是因为我使用translate命令使地图居中,而我应该使用center命令.
在代码中:
  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")
    });
Pau*_*ine 51
我是d3的新手 - 将尝试解释我是如何理解的,但我不确定我是否做得对.
秘诀是知道某些方法将在制图空间(纬度,经度)和笛卡尔空间(屏幕上的x,y)上进行操作.制图空间(我们的星球)是(几乎)球形,笛卡尔空间(屏幕)是平坦的 - 为了将一个映射到另一个,你需要一个算法,称为投影.这个空间太短,无法深入到投影的迷人主题中,以及它们如何扭曲地理特征以便将球形转变为平面; 一些设计用于保存角度,另一些设计用于保存距离等等 - 总是存在折衷(Mike Bostock有大量示例).

在d3中,投影对象具有中心属性/ setter,以地图单位给出:
projection.center([位置])
如果指定了center,则将投影的中心设置为指定位置,以度为单位的经度和纬度的双元素数组并返回投影.如果未指定center,则返回当前中心,默认为⟨0°,0°⟩.
还有以像素为单位的平移 - 投影中心相对于画布的位置:
projection.translate([点])
如果指定了point,则将投影的平移偏移设置为指定的双元素数组[x,y]并返回投影.如果未指定point,则返回当前平移偏移,默认为[480,250].平移偏移确定投影中心的像素坐标.默认平移偏移在960×500区域的中心放置⟨0°,0°..
当我想在画布中居中显示一个特征时,我喜欢将投影中心设置为特征边界框的中心 - 当我的国家(巴西)使用mercator(WGS 84,用于谷歌地图)时,这适用于我,从未使用其他投影和半球进行测试.您可能需要对其他情况进行调整,但如果您确定了这些基本原则,那么您将没事.
例如,给定投影和路径:
var projection = d3.geo.mercator()
    .scale(1);
var path = d3.geo.path()
    .projection(projection);
该bounds方法以像素为单位path返回边界框.使用它来查找正确的比例,将像素的大小与地图单位的大小进行比较(0.95给出的宽度或高度最佳拟合度为5%).这里的基本几何,计算对角线对角的矩形宽度/高度:
var b = path.bounds(feature),
    s = 0.9 / Math.max(
                   (b[1][0] - b[0][0]) / width, 
                   (b[1][1] - b[0][1]) / height
               );
projection.scale(s); 

使用此d3.geo.bounds方法以地图单位查找边界框:
b = d3.geo.bounds(feature);
将投影的中心设置为边界框的中心:
projection.center([(b[1][0]+b[0][0])/2, (b[1][1]+b[0][1])/2]);
使用此translate方法将地图的中心移动到画布的中心:
projection.translate([width/2, height/2]);
到目前为止,你应该让地图中心的特征放大5%边距.
dnl*_*tsk 44
随着d3 v4,它越来越容易!
var projection = d3.geoMercator().fitSize([width, height], geojson);
var path = d3.geoPath().projection(projection);
最后
g.selectAll('path')
  .data(geojson.features)
  .enter()
  .append('path')
  .attr('d', path)
  .style("fill", "red")
  .style("stroke-width", "1")
  .style("stroke", "black");
享受,干杯