Author: tim.bunce
Date: Sun Jun  7 14:32:32 2009
New Revision: 762

Added:
    trunk/lib/Devel/NYTProf/js/js-treemap/
    trunk/lib/Devel/NYTProf/js/js-treemap-readme.txt
    trunk/lib/Devel/NYTProf/js/js-treemap/BoxAnimator.js
    trunk/lib/Devel/NYTProf/js/js-treemap/Decorators.js
    trunk/lib/Devel/NYTProf/js/js-treemap/DivTreeMap.js
    trunk/lib/Devel/NYTProf/js/js-treemap/NodeFacade.js
    trunk/lib/Devel/NYTProf/js/js-treemap/Rectangle.js
    trunk/lib/Devel/NYTProf/js/js-treemap/TreeMap.js
    trunk/lib/Devel/NYTProf/js/js-treemap/TreeNode.js
    trunk/lib/Devel/NYTProf/js/js-treemap/TreeNodeAdaptor.js
    trunk/lib/Devel/NYTProf/js/js-treemap/TreeNodeShader.js
    trunk/lib/Devel/NYTProf/js/js-treemap/Util.js
    trunk/lib/Devel/NYTProf/js/js-treemap/XmlAdaptor.js
    trunk/lib/Devel/NYTProf/js/js-treemap/XmlShader.js
Removed:
    trunk/lib/Devel/NYTProf/js/uk.org.zowie.Treemap-0.9.js
Modified:
    trunk/bin/nytprofhtml

Log:
Switched to using raw (non-minimized) src code of js-treemap.


Modified: trunk/bin/nytprofhtml
==============================================================================
--- trunk/bin/nytprofhtml       (original)
+++ trunk/bin/nytprofhtml       Sun Jun  7 14:32:32 2009
@@ -666,8 +666,20 @@
      open(OUT, '>', "$opt{out}/$filename")
          or croak "Unable to open file $opt{out}/$filename: $!";

-    my $treemap_head = q{
-        <script type="text/javascript"  
src="js/uk.org.zowie.Treemap-0.9.js" ></script>
+    my $jstmdir = "js/js-treemap";
+    my $treemap_head = qq{
+       <script language="JavaScript" src="$jstmdir/BoxAnimator.js"></script>
+       <script language="JavaScript" src="$jstmdir/Decorators.js"></script>
+       <script language="JavaScript" src="$jstmdir/TreeMap.js"></script>
+       <script language="JavaScript" src="$jstmdir/DivTreeMap.js"></script>
+       <script language="JavaScript" src="$jstmdir/NodeFacade.js"></script>
+       <script language="JavaScript" src="$jstmdir/Rectangle.js"></script>
+       <script language="JavaScript" src="$jstmdir/TreeNode.js"></script>
+       <script language="JavaScript" 
src="$jstmdir/TreeNodeAdaptor.js"></script>
+       <script language="JavaScript" src="$jstmdir/TreeNodeShader.js"></script>
+       <script language="JavaScript" src="$jstmdir/Util.js"></script>
+       <script language="JavaScript" src="$jstmdir/XmlAdaptor.js"></script>
+       <script language="JavaScript" src="$jstmdir/XmlShader.js"></script>
      };

      print OUT get_html_header("Package Treemap - NYTProf", {

Added: trunk/lib/Devel/NYTProf/js/js-treemap-readme.txt
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap-readme.txt    Sun Jun  7 14:32:32  
2009
@@ -0,0 +1 @@
+svn export  
https://js-treemap.svn.sourceforge.net/svnroot/js-treemap/js-treemap/src/  
js-treemap

Added: trunk/lib/Devel/NYTProf/js/js-treemap/BoxAnimator.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/BoxAnimator.js        Sun Jun  7  
14:32:32 2009
@@ -0,0 +1,66 @@
+/**
+ * Create an instance of a BoxAnimator
+ * @constructor
+ * @param div The source DIV node to animator
+ * @param {Rectangle} newCoords The coordinates to animate the DIV unto
+ * @param {number} steps The number of animation steps to take
+ * @param {number} millis The number of milliseconds between each step
+ * @param {function} afters a callback function to execute once the  
animation is complete
+ *
+ * TODO: enlarge text label as part of animation
+ */
+function BoxAnimator( div, newCoords, steps, millis ) {
+       // Get current coords
+       this.div = div;
+       this.oldCoords = Rectangle.fromDIV( div );
+       this.newCoords = newCoords;
+       this.steps = steps;
+       this.millis = millis;
+       this.stepTime = Math.floor( millis/steps );
+
+       // Establish default values for callbacks
+       this.afters = this.before = null;
+}
+
+/**
+ * Begin the animations
+ */
+BoxAnimator.prototype.animate = function()
+{
+       if( this.before !== null ) { this.before(); }
+       
+       // Raise the div above the rest
+       this.div.style.zIndex = 10;
+       this.setPaint( 1 );
+};
+
+/**
+ * Paint an single step of the animation, or call the 'afters' callback
+ * @private
+ */
+BoxAnimator.prototype.paintStep = function( stepNumber )
+{
+       if( stepNumber > this.steps ) {
+               // Finally, call the next step in a bit
+               if( this.afters !== null ) this.afters();
+       } else {
+               // Interpolate the coordinates by step/steps
+               var stepCoords = this.oldCoords.interpolate( this.newCoords,  
stepNumber/this.steps );                
+               stepCoords.moveDIV( this.div );
+               
+               stepNumber++;
+               this.setPaint( stepNumber );
+       }
+};
+
+/**
+ * Set the timer for the next animation step
+ * @private
+ */
+BoxAnimator.prototype.setPaint = function( stepNumber )
+{
+       var self = this;
+       window.setTimeout( function() {
+               self.paintStep( stepNumber );
+       }, self.stepTime );
+};
\ No newline at end of file

Added: trunk/lib/Devel/NYTProf/js/js-treemap/Decorators.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/Decorators.js Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,48 @@
+/**
+ * A simple DIV decorator - that applies a CSS class - and that's it
+ * @constructor
+ * @param {string} cssClassName A CSS style name to apply
+ * A decorator need only implement a method 'decorate'
+ */
+function CssDecorator( cssClassName )
+{
+       this.cssClassName = cssClassName;
+}
+
+/**
+ * decorate a given DIV
+ * @param div the HTML DIV to decorate
+ * @param node the raw data node behind this DIV
+ * @param {Rectangle} coords The relative coordinates of this DIV
+ */
+CssDecorator.prototype.decorate = function( div, nodeFacade )
+{
+       div.className = this.cssClassName;
+};
+//  
============================================================================
+
+/**
+ * The default DIV decorator - applies something like a useful style to a  
given DIV
+ * @constructor
+ * @param {string} cssClassName A CSS style name to apply
+ */
+function DefaultDecorator()
+{
+       //LOW: figure out how to create a CSS class at runtime & apply that  
instead
+}
+
+DefaultDecorator.prototype = new CssDecorator();
+
+/**
+ * decorate a given DIV
+ * @param div the HTML DIV to decorate
+ * @param node the raw data node behind this DIV
+ * @param {Rectangle} coords The relative coordinates of this DIV
+ */
+DefaultDecorator.prototype.decorate = function( div, nodeFacade )
+{
+       var style = div.style;
+       style.borderWidth = "1px";
+       style.borderStyle = "outset";
+//     style.cursor = "default";
+};
\ No newline at end of file

Added: trunk/lib/Devel/NYTProf/js/js-treemap/DivTreeMap.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/DivTreeMap.js Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,283 @@
+//TODO: fix the minor overflow problems.
+
+/**
+ * Create a TreeMap widget
+ * @constructor
+ * @param {div} rootDIV A DIV element in the HTML DOM for use by the  
treemap
+ * @param dataRoot the data hierarchy the treemap is to explore. This must  
be a TreeParentNode unless an adaptor is given in the options argument
+ * @param options Optional settings for the object
+ * @param options.shader A Shader implementation that is used to colour  
individual boxes in the treemap
+ * @param options.decorator A Decorator implementation, used to decorate  
individual boxes in the treemap
+ * @param options.adaptor An adaptor object, used by the treemap to  
interogae the dataRoot object. Only necessary if dataRoot is not a  
TreeMapParent instance
+ */
+function DivTreeMap( rootDIV, dataRoot, options )
+{
+       TreeMap.call( this, ( "adaptor" in options ) ? options.adaptor : new  
TreeNodeAdaptor() ); // Call the parent constructor
+
+       // Process arguments
+       this.rootDIV = rootDIV;
+       this.displayNode = this.rootNode = dataRoot;
+       this.dimensions = { width: 0, height:0 };
+       
+       // Some internal state
+       this.selected = null; // currently/last 'selected' DIV
+       this.animSteps = 10;
+       this.animDuration = 500;
+       
+       // Process options
+       this.shader = ( "shader" in options ) ? options.shader : null;
+       this.decorator = ( "decorator" in options ) ? options.decorator : new  
DefaultDecorator();
+       
+       // Record of steps into the data
+       this.history = new Array();
+       
+       // MUST make the root container relatively positioned - to position 
text  
usefully
+       this.rootDIV.style.position = "relative";
+       
+       this.repaint();
+//     this.paint( this.displayNode, new Rectangle( 0, 0,  
this.rootDIV.clientWidth, this.rootDIV.clientHeight ) );
+}
+
+/**
+ * Ensure that DivTreeMap inherits from TreeMap
+ */
+DivTreeMap.prototype = new TreeMap();
+
+/**
+ * Space between a box label and it's parent DIV
+ */
+DivTreeMap.LEFT_MARGIN = 5; // LOW: arbitrary constant
+
+
+DivTreeMap.prototype.requestPaint = function( displayNode, displayRect,  
level )
+{
+       var cursorStyle = this.rootDIV.style.cursor;
+       this.rootDIV.style.cursor = "wait";
+       
+       // Clear the content
+       this.clear();
+       
+       var self = this;
+       window.setTimeout( function() {
+               self.repaint();
+       }, 100 );
+       
+       // redraw the lot
+       this.paint( this.displayNode, new Rectangle( 0, 0,  
this.rootDIV.clientWidth, this.rootDIV.clientHeight ) );
+
+       // Restore cursor style
+       this.rootDIV.style.cursor = cursorStyle;
+};
+
+/**
+ * Clear and then paint the control
+ * Used when (un)zooming and resizing
+ * @private
+ */
+DivTreeMap.prototype.repaint = function( )
+{
+       // Clear the content
+       this.clear();
+       
+       // redraw the lot
+       this.paint( this.displayNode, new Rectangle( 0, 0,  
this.rootDIV.clientWidth, this.rootDIV.clientHeight ) );
+};
+
+/**
+ * Paint this treemap
+ * @param displayNode data node used to render display
+ * @param {Rectangle} displayRect Rectangle of space to consume during  
rendition
+ * @param {number} level Depth into the overall hierarchy - displayNode  
may not be the rootNode
+ * @private
+ */
+DivTreeMap.prototype.paint = function( displayNode, displayRect, level )
+{
+       if( arguments.length != 3 )
+               level = this.adaptor.getLevel( displayNode );
+       
+       // Place all the items inside the given space
+       var nodeFacades = this.squarify( displayNode, displayRect );
+
+       for( var i=0, l=nodeFacades.length; i<l; i++ )
+       {
+               var facade = nodeFacades[i];
+               var coords = facade.getCoords();
+
+               // Parent the box div
+               var box = document.createElement( "div" );
+               box.style.position = "absolute";
+               coords.moveDIV( box );
+
+               // Longer term - there may be something to say for merging the 
shader &  
decorator iterfaces             
+               if( this.decorator ) this.decorator.decorate( box, facade );
+               if( this.shader ) box.style.background = 
this.shader.getBackground(  
level );
+
+               box.node = facade.getNode();
+               this.rootDIV.appendChild( box );
+
+               // Stick a text label in there ... it's tempting to add it to 
the box  
DIV, but that causes issues ...
+               var isParentNode = ! facade.isLeaf();
+               var label = document.createElement( isParentNode ? "a" : "div" 
);
+               label.style.position = "absolute";
+               label.style.left = coords.x + "px";
+               label.style.top = coords.y + "px";
+               label.style.marginLeft = DivTreeMap.LEFT_MARGIN + "px";
+               label.innerHTML = facade.getName();
+               if( this.shader ) label.style.color = 
this.shader.getForeground( level );
+               this.rootDIV.appendChild( label );              
+               
+               // The magic heuristic: if the box label is too big - don't 
render the  
box at all
+               // Get the width/height of the label - is it larger than the 
destined  
cell?
+               if( label.clientWidth + DivTreeMap.LEFT_MARGIN > coords.width 
||  
label.clientHeight > coords.height )
+               {
+                       // label.client* are not set until after they're 
parented, so we have  
to do this at least once
+                       this.rootDIV.removeChild( box );
+                       this.rootDIV.removeChild( label );
+                       continue;
+               }
+               
+               // Recurse into the child node - if sensible
+               if( isParentNode )
+               {
+                       label.onclick = this.createCallback( "onZoomClick", 
facade.getNode(),  
box, true );
+                       label.href="#"; // No HREF, and it doesn't render as a 
link
+                       
+                       // Shrink the coordinates to show the parent box
+                       var subRect = facade.getCoords().shrink( 
label.clientHeight );
+                       if( subRect !== null )
+                               this.paint( facade.getNode(), subRect, level +1 
);
+               } else {
+                       label.onclick = this.createCallback( "onBoxClick", 
facade.getNode(),  
box, true );
+               }
+               
+               var dataNode = facade.getNode();
+               
+               // Some minimal event handling
+               box.onclick = this.createCallback( "onBoxClick", 
facade.getNode(), box,  
true );
+               
+               // Hook up other events
+               box.onmouseover = this.createCallback( "onMouseOver", 
facade.getNode(),  
box, false );
+               box.onmouseout = this.createCallback( "onMouseOut", 
facade.getNode(),  
box, false );
+       }
+       
+       // Record the GUI size
+       this.dimensions = { width: displayRect.width , height: 
displayRect.height  
};      
+};
+
+/**
+ * Create a named callback
+ * @param {string} methodName Name of method to call on this, if it exists
+ * @param node data node to pass to the callback
+ * @param elem HTML DIV element to pass to the callback
+ * @param isSelectEvent Only true is this event is a 'select' event
+ * @private
+ */
+DivTreeMap.prototype.createCallback = function( methodName, node, elem,  
isSelectEvent )
+{
+       var self = this;
+       // NB: var-args style of argument passing would be nice,
+       // but 'arguments' is NOT an array and therefore lack a 'shift' method
+       return function() {
+               if( isSelectEvent ) self.setSelected( node, elem );
+               if( methodName in self ) self[methodName]( node );
+       };
+};
+
+/**
+ * Zoom into the currently selected node, with animation
+ */
+DivTreeMap.prototype.zoom = function()
+{      
+       if( !( "selected" in this ) )
+               throw "Nothing selected to zoom into";
+       
+       var map = this;
+       var selected = this.getSelected();
+       var anim = new BoxAnimator( selected.div, this.getCoords(),  
this.animSteps, this.animDuration );
+       
+       anim.before = function() { map.rootDIV.style.cursor = "wait"; };
+       anim.afters = function() { map.doZoom(); map.rootDIV.style.cursor  
= "default"; };
+       anim.animate(); 
+};
+
+/**
+ * Called once the animation is complete to effect the zoom
+ * @private
+ */
+DivTreeMap.prototype.doZoom = function()
+{
+       this.history.push( this.displayNode );
+       this.displayNode = this.getSelected().node;
+       this.repaint();
+       this.setSelected();
+} ;
+
+/**
+ * Unzoom the control a single step, if possible
+ * @return the number of steps left in the zoom history
+ */
+DivTreeMap.prototype.unzoom = function()
+{
+       if( this.history.length === 0 ) return 0;
+       this.displayNode = this.history.pop();
+       this.repaint();
+       this.setSelected();
+       
+       return this.history.length;
+};
+
+/**
+ * Repaint the control if it has been resized
+ */
+DivTreeMap.prototype.checkResize = function( width, height )
+{
+       if( this.dimensions.width == this.rootDIV.clientWidth &&
+               this.dimensions.height == this.rootDIV.clientHeight ) return;
+
+       // otherwise ...
+       this.repaint();         
+};
+
+/**
+ * Clear the contents of the control
+ * @private
+ */
+DivTreeMap.prototype.clear = function()
+{
+       // remove all DIVs and texts .. backwards
+       var children = this.rootDIV.childNodes;
+       for( var i=children.length-1; i >= 0  ;i-- )
+               this.rootDIV.removeChild( children[i] );
+};
+
+/**
+ * Get get relative coordinates of the control
+ * So x = y = 0 always
+ * @return {Rectangle} coordinates of ths control
+ */
+DivTreeMap.prototype.getCoords = function()
+{
+       return new Rectangle( 0, 0, this.dimensions.width, 
this.dimensions.height  
);
+};
+
+/**
+ * Return the DIV and the dataNode that are selected currently
+ * @return an object with properties 'div' and 'node'
+ */
+DivTreeMap.prototype.getSelected = function()
+{
+       return this.selected;
+};
+
+/**
+ * Set the currrent selected element, or unset one altogether
+ * @param node Optional data node that is 'selected'
+ * @param {DIV} Optional div the DIV currently 'selected'
+ */
+DivTreeMap.prototype.setSelected = function( node, div )
+{
+       this.selected = ( arguments.length === 0) ?
+               null:
+               { node: node, div: div };
+};
+

Added: trunk/lib/Devel/NYTProf/js/js-treemap/NodeFacade.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/NodeFacade.js Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,114 @@
+/**
+ * NodeFacade.js - 'Facade' for for the raw data objects - which are  
occasionally inviolate
+ * ... meaning that extra properties cannot be added to them
+ * @constructor
+ * @param {Adaptor} adaptor Object used to interact with the data object
+ * @param node raw data object
+ */
+function NodeFacade( adaptor, node )
+{
+       this.adaptor = adaptor;
+       this.node = node;
+       this.coords = null;
+}
+
+/**
+ * Static 'bulk constructor'
+ * @param {Adaptor} adaptor Object used to interact with the data objects
+ * @param node Parent node to children that are to be wrapped
+ * @return an array of NodeFacade objects
+ */
+NodeFacade.wrapChildren = function( adaptor, node )
+{
+       var children = adaptor.getChildren( node );
+       var result = new Array( children.length );
+       for( var i=0, l=result.length; i<l ;i++ )
+               result[i] = new NodeFacade( adaptor, children[i] );
+       return result;
+};
+
+/**
+ * @return {String} a human useful string, describing this node-facade
+ */
+NodeFacade.prototype.toString = function()
+{
+       return this.coords + " node: " + this.node;
+};
+
+/**
+ * Compare one nodefacade with another
+ * An ideal fit for Array.sort()
+ * @param a A nodefacade object
+ * @param b Another nodefacade object
+ * @return {number} negative number if A>B, positive number if A<B, zero  
otherwise
+ */
+NodeFacade.compare = function( a, b )
+{
+       return b.getValue() - a.getValue();
+};
+
+/**
+ * Fetch the value of the underlying node with the adaptor
+ * Using a cached local value - if at all possible
+ * @return {number} underlying node value
+ */
+NodeFacade.prototype.getValue = function()
+{
+       if( "value" in this ) return this.value;
+       return this.value = this.adaptor.getValue( this.node );
+};
+
+/**
+ * Fetch the name of the underlying node with the adaptor
+ * @return {string} underlying node name
+ */
+NodeFacade.prototype.getName = function()
+{
+       return this.value = this.adaptor.getName( this.node );
+};
+
+/**
+ * Fetch the children of the underlying node with the adaptor
+ * @return {Array} underlying node children
+ */
+NodeFacade.prototype.getChildren = function()
+{
+       return this.adaptor.getChildren( this.node );
+};
+
+/**
+ * Predicate - can this NodeFacade a leaf in the graph?
+ * @return {number} underlying node isLeaf value
+ */
+NodeFacade.prototype.isLeaf = function()
+{
+       return this.adaptor.isLeaf( this.node );
+};
+
+
+/**
+ * Set the coordinates
+ * @param {Rectangle} coords The new coordinates of this object
+ */
+NodeFacade.prototype.setCoords = function( coords )
+{
+       this.coords = coords;
+};
+
+/**
+ * Fetch the coordinates of this object
+ * @return {Rectangle} the coordinates of this object
+ */
+NodeFacade.prototype.getCoords = function()
+{
+       return this.coords;
+};
+
+/**
+ * Fetch the underlying data node
+ * @return the underlying data node
+ */
+NodeFacade.prototype.getNode = function()
+{
+       return this.node;
+};
\ No newline at end of file

Added: trunk/lib/Devel/NYTProf/js/js-treemap/Rectangle.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/Rectangle.js  Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,122 @@
+ /**
+  * Construct a rectangle, with either zero or four arguments
+  * @constructor
+  * @param {number} x X coordinate of this rectangle
+  * @param {number} y Y coordinate of this rectangle
+  * @param {number} width Width of this rectangle
+  * @param {number} height Height of this rectangle
+  */
+function Rectangle( x, y, width, height )
+{
+       this.width = this.height = this.x = this.y = 0;
+       if( arguments.length != 4 ) return;
+
+       this.x = x;
+       this.y = y;
+       this.width = width;
+       this.height = height;
+       if(( width < 0 ) || ( height < 0 ) )alert( this + ": has negative width 
"  
);
+}
+
+/**
+ * Get the relative coordinates of a div,
+ * @param div HTML div to query for coordinates
+ * @return {Rectangle} coordinates of the given div
+ */
+Rectangle.fromDIV = function( div )
+{
+       return new Rectangle( div.offsetLeft, div.offsetTop, div.offsetWidth,  
div.offsetHeight );
+};
+
+/**
+ * Create a copy of this rectangle
+ * @return {Rectangle} copy of this object
+ */
+Rectangle.prototype.clone = function()
+{
+       return new Rectangle( this.x, this.y, this.width, this.height );
+};
+
+/**
+ * Set a DIV to have these coordinates
+ * @param div HTML div to move
+ */
+Rectangle.prototype.moveDIV = function( div )
+{
+       var style = div.style;
+       style.left = this.x +"px";
+       style.top = this.y +"px";
+       style.width = this.width +"px";
+       style.height = this.height +"px";
+};
+
+/**
+ * @return a String representation of these coordinates
+ * Possibly a bit unnecessary with toSource()
+ */
+Rectangle.prototype.toString = function()
+{
+       return "(x=" + this.x + ", y=" + this.y + ", width = " + this.width + 
",  
height=" + this.height + ")";
+};
+
+/**
+ * Is this rectangle wider than it's tall?
+ * @return {boolean} true if this object is wider than tall
+ */
+Rectangle.prototype.isWide = function()
+{
+       return this.width > this.height;
+};
+
+/**
+ * Calculate a fraction of the distance between two numbers
+ * @private
+ * @return the fraction of the distance between two numbers
+ */
+function interp( from, to, fraction )
+{
+       return ( to - from ) * fraction;
+}
+
+/**
+ * Create a new rectangle that is interpolated between this and another
+ * @param {Rectangle} other Another Rectangle to interpolate towards
+ * @param {number} fraction a real number between 0 and 1, where 0 return  
this object and 1 returns 'other'
+ * @return {Rectangle} a new rectangle between the two
+ */
+Rectangle.prototype.interpolate = function( other, fraction )
+{
+       // For each coordinate - get the difference
+       var result = this.clone();
+       result.x += interp( result.x, other.x, fraction );
+       result.y += interp( result.y, other.y, fraction );
+       result.width += interp( result.width, other.width, fraction );
+       result.height += interp( result.height, other.height, fraction );
+       return result;
+};
+
+
+/**
+ * Margin applied in shrink
+ * @private
+ */
+Rectangle.margin = 2;
+
+/**
+ * Createa a smaller Rectangle, or none at all
+ * @param {number} space in pixels to leave at the top
+ * @return {Rectangle} a smaller box, or null if any of the dimensions  
become negative
+ *
+ */
+Rectangle.prototype.shrink = function(  topD )
+{
+       var result = this.clone();
+       result.x += Rectangle.margin;
+       result.y += Rectangle.margin + topD;
+       result.width -= ( Rectangle.margin *2 );
+       result.height -= ( ( Rectangle.margin *2 ) + topD );
+
+       if( result.width <= 0 || result.height <= 0 ) return null;
+       return result;
+
+};
\ No newline at end of file

Added: trunk/lib/Devel/NYTProf/js/js-treemap/TreeMap.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/TreeMap.js    Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,139 @@
+/**
+ * Base functionality for treemap implementations
+ * @constructor
+ * @param adaptor Data adaptor
+ */
+function TreeMap( adaptor )
+{
+       if( arguments.length === 0 ) return;
+       this.adaptor = adaptor;
+}
+
+TreeMap.HORIZONTAL = 1;
+TreeMap.VERTICAL = 2;
+
+/**
+ * Place boxes in the given rectangle, making each as square as possible,  
wasting no space
+ * @param parentNode, parent to children that are placed
+ * @param {Rectangle} rootRect rectangle to fix boxes into
+ */
+TreeMap.prototype.squarify = function( parentNode, rootRect )
+{
+       var facades = NodeFacade.wrapChildren( this.adaptor, parentNode );
+
+       // Sort the set of blocks
+       facades.sort( NodeFacade.compare );
+
+       // Allocate space to all the nodes
+       this.divideDisplayArea( facades, rootRect );
+       
+       return facades;
+};
+
+/**
+ * Tesselate the areas with the given areas into the given space
+ * @param {Array} facades An array of NodeFacades for placing
+ * @param {Rectangle} destRectangle Destination rectangle
+ * @private
+ */
+TreeMap.prototype.divideDisplayArea = function( facades, destRectangle )
+{      
+       // Check for boundary conditions
+       if( facades.length === 0 ) return;
+
+       if( facades.length == 1 )
+       {
+               facades[0].setCoords( destRectangle );
+               return;
+       }
+
+       // Find the 'centre of gravity' for this node-list
+       var halves = this.splitFairly( facades );
+
+    // We can now divide up the available area into two
+    // parts according to the lists' sizes.
+       var midPoint;
+       var orientation;
+       
+       var leftSum = this.sumValues( halves.left ),
+               rightSum = this.sumValues( halves.right ),
+               totalSum = leftSum + rightSum;
+
+       // Degenerate case:  All size-zero entries.
+       if( leftSum + rightSum <= 0 )
+       {
+               midPoint = 0;
+               orientation = TreeMap.HORIZONTAL;
+       } else {
+               
+               if( destRectangle.isWide() )
+               {
+                       orientation = TreeMap.HORIZONTAL;
+                       midPoint = Math.round( ( leftSum * destRectangle.width 
) / totalSum );
+               } else {
+                       orientation = TreeMap.VERTICAL;
+                       midPoint = Math.round( ( leftSum * destRectangle.height 
) / totalSum );
+               }
+       }
+
+       // Once we've split, we recurse to divide up the two
+       // new areas further, and we keep recursing until
+       // we're only trying to fit one entry into any
+       // given area.  This way, even size-zero entries will
+       // eventually be assigned a location somewhere in the
+       // display.  The rectangles below are created in
+       // (x, y, width, height) format.
+       
+       if( orientation == TreeMap.HORIZONTAL )
+       {
+               this.divideDisplayArea( halves.left, new Rectangle( 
destRectangle.x,  
destRectangle.y, midPoint, destRectangle.height ) );
+               this.divideDisplayArea( halves.right, new Rectangle( 
destRectangle.x +  
midPoint, destRectangle.y, destRectangle.width - midPoint,  
destRectangle.height ) );
+       } else {
+               this.divideDisplayArea( halves.left, new Rectangle( 
destRectangle.x,  
destRectangle.y, destRectangle.width, midPoint ) );
+               this.divideDisplayArea( halves.right, new Rectangle( 
destRectangle.x,  
destRectangle.y + midPoint, destRectangle.width, destRectangle.height -  
midPoint ) );
+       }
+};
+
+/*
+ * Break the list in two by size, roughly
+ * @param {Array} facades An array of NodeFacades
+ * @private
+ * @return An object with fields 'left' and 'right' containing Arrays of  
NodeFacade objects
+ */
+TreeMap.prototype.splitFairly = function( facades )
+{
+       var midPoint = 0;
+       
+       if( this.sumValues( facades ) === 0 )
+       {
+               midPoint = Math.round( facades.length /2 ); // JS uses 
floating-point  
maths
+       } else {
+               var halfValue = this.sumValues( facades ) /2;
+               var accValue = 0;
+               for( var l=facades.length; midPoint< l; midPoint++ )
+               {
+                       //NB: zeroth item _always_ goes into left-hand list
+                       if( midPoint > 0 && ( accValue + 
facades[midPoint].getValue() >  
halfValue ) )
+                               break;
+                       accValue += facades[midPoint].getValue();
+               }
+       }
+
+       return {
+               left: facades.slice( 0, midPoint ),
+               right: facades.slice( midPoint )
+       };
+};
+
+/*
+ * Convenience function - return the sum of the values for an array of  
facades
+ * @param {Array} facades An array of NodeFacade objects
+ * @private
+ */
+TreeMap.prototype.sumValues = function( facades )
+{
+       var result =0;
+       for( var i=0, l=facades.length; i<l; i++ )
+               result += facades[i].getValue();
+       return result;
+};

