add TODO
[p5sagit/Devel-Size.git] / static / public / tm.js
1 var labelType, useGradients, nativeTextSupport, animate;
2
3 (function() {
4   var ua = navigator.userAgent,
5       iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6       typeOfCanvas = typeof HTMLCanvasElement,
7       nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8       textSupport = nativeCanvasSupport 
9         && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10   //I'm setting this based on the fact that ExCanvas provides text support for IE
11   //and that as of today iPhone/iPad current text support is lame
12   labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13   nativeTextSupport = labelType == 'Native';
14   useGradients = nativeCanvasSupport;
15   animate = !(iStuff || !nativeCanvasSupport);
16   console.log({ "labelType":labelType, "useGradients":useGradients, "nativeTextSupport":nativeTextSupport });
17 })();
18
19 var Log = {
20   elem: false,
21   write: function(text){
22     if (!this.elem) 
23       this.elem = document.getElementById('log');
24     this.elem.innerHTML = text;
25     this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
26   }
27 };
28
29 /**
30  * Convert number of bytes into human readable format
31  *
32  * @param integer bytes     Number of bytes to convert
33  * @param integer precision Number of digits after the decimal separator
34  * @return string
35  * via http://codeaid.net/javascript/convert-size-in-bytes-to-human-readable-format-(javascript)
36  */
37 function bytesToSize(bytes, precision) {
38     var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
39     var posttxt = 0;
40     while( bytes >= 1024 ) {
41         posttxt++;
42         bytes = bytes / 1024;
43     }
44     var num = (posttxt) ? Number(bytes).toFixed(precision) : bytes;
45     return num + " " + sizes[posttxt];
46 }
47
48
49 // http://stackoverflow.com/questions/5199901/how-to-sort-an-associative-array-by-its-values-in-javascript
50 function bySortedValue(obj, comparitor, callback, context) {
51     var tuples = [];
52     for (var key in obj) {
53         if (obj.hasOwnProperty(key)) {
54             tuples.push([key, obj[key]]);
55         }
56     }
57
58     tuples.sort(comparitor);
59
60     if (callback) {
61         var length = tuples.length;
62         while (length--) callback.call(context, tuples[length][0], tuples[length][1]);
63     }
64     return tuples;
65 }
66
67
68
69 function request_jit_tree(nodeId, level, depth, onComplete){
70     var params = { };//logarea: 0 };
71     jQuery.getJSON('jit_tree/'+nodeId+'/'+depth, params, onComplete);
72 }
73
74
75 function init(){
76   var levelsToShow = 2;
77   //init TreeMap
78   var tm = new $jit.TM.Squarified({
79     //where to inject the visualization
80     injectInto: 'infovis',
81     //show only one tree level
82     levelsToShow: levelsToShow,
83     //parent box title heights
84     titleHeight: 14,
85     //enable animations
86     animate: animate,
87     //box offsets
88     offset: 1,
89     //use canvas text
90     XXX_Label: {
91       type: labelType,
92       size: 10,
93       family: 'Tahoma, Verdana, Arial'
94     },
95     //enable specific canvas styles
96     //when rendering nodes
97     Node: {
98       CanvasStyles: {
99         shadowBlur: 0,
100         shadowColor: '#000'
101       }
102     },
103     //Attach left and right click events
104     Events: {
105       enable: true,
106       onClick: function(node) {
107         if(node) tm.enter(node);
108       },
109       onRightClick: function() {
110         tm.out();
111       },
112       //change node styles and canvas styles
113       //when hovering a node
114       onMouseEnter: function(node, eventInfo) {
115         if(node) {
116           //add node selected styles and replot node
117           node.setCanvasStyle('shadowBlur', 7);
118           node.setData('color', '#888');
119           tm.fx.plotNode(node, tm.canvas);
120           tm.labels.plotLabel(tm.canvas, node);
121         }
122       },
123       onMouseLeave: function(node) {
124         if(node) {
125           node.removeData('color');
126           node.removeCanvasStyle('shadowBlur');
127           tm.plot();
128         }
129       }
130     },
131     //duration of the animations
132     duration: 300,
133     //Enable tips
134     Tips: {
135       enable: true,
136       type: 'Native',
137       //add positioning offsets
138       offsetX: 20,
139       offsetY: 20,
140       //implement the onShow method to
141       //add content to the tooltip when a node
142       //is hovered
143       onShow: function(tip, node, isLeaf, domElement) {
144         var data = node.data;
145         var html = "<div class=\"tip-title\">"
146           + (data.title ? "\""+data.title+"\"" : "")
147           + " " + data.name
148           + "</div><div class=\"tip-text\">";
149
150         html += "<br />";
151         html += sprintf("Memory use: %s<br />", bytesToSize(data.self_size+data.kids_size,2));
152         if (data.kids_size) {
153             html += sprintf("Child use:  %s<br />", bytesToSize(data.kids_size,2));
154         }
155         if (data.self_size) {
156             html += sprintf("Own use:    %s<br />", bytesToSize(data.self_size,2));
157             html += sprintf("<div style=\"color:grey\">");
158             bySortedValue(data.leaves,
159                 function(a, b) { return a[1] - b[1] },
160                 function(k, v) { html += sprintf(" %9s: %s<br />", k, bytesToSize(v,2));
161             });
162             html += sprintf("</div>");
163         }
164         html += "<br />";
165
166
167     if (0) {
168         html += sprintf("Attributes:<br />");
169         bySortedValue(data.attr,
170             function(a, b) { return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0 },
171             function(k, v) { html += sprintf(" %10s: %5d<br />", k, v);
172         });
173         html += "<br />";
174     }
175
176         html += sprintf("<div style=\"color:grey\">");
177         if (data.child_count) {
178             //html += sprintf("Children: %d of %d<br />", data.child_count, data.kids_node_count);
179             html += sprintf("Children: %d<br />", data.kids_node_count);
180         }
181         html += sprintf("Id: %s%s<br />", node.id, data._ids_merged ? data._ids_merged : "");
182         html += sprintf("Depth: %d<br />", data.depth);
183         html += sprintf("Parent: %d<br />", data.parent_id);
184
185         //html += JSON.stringify(data.attr, undefined, 4);
186         //html += JSON.stringify(data, undefined, 4);
187         html += sprintf("</div>");
188
189         tip.innerHTML =  html; 
190       }  
191     },
192     //Implement this method for retrieving a requested  
193     //subtree that has as root a node with id = nodeId,  
194     //and level as depth. This method could also make a server-side  
195     //call for the requested subtree. When completed, the onComplete   
196     //callback method should be called.  
197     request: function(nodeId, level, onComplete){  
198             request_jit_tree(nodeId, level, levelsToShow, function(data) {
199                 console.log("Fetched node "+nodeId);
200                 console.log(data);
201                 onComplete.onComplete(nodeId, data);  
202             });
203             // XXX workaround jit bug where old tooltip is still shown till the
204             // mouse moves
205             jQuery("#_tooltip").fadeOut("fast");
206     },
207     //Add the name of the node in the corresponding label
208     //This method is called once, on label creation and only for DOM labels.
209     onCreateLabel: function(domElement, node){
210         domElement.innerHTML = node.name;
211
212         // this doesn't work with Label:{} above
213         var style = domElement.style;  
214         style.display = '';  
215         style.border = '1px solid transparent';  
216         domElement.onmouseover = function() {  
217             style.border = '1px solid #9FD4FF';  
218         };  
219         domElement.onmouseout = function() {  
220             style.border = '1px solid transparent';  
221         };  
222
223     },
224     onPlaceLabel: function(domElement, node){ },
225   });
226
227   request_jit_tree(1, 0, levelsToShow, function(data) {
228         console.log(data);
229         tm.loadJSON(data);
230         tm.refresh();
231     });
232
233     //add event to buttons
234     $jit.util.addEvent($jit.id('back'), 'click', function() { tm.out() });
235     $jit.util.addEvent($jit.id('logarea'), 'onchange', function() { tm.refresh() });
236
237 }
238
239