d3js-plugins-rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +28 -0
- data/Rakefile +1 -0
- data/d3js-plugins-rails.gemspec +21 -0
- data/lib/d3js-plugins-rails/version.rb +7 -0
- data/lib/d3js-plugins-rails.rb +10 -0
- data/vendor/assets/javascripts/d3/plugins/.gitignore +1 -0
- data/vendor/assets/javascripts/d3/plugins/LICENSE +26 -0
- data/vendor/assets/javascripts/d3/plugins/Makefile +87 -0
- data/vendor/assets/javascripts/d3/plugins/README.md +19 -0
- data/vendor/assets/javascripts/d3/plugins/box/box.js +301 -0
- data/vendor/assets/javascripts/d3/plugins/bullet/README.md +14 -0
- data/vendor/assets/javascripts/d3/plugins/bullet/bullet.js +241 -0
- data/vendor/assets/javascripts/d3/plugins/chernoff/README.md +15 -0
- data/vendor/assets/javascripts/d3/plugins/chernoff/chernoff.js +176 -0
- data/vendor/assets/javascripts/d3/plugins/cie/README.md +54 -0
- data/vendor/assets/javascripts/d3/plugins/cie/cie.js +155 -0
- data/vendor/assets/javascripts/d3/plugins/fisheye/README.md +43 -0
- data/vendor/assets/javascripts/d3/plugins/fisheye/fisheye.js +85 -0
- data/vendor/assets/javascripts/d3/plugins/force_labels/README.md +29 -0
- data/vendor/assets/javascripts/d3/plugins/force_labels/force_labels.js +56 -0
- data/vendor/assets/javascripts/d3/plugins/geo/polyhedron/README.md +7 -0
- data/vendor/assets/javascripts/d3/plugins/geo/polyhedron/polyhedron.js +436 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/README.md +107 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/aitoff.js +40 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/armadillo.js +79 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/august.js +15 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/baker.js +28 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/berghaus.js +60 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/boggs.js +27 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/bonne.js +29 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/bromley.js +5 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/collignon.js +17 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/conic-conformal.js +29 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/conic-equidistant.js +27 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/craig.js +24 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/craster.js +18 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/cylindrical-equal-area.js +23 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/eckert1.js +18 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/eckert2.js +17 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/eckert3.js +17 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/eckert4.js +24 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/eckert5.js +17 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/eckert6.js +22 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/eisenlohr.js +16 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/end.js +1 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/gringorten.js +111 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/guyou.js +46 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/hammer-retroazimuthal.js +75 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/hammer.js +51 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/hatano.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/healpix.js +64 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/hill.js +64 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/homolosine.js +17 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/interrupt.js +111 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/kavrayskiy7.js +15 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/lagrange.js +27 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/larrivee.js +39 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/laskowski.js +31 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/littrow.js +21 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/loximuthal.js +29 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/miller.js +15 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/mollweide.js +35 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/mt-flat-polar-parabolic.js +21 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/mt-flat-polar-quartic.js +23 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/mt-flat-polar-sinusoidal.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/natural-earth.js +22 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/nell-hammer.js +20 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/parallel1.js +12 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/parallel2.js +13 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/peirce-quincuncial.js +14 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/polyconic.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/projection.js +29 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/robinson.js +83 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/satellite.js +68 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/sinu-mollweide.js +19 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/sinusoidal.js +15 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/start.js +1 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/aitoff-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/armadillo-test.js +28 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/baker-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/boggs-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/bonne-test.js +45 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/craig-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/craster-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/env.js +32 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/equirectangular-test.js +97 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/hammer-test.js +29 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/hatano-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/hill-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/larrivee-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/laskowski-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/littrow-test.js +24 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/loximuthal-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/mollweide-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/mt-flat-polar-parabolic-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/mt-flat-polar-quartic-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/mt-flat-polar-sinusoidal-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/natural-earth-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/quartic-authalic-test.js +0 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/robinson-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/wagner6-test.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/test/winkel3-test.js +26 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/van-der-grinten.js +41 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/van-der-grinten4.js +22 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/wagner4.js +9 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/wagner6.js +15 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/wagner7.js +22 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/wiechel.js +14 -0
- data/vendor/assets/javascripts/d3/plugins/geo/projection/winkel3.js +40 -0
- data/vendor/assets/javascripts/d3/plugins/geo/tile/README.md +6 -0
- data/vendor/assets/javascripts/d3/plugins/geo/tile/tile.js +53 -0
- data/vendor/assets/javascripts/d3/plugins/geodesic/README.md +3 -0
- data/vendor/assets/javascripts/d3/plugins/geodesic/geodesic.js +130 -0
- data/vendor/assets/javascripts/d3/plugins/geom/contour/README.md +5 -0
- data/vendor/assets/javascripts/d3/plugins/geom/contour/contour.js +72 -0
- data/vendor/assets/javascripts/d3/plugins/graph/README.md +148 -0
- data/vendor/assets/javascripts/d3/plugins/graph/data/cities-matrix.json +37 -0
- data/vendor/assets/javascripts/d3/plugins/graph/data/cities.csv +36 -0
- data/vendor/assets/javascripts/d3/plugins/graph/data/miserables.json +338 -0
- data/vendor/assets/javascripts/d3/plugins/graph/graph.js +161 -0
- data/vendor/assets/javascripts/d3/plugins/graph/index.html +37 -0
- data/vendor/assets/javascripts/d3/plugins/hexbin/README.md +58 -0
- data/vendor/assets/javascripts/d3/plugins/hexbin/hexbin.js +96 -0
- data/vendor/assets/javascripts/d3/plugins/hive/README.md +5 -0
- data/vendor/assets/javascripts/d3/plugins/hive/hive.js +80 -0
- data/vendor/assets/javascripts/d3/plugins/horizon/README.md +11 -0
- data/vendor/assets/javascripts/d3/plugins/horizon/horizon.js +192 -0
- data/vendor/assets/javascripts/d3/plugins/interpolate-zoom/README.md +11 -0
- data/vendor/assets/javascripts/d3/plugins/interpolate-zoom/interpolate-zoom.js +75 -0
- data/vendor/assets/javascripts/d3/plugins/jsonp/README.md +26 -0
- data/vendor/assets/javascripts/d3/plugins/jsonp/jsonp.js +25 -0
- data/vendor/assets/javascripts/d3/plugins/keybinding/README.md +17 -0
- data/vendor/assets/javascripts/d3/plugins/keybinding/keybinding.js +120 -0
- data/vendor/assets/javascripts/d3/plugins/longscroll/README.md +10 -0
- data/vendor/assets/javascripts/d3/plugins/longscroll/longscroll.js +75 -0
- data/vendor/assets/javascripts/d3/plugins/package.json +20 -0
- data/vendor/assets/javascripts/d3/plugins/qq/README.md +3 -0
- data/vendor/assets/javascripts/d3/plugins/qq/qq.js +249 -0
- data/vendor/assets/javascripts/d3/plugins/rollup/README.md +5 -0
- data/vendor/assets/javascripts/d3/plugins/rollup/rollup.js +131 -0
- data/vendor/assets/javascripts/d3/plugins/sankey/README.md +17 -0
- data/vendor/assets/javascripts/d3/plugins/sankey/sankey.js +292 -0
- data/vendor/assets/javascripts/d3/plugins/simplify/README.md +6 -0
- data/vendor/assets/javascripts/d3/plugins/simplify/simplify-test.js +193 -0
- data/vendor/assets/javascripts/d3/plugins/simplify/simplify.js +446 -0
- data/vendor/assets/javascripts/d3/plugins/superformula/superformula.js +98 -0
- data/vendor/assets/javascripts/d3/plugins/urlencode/urlencode-test.js +68 -0
- data/vendor/assets/javascripts/d3/plugins/urlencode/urlencode.js +37 -0
- metadata +218 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
# d3.cie
|
2
|
+
|
3
|
+
A plugin for CIE Lab and LCH color spaces. For an example, see
|
4
|
+
|
5
|
+
* http://bl.ocks.org/3014589
|
6
|
+
|
7
|
+
This plugin was incorporated into D3 2.10.0 on August 9, 2012 and can now be used directly as d3.hcl and d3.lab!
|
8
|
+
|
9
|
+
## Old Documentation
|
10
|
+
|
11
|
+
To create a Lab color, use the `d3.cie.lab` constructor. To create an LCH color, use the `d3.cie.lch` constructor. For example, here are two ugly colors:
|
12
|
+
|
13
|
+
```js
|
14
|
+
var green = d3.cie.lab(46.23, -51.70, 49.90),
|
15
|
+
blue = d3.cie.lch(32.30, 133.81, -53.72);
|
16
|
+
```
|
17
|
+
|
18
|
+
To convert from RGB to Lab (or LCH), simply specify an RGB color to the constructor. You can use the same technique to convert from HSV; D3 first converts the HSV color to RGB, and then then d3.cie plugin converts from RGB to Lab or LCH. The following three statements are equivalent:
|
19
|
+
|
20
|
+
```js
|
21
|
+
var color = d3.cie.lab("#048F07");
|
22
|
+
var color = d3.cie.lab("rgb(4,143,7)");
|
23
|
+
var color = d3.cie.lab(d3.rgb(4, 143, 7));
|
24
|
+
```
|
25
|
+
|
26
|
+
To convert from Lab (or LCH) to RGB, simply stringify the color. For example, you can pass a Lab color to [selection.attr](/mbostock/d3/wiki/Selections#wiki-attr) and [selection.style](/mbostock/d3/wiki/Selections#wiki-attr):
|
27
|
+
|
28
|
+
```js
|
29
|
+
d3.select("body").style("background", d3.cie.lab(46.23, -51.70, 49.90));
|
30
|
+
```
|
31
|
+
|
32
|
+
The Lab and LCH color classes support custom [brighter](/mbostock/d3/wiki/Colors#wiki-rgb_brighter) and [darker](/mbostock/d3/wiki/Colors#wiki-rgb_brighter) implementations that only modify the L (*lightness*) channel. This tends to produce better results than the RGB or HSL equivalents.
|
33
|
+
|
34
|
+
The d3.cie plugin also lets you interpolates in Lab or LCH space. For example:
|
35
|
+
|
36
|
+
```js
|
37
|
+
var x = d3.scale.linear()
|
38
|
+
.domain([0, 100])
|
39
|
+
.range(["brown", "steelblue"])
|
40
|
+
.interpolate(d3.cie.interpolateLab);
|
41
|
+
```
|
42
|
+
|
43
|
+
The d3.cie plugin does not support parsing CSS3-style color names for Lab and LCH, so you can't say `d3.rgb("lch(32, 133, -53")`; you must use the d3.cie.lab or d3.cie.lch constructors.
|
44
|
+
|
45
|
+
## Thank You
|
46
|
+
|
47
|
+
Various people contributed and helped in implementing this plugin.
|
48
|
+
|
49
|
+
* [Jeffery Heer](/jheer)
|
50
|
+
* [Justin Cormack](/justincormack)
|
51
|
+
* [Alex Gaynor](/alex)
|
52
|
+
* [Jacob Rus](/jrus)
|
53
|
+
|
54
|
+
If you like this, you might also like [Gregor Aisch](/gka)’s [Chroma.js](/gka/chroma.js).
|
@@ -0,0 +1,155 @@
|
|
1
|
+
(function(d3) {
|
2
|
+
var cie = d3.cie = {};
|
3
|
+
|
4
|
+
cie.lab = function(l, a, b) {
|
5
|
+
return arguments.length === 1
|
6
|
+
? (l instanceof Lab ? lab(l.l, l.a, l.b)
|
7
|
+
: (l instanceof Lch ? lch_lab(l.l, l.c, l.h)
|
8
|
+
: rgb_lab((l = d3.rgb(l)).r, l.g, l.b)))
|
9
|
+
: lab(+l, +a, +b);
|
10
|
+
};
|
11
|
+
|
12
|
+
cie.lch = function(l, c, h) {
|
13
|
+
return arguments.length === 1
|
14
|
+
? (l instanceof Lch ? lch(l.l, l.c, l.h)
|
15
|
+
: (l instanceof Lab ? lab_lch(l.l, l.a, l.b)
|
16
|
+
: lab_lch((l = rgb_lab((l = d3.rgb(l)).r, l.g, l.b)).l, l.a, l.b)))
|
17
|
+
: lch(+l, +c, +h);
|
18
|
+
};
|
19
|
+
|
20
|
+
cie.interpolateLab = function(a, b) {
|
21
|
+
a = cie.lab(a);
|
22
|
+
b = cie.lab(b);
|
23
|
+
var al = a.l,
|
24
|
+
aa = a.a,
|
25
|
+
ab = a.b,
|
26
|
+
bl = b.l - al,
|
27
|
+
ba = b.a - aa,
|
28
|
+
bb = b.b - ab;
|
29
|
+
return function(t) {
|
30
|
+
return lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
|
31
|
+
};
|
32
|
+
};
|
33
|
+
|
34
|
+
cie.interpolateLch = function(a, b) {
|
35
|
+
a = cie.lch(a);
|
36
|
+
b = cie.lch(b);
|
37
|
+
var al = a.l,
|
38
|
+
ac = a.c,
|
39
|
+
ah = a.h,
|
40
|
+
bl = b.l - al,
|
41
|
+
bc = b.c - ac,
|
42
|
+
bh = b.h - ah;
|
43
|
+
if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; // shortest path
|
44
|
+
return function(t) {
|
45
|
+
return lch_lab(al + bl * t, ac + bc * t, ah + bh * t) + "";
|
46
|
+
};
|
47
|
+
};
|
48
|
+
|
49
|
+
function lab(l, a, b) {
|
50
|
+
return new Lab(l, a, b);
|
51
|
+
}
|
52
|
+
|
53
|
+
function Lab(l, a, b) {
|
54
|
+
this.l = l;
|
55
|
+
this.a = a;
|
56
|
+
this.b = b;
|
57
|
+
}
|
58
|
+
|
59
|
+
Lab.prototype.brighter = function(k) {
|
60
|
+
return lab(Math.min(100, this.l + K * (arguments.length ? k : 1)), this.a, this.b);
|
61
|
+
};
|
62
|
+
|
63
|
+
Lab.prototype.darker = function(k) {
|
64
|
+
return lab(Math.max(0, this.l - K * (arguments.length ? k : 1)), this.a, this.b);
|
65
|
+
};
|
66
|
+
|
67
|
+
Lab.prototype.rgb = function() {
|
68
|
+
return lab_rgb(this.l, this.a, this.b);
|
69
|
+
};
|
70
|
+
|
71
|
+
Lab.prototype.toString = function() {
|
72
|
+
return this.rgb() + "";
|
73
|
+
};
|
74
|
+
|
75
|
+
function lch(l, c, h) {
|
76
|
+
return new Lch(l, c, h);
|
77
|
+
}
|
78
|
+
|
79
|
+
function Lch(l, c, h) {
|
80
|
+
this.l = l;
|
81
|
+
this.c = c;
|
82
|
+
this.h = h;
|
83
|
+
}
|
84
|
+
|
85
|
+
Lch.prototype.brighter = function(k) {
|
86
|
+
return lch(Math.min(100, this.l + K * (arguments.length ? k : 1)), this.c, this.h);
|
87
|
+
};
|
88
|
+
|
89
|
+
Lch.prototype.darker = function(k) {
|
90
|
+
return lch(Math.max(0, this.l - K * (arguments.length ? k : 1)), this.c, this.h);
|
91
|
+
};
|
92
|
+
|
93
|
+
Lch.prototype.rgb = function() {
|
94
|
+
return lch_lab(this.l, this.c, this.h).rgb();
|
95
|
+
};
|
96
|
+
|
97
|
+
Lch.prototype.toString = function() {
|
98
|
+
return this.rgb() + "";
|
99
|
+
};
|
100
|
+
|
101
|
+
// Corresponds roughly to RGB brighter/darker
|
102
|
+
var K = 18;
|
103
|
+
|
104
|
+
// D65 standard referent
|
105
|
+
var X = 0.950470, Y = 1, Z = 1.088830;
|
106
|
+
|
107
|
+
function lab_rgb(l, a, b) {
|
108
|
+
var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
|
109
|
+
x = lab_xyz(x) * X;
|
110
|
+
y = lab_xyz(y) * Y;
|
111
|
+
z = lab_xyz(z) * Z;
|
112
|
+
return d3.rgb(
|
113
|
+
xyz_rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z),
|
114
|
+
xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
|
115
|
+
xyz_rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z)
|
116
|
+
);
|
117
|
+
}
|
118
|
+
|
119
|
+
function rgb_lab(r, g, b) {
|
120
|
+
r = rgb_xyz(r);
|
121
|
+
g = rgb_xyz(g);
|
122
|
+
b = rgb_xyz(b);
|
123
|
+
var x = xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / X),
|
124
|
+
y = xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / Y),
|
125
|
+
z = xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / Z);
|
126
|
+
return lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
|
127
|
+
}
|
128
|
+
|
129
|
+
function lab_lch(l, a, b) {
|
130
|
+
var c = Math.sqrt(a * a + b * b),
|
131
|
+
h = Math.atan2(b, a) / Math.PI * 180;
|
132
|
+
return lch(l, c, h);
|
133
|
+
}
|
134
|
+
|
135
|
+
function lch_lab(l, c, h) {
|
136
|
+
h = h * Math.PI / 180;
|
137
|
+
return lab(l, Math.cos(h) * c, Math.sin(h) * c);
|
138
|
+
}
|
139
|
+
|
140
|
+
function lab_xyz(x) {
|
141
|
+
return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
|
142
|
+
}
|
143
|
+
|
144
|
+
function xyz_lab(x) {
|
145
|
+
return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
|
146
|
+
}
|
147
|
+
|
148
|
+
function xyz_rgb(r) {
|
149
|
+
return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055));
|
150
|
+
}
|
151
|
+
|
152
|
+
function rgb_xyz(r) {
|
153
|
+
return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
|
154
|
+
}
|
155
|
+
})(d3);
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Fisheye Distortion
|
2
|
+
|
3
|
+
Demo: <http://bost.ocks.org/mike/fisheye/>
|
4
|
+
|
5
|
+
Implements a fisheye distortion for two-dimensional layouts. Based on Sarkar and Brown’s [Graphical Fisheye Views of Graphs](http://dl.acm.org/citation.cfm?id=142763) (CHI '92), as well as [Flare](http://flare.prefuse.org/)'s [FisheyeDistortion](http://flare.prefuse.org/api/flare/vis/operator/distortion/FisheyeDistortion.html) and [Sigma.js](http://sigmajs.org/)'s [fisheye example](http://sigmajs.org/examples/a_plugin_example_advanced.html).
|
6
|
+
|
7
|
+
When constructing a fisheye distortion, you can specify the radius and distortion factor:
|
8
|
+
|
9
|
+
```js
|
10
|
+
var fisheye = d3.fisheye.circular()
|
11
|
+
.radius(200)
|
12
|
+
.distortion(2);
|
13
|
+
```
|
14
|
+
|
15
|
+
Typically, you then update the focal point of the distortion on mousemove:
|
16
|
+
|
17
|
+
```js
|
18
|
+
svg.on("mousemove", function() {
|
19
|
+
fisheye.focus(d3.mouse(this));
|
20
|
+
});
|
21
|
+
```
|
22
|
+
|
23
|
+
The distortion operator takes as input an object with `x` and `y` attributes, and returns a new object with `x`, `y` and `z` attributes. The returned object represents the distorted position of the input object; the `z` property is a scaling factor so that you can optionally distort the size of elements as well.
|
24
|
+
|
25
|
+
For example, to apply fisheye distortion to a force layout, stash the distorted positions in a `display` property on each node, and then use the distorted positions to update the nodes and links:
|
26
|
+
|
27
|
+
```js
|
28
|
+
svg.on("mousemove", function() {
|
29
|
+
fisheye.focus(d3.mouse(this));
|
30
|
+
|
31
|
+
node.each(function(d) { d.fisheye = fisheye(d); })
|
32
|
+
.attr("cx", function(d) { return d.fisheye.x; })
|
33
|
+
.attr("cy", function(d) { return d.fisheye.y; })
|
34
|
+
.attr("r", function(d) { return d.fisheye.z * 4.5; });
|
35
|
+
|
36
|
+
link.attr("x1", function(d) { return d.source.fisheye.x; })
|
37
|
+
.attr("y1", function(d) { return d.source.fisheye.y; })
|
38
|
+
.attr("x2", function(d) { return d.target.fisheye.x; })
|
39
|
+
.attr("y2", function(d) { return d.target.fisheye.y; });
|
40
|
+
});
|
41
|
+
```
|
42
|
+
|
43
|
+
There's also a d3.fisheye.scale for Cartesian distortion; see the above demo for an example.
|
@@ -0,0 +1,85 @@
|
|
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
|
+
range = d3.extent(scale.range()),
|
57
|
+
min = range[0],
|
58
|
+
max = range[1],
|
59
|
+
m = left ? a - min : max - a;
|
60
|
+
if (m == 0) m = max - min;
|
61
|
+
return (left ? -1 : 1) * m * (d + 1) / (d + (m / Math.abs(x - a))) + a;
|
62
|
+
}
|
63
|
+
|
64
|
+
fisheye.distortion = function(_) {
|
65
|
+
if (!arguments.length) return d;
|
66
|
+
d = +_;
|
67
|
+
return fisheye;
|
68
|
+
};
|
69
|
+
|
70
|
+
fisheye.focus = function(_) {
|
71
|
+
if (!arguments.length) return a;
|
72
|
+
a = +_;
|
73
|
+
return fisheye;
|
74
|
+
};
|
75
|
+
|
76
|
+
fisheye.copy = function() {
|
77
|
+
return d3_fisheye_scale(scale.copy(), d, a);
|
78
|
+
};
|
79
|
+
|
80
|
+
fisheye.nice = scale.nice;
|
81
|
+
fisheye.ticks = scale.ticks;
|
82
|
+
fisheye.tickFormat = scale.tickFormat;
|
83
|
+
return d3.rebind(fisheye, scale, "domain", "range");
|
84
|
+
}
|
85
|
+
})();
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# D3 Force Labels v 0.1
|
2
|
+
|
3
|
+
Demo: <http://bl.ocks.org/1691430/>
|
4
|
+
|
5
|
+
Generates an automatic and dynamic positioning for labels, using the d3 force layout. Once a```force_labels``` object has been created, simply call the bound function ```update``` with a selection of the objects you want to attach labels to as an argument. The force_labels object is a d3.force object which allows full control over the charge, gravity, theta etc.
|
6
|
+
|
7
|
+
At each tick the following occurs:
|
8
|
+
|
9
|
+
- Center of each object (anchor position) is determined by the SVG Bounding Box of that object and stored in object ```anchorPos``` under x,y
|
10
|
+
- The position of the label element is determined by a force layout where anchors are fixed nodes and labels are floating. New position for each label is stored in object ```labelPos``` under x,y
|
11
|
+
|
12
|
+
Both the ```anchorPos``` and ```labelPos``` are inserted in the ```__data__``` variable of the object being labeled. This allows easy access when drawing the labels and connectors.
|
13
|
+
|
14
|
+
In the demo the label and link are created as svg objects on the same data selection as the anchors. As the position information is embedded in ```__data__``` the redraw function is simply:
|
15
|
+
|
16
|
+
```js
|
17
|
+
function redrawLabels() {
|
18
|
+
labelBox
|
19
|
+
.attr("transform",function(d) { return "translate("+d.labelPos.x+" "+d.labelPos.y+")"});
|
20
|
+
|
21
|
+
links
|
22
|
+
.attr("x1",function(d) { return d.anchorPos.x})
|
23
|
+
.attr("y1",function(d) { return d.anchorPos.y})
|
24
|
+
.attr("x2",function(d) { return d.labelPos.x})
|
25
|
+
.attr("y2",function(d) { return d.labelPos.y});
|
26
|
+
}
|
27
|
+
```
|
28
|
+
|
29
|
+
<https://github.com/ZJONSSON>
|
@@ -0,0 +1,56 @@
|
|
1
|
+
(function() {
|
2
|
+
d3.force_labels = function force_labels() {
|
3
|
+
var labels = d3.layout.force()
|
4
|
+
|
5
|
+
// Update the position of the anchor based on the center of bounding box
|
6
|
+
function updateAnchor() {
|
7
|
+
if (!labels.selection) return
|
8
|
+
labels.selection.each(function(d) {
|
9
|
+
var bbox = this.getBBox(),
|
10
|
+
x=bbox.x+bbox.width/2,
|
11
|
+
y=bbox.y+bbox.height/2
|
12
|
+
|
13
|
+
d.anchorPos.x=x
|
14
|
+
d.anchorPos.y=y
|
15
|
+
|
16
|
+
// If a label position does not exist, set it to be the anchor position
|
17
|
+
if (d.labelPos.x==null) {
|
18
|
+
d.labelPos.x=x
|
19
|
+
d.labelPos.y=y
|
20
|
+
}
|
21
|
+
})
|
22
|
+
}
|
23
|
+
|
24
|
+
//The anchor position should be updated on each tick
|
25
|
+
labels.on("tick.labels",updateAnchor)
|
26
|
+
|
27
|
+
// This updates all nodes/links - retaining any previous labelPos on updated nodes
|
28
|
+
labels.update = function(selection) {
|
29
|
+
labels.selection = selection
|
30
|
+
var nodes=[],links=[];
|
31
|
+
selection[0].forEach(function(d) {
|
32
|
+
if(d && d.__data__) {
|
33
|
+
var data = d.__data__
|
34
|
+
|
35
|
+
if (!d.labelPos) d.labelPos = {fixed:false}
|
36
|
+
if (!d.anchorPos) d.anchorPos = {fixed:true}
|
37
|
+
|
38
|
+
// Place position objects in __data__ to make them available through
|
39
|
+
// d.labelPos/d.anchorPos for different elements
|
40
|
+
data.labelPos = d.labelPos
|
41
|
+
data.anchorPos = d.anchorPos
|
42
|
+
|
43
|
+
links.push({target:d.anchorPos,source:d.labelPos})
|
44
|
+
nodes.push(d.anchorPos)
|
45
|
+
nodes.push(d.labelPos)
|
46
|
+
}
|
47
|
+
})
|
48
|
+
labels.stop()
|
49
|
+
.nodes(nodes)
|
50
|
+
.links(links)
|
51
|
+
updateAnchor()
|
52
|
+
labels.start()
|
53
|
+
}
|
54
|
+
return labels
|
55
|
+
}
|
56
|
+
})()
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Polyhedral Geographic Projections
|
2
|
+
|
3
|
+
Examples:
|
4
|
+
|
5
|
+
* [Gnomonic Butterfly Map](http://www.jasondavies.com/maps/gnomonic-butterfly/)
|
6
|
+
* [Waterman Butterfly Map](http://www.jasondavies.com/maps/waterman-butterfly/)
|
7
|
+
* [Collignon Butterfly Map](http://www.jasondavies.com/maps/collignon-butterfly/)
|
@@ -0,0 +1,436 @@
|
|
1
|
+
(function() {
|
2
|
+
|
3
|
+
var ε = 1e-6,
|
4
|
+
π = Math.PI,
|
5
|
+
radians = π / 180,
|
6
|
+
degrees = 180 / π;
|
7
|
+
|
8
|
+
// Creates a polyhedral projection.
|
9
|
+
// * root: a spanning tree of polygon faces. Nodes are automatically
|
10
|
+
// augmented with a transform matrix.
|
11
|
+
// * face: a function that returns the appropriate node for a given {λ, φ}
|
12
|
+
// point (radians).
|
13
|
+
// * r: rotation angle for final polyhedron net. Defaults to -π / 6 (for
|
14
|
+
// butterflies).
|
15
|
+
d3.geo.polyhedron = function(root, face, r) {
|
16
|
+
|
17
|
+
r = r == null ? -π / 6 : r; // TODO automate
|
18
|
+
|
19
|
+
recurse(root, {transform: [
|
20
|
+
Math.cos(r), Math.sin(r), 0,
|
21
|
+
-Math.sin(r), Math.cos(r), 0
|
22
|
+
]});
|
23
|
+
|
24
|
+
function recurse(node, parent) {
|
25
|
+
node.edges = faceEdges(node.face);
|
26
|
+
if (parent) {
|
27
|
+
// Find shared edge.
|
28
|
+
if (parent.face) {
|
29
|
+
var shared = node.shared = sharedEdge(node.face, parent.face),
|
30
|
+
m = matrix(shared.map(parent.project), shared.map(node.project));
|
31
|
+
node.transform = parent.transform ? multiply(parent.transform, m) : m;
|
32
|
+
// Replace shared edge in parent edges array.
|
33
|
+
var edges = parent.edges;
|
34
|
+
for (var i = 0, n = edges.length; i < n; ++i) {
|
35
|
+
if (pointEqual(shared[0], edges[i][1]) && pointEqual(shared[1], edges[i][0])) edges[i] = node;
|
36
|
+
if (pointEqual(shared[0], edges[i][0]) && pointEqual(shared[1], edges[i][1])) edges[i] = node;
|
37
|
+
}
|
38
|
+
var edges = node.edges;
|
39
|
+
for (var i = 0, n = edges.length; i < n; ++i) {
|
40
|
+
if (pointEqual(shared[0], edges[i][0]) && pointEqual(shared[1], edges[i][1])) edges[i] = parent;
|
41
|
+
if (pointEqual(shared[0], edges[i][1]) && pointEqual(shared[1], edges[i][0])) edges[i] = parent;
|
42
|
+
}
|
43
|
+
} else {
|
44
|
+
node.transform = parent.transform;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
if (node.children) {
|
48
|
+
node.children.forEach(function(child) {
|
49
|
+
recurse(child, node);
|
50
|
+
});
|
51
|
+
}
|
52
|
+
return node;
|
53
|
+
}
|
54
|
+
|
55
|
+
function forward(λ, φ) {
|
56
|
+
var node = face(λ, φ),
|
57
|
+
point = node.project([λ * degrees, φ * degrees]),
|
58
|
+
t;
|
59
|
+
if (t = node.transform) {
|
60
|
+
return [
|
61
|
+
t[0] * point[0] + t[1] * point[1] + t[2],
|
62
|
+
-(t[3] * point[0] + t[4] * point[1] + t[5])
|
63
|
+
];
|
64
|
+
}
|
65
|
+
point[1] = -point[1];
|
66
|
+
return point;
|
67
|
+
}
|
68
|
+
|
69
|
+
// Naive inverse! A faster solution would use bounding boxes, or even a
|
70
|
+
// polygonal quadtree.
|
71
|
+
if (hasInverse(root)) forward.invert = function(x, y) {
|
72
|
+
var coordinates = faceInvert(root, [x, -y]);
|
73
|
+
return coordinates && (coordinates[0] *= radians, coordinates[1] *= radians, coordinates);
|
74
|
+
};
|
75
|
+
|
76
|
+
function faceInvert(node, coordinates) {
|
77
|
+
var invert = node.project.invert,
|
78
|
+
t = node.transform,
|
79
|
+
point = coordinates;
|
80
|
+
if (t) {
|
81
|
+
t = inverseTransform(t);
|
82
|
+
point = [
|
83
|
+
t[0] * point[0] + t[1] * point[1] + t[2],
|
84
|
+
(t[3] * point[0] + t[4] * point[1] + t[5])
|
85
|
+
];
|
86
|
+
}
|
87
|
+
if (invert && node === faceDegrees(p = invert(point))) return p;
|
88
|
+
var p,
|
89
|
+
children = node.children;
|
90
|
+
for (var i = 0, n = children && children.length; i < n; ++i) {
|
91
|
+
if (p = faceInvert(children[i], coordinates)) return p;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
function faceDegrees(coordinates) {
|
96
|
+
return face(coordinates[0] * radians, coordinates[1] * radians);
|
97
|
+
}
|
98
|
+
|
99
|
+
var projection = d3.geo.projection(forward),
|
100
|
+
stream_ = projection.stream;
|
101
|
+
|
102
|
+
projection.stream = function(stream) {
|
103
|
+
var rotate = projection.rotate(),
|
104
|
+
rotateStream = stream_(stream),
|
105
|
+
sphereStream = (projection.rotate([0, 0]), stream_(stream));
|
106
|
+
projection.rotate(rotate);
|
107
|
+
rotateStream.sphere = function() {
|
108
|
+
sphereStream.polygonStart();
|
109
|
+
sphereStream.lineStart();
|
110
|
+
outline(sphereStream, root);
|
111
|
+
sphereStream.lineEnd();
|
112
|
+
sphereStream.polygonEnd();
|
113
|
+
};
|
114
|
+
return rotateStream;
|
115
|
+
};
|
116
|
+
|
117
|
+
return projection;
|
118
|
+
};
|
119
|
+
|
120
|
+
d3.geo.polyhedron.butterfly = function(faceProjection) {
|
121
|
+
|
122
|
+
faceProjection = faceProjection || function(face) {
|
123
|
+
var centroid = d3.geo.centroid({type: "MultiPoint", coordinates: face});
|
124
|
+
return d3.geo.gnomonic().scale(1).translate([0, 0]).rotate([-centroid[0], -centroid[1]]);
|
125
|
+
};
|
126
|
+
|
127
|
+
var faces = d3.geo.polyhedron.octahedron.map(function(face) {
|
128
|
+
return {face: face, project: faceProjection(face)};
|
129
|
+
});
|
130
|
+
|
131
|
+
[-1, 0, 0, 1, 0, 1, 4, 5].forEach(function(d, i) {
|
132
|
+
var node = faces[d];
|
133
|
+
node && (node.children || (node.children = [])).push(faces[i]);
|
134
|
+
});
|
135
|
+
|
136
|
+
return d3.geo.polyhedron(faces[0], function(λ, φ) {
|
137
|
+
return faces[
|
138
|
+
λ < -π / 2 ? φ < 0 ? 6 : 4
|
139
|
+
: λ < 0 ? φ < 0 ? 2 : 0
|
140
|
+
: λ < π / 2 ? φ < 0 ? 3 : 1
|
141
|
+
: φ < 0 ? 7 : 5];
|
142
|
+
});
|
143
|
+
};
|
144
|
+
|
145
|
+
d3.geo.polyhedron.waterman = function(faceProjection) {
|
146
|
+
|
147
|
+
faceProjection = faceProjection || function(face) {
|
148
|
+
var centroid = face.length === 6 ? d3.geo.centroid({type: "MultiPoint", coordinates: face}) : face[0];
|
149
|
+
return d3.geo.gnomonic().scale(1).translate([0, 0]).rotate([-centroid[0], -centroid[1]]);
|
150
|
+
};
|
151
|
+
|
152
|
+
var octahedron = d3.geo.polyhedron.octahedron;
|
153
|
+
|
154
|
+
var w5 = octahedron.map(function(face) {
|
155
|
+
var xyz = face.map(cartesian),
|
156
|
+
n = xyz.length,
|
157
|
+
a = xyz[n - 1],
|
158
|
+
b,
|
159
|
+
hexagon = [];
|
160
|
+
for (var i = 0; i < n; ++i) {
|
161
|
+
b = xyz[i];
|
162
|
+
hexagon.push(spherical([
|
163
|
+
a[0] * 0.9486832980505138 + b[0] * 0.31622776601683794,
|
164
|
+
a[1] * 0.9486832980505138 + b[1] * 0.31622776601683794,
|
165
|
+
a[2] * 0.9486832980505138 + b[2] * 0.31622776601683794
|
166
|
+
]), spherical([
|
167
|
+
b[0] * 0.9486832980505138 + a[0] * 0.31622776601683794,
|
168
|
+
b[1] * 0.9486832980505138 + a[1] * 0.31622776601683794,
|
169
|
+
b[2] * 0.9486832980505138 + a[2] * 0.31622776601683794
|
170
|
+
]));
|
171
|
+
a = b;
|
172
|
+
}
|
173
|
+
return hexagon;
|
174
|
+
});
|
175
|
+
|
176
|
+
var cornerNormals = [];
|
177
|
+
|
178
|
+
var parents = [-1, 0, 0, 1, 0, 1, 4, 5];
|
179
|
+
|
180
|
+
w5.forEach(function(hexagon, j) {
|
181
|
+
var face = octahedron[j],
|
182
|
+
n = face.length,
|
183
|
+
normals = cornerNormals[j] = [];
|
184
|
+
for (var i = 0; i < n; ++i) {
|
185
|
+
w5.push([
|
186
|
+
face[i],
|
187
|
+
hexagon[(i * 2 + 2) % (2 * n)],
|
188
|
+
hexagon[(i * 2 + 1) % (2 * n)]
|
189
|
+
]);
|
190
|
+
parents.push(j);
|
191
|
+
normals.push(cross(
|
192
|
+
cartesian(hexagon[(i * 2 + 2) % (2 * n)]),
|
193
|
+
cartesian(hexagon[(i * 2 + 1) % (2 * n)])
|
194
|
+
));
|
195
|
+
}
|
196
|
+
});
|
197
|
+
|
198
|
+
var faces = w5.map(function(face) {
|
199
|
+
return {
|
200
|
+
project: faceProjection(face),
|
201
|
+
face: face
|
202
|
+
};
|
203
|
+
});
|
204
|
+
|
205
|
+
parents.forEach(function(d, i) {
|
206
|
+
var parent = faces[d];
|
207
|
+
parent && (parent.children || (parent.children = [])).push(faces[i]);
|
208
|
+
});
|
209
|
+
|
210
|
+
return d3.geo.polyhedron(faces[0], face).center([0, 45]);
|
211
|
+
|
212
|
+
function face(λ, φ) {
|
213
|
+
var cosφ = Math.cos(φ),
|
214
|
+
p = [cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)];
|
215
|
+
|
216
|
+
var hexagon = λ < -π / 2 ? φ < 0 ? 6 : 4
|
217
|
+
: λ < 0 ? φ < 0 ? 2 : 0
|
218
|
+
: λ < π / 2 ? φ < 0 ? 3 : 1
|
219
|
+
: φ < 0 ? 7 : 5;
|
220
|
+
|
221
|
+
var n = cornerNormals[hexagon];
|
222
|
+
|
223
|
+
return faces[
|
224
|
+
dot(n[0], p) < 0 ? 8 + 3 * hexagon
|
225
|
+
: dot(n[1], p) < 0 ? 8 + 3 * hexagon + 1
|
226
|
+
: dot(n[2], p) < 0 ? 8 + 3 * hexagon + 2
|
227
|
+
: hexagon];
|
228
|
+
}
|
229
|
+
};
|
230
|
+
|
231
|
+
function outline(stream, node, parent) {
|
232
|
+
var point,
|
233
|
+
edges = node.edges,
|
234
|
+
n = edges.length,
|
235
|
+
edge,
|
236
|
+
multiPoint = {type: "MultiPoint", coordinates: node.face},
|
237
|
+
notPoles = node.face.filter(function(d) { return Math.abs(d[1]) !== 90; }),
|
238
|
+
bounds = d3.geo.bounds({type: "MultiPoint", coordinates: notPoles}),
|
239
|
+
inside = false,
|
240
|
+
j = -1,
|
241
|
+
dx = bounds[1][0] - bounds[0][0];
|
242
|
+
// TODO
|
243
|
+
var centroid = dx === 180 || dx === 360
|
244
|
+
? [(bounds[0][0] + bounds[1][0]) / 2, (bounds[0][1] + bounds[1][1]) / 2]
|
245
|
+
: d3.geo.centroid(multiPoint);
|
246
|
+
// First find the shared edge…
|
247
|
+
if (parent) while (++j < n) {
|
248
|
+
if (edges[j] === parent) break;
|
249
|
+
}
|
250
|
+
++j;
|
251
|
+
for (var i = 0; i < n; ++i) {
|
252
|
+
edge = edges[(i + j) % n];
|
253
|
+
if (Array.isArray(edge)) {
|
254
|
+
if (!inside) {
|
255
|
+
stream.point((point = d3.geo.interpolate(edge[0], centroid)(ε))[0], point[1]);
|
256
|
+
inside = true;
|
257
|
+
}
|
258
|
+
stream.point((point = d3.geo.interpolate(edge[1], centroid)(ε))[0], point[1]);
|
259
|
+
} else {
|
260
|
+
inside = false;
|
261
|
+
if (edge !== parent) outline(stream, edge, node);
|
262
|
+
}
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
// TODO generate on-the-fly to avoid external modification.
|
267
|
+
var octahedron = [
|
268
|
+
[0, 90],
|
269
|
+
[-90, 0], [0, 0], [90, 0], [180, 0],
|
270
|
+
[0, -90]
|
271
|
+
];
|
272
|
+
|
273
|
+
d3.geo.polyhedron.octahedron = [
|
274
|
+
[0, 2, 1],
|
275
|
+
[0, 3, 2],
|
276
|
+
[5, 1, 2],
|
277
|
+
[5, 2, 3],
|
278
|
+
[0, 1, 4],
|
279
|
+
[0, 4, 3],
|
280
|
+
[5, 4, 1],
|
281
|
+
[5, 3, 4]
|
282
|
+
].map(function(face) {
|
283
|
+
return face.map(function(i) {
|
284
|
+
return octahedron[i];
|
285
|
+
});
|
286
|
+
});
|
287
|
+
|
288
|
+
var φ1 = Math.atan(Math.SQRT1_2) * degrees;
|
289
|
+
|
290
|
+
var cube = [
|
291
|
+
[0, φ1], [90, φ1], [180, φ1], [-90, φ1],
|
292
|
+
[0, -φ1], [90, -φ1], [180, -φ1], [-90, -φ1]
|
293
|
+
];
|
294
|
+
|
295
|
+
d3.geo.polyhedron.cube = [
|
296
|
+
[0, 3, 2, 1], // N
|
297
|
+
[0, 1, 5, 4],
|
298
|
+
[1, 2, 6, 5],
|
299
|
+
[2, 3, 7, 6],
|
300
|
+
[3, 0, 4, 7],
|
301
|
+
[4, 5, 6, 7] // S
|
302
|
+
].map(function(face) {
|
303
|
+
return face.map(function(i) {
|
304
|
+
return cube[i];
|
305
|
+
});
|
306
|
+
});
|
307
|
+
|
308
|
+
// Finds a shared edge given two clockwise polygons.
|
309
|
+
function sharedEdge(a, b) {
|
310
|
+
var x, y, n = a.length, found = null;
|
311
|
+
for (var i = 0; i < n; ++i) {
|
312
|
+
x = a[i];
|
313
|
+
for (var j = b.length; --j >= 0;) {
|
314
|
+
y = b[j];
|
315
|
+
if (x[0] === y[0] && x[1] === y[1]) {
|
316
|
+
if (found) return [found, x];
|
317
|
+
found = x;
|
318
|
+
}
|
319
|
+
}
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
// Note: 6-element arrays are used to denote the 3x3 affine transform matrix:
|
324
|
+
// [a, b, c,
|
325
|
+
// d, e, f,
|
326
|
+
// 0, 0, 1] - this redundant row is left out.
|
327
|
+
|
328
|
+
// Transform matrix for [a0, a1] -> [b0, b1].
|
329
|
+
function matrix(a, b) {
|
330
|
+
var u = subtract(a[1], a[0]),
|
331
|
+
v = subtract(b[1], b[0]),
|
332
|
+
φ = angle(u, v),
|
333
|
+
s = length(u) / length(v);
|
334
|
+
|
335
|
+
return multiply([
|
336
|
+
1, 0, a[0][0],
|
337
|
+
0, 1, a[0][1]
|
338
|
+
], multiply([
|
339
|
+
s, 0, 0,
|
340
|
+
0, s, 0
|
341
|
+
], multiply([
|
342
|
+
Math.cos(φ), Math.sin(φ), 0,
|
343
|
+
-Math.sin(φ), Math.cos(φ), 0
|
344
|
+
], [
|
345
|
+
1, 0, -b[0][0],
|
346
|
+
0, 1, -b[0][1]
|
347
|
+
])));
|
348
|
+
}
|
349
|
+
|
350
|
+
// Inverts a transform matrix.
|
351
|
+
function inverseTransform(m) {
|
352
|
+
var k = 1 / (m[0] * m[4] - m[1] * m[3]);
|
353
|
+
return [
|
354
|
+
k * m[4], -k * m[1], k * (m[1] * m[5] - m[2] * m[4]),
|
355
|
+
-k * m[3], k * m[0], k * (m[2] * m[3] - m[0] * m[5])
|
356
|
+
];
|
357
|
+
}
|
358
|
+
|
359
|
+
// Multiplies two 3x2 matrices.
|
360
|
+
function multiply(a, b) {
|
361
|
+
return [
|
362
|
+
a[0] * b[0] + a[1] * b[3],
|
363
|
+
a[0] * b[1] + a[1] * b[4],
|
364
|
+
a[0] * b[2] + a[1] * b[5] + a[2],
|
365
|
+
a[3] * b[0] + a[4] * b[3],
|
366
|
+
a[3] * b[1] + a[4] * b[4],
|
367
|
+
a[3] * b[2] + a[4] * b[5] + a[5]
|
368
|
+
];
|
369
|
+
}
|
370
|
+
|
371
|
+
// Subtracts 2D vectors.
|
372
|
+
function subtract(a, b) {
|
373
|
+
return [a[0] - b[0], a[1] - b[1]];
|
374
|
+
}
|
375
|
+
|
376
|
+
// Magnitude of a 2D vector.
|
377
|
+
function length(v) {
|
378
|
+
return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
379
|
+
}
|
380
|
+
|
381
|
+
// Angle between two 2D vectors.
|
382
|
+
function angle(a, b) {
|
383
|
+
return Math.atan2(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1]);
|
384
|
+
}
|
385
|
+
|
386
|
+
function dot(a, b) {
|
387
|
+
for (var i = 0, n = a.length, s = 0; i < n; ++i) s += a[i] * b[i];
|
388
|
+
return s;
|
389
|
+
}
|
390
|
+
|
391
|
+
function cross(a, b) {
|
392
|
+
return [
|
393
|
+
a[1] * b[2] - a[2] * b[1],
|
394
|
+
a[2] * b[0] - a[0] * b[2],
|
395
|
+
a[0] * b[1] - a[1] * b[0]
|
396
|
+
];
|
397
|
+
}
|
398
|
+
|
399
|
+
// Converts 3D Cartesian to spherical coordinates (degrees).
|
400
|
+
function spherical(cartesian) {
|
401
|
+
return [
|
402
|
+
Math.atan2(cartesian[1], cartesian[0]) * degrees,
|
403
|
+
Math.asin(Math.max(-1, Math.min(1, cartesian[2]))) * degrees
|
404
|
+
];
|
405
|
+
}
|
406
|
+
|
407
|
+
// Converts spherical coordinates (degrees) to 3D Cartesian.
|
408
|
+
function cartesian(coordinates) {
|
409
|
+
var λ = coordinates[0] * radians,
|
410
|
+
φ = coordinates[1] * radians,
|
411
|
+
cosφ = Math.cos(φ);
|
412
|
+
return [
|
413
|
+
cosφ * Math.cos(λ),
|
414
|
+
cosφ * Math.sin(λ),
|
415
|
+
Math.sin(φ)
|
416
|
+
];
|
417
|
+
}
|
418
|
+
|
419
|
+
// Tests equality of two spherical points.
|
420
|
+
function pointEqual(a, b) {
|
421
|
+
return a && b && a[0] === b[0] && a[1] === b[1];
|
422
|
+
}
|
423
|
+
|
424
|
+
// Converts an array of n face vertices to an array of n + 1 edges.
|
425
|
+
function faceEdges(face) {
|
426
|
+
var n = face.length,
|
427
|
+
edges = [];
|
428
|
+
for (var a = face[n - 1], i = 0; i < n; ++i) edges.push([a, a = face[i]]);
|
429
|
+
return edges;
|
430
|
+
}
|
431
|
+
|
432
|
+
function hasInverse(node) {
|
433
|
+
return node.project.invert || node.children && node.children.some(hasInverse);
|
434
|
+
}
|
435
|
+
|
436
|
+
})();
|