Added: trunk/lib/Devel/NYTProf/js/js-treemap/TreeNode.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/TreeNode.js   Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,115 @@
+
+
+/**
+ * Create a simple TreeNode oObject
+ * @constructor
+ * @param {string} name Name of this TreeNode
+ * @param {number} value Value of this TreeNode
+ */
+function TreeNode( name, value )
+{
+       if( TreeNode.arguments.length === 0 ) return; // NB: this is a base 
class  
constructor .. sometimes
+       this.name = name;
+       this.value = value;
+       this.parent = null;
+}
+
+
+/**
+ * Get the value of this node
+ * A simple value accessor .. something TreeParentNode can overload
+ * @return {number} the value of this node
+ */
+TreeNode.prototype.getValue = function()
+{
+       return this.value;
+};
+
+/**
+ * Fetch a string representation for this object
+ * @return {String} the fully qualified name of this node
+ */
+TreeNode.prototype.toString = function()
+{
+       return this.getFqName() + "=" + this.value;
+};
+
+/**
+ * Get the name of this node, preceded by the name of all parent nodes
+ * @return {string} fully qualified node name
+ */
+TreeNode.prototype.getFqName= function()
+{
+       if( this.parent === null )
+               return this.name;
+       else
+               return this.parent.getFqName() + "/" + this.name;
+};
+
+//  
============================================================================
+
+// The TreeParentNode class
+
+/**
+ * Construct a TreeParentNode object
+ * this inherits from the TreeNode class
+ * @constructor
+ * @param {string} name Name of this TreeNode
+ * @param children Array of TreeNode objects to contain
+ */
+function TreeParentNode( name, children )
+{
+       TreeNode.call( this, name, -1 );
+
+       // Some additional state
+       this.children = new Array();
+       
+       // Parent the children & weed out cuckoos (cause by trailing commas in 
IE  
- bah)
+       for( var i=0, l=children.length; i<l; i++ )
+       {
+               if( children[i] instanceof TreeNode )
+               {
+                       children[i].parent = this;
+                       this.children.push( children[i] );
+               }
+       }
+}
+
+// Inherits from TreeNode class
+TreeParentNode.prototype = new TreeNode();
+
+/**
+ * Get the value of this object, from a cache if possible
+ * Otherwise recursively calculate it
+ * @retun {number} the value of this object
+ */
+TreeParentNode.prototype.getValue = function()
+{
+       var result = 0;
+       if( this.value < 0 ) // Check for cached values
+       {
+               for( var i=0, l=this.children.length; i<l; i++ )
+                       result += this.children[i].getValue();
+               this.value = result;
+       }
+       return this.value;
+};
+
+/**
+ * How deep does this rabbit warren go?
+ * @return {number} number of levels this data model has
+ */
+TreeParentNode.prototype.countDepth = function()
+{
+       if( this.children.length === 0 ) return 0;
+       
+       var childDepth = 0;
+       for( var i=0,l=this.children.length; i<l; i++ )
+       {
+               if( this.children[i] instanceof TreeParentNode )
+               {
+                       childDepth = Math.max( childDepth, 
this.children[i].countDepth() );
+               }
+       }                       
+       return 1 + childDepth;
+};
\ No newline at end of file

Added: trunk/lib/Devel/NYTProf/js/js-treemap/TreeNodeAdaptor.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/TreeNodeAdaptor.js    Sun Jun  7  
14:32:32 2009
@@ -0,0 +1,58 @@
+/**
+ * TreeNodeAdaptor.js - an adaptor for a simple TreeNode/TreeParentNode  
hierarchy
+ */
+
+/**
+ * Create a TreeNodeAdaptor
+ * If JavaScript had abstract classes or interfaces, I would use them in  
here and in XmlAdaptor
+ */
+function TreeNodeAdaptor()
+{
+       /* a do-nothing constructor */
+}
+
+/**
+ * Fetch the value of the given node
+ * @return {number} node value
+ */
+TreeNodeAdaptor.prototype.getValue = function( node )
+{
+       return node.getValue(); // Important for polymorphism
+};
+
+/**
+ * Fetch the value of the given node
+ * @return {number} node value
+ */
+TreeNodeAdaptor.prototype.getChildren = function( node )
+{
+       return node.children;
+};
+
+/**
+ * Fetch the name of the given node
+ * @return {string} node name
+ */
+TreeNodeAdaptor.prototype.getName = function( node )
+{
+       return node.name;
+};
+
+/**
+ * Predicate: is the given node a leaf node?
+ * @return {boolean}
+ */
+TreeNodeAdaptor.prototype.isLeaf = function( node )
+{
+       return !( node instanceof TreeParentNode );
+};
+
+/**
+ * Fetch the level of the given node in the overall model
+ * @return {number} the depth of the given node the model
+ */
+TreeNodeAdaptor.prototype.getLevel = function( node )
+{
+       if( node.parent === null ) return 0;
+       return 1 + this.getLevel( node.parent );
+};

