Quick Tutorial - SpaceTree
This tutorial covers the basics about creating a SpaceTree-like visualization. If you want to know more about this visualization I’d recommend you to visit the documentation for the input JSON data, the Canvas Widget, and the SpaceTree layout, where you can find detailed information about its configuration options and controller methods.
Hi, this is going to be a quick tutorial on how to set the ST up and running.
We are going to work with this tree JSON structure:
var json = {
"id": "node02",
"name": "0.2",
"data": {},
"children": [{
"id": "node13",
"name": "1.3",
"data": {},
"children": [{
"id": "node24",
"name": "2.4",
"data": {},
"children": [{
"id": "node35",
"name": "3.5",
"data": {},
"children": [{
"id": "node46",
"name": "4.6",
"data": {},
"children": []
}, {
"id": "node47",
"name": "4.7",
"data": {},
"children": []
}]
}, {
"id": "node38",
"name": "3.8",
"data": {},
"children": [{
"id": "node49",
"name": "4.9",
"data": {},
"children": []
}, {
"id": "node410",
"name": "4.10",
"data": {},
"children": []
}, {
"id": "node411",
"name": "4.11",
"data": {},
"children": []
}]
}]
}, {
"id": "node212",
"name": "2.12",
"data": {},
"children": [{
"id": "node313",
"name": "3.13",
"data": {},
"children": [{
"id": "node414",
"name": "4.14",
"data": {},
"children": []
}, {
"id": "node415",
"name": "4.15",
"data": {},
"children": []
}, {
"id": "node416",
"name": "4.16",
"data": {},
"children": []
}]
}, {
"id": "node317",
"name": "3.17",
"data": {},
"children": [{
"id": "node418",
"name": "4.18",
"data": {},
"children": []
}, {
"id": "node419",
"name": "4.19",
"data": {},
"children": []
}, {
"id": "node420",
"name": "4.20",
"data": {},
"children": []
}, {
"id": "node421",
"name": "4.21",
"data": {},
"children": []
}]
}]
}, {
"id": "node222",
"name": "2.22",
"data": {},
"children": [{
"id": "node323",
"name": "3.23",
"data": {},
"children": [{
"id": "node424",
"name": "4.24",
"data": {},
"children": []
}, {
"id": "node425",
"name": "4.25",
"data": {},
"children": []
}, {
"id": "node426",
"name": "4.26",
"data": {},
"children": []
}]
}]
}]
}, {
"id": "node127",
"name": "1.27",
"data": {},
"children": [{
"id": "node228",
"name": "2.28",
"data": {},
"children": [{
"id": "node329",
"name": "3.29",
"data": {},
"children": [{
"id": "node430",
"name": "4.30",
"data": {},
"children": []
}, {
"id": "node431",
"name": "4.31",
"data": {},
"children": []
}, {
"id": "node432",
"name": "4.32",
"data": {},
"children": []
}]
}, {
"id": "node333",
"name": "3.33",
"data": {},
"children": [{
"id": "node434",
"name": "4.34",
"data": {},
"children": []
}, {
"id": "node435",
"name": "4.35",
"data": {},
"children": []
}]
}, {
"id": "node336",
"name": "3.36",
"data": {},
"children": [{
"id": "node437",
"name": "4.37",
"data": {},
"children": []
}, {
"id": "node438",
"name": "4.38",
"data": {},
"children": []
}, {
"id": "node439",
"name": "4.39",
"data": {},
"children": []
}, {
"id": "node440",
"name": "4.40",
"data": {},
"children": []
}]
}, {
"id": "node341",
"name": "3.41",
"data": {},
"children": [{
"id": "node442",
"name": "4.42",
"data": {},
"children": []
}, {
"id": "node443",
"name": "4.43",
"data": {},
"children": []
}, {
"id": "node444",
"name": "4.44",
"data": {},
"children": []
}, {
"id": "node445",
"name": "4.45",
"data": {},
"children": []
}]
}]
}, {
"id": "node246",
"name": "2.46",
"data": {},
"children": [{
"id": "node347",
"name": "3.47",
"data": {},
"children": [{
"id": "node448",
"name": "4.48",
"data": {},
"children": []
}, {
"id": "node449",
"name": "4.49",
"data": {},
"children": []
}, {
"id": "node450",
"name": "4.50",
"data": {},
"children": []
}, {
"id": "node451",
"name": "4.51",
"data": {},
"children": []
}]
}, {
"id": "node352",
"name": "3.52",
"data": {},
"children": [{
"id": "node453",
"name": "4.53",
"data": {},
"children": []
}, {
"id": "node454",
"name": "4.54",
"data": {},
"children": []
}, {
"id": "node455",
"name": "4.55",
"data": {},
"children": []
}, {
"id": "node456",
"name": "4.56",
"data": {},
"children": []
}]
}, {
"id": "node357",
"name": "3.57",
"data": {},
"children": [{
"id": "node458",
"name": "4.58",
"data": {},
"children": []
}]
}, {
"id": "node359",
"name": "3.59",
"data": {},
"children": [{
"id": "node460",
"name": "4.60",
"data": {},
"children": []
}, {
"id": "node461",
"name": "4.61",
"data": {},
"children": []
}, {
"id": "node462",
"name": "4.62",
"data": {},
"children": []
}, {
"id": "node463",
"name": "4.63",
"data": {},
"children": []
}]
}]
}, {
"id": "node264",
"name": "2.64",
"data": {},
"children": [{
"id": "node365",
"name": "3.65",
"data": {},
"children": [{
"id": "node466",
"name": "4.66",
"data": {},
"children": []
}, {
"id": "node467",
"name": "4.67",
"data": {},
"children": []
}]
}, {
"id": "node368",
"name": "3.68",
"data": {},
"children": [{
"id": "node469",
"name": "4.69",
"data": {},
"children": []
}, {
"id": "node470",
"name": "4.70",
"data": {},
"children": []
}]
}]
}, {
"id": "node271",
"name": "2.71",
"data": {},
"children": [{
"id": "node372",
"name": "3.72",
"data": {},
"children": [{
"id": "node473",
"name": "4.73",
"data": {},
"children": []
}, {
"id": "node474",
"name": "4.74",
"data": {},
"children": []
}, {
"id": "node475",
"name": "4.75",
"data": {},
"children": []
}, {
"id": "node476",
"name": "4.76",
"data": {},
"children": []
}]
}, {
"id": "node377",
"name": "3.77",
"data": {},
"children": [{
"id": "node478",
"name": "4.78",
"data": {},
"children": []
}, {
"id": "node479",
"name": "4.79",
"data": {},
"children": []
}, {
"id": "node480",
"name": "4.80",
"data": {},
"children": []
}]
}, {
"id": "node381",
"name": "3.81",
"data": {},
"children": [{
"id": "node482",
"name": "4.82",
"data": {},
"children": []
}]
}, {
"id": "node383",
"name": "3.83",
"data": {},
"children": [{
"id": "node484",
"name": "4.84",
"data": {},
"children": []
}, {
"id": "node485",
"name": "4.85",
"data": {},
"children": []
}, {
"id": "node486",
"name": "4.86",
"data": {},
"children": []
}, {
"id": "node487",
"name": "4.87",
"data": {},
"children": []
}]
}]
}]
}]
};
We’ll create three files: an example.html file, an example.css file and an example.js file.
I’ll put these files in the root library folder (i.e “Jit”), so I can access all libraries.
Put this HTML in your example.html page:
<html>
<head>
<link type="text/css" rel="stylesheet" href="example.css" />
<!--[if IE]>
<script type="text/javascript" src="Extras/excanvas.js"></script>
<![endif]-->
<script type="text/javascript" src="jit.js" ></script>
<script type="text/javascript" src="example.js" ></script>
</head>
<body onload="init();">
<div id="infovis"></div>
</body>
</html>
Now, create an example.css and put this code in it:
html, body {
width:100%;
height:100%;
background-color:#444;
text-align:center;
overflow:hidden;
font-size:9px;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
margin:0;padding:0;
}
/* visualization style container */
#infovis {
background-color:#222;
position:relative;
width:900px;
height:500px;
}
a, a:link, a:visited {
color:#343439;
}
/* spacetree nodes CSS class */
.node {
background-color:transparent;
font-weight:bold;
overflow:hidden;
text-decoration:none;
position:absolute;
text-align:center;
padding:4px 1px 1px 1px;
}
.node:hover {
color:#393434;
}
.hidden{
display:none;
}
Finally, create an example.js file and put this code in it:
function init() {
var json= //data defined previously
//Create a new canvas instance.
var canvas = new Canvas('mycanvas', {
//Where to inject canvas. Any HTML container will do.
'injectInto':'infovis',
//Set width and height, default's to 200.
'width': 900,
'height': 500,
//Set a background color in case the browser
//does not support clearing a specific area.
'backgroundColor': '#222'
});
//Create a new ST instance
var st= new ST(canvas, {
//set node and edge colors
Node: {
color: '#ccb'
},
Edge: {
color: '#ccb'
}
});
//load json data
st.loadJSON(json);
//compute node positions and layout
st.compute();
//optional: make a translation of the tree
Tree.Geometry.translate(st.tree,
new Complex(-200, 0), "startPos");
//Emulate a click on the root node.
st.onClick(st.root);
}
You should see a spacetree up and running (don’t worry if you can’t interact with it, we’ll add click event handlers on the labels below).
If you want to know more about the DOM structure created by the Canvas object and about the options for the controller of this class you can see this documentation entry.
Adding event handlers to the Spacetree
Let’s add an onclick event handler to the labels for triggering the Spacetree animation.
This is done by implementing an onCreateLabel controller method and passing it to the Spacetree constructor.
We’ll also add custom colors and styles for nodes and edges that lie between the root node and the selected node. Since all general Node and Edge styles defined by the Node and Edge configuration objects can be individually overriden by a node or edge, we’ll use the onBeforePlotLine and onBeforePlotNode controller methods to add some custom style to the nodes/edges.
The code would now be:
function init() {
var json= //data defined previously
//Create a new canvas instance.
var canvas = new Canvas('mycanvas', {
//Where to inject canvas. Any HTML container will do.
'injectInto':'infovis',
//Set width and height, default's to 200.
'width': 900,
'height': 500,
//Set a background color in case the browser
//does not support clearing a specific area.
'backgroundColor': '#222'
});
//Create a new ST instance
var st= new ST(canvas, {
//Set node and edge colors
//Set overridable=true to be able
//to override these properties
//individually
Node: {
overridable: true,
color: '#ccb'
},
Edge: {
overridable: true,
color: '#ccb'
},
//Add an event handler to the node when creating it.
onCreateLabel: function(label, node) {
label.id = node.id;
label.innerHTML = node.name;
label.onclick = function(){
st.onClick(node.id);
};
},
//This method is called right before plotting
//a node. It's useful for changing an individual node
//style properties before plotting it.
//The data properties prefixed with a dollar
//sign will override the global node style properties.
onBeforePlotNode: function(node) {
//add some color to the nodes in the path between the
//root node and the selected node.
if (node.selected) {
node.data.$color = "#ff7";
} else {
delete node.data.$color;
}
},
//This method is called right before plotting
//an edge. It's useful for changing an individual edge
//style properties before plotting it.
//Edge data properties prefixed with a dollar sign will
//override the Edge global style properties.
onBeforePlotLine: function(adj){
if (adj.nodeFrom.selected && adj.nodeTo.selected) {
adj.data.$color = "#eed";
adj.data.$lineWidth = 3;
}
else {
delete adj.data.$color;
delete adj.data.$lineWidth;
}
}
});
//load json data
st.loadJSON(json);
//compute node positions and layout
st.compute();
//optional: make a translation of the tree
Tree.Geometry.translate(st.tree,
new Complex(-200, 0), "startPos");
//Emulate a click on the root node.
st.onClick(st.root);
}
Customizing the Spacetree
The default layout for the spacetree is “left”. That means that the root node always lies at the left of the visualization. You can set the tree layout to “top”, “right” and “bottom” though.
For doing this we are going to add a dropdown in the html page:
<select id="switch">
<option>left</option>
<option>top</option>
<option>right</option>
<option>bottom</option>
</select>
Now lets add the change event handler at the bottom of the JS file.
//Add input handler to switch spacetree orientation.
var select = document.getElementById('switch');
select.onchange = function() {
var index = select.selectedIndex;
var or = select.options[index].text;
select.disabled = true;
st.switchPosition(or, "animate", {
onComplete: function() {
select.disabled = false;
}
});
};
Now if you change the value of the dropdown you should be able to switch the Spacetree orientation
You can also add many other configuration options and controller methods. Take a look at the documentation and the examples for this.
Hope it was helpful!