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