[ Launch: Node Upon Arcs ] 10081819 by dmann99
-
-
Save dmann99/10081819 to your computer and use it in GitHub Desktop.
Node Upon Arcs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"description":"Node Upon Arcs","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"data.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"mydata.json":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"ajax-caching":true,"thumbnail":"http://i.imgur.com/67gwtvF.png"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// David Mann | |
// @ba6dotus | |
// david@ba6.us | |
// This graph was created to show: | |
// o A Child (Center ring), 1..n Parents (Middle ring), 1..n Grandparents (Outer ring) | |
// o Ability to show relationships with some addl data mixed in, | |
// Each member had multiple types of data thus the nested arcs | |
// o Node overlay was added to convey the ancestral relationships | |
// Original idea from Scott Hayman. | |
// Things I would like to do: | |
// o Incorporate more data items into myTree | |
// o Proportional arc sizes to show more info about members | |
// I would like to have the size of the primary arc convey | |
// the proportion of the makeup of each ring | |
// o Basic ToolTips, ToolTips from additional data items | |
// See http://jsfiddle.net/kingernest/YDQR4/1/ for rollover stuff | |
// o Smooth animation? | |
// http://bl.ocks.org/mbostock/1346410 | |
// http://bl.ocks.org/mbostock/5872848 | |
// o Provide some real world data examples | |
var debug=false; | |
// Input JSON Object that holds hierarchy | |
var myTree = tributary.mydata; | |
// --------------- | |
// -- Constants -- | |
// --------------- | |
// Container | |
var width=800; | |
var height=800 | |
// Center of graphic | |
var xCenter = width/2; | |
var yCenter = height/2; | |
var SpacerPx = 18; // Space between nested arcs in pixels | |
var SpacerAng = 5; // Angle separator between nested arcs in degrees | |
var LevelWidth = 100; // Width of each donut level in pixels | |
var pi = Math.PI; // Constant for a yummy dessert | |
var lineWidth = 4; // Line thickness for node graph elements | |
// Color related code | |
// Some Triplets of pleasing colors | |
// Outside / Middle / Inside | |
var colorData = [ | |
{"arccolor2" : "#B8B800", "arccolor1" : "#FFFF00", "arccolor0" : "#FFFF99"}, | |
{"arccolor2" : "#993300", "arccolor1" : "#AD5C33", "arccolor0" : "#BD7D5C"}, | |
{"arccolor2" : "#000066", "arccolor1" : "#333385", "arccolor0" : "#5C5C9D"}, | |
{"arccolor2" : "#006600", "arccolor1" : "#338533", "arccolor0" : "#5C9D5C"}, | |
{"arccolor2" : "#990033", "arccolor1" : "#AC3059", "arccolor0" : "#BD597A"}, | |
{"arccolor2" : "#3D3D5C", "arccolor1" : "#64647D", "arccolor0" : "#838397"}, | |
{"arccolor2" : "#CC0099", "arccolor1" : "#D633AD", "arccolor0" : "#DE5CBD"}, | |
{"arccolor2" : "#6600FF", "arccolor1" : "#8533FF", "arccolor0" : "#9D5CFF"}, | |
{"arccolor2" : "#FF0000", "arccolor1" : "#FF3300", "arccolor0" : "#FFA375"}, | |
{"arccolor2" : "#33CC33", "arccolor1" : "#00FF00", "arccolor0" : "#B2FFB2"}, | |
{"arccolor2" : "#000000", "arccolor1" : "#666666", "arccolor0" : "#B2B2B2"} | |
]; | |
var colorCounter = 0; | |
// Set color of object, rotate through predefined palette | |
function setColors(myObj) { | |
myObj.fillcolor2 = colorData[colorCounter%colorData.length].arccolor2; | |
myObj.fillcolor1 = colorData[colorCounter%colorData.length].arccolor1; | |
myObj.fillcolor0 = colorData[colorCounter%colorData.length].arccolor0; | |
colorCounter++; | |
} | |
// Output to renderer | |
var data = new Array(); | |
// Using current level and existance of parents | |
// calculate parent arc info | |
function setArcInfo(myObj) { | |
// We are at the root label leaf at targetDepth, analyze it | |
if (myObj.level === 0) { | |
myObj.arcstart=0; | |
myObj.arclength=360; | |
} | |
// Check for parents, if exist set their Arc Info | |
if (myObj.parents) { | |
var sliceSizeDegrees = myObj.arclength / myObj.parents.length; | |
// Step through parents | |
for (pCounter=0;pCounter<myObj.parents.length;pCounter++) { | |
myObj.parents[pCounter].arcstart = myObj.arcstart + (pCounter*sliceSizeDegrees); | |
myObj.parents[pCounter].arclength = sliceSizeDegrees; | |
// Determine centroid angle for this piece. | |
myObj.parents[pCounter].arcmid = myObj.parents[pCounter].arcstart + (sliceSizeDegrees/2); | |
if (debug) { | |
console.log(myObj.parents[pCounter].label + " | arcstart " + myObj.parents[pCounter].arcstart + | |
" | arclength " + myObj.parents[pCounter].arclength + "<BR>"); | |
} | |
} | |
} | |
} | |
// Function to visit all nodes starting at center (child) node | |
// Pass it | |
function traverse(myObj, myFunc, depth ) { | |
// start at level zero | |
var depth = depth || 0; | |
// Separation between nodes | |
if (debug) { | |
console.log("<HR>"); | |
} | |
// Step through this node's keys | |
for (var i in myObj) { | |
if (typeof(myObj[i])=="object") { | |
// Found an object, step down into the object tree | |
traverse(myObj[i], myFunc, depth+0.5); | |
} else if (i == 'label') { | |
// We are at a leaf, process it | |
myObj.level=depth; | |
if (debug) { | |
console.log("Depth : " + myObj.level + " KEY : " + i + " / VALUE = "+myObj[i]+"<BR>"); | |
} | |
// Executed the passed in function with myObj as a parameter | |
myFunc(myObj); | |
} | |
} | |
} | |
// Prepare output array | |
function setData(myObj) { | |
data[ (data.length===0 ? 0 : data.length) ] = {"label": myObj.label, "level": myObj.level, "arcstart": myObj.arcstart, "arclen": myObj.arclength, "LevSpacer":0, "arccolor" : myObj.fillcolor2}; | |
data[ (data.length===0 ? 0 : data.length) ] = {"label": myObj.label, "level": myObj.level, "arcstart": myObj.arcstart, "arclen": myObj.arclength, "LevSpacer":1, "arccolor" : myObj.fillcolor1}; | |
data[ (data.length===0 ? 0 : data.length) ] = {"label": myObj.label, "level": myObj.level, "arcstart": myObj.arcstart, "arclen": myObj.arclength, "LevSpacer":2, "arccolor" : myObj.fillcolor0}; | |
} | |
// Draw node marker | |
// Using angle in degrees (0 degrees is top center, increasing clockwise) | |
// and Level 0,1,2, draw | |
function SetCentroidPos(myObj) { | |
var angle = myObj.arcmid; | |
var level = myObj.level; | |
// Find the middle of the arc in radians | |
var arcmidrad = (angle/360)*2*pi; | |
arcmidrad = arcmidrad - (0.5*pi); | |
// Find the desired distance from center | |
var arcpos = (level*LevelWidth)+(LevelWidth*0.5); | |
if (level === 0) { | |
xPos = xCenter; | |
yPos = yCenter; | |
myObj.centroidx = xPos; | |
myObj.centroidy = yPos; | |
} else { | |
xPos = xCenter + (arcpos) * Math.cos((arcmidrad)); | |
yPos = yCenter + (arcpos) * Math.sin((arcmidrad)); | |
myObj.centroidx = xPos; | |
myObj.centroidy = yPos; | |
} | |
} | |
// Draw node marker | |
// Using angle in degrees (0 degrees is top center, increasing clockwise) | |
// and Level 0,1,2, draw | |
function DrawNode(myObj) { | |
var myDotRadius=LevelWidth/10; | |
svg.append("circle") | |
.attr("r",myDotRadius) | |
.attr("cx",myObj.centroidx) | |
.attr("cy",myObj.centroidy) | |
.attr("class","node") | |
.on("mouseover",mouseOverNode); | |
} | |
function mouseOverNode() { | |
// Todo: Make this work! | |
var myCircle = d3.select(this); | |
myCircle.attr("fill","gray"); | |
// d3.select(this).attr("fill", "black"); //Color circle green | |
console.log("mouseOverNode"); | |
// tooltip.html( //Populate tooltip text | |
// "Username: " + d3.select(this).attr("username") + "<br/>" + | |
// "Session ID: " + d3.select(this).attr("sessionid") + "<br/>" + | |
// "Impact CPU: " + d3.select(this).attr("impact") | |
// ) | |
// .transition() | |
// .duration(250) | |
// .style("opacity", .7); | |
} | |
function DrawEdges(myObj) { | |
// Build edges | |
// For each edge build from the child to the parent | |
// In getData, use this info to determine a node's source and parent coords for an edge | |
// Check for parents, if exist draw lines to them | |
if (myObj.parents) { | |
// Step through parents | |
for (pCounter=0;pCounter<myObj.parents.length;pCounter++) { | |
svg.append("line") | |
.attr("x1", myObj.centroidx) | |
.attr("y1", myObj.centroidy) | |
.attr("x2", myObj.parents[pCounter].centroidx) | |
.attr("y2", myObj.parents[pCounter].centroidy) | |
.style("stroke", "black") | |
.style("stroke-width", lineWidth); | |
} | |
} | |
} | |
// definitions for arc, col, title callbacks | |
var arc = d3.svg.arc() | |
.innerRadius(function(d,i) { | |
if (d.level===0) { | |
// Level 0 = inner circle, has to be handled differently | |
return 0; | |
} else { | |
return (LevelWidth*(d.level)+(d.LevSpacer*SpacerPx)); | |
} | |
}) | |
.outerRadius(function(d,i) {return (LevelWidth*(d.level+1)-(d.LevSpacer*SpacerPx)); }) | |
.startAngle(function(d,i) { | |
var myretval; | |
if (d.level===0) { | |
// Level 0 = inner circle, has to be handled differently | |
myretval = ( (d.arcstart) * pi / 180 ); | |
} else { | |
myretval = ( (d.arcstart+(d.LevSpacer*SpacerAng)) * pi / 180 ); | |
} | |
return myretval; | |
}) | |
.endAngle(function(d) { | |
var myretval; | |
if (d.level===0) { | |
// Level 0 = inner circle, has to be handled differently | |
myretval = ( ( (d.arcstart+d.arclen)) * pi / 180); | |
} else { | |
myretval = ( ( (d.arcstart+d.arclen-(d.LevSpacer*SpacerAng))) * pi / 180); | |
} | |
return myretval; | |
}); | |
var col = function(d) { return ( d.arccolor ); }; | |
var mytitle= function(d) { return ( d.label ); }; | |
// Create container and draw in it | |
var svg=d3.select("svg"); | |
//var svg = d3.select("body") | |
// .append("svg:svg") | |
// .attr("width", width) | |
// .attr("height", height); | |
var chartContainer = svg.append("g") | |
.attr('class', 'some_class') | |
.attr("transform", "translate(400, 400)"); | |
// Draw Donuts | |
// Make multiple passes at the data by traversing tree | |
// and executing these functions against the nodes | |
traverse( myTree, setArcInfo ); | |
traverse( myTree, setColors ); | |
traverse( myTree, setData ); | |
// Now that data is in place, build the arcs | |
chartContainer.selectAll("path") | |
.data(data) | |
.enter() | |
.append("path") | |
.attr("d", arc) | |
.attr("fill",col) | |
.attr("class","bar") | |
.attr('title',function(d){ | |
return d.label; | |
}); | |
// Build the node graph | |
traverse( myTree, SetCentroidPos ); | |
traverse( myTree, DrawEdges ); | |
traverse( myTree, DrawNode ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"label" : "LEV0-1of1", | |
"parents": [ | |
{ | |
"label": "LEV1-1of2", | |
"parents": [ | |
{"label": "LEV2-1of5"}, | |
{"label": "LEV2-2of5"}, | |
{"label": "LEV2-3of5"}, | |
{"label": "LEV2-4of5"} ] | |
}, | |
{ | |
"label": "LEV1-2of2", | |
"parents": [ | |
{"label": "LEV2-1of3"}, | |
{"label": "LEV2-2of3"}, | |
{"label": "LEV2-3of3"} | |
] | |
}, | |
{ | |
"label": "LEV1-3of3", | |
"parents": [ | |
{"label": "LEV2-1of3"}, | |
{"label": "LEV2-2of3"} | |
] | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.bar { | |
display:inline-block; | |
width: 3px; border:1px outset #69f; | |
background: #369; border-bottom:1px solid #000; | |
} | |
.bar:hover { fill:#EEE; | |
stroke : #AAA;} | |
/* | |
.bar:hover { fill:#EEE; | |
stroke : #EEE; | |
stroke-width=10px} | |
*/ | |
.node { | |
stroke:#000; | |
stroke-width:3; | |
stroke-color:#000; | |
fill : #EEE; | |
} | |
.node:hover { fill:#AAA; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment