Skip to content

Instantly share code, notes, and snippets.

@LukeKuenneke
Last active November 1, 2017 21:00
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 LukeKuenneke/8ad35cefbcc9b79a14a08a7be8179ec8 to your computer and use it in GitHub Desktop.
Save LukeKuenneke/8ad35cefbcc9b79a14a08a7be8179ec8 to your computer and use it in GitHub Desktop.
Sankey Wimsatt Design Seed Team
<p id="chart">
function getViewPortWidth() {
return Math.max(document.documentElement.clientWidth, window.innerWidth || 0) * 0.99;
}
function getViewPortHeight() {
return Math.max(document.documentElement.clientHeight, window.innerHeight || 0) * 0.985;
}
var margin = {
top: 1,
right: 1,
bottom: 6,
left: 1
},
width = getViewPortWidth() - margin.left - margin.right,
height = getViewPortHeight() - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"),
format = function (d) {
return formatNumber(d) + " TWh";
},
color = d3.scale.category20();
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey()
.nodeWidth(20)
.nodePadding(50)
.size([width, height]);
var path = sankey.link();
var json_data = {
nodes: [
// Columns
{ "id": 0, "name": "Object" },
{ "id": 1, "name": "Behavior" },
{ "id": 2, "name": "System" },
{ "id": 3, "name": "Enviornment" },
{ "id": 4, "name": "Purpose" },
{ "id": 5, "name": "Theory" },
{ "id": 6, "name": "Consequence" },
// Objects
{ "id": 7, "name": "NULL Object" },
{ "id": 8, "name": "Tarmac" },
{ "id": 9, "name": "No Dock" },
{ "id": 10, "name": "Underground Buildings" },
{ "id": 11, "name": "Hangars" },
{ "id": 12, "name": "Perimiter Walls" },
{ "id": 13, "name": "Perimiter Tower" },
{ "id": 14, "name": "Perimiter Fences" },
// Behaviors
{ "id": 15, "name": "NULL Behavior" },
{ "id": 16, "name": "Organization Of The Base" },
{ "id": 17, "name": "Controlling Movements" },
{ "id": 18, "name": "Housing Airplanes" },
{ "id": 19, "name": "Housing Objects" },
{ "id": 20, "name": "Not Landing - Fixed Wing" },
{ "id": 21, "name": "Landing Helicopter" },
{ "id": 22, "name": "Stability" },
// Systems
{ "id": 23, "name": "NULL System" },
{ "id": 24, "name": "Chinese Military Base" },
{ "id": 25, "name": "Shoreline" },
{ "id": 26, "name": "Base And Port" },
{ "id": 27, "name": "Horn of Africa Bases" },
{ "id": 28, "name": "Perimiter Security" },
{ "id": 29, "name": "Air Traffic" },
{ "id": 30, "name": "Road Network" },
// // Enviornments
{ "id": 31, "name": "NULL Enviornment" },
{ "id": 32, "name": "Commercial Port Nextdoor" },
{ "id": 33, "name": "Djibouti" },
{ "id": 34, "name": "April - July Timeframe" },
// // Purposes
{ "id": 35, "name": "NULL Purpose" },
{ "id": 36, "name": "Conduct Operations Unobserved" },
{ "id": 37, "name": "Facade" },
{ "id": 38, "name": "Anti Piracy" },
{ "id": 39, "name": "Storage for Humanitarian Supplies" },
{ "id": 40, "name": "Security" },
{ "id": 41, "name": "Intel" },
// Theories
{ "id": 42, "name": "NULL Theory" },
{ "id": 43, "name": "Chinese Goverment Approach To Africa" },
{ "id": 44, "name": "Physical Propertium" },
// // Consequences
{ "id": 45, "name": "NULL Consequence" },
{ "id": 46, "name": "Anti Piracy / Humanitarian" },
{ "id": 47, "name": "Secure Facility" },
{ "id": 48, "name": "Intel Outpost" },
{ "id": 49, "name": "Not Big Exercises" }
],
"links": [
// Headers
{ "source": 0, "target": 1, "value": 1 },
{ "source": 1, "target": 2, "value": 1 },
{ "source": 2, "target": 3, "value": 1 },
{ "source": 3, "target": 4, "value": 1 },
{ "source": 4, "target": 5, "value": 1 },
{ "source": 5, "target": 6, "value": 1 },
// Null Entities
{ "source": 7, "target": 15, "value": 1 },
{ "source": 15, "target": 23, "value": 1 },
{ "source": 23, "target": 31, "value": 1 },
{ "source": 31, "target": 35, "value": 1 },
{ "source": 35, "target": 42, "value": 1 },
{ "source": 42, "target": 45, "value": 1 },
// NULL Object, Organization of the base
{ "source": 7, "target": 16, "value": 1 },
// Organization of the base, Null System
{ "source": 16, "target": 23, "value": 1 },
// Tarmac, Stability
{ "source": 8, "target": 22, "value": 1 },
// Stability, NULL System
{ "source": 22, "target": 23, "value": 1 },
// Tarmac, Landing Helicopter
{ "source": 8, "target": 21, "value": 1 },
// Tarmac, Not Landing - Fixed Wing
{ "source": 8, "target": 20, "value": 1 },
// No Dock, Not Landing - Fixed Wing
{ "source": 9, "target": 20, "value": 1 },
// Underground Buildings, Landing Helicopter
{ "source": 10, "target": 21, "value": 1 },
// Underground Buildings, Not Landing - Fixed Wing
{ "source": 10, "target": 20, "value": 1 },
// Underground Buildings, NULL Behaviour
{ "source": 10, "target": 15, "value": 1 },
// Hangars, Housing Objects
{ "source": 11, "target": 19, "value": 1 },
// Housing Object, Null System
{ "source": 19, "target": 23, "value": 1 },
// Hangars, Housing Airplanes
{ "source": 11, "target": 18, "value": 1 },
// Housing Airplanes, NULL System
{ "source": 18, "target": 23, "value": 1 },
// Perimiter Walls, Controlling Movements
{ "source": 12, "target": 17, "value": 1 },
// Perimiter Fences, Controlling Movements
{ "source": 14, "target": 17, "value": 1 },
// Perimiter Tower, Controlling Movements
{ "source": 13, "target": 17, "value": 1 },
// NULL Object, NULL Behavior
{ "source": 7, "target": 15, "value": 1 },
// Landing Helicopter, Base + Port
{ "source": 21, "target": 26, "value": 1 },
// Not Landing Fixed Wing, Chinese Military Base
{ "source": 20, "target": 24, "value": 1 },
// Not Landing fixed wing, Base + Port
{ "source": 20, "target": 26, "value": 1 },
// Not Landing fixed wing, Horn of Africa Base
{ "source": 20, "target": 27, "value": 1 },
// Controlling Movements, Perimeter Security
{ "source": 17, "target": 28, "value": 1 },
// NULL Object, Air Traffic
{ "source": 13, "target": 29, "value": 1 },
// Air Traffic, Null System
{ "source": 29, "target": 23, "value": 1 },
// NULL Behavior, Road Network
{ "source": 13, "target": 30, "value": 1 },
// Road Network, Null System
{ "source": 30, "target": 23, "value": 1 },
// Chinese Military Base, Djibouti
{ "source": 24, "target": 33, "value": 1 },
// Shoreline, NULL Behavior
{ "source": 15, "target": 25, "value": 1 },
// Shoreline, Djibouti
{ "source": 25, "target": 33, "value": 1 },
// Base + Ports, Commercial Port Next Door
{ "source": 26, "target": 32, "value": 1 },
// Base + Ports, Djibouti
{ "source": 26, "target": 33, "value": 1 },
// Horn of Africa Bases, Djibouti
{ "source": 27, "target": 33, "value": 1 },
// Perimeter Security, Commercial Port Next Door
{ "source": 28, "target": 32, "value": 1 },
// Perimeter Security, Djibouti
{ "source": 28, "target": 33, "value": 1 },
// Perimeter Security, April - July Timeframe
{ "source": 28, "target": 34, "value": 1 },
// Perimeter Security, NULL Enviorment
{ "source": 28, "target": 31, "value": 1 },
// Commercial Port Next Door, Anti Piracy
{ "source": 32, "target": 38, "value": 1 },
// Commercial Port Next Door, Storage for humanitarian supplies
{ "source": 32, "target": 39, "value": 1 },
// Djibouti, Facade
{ "source": 33, "target": 37, "value": 1 },
// Djibouti, Anti Piracy
{ "source": 33, "target": 38, "value": 1 },
// Djibouti, Storage for humanitarian supplies
{ "source": 33, "target": 39, "value": 1 },
// Djibouti, Intel
{ "source": 33, "target": 41, "value": 1 },
// April - June Timeframe, Security
{ "source": 34, "target": 40, "value": 1 },
// NULL Enviorment, Security
{ "source": 31, "target": 40, "value": 1 },
// Facade, Chinese Gov't Apporoach to Africa
{ "source": 37, "target": 43, "value": 1 },
// Anti Piracy, Chinese Gov't Apporoach to Africa
{ "source": 38, "target": 43, "value": 1 },
// Anti Piracy, Physical Propertium
{ "source": 38, "target": 44, "value": 1 },
// Storage for Humanitarian Supplies, Chinese Gov't Apporoach to Africa
{ "source": 39, "target": 43, "value": 1 },
// Security, Physical Propertium
{ "source": 40, "target": 44, "value": 1 },
// Intel, Null Theory
{ "source": 41, "target": 42, "value": 1 },
// Chinese Gov't Approach to Africa, Anti Piracy / Humanitarian
{ "source": 43, "target": 46, "value": 1 },
// Physical Propertium, Secure Facility
{ "source": 44, "target": 47, "value": 1 },
// Chinese Gov't Approach to Africa, Not Big Exercises
{ "source": 43, "target": 49, "value": 1 },
// NULL Theory, Intel Outpost
{ "source": 42, "target": 48, "value": 1 },
// Null Env, Conduct operations Unobserved
{ "source": 31, "target": 36, "value": 1 },
// Conduct operations Unobserved, NULL Theory
{ "source": 36, "target": 42, "value": 1 },
]
};
d3.json(JSON.stringify(json_data), function (error) {
sankey
.nodes(json_data.nodes)
.links(json_data.links)
.layout(32);
var link = svg.append("g").selectAll(".link")
.data(json_data.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.attr("id", function(d,i){
d.id = i;
return "link-"+i;
})
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
link.append("title")
.text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value); });
var node = svg.append("g").selectAll(".node")
.data(json_data.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.on("click", highlightNodeLinks)
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("drag", dragmove));
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) { return d.name + "\n" + format(d.value); });
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
function dragmove(d) {
d3.select(this).attr("transform", "translate(" + (d.x = Math.max(0, Math.min(width - d.dx, d3.event.x))) + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}
function highlightNodeLinks(node,i){
var remainingNodes=[],
nextNodes=[];
var stroke_opacity = 0;
if( d3.select(this).attr("data-clicked") == "1" ){
d3.select(this).attr("data-clicked","0");
stroke_opacity = 0.2;
}else{
d3.select(this).attr("data-clicked","1");
stroke_opacity = 0.5;
}
var traverse = [{
linkType : "sourceLinks",
nodeType : "target"
},{
linkType : "targetLinks",
nodeType : "source"
}];
traverse.forEach(function(step){
node[step.linkType].forEach(function(link) {
remainingNodes.push(link[step.nodeType]);
highlight_link(link.id, stroke_opacity);
});
while (remainingNodes.length) {
nextNodes = [];
remainingNodes.forEach(function(node) {
node[step.linkType].forEach(function(link) {
nextNodes.push(link[step.nodeType]);
highlight_link(link.id, stroke_opacity);
});
});
remainingNodes = nextNodes;
}
});
}
function highlight_link(id,opacity){
d3.select("#link-"+id).style("stroke-opacity", opacity);
}
});
<script src="https://d3js.org/d3.v2.min.js?2.9.1"></script>
<script src="https://bost.ocks.org/mike/sankey/sankey.js"></script>
#chart {
height: 500px;
}
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment