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/1073373? d3.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
- 从包布局开始,获取圆半径
- 使用此修改后的力布局中的状态质心http://bl.ocks.org/mbostock/1073373
- 设法使用碰撞避免重叠 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();
使用 d3 的包布局,我制作了一些与状态相关的气泡。当前测试脚本:https://jsfiddle.net/80wjyxp4/4/。它们根据地区着色。您会注意到德克萨斯位于 "NW",加利福尼亚位于 "SE",等等
问题:
你会如何在地理上对包装布局中的圆圈进行排序?
一种 hack 方式可能会使用默认值 d3.layout.pack.sort(null)
。这种排序从第一个数据点(在本例中为 AK)开始,然后逆时针方向添加气泡。我可以按照接近状态位置的顺序手动对要输入的数据进行排序,并添加空白圆圈以移动边缘圆圈。
我对更好的想法很感兴趣。使用修改后的强制布局会更好吗,比如 http://bl.ocks.org/mbostock/1073373? d3.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
- 从包布局开始,获取圆半径
- 使用此修改后的力布局中的状态质心http://bl.ocks.org/mbostock/1073373
- 设法使用碰撞避免重叠 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();