toolkit/javascript/d3/src/layout/chord.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 d3.layout.chord = function() {
       
     2   var chord = {},
       
     3       chords,
       
     4       groups,
       
     5       matrix,
       
     6       n,
       
     7       padding = 0,
       
     8       sortGroups,
       
     9       sortSubgroups,
       
    10       sortChords;
       
    11 
       
    12   function relayout() {
       
    13     var subgroups = {},
       
    14         groupSums = [],
       
    15         groupIndex = d3.range(n),
       
    16         subgroupIndex = [],
       
    17         k,
       
    18         x,
       
    19         x0,
       
    20         i,
       
    21         j;
       
    22 
       
    23     chords = [];
       
    24     groups = [];
       
    25 
       
    26     // Compute the sum.
       
    27     k = 0, i = -1; while (++i < n) {
       
    28       x = 0, j = -1; while (++j < n) {
       
    29         x += matrix[i][j];
       
    30       }
       
    31       groupSums.push(x);
       
    32       subgroupIndex.push(d3.range(n));
       
    33       k += x;
       
    34     }
       
    35 
       
    36     // Sort groups…
       
    37     if (sortGroups) {
       
    38       groupIndex.sort(function(a, b) {
       
    39         return sortGroups(groupSums[a], groupSums[b]);
       
    40       });
       
    41     }
       
    42 
       
    43     // Sort subgroups…
       
    44     if (sortSubgroups) {
       
    45       subgroupIndex.forEach(function(d, i) {
       
    46         d.sort(function(a, b) {
       
    47           return sortSubgroups(matrix[i][a], matrix[i][b]);
       
    48         });
       
    49       });
       
    50     }
       
    51 
       
    52     // Convert the sum to scaling factor for [0, 2pi].
       
    53     // TODO Allow start and end angle to be specified.
       
    54     // TODO Allow padding to be specified as percentage?
       
    55     k = (2 * Math.PI - padding * n) / k;
       
    56 
       
    57     // Compute the start and end angle for each group and subgroup.
       
    58     // Note: Opera has a bug reordering object literal properties!
       
    59     x = 0, i = -1; while (++i < n) {
       
    60       x0 = x, j = -1; while (++j < n) {
       
    61         var di = groupIndex[i],
       
    62             dj = subgroupIndex[di][j],
       
    63             v = matrix[di][dj],
       
    64             a0 = x,
       
    65             a1 = x += v * k;
       
    66         subgroups[di + "-" + dj] = {
       
    67           index: di,
       
    68           subindex: dj,
       
    69           startAngle: a0,
       
    70           endAngle: a1,
       
    71           value: v
       
    72         };
       
    73       }
       
    74       groups.push({
       
    75         index: di,
       
    76         startAngle: x0,
       
    77         endAngle: x,
       
    78         value: (x - x0) / k
       
    79       });
       
    80       x += padding;
       
    81     }
       
    82 
       
    83     // Generate chords for each (non-empty) subgroup-subgroup link.
       
    84     i = -1; while (++i < n) {
       
    85       j = i - 1; while (++j < n) {
       
    86         var source = subgroups[i + "-" + j],
       
    87             target = subgroups[j + "-" + i];
       
    88         if (source.value || target.value) {
       
    89           chords.push(source.value < target.value
       
    90               ? {source: target, target: source}
       
    91               : {source: source, target: target});
       
    92         }
       
    93       }
       
    94     }
       
    95 
       
    96     if (sortChords) resort();
       
    97   }
       
    98 
       
    99   function resort() {
       
   100     chords.sort(function(a, b) {
       
   101       return sortChords(
       
   102           (a.source.value + a.target.value) / 2,
       
   103           (b.source.value + b.target.value) / 2);
       
   104     });
       
   105   }
       
   106 
       
   107   chord.matrix = function(x) {
       
   108     if (!arguments.length) return matrix;
       
   109     n = (matrix = x) && matrix.length;
       
   110     chords = groups = null;
       
   111     return chord;
       
   112   };
       
   113 
       
   114   chord.padding = function(x) {
       
   115     if (!arguments.length) return padding;
       
   116     padding = x;
       
   117     chords = groups = null;
       
   118     return chord;
       
   119   };
       
   120 
       
   121   chord.sortGroups = function(x) {
       
   122     if (!arguments.length) return sortGroups;
       
   123     sortGroups = x;
       
   124     chords = groups = null;
       
   125     return chord;
       
   126   };
       
   127 
       
   128   chord.sortSubgroups = function(x) {
       
   129     if (!arguments.length) return sortSubgroups;
       
   130     sortSubgroups = x;
       
   131     chords = null;
       
   132     return chord;
       
   133   };
       
   134 
       
   135   chord.sortChords = function(x) {
       
   136     if (!arguments.length) return sortChords;
       
   137     sortChords = x;
       
   138     if (chords) resort();
       
   139     return chord;
       
   140   };
       
   141 
       
   142   chord.chords = function() {
       
   143     if (!chords) relayout();
       
   144     return chords;
       
   145   };
       
   146 
       
   147   chord.groups = function() {
       
   148     if (!groups) relayout();
       
   149     return groups;
       
   150   };
       
   151 
       
   152   return chord;
       
   153 };