This commit is contained in:
Mike Bostock 2011-08-29 11:56:58 -07:00
Родитель cd135d5e90 0d6c2e7692
Коммит 082beb1eb9
27 изменённых файлов: 656 добавлений и 124 удалений

Просмотреть файл

@ -36,9 +36,9 @@ d3.custom.js: \
src/end.js
d3.core.js: \
src/compat/date.js \
src/compat/style.js \
src/core/core.js \
src/core/date.js \
src/core/object.js \
src/core/array.js \
src/core/this.js \
src/core/functor.js \
@ -185,6 +185,7 @@ d3.geo.js: \
src/geo/mercator.js \
src/geo/path.js \
src/geo/bounds.js \
src/geo/greatCircle.js \
src/end.js
d3.csv.js: \

133
d3.geo.js
Просмотреть файл

@ -17,7 +17,7 @@ d3.geo.azimuthal = function() {
sx1 = Math.sin(x1),
cy1 = Math.cos(y1),
sy1 = Math.sin(y1),
k = mode == "stereographic" ? 1 / (1 + sy0 * sy1 + cy0 * cy1 * cx1) : 1,
k = mode === "stereographic" ? 1 / (1 + sy0 * sy1 + cy0 * cy1 * cx1) : 1,
x = k * cy1 * sx1,
y = k * (sy0 * cy1 * cx1 - cy0 * sy1);
return [
@ -26,9 +26,22 @@ 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) : Math.asin(p),
sc = Math.sin(c),
cc = Math.cos(c);
return [
(x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_radians,
Math.asin(cc * sy0 - (y * sc * cy0) / p) / d3_radians
];
};
azimuthal.mode = function(x) {
if (!arguments.length) return mode;
mode = x;
mode = x + "";
return azimuthal;
};
@ -79,6 +92,18 @@ d3.geo.albers = function() {
];
}
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_radians,
Math.asin((C - p * p * n * n) / (2 * n)) / d3_radians
];
};
function reload() {
var phi1 = d3_radians * parallels[0],
phi2 = d3_radians * parallels[1],
@ -177,14 +202,23 @@ d3.geo.mercator = function() {
translate = [480, 250];
function mercator(coordinates) {
var x = (coordinates[0]) / 360,
y = (-180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + coordinates[1] * Math.PI / 360))) / 360;
var x = coordinates[0] / 360,
y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_radians / 2)) / d3_radians) / 360;
return [
scale * x + translate[0],
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_radians)) / d3_radians - 90
];
};
mercator.scale = function(x) {
if (!arguments.length) return scale;
scale = +x;
@ -564,4 +598,95 @@ function d3_geo_boundsPolygon(o, f) {
f.apply(null, a[i]);
}
}
// From http://williams.best.vwh.net/avform.htm#Intermediate
d3.geo.greatCircle = function() {
var source = d3_geo_greatCircleSource,
target = d3_geo_greatCircleTarget,
n = 100,
radius = 6371; // Mean radius of Earth, in km.
// TODO: breakAtDateLine?
function greatCircle(d, i) {
var from = source.call(this, d, i),
to = target.call(this, d, i),
x0 = from[0] * d3_radians,
y0 = from[1] * d3_radians,
x1 = to[0] * d3_radians,
y1 = to[1] * d3_radians,
cx0 = Math.cos(x0), sx0 = Math.sin(x0),
cy0 = Math.cos(y0), sy0 = Math.sin(y0),
cx1 = Math.cos(x1), sx1 = Math.sin(x1),
cy1 = Math.cos(y1), sy1 = Math.sin(y1),
d = Math.acos(sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)),
sd = Math.sin(d),
f = d / (n - 1),
e = -f,
path = [],
i = -1;
while (++i < n) {
e += f;
var A = Math.sin(d - e) / sd,
B = Math.sin(e) / sd,
x = A * cy0 * cx0 + B * cy1 * cx1,
y = A * cy0 * sx0 + B * cy1 * sx1,
z = A * sy0 + B * sy1;
path[i] = [
Math.atan2(y, x) / d3_radians,
Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians
];
}
return path;
}
greatCircle.source = function(x) {
if (!arguments.length) return source;
source = x;
return greatCircle;
};
greatCircle.target = function(x) {
if (!arguments.length) return target;
target = x;
return greatCircle;
};
greatCircle.n = function(x) {
if (!arguments.length) return n;
n = +x;
return greatCircle;
};
greatCircle.radius = function(x) {
if (!arguments.length) return radius;
radius = +x;
return greatCircle;
};
// Haversine formula for great-circle distance.
greatCircle.distance = function(d, i) {
var from = source.call(this, d, i),
to = target.call(this, d, i),
x0 = from[0] * d3_radians,
y0 = from[1] * d3_radians,
x1 = to[0] * d3_radians,
y1 = to[1] * d3_radians,
sy = Math.sin((y1 - y0) / 2),
sx = Math.sin((x1 - x0) / 2),
a = sy * sy + Math.cos(y0) * Math.cos(y1) * sx * sx;
return radius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
};
return greatCircle;
};
function d3_geo_greatCircleSource(d) {
return d.source;
}
function d3_geo_greatCircleTarget(d) {
return d.target;
}
})();

2
d3.geo.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

59
d3.js поставляемый
Просмотреть файл

@ -1,12 +1,16 @@
(function(){d3 = {version: "2.0.4"}; // semver
if (!Date.now) Date.now = function() {
(function(){if (!Date.now) Date.now = function() {
return +new Date;
};
if (!Object.create) Object.create = function(o) {
/** @constructor */ function f() {}
f.prototype = o;
return new f;
};
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);
};
}
d3 = {version: "2.1.0"}; // semver
var d3_arraySubclass = [].__proto__?
// Until ECMAScript supports array subclassing, prototype injection works well.
@ -1780,7 +1784,7 @@ function d3_transition(groups, id) {
delay <= elapsed ? start() : d3.timer(start, delay, then);
function start() {
function start(elapsed) {
if (lock.active > id) return stop();
lock.active = id;
@ -1791,7 +1795,7 @@ function d3_transition(groups, id) {
}
event.start.dispatch.call(node, d, i);
d3.timer(tick, 0, then);
if (!tick(elapsed)) d3.timer(tick, 0, then);
return 1;
}
@ -1910,12 +1914,12 @@ d3_transitionPrototype.attrTween = function(name, tween) {
return this.tween("attr." + name, name.local ? attrTweenNS : attrTween);
};
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);
};
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) {
var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
return f && function(t) {
@ -2368,23 +2372,24 @@ d3.scale.sqrt = function() {
return d3.scale.pow().exponent(.5);
};
d3.scale.ordinal = function() {
return d3_scale_ordinal({}, 0, {t: "range", x: []});
return d3_scale_ordinal([], {t: "range", x: []});
};
function d3_scale_ordinal(domain, size, ranger) {
var range,
function d3_scale_ordinal(domain, ranger) {
var index,
range,
rangeBand;
function scale(x) {
return range[((domain[x] || (domain[x] = ++size)) - 1) % range.length];
return range[((index[x] || (index[x] = domain.push(x))) - 1) % range.length];
}
scale.domain = function(x) {
if (!arguments.length) return d3.keys(domain);
domain = {};
size = 0;
if (!arguments.length) return domain;
domain = [];
index = {};
var i = -1, n = x.length, xi;
while (++i < n) if (!domain[xi = x[i]]) domain[xi] = ++size;
while (++i < n) if (!index[xi = x[i]]) index[xi] = domain.push(xi);
return scale[ranger.t](ranger.x, ranger.p);
};
@ -2400,8 +2405,8 @@ function d3_scale_ordinal(domain, size, ranger) {
if (arguments.length < 2) padding = 0;
var start = x[0],
stop = x[1],
step = (stop - start) / (size - 1 + padding);
range = size < 2 ? [(start + stop) / 2] : d3.range(start + step * padding / 2, stop + step / 2, step);
step = (stop - start) / (domain.length - 1 + padding);
range = domain.length < 2 ? [(start + stop) / 2] : d3.range(start + step * padding / 2, stop + step / 2, step);
rangeBand = 0;
ranger = {t: "rangePoints", x: x, p: padding};
return scale;
@ -2411,7 +2416,7 @@ function d3_scale_ordinal(domain, size, ranger) {
if (arguments.length < 2) padding = 0;
var start = x[0],
stop = x[1],
step = (stop - start) / (size + padding);
step = (stop - start) / (domain.length + padding);
range = d3.range(start + step * padding, stop, step);
rangeBand = step * (1 - padding);
ranger = {t: "rangeBands", x: x, p: padding};
@ -2422,8 +2427,8 @@ function d3_scale_ordinal(domain, size, ranger) {
if (arguments.length < 2) padding = 0;
var start = x[0],
stop = x[1],
step = Math.floor((stop - start) / (size + padding)),
err = stop - start - (size - padding) * step;
step = Math.floor((stop - start) / (domain.length + padding)),
err = stop - start - (domain.length - padding) * step;
range = d3.range(start + Math.round(err / 2), stop, step);
rangeBand = Math.round(step * (1 - padding));
ranger = {t: "rangeRoundBands", x: x, p: padding};
@ -2435,12 +2440,10 @@ function d3_scale_ordinal(domain, size, ranger) {
};
scale.copy = function() {
var copy = {}, x;
for (x in domain) copy[x] = domain[x];
return d3_scale_ordinal(copy, size, ranger);
return d3_scale_ordinal(domain, ranger);
};
return scale[ranger.t](ranger.x, ranger.p);
return scale.domain(domain);
};
/*
* This product includes color specifications and designs developed by Cynthia

Просмотреть файл

@ -233,15 +233,15 @@ d3.layout.force = function() {
/* Barnes-Hut criterion. */
if ((x2 - x1) * dn < theta) {
var k = kc * quad.count * dn * dn;
node.x += dx * k;
node.y += dy * k;
node.px -= dx * k;
node.py -= dy * k;
return true;
}
if (quad.point && isFinite(dn)) {
var k = kc * dn * dn;
node.x += dx * k;
node.y += dy * k;
node.px -= dx * k;
node.py -= dy * k;
}
}
};
@ -250,12 +250,13 @@ d3.layout.force = function() {
function tick() {
var n = nodes.length,
m = links.length,
q = d3.geom.quadtree(nodes),
q,
i, // current index
o, // current object
s, // current source
t, // current target
l, // current distance
k, // current force
x, // x-distance
y; // y-distance
@ -270,30 +271,32 @@ d3.layout.force = function() {
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
x *= l;
y *= l;
t.x -= x / t.weight;
t.y -= y / t.weight;
s.x += x / s.weight;
s.y += y / s.weight;
t.x -= x * (k = s.weight / (t.weight + s.weight));
t.y -= y * k;
s.x += x * (k = 1 - k);
s.y += y * k;
}
}
// apply gravity forces
var kg = alpha * gravity;
x = size[0] / 2;
y = size[1] / 2;
i = -1; while (++i < n) {
o = nodes[i];
o.x += (x - o.x) * kg;
o.y += (y - o.y) * kg;
if (k = alpha * gravity) {
x = size[0] / 2;
y = size[1] / 2;
i = -1; if (k) while (++i < n) {
o = nodes[i];
o.x += (x - o.x) * k;
o.y += (y - o.y) * k;
}
}
// compute quadtree center of mass
d3_layout_forceAccumulate(q);
// apply charge forces
var kc = alpha * charge;
i = -1; while (++i < n) {
q.visit(repulse(nodes[i], kc));
// compute quadtree center of mass and apply charge forces
if (k = alpha * charge) {
d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes));
i = -1; while (++i < n) {
if (!(o = nodes[i]).fixed) {
q.visit(repulse(o, k));
}
}
}
// position verlet integration

2
d3.layout.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

4
d3.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -9,7 +9,8 @@ var vis = d3.select("#chart")
d3.json("miserables.json", function(json) {
var force = d3.layout.force()
.charge(-60)
.charge(-120)
.linkDistance(30)
.nodes(json.nodes)
.links(json.links)
.size([w, h])

Просмотреть файл

9
src/compat/style.js Normal file
Просмотреть файл

@ -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 +1 @@
d3 = {version: "2.0.4"}; // semver
d3 = {version: "2.1.0"}; // semver

Просмотреть файл

@ -1,5 +0,0 @@
if (!Object.create) Object.create = function(o) {
/** @constructor */ function f() {}
f.prototype = o;
return new f;
};

Просмотреть файл

@ -1,10 +1,10 @@
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);
};
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) {
var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
return f && function(t) {

Просмотреть файл

@ -39,7 +39,7 @@ function d3_transition(groups, id) {
delay <= elapsed ? start() : d3.timer(start, delay, then);
function start() {
function start(elapsed) {
if (lock.active > id) return stop();
lock.active = id;
@ -50,7 +50,7 @@ function d3_transition(groups, id) {
}
event.start.dispatch.call(node, d, i);
d3.timer(tick, 0, then);
if (!tick(elapsed)) d3.timer(tick, 0, then);
return 1;
}

Просмотреть файл

@ -21,6 +21,18 @@ d3.geo.albers = function() {
];
}
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_radians,
Math.asin((C - p * p * n * n) / (2 * n)) / d3_radians
];
};
function reload() {
var phi1 = d3_radians * parallels[0],
phi2 = d3_radians * parallels[1],

Просмотреть файл

@ -16,7 +16,7 @@ d3.geo.azimuthal = function() {
sx1 = Math.sin(x1),
cy1 = Math.cos(y1),
sy1 = Math.sin(y1),
k = mode == "stereographic" ? 1 / (1 + sy0 * sy1 + cy0 * cy1 * cx1) : 1,
k = mode === "stereographic" ? 1 / (1 + sy0 * sy1 + cy0 * cy1 * cx1) : 1,
x = k * cy1 * sx1,
y = k * (sy0 * cy1 * cx1 - cy0 * sy1);
return [
@ -25,9 +25,22 @@ 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) : Math.asin(p),
sc = Math.sin(c),
cc = Math.cos(c);
return [
(x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_radians,
Math.asin(cc * sy0 - (y * sc * cy0) / p) / d3_radians
];
};
azimuthal.mode = function(x) {
if (!arguments.length) return mode;
mode = x;
mode = x + "";
return azimuthal;
};

91
src/geo/greatCircle.js Normal file
Просмотреть файл

@ -0,0 +1,91 @@
// From http://williams.best.vwh.net/avform.htm#Intermediate
d3.geo.greatCircle = function() {
var source = d3_geo_greatCircleSource,
target = d3_geo_greatCircleTarget,
n = 100,
radius = 6371; // Mean radius of Earth, in km.
// TODO: breakAtDateLine?
function greatCircle(d, i) {
var from = source.call(this, d, i),
to = target.call(this, d, i),
x0 = from[0] * d3_radians,
y0 = from[1] * d3_radians,
x1 = to[0] * d3_radians,
y1 = to[1] * d3_radians,
cx0 = Math.cos(x0), sx0 = Math.sin(x0),
cy0 = Math.cos(y0), sy0 = Math.sin(y0),
cx1 = Math.cos(x1), sx1 = Math.sin(x1),
cy1 = Math.cos(y1), sy1 = Math.sin(y1),
d = Math.acos(sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)),
sd = Math.sin(d),
f = d / (n - 1),
e = -f,
path = [],
i = -1;
while (++i < n) {
e += f;
var A = Math.sin(d - e) / sd,
B = Math.sin(e) / sd,
x = A * cy0 * cx0 + B * cy1 * cx1,
y = A * cy0 * sx0 + B * cy1 * sx1,
z = A * sy0 + B * sy1;
path[i] = [
Math.atan2(y, x) / d3_radians,
Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians
];
}
return path;
}
greatCircle.source = function(x) {
if (!arguments.length) return source;
source = x;
return greatCircle;
};
greatCircle.target = function(x) {
if (!arguments.length) return target;
target = x;
return greatCircle;
};
greatCircle.n = function(x) {
if (!arguments.length) return n;
n = +x;
return greatCircle;
};
greatCircle.radius = function(x) {
if (!arguments.length) return radius;
radius = +x;
return greatCircle;
};
// Haversine formula for great-circle distance.
greatCircle.distance = function(d, i) {
var from = source.call(this, d, i),
to = target.call(this, d, i),
x0 = from[0] * d3_radians,
y0 = from[1] * d3_radians,
x1 = to[0] * d3_radians,
y1 = to[1] * d3_radians,
sy = Math.sin((y1 - y0) / 2),
sx = Math.sin((x1 - x0) / 2),
a = sy * sy + Math.cos(y0) * Math.cos(y1) * sx * sx;
return radius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
};
return greatCircle;
};
function d3_geo_greatCircleSource(d) {
return d.source;
}
function d3_geo_greatCircleTarget(d) {
return d.target;
}

Просмотреть файл

@ -3,14 +3,23 @@ d3.geo.mercator = function() {
translate = [480, 250];
function mercator(coordinates) {
var x = (coordinates[0]) / 360,
y = (-180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + coordinates[1] * Math.PI / 360))) / 360;
var x = coordinates[0] / 360,
y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_radians / 2)) / d3_radians) / 360;
return [
scale * x + translate[0],
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_radians)) / d3_radians - 90
];
};
mercator.scale = function(x) {
if (!arguments.length) return scale;
scale = +x;

Просмотреть файл

@ -27,15 +27,15 @@ d3.layout.force = function() {
/* Barnes-Hut criterion. */
if ((x2 - x1) * dn < theta) {
var k = kc * quad.count * dn * dn;
node.x += dx * k;
node.y += dy * k;
node.px -= dx * k;
node.py -= dy * k;
return true;
}
if (quad.point && isFinite(dn)) {
var k = kc * dn * dn;
node.x += dx * k;
node.y += dy * k;
node.px -= dx * k;
node.py -= dy * k;
}
}
};
@ -44,12 +44,13 @@ d3.layout.force = function() {
function tick() {
var n = nodes.length,
m = links.length,
q = d3.geom.quadtree(nodes),
q,
i, // current index
o, // current object
s, // current source
t, // current target
l, // current distance
k, // current force
x, // x-distance
y; // y-distance
@ -64,30 +65,32 @@ d3.layout.force = function() {
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
x *= l;
y *= l;
t.x -= x / t.weight;
t.y -= y / t.weight;
s.x += x / s.weight;
s.y += y / s.weight;
t.x -= x * (k = s.weight / (t.weight + s.weight));
t.y -= y * k;
s.x += x * (k = 1 - k);
s.y += y * k;
}
}
// apply gravity forces
var kg = alpha * gravity;
x = size[0] / 2;
y = size[1] / 2;
i = -1; while (++i < n) {
o = nodes[i];
o.x += (x - o.x) * kg;
o.y += (y - o.y) * kg;
if (k = alpha * gravity) {
x = size[0] / 2;
y = size[1] / 2;
i = -1; if (k) while (++i < n) {
o = nodes[i];
o.x += (x - o.x) * k;
o.y += (y - o.y) * k;
}
}
// compute quadtree center of mass
d3_layout_forceAccumulate(q);
// apply charge forces
var kc = alpha * charge;
i = -1; while (++i < n) {
q.visit(repulse(nodes[i], kc));
// compute quadtree center of mass and apply charge forces
if (k = alpha * charge) {
d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes));
i = -1; while (++i < n) {
if (!(o = nodes[i]).fixed) {
q.visit(repulse(o, k));
}
}
}
// position verlet integration

Просмотреть файл

@ -1,21 +1,22 @@
d3.scale.ordinal = function() {
return d3_scale_ordinal({}, 0, {t: "range", x: []});
return d3_scale_ordinal([], {t: "range", x: []});
};
function d3_scale_ordinal(domain, size, ranger) {
var range,
function d3_scale_ordinal(domain, ranger) {
var index,
range,
rangeBand;
function scale(x) {
return range[((domain[x] || (domain[x] = ++size)) - 1) % range.length];
return range[((index[x] || (index[x] = domain.push(x))) - 1) % range.length];
}
scale.domain = function(x) {
if (!arguments.length) return d3.keys(domain);
domain = {};
size = 0;
if (!arguments.length) return domain;
domain = [];
index = {};
var i = -1, n = x.length, xi;
while (++i < n) if (!domain[xi = x[i]]) domain[xi] = ++size;
while (++i < n) if (!index[xi = x[i]]) index[xi] = domain.push(xi);
return scale[ranger.t](ranger.x, ranger.p);
};
@ -31,8 +32,8 @@ function d3_scale_ordinal(domain, size, ranger) {
if (arguments.length < 2) padding = 0;
var start = x[0],
stop = x[1],
step = (stop - start) / (size - 1 + padding);
range = size < 2 ? [(start + stop) / 2] : d3.range(start + step * padding / 2, stop + step / 2, step);
step = (stop - start) / (domain.length - 1 + padding);
range = domain.length < 2 ? [(start + stop) / 2] : d3.range(start + step * padding / 2, stop + step / 2, step);
rangeBand = 0;
ranger = {t: "rangePoints", x: x, p: padding};
return scale;
@ -42,7 +43,7 @@ function d3_scale_ordinal(domain, size, ranger) {
if (arguments.length < 2) padding = 0;
var start = x[0],
stop = x[1],
step = (stop - start) / (size + padding);
step = (stop - start) / (domain.length + padding);
range = d3.range(start + step * padding, stop, step);
rangeBand = step * (1 - padding);
ranger = {t: "rangeBands", x: x, p: padding};
@ -53,8 +54,8 @@ function d3_scale_ordinal(domain, size, ranger) {
if (arguments.length < 2) padding = 0;
var start = x[0],
stop = x[1],
step = Math.floor((stop - start) / (size + padding)),
err = stop - start - (size - padding) * step;
step = Math.floor((stop - start) / (domain.length + padding)),
err = stop - start - (domain.length - padding) * step;
range = d3.range(start + Math.round(err / 2), stop, step);
rangeBand = Math.round(step * (1 - padding));
ranger = {t: "rangeRoundBands", x: x, p: padding};
@ -66,10 +67,8 @@ function d3_scale_ordinal(domain, size, ranger) {
};
scale.copy = function() {
var copy = {}, x;
for (x in domain) copy[x] = domain[x];
return d3_scale_ordinal(copy, size, ranger);
return d3_scale_ordinal(domain, ranger);
};
return scale[ranger.t](ranger.x, ranger.p);
return scale.domain(domain);
};

Просмотреть файл

@ -17,7 +17,7 @@ suite.addBatch({
},
"sets a property as a number": function(body) {
body.style("opacity", .3);
assert.equal(document.body.style["opacity"], ".3");
assert.equal(document.body.style["opacity"], "0.3");
},
"sets a property as a function": function(body) {
body.style("background-color", function() { return "orange"; });
@ -57,8 +57,8 @@ suite.addBatch({
},
"sets a property as a number": function(div) {
div.style("opacity", .5);
assert.equal(div[0][0].style["opacity"], ".5");
assert.equal(div[0][1].style["opacity"], ".5");
assert.equal(div[0][0].style["opacity"], "0.5");
assert.equal(div[0][1].style["opacity"], "0.5");
},
"sets a property as a function": function(div) {
div.style("background-color", d3.interpolateRgb("orange", "yellow"));

Просмотреть файл

@ -1,6 +1,7 @@
document = require("jsdom").jsdom("<html><head></head><body></body></html>");
window = document.createWindow();
navigator = window.navigator;
CSSStyleDeclaration = window.CSSStyleDeclaration;
require("../lib/sizzle/sizzle");
Sizzle = window.Sizzle;

57
test/geo/albers-test.js Normal file
Просмотреть файл

@ -0,0 +1,57 @@
require("../env");
require("../../d3");
require("../../d3.geo");
var vows = require("vows"),
assert = require("assert");
var suite = vows.describe("d3.geo.albers");
suite.addBatch({
"albers": {
topic: function() {
return d3.geo.albers();
},
"Arctic": function(albers) {
var coords = albers([0, 85]);
assert.inDelta(coords[0], 1031.393796, 1e-6);
assert.inDelta(coords[1], -714.160436, 1e-6);
var lonlat = albers.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
},
"Antarctic": function(albers) {
var coords = albers([0, -85]);
assert.inDelta(coords[0], 2753.458335, 1e-6);
assert.inDelta(coords[1], 317.371122, 1e-6);
var lonlat = albers.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], -85, 1e-6);
},
"Hawaii": function(albers) {
var coords = albers([-180, 0]);
assert.inDelta(coords[0], -984.779405, 1e-6);
assert.inDelta(coords[1], 209.571197, 1e-6);
var lonlat = albers.invert(coords);
assert.inDelta(lonlat[0], -180, 1e-6);
assert.inDelta(lonlat[1], 0, 1e-6);
},
"Phillipines": function(albers) {
var coords = albers([180, 0]);
assert.inDelta(coords[0], 894.435228, 1e-6);
assert.inDelta(coords[1], -2927.636630, 1e-6);
var lonlat = albers.invert(coords);
assert.inDelta(lonlat[0], 180, 1e-6);
assert.inDelta(lonlat[1], 0, 1e-6);
},
"Inversion works for non-zero translation": function() {
var albers = d3.geo.albers().translate([123, 99]).scale(100),
coords = albers([0, 85]),
lonlat = albers.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
}
}
});
suite.export(module);

Просмотреть файл

@ -0,0 +1,89 @@
require("../env");
require("../../d3");
require("../../d3.geo");
var vows = require("vows"),
assert = require("assert");
var suite = vows.describe("d3.geo.azimuthal");
suite.addBatch({
"azimuthal.stereographic": {
topic: function() {
return d3.geo.azimuthal().mode("stereographic").translate([0, 0]).scale(100);
},
"Arctic": function(azimuthal) {
var coords = azimuthal([0, 85]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], -91.633117, 1e-6);
var lonlat = azimuthal.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
},
"Antarctic": function(azimuthal) {
var coords = azimuthal([0, -85]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], 91.633117, 1e-6);
var lonlat = azimuthal.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], -85, 1e-6);
},
"Hawaii": function(azimuthal) {
var coords = azimuthal([-180, 0]);
assert.equal(coords[0], -Infinity);
assert.isTrue(isNaN(coords[1]));
},
"Phillipines": function(azimuthal) {
var coords = azimuthal([180, 0]);
assert.equal(coords[0], Infinity);
assert.isTrue(isNaN(coords[1]));
},
"Inversion works for non-zero translation": function() {
var azimuthal = d3.geo.azimuthal().mode("stereographic").translate([123, 99]).scale(100),
coords = azimuthal([0, 85]),
lonlat = azimuthal.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
}
},
"azimuthal.orthographic": {
topic: function() {
return d3.geo.azimuthal().mode("orthographic").translate([0, 0]).scale(100);
},
"Arctic": function(azimuthal) {
var coords = azimuthal([0, 85]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], -99.619469, 1e-6);
var lonlat = azimuthal.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
},
"Antarctic": function(azimuthal) {
var coords = azimuthal([0, -85]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], 99.619469, 1e-6);
var lonlat = azimuthal.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], -85, 1e-6);
},
"Hawaii": function(azimuthal) {
var coords = azimuthal([-180, 0]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], 0, 1e-6);
},
"Phillipines": function(azimuthal) {
var coords = azimuthal([180, 0]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], 0, 1e-6);
},
"Inversion works for non-zero translation": function() {
var azimuthal = d3.geo.azimuthal().mode("orthographic").translate([123, 99]).scale(100),
coords = azimuthal([0, 85]),
lonlat = azimuthal.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
}
}
});
suite.export(module);

Просмотреть файл

@ -0,0 +1,42 @@
require("../env");
require("../../d3");
require("../../d3.geo");
var vows = require("vows"),
assert = require("assert");
var suite = vows.describe("d3.geo.greatCircle");
suite.addBatch({
"greatCircle": {
topic: function() {
return d3.geo.greatCircle()
.n(12);
},
"distance": function(circle) {
assert.equal(circle.distance({source: [0, 0], target: [0, 0]}), 0);
assert.inDelta(circle.distance({
source: [118 + 24 / 60, 33 + 57 / 60],
target: [ 73 + 47 / 60, 40 + 38 / 60]
}), 3973, .5);
},
"geodesic": function(circle) {
assert.inDelta(circle({source: [5, 52], target: [-120, 37]}), [
[ 5, 52 ],
[ -3.805036, 57.05083],
[ -15.122869, 61.30118],
[ -29.396213, 64.34584],
[ -46.132729, 65.72409],
[ -63.394401, 65.15597],
[ -78.854311, 62.76337],
[ -91.401599, 58.96701],
[-101.190927, 54.21333],
[-108.843633, 48.83586],
[-114.961152, 43.05231],
[-120, 37 ]
], .5);
}
}
});
suite.export(module);

57
test/geo/mercator-test.js Normal file
Просмотреть файл

@ -0,0 +1,57 @@
require("../env");
require("../../d3");
require("../../d3.geo");
var vows = require("vows"),
assert = require("assert");
var suite = vows.describe("d3.geo.mercator");
suite.addBatch({
"mercator": {
topic: function() {
return d3.geo.mercator().translate([0, 0]).scale(100);
},
"Arctic": function(mercator) {
var coords = mercator([0, 85]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], -49.8362085, 1e-6);
var lonlat = mercator.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
},
"Antarctic": function(mercator) {
var coords = mercator([0, -85]);
assert.inDelta(coords[0], 0, 1e-6);
assert.inDelta(coords[1], 49.8362085, 1e-6);
var lonlat = mercator.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], -85, 1e-6);
},
"Hawaii": function(mercator) {
var coords = mercator([-180, 0]);
assert.inDelta(coords[0], -50, 1e-6);
assert.inDelta(coords[1], 0, 1e-6);
var lonlat = mercator.invert(coords);
assert.inDelta(lonlat[0], -180, 1e-6);
assert.inDelta(lonlat[1], 0, 1e-6);
},
"Phillipines": function(mercator) {
var coords = mercator([180, 0]);
assert.inDelta(coords[0], 50, 1e-6);
assert.inDelta(coords[1], 0, 1e-6);
var lonlat = mercator.invert(coords);
assert.inDelta(lonlat[0], 180, 1e-6);
assert.inDelta(lonlat[1], 0, 1e-6);
},
"Inversion works for non-zero translation": function() {
var mercator = d3.geo.mercator().translate([123, 99]).scale(100),
coords = mercator([0, 85]),
lonlat = mercator.invert(coords);
assert.inDelta(lonlat[0], 0, 1e-6);
assert.inDelta(lonlat[1], 85, 1e-6);
}
}
});
suite.export(module);

