Skip to content

Instantly share code, notes, and snippets.

@marvec
Created June 9, 2017 09:51
Show Gist options
  • Save marvec/8d7774f07167d95556e1862e5ecf633d to your computer and use it in GitHub Desktop.
Save marvec/8d7774f07167d95556e1862e5ecf633d to your computer and use it in GitHub Desktop.
Graph with labeled edges
license: mit
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Force Layout with labels on edges</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
</style>
</head>
<body>
<script type="text/javascript">
var w = 1200;
var h = 1000;
var linkDistance=100;
var colors = d3.scale.category10();
var dataset = {
nodes: [
{name: "Adam", d: 40}, // 0
{name: "Bob", d: 20}, // 1
{name: "Carrie", d: 33}, // 2
{name: "Donovan", d: 40}, // 3
{name: "Edward", d: 20}, // 4
{name: "Team A (85md)", d: 85}, // 5
{name: "Team B (60md)", d: 60}, // 6
{name: "Team C (8md)", d: 8}, // 7
{name: "Task 1", d: 35}, // 8
{name: "Task 2", d: 55}, // 9
{name: "Task 3", d: 35}, // 10
{name: "Task 4", d: 55}, // 11
{name: "Story I", d: 15}, // 12
{name: "Story II", d: 15} // 13
],
edges: [
{source: 0, target: 5, stroke: 4, color: "#00afef", label: "80% (32hrs)"},
{source: 0, target: 6, stroke: 1, color: "#000", label: "20% (8hrs)"},
{source: 1, target: 5, stroke: 5, color: "#000", label: "100% (20hrs)"},
{source: 2, target: 5, stroke: 5, color: "#000", label: "100% (33hrs)"},
{source: 3, target: 6, stroke: 5, color: "#000", label: "100% (40hrs)"},
{source: 4, target: 6, stroke: 3, color: "#000", label: "60% (12hrs)"},
{source: 4, target: 7, stroke: 2, color: "#000", label: "40% (8hrs)"},
{source: 5, target: 8, stroke: 2, color: "#000", label: "40% (34md)"},
{source: 5, target: 9, stroke: 3, color: "#000", label: "60% (51md)"},
{source: 6, target: 8, stroke: 5, color: "#000", label: "33% (20md)"},
{source: 7, target: 9, stroke: 5, color: "#000", label: "100% (8md)"},
{source: 6, target: 10, stroke: 5, color: "#000", label: "33% (20md)"},
{source: 6, target: 11, stroke: 5, color: "#000", label: "33% (20md)"},
{source: 12, target: 9, stroke: 1, color: "#000", label: ""},
{source: 12, target: 10, stroke: 1, color: "#000", label: ""},
{source: 12, target: 11, stroke: 1, color: "#000", label: ""},
{source: 13, target: 8, stroke: 1, color: "#000", label: ""},
{source: 13, target: 10, stroke: 1, color: "#000", label: ""},
]
};
var svg = d3.select("body").append("svg").attr({"width":w,"height":h});
var force = d3.layout.force()
.nodes(dataset.nodes)
.links(dataset.edges)
.size([w,h])
.linkDistance([linkDistance + Math.random() * 100 - 50])
.charge([-3500])
.theta(0.1)
.gravity(0.05)
.start();
var edges = svg.selectAll("line")
.data(dataset.edges)
.enter()
.append("line")
.attr("id",function(d,i) {return 'edge'+i})
//.attr('marker-end','url(#arrowhead)')
.style("stroke", function(d) { return d.color })
.style("stroke-width", function(d) { return d.stroke + 'px' })
.style("pointer-events", "none");
var nodes = svg.selectAll("circle")
.data(dataset.nodes)
.enter()
.append("circle")
.attr({"r": function(d) { return d.d }})
.style("fill",function(d,i){return colors(i);})
.call(force.drag)
var nodelabels = svg.selectAll(".nodelabel")
.data(dataset.nodes)
.enter()
.append("text")
.attr({"x":function(d){return d.x;},
"y":function(d){return d.y;},
"class":"nodelabel",
"stroke":"black"})
.text(function(d){return d.name;});
var edgepaths = svg.selectAll(".edgepath")
.data(dataset.edges)
.enter()
.append('path')
.attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
'class':'edgepath',
'fill-opacity':0,
'stroke-opacity':0,
'fill':'blue',
'stroke':'red',
'id':function(d,i) {return 'edgepath'+i}})
.style("pointer-events", "none");
var edgelabels = svg.selectAll(".edgelabel")
.data(dataset.edges)
.enter()
.append('text')
.style("pointer-events", "none")
.attr({'class':'edgelabel',
'id':function(d,i){return 'edgelabel'+i},
'dx':80,
'dy':-5,
'font-size':12,
'fill':'#000'});
edgelabels.append('textPath')
.attr('xlink:href',function(d,i) {return '#edgepath'+i})
.style("pointer-events", "none")
.text(function(d,i){return d.label});
svg.append('defs').append('marker')
.attr({'id':'arrowhead',
'viewBox':'-0 -5 10 10',
'refX':"25px",
'refY':0,
'markerUnits':'userSpaceOnUse',
'orient':'auto',
'markerWidth':10,
'markerHeight':10,
'xoverflow':'visible'})
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5');
//.attr('fill', '#ccc')
//.attr('stroke','#ccc');
force.on("tick", function(){
edges.attr({"x1": function(d){return d.source.x;},
"y1": function(d){return d.source.y;},
"x2": function(d){return d.target.x;},
"y2": function(d){return d.target.y;}
});
nodes.attr({"cx":function(d){return d.x;},
"cy":function(d){return d.y;}
});
nodelabels.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
edgepaths.attr('d', function(d) { var path='M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y;
//console.log(d)
return path});
edgelabels.attr('transform',function(d,i){
if (d.target.x<d.source.x){
bbox = this.getBBox();
rx = bbox.x+bbox.width/2;
ry = bbox.y+bbox.height/2;
return 'rotate(180 '+rx+' '+ry+')';
}
else {
return 'rotate(0)';
}
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment