158 lines
3.5 KiB
JavaScript
158 lines
3.5 KiB
JavaScript
import "../arrays/range";
|
|
import "../math/trigonometry";
|
|
import "layout";
|
|
|
|
d3.layout.chord = function() {
|
|
var chord = {},
|
|
chords,
|
|
groups,
|
|
matrix,
|
|
n,
|
|
padding = 0,
|
|
sortGroups,
|
|
sortSubgroups,
|
|
sortChords;
|
|
|
|
function relayout() {
|
|
var subgroups = {},
|
|
groupSums = [],
|
|
groupIndex = d3.range(n),
|
|
subgroupIndex = [],
|
|
k,
|
|
x,
|
|
x0,
|
|
i,
|
|
j;
|
|
|
|
chords = [];
|
|
groups = [];
|
|
|
|
// Compute the sum.
|
|
k = 0, i = -1; while (++i < n) {
|
|
x = 0, j = -1; while (++j < n) {
|
|
x += matrix[i][j];
|
|
}
|
|
groupSums.push(x);
|
|
subgroupIndex.push(d3.range(n));
|
|
k += x;
|
|
}
|
|
|
|
// Sort groups…
|
|
if (sortGroups) {
|
|
groupIndex.sort(function(a, b) {
|
|
return sortGroups(groupSums[a], groupSums[b]);
|
|
});
|
|
}
|
|
|
|
// Sort subgroups…
|
|
if (sortSubgroups) {
|
|
subgroupIndex.forEach(function(d, i) {
|
|
d.sort(function(a, b) {
|
|
return sortSubgroups(matrix[i][a], matrix[i][b]);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Convert the sum to scaling factor for [0, 2pi].
|
|
// TODO Allow start and end angle to be specified.
|
|
// TODO Allow padding to be specified as percentage?
|
|
k = (τ - padding * n) / k;
|
|
|
|
// Compute the start and end angle for each group and subgroup.
|
|
// Note: Opera has a bug reordering object literal properties!
|
|
x = 0, i = -1; while (++i < n) {
|
|
x0 = x, j = -1; while (++j < n) {
|
|
var di = groupIndex[i],
|
|
dj = subgroupIndex[di][j],
|
|
v = matrix[di][dj],
|
|
a0 = x,
|
|
a1 = x += v * k;
|
|
subgroups[di + "-" + dj] = {
|
|
index: di,
|
|
subindex: dj,
|
|
startAngle: a0,
|
|
endAngle: a1,
|
|
value: v
|
|
};
|
|
}
|
|
groups[di] = {
|
|
index: di,
|
|
startAngle: x0,
|
|
endAngle: x,
|
|
value: groupSums[di]
|
|
};
|
|
x += padding;
|
|
}
|
|
|
|
// Generate chords for each (non-empty) subgroup-subgroup link.
|
|
i = -1; while (++i < n) {
|
|
j = i - 1; while (++j < n) {
|
|
var source = subgroups[i + "-" + j],
|
|
target = subgroups[j + "-" + i];
|
|
if (source.value || target.value) {
|
|
chords.push(source.value < target.value
|
|
? {source: target, target: source}
|
|
: {source: source, target: target});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sortChords) resort();
|
|
}
|
|
|
|
function resort() {
|
|
chords.sort(function(a, b) {
|
|
return sortChords(
|
|
(a.source.value + a.target.value) / 2,
|
|
(b.source.value + b.target.value) / 2);
|
|
});
|
|
}
|
|
|
|
chord.matrix = function(x) {
|
|
if (!arguments.length) return matrix;
|
|
n = (matrix = x) && matrix.length;
|
|
chords = groups = null;
|
|
return chord;
|
|
};
|
|
|
|
chord.padding = function(x) {
|
|
if (!arguments.length) return padding;
|
|
padding = x;
|
|
chords = groups = null;
|
|
return chord;
|
|
};
|
|
|
|
chord.sortGroups = function(x) {
|
|
if (!arguments.length) return sortGroups;
|
|
sortGroups = x;
|
|
chords = groups = null;
|
|
return chord;
|
|
};
|
|
|
|
chord.sortSubgroups = function(x) {
|
|
if (!arguments.length) return sortSubgroups;
|
|
sortSubgroups = x;
|
|
chords = null;
|
|
return chord;
|
|
};
|
|
|
|
chord.sortChords = function(x) {
|
|
if (!arguments.length) return sortChords;
|
|
sortChords = x;
|
|
if (chords) resort();
|
|
return chord;
|
|
};
|
|
|
|
chord.chords = function() {
|
|
if (!chords) relayout();
|
|
return chords;
|
|
};
|
|
|
|
chord.groups = function() {
|
|
if (!groups) relayout();
|
|
return groups;
|
|
};
|
|
|
|
return chord;
|
|
};
|