Skip to content

Instantly share code, notes, and snippets.

@colin-young
Last active December 14, 2015 23:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save colin-young/5165614 to your computer and use it in GitHub Desktop.
Save colin-young/5165614 to your computer and use it in GitHub Desktop.
Demonstration of d3.js force directed layout with fixed x-values.

This example demonstrates D3.js force directed layout with fixed x-values and a band on the y-axis where source nodes will not be placed. Target nodes are fixed at y = 0.

Color Scheme: http://colorschemedesigner.com/#3q61Uw0w0w0w0

@font-face {
font-family:'Oxygen';
font-style: normal;
font-weight: 400;
src: local('Oxygen'), local('Oxygen-Regular'), url(http://themes.googleusercontent.com/static/fonts/oxygen/v2/RzoNiRR1p2Mqyyz2RwqSMw.woff) format('woff');
}
@font-face {
font-family:'Oxygen';
font-style: normal;
font-weight: 700;
src: local('Oxygen Bold'), local('Oxygen-Bold'), url(http://themes.googleusercontent.com/static/fonts/oxygen/v2/yVHpdQrmTj9Kax1tmFSx2j8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
}
svg {
}
.axis text {
font-family: Oxygen;
font-size: 10px;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.node {
stroke-width: 1.5px;
}
.node.target {
fill: #FFBC73;
stroke: #FFA340;
}
.node.source {
fill: #62B1D0;
stroke: #0776A0;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>SVG Time-Dependent Graph Example - jsFiddle demo by colin_young</title>
<script type='text/javascript' src="http://d3js.org/d3.v3.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="demo.css">
</head>
<body>
<div class="graph"></div>
<div id="slider"></div>
<div id="charge"></div>
<script type='text/javascript' src='network.js'></script>
</body>
</html>
var lineColor = "#172CAF";
var circleOutlineColor = "#0776A0";
var circleFillColor = "#62B1D0";
var textColorSource = "#FFFFFF";
var circleOutlineColorTarget = "#FFA340";
var circleFillColorTarget = "#FFBC73";
var textColorTarget = "#A65600";
var nodes = [{
id : "T0",
name : "Target 0",
type : "t",
time : 0,
strength : 1
}, {
id : "T1",
name : "Target 1",
type : "t",
time : 3,
strength : 10
}, {
id : "T2",
name : "Target 2",
type : "t",
time : 5,
strength : 2
}, {
id : "T3",
name : "Target 3",
type : "t",
time : 8,
strength : 7
}, {
id : "T4",
name : "Target 4",
type : "t",
time : 6,
strength : 7
}, {
id : "S1",
name : "Source 1",
type : "s",
time : 1,
count : 2
}, {
id : "S2",
name : "Source 2",
type : "s",
time : 2,
count : 1
}, {
id : "S3",
name : "Source 3",
type : "s",
time : 2,
count : 4
}, {
id : "S4",
name : "Source 4",
type : "s",
time : 4,
count : 2
}, {
id : "S5",
name : "Source 5",
type : "s",
time : 3,
count : 2
}
];
var links = [{
source : "S1",
target : "T1",
strength : 0.05
}, {
source : "S2",
target : "T1",
strength : 0.1
}, {
source : "S3",
target : "T1",
strength : 0.3
}, {
source : "S3",
target : "T2",
strength : 0.8
}, {
source : "S1",
target : "T2",
strength : 0.05
}, {
source : "S3",
target : "T3",
strength : 1.0
}, {
source : "S4",
target : "T4",
strength : 1.0
}, {
source : "S4",
target : "T2",
strength : 0.3
}, {
source : "S5",
target : "T3",
strength : 1.0
}, {
source : "S5",
target : "T2",
strength : 0.1
}, {
source : "S3",
target : "T4",
strength : 1.0
}
];
var margin = {
top : 20,
right : 10,
bottom : 20,
left : 10
},
padding = {
top : 60,
right : 60,
bottom : 60,
left : 60
},
outerWidth = 500,
outerHeight = 400,
innerWidth = outerWidth - margin.left - margin.right,
innerHeight = outerHeight - margin.top - margin.bottom,
width = innerWidth - padding.left - padding.right,
height = innerHeight - padding.top - padding.bottom,
axisBand = 15;
var x_max = d3.max(nodes, function(d) { return d.time; });
var x = d3.scale.linear()
.domain([0, x_max])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, 100])
.range([0, height]);
var target_axis_position = y(50);
mapNodes = function (nodes) {
var nodesMap;
nodesMap = d3.map();
nodes.forEach(function (n) {
return nodesMap.set(n.id, n);
});
return nodesMap;
};
nodesMap = mapNodes(nodes);
links.forEach(function (l) {
l.source = nodesMap.get(l.source);
l.target = nodesMap.get(l.target);
});
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-240)
.gravity(0.2)
.linkStrength(function (l, i) {
return l.strength;
})
.size([width, height]);
var svg = d3.select("div.graph").append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
force.nodes(nodes)
.links(links)
.start();
g.append("rect")
.attr("x", 0)
.attr("y", y(50 - axisBand))
.attr("width", x(x_max))
.attr("height", y(2 * axisBand))
.attr("fill", "#EEE");
var link = g.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function (d) {
return Math.sqrt(d.strength * 10);
});
var node = g.selectAll(".node")
.data(nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function (d) {
if (d.type == "t") {
return Math.sqrt(d.strength) * 5;
} else if (d.type = "s") {
return Math.sqrt(d.count) * 5;
} else {
return 5;
}
})
.classed("target", function (d) {
return d.type == "t";
})
.classed("source", function (d) {
return d.type == "s";
})
.call(force.drag);
node.append("title")
.text(function (d) {
return d.name;
});
// drag zoom adapted from http://bl.ocks.org/rmarimon/1179647
var downx = Math.NaN;
var downscalex;
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
function dragX(d) {
var p = d3.mouse(svg[0][0]);
downx = x.invert(p[0]);
downscalex = x;
};
g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + target_axis_position + ")")
.call(xAxis)
.on("mousedown", function (d) { dragX(d); });
svg.select('.x.axis text')
.on("mousedown", function (d) { dragX(d); });
d3.select('body')
.on("mousemove", function (d) {
if (!isNaN(downx)) {
var p = d3.mouse(svg[0][0]);
var rupx = p[0];
if (rupx != 0) {
x.domain([downscalex.domain()[0], width * (downx - downscalex.domain()[0]) / rupx + downscalex.domain()[0]]);
}
svg.select('.x.axis').call(xAxis);
force.start();
}
})
.on("mouseup", function (d) {
downx = Math.NaN;
});
var adjust_y = function(d) {
if (d.type == "t") {
return y(50);
} else {
if (Math.abs(y(50) - d.y) < y(axisBand)) {
return d.y < y(50) ? y(50 - axisBand) : y(50 + axisBand);
} else {
return d.y;
}
}
};
var adjust_x = function(d) {
return x(d.time);
};
force.on("tick", function () {
link.attr("x1", function (d) {
return adjust_x(d.source);
})
.attr("y1", function (d) {
return adjust_y(d.source);
})
.attr("x2", function (d) {
return adjust_x(d.target);
})
.attr("y2", function (d) {
return adjust_y(d.target);
});
node.attr("cx", function (d) {
return adjust_x(d);
})
.attr("cy", function (d) {
return adjust_y(d);
});
});
$(function() {
$( "#slider" ).slider({
range: "min",
value: -240,
min: -960,
max: 0,
slide: function( event, ui ) {
$('#charge').text(ui.value);
force.charge($('#charge').text()).start();
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment