Skip to content

Instantly share code, notes, and snippets.

@flowstate
Created April 3, 2014 22:35
Show Gist options
  • Save flowstate/9964247 to your computer and use it in GitHub Desktop.
Save flowstate/9964247 to your computer and use it in GitHub Desktop.
{
"libraries": [
"d3"
],
"mode": "javascript",
"layout": "fullscreen mode (vertical)",
"resolution": "reset"
}
svg {
position: absolute;
}
<div id="lexDrag"></div>
var width = 960,
height = 960,
count = 30,
fill = d3.scale.category10();
nodes = d3.range(count).map(Object);
var groupPath = function (interiorPoints) {
return "M" +
d3.geom.hull(interiorPoints.map(function (point) { return [point.x, point.y]; }))
.join("L")
+ "Z";
};
var groups = [];
groups.init = function () {
groups.a = Math.min(width, height);
groups.r = groups.a * 0.10;
for (i = 0; i < 4; i++) {
var g = [];
g.groupId = i;
g.x = width / 2;
g.y = height / 2;
var k = 0.25 * groups.a;
g.x += i & 2 ? k : -k;
g.y += i & 1 ? k : -k;
for (j = 0; j < 5; j++) {
var alpha = (2 * Math.PI * j / 5);
var dummy = { x: g.x + 10 * Math.sin(alpha), y: g.y + 10 * Math.cos(alpha) };
g.push(dummy);
}
groups[i] = g;
};
}
groups.snap = function (d) {
function change(d, to) {
if (d.groupId != null) {
var oldGroup = groups[d.groupId];
var index = oldGroup.indexOf(d);
if (index >= 0) {
oldGroup.splice(index, 1);
}
}
if (to == null) {
d.groupId = null;
} else {
d.groupId = to.groupId;
to.push(d);
}
}
groups.forEach(function (g) {
var distance = Math.sqrt(Math.pow(d.x - g.x, 2) + Math.pow(d.y - g.y, 2));
if (distance < groups.r) {
if (d.groupId != g.groupId) {
change(d, g);
}
} else {
if (d.groupId == g.groupId) {
change(d, null)
}
}
});
}
groups.delta = function (d) {
function massCenter(g) {
var x = 0, y = 0;
g.forEach(function (e) {
x += e.x;
y += e.y;
});
return { x: x / g.length, y: y / g.length };
}
if (d.groupId == null) return 0;
var g = groups[d.groupId];
var massCenter = massCenter(g);
var delta = {
x: g.x - massCenter.x,
y: g.y - massCenter.y
}
return delta;
}
groups.init();
var nodeFill = function (n) { return n.groupId != null ? fill(n.groupId) : "lightgray"; };
var vis = d3.select("#lexDrag").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.nodes(nodes)
.links([])
.size([width, height])
.start();
var node = vis.selectAll("circle.node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("r", 8)
.style("fill", nodeFill)
.style("stroke", function (d, i) { return d3.rgb(nodeFill).darker(2); })
.style("stroke-width", 1.5)
.on("mousemove", groups.snap)
.call(force.drag);
var text = vis.selectAll("text")
.data(nodes)
.enter().append("text");
var textLabels = text
.attr("x", function(d) { return 100; })
.attr("y", function(d) { return 100; })
.text( function (d) { return "( testing )"; })
.attr("font-family", "sans-serif")
.attr("font-size", "20px")
.attr("fill", "red");
vis.style("opacity", 1e-6)
.transition()
.duration(1000)
.style("opacity", 1);
var group = vis.selectAll("path")
.data(groups)
.attr("d", groupPath)
.enter().insert("path", "circle")
.style("fill", nodeFill)
.style("stroke", nodeFill)
.style("stroke-width", 40)
.style("stroke-linejoin", "round")
.style("opacity", .2)
force.on("tick", function (e) {
nodes.forEach(function (o) {
if (o.groupId == null) return;
// pull towards the 'group' x and y
o.x += groups.delta(o).x * .3;
o.y += groups.delta(o).y * .3;
});
node.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.style("fill", nodeFill);
group.attr("d", groupPath);
});
{
"data": [
[
11975,
5871,
8916,
2868
],
[
1951,
10048,
2060,
6171
],
[
8010,
16145,
8090,
8045
],
[
1013,
990,
940,
6907
]
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment