fbf528b0c682bbb8a11f7c275b973a220d8bb49b
ceisenhart
  Tue May 17 10:07:46 2016 -0700
Committing some old work, fixing up run speed and some other refactoring, refs #16341

diff --git src/hg/js/d3.dendrograms.js src/hg/js/d3.dendrograms.js
index 657cc40..3f6667a 100644
--- src/hg/js/d3.dendrograms.js
+++ src/hg/js/d3.dendrograms.js
@@ -226,57 +226,57 @@
 		var legend=vis.selectAll('g.'+layer+'Legend').data(val); // Define the DOM elements
 		var horz, vert;
 		var first = 1; // Use this as a boolean to only draw the title and label one time. 
 		var viewerWidth = $(document).width()/3;	// Scale to fit width
 		var viewerHeight = $(document).height();  // Scale to fit height
 		
 		legend.enter() // Fill out the DOM elements 
 			.append('g')
 				.attr('class',layer+ 'Legend')
 				.attr('transform', function (d, i){
 					var height=legendRectSize + legendSpacing;
 					var offset= height * colors.domain().length / 2; 
 					vert = (i * height - offset) + (radius*(1/2)) ; // All legends are the same height, the width location varies	
 					// Asign the legend width for each ring, scale to fit. 
 					if (layer=="inner") horz= 20 ;  
-					if (layer=="middle") horz= 40 + viewerWidth/3; 
-					if (layer=="outer") horz= 60 + 2*viewerWidth/3; 
+					else if (layer=="middle") horz= 40 + viewerWidth/3; 
+					else if (layer=="outer") horz= 60 + 2*viewerWidth/3; 
 					if (first)
 						{
 						vis.append("text")// The layer, this is either 'inner', 'middle', or 'outer'.  
 							.attr('class',layer+'LegendTitle')
 							.style("font-size","16px")
 							.style("font-weight","bold")
 							.attr("transform", "translate(" + (horz-15) + "," + (vert-35)+ ")")
 							.attr('x', legendRectSize + legendSpacing)
 							.attr('y', legendRectSize - legendSpacing)
 							.text(capitalizeFirstLetter(layer)); 
 
 						vis.append("text")// The title, this is mined from the meta data
 							.attr('class',layer+'LegendLabel')
 							.style("font-size","16px")
 							.style("font-weight","bold")
 							.attr("transform", "translate(" + (horz-15) + "," + (vert-15)+ ")")
 							.attr('x', legendRectSize + legendSpacing)
 							.attr('y', legendRectSize - legendSpacing)				
 							.text(function (){
 								if (title.length > 15){
 									return title.substring(0,14)+"...";
 									} 
 								return title; 
 								});
-						first =0;
+						first = 0;// 1 is true, 0 is false; 
 						}
 					return 'translate(' + horz + ',' + vert + ')'; // Actually move the legend. 
 					});
 
 		// Apply the colored rectangles.
 		legend.append('rect')
 			.attr('width', legendRectSize)
 			.attr('height', legendRectSize)
 			.style('fill', colors)
 			.style('stroke', colors);
 		
 		// Give the colored rectangles associated name tags.  
 		legend.append('text')
 			.style("font-size","12px")
 			.style("font-weight","bold")
@@ -381,53 +381,54 @@
 			.attr("class","btn btn-default dropdown-toggle")
 			.attr("type", "button")
 			.attr("data-toggle","dropdown")
 			.html("Outer ring")
 			.append("span")
 				.attr("class","caret"); 
 			
 		outerDropdown.append("ul")
 			.attr("class","dropdown-menu")
 			.html("<div id=outer"+treeType+"Leaves </div>"); 
 		};
 	
 	d3.dendrogram.nodeColors = function(val, selector){
 		var vis = d3.select(selector).selectAll("svg");
 		var node=vis.selectAll("g.internalNode").selectAll("circle");
-		if (val < 6)
+		if (val < 8)
 			{
 			node.attr("r", function(d){
 				if (d.name === " "){
 					if (val == 2) return Math.sqrt(d.kids-1);
-					if (val == 3) return 1; 	
-					if (val == 4) return 3; 	
-					if (val == 5) return 5; 	
+					else if (val == 3) return 1; //small	
+					else if (val == 4) return 3; //normal
+					else if (val == 5) return 5; //large
+					else if (val == 6) return 0.5; //tiny
+					else if (val == 7) return 10; //huge
 					}
 				});
 			}
-		if (val > 5)
+		else
 			{
 			var link = vis.selectAll("path.link")
 				.attr("stroke-width", function(d){
-					if (val == 6) return ".04px"; 
-					if (val == 7) return ".2px"; 
-					if (val == 8) return "1px"; 
+					if (val == 8) return ".07px"; // small
+					else if (val ==9) return ".2px"; // normal
+					else if (val == 10) return ".5px"; // large
 					}); 
 			}
 		}; 
 
