我有基于this tutorial的气泡图。
我已启用以下代码拖动气泡。这使得个别圆圈可以拖动,但拖动圆圈时,其他圆圈不会自动调整。我正在使用包循环算法,请让我知道这个算法是否可行。
这是我的拖动代码:
// draggable
if(this.dragging){
var drag = d3.behavior.drag()
.on("drag", function( d, i) {
var selection = d3.selectAll( '.selected');
if( selection[0].indexOf( this)==-1) {
selection.classed( "selected", false);
selection = d3.select( this);
selection.classed( "selected", true);
}
selection.attr("transform", function( d, i) {
d.x += d3.event.dx;
d.y += d3.event.dy;
return "translate(" + [ d.x,d.y ] + ")"
})
// reappend dragged element as last
// so that its stays on top
this.parentNode.appendChild( this);
d3.event.sourceEvent.stopPropagation();
});
node.call( drag);
}
答案 0 :(得分:1)
这里有一些代码可能会达到您正在寻找的效果。它主要归功于Mike Bostock的Bubble Chart和Collision Detection例子。
这使用D3' pack layout来初始定位节点。然后force layout用于"自动调整"拖动节点时的其他圆圈。
Working example at bl.ocks.org
var width = 900;
var height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var nodes = d3.range(128).map(function () { return {radius: Math.random() * 16 + 8}; });
var nodesCopy = $.extend(true, [], nodes);
function dblclick(d) {
d3.select(this).classed("fixed", d.fixed = false);
}
function dragstart(d) {
d3.select(this).classed("fixed", d.fixed = true);
}
function collide(node) {
var r = node.radius + 16;
var nx1 = node.x - r;
var nx2 = node.x + r;
var ny1 = node.y - r;
var ny2 = node.y + r;
return function (quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== node)) {
var x = node.x - quad.point.x;
var y = node.y - quad.point.y;
var l = Math.sqrt(x * x + y * y);
var npr = node.radius + quad.point.radius;
if (l < npr) {
l = (l - npr) / l * 0.5;
x *= l;
node.x -= x;
y *= l;
node.y -= y;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
};
}
function packup() {
var pack = d3.layout.pack()
.sort(null)
.size([width, height])
.padding(0)
.value(function (d) { return d.radius; });
svg.selectAll(".node")
.data(pack.nodes({"children": nodes})
.filter(function (d) { return !d.children; }))
.enter().append("circle")
.attr("r", function (d) { return d.radius; })
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
}
function forceup() {
var force = d3.layout.force()
.nodes(nodes)
.gravity(0.05)
.charge(0)
.size([width, height])
.start();
var drag = force.drag().on("dragstart", dragstart);
force.on("tick", function () {
var q = d3.geom.quadtree(nodes);
var i = 0;
var n = nodes.length;
while (++i < n) {
q.visit(collide(nodes[i]));
}
svg.selectAll("circle")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
});
d3.selectAll("circle")
.on("dblclick", dblclick)
.call(drag);
}
function reset() {
svg.selectAll("*").remove();
nodes = $.extend(true, [], nodesCopy);
packup();
forceup();
}
packup();
forceup();