Move sizeme_graph.pl to bin and the static files into lib so they're installed.
[p5sagit/Devel-Size.git] / lib / Devel / SizeMe / Graph / static / treemap.js
CommitLineData
d3b8a135 1// based closely on http://thejit.org/static/v20/Jit/Examples/Treemap/example2.html
b2fc39a5 2var 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);
c065a0c3 17 console.log({ "labelType":labelType, "useGradients":useGradients, "nativeTextSupport":nativeTextSupport });
b2fc39a5 18})();
19
20var 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
ee6e37bf 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 */
38function 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
5ab994e6 50// http://stackoverflow.com/questions/5199901/how-to-sort-an-associative-array-by-its-values-in-javascript
51function 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
b2fc39a5 69
8f4f09eb 70function request_jit_tree(nodeId, level, depth, onComplete){
ee6e37bf 71 var params = { };//logarea: 0 };
8f4f09eb 72 jQuery.getJSON('jit_tree/'+nodeId+'/'+depth, params, onComplete);
e8f4c506 73}
74
75
b2fc39a5 76function init(){
8f4f09eb 77 var levelsToShow = 2;
b2fc39a5 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
8f4f09eb 83 levelsToShow: levelsToShow,
b2fc39a5 84 //parent box title heights
a74b795d 85 titleHeight: 14,
b2fc39a5 86 //enable animations
87 animate: animate,
88 //box offsets
89 offset: 1,
90 //use canvas text
d3b8a135 91 // XXX disabled to allow the onMouseEnter/onMouseLeave Events to fire to set the blue border
ee6e37bf 92 XXX_Label: {
b2fc39a5 93 type: labelType,
a74b795d 94 size: 10,
b2fc39a5 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
a3382177 134 duration: 300,
b2fc39a5 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) {
d3b8a135 146
147 // XXX all this needs html escaping
b2fc39a5 148 var data = node.data;
e8f4c506 149 var html = "<div class=\"tip-title\">"
ee6e37bf 150 + (data.title ? "\""+data.title+"\"" : "")
e8f4c506 151 + " " + data.name
152 + "</div><div class=\"tip-text\">";
bb66f8a1 153
5ab994e6 154 html += "<br />";
ee6e37bf 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 }
5ab994e6 159 if (data.self_size) {
c98b4b83 160 if (data.kids_size)
161 html += sprintf("Own use: %s<br />", bytesToSize(data.self_size,2));
ee6e37bf 162 html += sprintf("<div style=\"color:grey\">");
5ab994e6 163 bySortedValue(data.leaves,
164 function(a, b) { return a[1] - b[1] },
ee6e37bf 165 function(k, v) { html += sprintf(" %9s: %s<br />", k, bytesToSize(v,2));
5ab994e6 166 });
ee6e37bf 167 html += sprintf("</div>");
5ab994e6 168 }
ee6e37bf 169 html += "<br />";
5ab994e6 170
c98b4b83 171 html += sprintf("<div style=\"color:grey\">");
e8f4c506 172
c98b4b83 173 if (1) {
5ab994e6 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 />";
ee6e37bf 180 }
5ab994e6 181
bb66f8a1 182 if (data.child_count) {
bcedcc81 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);
b2fc39a5 185 }
5ab994e6 186 html += sprintf("Id: %s%s<br />", node.id, data._ids_merged ? data._ids_merged : "");
5a78486c 187 html += sprintf("Depth: %d<br />", data.depth);
188 html += sprintf("Parent: %d<br />", data.parent_id);
bb66f8a1 189
c98b4b83 190 html += JSON.stringify(data.attr, undefined, 4);
e8f4c506 191 //html += JSON.stringify(data, undefined, 4);
ee6e37bf 192 html += sprintf("</div>");
e8f4c506 193
b2fc39a5 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){
8f4f09eb 203 request_jit_tree(nodeId, level, levelsToShow, function(data) {
e8f4c506 204 console.log("Fetched node "+nodeId);
f9d8678b 205 console.log(data);
b2fc39a5 206 onComplete.onComplete(nodeId, data);
207 });
a74b795d 208 // XXX workaround jit bug where old tooltip is still shown till the
209 // mouse moves
210 jQuery("#_tooltip").fadeOut("fast");
b2fc39a5 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;
c065a0c3 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
ee6e37bf 228 },
229 onPlaceLabel: function(domElement, node){ },
b2fc39a5 230 });
e8f4c506 231
8f4f09eb 232 request_jit_tree(1, 0, levelsToShow, function(data) {
f9d8678b 233 console.log(data);
b2fc39a5 234 tm.loadJSON(data);
235 tm.refresh();
236 });
b2fc39a5 237
e8f4c506 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
b2fc39a5 242}
e8f4c506 243
244