Last active
April 27, 2016 10:11
-
-
Save rphv/0d6c8f05b3afe882e166 to your computer and use it in GitHub Desktop.
Draggable Circle Packing - D3.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Draggable Circle Packing</title> | |
<style> | |
svg circle { | |
cursor: move; | |
stroke: #000; | |
stroke-width: 1.5px; | |
fill: #827d92; | |
} | |
.fixed { | |
fill: #f00; | |
} | |
button { | |
position: absolute; | |
top: 10px; | |
left: 10px; | |
} | |
</style> | |
</head> | |
<body> | |
<button onclick="reset()">Reset</button> | |
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
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(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, Could you please give me an example of resizing the parent node on drag and drop of the children from one parent to different parent
http://codepen.io/MrHen/pen/GZQOPW, I am unable to resize of the bubble on drop of the bubble into other circles?