d3 包布局的地理排序功能

geographic sort function for d3's pack layout

使用 d3 的包布局,我制作了一些与状态相关的气泡。当前测试脚本:https://jsfiddle.net/80wjyxp4/4/。它们根据地区着色。您会注意到德克萨斯位于 "NW",加利福尼亚位于 "SE",等等

问题:

你会如何在地理上对包装布局中的圆圈进行排序?

一种 hack 方式可能会使用默认值 d3.layout.pack.sort(null)。这种排序从第一个数据点(在本例中为 AK)开始,然后逆时针方向添加气泡。我可以按照接近状态位置的顺序手动对要输入的数据进行排序,并添加空白圆圈以移动边缘圆圈。

我对更好的想法很感兴趣。使用修改后的强制布局会更好吗,比如 http://bl.ocks.org/mbostock/1073373d3.geom.voronoi() 似乎很有用。

在这个 http://bl.ocks.org/mbostock/1073373 上看这些行:

  states.features.forEach(function(d, i) {
    if (d.id === 2 || d.id === 15 || d.id === 72) return; // lower 48
    var centroid = path.centroid(d);  //   <===== polygon center
    if (centroid.some(isNaN)) return;
    centroid.x = centroid[0];              <==== polygon lat
    centroid.y = centroid[1];              <==== polygon lng
    centroid.feature = d;                  
    nodes.push(centroid);              <== made node array of centroids
  });
----------------
force
      .gravity(0)
      .nodes(nodes)           <==== asign array nodes to nodes
      .links(links)
      .linkDistance(function(d) { return d.distance; })
      .start();

每个状态就像一个多焦点布局。就像这个:http://bl.ocks.org/mbostock/1021841

  1. 从包布局开始,获取圆半径
  2. 使用此修改后的力布局中的状态质心http://bl.ocks.org/mbostock/1073373
  3. 设法使用碰撞避免重叠 https://bl.ocks.org/mbostock/7881887

代码在这里:https://jsfiddle.net/xyn85de1/. It does NOT run because I can't get data for the topojson file, at http://bl.ocks.org/mbostock/raw/4090846/us.json,来自 link,文件太大 copy-paste。然后下载到自己的服务器运行.

它有一个 hover-title 文本和过渡,但最终看起来像这样:

间距和东西可以用不同的参数修改。这些圆圈大致按地理排序。 MO是中间那个大金色的; AK和HI在左边是深蓝色; CA 在左下方为粉红色; TX 位于底部,呈浅蓝色。等等。 代码: 将所有数据(圆圈初始位置的位置数据)以及州名称、值、面积(用于颜色编码)收集到 nodes 变量后:

// circles
var circles = svg.selectAll("g") //g
    .data(nodes)
    .enter()
    .append("g")
    .attr("transform", function(d) {
        return "translate(" + -d.x + "," + -d.y + ")";
    })
    .append("circle")
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
    })
    .attr("r", function(d) {return d.r;})
    .attr("fill", function(d) { return color(d.area); })
    .call(force.drag); // lets you change the orientation

// title text
circles.append("title")
    .text(function(d) { return d.state + ": " + format(d.value) + " GWh"; });

// // text // doesn't work :/ porque?
// circles.append("text")
//     .attr("dy", ".3em")
//     //.style("text-anchor", "middle")
//     .text(function(d) { return d.state.substring(0, d.r / 3); });

// circle tick function
function tick(e) {
    circles
        .each(collide(collision_alpha))
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
}

// force
force.nodes(nodes)
    .on("tick", tick)
    .start();