Added: trunk/lib/Devel/NYTProf/js/js-treemap/TreeNodeShader.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/TreeNodeShader.js     Sun Jun  7  
14:32:32 2009
@@ -0,0 +1,58 @@
+/*
+ * Shader object, for use with TreeNode hierarchies
+ */
+
+/**
+ * Construct a TreeNodeShader
+ * @constructor
+ * @param rootNode a root TreeParentNode
+ */
+function TreeNodeShader( rootNode )
+{
+       this.levels = rootNode.countDepth();
+}
+
+/**
+ * Set of colours to use
+ */
+TreeNodeShader.purples = [
+       "#E6E6FA",
+       "#D8BFD8",
+       "#DDA0DD",
+       "#EE82EE",
+       "#DA70D6",
+       "#FF00FF",
+       "#BA55D3",
+       "#9370DB",
+       "#8A2BE2",
+       "#9400D3" ];
+
+/**
+ * Fetch a background colour
+ * @param {number} level Depth into the data model
+ * @return {string} a CSS colour string
+ */
+TreeNodeShader.prototype.getBackground = function( level )
+{
+       return TreeNodeShader.purples[ this.scale( level ) ];
+};
+
+/**
+ * Fetch a foreground colour
+ * @param {number} level Depth into the data model
+ * @return {string} a CSS colour string
+ */
+TreeNodeShader.prototype.getForeground = function( level )
+{
+       // LOW: fairly arbitrary judgement of when black text isn't clear enough
+       return ( this.scale( level )  <= ( TreeNodeShader.purples.length /2 )  
) ? "black" : "white";
+};
+
+/**
+ * Scale a number by the ratio of level:levels
+ * @private
+ */
+TreeNodeShader.prototype.scale = function( level )
+{
+       return Math.floor( ( level * TreeNodeShader.purples.length ) /  
this.levels );
+};
\ No newline at end of file

