d3 美国带标记的州地图,缩放变换问题

Posted

技术标签:

【中文标题】d3 美国带标记的州地图,缩放变换问题【英文标题】:d3 US state map with markers, zooming transform issues 【发布时间】:2016-03-23 06:08:50 【问题描述】:

按照这个例子,我创建了一个包含美国各州的 d3 地图:

http://bl.ocks.org/mbostock/4699541

并在这个 SO 问题之后添加了标记:

Put markers to a map generated with topoJSON and d3.js

问题是在缩放时,地图标记保持在原位。我认为我需要将它们转化为新的职位,但不知道如何实现。

var width = 900,
  height = 500,
  active = d3.select(null);

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

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

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

svg.append("rect")
  .attr("class", "background")
  .attr("width", width)
  .attr("height", height)
  .on("click", reset);

var g = svg.append("g")
  .style("stroke-width", "1.5px");

d3.json("/files/d3-geo/us.json", function(error, us) 
  if (error)  throw error; 

  g.selectAll("path")
    .data(topojson.feature(us, us.objects.states).features)
    .enter().append("path")
    .attr("d", path)
    .attr("class", function(item) 
      return window.US_STATES[item.id].water_authorities > 0 ? 'avail' : 'unavail';
    )
    .on("click", clicked);

  g.append("path")
    .datum(topojson.mesh(us, us.objects.states, function(a, b)  return a !== b; ))
    .attr("class", "mesh")
    .attr("d", path);
);

d3.json('/files/coordinates.json', function(error, coords) 
  if (error)  throw error; 

  svg.selectAll(".mark")
    .data(coords)
    .enter()
    .append("image")
    .attr('class','mark')
    .attr('width', 20)
    .attr('height', 20)
    .attr("xlink:href",'assets/gmap_red.png')
    .attr("transform", function(d) 
      return "translate(" + projection([d[1],d[0]]) + ")";
    );
);

function clicked(d) 
  if (active.node() === this)  return reset(); 
  if (window.US_STATES[d.id].water_authorities === 0)  return; 

  active.classed("active", false);
  active = d3.select(this).classed("active", true);

  var bounds = path.bounds(d),
    dx = bounds[1][0] - bounds[0][0],
    dy = bounds[1][1] - bounds[0][1],
    x = (bounds[0][0] + bounds[1][0]) / 2,
    y = (bounds[0][1] + bounds[1][1]) / 2,
    scale = .9 / Math.max(dx / width, dy / height),
    translate = [width / 2 - scale * x, height / 2 - scale * y];

  g.transition()
    .duration(750)
    .style("stroke-width", 1.5 / scale + "px")
    .attr("transform", "translate(" + translate + ")scale(" + scale + ")");


function reset() 
  active.classed("active", false);
  active = d3.select(null);

  rebatesTable.clear().draw();

  g.transition()
    .duration(750)
    .style("stroke-width", "1.5px")
    .attr("transform", "");

【问题讨论】:

我会将投影更改为缩放,然后使用更改后的投影重新计算标记的位置。 【参考方案1】:

第 1 步

在组中添加所有点,而不是在 svg 中。 这将确保标记点与主组一起平移。

  g.selectAll(".mark")//adding mark in the group
    .data(marks)
    .enter()
    .append("image")
    .attr('class', 'mark')
    .attr('width', 20)
    .attr('height', 20)
    .attr("xlink:href", 'https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/24x24/DrawingPin1_Blue.png')
    .attr("transform", function(d) 
      return "translate(" + projection([d.long, d.lat]) + ")";
    );

第二步

否定主组的缩放效果。否则标记会放大。

  g.selectAll(".mark")
  .transition()
    .duration(750)
    .attr("transform", function(d) 
      var t = d3.transform(d3.select(this).attr("transform")).translate;//maintain aold marker translate 
      return "translate(" + t[0] +","+ t[1] + ")scale("+1/scale+")";//inverse the scale of parent
    );        

第三步

在缩小时使标记缩放回 1。

  g.selectAll(".mark")
    .attr("transform", function(d) 
      var t = d3.transform(d3.select(this).attr("transform")).translate;
      console.log(t)
      return "translate(" + t[0] +","+ t[1] + ")scale("+1+")";
    );   

工作代码here

希望这会有所帮助!

【讨论】:

非常好的答案,谢谢!我通过添加 .transform().duration(750)(在 .attr(...) 之前)对第 3 步做了一个小改进,它在缩小时添加了与放大时相同的缓动。 如何在缩放时保持标记的相对位置,而不是将其移动到所选状态路径的中心? clicked 函数中计算翻译,您必须相应地更新它..使标记位于中心 您能否更具体地说明示例代码中对第 110-116 行的更改,这将允许引脚在放大时保持在状态形状中的相同位置?谢谢 问题发布:***.com/questions/39796327/… 以及答案:jsbin.com/barekeyaca/edit?html,output

以上是关于d3 美国带标记的州地图,缩放变换问题的主要内容,如果未能解决你的问题,请参考以下文章

缩放 d3 v4 地图以适合 SVG(或根本不适合)

使用 GADM shapefile 为美国地图绘制较粗的州边界和较细的县边界

如何根据标记位置设置谷歌地图的缩放级别

单击反应传单 v.3.x 中的标记时如何动态更改地图缩放?

无法在 Ionic V5 App 上禁用 d3 topojson 底图缩放

缩放地图时D3js Geo取消缩放元素