Author: tim.bunce
Date: Thu May 7 16:34:59 2009
New Revision: 744
Added:
trunk/lib/Devel/NYTProf/js/uk.org.zowie.Treemap-0.9.js
Modified:
trunk/bin/nytprofhtml
Log:
Yet another take on treemaps. This time using js-treemap.
(Still very rough)
Modified: trunk/bin/nytprofhtml
==============================================================================
--- trunk/bin/nytprofhtml (original)
+++ trunk/bin/nytprofhtml Thu May 7 16:34:59 2009
@@ -663,89 +663,115 @@
or croak "Unable to open file $opt{out}/$filename: $!";
my $treemap_head = q{
- <link type="text/css" rel="stylesheet" href="jit/infovis.css" />
- <link type="text/css" rel="stylesheet" href="jit/treemap.css" />
- <script type="text/javascript" src="jit/mootools-1.2.js"></script>
- <script type="text/javascript" src="jit/Treemap.js" ></script>
+ <script type="text/javascript"
src="js/uk.org.zowie.Treemap-0.9.js" ></script>
};
print OUT get_html_header("Package Treemap - NYTProf", {
skip_style => 1,
skip_jquery => 1,
head_epilogue => $treemap_head,
+ not_xhtml => 1, # XXX js-treemap doesn't worth with xhtml at the
moment
});
print OUT get_page_header(
profile => $profile,
title => "Performance Profile Subroutine Index",
body_onload => "init();"
) if 0;
- print OUT qq{<body onload="init();">};
+ print OUT qq{<body onload="createGUI();">};
local $Data::Dumper::Sortkeys = 1;
local $Data::Dumper::Indent = 1;
local $Data::Dumper::Maxdepth = 3;
warn Data::Dumper::Dumper($profile->package_subinfo_map(1,1));
my $package_tree_subinfo_map = $profile->package_subinfo_map(1,1);
- use JSON::Any;
# { "id":"node02", "name":"0.2", "data":[
{"key":"key1", "value":195}, {"key":"key2", "value":5}], "children":[ ... ]
}
- my $node = 1;
my $node_mapper;
$node_mapper = sub {
- my ($k, $v, $title) = @_;
+ my ($k, $v, $path, $depth) = @_;
# { main => { '' => [...] } }
# { Foo => { '' => [...], '::Bar' => { ''=>[...], '::Baz'=>[...] }
} }
- warn "pkgtree2treemapnode: $title\n";
- my $n = { id => "n".++$node };
+ my $pad = "\t" x $depth;
+ #if (ref $v eq 'HASH' and keys %$v == 1 and $v->{''}) { $v =
$v->{''}; }
+
+ my $title = @$path ? '::'.$path->[-1] : $k || 'main';
if (ref $v eq 'ARRAY') { # leaf node
- $n->{name} = "subs";
- $n->{data} = [ { key=>"key1", value=>$v->[0]->excl_time } ],
- $n->{children} = [];
- }
- else {
- $title = ($title) ? '::'.$k : $k;
- my @kids = map { $node_mapper->($_, $v->{$_}, $title) }
keys %$v;
- $n->{name} = "$title";
- $n->{children} = \...@kids;
- $n->{data} = [ { key=>"key1", value=>sum(map {
$_->{data}[0]{value} } @kids) } ];
+ return sprintf qq{%snew TreeNode( "%s", %s )},
+ $pad, "subs", $v->[0]->excl_time;
}
-
- return $n;
+ my @kids = map { $node_mapper->($_, $v->{$_}, [ @$path, $_ ],
$depth+1) } keys %$v;
+ return sprintf qq{%snew TreeParentNode( "%s", [\n%s\n%s] )},
+ $pad, $title, join(",\n", @kids), $pad;
};
- my $ary = $node_mapper->('', $package_tree_subinfo_map, '');
- $ary->{name} = "Treemap of time spent in package hierarchy of
$profile->{attribute}{application}";
- my $json = JSON::Any->new->objToJson($ary);
+ my $nodes = $node_mapper->('', $package_tree_subinfo_map, [], 0);
+ warn $nodes;
print OUT qq{
- <script type="text/javascript" >
- var treemap;
- function init() {
- var json = $json;
- treemap = new TM.Squarified();
- treemap.loadFromJSON(json);
- }
- </script>
+<script type="text/javascript">
+
+function createGUI()
+{
+ // Load the XML from the server
+ var filename = "js/treeNodes.json";
+
+ var request = createAjaxRequest();
+ request.onreadystatechange = function () {
+ if( request.readyState != 4 )
+ return;
+ if( 0 != request.status && request.status != 200 ) {
+ alert("Cannot GET '" + filename + "' (" + request.status
+ ")");
+ return;
+ }
+
+ // Evaluate the JSON
+ var rootNode = $nodes;
+
+ // Render the DIV treemap
+ var mapDIV = document.getElementById( "myDiv" );
+ var map = new DivTreeMap( mapDIV, rootNode, {
+ shader: new TreeNodeShader( rootNode )
+ } );
+
+ // Set up surrounding GUI controls
+ var infoBox = document.getElementById( "infoBox" );
+ var backButton = document.getElementById( "backButton" );
+ backButton.disabled = true;
+
+ map.onMouseOver = function( node ) { infoBox.innerHTML =
node.toString(); };
+ map.onMouseOut = function( node ) { infoBox.innerHTML = ""; };
+ map.onZoomClick = function( node ) { map.zoom();
backButton.disabled = false; }
+ backButton.onclick = function() { backButton.disabled = ( 0 ===
map.unzoom() ); };
+
+ // Define & plug in a resize hook
+ window.onresize = function() { map.checkResize(); };
+ map.checkResize();
+ };
+ request.open( 'GET', filename, true );
+ request.send( null );
+}
+
+function attrToString( attr )
+{
+ return attr.nodeName + "=" + attr.nodeValue;
+}
+</script>
};
my $pkg_html;
$pkg_html .= qq{
- <div id="infovis" /> </div>
- <div id="left">
- <div id="details" class="toggler left-item">Details</div>
- <div class="element contained-item">
- <div class="inner" id="inner-details">
- <input id="opera_right_button" value="go to parent"
type="button" onclick="treemap.out()" />
- </div>
- </div>
- </div>
+<div class="divBox" style="position: relative; width: 100%; margin-top:
3px">
+ <button style="right: 0px;" id="backButton">Back</button>
+ <span id="infoBox"></span>
+</div>
+<div class="divBox" id="myDiv" style="height: 80%; width: 100%;
background: #7777AA"></div>
};
print OUT $pkg_html;
#push @on_ready_js, qq{ };
my $footer = ""; # get_footer($profile);
- print OUT "</div>$footer</body></html>";
+ print OUT "$footer</body></html>";
close OUT;
}
@@ -753,15 +779,25 @@
sub output_js_files {
my ($profile) = @_;
# find the js, gif, css etc files installed with Devel::NYTProf
- # XXX hackish, needs a rewrite
- (my $lib = $INC{"Devel/NYTProf/Data.pm"}) =~ s/Data\.pm$//;
- mkdir "$opt{out}/jit";
- for my $src (<$lib/js/*>, <$lib/js/jit/*>) {
- next unless -f $src;
- (my $file = $src) =~ s{.*/js/}{};
- unlink "$opt{out}/$file";
- copy($src, "$opt{out}/$file")
- or warn "Unable to copy $src to $opt{out}/$file: $!";
+ (my $lib = $INC{"Devel/NYTProf/Data.pm"}) =~ s/\/Data\.pm$//;
+ _copy_dir("$lib/js", "$opt{out}/js");
+}
+
+sub _copy_dir {
+ my ($srcdir, $dstdir) = @_;
+ mkdir $dstdir or die "Can't create $dstdir directory: $!\n"
+ unless -d $dstdir;
+ for my $src (glob("$srcdir/*")) {
+ (my $name = $src) =~ s{.*/}{};
+ next if $name =~ m/^\./; # skip . and .. etc
+ my $dstname = "$dstdir/$name";
+ if (not -f $src) {
+ _copy_dir($src, $dstname) if -d $src; # recurse
+ next; # skip non-ordinary-files
+ }
+ unlink $dstname;
+ copy($src, $dstname)
+ or warn "Unable to copy $src to $dstname: $!";
}
}
@@ -1078,10 +1114,11 @@
my $opts = shift || {};
my $html = <<EOD;
-<!DOCTYPE html
- PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml">
+EOD
+ $html = "<html>" if $opts->{not_xhtml};
+ $html .= <<EOD;
<!--
This file was generated by Devel::NYTProf version
$Devel::NYTProf::Core::VERSION
-->
@@ -1095,9 +1132,9 @@
unless $opts->{skip_style};
$html .= <<EOD unless $opts->{skip_jquery};
- <script type="text/javascript" src="jquery-min.js"></script>
+ <script type="text/javascript" src="js/jquery-min.js"></script>
- <script type="text/javascript"
src="jquery-tablesorter-min.js"></script>
+ <script type="text/javascript"
src="js/jquery-tablesorter-min.js"></script>
<link rel="stylesheet" type="text/css"
href="style-tablesorter.css"></link>
<script type="text/javascript">
// when a column is first clicked on to sort it, use descending order
Added: trunk/lib/Devel/NYTProf/js/uk.org.zowie.Treemap-0.9.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/uk.org.zowie.Treemap-0.9.js Thu May 7
16:34:59 2009
@@ -0,0 +1,2 @@
+eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]|
|
e(c);k=[function(e){return
d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new
RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('7
1y(g,1O,1f,1P){6.g=g;6.3a=o.2P(g);6.1O=1O;6.1f=1f;6.1P=1P;6.37=T.1Q(1P/1f);6.1J=6.1K=F}1y.9.2R=7(){d(6.1K!==F){6.1K()}6.g.n.4f=10;6.2n(1)};1y.9.38=7(14){d(14>6.1f){d(6.1J!==F)6.1J()}N{c
39=6.3a.2N(6.1O,14/6.1f);39.29(6.g);14++;6.2n(14)}};1y.9.2n=7(14){c
Q=6;1V.34(7(){Q.38(14)},Q.37)};7
2m(1N){6.1N=1N}2m.9.2k=7(g,36){g.4e=6.1N};7 1M(){}1M.9=m
2m();1M.9.2k=7(g,36){c n=g.n;n.4d="4c";n.4b="4a"};7
z(r,35,13){G.2B(6,("w"1b 13)?13.w:m
W());6.r=r;6.L=6.1Y=35;6.1c={h:0,k:0};6.11=F;6.2U=10;6.2T=49;6.12=("12"1b
13)?13.12:F;6.1A=("1A"1b 13)?13.1A:m 1M();6.1w=m
1C();6.r.n.2j="48";6.1d()}z.9=m G();z.2i=5;z.9.47=7(L,1z,v){c
33=6.r.n.1x;6.r.n.1x="2S";6.2c();c Q=6;1V.34(7(){Q.1d()},46);6.1L(6.L,m
o(0,0,6.r.1G,6.r.1v));6.r.n.1x=33};z.9.1d=7(){6.2c();6.1L(6.L,m
o(0,0,6.r.1G,6.r.1v))};z.9.1L=7(L,1z,v){d(1n.j!=3)v=6.w.1i(L);c
2l=6.2L(L,1z);K(c i=0,l=2l.j;i<l;i++){c D=2l[i];c I=D.1u();c
A=32.31("g");A.n.2j="30";I.29(A);d(6.1A)6.1A.2k(A,D);d(6.12)A.n.45=6.12.1S(v);A.e=D.P();6.r.2Z(A);c
2h=!D.1j();c
B=32.31(2h?"a":"g");B.n.2j="30";B.n.O=I.x+"Z";B.n.1m=I.y+"Z";B.n.44=z.2i+"Z";B.43=D.1k();d(6.12)B.n.42=6.12.1R(v);6.r.2Z(B);d(B.1G+z.2i>I.h|
|
B.1v>I.k){6.r.2b(A);6.r.2b(B);41}d(2h){B.2f=6.1e("40",D.P(),A,2e);B.3Z="#";c
2g=D.1u().2M(B.1v);d(2g!==F)6.1L(D.P(),2g,v+1)}N{B.2f=6.1e("2Y",D.P(),A,2e)}c
3Y=D.P();A.2f=6.1e("2Y",D.P(),A,2e);A.3X=6.1e("3W",D.P(),A,2X);A.3V=6.1e("3U",D.P(),A,2X)}6.1c={h:1z.h,k:1z.k}};z.9.1e=7(2d,e,p,2W){c
Q=6;8 7(){d(2W)Q.1F(e,p);d(2d 1b Q)Q[2d](e)}};z.9.2V=7(){d(!("11"1b
6))3T"3S 11 28 2V 3R";c 1I=6;c 11=6.2a();c 1H=m
1y(11.g,6.1u(),6.2U,6.2T);1H.1K=7(){1I.r.n.1x="2S"};1H.1J=7(){1I.2Q();1I.r.n.1x="3Q"};1H.2R()};z.9.2Q=7(){6.1w.1T(6.L);6.L=6.2a().e;6.1d();6.1F()};z.9.3P=7(){d(6.1w.j===0)8
0;6.L=6.1w.3O();6.1d();6.1F();8
6.1w.j};z.9.3N=7(h,k){d(6.1c.h==6.r.1G&&6.1c.k==6.r.1v)8;6.1d()};z.9.2c=7(){c
s=6.r.S;K(c i=s.j-1;i>=0;i--)6.r.2b(s[i])};z.9.1u=7(){8 m
o(0,0,6.1c.h,6.1c.k)};z.9.2a=7(){8
6.11};z.9.1F=7(e,g){6.11=(1n.j===0)?F:{e:e,g:g}};7
C(w,e){6.w=w;6.e=e;6.I=F}C.2K=7(w,e){c s=w.1l(e);c f=m 1C(s.j);K(c
i=0,l=f.j;i<l;i++)f[i]=m C(w,s[i]);8 f};C.9.21=7(){8 6.I+"
e: "+6.e};C.2J=7(a,b){8 b.E()-a.E()};C.9.E=7(){d("H"1b 6)8 6.H;8
6.H=6.w.E(6.e)};C.9.1k=7(){8 6.H=6.w.1k(6.e)};C.9.1l=7(){8
6.w.1l(6.e)};C.9.1j=7(){8 6.w.1j(6.e)};C.9.2H=7(I){6.I=I};C.9.1u=7(){8
6.I};C.9.P=7(){8 6.e};7
o(x,y,h,k){6.h=6.k=6.x=6.y=0;d(1n.j!=4)8;6.x=x;6.y=y;6.h=h;6.k=k;d((h<0)||
(k<0))3M(6+": 3L 3K h ")}o.2P=7(g){8 m o(g.2y,g.2x,g.3J,g.3I)};o.9.27=7(){8
m o(6.x,6.y,6.h,6.k)};o.9.29=7(g){c
n=g.n;n.O=6.x+"Z";n.1m=6.y+"Z";n.h=6.h+"Z";n.k=6.k+"Z"};o.9.21=7(){8"(x="+6.x+",
y="+6.y+", h = "+6.h+", k="+6.k+")"};o.9.2G=7(){8 6.h>6.k};7
1t(2O,28,Y){8(28-2O)*Y}o.9.2N=7(1s,Y){c
f=6.27();f.x+=1t(f.x,1s.x,Y);f.y+=1t(f.y,1s.y,Y);f.h+=1t(f.h,1s.h,Y);f.k+=1t(f.k,1s.k,Y);8
f};o.1r=2;o.9.2M=7(26){c
f=6.27();f.x+=o.1r;f.y+=o.1r+26;f.h-=(o.1r*2);f.k-=((o.1r*2)+26);d(f.h<=0||
f.k<=0)8 F;8 f};7 G(w){d(1n.j===0)8;6.w=w}G.1E=1;G.2F=2;G.9.2L=7(1h,2I){c
q=C.2K(6.w,1h);q.3H(C.2J);6.1a(q,2I);8
q};G.9.1a=7(q,u){d(q.j===0)8;d(q.j==1){q[0].2H(u);8}c X=6.2E(q);c t;c 1p;c
1q=6.1o(X.O),25=6.1o(X.1D),24=1q+25;d(1q+25<=0){t=0;1p=G.1E}N{d(u.2G()){1p=G.1E;t=T.23((1q*u.h)/24)}N{1p=G.2F;t=T.23((1q*u.k)/24)}}d(1p==G.1E){6.1a(X.O,m
o(u.x,u.y,t,u.k));6.1a(X.1D,m o(u.x+t,u.y,u.h-t,u.k))}N{6.1a(X.O,m
o(u.x,u.y,u.h,t));6.1a(X.1D,m o(u.x,u.y+t,u.h,u.k-t))}};G.9.2E=7(q){c
t=0;d(6.1o(q)===0){t=T.23(q.j/2); }N{c 2D=6.1o(q)/2;c 22=0;K(c
l=q.j;t<l;t++){d(t>0&&(22+q[t].E()>2D))3G;22+=q[t].E()}}8{O:q.2C(0,t),1D:q.2C(t)}};G.9.1o=7(q){c
f=0;K(c i=0,l=q.j;i<l;i++)f+=q[i].E();8 f};7
U(M,H){d(U.1n.j===0)8;6.M=M;6.H=H;6.18=F}U.9.E=7(){8 6.H};U.9.21=7(){8
6.20()+"="+6.H};U.9.20=7(){d(6.18===F)8 6.M;N 8 6.18.20()+"/"+6.M};7
19(M,s){U.2B(6,M,-1);6.s=m 1C();K(c i=0,l=s.j;i<l;i++){d(s[i]1Z
U){s[i].18=6;6.s.1T(s[i])}}}19.9=m U();19.9.E=7(){c f=0;d(6.H<0){K(c
i=0,l=6.s.j;i<l;i++)f+=6.s[i].E();6.H=f}8 6.H};19.9.15=7(){d(6.s.j===0)8
0;c R=0;K(c i=0,l=6.s.j;i<l;i++){d(6.s[i]1Z 19){R=T.2o(R,6.s[i].15())}}8
1+R};7 W(){}W.9.E=7(e){8 e.E()};W.9.1l=7(e){8 e.s};W.9.1k=7(e){8
e.M};W.9.1j=7(e){8!(e 1Z 19)};W.9.1i=7(e){d(e.18===F)8 0;8 1+6.1i(e.18)};7
J(1Y){6.1B=1Y.15()}J.V=["#3F","#3E","#3D","#3C","#3B","#3A","#3z","#3y","#3x","#3w"];J.9.1S=7(v){8
J.V[6.16(v)]};J.9.1R=7(v){8(6.16(v)<=(J.V.j/2))?"2q":"2p"};J.9.16=7(v){8
T.1Q((v*J.V.j)/6.1B)};7 2A(e,1X){d(e.2s.1U()==1X.1U())8 e;8 2A(e.1h,1X)}7
2z(g){d(g===F){8{O:0,1m:0}}N{c 1W=2z(g.3v);8{O:g.2y+1W.O,1m:g.2x+1W.1m}}}7
3u(){d(1V.2w)8 m 2w();N{3t{8 m 2v("3s.2u")}3r(3q){8 m m 2v("3p.2u")}}}7
3o(){8 3n.3m.1U().3l("3k 3j")!=-1}7 17(){}17.9.E=7(p){8
3i(p.2t("3h"),10)};17.9.1l=7(p){c f=m 1C();K(c
i=0,l=p.S.j;i<l;i++){d(p.S[i].3g==1){f.1T(p.S[i])}}8 f};17.9.1k=7(p){8
p.2t("M")};17.9.1j=7(p){8 p.2s=="3f"};17.9.1i=7(p){d(p.1h==p.3e)8 0;8
1+6.1i(p.1h)};7 1g(2r){6.1B=6.15(2r.3d)}1g.9.1S=7(v){8
J.V[6.16(v)]};1g.9.1R=7(v){8(6.16(v)<=(J.V.j/2))?"2q":"2p"};1g.9.16=7(v){8
T.1Q((v*J.V.j)/6.1B)};1g.9.15=7(p){d(p.S.j===0)8 0;c R=0;K(c
i=0,l=p.S.j;i<l;i++){d(p.S[i].3c=="3b"){R=T.2o(R,6.15(p.S[i]))}}8
1+R};',62,264,'||||||this|function|return|prototype|||var|if|node|result|
div|width||length|height||new|style|Rectangle|elem|facades|rootDIV|children|
midPoint|destRectangle|level|adaptor|||DivTreeMap|box|label|NodeFacade|
facade|getValue|null|TreeMap|value|coords|TreeNodeShader|for|displayNode|
name|else|left|getNode|self|childDepth|childNodes|Math|TreeNode|purples|
TreeNodeAdaptor|halves|fraction|px||selected|shader|options|stepNumber|
countDepth|scale|XmlAdaptor|parent|TreeParentNode|divideDisplayArea|in|
dimensions|repaint|createCallback|steps|XmlShader|parentNode|getLevel|
isLeaf|getName|getChildren|top|arguments|sumValues|orientation|leftSum|
margin|other|interp|getCoords|clientHeight|history|cursor|BoxAnimator|
displayRect|decorator|levels|Array|right|HORIZONTAL|setSelected|clientWidth|
anim|map|afters|before|paint|DefaultDecorator|cssClassName|newCoords|millis|
floor|getForeground|getBackground|push|toLowerCase|window|parentCoords|
parentTag|rootNode|instanceof|getFqName|toString|accValue|round|totalSum|
rightSum|topD|clone|to|moveDIV|getSelected|removeChild|clear|methodName|
true|onclick|subRect|isParentNode|LEFT_MARGIN|position|decorate|nodeFacades|
CssDecorator|setPaint|max|white|black|xmlDoc|tagName|getAttribute|XMLHTTP|
ActiveXObject|XMLHttpRequest|offsetTop|offsetLeft|getAbsCoords|
findParentNode|call|slice|halfValue|splitFairly|VERTICAL|isWide|setCoords|
rootRect|compare|wrapChildren|squarify|shrink|interpolate|from|fromDIV|
doZoom|animate|wait|animDuration|animSteps|zoom|isSelectEvent|false|
onBoxClick|appendChild|absolute|createElement|document|cursorStyle|
setTimeout|dataRoot|nodeFacade|stepTime|paintStep|stepCoords|oldCoords|dir|
nodeName|documentElement|ownerDocument|file|nodeType|bytes|parseInt|
explorer|internet|search|appName|navigator|isInternetExplorer|Msxml2|ex|
catch|Microsoft|try|createAjaxRequest|offsetParent|9400D3|8A2BE2|9370DB|
BA55D3|FF00FF|DA70D6|EE82EE|DDA0DD|D8BFD8|E6E6FA|break|sort|offsetHeight|
offsetWidth|negative|has|alert|checkResize|pop|unzoom|default|into|Nothing|
throw|onMouseOut|onmouseout|onMouseOver|onmouseover|dataNode|href|
onZoomClick|continue|color|innerHTML|marginLeft|background|100|requestPaint|
relative|500|outset|borderStyle|1px|borderWidth|className|
zIndex'.split('|'),0,{}))
+
--~--~---------~--~----~------------~-------~--~----~
You've received this message because you are subscribed to
the Devel::NYTProf Development User group.
Group hosted at: http://groups.google.com/group/develnytprof-dev
Project hosted at: http://perl-devel-nytprof.googlecode.com
CPAN distribution: http://search.cpan.org/dist/Devel-NYTProf
To post, email: [email protected]
To unsubscribe, email: [email protected]
-~----------~----~----~----~------~----~------~--~---