Skip to content

Instantly share code, notes, and snippets.

@emeeks
Created April 30, 2016 03:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save emeeks/302096884d5fbc1817062492605b50dd to your computer and use it in GitHub Desktop.
Save emeeks/302096884d5fbc1817062492605b50dd to your computer and use it in GitHub Desktop.
D3v4 Constraint-Based Layout
{"nodes": [{"id":"1","module":0,"i":0},{"id":"3","module":0,"i":1},{"id":"8","module":2,"i":2},{"id":"9","module":4,"i":3},{"id":"12","module":2,"i":4},{"id":"15","module":2,"i":5},{"id":"23","module":3,"i":6},{"id":"26","module":3,"i":7},{"id":"37","module":10,"i":8},{"id":"46","module":2,"i":9},{"id":"2","module":1,"i":10},{"id":"4","module":2,"i":11},{"id":"5","module":3,"i":12},{"id":"6","module":3,"i":13},{"id":"7","module":1,"i":14},{"id":"10","module":4,"i":15},{"id":"11","module":1,"i":16},{"id":"13","module":1,"i":17},{"id":"14","module":1,"i":18},{"id":"16","module":5,"i":19},{"id":"18","module":1,"i":20},{"id":"19","module":3,"i":21},{"id":"20","module":1,"i":22},{"id":"21","module":6,"i":23},{"id":"22","module":2,"i":24},{"id":"25","module":3,"i":25},{"id":"27","module":1,"i":26},{"id":"28","module":3,"i":27},{"id":"29","module":1,"i":28},{"id":"31","module":2,"i":29},{"id":"33","module":2,"i":30},{"id":"34","module":9,"i":31},{"id":"35","module":1,"i":32},{"id":"38","module":2,"i":33},{"id":"41","module":4,"i":34},{"id":"32","module":2,"i":35},{"id":"40","module":2,"i":36},{"id":"17","module":4,"i":37},{"id":"36","module":3,"i":38},{"id":"39","module":3,"i":39},{"id":"44","module":3,"i":40},{"id":"45","module":3,"i":41},{"id":"42","module":9,"i":42},{"id":"43","module":11,"i":43},{"id":"24","module":7,"i":44},{"id":"30","module":8,"i":45}],
"edges": [{"source":0,"target":1},{"source":10,"target":14},{"source":10,"target":16},{"source":10,"target":22},{"source":10,"target":28},{"source":10,"target":32},{"source":11,"target":36},{"source":12,"target":13},{"source":12,"target":21},{"source":12,"target":7},{"source":12,"target":41},{"source":13,"target":25},{"source":13,"target":7},{"source":13,"target":27},{"source":13,"target":38},{"source":13,"target":39},{"source":13,"target":40},{"source":14,"target":10},{"source":14,"target":18},{"source":14,"target":32},{"source":2,"target":29},{"source":2,"target":30},{"source":3,"target":37},{"source":15,"target":3},{"source":15,"target":37},{"source":16,"target":10},{"source":4,"target":24},{"source":4,"target":30},{"source":4,"target":9},{"source":37,"target":15},{"source":20,"target":17},{"source":21,"target":12},{"source":21,"target":13},{"source":21,"target":7},{"source":21,"target":38},{"source":21,"target":39},{"source":21,"target":40},{"source":21,"target":41},{"source":22,"target":17},{"source":24,"target":4},{"source":24,"target":5},{"source":24,"target":30},{"source":24,"target":36},{"source":6,"target":38},{"source":25,"target":13},{"source":7,"target":12},{"source":7,"target":13},{"source":7,"target":21},{"source":7,"target":6},{"source":7,"target":25},{"source":7,"target":38},{"source":7,"target":39},{"source":7,"target":40},{"source":7,"target":41},{"source":26,"target":17},{"source":26,"target":32},{"source":27,"target":13},{"source":29,"target":2},{"source":35,"target":11},{"source":35,"target":36},{"source":30,"target":11},{"source":30,"target":2},{"source":30,"target":4},{"source":30,"target":24},{"source":30,"target":36},{"source":31,"target":42},{"source":38,"target":13},{"source":38,"target":6},{"source":38,"target":7},{"source":38,"target":40},{"source":38,"target":41},{"source":33,"target":24},{"source":39,"target":13},{"source":39,"target":21},{"source":39,"target":41},{"source":36,"target":11},{"source":36,"target":35},{"source":36,"target":30},{"source":34,"target":15},{"source":40,"target":13},{"source":40,"target":21},{"source":41,"target":12},{"source":41,"target":13},{"source":41,"target":7},{"source":41,"target":38},{"source":9,"target":4}]
}
<html>
<head>
<title>d3v4 Constraint-based Layout</title>
<meta charset="utf-8" />
<script src="https://d3js.org/d3.v4.0.0-alpha.33.min.js"></script>
</head>
<style>
svg {
height: 500px;
width: 500px;
border: 1px solid gray;
}
</style>
<body>
<div id="viz">
<svg class="main">
</svg>
</div>
</body>
<footer>
<script>
d3.json("graph.json",function(error,data) {createNetwork(data)});
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
function createNetwork(data) {
var edges = data.edges;
var nodes = data.nodes;
//create a network from an edgelist
var colors = ["#996666", "#66CCCC", "#FFFF99", "#CC9999", "#666633", "#993300", "#999966", "#660000", "#996699", "#cc6633", "#ff9966", "#339999", "#6699cc", "#ffcc66", "#ff6600", "#00ccccc"]
//This isn't "gravity" it's the visual centering of the network based on its mass
var networkCenter = d3.forceCenter().x(250).y(250);
//CHARGE
var manyBody = d3.forceManyBody().strength(-150).distanceMax(100)
//Specify module position for the three largest modules. This is the x-y center of the modules
//singletons and small modules will be handled as a whole
var modulePosition = {
"2": {x: 0, y: 0},
"3": {x: 200, y: 25},
"1": {x: 0, y: 200}
}
//Make the x-position equal to the x-position specified in the module positioning object or, if not in
//the hash, then set it to 250
var forceX = d3.forceX(function (d) {return modulePosition[d.module] ? modulePosition[d.module].x : 250})
.strength(0.05)
//Same for forceY--these act as a gravity parameter so the different strength determines how closely
//the individual nodes are pulled to the center of their module position
var forceY = d3.forceY(function (d) {return modulePosition[d.module] ? modulePosition[d.module].y : 250})
.strength(0.05)
var force = d3.forceSimulation(nodes)
.force("charge", manyBody)
.force("link", d3.forceLink(edges).distance(30).iterations(1))
.force("center", networkCenter)
.force("x", forceX)
.force("y", forceY)
.on("tick", updateNetwork);
var edgeEnter = d3.select("svg.main").selectAll("g.edge")
.data(edges)
.enter()
.append("g")
.attr("class", "edge");
edgeEnter
.append("line")
.style("stroke-width", function (d) {return d.border ? "3px" : "1px"})
.style("stroke", "black")
.style("pointer-events", "none");
var nodeEnter = d3.select("svg.main").selectAll("g.node")
.data(nodes, function (d) {return d.id})
.enter()
.append("g")
.attr("class", "node")
nodeEnter.append("circle")
.attr("r", 8)
.style("fill", function (d) {return colors[d.module]})
.style("stroke", "black")
.style("stroke-width", function (d) {return d.border ? "3px" : "1px"})
nodeEnter.append("text")
.style("text-anchor", "middle")
.attr("y", 3)
.style("stroke-width", "1px")
.style("stroke-opacity", 0.75)
.style("stroke", "white")
.style("font-size", "8px")
.text(function (d) {return d.id})
.style("pointer-events", "none")
nodeEnter.append("text")
.style("text-anchor", "middle")
.attr("y", 3)
.style("font-size", "8px")
.text(function (d) {return d.id})
.style("pointer-events", "none")
// force.start();
function updateNetwork(e) {
d3.select("svg.main").selectAll("line")
.attr("x1", function (d) {return d.source.x})
.attr("y1", function (d) {return d.source.y})
.attr("x2", function (d) {return d.target.x})
.attr("y2", function (d) {return d.target.y});
d3.select("svg.main").selectAll("g.node")
.attr("transform", function (d) {return "translate(" + d.x + "," + d.y + ")"});
}
}
</script>
</footer>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment