Hypertree quick tutorial

This tutorial requires you to have read Feeding JSON tree structures to the JIT and on controllers first.

Hi, this is going to be a quick tutorial on how to set the hyperbolic tree up and running.

We are going to work with this tree JSON structure:

var json = {"id":"node02",
"name":"0.2",
"data":[
{"key":"key1",
"value":9},
{"key":"key2",
"value":71}],
"children":[
{"id":"node13",
"name":"1.3",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":-9}],
"children":[
{"id":"node24",
"name":"2.4",
"data":[
{"key":"key1",
"value":3},
{"key":"key2",
"value":-42}],
"children":[]},
{"id":"node25",
"name":"2.5",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":59}],
"children":[]},
{"id":"node26",
"name":"2.6",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":-50}],
"children":[]},
{"id":"node27",
"name":"2.7",
"data":[
{"key":"key1",
"value":3},
{"key":"key2",
"value":-78}],
"children":[]}]},
{"id":"node18",
"name":"1.8",
"data":[
{"key":"key1",
"value":1},
{"key":"key2",
"value":79}],
"children":[
{"id":"node29",
"name":"2.9",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":77}],
"children":[]},
{"id":"node210",
"name":"2.10",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":30}],
"children":[]},
{"id":"node211",
"name":"2.11",
"data":[
{"key":"key1",
"value":3},
{"key":"key2",
"value":-44}],
"children":[]}]},
{"id":"node112",
"name":"1.12",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":94}],
"children":[
{"id":"node213",
"name":"2.13",
"data":[
{"key":"key1",
"value":3},
{"key":"key2",
"value":99}],
"children":[]},
{"id":"node214",
"name":"2.14",
"data":[
{"key":"key1",
"value":4},
{"key":"key2",
"value":-72}],
"children":[]},
{"id":"node215",
"name":"2.15",
"data":[
{"key":"key1",
"value":10},
{"key":"key2",
"value":17}],
"children":[]},
{"id":"node216",
"name":"2.16",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":53}],
"children":[]},
{"id":"node217",
"name":"2.17",
"data":[
{"key":"key1",
"value":4},
{"key":"key2",
"value":-96}],
"children":[]},
{"id":"node218",
"name":"2.18",
"data":[
{"key":"key1",
"value":10},
{"key":"key2",
"value":-84}],
"children":[]},
{"id":"node219",
"name":"2.19",
"data":[
{"key":"key1",
"value":9},
{"key":"key2",
"value":-4}],
"children":[]},
{"id":"node220",
"name":"2.20",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":66}],
"children":[]}]},
{"id":"node121",
"name":"1.21",
"data":[
{"key":"key1",
"value":10},
{"key":"key2",
"value":0}],
"children":[
{"id":"node222",
"name":"2.22",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":66}],
"children":[]},
{"id":"node223",
"name":"2.23",
"data":[
{"key":"key1",
"value":10},
{"key":"key2",
"value":-78}],
"children":[]},
{"id":"node224",
"name":"2.24",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":-91}],
"children":[]},
{"id":"node225",
"name":"2.25",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":-51}],
"children":[]},
{"id":"node226",
"name":"2.26",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":25}],
"children":[]},
{"id":"node227",
"name":"2.27",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":30}],
"children":[]},
{"id":"node228",
"name":"2.28",
"data":[
{"key":"key1",
"value":3},
{"key":"key2",
"value":-43}],
"children":[]}]},
{"id":"node129",
"name":"1.29",
"data":[
{"key":"key1",
"value":3},
{"key":"key2",
"value":-89}],
"children":[
{"id":"node230",
"name":"2.30",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":96}],
"children":[]},
{"id":"node231",
"name":"2.31",
"data":[
{"key":"key1",
"value":1},
{"key":"key2",
"value":-21}],
"children":[]},
{"id":"node232",
"name":"2.32",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":17}],
"children":[]},
{"id":"node233",
"name":"2.33",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":42}],
"children":[]}]},
{"id":"node134",
"name":"1.34",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":84}],
"children":[
{"id":"node235",
"name":"2.35",
"data":[
{"key":"key1",
"value":9},
{"key":"key2",
"value":-14}],
"children":[]},
{"id":"node236",
"name":"2.36",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":60}],
"children":[]},
{"id":"node237",
"name":"2.37",
"data":[
{"key":"key1",
"value":1},
{"key":"key2",
"value":-71}],
"children":[]}]},
{"id":"node138",
"name":"1.38",
"data":[
{"key":"key1",
"value":9},
{"key":"key2",
"value":-70}],
"children":[
{"id":"node239",
"name":"2.39",
"data":[
{"key":"key1",
"value":10},
{"key":"key2",
"value":-69}],
"children":[]},
{"id":"node240",
"name":"2.40",
"data":[
{"key":"key1",
"value":4},
{"key":"key2",
"value":-31}],
"children":[]},
{"id":"node241",
"name":"2.41",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":-5}],
"children":[]},
{"id":"node242",
"name":"2.42",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":62}],
"children":[]},
{"id":"node243",
"name":"2.43",
"data":[
{"key":"key1",
"value":9},
{"key":"key2",
"value":91}],
"children":[]}]},
{"id":"node144",
"name":"1.44",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":10}],
"children":[
{"id":"node245",
"name":"2.45",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":-2}],
"children":[]},
{"id":"node246",
"name":"2.46",
"data":[
{"key":"key1",
"value":1},
{"key":"key2",
"value":93}],
"children":[]},
{"id":"node247",
"name":"2.47",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":70}],
"children":[]},
{"id":"node248",
"name":"2.48",
"data":[
{"key":"key1",
"value":4},
{"key":"key2",
"value":-40}],
"children":[]}]},
{"id":"node149",
"name":"1.49",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":-58}],
"children":[
{"id":"node250",
"name":"2.50",
"data":[
{"key":"key1",
"value":4},
{"key":"key2",
"value":-41}],
"children":[]},
{"id":"node251",
"name":"2.51",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":-91}],
"children":[]},
{"id":"node252",
"name":"2.52",
"data":[
{"key":"key1",
"value":5},
{"key":"key2",
"value":-21}],
"children":[]},
{"id":"node253",
"name":"2.53",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":-69}],
"children":[]},
{"id":"node254",
"name":"2.54",
"data":[
{"key":"key1",
"value":10},
{"key":"key2",
"value":5}],
"children":[]},
{"id":"node255",
"name":"2.55",
"data":[
{"key":"key1",
"value":5},
{"key":"key2",
"value":-43}],
"children":[]},
{"id":"node256",
"name":"2.56",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":64}],
"children":[]},
{"id":"node257",
"name":"2.57",
"data":[
{"key":"key1",
"value":10},
{"key":"key2",
"value":-60}],
"children":[]}]},
{"id":"node158",
"name":"1.58",
"data":[
{"key":"key1",
"value":7},
{"key":"key2",
"value":-63}],
"children":[
{"id":"node259",
"name":"2.59",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":86}],
"children":[]},
{"id":"node260",
"name":"2.60",
"data":[
{"key":"key1",
"value":4},
{"key":"key2",
"value":13}],
"children":[]},
{"id":"node261",
"name":"2.61",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":-70}],
"children":[]},
{"id":"node262",
"name":"2.62",
"data":[
{"key":"key1",
"value":5},
{"key":"key2",
"value":-83}],
"children":[]},
{"id":"node263",
"name":"2.63",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":-98}],
"children":[]},
{"id":"node264",
"name":"2.64",
"data":[
{"key":"key1",
"value":2},
{"key":"key2",
"value":-79}],
"children":[]},
{"id":"node265",
"name":"2.65",
"data":[
{"key":"key1",
"value":9},
{"key":"key2",
"value":10}],
"children":[]},
{"id":"node266",
"name":"2.66",
"data":[
{"key":"key1",
"value":6},
{"key":"key2",
"value":17}],
"children":[]},
{"id":"node267",
"name":"2.67",
"data":[
{"key":"key1",
"value":8},
{"key":"key2",
"value":26}],
"children":[]}]}]};

Put this HTML in your page:

<html>
<head>

<link type="text/css" rel="stylesheet" href="/static/css/example-hypertree.css" />

<!--[if IE]>
<script type="text/javascript" src="/static/js/excanvas.js"></script>
<![endif]-->

<script type="text/javascript" src="/static/js/hypertree/Hypertree.js" ></script>
<script type="text/javascript" src="/static/js/example/example-hypertree.js" ></script>

</head>
<body onload="init();">

<canvas id="infovis" width="900" height="500"></canvas>
<div id="label_container"></div>

</body>
</html>

Note: You’ll probably have to change the paths to the css and javascript files.

Now, create a hypertree-example.css and put this code in it:

html, body {
width:100%;
height:100%;
background-color:#444;
text-align:center;
overflow:hidden;
font-size:10px;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;

}

#infovis {
background-color:#222;
width:900px;
height:500px;
}

.node {
border: 1px solid #555;
background-color: #ccc;
color:#222;
cursor:pointer;
padding:2px;
display:none;
}

.hidden {
display:none;
}

Note: I like the canvas black, just like my coffee.

Finally, create an example-hypertree.js file and put this code in it:

function init() {

var json = //the json structure mentioned above...
//Create a new canvas instance.
var canvas= new Canvas('infovis', '#fff', '#fff');
//create a new hypertree instance.
var ht= new Hypertree(canvas);
//feed the hypertree with a JSON structure.
ht.loadTreeFromJSON(json);
//compute node positions
ht.compute();
//plot the hypertree on canvas
ht.plot();
//add event handlers to the canvas in order to move the hypertree when I click con the canvas -optional-
ht.prepareCanvasEvents();
}

You should see a hypertree up and running (it may take a few seconds to load).

Some notes:

  • It’s mandatory to put the width and height properties on the canvas html tag.
    You could set those properties dynamically, of course, but what I mean is that setting only width and height style properties (as with CSS) isn’t enough.
  • You could change the label container id by setting the Config.labelContainer property to whatever id you like. Be sure to set that property before making a Canvas instance.
  • The Canvas constructor takes 3 parameters: the canvas id, the fillStyle property and the strokeStyle property. If you don’t know what those properties are, take a look at this section from the canvas tutorial.
  • It’s not mandatory to add the ht.prepareCanvasEvents(); method. This method just adds some event handlers to the canvas tag in order to move the tree when you click on the canvas.
  • You can take off the main circle by setting Config.drawMainCircle to false. Just be sure you do that before making a canvas or Hypertree instance.

Customizing the Hypertree

Let’s add some labels!
Note: I’ll be using the Mootools library to do this, just because I don’t want to spend time writing low level code that would make the code uglier. You can use any library you want (or none at all) though.

First, strip off the display:none; line from the .node class in your CSS file.
It should look like this:

.node {
border: 1px solid #555;
background-color: #ccc;
color:#222;
cursor:pointer;
padding:2px;
}

Now we are going to add a javascript controller in order to put the name of the nodes into the labels. Since we only need to do this once, we’ll use the onCreateLabel method. If you don’t know what I’m talking about you should probably read the on controllers post first.

So the JavaScript file should look like this now:

function init() {
	var json = //json data mentioned above...
	var canvas= new Canvas('infovis', '#fff', '#fff');
	var ht= new Hypertree(canvas, {
		onCreateLabel: function(domElement, node) {
		$(domElement).set('html', node.name + " and text");
		}
	});

	ht.loadTreeFromJSON(json);
	ht.compute();
	ht.plot();
	ht.prepareCanvasEvents();
}

You should see some labels now.
The thing is that… well, they are not centered. So we’ll just add an onPlaceLabel method to the controller in order to do that, since the onPlaceLabel method is called after labels have been placed.

So the js code should now look like:

function init() {
	var json = //json data...
	var canvas= new Canvas('infovis', '#fff', '#fff');
	var ht= new Hypertree(canvas, {
		onCreateLabel: function(domElement, node) {
		$(domElement).set('html', node.name + " and text");
		},

		//Take the left style property and
		// substract half of the label actual width.
		onPlaceLabel: function(tag, node) {
		var width = tag.offsetWidth;
		var intX = tag.style.left.toInt();
		intX -= width/2;
		tag.style.left = intX + 'px';
		}

	});

	ht.loadTreeFromJSON(json);
	ht.compute();
	ht.plot();
	ht.prepareCanvasEvents();
}

You should see some centered labels now!

Finally, we’ll add an onclick event handler in order to move the tree when clicking on a label, hows that!

We’ll add this method on the onCreateLabel method, just because we only want to add label event handlers once.
So the code should look like:

function init() {
	var json = //some json data
	var canvas= new Canvas('infovis', '#fff', '#fff');
	var ht= new Hypertree(canvas, {
		onCreateLabel: function(domElement, node) {
			$(domElement).set('html', node.name + " and text").addEvents({
					//Call the "onclick" method from
					//the hypertree to move the hypertree
					//correspondingly.
					//This method takes the native event object.
					//Since Mootools uses a wrapper for this
					//event, I have to put e.event to get the
					//native event object.
					'click': function(e) {
					ht.onClick(e.event);
					}
				});

		},

		//Take the left style property and
		//substract half of the label actual width.
		onPlaceLabel: function(tag, node) {
			var width = tag.offsetWidth;
			var intX = tag.style.left.toInt();
			intX -= width/2;
			tag.style.left = intX + 'px';
		}

	});

	ht.loadTreeFromJSON(json);
	ht.compute();
	ht.plot();
	ht.prepareCanvasEvents();
}

Remember that you have more controller methods!
Remember also that you can change the animation time and the frames per second in the animation with Config.animationTime and Config.fps.
Hope it was helpful.

0 Responses to “Hypertree quick tutorial”


Comments are currently closed.