You could do something like this... It's not a force layout, but you should be able to extend it to that pretty easily.
Click on a circle to select it, and then click and drag somewhere else to move them around.
Basically, I'm keeping track of the index of the selected circles in an array, and updating the corresponding data in the drag
handler. After the data is updated, I then modify the cx
and cy
attributes of the selected circles.
Note: the drag
handler is attached to a transparent rect
that covers the entire SVG, and I'm using CSS styles to get the events to cascade to the respective SVG elements correctly with pointer-events: all;
applied to the rect
.
var width = 500,
height = 500;
var data = d3.range(10).map(function(d) {
return {
x: parseInt(Math.random() * width),
y: parseInt(Math.random() * height),
r: parseInt(Math.random() * 10 + 10)
}
});
var selectedNodes = [],
selectedData = [];
var drag = d3.behavior.drag()
.on("drag", dragged)
var vis = d3.select("#vis").append("svg")
.attr("width", width)
.attr("height", height);
var dragRect = vis.append("rect")
.attr("class", "drag")
.attr("width", width)
.attr("height", height)
.call(drag);
var nodes = vis.selectAll("circle.node")
.data(data)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) {
return d.r;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.on("click", clicked);
function dragged(d) {
selectedData.forEach(function(i) {
data[i].x += d3.event.dx;
data[i].y += d3.event.dy;
});
d3.selectAll("circle.node.selected")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
}
function clicked(d, i) {
var j = selectedData.indexOf(i);
if (j === -1) {
selectedData.push(i);
d3.select(this).classed("selected", true);
} else {
selectedData.splice(j, 1);
d3.select(this).classed("selected", false);
}
}
rect.drag {
fill: none;
pointer-events: all;
}
circle.node {
fill: #000;
}
circle.node:hover {
cursor: pointer;
}
circle.node.selected {
fill: #f00;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="vis"></div>