Просмотреть файл

@ -29,17 +29,39 @@ suite.addBatch({
var x = ordinal().range(["foo", "bar"]);
assert.equal(x(1), "foo");
assert.equal(x(0), "bar");
assert.deepEqual(x.domain(), ["0", "1"]);
assert.deepEqual(x.domain(), [1, 0]);
x.domain(["0", "1"]);
assert.equal(x(0), "foo"); // it changed!
assert.equal(x(1), "bar");
assert.deepEqual(x.domain(), ["0", "1"]);
},
"coerces domain values to strings": function(ordinal) {
"uniqueness is based on string coercion": function(ordinal) {
var x = ordinal().domain(["foo"]).range([42, 43, 44]);
assert.equal(x(new String("foo")), 42);
assert.equal(x({toString: function() { return "foo"; }}), 42);
assert.equal(x({toString: function() { return "bar"; }}), 43);
},
"orders domain values by the order in which they are seen": function(ordinal) {
var x = ordinal();
x("foo");
x("bar");
x("baz");
assert.deepEqual(x.domain(), ["foo", "bar", "baz"]);
x.domain(["baz", "bar"]);
x("foo");
assert.deepEqual(x.domain(), ["baz", "bar", "foo"]);
x.domain(["baz", "foo"]);
assert.deepEqual(x.domain(), ["baz", "foo"]);
x.domain([]);
x("foo");
x("bar");
assert.deepEqual(x.domain(), ["foo", "bar"]);
},
"does not coerce domain values to strings": function(ordinal) {
var x = ordinal().domain([0, 1]);
assert.deepEqual(x.domain(), ["0", "1"]);
assert.typeOf(x.domain()[0], "string");
assert.typeOf(x.domain()[1], "string");
assert.deepEqual(x.domain(), [0, 1]);
assert.typeOf(x.domain()[0], "number");
assert.typeOf(x.domain()[1], "number");
}
},