Hypertree quick tutorial

Posted in: javascript infovis toolkit , visualization , tutorial
This tutorial requires you to have read Feeding JSON tree structures to the JIT and on controllers first. **Note:** I'll be using Mootools for this tutorial. However, this visualization can be used without the Mootools library. You can find a Mootools build in the extras folder of the library. 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/blog/css" rel="stylesheet" href="/static/blog/css/example-hypertree.css" />

<!--[if IE]>
<script type="text/javascript" src="/static/js/excanvas.js"></script>
<![endif]-->
<script type="text/javascript" src="/static/js/mootools-1.2.js" ></script>
<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();">
<div id="infovis"></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('mycanvas', {
    //Where to inject the canvas. Any HTML container will do.
    'injectInto':'infovis',
    //Width and height of canvas, default's to 200.
    'width': 900,
    'height':500,
    //Canvas styles.
    'styles': {
        'fillStyle': '#ddd',
        'strokeStyle': '#dd00bb'
    }
  });
//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();
}
You should see a hypertree up and running (don't worry if it doesn't move, we'll add click events later).

Some notes:

Customizing the Hypertree

Let's add some labels! 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...
  //Create a new canvas instance.
  var canvas = new Canvas('mycanvas', {
    //Where to inject the canvas. Any HTML container will do.
    'injectInto':'infovis',
    //Width and height of canvas, default's to 200.
    'width': 900,
    'height':500,
    //Canvas styles.
    'styles': {
        'fillStyle': '#ddd',
        'strokeStyle': '#dd00bb'
    }
  });
  var ht= new Hypertree(canvas, {

    onCreateLabel: function(domElement, node) {
      $(domElement).set('html', node.name + " and text");
    }

  });
  
  ht.loadTreeFromJSON(json);
  ht.compute();
  ht.plot();
}
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...
  //Create a new canvas instance.
  var canvas = new Canvas('mycanvas', {
    //Where to inject the canvas. Any HTML container will do.
    'injectInto':'infovis',
    //Width and height of canvas, default's to 200.
    'width': 900,
    'height':500,
    //Canvas styles.
    'styles': {
        'fillStyle': '#ddd',
        'strokeStyle': '#dd00bb'
    }
  });
  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();
}
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
  //Create a new canvas instance.
  var canvas = new Canvas('mycanvas', {
    //Where to inject the canvas. Any HTML container will do.
    'injectInto':'infovis',
    //Width and height of canvas, default's to 200.
    'width': 900,
    'height':500,
    //Canvas styles.
    'styles': {
        'fillStyle': '#ddd',
        'strokeStyle': '#dd00bb'
    }
  });
  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 clicked node's id.
          'click': function(e) {
          ht.onClick(node.id);
          }
        });
    
    },
    
    //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();
}
If you want to see more advanced examples please check the "examples" folder in the library. 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.
Comments
blog comments powered by Disqus