Merge branch 'master' into default-namespace
This commit is contained in:
Коммит
cc3f5da0bb
|
@ -1,2 +1,3 @@
|
||||||
_site
|
_site
|
||||||
node_modules
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
examples/
|
||||||
|
test/
|
||||||
|
lib/
|
||||||
|
.DS_Store
|
64
Makefile
64
Makefile
|
@ -1,23 +1,22 @@
|
||||||
# See the README for installation instructions.
|
# See the README for installation instructions.
|
||||||
|
|
||||||
JS_COMPILER = ./node_modules/uglify-js/bin/uglifyjs
|
NODE_PATH ?= ./node_modules
|
||||||
JS_TESTER = ./node_modules/vows/bin/vows
|
JS_COMPILER = $(NODE_PATH)/uglify-js/bin/uglifyjs
|
||||||
|
JS_TESTER = $(NODE_PATH)/vows/bin/vows
|
||||||
|
|
||||||
|
JS_FILES = \
|
||||||
|
d3.js \
|
||||||
|
d3.chart.js \
|
||||||
|
d3.layout.js \
|
||||||
|
d3.csv.js \
|
||||||
|
d3.geo.js \
|
||||||
|
d3.geom.js \
|
||||||
|
d3.time.js
|
||||||
|
|
||||||
all: \
|
all: \
|
||||||
d3.js \
|
$(JS_FILES) \
|
||||||
d3.min.js \
|
$(JS_FILES:.js=.min.js) \
|
||||||
d3.chart.js \
|
package.json
|
||||||
d3.chart.min.js \
|
|
||||||
d3.layout.js \
|
|
||||||
d3.layout.min.js \
|
|
||||||
d3.csv.js \
|
|
||||||
d3.csv.min.js \
|
|
||||||
d3.geo.js \
|
|
||||||
d3.geo.min.js \
|
|
||||||
d3.geom.js \
|
|
||||||
d3.geom.min.js \
|
|
||||||
d3.time.js \
|
|
||||||
d3.time.min.js
|
|
||||||
|
|
||||||
# Modify this rule to build your own custom release.
|
# Modify this rule to build your own custom release.
|
||||||
# Run `make d3.custom.min.js` to produce the minified version.
|
# Run `make d3.custom.min.js` to produce the minified version.
|
||||||
|
@ -36,17 +35,22 @@ d3.custom.js: \
|
||||||
src/end.js
|
src/end.js
|
||||||
|
|
||||||
d3.core.js: \
|
d3.core.js: \
|
||||||
|
src/compat/date.js \
|
||||||
|
src/compat/style.js \
|
||||||
src/core/core.js \
|
src/core/core.js \
|
||||||
src/core/date.js \
|
|
||||||
src/core/object.js \
|
|
||||||
src/core/array.js \
|
src/core/array.js \
|
||||||
src/core/this.js \
|
src/core/this.js \
|
||||||
src/core/functor.js \
|
src/core/functor.js \
|
||||||
src/core/rebind.js \
|
src/core/rebind.js \
|
||||||
src/core/ascending.js \
|
src/core/ascending.js \
|
||||||
src/core/descending.js \
|
src/core/descending.js \
|
||||||
|
src/core/mean.js \
|
||||||
|
src/core/median.js \
|
||||||
src/core/min.js \
|
src/core/min.js \
|
||||||
src/core/max.js \
|
src/core/max.js \
|
||||||
|
src/core/extent.js \
|
||||||
|
src/core/random.js \
|
||||||
|
src/core/number.js \
|
||||||
src/core/sum.js \
|
src/core/sum.js \
|
||||||
src/core/quantile.js \
|
src/core/quantile.js \
|
||||||
src/core/zip.js \
|
src/core/zip.js \
|
||||||
|
@ -72,6 +76,7 @@ d3.core.js: \
|
||||||
src/core/ns.js \
|
src/core/ns.js \
|
||||||
src/core/dispatch.js \
|
src/core/dispatch.js \
|
||||||
src/core/format.js \
|
src/core/format.js \
|
||||||
|
src/core/formatPrefix.js \
|
||||||
src/core/ease.js \
|
src/core/ease.js \
|
||||||
src/core/event.js \
|
src/core/event.js \
|
||||||
src/core/interpolate.js \
|
src/core/interpolate.js \
|
||||||
|
@ -91,8 +96,6 @@ d3.core.js: \
|
||||||
src/core/selection-insert.js \
|
src/core/selection-insert.js \
|
||||||
src/core/selection-remove.js \
|
src/core/selection-remove.js \
|
||||||
src/core/selection-data.js \
|
src/core/selection-data.js \
|
||||||
src/core/selection-enter.js \
|
|
||||||
src/core/selection-enter-select.js \
|
|
||||||
src/core/selection-filter.js \
|
src/core/selection-filter.js \
|
||||||
src/core/selection-map.js \
|
src/core/selection-map.js \
|
||||||
src/core/selection-sort.js \
|
src/core/selection-sort.js \
|
||||||
|
@ -103,6 +106,8 @@ d3.core.js: \
|
||||||
src/core/selection-node.js \
|
src/core/selection-node.js \
|
||||||
src/core/selection-transition.js \
|
src/core/selection-transition.js \
|
||||||
src/core/selection-root.js \
|
src/core/selection-root.js \
|
||||||
|
src/core/selection-enter.js \
|
||||||
|
src/core/selection-enter-select.js \
|
||||||
src/core/transition.js \
|
src/core/transition.js \
|
||||||
src/core/transition-select.js \
|
src/core/transition-select.js \
|
||||||
src/core/transition-selectAll.js \
|
src/core/transition-selectAll.js \
|
||||||
|
@ -115,6 +120,7 @@ d3.core.js: \
|
||||||
src/core/transition-each.js \
|
src/core/transition-each.js \
|
||||||
src/core/transition-transition.js \
|
src/core/transition-transition.js \
|
||||||
src/core/timer.js \
|
src/core/timer.js \
|
||||||
|
src/core/transform.js \
|
||||||
src/core/noop.js
|
src/core/noop.js
|
||||||
|
|
||||||
d3.scale.js: \
|
d3.scale.js: \
|
||||||
|
@ -144,7 +150,8 @@ d3.svg.js: \
|
||||||
src/svg/mouse.js \
|
src/svg/mouse.js \
|
||||||
src/svg/touches.js \
|
src/svg/touches.js \
|
||||||
src/svg/symbol.js \
|
src/svg/symbol.js \
|
||||||
src/svg/axis.js
|
src/svg/axis.js \
|
||||||
|
src/svg/brush.js
|
||||||
|
|
||||||
d3.behavior.js: \
|
d3.behavior.js: \
|
||||||
src/behavior/behavior.js \
|
src/behavior/behavior.js \
|
||||||
|
@ -182,9 +189,15 @@ d3.geo.js: \
|
||||||
src/geo/geo.js \
|
src/geo/geo.js \
|
||||||
src/geo/azimuthal.js \
|
src/geo/azimuthal.js \
|
||||||
src/geo/albers.js \
|
src/geo/albers.js \
|
||||||
|
src/geo/bonne.js \
|
||||||
|
src/geo/equirectangular.js \
|
||||||
src/geo/mercator.js \
|
src/geo/mercator.js \
|
||||||
|
src/geo/type.js \
|
||||||
src/geo/path.js \
|
src/geo/path.js \
|
||||||
src/geo/bounds.js \
|
src/geo/bounds.js \
|
||||||
|
src/geo/circle.js \
|
||||||
|
src/geo/greatArc.js \
|
||||||
|
src/geo/greatCircle.js \
|
||||||
src/end.js
|
src/end.js
|
||||||
|
|
||||||
d3.csv.js: \
|
d3.csv.js: \
|
||||||
|
@ -237,10 +250,17 @@ test: all
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
$(JS_COMPILER) < $< > $@
|
$(JS_COMPILER) < $< > $@
|
||||||
|
|
||||||
d3.js d3%.js: Makefile
|
d3.%: Makefile
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
cat $(filter %.js,$^) > $@
|
cat $(filter %.js,$^) > $@
|
||||||
@chmod a-w $@
|
@chmod a-w $@
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p node_modules
|
||||||
|
npm install
|
||||||
|
|
||||||
|
package.json: d3.js src/package.js
|
||||||
|
node src/package.js > $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f d3*.js
|
rm -f d3*.js
|
||||||
|
|
|
@ -45,7 +45,7 @@ developing on Mac OS X, an easy way to install Node and NPM is using
|
||||||
|
|
||||||
Next, from the root directory of this repository, install D3's dependencies:
|
Next, from the root directory of this repository, install D3's dependencies:
|
||||||
|
|
||||||
npm install
|
make install
|
||||||
|
|
||||||
You can see the list of dependencies in package.json. The packages will be
|
You can see the list of dependencies in package.json. NPM will install the
|
||||||
installed in the node_modules directory.
|
packages in the node_modules directory.
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1 +1 @@
|
||||||
(function(){function b(a){return/[",\n]/.test(a)?'"'+a.replace(/\"/g,'""')+'"':a}function a(a){return a.map(b).join(",")}d3.csv=function(a,b){d3.text(a,"text/csv",function(a){b(a&&d3.csv.parse(a))})},d3.csv.parse=function(a){var b;return d3.csv.parseRows(a,function(a,c){if(c){var d={},e=-1,f=b.length;while(++e<f)d[b[e]]=a[e];return d}b=a;return null})},d3.csv.parseRows=function(a,b){function j(){if(f.lastIndex>=a.length)return d;if(i){i=!1;return c}var b=f.lastIndex;if(a.charCodeAt(b)===34){var e=b;while(e++<a.length)if(a.charCodeAt(e)===34){if(a.charCodeAt(e+1)!==34)break;e++}f.lastIndex=e+2;var g=a.charCodeAt(e+1);g===13?(i=!0,a.charCodeAt(e+2)===10&&f.lastIndex++):g===10&&(i=!0);return a.substring(b+1,e).replace(/""/g,'"')}var h=f.exec(a);if(h){i=h[0].charCodeAt(0)!==44;return a.substring(b,h.index)}f.lastIndex=a.length;return a.substring(b)}var c={},d={},e=[],f=/\r\n|[,\r\n]/g,g=0,h,i;f.lastIndex=0;while((h=j())!==d){var k=[];while(h!==c&&h!==d)k.push(h),h=j();if(b&&!(k=b(k,g++)))continue;e.push(k)}return e},d3.csv.format=function(b){return b.map(a).join("\n")}})()
|
(function(){function a(a){return a.map(b).join(",")}function b(a){return/[",\n]/.test(a)?'"'+a.replace(/\"/g,'""')+'"':a}d3.csv=function(a,b){d3.text(a,"text/csv",function(a){b(a&&d3.csv.parse(a))})},d3.csv.parse=function(a){var b;return d3.csv.parseRows(a,function(a,c){if(c){var d={},e=-1,f=b.length;while(++e<f)d[b[e]]=a[e];return d}return b=a,null})},d3.csv.parseRows=function(a,b){function j(){if(f.lastIndex>=a.length)return d;if(i)return i=!1,c;var b=f.lastIndex;if(a.charCodeAt(b)===34){var e=b;while(e++<a.length)if(a.charCodeAt(e)===34){if(a.charCodeAt(e+1)!==34)break;e++}f.lastIndex=e+2;var g=a.charCodeAt(e+1);return g===13?(i=!0,a.charCodeAt(e+2)===10&&f.lastIndex++):g===10&&(i=!0),a.substring(b+1,e).replace(/""/g,'"')}var h=f.exec(a);return h?(i=h[0].charCodeAt(0)!==44,a.substring(b,h.index)):(f.lastIndex=a.length,a.substring(b))}var c={},d={},e=[],f=/\r\n|[,\r\n]/g,g=0,h,i;f.lastIndex=0;while((h=j())!==d){var k=[];while(h!==c&&h!==d)k.push(h),h=j();if(b&&!(k=b(k,g++)))continue;e.push(k)}return e},d3.csv.format=function(b){return b.map(a).join("\n")}})();
|
496
d3.geo.js
496
d3.geo.js
|
@ -1,7 +1,9 @@
|
||||||
(function(){d3.geo = {};
|
(function(){d3.geo = {};
|
||||||
|
|
||||||
|
var d3_geo_radians = Math.PI / 180;
|
||||||
// TODO clip input coordinates on opposite hemisphere
|
// TODO clip input coordinates on opposite hemisphere
|
||||||
d3.geo.azimuthal = function() {
|
d3.geo.azimuthal = function() {
|
||||||
var mode = "orthographic", // or stereographic
|
var mode = "orthographic", // or stereographic, gnomonic, equidistant or equalarea
|
||||||
origin,
|
origin,
|
||||||
scale = 200,
|
scale = 200,
|
||||||
translate = [480, 250],
|
translate = [480, 250],
|
||||||
|
@ -11,13 +13,19 @@ d3.geo.azimuthal = function() {
|
||||||
sy0;
|
sy0;
|
||||||
|
|
||||||
function azimuthal(coordinates) {
|
function azimuthal(coordinates) {
|
||||||
var x1 = coordinates[0] * d3_radians - x0,
|
var x1 = coordinates[0] * d3_geo_radians - x0,
|
||||||
y1 = coordinates[1] * d3_radians,
|
y1 = coordinates[1] * d3_geo_radians,
|
||||||
cx1 = Math.cos(x1),
|
cx1 = Math.cos(x1),
|
||||||
sx1 = Math.sin(x1),
|
sx1 = Math.sin(x1),
|
||||||
cy1 = Math.cos(y1),
|
cy1 = Math.cos(y1),
|
||||||
sy1 = Math.sin(y1),
|
sy1 = Math.sin(y1),
|
||||||
k = mode == "stereographic" ? 1 / (1 + sy0 * sy1 + cy0 * cy1 * cx1) : 1,
|
cc = mode !== "orthographic" ? sy0 * sy1 + cy0 * cy1 * cx1 : null,
|
||||||
|
c,
|
||||||
|
k = mode === "stereographic" ? 1 / (1 + cc)
|
||||||
|
: mode === "gnomonic" ? 1 / cc
|
||||||
|
: mode === "equidistant" ? (c = Math.acos(cc), c ? c / Math.sin(c) : 0)
|
||||||
|
: mode === "equalarea" ? Math.sqrt(2 / (1 + cc))
|
||||||
|
: 1,
|
||||||
x = k * cy1 * sx1,
|
x = k * cy1 * sx1,
|
||||||
y = k * (sy0 * cy1 * cx1 - cy0 * sy1);
|
y = k * (sy0 * cy1 * cx1 - cy0 * sy1);
|
||||||
return [
|
return [
|
||||||
|
@ -26,17 +34,34 @@ d3.geo.azimuthal = function() {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
azimuthal.invert = function(coordinates) {
|
||||||
|
var x = (coordinates[0] - translate[0]) / scale,
|
||||||
|
y = (coordinates[1] - translate[1]) / scale,
|
||||||
|
p = Math.sqrt(x * x + y * y),
|
||||||
|
c = mode === "stereographic" ? 2 * Math.atan(p)
|
||||||
|
: mode === "gnomonic" ? Math.atan(p)
|
||||||
|
: mode === "equidistant" ? p
|
||||||
|
: mode === "equalarea" ? 2 * Math.asin(.5 * p)
|
||||||
|
: Math.asin(p),
|
||||||
|
sc = Math.sin(c),
|
||||||
|
cc = Math.cos(c);
|
||||||
|
return [
|
||||||
|
(x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_geo_radians,
|
||||||
|
Math.asin(cc * sy0 - (p ? (y * sc * cy0) / p : 0)) / d3_geo_radians
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
azimuthal.mode = function(x) {
|
azimuthal.mode = function(x) {
|
||||||
if (!arguments.length) return mode;
|
if (!arguments.length) return mode;
|
||||||
mode = x;
|
mode = x + "";
|
||||||
return azimuthal;
|
return azimuthal;
|
||||||
};
|
};
|
||||||
|
|
||||||
azimuthal.origin = function(x) {
|
azimuthal.origin = function(x) {
|
||||||
if (!arguments.length) return origin;
|
if (!arguments.length) return origin;
|
||||||
origin = x;
|
origin = x;
|
||||||
x0 = origin[0] * d3_radians;
|
x0 = origin[0] * d3_geo_radians;
|
||||||
y0 = origin[1] * d3_radians;
|
y0 = origin[1] * d3_geo_radians;
|
||||||
cy0 = Math.cos(y0);
|
cy0 = Math.cos(y0);
|
||||||
sy0 = Math.sin(y0);
|
sy0 = Math.sin(y0);
|
||||||
return azimuthal;
|
return azimuthal;
|
||||||
|
@ -65,27 +90,39 @@ d3.geo.albers = function() {
|
||||||
parallels = [29.5, 45.5],
|
parallels = [29.5, 45.5],
|
||||||
scale = 1000,
|
scale = 1000,
|
||||||
translate = [480, 250],
|
translate = [480, 250],
|
||||||
lng0, // d3_radians * origin[0]
|
lng0, // d3_geo_radians * origin[0]
|
||||||
n,
|
n,
|
||||||
C,
|
C,
|
||||||
p0;
|
p0;
|
||||||
|
|
||||||
function albers(coordinates) {
|
function albers(coordinates) {
|
||||||
var t = n * (d3_radians * coordinates[0] - lng0),
|
var t = n * (d3_geo_radians * coordinates[0] - lng0),
|
||||||
p = Math.sqrt(C - 2 * n * Math.sin(d3_radians * coordinates[1])) / n;
|
p = Math.sqrt(C - 2 * n * Math.sin(d3_geo_radians * coordinates[1])) / n;
|
||||||
return [
|
return [
|
||||||
scale * p * Math.sin(t) + translate[0],
|
scale * p * Math.sin(t) + translate[0],
|
||||||
scale * (p * Math.cos(t) - p0) + translate[1]
|
scale * (p * Math.cos(t) - p0) + translate[1]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
albers.invert = function(coordinates) {
|
||||||
|
var x = (coordinates[0] - translate[0]) / scale,
|
||||||
|
y = (coordinates[1] - translate[1]) / scale,
|
||||||
|
p0y = p0 + y,
|
||||||
|
t = Math.atan2(x, p0y),
|
||||||
|
p = Math.sqrt(x * x + p0y * p0y);
|
||||||
|
return [
|
||||||
|
(lng0 + t / n) / d3_geo_radians,
|
||||||
|
Math.asin((C - p * p * n * n) / (2 * n)) / d3_geo_radians
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
function reload() {
|
function reload() {
|
||||||
var phi1 = d3_radians * parallels[0],
|
var phi1 = d3_geo_radians * parallels[0],
|
||||||
phi2 = d3_radians * parallels[1],
|
phi2 = d3_geo_radians * parallels[1],
|
||||||
lat0 = d3_radians * origin[1],
|
lat0 = d3_geo_radians * origin[1],
|
||||||
s = Math.sin(phi1),
|
s = Math.sin(phi1),
|
||||||
c = Math.cos(phi1);
|
c = Math.cos(phi1);
|
||||||
lng0 = d3_radians * origin[0];
|
lng0 = d3_geo_radians * origin[0];
|
||||||
n = .5 * (s + Math.sin(phi2));
|
n = .5 * (s + Math.sin(phi2));
|
||||||
C = c * c + 2 * n * s;
|
C = c * c + 2 * n * s;
|
||||||
p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n;
|
p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n;
|
||||||
|
@ -170,21 +207,134 @@ d3.geo.albersUsa = function() {
|
||||||
|
|
||||||
return albersUsa.scale(lower48.scale());
|
return albersUsa.scale(lower48.scale());
|
||||||
};
|
};
|
||||||
|
d3.geo.bonne = function() {
|
||||||
|
var scale = 200,
|
||||||
|
translate = [480, 250],
|
||||||
|
x0, // origin longitude in radians
|
||||||
|
y0, // origin latitude in radians
|
||||||
|
y1, // parallel latitude in radians
|
||||||
|
c1; // cot(y1)
|
||||||
|
|
||||||
var d3_radians = Math.PI / 180;
|
function bonne(coordinates) {
|
||||||
|
var x = coordinates[0] * d3_geo_radians - x0,
|
||||||
|
y = coordinates[1] * d3_geo_radians - y0;
|
||||||
|
if (y1) {
|
||||||
|
var p = c1 + y1 - y, E = x * Math.cos(y) / p;
|
||||||
|
x = p * Math.sin(E);
|
||||||
|
y = p * Math.cos(E) - c1;
|
||||||
|
} else {
|
||||||
|
x *= Math.cos(y);
|
||||||
|
y *= -1;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
scale * x + translate[0],
|
||||||
|
scale * y + translate[1]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
bonne.invert = function(coordinates) {
|
||||||
|
var x = (coordinates[0] - translate[0]) / scale,
|
||||||
|
y = (coordinates[1] - translate[1]) / scale;
|
||||||
|
if (y1) {
|
||||||
|
var c = c1 + y, p = Math.sqrt(x * x + c * c);
|
||||||
|
y = c1 + y1 - p;
|
||||||
|
x = x0 + p * Math.atan2(x, c) / Math.cos(y);
|
||||||
|
} else {
|
||||||
|
y *= -1;
|
||||||
|
x /= Math.cos(y);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
x / d3_geo_radians,
|
||||||
|
y / d3_geo_radians
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 90° for Werner, 0° for Sinusoidal
|
||||||
|
bonne.parallel = function(x) {
|
||||||
|
if (!arguments.length) return y1 / d3_geo_radians;
|
||||||
|
c1 = 1 / Math.tan(y1 = x * d3_geo_radians);
|
||||||
|
return bonne;
|
||||||
|
};
|
||||||
|
|
||||||
|
bonne.origin = function(x) {
|
||||||
|
if (!arguments.length) return [x0 / d3_geo_radians, y0 / d3_geo_radians];
|
||||||
|
x0 = x[0] * d3_geo_radians;
|
||||||
|
y0 = x[1] * d3_geo_radians;
|
||||||
|
return bonne;
|
||||||
|
};
|
||||||
|
|
||||||
|
bonne.scale = function(x) {
|
||||||
|
if (!arguments.length) return scale;
|
||||||
|
scale = +x;
|
||||||
|
return bonne;
|
||||||
|
};
|
||||||
|
|
||||||
|
bonne.translate = function(x) {
|
||||||
|
if (!arguments.length) return translate;
|
||||||
|
translate = [+x[0], +x[1]];
|
||||||
|
return bonne;
|
||||||
|
};
|
||||||
|
|
||||||
|
return bonne.origin([0, 0]).parallel(45);
|
||||||
|
};
|
||||||
|
d3.geo.equirectangular = function() {
|
||||||
|
var scale = 500,
|
||||||
|
translate = [480, 250];
|
||||||
|
|
||||||
|
function equirectangular(coordinates) {
|
||||||
|
var x = coordinates[0] / 360,
|
||||||
|
y = -coordinates[1] / 360;
|
||||||
|
return [
|
||||||
|
scale * x + translate[0],
|
||||||
|
scale * y + translate[1]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
equirectangular.invert = function(coordinates) {
|
||||||
|
var x = (coordinates[0] - translate[0]) / scale,
|
||||||
|
y = (coordinates[1] - translate[1]) / scale;
|
||||||
|
return [
|
||||||
|
360 * x,
|
||||||
|
-360 * y
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
equirectangular.scale = function(x) {
|
||||||
|
if (!arguments.length) return scale;
|
||||||
|
scale = +x;
|
||||||
|
return equirectangular;
|
||||||
|
};
|
||||||
|
|
||||||
|
equirectangular.translate = function(x) {
|
||||||
|
if (!arguments.length) return translate;
|
||||||
|
translate = [+x[0], +x[1]];
|
||||||
|
return equirectangular;
|
||||||
|
};
|
||||||
|
|
||||||
|
return equirectangular;
|
||||||
|
};
|
||||||
d3.geo.mercator = function() {
|
d3.geo.mercator = function() {
|
||||||
var scale = 500,
|
var scale = 500,
|
||||||
translate = [480, 250];
|
translate = [480, 250];
|
||||||
|
|
||||||
function mercator(coordinates) {
|
function mercator(coordinates) {
|
||||||
var x = (coordinates[0]) / 360,
|
var x = coordinates[0] / 360,
|
||||||
y = (-180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + coordinates[1] * Math.PI / 360))) / 360;
|
y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_geo_radians / 2)) / d3_geo_radians) / 360;
|
||||||
return [
|
return [
|
||||||
scale * x + translate[0],
|
scale * x + translate[0],
|
||||||
scale * Math.max(-.5, Math.min(.5, y)) + translate[1]
|
scale * Math.max(-.5, Math.min(.5, y)) + translate[1]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mercator.invert = function(coordinates) {
|
||||||
|
var x = (coordinates[0] - translate[0]) / scale,
|
||||||
|
y = (coordinates[1] - translate[1]) / scale;
|
||||||
|
return [
|
||||||
|
360 * x,
|
||||||
|
2 * Math.atan(Math.exp(-360 * y * d3_geo_radians)) / d3_geo_radians - 90
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
mercator.scale = function(x) {
|
mercator.scale = function(x) {
|
||||||
if (!arguments.length) return scale;
|
if (!arguments.length) return scale;
|
||||||
scale = +x;
|
scale = +x;
|
||||||
|
@ -199,6 +349,11 @@ d3.geo.mercator = function() {
|
||||||
|
|
||||||
return mercator;
|
return mercator;
|
||||||
};
|
};
|
||||||
|
function d3_geo_type(types, defaultValue) {
|
||||||
|
return function(object) {
|
||||||
|
return object && object.type in types ? types[object.type](object) : defaultValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Returns a function that, given a GeoJSON object (e.g., a feature), returns
|
* Returns a function that, given a GeoJSON object (e.g., a feature), returns
|
||||||
* the corresponding SVG path. The function can be customized by overriding the
|
* the corresponding SVG path. The function can be customized by overriding the
|
||||||
|
@ -215,26 +370,26 @@ d3.geo.path = function() {
|
||||||
if (typeof pointRadius === "function") {
|
if (typeof pointRadius === "function") {
|
||||||
pointCircle = d3_path_circle(pointRadius.apply(this, arguments));
|
pointCircle = d3_path_circle(pointRadius.apply(this, arguments));
|
||||||
}
|
}
|
||||||
return d3_geo_pathType(pathTypes, d);
|
return pathType(d) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function project(coordinates) {
|
function project(coordinates) {
|
||||||
return projection(coordinates).join(",");
|
return projection(coordinates).join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
var pathTypes = {
|
var pathType = d3_geo_type({
|
||||||
|
|
||||||
FeatureCollection: function(f) {
|
FeatureCollection: function(o) {
|
||||||
var path = [],
|
var path = [],
|
||||||
features = f.features,
|
features = o.features,
|
||||||
i = -1, // features.index
|
i = -1, // features.index
|
||||||
n = features.length;
|
n = features.length;
|
||||||
while (++i < n) path.push(d3_geo_pathType(pathTypes, features[i].geometry));
|
while (++i < n) path.push(pathType(features[i].geometry));
|
||||||
return path.join("");
|
return path.join("");
|
||||||
},
|
},
|
||||||
|
|
||||||
Feature: function(f) {
|
Feature: function(o) {
|
||||||
return d3_geo_pathType(pathTypes, f.geometry);
|
return pathType(o.geometry);
|
||||||
},
|
},
|
||||||
|
|
||||||
Point: function(o) {
|
Point: function(o) {
|
||||||
|
@ -290,11 +445,12 @@ d3.geo.path = function() {
|
||||||
while (++i < n) {
|
while (++i < n) {
|
||||||
subcoordinates = coordinates[i];
|
subcoordinates = coordinates[i];
|
||||||
j = -1;
|
j = -1;
|
||||||
m = subcoordinates.length;
|
if ((m = subcoordinates.length - 1) > 0) {
|
||||||
path.push("M");
|
path.push("M");
|
||||||
while (++j < m) path.push(project(subcoordinates[j]), "L");
|
while (++j < m) path.push(project(subcoordinates[j]), "L");
|
||||||
path[path.length - 1] = "Z";
|
path[path.length - 1] = "Z";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return path.join("");
|
return path.join("");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -316,12 +472,13 @@ d3.geo.path = function() {
|
||||||
while (++j < m) {
|
while (++j < m) {
|
||||||
subsubcoordinates = subcoordinates[j];
|
subsubcoordinates = subcoordinates[j];
|
||||||
k = -1;
|
k = -1;
|
||||||
p = subsubcoordinates.length - 1;
|
if ((p = subsubcoordinates.length - 1) > 0) {
|
||||||
path.push("M");
|
path.push("M");
|
||||||
while (++k < p) path.push(project(subsubcoordinates[k]), "L");
|
while (++k < p) path.push(project(subsubcoordinates[k]), "L");
|
||||||
path[path.length - 1] = "Z";
|
path[path.length - 1] = "Z";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return path.join("");
|
return path.join("");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -330,32 +487,27 @@ d3.geo.path = function() {
|
||||||
geometries = o.geometries,
|
geometries = o.geometries,
|
||||||
i = -1, // geometries index
|
i = -1, // geometries index
|
||||||
n = geometries.length;
|
n = geometries.length;
|
||||||
while (++i < n) path.push(d3_geo_pathType(pathTypes, geometries[i]));
|
while (++i < n) path.push(pathType(geometries[i]));
|
||||||
return path.join("");
|
return path.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
});
|
||||||
|
|
||||||
var areaTypes = {
|
var areaType = path.area = d3_geo_type({
|
||||||
|
|
||||||
FeatureCollection: function(f) {
|
FeatureCollection: function(o) {
|
||||||
var area = 0,
|
var area = 0,
|
||||||
features = f.features,
|
features = o.features,
|
||||||
i = -1, // features.index
|
i = -1, // features.index
|
||||||
n = features.length;
|
n = features.length;
|
||||||
while (++i < n) area += d3_geo_pathType(areaTypes, features[i]);
|
while (++i < n) area += areaType(features[i]);
|
||||||
return area;
|
return area;
|
||||||
},
|
},
|
||||||
|
|
||||||
Feature: function(f) {
|
Feature: function(o) {
|
||||||
return d3_geo_pathType(areaTypes, f.geometry);
|
return areaType(o.geometry);
|
||||||
},
|
},
|
||||||
|
|
||||||
Point: d3_geo_pathZero,
|
|
||||||
MultiPoint: d3_geo_pathZero,
|
|
||||||
LineString: d3_geo_pathZero,
|
|
||||||
MultiLineString: d3_geo_pathZero,
|
|
||||||
|
|
||||||
Polygon: function(o) {
|
Polygon: function(o) {
|
||||||
return polygonArea(o.coordinates);
|
return polygonArea(o.coordinates);
|
||||||
},
|
},
|
||||||
|
@ -374,11 +526,11 @@ d3.geo.path = function() {
|
||||||
geometries = o.geometries,
|
geometries = o.geometries,
|
||||||
i = -1, // geometries index
|
i = -1, // geometries index
|
||||||
n = geometries.length;
|
n = geometries.length;
|
||||||
while (++i < n) sum += d3_geo_pathType(areaTypes, geometries[i]);
|
while (++i < n) sum += areaType(geometries[i]);
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}, 0);
|
||||||
|
|
||||||
function polygonArea(coordinates) {
|
function polygonArea(coordinates) {
|
||||||
var sum = area(coordinates[0]), // exterior ring
|
var sum = area(coordinates[0]), // exterior ring
|
||||||
|
@ -390,23 +542,25 @@ d3.geo.path = function() {
|
||||||
|
|
||||||
function polygonCentroid(coordinates) {
|
function polygonCentroid(coordinates) {
|
||||||
var polygon = d3.geom.polygon(coordinates[0].map(projection)), // exterior ring
|
var polygon = d3.geom.polygon(coordinates[0].map(projection)), // exterior ring
|
||||||
centroid = polygon.centroid(1),
|
area = polygon.area(),
|
||||||
|
centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1),
|
||||||
x = centroid[0],
|
x = centroid[0],
|
||||||
y = centroid[1],
|
y = centroid[1],
|
||||||
z = Math.abs(polygon.area()),
|
z = area,
|
||||||
i = 0, // coordinates index
|
i = 0, // coordinates index
|
||||||
n = coordinates.length;
|
n = coordinates.length;
|
||||||
while (++i < n) {
|
while (++i < n) {
|
||||||
polygon = d3.geom.polygon(coordinates[i].map(projection)); // holes
|
polygon = d3.geom.polygon(coordinates[i].map(projection)); // holes
|
||||||
centroid = polygon.centroid(1);
|
area = polygon.area();
|
||||||
|
centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1);
|
||||||
x -= centroid[0];
|
x -= centroid[0];
|
||||||
y -= centroid[1];
|
y -= centroid[1];
|
||||||
z -= Math.abs(polygon.area());
|
z -= area;
|
||||||
}
|
}
|
||||||
return [x, y, 6 * z]; // weighted centroid
|
return [x, y, 6 * z]; // weighted centroid
|
||||||
}
|
}
|
||||||
|
|
||||||
var centroidTypes = {
|
var centroidType = path.centroid = d3_geo_type({
|
||||||
|
|
||||||
// TODO FeatureCollection
|
// TODO FeatureCollection
|
||||||
// TODO Point
|
// TODO Point
|
||||||
|
@ -415,8 +569,8 @@ d3.geo.path = function() {
|
||||||
// TODO MultiLineString
|
// TODO MultiLineString
|
||||||
// TODO GeometryCollection
|
// TODO GeometryCollection
|
||||||
|
|
||||||
Feature: function(f) {
|
Feature: function(o) {
|
||||||
return d3_geo_pathType(centroidTypes, f.geometry);
|
return centroidType(o.geometry);
|
||||||
},
|
},
|
||||||
|
|
||||||
Polygon: function(o) {
|
Polygon: function(o) {
|
||||||
|
@ -442,8 +596,7 @@ d3.geo.path = function() {
|
||||||
return [x / z, y / z];
|
return [x / z, y / z];
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
});
|
||||||
|
|
||||||
|
|
||||||
function area(coordinates) {
|
function area(coordinates) {
|
||||||
return Math.abs(d3.geom.polygon(coordinates.map(projection)).area());
|
return Math.abs(d3.geom.polygon(coordinates.map(projection)).area());
|
||||||
|
@ -454,14 +607,6 @@ d3.geo.path = function() {
|
||||||
return path;
|
return path;
|
||||||
};
|
};
|
||||||
|
|
||||||
path.area = function(d) {
|
|
||||||
return d3_geo_pathType(areaTypes, d);
|
|
||||||
};
|
|
||||||
|
|
||||||
path.centroid = function(d) {
|
|
||||||
return d3_geo_pathType(centroidTypes, d);
|
|
||||||
};
|
|
||||||
|
|
||||||
path.pointRadius = function(x) {
|
path.pointRadius = function(x) {
|
||||||
if (typeof x === "function") pointRadius = x;
|
if (typeof x === "function") pointRadius = x;
|
||||||
else {
|
else {
|
||||||
|
@ -480,14 +625,6 @@ function d3_path_circle(radius) {
|
||||||
+ "a" + radius + "," + radius + " 0 1,1 0," + (+2 * radius)
|
+ "a" + radius + "," + radius + " 0 1,1 0," + (+2 * radius)
|
||||||
+ "z";
|
+ "z";
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_geo_pathZero() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function d3_geo_pathType(types, o) {
|
|
||||||
return o && o.type in types ? types[o.type](o) : "";
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Given a GeoJSON object, returns the corresponding bounding box. The bounding
|
* Given a GeoJSON object, returns the corresponding bounding box. The bounding
|
||||||
* box is represented by a two-dimensional array: [[left, bottom], [right,
|
* box is represented by a two-dimensional array: [[left, bottom], [right,
|
||||||
|
@ -564,4 +701,231 @@ function d3_geo_boundsPolygon(o, f) {
|
||||||
f.apply(null, a[i]);
|
f.apply(null, a[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO breakAtDateLine?
|
||||||
|
|
||||||
|
d3.geo.circle = function() {
|
||||||
|
var origin = [0, 0],
|
||||||
|
degrees = 90 - 1e-2,
|
||||||
|
radians = degrees * d3_geo_radians,
|
||||||
|
arc = d3.geo.greatArc().target(Object);
|
||||||
|
|
||||||
|
function circle() {
|
||||||
|
// TODO render a circle as a Polygon
|
||||||
|
}
|
||||||
|
|
||||||
|
function visible(point) {
|
||||||
|
return arc.distance(point) < radians;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle.clip = function(d) {
|
||||||
|
arc.source(typeof origin === "function" ? origin.apply(this, arguments) : origin);
|
||||||
|
return clipType(d);
|
||||||
|
};
|
||||||
|
|
||||||
|
var clipType = d3_geo_type({
|
||||||
|
|
||||||
|
FeatureCollection: function(o) {
|
||||||
|
var features = o.features.map(clipType).filter(Object);
|
||||||
|
return features && (o = Object.create(o), o.features = features, o);
|
||||||
|
},
|
||||||
|
|
||||||
|
Feature: function(o) {
|
||||||
|
var geometry = clipType(o.geometry);
|
||||||
|
return geometry && (o = Object.create(o), o.geometry = geometry, o);
|
||||||
|
},
|
||||||
|
|
||||||
|
Point: function(o) {
|
||||||
|
return visible(o.coordinates) && o;
|
||||||
|
},
|
||||||
|
|
||||||
|
MultiPoint: function(o) {
|
||||||
|
var coordinates = o.coordinates.filter(visible);
|
||||||
|
return coordinates.length && {
|
||||||
|
type: o.type,
|
||||||
|
coordinates: coordinates
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
LineString: function(o) {
|
||||||
|
var coordinates = clip(o.coordinates);
|
||||||
|
return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
|
||||||
|
},
|
||||||
|
|
||||||
|
MultiLineString: function(o) {
|
||||||
|
var coordinates = o.coordinates.map(clip).filter(function(d) { return d.length; });
|
||||||
|
return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
|
||||||
|
},
|
||||||
|
|
||||||
|
Polygon: function(o) {
|
||||||
|
var coordinates = o.coordinates.map(clip);
|
||||||
|
return coordinates[0].length && (o = Object.create(o), o.coordinates = coordinates, o);
|
||||||
|
},
|
||||||
|
|
||||||
|
MultiPolygon: function(o) {
|
||||||
|
var coordinates = o.coordinates.map(function(d) { return d.map(clip); }).filter(function(d) { return d[0].length; });
|
||||||
|
return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
|
||||||
|
},
|
||||||
|
|
||||||
|
GeometryCollection: function(o) {
|
||||||
|
var geometries = o.geometries.map(clipType).filter(Object);
|
||||||
|
return geometries.length && (o = Object.create(o), o.geometries = geometries, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function clip(coordinates) {
|
||||||
|
var i = -1,
|
||||||
|
n = coordinates.length,
|
||||||
|
clipped = [],
|
||||||
|
p0,
|
||||||
|
p1,
|
||||||
|
p2,
|
||||||
|
d0,
|
||||||
|
d1;
|
||||||
|
|
||||||
|
while (++i < n) {
|
||||||
|
d1 = arc.distance(p2 = coordinates[i]);
|
||||||
|
if (d1 < radians) {
|
||||||
|
if (p1) clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1)));
|
||||||
|
clipped.push(p2);
|
||||||
|
p0 = p1 = null;
|
||||||
|
} else {
|
||||||
|
p1 = p2;
|
||||||
|
if (!p0 && clipped.length) {
|
||||||
|
clipped.push(d3_geo_greatArcInterpolate(clipped[clipped.length - 1], p1)((radians - d0) / (d1 - d0)));
|
||||||
|
p0 = p1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d0 = d1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p1 && clipped.length) {
|
||||||
|
d1 = arc.distance(p2 = clipped[0]);
|
||||||
|
clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resample(clipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resample coordinates, creating great arcs between each.
|
||||||
|
function resample(coordinates) {
|
||||||
|
var i = 0,
|
||||||
|
n = coordinates.length,
|
||||||
|
j,
|
||||||
|
m,
|
||||||
|
resampled = n ? [coordinates[0]] : coordinates,
|
||||||
|
resamples,
|
||||||
|
origin = arc.source();
|
||||||
|
|
||||||
|
while (++i < n) {
|
||||||
|
resamples = arc.source(coordinates[i - 1])(coordinates[i]).coordinates;
|
||||||
|
for (j = 0, m = resamples.length; ++j < m;) resampled.push(resamples[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
arc.source(origin);
|
||||||
|
return resampled;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle.origin = function(x) {
|
||||||
|
if (!arguments.length) return origin;
|
||||||
|
origin = x;
|
||||||
|
return circle;
|
||||||
|
};
|
||||||
|
|
||||||
|
circle.angle = function(x) {
|
||||||
|
if (!arguments.length) return degrees;
|
||||||
|
radians = (degrees = +x) * d3_geo_radians;
|
||||||
|
return circle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Precision is specified in degrees.
|
||||||
|
circle.precision = function(x) {
|
||||||
|
if (!arguments.length) return arc.precision();
|
||||||
|
arc.precision(x);
|
||||||
|
return circle;
|
||||||
|
};
|
||||||
|
|
||||||
|
return circle;
|
||||||
|
}
|
||||||
|
d3.geo.greatArc = function() {
|
||||||
|
var source = d3_geo_greatArcSource,
|
||||||
|
target = d3_geo_greatArcTarget,
|
||||||
|
precision = 6 * d3_geo_radians;
|
||||||
|
|
||||||
|
function greatArc() {
|
||||||
|
var a = typeof source === "function" ? source.apply(this, arguments) : source,
|
||||||
|
b = typeof target === "function" ? target.apply(this, arguments) : target,
|
||||||
|
i = d3_geo_greatArcInterpolate(a, b),
|
||||||
|
dt = precision / i.d,
|
||||||
|
t = 0,
|
||||||
|
coordinates = [a];
|
||||||
|
while ((t += dt) < 1) coordinates.push(i(t));
|
||||||
|
coordinates.push(b);
|
||||||
|
return {
|
||||||
|
type: "LineString",
|
||||||
|
coordinates: coordinates
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Length returned in radians; multiply by radius for distance.
|
||||||
|
greatArc.distance = function() {
|
||||||
|
var a = typeof source === "function" ? source.apply(this, arguments) : source,
|
||||||
|
b = typeof target === "function" ? target.apply(this, arguments) : target;
|
||||||
|
return d3_geo_greatArcInterpolate(a, b).d;
|
||||||
|
};
|
||||||
|
|
||||||
|
greatArc.source = function(x) {
|
||||||
|
if (!arguments.length) return source;
|
||||||
|
source = x;
|
||||||
|
return greatArc;
|
||||||
|
};
|
||||||
|
|
||||||
|
greatArc.target = function(x) {
|
||||||
|
if (!arguments.length) return target;
|
||||||
|
target = x;
|
||||||
|
return greatArc;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Precision is specified in degrees.
|
||||||
|
greatArc.precision = function(x) {
|
||||||
|
if (!arguments.length) return precision / d3_geo_radians;
|
||||||
|
precision = x * d3_geo_radians;
|
||||||
|
return greatArc;
|
||||||
|
};
|
||||||
|
|
||||||
|
return greatArc;
|
||||||
|
};
|
||||||
|
|
||||||
|
function d3_geo_greatArcSource(d) {
|
||||||
|
return d.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
function d3_geo_greatArcTarget(d) {
|
||||||
|
return d.target;
|
||||||
|
}
|
||||||
|
|
||||||
|
function d3_geo_greatArcInterpolate(a, b) {
|
||||||
|
var x0 = a[0] * d3_geo_radians, cx0 = Math.cos(x0), sx0 = Math.sin(x0),
|
||||||
|
y0 = a[1] * d3_geo_radians, cy0 = Math.cos(y0), sy0 = Math.sin(y0),
|
||||||
|
x1 = b[0] * d3_geo_radians, cx1 = Math.cos(x1), sx1 = Math.sin(x1),
|
||||||
|
y1 = b[1] * d3_geo_radians, cy1 = Math.cos(y1), sy1 = Math.sin(y1),
|
||||||
|
d = interpolate.d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))),
|
||||||
|
sd = Math.sin(d);
|
||||||
|
|
||||||
|
// From http://williams.best.vwh.net/avform.htm#Intermediate
|
||||||
|
function interpolate(t) {
|
||||||
|
var A = Math.sin(d - (t *= d)) / sd,
|
||||||
|
B = Math.sin(t) / sd,
|
||||||
|
x = A * cy0 * cx0 + B * cy1 * cx1,
|
||||||
|
y = A * cy0 * sx0 + B * cy1 * sx1,
|
||||||
|
z = A * sy0 + B * sy1;
|
||||||
|
return [
|
||||||
|
Math.atan2(y, x) / d3_geo_radians,
|
||||||
|
Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_geo_radians
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return interpolate;
|
||||||
|
}
|
||||||
|
d3.geo.greatCircle = d3.geo.circle;
|
||||||
})();
|
})();
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
14
d3.geom.js
14
d3.geom.js
|
@ -198,7 +198,7 @@ d3.geom.polygon = function(coordinates) {
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
c;
|
c;
|
||||||
if (!arguments.length) k = 1 / (6 * coordinates.area());
|
if (!arguments.length) k = -1 / (6 * coordinates.area());
|
||||||
while (++i < n) {
|
while (++i < n) {
|
||||||
a = coordinates[i];
|
a = coordinates[i];
|
||||||
b = coordinates[i + 1];
|
b = coordinates[i + 1];
|
||||||
|
@ -268,6 +268,17 @@ function d3_geom_polygonIntersect(c, d, a, b) {
|
||||||
// http://blog.thejit.org/assets/voronoijs/voronoi.js
|
// http://blog.thejit.org/assets/voronoijs/voronoi.js
|
||||||
// See lib/jit/LICENSE for details.
|
// See lib/jit/LICENSE for details.
|
||||||
|
|
||||||
|
// Notes:
|
||||||
|
//
|
||||||
|
// This implementation does not clip the returned polygons, so if you want to
|
||||||
|
// clip them to a particular shape you will need to do that either in SVG or by
|
||||||
|
// post-processing with d3.geom.polygon's clip method.
|
||||||
|
//
|
||||||
|
// If any vertices are coincident or have NaN positions, the behavior of this
|
||||||
|
// method is undefined. Most likely invalid polygons will be returned. You
|
||||||
|
// should filter invalid points, and consolidate coincident points, before
|
||||||
|
// computing the tessellation.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param vertices [[x1, y1], [x2, y2], …]
|
* @param vertices [[x1, y1], [x2, y2], …]
|
||||||
* @returns polygons [[[x1, y1], [x2, y2], …], …]
|
* @returns polygons [[[x1, y1], [x2, y2], …], …]
|
||||||
|
@ -275,7 +286,6 @@ function d3_geom_polygonIntersect(c, d, a, b) {
|
||||||
d3.geom.voronoi = function(vertices) {
|
d3.geom.voronoi = function(vertices) {
|
||||||
var polygons = vertices.map(function() { return []; });
|
var polygons = vertices.map(function() { return []; });
|
||||||
|
|
||||||
// Note: we expect the caller to clip the polygons, if needed.
|
|
||||||
d3_voronoi_tessellate(vertices, function(e) {
|
d3_voronoi_tessellate(vertices, function(e) {
|
||||||
var s1,
|
var s1,
|
||||||
s2,
|
s2,
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
246
d3.layout.js
246
d3.layout.js
|
@ -113,16 +113,19 @@ d3.layout.chord = function() {
|
||||||
k = (2 * Math.PI - padding * n) / k;
|
k = (2 * Math.PI - padding * n) / k;
|
||||||
|
|
||||||
// Compute the start and end angle for each group and subgroup.
|
// 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) {
|
x = 0, i = -1; while (++i < n) {
|
||||||
x0 = x, j = -1; while (++j < n) {
|
x0 = x, j = -1; while (++j < n) {
|
||||||
var di = groupIndex[i],
|
var di = groupIndex[i],
|
||||||
dj = subgroupIndex[i][j],
|
dj = subgroupIndex[di][j],
|
||||||
v = matrix[di][dj];
|
v = matrix[di][dj],
|
||||||
|
a0 = x,
|
||||||
|
a1 = x += v * k;
|
||||||
subgroups[di + "-" + dj] = {
|
subgroups[di + "-" + dj] = {
|
||||||
index: di,
|
index: di,
|
||||||
subindex: dj,
|
subindex: dj,
|
||||||
startAngle: x,
|
startAngle: a0,
|
||||||
endAngle: x += v * k,
|
endAngle: a1,
|
||||||
value: v
|
value: v
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -153,7 +156,9 @@ d3.layout.chord = function() {
|
||||||
|
|
||||||
function resort() {
|
function resort() {
|
||||||
chords.sort(function(a, b) {
|
chords.sort(function(a, b) {
|
||||||
return sortChords(a.target.value, b.target.value);
|
return sortChords(
|
||||||
|
(a.source.value + a.target.value) / 2,
|
||||||
|
(b.source.value + b.target.value) / 2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,9 +226,10 @@ d3.layout.force = function() {
|
||||||
nodes = [],
|
nodes = [],
|
||||||
links = [],
|
links = [],
|
||||||
distances,
|
distances,
|
||||||
strengths;
|
strengths,
|
||||||
|
charges;
|
||||||
|
|
||||||
function repulse(node, kc) {
|
function repulse(node) {
|
||||||
return function(quad, x1, y1, x2, y2) {
|
return function(quad, x1, y1, x2, y2) {
|
||||||
if (quad.point !== node) {
|
if (quad.point !== node) {
|
||||||
var dx = quad.cx - node.x,
|
var dx = quad.cx - node.x,
|
||||||
|
@ -232,30 +238,32 @@ d3.layout.force = function() {
|
||||||
|
|
||||||
/* Barnes-Hut criterion. */
|
/* Barnes-Hut criterion. */
|
||||||
if ((x2 - x1) * dn < theta) {
|
if ((x2 - x1) * dn < theta) {
|
||||||
var k = kc * quad.count * dn * dn;
|
var k = quad.charge * dn * dn;
|
||||||
node.x += dx * k;
|
node.px -= dx * k;
|
||||||
node.y += dy * k;
|
node.py -= dy * k;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quad.point && isFinite(dn)) {
|
if (quad.point && isFinite(dn)) {
|
||||||
var k = kc * dn * dn;
|
var k = quad.pointCharge * dn * dn;
|
||||||
node.x += dx * k;
|
node.px -= dx * k;
|
||||||
node.y += dy * k;
|
node.py -= dy * k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return !quad.charge;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function tick() {
|
function tick() {
|
||||||
var n = nodes.length,
|
var n = nodes.length,
|
||||||
m = links.length,
|
m = links.length,
|
||||||
q = d3.geom.quadtree(nodes),
|
q,
|
||||||
i, // current index
|
i, // current index
|
||||||
o, // current object
|
o, // current object
|
||||||
s, // current source
|
s, // current source
|
||||||
t, // current target
|
t, // current target
|
||||||
l, // current distance
|
l, // current distance
|
||||||
|
k, // current force
|
||||||
x, // x-distance
|
x, // x-distance
|
||||||
y; // y-distance
|
y; // y-distance
|
||||||
|
|
||||||
|
@ -270,30 +278,32 @@ d3.layout.force = function() {
|
||||||
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
|
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
|
||||||
x *= l;
|
x *= l;
|
||||||
y *= l;
|
y *= l;
|
||||||
t.x -= x / t.weight;
|
t.x -= x * (k = s.weight / (t.weight + s.weight));
|
||||||
t.y -= y / t.weight;
|
t.y -= y * k;
|
||||||
s.x += x / s.weight;
|
s.x += x * (k = 1 - k);
|
||||||
s.y += y / s.weight;
|
s.y += y * k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply gravity forces
|
// apply gravity forces
|
||||||
var kg = alpha * gravity;
|
if (k = alpha * gravity) {
|
||||||
x = size[0] / 2;
|
x = size[0] / 2;
|
||||||
y = size[1] / 2;
|
y = size[1] / 2;
|
||||||
i = -1; while (++i < n) {
|
i = -1; if (k) while (++i < n) {
|
||||||
o = nodes[i];
|
o = nodes[i];
|
||||||
o.x += (x - o.x) * kg;
|
o.x += (x - o.x) * k;
|
||||||
o.y += (y - o.y) * kg;
|
o.y += (y - o.y) * k;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute quadtree center of mass
|
// compute quadtree center of mass and apply charge forces
|
||||||
d3_layout_forceAccumulate(q);
|
if (charge) {
|
||||||
|
d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
|
||||||
// apply charge forces
|
|
||||||
var kc = alpha * charge;
|
|
||||||
i = -1; while (++i < n) {
|
i = -1; while (++i < n) {
|
||||||
q.visit(repulse(nodes[i], kc));
|
if (!(o = nodes[i]).fixed) {
|
||||||
|
q.visit(repulse(o));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// position verlet integration
|
// position verlet integration
|
||||||
|
@ -308,17 +318,12 @@ d3.layout.force = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.tick.dispatch({type: "tick", alpha: alpha});
|
event.tick({type: "tick", alpha: alpha});
|
||||||
|
|
||||||
// simulated annealing, basically
|
// simulated annealing, basically
|
||||||
return (alpha *= .99) < .005;
|
return (alpha *= .99) < .005;
|
||||||
}
|
}
|
||||||
|
|
||||||
force.on = function(type, listener) {
|
|
||||||
event[type].add(listener);
|
|
||||||
return force;
|
|
||||||
};
|
|
||||||
|
|
||||||
force.nodes = function(x) {
|
force.nodes = function(x) {
|
||||||
if (!arguments.length) return nodes;
|
if (!arguments.length) return nodes;
|
||||||
nodes = x;
|
nodes = x;
|
||||||
|
@ -360,7 +365,7 @@ d3.layout.force = function() {
|
||||||
|
|
||||||
force.charge = function(x) {
|
force.charge = function(x) {
|
||||||
if (!arguments.length) return charge;
|
if (!arguments.length) return charge;
|
||||||
charge = x;
|
charge = typeof x === "function" ? x : +x;
|
||||||
return force;
|
return force;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -411,6 +416,17 @@ d3.layout.force = function() {
|
||||||
if (isNaN(o.py)) o.py = o.y;
|
if (isNaN(o.py)) o.py = o.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
charges = [];
|
||||||
|
if (typeof charge === "function") {
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
charges[i] = +charge.call(this, nodes[i], i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
charges[i] = charge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// initialize node position based on first neighbor
|
// initialize node position based on first neighbor
|
||||||
function position(dimension, size) {
|
function position(dimension, size) {
|
||||||
var neighbors = neighbor(i),
|
var neighbors = neighbor(i),
|
||||||
|
@ -468,7 +484,7 @@ d3.layout.force = function() {
|
||||||
d3_layout_forceDragForce = force;
|
d3_layout_forceDragForce = force;
|
||||||
}
|
}
|
||||||
|
|
||||||
return force;
|
return d3.rebind(force, event, "on");
|
||||||
};
|
};
|
||||||
|
|
||||||
var d3_layout_forceDragForce,
|
var d3_layout_forceDragForce,
|
||||||
|
@ -494,10 +510,10 @@ function d3_layout_forceDrag() {
|
||||||
d3_layout_forceDragForce.resume(); // restart annealing
|
d3_layout_forceDragForce.resume(); // restart annealing
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_layout_forceAccumulate(quad) {
|
function d3_layout_forceAccumulate(quad, alpha, charges) {
|
||||||
var cx = 0,
|
var cx = 0,
|
||||||
cy = 0;
|
cy = 0;
|
||||||
quad.count = 0;
|
quad.charge = 0;
|
||||||
if (!quad.leaf) {
|
if (!quad.leaf) {
|
||||||
var nodes = quad.nodes,
|
var nodes = quad.nodes,
|
||||||
n = nodes.length,
|
n = nodes.length,
|
||||||
|
@ -506,10 +522,10 @@ function d3_layout_forceAccumulate(quad) {
|
||||||
while (++i < n) {
|
while (++i < n) {
|
||||||
c = nodes[i];
|
c = nodes[i];
|
||||||
if (c == null) continue;
|
if (c == null) continue;
|
||||||
d3_layout_forceAccumulate(c);
|
d3_layout_forceAccumulate(c, alpha, charges);
|
||||||
quad.count += c.count;
|
quad.charge += c.charge;
|
||||||
cx += c.count * c.cx;
|
cx += c.charge * c.cx;
|
||||||
cy += c.count * c.cy;
|
cy += c.charge * c.cy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (quad.point) {
|
if (quad.point) {
|
||||||
|
@ -518,12 +534,13 @@ function d3_layout_forceAccumulate(quad) {
|
||||||
quad.point.x += Math.random() - .5;
|
quad.point.x += Math.random() - .5;
|
||||||
quad.point.y += Math.random() - .5;
|
quad.point.y += Math.random() - .5;
|
||||||
}
|
}
|
||||||
quad.count++;
|
var k = alpha * charges[quad.point.index];
|
||||||
cx += quad.point.x;
|
quad.charge += quad.pointCharge = k;
|
||||||
cy += quad.point.y;
|
cx += k * quad.point.x;
|
||||||
|
cy += k * quad.point.y;
|
||||||
}
|
}
|
||||||
quad.cx = cx / quad.count;
|
quad.cx = cx / quad.charge;
|
||||||
quad.cy = cy / quad.count;
|
quad.cy = cy / quad.charge;
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_layout_forceLinkDistance(link) {
|
function d3_layout_forceLinkDistance(link) {
|
||||||
|
@ -543,9 +560,9 @@ d3.layout.partition = function() {
|
||||||
node.y = node.depth * dy;
|
node.y = node.depth * dy;
|
||||||
node.dx = dx;
|
node.dx = dx;
|
||||||
node.dy = dy;
|
node.dy = dy;
|
||||||
if (children) {
|
if (children && (n = children.length)) {
|
||||||
var i = -1,
|
var i = -1,
|
||||||
n = children.length,
|
n,
|
||||||
c,
|
c,
|
||||||
d;
|
d;
|
||||||
dx = node.value ? dx / node.value : 0;
|
dx = node.value ? dx / node.value : 0;
|
||||||
|
@ -559,9 +576,9 @@ d3.layout.partition = function() {
|
||||||
function depth(node) {
|
function depth(node) {
|
||||||
var children = node.children,
|
var children = node.children,
|
||||||
d = 0;
|
d = 0;
|
||||||
if (children) {
|
if (children && (n = children.length)) {
|
||||||
var i = -1,
|
var i = -1,
|
||||||
n = children.length;
|
n;
|
||||||
while (++i < n) d = Math.max(d, depth(children[i]));
|
while (++i < n) d = Math.max(d, depth(children[i]));
|
||||||
}
|
}
|
||||||
return 1 + d;
|
return 1 + d;
|
||||||
|
@ -583,33 +600,31 @@ d3.layout.partition = function() {
|
||||||
};
|
};
|
||||||
d3.layout.pie = function() {
|
d3.layout.pie = function() {
|
||||||
var value = Number,
|
var value = Number,
|
||||||
sort = null,
|
sort = d3_layout_pieSortByValue,
|
||||||
startAngle = 0,
|
startAngle = 0,
|
||||||
endAngle = 2 * Math.PI;
|
endAngle = 2 * Math.PI;
|
||||||
|
|
||||||
function pie(data, i) {
|
function pie(data, i) {
|
||||||
|
|
||||||
|
// Compute the numeric values for each data element.
|
||||||
|
var values = data.map(function(d, i) { return +value.call(pie, d, i); });
|
||||||
|
|
||||||
// Compute the start angle.
|
// Compute the start angle.
|
||||||
var a = +(typeof startAngle === "function"
|
var a = +(typeof startAngle === "function"
|
||||||
? startAngle.apply(this, arguments)
|
? startAngle.apply(this, arguments)
|
||||||
: startAngle);
|
: startAngle);
|
||||||
|
|
||||||
// Compute the angular range (end - start).
|
// Compute the angular scale factor: from value to radians.
|
||||||
var k = (typeof endAngle === "function"
|
var k = ((typeof endAngle === "function"
|
||||||
? endAngle.apply(this, arguments)
|
? endAngle.apply(this, arguments)
|
||||||
: endAngle) - startAngle;
|
: endAngle) - startAngle)
|
||||||
|
/ d3.sum(values);
|
||||||
|
|
||||||
// Optionally sort the data.
|
// Optionally sort the data.
|
||||||
var index = d3.range(data.length);
|
var index = d3.range(data.length);
|
||||||
if (sort != null) index.sort(function(i, j) {
|
if (sort != null) index.sort(sort === d3_layout_pieSortByValue
|
||||||
return sort(data[i], data[j]);
|
? function(i, j) { return values[j] - values[i]; }
|
||||||
});
|
: function(i, j) { return sort(data[i], data[j]); });
|
||||||
|
|
||||||
// Compute the numeric values for each data element.
|
|
||||||
var values = data.map(value);
|
|
||||||
|
|
||||||
// Convert k into a scale factor from value to angle, using the sum.
|
|
||||||
k /= values.reduce(function(p, d) { return p + d; }, 0);
|
|
||||||
|
|
||||||
// Compute the arcs!
|
// Compute the arcs!
|
||||||
var arcs = index.map(function(i) {
|
var arcs = index.map(function(i) {
|
||||||
|
@ -676,6 +691,8 @@ d3.layout.pie = function() {
|
||||||
|
|
||||||
return pie;
|
return pie;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var d3_layout_pieSortByValue = {};
|
||||||
// data is two-dimensional array of x,y; we populate y0
|
// data is two-dimensional array of x,y; we populate y0
|
||||||
d3.layout.stack = function() {
|
d3.layout.stack = function() {
|
||||||
var values = Object,
|
var values = Object,
|
||||||
|
@ -1027,9 +1044,9 @@ d3.layout.hierarchy = function() {
|
||||||
node = d3_layout_hierarchyInline ? data : {data: data};
|
node = d3_layout_hierarchyInline ? data : {data: data};
|
||||||
node.depth = depth;
|
node.depth = depth;
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
if (childs) {
|
if (childs && (n = childs.length)) {
|
||||||
var i = -1,
|
var i = -1,
|
||||||
n = childs.length,
|
n,
|
||||||
c = node.children = [],
|
c = node.children = [],
|
||||||
v = 0,
|
v = 0,
|
||||||
j = depth + 1;
|
j = depth + 1;
|
||||||
|
@ -1051,9 +1068,9 @@ d3.layout.hierarchy = function() {
|
||||||
function revalue(node, depth) {
|
function revalue(node, depth) {
|
||||||
var children = node.children,
|
var children = node.children,
|
||||||
v = 0;
|
v = 0;
|
||||||
if (children) {
|
if (children && (n = children.length)) {
|
||||||
var i = -1,
|
var i = -1,
|
||||||
n = children.length,
|
n,
|
||||||
j = depth + 1;
|
j = depth + 1;
|
||||||
while (++i < n) v += revalue(children[i], j);
|
while (++i < n) v += revalue(children[i], j);
|
||||||
} else if (value) {
|
} else if (value) {
|
||||||
|
@ -1098,10 +1115,10 @@ d3.layout.hierarchy = function() {
|
||||||
|
|
||||||
// A method assignment helper for hierarchy subclasses.
|
// A method assignment helper for hierarchy subclasses.
|
||||||
function d3_layout_hierarchyRebind(object, hierarchy) {
|
function d3_layout_hierarchyRebind(object, hierarchy) {
|
||||||
object.sort = d3.rebind(object, hierarchy.sort);
|
d3.rebind(object, hierarchy, "sort", "children", "value");
|
||||||
object.children = d3.rebind(object, hierarchy.children);
|
|
||||||
|
// Add an alias for links, for convenience.
|
||||||
object.links = d3_layout_hierarchyLinks;
|
object.links = d3_layout_hierarchyLinks;
|
||||||
object.value = d3.rebind(object, hierarchy.value);
|
|
||||||
|
|
||||||
// If the new API is used, enabling inlining.
|
// If the new API is used, enabling inlining.
|
||||||
object.nodes = function(d) {
|
object.nodes = function(d) {
|
||||||
|
@ -1301,7 +1318,7 @@ function d3_layout_packUnlink(node) {
|
||||||
|
|
||||||
function d3_layout_packTree(node) {
|
function d3_layout_packTree(node) {
|
||||||
var children = node.children;
|
var children = node.children;
|
||||||
if (children) {
|
if (children && children.length) {
|
||||||
children.forEach(d3_layout_packTree);
|
children.forEach(d3_layout_packTree);
|
||||||
node.r = d3_layout_packCircle(children);
|
node.r = d3_layout_packCircle(children);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1321,19 +1338,22 @@ function d3_layout_packTransform(node, x, y, k) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_layout_packPlace(a, b, c) {
|
function d3_layout_packPlace(a, b, c) {
|
||||||
var da = b.r + c.r,
|
var db = a.r + c.r,
|
||||||
db = a.r + c.r,
|
|
||||||
dx = b.x - a.x,
|
dx = b.x - a.x,
|
||||||
dy = b.y - a.y,
|
dy = b.y - a.y;
|
||||||
|
if (db && (dx || dy)) {
|
||||||
|
var da = b.r + c.r,
|
||||||
dc = Math.sqrt(dx * dx + dy * dy),
|
dc = Math.sqrt(dx * dx + dy * dy),
|
||||||
cos = (db * db + dc * dc - da * da) / (2 * db * dc),
|
cos = Math.max(-1, Math.min(1, (db * db + dc * dc - da * da) / (2 * db * dc))),
|
||||||
theta = Math.acos(cos),
|
theta = Math.acos(cos),
|
||||||
x = cos * db,
|
x = cos * (db /= dc),
|
||||||
h = Math.sin(theta) * db;
|
y = Math.sin(theta) * db;
|
||||||
dx /= dc;
|
c.x = a.x + x * dx + y * dy;
|
||||||
dy /= dc;
|
c.y = a.y + x * dy - y * dx;
|
||||||
c.x = a.x + x * dx + h * dy;
|
} else {
|
||||||
c.y = a.y + x * dy - h * dx;
|
c.x = a.x + db;
|
||||||
|
c.y = a.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Implements a hierarchical layout using the cluster (or dendogram) algorithm.
|
// Implements a hierarchical layout using the cluster (or dendogram) algorithm.
|
||||||
d3.layout.cluster = function() {
|
d3.layout.cluster = function() {
|
||||||
|
@ -1351,9 +1371,10 @@ d3.layout.cluster = function() {
|
||||||
|
|
||||||
// First walk, computing the initial x & y values.
|
// First walk, computing the initial x & y values.
|
||||||
d3_layout_treeVisitAfter(root, function(node) {
|
d3_layout_treeVisitAfter(root, function(node) {
|
||||||
if (node.children) {
|
var children = node.children;
|
||||||
node.x = d3_layout_clusterX(node.children);
|
if (children && children.length) {
|
||||||
node.y = d3_layout_clusterY(node.children);
|
node.x = d3_layout_clusterX(children);
|
||||||
|
node.y = d3_layout_clusterY(children);
|
||||||
} else {
|
} else {
|
||||||
node.x = previousNode ? x += separation(node, previousNode) : 0;
|
node.x = previousNode ? x += separation(node, previousNode) : 0;
|
||||||
node.y = 0;
|
node.y = 0;
|
||||||
|
@ -1405,12 +1426,12 @@ function d3_layout_clusterX(children) {
|
||||||
|
|
||||||
function d3_layout_clusterLeft(node) {
|
function d3_layout_clusterLeft(node) {
|
||||||
var children = node.children;
|
var children = node.children;
|
||||||
return children ? d3_layout_clusterLeft(children[0]) : node;
|
return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_layout_clusterRight(node) {
|
function d3_layout_clusterRight(node) {
|
||||||
var children = node.children;
|
var children = node.children, n;
|
||||||
return children ? d3_layout_clusterRight(children[children.length - 1]) : node;
|
return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
|
||||||
}
|
}
|
||||||
// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
|
// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
|
||||||
d3.layout.tree = function() {
|
d3.layout.tree = function() {
|
||||||
|
@ -1456,9 +1477,9 @@ d3.layout.tree = function() {
|
||||||
function secondWalk(node, x) {
|
function secondWalk(node, x) {
|
||||||
node.x = node._tree.prelim + x;
|
node.x = node._tree.prelim + x;
|
||||||
var children = node.children;
|
var children = node.children;
|
||||||
if (children) {
|
if (children && (n = children.length)) {
|
||||||
var i = -1,
|
var i = -1,
|
||||||
n = children.length;
|
n;
|
||||||
x += node._tree.mod;
|
x += node._tree.mod;
|
||||||
while (++i < n) {
|
while (++i < n) {
|
||||||
secondWalk(children[i], x);
|
secondWalk(children[i], x);
|
||||||
|
@ -1563,18 +1584,21 @@ function d3_layout_treeSeparation(a, b) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function d3_layout_treeLeft(node) {
|
function d3_layout_treeLeft(node) {
|
||||||
return node.children ? node.children[0] : node._tree.thread;
|
var children = node.children;
|
||||||
|
return children && children.length ? children[0] : node._tree.thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_layout_treeRight(node) {
|
function d3_layout_treeRight(node) {
|
||||||
return node.children ? node.children[node.children.length - 1] : node._tree.thread;
|
var children = node.children,
|
||||||
|
n;
|
||||||
|
return children && (n = children.length) ? children[n - 1] : node._tree.thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_layout_treeSearch(node, compare) {
|
function d3_layout_treeSearch(node, compare) {
|
||||||
var children = node.children;
|
var children = node.children;
|
||||||
if (children) {
|
if (children && (n = children.length)) {
|
||||||
var child,
|
var child,
|
||||||
n = children.length,
|
n,
|
||||||
i = -1;
|
i = -1;
|
||||||
while (++i < n) {
|
while (++i < n) {
|
||||||
if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
|
if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
|
||||||
|
@ -1600,11 +1624,11 @@ function d3_layout_treeDeepest(a, b) {
|
||||||
function d3_layout_treeVisitAfter(node, callback) {
|
function d3_layout_treeVisitAfter(node, callback) {
|
||||||
function visit(node, previousSibling) {
|
function visit(node, previousSibling) {
|
||||||
var children = node.children;
|
var children = node.children;
|
||||||
if (children) {
|
if (children && (n = children.length)) {
|
||||||
var child,
|
var child,
|
||||||
previousChild = null,
|
previousChild = null,
|
||||||
i = -1,
|
i = -1,
|
||||||
n = children.length;
|
n;
|
||||||
while (++i < n) {
|
while (++i < n) {
|
||||||
child = children[i];
|
child = children[i];
|
||||||
visit(child, previousChild);
|
visit(child, previousChild);
|
||||||
|
@ -1672,22 +1696,23 @@ d3.layout.treemap = function() {
|
||||||
|
|
||||||
// Recursively arranges the specified node's children into squarified rows.
|
// Recursively arranges the specified node's children into squarified rows.
|
||||||
function squarify(node) {
|
function squarify(node) {
|
||||||
if (!node.children) return;
|
var children = node.children;
|
||||||
|
if (children && children.length) {
|
||||||
var rect = pad(node),
|
var rect = pad(node),
|
||||||
row = [],
|
row = [],
|
||||||
children = node.children.slice(), // copy-on-write
|
remaining = children.slice(), // copy-on-write
|
||||||
child,
|
child,
|
||||||
best = Infinity, // the best row score so far
|
best = Infinity, // the best row score so far
|
||||||
score, // the current row score
|
score, // the current row score
|
||||||
u = Math.min(rect.dx, rect.dy), // initial orientation
|
u = Math.min(rect.dx, rect.dy), // initial orientation
|
||||||
n;
|
n;
|
||||||
scale(children, rect.dx * rect.dy / node.value);
|
scale(remaining, rect.dx * rect.dy / node.value);
|
||||||
row.area = 0;
|
row.area = 0;
|
||||||
while ((n = children.length) > 0) {
|
while ((n = remaining.length) > 0) {
|
||||||
row.push(child = children[n - 1]);
|
row.push(child = remaining[n - 1]);
|
||||||
row.area += child.area;
|
row.area += child.area;
|
||||||
if ((score = worst(row, u)) <= best) { // continue with this orientation
|
if ((score = worst(row, u)) <= best) { // continue with this orientation
|
||||||
children.pop();
|
remaining.pop();
|
||||||
best = score;
|
best = score;
|
||||||
} else { // abort, and try a different orientation
|
} else { // abort, and try a different orientation
|
||||||
row.area -= row.pop().area;
|
row.area -= row.pop().area;
|
||||||
|
@ -1701,28 +1726,31 @@ d3.layout.treemap = function() {
|
||||||
position(row, u, rect, true);
|
position(row, u, rect, true);
|
||||||
row.length = row.area = 0;
|
row.length = row.area = 0;
|
||||||
}
|
}
|
||||||
node.children.forEach(squarify);
|
children.forEach(squarify);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively resizes the specified node's children into existing rows.
|
// Recursively resizes the specified node's children into existing rows.
|
||||||
// Preserves the existing layout!
|
// Preserves the existing layout!
|
||||||
function stickify(node) {
|
function stickify(node) {
|
||||||
if (!node.children) return;
|
var children = node.children;
|
||||||
|
if (children && children.length) {
|
||||||
var rect = pad(node),
|
var rect = pad(node),
|
||||||
children = node.children.slice(), // copy-on-write
|
remaining = children.slice(), // copy-on-write
|
||||||
child,
|
child,
|
||||||
row = [];
|
row = [];
|
||||||
scale(children, rect.dx * rect.dy / node.value);
|
scale(remaining, rect.dx * rect.dy / node.value);
|
||||||
row.area = 0;
|
row.area = 0;
|
||||||
while (child = children.pop()) {
|
while (child = remaining.pop()) {
|
||||||
row.push(child);
|
row.push(child);
|
||||||
row.area += child.area;
|
row.area += child.area;
|
||||||
if (child.z != null) {
|
if (child.z != null) {
|
||||||
position(row, child.z ? rect.dx : rect.dy, rect, !children.length);
|
position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
|
||||||
row.length = row.area = 0;
|
row.length = row.area = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.children.forEach(stickify);
|
children.forEach(stickify);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Computes the score for the specified row, as the worst aspect ratio.
|
// Computes the score for the specified row, as the worst aspect ratio.
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
46
d3.time.js
46
d3.time.js
|
@ -78,6 +78,7 @@ var d3_time_formats = {
|
||||||
H: function(d) { return d3_time_zfill2(d.getHours()); },
|
H: function(d) { return d3_time_zfill2(d.getHours()); },
|
||||||
I: function(d) { return d3_time_zfill2(d.getHours() % 12 || 12); },
|
I: function(d) { return d3_time_zfill2(d.getHours() % 12 || 12); },
|
||||||
j: d3_time_dayOfYear,
|
j: d3_time_dayOfYear,
|
||||||
|
L: function(d) { return d3_time_zfill3(d.getMilliseconds()); },
|
||||||
m: function(d) { return d3_time_zfill2(d.getMonth() + 1); },
|
m: function(d) { return d3_time_zfill2(d.getMonth() + 1); },
|
||||||
M: function(d) { return d3_time_zfill2(d.getMinutes()); },
|
M: function(d) { return d3_time_zfill2(d.getMinutes()); },
|
||||||
p: function(d) { return d.getHours() >= 12 ? "PM" : "AM"; },
|
p: function(d) { return d.getHours() >= 12 ? "PM" : "AM"; },
|
||||||
|
@ -104,6 +105,7 @@ var d3_time_parsers = {
|
||||||
H: d3_time_parseHour24,
|
H: d3_time_parseHour24,
|
||||||
I: d3_time_parseHour12,
|
I: d3_time_parseHour12,
|
||||||
// j: function(d, s, i) { /*TODO day of year [001,366] */ return i; },
|
// j: function(d, s, i) { /*TODO day of year [001,366] */ return i; },
|
||||||
|
L: d3_time_parseMilliseconds,
|
||||||
m: d3_time_parseMonthNumber,
|
m: d3_time_parseMonthNumber,
|
||||||
M: d3_time_parseMinutes,
|
M: d3_time_parseMinutes,
|
||||||
p: d3_time_parseAmPm,
|
p: d3_time_parseAmPm,
|
||||||
|
@ -277,6 +279,12 @@ function d3_time_parseSeconds(date, string, i) {
|
||||||
return n ? (date.setSeconds(+n[0]), i += n[0].length) : -1;
|
return n ? (date.setSeconds(+n[0]), i += n[0].length) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function d3_time_parseMilliseconds(date, string, i) {
|
||||||
|
d3_time_numberRe.lastIndex = 0;
|
||||||
|
var n = d3_time_numberRe.exec(string.substring(i, i + 3));
|
||||||
|
return n ? (date.setMilliseconds(+n[0]), i += n[0].length) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Note: we don't look at the next directive.
|
// Note: we don't look at the next directive.
|
||||||
var d3_time_numberRe = /\s*\d+/;
|
var d3_time_numberRe = /\s*\d+/;
|
||||||
|
|
||||||
|
@ -294,18 +302,22 @@ function d3_time_year(d) {
|
||||||
return new d3_time(d.getFullYear(), 0, 1);
|
return new d3_time(d.getFullYear(), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function d3_time_daysElapsed(d0, d1) {
|
||||||
|
return ~~((d1 - d0) / 864e5 - (d1.getTimezoneOffset() - d0.getTimezoneOffset()) / 1440);
|
||||||
|
}
|
||||||
|
|
||||||
function d3_time_dayOfYear(d) {
|
function d3_time_dayOfYear(d) {
|
||||||
return d3_time_zfill3(1 + ~~((d - d3_time_year(d)) / 864e5));
|
return d3_time_zfill3(1 + d3_time_daysElapsed(d3_time_year(d), d));
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_time_weekNumberSunday(d) {
|
function d3_time_weekNumberSunday(d) {
|
||||||
var d0 = d3_time_year(d);
|
var d0 = d3_time_year(d);
|
||||||
return d3_time_zfill2(~~(((d - d0) / 864e5 + d0.getDay()) / 7));
|
return d3_time_zfill2(~~((d3_time_daysElapsed(d0, d) + d0.getDay()) / 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_time_weekNumberMonday(d) {
|
function d3_time_weekNumberMonday(d) {
|
||||||
var d0 = d3_time_year(d);
|
var d0 = d3_time_year(d);
|
||||||
return d3_time_zfill2(~~(((d - d0) / 864e5 + (d0.getDay() + 6) % 7) / 7));
|
return d3_time_zfill2(~~((d3_time_daysElapsed(d0, d) + (d0.getDay() + 6) % 7) / 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO table of time zone offset names?
|
// TODO table of time zone offset names?
|
||||||
|
@ -320,9 +332,14 @@ d3.time.format.utc = function(template) {
|
||||||
var local = d3.time.format(template);
|
var local = d3.time.format(template);
|
||||||
|
|
||||||
function format(date) {
|
function format(date) {
|
||||||
var utc = new d3_time_format_utc();
|
try {
|
||||||
|
d3_time = d3_time_format_utc;
|
||||||
|
var utc = new d3_time();
|
||||||
utc._ = date;
|
utc._ = date;
|
||||||
return local(utc);
|
return local(utc);
|
||||||
|
} finally {
|
||||||
|
d3_time = Date;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format.parse = function(string) {
|
format.parse = function(string) {
|
||||||
|
@ -364,7 +381,19 @@ d3_time_format_utc.prototype = {
|
||||||
setMonth: function(x) { this._.setUTCMonth(x); },
|
setMonth: function(x) { this._.setUTCMonth(x); },
|
||||||
setSeconds: function(x) { this._.setUTCSeconds(x); }
|
setSeconds: function(x) { this._.setUTCSeconds(x); }
|
||||||
};
|
};
|
||||||
d3.time.format.iso = d3.time.format.utc("%Y-%m-%dT%H:%M:%SZ");
|
var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");
|
||||||
|
|
||||||
|
d3.time.format.iso = Date.prototype.toISOString ? d3_time_formatIsoNative : d3_time_formatIso;
|
||||||
|
|
||||||
|
function d3_time_formatIsoNative(date) {
|
||||||
|
return date.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
d3_time_formatIsoNative.parse = function(string) {
|
||||||
|
return new Date(string);
|
||||||
|
};
|
||||||
|
|
||||||
|
d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
|
||||||
function d3_time_range(floor, step, number) {
|
function d3_time_range(floor, step, number) {
|
||||||
return function(t0, t1, dt) {
|
return function(t0, t1, dt) {
|
||||||
var time = floor(t0), times = [];
|
var time = floor(t0), times = [];
|
||||||
|
@ -541,12 +570,7 @@ function d3_time_scale(linear, methods, format) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// TOOD expose d3_scale_linear_rebind?
|
// TOOD expose d3_scale_linear_rebind?
|
||||||
scale.range = d3.rebind(scale, linear.range);
|
return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
|
||||||
scale.rangeRound = d3.rebind(scale, linear.rangeRound);
|
|
||||||
scale.interpolate = d3.rebind(scale, linear.interpolate);
|
|
||||||
scale.clamp = d3.rebind(scale, linear.clamp);
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO expose d3_scaleExtent?
|
// TODO expose d3_scaleExtent?
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -51,7 +51,7 @@ var svg = d3.select("body").append("svg:svg")
|
||||||
|
|
||||||
svg.append("svg:rect")
|
svg.append("svg:rect")
|
||||||
.attr("width", w)
|
.attr("width", w)
|
||||||
.attr("height", h)
|
.attr("height", h);
|
||||||
|
|
||||||
svg.append("svg:g")
|
svg.append("svg:g")
|
||||||
.attr("class", "x grid")
|
.attr("class", "x grid")
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<title>Polar Stereographic Projection</title>
|
<title>Azimuthal Projection</title>
|
||||||
<script type="text/javascript" src="../../d3.js"></script>
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
<script type="text/javascript" src="../../d3.geo.js"></script>
|
<script type="text/javascript" src="../../d3.geo.js"></script>
|
||||||
<script type="text/javascript" src="../../lib/jquery/jquery.min.js"></script>
|
<script type="text/javascript" src="../../lib/jquery/jquery.min.js"></script>
|
||||||
|
@ -12,6 +12,13 @@
|
||||||
<body>
|
<body>
|
||||||
<h3>Azimuthal Projection</h3>
|
<h3>Azimuthal Projection</h3>
|
||||||
<script type="text/javascript" src="azimuthal.js"></script><p>
|
<script type="text/javascript" src="azimuthal.js"></script><p>
|
||||||
|
<select id="mode">
|
||||||
|
<option value="stereographic">stereographic</option>
|
||||||
|
<option value="orthographic">orthographic</option>
|
||||||
|
<option value="equidistant">equidistant</option>
|
||||||
|
<option value="gnomonic">gnomonic</option>
|
||||||
|
<option value="equalarea">equalarea</option>
|
||||||
|
</select>
|
||||||
<div id="lon">origin.longitude: <span>0</span></div>
|
<div id="lon">origin.longitude: <span>0</span></div>
|
||||||
<div id="lat">origin.latitude: <span>0</span></div><p>
|
<div id="lat">origin.latitude: <span>0</span></div><p>
|
||||||
<div id="scale">scale: <span>240</span></div><p>
|
<div id="scale">scale: <span>240</span></div><p>
|
||||||
|
@ -28,6 +35,7 @@ $("#lon").slider({
|
||||||
var origin = xy.origin();
|
var origin = xy.origin();
|
||||||
origin[0] = ui.value;
|
origin[0] = ui.value;
|
||||||
xy.origin(origin);
|
xy.origin(origin);
|
||||||
|
circle.origin(origin);
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -41,6 +49,7 @@ $("#lat").slider({
|
||||||
var origin = xy.origin();
|
var origin = xy.origin();
|
||||||
origin[1] = ui.value;
|
origin[1] = ui.value;
|
||||||
xy.origin(origin);
|
xy.origin(origin);
|
||||||
|
circle.origin(origin);
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -79,6 +88,12 @@ $("#translate-y").slider({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#mode").change(function() {
|
||||||
|
var mode = $(this).val();
|
||||||
|
xy.mode(mode);
|
||||||
|
refresh(500);
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var xy = d3.geo.azimuthal().scale(240).mode("stereographic"),
|
var xy = d3.geo.azimuthal().scale(240).mode("stereographic"),
|
||||||
|
circle = d3.geo.greatCircle(),
|
||||||
path = d3.geo.path().projection(xy),
|
path = d3.geo.path().projection(xy),
|
||||||
svg = d3.select("body").append("svg:svg");
|
svg = d3.select("body").append("svg:svg");
|
||||||
|
|
||||||
|
@ -6,14 +7,15 @@ d3.json("../data/world-countries.json", function(collection) {
|
||||||
svg.selectAll("path")
|
svg.selectAll("path")
|
||||||
.data(collection.features)
|
.data(collection.features)
|
||||||
.enter().append("svg:path")
|
.enter().append("svg:path")
|
||||||
.attr("d", path)
|
.attr("d", function(d) { return path(circle.clip(d)); })
|
||||||
.append("svg:title")
|
.append("svg:title")
|
||||||
.text(function(d) { return d.properties.name; });
|
.text(function(d) { return d.properties.name; });
|
||||||
});
|
});
|
||||||
|
|
||||||
function refresh() {
|
function refresh(duration) {
|
||||||
svg.selectAll("path")
|
var p = svg.selectAll("path");
|
||||||
.attr("d", path);
|
if (duration) p = p.transition().duration(duration);
|
||||||
|
p.attr("d", function(d) { return path(circle.clip(d)); });
|
||||||
d3.select("#lon span")
|
d3.select("#lon span")
|
||||||
.text(xy.origin()[0]);
|
.text(xy.origin()[0]);
|
||||||
d3.select("#lat span")
|
d3.select("#lat span")
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hierarchical Bar Chart</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.layout.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
text {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.background {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis {
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis path, .axis line {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var m = [20, 20, 20, 120], // top right bottom left
|
||||||
|
w = 960 - m[1] - m[3], // width
|
||||||
|
h = 500 - m[0] - m[2], // height
|
||||||
|
x = d3.scale.linear().range([0, w]),
|
||||||
|
y = 20, // bar height
|
||||||
|
z = d3.scale.ordinal().range(["steelblue", "#ccc"]), // bar color
|
||||||
|
duration = 750,
|
||||||
|
delay = 25;
|
||||||
|
|
||||||
|
var hierarchy = d3.layout.partition()
|
||||||
|
.value(function(d) { return d.size; });
|
||||||
|
|
||||||
|
var xAxis = d3.svg.axis()
|
||||||
|
.scale(x)
|
||||||
|
.orient("top");
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w + m[1] + m[3])
|
||||||
|
.attr("height", h + m[0] + m[2])
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
|
svg.append("svg:rect")
|
||||||
|
.attr("class", "background")
|
||||||
|
.attr("width", w)
|
||||||
|
.attr("height", h)
|
||||||
|
.on("click", up);
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "x axis");
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "y axis")
|
||||||
|
.append("svg:line")
|
||||||
|
.attr("y1", "100%");
|
||||||
|
|
||||||
|
d3.json("../data/flare.json", function(root) {
|
||||||
|
hierarchy.nodes(root);
|
||||||
|
x.domain([0, root.value]).nice();
|
||||||
|
down(root, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
function down(d, i) {
|
||||||
|
if (!d.children || this.__transition__) return;
|
||||||
|
var end = duration + d.children.length * delay;
|
||||||
|
|
||||||
|
// Mark any currently-displayed bars as exiting.
|
||||||
|
var exit = svg.selectAll(".enter").attr("class", "exit");
|
||||||
|
|
||||||
|
// Entering nodes immediately obscure the clicked-on bar, so hide it.
|
||||||
|
exit.selectAll("rect").filter(function(p) { return p === d; })
|
||||||
|
.style("fill-opacity", 1e-6);
|
||||||
|
|
||||||
|
// Enter the new bars for the clicked-on data.
|
||||||
|
// Per above, entering bars are immediately visible.
|
||||||
|
var enter = bar(d)
|
||||||
|
.attr("transform", stack(i))
|
||||||
|
.style("opacity", 1);
|
||||||
|
|
||||||
|
// Have the text fade-in, even though the bars are visible.
|
||||||
|
// Color the bars as parents; they will fade to children if appropriate.
|
||||||
|
enter.select("text").style("fill-opacity", 1e-6);
|
||||||
|
enter.select("rect").style("fill", z(true));
|
||||||
|
|
||||||
|
// Update the x-scale domain.
|
||||||
|
x.domain([0, d3.max(d.children, function(d) { return d.value; })]).nice();
|
||||||
|
|
||||||
|
// Update the x-axis.
|
||||||
|
svg.selectAll(".x.axis").transition().duration(duration).call(xAxis);
|
||||||
|
|
||||||
|
// Transition entering bars to their new position.
|
||||||
|
var enterTransition = enter.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.delay(function(d, i) { return i * delay; })
|
||||||
|
.attr("transform", function(d, i) { return "translate(0," + y * i * 1.2 + ")"; });
|
||||||
|
|
||||||
|
// Transition entering text.
|
||||||
|
enterTransition.select("text").style("fill-opacity", 1);
|
||||||
|
|
||||||
|
// Transition entering rects to the new x-scale.
|
||||||
|
enterTransition.select("rect")
|
||||||
|
.attr("width", function(d) { return x(d.value); })
|
||||||
|
.style("fill", function(d) { return z(!!d.children); });
|
||||||
|
|
||||||
|
// Transition exiting bars to fade out.
|
||||||
|
var exitTransition = exit.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.style("opacity", 1e-6)
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
// Transition exiting bars to the new x-scale.
|
||||||
|
exitTransition.selectAll("rect").attr("width", function(d) { return x(d.value); });
|
||||||
|
|
||||||
|
// Rebind the current node to the background.
|
||||||
|
svg.select(".background").data([d]).transition().duration(end); d.index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
function up(d) {
|
||||||
|
if (!d.parent || this.__transition__) return;
|
||||||
|
var end = duration + d.children.length * delay;
|
||||||
|
|
||||||
|
// Mark any currently-displayed bars as exiting.
|
||||||
|
var exit = svg.selectAll(".enter").attr("class", "exit");
|
||||||
|
|
||||||
|
// Enter the new bars for the clicked-on data's parent.
|
||||||
|
var enter = bar(d.parent)
|
||||||
|
.attr("transform", function(d, i) { return "translate(0," + y * i * 1.2 + ")"; })
|
||||||
|
.style("opacity", 1e-6);
|
||||||
|
|
||||||
|
// Color the bars as appropriate.
|
||||||
|
// Exiting nodes will obscure the parent bar, so hide it.
|
||||||
|
enter.select("rect")
|
||||||
|
.style("fill", function(d) { return z(!!d.children); })
|
||||||
|
.filter(function(p) { return p === d; })
|
||||||
|
.style("fill-opacity", 1e-6);
|
||||||
|
|
||||||
|
// Update the x-scale domain.
|
||||||
|
x.domain([0, d3.max(d.parent.children, function(d) { return d.value; })]).nice();
|
||||||
|
|
||||||
|
// Update the x-axis.
|
||||||
|
svg.selectAll(".x.axis").transition().duration(duration).call(xAxis);
|
||||||
|
|
||||||
|
// Transition entering bars to fade in over the full duration.
|
||||||
|
var enterTransition = enter.transition()
|
||||||
|
.duration(end)
|
||||||
|
.style("opacity", 1);
|
||||||
|
|
||||||
|
// Transition entering rects to the new x-scale.
|
||||||
|
// When the entering parent rect is done, make it visible!
|
||||||
|
enterTransition.select("rect")
|
||||||
|
.attr("width", function(d) { return x(d.value); })
|
||||||
|
.each("end", function(p) { if (p === d) d3.select(this).style("fill-opacity", null); });
|
||||||
|
|
||||||
|
// Transition exiting bars to the parent's position.
|
||||||
|
var exitTransition = exit.selectAll("g").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.delay(function(d, i) { return i * delay; })
|
||||||
|
.attr("transform", stack(d.index));
|
||||||
|
|
||||||
|
// Transition exiting text to fade out.
|
||||||
|
exitTransition.select("text")
|
||||||
|
.style("fill-opacity", 1e-6);
|
||||||
|
|
||||||
|
// Transition exiting rects to the new scale and fade to parent color.
|
||||||
|
exitTransition.select("rect")
|
||||||
|
.attr("width", function(d) { return x(d.value); })
|
||||||
|
.style("fill", z(true));
|
||||||
|
|
||||||
|
// Remove exiting nodes when the last child has finished transitioning.
|
||||||
|
exit.transition().duration(end).remove();
|
||||||
|
|
||||||
|
// Rebind the current parent to the background.
|
||||||
|
svg.select(".background").data([d.parent]).transition().duration(end);;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a set of bars for the given data node, at the specified index.
|
||||||
|
function bar(d) {
|
||||||
|
var bar = svg.insert("svg:g", ".y.axis")
|
||||||
|
.attr("class", "enter")
|
||||||
|
.attr("transform", "translate(0,5)")
|
||||||
|
.selectAll("g")
|
||||||
|
.data(d.children)
|
||||||
|
.enter().append("svg:g")
|
||||||
|
.style("cursor", function(d) { return !d.children ? null : "pointer"; })
|
||||||
|
.on("click", down);
|
||||||
|
|
||||||
|
bar.append("svg:text")
|
||||||
|
.attr("x", -6)
|
||||||
|
.attr("y", y / 2)
|
||||||
|
.attr("dy", ".35em")
|
||||||
|
.attr("text-anchor", "end")
|
||||||
|
.text(function(d) { return d.name; });
|
||||||
|
|
||||||
|
bar.append("svg:rect")
|
||||||
|
.attr("width", function(d) { return x(d.value); })
|
||||||
|
.attr("height", y);
|
||||||
|
|
||||||
|
return bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A stateful closure for stacking bars horizontally.
|
||||||
|
function stack(i) {
|
||||||
|
var x0 = 0;
|
||||||
|
return function(d) {
|
||||||
|
var tx = "translate(" + x0 + "," + y * i * 1.2 + ")";
|
||||||
|
x0 += x(d.value);
|
||||||
|
return tx;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,159 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
|
<title>Bonne Projection</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.geo.js"></script>
|
||||||
|
<script type="text/javascript" src="../../lib/jquery/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../../lib/jquery-ui/jquery-ui.min.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
@import url("../../lib/jquery-ui/jquery-ui.css");
|
||||||
|
|
||||||
|
body, .ui-widget {
|
||||||
|
font: 14px Helvetica Neue;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 960px;
|
||||||
|
height: 500px;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
line {
|
||||||
|
stroke: brown;
|
||||||
|
stroke-dasharray: 4,2;
|
||||||
|
}
|
||||||
|
|
||||||
|
path {
|
||||||
|
fill: #ccc;
|
||||||
|
stroke: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
width: 960px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3>Bonne Projection</h3>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
// Our projection.
|
||||||
|
var xy = d3.geo.bonne(),
|
||||||
|
path = d3.geo.path().projection(xy);
|
||||||
|
|
||||||
|
var countries = d3.select("body").append("svg:svg")
|
||||||
|
.attr("id", "countries");
|
||||||
|
|
||||||
|
d3.json("../data/world-countries.json", function(collection) {
|
||||||
|
countries.selectAll("path")
|
||||||
|
.data(collection.features)
|
||||||
|
.enter().append("svg:path")
|
||||||
|
.attr("d", path)
|
||||||
|
.append("svg:title")
|
||||||
|
.text(function(d) { return d.properties.name; });
|
||||||
|
});
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
countries.selectAll("path")
|
||||||
|
.attr("d", path);
|
||||||
|
d3.select("#lon span")
|
||||||
|
.text(xy.origin()[0]);
|
||||||
|
d3.select("#lat span")
|
||||||
|
.text(xy.origin()[1]);
|
||||||
|
d3.select("#parallel span")
|
||||||
|
.text(xy.parallel());
|
||||||
|
d3.select("#scale span")
|
||||||
|
.text(xy.scale());
|
||||||
|
d3.select("#translate-x span")
|
||||||
|
.text(xy.translate()[0]);
|
||||||
|
d3.select("#translate-y span")
|
||||||
|
.text(xy.translate()[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script><p>
|
||||||
|
<div id="lon">origin.longitude: <span>0</span></div>
|
||||||
|
<div id="lat">origin.latitude: <span>0</span></div><p>
|
||||||
|
<div id="parallel">parallel: <span>45</span></div><p>
|
||||||
|
<div id="scale">scale: <span>200</span></div><p>
|
||||||
|
<div id="translate-x">translate.x: <span>480</span></div>
|
||||||
|
<div id="translate-y">translate.y: <span>250</span></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$("#lon").slider({
|
||||||
|
min: -180,
|
||||||
|
max: 180,
|
||||||
|
step: 1e-1,
|
||||||
|
value: 0,
|
||||||
|
slide: function(event, ui) {
|
||||||
|
var origin = xy.origin();
|
||||||
|
origin[0] = ui.value;
|
||||||
|
xy.origin(origin);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#lat").slider({
|
||||||
|
min: -90,
|
||||||
|
max: 90,
|
||||||
|
step: 1e-1,
|
||||||
|
value: 0,
|
||||||
|
slide: function(event, ui) {
|
||||||
|
var origin = xy.origin();
|
||||||
|
origin[1] = ui.value;
|
||||||
|
xy.origin(origin);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#parallel").slider({
|
||||||
|
min: 0,
|
||||||
|
max: 90,
|
||||||
|
value: 45,
|
||||||
|
slide: function(event, ui) {
|
||||||
|
xy.parallel(ui.value);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#scale").slider({
|
||||||
|
min: 0,
|
||||||
|
max: 800,
|
||||||
|
value: 200,
|
||||||
|
slide: function(event, ui) {
|
||||||
|
xy.scale(ui.value);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#translate-x").slider({
|
||||||
|
min: -2000,
|
||||||
|
max: 2000,
|
||||||
|
value: 480,
|
||||||
|
slide: function(event, ui) {
|
||||||
|
var translate = xy.translate();
|
||||||
|
translate[0] = ui.value;
|
||||||
|
xy.translate(translate);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#translate-y").slider({
|
||||||
|
min: -2000,
|
||||||
|
max: 2000,
|
||||||
|
value: 250,
|
||||||
|
slide: function(event, ui) {
|
||||||
|
var translate = xy.translate();
|
||||||
|
translate[1] = ui.value;
|
||||||
|
xy.translate(translate);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,92 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||||||
|
<title>Brush</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
svg {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle {
|
||||||
|
-webkit-transition: fill-opacity 250ms linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selecting circle {
|
||||||
|
fill-opacity: .2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selecting circle.selected {
|
||||||
|
stroke: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis path, .axis line {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brush .extent {
|
||||||
|
stroke: #fff;
|
||||||
|
fill-opacity: .125;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var data = d3.range(800).map(Math.random);
|
||||||
|
|
||||||
|
var m = [10, 10, 20, 10],
|
||||||
|
w = 960 - m[1] - m[3],
|
||||||
|
h = 100 - m[0] - m[2];
|
||||||
|
|
||||||
|
var x = d3.scale.linear().range([0, w]),
|
||||||
|
y = d3.random.normal(h / 2, h / 8);
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w + m[1] + m[3])
|
||||||
|
.attr("height", h + m[0] + m[2])
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "x axis")
|
||||||
|
.attr("transform", "translate(0," + h + ")")
|
||||||
|
.call(d3.svg.axis().scale(x).orient("bottom"));
|
||||||
|
|
||||||
|
var circle = svg.selectAll("circle")
|
||||||
|
.data(data)
|
||||||
|
.enter().append("svg:circle")
|
||||||
|
.attr("transform", function(d) { return "translate(" + x(d) + "," + y() + ")"; })
|
||||||
|
.attr("r", 3.5);
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "brush")
|
||||||
|
.call(d3.svg.brush().x(x)
|
||||||
|
.on("brushstart", brushstart)
|
||||||
|
.on("brush", brush)
|
||||||
|
.on("brushend", brushend))
|
||||||
|
.selectAll("rect")
|
||||||
|
.attr("height", h);
|
||||||
|
|
||||||
|
function brushstart() {
|
||||||
|
svg.classed("selecting", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function brush() {
|
||||||
|
var s = d3.event.target.extent();
|
||||||
|
circle.classed("selected", function(d) { return s[0] <= d && d <= s[1]; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function brushend() {
|
||||||
|
svg.classed("selecting", !d3.event.target.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,91 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||||||
|
<title>Brush</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
svg {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle {
|
||||||
|
-webkit-transition: fill-opacity 250ms linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selecting circle {
|
||||||
|
fill-opacity: .2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selecting circle.selected {
|
||||||
|
stroke: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis path, .axis line {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brush .extent {
|
||||||
|
stroke: #fff;
|
||||||
|
fill-opacity: .125;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var data = d3.range(800).map(Math.random);
|
||||||
|
|
||||||
|
var m = [10, 10, 10, 40],
|
||||||
|
w = 120 - m[1] - m[3],
|
||||||
|
h = 960 - m[0] - m[2];
|
||||||
|
|
||||||
|
var x = d3.random.normal(w / 2, w / 8),
|
||||||
|
y = d3.scale.linear().range([h, 0]);
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w + m[1] + m[3])
|
||||||
|
.attr("height", h + m[0] + m[2])
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "y axis")
|
||||||
|
.call(d3.svg.axis().scale(y).orient("left"));
|
||||||
|
|
||||||
|
var circle = svg.selectAll("circle")
|
||||||
|
.data(data)
|
||||||
|
.enter().append("svg:circle")
|
||||||
|
.attr("transform", function(d) { return "translate(" + x() + "," + y(d) + ")"; })
|
||||||
|
.attr("r", 3.5);
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "brush")
|
||||||
|
.call(d3.svg.brush().y(y)
|
||||||
|
.on("brushstart", brushstart)
|
||||||
|
.on("brush", brush)
|
||||||
|
.on("brushend", brushend))
|
||||||
|
.selectAll("rect")
|
||||||
|
.attr("width", w);
|
||||||
|
|
||||||
|
function brushstart() {
|
||||||
|
svg.classed("selecting", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function brush() {
|
||||||
|
var e = d3.event.target.extent();
|
||||||
|
circle.classed("selected", function(d) { return e[0] <= d && d <= e[1]; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function brushend() {
|
||||||
|
svg.classed("selecting", !d3.event.target.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,98 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||||||
|
<title>Brush</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
svg {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle {
|
||||||
|
-webkit-transition: fill-opacity 250ms linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selecting circle {
|
||||||
|
fill-opacity: .2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selecting circle.selected {
|
||||||
|
stroke: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis path, .axis line {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brush .extent {
|
||||||
|
stroke: #fff;
|
||||||
|
fill-opacity: .125;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var random = d3.random.normal(.5, .1),
|
||||||
|
data = d3.range(800).map(function() { return [random(), random()]; });
|
||||||
|
|
||||||
|
var m = [10, 10, 20, 40],
|
||||||
|
w = 960 - m[1] - m[3],
|
||||||
|
h = 500 - m[0] - m[2];
|
||||||
|
|
||||||
|
var x = d3.scale.linear().range([0, w]),
|
||||||
|
y = d3.scale.linear().range([h, 0]);
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w + m[1] + m[3])
|
||||||
|
.attr("height", h + m[0] + m[2])
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "x axis")
|
||||||
|
.attr("transform", "translate(0," + h + ")")
|
||||||
|
.call(d3.svg.axis().scale(x).orient("bottom"));
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "y axis")
|
||||||
|
.call(d3.svg.axis().scale(y).orient("left"));
|
||||||
|
|
||||||
|
var circle = svg.selectAll("circle")
|
||||||
|
.data(data)
|
||||||
|
.enter().append("svg:circle")
|
||||||
|
.attr("transform", function(d) { return "translate(" + x(d[0]) + "," + y(d[1]) + ")"; })
|
||||||
|
.attr("r", 3.5);
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "brush")
|
||||||
|
.call(d3.svg.brush().x(x).y(y)
|
||||||
|
.on("brushstart", brushstart)
|
||||||
|
.on("brush", brush)
|
||||||
|
.on("brushend", brushend));
|
||||||
|
|
||||||
|
function brushstart() {
|
||||||
|
svg.classed("selecting", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function brush() {
|
||||||
|
var e = d3.event.target.extent();
|
||||||
|
circle.classed("selected", function(d) {
|
||||||
|
return e[0][0] <= d[0] && d[0] <= e[1][0]
|
||||||
|
&& e[0][1] <= d[1] && d[1] <= e[1][1];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function brushend() {
|
||||||
|
svg.classed("selecting", !d3.event.target.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,16 +1,15 @@
|
||||||
#chart {
|
#chart {
|
||||||
font: 10px sans-serif;
|
font: 10px sans-serif;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
}
|
}
|
||||||
|
|
||||||
.day {
|
.day {
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
stroke: #ccc;
|
stroke: #ccc;
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.month {
|
.month {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: #000;
|
stroke: #000;
|
||||||
stroke-width: 2px;
|
stroke-width: 2px;
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
var calendar = {
|
|
||||||
|
|
||||||
format: d3.time.format("%Y-%m-%d"),
|
|
||||||
|
|
||||||
dates: function(year) {
|
|
||||||
var dates = [],
|
|
||||||
date = new Date(year, 0, 1),
|
|
||||||
week = 0,
|
|
||||||
day;
|
|
||||||
do {
|
|
||||||
dates.push({
|
|
||||||
day: day = date.getDay(),
|
|
||||||
week: week,
|
|
||||||
month: date.getMonth(),
|
|
||||||
Date: calendar.format(date)
|
|
||||||
});
|
|
||||||
date.setDate(date.getDate() + 1);
|
|
||||||
if (day === 6) week++;
|
|
||||||
} while (date.getFullYear() === year);
|
|
||||||
return dates;
|
|
||||||
},
|
|
||||||
|
|
||||||
months: function(year) {
|
|
||||||
var months = [],
|
|
||||||
date = new Date(year, 0, 1),
|
|
||||||
month,
|
|
||||||
firstDay,
|
|
||||||
firstWeek,
|
|
||||||
day,
|
|
||||||
week = 0;
|
|
||||||
do {
|
|
||||||
firstDay = date.getDay();
|
|
||||||
firstWeek = week;
|
|
||||||
month = date.getMonth();
|
|
||||||
do {
|
|
||||||
day = date.getDay();
|
|
||||||
if (day === 6) week++;
|
|
||||||
date.setDate(date.getDate() + 1);
|
|
||||||
} while (date.getMonth() === month);
|
|
||||||
months.push({
|
|
||||||
firstDay: firstDay,
|
|
||||||
firstWeek: firstWeek,
|
|
||||||
lastDay: day,
|
|
||||||
lastWeek: day === 6 ? week - 1 : week
|
|
||||||
});
|
|
||||||
} while (date.getFullYear() === year);
|
|
||||||
return months;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>DJI</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.csv.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.time.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
body {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect {
|
||||||
|
fill: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.area {
|
||||||
|
fill: #000;
|
||||||
|
fill-opacity: .75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis, .grid {
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid line {
|
||||||
|
stroke: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid line.minor {
|
||||||
|
stroke-opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis line {
|
||||||
|
stroke: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid path, .axis path {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var m = [10, 50, 20, 10],
|
||||||
|
w = 960 - m[1] - m[3],
|
||||||
|
h = 500 - m[0] - m[2],
|
||||||
|
parse = d3.time.format("%Y-%m-%d").parse;
|
||||||
|
|
||||||
|
// Scales. Note the inverted domain for the y-scale: bigger is up!
|
||||||
|
var x = d3.time.scale().range([20, w - 20]),
|
||||||
|
y = d3.scale.linear().range([h - 20, 20]);
|
||||||
|
|
||||||
|
// Axes.
|
||||||
|
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
|
||||||
|
yAxis = d3.svg.axis().scale(y).orient("right");
|
||||||
|
|
||||||
|
// An area generator.
|
||||||
|
var area = d3.svg.area()
|
||||||
|
.x(function(d) { return x(d.Date); })
|
||||||
|
.y0(y(0))
|
||||||
|
.y1(function(d) { return y(d.Close); });
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w + m[1] + m[3])
|
||||||
|
.attr("height", h + m[0] + m[2])
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
|
svg.append("svg:rect")
|
||||||
|
.attr("width", w)
|
||||||
|
.attr("height", h);
|
||||||
|
|
||||||
|
d3.csv("dji.csv", function(data) {
|
||||||
|
|
||||||
|
// Parse dates and numbers.
|
||||||
|
data.reverse().forEach(function(d) {
|
||||||
|
d.Date = parse(d.Date);
|
||||||
|
d.Close = +d.Close;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compute the minimum and maximum date, and the maximum price.
|
||||||
|
x.domain([data[0].Date, data[data.length - 1].Date]);
|
||||||
|
y.domain([0, d3.max(data, function(d) { return d.Close; })]);
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "x grid")
|
||||||
|
.attr("transform", "translate(0," + h + ")")
|
||||||
|
.call(xAxis.tickSubdivide(1).tickSize(-h));
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "y grid")
|
||||||
|
.attr("transform", "translate(" + w + ",0)")
|
||||||
|
.call(yAxis.tickSubdivide(1).tickSize(-w));
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "x axis")
|
||||||
|
.attr("transform", "translate(0," + h + ")")
|
||||||
|
.call(xAxis.tickSubdivide(0).tickSize(6));
|
||||||
|
|
||||||
|
svg.append("svg:g")
|
||||||
|
.attr("class", "y axis")
|
||||||
|
.attr("transform", "translate(" + w + ",0)")
|
||||||
|
.call(yAxis.tickSubdivide(0).tickSize(6));
|
||||||
|
|
||||||
|
svg.append("svg:path")
|
||||||
|
.attr("class", "area")
|
||||||
|
.attr("d", area(data));
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -5,7 +5,6 @@
|
||||||
<script type="text/javascript" src="../../d3.js"></script>
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
<script type="text/javascript" src="../../d3.csv.js"></script>
|
<script type="text/javascript" src="../../d3.csv.js"></script>
|
||||||
<script type="text/javascript" src="../../d3.time.js"></script>
|
<script type="text/javascript" src="../../d3.time.js"></script>
|
||||||
<script type="text/javascript" src="calendar.js"></script>
|
|
||||||
<link type="text/css" rel="stylesheet" href="../../lib/colorbrewer/colorbrewer.css"/>
|
<link type="text/css" rel="stylesheet" href="../../lib/colorbrewer/colorbrewer.css"/>
|
||||||
<link type="text/css" rel="stylesheet" href="calendar.css"/>
|
<link type="text/css" rel="stylesheet" href="calendar.css"/>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -1,48 +1,45 @@
|
||||||
var w = 960,
|
var m = [19, 20, 20, 19], // top right bottom left margin
|
||||||
pw = 14,
|
w = 960 - m[1] - m[3], // width
|
||||||
z = ~~((w - pw * 2) / 53),
|
h = 136 - m[0] - m[2], // height
|
||||||
ph = z >> 1,
|
z = 17; // cell size
|
||||||
h = z * 7;
|
|
||||||
|
|
||||||
var vis = d3.select("#chart")
|
var day = d3.time.format("%w"),
|
||||||
.selectAll("svg")
|
week = d3.time.format("%U"),
|
||||||
|
percent = d3.format(".1%"),
|
||||||
|
format = d3.time.format("%Y-%m-%d");
|
||||||
|
|
||||||
|
var color = d3.scale.quantize()
|
||||||
|
.domain([-.05, .05])
|
||||||
|
.range(d3.range(9));
|
||||||
|
|
||||||
|
var svg = d3.select("#chart").selectAll("svg")
|
||||||
.data(d3.range(1990, 2011))
|
.data(d3.range(1990, 2011))
|
||||||
.enter().append("svg:svg")
|
.enter().append("svg:svg")
|
||||||
.attr("width", w)
|
.attr("width", w + m[1] + m[3])
|
||||||
.attr("height", h + ph * 2)
|
.attr("height", h + m[0] + m[2])
|
||||||
.attr("class", "RdYlGn")
|
.attr("class", "RdYlGn")
|
||||||
.append("svg:g")
|
.append("svg:g")
|
||||||
.attr("transform", "translate(" + pw + "," + ph + ")");
|
.attr("transform", "translate(" + (m[3] + (w - z * 53) / 2) + "," + (m[0] + (h - z * 7) / 2) + ")");
|
||||||
|
|
||||||
vis.append("svg:text")
|
svg.append("svg:text")
|
||||||
.attr("transform", "translate(-6," + h / 2 + ")rotate(-90)")
|
.attr("transform", "translate(-6," + z * 3.5 + ")rotate(-90)")
|
||||||
.attr("text-anchor", "middle")
|
.attr("text-anchor", "middle")
|
||||||
.text(function(d) { return d; });
|
.text(String);
|
||||||
|
|
||||||
vis.selectAll("rect.day")
|
var rect = svg.selectAll("rect.day")
|
||||||
.data(calendar.dates)
|
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
|
||||||
.enter().append("svg:rect")
|
.enter().append("svg:rect")
|
||||||
.attr("x", function(d) { return d.week * z; })
|
|
||||||
.attr("y", function(d) { return d.day * z; })
|
|
||||||
.attr("class", "day")
|
.attr("class", "day")
|
||||||
.attr("width", z)
|
.attr("width", z)
|
||||||
.attr("height", z);
|
.attr("height", z)
|
||||||
|
.attr("x", function(d) { return week(d) * z; })
|
||||||
|
.attr("y", function(d) { return day(d) * z; });
|
||||||
|
|
||||||
vis.selectAll("path.month")
|
svg.selectAll("path.month")
|
||||||
.data(calendar.months)
|
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
|
||||||
.enter().append("svg:path")
|
.enter().append("svg:path")
|
||||||
.attr("class", "month")
|
.attr("class", "month")
|
||||||
.attr("d", function(d) {
|
.attr("d", monthPath);
|
||||||
return "M" + (d.firstWeek + 1) * z + "," + d.firstDay * z
|
|
||||||
+ "H" + d.firstWeek * z
|
|
||||||
+ "V" + 7 * z
|
|
||||||
+ "H" + d.lastWeek * z
|
|
||||||
+ "V" + (d.lastDay + 1) * z
|
|
||||||
+ "H" + (d.lastWeek + 1) * z
|
|
||||||
+ "V" + 0
|
|
||||||
+ "H" + (d.firstWeek + 1) * z
|
|
||||||
+ "Z";
|
|
||||||
});
|
|
||||||
|
|
||||||
d3.csv("dji.csv", function(csv) {
|
d3.csv("dji.csv", function(csv) {
|
||||||
var data = d3.nest()
|
var data = d3.nest()
|
||||||
|
@ -50,12 +47,19 @@ d3.csv("dji.csv", function(csv) {
|
||||||
.rollup(function(d) { return (d[0].Close - d[0].Open) / d[0].Open; })
|
.rollup(function(d) { return (d[0].Close - d[0].Open) / d[0].Open; })
|
||||||
.map(csv);
|
.map(csv);
|
||||||
|
|
||||||
var color = d3.scale.quantize()
|
rect
|
||||||
.domain([-.05, .05])
|
.attr("class", function(d) { return "day q" + color(data[format(d)]) + "-9"; })
|
||||||
.range(d3.range(9));
|
|
||||||
|
|
||||||
vis.selectAll("rect.day")
|
|
||||||
.attr("class", function(d) { return "day q" + color(data[d.Date]) + "-9"; })
|
|
||||||
.append("svg:title")
|
.append("svg:title")
|
||||||
.text(function(d) { return d.Date + ": " + (data[d.Date] * 100).toFixed(1) + "%"; });
|
.text(function(d) { return (d = format(d)) + (d in data ? ": " + percent(data[d]) : ""); });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function monthPath(t0) {
|
||||||
|
var t1 = new Date(t0.getUTCFullYear(), t0.getUTCMonth() + 1, 0),
|
||||||
|
d0 = +day(t0), w0 = +week(t0),
|
||||||
|
d1 = +day(t1), w1 = +week(t1);
|
||||||
|
return "M" + (w0 + 1) * z + "," + d0 * z
|
||||||
|
+ "H" + w0 * z + "V" + 7 * z
|
||||||
|
+ "H" + w1 * z + "V" + (d1 + 1) * z
|
||||||
|
+ "H" + (w1 + 1) * z + "V" + 0
|
||||||
|
+ "H" + (w0 + 1) * z + "Z";
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<script type="text/javascript" src="../../d3.js"></script>
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
<script type="text/javascript" src="../../d3.csv.js"></script>
|
<script type="text/javascript" src="../../d3.csv.js"></script>
|
||||||
<script type="text/javascript" src="../../d3.time.js"></script>
|
<script type="text/javascript" src="../../d3.time.js"></script>
|
||||||
<script type="text/javascript" src="calendar.js"></script>
|
|
||||||
<link type="text/css" rel="stylesheet" href="../../lib/colorbrewer/colorbrewer.css"/>
|
<link type="text/css" rel="stylesheet" href="../../lib/colorbrewer/colorbrewer.css"/>
|
||||||
<link type="text/css" rel="stylesheet" href="calendar.css"/>
|
<link type="text/css" rel="stylesheet" href="calendar.css"/>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -1,47 +1,43 @@
|
||||||
var w = 960,
|
var m = [19, 20, 20, 19], // top right bottom left margin
|
||||||
pw = 14,
|
w = 960 - m[1] - m[3], // width
|
||||||
z = ~~((w - pw * 2) / 53),
|
h = 136 - m[0] - m[2], // height
|
||||||
ph = z >> 1,
|
z = 17; // cell size
|
||||||
h = z * 7;
|
|
||||||
|
|
||||||
var vis = d3.select("#chart")
|
var day = d3.time.format("%w"),
|
||||||
.selectAll("svg")
|
week = d3.time.format("%U"),
|
||||||
|
format = d3.time.format("%Y-%m-%d");
|
||||||
|
|
||||||
|
var color = d3.scale.quantile()
|
||||||
|
.range(d3.range(9).reverse());
|
||||||
|
|
||||||
|
var svg = d3.select("#chart").selectAll("svg")
|
||||||
.data(d3.range(1993, 2011))
|
.data(d3.range(1993, 2011))
|
||||||
.enter().append("svg:svg")
|
.enter().append("svg:svg")
|
||||||
.attr("width", w)
|
.attr("width", w + m[1] + m[3])
|
||||||
.attr("height", h + ph * 2)
|
.attr("height", h + m[0] + m[2])
|
||||||
.attr("class", "RdYlGn")
|
.attr("class", "RdYlGn")
|
||||||
.append("svg:g")
|
.append("svg:g")
|
||||||
.attr("transform", "translate(" + pw + "," + ph + ")");
|
.attr("transform", "translate(" + (m[3] + (w - z * 53) / 2) + "," + (m[0] + (h - z * 7) / 2) + ")");
|
||||||
|
|
||||||
vis.append("svg:text")
|
svg.append("svg:text")
|
||||||
.attr("transform", "translate(-6," + h / 2 + ")rotate(-90)")
|
.attr("transform", "translate(-6," + z * 3.5 + ")rotate(-90)")
|
||||||
.text(function(d) { return d; });
|
.attr("text-anchor", "middle")
|
||||||
|
.text(String);
|
||||||
|
|
||||||
vis.selectAll("rect.day")
|
var rect = svg.selectAll("rect.day")
|
||||||
.data(calendar.dates)
|
.data(function(d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
|
||||||
.enter().append("svg:rect")
|
.enter().append("svg:rect")
|
||||||
.attr("x", function(d) { return d.week * z; })
|
|
||||||
.attr("y", function(d) { return d.day * z; })
|
|
||||||
.attr("class", "day")
|
.attr("class", "day")
|
||||||
.attr("width", z)
|
.attr("width", z)
|
||||||
.attr("height", z);
|
.attr("height", z)
|
||||||
|
.attr("x", function(d) { return week(d) * z; })
|
||||||
|
.attr("y", function(d) { return day(d) * z; });
|
||||||
|
|
||||||
vis.selectAll("path.month")
|
svg.selectAll("path.month")
|
||||||
.data(calendar.months)
|
.data(function(d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
|
||||||
.enter().append("svg:path")
|
.enter().append("svg:path")
|
||||||
.attr("class", "month")
|
.attr("class", "month")
|
||||||
.attr("d", function(d) {
|
.attr("d", monthPath);
|
||||||
return "M" + (d.firstWeek + 1) * z + "," + d.firstDay * z
|
|
||||||
+ "H" + d.firstWeek * z
|
|
||||||
+ "V" + 7 * z
|
|
||||||
+ "H" + d.lastWeek * z
|
|
||||||
+ "V" + (d.lastDay + 1) * z
|
|
||||||
+ "H" + (d.lastWeek + 1) * z
|
|
||||||
+ "V" + 0
|
|
||||||
+ "H" + (d.firstWeek + 1) * z
|
|
||||||
+ "Z";
|
|
||||||
});
|
|
||||||
|
|
||||||
d3.csv("vix.csv", function(csv) {
|
d3.csv("vix.csv", function(csv) {
|
||||||
var data = d3.nest()
|
var data = d3.nest()
|
||||||
|
@ -49,12 +45,21 @@ d3.csv("vix.csv", function(csv) {
|
||||||
.rollup(function(d) { return d[0].Open; })
|
.rollup(function(d) { return d[0].Open; })
|
||||||
.map(csv);
|
.map(csv);
|
||||||
|
|
||||||
var color = d3.scale.quantile()
|
color.domain(d3.values(data));
|
||||||
.domain(d3.values(data))
|
|
||||||
.range(d3.range(9).reverse());
|
|
||||||
|
|
||||||
vis.selectAll("rect.day")
|
rect
|
||||||
.attr("class", function(d) { return "day q" + color(data[d.Date]) + "-9"; })
|
.attr("class", function(d) { return "day q" + color(data[format(d)]) + "-9"; })
|
||||||
.append("svg:title")
|
.append("svg:title")
|
||||||
.text(function(d) { return d.Date + ": " + data[d.Date]; });
|
.text(function(d) { return (d = format(d)) + (d in data ? ": " + data[d] : ""); });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function monthPath(t0) {
|
||||||
|
var t1 = new Date(t0.getUTCFullYear(), t0.getUTCMonth() + 1, 0),
|
||||||
|
d0 = +day(t0), w0 = +week(t0),
|
||||||
|
d1 = +day(t1), w1 = +week(t1);
|
||||||
|
return "M" + (w0 + 1) * z + "," + d0 * z
|
||||||
|
+ "H" + w0 * z + "V" + 7 * z
|
||||||
|
+ "H" + w1 * z + "V" + (d1 + 1) * z
|
||||||
|
+ "H" + (w1 + 1) * z + "V" + 0
|
||||||
|
+ "H" + (w0 + 1) * z + "Z";
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ d3.json("../data/us-states.json", function(json) {
|
||||||
.selectAll("path")
|
.selectAll("path")
|
||||||
.data(json.features)
|
.data(json.features)
|
||||||
.enter().append("svg:path")
|
.enter().append("svg:path")
|
||||||
|
.attr("d", path)
|
||||||
.attr("transform", function(d) {
|
.attr("transform", function(d) {
|
||||||
var centroid = path.centroid(d),
|
var centroid = path.centroid(d),
|
||||||
x = centroid[0],
|
x = centroid[0],
|
||||||
|
@ -44,8 +45,7 @@ d3.json("../data/us-states.json", function(json) {
|
||||||
+ "translate(" + -x + "," + -y + ")";
|
+ "translate(" + -x + "," + -y + ")";
|
||||||
})
|
})
|
||||||
.style("stroke-width", function(d) {
|
.style("stroke-width", function(d) {
|
||||||
return 1 / Math.sqrt(data[+d.id] * 5);
|
return 1 / Math.sqrt(data[+d.id] * 5 || 1);
|
||||||
})
|
});
|
||||||
.attr("d", path);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Crimean War</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.layout.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.time.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.csv.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 960px;
|
||||||
|
height: 500px;
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule {
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.line {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var p = [20, 50, 30, 20],
|
||||||
|
w = 960 - p[1] - p[3],
|
||||||
|
h = 500 - p[0] - p[2],
|
||||||
|
x = d3.time.scale().range([0, w]),
|
||||||
|
y = d3.scale.linear().range([h, 0]),
|
||||||
|
z = d3.scale.ordinal().range(["lightpink", "darkgray", "lightblue"]),
|
||||||
|
parse = d3.time.format("%m/%Y").parse,
|
||||||
|
format = d3.time.format("%b");
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w)
|
||||||
|
.attr("height", h)
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + p[3] + "," + p[0] + ")");
|
||||||
|
|
||||||
|
d3.csv("crimea.csv", function(crimea) {
|
||||||
|
|
||||||
|
// Transpose the data into layers by cause.
|
||||||
|
var causes = d3.layout.stack()(["wounds", "other", "disease"].map(function(cause) {
|
||||||
|
return crimea.map(function(d) {
|
||||||
|
return {x: parse(d.date), y: +d[cause]};
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Compute the x-domain (by date) and y-domain (by top).
|
||||||
|
x.domain([causes[0][0].x, causes[0][causes[0].length - 1].x]);
|
||||||
|
y.domain([0, d3.max(causes[causes.length - 1], function(d) { return d.y0 + d.y; })]);
|
||||||
|
|
||||||
|
// Add an area for each cause.
|
||||||
|
svg.selectAll("path.area")
|
||||||
|
.data(causes)
|
||||||
|
.enter().append("svg:path")
|
||||||
|
.attr("class", "area")
|
||||||
|
.style("fill", function(d, i) { return z(i); })
|
||||||
|
.attr("d", d3.svg.area()
|
||||||
|
.x(function(d) { return x(d.x); })
|
||||||
|
.y0(function(d) { return y(d.y0); })
|
||||||
|
.y1(function(d) { return y(d.y0 + d.y); }));
|
||||||
|
|
||||||
|
// Add a line for each cause.
|
||||||
|
svg.selectAll("path.line")
|
||||||
|
.data(causes)
|
||||||
|
.enter().append("svg:path")
|
||||||
|
.attr("class", "line")
|
||||||
|
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); })
|
||||||
|
.attr("d", d3.svg.line()
|
||||||
|
.x(function(d) { return x(d.x); })
|
||||||
|
.y(function(d) { return y(d.y0 + d.y); }));
|
||||||
|
|
||||||
|
// Add a label per date.
|
||||||
|
svg.selectAll("text")
|
||||||
|
.data(x.ticks(12))
|
||||||
|
.enter().append("svg:text")
|
||||||
|
.attr("x", x)
|
||||||
|
.attr("y", h + 6)
|
||||||
|
.attr("text-anchor", "middle")
|
||||||
|
.attr("dy", ".71em")
|
||||||
|
.text(x.tickFormat(12));
|
||||||
|
|
||||||
|
// Add y-axis rules.
|
||||||
|
var rule = svg.selectAll("g.rule")
|
||||||
|
.data(y.ticks(5))
|
||||||
|
.enter().append("svg:g")
|
||||||
|
.attr("class", "rule")
|
||||||
|
.attr("transform", function(d) { return "translate(0," + y(d) + ")"; });
|
||||||
|
|
||||||
|
rule.append("svg:line")
|
||||||
|
.attr("x2", w)
|
||||||
|
.style("stroke", function(d) { return d ? "#fff" : "#000"; })
|
||||||
|
.style("stroke-opacity", function(d) { return d ? .7 : null; });
|
||||||
|
|
||||||
|
rule.append("svg:text")
|
||||||
|
.attr("x", w + 6)
|
||||||
|
.attr("dy", ".35em")
|
||||||
|
.text(d3.format(",d"));
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,83 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Custom Elements</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
// Register the "custom" namespace prefix for our custom elements.
|
||||||
|
d3.ns.prefix.custom = "http://github.com/mbostock/d3/examples/dom";
|
||||||
|
|
||||||
|
var w = 960,
|
||||||
|
h = 500;
|
||||||
|
|
||||||
|
// Add our "custom" sketch element to the body.
|
||||||
|
var sketch = d3.select("body").append("custom:sketch")
|
||||||
|
.attr("width", w)
|
||||||
|
.attr("height", h)
|
||||||
|
.call(custom);
|
||||||
|
|
||||||
|
// On each mouse move, create a circle that increases in size and fades away.
|
||||||
|
d3.select(window).on("mousemove", function() {
|
||||||
|
sketch.append("custom:circle")
|
||||||
|
.attr("x", d3.event.clientX)
|
||||||
|
.attr("y", d3.event.clientY)
|
||||||
|
.attr("radius", 0)
|
||||||
|
.attr("strokeStyle", "red")
|
||||||
|
.transition()
|
||||||
|
.duration(2000)
|
||||||
|
.ease(Math.sqrt)
|
||||||
|
.attr("radius", 200)
|
||||||
|
.attr("strokeStyle", "white")
|
||||||
|
.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
function custom(selection) {
|
||||||
|
selection.each(function() {
|
||||||
|
var root = this,
|
||||||
|
canvas = root.parentNode.appendChild(document.createElement("canvas")),
|
||||||
|
context = canvas.getContext("2d");
|
||||||
|
|
||||||
|
canvas.style.position = "absolute";
|
||||||
|
canvas.style.top = root.offsetTop + "px";
|
||||||
|
canvas.style.left = root.offsetLeft + "px";
|
||||||
|
|
||||||
|
// It'd be nice to use DOM Mutation Events here instead.
|
||||||
|
// However, they appear to arrive irregularly, causing choppy animation.
|
||||||
|
d3.timer(redraw);
|
||||||
|
|
||||||
|
// Clear the canvas and then iterate over child elements.
|
||||||
|
function redraw() {
|
||||||
|
canvas.width = root.getAttribute("width");
|
||||||
|
canvas.height = root.getAttribute("height");
|
||||||
|
for (var child = root.firstChild; child; child = child.nextSibling) draw(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now we only support circles with strokeStyle.
|
||||||
|
// But you should imagine extending this to arbitrary shapes and groups!
|
||||||
|
function draw(element) {
|
||||||
|
switch (element.tagName) {
|
||||||
|
case "circle": {
|
||||||
|
context.strokeStyle = element.getAttribute("strokeStyle");
|
||||||
|
context.beginPath();
|
||||||
|
context.arc(element.getAttribute("x"), element.getAttribute("y"), element.getAttribute("radius"), 0, 2 * Math.PI);
|
||||||
|
context.stroke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,5 +0,0 @@
|
||||||
These are derived from the cartographic boundary files from the 2000 U.S. Census:
|
|
||||||
|
|
||||||
http://www.census.gov/geo/www/cob/bdy_files.html
|
|
||||||
|
|
||||||
Then, MapShaper was used to simplify the geometry, and ogr2ogr to convert the shapefiles to GeoJSON. Some additional work was done to preserve the FIPS codes, which are dropped from the shapefiles by MapShaper.
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
## World Boundaries
|
||||||
|
|
||||||
|
These are derived from the public domain [Natural Earth](http://www.naturalearthdata.com/downloads/) cultural vector files, 110m resolution. Then, ogr2ogr was used to convert to GeoJSON. Lastly, the data was cleaned up slightly, removing extra properties and a degenerate edge from Antarctica.
|
||||||
|
|
||||||
|
collection.features.forEach(function(d, i) {
|
||||||
|
d.id = d.properties.ISO_A3;
|
||||||
|
d.properties = {name: d.properties.SOVEREIGNT};
|
||||||
|
});
|
||||||
|
|
||||||
|
## United States Boundaries
|
||||||
|
|
||||||
|
These are derived from the cartographic boundary files from the 2000 [U.S. Census](http://www.census.gov/geo/www/cob/bdy_files.html
|
||||||
|
). Then, MapShaper was used to simplify the geometry, and ogr2ogr to convert the shapefiles to GeoJSON. Some additional work was done to preserve the FIPS codes, which are dropped from the shapefiles by MapShaper.
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -26,7 +26,7 @@ var w = 400,
|
||||||
data,
|
data,
|
||||||
color = d3.scale.category20(),
|
color = d3.scale.category20(),
|
||||||
arc = d3.svg.arc(),
|
arc = d3.svg.arc(),
|
||||||
donut = d3.layout.pie();
|
donut = d3.layout.pie().sort(null);
|
||||||
|
|
||||||
var vis = d3.select("body")
|
var vis = d3.select("body")
|
||||||
.append("svg:svg")
|
.append("svg:svg")
|
||||||
|
|
|
@ -213,7 +213,6 @@ function init() {
|
||||||
.attr("x2", function(d) { return d.target.x; })
|
.attr("x2", function(d) { return d.target.x; })
|
||||||
.attr("y2", function(d) { return d.target.y; })
|
.attr("y2", function(d) { return d.target.y; })
|
||||||
.style("stroke-width", function(d) { return d.size || 1; });
|
.style("stroke-width", function(d) { return d.size || 1; });
|
||||||
link = linkg.selectAll("line.link");
|
|
||||||
|
|
||||||
node = nodeg.selectAll("circle.node").data(net.nodes, nodeid);
|
node = nodeg.selectAll("circle.node").data(net.nodes, nodeid);
|
||||||
node.exit().remove();
|
node.exit().remove();
|
||||||
|
@ -227,8 +226,7 @@ function init() {
|
||||||
if (d.size) { expand[d.group] = true; init(); }
|
if (d.size) { expand[d.group] = true; init(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
node = nodeg.selectAll("circle.node")
|
node.call(force.drag);
|
||||||
.call(force.drag);
|
|
||||||
|
|
||||||
force.on("tick", function() {
|
force.on("tick", function() {
|
||||||
if (!hull.empty()) {
|
if (!hull.empty()) {
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
circle.node {
|
circle.node {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
stroke: #3182bd;
|
stroke: #000;
|
||||||
stroke-width: 1.5px;
|
stroke-width: .5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
line.link {
|
line.link {
|
||||||
|
@ -28,9 +28,14 @@ line.link {
|
||||||
|
|
||||||
var w = 960,
|
var w = 960,
|
||||||
h = 500,
|
h = 500,
|
||||||
|
node,
|
||||||
|
link,
|
||||||
root;
|
root;
|
||||||
|
|
||||||
var force = d3.layout.force()
|
var force = d3.layout.force()
|
||||||
|
.on("tick", tick)
|
||||||
|
.charge(function(d) { return d._children ? -d.size / 100 : -30; })
|
||||||
|
.linkDistance(function(d) { return d.target._children ? 80 : 30; })
|
||||||
.size([w, h]);
|
.size([w, h]);
|
||||||
|
|
||||||
var vis = d3.select("#chart").append("svg:svg")
|
var vis = d3.select("#chart").append("svg:svg")
|
||||||
|
@ -39,6 +44,9 @@ var vis = d3.select("#chart").append("svg:svg")
|
||||||
|
|
||||||
d3.json("../data/flare.json", function(json) {
|
d3.json("../data/flare.json", function(json) {
|
||||||
root = json;
|
root = json;
|
||||||
|
root.fixed = true;
|
||||||
|
root.x = w / 2;
|
||||||
|
root.y = h / 2;
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -53,7 +61,7 @@ function update() {
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
// Update the links…
|
// Update the links…
|
||||||
var link = vis.selectAll("line.link")
|
link = vis.selectAll("line.link")
|
||||||
.data(links, function(d) { return d.target.id; });
|
.data(links, function(d) { return d.target.id; });
|
||||||
|
|
||||||
// Enter any new links.
|
// Enter any new links.
|
||||||
|
@ -68,28 +76,28 @@ function update() {
|
||||||
link.exit().remove();
|
link.exit().remove();
|
||||||
|
|
||||||
// Update the nodes…
|
// Update the nodes…
|
||||||
var node = vis.selectAll("circle.node")
|
node = vis.selectAll("circle.node")
|
||||||
.data(nodes, function(d) { return d.id; })
|
.data(nodes, function(d) { return d.id; })
|
||||||
.style("fill", color);
|
.style("fill", color);
|
||||||
|
|
||||||
|
node.transition()
|
||||||
|
.attr("r", function(d) { return d.children ? 4.5 : Math.sqrt(d.size) / 10; });
|
||||||
|
|
||||||
// Enter any new nodes.
|
// Enter any new nodes.
|
||||||
node.enter().append("svg:circle")
|
node.enter().append("svg:circle")
|
||||||
.attr("class", "node")
|
.attr("class", "node")
|
||||||
.attr("cx", function(d) { return d.x; })
|
.attr("cx", function(d) { return d.x; })
|
||||||
.attr("cy", function(d) { return d.y; })
|
.attr("cy", function(d) { return d.y; })
|
||||||
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
|
.attr("r", function(d) { return d.children ? 4.5 : Math.sqrt(d.size) / 10; })
|
||||||
.style("fill", color)
|
.style("fill", color)
|
||||||
.on("click", click)
|
.on("click", click)
|
||||||
.call(force.drag);
|
.call(force.drag);
|
||||||
|
|
||||||
// Exit any old nodes.
|
// Exit any old nodes.
|
||||||
node.exit().remove();
|
node.exit().remove();
|
||||||
|
}
|
||||||
|
|
||||||
// Re-select for update.
|
function tick() {
|
||||||
link = vis.selectAll("line.link");
|
|
||||||
node = vis.selectAll("circle.node");
|
|
||||||
|
|
||||||
force.on("tick", function() {
|
|
||||||
link.attr("x1", function(d) { return d.source.x; })
|
link.attr("x1", function(d) { return d.source.x; })
|
||||||
.attr("y1", function(d) { return d.source.y; })
|
.attr("y1", function(d) { return d.source.y; })
|
||||||
.attr("x2", function(d) { return d.target.x; })
|
.attr("x2", function(d) { return d.target.x; })
|
||||||
|
@ -97,7 +105,6 @@ function update() {
|
||||||
|
|
||||||
node.attr("cx", function(d) { return d.x; })
|
node.attr("cx", function(d) { return d.x; })
|
||||||
.attr("cy", function(d) { return d.y; });
|
.attr("cy", function(d) { return d.y; });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color leaf nodes orange, and packages white or blue.
|
// Color leaf nodes orange, and packages white or blue.
|
||||||
|
@ -122,12 +129,13 @@ function flatten(root) {
|
||||||
var nodes = [], i = 0;
|
var nodes = [], i = 0;
|
||||||
|
|
||||||
function recurse(node) {
|
function recurse(node) {
|
||||||
if (node.children) node.children.forEach(recurse);
|
if (node.children) node.size = node.children.reduce(function(p, v) { return p + recurse(v); }, 0);
|
||||||
if (!node.id) node.id = ++i;
|
if (!node.id) node.id = ++i;
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
|
return node.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
recurse(root);
|
root.size = recurse(root);
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,14 @@ var w = 960,
|
||||||
h = 500,
|
h = 500,
|
||||||
fill = d3.scale.category20();
|
fill = d3.scale.category20();
|
||||||
|
|
||||||
var vis = d3.select("#chart")
|
var vis = d3.select("#chart").append("svg:svg")
|
||||||
.append("svg:svg")
|
|
||||||
.attr("width", w)
|
.attr("width", w)
|
||||||
.attr("height", h);
|
.attr("height", h);
|
||||||
|
|
||||||
d3.json("miserables.json", function(json) {
|
d3.json("miserables.json", function(json) {
|
||||||
var force = d3.layout.force()
|
var force = d3.layout.force()
|
||||||
.charge(-60)
|
.charge(-120)
|
||||||
|
.linkDistance(30)
|
||||||
.nodes(json.nodes)
|
.nodes(json.nodes)
|
||||||
.links(json.links)
|
.links(json.links)
|
||||||
.size([w, h])
|
.size([w, h])
|
||||||
|
@ -38,11 +38,6 @@ d3.json("miserables.json", function(json) {
|
||||||
node.append("svg:title")
|
node.append("svg:title")
|
||||||
.text(function(d) { return d.name; });
|
.text(function(d) { return d.name; });
|
||||||
|
|
||||||
vis.style("opacity", 1e-6)
|
|
||||||
.transition()
|
|
||||||
.duration(1000)
|
|
||||||
.style("opacity", 1);
|
|
||||||
|
|
||||||
force.on("tick", function() {
|
force.on("tick", function() {
|
||||||
link.attr("x1", function(d) { return d.source.x; })
|
link.attr("x1", function(d) { return d.source.x; })
|
||||||
.attr("y1", function(d) { return d.source.y; })
|
.attr("y1", function(d) { return d.source.y; })
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Great Arc</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.geo.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
#states path {
|
||||||
|
fill: #ddd;
|
||||||
|
stroke: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#arcs path {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
stroke-width: .5px;
|
||||||
|
stroke-opacity: .2;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var w = 960,
|
||||||
|
h = 500;
|
||||||
|
|
||||||
|
var projection = d3.geo.azimuthal()
|
||||||
|
.origin([-115, 50])
|
||||||
|
.scale(500);
|
||||||
|
|
||||||
|
var path = d3.geo.path()
|
||||||
|
.projection(projection);
|
||||||
|
|
||||||
|
var arc = d3.geo.greatArc();
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w)
|
||||||
|
.attr("height", h);
|
||||||
|
|
||||||
|
var states = svg.append("svg:g")
|
||||||
|
.attr("id", "states");
|
||||||
|
|
||||||
|
var arcs = svg.append("svg:g")
|
||||||
|
.attr("id", "arcs");
|
||||||
|
|
||||||
|
d3.json("../data/us-states.json", function(collection) {
|
||||||
|
states.selectAll("path")
|
||||||
|
.data(collection.features)
|
||||||
|
.enter().append("svg:path")
|
||||||
|
.attr("d", path);
|
||||||
|
});
|
||||||
|
|
||||||
|
d3.json("../data/us-state-centroids.json", function(collection) {
|
||||||
|
var links = [];
|
||||||
|
|
||||||
|
// Create a link between each state centroid.
|
||||||
|
collection.features.forEach(function(a) {
|
||||||
|
collection.features.forEach(function(b) {
|
||||||
|
if (a !== b) {
|
||||||
|
links.push({
|
||||||
|
source: a.geometry.coordinates,
|
||||||
|
target: b.geometry.coordinates
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
arcs.selectAll("path")
|
||||||
|
.data(links)
|
||||||
|
.enter().append("svg:path")
|
||||||
|
.attr("d", function(d) { return path(arc(d)); });
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,70 @@
|
||||||
|
require("../../test/env");
|
||||||
|
require("../../d3");
|
||||||
|
require("../../d3.geo");
|
||||||
|
|
||||||
|
var fs = require("fs"),
|
||||||
|
util = require("util"),
|
||||||
|
Canvas = require("canvas");
|
||||||
|
|
||||||
|
var w = 1920,
|
||||||
|
h = 1080;
|
||||||
|
|
||||||
|
var projection = d3.geo.albersUsa()
|
||||||
|
.scale(2000)
|
||||||
|
.translate([w / 2, h / 2]);
|
||||||
|
|
||||||
|
var path = d3.geo.path()
|
||||||
|
.projection(projection);
|
||||||
|
|
||||||
|
var canvas = new Canvas(w, h),
|
||||||
|
context = canvas.getContext("2d");
|
||||||
|
|
||||||
|
context.antialias = "none";
|
||||||
|
context.lineWidth = 8;
|
||||||
|
context.lineJoin = "round";
|
||||||
|
|
||||||
|
d3.json(__dirname + "/../data/us-counties.json", function(collection) {
|
||||||
|
renderAll("stroke");
|
||||||
|
renderAll("fill");
|
||||||
|
fs.writeFile("us-counties.png", canvas.toBuffer());
|
||||||
|
|
||||||
|
function renderAll(action) {
|
||||||
|
collection.features.forEach(function(feature) {
|
||||||
|
var re = /[MLZ]/g,
|
||||||
|
d = path(feature),
|
||||||
|
i = 0,
|
||||||
|
m;
|
||||||
|
|
||||||
|
context[action + "Style"] = "#" + pad((+feature.id).toString(16));
|
||||||
|
context.beginPath();
|
||||||
|
re.lastIndex = 1;
|
||||||
|
while (m = re.exec(d)) render(m.index);
|
||||||
|
render();
|
||||||
|
context[action]();
|
||||||
|
|
||||||
|
function render(j) {
|
||||||
|
switch (d.charAt(i)) {
|
||||||
|
case "M": {
|
||||||
|
var p = d.substring(i + 1, j).split(",").map(Number);
|
||||||
|
context.moveTo(p[0], p[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "L": {
|
||||||
|
var p = d.substring(i + 1, j).split(",").map(Number);
|
||||||
|
context.lineTo(p[0], p[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "Z": {
|
||||||
|
context.closePath();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function pad(s) {
|
||||||
|
return s.length < 6 ? new Array(7 - s.length).join("0") + s : s;
|
||||||
|
}
|
|
@ -0,0 +1,407 @@
|
||||||
|
name,economy (mpg),cylinders,displacement (cc),power (hp),weight (lb),0-60 mph (s),year
|
||||||
|
AMC Ambassador Brougham,13,8,360,175,3821,11,73
|
||||||
|
AMC Ambassador DPL,15,8,390,190,3850,8.5,70
|
||||||
|
AMC Ambassador SST,17,8,304,150,3672,11.5,72
|
||||||
|
AMC Concord DL 6,20.2,6,232,90,3265,18.2,79
|
||||||
|
AMC Concord DL,18.1,6,258,120,3410,15.1,78
|
||||||
|
AMC Concord DL,23,4,151,,3035,20.5,82
|
||||||
|
AMC Concord,19.4,6,232,90,3210,17.2,78
|
||||||
|
AMC Concord,24.3,4,151,90,3003,20.1,80
|
||||||
|
AMC Gremlin,18,6,232,100,2789,15,73
|
||||||
|
AMC Gremlin,19,6,232,100,2634,13,71
|
||||||
|
AMC Gremlin,20,6,232,100,2914,16,75
|
||||||
|
AMC Gremlin,21,6,199,90,2648,15,70
|
||||||
|
AMC Hornet Sportabout (Wagon),18,6,258,110,2962,13.5,71
|
||||||
|
AMC Hornet,18,6,199,97,2774,15.5,70
|
||||||
|
AMC Hornet,18,6,232,100,2945,16,73
|
||||||
|
AMC Hornet,19,6,232,100,2901,16,74
|
||||||
|
AMC Hornet,22.5,6,232,90,3085,17.6,76
|
||||||
|
AMC Matador (Wagon),14,8,304,150,4257,15.5,74
|
||||||
|
AMC Matador (Wagon),15,8,304,150,3892,12.5,72
|
||||||
|
AMC Matador,14,8,304,150,3672,11.5,73
|
||||||
|
AMC Matador,15,6,258,110,3730,19,75
|
||||||
|
AMC Matador,15.5,8,304,120,3962,13.9,76
|
||||||
|
AMC Matador,16,6,258,110,3632,18,74
|
||||||
|
AMC Matador,18,6,232,100,3288,15.5,71
|
||||||
|
AMC Pacer D/L,17.5,6,258,95,3193,17.8,76
|
||||||
|
AMC Pacer,19,6,232,90,3211,17,75
|
||||||
|
AMC Rebel SST (Wagon),,8,360,175,3850,11,70
|
||||||
|
AMC Rebel SST,16,8,304,150,3433,12,70
|
||||||
|
AMC Spirit DL,27.4,4,121,80,2670,15,79
|
||||||
|
Audi 100 LS,20,4,114,91,2582,14,73
|
||||||
|
Audi 100 LS,23,4,115,95,2694,15,75
|
||||||
|
Audi 100 LS,24,4,107,90,2430,14.5,70
|
||||||
|
Audi 4000,34.3,4,97,78,2188,15.8,80
|
||||||
|
Audi 5000,20.3,5,131,103,2830,15.9,78
|
||||||
|
Audi 5000S (Diesel),36.4,5,121,67,2950,19.9,80
|
||||||
|
Audi Fox,29,4,98,83,2219,16.5,74
|
||||||
|
BMW 2002,26,4,121,113,2234,12.5,70
|
||||||
|
BMW 320i,21.5,4,121,110,2600,12.8,77
|
||||||
|
Buick Century 350,13,8,350,175,4100,13,73
|
||||||
|
Buick Century Limited,25,6,181,110,2945,16.4,82
|
||||||
|
Buick Century Luxus (Wagon),13,8,350,150,4699,14.5,74
|
||||||
|
Buick Century Special,20.6,6,231,105,3380,15.8,78
|
||||||
|
Buick Century,17,6,231,110,3907,21,75
|
||||||
|
Buick Century,22.4,6,231,110,3415,15.8,81
|
||||||
|
Buick Electra 225 Custom,12,8,455,225,4951,11,73
|
||||||
|
Buick Estate Wagon (Wagon),14,8,455,225,3086,10,70
|
||||||
|
Buick Estate Wagon (Wagon),16.9,8,350,155,4360,14.9,79
|
||||||
|
Buick Lesabre Custom,13,8,350,155,4502,13.5,72
|
||||||
|
Buick Opel Isuzu Deluxe,30,4,111,80,2155,14.8,77
|
||||||
|
Buick Regal Sport Coupe (Turbo),17.7,6,231,165,3445,13.4,78
|
||||||
|
Buick Skyhawk,21,6,231,110,3039,15,75
|
||||||
|
Buick Skylark 320,15,8,350,165,3693,11.5,70
|
||||||
|
Buick Skylark Limited,28.4,4,151,90,2670,16,79
|
||||||
|
Buick Skylark,20.5,6,231,105,3425,16.9,77
|
||||||
|
Buick Skylark,26.6,4,151,84,2635,16.4,81
|
||||||
|
Cadillac Eldorado,23,8,350,125,3900,17.4,79
|
||||||
|
Cadillac Seville,16.5,8,350,180,4380,12.1,76
|
||||||
|
Chevroelt Chevelle Malibu,16,6,250,105,3897,18.5,75
|
||||||
|
Chevrolet Bel Air,15,8,350,145,4440,14,75
|
||||||
|
Chevrolet Camaro,27,4,151,90,2950,17.3,82
|
||||||
|
Chevrolet Caprice Classic,13,8,400,150,4464,12,73
|
||||||
|
Chevrolet Caprice Classic,17,8,305,130,3840,15.4,79
|
||||||
|
Chevrolet Caprice Classic,17.5,8,305,145,3880,12.5,77
|
||||||
|
Chevrolet Cavalier 2-Door,34,4,112,88,2395,18,82
|
||||||
|
Chevrolet Cavalier Wagon,27,4,112,88,2640,18.6,82
|
||||||
|
Chevrolet Cavalier,28,4,112,88,2605,19.6,82
|
||||||
|
Chevrolet Chevelle Concours (Wagon),,8,350,165,4142,11.5,70
|
||||||
|
Chevrolet Chevelle Concours (Wagon),13,8,307,130,4098,14,72
|
||||||
|
Chevrolet Chevelle Malibu Classic,16,6,250,100,3781,17,74
|
||||||
|
Chevrolet Chevelle Malibu Classic,17.5,8,305,140,4215,13,76
|
||||||
|
Chevrolet Chevelle Malibu,17,6,250,100,3329,15.5,71
|
||||||
|
Chevrolet Chevelle Malibu,18,8,307,130,3504,12,70
|
||||||
|
Chevrolet Chevette,29,4,85,52,2035,22.2,76
|
||||||
|
Chevrolet Chevette,30,4,98,68,2155,16.5,78
|
||||||
|
Chevrolet Chevette,30.5,4,98,63,2051,17,77
|
||||||
|
Chevrolet Chevette,32.1,4,98,70,2120,15.5,80
|
||||||
|
Chevrolet Citation,23.5,6,173,110,2725,12.6,81
|
||||||
|
Chevrolet Citation,28,4,151,90,2678,16.5,80
|
||||||
|
Chevrolet Citation,28.8,6,173,115,2595,11.3,79
|
||||||
|
Chevrolet Concours,17.5,6,250,110,3520,16.4,77
|
||||||
|
Chevrolet Impala,11,8,400,150,4997,14,73
|
||||||
|
Chevrolet Impala,13,8,350,165,4274,12,72
|
||||||
|
Chevrolet Impala,14,8,350,165,4209,12,71
|
||||||
|
Chevrolet Impala,14,8,454,220,4354,9,70
|
||||||
|
Chevrolet Malibu Classic (Wagon),19.2,8,267,125,3605,15,79
|
||||||
|
Chevrolet Malibu,13,8,350,145,3988,13,73
|
||||||
|
Chevrolet Malibu,20.5,6,200,95,3155,18.2,78
|
||||||
|
Chevrolet Monte Carlo Landau,15.5,8,350,170,4165,11.4,77
|
||||||
|
Chevrolet Monte Carlo Landau,19.2,8,305,145,3425,13.2,78
|
||||||
|
Chevrolet Monte Carlo S,15,8,350,145,4082,13,73
|
||||||
|
Chevrolet Monte Carlo,15,8,400,150,3761,9.5,70
|
||||||
|
Chevrolet Monza 2+2,20,8,262,110,3221,13.5,75
|
||||||
|
Chevrolet Nova Custom,16,6,250,100,3278,18,73
|
||||||
|
Chevrolet Nova,15,6,250,100,3336,17,74
|
||||||
|
Chevrolet Nova,18,6,250,105,3459,16,75
|
||||||
|
Chevrolet Nova,22,6,250,105,3353,14.5,76
|
||||||
|
Chevrolet Vega (Wagon),22,4,140,72,2408,19,71
|
||||||
|
Chevrolet Vega 2300,28,4,140,90,2264,15.5,71
|
||||||
|
Chevrolet Vega,20,4,140,90,2408,19.5,72
|
||||||
|
Chevrolet Vega,21,4,140,72,2401,19.5,73
|
||||||
|
Chevrolet Vega,25,4,140,75,2542,17,74
|
||||||
|
Chevrolet Woody,24.5,4,98,60,2164,22.1,76
|
||||||
|
Chevy C10,13,8,350,145,4055,12,76
|
||||||
|
Chevy C20,10,8,307,200,4376,15,70
|
||||||
|
Chevy S-10,31,4,119,82,2720,19.4,82
|
||||||
|
Chrysler Cordoba,15.5,8,400,190,4325,12.2,77
|
||||||
|
Chrysler Lebaron Medallion,26,4,156,92,2585,14.5,82
|
||||||
|
Chrysler Lebaron Salon,17.6,6,225,85,3465,16.6,81
|
||||||
|
Chrysler Lebaron Town & Country (Wagon),18.5,8,360,150,3940,13,79
|
||||||
|
Chrysler New Yorker Brougham,13,8,440,215,4735,11,73
|
||||||
|
Chrysler Newport Royal,13,8,400,190,4422,12.5,72
|
||||||
|
Citroen DS-21 Pallas,,4,133,115,3090,17.5,70
|
||||||
|
Datsun 1200,35,4,72,69,1613,18,71
|
||||||
|
Datsun 200SX,23.9,4,119,97,2405,14.9,78
|
||||||
|
Datsun 200SX,32.9,4,119,100,2615,14.8,81
|
||||||
|
Datsun 210,31.8,4,85,65,2020,19.2,79
|
||||||
|
Datsun 210,37,4,85,65,1975,19.4,81
|
||||||
|
Datsun 210,40.8,4,85,65,2110,19.2,80
|
||||||
|
Datsun 280ZX,32.7,6,168,132,2910,11.4,80
|
||||||
|
Datsun 310 GX,38,4,91,67,1995,16.2,82
|
||||||
|
Datsun 310,37.2,4,86,65,2019,16.4,80
|
||||||
|
Datsun 510 (Wagon),28,4,97,92,2288,17,72
|
||||||
|
Datsun 510 Hatchback,37,4,119,92,2434,15,80
|
||||||
|
Datsun 510,27.2,4,119,97,2300,14.7,78
|
||||||
|
Datsun 610,22,4,108,94,2379,16.5,73
|
||||||
|
Datsun 710,24,4,119,97,2545,17,75
|
||||||
|
Datsun 710,32,4,83,61,2003,19,74
|
||||||
|
Datsun 810 Maxima,24.2,6,146,120,2930,13.8,81
|
||||||
|
Datsun 810,22,6,146,97,2815,14.5,77
|
||||||
|
Datsun B-210,32,4,85,70,1990,17,76
|
||||||
|
Datsun B210 GX,39.4,4,85,70,2070,18.6,78
|
||||||
|
Datsun B210,31,4,79,67,1950,19,74
|
||||||
|
Datsun F-10 Hatchback,33.5,4,85,70,1945,16.8,77
|
||||||
|
Datsun PL510,27,4,97,88,2130,14.5,70
|
||||||
|
Datsun PL510,27,4,97,88,2130,14.5,71
|
||||||
|
Dodge Aries SE,29,4,135,84,2525,16,82
|
||||||
|
Dodge Aries Wagon (Wagon),25.8,4,156,92,2620,14.4,81
|
||||||
|
Dodge Aspen 6,20.6,6,225,110,3360,16.6,79
|
||||||
|
Dodge Aspen SE,20,6,225,100,3651,17.7,76
|
||||||
|
Dodge Aspen,18.6,6,225,110,3620,18.7,78
|
||||||
|
Dodge Aspen,19.1,6,225,90,3381,18.7,80
|
||||||
|
Dodge Challenger SE,15,8,383,170,3563,10,70
|
||||||
|
Dodge Charger 2.2,36,4,135,84,2370,13,82
|
||||||
|
Dodge Colt (Wagon),28,4,98,80,2164,15,72
|
||||||
|
Dodge Colt Hardtop,25,4,97.5,80,2126,17,72
|
||||||
|
Dodge Colt Hatchback Custom,35.7,4,98,80,1915,14.4,79
|
||||||
|
Dodge Colt M/M,33.5,4,98,83,2075,15.9,77
|
||||||
|
Dodge Colt,26,4,98,79,2255,17.7,76
|
||||||
|
Dodge Colt,27.9,4,156,105,2800,14.4,80
|
||||||
|
Dodge Colt,28,4,90,75,2125,14.5,74
|
||||||
|
Dodge Coronet Brougham,16,8,318,150,4190,13,76
|
||||||
|
Dodge Coronet Custom (Wagon),14,8,318,150,4457,13.5,74
|
||||||
|
Dodge Coronet Custom,15,8,318,150,3777,12.5,73
|
||||||
|
Dodge D100,13,8,318,150,3755,14,76
|
||||||
|
Dodge D200,11,8,318,210,4382,13.5,70
|
||||||
|
Dodge Dart Custom,15,8,318,150,3399,11,73
|
||||||
|
Dodge Diplomat,19.4,8,318,140,3735,13.2,78
|
||||||
|
Dodge Magnum XE,17.5,8,318,140,4080,13.7,78
|
||||||
|
Dodge Monaco (Wagon),12,8,383,180,4955,11.5,71
|
||||||
|
Dodge Monaco Brougham,15.5,8,318,145,4140,13.7,77
|
||||||
|
Dodge Omni,30.9,4,105,75,2230,14.5,78
|
||||||
|
Dodge Rampage,32,4,135,84,2295,11.6,82
|
||||||
|
Dodge St. Regis,18.2,8,318,135,3830,15.2,79
|
||||||
|
Fiat 124 Sport Coupe,26,4,98,90,2265,15.5,73
|
||||||
|
Fiat 124 TC,26,4,116,75,2246,14,74
|
||||||
|
Fiat 124B,30,4,88,76,2065,14.5,71
|
||||||
|
Fiat 128,24,4,90,75,2108,15.5,74
|
||||||
|
Fiat 128,29,4,68,49,1867,19.5,73
|
||||||
|
Fiat 131,28,4,107,86,2464,15.5,76
|
||||||
|
Fiat Strada Custom,37.3,4,91,69,2130,14.7,79
|
||||||
|
Fiat X1.9,31,4,79,67,2000,16,74
|
||||||
|
Ford Capri II,25,4,140,92,2572,14.9,76
|
||||||
|
Ford Country Squire (Wagon),13,8,400,170,4746,12,71
|
||||||
|
Ford Country Squire (Wagon),15.5,8,351,142,4054,14.3,79
|
||||||
|
Ford Country,12,8,400,167,4906,12.5,73
|
||||||
|
Ford Escort 2H,29.9,4,98,65,2380,20.7,81
|
||||||
|
Ford Escort 4W,34.4,4,98,65,2045,16.2,81
|
||||||
|
Ford F108,13,8,302,130,3870,15,76
|
||||||
|
Ford F250,10,8,360,215,4615,14,70
|
||||||
|
Ford Fairmont (Auto),20.2,6,200,85,2965,15.8,78
|
||||||
|
Ford Fairmont (Man),25.1,4,140,88,2720,15.4,78
|
||||||
|
Ford Fairmont 4,22.3,4,140,88,2890,17.3,79
|
||||||
|
Ford Fairmont Futura,24,4,140,92,2865,16.4,82
|
||||||
|
Ford Fairmont,26.4,4,140,88,2870,18.1,80
|
||||||
|
Ford Fiesta,36.1,4,98,66,1800,14.4,78
|
||||||
|
Ford Futura,18.1,8,302,139,3205,11.2,78
|
||||||
|
Ford Galaxie 500,14,8,351,153,4129,13,72
|
||||||
|
Ford Galaxie 500,14,8,351,153,4154,13.5,71
|
||||||
|
Ford Galaxie 500,15,8,429,198,4341,10,70
|
||||||
|
Ford Gran Torino (Wagon),13,8,302,140,4294,16,72
|
||||||
|
Ford Gran Torino (Wagon),14,8,302,140,4638,16,74
|
||||||
|
Ford Gran Torino,14,8,302,137,4042,14.5,73
|
||||||
|
Ford Gran Torino,14.5,8,351,152,4215,12.8,76
|
||||||
|
Ford Gran Torino,16,8,302,140,4141,14,74
|
||||||
|
Ford Granada Ghia,18,6,250,78,3574,21,76
|
||||||
|
Ford Granada GL,20.2,6,200,88,3060,17.1,81
|
||||||
|
Ford Granada L,22,6,232,112,2835,14.7,82
|
||||||
|
Ford Granada,18.5,6,250,98,3525,19,77
|
||||||
|
Ford LTD Landau,17.6,8,302,129,3725,13.4,79
|
||||||
|
Ford LTD,13,8,351,158,4363,13,73
|
||||||
|
Ford LTD,14,8,351,148,4657,13.5,75
|
||||||
|
Ford Maverick,15,6,250,72,3158,19.5,75
|
||||||
|
Ford Maverick,18,6,250,88,3021,16.5,73
|
||||||
|
Ford Maverick,21,6,200,,2875,17,74
|
||||||
|
Ford Maverick,21,6,200,85,2587,16,70
|
||||||
|
Ford Maverick,24,6,200,81,3012,17.6,76
|
||||||
|
Ford Mustang Boss 302,,8,302,140,3353,8,70
|
||||||
|
Ford Mustang Cobra,23.6,4,140,,2905,14.3,80
|
||||||
|
Ford Mustang GL,27,4,140,86,2790,15.6,82
|
||||||
|
Ford Mustang II 2+2,25.5,4,140,89,2755,15.8,77
|
||||||
|
Ford Mustang II,13,8,302,129,3169,12,75
|
||||||
|
Ford Mustang,18,6,250,88,3139,14.5,71
|
||||||
|
Ford Pinto (Wagon),22,4,122,86,2395,16,72
|
||||||
|
Ford Pinto Runabout,21,4,122,86,2226,16.5,72
|
||||||
|
Ford Pinto,18,6,171,97,2984,14.5,75
|
||||||
|
Ford Pinto,19,4,122,85,2310,18.5,73
|
||||||
|
Ford Pinto,23,4,140,83,2639,17,75
|
||||||
|
Ford Pinto,25,4,98,,2046,19,71
|
||||||
|
Ford Pinto,26,4,122,80,2451,16.5,74
|
||||||
|
Ford Pinto,26.5,4,140,72,2565,13.6,76
|
||||||
|
Ford Ranger,28,4,120,79,2625,18.6,82
|
||||||
|
Ford Thunderbird,16,8,351,149,4335,14.5,77
|
||||||
|
Ford Torino (Wagon),,8,351,153,4034,11,70
|
||||||
|
Ford Torino 500,19,6,250,88,3302,15.5,71
|
||||||
|
Ford Torino,17,8,302,140,3449,10.5,70
|
||||||
|
Hi 1200D,9,8,304,193,4732,18.5,70
|
||||||
|
Honda Accord CVCC,31.5,4,98,68,2045,18.5,77
|
||||||
|
Honda Accord LX,29.5,4,98,68,2135,16.6,78
|
||||||
|
Honda Accord,32.4,4,107,72,2290,17,80
|
||||||
|
Honda Accord,36,4,107,75,2205,14.5,82
|
||||||
|
Honda Civic (Auto),32,4,91,67,1965,15.7,82
|
||||||
|
Honda Civic 1300,35.1,4,81,60,1760,16.1,81
|
||||||
|
Honda Civic 1500 GL,44.6,4,91,67,1850,13.8,80
|
||||||
|
Honda Civic CVCC,33,4,91,53,1795,17.5,75
|
||||||
|
Honda Civic CVCC,36.1,4,91,60,1800,16.4,78
|
||||||
|
Honda Civic,24,4,120,97,2489,15,74
|
||||||
|
Honda Civic,33,4,91,53,1795,17.4,76
|
||||||
|
Honda Civic,38,4,91,67,1965,15,82
|
||||||
|
Honda Prelude,33.7,4,107,75,2210,14.4,81
|
||||||
|
Maxda GLC Deluxe,34.1,4,86,65,1975,15.2,79
|
||||||
|
Maxda RX-3,18,3,70,90,2124,13.5,73
|
||||||
|
Mazda 626,31.3,4,120,75,2542,17.5,80
|
||||||
|
Mazda 626,31.6,4,120,74,2635,18.3,81
|
||||||
|
Mazda GLC 4,34.1,4,91,68,1985,16,81
|
||||||
|
Mazda GLC Custom L,37,4,91,68,2025,18.2,82
|
||||||
|
Mazda GLC Custom,31,4,91,68,1970,17.6,82
|
||||||
|
Mazda GLC Deluxe,32.8,4,78,52,1985,19.4,78
|
||||||
|
Mazda GLC,46.6,4,86,65,2110,17.9,80
|
||||||
|
Mazda RX-2 Coupe,19,3,70,97,2330,13.5,72
|
||||||
|
Mazda RX-4,21.5,3,80,110,2720,13.5,77
|
||||||
|
Mazda RX-7 Gs,23.7,3,70,100,2420,12.5,80
|
||||||
|
Mercedes-Benz 240D,30,4,146,67,3250,21.8,80
|
||||||
|
Mercedes-Benz 280S,16.5,6,168,120,3820,16.7,76
|
||||||
|
Mercedes-Benz 300D,25.4,5,183,77,3530,20.1,79
|
||||||
|
Mercury Capri 2000,23,4,122,86,2220,14,71
|
||||||
|
Mercury Capri V6,21,6,155,107,2472,14,73
|
||||||
|
Mercury Cougar Brougham,15,8,302,130,4295,14.9,77
|
||||||
|
Mercury Grand Marquis,16.5,8,351,138,3955,13.2,79
|
||||||
|
Mercury Lynx L,36,4,98,70,2125,17.3,82
|
||||||
|
Mercury Marquis Brougham,12,8,429,198,4952,11.5,73
|
||||||
|
Mercury Marquis,11,8,429,208,4633,11,72
|
||||||
|
Mercury Monarch Ghia,20.2,8,302,139,3570,12.8,78
|
||||||
|
Mercury Monarch,15,6,250,72,3432,21,75
|
||||||
|
Mercury Zephyr 6,19.8,6,200,85,2990,18.2,79
|
||||||
|
Mercury Zephyr,20.8,6,200,85,3070,16.7,78
|
||||||
|
Nissan Stanza XE,36,4,120,88,2160,14.5,82
|
||||||
|
Oldsmobile Cutlass Ciera (Diesel),38,6,262,85,3015,17,82
|
||||||
|
Oldsmobile Cutlass LS,26.6,8,350,105,3725,19,81
|
||||||
|
Oldsmobile Cutlass Salon Brougham,19.9,8,260,110,3365,15.5,78
|
||||||
|
Oldsmobile Cutlass Salon Brougham,23.9,8,260,90,3420,22.2,79
|
||||||
|
Oldsmobile Cutlass Supreme,17,8,260,110,4060,19,77
|
||||||
|
Oldsmobile Delta 88 Royale,12,8,350,160,4456,13.5,72
|
||||||
|
Oldsmobile Omega Brougham,26.8,6,173,115,2700,12.9,79
|
||||||
|
Oldsmobile Omega,11,8,350,180,3664,11,73
|
||||||
|
Oldsmobile Starfire SX,23.8,4,151,85,2855,17.6,78
|
||||||
|
Oldsmobile Vista Cruiser,12,8,350,180,4499,12.5,73
|
||||||
|
Opel 1900,25,4,116,81,2220,16.9,76
|
||||||
|
Opel 1900,28,4,116,90,2123,14,71
|
||||||
|
Opel Manta,24,4,116,75,2158,15.5,73
|
||||||
|
Opel Manta,26,4,97,78,2300,14.5,74
|
||||||
|
Peugeot 304,30,4,79,70,2074,19.5,71
|
||||||
|
Peugeot 504 (Wagon),21,4,120,87,2979,19.5,72
|
||||||
|
Peugeot 504,19,4,120,88,3270,21.9,76
|
||||||
|
Peugeot 504,23,4,120,88,2957,17,75
|
||||||
|
Peugeot 504,25,4,110,87,2672,17.5,70
|
||||||
|
Peugeot 504,27.2,4,141,71,3190,24.8,79
|
||||||
|
Peugeot 505S Turbo Diesel,28.1,4,141,80,3230,20.4,81
|
||||||
|
Peugeot 604SL,16.2,6,163,133,3410,15.8,78
|
||||||
|
Plymouth Arrow GS,25.5,4,122,96,2300,15.5,77
|
||||||
|
Plymouth Barracuda 340,14,8,340,160,3609,8,70
|
||||||
|
Plymouth Champ,39,4,86,64,1875,16.4,81
|
||||||
|
Plymouth Cricket,26,4,91,70,1955,20.5,71
|
||||||
|
Plymouth Custom Suburb,13,8,360,170,4654,13,73
|
||||||
|
Plymouth Duster,20,6,198,95,3102,16.5,74
|
||||||
|
Plymouth Duster,22,6,198,95,2833,15.5,70
|
||||||
|
Plymouth Duster,23,6,198,95,2904,16,73
|
||||||
|
Plymouth Fury Gran Sedan,14,8,318,150,4237,14.5,73
|
||||||
|
Plymouth Fury III,14,8,318,150,4096,13,71
|
||||||
|
Plymouth Fury III,14,8,440,215,4312,8.5,70
|
||||||
|
Plymouth Fury III,15,8,318,150,4135,13.5,72
|
||||||
|
Plymouth Fury,18,6,225,95,3785,19,75
|
||||||
|
Plymouth Grand Fury,16,8,318,150,4498,14.5,75
|
||||||
|
Plymouth Horizon 4,34.7,4,105,63,2215,14.9,81
|
||||||
|
Plymouth Horizon Miser,38,4,105,63,2125,14.7,82
|
||||||
|
Plymouth Horizon TC3,34.5,4,105,70,2150,14.9,79
|
||||||
|
Plymouth Horizon,34.2,4,105,70,2200,13.2,79
|
||||||
|
Plymouth Reliant,27.2,4,135,84,2490,15.7,81
|
||||||
|
Plymouth Reliant,30,4,135,84,2385,12.9,81
|
||||||
|
Plymouth Sapporo,23.2,4,156,105,2745,16.7,78
|
||||||
|
Plymouth Satellite (Wagon),,8,383,175,4166,10.5,70
|
||||||
|
Plymouth Satellite Custom (Wagon),14,8,318,150,4077,14,72
|
||||||
|
Plymouth Satellite Custom,16,6,225,105,3439,15.5,71
|
||||||
|
Plymouth Satellite Sebring,18,6,225,105,3613,16.5,74
|
||||||
|
Plymouth Satellite,18,8,318,150,3436,11,70
|
||||||
|
Plymouth Valiant Custom,19,6,225,95,3264,16,75
|
||||||
|
Plymouth Valiant,18,6,225,105,3121,16.5,73
|
||||||
|
Plymouth Valiant,22,6,225,100,3233,15.4,76
|
||||||
|
Plymouth Volare Custom,19,6,225,100,3630,17.7,77
|
||||||
|
Plymouth Volare Premier V8,13,8,318,150,3940,13.2,76
|
||||||
|
Plymouth Volare,20.5,6,225,100,3430,17.2,78
|
||||||
|
Pontiac Astro,23,4,140,78,2592,18.5,75
|
||||||
|
Pontiac Catalina Brougham,14,8,400,175,4464,11.5,71
|
||||||
|
Pontiac Catalina,14,8,400,175,4385,12,72
|
||||||
|
Pontiac Catalina,14,8,455,225,4425,10,70
|
||||||
|
Pontiac Catalina,16,8,400,170,4668,11.5,75
|
||||||
|
Pontiac Firebird,19,6,250,100,3282,15,71
|
||||||
|
Pontiac Grand Prix Lj,16,8,400,180,4220,11.1,77
|
||||||
|
Pontiac Grand Prix,16,8,400,230,4278,9.5,73
|
||||||
|
Pontiac J2000 Se Hatchback,31,4,112,85,2575,16.2,82
|
||||||
|
Pontiac Lemans V6,21.5,6,231,115,3245,15.4,79
|
||||||
|
Pontiac Phoenix LJ,19.2,6,231,105,3535,19.2,78
|
||||||
|
Pontiac Phoenix,27,4,151,90,2735,18,82
|
||||||
|
Pontiac Phoenix,33.5,4,151,90,2556,13.2,79
|
||||||
|
Pontiac Safari (Wagon),13,8,400,175,5140,12,71
|
||||||
|
Pontiac Sunbird Coupe,24.5,4,151,88,2740,16,77
|
||||||
|
Pontiac Ventura Sj,18.5,6,250,110,3645,16.2,76
|
||||||
|
Renault 12 (Wagon),26,4,96,69,2189,18,72
|
||||||
|
Renault 12TL,27,4,101,83,2202,15.3,76
|
||||||
|
Renault 18I,34.5,4,100,,2320,15.8,81
|
||||||
|
Renault 5 Gtl,36,4,79,58,1825,18.6,77
|
||||||
|
Renault Lecar Deluxe,40.9,4,85,,1835,17.3,80
|
||||||
|
Saab 900S,,4,121,110,2800,15.4,81
|
||||||
|
Saab 99E,25,4,104,95,2375,17.5,70
|
||||||
|
Saab 99GLE,21.6,4,121,115,2795,15.7,78
|
||||||
|
Saab 99LE,24,4,121,110,2660,14,73
|
||||||
|
Saab 99LE,25,4,121,115,2671,13.5,75
|
||||||
|
Subaru DL,30,4,97,67,1985,16.4,77
|
||||||
|
Subaru DL,33.8,4,97,67,2145,18,80
|
||||||
|
Subaru,26,4,108,93,2391,15.5,74
|
||||||
|
Subaru,32.3,4,97,67,2065,17.8,81
|
||||||
|
Toyota Carina,20,4,97,88,2279,19,73
|
||||||
|
Toyota Celica GT Liftback,21.1,4,134,95,2515,14.8,78
|
||||||
|
Toyota Celica GT,32,4,144,96,2665,13.9,82
|
||||||
|
Toyota Corolla 1200,31,4,71,65,1773,19,71
|
||||||
|
Toyota Corolla 1200,32,4,71,65,1836,21,74
|
||||||
|
Toyota Corolla 1600 (Wagon),27,4,97,88,2100,16.5,72
|
||||||
|
Toyota Corolla Liftback,26,4,97,75,2265,18.2,77
|
||||||
|
Toyota Corolla Tercel,38.1,4,89,60,1968,18.8,80
|
||||||
|
Toyota Corolla,28,4,97,75,2155,16.4,76
|
||||||
|
Toyota Corolla,29,4,97,75,2171,16,75
|
||||||
|
Toyota Corolla,32.2,4,108,75,2265,15.2,80
|
||||||
|
Toyota Corolla,32.4,4,108,75,2350,16.8,81
|
||||||
|
Toyota Corolla,34,4,108,70,2245,16.9,82
|
||||||
|
Toyota Corona Hardtop,24,4,113,95,2278,15.5,72
|
||||||
|
Toyota Corona Liftback,29.8,4,134,90,2711,15.5,80
|
||||||
|
Toyota Corona Mark II,24,4,113,95,2372,15,70
|
||||||
|
Toyota Corona,24,4,134,96,2702,13.5,75
|
||||||
|
Toyota Corona,25,4,113,95,2228,14,71
|
||||||
|
Toyota Corona,27.5,4,134,95,2560,14.2,78
|
||||||
|
Toyota Corona,31,4,76,52,1649,16.5,74
|
||||||
|
Toyota Cressida,25.4,6,168,116,2900,12.6,81
|
||||||
|
Toyota Mark II,19,6,156,108,2930,15.5,76
|
||||||
|
Toyota Mark II,20,6,156,122,2807,13.5,73
|
||||||
|
Toyota Starlet,39.1,4,79,58,1755,16.9,81
|
||||||
|
Toyota Tercel,37.7,4,89,62,2050,17.3,81
|
||||||
|
Toyouta Corona Mark II (Wagon),23,4,120,97,2506,14.5,72
|
||||||
|
Triumph TR7 Coupe,35,4,122,88,2500,15.1,80
|
||||||
|
Vokswagen Rabbit,29.8,4,89,62,1845,15.3,80
|
||||||
|
Volkswagen 1131 Deluxe Sedan,26,4,97,46,1835,20.5,70
|
||||||
|
Volkswagen 411 (Wagon),22,4,121,76,2511,18,72
|
||||||
|
Volkswagen Dasher (Diesel),43.4,4,90,48,2335,23.7,80
|
||||||
|
Volkswagen Dasher,25,4,90,71,2223,16.5,75
|
||||||
|
Volkswagen Dasher,26,4,79,67,1963,15.5,74
|
||||||
|
Volkswagen Dasher,30.5,4,97,78,2190,14.1,77
|
||||||
|
Volkswagen Jetta,33,4,105,74,2190,14.2,81
|
||||||
|
Volkswagen Model 111,27,4,97,60,1834,19,71
|
||||||
|
Volkswagen Pickup,44,4,97,52,2130,24.6,82
|
||||||
|
Volkswagen Rabbit C (Diesel),44.3,4,90,48,2085,21.7,80
|
||||||
|
Volkswagen Rabbit Custom Diesel,43.1,4,90,48,1985,21.5,78
|
||||||
|
Volkswagen Rabbit Custom,29,4,97,78,1940,14.5,77
|
||||||
|
Volkswagen Rabbit Custom,31.9,4,89,71,1925,14,79
|
||||||
|
Volkswagen Rabbit L,36,4,105,74,1980,15.3,82
|
||||||
|
Volkswagen Rabbit,29,4,90,70,1937,14,75
|
||||||
|
Volkswagen Rabbit,29,4,90,70,1937,14.2,76
|
||||||
|
Volkswagen Rabbit,29.5,4,97,71,1825,12.2,76
|
||||||
|
Volkswagen Rabbit,41.5,4,98,76,2144,14.7,80
|
||||||
|
Volkswagen Scirocco,31.5,4,89,71,1990,14.9,78
|
||||||
|
Volkswagen Super Beetle 117,,4,97,48,1978,20,71
|
||||||
|
Volkswagen Super Beetle,26,4,97,46,1950,21,73
|
||||||
|
Volkswagen Type 3,23,4,97,54,2254,23.5,72
|
||||||
|
Volvo 144EA,19,4,121,112,2868,15.5,73
|
||||||
|
Volvo 145E (Wagon),18,4,121,112,2933,14.5,72
|
||||||
|
Volvo 244DL,22,4,121,98,2945,14.5,75
|
||||||
|
Volvo 245,20,4,130,102,3150,15.7,76
|
||||||
|
Volvo 264GL,17,6,163,125,3140,13.6,78
|
||||||
|
Volvo Diesel,30.7,6,145,76,3160,19.6,81
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||||||
|
<title>Parallel Coordinates</title>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
svg {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background path {
|
||||||
|
fill: none;
|
||||||
|
stroke: #ccc;
|
||||||
|
stroke-opacity: .4;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foreground path {
|
||||||
|
fill: none;
|
||||||
|
stroke: steelblue;
|
||||||
|
stroke-opacity: .7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brush .extent {
|
||||||
|
fill-opacity: .3;
|
||||||
|
stroke: #fff;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis line, .axis path {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis text {
|
||||||
|
text-shadow: 0 1px 0 #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.csv.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var m = [30, 10, 10, 10],
|
||||||
|
w = 960 - m[1] - m[3],
|
||||||
|
h = 500 - m[0] - m[2];
|
||||||
|
|
||||||
|
var x = d3.scale.ordinal().rangePoints([0, w], 1),
|
||||||
|
y = {};
|
||||||
|
|
||||||
|
var line = d3.svg.line(),
|
||||||
|
axis = d3.svg.axis().orient("left"),
|
||||||
|
background,
|
||||||
|
foreground;
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w + m[1] + m[3])
|
||||||
|
.attr("height", h + m[0] + m[2])
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
|
d3.csv("cars.csv", function(cars) {
|
||||||
|
|
||||||
|
// Extract the list of dimensions and create a scale for each.
|
||||||
|
x.domain(dimensions = d3.keys(cars[0]).filter(function(d) {
|
||||||
|
return d != "name" && (y[d] = d3.scale.linear()
|
||||||
|
.domain(d3.extent(cars, function(p) { return +p[d]; }))
|
||||||
|
.range([h, 0]));
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Add grey background lines for context.
|
||||||
|
background = svg.append("svg:g")
|
||||||
|
.attr("class", "background")
|
||||||
|
.selectAll("path")
|
||||||
|
.data(cars)
|
||||||
|
.enter().append("svg:path")
|
||||||
|
.attr("d", path);
|
||||||
|
|
||||||
|
// Add blue foreground lines for focus.
|
||||||
|
foreground = svg.append("svg:g")
|
||||||
|
.attr("class", "foreground")
|
||||||
|
.selectAll("path")
|
||||||
|
.data(cars)
|
||||||
|
.enter().append("svg:path")
|
||||||
|
.attr("d", path);
|
||||||
|
|
||||||
|
// Add a group element for each dimension.
|
||||||
|
var g = svg.selectAll(".dimension")
|
||||||
|
.data(dimensions)
|
||||||
|
.enter().append("svg:g")
|
||||||
|
.attr("class", "dimension")
|
||||||
|
.attr("transform", function(d) { return "translate(" + x(d) + ")"; });
|
||||||
|
|
||||||
|
// Add an axis and title.
|
||||||
|
g.append("svg:g")
|
||||||
|
.attr("class", "axis")
|
||||||
|
.each(function(d) { d3.select(this).call(axis.scale(y[d])); })
|
||||||
|
.append("svg:text")
|
||||||
|
.attr("text-anchor", "middle")
|
||||||
|
.attr("y", -9)
|
||||||
|
.text(String);
|
||||||
|
|
||||||
|
// Add and store a brush for each axis.
|
||||||
|
g.append("svg:g")
|
||||||
|
.attr("class", "brush")
|
||||||
|
.each(function(d) { d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brush", brush)); })
|
||||||
|
.selectAll("rect")
|
||||||
|
.attr("x", -8)
|
||||||
|
.attr("width", 16);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Returns the path for a given data point.
|
||||||
|
function path(d) {
|
||||||
|
return line(dimensions.map(function(p) { return [x(p), y[p](d[p])]; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles a brush event, toggling the display of foreground lines.
|
||||||
|
function brush() {
|
||||||
|
var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
|
||||||
|
extents = actives.map(function(p) { return y[p].brush.extent(); });
|
||||||
|
foreground.style("display", function(d) {
|
||||||
|
return actives.every(function(p, i) {
|
||||||
|
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
|
||||||
|
}) ? null : "none";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -18,14 +18,13 @@ body {
|
||||||
var w = 400,
|
var w = 400,
|
||||||
h = 400,
|
h = 400,
|
||||||
r = Math.min(w, h) / 2,
|
r = Math.min(w, h) / 2,
|
||||||
data = d3.range(10).map(Math.random),
|
data = d3.range(10).map(Math.random).sort(d3.descending),
|
||||||
color = d3.scale.category20(),
|
color = d3.scale.category20(),
|
||||||
arc = d3.svg.arc().outerRadius(r),
|
arc = d3.svg.arc().outerRadius(r),
|
||||||
donut = d3.layout.pie();
|
donut = d3.layout.pie();
|
||||||
|
|
||||||
var vis = d3.select("body")
|
var vis = d3.select("body").append("svg:svg")
|
||||||
.append("svg:svg")
|
.data([data])
|
||||||
.data([data.sort(d3.descending)])
|
|
||||||
.attr("width", w)
|
.attr("width", w)
|
||||||
.attr("height", h);
|
.attr("height", h);
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ var w = 400,
|
||||||
r = Math.min(w, h) / 2,
|
r = Math.min(w, h) / 2,
|
||||||
data = d3.range(10).map(Math.random),
|
data = d3.range(10).map(Math.random),
|
||||||
color = d3.scale.category20(),
|
color = d3.scale.category20(),
|
||||||
donut = d3.layout.pie().sort(d3.descending),
|
donut = d3.layout.pie(),
|
||||||
arc = d3.svg.arc().innerRadius(r * .6).outerRadius(r);
|
arc = d3.svg.arc().innerRadius(r * .6).outerRadius(r);
|
||||||
|
|
||||||
var vis = d3.select("body")
|
var vis = d3.select("body")
|
||||||
|
|
|
@ -0,0 +1,661 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.csv.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.geo.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.geom.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.layout.js"></script>
|
||||||
|
<script type="text/javascript" src="../../d3.time.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
svg {
|
||||||
|
border: solid 1px #000;
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
font-family: "Helvetica Neue";
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
stroke-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var m = [120, 60, 60, 60],
|
||||||
|
w = 1280 - m[1] - m[3],
|
||||||
|
h = 720 - m[0] - m[2];
|
||||||
|
|
||||||
|
var x = d3.time.scale().range([0, w - 60]),
|
||||||
|
y = d3.scale.linear().range([h / 4 - 20, 0]),
|
||||||
|
duration = 1500,
|
||||||
|
delay = 500;
|
||||||
|
|
||||||
|
var color = d3.scale.category10();
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w + m[1] + m[3])
|
||||||
|
.attr("height", h + m[0] + m[2])
|
||||||
|
.append("svg:g")
|
||||||
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
|
var stocks,
|
||||||
|
symbols;
|
||||||
|
|
||||||
|
// A line generator, for the dark stroke.
|
||||||
|
var line = d3.svg.line()
|
||||||
|
.interpolate("basis")
|
||||||
|
.x(function(d) { return x(d.date); })
|
||||||
|
.y(function(d) { return y(d.price); });
|
||||||
|
|
||||||
|
// A line generator, for the dark stroke.
|
||||||
|
var axis = d3.svg.line()
|
||||||
|
.interpolate("basis")
|
||||||
|
.x(function(d) { return x(d.date); })
|
||||||
|
.y(h);
|
||||||
|
|
||||||
|
// A area generator, for the dark stroke.
|
||||||
|
var area = d3.svg.area()
|
||||||
|
.interpolate("basis")
|
||||||
|
.x(function(d) { return x(d.date); })
|
||||||
|
.y0(h / 4 - 20)
|
||||||
|
.y1(function(d) { return y(d.price); });
|
||||||
|
|
||||||
|
d3.csv("../data/stocks.csv", function(data) {
|
||||||
|
var parse = d3.time.format("%b %Y").parse,
|
||||||
|
filter = {AAPL: 1, AMZN: 1, MSFT: 1, IBM: 1};
|
||||||
|
|
||||||
|
stocks = data.filter(function(d) { return d.symbol in filter; });
|
||||||
|
|
||||||
|
// Nest stock values by symbol.
|
||||||
|
symbols = d3.nest()
|
||||||
|
.key(function(d) { return d.symbol; })
|
||||||
|
.entries(stocks);
|
||||||
|
|
||||||
|
// Parse dates and numbers. We assume values are sorted by date.
|
||||||
|
// Also compute the maximum price per symbol, needed for the y-domain.
|
||||||
|
symbols.forEach(function(s) {
|
||||||
|
s.values.forEach(function(d) { d.date = parse(d.date); d.price = +d.price; });
|
||||||
|
s.maxPrice = d3.max(s.values, function(d) { return d.price; });
|
||||||
|
s.sumPrice = d3.sum(s.values, function(d) { return d.price; });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort by maximum price, descending.
|
||||||
|
symbols.sort(function(a, b) { return b.maxPrice - a.maxPrice; });
|
||||||
|
|
||||||
|
// Compute the minimum and maximum date across symbols.
|
||||||
|
x.domain([
|
||||||
|
d3.min(symbols, function(d) { return d.values[0].date; }),
|
||||||
|
d3.max(symbols, function(d) { return d.values[d.values.length - 1].date; })
|
||||||
|
]);
|
||||||
|
|
||||||
|
var g = svg.selectAll("g")
|
||||||
|
.data(symbols)
|
||||||
|
.enter().append("svg:g")
|
||||||
|
.attr("class", "symbol");
|
||||||
|
|
||||||
|
setTimeout(lines, duration);
|
||||||
|
});
|
||||||
|
|
||||||
|
function lines() {
|
||||||
|
|
||||||
|
var g = svg.selectAll(".symbol")
|
||||||
|
.attr("transform", function(d, i) { return "translate(0," + i * h / 4 + ")"; });
|
||||||
|
|
||||||
|
g.each(function(d) {
|
||||||
|
var e = d3.select(this);
|
||||||
|
|
||||||
|
e.append("svg:path")
|
||||||
|
.attr("class", "line");
|
||||||
|
|
||||||
|
e.append("svg:circle")
|
||||||
|
.attr("r", 5)
|
||||||
|
.style("fill", function(d) { return color(d.key); })
|
||||||
|
.style("stroke", "#000")
|
||||||
|
.style("stroke-width", "2px");
|
||||||
|
|
||||||
|
e.append("svg:text")
|
||||||
|
.attr("x", 12)
|
||||||
|
.attr("dy", ".31em")
|
||||||
|
.text(d.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
function draw(k) {
|
||||||
|
g.each(function(d) {
|
||||||
|
var e = d3.select(this);
|
||||||
|
y.domain([0, d.maxPrice]);
|
||||||
|
|
||||||
|
e.select("path")
|
||||||
|
.attr("d", function(d) { return line(d.values.slice(0, k + 1)); });
|
||||||
|
|
||||||
|
e.selectAll("circle, text")
|
||||||
|
.data(function(d) { return [d.values[k], d.values[k]]; })
|
||||||
|
.attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.price) + ")"; });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var k = 1, n = symbols[0].values.length;
|
||||||
|
d3.timer(function() {
|
||||||
|
draw(k);
|
||||||
|
if ((k += 2) >= n - 1) {
|
||||||
|
draw(n - 1);
|
||||||
|
setTimeout(horizons, 500);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function horizons() {
|
||||||
|
svg.insert("svg:defs", ".symbol")
|
||||||
|
.append("svg:clipPath")
|
||||||
|
.attr("id", "clip")
|
||||||
|
.append("svg:rect")
|
||||||
|
.attr("width", w)
|
||||||
|
.attr("height", h / 4 - 20);
|
||||||
|
|
||||||
|
var color = d3.scale.ordinal()
|
||||||
|
.range(["#c6dbef", "#9ecae1", "#6baed6"]);
|
||||||
|
|
||||||
|
var g = svg.selectAll(".symbol")
|
||||||
|
.attr("clip-path", "url(#clip)");
|
||||||
|
|
||||||
|
g.select("circle").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (-h / 4) + ")"; })
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
g.select("text").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (h / 4 - 20) + ")"; })
|
||||||
|
.attr("dy", "0em");
|
||||||
|
|
||||||
|
g.each(function(d) {
|
||||||
|
y.domain([0, d.maxPrice]);
|
||||||
|
|
||||||
|
d3.select(this).selectAll(".area")
|
||||||
|
.data(d3.range(3))
|
||||||
|
.enter().insert("svg:path", ".line")
|
||||||
|
.attr("class", "area")
|
||||||
|
.attr("transform", function(d) { return "translate(0," + (d * (h / 4 - 20)) + ")"; })
|
||||||
|
.attr("d", area(d.values))
|
||||||
|
.style("fill", function(d, i) { return color(i); })
|
||||||
|
.style("fill-opacity", 1e-6);
|
||||||
|
|
||||||
|
y.domain([0, d.maxPrice / 3]);
|
||||||
|
|
||||||
|
d3.select(this).selectAll(".line").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("d", line(d.values))
|
||||||
|
.style("stroke-opacity", 1e-6);
|
||||||
|
|
||||||
|
d3.select(this).selectAll(".area").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.style("fill-opacity", 1)
|
||||||
|
.attr("d", area(d.values))
|
||||||
|
.each("end", function() { d3.select(this).style("fill-opacity", null); });
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(areas, duration + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function areas() {
|
||||||
|
var g = svg.selectAll(".symbol");
|
||||||
|
|
||||||
|
axis
|
||||||
|
.y(h / 4 - 21);
|
||||||
|
|
||||||
|
g.select(".line")
|
||||||
|
.attr("d", function(d) { return axis(d.values); });
|
||||||
|
|
||||||
|
g.each(function(d) {
|
||||||
|
y.domain([0, d.maxPrice]);
|
||||||
|
|
||||||
|
d3.select(this).select(".line").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.style("stroke-opacity", 1)
|
||||||
|
.each("end", function() { d3.select(this).style("stroke-opacity", null); });
|
||||||
|
|
||||||
|
d3.select(this).selectAll(".area")
|
||||||
|
.filter(function(d, i) { return i; })
|
||||||
|
.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.style("fill-opacity", 1e-6)
|
||||||
|
.attr("d", area(d.values))
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
d3.select(this).selectAll(".area")
|
||||||
|
.filter(function(d, i) { return !i; })
|
||||||
|
.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.style("fill", color(d.key))
|
||||||
|
.attr("d", area(d.values));
|
||||||
|
});
|
||||||
|
|
||||||
|
svg.select("defs").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
g.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.each("end", function() { d3.select(this).attr("clip-path", null); });
|
||||||
|
|
||||||
|
setTimeout(stackedArea, duration + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stackedArea() {
|
||||||
|
var stack = d3.layout.stack()
|
||||||
|
.values(function(d) { return d.values; })
|
||||||
|
.x(function(d) { return d.date; })
|
||||||
|
.y(function(d) { return d.price; })
|
||||||
|
.out(function(d, y0, y) { d.price0 = y0; })
|
||||||
|
.order("reverse");
|
||||||
|
|
||||||
|
stack(symbols);
|
||||||
|
|
||||||
|
y
|
||||||
|
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
|
||||||
|
.range([h, 0]);
|
||||||
|
|
||||||
|
line
|
||||||
|
.y(function(d) { return y(d.price0); });
|
||||||
|
|
||||||
|
area
|
||||||
|
.y0(function(d) { return y(d.price0); })
|
||||||
|
.y1(function(d) { return y(d.price0 + d.price); });
|
||||||
|
|
||||||
|
var t = svg.selectAll(".symbol").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("transform", "translate(0,0)")
|
||||||
|
.each("end", function() { d3.select(this).attr("transform", null); });
|
||||||
|
|
||||||
|
t.select("path.area")
|
||||||
|
.attr("d", function(d) { return area(d.values); });
|
||||||
|
|
||||||
|
t.select("path.line")
|
||||||
|
.style("stroke-opacity", function(d, i) { return i < 3 ? 1e-6 : 1; })
|
||||||
|
.attr("d", function(d) { return line(d.values); });
|
||||||
|
|
||||||
|
t.select("text")
|
||||||
|
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
|
||||||
|
|
||||||
|
setTimeout(streamgraph, duration + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function streamgraph() {
|
||||||
|
var stack = d3.layout.stack()
|
||||||
|
.values(function(d) { return d.values; })
|
||||||
|
.x(function(d) { return d.date; })
|
||||||
|
.y(function(d) { return d.price; })
|
||||||
|
.out(function(d, y0, y) { d.price0 = y0; })
|
||||||
|
.order("reverse")
|
||||||
|
.offset("wiggle");
|
||||||
|
|
||||||
|
stack(symbols);
|
||||||
|
|
||||||
|
line
|
||||||
|
.y(function(d) { return y(d.price0); });
|
||||||
|
|
||||||
|
var t = svg.selectAll(".symbol").transition()
|
||||||
|
.duration(duration);
|
||||||
|
|
||||||
|
t.select("path.area")
|
||||||
|
.attr("d", function(d) { return area(d.values); });
|
||||||
|
|
||||||
|
t.select("path.line")
|
||||||
|
.style("stroke-opacity", 1e-6)
|
||||||
|
.attr("d", function(d) { return line(d.values); });
|
||||||
|
|
||||||
|
t.select("text")
|
||||||
|
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
|
||||||
|
|
||||||
|
setTimeout(overlappingArea, duration + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function overlappingArea() {
|
||||||
|
var g = svg.selectAll(".symbol");
|
||||||
|
|
||||||
|
line
|
||||||
|
.y(function(d) { return y(d.price0 + d.price); });
|
||||||
|
|
||||||
|
g.select(".line")
|
||||||
|
.attr("d", function(d) { return line(d.values); });
|
||||||
|
|
||||||
|
y
|
||||||
|
.domain([0, d3.max(symbols.map(function(d) { return d.maxPrice; }))])
|
||||||
|
.range([h, 0]);
|
||||||
|
|
||||||
|
area
|
||||||
|
.y0(h)
|
||||||
|
.y1(function(d) { return y(d.price); });
|
||||||
|
|
||||||
|
line
|
||||||
|
.y(function(d) { return y(d.price); });
|
||||||
|
|
||||||
|
var t = g.transition()
|
||||||
|
.duration(duration);
|
||||||
|
|
||||||
|
t.select(".line")
|
||||||
|
.style("stroke-opacity", 1)
|
||||||
|
.attr("d", function(d) { return line(d.values); });
|
||||||
|
|
||||||
|
t.select(".area")
|
||||||
|
.style("fill-opacity", .5)
|
||||||
|
.attr("d", function(d) { return area(d.values); });
|
||||||
|
|
||||||
|
t.select("text")
|
||||||
|
.attr("dy", ".31em")
|
||||||
|
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price) + ")"; });
|
||||||
|
|
||||||
|
svg.append("svg:line")
|
||||||
|
.attr("class", "line")
|
||||||
|
.attr("x1", 0)
|
||||||
|
.attr("x2", w - 60)
|
||||||
|
.attr("y1", h)
|
||||||
|
.attr("y2", h)
|
||||||
|
.style("stroke-opacity", 1e-6)
|
||||||
|
.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.style("stroke-opacity", 1);
|
||||||
|
|
||||||
|
setTimeout(groupedBar, duration + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupedBar() {
|
||||||
|
x = d3.scale.ordinal()
|
||||||
|
.domain(symbols[0].values.map(function(d) { return d.date; }))
|
||||||
|
.rangeBands([0, w - 60], .1);
|
||||||
|
|
||||||
|
var x1 = d3.scale.ordinal()
|
||||||
|
.domain(symbols.map(function(d) { return d.key; }))
|
||||||
|
.rangeBands([0, x.rangeBand()]);
|
||||||
|
|
||||||
|
var g = svg.selectAll(".symbol");
|
||||||
|
|
||||||
|
var t = g.transition()
|
||||||
|
.duration(duration);
|
||||||
|
|
||||||
|
t.select(".line")
|
||||||
|
.style("stroke-opacity", 1e-6)
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
t.select(".area")
|
||||||
|
.style("fill-opacity", 1e-6)
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
g.each(function(p, j) {
|
||||||
|
d3.select(this).selectAll("rect")
|
||||||
|
.data(function(d) { return d.values; })
|
||||||
|
.enter().append("svg:rect")
|
||||||
|
.attr("x", function(d) { return x(d.date) + x1(p.key); })
|
||||||
|
.attr("y", function(d) { return y(d.price); })
|
||||||
|
.attr("width", x1.rangeBand())
|
||||||
|
.attr("height", function(d) { return h - y(d.price); })
|
||||||
|
.style("fill", color(p.key))
|
||||||
|
.style("fill-opacity", 1e-6)
|
||||||
|
.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.style("fill-opacity", 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(stackedBar, duration + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stackedBar() {
|
||||||
|
x.rangeRoundBands([0, w - 60], .1);
|
||||||
|
|
||||||
|
var stack = d3.layout.stack()
|
||||||
|
.values(function(d) { return d.values; })
|
||||||
|
.x(function(d) { return d.date; })
|
||||||
|
.y(function(d) { return d.price; })
|
||||||
|
.out(function(d, y0, y) { d.price0 = y0; })
|
||||||
|
.order("reverse");
|
||||||
|
|
||||||
|
var g = svg.selectAll(".symbol");
|
||||||
|
|
||||||
|
stack(symbols);
|
||||||
|
|
||||||
|
y
|
||||||
|
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
|
||||||
|
.range([h, 0]);
|
||||||
|
|
||||||
|
var t = g.transition()
|
||||||
|
.duration(duration / 2);
|
||||||
|
|
||||||
|
t.select("text")
|
||||||
|
.delay(symbols[0].values.length * 10)
|
||||||
|
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
|
||||||
|
|
||||||
|
t.selectAll("rect")
|
||||||
|
.delay(function(d, i) { return i * 10; })
|
||||||
|
.attr("y", function(d) { return y(d.price0 + d.price); })
|
||||||
|
.attr("height", function(d) { return h - y(d.price); })
|
||||||
|
.each("end", function() {
|
||||||
|
d3.select(this)
|
||||||
|
.style("stroke", "#fff")
|
||||||
|
.style("stroke-opacity", 1e-6)
|
||||||
|
.transition()
|
||||||
|
.duration(duration / 2)
|
||||||
|
.attr("x", function(d) { return x(d.date); })
|
||||||
|
.attr("width", x.rangeBand())
|
||||||
|
.style("stroke-opacity", 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(transposeBar, duration + symbols[0].values.length * 10 + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transposeBar() {
|
||||||
|
x
|
||||||
|
.domain(symbols.map(function(d) { return d.key; }))
|
||||||
|
.rangeRoundBands([0, w], .2);
|
||||||
|
|
||||||
|
y
|
||||||
|
.domain([0, d3.max(symbols.map(function(d) { return d3.sum(d.values.map(function(d) { return d.price; })); }))]);
|
||||||
|
|
||||||
|
var stack = d3.layout.stack()
|
||||||
|
.x(function(d, i) { return i; })
|
||||||
|
.y(function(d) { return d.price; })
|
||||||
|
.out(function(d, y0, y) { d.price0 = y0; });
|
||||||
|
|
||||||
|
stack(d3.zip.apply(null, symbols.map(function(d) { return d.values; }))); // transpose!
|
||||||
|
|
||||||
|
var g = svg.selectAll(".symbol");
|
||||||
|
|
||||||
|
var t = g.transition()
|
||||||
|
.duration(duration / 2);
|
||||||
|
|
||||||
|
t.selectAll("rect")
|
||||||
|
.delay(function(d, i) { return i * 10; })
|
||||||
|
.attr("y", function(d) { return y(d.price0 + d.price) - 1; })
|
||||||
|
.attr("height", function(d) { return h - y(d.price) + 1; })
|
||||||
|
.attr("x", function(d) { return x(d.symbol); })
|
||||||
|
.attr("width", x.rangeBand())
|
||||||
|
.style("stroke-opacity", 1e-6);
|
||||||
|
|
||||||
|
t.select("text")
|
||||||
|
.attr("x", 0)
|
||||||
|
.attr("transform", function(d) { return "translate(" + (x(d.key) + x.rangeBand() / 2) + "," + h + ")"; })
|
||||||
|
.attr("dy", "1.31em")
|
||||||
|
.each("end", function() { d3.select(this).attr("x", null).attr("text-anchor", "middle"); });
|
||||||
|
|
||||||
|
svg.select("line").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("x2", w);
|
||||||
|
|
||||||
|
setTimeout(donut, duration / 2 + symbols[0].values.length * 10 + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
function donut() {
|
||||||
|
var g = svg.selectAll(".symbol");
|
||||||
|
|
||||||
|
g.selectAll("rect").remove();
|
||||||
|
|
||||||
|
var pie = d3.layout.pie()
|
||||||
|
.value(function(d) { return d.sumPrice; });
|
||||||
|
|
||||||
|
var arc = d3.svg.arc();
|
||||||
|
|
||||||
|
g.append("svg:path")
|
||||||
|
.style("fill", function(d) { return color(d.key); })
|
||||||
|
.data(function() { return pie(symbols); })
|
||||||
|
.transition()
|
||||||
|
.duration(duration)
|
||||||
|
.tween("arc", arcTween);
|
||||||
|
|
||||||
|
g.select("text").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("dy", ".31em");
|
||||||
|
|
||||||
|
svg.select("line").transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("y1", 2 * h)
|
||||||
|
.attr("y2", 2 * h)
|
||||||
|
.remove();
|
||||||
|
|
||||||
|
function arcTween(d) {
|
||||||
|
var path = d3.select(this),
|
||||||
|
text = d3.select(this.parentNode.appendChild(this.previousSibling)),
|
||||||
|
x0 = x(d.data.key),
|
||||||
|
y0 = h - y(d.data.sumPrice);
|
||||||
|
|
||||||
|
return function(t) {
|
||||||
|
var r = h / 2 / Math.min(1, t + 1e-3),
|
||||||
|
a = Math.cos(t * Math.PI / 2),
|
||||||
|
xx = (-r + (a) * (x0 + x.rangeBand()) + (1 - a) * (w + h) / 2),
|
||||||
|
yy = ((a) * h + (1 - a) * h / 2),
|
||||||
|
f = {
|
||||||
|
innerRadius: r - x.rangeBand() / (2 - a),
|
||||||
|
outerRadius: r,
|
||||||
|
startAngle: a * (Math.PI / 2 - y0 / r) + (1 - a) * d.startAngle,
|
||||||
|
endAngle: a * (Math.PI / 2) + (1 - a) * d.endAngle
|
||||||
|
};
|
||||||
|
|
||||||
|
path.attr("transform", "translate(" + xx + "," + yy + ")");
|
||||||
|
path.attr("d", arc(f));
|
||||||
|
text.attr("transform", "translate(" + arc.centroid(f) + ")translate(" + xx + "," + yy + ")rotate(" + ((f.startAngle + f.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(donutExplode, duration + delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function donutTransition() {
|
||||||
|
var r0 = h / 2 - x.rangeBand() / 2,
|
||||||
|
r1 = h / 2,
|
||||||
|
pie1 = d3.layout.pie().value(function(d) { return d.sumPrice; })(symbols),
|
||||||
|
pie2 = d3.layout.pie().value(function(d) { return d.maxPrice; })(symbols),
|
||||||
|
arc = d3.svg.arc();
|
||||||
|
|
||||||
|
svg.selectAll(".symbol path")
|
||||||
|
.map(function(d, i) {
|
||||||
|
d = pie1[i];
|
||||||
|
d.innerRadius = r0;
|
||||||
|
d.outerRadius = r1;
|
||||||
|
d.next = pie2[i];
|
||||||
|
return d;
|
||||||
|
})
|
||||||
|
.each(transitionSplit);
|
||||||
|
|
||||||
|
function transitionSplit(d, i) {
|
||||||
|
d3.select(this).transition()
|
||||||
|
.duration(duration / 2)
|
||||||
|
.tween("arc", tweenArc({
|
||||||
|
innerRadius: i & 1 ? r0 : (r0 + r1) / 2,
|
||||||
|
outerRadius: i & 1 ? (r0 + r1) / 2 : r1
|
||||||
|
}))
|
||||||
|
.each("end", transitionRotate);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transitionRotate(d, i) {
|
||||||
|
var a0 = d.next.startAngle + d.next.endAngle,
|
||||||
|
a1 = d.startAngle - d.endAngle;
|
||||||
|
d3.select(this).transition()
|
||||||
|
.duration(duration / 2)
|
||||||
|
.tween("arc", tweenArc({
|
||||||
|
startAngle: (a0 + a1) / 2,
|
||||||
|
endAngle: (a0 - a1) / 2
|
||||||
|
}))
|
||||||
|
.each("end", transitionResize);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transitionResize(d, i) {
|
||||||
|
d3.select(this).transition()
|
||||||
|
.duration(duration / 2)
|
||||||
|
.tween("arc", tweenArc({
|
||||||
|
startAngle: d.next.startAngle,
|
||||||
|
endAngle: d.next.endAngle
|
||||||
|
}))
|
||||||
|
.each("end", transitionUnite);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transitionUnite(d, i) {
|
||||||
|
d3.select(this).transition()
|
||||||
|
.duration(duration / 2)
|
||||||
|
.tween("arc", tweenArc({
|
||||||
|
innerRadius: r0,
|
||||||
|
outerRadius: r1
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function tweenArc(b) {
|
||||||
|
return function(a) {
|
||||||
|
var path = d3.select(this),
|
||||||
|
text = d3.select(this.nextSibling),
|
||||||
|
i = d3.interpolate(a, b);
|
||||||
|
for (var key in b) a[key] = b[key]; // update data
|
||||||
|
return function(t) {
|
||||||
|
var a = i(t);
|
||||||
|
path.attr("d", arc(a));
|
||||||
|
text.attr("transform", "translate(" + arc.centroid(a) + ")translate(" + w / 2 + "," + h / 2 +")rotate(" + ((a.startAngle + a.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(donutExplode, 2 * duration + delay);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function donutExplode() {
|
||||||
|
var r0a = h / 2 - x.rangeBand() / 2,
|
||||||
|
r1a = h / 2,
|
||||||
|
r0b = 2 * h - x.rangeBand() / 2,
|
||||||
|
r1b = 2 * h,
|
||||||
|
arc = d3.svg.arc();
|
||||||
|
|
||||||
|
svg.selectAll(".symbol path")
|
||||||
|
.each(transitionExplode);
|
||||||
|
|
||||||
|
function transitionExplode(d, i) {
|
||||||
|
d.innerRadius = r0a;
|
||||||
|
d.outerRadius = r1a;
|
||||||
|
d3.select(this).transition()
|
||||||
|
.duration(duration / 2)
|
||||||
|
.tween("arc", tweenArc({
|
||||||
|
innerRadius: r0b,
|
||||||
|
outerRadius: r1b
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function tweenArc(b) {
|
||||||
|
return function(a) {
|
||||||
|
var path = d3.select(this),
|
||||||
|
text = d3.select(this.nextSibling),
|
||||||
|
i = d3.interpolate(a, b);
|
||||||
|
for (var key in b) a[key] = b[key]; // update data
|
||||||
|
return function(t) {
|
||||||
|
var a = i(t);
|
||||||
|
path.attr("d", arc(a));
|
||||||
|
text.attr("transform", "translate(" + arc.centroid(a) + ")translate(" + w / 2 + "," + h / 2 +")rotate(" + ((a.startAngle + a.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,7 +0,0 @@
|
||||||
function cross(a) {
|
|
||||||
return function(d) {
|
|
||||||
var c = [];
|
|
||||||
for (var i = 0, n = a.length; i < n; i++) c.push({x: d, y: a[i]});
|
|
||||||
return c;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,8 +1,49 @@
|
||||||
line {
|
svg {
|
||||||
stroke: #eee;
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis {
|
||||||
shape-rendering: crispEdges;
|
shape-rendering: crispEdges;
|
||||||
}
|
}
|
||||||
|
|
||||||
rect {
|
.axis line {
|
||||||
cursor: crosshair;
|
stroke: #ddd;
|
||||||
|
stroke-width: .5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis path {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.extent {
|
||||||
|
fill: #000;
|
||||||
|
fill-opacity: .125;
|
||||||
|
stroke: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.frame {
|
||||||
|
fill: #fff;
|
||||||
|
fill-opacity: .7;
|
||||||
|
stroke: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle {
|
||||||
|
fill: #ccc;
|
||||||
|
fill-opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell text {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setosa {
|
||||||
|
fill: #800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.versicolor {
|
||||||
|
fill: #080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.virginica {
|
||||||
|
fill: #008;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<title>Scatterplot Matrix</title>
|
<title>Scatterplot Matrix</title>
|
||||||
<script type="text/javascript" src="../../d3.js"></script>
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
<script type="text/javascript" src="cross.js"></script>
|
|
||||||
<link type="text/css" rel="stylesheet" href="splom.css"/>
|
<link type="text/css" rel="stylesheet" href="splom.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -2,148 +2,118 @@ d3.json("flowers.json", function(flower) {
|
||||||
|
|
||||||
// Size parameters.
|
// Size parameters.
|
||||||
var size = 150,
|
var size = 150,
|
||||||
padding = 20;
|
padding = 19.5,
|
||||||
|
n = flower.traits.length;
|
||||||
// Color scale.
|
|
||||||
var color = d3.scale.ordinal().range([
|
|
||||||
"rgb(50%, 0%, 0%)",
|
|
||||||
"rgb(0%, 50%, 0%)",
|
|
||||||
"rgb(0%, 0%, 50%)"
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Position scales.
|
// Position scales.
|
||||||
var position = {};
|
var x = {}, y = {};
|
||||||
flower.traits.forEach(function(trait) {
|
flower.traits.forEach(function(trait) {
|
||||||
function value(d) { return d[trait]; }
|
var value = function(d) { return d[trait]; },
|
||||||
position[trait] = d3.scale.linear()
|
domain = [d3.min(flower.values, value), d3.max(flower.values, value)],
|
||||||
.domain([d3.min(flower.values, value), d3.max(flower.values, value)])
|
range = [padding / 2, size - padding / 2];
|
||||||
.range([padding / 2, size - padding / 2]);
|
x[trait] = d3.scale.linear().domain(domain).range(range);
|
||||||
|
y[trait] = d3.scale.linear().domain(domain).range(range.reverse());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Root panel.
|
// Axes.
|
||||||
var svg = d3.select("#chart")
|
var axis = d3.svg.axis()
|
||||||
.append("svg:svg")
|
.ticks(5)
|
||||||
.attr("width", size * flower.traits.length)
|
.tickSize(size * n);
|
||||||
.attr("height", size * flower.traits.length);
|
|
||||||
|
|
||||||
// One column per trait.
|
// Brush.
|
||||||
var column = svg.selectAll("g")
|
var brush = d3.svg.brush()
|
||||||
|
.on("brushstart", brushstart)
|
||||||
|
.on("brush", brush)
|
||||||
|
.on("brushend", brushend);
|
||||||
|
|
||||||
|
// Root panel.
|
||||||
|
var svg = d3.select("#chart").append("svg:svg")
|
||||||
|
.attr("width", size * n + padding)
|
||||||
|
.attr("height", size * n + padding);
|
||||||
|
|
||||||
|
// X-axis.
|
||||||
|
svg.selectAll("g.x.axis")
|
||||||
.data(flower.traits)
|
.data(flower.traits)
|
||||||
.enter().append("svg:g")
|
.enter().append("svg:g")
|
||||||
.attr("transform", function(d, i) { return "translate(" + i * size + ",0)"; });
|
.attr("class", "x axis")
|
||||||
|
.attr("transform", function(d, i) { return "translate(" + i * size + ",0)"; })
|
||||||
|
.each(function(d) { d3.select(this).call(axis.scale(x[d]).orient("bottom")); });
|
||||||
|
|
||||||
// One row per trait.
|
// Y-axis.
|
||||||
var row = column.selectAll("g")
|
svg.selectAll("g.y.axis")
|
||||||
.data(cross(flower.traits))
|
.data(flower.traits)
|
||||||
.enter().append("svg:g")
|
.enter().append("svg:g")
|
||||||
.attr("transform", function(d, i) { return "translate(0," + i * size + ")"; });
|
.attr("class", "y axis")
|
||||||
|
.attr("transform", function(d, i) { return "translate(0," + i * size + ")"; })
|
||||||
|
.each(function(d) { d3.select(this).call(axis.scale(y[d]).orient("right")); });
|
||||||
|
|
||||||
// X-ticks. TODO Cross the trait into the tick data?
|
// Cell and plot.
|
||||||
row.selectAll("line.x")
|
var cell = svg.selectAll("g.cell")
|
||||||
.data(function(d) { return position[d.x].ticks(5).map(position[d.x]); })
|
.data(cross(flower.traits, flower.traits))
|
||||||
.enter().append("svg:line")
|
.enter().append("svg:g")
|
||||||
.attr("class", "x")
|
.attr("class", "cell")
|
||||||
.attr("x1", function(d) { return d; })
|
.attr("transform", function(d) { return "translate(" + d.i * size + "," + d.j * size + ")"; })
|
||||||
.attr("x2", function(d) { return d; })
|
.each(plot);
|
||||||
.attr("y1", padding / 2)
|
|
||||||
.attr("y2", size - padding / 2);
|
|
||||||
|
|
||||||
// Y-ticks. TODO Cross the trait into the tick data?
|
// Titles for the diagonal.
|
||||||
row.selectAll("line.y")
|
cell.filter(function(d) { return d.i == d.j; }).append("svg:text")
|
||||||
.data(function(d) { return position[d.y].ticks(5).map(position[d.y]); })
|
.attr("x", padding)
|
||||||
.enter().append("svg:line")
|
.attr("y", padding)
|
||||||
.attr("class", "y")
|
.attr("dy", ".71em")
|
||||||
.attr("x1", padding / 2)
|
.text(function(d) { return d.x; });
|
||||||
.attr("x2", size - padding / 2)
|
|
||||||
.attr("y1", function(d) { return d; })
|
|
||||||
.attr("y2", function(d) { return d; });
|
|
||||||
|
|
||||||
// Frame.
|
function plot(p) {
|
||||||
row.append("svg:rect")
|
var cell = d3.select(this);
|
||||||
|
|
||||||
|
// Plot frame.
|
||||||
|
cell.append("svg:rect")
|
||||||
|
.attr("class", "frame")
|
||||||
.attr("x", padding / 2)
|
.attr("x", padding / 2)
|
||||||
.attr("y", padding / 2)
|
.attr("y", padding / 2)
|
||||||
.attr("width", size - padding)
|
.attr("width", size - padding)
|
||||||
.attr("height", size - padding)
|
.attr("height", size - padding);
|
||||||
.style("fill", "none")
|
|
||||||
.style("stroke", "#aaa")
|
|
||||||
.style("stroke-width", 1.5)
|
|
||||||
.attr("pointer-events", "all")
|
|
||||||
.on("mousedown", mousedown);
|
|
||||||
|
|
||||||
// Dot plot.
|
// Plot dots.
|
||||||
var dot = row.selectAll("circle")
|
cell.selectAll("circle")
|
||||||
.data(cross(flower.values))
|
.data(flower.values)
|
||||||
.enter().append("svg:circle")
|
.enter().append("svg:circle")
|
||||||
.attr("cx", function(d) { return position[d.x.x](d.y[d.x.x]); })
|
.attr("class", function(d) { return d.species; })
|
||||||
.attr("cy", function(d) { return size - position[d.x.y](d.y[d.x.y]); })
|
.attr("cx", function(d) { return x[p.x](d[p.x]); })
|
||||||
.attr("r", 3)
|
.attr("cy", function(d) { return y[p.y](d[p.y]); })
|
||||||
.style("fill", function(d) { return color(d.y.species); })
|
.attr("r", 3);
|
||||||
.style("fill-opacity", .5)
|
|
||||||
.attr("pointer-events", "none");
|
|
||||||
|
|
||||||
d3.select(window)
|
// Plot brush.
|
||||||
.on("mousemove", mousemove)
|
cell.call(brush.x(x[p.x]).y(y[p.y]));
|
||||||
.on("mouseup", mouseup);
|
|
||||||
|
|
||||||
var rect, x0, x1, count;
|
|
||||||
|
|
||||||
function mousedown() {
|
|
||||||
x0 = d3.svg.mouse(this);
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
rect = d3.select(this.parentNode)
|
|
||||||
.append("svg:rect")
|
|
||||||
.style("fill", "#999")
|
|
||||||
.style("fill-opacity", .5);
|
|
||||||
|
|
||||||
d3.event.preventDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mousemove() {
|
// Clear the previously-active brush, if any.
|
||||||
if (!rect) return;
|
function brushstart(p) {
|
||||||
x1 = d3.svg.mouse(rect.node());
|
if (brush.data !== p) {
|
||||||
|
cell.call(brush.clear());
|
||||||
|
brush.x(x[p.x]).y(y[p.y]).data = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
x1[0] = Math.max(padding / 2, Math.min(size - padding / 2, x1[0]));
|
// Highlight the selected circles.
|
||||||
x1[1] = Math.max(padding / 2, Math.min(size - padding / 2, x1[1]));
|
function brush(p) {
|
||||||
|
var e = brush.extent();
|
||||||
var minx = Math.min(x0[0], x1[0]),
|
svg.selectAll("circle").attr("class", function(d) {
|
||||||
maxx = Math.max(x0[0], x1[0]),
|
return e[0][0] <= d[p.x] && d[p.x] <= e[1][0]
|
||||||
miny = Math.min(x0[1], x1[1]),
|
&& e[0][1] <= d[p.y] && d[p.y] <= e[1][1]
|
||||||
maxy = Math.max(x0[1], x1[1]);
|
? d.species : null;
|
||||||
|
|
||||||
rect
|
|
||||||
.attr("x", minx - .5)
|
|
||||||
.attr("y", miny - .5)
|
|
||||||
.attr("width", maxx - minx + 1)
|
|
||||||
.attr("height", maxy - miny + 1);
|
|
||||||
|
|
||||||
var v = rect.node().__data__,
|
|
||||||
x = position[v.x],
|
|
||||||
y = position[v.y],
|
|
||||||
mins = x.invert(minx),
|
|
||||||
maxs = x.invert(maxx),
|
|
||||||
mint = y.invert(size - maxy),
|
|
||||||
maxt = y.invert(size - miny);
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
svg.selectAll("circle")
|
|
||||||
.style("fill", function(d) {
|
|
||||||
return mins <= d.y[v.x] && maxs >= d.y[v.x]
|
|
||||||
&& mint <= d.y[v.y] && maxt >= d.y[v.y]
|
|
||||||
? (count++, color(d.y.species))
|
|
||||||
: "#ccc";
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function mouseup() {
|
// If the brush is empty, select all circles.
|
||||||
if (!rect) return;
|
function brushend() {
|
||||||
rect.remove();
|
if (brush.empty()) svg.selectAll("circle").attr("class", function(d) {
|
||||||
rect = null;
|
return d.species;
|
||||||
|
|
||||||
if (!count) svg.selectAll("circle")
|
|
||||||
.style("fill", function(d) {
|
|
||||||
return color(d.y.species);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cross(a, b) {
|
||||||
|
var c = [], n = a.length, m = b.length, i, j;
|
||||||
|
for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j});
|
||||||
|
return c;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||||||
|
<title>Transform Test</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
th, td { border: solid #ccc 1px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var outcome = d3.select("body").append("p");
|
||||||
|
|
||||||
|
var g = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", 10)
|
||||||
|
.attr("height", 10)
|
||||||
|
.append("svg:g");
|
||||||
|
|
||||||
|
var results = d3.select("body").append("table")
|
||||||
|
.style("display", "none");
|
||||||
|
results.append("tr").selectAll("th")
|
||||||
|
.data(["Expected", "Actual", "Expected matrix", "Actual matrix"])
|
||||||
|
.enter().append("th").text(String);
|
||||||
|
|
||||||
|
var el = g[0][0],
|
||||||
|
v,
|
||||||
|
m,
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
failures = 0;
|
||||||
|
|
||||||
|
for (var tx = -10; tx <= 10; tx += 5) {
|
||||||
|
for (var ty = -10; ty <= 10; ty += 5) {
|
||||||
|
for (var r = -180; r <= 180; r += 15) {
|
||||||
|
for (var skx = -45; skx <= 45; skx += 45) {
|
||||||
|
for (var sx = -2; sx <= 2; sx++) {
|
||||||
|
for (var sy = -2; sy <= 2; sy++) {
|
||||||
|
v = "translate(" + tx + "," + ty + ")rotate(" + r + ")skewX(" + skx + ")scale(" + sx + "," + sy + ")";
|
||||||
|
g.attr("transform", v);
|
||||||
|
a = matrix(el);
|
||||||
|
g.attr("transform", d3.transform(v));
|
||||||
|
b = matrix(el);
|
||||||
|
if (!deepEqual(a, b, 1e-6)) {
|
||||||
|
failures++;
|
||||||
|
results
|
||||||
|
.style("display", null)
|
||||||
|
.append("tr").selectAll("td")
|
||||||
|
.data([v, d3.transform(v), a, b])
|
||||||
|
.enter().append("td").text(String);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outcome.text(failures ? failures + " failures" : "Success!");
|
||||||
|
|
||||||
|
function matrix(el) {
|
||||||
|
var t = el.transform.baseVal.consolidate();
|
||||||
|
if (t) {
|
||||||
|
var m = t.matrix;
|
||||||
|
return [m.a, m.b, m.c, m.d, m.e, m.f];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepEqual(actual, expected, epsilon) {
|
||||||
|
epsilon = epsilon || 0;
|
||||||
|
if (actual === expected) return true;
|
||||||
|
if (actual == null || expected == null) return false;
|
||||||
|
if (actual.length !== expected.length) return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < actual.length; i++) {
|
||||||
|
if (Math.abs(actual[i] - expected[i]) > epsilon) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||||||
|
<title>Transform Transitions</title>
|
||||||
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect {
|
||||||
|
stroke: #fff;
|
||||||
|
stroke-width: .05px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var w = 960,
|
||||||
|
h = 500,
|
||||||
|
z = 20,
|
||||||
|
x = w / z,
|
||||||
|
y = h / z;
|
||||||
|
|
||||||
|
var svg = d3.select("body").append("svg:svg")
|
||||||
|
.attr("width", w)
|
||||||
|
.attr("height", h);
|
||||||
|
|
||||||
|
svg.selectAll("rect")
|
||||||
|
.data(d3.range(x * y))
|
||||||
|
.enter().append("svg:rect")
|
||||||
|
.attr("transform", translate)
|
||||||
|
.attr("width", z)
|
||||||
|
.attr("height", z)
|
||||||
|
.style("fill", d3.scale.linear().domain([0, x * y]).range(["brown", "steelblue"]))
|
||||||
|
.on("mouseover", mouseover);
|
||||||
|
|
||||||
|
function translate(d) {
|
||||||
|
return "translate(" + (d % x) * z + "," + Math.floor(d / x) * z + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseover(d) {
|
||||||
|
this.parentNode.appendChild(this);
|
||||||
|
d3.select(this).transition()
|
||||||
|
.duration(750)
|
||||||
|
.attr("transform", "translate(480,480)scale(23)rotate(180)")
|
||||||
|
.transition()
|
||||||
|
.delay(1500)
|
||||||
|
.attr("transform", "translate(240,240)scale(0)rotate(180)")
|
||||||
|
.style("fill-opacity", 0)
|
||||||
|
.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -7,13 +7,17 @@
|
||||||
<script type="text/javascript" src="../../d3.layout.js"></script>
|
<script type="text/javascript" src="../../d3.layout.js"></script>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
circle.node {
|
.node circle {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
stroke: steelblue;
|
stroke: steelblue;
|
||||||
stroke-width: 1.5px;
|
stroke-width: 1.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.node text {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
path.link {
|
path.link {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: #ccc;
|
stroke: #ccc;
|
||||||
|
@ -26,28 +30,40 @@ path.link {
|
||||||
<div id="chart"></div>
|
<div id="chart"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
var w = 960,
|
var m = [20, 120, 20, 120],
|
||||||
h = 2000,
|
w = 1280 - m[1] - m[3],
|
||||||
|
h = 800 - m[0] - m[2],
|
||||||
i = 0,
|
i = 0,
|
||||||
duration = 500,
|
duration = 500,
|
||||||
root;
|
root;
|
||||||
|
|
||||||
var tree = d3.layout.tree()
|
var tree = d3.layout.tree()
|
||||||
.size([h, w - 160]);
|
.size([h, w]);
|
||||||
|
|
||||||
var diagonal = d3.svg.diagonal()
|
var diagonal = d3.svg.diagonal()
|
||||||
.projection(function(d) { return [d.y, d.x]; });
|
.projection(function(d) { return [d.y, d.x]; });
|
||||||
|
|
||||||
var vis = d3.select("#chart").append("svg:svg")
|
var vis = d3.select("#chart").append("svg:svg")
|
||||||
.attr("width", w)
|
.attr("width", w + m[1] + m[3])
|
||||||
.attr("height", h)
|
.attr("height", h + m[0] + m[2])
|
||||||
.append("svg:g")
|
.append("svg:g")
|
||||||
.attr("transform", "translate(40,0)");
|
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
|
||||||
|
|
||||||
d3.json("../data/flare.json", function(json) {
|
d3.json("../data/flare.json", function(json) {
|
||||||
json.x0 = 800;
|
root = json;
|
||||||
json.y0 = 0;
|
root.x0 = h / 2;
|
||||||
update(root = json);
|
root.y0 = 0;
|
||||||
|
|
||||||
|
function collapse(d) {
|
||||||
|
if (d.children) {
|
||||||
|
d._children = d.children;
|
||||||
|
d._children.forEach(collapse);
|
||||||
|
d.children = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root.children.forEach(collapse);
|
||||||
|
update(root);
|
||||||
});
|
});
|
||||||
|
|
||||||
function update(source) {
|
function update(source) {
|
||||||
|
@ -55,43 +71,60 @@ function update(source) {
|
||||||
// Compute the new tree layout.
|
// Compute the new tree layout.
|
||||||
var nodes = tree.nodes(root).reverse();
|
var nodes = tree.nodes(root).reverse();
|
||||||
|
|
||||||
|
// Normalize for fixed-depth.
|
||||||
|
nodes.forEach(function(d) { d.y = d.depth * 180; });
|
||||||
|
|
||||||
// Update the nodes…
|
// Update the nodes…
|
||||||
var node = vis.selectAll("circle.node")
|
var node = vis.selectAll("g.node")
|
||||||
.data(nodes, function(d) { return d.id || (d.id = ++i); });
|
.data(nodes, function(d) { return d.id || (d.id = ++i); });
|
||||||
|
|
||||||
// Enter any new nodes at the parent's previous position.
|
// Enter any new nodes at the parent's previous position.
|
||||||
node.enter().append("svg:circle")
|
var nodeEnter = node.enter().append("svg:g")
|
||||||
.attr("class", "node")
|
.attr("class", "node")
|
||||||
.attr("cx", function(d) { return source.y0; })
|
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
|
||||||
.attr("cy", function(d) { return source.x0; })
|
.on("click", click);
|
||||||
.attr("r", 4.5)
|
|
||||||
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; })
|
|
||||||
.on("click", click)
|
|
||||||
.transition()
|
|
||||||
.duration(duration)
|
|
||||||
.attr("cx", function(d) { return d.y; })
|
|
||||||
.attr("cy", function(d) { return d.x; });
|
|
||||||
|
|
||||||
// Transition nodes to their new position.
|
nodeEnter.append("svg:circle")
|
||||||
node.transition()
|
.attr("r", 1e-6)
|
||||||
.duration(duration)
|
|
||||||
.attr("cx", function(d) { return d.y; })
|
|
||||||
.attr("cy", function(d) { return d.x; })
|
|
||||||
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
|
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
|
||||||
|
|
||||||
// Transition exiting nodes to the parent's new position.
|
nodeEnter.append("svg:text")
|
||||||
node.exit().transition()
|
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
|
||||||
|
.attr("dy", ".35em")
|
||||||
|
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
|
||||||
|
.text(function(d) { return d.name; })
|
||||||
|
.style("fill-opacity", 1e-6);
|
||||||
|
|
||||||
|
// Transition nodes to their new position.
|
||||||
|
var nodeUpdate = node.transition()
|
||||||
.duration(duration)
|
.duration(duration)
|
||||||
.attr("cx", function(d) { return source.y; })
|
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
|
||||||
.attr("cy", function(d) { return source.x; })
|
|
||||||
|
nodeUpdate.select("circle")
|
||||||
|
.attr("r", 4.5)
|
||||||
|
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
|
||||||
|
|
||||||
|
nodeUpdate.select("text")
|
||||||
|
.style("fill-opacity", 1);
|
||||||
|
|
||||||
|
// Transition exiting nodes to the parent's new position.
|
||||||
|
var nodeExit = node.exit().transition()
|
||||||
|
.duration(duration)
|
||||||
|
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
|
||||||
.remove();
|
.remove();
|
||||||
|
|
||||||
|
nodeExit.select("circle")
|
||||||
|
.attr("r", 1e-6);
|
||||||
|
|
||||||
|
nodeExit.select("text")
|
||||||
|
.style("fill-opacity", 1e-6);
|
||||||
|
|
||||||
// Update the links…
|
// Update the links…
|
||||||
var link = vis.selectAll("path.link")
|
var link = vis.selectAll("path.link")
|
||||||
.data(tree.links(nodes), function(d) { return d.target.id; });
|
.data(tree.links(nodes), function(d) { return d.target.id; });
|
||||||
|
|
||||||
// Enter any new links at the parent's previous position.
|
// Enter any new links at the parent's previous position.
|
||||||
link.enter().insert("svg:path", "circle")
|
link.enter().insert("svg:path", "g")
|
||||||
.attr("class", "link")
|
.attr("class", "link")
|
||||||
.attr("d", function(d) {
|
.attr("d", function(d) {
|
||||||
var o = {x: source.x0, y: source.y0};
|
var o = {x: source.x0, y: source.y0};
|
||||||
|
|
|
@ -8,8 +8,8 @@ var treemap = d3.layout.treemap()
|
||||||
.value(function(d) { return d.size; });
|
.value(function(d) { return d.size; });
|
||||||
|
|
||||||
var svg = d3.select("body").append("svg:svg")
|
var svg = d3.select("body").append("svg:svg")
|
||||||
.style("width", w)
|
.attr("width", w)
|
||||||
.style("height", h)
|
.attr("height", h)
|
||||||
.append("svg:g")
|
.append("svg:g")
|
||||||
.attr("transform", "translate(-.5,-.5)");
|
.attr("transform", "translate(-.5,-.5)");
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<title>Zoom + Pan</title>
|
<title>Zoom + Pan</title>
|
||||||
<script type="text/javascript" src="../../d3.js"></script>
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
<script type="text/javascript" src="../../d3.behavior.js"></script>
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
@ -39,7 +38,9 @@ var svg = d3.select("body").append("svg:svg")
|
||||||
.attr("pointer-events", "all")
|
.attr("pointer-events", "all")
|
||||||
.append("svg:g")
|
.append("svg:g")
|
||||||
.attr("transform", "translate(" + padding[3] + "," + padding[0] + ")")
|
.attr("transform", "translate(" + padding[3] + "," + padding[0] + ")")
|
||||||
.call(d3.behavior.zoom().on("zoom", redraw))
|
.call(d3.behavior.zoom()
|
||||||
|
.extent([[0, size[0]], [0, size[1]], [0, Infinity]])
|
||||||
|
.on("zoom", redraw))
|
||||||
.append("svg:g");
|
.append("svg:g");
|
||||||
|
|
||||||
// Generate x-ticks…
|
// Generate x-ticks…
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<title>Zoom + Pan</title>
|
<title>Zoom + Pan</title>
|
||||||
<script type="text/javascript" src="../../d3.js"></script>
|
<script type="text/javascript" src="../../d3.js"></script>
|
||||||
<script type="text/javascript" src="../../d3.behavior.js"></script>
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
@ -39,7 +38,9 @@ var svg = d3.select("body").append("svg:svg")
|
||||||
.attr("pointer-events", "all")
|
.attr("pointer-events", "all")
|
||||||
.append("svg:g")
|
.append("svg:g")
|
||||||
.attr("transform", "translate(" + padding[3] + "," + padding[0] + ")")
|
.attr("transform", "translate(" + padding[3] + "," + padding[0] + ")")
|
||||||
.call(d3.behavior.zoom().on("zoom", redraw));
|
.call(d3.behavior.zoom()
|
||||||
|
.extent([[0, size[0]], [0, size[1]], [0, 3]])
|
||||||
|
.on("zoom", redraw));
|
||||||
|
|
||||||
svg.append("svg:rect")
|
svg.append("svg:rect")
|
||||||
.attr("width", size[0])
|
.attr("width", size[0])
|
||||||
|
|
|
@ -1,5 +1,225 @@
|
||||||
(function(){science = {version: "0.0.1"}; // semver
|
(function(){science = {version: "1.7.0"}; // semver
|
||||||
|
science.ascending = function(a, b) {
|
||||||
|
return a - b;
|
||||||
|
};
|
||||||
|
// Euler's constant.
|
||||||
|
science.EULER = .5772156649015329;
|
||||||
|
// Compute exp(x) - 1 accurately for small x.
|
||||||
|
science.expm1 = function(x) {
|
||||||
|
return (x < 1e-5 && x > -1e-5) ? x + .5 * x * x : Math.exp(x) - 1;
|
||||||
|
};
|
||||||
science.functor = function(v) {
|
science.functor = function(v) {
|
||||||
return typeof v === "function" ? v : function() { return v; };
|
return typeof v === "function" ? v : function() { return v; };
|
||||||
};
|
};
|
||||||
|
// Based on:
|
||||||
|
// http://www.johndcook.com/blog/2010/06/02/whats-so-hard-about-finding-a-hypotenuse/
|
||||||
|
science.hypot = function(x, y) {
|
||||||
|
x = Math.abs(x);
|
||||||
|
y = Math.abs(y);
|
||||||
|
var max,
|
||||||
|
min;
|
||||||
|
if (x > y) { max = x; min = y; }
|
||||||
|
else { max = y; min = x; }
|
||||||
|
var r = min / max;
|
||||||
|
return max * Math.sqrt(1 + r * r);
|
||||||
|
};
|
||||||
|
science.quadratic = function() {
|
||||||
|
var complex = false;
|
||||||
|
|
||||||
|
function quadratic(a, b, c) {
|
||||||
|
var d = b * b - 4 * a * c;
|
||||||
|
if (d > 0) {
|
||||||
|
d = Math.sqrt(d) / (2 * a);
|
||||||
|
return complex
|
||||||
|
? [{r: -b - d, i: 0}, {r: -b + d, i: 0}]
|
||||||
|
: [-b - d, -b + d];
|
||||||
|
} else if (d === 0) {
|
||||||
|
d = -b / (2 * a);
|
||||||
|
return complex ? [{r: d, i: 0}] : [d];
|
||||||
|
} else {
|
||||||
|
if (complex) {
|
||||||
|
d = Math.sqrt(-d) / (2 * a);
|
||||||
|
return [
|
||||||
|
{r: -b, i: -d},
|
||||||
|
{r: -b, i: d}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quadratic.complex = function(x) {
|
||||||
|
if (!arguments.length) return complex;
|
||||||
|
complex = x;
|
||||||
|
return quadratic;
|
||||||
|
};
|
||||||
|
|
||||||
|
return quadratic;
|
||||||
|
};
|
||||||
|
// Constructs a multi-dimensional array filled with zeroes.
|
||||||
|
science.zeroes = function(n) {
|
||||||
|
var i = -1,
|
||||||
|
a = [];
|
||||||
|
if (arguments.length === 1)
|
||||||
|
while (++i < n)
|
||||||
|
a[i] = 0;
|
||||||
|
else
|
||||||
|
while (++i < n)
|
||||||
|
a[i] = science.zeroes.apply(
|
||||||
|
this, Array.prototype.slice.call(arguments, 1));
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
science.vector = {};
|
||||||
|
science.vector.cross = function(a, b) {
|
||||||
|
// TODO how to handle non-3D vectors?
|
||||||
|
// TODO handle 7D vectors?
|
||||||
|
return [
|
||||||
|
a[1] * b[2] - a[2] * b[1],
|
||||||
|
a[2] * b[0] - a[0] * b[2],
|
||||||
|
a[0] * b[1] - a[1] * b[0]
|
||||||
|
];
|
||||||
|
};
|
||||||
|
science.vector.dot = function(a, b) {
|
||||||
|
var s = 0,
|
||||||
|
i = -1,
|
||||||
|
n = Math.min(a.length, b.length);
|
||||||
|
while (++i < n) s += a[i] * b[i];
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
science.vector.length = function(p) {
|
||||||
|
return Math.sqrt(science.vector.dot(p, p));
|
||||||
|
};
|
||||||
|
science.vector.normalize = function(p) {
|
||||||
|
var length = science.vector.length(p);
|
||||||
|
return p.map(function(d) { return d / length; });
|
||||||
|
};
|
||||||
|
// 4x4 matrix determinant.
|
||||||
|
science.vector.determinant = function(matrix) {
|
||||||
|
var m = matrix[0].concat(matrix[1]).concat(matrix[2]).concat(matrix[3]);
|
||||||
|
return (
|
||||||
|
m[12] * m[9] * m[6] * m[3] - m[8] * m[13] * m[6] * m[3] -
|
||||||
|
m[12] * m[5] * m[10] * m[3] + m[4] * m[13] * m[10] * m[3] +
|
||||||
|
m[8] * m[5] * m[14] * m[3] - m[4] * m[9] * m[14] * m[3] -
|
||||||
|
m[12] * m[9] * m[2] * m[7] + m[8] * m[13] * m[2] * m[7] +
|
||||||
|
m[12] * m[1] * m[10] * m[7] - m[0] * m[13] * m[10] * m[7] -
|
||||||
|
m[8] * m[1] * m[14] * m[7] + m[0] * m[9] * m[14] * m[7] +
|
||||||
|
m[12] * m[5] * m[2] * m[11] - m[4] * m[13] * m[2] * m[11] -
|
||||||
|
m[12] * m[1] * m[6] * m[11] + m[0] * m[13] * m[6] * m[11] +
|
||||||
|
m[4] * m[1] * m[14] * m[11] - m[0] * m[5] * m[14] * m[11] -
|
||||||
|
m[8] * m[5] * m[2] * m[15] + m[4] * m[9] * m[2] * m[15] +
|
||||||
|
m[8] * m[1] * m[6] * m[15] - m[0] * m[9] * m[6] * m[15] -
|
||||||
|
m[4] * m[1] * m[10] * m[15] + m[0] * m[5] * m[10] * m[15]);
|
||||||
|
};
|
||||||
|
// Performs in-place Gauss-Jordan elimination.
|
||||||
|
//
|
||||||
|
// Based on Jarno Elonen's Python version (public domain):
|
||||||
|
// http://elonen.iki.fi/code/misc-notes/python-gaussj/index.html
|
||||||
|
science.vector.gaussjordan = function(m, eps) {
|
||||||
|
if (!eps) eps = 1e-10;
|
||||||
|
|
||||||
|
var h = m.length,
|
||||||
|
w = m[0].length,
|
||||||
|
y = -1,
|
||||||
|
y2,
|
||||||
|
x;
|
||||||
|
|
||||||
|
while (++y < h) {
|
||||||
|
var maxrow = y;
|
||||||
|
|
||||||
|
// Find max pivot.
|
||||||
|
y2 = y; while (++y2 < h) {
|
||||||
|
if (Math.abs(m[y2][y]) > Math.abs(m[maxrow][y]))
|
||||||
|
maxrow = y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap.
|
||||||
|
var tmp = m[y];
|
||||||
|
m[y] = m[maxrow];
|
||||||
|
m[maxrow] = tmp;
|
||||||
|
|
||||||
|
// Singular?
|
||||||
|
if (Math.abs(m[y][y]) <= eps) return false;
|
||||||
|
|
||||||
|
// Eliminate column y.
|
||||||
|
y2 = y; while (++y2 < h) {
|
||||||
|
var c = m[y2][y] / m[y][y];
|
||||||
|
x = y - 1; while (++x < w) {
|
||||||
|
m[y2][x] -= m[y][x] * c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backsubstitute.
|
||||||
|
y = h; while (--y >= 0) {
|
||||||
|
var c = m[y][y];
|
||||||
|
y2 = -1; while (++y2 < y) {
|
||||||
|
x = w; while (--x >= y) {
|
||||||
|
m[y2][x] -= m[y][x] * m[y2][y] / c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m[y][y] /= c;
|
||||||
|
// Normalize row y.
|
||||||
|
x = h - 1; while (++x < w) {
|
||||||
|
m[y][x] /= c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
// Find matrix inverse using Gauss-Jordan.
|
||||||
|
science.vector.inverse = function(m) {
|
||||||
|
var n = m.length
|
||||||
|
i = -1;
|
||||||
|
|
||||||
|
// Check if the matrix is square.
|
||||||
|
if (n !== m[0].length) return;
|
||||||
|
|
||||||
|
// Augment with identity matrix I to get AI.
|
||||||
|
m = m.map(function(row, i) {
|
||||||
|
var identity = new Array(n),
|
||||||
|
j = -1;
|
||||||
|
while (++j < n) identity[j] = i === j ? 1 : 0;
|
||||||
|
return row.concat(identity);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compute IA^-1.
|
||||||
|
science.vector.gaussjordan(m);
|
||||||
|
|
||||||
|
// Remove identity matrix I to get A^-1.
|
||||||
|
while (++i < n) {
|
||||||
|
m[i] = m[i].slice(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
};
|
||||||
|
science.vector.multiply = function(a, b) {
|
||||||
|
var m = a.length,
|
||||||
|
n = b[0].length,
|
||||||
|
p = b.length,
|
||||||
|
i = -1,
|
||||||
|
j,
|
||||||
|
k;
|
||||||
|
if (p !== a[0].length) throw {"error": "columns(a) != rows(b); " + a[0].length + " != " + p};
|
||||||
|
var ab = new Array(m);
|
||||||
|
while (++i < m) {
|
||||||
|
ab[i] = new Array(n);
|
||||||
|
j = -1; while(++j < n) {
|
||||||
|
var s = 0;
|
||||||
|
k = -1; while (++k < p) s += a[i][k] * b[k][j];
|
||||||
|
ab[i][j] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ab;
|
||||||
|
};
|
||||||
|
science.vector.transpose = function(a) {
|
||||||
|
var m = a.length,
|
||||||
|
n = a[0].length,
|
||||||
|
i = -1,
|
||||||
|
j,
|
||||||
|
b = new Array(n);
|
||||||
|
while (++i < n) {
|
||||||
|
b[i] = new Array(m);
|
||||||
|
j = -1; while (++j < m) b[i][j] = a[j][i];
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
};
|
||||||
})()
|
})()
|
|
@ -0,0 +1,27 @@
|
||||||
|
(function(){science.lin = {};
|
||||||
|
/**
|
||||||
|
* Solves tridiagonal systems of linear equations.
|
||||||
|
*
|
||||||
|
* Source: http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm
|
||||||
|
*
|
||||||
|
* @param {number[]} a
|
||||||
|
* @param {number[]} b
|
||||||
|
* @param {number[]} c
|
||||||
|
* @param {number[]} d
|
||||||
|
* @param {number[]} x
|
||||||
|
* @param {number} n
|
||||||
|
*/
|
||||||
|
science.lin.tridag = function(a, b, c, d, x, n) {
|
||||||
|
var i,
|
||||||
|
m;
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
m = a[i] / b[i - 1];
|
||||||
|
b[i] -= m * c[i - 1];
|
||||||
|
d[i] -= m * d[i - 1];
|
||||||
|
}
|
||||||
|
x[n - 1] = d[n - 1] / b[n - 1];
|
||||||
|
for (i = n - 2; i >= 0; i--) {
|
||||||
|
x[i] = (d[i] - c[i] * x[i + 1]) / b[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})()
|
|
@ -0,0 +1 @@
|
||||||
|
(function(){science.lin={},science.lin.tridag=function(a,b,c,d,e,f){var g,h;for(g=1;g<f;g++)h=a[g]/b[g-1],b[g]-=h*c[g-1],d[g]-=h*d[g-1];e[f-1]=d[f-1]/b[f-1];for(g=f-2;g>=0;g--)e[g]=(d[g]-c[g]*e[g+1])/b[g]}})()
|
|
@ -1 +1 @@
|
||||||
(function(){science={version:"0.0.1"},science.functor=function(a){return typeof a=="function"?a:function(){return a}}})()
|
(function(){science={version:"1.7.0"},science.ascending=function(a,b){return a-b},science.EULER=.5772156649015329,science.expm1=function(a){return a<1e-5&&a>-0.00001?a+.5*a*a:Math.exp(a)-1},science.functor=function(a){return typeof a=="function"?a:function(){return a}},science.hypot=function(a,b){a=Math.abs(a),b=Math.abs(b);var c,d;a>b?(c=a,d=b):(c=b,d=a);var e=d/c;return c*Math.sqrt(1+e*e)},science.quadratic=function(){function b(b,c,d){var e=c*c-4*b*d;if(e>0){e=Math.sqrt(e)/(2*b);return a?[{r:-c-e,i:0},{r:-c+e,i:0}]:[-c-e,-c+e]}if(e===0){e=-c/(2*b);return a?[{r:e,i:0}]:[e]}if(a){e=Math.sqrt(-e)/(2*b);return[{r:-c,i:-e},{r:-c,i:e}]}return[]}var a=!1;b.complex=function(c){if(!arguments.length)return a;a=c;return b};return b},science.zeroes=function(a){var b=-1,c=[];if(arguments.length===1)while(++b<a)c[b]=0;else while(++b<a)c[b]=science.zeroes.apply(this,Array.prototype.slice.call(arguments,1));return c},science.vector={},science.vector.cross=function(a,b){return[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]},science.vector.dot=function(a,b){var c=0,d=-1,e=Math.min(a.length,b.length);while(++d<e)c+=a[d]*b[d];return c},science.vector.length=function(a){return Math.sqrt(science.vector.dot(a,a))},science.vector.normalize=function(a){var b=science.vector.length(a);return a.map(function(a){return a/b})},science.vector.determinant=function(a){var b=a[0].concat(a[1]).concat(a[2]).concat(a[3]);return b[12]*b[9]*b[6]*b[3]-b[8]*b[13]*b[6]*b[3]-b[12]*b[5]*b[10]*b[3]+b[4]*b[13]*b[10]*b[3]+b[8]*b[5]*b[14]*b[3]-b[4]*b[9]*b[14]*b[3]-b[12]*b[9]*b[2]*b[7]+b[8]*b[13]*b[2]*b[7]+b[12]*b[1]*b[10]*b[7]-b[0]*b[13]*b[10]*b[7]-b[8]*b[1]*b[14]*b[7]+b[0]*b[9]*b[14]*b[7]+b[12]*b[5]*b[2]*b[11]-b[4]*b[13]*b[2]*b[11]-b[12]*b[1]*b[6]*b[11]+b[0]*b[13]*b[6]*b[11]+b[4]*b[1]*b[14]*b[11]-b[0]*b[5]*b[14]*b[11]-b[8]*b[5]*b[2]*b[15]+b[4]*b[9]*b[2]*b[15]+b[8]*b[1]*b[6]*b[15]-b[0]*b[9]*b[6]*b[15]-b[4]*b[1]*b[10]*b[15]+b[0]*b[5]*b[10]*b[15]},science.vector.gaussjordan=function(a,b){b||(b=1e-10);var c=a.length,d=a[0].length,e=-1,f,g;while(++e<c){var h=e;f=e;while(++f<c)Math.abs(a[f][e])>Math.abs(a[h][e])&&(h=f);var i=a[e];a[e]=a[h],a[h]=i;if(Math.abs(a[e][e])<=b)return!1;f=e;while(++f<c){var j=a[f][e]/a[e][e];g=e-1;while(++g<d)a[f][g]-=a[e][g]*j}}e=c;while(--e>=0){var j=a[e][e];f=-1;while(++f<e){g=d;while(--g>=e)a[f][g]-=a[e][g]*a[f][e]/j}a[e][e]/=j,g=c-1;while(++g<d)a[e][g]/=j}return!0},science.vector.inverse=function(a){var b=a.length;i=-1;if(b===a[0].length){a=a.map(function(a,c){var d=Array(b),e=-1;while(++e<b)d[e]=c===e?1:0;return a.concat(d)}),science.vector.gaussjordan(a);while(++i<b)a[i]=a[i].slice(b);return a}},science.vector.multiply=function(a,b){var c=a.length,d=b[0].length,e=b.length,f=-1,g,h;if(e!==a[0].length)throw{error:"columns(a) != rows(b); "+a[0].length+" != "+e};var i=Array(c);while(++f<c){i[f]=Array(d),g=-1;while(++g<d){var j=0;h=-1;while(++h<e)j+=a[f][h]*b[h][g];i[f][g]=j}}return i},science.vector.transpose=function(a){var b=a.length,c=a[0].length,d=-1,e,f=Array(c);while(++d<c){f[d]=Array(b),e=-1;while(++e<b)f[d][e]=a[e][d]}return f}})()
|
|
@ -19,6 +19,100 @@ science.stats.bandwidth = {
|
||||||
* Math.pow(x.length, -1/5);
|
* Math.pow(x.length, -1/5);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
science.stats.distance = {
|
||||||
|
euclidean: function(a, b) {
|
||||||
|
var n = a.length,
|
||||||
|
i = -1,
|
||||||
|
s = 0,
|
||||||
|
x;
|
||||||
|
while (++i < n) {
|
||||||
|
x = a[i] - b[i];
|
||||||
|
s += x * x;
|
||||||
|
}
|
||||||
|
return Math.sqrt(s);
|
||||||
|
},
|
||||||
|
manhattan: function(a, b) {
|
||||||
|
var n = a.length,
|
||||||
|
i = -1,
|
||||||
|
s = 0;
|
||||||
|
while (++i < n) s += Math.abs(a[i] - b[i]);
|
||||||
|
return s;
|
||||||
|
},
|
||||||
|
minkowski: function(p) {
|
||||||
|
return function(a, b) {
|
||||||
|
var n = a.length,
|
||||||
|
i = -1,
|
||||||
|
s = 0;
|
||||||
|
while (++i < n) s += Math.pow(Math.abs(a[i] - b[i]), p);
|
||||||
|
return Math.pow(s, 1 / p);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
chebyshev: function(a, b) {
|
||||||
|
var n = a.length,
|
||||||
|
i = -1,
|
||||||
|
max = 0,
|
||||||
|
x;
|
||||||
|
while (++i < n) {
|
||||||
|
x = Math.abs(a[i] - b[i]);
|
||||||
|
if (x > max) max = x;
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
},
|
||||||
|
hamming: function(a, b) {
|
||||||
|
var n = a.length,
|
||||||
|
i = -1,
|
||||||
|
d = 0;
|
||||||
|
while (++i < n) if (a[i] !== b[i]) d++;
|
||||||
|
return d;
|
||||||
|
},
|
||||||
|
jaccard: function(a, b) {
|
||||||
|
var n = a.length,
|
||||||
|
i = -1,
|
||||||
|
s = 0;
|
||||||
|
while (++i < n) if (a[i] === b[i]) s++;
|
||||||
|
return s / n;
|
||||||
|
},
|
||||||
|
braycurtis: function(a, b) {
|
||||||
|
var n = a.length,
|
||||||
|
i = -1,
|
||||||
|
s0 = 0,
|
||||||
|
s1 = 0,
|
||||||
|
ai,
|
||||||
|
bi;
|
||||||
|
while (++i < n) {
|
||||||
|
ai = a[i];
|
||||||
|
bi = b[i];
|
||||||
|
s0 += Math.abs(ai - bi);
|
||||||
|
s1 += Math.abs(ai + bi);
|
||||||
|
}
|
||||||
|
return s0 / s1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Based on implementation in http://picomath.org/.
|
||||||
|
science.stats.erf = function(x) {
|
||||||
|
var a1 = 0.254829592,
|
||||||
|
a2 = -0.284496736,
|
||||||
|
a3 = 1.421413741,
|
||||||
|
a4 = -1.453152027,
|
||||||
|
a5 = 1.061405429,
|
||||||
|
p = 0.3275911;
|
||||||
|
|
||||||
|
// Save the sign of x
|
||||||
|
var sign = x < 0 ? -1 : 1;
|
||||||
|
if (x < 0) {
|
||||||
|
sign = -1;
|
||||||
|
x = -x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A&S formula 7.1.26
|
||||||
|
var t = 1 / (1 + p * x);
|
||||||
|
return sign * (
|
||||||
|
1 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1)
|
||||||
|
* t * Math.exp(-x * x));
|
||||||
|
};
|
||||||
|
science.stats.phi = function(x) {
|
||||||
|
return .5 * (1 + science.stats.erf(x / Math.SQRT2));
|
||||||
|
};
|
||||||
// See <http://en.wikipedia.org/wiki/Kernel_(statistics)>.
|
// See <http://en.wikipedia.org/wiki/Kernel_(statistics)>.
|
||||||
science.stats.kernel = {
|
science.stats.kernel = {
|
||||||
uniform: function(u) {
|
uniform: function(u) {
|
||||||
|
@ -94,10 +188,470 @@ science.stats.kde = function() {
|
||||||
|
|
||||||
return kde;
|
return kde;
|
||||||
};
|
};
|
||||||
|
// Based on figue implementation by Jean-Yves Delort.
|
||||||
|
// http://code.google.com/p/figue/
|
||||||
|
science.stats.kmeans = function() {
|
||||||
|
var distance = science.stats.distance.euclidean,
|
||||||
|
maxIterations = 1000,
|
||||||
|
k = 1;
|
||||||
|
|
||||||
|
function kmeans(vectors) {
|
||||||
|
var n = vectors.length,
|
||||||
|
assignments = [],
|
||||||
|
clusterSizes = [],
|
||||||
|
repeat = 1,
|
||||||
|
iterations = 0,
|
||||||
|
centroids = science_stats_kmeansRandom(k, vectors),
|
||||||
|
newCentroids,
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
x,
|
||||||
|
d,
|
||||||
|
min,
|
||||||
|
best;
|
||||||
|
|
||||||
|
while (repeat && iterations < maxIterations) {
|
||||||
|
// Assignment step.
|
||||||
|
j = -1; while (++j < k) {
|
||||||
|
clusterSizes[j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = -1; while (++i < n) {
|
||||||
|
x = vectors[i];
|
||||||
|
min = Infinity;
|
||||||
|
j = -1; while (++j < k) {
|
||||||
|
d = distance.call(this, centroids[j], x);
|
||||||
|
if (d < min) {
|
||||||
|
min = d;
|
||||||
|
best = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clusterSizes[assignments[i] = best]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update centroids step.
|
||||||
|
newCentroids = [];
|
||||||
|
i = -1; while (++i < n) {
|
||||||
|
x = assignments[i];
|
||||||
|
d = newCentroids[x];
|
||||||
|
if (d == null) newCentroids[x] = vectors[i].slice();
|
||||||
|
else {
|
||||||
|
j = -1; while (++j < d.length) {
|
||||||
|
d[j] += vectors[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = -1; while (++j < k) {
|
||||||
|
x = newCentroids[j];
|
||||||
|
d = 1 / clusterSizes[j];
|
||||||
|
i = -1; while (++i < x.length) x[i] *= d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check convergence.
|
||||||
|
repeat = 0;
|
||||||
|
j = -1; while (++j < k) {
|
||||||
|
if (!science_stats_kmeansCompare(newCentroids[j], centroids[j])) {
|
||||||
|
repeat = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
centroids = newCentroids;
|
||||||
|
iterations++;
|
||||||
|
}
|
||||||
|
return {assignments: assignments, centroids: centroids};
|
||||||
|
}
|
||||||
|
|
||||||
|
kmeans.k = function(x) {
|
||||||
|
if (!arguments.length) return k;
|
||||||
|
k = x;
|
||||||
|
return kmeans;
|
||||||
|
};
|
||||||
|
|
||||||
|
kmeans.distance = function(x) {
|
||||||
|
if (!arguments.length) return distance;
|
||||||
|
distance = x;
|
||||||
|
return kmeans;
|
||||||
|
};
|
||||||
|
|
||||||
|
return kmeans;
|
||||||
|
};
|
||||||
|
|
||||||
|
function science_stats_kmeansCompare(a, b) {
|
||||||
|
if (!a || !b || a.length !== b.length) return false;
|
||||||
|
var n = a.length,
|
||||||
|
i = -1;
|
||||||
|
while (++i < n) if (a[i] !== b[i]) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an array of k distinct vectors randomly selected from the input
|
||||||
|
// array of vectors. Returns null if k > n or if there are less than k distinct
|
||||||
|
// objects in vectors.
|
||||||
|
function science_stats_kmeansRandom(k, vectors) {
|
||||||
|
var n = vectors.length;
|
||||||
|
if (k > n) return null;
|
||||||
|
|
||||||
|
var selected_vectors = [];
|
||||||
|
var selected_indices = [];
|
||||||
|
var tested_indices = {};
|
||||||
|
var tested = 0;
|
||||||
|
var selected = 0;
|
||||||
|
var i,
|
||||||
|
vector,
|
||||||
|
select;
|
||||||
|
|
||||||
|
while (selected < k) {
|
||||||
|
if (tested === n) return null;
|
||||||
|
|
||||||
|
var random_index = Math.floor(Math.random() * n);
|
||||||
|
if (random_index in tested_indices) continue;
|
||||||
|
|
||||||
|
tested_indices[random_index] = 1;
|
||||||
|
tested++;
|
||||||
|
vector = vectors[random_index];
|
||||||
|
select = true;
|
||||||
|
for (i = 0; i < selected; i++) {
|
||||||
|
if (science_stats_kmeansCompare(vector, selected_vectors[i])) {
|
||||||
|
select = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (select) {
|
||||||
|
selected_vectors[selected] = vector;
|
||||||
|
selected_indices[selected] = random_index;
|
||||||
|
selected++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selected_vectors;
|
||||||
|
}
|
||||||
|
science.stats.hcluster = function() {
|
||||||
|
var distance = science.stats.distance.euclidean,
|
||||||
|
linkage = "simple"; // simple, complete or average
|
||||||
|
|
||||||
|
function hcluster(vectors) {
|
||||||
|
var n = vectors.length,
|
||||||
|
dMin = [],
|
||||||
|
cSize = [],
|
||||||
|
distMatrix = [],
|
||||||
|
clusters = [],
|
||||||
|
c1,
|
||||||
|
c2,
|
||||||
|
c1Cluster,
|
||||||
|
c2Cluster,
|
||||||
|
p,
|
||||||
|
root,
|
||||||
|
i,
|
||||||
|
j;
|
||||||
|
|
||||||
|
// Initialise distance matrix and vector of closest clusters.
|
||||||
|
i = -1; while (++i < n) {
|
||||||
|
dMin[i] = 0;
|
||||||
|
distMatrix[i] = [];
|
||||||
|
j = -1; while (++j < n) {
|
||||||
|
distMatrix[i][j] = i === j ? Infinity : distance(vectors[i] , vectors[j]);
|
||||||
|
if (distMatrix[i][dMin[i]] > distMatrix[i][j]) dMin[i] = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create leaves of the tree
|
||||||
|
i = -1; while (++i < n) {
|
||||||
|
clusters[i] = [];
|
||||||
|
clusters[i][0] = {
|
||||||
|
left: null,
|
||||||
|
right: null,
|
||||||
|
dist: 0,
|
||||||
|
centroid: vectors[i],
|
||||||
|
size: 1,
|
||||||
|
depth: 0
|
||||||
|
};
|
||||||
|
cSize[i] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
for (p = 0; p < n-1; p++) {
|
||||||
|
// find the closest pair of clusters
|
||||||
|
c1 = 0;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (distMatrix[i][dMin[i]] < distMatrix[c1][dMin[c1]]) c1 = i;
|
||||||
|
}
|
||||||
|
c2 = dMin[c1];
|
||||||
|
|
||||||
|
// create node to store cluster info
|
||||||
|
c1Cluster = clusters[c1][0];
|
||||||
|
c2Cluster = clusters[c2][0];
|
||||||
|
|
||||||
|
newCluster = {
|
||||||
|
left: c1Cluster,
|
||||||
|
right: c2Cluster,
|
||||||
|
dist: distMatrix[c1][c2],
|
||||||
|
centroid: calculateCentroid(c1Cluster.size, c1Cluster.centroid,
|
||||||
|
c2Cluster.size, c2Cluster.centroid),
|
||||||
|
size: c1Cluster.size + c2Cluster.size,
|
||||||
|
depth: 1 + Math.max(c1Cluster.depth, c2Cluster.depth)
|
||||||
|
};
|
||||||
|
clusters[c1].splice(0, 0, newCluster);
|
||||||
|
cSize[c1] += cSize[c2];
|
||||||
|
|
||||||
|
// overwrite row c1 with respect to the linkage type
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
|
switch (linkage) {
|
||||||
|
case "single":
|
||||||
|
if (distMatrix[c1][j] > distMatrix[c2][j])
|
||||||
|
distMatrix[j][c1] = distMatrix[c1][j] = distMatrix[c2][j];
|
||||||
|
break;
|
||||||
|
case "complete":
|
||||||
|
if (distMatrix[c1][j] < distMatrix[c2][j])
|
||||||
|
distMatrix[j][c1] = distMatrix[c1][j] = distMatrix[c2][j];
|
||||||
|
break;
|
||||||
|
case "average":
|
||||||
|
distMatrix[j][c1] = distMatrix[c1][j] = (cSize[c1] * distMatrix[c1][j] + cSize[c2] * distMatrix[c2][j]) / (cSize[c1] + cSize[j]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
distMatrix[c1][c1] = Infinity;
|
||||||
|
|
||||||
|
// infinity out old row c2 and column c2
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
distMatrix[i][c2] = distMatrix[c2][i] = Infinity;
|
||||||
|
|
||||||
|
// update dmin and replace ones that previous pointed to c2 to point to c1
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
|
if (dMin[j] == c2) dMin[j] = c1;
|
||||||
|
if (distMatrix[c1][j] < distMatrix[c1][dMin[c1]]) dMin[c1] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep track of the last added cluster
|
||||||
|
root = newCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
hcluster.distance = function(x) {
|
||||||
|
if (!arguments.length) return distance;
|
||||||
|
distance = x;
|
||||||
|
return hcluster;
|
||||||
|
};
|
||||||
|
|
||||||
|
return hcluster;
|
||||||
|
};
|
||||||
|
|
||||||
|
function calculateCentroid(c1Size, c1Centroid, c2Size, c2Centroid) {
|
||||||
|
var newCentroid = [],
|
||||||
|
newSize = c1Size + c2Size,
|
||||||
|
n = c1Centroid.length,
|
||||||
|
i = -1;
|
||||||
|
while (++i < n) {
|
||||||
|
newCentroid[i] = (c1Size * c1Centroid[i] + c2Size * c2Centroid[i]) / newSize;
|
||||||
|
}
|
||||||
|
return newCentroid;
|
||||||
|
}
|
||||||
science.stats.iqr = function(x) {
|
science.stats.iqr = function(x) {
|
||||||
var quartiles = science.stats.quantiles(x, [.25, .75]);
|
var quartiles = science.stats.quantiles(x, [.25, .75]);
|
||||||
return quartiles[1] - quartiles[0];
|
return quartiles[1] - quartiles[0];
|
||||||
};
|
};
|
||||||
|
// Based on org.apache.commons.math.analysis.interpolation.LoessInterpolator
|
||||||
|
// from http://commons.apache.org/math/
|
||||||
|
science.stats.loess = function() {
|
||||||
|
var bandwidth = .3,
|
||||||
|
robustnessIters = 2,
|
||||||
|
accuracy = 1e-12;
|
||||||
|
|
||||||
|
function smooth(xval, yval, weights) {
|
||||||
|
var n = xval.length,
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (n !== yval.length) throw {error: "Mismatched array lengths"};
|
||||||
|
if (n == 0) throw {error: "At least one point required."};
|
||||||
|
|
||||||
|
if (arguments.length < 3) {
|
||||||
|
weights = [];
|
||||||
|
i = -1; while (++i < n) weights[i] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
science_stats_loessFiniteReal(xval);
|
||||||
|
science_stats_loessFiniteReal(yval);
|
||||||
|
science_stats_loessFiniteReal(weights);
|
||||||
|
science_stats_loessStrictlyIncreasing(xval);
|
||||||
|
|
||||||
|
if (n == 1) return [yval[0]];
|
||||||
|
if (n == 2) return [yval[0], yval[1]];
|
||||||
|
|
||||||
|
var bandwidthInPoints = Math.floor(bandwidth * n);
|
||||||
|
|
||||||
|
if (bandwidthInPoints < 2) throw {error: "Bandwidth too small."};
|
||||||
|
|
||||||
|
var res = [],
|
||||||
|
residuals = [],
|
||||||
|
robustnessWeights = [];
|
||||||
|
|
||||||
|
// Do an initial fit and 'robustnessIters' robustness iterations.
|
||||||
|
// This is equivalent to doing 'robustnessIters+1' robustness iterations
|
||||||
|
// starting with all robustness weights set to 1.
|
||||||
|
i = -1; while (++i < n) {
|
||||||
|
res[i] = 0;
|
||||||
|
residuals[i] = 0;
|
||||||
|
robustnessWeights[i] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iter = -1;
|
||||||
|
while (++iter <= robustnessIters) {
|
||||||
|
var bandwidthInterval = [0, bandwidthInPoints - 1];
|
||||||
|
// At each x, compute a local weighted linear regression
|
||||||
|
var x;
|
||||||
|
i = -1; while (++i < n) {
|
||||||
|
x = xval[i];
|
||||||
|
|
||||||
|
// Find out the interval of source points on which
|
||||||
|
// a regression is to be made.
|
||||||
|
if (i > 0) {
|
||||||
|
science_stats_loessUpdateBandwidthInterval(xval, weights, i, bandwidthInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ileft = bandwidthInterval[0],
|
||||||
|
iright = bandwidthInterval[1];
|
||||||
|
|
||||||
|
// Compute the point of the bandwidth interval that is
|
||||||
|
// farthest from x
|
||||||
|
var edge = (xval[i] - xval[ileft]) > (xval[iright] - xval[i]) ? ileft : iright;
|
||||||
|
|
||||||
|
// Compute a least-squares linear fit weighted by
|
||||||
|
// the product of robustness weights and the tricube
|
||||||
|
// weight function.
|
||||||
|
// See http://en.wikipedia.org/wiki/Linear_regression
|
||||||
|
// (section "Univariate linear case")
|
||||||
|
// and http://en.wikipedia.org/wiki/Weighted_least_squares
|
||||||
|
// (section "Weighted least squares")
|
||||||
|
var sumWeights = 0,
|
||||||
|
sumX = 0,
|
||||||
|
sumXSquared = 0,
|
||||||
|
sumY = 0,
|
||||||
|
sumXY = 0,
|
||||||
|
denom = Math.abs(1 / (xval[edge] - x));
|
||||||
|
|
||||||
|
for (var k = ileft; k <= iright; ++k) {
|
||||||
|
var xk = xval[k],
|
||||||
|
yk = yval[k],
|
||||||
|
dist = k < i ? x - xk : xk - x,
|
||||||
|
w = science_stats_loessTricube(dist * denom) * robustnessWeights[k] * weights[k],
|
||||||
|
xkw = xk * w;
|
||||||
|
sumWeights += w;
|
||||||
|
sumX += xkw;
|
||||||
|
sumXSquared += xk * xkw;
|
||||||
|
sumY += yk * w;
|
||||||
|
sumXY += yk * xkw;
|
||||||
|
}
|
||||||
|
|
||||||
|
var meanX = sumX / sumWeights,
|
||||||
|
meanY = sumY / sumWeights,
|
||||||
|
meanXY = sumXY / sumWeights,
|
||||||
|
meanXSquared = sumXSquared / sumWeights;
|
||||||
|
|
||||||
|
var beta = (Math.sqrt(Math.abs(meanXSquared - meanX * meanX)) < accuracy)
|
||||||
|
? 0 : ((meanXY - meanX * meanY) / (meanXSquared - meanX * meanX));
|
||||||
|
|
||||||
|
var alpha = meanY - beta * meanX;
|
||||||
|
|
||||||
|
res[i] = beta * x + alpha;
|
||||||
|
residuals[i] = Math.abs(yval[i] - res[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to recompute the robustness weights at the last
|
||||||
|
// iteration, they won't be needed anymore
|
||||||
|
if (iter === robustnessIters) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recompute the robustness weights.
|
||||||
|
|
||||||
|
// Find the median residual.
|
||||||
|
var sortedResiduals = residuals.slice();
|
||||||
|
sortedResiduals.sort();
|
||||||
|
var medianResidual = sortedResiduals[Math.floor(n / 2)];
|
||||||
|
|
||||||
|
if (Math.abs(medianResidual) < accuracy)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var arg,
|
||||||
|
w;
|
||||||
|
i = -1; while (++i < n) {
|
||||||
|
arg = residuals[i] / (6 * medianResidual);
|
||||||
|
robustnessWeights[i] = (arg >= 1) ? 0 : ((w = 1 - arg * arg) * w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
smooth.bandwidth = function(x) {
|
||||||
|
if (!arguments.length) return x;
|
||||||
|
bandwidth = x;
|
||||||
|
return smooth;
|
||||||
|
};
|
||||||
|
|
||||||
|
smooth.robustnessIterations = function(x) {
|
||||||
|
if (!arguments.length) return x;
|
||||||
|
robustnessIters = x;
|
||||||
|
return smooth;
|
||||||
|
};
|
||||||
|
|
||||||
|
smooth.accuracy = function(x) {
|
||||||
|
if (!arguments.length) return x;
|
||||||
|
accuracy = x;
|
||||||
|
return smooth;
|
||||||
|
};
|
||||||
|
|
||||||
|
return smooth;
|
||||||
|
};
|
||||||
|
|
||||||
|
function science_stats_loessFiniteReal(values) {
|
||||||
|
var n = values.length,
|
||||||
|
i = -1;
|
||||||
|
|
||||||
|
while (++i < n) if (!isFinite(values[i])) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function science_stats_loessStrictlyIncreasing(xval) {
|
||||||
|
var n = xval.length,
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while (++i < n) if (xval[i - 1] >= xval[i]) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the tricube weight function.
|
||||||
|
// http://en.wikipedia.org/wiki/Local_regression#Weight_function
|
||||||
|
function science_stats_loessTricube(x) {
|
||||||
|
return (x = 1 - x * x * x) * x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given an index interval into xval that embraces a certain number of
|
||||||
|
// points closest to xval[i-1], update the interval so that it embraces
|
||||||
|
// the same number of points closest to xval[i], ignoring zero weights.
|
||||||
|
function science_stats_loessUpdateBandwidthInterval(
|
||||||
|
xval, weights, i, bandwidthInterval) {
|
||||||
|
|
||||||
|
var left = bandwidthInterval[0],
|
||||||
|
right = bandwidthInterval[1];
|
||||||
|
|
||||||
|
// The right edge should be adjusted if the next point to the right
|
||||||
|
// is closer to xval[i] than the leftmost point of the current interval
|
||||||
|
var nextRight = science_stats_loessNextNonzero(weights, right);
|
||||||
|
if ((nextRight < xval.length) && (xval[nextRight] - xval[i]) < (xval[i] - xval[left])) {
|
||||||
|
var nextLeft = science_stats_loessNextNonzero(weights, left);
|
||||||
|
bandwidthInterval[0] = nextLeft;
|
||||||
|
bandwidthInterval[1] = nextRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function science_stats_loessNextNonzero(weights, i) {
|
||||||
|
var j = i + 1;
|
||||||
|
while (j < weights.length && weights[j] === 0) j++;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
// Welford's algorithm.
|
// Welford's algorithm.
|
||||||
science.stats.mean = function(x) {
|
science.stats.mean = function(x) {
|
||||||
var n = x.length;
|
var n = x.length;
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
28
package.json
28
package.json
|
@ -1,14 +1,28 @@
|
||||||
{
|
{
|
||||||
"name": "d3",
|
"name": "d3",
|
||||||
"version": "1.29.5",
|
"version": "2.5.2",
|
||||||
"description": "A small, free JavaScript library for manipulating documents based on data.",
|
"description": "A small, free JavaScript library for manipulating documents based on data.",
|
||||||
"keywords": ["dom", "w3c", "visualization", "svg", "animation", "canvas"],
|
"keywords": [
|
||||||
|
"dom",
|
||||||
|
"w3c",
|
||||||
|
"visualization",
|
||||||
|
"svg",
|
||||||
|
"animation",
|
||||||
|
"canvas"
|
||||||
|
],
|
||||||
"homepage": "http://mbostock.github.com/d3/",
|
"homepage": "http://mbostock.github.com/d3/",
|
||||||
"author": {"name": "Mike Bostock", "url": "http://bost.ocks.org/mike"},
|
"author": {
|
||||||
"repository": {"type": "git", "url": "http://github.com/mbostock/d3.git"},
|
"name": "Mike Bostock",
|
||||||
|
"url": "http://bost.ocks.org/mike"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "http://github.com/mbostock/d3.git"
|
||||||
|
},
|
||||||
|
"main": "d3.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"uglify-js": "1.0.6",
|
"uglify-js": "1.1.1",
|
||||||
"jsdom": "0.2.3",
|
"jsdom": "0.2.9",
|
||||||
"vows": "0.5.10"
|
"vows": "0.5.13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ d3.behavior.drag = function() {
|
||||||
// snapshot the local context for subsequent dispatch
|
// snapshot the local context for subsequent dispatch
|
||||||
function start() {
|
function start() {
|
||||||
d3_behavior_dragEvent = event;
|
d3_behavior_dragEvent = event;
|
||||||
|
d3_behavior_dragEventTarget = d3.event.target;
|
||||||
d3_behavior_dragOffset = d3_behavior_dragPoint((d3_behavior_dragTarget = this).parentNode);
|
d3_behavior_dragOffset = d3_behavior_dragPoint((d3_behavior_dragTarget = this).parentNode);
|
||||||
d3_behavior_dragMoved = 0;
|
d3_behavior_dragMoved = 0;
|
||||||
d3_behavior_dragArguments = arguments;
|
d3_behavior_dragArguments = arguments;
|
||||||
|
@ -27,15 +28,11 @@ d3.behavior.drag = function() {
|
||||||
d3_behavior_dragDispatch("dragstart");
|
d3_behavior_dragDispatch("dragstart");
|
||||||
}
|
}
|
||||||
|
|
||||||
drag.on = function(type, listener) {
|
return d3.rebind(drag, event, "on");
|
||||||
event[type].add(listener);
|
|
||||||
return drag;
|
|
||||||
};
|
|
||||||
|
|
||||||
return drag;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var d3_behavior_dragEvent,
|
var d3_behavior_dragEvent,
|
||||||
|
d3_behavior_dragEventTarget,
|
||||||
d3_behavior_dragTarget,
|
d3_behavior_dragTarget,
|
||||||
d3_behavior_dragArguments,
|
d3_behavior_dragArguments,
|
||||||
d3_behavior_dragOffset,
|
d3_behavior_dragOffset,
|
||||||
|
@ -55,7 +52,7 @@ function d3_behavior_dragDispatch(type) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
d3.event = {dx: dx, dy: dy};
|
d3.event = {dx: dx, dy: dy};
|
||||||
d3_behavior_dragEvent[type].dispatch.apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
|
d3_behavior_dragEvent[type].apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
|
||||||
} finally {
|
} finally {
|
||||||
d3.event = o;
|
d3.event = o;
|
||||||
}
|
}
|
||||||
|
@ -63,10 +60,10 @@ function d3_behavior_dragDispatch(type) {
|
||||||
o.preventDefault();
|
o.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_behavior_dragPoint(container) {
|
function d3_behavior_dragPoint(container, type) {
|
||||||
return d3.event.touches
|
// TODO Track touch points by identifier.
|
||||||
? d3.svg.touches(container)[0]
|
var t = d3.event.changedTouches;
|
||||||
: d3.svg.mouse(container);
|
return t ? d3.svg.touches(container, t)[0] : d3.svg.mouse(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_behavior_dragMove() {
|
function d3_behavior_dragMove() {
|
||||||
|
@ -77,7 +74,7 @@ function d3_behavior_dragMove() {
|
||||||
if (!parent) return d3_behavior_dragUp();
|
if (!parent) return d3_behavior_dragUp();
|
||||||
|
|
||||||
d3_behavior_dragDispatch("drag");
|
d3_behavior_dragDispatch("drag");
|
||||||
d3_behavior_dragCancel();
|
d3_eventCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_behavior_dragUp() {
|
function d3_behavior_dragUp() {
|
||||||
|
@ -87,20 +84,16 @@ function d3_behavior_dragUp() {
|
||||||
|
|
||||||
// If the node was moved, prevent the mouseup from propagating.
|
// If the node was moved, prevent the mouseup from propagating.
|
||||||
// Also prevent the subsequent click from propagating (e.g., for anchors).
|
// Also prevent the subsequent click from propagating (e.g., for anchors).
|
||||||
if (d3_behavior_dragMoved) {
|
if (d3_behavior_dragMoved && d3_behavior_dragEventTarget === d3.event.target) {
|
||||||
d3_behavior_dragStopClick = true;
|
d3_behavior_dragStopClick = true;
|
||||||
d3_behavior_dragCancel();
|
d3_eventCancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_behavior_dragClick() {
|
function d3_behavior_dragClick() {
|
||||||
if (d3_behavior_dragStopClick) {
|
if (d3_behavior_dragStopClick && d3_behavior_dragEventTarget === d3.event.target) {
|
||||||
d3_behavior_dragCancel();
|
d3_eventCancel();
|
||||||
d3_behavior_dragStopClick = false;
|
d3_behavior_dragStopClick = false;
|
||||||
|
d3_behavior_dragEventTarget = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_behavior_dragCancel() {
|
|
||||||
d3.event.stopPropagation();
|
|
||||||
d3.event.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// TODO unbind zoom behavior?
|
// TODO unbind zoom behavior?
|
||||||
// TODO unbind listener?
|
|
||||||
d3.behavior.zoom = function() {
|
d3.behavior.zoom = function() {
|
||||||
var xyz = [0, 0, 0],
|
var xyz = [0, 0, 0],
|
||||||
event = d3.dispatch("zoom");
|
event = d3.dispatch("zoom"),
|
||||||
|
extent = d3_behavior_zoomInfiniteExtent;
|
||||||
|
|
||||||
function zoom() {
|
function zoom() {
|
||||||
this
|
this
|
||||||
|
@ -23,7 +23,9 @@ d3.behavior.zoom = function() {
|
||||||
// snapshot the local context for subsequent dispatch
|
// snapshot the local context for subsequent dispatch
|
||||||
function start() {
|
function start() {
|
||||||
d3_behavior_zoomXyz = xyz;
|
d3_behavior_zoomXyz = xyz;
|
||||||
d3_behavior_zoomDispatch = event.zoom.dispatch;
|
d3_behavior_zoomExtent = extent;
|
||||||
|
d3_behavior_zoomDispatch = event.zoom;
|
||||||
|
d3_behavior_zoomEventTarget = d3.event.target;
|
||||||
d3_behavior_zoomTarget = this;
|
d3_behavior_zoomTarget = this;
|
||||||
d3_behavior_zoomArguments = arguments;
|
d3_behavior_zoomArguments = arguments;
|
||||||
}
|
}
|
||||||
|
@ -61,12 +63,13 @@ d3.behavior.zoom = function() {
|
||||||
d3_behavior_zoomLast = now;
|
d3_behavior_zoomLast = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
zoom.on = function(type, listener) {
|
zoom.extent = function(x) {
|
||||||
event[type].add(listener);
|
if (!arguments.length) return extent;
|
||||||
|
extent = x == null ? d3_behavior_zoomInfiniteExtent : x;
|
||||||
return zoom;
|
return zoom;
|
||||||
};
|
};
|
||||||
|
|
||||||
return zoom;
|
return d3.rebind(zoom, event, "on");
|
||||||
};
|
};
|
||||||
|
|
||||||
var d3_behavior_zoomDiv,
|
var d3_behavior_zoomDiv,
|
||||||
|
@ -75,7 +78,9 @@ var d3_behavior_zoomDiv,
|
||||||
d3_behavior_zoomLocations = {}, // identifier -> location
|
d3_behavior_zoomLocations = {}, // identifier -> location
|
||||||
d3_behavior_zoomLast = 0,
|
d3_behavior_zoomLast = 0,
|
||||||
d3_behavior_zoomXyz,
|
d3_behavior_zoomXyz,
|
||||||
|
d3_behavior_zoomExtent,
|
||||||
d3_behavior_zoomDispatch,
|
d3_behavior_zoomDispatch,
|
||||||
|
d3_behavior_zoomEventTarget,
|
||||||
d3_behavior_zoomTarget,
|
d3_behavior_zoomTarget,
|
||||||
d3_behavior_zoomArguments,
|
d3_behavior_zoomArguments,
|
||||||
d3_behavior_zoomMoved,
|
d3_behavior_zoomMoved,
|
||||||
|
@ -166,40 +171,45 @@ function d3_behavior_zoomMousemove() {
|
||||||
|
|
||||||
function d3_behavior_zoomMouseup() {
|
function d3_behavior_zoomMouseup() {
|
||||||
if (d3_behavior_zoomPanning) {
|
if (d3_behavior_zoomPanning) {
|
||||||
if (d3_behavior_zoomMoved) d3_behavior_zoomStopClick = true;
|
if (d3_behavior_zoomMoved && d3_behavior_zoomEventTarget === d3.event.target) {
|
||||||
|
d3_behavior_zoomStopClick = true;
|
||||||
|
}
|
||||||
d3_behavior_zoomMousemove();
|
d3_behavior_zoomMousemove();
|
||||||
d3_behavior_zoomPanning = null;
|
d3_behavior_zoomPanning = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_behavior_zoomClick() {
|
function d3_behavior_zoomClick() {
|
||||||
if (d3_behavior_zoomStopClick) {
|
if (d3_behavior_zoomStopClick && d3_behavior_zoomEventTarget === d3.event.target) {
|
||||||
d3.event.stopPropagation();
|
d3.event.stopPropagation();
|
||||||
d3.event.preventDefault();
|
d3.event.preventDefault();
|
||||||
d3_behavior_zoomStopClick = false;
|
d3_behavior_zoomStopClick = false;
|
||||||
|
d3_behavior_zoomEventTarget = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_behavior_zoomTo(z, x0, x1) {
|
function d3_behavior_zoomTo(z, x0, x1) {
|
||||||
var K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
|
z = d3_behavior_zoomExtentClamp(z, 2);
|
||||||
x = d3_behavior_zoomXyz[0] = x0[0] - K * x1[0],
|
var j = Math.pow(2, d3_behavior_zoomXyz[2]),
|
||||||
y = d3_behavior_zoomXyz[1] = x0[1] - K * x1[1],
|
k = Math.pow(2, z),
|
||||||
o = d3.event, // Events can be reentrant (e.g., focus).
|
K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
|
||||||
k = Math.pow(2, z);
|
x_ = d3_behavior_zoomXyz[0],
|
||||||
|
y_ = d3_behavior_zoomXyz[1],
|
||||||
|
x = d3_behavior_zoomXyz[0] = d3_behavior_zoomExtentClamp((x0[0] - x1[0] * K), 0, k),
|
||||||
|
y = d3_behavior_zoomXyz[1] = d3_behavior_zoomExtentClamp((x0[1] - x1[1] * K), 1, k),
|
||||||
|
o = d3.event; // Events can be reentrant (e.g., focus).
|
||||||
|
|
||||||
d3.event = {
|
d3.event = {
|
||||||
scale: k,
|
scale: k,
|
||||||
translate: [x, y],
|
translate: [x, y],
|
||||||
transform: function(sx, sy) {
|
transform: function(sx, sy) {
|
||||||
if (sx) transform(sx, x);
|
if (sx) transform(sx, x_, x);
|
||||||
if (sy) transform(sy, y);
|
if (sy) transform(sy, y_, y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function transform(scale, o) {
|
function transform(scale, a, b) {
|
||||||
var domain = scale.__domain || (scale.__domain = scale.domain()),
|
scale.domain(scale.range().map(function(v) { return scale.invert(((v - b) * j) / k + a); }));
|
||||||
range = scale.range().map(function(v) { return (v - o) / k; });
|
|
||||||
scale.domain(domain).domain(range.map(scale.invert));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -210,3 +220,19 @@ function d3_behavior_zoomTo(z, x0, x1) {
|
||||||
|
|
||||||
o.preventDefault();
|
o.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var d3_behavior_zoomInfiniteExtent = [
|
||||||
|
[-Infinity, Infinity],
|
||||||
|
[-Infinity, Infinity],
|
||||||
|
[-Infinity, Infinity]
|
||||||
|
];
|
||||||
|
|
||||||
|
function d3_behavior_zoomExtentClamp(x, i, k) {
|
||||||
|
var range = d3_behavior_zoomExtent[i],
|
||||||
|
r0 = range[0],
|
||||||
|
r1 = range[1];
|
||||||
|
return arguments.length === 3
|
||||||
|
? Math.max(r1 * (r1 === Infinity ? -Infinity : 1 / k - 1),
|
||||||
|
Math.min(r0 === -Infinity ? Infinity : r0, x / k)) * k
|
||||||
|
: Math.max(r0, Math.min(r1, x));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
try {
|
||||||
|
document.createElement("div").style.setProperty("opacity", 0, "");
|
||||||
|
} catch (error) {
|
||||||
|
var d3_style_prototype = CSSStyleDeclaration.prototype,
|
||||||
|
d3_style_setProperty = d3_style_prototype.setProperty;
|
||||||
|
d3_style_prototype.setProperty = function(name, value, priority) {
|
||||||
|
d3_style_setProperty.call(this, name, value + "", priority);
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,3 +1,21 @@
|
||||||
|
var d3_array = d3_arraySlice; // conversion for NodeLists
|
||||||
|
|
||||||
|
function d3_arrayCopy(pseudoarray) {
|
||||||
|
var i = -1, n = pseudoarray.length, array = [];
|
||||||
|
while (++i < n) array.push(pseudoarray[i]);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function d3_arraySlice(pseudoarray) {
|
||||||
|
return Array.prototype.slice.call(pseudoarray);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
d3_array(document.documentElement.childNodes)[0].nodeType;
|
||||||
|
} catch(e) {
|
||||||
|
d3_array = d3_arrayCopy;
|
||||||
|
}
|
||||||
|
|
||||||
var d3_arraySubclass = [].__proto__?
|
var d3_arraySubclass = [].__proto__?
|
||||||
|
|
||||||
// Until ECMAScript supports array subclassing, prototype injection works well.
|
// Until ECMAScript supports array subclassing, prototype injection works well.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
d3 = {version: "2.0.4"}; // semver
|
d3 = {version: "2.5.2"}; // semver
|
||||||
|
|
|
@ -1,45 +1,60 @@
|
||||||
/** @param {...string} types */
|
d3.dispatch = function() {
|
||||||
d3.dispatch = function(types) {
|
var dispatch = new d3_dispatch(),
|
||||||
var dispatch = {},
|
i = -1,
|
||||||
type;
|
n = arguments.length;
|
||||||
for (var i = 0, n = arguments.length; i < n; i++) {
|
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event();
|
||||||
type = arguments[i];
|
|
||||||
dispatch[type] = d3_dispatch(type);
|
|
||||||
}
|
|
||||||
return dispatch;
|
return dispatch;
|
||||||
};
|
};
|
||||||
|
|
||||||
function d3_dispatch(type) {
|
function d3_dispatch() {}
|
||||||
var dispatch = {},
|
|
||||||
listeners = [];
|
|
||||||
|
|
||||||
dispatch.add = function(listener) {
|
d3_dispatch.prototype.on = function(type, listener) {
|
||||||
for (var i = 0; i < listeners.length; i++) {
|
var i = type.indexOf("."),
|
||||||
if (listeners[i].listener == listener) return dispatch; // already registered
|
name = "";
|
||||||
|
|
||||||
|
// Extract optional namespace, e.g., "click.foo"
|
||||||
|
if (i > 0) {
|
||||||
|
name = type.substring(i + 1);
|
||||||
|
type = type.substring(0, i);
|
||||||
}
|
}
|
||||||
listeners.push({listener: listener, on: true});
|
|
||||||
|
return arguments.length < 2
|
||||||
|
? this[type].on(name)
|
||||||
|
: (this[type].on(name, listener), this);
|
||||||
|
};
|
||||||
|
|
||||||
|
function d3_dispatch_event() {
|
||||||
|
var listeners = [],
|
||||||
|
listenerByName = {};
|
||||||
|
|
||||||
|
function dispatch() {
|
||||||
|
var z = listeners, // defensive reference
|
||||||
|
i = -1,
|
||||||
|
n = z.length,
|
||||||
|
l;
|
||||||
|
while (++i < n) if (l = z[i].on) l.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch.on = function(name, listener) {
|
||||||
|
var l, i;
|
||||||
|
|
||||||
|
// return the current listener, if any
|
||||||
|
if (arguments.length < 2) return (l = listenerByName[name]) && l.on;
|
||||||
|
|
||||||
|
// remove the old listener, if any (with copy-on-write)
|
||||||
|
if (l = listenerByName[name]) {
|
||||||
|
l.on = null;
|
||||||
|
listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
|
||||||
|
delete listenerByName[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the new listener, if any
|
||||||
|
if (listener) {
|
||||||
|
listeners.push(listenerByName[name] = {on: listener});
|
||||||
|
}
|
||||||
|
|
||||||
return dispatch;
|
return dispatch;
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatch.remove = function(listener) {
|
|
||||||
for (var i = 0; i < listeners.length; i++) {
|
|
||||||
var l = listeners[i];
|
|
||||||
if (l.listener == listener) {
|
|
||||||
l.on = false;
|
|
||||||
listeners = listeners.slice(0, i).concat(listeners.slice(i + 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dispatch;
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch.dispatch = function() {
|
|
||||||
var ls = listeners; // defensive reference
|
|
||||||
for (var i = 0, n = ls.length; i < n; i++) {
|
|
||||||
var l = ls[i];
|
|
||||||
if (l.on) l.listener.apply(this, arguments);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return dispatch;
|
return dispatch;
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,9 +60,15 @@ d3.ease = function(name) {
|
||||||
var i = name.indexOf("-"),
|
var i = name.indexOf("-"),
|
||||||
t = i >= 0 ? name.substring(0, i) : name,
|
t = i >= 0 ? name.substring(0, i) : name,
|
||||||
m = i >= 0 ? name.substring(i + 1) : "in";
|
m = i >= 0 ? name.substring(i + 1) : "in";
|
||||||
return d3_ease_mode[m](d3_ease[t].apply(null, Array.prototype.slice.call(arguments, 1)));
|
return d3_ease_clamp(d3_ease_mode[m](d3_ease[t].apply(null, Array.prototype.slice.call(arguments, 1))));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function d3_ease_clamp(f) {
|
||||||
|
return function(t) {
|
||||||
|
return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function d3_ease_reverse(f) {
|
function d3_ease_reverse(f) {
|
||||||
return function(t) {
|
return function(t) {
|
||||||
return 1 - f(1 - t);
|
return 1 - f(1 - t);
|
||||||
|
|
|
@ -1 +1,6 @@
|
||||||
d3.event = null;
|
d3.event = null;
|
||||||
|
|
||||||
|
function d3_eventCancel() {
|
||||||
|
d3.event.stopPropagation();
|
||||||
|
d3.event.preventDefault();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
d3.extent = function(array, f) {
|
||||||
|
var i = -1,
|
||||||
|
n = array.length,
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
c;
|
||||||
|
if (arguments.length === 1) {
|
||||||
|
while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;
|
||||||
|
while (++i < n) if ((b = array[i]) != null) {
|
||||||
|
if (a > b) a = b;
|
||||||
|
if (c < b) c = b;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
|
||||||
|
while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
|
||||||
|
if (a > b) a = b;
|
||||||
|
if (c < b) c = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [a, c];
|
||||||
|
};
|
|
@ -8,10 +8,11 @@ d3.format = function(specifier) {
|
||||||
comma = match[7],
|
comma = match[7],
|
||||||
precision = match[8],
|
precision = match[8],
|
||||||
type = match[9],
|
type = match[9],
|
||||||
percentage = false,
|
scale = 1,
|
||||||
|
suffix = "",
|
||||||
integer = false;
|
integer = false;
|
||||||
|
|
||||||
if (precision) precision = precision.substring(1);
|
if (precision) precision = +precision.substring(1);
|
||||||
|
|
||||||
if (zfill) {
|
if (zfill) {
|
||||||
fill = "0"; // TODO align = "=";
|
fill = "0"; // TODO align = "=";
|
||||||
|
@ -20,22 +21,36 @@ d3.format = function(specifier) {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "n": comma = true; type = "g"; break;
|
case "n": comma = true; type = "g"; break;
|
||||||
case "%": percentage = true; type = "f"; break;
|
case "%": scale = 100; suffix = "%"; type = "f"; break;
|
||||||
case "p": percentage = true; type = "r"; break;
|
case "p": scale = 100; suffix = "%"; type = "r"; break;
|
||||||
case "d": integer = true; precision = "0"; break;
|
case "d": integer = true; precision = 0; break;
|
||||||
|
case "s": scale = -1; type = "r"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no precision is specified for r, fallback to general notation.
|
||||||
|
if (type == "r" && !precision) type = "g";
|
||||||
|
|
||||||
type = d3_format_types[type] || d3_format_typeDefault;
|
type = d3_format_types[type] || d3_format_typeDefault;
|
||||||
|
|
||||||
return function(value) {
|
return function(value) {
|
||||||
var number = percentage ? value * 100 : +value,
|
|
||||||
negative = (number < 0) && (number = -number) ? "\u2212" : sign;
|
|
||||||
|
|
||||||
// Return the empty string for floats formatted as ints.
|
// Return the empty string for floats formatted as ints.
|
||||||
if (integer && (number % 1)) return "";
|
if (integer && (value % 1)) return "";
|
||||||
|
|
||||||
// Convert the input value to the desired precision.
|
// Convert negative to positive, and record the sign prefix.
|
||||||
value = type(number, precision);
|
var negative = (value < 0) && (value = -value) ? "\u2212" : sign;
|
||||||
|
|
||||||
|
// Apply the scale, computing it from the value's exponent for si format.
|
||||||
|
if (scale < 0) {
|
||||||
|
var prefix = d3.formatPrefix(value, precision);
|
||||||
|
value *= prefix.scale;
|
||||||
|
suffix = prefix.symbol;
|
||||||
|
} else {
|
||||||
|
value *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to the desired precision.
|
||||||
|
value = type(value, precision);
|
||||||
|
|
||||||
// If the fill character is 0, the sign and group is applied after the fill.
|
// If the fill character is 0, the sign and group is applied after the fill.
|
||||||
if (zfill) {
|
if (zfill) {
|
||||||
|
@ -52,9 +67,8 @@ d3.format = function(specifier) {
|
||||||
var length = value.length;
|
var length = value.length;
|
||||||
if (length < width) value = new Array(width - length + 1).join(fill) + value;
|
if (length < width) value = new Array(width - length + 1).join(fill) + value;
|
||||||
}
|
}
|
||||||
if (percentage) value += "%";
|
|
||||||
|
|
||||||
return value;
|
return value + suffix;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,12 +79,13 @@ var d3_format_types = {
|
||||||
g: function(x, p) { return x.toPrecision(p); },
|
g: function(x, p) { return x.toPrecision(p); },
|
||||||
e: function(x, p) { return x.toExponential(p); },
|
e: function(x, p) { return x.toExponential(p); },
|
||||||
f: function(x, p) { return x.toFixed(p); },
|
f: function(x, p) { return x.toFixed(p); },
|
||||||
r: function(x, p) {
|
r: function(x, p) { return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p))); }
|
||||||
var n = 1 + Math.floor(1e-15 + Math.log(x) / Math.LN10);
|
|
||||||
return d3.round(x, p - n).toFixed(Math.max(0, Math.min(20, p - n)));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function d3_format_precision(x, p) {
|
||||||
|
return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
|
||||||
|
}
|
||||||
|
|
||||||
function d3_format_typeDefault(x) {
|
function d3_format_typeDefault(x) {
|
||||||
return x + "";
|
return x + "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
var d3_formatPrefixes = ["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(d3_formatPrefix);
|
||||||
|
|
||||||
|
d3.formatPrefix = function(value, precision) {
|
||||||
|
var i = 0;
|
||||||
|
if (value) {
|
||||||
|
if (value < 0) value *= -1;
|
||||||
|
if (precision) value = d3.round(value, d3_format_precision(value, precision));
|
||||||
|
i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
|
||||||
|
i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
|
||||||
|
}
|
||||||
|
return d3_formatPrefixes[8 + i / 3];
|
||||||
|
};
|
||||||
|
|
||||||
|
function d3_formatPrefix(d, i) {
|
||||||
|
return {
|
||||||
|
scale: Math.pow(10, (8 - i) * 3),
|
||||||
|
symbol: d
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
d3.hsl = function(h, s, l) {
|
d3.hsl = function(h, s, l) {
|
||||||
return arguments.length === 1
|
return arguments.length === 1
|
||||||
? d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl)
|
? (h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l)
|
||||||
|
: d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl))
|
||||||
: d3_hsl(+h, +s, +l);
|
: d3_hsl(+h, +s, +l);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ d3_Hsl.prototype.rgb = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
d3_Hsl.prototype.toString = function() {
|
d3_Hsl.prototype.toString = function() {
|
||||||
return "hsl(" + this.h + "," + this.s * 100 + "%," + this.l * 100 + "%)";
|
return this.rgb().toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
function d3_hsl_rgb(h, s, l) {
|
function d3_hsl_rgb(h, s, l) {
|
||||||
|
|
|
@ -92,6 +92,10 @@ d3.interpolateString = function(a, b) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
d3.interpolateTransform = function(a, b) {
|
||||||
|
return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
|
||||||
|
};
|
||||||
|
|
||||||
d3.interpolateRgb = function(a, b) {
|
d3.interpolateRgb = function(a, b) {
|
||||||
a = d3.rgb(a);
|
a = d3.rgb(a);
|
||||||
b = d3.rgb(b);
|
b = d3.rgb(b);
|
||||||
|
@ -102,10 +106,10 @@ d3.interpolateRgb = function(a, b) {
|
||||||
bg = b.g - ag,
|
bg = b.g - ag,
|
||||||
bb = b.b - ab;
|
bb = b.b - ab;
|
||||||
return function(t) {
|
return function(t) {
|
||||||
return "rgb(" + Math.round(ar + br * t)
|
return "#"
|
||||||
+ "," + Math.round(ag + bg * t)
|
+ d3_rgb_hex(Math.round(ar + br * t))
|
||||||
+ "," + Math.round(ab + bb * t)
|
+ d3_rgb_hex(Math.round(ag + bg * t))
|
||||||
+ ")";
|
+ d3_rgb_hex(Math.round(ab + bb * t));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,19 +166,18 @@ d3.interpolateObject = function(a, b) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var d3_interpolate_number = /[-+]?(?:\d+\.\d+|\d+\.|\.\d+|\d+)(?:[eE][-]?\d+)?/g,
|
var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g;
|
||||||
d3_interpolate_rgb = {background: 1, fill: 1, stroke: 1};
|
|
||||||
|
|
||||||
function d3_interpolateByName(n) {
|
function d3_interpolateByName(n) {
|
||||||
return n in d3_interpolate_rgb || /\bcolor\b/.test(n)
|
return n == "transform"
|
||||||
? d3.interpolateRgb
|
? d3.interpolateTransform
|
||||||
: d3.interpolate;
|
: d3.interpolate;
|
||||||
}
|
}
|
||||||
|
|
||||||
d3.interpolators = [
|
d3.interpolators = [
|
||||||
d3.interpolateObject,
|
d3.interpolateObject,
|
||||||
function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
|
function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
|
||||||
function(a, b) { return (typeof b === "string") && d3.interpolateString(String(a), b); },
|
function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
|
||||||
function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(String(a), b); },
|
function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a + "", b); },
|
||||||
function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
|
function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
d3.mean = function(array, f) {
|
||||||
|
var n = array.length,
|
||||||
|
a,
|
||||||
|
m = 0,
|
||||||
|
i = -1,
|
||||||
|
j = 0;
|
||||||
|
if (arguments.length === 1) {
|
||||||
|
while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
|
||||||
|
} else {
|
||||||
|
while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
|
||||||
|
}
|
||||||
|
return j ? m : undefined;
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
d3.median = function(array, f) {
|
||||||
|
if (arguments.length > 1) array = array.map(f);
|
||||||
|
array = array.filter(d3_number);
|
||||||
|
return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
function d3_number(x) {
|
||||||
|
return x != null && !isNaN(x);
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
if (!Object.create) Object.create = function(o) {
|
|
||||||
/** @constructor */ function f() {}
|
|
||||||
f.prototype = o;
|
|
||||||
return new f;
|
|
||||||
};
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
d3.random = {
|
||||||
|
normal: function(mean, deviation) {
|
||||||
|
if (arguments.length < 2) deviation = 1;
|
||||||
|
if (arguments.length < 1) mean = 0;
|
||||||
|
return function() {
|
||||||
|
var x, y, r;
|
||||||
|
do {
|
||||||
|
x = Math.random() * 2 - 1;
|
||||||
|
y = Math.random() * 2 - 1;
|
||||||
|
r = x * x + y * y;
|
||||||
|
} while (!r || r > 1);
|
||||||
|
return mean + deviation * x * Math.sqrt(-2 * Math.log(r) / r);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,7 +1,16 @@
|
||||||
// A getter-setter method that preserves the appropriate `this` context.
|
// Copies a variable number of methods from source to target.
|
||||||
d3.rebind = function(object, method) {
|
d3.rebind = function(target, source) {
|
||||||
return function() {
|
var i = 1, n = arguments.length, method;
|
||||||
var x = method.apply(object, arguments);
|
while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
|
||||||
return arguments.length ? object : x;
|
return target;
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Method is assumed to be a standard D3 getter-setter:
|
||||||
|
// If passed with no arguments, gets the value.
|
||||||
|
// If passed with arguments, sets the value and returns the target.
|
||||||
|
function d3_rebind(target, source, method) {
|
||||||
|
return function() {
|
||||||
|
var value = method.apply(source, arguments);
|
||||||
|
return arguments.length ? target : value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
d3.rgb = function(r, g, b) {
|
d3.rgb = function(r, g, b) {
|
||||||
return arguments.length === 1
|
return arguments.length === 1
|
||||||
? d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb)
|
? (r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b)
|
||||||
|
: d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb))
|
||||||
: d3_rgb(~~r, ~~g, ~~b);
|
: d3_rgb(~~r, ~~g, ~~b);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,9 +34,9 @@ d3_Rgb.prototype.brighter = function(k) {
|
||||||
d3_Rgb.prototype.darker = function(k) {
|
d3_Rgb.prototype.darker = function(k) {
|
||||||
k = Math.pow(0.7, arguments.length ? k : 1);
|
k = Math.pow(0.7, arguments.length ? k : 1);
|
||||||
return d3_rgb(
|
return d3_rgb(
|
||||||
Math.max(0, Math.floor(k * this.r)),
|
Math.floor(k * this.r),
|
||||||
Math.max(0, Math.floor(k * this.g)),
|
Math.floor(k * this.g),
|
||||||
Math.max(0, Math.floor(k * this.b)));
|
Math.floor(k * this.b));
|
||||||
};
|
};
|
||||||
|
|
||||||
d3_Rgb.prototype.hsl = function() {
|
d3_Rgb.prototype.hsl = function() {
|
||||||
|
@ -47,7 +48,9 @@ d3_Rgb.prototype.toString = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
function d3_rgb_hex(v) {
|
function d3_rgb_hex(v) {
|
||||||
return v < 0x10 ? "0" + v.toString(16) : v.toString(16);
|
return v < 0x10
|
||||||
|
? "0" + Math.max(0, v).toString(16)
|
||||||
|
: Math.min(255, v).toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_rgb_parse(format, rgb, hsl) {
|
function d3_rgb_parse(format, rgb, hsl) {
|
||||||
|
|
|
@ -1,4 +1,19 @@
|
||||||
d3_selectionPrototype.classed = function(name, value) {
|
d3_selectionPrototype.classed = function(name, value) {
|
||||||
|
var names = name.split(d3_selection_classedWhitespace),
|
||||||
|
n = names.length,
|
||||||
|
i = -1;
|
||||||
|
if (arguments.length > 1) {
|
||||||
|
while (++i < n) d3_selection_classed.call(this, names[i], value);
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
while (++i < n) if (!d3_selection_classed.call(this, names[i])) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var d3_selection_classedWhitespace = /\s+/g;
|
||||||
|
|
||||||
|
function d3_selection_classed(name, value) {
|
||||||
var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g");
|
var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g");
|
||||||
|
|
||||||
// If no value is specified, return the first value.
|
// If no value is specified, return the first value.
|
||||||
|
@ -43,4 +58,4 @@ d3_selectionPrototype.classed = function(name, value) {
|
||||||
? classedFunction : value
|
? classedFunction : value
|
||||||
? classedAdd
|
? classedAdd
|
||||||
: classedRemove);
|
: classedRemove);
|
||||||
};
|
}
|
||||||
|
|
|
@ -8,3 +8,4 @@ var d3_selection_enterPrototype = [];
|
||||||
d3_selection_enterPrototype.append = d3_selectionPrototype.append;
|
d3_selection_enterPrototype.append = d3_selectionPrototype.append;
|
||||||
d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
|
d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
|
||||||
d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
|
d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
|
||||||
|
d3_selection_enterPrototype.node = d3_selectionPrototype.node;
|
||||||
|
|
|
@ -3,14 +3,16 @@ var d3_selectionRoot = d3_selection([[document]]);
|
||||||
d3_selectionRoot[0].parentNode = document.documentElement;
|
d3_selectionRoot[0].parentNode = document.documentElement;
|
||||||
|
|
||||||
// TODO fast singleton implementation!
|
// TODO fast singleton implementation!
|
||||||
|
// TODO select(function)
|
||||||
d3.select = function(selector) {
|
d3.select = function(selector) {
|
||||||
return typeof selector === "string"
|
return typeof selector === "string"
|
||||||
? d3_selectionRoot.select(selector)
|
? d3_selectionRoot.select(selector)
|
||||||
: d3_selection([[selector]]); // assume node
|
: d3_selection([[selector]]); // assume node
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO selectAll(function)
|
||||||
d3.selectAll = function(selector) {
|
d3.selectAll = function(selector) {
|
||||||
return typeof selector === "string"
|
return typeof selector === "string"
|
||||||
? d3_selectionRoot.selectAll(selector)
|
? d3_selectionRoot.selectAll(selector)
|
||||||
: d3_selection([selector]); // assume node[]
|
: d3_selection([d3_array(selector)]); // assume node[]
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ d3_selectionPrototype.selectAll = function(selector) {
|
||||||
for (var j = -1, m = this.length; ++j < m;) {
|
for (var j = -1, m = this.length; ++j < m;) {
|
||||||
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
|
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
|
||||||
if (node = group[i]) {
|
if (node = group[i]) {
|
||||||
subgroups.push(subgroup = selector.call(node, node.__data__, i));
|
subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));
|
||||||
subgroup.parentNode = node;
|
subgroup.parentNode = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,5 @@ d3_selectionPrototype.transition = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return d3_transition(subgroups, d3_transitionInheritId || ++d3_transitionId);
|
return d3_transition(subgroups, d3_transitionInheritId || ++d3_transitionId, Date.now());
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
d3.transform = function(string) {
|
||||||
|
d3_transformG.setAttribute("transform", string);
|
||||||
|
var t = d3_transformG.transform.baseVal.consolidate();
|
||||||
|
return new d3_transform(t ? t.matrix : d3_transformIdentity);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compute x-scale and normalize the first row.
|
||||||
|
// Compute shear and make second row orthogonal to first.
|
||||||
|
// Compute y-scale and normalize the second row.
|
||||||
|
// Finally, compute the rotation.
|
||||||
|
function d3_transform(m) {
|
||||||
|
var r0 = [m.a, m.b],
|
||||||
|
r1 = [m.c, m.d],
|
||||||
|
kx = d3_transformNormalize(r0),
|
||||||
|
kz = d3_transformDot(r0, r1),
|
||||||
|
ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
|
||||||
|
if (r0[0] * r1[1] < r1[0] * r0[1]) {
|
||||||
|
r0[0] *= -1;
|
||||||
|
r0[1] *= -1;
|
||||||
|
kx *= -1;
|
||||||
|
kz *= -1;
|
||||||
|
}
|
||||||
|
this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees;
|
||||||
|
this.translate = [m.e, m.f];
|
||||||
|
this.scale = [kx, ky];
|
||||||
|
this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
d3_transform.prototype.toString = function() {
|
||||||
|
return "translate(" + this.translate
|
||||||
|
+ ")rotate(" + this.rotate
|
||||||
|
+ ")skewX(" + this.skew
|
||||||
|
+ ")scale(" + this.scale
|
||||||
|
+ ")";
|
||||||
|
};
|
||||||
|
|
||||||
|
function d3_transformDot(a, b) {
|
||||||
|
return a[0] * b[0] + a[1] * b[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function d3_transformNormalize(a) {
|
||||||
|
var k = Math.sqrt(d3_transformDot(a, a));
|
||||||
|
if (k) {
|
||||||
|
a[0] /= k;
|
||||||
|
a[1] /= k;
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
function d3_transformCombine(a, b, k) {
|
||||||
|
a[0] += k * b[0];
|
||||||
|
a[1] += k * b[1];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"),
|
||||||
|
d3_transformIdentity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0},
|
||||||
|
d3_transformDegrees = 180 / Math.PI;
|
|
@ -1,23 +1,23 @@
|
||||||
d3_transitionPrototype.attr = function(name, value) {
|
d3_transitionPrototype.attr = function(name, value) {
|
||||||
return this.attrTween(name, d3_transitionTween(value));
|
return this.attrTween(name, d3_transitionTween(name, value));
|
||||||
};
|
};
|
||||||
|
|
||||||
d3_transitionPrototype.attrTween = function(name, tween) {
|
d3_transitionPrototype.attrTween = function(nameNS, tween) {
|
||||||
name = d3.ns.qualify(name);
|
var name = d3.ns.qualify(nameNS);
|
||||||
|
|
||||||
function attrTween(d, i) {
|
function attrTween(d, i) {
|
||||||
var f = tween.call(this, d, i, this.getAttribute(name));
|
var f = tween.call(this, d, i, this.getAttribute(name));
|
||||||
return f && function(t) {
|
return f === d3_transitionRemove
|
||||||
this.setAttribute(name, f(t));
|
? (this.removeAttribute(name), null)
|
||||||
};
|
: f && function(t) { this.setAttribute(name, f(t)); };
|
||||||
}
|
}
|
||||||
|
|
||||||
function attrTweenNS(d, i) {
|
function attrTweenNS(d, i) {
|
||||||
var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
|
var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
|
||||||
return f && function(t) {
|
return f === d3_transitionRemove
|
||||||
this.setAttributeNS(name.space, name.local, f(t));
|
? (this.removeAttributeNS(name.space, name.local), null)
|
||||||
};
|
: f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); };
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.tween("attr." + name, name.local ? attrTweenNS : attrTween);
|
return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,5 +18,5 @@ d3_transitionPrototype.select = function(selector) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return d3_transition(subgroups, this.id).ease(this.ease());
|
return d3_transition(subgroups, this.id, this.time).ease(this.ease());
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
d3_transitionPrototype.selectAll = function(selector) {
|
d3_transitionPrototype.selectAll = function(selector) {
|
||||||
var subgroups = [],
|
var subgroups = [],
|
||||||
subgroup,
|
subgroup,
|
||||||
|
subnodes,
|
||||||
node;
|
node;
|
||||||
|
|
||||||
if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
|
if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
|
||||||
|
@ -8,13 +9,14 @@ d3_transitionPrototype.selectAll = function(selector) {
|
||||||
for (var j = -1, m = this.length; ++j < m;) {
|
for (var j = -1, m = this.length; ++j < m;) {
|
||||||
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
|
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
|
||||||
if (node = group[i]) {
|
if (node = group[i]) {
|
||||||
subgroups.push(subgroup = selector.call(node.node, node.node.__data__, i));
|
subnodes = selector.call(node.node, node.node.__data__, i);
|
||||||
for (var k = -1, o = subgroup.length; ++k < o;) {
|
subgroups.push(subgroup = []);
|
||||||
subgroup[k] = {node: subgroup[k], delay: node.delay, duration: node.duration};
|
for (var k = -1, o = subnodes.length; ++k < o;) {
|
||||||
|
subgroup.push({node: subnodes[k], delay: node.delay, duration: node.duration});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return d3_transition(subgroups, this.id).ease(this.ease());
|
return d3_transition(subgroups, this.id, this.time).ease(this.ease());
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
d3_transitionPrototype.style = function(name, value, priority) {
|
d3_transitionPrototype.style = function(name, value, priority) {
|
||||||
if (arguments.length < 3) priority = null;
|
if (arguments.length < 3) priority = "";
|
||||||
return this.styleTween(name, d3_transitionTween(value), priority);
|
return this.styleTween(name, d3_transitionTween(name, value), priority);
|
||||||
};
|
};
|
||||||
|
|
||||||
d3_transitionPrototype.styleTween = function(name, tween, priority) {
|
d3_transitionPrototype.styleTween = function(name, tween, priority) {
|
||||||
if (arguments.length < 3) priority = null;
|
if (arguments.length < 3) priority = "";
|
||||||
return this.tween("style." + name, function(d, i) {
|
return this.tween("style." + name, function(d, i) {
|
||||||
var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
|
var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
|
||||||
return f && function(t) {
|
return f === d3_transitionRemove
|
||||||
this.style.setProperty(name, f(t), priority);
|
? (this.style.removeProperty(name), null)
|
||||||
};
|
: f && function(t) { this.style.setProperty(name, f(t), priority); };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
function d3_transition(groups, id) {
|
function d3_transition(groups, id, time) {
|
||||||
d3_arraySubclass(groups, d3_transitionPrototype);
|
d3_arraySubclass(groups, d3_transitionPrototype);
|
||||||
|
|
||||||
var tweens = {},
|
var tweens = {},
|
||||||
event = d3.dispatch("start", "end"),
|
event = d3.dispatch("start", "end"),
|
||||||
ease = d3_transitionEase,
|
ease = d3_transitionEase;
|
||||||
then = Date.now();
|
|
||||||
|
|
||||||
groups.id = id;
|
groups.id = id;
|
||||||
|
|
||||||
|
groups.time = time;
|
||||||
|
|
||||||
groups.tween = function(name, tween) {
|
groups.tween = function(name, tween) {
|
||||||
if (arguments.length < 2) return tweens[name];
|
if (arguments.length < 2) return tweens[name];
|
||||||
if (tween == null) delete tweens[name];
|
if (tween == null) delete tweens[name];
|
||||||
|
@ -23,7 +24,7 @@ function d3_transition(groups, id) {
|
||||||
|
|
||||||
groups.each = function(type, listener) {
|
groups.each = function(type, listener) {
|
||||||
if (arguments.length < 2) return d3_transition_each.call(groups, type);
|
if (arguments.length < 2) return d3_transition_each.call(groups, type);
|
||||||
event[type].add(listener);
|
event.on(type, listener);
|
||||||
return groups;
|
return groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,9 +38,9 @@ function d3_transition(groups, id) {
|
||||||
|
|
||||||
++lock.count;
|
++lock.count;
|
||||||
|
|
||||||
delay <= elapsed ? start() : d3.timer(start, delay, then);
|
delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time);
|
||||||
|
|
||||||
function start() {
|
function start(elapsed) {
|
||||||
if (lock.active > id) return stop();
|
if (lock.active > id) return stop();
|
||||||
lock.active = id;
|
lock.active = id;
|
||||||
|
|
||||||
|
@ -49,15 +50,15 @@ function d3_transition(groups, id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event.start.dispatch.call(node, d, i);
|
event.start.call(node, d, i);
|
||||||
d3.timer(tick, 0, then);
|
if (!tick(elapsed)) d3.timer(tick, 0, time);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function tick(elapsed) {
|
function tick(elapsed) {
|
||||||
if (lock.active !== id) return stop();
|
if (lock.active !== id) return stop();
|
||||||
|
|
||||||
var t = Math.min(1, (elapsed - delay) / duration),
|
var t = (elapsed - delay) / duration,
|
||||||
e = ease(t),
|
e = ease(t),
|
||||||
n = tweened.length;
|
n = tweened.length;
|
||||||
|
|
||||||
|
@ -65,10 +66,10 @@ function d3_transition(groups, id) {
|
||||||
tweened[--n].call(node, e);
|
tweened[--n].call(node, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t === 1) {
|
if (t >= 1) {
|
||||||
stop();
|
stop();
|
||||||
d3_transitionInheritId = id;
|
d3_transitionInheritId = id;
|
||||||
event.end.dispatch.call(node, d, i);
|
event.end.call(node, d, i);
|
||||||
d3_transitionInheritId = 0;
|
d3_transitionInheritId = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -80,15 +81,34 @@ function d3_transition(groups, id) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return 1;
|
return 1;
|
||||||
}, 0, then);
|
}, 0, time);
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
function d3_transitionTween(b) {
|
var d3_transitionRemove = {};
|
||||||
return typeof b === "function"
|
|
||||||
? function(d, i, a) { var v = b.call(this, d, i) + ""; return a != v && d3.interpolate(a, v); }
|
function d3_transitionNull(d, i, a) {
|
||||||
: (b = b + "", function(d, i, a) { return a != b && d3.interpolate(a, b); });
|
return a != "" && d3_transitionRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
function d3_transitionTween(name, b) {
|
||||||
|
var interpolate = d3_interpolateByName(name);
|
||||||
|
|
||||||
|
function transitionFunction(d, i, a) {
|
||||||
|
var v = b.call(this, d, i);
|
||||||
|
return v == null
|
||||||
|
? a != "" && d3_transitionRemove
|
||||||
|
: a != v && interpolate(a, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transitionString(d, i, a) {
|
||||||
|
return a != b && interpolate(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeof b === "function" ? transitionFunction
|
||||||
|
: b == null ? d3_transitionNull
|
||||||
|
: (b += "", transitionString);
|
||||||
}
|
}
|
||||||
|
|
||||||
var d3_transitionPrototype = [],
|
var d3_transitionPrototype = [],
|
||||||
|
|
|
@ -7,27 +7,39 @@ d3.geo.albers = function() {
|
||||||
parallels = [29.5, 45.5],
|
parallels = [29.5, 45.5],
|
||||||
scale = 1000,
|
scale = 1000,
|
||||||
translate = [480, 250],
|
translate = [480, 250],
|
||||||
lng0, // d3_radians * origin[0]
|
lng0, // d3_geo_radians * origin[0]
|
||||||
n,
|
n,
|
||||||
C,
|
C,
|
||||||
p0;
|
p0;
|
||||||
|
|
||||||
function albers(coordinates) {
|
function albers(coordinates) {
|
||||||
var t = n * (d3_radians * coordinates[0] - lng0),
|
var t = n * (d3_geo_radians * coordinates[0] - lng0),
|
||||||
p = Math.sqrt(C - 2 * n * Math.sin(d3_radians * coordinates[1])) / n;
|
p = Math.sqrt(C - 2 * n * Math.sin(d3_geo_radians * coordinates[1])) / n;
|
||||||
return [
|
return [
|
||||||
scale * p * Math.sin(t) + translate[0],
|
scale * p * Math.sin(t) + translate[0],
|
||||||
scale * (p * Math.cos(t) - p0) + translate[1]
|
scale * (p * Math.cos(t) - p0) + translate[1]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
albers.invert = function(coordinates) {
|
||||||
|
var x = (coordinates[0] - translate[0]) / scale,
|
||||||
|
y = (coordinates[1] - translate[1]) / scale,
|
||||||
|
p0y = p0 + y,
|
||||||
|
t = Math.atan2(x, p0y),
|
||||||
|
p = Math.sqrt(x * x + p0y * p0y);
|
||||||
|
return [
|
||||||
|
(lng0 + t / n) / d3_geo_radians,
|
||||||
|
Math.asin((C - p * p * n * n) / (2 * n)) / d3_geo_radians
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
function reload() {
|
function reload() {
|
||||||
var phi1 = d3_radians * parallels[0],
|
var phi1 = d3_geo_radians * parallels[0],
|
||||||
phi2 = d3_radians * parallels[1],
|
phi2 = d3_geo_radians * parallels[1],
|
||||||
lat0 = d3_radians * origin[1],
|
lat0 = d3_geo_radians * origin[1],
|
||||||
s = Math.sin(phi1),
|
s = Math.sin(phi1),
|
||||||
c = Math.cos(phi1);
|
c = Math.cos(phi1);
|
||||||
lng0 = d3_radians * origin[0];
|
lng0 = d3_geo_radians * origin[0];
|
||||||
n = .5 * (s + Math.sin(phi2));
|
n = .5 * (s + Math.sin(phi2));
|
||||||
C = c * c + 2 * n * s;
|
C = c * c + 2 * n * s;
|
||||||
p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n;
|
p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n;
|
||||||
|
@ -112,5 +124,3 @@ d3.geo.albersUsa = function() {
|
||||||
|
|
||||||
return albersUsa.scale(lower48.scale());
|
return albersUsa.scale(lower48.scale());
|
||||||
};
|
};
|
||||||
|
|
||||||
var d3_radians = Math.PI / 180;
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче