| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 | 
							- /*
 
-   (agr@ncgr.org : this is a significantly modified version of
 
-   d3.phylogram.js....  retaining attribution/copyright per below)
 
-   d3.phylogram.js http://bl.ocks.org/kueda/1036776
 
-   Wrapper around a d3-based phylogram (tree where branch lengths are scaled)
 
-   Also includes a radial dendrogram visualization (branch lengths not scaled)
 
-   along with some helper methods for building angled-branch trees.
 
-   Copyright (c) 2013, Ken-ichi Ueda
 
-   All rights reserved.
 
-   Redistribution and use in source and binary forms, with or without
 
-   modification, are permitted provided that the following conditions are met:
 
-   Redistributions of source code must retain the above copyright notice, this
 
-   list of conditions and the following disclaimer. Redistributions in binary
 
-   form must reproduce the above copyright notice, this list of conditions and
 
-   the following disclaimer in the documentation and/or other materials
 
-   provided with the distribution.
 
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
-   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
-   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
-   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 
-   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
-   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
-   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
-   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
-   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
-   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
-   POSSIBILITY OF SUCH DAMAGE.
 
-   DOCUEMENTATION
 
-   d3.phylogram.build(selector, nodes, options)
 
-     Creates a phylogram.
 
-     Arguments:
 
-       selector: selector of an element that will contain the SVG
 
-       nodes: JS object of nodes
 
-     Options:
 
-       width       
 
-         Width of the vis, will attempt to set a default based on the width of
 
-         the container.
 
-       height
 
-         Height of the vis, will attempt to set a default based on the height
 
-         of the container.
 
-       fill
 
-         Function for generating fill color for leaf nodes.
 
-       vis
 
-         Pre-constructed d3 vis.
 
-       tree
 
-         Pre-constructed d3 tree layout.
 
-       children
 
-         Function for retrieving an array of children given a node. Default is
 
-         to assume each node has an attribute called "children"
 
-       diagonal
 
-         Function that creates the d attribute for an svg:path. Defaults to a
 
-         right-angle diagonal.
 
-       skipTicks
 
-         Skip the tick rule.
 
-       skipBranchLengthScaling
 
-         Make a dendrogram instead of a phylogram.
 
-   
 
-   d3.phylogram.buildRadial(selector, nodes, options)
 
-     Creates a radial dendrogram.
 
-     Options: same as build, but without diagonal, skipTicks, and 
 
-       skipBranchLengthScaling
 
-   
 
-   d3.phylogram.rightAngleDiagonal()
 
-     Similar to d3.diagonal except it create an orthogonal crook instead of a
 
-     smooth Bezier curve.
 
-     
 
-   d3.phylogram.radialRightAngleDiagonal()
 
-     d3.phylogram.rightAngleDiagonal for radial layouts.
 
- */
 
- if (!d3) { throw "d3 wasn't included!"};
 
- (function() {
 
-   d3.phylogram = {}
 
-   d3.phylogram.rightAngleDiagonal = function() {
 
-     var projection = function(d) { return [d.y, d.x]; }
 
-     
 
-     var path = function(pathData) {
 
-       return "M" + pathData[0] + ' ' + pathData[1] + " " + pathData[2];
 
-     }
 
-     
 
-     function diagonal(diagonalPath, i) {
 
-       var source = diagonalPath.source,
 
-           target = diagonalPath.target,
 
-           midpointX = (source.x + target.x) / 2,
 
-           midpointY = (source.y + target.y) / 2,
 
-           pathData = [source, {x: target.x, y: source.y}, target];
 
-       pathData = pathData.map(projection);
 
-       return path(pathData)
 
-     }
 
-     
 
-     diagonal.projection = function(x) {
 
-       if (!arguments.length) return projection;
 
-       projection = x;
 
-       return diagonal;
 
-     };
 
-     
 
-     diagonal.path = function(x) {
 
-       if (!arguments.length) return path;
 
-       path = x;
 
-       return diagonal;
 
-     };
 
-     
 
-     return diagonal;
 
-   }
 
-   
 
-   d3.phylogram.radialRightAngleDiagonal = function() {
 
-     return d3.phylogram.rightAngleDiagonal()
 
-       .path(function(pathData) {
 
-         var src = pathData[0],
 
-             mid = pathData[1],
 
-             dst = pathData[2],
 
-             radius = Math.sqrt(src[0]*src[0] + src[1]*src[1]),
 
-             srcAngle = d3.phylogram.coordinateToAngle(src, radius),
 
-             midAngle = d3.phylogram.coordinateToAngle(mid, radius),
 
-             clockwise = Math.abs(midAngle - srcAngle) > Math.PI ? midAngle <= srcAngle : midAngle > srcAngle,
 
-             rotation = 0,
 
-             largeArc = 0,
 
-             sweep = clockwise ? 0 : 1;
 
-         return 'M' + src + ' ' +
 
-           "A" + [radius,radius] + ' ' + rotation + ' ' + largeArc+','+sweep + ' ' + mid +
 
-           'L' + dst;
 
-       })
 
-       .projection(function(d) {
 
-         var r = d.y, a = (d.x - 90) / 180 * Math.PI;
 
-         return [r * Math.cos(a), r * Math.sin(a)];
 
-       })
 
-   }
 
-   
 
-   // Convert XY and radius to angle of a circle centered at 0,0
 
-   d3.phylogram.coordinateToAngle = function(coord, radius) {
 
-     var wholeAngle = 2 * Math.PI,
 
-         quarterAngle = wholeAngle / 4
 
-     
 
-     var coordQuad = coord[0] >= 0 ? (coord[1] >= 0 ? 1 : 2) : (coord[1] >= 0 ? 4 : 3),
 
-         coordBaseAngle = Math.abs(Math.asin(coord[1] / radius))
 
-     
 
-     // Since this is just based on the angle of the right triangle formed
 
-     // by the coordinate and the origin, each quad will have different 
 
-     // offsets
 
-     switch (coordQuad) {
 
-       case 1:
 
-         coordAngle = quarterAngle - coordBaseAngle
 
-         break
 
-       case 2:
 
-         coordAngle = quarterAngle + coordBaseAngle
 
-         break
 
-       case 3:
 
-         coordAngle = 2*quarterAngle + quarterAngle - coordBaseAngle
 
-         break
 
-       case 4:
 
-         coordAngle = 3*quarterAngle + coordBaseAngle
 
-     }
 
-     return coordAngle
 
-   }
 
-   function scaleBranchLengths(nodes, w) {
 
-     // Visit all nodes and adjust y pos width distance metric
 
-     var visitPreOrder = function(root, callback) {
 
-       callback(root)
 
-       if (root.children) {
 
-         for (var i = root.children.length - 1; i >= 0; i--){
 
-           visitPreOrder(root.children[i], callback);
 
-         };
 
-       }
 
-     }
 
-     visitPreOrder(nodes[0], function(node) {
 
-       node.rootDist = (node.parent ? node.parent.rootDist : 0) + (node.length || 0)
 
-     })
 
-     var rootDists = nodes.map(function(n) { return n.rootDist; });
 
-     var yscale = d3.scale.linear()
 
-       .domain([0, d3.max(rootDists)])
 
-       .range([0, w]);
 
-     visitPreOrder(nodes[0], function(node) {
 
-       node.y = yscale(node.rootDist)
 
-     })
 
-     return yscale
 
-   }
 
-   
 
-   d3.phylogram.build = function(selector, nodes, options) {
 
-     options = options || {}
 
-     var w = options.width || d3.select(selector).style('width') || d3.select(selector).attr('width'),
 
-         h = options.height || d3.select(selector).style('height') || d3.select(selector).attr('height'),
 
-         w = parseInt(w),
 
-         h = parseInt(h);
 
-     var fill = options.fill || function(d) {
 
-       return 'cyan';
 
-     };
 
-     var size = options.size || function(d) {
 
-       return 6;
 
-     }
 
-     var nodeMouseOver = options.nodeMouseOver || function(d) {};
 
-     var nodeMouseOut  = options.nodeMouseOut  || function(d) {};
 
-     var nodeMouseDown = options.nodeMouseDown || function(d) {};
 
-     
 
-     var tree = options.tree || d3.layout.cluster()
 
-       .size([h, w])
 
-       .sort(function(node) { return node.children ? node.children.length : -1; })
 
-       .children(options.children || function(node) {
 
-         return node.children;
 
-       });
 
-     var diagonal = options.diagonal || d3.phylogram.rightAngleDiagonal();
 
-     var vis = options.vis || d3.select(selector).append("svg:svg")
 
-         .attr("width", w + 300)
 
-         .attr("height", h + 30)
 
-         .append("svg:g")
 
-         .attr("transform", "translate(20, 20)");
 
-     var nodes = tree(nodes);
 
-     
 
-     if (options.skipBranchLengthScaling) {
 
-       var yscale = d3.scale.linear()
 
-         .domain([0, w])
 
-         .range([0, w]);
 
-     } 
 
-     else {
 
-       var yscale = scaleBranchLengths(nodes, w)
 
-     }
 
-     
 
-     if (!options.skipTicks) {
 
-       vis.selectAll('line')
 
-           .data(yscale.ticks(10))
 
-           .enter().append('svg:line')
 
-           .attr('y1', 0)
 
-           .attr('y2', h)
 
-           .attr('x1', yscale)
 
-           .attr('x2', yscale)
 
-           .attr("stroke", "#ddd");
 
-       vis.selectAll("text.rule")
 
-           .data(yscale.ticks(10))
 
-           .enter().append("svg:text")
 
-           .attr("class", "rule")
 
-           .attr("x", yscale)
 
-           .attr("y", 0)
 
-           .attr("dy", -3)
 
-           .attr("text-anchor", "middle")
 
-           .attr('font-size', '9px')
 
-           .attr('fill', 'grey')
 
-           .text(function(d) { return Math.round(d*100) / 100; });
 
-     }
 
-         
 
-     var link = vis.selectAll("path.link")
 
-         .data(tree.links(nodes))
 
-         .enter().append("svg:path")
 
-         .attr("class", "link")
 
-         .attr("d", diagonal)
 
-         .attr("fill", "none")
 
-         .attr("stroke", "#aaa")
 
-         .attr("stroke-width", "4px");
 
-         
 
-     var node = vis.selectAll("g.node")
 
-         .data(nodes)
 
-         .enter().append("svg:g")
 
-         .attr("class", function(n) {
 
-           if (n.children) {
 
-             if (n.depth == 0) {
 
-               return "root node"
 
-             } 
 
-             else {
 
-               return "inner node"
 
-             }
 
-           } 
 
-           else {
 
-             return "leaf node"
 
-           }
 
-         })
 
-         .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
 
-      // style the root node
 
-      vis.selectAll('g.root.node')
 
-       .append('svg:circle')
 
-       .on('click', nodeMouseDown)
 
-       .on('mouseover', nodeMouseOver)
 
-       .on('mouseout', nodeMouseOut)
 
-       .attr("r", size)
 
-       .attr('fill', 'dimgrey')
 
-       .attr('stroke', 'black')
 
-       .attr('stroke-width', '2px');
 
-     // style the leaf nodes and add js event handlers
 
-     vis.selectAll('g.leaf.node')
 
-       .on('click', nodeMouseDown)
 
-       .on('mouseover', nodeMouseOver)
 
-       .on('mouseout', nodeMouseOut)
 
-       .append("svg:circle")
 
-       .attr("r", size)
 
-       .attr('stroke', 'dimgrey')
 
-       .attr('fill', fill)
 
-       .attr('stroke-width', '2px');
 
-     vis.selectAll('g.inner.node')
 
-       .on('click', nodeMouseDown)
 
-       .on('mouseover', nodeMouseOver)
 
-       .on('mouseout', nodeMouseOut)
 
-       .append("svg:circle")
 
-       .attr("r", size)
 
-       .attr('stroke', 'dimgrey')
 
-       .attr('stroke-width', '2px')
 
-       .attr('fill', 'white');
 
-     
 
-     if (!options.skipLabels) {
 
-       vis.selectAll('g.inner.node')
 
-         .append("svg:text")
 
-           .attr("dx", -6)
 
-           .attr("dy", -6)
 
-           .attr("text-anchor", 'end')
 
-           .attr('font-size', '9px')
 
-           .attr('fill', 'black')
 
-         //.text(function(d) { return d.length.toFixed(4); }); // hide length
 
-       vis.selectAll('g.leaf.node').append("svg:text")
 
-         .attr("dx", 8)
 
-         .attr("dy", 3)
 
-         .attr("text-anchor", "start")
 
-         .attr('font-family', 'Helvetica Neue, Helvetica, sans-serif')
 
-         .attr('font-size', '10px')
 
-         .attr('fill', 'black')
 
-         .text(function(d) {
 
-           // return d.name + ' (' + d.length.toFixed(4) + ')'; // hide length
 
-           return d.name;
 
-          });
 
-     }
 
-     return {tree: tree, vis: vis}
 
-   }
 
-   
 
-   d3.phylogram.buildRadial = function(selector, nodes, options) {
 
-     options = options || {};
 
-     
 
-     var fill = options.fill || function(d) {
 
-       return 'cyan';
 
-     };
 
-     var size = options.size || function(d) {
 
-       return 6;
 
-     }
 
-     var nodeMouseOver = options.nodeMouseOver || function(d) {};
 
-     var nodeMouseOut = options.nodeMouseOut || function(d) {};
 
-     var nodeMouseDown = options.nodeMouseDown || function(d) {};
 
-     
 
-     var w = options.width || d3.select(selector).style('width') || d3.select(selector).attr('width'),
 
-         r = w / 2,
 
-         labelWidth = options.skipLabels ? 10 : options.labelWidth || 120;
 
-     
 
-     var vis = d3.select(selector).append("svg:svg")
 
-         .attr("width", r * 2)
 
-         .attr("height", r * 2)
 
-         .append("svg:g")
 
-         .attr("transform", "translate(" + r + "," + r + ")");
 
-         
 
-     var tree = d3.layout.tree()
 
-       .size([360, r - labelWidth])
 
-       .sort(function(node) { return node.children ? node.children.length : -1; })
 
-       .children(options.children || function(node) {
 
-         return node.children;
 
-       })
 
-       .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
 
-     var phylogram = d3.phylogram.build(selector, nodes, {
 
-       vis: vis,
 
-       tree: tree,
 
-       fill : fill,
 
-       size: size,
 
-       nodeMouseOver : nodeMouseOver,
 
-       nodeMouseOut : nodeMouseOut,
 
-       nodeMouseDown : nodeMouseDown,
 
-       skipBranchLengthScaling: true,
 
-       skipTicks: true,
 
-       skipLabels: options.skipLabels,
 
-       diagonal: d3.phylogram.radialRightAngleDiagonal()
 
-     })
 
-     vis.selectAll('g.node')
 
-       .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
 
-     
 
-     if (!options.skipLabels) {
 
-       vis.selectAll('g.leaf.node text')
 
-         .attr("dx", function(d) { return d.x < 180 ? 8 : -8; })
 
-         .attr("dy", ".31em")
 
-         .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
 
-         .attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
 
-         .attr('font-family', 'Helvetica Neue, Helvetica, sans-serif')
 
-         .attr('font-size', '10px')
 
-         .attr('fill', 'black')
 
-         .text(function(d) {
 
-           return d.name;
 
-         });
 
-       vis.selectAll('g.inner.node text')
 
-         .attr("dx", function(d) { return d.x < 180 ? -6 : 6; })
 
-         .attr("text-anchor", function(d) { return d.x < 180 ? "end" : "start"; })
 
-         .attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; });
 
-     }
 
-     
 
-     return {tree: tree, vis: vis}
 
-   }
 
- }());
 
 
  |