function computeNodeBreadths()

in app/assets/javascripts/sankey.js [336:446]


  function computeNodeBreadths() {

    layerComponents();

    components.forEach(function(component, i){
      bfs(component.root, function(node){
        var result = node.sourceLinks
          .filter(function(sourceLink){
            return sourceLink.target.component == i;
          })
          .map(function(sourceLink){
            return sourceLink.target;
          });
        return result;
      });
    });

    var max = 0;
    var componentsByBreadth = d3.nest()
      .key(function(d) { return d.x; })
      // .sortKeys(d3.ascending)
      .entries(components)
      .map(function(d) { return d.values; });

    var max = -1, nextMax = -1;
    componentsByBreadth.forEach(function(c){
      c.forEach(function(component){
        component.x = max + 1;
        component.scc.forEach(function(node){
          if (node.layer) 
            node.x = node.layer;
          else 
            node.x = component.x + node.x;
          nextMax = Math.max(nextMax, node.x);

        });
      });
      max = nextMax;
    });

    
    nodes
      .filter(function(node) {
        var outLinks = node.sourceLinks.filter(function(link){ return link.source.name != link.target.name; });
        return (outLinks.length == 0);
      })
      .forEach(function(node) { node.x = max; })

    scaleNodeBreadths((size[0] - nodeWidth) / Math.max(max, 1));

    function flatten(a) {
      return [].concat.apply([], a);
    }

    function layerComponents() {
      var remainingComponents = components,
          nextComponents,
          visitedIndex,
          x = 0;

      while (remainingComponents.length) {
        nextComponents = [];
        visitedIndex = {};

        remainingComponents.forEach(function(component) {
          component.x = x;

          component.scc.forEach(function(n) {
            n.sourceLinks.forEach(function(l) {
              if (!visitedIndex.hasOwnProperty(l.target.component) &&
                   l.target.component != component.index) {
                nextComponents.push(components[l.target.component]);
                visitedIndex[l.target.component] = true;
              }
            })
          });
        });

        remainingComponents = nextComponents;
        ++x;
      }
    }

    function bfs(node, extractTargets) {
      var queue = [node], currentCount = 1, nextCount = 0;
      var x = 0;

      while(currentCount > 0) {
        var currentNode = queue.shift();
        currentCount--;

        if (!currentNode.hasOwnProperty('x')) {
          currentNode.x = x;
          currentNode.dx = nodeWidth;

          var targets = extractTargets(currentNode);

          queue = queue.concat(targets);
          nextCount += targets.length;
        }


        if (currentCount == 0) { // level change
          x++;
          currentCount = nextCount;
          nextCount = 0;
        }

      }
    }
  }