pyk 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/app/assets/javascripts/lib/chardinjs.min.js +2 -0
- data/app/assets/javascripts/lib/crossfilter.js +1383 -1
- data/app/assets/javascripts/lib/{d3.js → d3.v3.js} +0 -0
- data/app/assets/javascripts/lib/dc.js +3492 -757
- data/app/assets/javascripts/lib/jquery.gridster.js +2 -3621
- data/app/assets/javascripts/lib/markermanager.js +2 -980
- data/app/assets/javascripts/lib/underscore.js +1276 -0
- data/app/assets/javascripts/nvd3/lib/colorbrewer.js +302 -0
- data/app/assets/javascripts/nvd3/lib/crossfilter.js +1180 -0
- data/app/assets/javascripts/nvd3/lib/crossfilter.min.js +1 -0
- data/app/assets/javascripts/nvd3/lib/d3.v2.js +7033 -0
- data/app/assets/javascripts/nvd3/lib/d3.v2.min.js +4 -0
- data/app/assets/javascripts/nvd3/lib/d3.v3.js +8436 -0
- data/app/assets/javascripts/nvd3/lib/fisheye.js +86 -0
- data/app/assets/javascripts/nvd3/lib/hive.js +80 -0
- data/app/assets/javascripts/nvd3/lib/horizon.js +192 -0
- data/app/assets/javascripts/nvd3/lib/sankey.js +292 -0
- data/app/assets/javascripts/nvd3/nv.d3.js +14312 -0
- data/app/assets/javascripts/nvd3/nv.d3.min.js +6 -0
- data/app/assets/javascripts/nvd3/src/core.js +122 -0
- data/app/assets/javascripts/nvd3/src/interactiveLayer.js +251 -0
- data/app/assets/javascripts/nvd3/src/models/axis.js +405 -0
- data/app/assets/javascripts/nvd3/src/models/backup/bullet.js +250 -0
- data/app/assets/javascripts/nvd3/src/models/backup/bulletChart.js +349 -0
- data/app/assets/javascripts/nvd3/src/models/boilerplate.js +104 -0
- data/app/assets/javascripts/nvd3/src/models/bullet.js +385 -0
- data/app/assets/javascripts/nvd3/src/models/bulletChart.js +343 -0
- data/app/assets/javascripts/nvd3/src/models/cumulativeLineChart.js +782 -0
- data/app/assets/javascripts/nvd3/src/models/discreteBar.js +349 -0
- data/app/assets/javascripts/nvd3/src/models/discreteBarChart.js +333 -0
- data/app/assets/javascripts/nvd3/src/models/distribution.js +148 -0
- data/app/assets/javascripts/nvd3/src/models/historicalBar.js +331 -0
- data/app/assets/javascripts/nvd3/src/models/historicalBarChart.js +419 -0
- data/app/assets/javascripts/nvd3/src/models/indentedTree.js +337 -0
- data/app/assets/javascripts/nvd3/src/models/legend.js +270 -0
- data/app/assets/javascripts/nvd3/src/models/line.js +284 -0
- data/app/assets/javascripts/nvd3/src/models/lineChart.js +465 -0
- data/app/assets/javascripts/nvd3/src/models/linePlusBarChart.js +433 -0
- data/app/assets/javascripts/nvd3/src/models/linePlusBarWithFocusChart.js +658 -0
- data/app/assets/javascripts/nvd3/src/models/lineWithFisheye.js +200 -0
- data/app/assets/javascripts/nvd3/src/models/lineWithFisheyeChart.js +297 -0
- data/app/assets/javascripts/nvd3/src/models/lineWithFocusChart.js +574 -0
- data/app/assets/javascripts/nvd3/src/models/multiBar.js +461 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarChart.js +524 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarHorizontal.js +424 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarHorizontalChart.js +434 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarTimeSeries.js +384 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarTimeSeriesChart.js +405 -0
- data/app/assets/javascripts/nvd3/src/models/multiChart.js +452 -0
- data/app/assets/javascripts/nvd3/src/models/ohlcBar.js +380 -0
- data/app/assets/javascripts/nvd3/src/models/parallelCoordinates.js +239 -0
- data/app/assets/javascripts/nvd3/src/models/pie.js +398 -0
- data/app/assets/javascripts/nvd3/src/models/pieChart.js +292 -0
- data/app/assets/javascripts/nvd3/src/models/scatter.js +674 -0
- data/app/assets/javascripts/nvd3/src/models/scatterChart.js +628 -0
- data/app/assets/javascripts/nvd3/src/models/scatterPlusLineChart.js +620 -0
- data/app/assets/javascripts/nvd3/src/models/sparkline.js +194 -0
- data/app/assets/javascripts/nvd3/src/models/sparklinePlus.js +295 -0
- data/app/assets/javascripts/nvd3/src/models/stackedArea.js +368 -0
- data/app/assets/javascripts/nvd3/src/models/stackedAreaChart.js +629 -0
- data/app/assets/javascripts/nvd3/src/tooltip.js +490 -0
- data/app/assets/javascripts/nvd3/src/utils.js +152 -0
- data/app/assets/javascripts/pyk.js +1 -0
- data/app/assets/stylesheets/lib/chardinjs.css +82 -0
- data/app/assets/stylesheets/nvd3/nv.d3.css +769 -0
- data/app/assets/stylesheets/pyk.css.scss +1 -0
- metadata +61 -2
@@ -0,0 +1,86 @@
|
|
1
|
+
(function() {
|
2
|
+
d3.fisheye = {
|
3
|
+
scale: function(scaleType) {
|
4
|
+
return d3_fisheye_scale(scaleType(), 3, 0);
|
5
|
+
},
|
6
|
+
circular: function() {
|
7
|
+
var radius = 200,
|
8
|
+
distortion = 2,
|
9
|
+
k0,
|
10
|
+
k1,
|
11
|
+
focus = [0, 0];
|
12
|
+
|
13
|
+
function fisheye(d) {
|
14
|
+
var dx = d.x - focus[0],
|
15
|
+
dy = d.y - focus[1],
|
16
|
+
dd = Math.sqrt(dx * dx + dy * dy);
|
17
|
+
if (!dd || dd >= radius) return {x: d.x, y: d.y, z: 1};
|
18
|
+
var k = k0 * (1 - Math.exp(-dd * k1)) / dd * .75 + .25;
|
19
|
+
return {x: focus[0] + dx * k, y: focus[1] + dy * k, z: Math.min(k, 10)};
|
20
|
+
}
|
21
|
+
|
22
|
+
function rescale() {
|
23
|
+
k0 = Math.exp(distortion);
|
24
|
+
k0 = k0 / (k0 - 1) * radius;
|
25
|
+
k1 = distortion / radius;
|
26
|
+
return fisheye;
|
27
|
+
}
|
28
|
+
|
29
|
+
fisheye.radius = function(_) {
|
30
|
+
if (!arguments.length) return radius;
|
31
|
+
radius = +_;
|
32
|
+
return rescale();
|
33
|
+
};
|
34
|
+
|
35
|
+
fisheye.distortion = function(_) {
|
36
|
+
if (!arguments.length) return distortion;
|
37
|
+
distortion = +_;
|
38
|
+
return rescale();
|
39
|
+
};
|
40
|
+
|
41
|
+
fisheye.focus = function(_) {
|
42
|
+
if (!arguments.length) return focus;
|
43
|
+
focus = _;
|
44
|
+
return fisheye;
|
45
|
+
};
|
46
|
+
|
47
|
+
return rescale();
|
48
|
+
}
|
49
|
+
};
|
50
|
+
|
51
|
+
function d3_fisheye_scale(scale, d, a) {
|
52
|
+
|
53
|
+
function fisheye(_) {
|
54
|
+
var x = scale(_),
|
55
|
+
left = x < a,
|
56
|
+
v,
|
57
|
+
range = d3.extent(scale.range()),
|
58
|
+
min = range[0],
|
59
|
+
max = range[1],
|
60
|
+
m = left ? a - min : max - a;
|
61
|
+
if (m == 0) m = max - min;
|
62
|
+
return (left ? -1 : 1) * m * (d + 1) / (d + (m / Math.abs(x - a))) + a;
|
63
|
+
}
|
64
|
+
|
65
|
+
fisheye.distortion = function(_) {
|
66
|
+
if (!arguments.length) return d;
|
67
|
+
d = +_;
|
68
|
+
return fisheye;
|
69
|
+
};
|
70
|
+
|
71
|
+
fisheye.focus = function(_) {
|
72
|
+
if (!arguments.length) return a;
|
73
|
+
a = +_;
|
74
|
+
return fisheye;
|
75
|
+
};
|
76
|
+
|
77
|
+
fisheye.copy = function() {
|
78
|
+
return d3_fisheye_scale(scale.copy(), d, a);
|
79
|
+
};
|
80
|
+
|
81
|
+
fisheye.nice = scale.nice;
|
82
|
+
fisheye.ticks = scale.ticks;
|
83
|
+
fisheye.tickFormat = scale.tickFormat;
|
84
|
+
return d3.rebind(fisheye, scale, "domain", "range");
|
85
|
+
}
|
86
|
+
})();
|
@@ -0,0 +1,80 @@
|
|
1
|
+
d3.hive = {};
|
2
|
+
|
3
|
+
d3.hive.link = function() {
|
4
|
+
var source = function(d) { return d.source; },
|
5
|
+
target = function(d) { return d.target; },
|
6
|
+
angle = function(d) { return d.angle; },
|
7
|
+
startRadius = function(d) { return d.radius; },
|
8
|
+
endRadius = startRadius,
|
9
|
+
arcOffset = -Math.PI / 2;
|
10
|
+
|
11
|
+
function link(d, i) {
|
12
|
+
var s = node(source, this, d, i),
|
13
|
+
t = node(target, this, d, i),
|
14
|
+
x;
|
15
|
+
if (t.a < s.a) x = t, t = s, s = x;
|
16
|
+
if (t.a - s.a > Math.PI) s.a += 2 * Math.PI;
|
17
|
+
var a1 = s.a + (t.a - s.a) / 3,
|
18
|
+
a2 = t.a - (t.a - s.a) / 3;
|
19
|
+
return s.r0 - s.r1 || t.r0 - t.r1
|
20
|
+
? "M" + Math.cos(s.a) * s.r0 + "," + Math.sin(s.a) * s.r0
|
21
|
+
+ "L" + Math.cos(s.a) * s.r1 + "," + Math.sin(s.a) * s.r1
|
22
|
+
+ "C" + Math.cos(a1) * s.r1 + "," + Math.sin(a1) * s.r1
|
23
|
+
+ " " + Math.cos(a2) * t.r1 + "," + Math.sin(a2) * t.r1
|
24
|
+
+ " " + Math.cos(t.a) * t.r1 + "," + Math.sin(t.a) * t.r1
|
25
|
+
+ "L" + Math.cos(t.a) * t.r0 + "," + Math.sin(t.a) * t.r0
|
26
|
+
+ "C" + Math.cos(a2) * t.r0 + "," + Math.sin(a2) * t.r0
|
27
|
+
+ " " + Math.cos(a1) * s.r0 + "," + Math.sin(a1) * s.r0
|
28
|
+
+ " " + Math.cos(s.a) * s.r0 + "," + Math.sin(s.a) * s.r0
|
29
|
+
: "M" + Math.cos(s.a) * s.r0 + "," + Math.sin(s.a) * s.r0
|
30
|
+
+ "C" + Math.cos(a1) * s.r1 + "," + Math.sin(a1) * s.r1
|
31
|
+
+ " " + Math.cos(a2) * t.r1 + "," + Math.sin(a2) * t.r1
|
32
|
+
+ " " + Math.cos(t.a) * t.r1 + "," + Math.sin(t.a) * t.r1;
|
33
|
+
}
|
34
|
+
|
35
|
+
function node(method, thiz, d, i) {
|
36
|
+
var node = method.call(thiz, d, i),
|
37
|
+
a = +(typeof angle === "function" ? angle.call(thiz, node, i) : angle) + arcOffset,
|
38
|
+
r0 = +(typeof startRadius === "function" ? startRadius.call(thiz, node, i) : startRadius),
|
39
|
+
r1 = (startRadius === endRadius ? r0 : +(typeof endRadius === "function" ? endRadius.call(thiz, node, i) : endRadius));
|
40
|
+
return {r0: r0, r1: r1, a: a};
|
41
|
+
}
|
42
|
+
|
43
|
+
link.source = function(_) {
|
44
|
+
if (!arguments.length) return source;
|
45
|
+
source = _;
|
46
|
+
return link;
|
47
|
+
};
|
48
|
+
|
49
|
+
link.target = function(_) {
|
50
|
+
if (!arguments.length) return target;
|
51
|
+
target = _;
|
52
|
+
return link;
|
53
|
+
};
|
54
|
+
|
55
|
+
link.angle = function(_) {
|
56
|
+
if (!arguments.length) return angle;
|
57
|
+
angle = _;
|
58
|
+
return link;
|
59
|
+
};
|
60
|
+
|
61
|
+
link.radius = function(_) {
|
62
|
+
if (!arguments.length) return startRadius;
|
63
|
+
startRadius = endRadius = _;
|
64
|
+
return link;
|
65
|
+
};
|
66
|
+
|
67
|
+
link.startRadius = function(_) {
|
68
|
+
if (!arguments.length) return startRadius;
|
69
|
+
startRadius = _;
|
70
|
+
return link;
|
71
|
+
};
|
72
|
+
|
73
|
+
link.endRadius = function(_) {
|
74
|
+
if (!arguments.length) return endRadius;
|
75
|
+
endRadius = _;
|
76
|
+
return link;
|
77
|
+
};
|
78
|
+
|
79
|
+
return link;
|
80
|
+
};
|
@@ -0,0 +1,192 @@
|
|
1
|
+
(function() {
|
2
|
+
d3.horizon = function() {
|
3
|
+
var bands = 1, // between 1 and 5, typically
|
4
|
+
mode = "offset", // or mirror
|
5
|
+
interpolate = "linear", // or basis, monotone, step-before, etc.
|
6
|
+
x = d3_horizonX,
|
7
|
+
y = d3_horizonY,
|
8
|
+
w = 960,
|
9
|
+
h = 40,
|
10
|
+
duration = 0;
|
11
|
+
|
12
|
+
var color = d3.scale.linear()
|
13
|
+
.domain([-1, 0, 1])
|
14
|
+
.range(["#d62728", "#fff", "#1f77b4"]);
|
15
|
+
|
16
|
+
// For each small multiple…
|
17
|
+
function horizon(g) {
|
18
|
+
g.each(function(d, i) {
|
19
|
+
var g = d3.select(this),
|
20
|
+
n = 2 * bands + 1,
|
21
|
+
xMin = Infinity,
|
22
|
+
xMax = -Infinity,
|
23
|
+
yMax = -Infinity,
|
24
|
+
x0, // old x-scale
|
25
|
+
y0, // old y-scale
|
26
|
+
id; // unique id for paths
|
27
|
+
|
28
|
+
// Compute x- and y-values along with extents.
|
29
|
+
var data = d.map(function(d, i) {
|
30
|
+
var xv = x.call(this, d, i),
|
31
|
+
yv = y.call(this, d, i);
|
32
|
+
if (xv < xMin) xMin = xv;
|
33
|
+
if (xv > xMax) xMax = xv;
|
34
|
+
if (-yv > yMax) yMax = -yv;
|
35
|
+
if (yv > yMax) yMax = yv;
|
36
|
+
return [xv, yv];
|
37
|
+
});
|
38
|
+
|
39
|
+
// Compute the new x- and y-scales, and transform.
|
40
|
+
var x1 = d3.scale.linear().domain([xMin, xMax]).range([0, w]),
|
41
|
+
y1 = d3.scale.linear().domain([0, yMax]).range([0, h * bands]),
|
42
|
+
t1 = d3_horizonTransform(bands, h, mode);
|
43
|
+
|
44
|
+
// Retrieve the old scales, if this is an update.
|
45
|
+
if (this.__chart__) {
|
46
|
+
x0 = this.__chart__.x;
|
47
|
+
y0 = this.__chart__.y;
|
48
|
+
t0 = this.__chart__.t;
|
49
|
+
id = this.__chart__.id;
|
50
|
+
} else {
|
51
|
+
x0 = x1.copy();
|
52
|
+
y0 = y1.copy();
|
53
|
+
t0 = t1;
|
54
|
+
id = ++d3_horizonId;
|
55
|
+
}
|
56
|
+
|
57
|
+
// We'll use a defs to store the area path and the clip path.
|
58
|
+
var defs = g.selectAll("defs")
|
59
|
+
.data([null]);
|
60
|
+
|
61
|
+
// The clip path is a simple rect.
|
62
|
+
defs.enter().append("defs").append("clipPath")
|
63
|
+
.attr("id", "d3_horizon_clip" + id)
|
64
|
+
.append("rect")
|
65
|
+
.attr("width", w)
|
66
|
+
.attr("height", h);
|
67
|
+
|
68
|
+
defs.select("rect").transition()
|
69
|
+
.duration(duration)
|
70
|
+
.attr("width", w)
|
71
|
+
.attr("height", h);
|
72
|
+
|
73
|
+
// We'll use a container to clip all horizon layers at once.
|
74
|
+
g.selectAll("g")
|
75
|
+
.data([null])
|
76
|
+
.enter().append("g")
|
77
|
+
.attr("clip-path", "url(#d3_horizon_clip" + id + ")");
|
78
|
+
|
79
|
+
// Instantiate each copy of the path with different transforms.
|
80
|
+
var path = g.select("g").selectAll("path")
|
81
|
+
.data(d3.range(-1, -bands - 1, -1).concat(d3.range(1, bands + 1)), Number);
|
82
|
+
|
83
|
+
var d0 = d3_horizonArea
|
84
|
+
.interpolate(interpolate)
|
85
|
+
.x(function(d) { return x0(d[0]); })
|
86
|
+
.y0(h * bands)
|
87
|
+
.y1(function(d) { return h * bands - y0(d[1]); })
|
88
|
+
(data);
|
89
|
+
|
90
|
+
var d1 = d3_horizonArea
|
91
|
+
.x(function(d) { return x1(d[0]); })
|
92
|
+
.y1(function(d) { return h * bands - y1(d[1]); })
|
93
|
+
(data);
|
94
|
+
|
95
|
+
path.enter().append("path")
|
96
|
+
.style("fill", color)
|
97
|
+
.attr("transform", t0)
|
98
|
+
.attr("d", d0);
|
99
|
+
|
100
|
+
path.transition()
|
101
|
+
.duration(duration)
|
102
|
+
.style("fill", color)
|
103
|
+
.attr("transform", t1)
|
104
|
+
.attr("d", d1);
|
105
|
+
|
106
|
+
path.exit().transition()
|
107
|
+
.duration(duration)
|
108
|
+
.attr("transform", t1)
|
109
|
+
.attr("d", d1)
|
110
|
+
.remove();
|
111
|
+
|
112
|
+
// Stash the new scales.
|
113
|
+
this.__chart__ = {x: x1, y: y1, t: t1, id: id};
|
114
|
+
});
|
115
|
+
d3.timer.flush();
|
116
|
+
}
|
117
|
+
|
118
|
+
horizon.duration = function(x) {
|
119
|
+
if (!arguments.length) return duration;
|
120
|
+
duration = +x;
|
121
|
+
return horizon;
|
122
|
+
};
|
123
|
+
|
124
|
+
horizon.bands = function(x) {
|
125
|
+
if (!arguments.length) return bands;
|
126
|
+
bands = +x;
|
127
|
+
color.domain([-bands, 0, bands]);
|
128
|
+
return horizon;
|
129
|
+
};
|
130
|
+
|
131
|
+
horizon.mode = function(x) {
|
132
|
+
if (!arguments.length) return mode;
|
133
|
+
mode = x + "";
|
134
|
+
return horizon;
|
135
|
+
};
|
136
|
+
|
137
|
+
horizon.colors = function(x) {
|
138
|
+
if (!arguments.length) return color.range();
|
139
|
+
color.range(x);
|
140
|
+
return horizon;
|
141
|
+
};
|
142
|
+
|
143
|
+
horizon.interpolate = function(x) {
|
144
|
+
if (!arguments.length) return interpolate;
|
145
|
+
interpolate = x + "";
|
146
|
+
return horizon;
|
147
|
+
};
|
148
|
+
|
149
|
+
horizon.x = function(z) {
|
150
|
+
if (!arguments.length) return x;
|
151
|
+
x = z;
|
152
|
+
return horizon;
|
153
|
+
};
|
154
|
+
|
155
|
+
horizon.y = function(z) {
|
156
|
+
if (!arguments.length) return y;
|
157
|
+
y = z;
|
158
|
+
return horizon;
|
159
|
+
};
|
160
|
+
|
161
|
+
horizon.width = function(x) {
|
162
|
+
if (!arguments.length) return w;
|
163
|
+
w = +x;
|
164
|
+
return horizon;
|
165
|
+
};
|
166
|
+
|
167
|
+
horizon.height = function(x) {
|
168
|
+
if (!arguments.length) return h;
|
169
|
+
h = +x;
|
170
|
+
return horizon;
|
171
|
+
};
|
172
|
+
|
173
|
+
return horizon;
|
174
|
+
};
|
175
|
+
|
176
|
+
var d3_horizonArea = d3.svg.area(),
|
177
|
+
d3_horizonId = 0;
|
178
|
+
|
179
|
+
function d3_horizonX(d) {
|
180
|
+
return d[0];
|
181
|
+
}
|
182
|
+
|
183
|
+
function d3_horizonY(d) {
|
184
|
+
return d[1];
|
185
|
+
}
|
186
|
+
|
187
|
+
function d3_horizonTransform(bands, h, mode) {
|
188
|
+
return mode == "offset"
|
189
|
+
? function(d) { return "translate(0," + (d + (d < 0) - bands) * h + ")"; }
|
190
|
+
: function(d) { return (d < 0 ? "scale(1,-1)" : "") + "translate(0," + (d - bands) * h + ")"; };
|
191
|
+
}
|
192
|
+
})();
|
@@ -0,0 +1,292 @@
|
|
1
|
+
d3.sankey = function() {
|
2
|
+
var sankey = {},
|
3
|
+
nodeWidth = 24,
|
4
|
+
nodePadding = 8,
|
5
|
+
size = [1, 1],
|
6
|
+
nodes = [],
|
7
|
+
links = [];
|
8
|
+
|
9
|
+
sankey.nodeWidth = function(_) {
|
10
|
+
if (!arguments.length) return nodeWidth;
|
11
|
+
nodeWidth = +_;
|
12
|
+
return sankey;
|
13
|
+
};
|
14
|
+
|
15
|
+
sankey.nodePadding = function(_) {
|
16
|
+
if (!arguments.length) return nodePadding;
|
17
|
+
nodePadding = +_;
|
18
|
+
return sankey;
|
19
|
+
};
|
20
|
+
|
21
|
+
sankey.nodes = function(_) {
|
22
|
+
if (!arguments.length) return nodes;
|
23
|
+
nodes = _;
|
24
|
+
return sankey;
|
25
|
+
};
|
26
|
+
|
27
|
+
sankey.links = function(_) {
|
28
|
+
if (!arguments.length) return links;
|
29
|
+
links = _;
|
30
|
+
return sankey;
|
31
|
+
};
|
32
|
+
|
33
|
+
sankey.size = function(_) {
|
34
|
+
if (!arguments.length) return size;
|
35
|
+
size = _;
|
36
|
+
return sankey;
|
37
|
+
};
|
38
|
+
|
39
|
+
sankey.layout = function(iterations) {
|
40
|
+
computeNodeLinks();
|
41
|
+
computeNodeValues();
|
42
|
+
computeNodeBreadths();
|
43
|
+
computeNodeDepths(iterations);
|
44
|
+
computeLinkDepths();
|
45
|
+
return sankey;
|
46
|
+
};
|
47
|
+
|
48
|
+
sankey.relayout = function() {
|
49
|
+
computeLinkDepths();
|
50
|
+
return sankey;
|
51
|
+
};
|
52
|
+
|
53
|
+
sankey.link = function() {
|
54
|
+
var curvature = .5;
|
55
|
+
|
56
|
+
function link(d) {
|
57
|
+
var x0 = d.source.x + d.source.dx,
|
58
|
+
x1 = d.target.x,
|
59
|
+
xi = d3.interpolateNumber(x0, x1),
|
60
|
+
x2 = xi(curvature),
|
61
|
+
x3 = xi(1 - curvature),
|
62
|
+
y0 = d.source.y + d.sy + d.dy / 2,
|
63
|
+
y1 = d.target.y + d.ty + d.dy / 2;
|
64
|
+
return "M" + x0 + "," + y0
|
65
|
+
+ "C" + x2 + "," + y0
|
66
|
+
+ " " + x3 + "," + y1
|
67
|
+
+ " " + x1 + "," + y1;
|
68
|
+
}
|
69
|
+
|
70
|
+
link.curvature = function(_) {
|
71
|
+
if (!arguments.length) return curvature;
|
72
|
+
curvature = +_;
|
73
|
+
return link;
|
74
|
+
};
|
75
|
+
|
76
|
+
return link;
|
77
|
+
};
|
78
|
+
|
79
|
+
// Populate the sourceLinks and targetLinks for each node.
|
80
|
+
// Also, if the source and target are not objects, assume they are indices.
|
81
|
+
function computeNodeLinks() {
|
82
|
+
nodes.forEach(function(node) {
|
83
|
+
node.sourceLinks = [];
|
84
|
+
node.targetLinks = [];
|
85
|
+
});
|
86
|
+
links.forEach(function(link) {
|
87
|
+
var source = link.source,
|
88
|
+
target = link.target;
|
89
|
+
if (typeof source === "number") source = link.source = nodes[link.source];
|
90
|
+
if (typeof target === "number") target = link.target = nodes[link.target];
|
91
|
+
source.sourceLinks.push(link);
|
92
|
+
target.targetLinks.push(link);
|
93
|
+
});
|
94
|
+
}
|
95
|
+
|
96
|
+
// Compute the value (size) of each node by summing the associated links.
|
97
|
+
function computeNodeValues() {
|
98
|
+
nodes.forEach(function(node) {
|
99
|
+
node.value = Math.max(
|
100
|
+
d3.sum(node.sourceLinks, value),
|
101
|
+
d3.sum(node.targetLinks, value)
|
102
|
+
);
|
103
|
+
});
|
104
|
+
}
|
105
|
+
|
106
|
+
// Iteratively assign the breadth (x-position) for each node.
|
107
|
+
// Nodes are assigned the maximum breadth of incoming neighbors plus one;
|
108
|
+
// nodes with no incoming links are assigned breadth zero, while
|
109
|
+
// nodes with no outgoing links are assigned the maximum breadth.
|
110
|
+
function computeNodeBreadths() {
|
111
|
+
var remainingNodes = nodes,
|
112
|
+
nextNodes,
|
113
|
+
x = 0;
|
114
|
+
|
115
|
+
while (remainingNodes.length) {
|
116
|
+
nextNodes = [];
|
117
|
+
remainingNodes.forEach(function(node) {
|
118
|
+
node.x = x;
|
119
|
+
node.dx = nodeWidth;
|
120
|
+
node.sourceLinks.forEach(function(link) {
|
121
|
+
nextNodes.push(link.target);
|
122
|
+
});
|
123
|
+
});
|
124
|
+
remainingNodes = nextNodes;
|
125
|
+
++x;
|
126
|
+
}
|
127
|
+
|
128
|
+
//
|
129
|
+
moveSinksRight(x);
|
130
|
+
scaleNodeBreadths((size[0] - nodeWidth) / (x - 1));
|
131
|
+
}
|
132
|
+
|
133
|
+
function moveSourcesRight() {
|
134
|
+
nodes.forEach(function(node) {
|
135
|
+
if (!node.targetLinks.length) {
|
136
|
+
node.x = d3.min(node.sourceLinks, function(d) { return d.target.x; }) - 1;
|
137
|
+
}
|
138
|
+
});
|
139
|
+
}
|
140
|
+
|
141
|
+
function moveSinksRight(x) {
|
142
|
+
nodes.forEach(function(node) {
|
143
|
+
if (!node.sourceLinks.length) {
|
144
|
+
node.x = x - 1;
|
145
|
+
}
|
146
|
+
});
|
147
|
+
}
|
148
|
+
|
149
|
+
function scaleNodeBreadths(kx) {
|
150
|
+
nodes.forEach(function(node) {
|
151
|
+
node.x *= kx;
|
152
|
+
});
|
153
|
+
}
|
154
|
+
|
155
|
+
function computeNodeDepths(iterations) {
|
156
|
+
var nodesByBreadth = d3.nest()
|
157
|
+
.key(function(d) { return d.x; })
|
158
|
+
.sortKeys(d3.ascending)
|
159
|
+
.entries(nodes)
|
160
|
+
.map(function(d) { return d.values; });
|
161
|
+
|
162
|
+
//
|
163
|
+
initializeNodeDepth();
|
164
|
+
resolveCollisions();
|
165
|
+
for (var alpha = 1; iterations > 0; --iterations) {
|
166
|
+
relaxRightToLeft(alpha *= .99);
|
167
|
+
resolveCollisions();
|
168
|
+
relaxLeftToRight(alpha);
|
169
|
+
resolveCollisions();
|
170
|
+
}
|
171
|
+
|
172
|
+
function initializeNodeDepth() {
|
173
|
+
var ky = d3.min(nodesByBreadth, function(nodes) {
|
174
|
+
return (size[1] - (nodes.length - 1) * nodePadding) / d3.sum(nodes, value);
|
175
|
+
});
|
176
|
+
|
177
|
+
nodesByBreadth.forEach(function(nodes) {
|
178
|
+
nodes.forEach(function(node, i) {
|
179
|
+
node.y = i;
|
180
|
+
node.dy = node.value * ky;
|
181
|
+
});
|
182
|
+
});
|
183
|
+
|
184
|
+
links.forEach(function(link) {
|
185
|
+
link.dy = link.value * ky;
|
186
|
+
});
|
187
|
+
}
|
188
|
+
|
189
|
+
function relaxLeftToRight(alpha) {
|
190
|
+
nodesByBreadth.forEach(function(nodes, breadth) {
|
191
|
+
nodes.forEach(function(node) {
|
192
|
+
if (node.targetLinks.length) {
|
193
|
+
var y = d3.sum(node.targetLinks, weightedSource) / d3.sum(node.targetLinks, value);
|
194
|
+
node.y += (y - center(node)) * alpha;
|
195
|
+
}
|
196
|
+
});
|
197
|
+
});
|
198
|
+
|
199
|
+
function weightedSource(link) {
|
200
|
+
return center(link.source) * link.value;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
function relaxRightToLeft(alpha) {
|
205
|
+
nodesByBreadth.slice().reverse().forEach(function(nodes) {
|
206
|
+
nodes.forEach(function(node) {
|
207
|
+
if (node.sourceLinks.length) {
|
208
|
+
var y = d3.sum(node.sourceLinks, weightedTarget) / d3.sum(node.sourceLinks, value);
|
209
|
+
node.y += (y - center(node)) * alpha;
|
210
|
+
}
|
211
|
+
});
|
212
|
+
});
|
213
|
+
|
214
|
+
function weightedTarget(link) {
|
215
|
+
return center(link.target) * link.value;
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
function resolveCollisions() {
|
220
|
+
nodesByBreadth.forEach(function(nodes) {
|
221
|
+
var node,
|
222
|
+
dy,
|
223
|
+
y0 = 0,
|
224
|
+
n = nodes.length,
|
225
|
+
i;
|
226
|
+
|
227
|
+
// Push any overlapping nodes down.
|
228
|
+
nodes.sort(ascendingDepth);
|
229
|
+
for (i = 0; i < n; ++i) {
|
230
|
+
node = nodes[i];
|
231
|
+
dy = y0 - node.y;
|
232
|
+
if (dy > 0) node.y += dy;
|
233
|
+
y0 = node.y + node.dy + nodePadding;
|
234
|
+
}
|
235
|
+
|
236
|
+
// If the bottommost node goes outside the bounds, push it back up.
|
237
|
+
dy = y0 - nodePadding - size[1];
|
238
|
+
if (dy > 0) {
|
239
|
+
y0 = node.y -= dy;
|
240
|
+
|
241
|
+
// Push any overlapping nodes back up.
|
242
|
+
for (i = n - 2; i >= 0; --i) {
|
243
|
+
node = nodes[i];
|
244
|
+
dy = node.y + node.dy + nodePadding - y0;
|
245
|
+
if (dy > 0) node.y -= dy;
|
246
|
+
y0 = node.y;
|
247
|
+
}
|
248
|
+
}
|
249
|
+
});
|
250
|
+
}
|
251
|
+
|
252
|
+
function ascendingDepth(a, b) {
|
253
|
+
return a.y - b.y;
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
function computeLinkDepths() {
|
258
|
+
nodes.forEach(function(node) {
|
259
|
+
node.sourceLinks.sort(ascendingTargetDepth);
|
260
|
+
node.targetLinks.sort(ascendingSourceDepth);
|
261
|
+
});
|
262
|
+
nodes.forEach(function(node) {
|
263
|
+
var sy = 0, ty = 0;
|
264
|
+
node.sourceLinks.forEach(function(link) {
|
265
|
+
link.sy = sy;
|
266
|
+
sy += link.dy;
|
267
|
+
});
|
268
|
+
node.targetLinks.forEach(function(link) {
|
269
|
+
link.ty = ty;
|
270
|
+
ty += link.dy;
|
271
|
+
});
|
272
|
+
});
|
273
|
+
|
274
|
+
function ascendingSourceDepth(a, b) {
|
275
|
+
return a.source.y - b.source.y;
|
276
|
+
}
|
277
|
+
|
278
|
+
function ascendingTargetDepth(a, b) {
|
279
|
+
return a.target.y - b.target.y;
|
280
|
+
}
|
281
|
+
}
|
282
|
+
|
283
|
+
function center(node) {
|
284
|
+
return node.y + node.dy / 2;
|
285
|
+
}
|
286
|
+
|
287
|
+
function value(link) {
|
288
|
+
return link.value;
|
289
|
+
}
|
290
|
+
|
291
|
+
return sankey;
|
292
|
+
};
|