Skip to content

Instantly share code, notes, and snippets.

@spendres
Created December 2, 2013 17:01
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 spendres/7752696 to your computer and use it in GitHub Desktop.
Save spendres/7752696 to your computer and use it in GitHub Desktop.
D3 Node plot.
<html>
<head>
<meta charset="utf-8">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<style>
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node {
font: 14px "HelveticaNeue-Light";
}
.node:nth-of-type(1) {
font: 16px "HelveticaNeue-Light";
}
.legend {
font: 18px "HelveticaNeue-Light";
font-weight:200;
font-style:oblique;
//fill: #00b;
}
.suffix {
font-weight:300;
fill:rgb(12,162,234);
}
rect.common {
fill:rgb(237,237,237);
z-index: -10;
}
rect.phenomenon {
fill:rgb(237,245,250);
z-index: -10;
}
.bracket {
fill: none;
stroke: #00b;
stroke-width: 1.0px;
}
.link {
fill: none;
stroke: #ddd;
stroke-width: 1.5px;
}
.link:nth-child(1) {
fill: none;
stroke: #ddd;
stroke-width: 1.5px;
}
body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Arial, Helvetica , "Lucida Grande", sans-serif;
font-weight: 300;
}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script id="flare" type="application/json">
{
"name":"exhaustless\ntakeoffs",
"children":[
{
"name": "separate takeoffs\nfrom landings",
"tech":"common",
"children":[
{
"name":"simultaneous landings\nand takeoffs",
"tech":"common",
"children":[
{
"name":"more takeoff slots",
"tech":"common",
"children":[
{"name":"increased\ncapacity"}
]
}
]
}
]
},
{
"name": "increase acceleration\nrate",
"children":[
{"name":"less distance and time\nrequired for takeoff",
"children":[
{
"name":"fewer\nbird strikes",
"children":[
{"name":"increased\nsafety"}
]
},
{
"name":"shorter takeoff slots",
"children":[
{"name":"increased\ncapacity"},
{"name":"increased\nproductivity"}
]
},
{
"name":"less sprawl",
"children":[
{"name":"increased\nproductivity"}
]
}
]
}
]
},
{
"name": "increase takeoff\nvelocity",
"children":[
{
"name":"faster climb to cruise",
"children":[
{
"name":"reduce noise during\ntakeoff and climb",
"children":[
{"name":"better\nquality of life"}
]
},
{
"name":"fewer\nbird strikes",
"children":[
{"name":"increased\nsafety"}
]
}
]
},
{
"name":"increase stall margin",
"children":[
{"name":"increased\nsafety"}
]
},
{
"name":"wind direction\nindependence",
"children":[
{
"name":"more operational\nflexibility",
"children":[
{
"name":"increased\nproductivity"
}
]
}
]
},
{
"name":"reduce jet fuel\nburned during\ntakeoff and climb",
"children":[
{
"name":"reduce exhaust from\ntakeoff and climb",
"children":[
{"name":"better\nquality of life"},
{"name":"reduced\ncarbon\nemissions"}
]
}
]
}
]
},
{
"name": "use grid energy\ninstead of jet fuel",
"children":[
{
"name":"reduce jet fuel\nburned during\ntakeoff and climb",
"children":[
{
"name":"reduce noise during\ntakeoff and climb",
"children":[
{"name":"better\nquality of life"},
{"name":"increased\ncapacity"}
]
},
{
"name":"reduce exhaust from\ntakeoff and climb",
"children":[
{"name":"better\nquality of life"},
{"name":"reduced\ncarbon\nemissions"}
]
},
{
"name":"reduce chronic\nhealth problems",
"children":[
{"name":"better\nquality of life"},
{"name":"increased\neconomic\ngrowth"}
]
}
]
},
{
"name":"increase energy\nefficiency",
"children":[
{
"name":"create local grid\nand operational\njobs",
"children":[
{"name":"increased\neconomic\ngrowth"}
]
}
,{
"name":"reduced\ncarbon\nemissions"
}
]
}
]
}
]
}
</script>
</head>
<body>
<script type="text/javascript">
function setup() {
var removeDups = function (d) {
var count = [];
var preen = [];
var depth = 0;
var nodes = d.slice(0);
//nodes.reverse();
d.forEach( function(dd,index) {
dd.id = index;
//console.log("dd: ",dd.name,dd.id);
depth = ( (dd.depth > depth) ? dd.depth : depth );
(count[dd.name]==undefined) ? (count[dd.name]=[dd.id]) : ( count[dd.name].push(dd.id) );
//(count[dd.name]==undefined) ? (count[dd.name]=[dd.id]) : (preen.push(dd.id), );
});
while (depth > 0) {
nodes.forEach( function(dd,index) {
if(dd.depth == depth){
if( count[dd.name].length > 1 ){
var modeIndex = count[dd.name].length>>1;
var merged = count[dd.name].splice(modeIndex,1);
var duplicates = count[dd.name]; //.splice(1);
preen = preen.concat(duplicates);
duplicates.forEach( function(duplicate,index){
var children = nodes[duplicate].parent.children;
children.forEach( function(child,ii){
if(child.id == duplicate){
nodes[duplicate].parent.children[ii] = nodes[merged];
}
//console.log(nodes[duplicate].parent);
});
});
}
}
});
depth--;
}
preen = preen.filter(function (e, i, arr) {
return preen.lastIndexOf(e) === i;
});
preen.sort(function(a,b){return b - a});
preen.forEach( function(dd,index) { nodes.splice(dd,1)} );
return nodes;
};
var insertLinebreaks = function (d) {
var el = d3.select(this);
var words = d.name.split('\n');
el.text('');
for (var i = 0; i < words.length; i++) {
var tspan = el.append('tspan').text(words[i]);
if (i > 0)
tspan.attr('x', "-.2em").attr('dy', '15');
}
};
var insertColorSuffix = function (d) {
var el = d3.select(this);
var words = d.name.split('\n');
if (words[0] == 'exhaustless'){
el.text('exhaust');
var tspan = el.append('tspan').text('less').attr("class","suffix");
tspan = el.append('tspan').text('\n'+words[1]);
tspan.attr('x', "-.2em").attr('dy', '15');
}
};
var width = 760,
height = 560;
var cluster = d3.layout.tree()
.size([height, width-50]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var radius = 5.5;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40,50) scale(.85)");
svg.append("rect")
.attr("class", "common")
.attr("width",width*1.1)
.attr("height","14%")
.attr("transform", function(d) { return "translate(" + -25 + "," + -40 + ")"; });
svg.append("rect")
.attr("class", "phenomenon")
.attr("width",width*1.1)
.attr("height","100%")
.attr("transform", function(d) { return "translate(" + -25 + "," + 45 + ")"; });
var data = JSON.parse($("#flare").html());
var nodes = cluster.nodes(data);
nodes = removeDups(nodes);
var maxDepth = 0;
var byDepth = {};
depth = nodes.forEach( function(n,index) {
maxDepth = (n.depth > maxDepth) ? n.depth : maxDepth;
(byDepth[n.depth]==undefined) ? (byDepth[n.depth]=[n]) : byDepth[n.depth].push(n);
});
var itemsToDistribute = byDepth[maxDepth];
var increment = height*.8/(itemsToDistribute.length-1);
itemsToDistribute.forEach( function(n,index) {
n.x = increment*(index+1);
});
links = cluster.links(nodes);
var link = svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", radius);
node.append("text")
.attr("dx", function(d) { return "-.2em"; })
.attr("dy", function(d) {
var s = d.name.split(" ");
// work around
if(s[0]=="wind" || s[0] =="create"){
return "1.5em";
}
return (d.name.split("\n").length*-1.0) + "em";
})
.attr("font-family","sans-serif")
.attr("font-weight","200")
.text(function(d) { return d.name; });
svg.selectAll("g text").each(insertLinebreaks);
svg.selectAll("g text").each(insertColorSuffix);
svg.append("text")
.attr("dx", function(d) { return "0em"; })
.attr("dy", "4.2em")
.attr("class","legend")
.text(function(d) { return "exhaust"; })
.append("tspan")
.text(function(d) { return "less"; })
.attr("class","legend suffix");
svg.append("text")
.attr("dx", function(d) { return "0em"; })
.attr("dy", "5.2em")
.attr("class","legend")
.text(function(d) { return "phenomenon"; });
svg.append("text")
.attr("dx", function(d) { return "0em"; })
.attr("dy", ".2em")
.attr("class","legend")
.text(function(d) { return "common to"; });
svg.append("text")
.attr("dx", function(d) { return "0em"; })
.attr("dy", "1.2em")
.attr("class","legend")
.text(function(d) { return "all solutions"; });
//d3.select(self.frameElement).style("height", height + "px");
}
window.onload = setup();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment