my $depth = $self->stash('depth');
warn "jit_tree $id $depth";
my $jit_tree = _fetch_node($id, $depth, sub {
- my $node=shift; $node->{data}{'$area'} = $node->{self_size}+$node->{kids_size}
+ my ($node, $children) = @_;
+ $node->{'$area'} = $node->{self_size}+$node->{kids_size};
+ $node->{child_count} = @$children if $children;
+ my $jit_node = {
+ id => $node->{id},
+ name => $node->{name},
+ data => $node,
+ };
+ $jit_node->{children} = $children if $children;
+ return $jit_node;
});
- use Devel::Dwarn; Dwarn($jit_tree);
+if(1){
+ use Devel::Dwarn;
+ use Data::Dump qw(pp);
+ local $jit_tree->{children};
+ pp($jit_tree);
+}
$self->render_json($jit_tree);
};
sub _fetch_node {
my ($id, $depth, $transform) = @_;
my $node = MemView->selectrow_hashref("select * from node where id = ?", undef, $id);
+ my $children;
if ($depth && $node->{child_seqns}) {
my @child_seqns = split /,/, $node->{child_seqns};
- my @children = map { _fetch_node($_, $depth-1, $transform) } @child_seqns;
- $node->{children} = \@children;
+ $children = [ map { _fetch_node($_, $depth-1, $transform) } @child_seqns ];
}
- $transform->($node) if $transform;
+ $node = $transform->($node, $children) if $transform;
return $node;
}
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title>Treemap - TreeMap with on-demand nodes</title>
+<title>Perl Memory Treemap</title>
<!-- CSS Files -->
<link type="text/css" href="css/base.css" rel="stylesheet" />
<script language="javascript" type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<!-- Example File -->
-<script language="javascript" type="text/javascript" src="tmdata.js"></script>
+<script language="javascript" type="text/javascript" src="sprintf.js"></script>
<script language="javascript" type="text/javascript" src="tm.js"></script>
</head>
<div id="left-container">
-
-
<div class="text">
<h4>
-TreeMap with on-demand nodes
+Perl Memory TreeMap
</h4>
-
- This example shows how you can use the <b>request</b> controller method to create a TreeMap with on demand nodes<br /><br />
- This example makes use of native Canvas text and shadows, but can be easily adapted to use HTML like the other examples.<br /><br />
- There should be only one level shown at a time.<br /><br />
- Clicking on a band should show a new TreeMap with its most listened albums.<br /><br />
-
-</div>
-
-<div id="id-list">
-<table>
- <tr>
- <td>
- <label for="r-sq">Squarified </label>
- </td>
- <td>
- <input type="radio" id="r-sq" name="layout" checked="checked" value="left" />
- </td>
- </tr>
- <tr>
- <td>
- <label for="r-st">Strip </label>
- </td>
- <td>
- <input type="radio" id="r-st" name="layout" value="top" />
- </td>
- <tr>
- <td>
- <label for="r-sd">SliceAndDice </label>
- </td>
- <td>
- <input type="radio" id="r-sd" name="layout" value="bottom" />
- </td>
- </tr>
-</table>
+ Clicking on a node will show a new TreeMap with the contents of that node.<br /><br />
</div>
<a id="back" href="#" class="theme button white">Go to Parent</a>
-
-
-<div style="text-align:center;"><a href="example2.js">See the Example Code</a></div>
</div>
<div id="center-container">
--- /dev/null
+// from https://raw.github.com/kvz/phpjs/master/functions/strings/sprintf.js\r
+function sprintf () {\r
+ // http://kevin.vanzonneveld.net\r
+ // + original by: Ash Searle (http://hexmen.com/blog/)\r
+ // + namespaced by: Michael White (http://getsprink.com)\r
+ // + tweaked by: Jack\r
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\r
+ // + input by: Paulo Freitas\r
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\r
+ // + input by: Brett Zamir (http://brett-zamir.me)\r
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\r
+ // + improved by: Dj\r
+ // * example 1: sprintf("%01.2f", 123.1);\r
+ // * returns 1: 123.10\r
+ // * example 2: sprintf("[%10s]", 'monkey');\r
+ // * returns 2: '[ monkey]'\r
+ // * example 3: sprintf("[%'#10s]", 'monkey');\r
+ // * returns 3: '[####monkey]'\r
+ var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g;\r
+ var a = arguments,\r
+ i = 0,\r
+ format = a[i++];\r
+\r
+ // pad()\r
+ var pad = function (str, len, chr, leftJustify) {\r
+ if (!chr) {\r
+ chr = ' ';\r
+ }\r
+ var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);\r
+ return leftJustify ? str + padding : padding + str;\r
+ };\r
+\r
+ // justify()\r
+ var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {\r
+ var diff = minWidth - value.length;\r
+ if (diff > 0) {\r
+ if (leftJustify || !zeroPad) {\r
+ value = pad(value, minWidth, customPadChar, leftJustify);\r
+ } else {\r
+ value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);\r
+ }\r
+ }\r
+ return value;\r
+ };\r
+\r
+ // formatBaseX()\r
+ var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {\r
+ // Note: casts negative numbers to positive ones\r
+ var number = value >>> 0;\r
+ prefix = prefix && number && {\r
+ '2': '0b',\r
+ '8': '0',\r
+ '16': '0x'\r
+ }[base] || '';\r
+ value = prefix + pad(number.toString(base), precision || 0, '0', false);\r
+ return justify(value, prefix, leftJustify, minWidth, zeroPad);\r
+ };\r
+\r
+ // formatString()\r
+ var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {\r
+ if (precision != null) {\r
+ value = value.slice(0, precision);\r
+ }\r
+ return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);\r
+ };\r
+\r
+ // doFormat()\r
+ var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {\r
+ var number;\r
+ var prefix;\r
+ var method;\r
+ var textTransform;\r
+ var value;\r
+\r
+ if (substring == '%%') {\r
+ return '%';\r
+ }\r
+\r
+ // parse flags\r
+ var leftJustify = false,\r
+ positivePrefix = '',\r
+ zeroPad = false,\r
+ prefixBaseX = false,\r
+ customPadChar = ' ';\r
+ var flagsl = flags.length;\r
+ for (var j = 0; flags && j < flagsl; j++) {\r
+ switch (flags.charAt(j)) {\r
+ case ' ':\r
+ positivePrefix = ' ';\r
+ break;\r
+ case '+':\r
+ positivePrefix = '+';\r
+ break;\r
+ case '-':\r
+ leftJustify = true;\r
+ break;\r
+ case "'":\r
+ customPadChar = flags.charAt(j + 1);\r
+ break;\r
+ case '0':\r
+ zeroPad = true;\r
+ break;\r
+ case '#':\r
+ prefixBaseX = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ // parameters may be null, undefined, empty-string or real valued\r
+ // we want to ignore null, undefined and empty-string values\r
+ if (!minWidth) {\r
+ minWidth = 0;\r
+ } else if (minWidth == '*') {\r
+ minWidth = +a[i++];\r
+ } else if (minWidth.charAt(0) == '*') {\r
+ minWidth = +a[minWidth.slice(1, -1)];\r
+ } else {\r
+ minWidth = +minWidth;\r
+ }\r
+\r
+ // Note: undocumented perl feature:\r
+ if (minWidth < 0) {\r
+ minWidth = -minWidth;\r
+ leftJustify = true;\r
+ }\r
+\r
+ if (!isFinite(minWidth)) {\r
+ throw new Error('sprintf: (minimum-)width must be finite');\r
+ }\r
+\r
+ if (!precision) {\r
+ precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;\r
+ } else if (precision == '*') {\r
+ precision = +a[i++];\r
+ } else if (precision.charAt(0) == '*') {\r
+ precision = +a[precision.slice(1, -1)];\r
+ } else {\r
+ precision = +precision;\r
+ }\r
+\r
+ // grab value using valueIndex if required?\r
+ value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];\r
+\r
+ switch (type) {\r
+ case 's':\r
+ return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);\r
+ case 'c':\r
+ return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);\r
+ case 'b':\r
+ return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r
+ case 'o':\r
+ return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r
+ case 'x':\r
+ return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r
+ case 'X':\r
+ return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();\r
+ case 'u':\r
+ return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);\r
+ case 'i':\r
+ case 'd':\r
+ number = (+value) | 0;\r
+ prefix = number < 0 ? '-' : positivePrefix;\r
+ value = prefix + pad(String(Math.abs(number)), precision, '0', false);\r
+ return justify(value, prefix, leftJustify, minWidth, zeroPad);\r
+ case 'e':\r
+ case 'E':\r
+ case 'f': // Should handle locales (as per setlocale)\r
+ case 'F':\r
+ case 'g':\r
+ case 'G':\r
+ number = +value;\r
+ prefix = number < 0 ? '-' : positivePrefix;\r
+ method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];\r
+ textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];\r
+ value = prefix + Math.abs(number)[method](precision);\r
+ return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();\r
+ default:\r
+ return substring;\r
+ }\r
+ };\r
+\r
+ return format.replace(regex, doFormat);\r
+}\r
var html = "<div class=\"tip-title\">" + node.name
+ "</div><div class=\"tip-text\">";
var data = node.data;
- if(data.artist) {
- html += "Artist: " + data.artist + "<br />";
- }
- if(data.playcount) {
- html += "Play count: " + data.playcount;
- }
- if(data.image) {
- html += "<img src=\""+ data.image +"\" class=\"album\" />";
+
+ //"child_seqns" => 4,
+ //"depth" => 2,
+ //"id" => 3,
+ //"kids_node_count" => 4426,
+ //"kids_size" => 560058,
+ //"name" => "SV(PVHV)",
+ //"parent_seqn" => 2,
+ //"self_size" => 1080,
+
+ html += sprintf("Name: %s<br />\n", data.name);
+ html += sprintf("Size: %d (%d + %d)<br />", data.self_size+data.kids_size, data.self_size, data.kids_size);
+ if (data.child_count) {
+ html += sprintf("Children: %d of %d<br />", data.child_count, data.kids_node_count);
}
+
tip.innerHTML = html;
}
},
tm.refresh();
}
- var sq = $jit.id('r-sq'),
- st = $jit.id('r-st'),
- sd = $jit.id('r-sd');
- var util = $jit.util;
- util.addEvent(sq, 'change', function() {
- if(!sq.checked) return;
- util.extend(tm, new $jit.Layouts.TM.Squarified);
- tm.refresh();
- });
- util.addEvent(st, 'change', function() {
- if(!st.checked) return;
- util.extend(tm, new $jit.Layouts.TM.Strip);
- tm.layout.orientation = "v";
- tm.refresh();
- });
- util.addEvent(sd, 'change', function() {
- if(!sd.checked) return;
- util.extend(tm, new $jit.Layouts.TM.SliceAndDice);
- tm.layout.orientation = "v";
- tm.refresh();
- });
//add event to the back button
var back = $jit.id('back');
$jit.util.addEvent(back, 'click', function() {