Added: trunk/lib/Devel/NYTProf/js/js-treemap/Util.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/Util.js       Sun Jun  7 14:32:32 2009
@@ -0,0 +1,54 @@
+/**
+ * Find a parent node of a specific type
+ * @param node HTML node to begin the search at
+ * @param {string} parentTag element type to search fo
+ */
+function findParentNode( node, parentTag )
+{
+       if( node.tagName.toLowerCase() == parentTag.toLowerCase() ) return node;
+       return findParentNode( node.parentNode, parentTag );
+}
+
+/**
+ * Get the absolute coordinates of a given div
+ * @return Object with fields 'left' and 'top', both numbers
+ */
+function getAbsCoords( div )
+{
+       if( div === null )
+       {
+               return { left: 0, top: 0 };
+       } else {
+               var parentCoords = getAbsCoords( div.offsetParent );
+               return {
+                       left: div.offsetLeft + parentCoords.left,
+                       top: div.offsetTop + parentCoords.top
+               };
+       }
+}
+
+/**
+ * Create an AJAX request object, taking platform differences into some  
account
+ * @return {XMLHttpRequest}
+ */
+function createAjaxRequest()
+{
+       if (window.XMLHttpRequest)
+               return new XMLHttpRequest();
+       else {
+               try {
+                       return new ActiveXObject( "Microsoft.XMLHTTP" );
+               } catch (ex) {
+                       return new new ActiveXObject( "Msxml2.XMLHTTP" );
+               }
+       }
+}
+
+/**
+ * Is this running in Internet Explorer?
+ * @return {boolean}
+ */
+function isInternetExplorer()
+{
+               return navigator.appName.toLowerCase().search( "internet 
explorer" ) !=  
-1;
+}
\ No newline at end of file

Added: trunk/lib/Devel/NYTProf/js/js-treemap/XmlAdaptor.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/XmlAdaptor.js Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,67 @@
+/*
+ * XmlAdaptor.js - simple data adaptor for XML describing a directory  
hierarchy
+ */
+
+/**
+ * Create a XmlAdaptor
+ * If JavaScript had abstract classes or interfaces, I would use them in  
here and in TreeNodeAdaptor
+ */
+function XmlAdaptor()
+{
+       /* a do-nothing constructor */
+}
+
+/**
+ * Fetch the value of the given node
+ * @return {number} node value
+ */
+XmlAdaptor.prototype.getValue = function( elem )
+{
+       return parseInt( elem.getAttribute( "bytes" ), 10 );
+};
+
+/**
+ * Fetch the value of the given node
+ * @return {number} node value
+ */
+XmlAdaptor.prototype.getChildren = function( elem )
+{
+       var result = new Array();
+       for( var i=0, l=elem.childNodes.length; i<l; i++ )
+       {
+               if( elem.childNodes[i].nodeType == 1 )
+               {
+                       result.push( elem.childNodes[i] );
+               }
+       }
+       return result;
+};
+
+/**
+ * Fetch the name of the given node
+ * @return {string} node name
+ */
+XmlAdaptor.prototype.getName = function( elem )
+{
+       return elem.getAttribute( "name" );
+};
+
+/**
+ * Predicate: is the given node a leaf node?
+ * @return {boolean}
+ */
+XmlAdaptor.prototype.isLeaf = function( elem )
+{
+       return elem.tagName == "file";
+};
+
+/**
+ * Fetch the level of the given node in the overall model
+ * @return {number} the depth of the given node the model
+ */
+XmlAdaptor.prototype.getLevel = function( elem )
+{
+       if( elem.parentNode == elem.ownerDocument ) return 0;
+       return 1 + this.getLevel( elem.parentNode );
+};
+

Added: trunk/lib/Devel/NYTProf/js/js-treemap/XmlShader.js
==============================================================================
--- (empty file)
+++ trunk/lib/Devel/NYTProf/js/js-treemap/XmlShader.js  Sun Jun  7 14:32:32  
2009
@@ -0,0 +1,62 @@
+/*
+ * Shader object, for use with XML hierarchies
+ */
+
+/**
+ * Construct an XmlShader
+ * @constructor
+ * @param xmlDoc an XML Document
+ */
+function XmlShader( xmlDoc )
+{
+       this.levels = this.countDepth( xmlDoc.documentElement  );
+}
+
+/**
+ * Fetch a background colour
+ * @param {number} level Depth into the data model
+ * @return {string} a CSS colour string
+ */
+XmlShader.prototype.getBackground = function( level )
+{
+       return TreeNodeShader.purples[ this.scale( level ) ];
+};
+
+/**
+ * Fetch a foreground colour
+ * @param {number} level Depth into the data model
+ * @return {string} a CSS colour string
+ */
+XmlShader.prototype.getForeground = function( level )
+{
+       return ( this.scale( level )  <= ( TreeNodeShader.purples.length /2 )  
) ? "black" : "white";
+};
+
+/**
+ * Scale a number by the ratio of level:levels
+ * @private
+ */
+XmlShader.prototype.scale = function( level )
+{
+       return Math.floor( ( level * TreeNodeShader.purples.length ) /  
this.levels );
+};
+
+/**
+ * Recursively find the maximum depth of the given XML element
+ * @private
+ * @return {number}
+ */
+XmlShader.prototype.countDepth = function( elem )
+{
+       if( elem.childNodes.length === 0 ) return 0;
+       
+       var childDepth = 0;
+       for( var i=0, l=elem.childNodes.length; i<l; i++ )
+       {
+               if( elem.childNodes[i].nodeName == "dir" )
+               {
+                       childDepth = Math.max( childDepth, this.countDepth( 
elem.childNodes[i]  
) );
+               }
+       }                       
+       return 1 + childDepth;
+};
\ No newline at end of file

--~--~---------~--~----~------------~-------~--~----~
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]
-~----------~----~----~----~------~----~------~--~---

Reply via email to