-  	// README
 	// The javascript buttons are created at runtime based on the .json file provided. This allows the .html code to be greatly
 	// simplified at the expense of some rather confusing javascript.  All functions with the prefix d3.dendrograms.js are
 	// accessible from outside this module. All functions without the prefix can only be used within the module. 
 	//
 	// The addLeafButton and addNodeButton functions are used within this program to write buttons, the buttons themselves use the globally available 
 	// functions d3.dendrogram.leafColors and d3.dendrogram.nodeColors to apply the colors.  This is necesseary because the addLeafButton and
 	// addNodeButton functions are writing new elements to the DOM, namely buttons. These buttons have an on click function that points to
 	// the corresponding function in this module (d3.dendrogram.leafColors/d3.dendrogram.nodeColors), so the prefix is necessary to identify
 	// where the function resides. 
 	//
 	// A cool side effect/result of this is there is no buttons in the .html (and the user doesn't have to fus with them). 
 	// The buttons are all created at runtime by the javascript! 
 	
 	addNodeButton = function (dropdownSelector, val, graph, title) {
 		// Add a node button to the corresponding dropdown list. 
@@ -481,49 +482,53 @@
 		d3.select("#"+layer+"Dropdown").html(capitalizeFirstLetter(layer)+" ring: " + ringName);
 
 		// Reset if the user clicks the Remove button. 
 		if (val == -1)  d3.select("#"+layer+"Dropdown").html(capitalizeFirstLetter(layer) + " ring"); 
 		
 		// If there is no remove button and this function is being called then generate a remove button function. 
 		if (!d3.select("#"+layer+"RemoveButton")[0][0]){
 			addLeafButton("Remove", -1, layer, 10, '#'+layer+'DendroLeaves', selector, offset);
 			}
 
 		// Keep track of the currently selected button so its color can be reverted when another button is clicked. 
 		if (layer == "inner") prevInBut = d3.select("#"+layer+capitalizeFirstLetter(title).replace("_","")+"Button").selectAll("button");
 		if (layer == "middle") prevMidBut = d3.select("#"+layer+capitalizeFirstLetter(title).replace("_","")+"Button").selectAll("button");
 		if (layer == "outer") prevOutBut = d3.select("#"+layer+capitalizeFirstLetter(title).replace("_","")+"Button").selectAll("button");
 	
+		if (val == -1)
+			{
+			vis.selectAll("text."+layer+"LegendTitle").remove(); 
+			vis.selectAll("text."+layer+"LegendTitleLabel").remove(); 
+			d3.select("#"+layer+"RemoveButton").remove();
+			}
+
 		// Color the current button. 
 		d3.select("#"+layer+capitalizeFirstLetter(title).replace("_", "")+"Button").selectAll("button")	
 			.style("background","cornflowerblue"); 
 
 		// Update the ring color. Start by selecting all the polygons.  
 		node.selectAll("polygon")
 			.style("fill", function(d){
 				// This block links the extra leaf json fields to a specific value (count). This value
 				// is provided when the buttons are written in the main function. 
 				if (val==1) // A val of 1 indicates a distance ring, update the colors dictionary so the legend displays properly.  
 					{ 
 					colors = d3.scale.category20().range(distanceRange).domain(distanceDomain); 
 					return d3.rgb(d.colorGroup);
 					}
-				if (val==-1) // A val of -1 indicates a remove ring call. Kill everything. 
+				else if (val==-1) // A val of -1 indicates a remove ring call. Kill everything. 
 					{
-					vis.selectAll("text."+layer+"LegendTitle").remove(); 
-					vis.selectAll("text."+layer+"LegendTitleLabel").remove(); 
-					d3.select("#"+layer+"RemoveButton").remove();
 					return "none";
 					}
 				var count = 0;
 				// Go through the json fields in each leaf node and find the corresponding field using the val variable
 				// once found give it a new color with the d3 colors dictionary/function/object.  
 				for (var key in d) {
 					if (d.hasOwnProperty(key)){ // Ignore several json fields that don't need meta data rings.  
 						if (key != "x" && key!="y" && key!= "name" && key!="kids" && key!="length" && key!="colorGroup" && key!="parent" && key!="depth" && key!="rootDist"){
 							if (count == val){
 								var sub = d[key]; // Format the json field. 
 								if (typeof d[key] === 'string' && d[key].length > 20)
 									{
 									sub = d[key].substring(0,19)+"...";
 									}
 								count += 1;
@@ -787,31 +792,31 @@
 		var tree = options.tree || d3.layout.cluster()
 			.size([360, radius - 45])
 			.separation(function separation(a, b) {
 				return (a.parent == b.parent ? 1 : 1) ; // Evenly place leaf nodes.  
 				});
 		
 		var zoomListener = d3.behavior.zoom().scaleExtent([1, 10]) // Let the user zoom up to 10x 
 			.on("zoom", zoom); 
 		
 		var diagonal = options.diagonal || radialRightAngleDiagonal(); // Makes links right angled. 
 
 		var scaling = options.scaling || 1; 
 		var width =  viewerWidth -25,
 			height = viewerHeight - 50; 
 
-		var metaHorz = (viewerWidth)/12,
+		var metaHorz = 50,
 			metaVert = (viewerHeight)/2; 
 		
 		// Setup the svg for the radial display. 
 		var vis = options.vis || d3.select(selector) 
 			.attr("style", "display:inline-flex") 
 			.append("svg")
 				.attr("width", 3*width/5 )
 				.attr("height", height)
 				.attr("class", "overlay")
 				.call(zoomListener);
 		
 		// Setup the svg for the control display. 
 		var legendVis = options.vis || d3.select(selector)
 			.append("svg")
 			.style("background","rgb(239,239,239)")
@@ -860,36 +865,38 @@
 				.attr("stroke", "black")
 				.attr("stroke-width", ".2px")
 				.attr("d", diagonal); 	
 	
 		var first = 1; // Essentially a boolean. 
 		var leafCount; // The total number of leaves, will be used to calculate the polygon width. 
 		var innerOffset, middleOffset, outerOffset, rawOffset; // The offsets are used to center the polygons.  
 		var inR=6, midR=13, outR=20; // This is the pixel offset for each ring.  
 		var filled = 1; // Essentially a boolean for the first tooltip trigger.   
 		var prevSelLeaf, prevSelLeafNode; // Keep track of the previously selected node so that its color can be reverted when another node is clicked. 
 		
 		makeDropdownSkeleton("Dendro"); //Looks for the div 'dropdown' and generates the outer list and buttons
 		
 		// Add a bunch of the default options for to the general commands dropdown. 
 		addNodeButton("#interiorDendroNodes" ,2, selector, "Node size: sqrt(kids)"); 
+		addNodeButton("#interiorDendroNodes" ,6, selector, "Node size: tiny"); 
 		addNodeButton("#interiorDendroNodes" ,3, selector, "Node size: small"); 
 		addNodeButton("#interiorDendroNodes" ,4, selector, "Node size: normal"); 
 		addNodeButton("#interiorDendroNodes" ,5, selector, "Node size: large"); 
-		addNodeButton("#interiorDendroNodes" ,6, selector, "Link width: thin"); 
-		addNodeButton("#interiorDendroNodes" ,7, selector, "Link width: normal"); 
-		addNodeButton("#interiorDendroNodes" ,8, selector, "Link width: thick"); 
+		addNodeButton("#interiorDendroNodes" ,7, selector, "Node size: huge"); 
+		addNodeButton("#interiorDendroNodes" ,8, selector, "Link width: thin"); 
+		addNodeButton("#interiorDendroNodes" ,9, selector, "Link width: normal"); 
+		addNodeButton("#interiorDendroNodes" ,10, selector, "Link width: thick"); 
 
 		// These are true nodes in the sense that they are actually calculated and defined, 
 		// however this code is not repsonsible for the actual visuale representation. This
 		// block only handles the backend DOM construction, the shapes and colors are assigned later.
 
 		var trueNodes = svgGroup.selectAll("g")
 			.data(nodes).enter()
 			.append("g")
 				.attr("class", function(n) {
 					if (n.depth===0){ // This is the root, do a bunch of one off things. 
 						leafCount = n.kids; 
 						rawOffset = Math.PI*2*(radius)/(parseInt(leafCount)*3); 
 						innerOffset =  Math.PI*2*(radius+inR)/(parseInt((leafCount*(scaling))*2)); 
 						middleOffset =  Math.PI*2*(radius+midR)/(parseInt((leafCount*(scaling))*2)); 
 						outerOffset =   Math.PI*2*(radius+outR)/(parseInt((leafCount*(scaling))*2)); 
@@ -916,31 +923,31 @@
 								}
 							first = 0;
 							}
 						return "leaf";
 						}
 					})
 				.attr("transform", function(d){return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";});
 		
 		
 		// This section handles the internal node visual representation, including the node initial size/color
 		// and the tooltips (on click visualizations) 
 		var interiorNodes = svgGroup.selectAll("g.internalNode")
 			.append("circle")
 				.attr("r", function(d){ // Handle node size
 					if (d.name==" "){
-					return Math.sqrt(d.kids-1);}
+					return 3;}
 					else{return 0;}
 					})
 				.style("fill", function(d){ // Handle node color 
 					if (d.name==" "){return d.whiteToBlack;}
 					else{return "none";}})
 				.on("click", function(d) { // Tooltip stuffs 
 					d3.select(this).style("fill", "red"); // Color this node red 
 					if (filled == 2) { // Another node was previously clicked, its color needs to be reverted. 
 						if (d3.select(this) != prevSelLeaf && d3.select(this) != prevSelLeafNode && d != prevSelLeaf && d != prevSelLeafNode)
 							{
 							if (prevSelLeafNode.name==" "){prevSelLeaf.style("fill", prevSelLeafNode.whiteToBlack);}
 							else{prevSelLeaf.style("fill", "white");}
 							}
 						} 
 					tooltip.transition()