1 // based closely on http://thejit.org/static/v20/Jit/Examples/Treemap/example2.html
2 var labelType, useGradients, nativeTextSupport, animate;
5 var ua = navigator.userAgent,
6 iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
7 typeOfCanvas = typeof HTMLCanvasElement,
8 nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
9 textSupport = nativeCanvasSupport
10 && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
11 //I'm setting this based on the fact that ExCanvas provides text support for IE
12 //and that as of today iPhone/iPad current text support is lame
13 labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
14 nativeTextSupport = labelType == 'Native';
15 useGradients = nativeCanvasSupport;
16 animate = !(iStuff || !nativeCanvasSupport);
17 console.log({ "labelType":labelType, "useGradients":useGradients, "nativeTextSupport":nativeTextSupport });
22 write: function(text){
24 this.elem = document.getElementById('log');
25 this.elem.innerHTML = text;
26 this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
31 * Convert number of bytes into human readable format
33 * @param integer bytes Number of bytes to convert
34 * @param integer precision Number of digits after the decimal separator
36 * via http://codeaid.net/javascript/convert-size-in-bytes-to-human-readable-format-(javascript)
38 function bytesToSize(bytes, precision) {
39 var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
41 while( bytes >= 1024 ) {
45 var num = (posttxt) ? Number(bytes).toFixed(precision) : bytes;
46 return num + " " + sizes[posttxt];
50 // http://stackoverflow.com/questions/5199901/how-to-sort-an-associative-array-by-its-values-in-javascript
51 function bySortedValue(obj, comparitor, callback, context) {
53 for (var key in obj) {
54 if (obj.hasOwnProperty(key)) {
55 tuples.push([key, obj[key]]);
59 tuples.sort(comparitor);
62 var length = tuples.length;
63 while (length--) callback.call(context, tuples[length][0], tuples[length][1]);
70 function request_jit_tree(nodeId, level, depth, onComplete){
71 var params = { };//logarea: 0 };
72 jQuery.getJSON('jit_tree/'+nodeId+'/'+depth, params, onComplete);
79 var tm = new $jit.TM.Squarified({
80 //where to inject the visualization
81 injectInto: 'infovis',
82 //show only one tree level
83 levelsToShow: levelsToShow,
84 //parent box title heights
91 // XXX disabled to allow the onMouseEnter/onMouseLeave Events to fire to set the blue border
95 family: 'Tahoma, Verdana, Arial'
97 //enable specific canvas styles
98 //when rendering nodes
105 //Attach left and right click events
108 onClick: function(node) {
109 if(node) tm.enter(node);
111 onRightClick: function() {
114 //change node styles and canvas styles
115 //when hovering a node
116 onMouseEnter: function(node, eventInfo) {
118 //add node selected styles and replot node
119 node.setCanvasStyle('shadowBlur', 7);
120 node.setData('color', '#888');
121 tm.fx.plotNode(node, tm.canvas);
122 tm.labels.plotLabel(tm.canvas, node);
125 onMouseLeave: function(node) {
127 node.removeData('color');
128 node.removeCanvasStyle('shadowBlur');
133 //duration of the animations
139 //add positioning offsets
142 //implement the onShow method to
143 //add content to the tooltip when a node
145 onShow: function(tip, node, isLeaf, domElement) {
147 // XXX all this needs html escaping
148 var data = node.data;
149 var html = "<div class=\"tip-title\">"
150 + (data.title ? "\""+data.title+"\"" : "")
152 + "</div><div class=\"tip-text\">";
155 html += sprintf("Memory use: %s<br />", bytesToSize(data.self_size+data.kids_size,2));
156 if (data.kids_size) {
157 html += sprintf("Child use: %s<br />", bytesToSize(data.kids_size,2));
159 if (data.self_size) {
160 html += sprintf("Own use: %s<br />", bytesToSize(data.self_size,2));
161 html += sprintf("<div style=\"color:grey\">");
162 bySortedValue(data.leaves,
163 function(a, b) { return a[1] - b[1] },
164 function(k, v) { html += sprintf(" %9s: %s<br />", k, bytesToSize(v,2));
166 html += sprintf("</div>");
172 html += sprintf("Attributes:<br />");
173 bySortedValue(data.attr,
174 function(a, b) { return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0 },
175 function(k, v) { html += sprintf(" %10s: %5d<br />", k, v);
180 html += sprintf("<div style=\"color:grey\">");
181 if (data.child_count) {
182 //html += sprintf("Children: %d of %d<br />", data.child_count, data.kids_node_count);
183 html += sprintf("Children: %d<br />", data.kids_node_count);
185 html += sprintf("Id: %s%s<br />", node.id, data._ids_merged ? data._ids_merged : "");
186 html += sprintf("Depth: %d<br />", data.depth);
187 html += sprintf("Parent: %d<br />", data.parent_id);
189 //html += JSON.stringify(data.attr, undefined, 4);
190 //html += JSON.stringify(data, undefined, 4);
191 html += sprintf("</div>");
193 tip.innerHTML = html;
196 //Implement this method for retrieving a requested
197 //subtree that has as root a node with id = nodeId,
198 //and level as depth. This method could also make a server-side
199 //call for the requested subtree. When completed, the onComplete
200 //callback method should be called.
201 request: function(nodeId, level, onComplete){
202 request_jit_tree(nodeId, level, levelsToShow, function(data) {
203 console.log("Fetched node "+nodeId);
205 onComplete.onComplete(nodeId, data);
207 // XXX workaround jit bug where old tooltip is still shown till the
209 jQuery("#_tooltip").fadeOut("fast");
211 //Add the name of the node in the corresponding label
212 //This method is called once, on label creation and only for DOM labels.
213 onCreateLabel: function(domElement, node){
214 domElement.innerHTML = node.name;
216 // this doesn't work with Label:{} above
217 var style = domElement.style;
219 style.border = '1px solid transparent';
220 domElement.onmouseover = function() {
221 style.border = '1px solid #9FD4FF';
223 domElement.onmouseout = function() {
224 style.border = '1px solid transparent';
228 onPlaceLabel: function(domElement, node){ },
231 request_jit_tree(1, 0, levelsToShow, function(data) {
237 //add event to buttons
238 $jit.util.addEvent($jit.id('back'), 'click', function() { tm.out() });
239 $jit.util.addEvent($jit.id('logarea'), 'onchange', function() { tm.refresh() });