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("
");
};
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()