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 | x = 0, i = -1; while (++i < n) { |
---|
59 | x0 = x, j = -1; while (++j < n) { |
---|
60 | var di = groupIndex[i], |
---|
61 | dj = subgroupIndex[i][j], |
---|
62 | v = matrix[di][dj]; |
---|
63 | subgroups[di + "-" + dj] = { |
---|
64 | index: di, |
---|
65 | subindex: dj, |
---|
66 | startAngle: x, |
---|
67 | endAngle: x += v * k, |
---|
68 | value: v |
---|
69 | }; |
---|
70 | } |
---|
71 | groups.push({ |
---|
72 | index: di, |
---|
73 | startAngle: x0, |
---|
74 | endAngle: x, |
---|
75 | value: (x - x0) / k |
---|
76 | }); |
---|
77 | x += padding; |
---|
78 | } |
---|
79 | |
---|
80 | // Generate chords for each (non-empty) subgroup-subgroup link. |
---|
81 | i = -1; while (++i < n) { |
---|
82 | j = i - 1; while (++j < n) { |
---|
83 | var source = subgroups[i + "-" + j], |
---|
84 | target = subgroups[j + "-" + i]; |
---|
85 | if (source.value || target.value) { |
---|
86 | chords.push(source.value < target.value |
---|
87 | ? {source: target, target: source} |
---|
88 | : {source: source, target: target}) |
---|
89 | } |
---|
90 | } |
---|
91 | } |
---|
92 | |
---|
93 | if (sortChords) resort(); |
---|
94 | } |
---|
95 | |
---|
96 | function resort() { |
---|
97 | chords.sort(function(a, b) { |
---|
98 | return sortChords(a.target.value, b.target.value); |
---|
99 | }); |
---|
100 | } |
---|
101 | |
---|
102 | chord.matrix = function(x) { |
---|
103 | if (!arguments.length) return matrix; |
---|
104 | n = (matrix = x) && matrix.length; |
---|
105 | chords = groups = null; |
---|
106 | return chord; |
---|
107 | }; |
---|
108 | |
---|
109 | chord.padding = function(x) { |
---|
110 | if (!arguments.length) return padding; |
---|
111 | padding = x; |
---|
112 | chords = groups = null; |
---|
113 | return chord; |
---|
114 | }; |
---|
115 | |
---|
116 | chord.sortGroups = function(x) { |
---|
117 | if (!arguments.length) return sortGroups; |
---|
118 | sortGroups = x; |
---|
119 | chords = groups = null; |
---|
120 | return chord; |
---|
121 | }; |
---|
122 | |
---|
123 | chord.sortSubgroups = function(x) { |
---|
124 | if (!arguments.length) return sortSubgroups; |
---|
125 | sortSubgroups = x; |
---|
126 | chords = null; |
---|
127 | return chord; |
---|
128 | }; |
---|
129 | |
---|
130 | chord.sortChords = function(x) { |
---|
131 | if (!arguments.length) return sortChords; |
---|
132 | sortChords = x; |
---|
133 | if (chords) resort(); |
---|
134 | return chord; |
---|
135 | }; |
---|
136 | |
---|
137 | chord.chords = function() { |
---|
138 | if (!chords) relayout(); |
---|
139 | return chords; |
---|
140 | }; |
---|
141 | |
---|
142 | chord.groups = function() { |
---|
143 | if (!groups) relayout(); |
---|
144 | return groups; |
---|
145 | }; |
---|
146 | |
---|
147 | return chord; |
---|
148 | }; |
---|