Skip to content

Instantly share code, notes, and snippets.

@Thanaporn-sk
Created January 18, 2017 01:35
Show Gist options
  • Save Thanaporn-sk/4d8ab5e5d8feb16e9e3ba0b2c284a492 to your computer and use it in GitHub Desktop.
Save Thanaporn-sk/4d8ab5e5d8feb16e9e3ba0b2c284a492 to your computer and use it in GitHub Desktop.
Mutliple connected beeswarm plots
license: mit
// https://d3js.org Version 4.1.0. Copyright 2016 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, function (exports) { 'use strict';
var version = "4.1.0";
function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
function bisector(compare) {
if (compare.length === 1) compare = ascendingComparator(compare);
return {
left: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) < 0) lo = mid + 1;
else hi = mid;
}
return lo;
},
right: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) > 0) hi = mid;
else lo = mid + 1;
}
return lo;
}
};
}
function ascendingComparator(f) {
return function(d, x) {
return ascending(f(d), x);
};
}
var ascendingBisect = bisector(ascending);
var bisectRight = ascendingBisect.right;
var bisectLeft = ascendingBisect.left;
function descending(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
function number(x) {
return x === null ? NaN : +x;
}
function variance(array, f) {
var n = array.length,
m = 0,
a,
d,
s = 0,
i = -1,
j = 0;
if (f == null) {
while (++i < n) {
if (!isNaN(a = number(array[i]))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
}
else {
while (++i < n) {
if (!isNaN(a = number(f(array[i], i, array)))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
}
if (j > 1) return s / (j - 1);
}
function deviation(array, f) {
var v = variance(array, f);
return v ? Math.sqrt(v) : v;
}
function extent(array, f) {
var i = -1,
n = array.length,
a,
b,
c;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; }
while (++i < n) if ((b = array[i]) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = c = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
}
return [a, c];
}
var array = Array.prototype;
var slice = array.slice;
var map = array.map;
function constant(x) {
return function() {
return x;
};
}
function identity(x) {
return x;
}
function range(start, stop, step) {
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
var i = -1,
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
range = new Array(n);
while (++i < n) {
range[i] = start + i * step;
}
return range;
}
var e10 = Math.sqrt(50);
var e5 = Math.sqrt(10);
var e2 = Math.sqrt(2);
function ticks(start, stop, count) {
var step = tickStep(start, stop, count);
return range(
Math.ceil(start / step) * step,
Math.floor(stop / step) * step + step / 2, // inclusive
step
);
}
function tickStep(start, stop, count) {
var step0 = Math.abs(stop - start) / Math.max(0, count),
step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
error = step0 / step1;
if (error >= e10) step1 *= 10;
else if (error >= e5) step1 *= 5;
else if (error >= e2) step1 *= 2;
return stop < start ? -step1 : step1;
}
function sturges(values) {
return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
}
function histogram() {
var value = identity,
domain = extent,
threshold = sturges;
function histogram(data) {
var i,
n = data.length,
x,
values = new Array(n);
for (i = 0; i < n; ++i) {
values[i] = value(data[i], i, data);
}
var xz = domain(values),
x0 = xz[0],
x1 = xz[1],
tz = threshold(values, x0, x1);
// Convert number of thresholds into uniform thresholds.
if (!Array.isArray(tz)) tz = ticks(x0, x1, tz);
// Remove any thresholds outside the domain.
var m = tz.length;
while (tz[0] <= x0) tz.shift(), --m;
while (tz[m - 1] >= x1) tz.pop(), --m;
var bins = new Array(m + 1),
bin;
// Initialize bins.
for (i = 0; i <= m; ++i) {
bin = bins[i] = [];
bin.x0 = i > 0 ? tz[i - 1] : x0;
bin.x1 = i < m ? tz[i] : x1;
}
// Assign data to bins by value, ignoring any outside the domain.
for (i = 0; i < n; ++i) {
x = values[i];
if (x0 <= x && x <= x1) {
bins[bisectRight(tz, x, 0, m)].push(data[i]);
}
}
return bins;
}
histogram.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
};
histogram.domain = function(_) {
return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
};
histogram.thresholds = function(_) {
return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
};
return histogram;
}
function threshold(array, p, f) {
if (f == null) f = number;
if (!(n = array.length)) return;
if ((p = +p) <= 0 || n < 2) return +f(array[0], 0, array);
if (p >= 1) return +f(array[n - 1], n - 1, array);
var n,
h = (n - 1) * p,
i = Math.floor(h),
a = +f(array[i], i, array),
b = +f(array[i + 1], i + 1, array);
return a + (b - a) * (h - i);
}
function freedmanDiaconis(values, min, max) {
values = map.call(values, number).sort(ascending);
return Math.ceil((max - min) / (2 * (threshold(values, 0.75) - threshold(values, 0.25)) * Math.pow(values.length, -1 / 3)));
}
function scott(values, min, max) {
return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
}
function max(array, f) {
var i = -1,
n = array.length,
a,
b;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = array[i]) != null && b > a) a = b;
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null && b > a) a = b;
}
return a;
}
function mean(array, f) {
var s = 0,
n = array.length,
a,
i = -1,
j = n;
if (f == null) {
while (++i < n) if (!isNaN(a = number(array[i]))) s += a; else --j;
}
else {
while (++i < n) if (!isNaN(a = number(f(array[i], i, array)))) s += a; else --j;
}
if (j) return s / j;
}
function median(array, f) {
var numbers = [],
n = array.length,
a,
i = -1;
if (f == null) {
while (++i < n) if (!isNaN(a = number(array[i]))) numbers.push(a);
}
else {
while (++i < n) if (!isNaN(a = number(f(array[i], i, array)))) numbers.push(a);
}
return threshold(numbers.sort(ascending), 0.5);
}
function merge(arrays) {
var n = arrays.length,
m,
i = -1,
j = 0,
merged,
array;
while (++i < n) j += arrays[i].length;
merged = new Array(j);
while (--n >= 0) {
array = arrays[n];
m = array.length;
while (--m >= 0) {
merged[--j] = array[m];
}
}
return merged;
}
function min(array, f) {
var i = -1,
n = array.length,
a,
b;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = array[i]) != null && a > b) a = b;
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null && a > b) a = b;
}
return a;
}
function pairs(array) {
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
while (i < n) pairs[i] = [p, p = array[++i]];
return pairs;
}
function permute(array, indexes) {
var i = indexes.length, permutes = new Array(i);
while (i--) permutes[i] = array[indexes[i]];
return permutes;
}
function scan(array, compare) {
if (!(n = array.length)) return;
var i = 0,
n,
j = 0,
xi,
xj = array[j];
if (!compare) compare = ascending;
while (++i < n) if (compare(xi = array[i], xj) < 0 || compare(xj, xj) !== 0) xj = xi, j = i;
if (compare(xj, xj) === 0) return j;
}
function shuffle(array, i0, i1) {
var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
t,
i;
while (m) {
i = Math.random() * m-- | 0;
t = array[m + i0];
array[m + i0] = array[i + i0];
array[i + i0] = t;
}
return array;
}
function sum(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (f == null) {
while (++i < n) if (a = +array[i]) s += a; // Note: zero and null are equivalent.
}
else {
while (++i < n) if (a = +f(array[i], i, array)) s += a;
}
return s;
}
function transpose(matrix) {
if (!(n = matrix.length)) return [];
for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
row[j] = matrix[j][i];
}
}
return transpose;
}
function length(d) {
return d.length;
}
function zip() {
return transpose(arguments);
}
var prefix = "$";
function Map() {}
Map.prototype = map$1.prototype = {
constructor: Map,
has: function(key) {
return (prefix + key) in this;
},
get: function(key) {
return this[prefix + key];
},
set: function(key, value) {
this[prefix + key] = value;
return this;
},
remove: function(key) {
var property = prefix + key;
return property in this && delete this[property];
},
clear: function() {
for (var property in this) if (property[0] === prefix) delete this[property];
},
keys: function() {
var keys = [];
for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
return keys;
},
values: function() {
var values = [];
for (var property in this) if (property[0] === prefix) values.push(this[property]);
return values;
},
entries: function() {
var entries = [];
for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
return entries;
},
size: function() {
var size = 0;
for (var property in this) if (property[0] === prefix) ++size;
return size;
},
empty: function() {
for (var property in this) if (property[0] === prefix) return false;
return true;
},
each: function(f) {
for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
}
};
function map$1(object, f) {
var map = new Map;
// Copy constructor.
if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
// Index array by numeric index or specified key function.
else if (Array.isArray(object)) {
var i = -1,
n = object.length,
o;
if (f == null) while (++i < n) map.set(i, object[i]);
else while (++i < n) map.set(f(o = object[i], i, object), o);
}
// Convert object to map.
else if (object) for (var key in object) map.set(key, object[key]);
return map;
}
function nest() {
var keys = [],
sortKeys = [],
sortValues,
rollup,
nest;
function apply(array, depth, createResult, setResult) {
if (depth >= keys.length) return rollup != null
? rollup(array) : (sortValues != null
? array.sort(sortValues)
: array);
var i = -1,
n = array.length,
key = keys[depth++],
keyValue,
value,
valuesByKey = map$1(),
values,
result = createResult();
while (++i < n) {
if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
values.push(value);
} else {
valuesByKey.set(keyValue, [value]);
}
}
valuesByKey.each(function(values, key) {
setResult(result, key, apply(values, depth, createResult, setResult));
});
return result;
}
function entries(map, depth) {
if (++depth > keys.length) return map;
var array, sortKey = sortKeys[depth - 1];
if (rollup != null && depth >= keys.length) array = map.entries();
else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
}
return nest = {
object: function(array) { return apply(array, 0, createObject, setObject); },
map: function(array) { return apply(array, 0, createMap, setMap); },
entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
key: function(d) { keys.push(d); return nest; },
sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
sortValues: function(order) { sortValues = order; return nest; },
rollup: function(f) { rollup = f; return nest; }
};
}
function createObject() {
return {};
}
function setObject(object, key, value) {
object[key] = value;
}
function createMap() {
return map$1();
}
function setMap(map, key, value) {
map.set(key, value);
}
function Set() {}
var proto = map$1.prototype;
Set.prototype = set.prototype = {
constructor: Set,
has: proto.has,
add: function(value) {
value += "";
this[prefix + value] = value;
return this;
},
remove: proto.remove,
clear: proto.clear,
values: proto.keys,
size: proto.size,
empty: proto.empty,
each: proto.each
};
function set(object, f) {
var set = new Set;
// Copy constructor.
if (object instanceof Set) object.each(function(value) { set.add(value); });
// Otherwise, assume it’s an array.
else if (object) {
var i = -1, n = object.length;
if (f == null) while (++i < n) set.add(object[i]);
else while (++i < n) set.add(f(object[i], i, object));
}
return set;
}
function keys(map) {
var keys = [];
for (var key in map) keys.push(key);
return keys;
}
function values(map) {
var values = [];
for (var key in map) values.push(map[key]);
return values;
}
function entries(map) {
var entries = [];
for (var key in map) entries.push({key: key, value: map[key]});
return entries;
}
function uniform(min, max) {
min = min == null ? 0 : +min;
max = max == null ? 1 : +max;
if (arguments.length === 1) max = min, min = 0;
else max -= min;
return function() {
return Math.random() * max + min;
};
}
function normal(mu, sigma) {
var x, r;
mu = mu == null ? 0 : +mu;
sigma = sigma == null ? 1 : +sigma;
return function() {
var y;
// If available, use the second previously-generated uniform random.
if (x != null) y = x, x = null;
// Otherwise, generate a new x and y.
else do {
x = Math.random() * 2 - 1;
y = Math.random() * 2 - 1;
r = x * x + y * y;
} while (!r || r > 1);
return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
};
}
function logNormal() {
var randomNormal = normal.apply(this, arguments);
return function() {
return Math.exp(randomNormal());
};
}
function irwinHall(n) {
return function() {
for (var sum = 0, i = 0; i < n; ++i) sum += Math.random();
return sum;
};
}
function bates(n) {
var randomIrwinHall = irwinHall(n);
return function() {
return randomIrwinHall() / n;
};
}
function exponential(lambda) {
return function() {
return -Math.log(1 - Math.random()) / lambda;
};
}
function linear(t) {
return +t;
}
function quadIn(t) {
return t * t;
}
function quadOut(t) {
return t * (2 - t);
}
function quadInOut(t) {
return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
}
function cubicIn(t) {
return t * t * t;
}
function cubicOut(t) {
return --t * t * t + 1;
}
function easeCubicInOut(t) {
return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
}
var exponent = 3;
var polyIn = (function custom(e) {
e = +e;
function polyIn(t) {
return Math.pow(t, e);
}
polyIn.exponent = custom;
return polyIn;
})(exponent);
var polyOut = (function custom(e) {
e = +e;
function polyOut(t) {
return 1 - Math.pow(1 - t, e);
}
polyOut.exponent = custom;
return polyOut;
})(exponent);
var polyInOut = (function custom(e) {
e = +e;
function polyInOut(t) {
return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
}
polyInOut.exponent = custom;
return polyInOut;
})(exponent);
var pi = Math.PI;
var halfPi = pi / 2;
function sinIn(t) {
return 1 - Math.cos(t * halfPi);
}
function sinOut(t) {
return Math.sin(t * halfPi);
}
function sinInOut(t) {
return (1 - Math.cos(pi * t)) / 2;
}
function expIn(t) {
return Math.pow(2, 10 * t - 10);
}
function expOut(t) {
return 1 - Math.pow(2, -10 * t);
}
function expInOut(t) {
return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
}
function circleIn(t) {
return 1 - Math.sqrt(1 - t * t);
}
function circleOut(t) {
return Math.sqrt(1 - --t * t);
}
function circleInOut(t) {
return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
}
var b1 = 4 / 11;
var b2 = 6 / 11;
var b3 = 8 / 11;
var b4 = 3 / 4;
var b5 = 9 / 11;
var b6 = 10 / 11;
var b7 = 15 / 16;
var b8 = 21 / 22;
var b9 = 63 / 64;
var b0 = 1 / b1 / b1;
function bounceIn(t) {
return 1 - bounceOut(1 - t);
}
function bounceOut(t) {
return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
}
function bounceInOut(t) {
return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
}
var overshoot = 1.70158;
var backIn = (function custom(s) {
s = +s;
function backIn(t) {
return t * t * ((s + 1) * t - s);
}
backIn.overshoot = custom;
return backIn;
})(overshoot);
var backOut = (function custom(s) {
s = +s;
function backOut(t) {
return --t * t * ((s + 1) * t + s) + 1;
}
backOut.overshoot = custom;
return backOut;
})(overshoot);
var backInOut = (function custom(s) {
s = +s;
function backInOut(t) {
return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
}
backInOut.overshoot = custom;
return backInOut;
})(overshoot);
var tau = 2 * Math.PI;
var amplitude = 1;
var period = 0.3;
var elasticIn = (function custom(a, p) {
var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
function elasticIn(t) {
return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
}
elasticIn.amplitude = function(a) { return custom(a, p * tau); };
elasticIn.period = function(p) { return custom(a, p); };
return elasticIn;
})(amplitude, period);
var elasticOut = (function custom(a, p) {
var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
function elasticOut(t) {
return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
}
elasticOut.amplitude = function(a) { return custom(a, p * tau); };
elasticOut.period = function(p) { return custom(a, p); };
return elasticOut;
})(amplitude, period);
var elasticInOut = (function custom(a, p) {
var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
function elasticInOut(t) {
return ((t = t * 2 - 1) < 0
? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
: 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
}
elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
elasticInOut.period = function(p) { return custom(a, p); };
return elasticInOut;
})(amplitude, period);
function area(polygon) {
var i = -1,
n = polygon.length,
a,
b = polygon[n - 1],
area = 0;
while (++i < n) {
a = b;
b = polygon[i];
area += a[1] * b[0] - a[0] * b[1];
}
return area / 2;
}
function centroid(polygon) {
var i = -1,
n = polygon.length,
x = 0,
y = 0,
a,
b = polygon[n - 1],
c,
k = 0;
while (++i < n) {
a = b;
b = polygon[i];
k += c = a[0] * b[1] - b[0] * a[1];
x += (a[0] + b[0]) * c;
y += (a[1] + b[1]) * c;
}
return k *= 3, [x / k, y / k];
}
// Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
// the 3D cross product in a quadrant I Cartesian coordinate system (+x is
// right, +y is up). Returns a positive value if ABC is counter-clockwise,
// negative if clockwise, and zero if the points are collinear.
function cross(a, b, c) {
return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
}
function lexicographicOrder(a, b) {
return a[0] - b[0] || a[1] - b[1];
}
// Computes the upper convex hull per the monotone chain algorithm.
// Assumes points.length >= 3, is sorted by x, unique in y.
// Returns an array of indices into points in left-to-right order.
function computeUpperHullIndexes(points) {
var n = points.length,
indexes = [0, 1],
size = 2;
for (var i = 2; i < n; ++i) {
while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
indexes[size++] = i;
}
return indexes.slice(0, size); // remove popped points
}
function hull(points) {
if ((n = points.length) < 3) return null;
var i,
n,
sortedPoints = new Array(n),
flippedPoints = new Array(n);
for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
sortedPoints.sort(lexicographicOrder);
for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
var upperIndexes = computeUpperHullIndexes(sortedPoints),
lowerIndexes = computeUpperHullIndexes(flippedPoints);
// Construct the hull polygon, removing possible duplicate endpoints.
var skipLeft = lowerIndexes[0] === upperIndexes[0],
skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
hull = [];
// Add upper hull in right-to-l order.
// Then add lower hull in left-to-right order.
for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
return hull;
}
function contains(polygon, point) {
var n = polygon.length,
p = polygon[n - 1],
x = point[0], y = point[1],
x0 = p[0], y0 = p[1],
x1, y1,
inside = false;
for (var i = 0; i < n; ++i) {
p = polygon[i], x1 = p[0], y1 = p[1];
if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
x0 = x1, y0 = y1;
}
return inside;
}
function length$1(polygon) {
var i = -1,
n = polygon.length,
b = polygon[n - 1],
xa,
ya,
xb = b[0],
yb = b[1],
perimeter = 0;
while (++i < n) {
xa = xb;
ya = yb;
b = polygon[i];
xb = b[0];
yb = b[1];
xa -= xb;
ya -= yb;
perimeter += Math.sqrt(xa * xa + ya * ya);
}
return perimeter;
}
var pi$1 = Math.PI;
var tau$1 = 2 * pi$1;
var epsilon = 1e-6;
var tauEpsilon = tau$1 - epsilon;
function Path() {
this._x0 = this._y0 = // start of current subpath
this._x1 = this._y1 = null; // end of current subpath
this._ = [];
}
function path() {
return new Path;
}
Path.prototype = path.prototype = {
constructor: Path,
moveTo: function(x, y) {
this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y);
},
closePath: function() {
if (this._x1 !== null) {
this._x1 = this._x0, this._y1 = this._y0;
this._.push("Z");
}
},
lineTo: function(x, y) {
this._.push("L", this._x1 = +x, ",", this._y1 = +y);
},
quadraticCurveTo: function(x1, y1, x, y) {
this._.push("Q", +x1, ",", +y1, ",", this._x1 = +x, ",", this._y1 = +y);
},
bezierCurveTo: function(x1, y1, x2, y2, x, y) {
this._.push("C", +x1, ",", +y1, ",", +x2, ",", +y2, ",", this._x1 = +x, ",", this._y1 = +y);
},
arcTo: function(x1, y1, x2, y2, r) {
x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
var x0 = this._x1,
y0 = this._y1,
x21 = x2 - x1,
y21 = y2 - y1,
x01 = x0 - x1,
y01 = y0 - y1,
l01_2 = x01 * x01 + y01 * y01;
// Is the radius negative? Error.
if (r < 0) throw new Error("negative radius: " + r);
// Is this path empty? Move to (x1,y1).
if (this._x1 === null) {
this._.push(
"M", this._x1 = x1, ",", this._y1 = y1
);
}
// Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
else if (!(l01_2 > epsilon));
// Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
// Equivalently, is (x1,y1) coincident with (x2,y2)?
// Or, is the radius zero? Line to (x1,y1).
else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {
this._.push(
"L", this._x1 = x1, ",", this._y1 = y1
);
}
// Otherwise, draw an arc!
else {
var x20 = x2 - x0,
y20 = y2 - y0,
l21_2 = x21 * x21 + y21 * y21,
l20_2 = x20 * x20 + y20 * y20,
l21 = Math.sqrt(l21_2),
l01 = Math.sqrt(l01_2),
l = r * Math.tan((pi$1 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
t01 = l / l01,
t21 = l / l21;
// If the start tangent is not coincident with (x0,y0), line to.
if (Math.abs(t01 - 1) > epsilon) {
this._.push(
"L", x1 + t01 * x01, ",", y1 + t01 * y01
);
}
this._.push(
"A", r, ",", r, ",0,0,", +(y01 * x20 > x01 * y20), ",", this._x1 = x1 + t21 * x21, ",", this._y1 = y1 + t21 * y21
);
}
},
arc: function(x, y, r, a0, a1, ccw) {
x = +x, y = +y, r = +r;
var dx = r * Math.cos(a0),
dy = r * Math.sin(a0),
x0 = x + dx,
y0 = y + dy,
cw = 1 ^ ccw,
da = ccw ? a0 - a1 : a1 - a0;
// Is the radius negative? Error.
if (r < 0) throw new Error("negative radius: " + r);
// Is this path empty? Move to (x0,y0).
if (this._x1 === null) {
this._.push(
"M", x0, ",", y0
);
}
// Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {
this._.push(
"L", x0, ",", y0
);
}
// Is this arc empty? We’re done.
if (!r) return;
// Is this a complete circle? Draw two arcs to complete the circle.
if (da > tauEpsilon) {
this._.push(
"A", r, ",", r, ",0,1,", cw, ",", x - dx, ",", y - dy,
"A", r, ",", r, ",0,1,", cw, ",", this._x1 = x0, ",", this._y1 = y0
);
}
// Otherwise, draw an arc!
else {
if (da < 0) da = da % tau$1 + tau$1;
this._.push(
"A", r, ",", r, ",0,", +(da >= pi$1), ",", cw, ",", this._x1 = x + r * Math.cos(a1), ",", this._y1 = y + r * Math.sin(a1)
);
}
},
rect: function(x, y, w, h) {
this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y, "h", +w, "v", +h, "h", -w, "Z");
},
toString: function() {
return this._.join("");
}
};
function tree_add(d) {
var x = +this._x.call(null, d),
y = +this._y.call(null, d);
return add(this.cover(x, y), x, y, d);
}
function add(tree, x, y, d) {
if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
var parent,
node = tree._root,
leaf = {data: d},
x0 = tree._x0,
y0 = tree._y0,
x1 = tree._x1,
y1 = tree._y1,
xm,
ym,
xp,
yp,
right,
bottom,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return tree._root = leaf, tree;
// Find the existing leaf for the new point, or add it.
while (node.length) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
}
// Is the new point is exactly coincident with the existing point?
xp = +tree._x.call(null, node.data);
yp = +tree._y.call(null, node.data);
if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
// Otherwise, split the leaf node until the old and new point are separated.
do {
parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
} while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
return parent[j] = node, parent[i] = leaf, tree;
}
function addAll(data) {
var d, i, n = data.length,
x,
y,
xz = new Array(n),
yz = new Array(n),
x0 = Infinity,
y0 = Infinity,
x1 = -Infinity,
y1 = -Infinity;
// Compute the points and their extent.
for (i = 0; i < n; ++i) {
if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
xz[i] = x;
yz[i] = y;
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
// If there were no (valid) points, inherit the existing extent.
if (x1 < x0) x0 = this._x0, x1 = this._x1;
if (y1 < y0) y0 = this._y0, y1 = this._y1;
// Expand the tree to cover the new points.
this.cover(x0, y0).cover(x1, y1);
// Add the new points.
for (i = 0; i < n; ++i) {
add(this, xz[i], yz[i], data[i]);
}
return this;
}
function tree_cover(x, y) {
if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
var x0 = this._x0,
y0 = this._y0,
x1 = this._x1,
y1 = this._y1;
// If the quadtree has no extent, initialize them.
// Integer extent are necessary so that if we later double the extent,
// the existing quadrant boundaries don’t change due to floating point error!
if (isNaN(x0)) {
x1 = (x0 = Math.floor(x)) + 1;
y1 = (y0 = Math.floor(y)) + 1;
}
// Otherwise, double repeatedly to cover.
else if (x0 > x || x > x1 || y0 > y || y > y1) {
var z = x1 - x0,
node = this._root,
parent,
i;
switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
case 0: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
break;
}
case 1: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
break;
}
case 2: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
break;
}
case 3: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
break;
}
}
if (this._root && this._root.length) this._root = node;
}
// If the quadtree covers the point already, just return.
else return this;
this._x0 = x0;
this._y0 = y0;
this._x1 = x1;
this._y1 = y1;
return this;
}
function tree_data() {
var data = [];
this.visit(function(node) {
if (!node.length) do data.push(node.data); while (node = node.next)
});
return data;
}
function tree_extent(_) {
return arguments.length
? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
: isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
}
function Quad(node, x0, y0, x1, y1) {
this.node = node;
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
}
function tree_find(x, y, radius) {
var data,
x0 = this._x0,
y0 = this._y0,
x1,
y1,
x2,
y2,
x3 = this._x1,
y3 = this._y1,
quads = [],
node = this._root,
q,
i;
if (node) quads.push(new Quad(node, x0, y0, x3, y3));
if (radius == null) radius = Infinity;
else {
x0 = x - radius, y0 = y - radius;
x3 = x + radius, y3 = y + radius;
radius *= radius;
}
while (q = quads.pop()) {
// Stop searching if this quadrant can’t contain a closer node.
if (!(node = q.node)
|| (x1 = q.x0) > x3
|| (y1 = q.y0) > y3
|| (x2 = q.x1) < x0
|| (y2 = q.y1) < y0) continue;
// Bisect the current quadrant.
if (node.length) {
var xm = (x1 + x2) / 2,
ym = (y1 + y2) / 2;
quads.push(
new Quad(node[3], xm, ym, x2, y2),
new Quad(node[2], x1, ym, xm, y2),
new Quad(node[1], xm, y1, x2, ym),
new Quad(node[0], x1, y1, xm, ym)
);
// Visit the closest quadrant first.
if (i = (y >= ym) << 1 | (x >= xm)) {
q = quads[quads.length - 1];
quads[quads.length - 1] = quads[quads.length - 1 - i];
quads[quads.length - 1 - i] = q;
}
}
// Visit this point. (Visiting coincident points isn’t necessary!)
else {
var dx = x - +this._x.call(null, node.data),
dy = y - +this._y.call(null, node.data),
d2 = dx * dx + dy * dy;
if (d2 < radius) {
var d = Math.sqrt(radius = d2);
x0 = x - d, y0 = y - d;
x3 = x + d, y3 = y + d;
data = node.data;
}
}
}
return data;
}
function tree_remove(d) {
if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
var parent,
node = this._root,
retainer,
previous,
next,
x0 = this._x0,
y0 = this._y0,
x1 = this._x1,
y1 = this._y1,
x,
y,
xm,
ym,
right,
bottom,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return this;
// Find the leaf node for the point.
// While descending, also retain the deepest parent with a non-removed sibling.
if (node.length) while (true) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
if (!node.length) break;
if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
}
// Find the point to remove.
while (node.data !== d) if (!(previous = node, node = node.next)) return this;
if (next = node.next) delete node.next;
// If there are multiple coincident points, remove just the point.
if (previous) return (next ? previous.next = next : delete previous.next), this;
// If this is the root point, remove it.
if (!parent) return this._root = next, this;
// Remove this leaf.
next ? parent[i] = next : delete parent[i];
// If the parent now contains exactly one leaf, collapse superfluous parents.
if ((node = parent[0] || parent[1] || parent[2] || parent[3])
&& node === (parent[3] || parent[2] || parent[1] || parent[0])
&& !node.length) {
if (retainer) retainer[j] = node;
else this._root = node;
}
return this;
}
function removeAll(data) {
for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
return this;
}
function tree_root() {
return this._root;
}
function tree_size() {
var size = 0;
this.visit(function(node) {
if (!node.length) do ++size; while (node = node.next)
});
return size;
}
function tree_visit(callback) {
var quads = [], q, node = this._root, child, x0, y0, x1, y1;
if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
while (q = quads.pop()) {
if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
}
}
return this;
}
function tree_visitAfter(callback) {
var quads = [], next = [], q;
if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
while (q = quads.pop()) {
var node = q.node;
if (node.length) {
var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
}
next.push(q);
}
while (q = next.pop()) {
callback(q.node, q.x0, q.y0, q.x1, q.y1);
}
return this;
}
function defaultX(d) {
return d[0];
}
function tree_x(_) {
return arguments.length ? (this._x = _, this) : this._x;
}
function defaultY(d) {
return d[1];
}
function tree_y(_) {
return arguments.length ? (this._y = _, this) : this._y;
}
function quadtree(nodes, x, y) {
var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
return nodes == null ? tree : tree.addAll(nodes);
}
function Quadtree(x, y, x0, y0, x1, y1) {
this._x = x;
this._y = y;
this._x0 = x0;
this._y0 = y0;
this._x1 = x1;
this._y1 = y1;
this._root = undefined;
}
function leaf_copy(leaf) {
var copy = {data: leaf.data}, next = copy;
while (leaf = leaf.next) next = next.next = {data: leaf.data};
return copy;
}
var treeProto = quadtree.prototype = Quadtree.prototype;
treeProto.copy = function() {
var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
node = this._root,
nodes,
child;
if (!node) return copy;
if (!node.length) return copy._root = leaf_copy(node), copy;
nodes = [{source: node, target: copy._root = new Array(4)}];
while (node = nodes.pop()) {
for (var i = 0; i < 4; ++i) {
if (child = node.source[i]) {
if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
else node.target[i] = leaf_copy(child);
}
}
}
return copy;
};
treeProto.add = tree_add;
treeProto.addAll = addAll;
treeProto.cover = tree_cover;
treeProto.data = tree_data;
treeProto.extent = tree_extent;
treeProto.find = tree_find;
treeProto.remove = tree_remove;
treeProto.removeAll = removeAll;
treeProto.root = tree_root;
treeProto.size = tree_size;
treeProto.visit = tree_visit;
treeProto.visitAfter = tree_visitAfter;
treeProto.x = tree_x;
treeProto.y = tree_y;
var slice$1 = [].slice;
var noabort = {};
function Queue(size) {
if (!(size >= 1)) throw new Error;
this._size = size;
this._call =
this._error = null;
this._tasks = [];
this._data = [];
this._waiting =
this._active =
this._ended =
this._start = 0; // inside a synchronous task callback?
}
Queue.prototype = queue.prototype = {
constructor: Queue,
defer: function(callback) {
if (typeof callback !== "function" || this._call) throw new Error;
if (this._error != null) return this;
var t = slice$1.call(arguments, 1);
t.push(callback);
++this._waiting, this._tasks.push(t);
poke(this);
return this;
},
abort: function() {
if (this._error == null) abort(this, new Error("abort"));
return this;
},
await: function(callback) {
if (typeof callback !== "function" || this._call) throw new Error;
this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
maybeNotify(this);
return this;
},
awaitAll: function(callback) {
if (typeof callback !== "function" || this._call) throw new Error;
this._call = callback;
maybeNotify(this);
return this;
}
};
function poke(q) {
if (!q._start) try { start(q); } // let the current task complete
catch (e) { if (q._tasks[q._ended + q._active - 1]) abort(q, e); } // task errored synchronously
}
function start(q) {
while (q._start = q._waiting && q._active < q._size) {
var i = q._ended + q._active,
t = q._tasks[i],
j = t.length - 1,
c = t[j];
t[j] = end(q, i);
--q._waiting, ++q._active;
t = c.apply(null, t);
if (!q._tasks[i]) continue; // task finished synchronously
q._tasks[i] = t || noabort;
}
}
function end(q, i) {
return function(e, r) {
if (!q._tasks[i]) return; // ignore multiple callbacks
--q._active, ++q._ended;
q._tasks[i] = null;
if (q._error != null) return; // ignore secondary errors
if (e != null) {
abort(q, e);
} else {
q._data[i] = r;
if (q._waiting) poke(q);
else maybeNotify(q);
}
};
}
function abort(q, e) {
var i = q._tasks.length, t;
q._error = e; // ignore active callbacks
q._data = undefined; // allow gc
q._waiting = NaN; // prevent starting
while (--i >= 0) {
if (t = q._tasks[i]) {
q._tasks[i] = null;
if (t.abort) try { t.abort(); }
catch (e) { /* ignore */ }
}
}
q._active = NaN; // allow notification
maybeNotify(q);
}
function maybeNotify(q) {
if (!q._active && q._call) q._call(q._error, q._data);
}
function queue(concurrency) {
return new Queue(arguments.length ? +concurrency : Infinity);
}
function constant$1(x) {
return function constant() {
return x;
};
}
var epsilon$1 = 1e-12;
var pi$2 = Math.PI;
var halfPi$1 = pi$2 / 2;
var tau$2 = 2 * pi$2;
function arcInnerRadius(d) {
return d.innerRadius;
}
function arcOuterRadius(d) {
return d.outerRadius;
}
function arcStartAngle(d) {
return d.startAngle;
}
function arcEndAngle(d) {
return d.endAngle;
}
function arcPadAngle(d) {
return d && d.padAngle; // Note: optional!
}
function asin(x) {
return x >= 1 ? halfPi$1 : x <= -1 ? -halfPi$1 : Math.asin(x);
}
function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
var x10 = x1 - x0, y10 = y1 - y0,
x32 = x3 - x2, y32 = y3 - y2,
t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
return [x0 + t * x10, y0 + t * y10];
}
// Compute perpendicular offset line of length rc.
// http://mathworld.wolfram.com/Circle-LineIntersection.html
function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
var x01 = x0 - x1,
y01 = y0 - y1,
lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01),
ox = lo * y01,
oy = -lo * x01,
x11 = x0 + ox,
y11 = y0 + oy,
x10 = x1 + ox,
y10 = y1 + oy,
x00 = (x11 + x10) / 2,
y00 = (y11 + y10) / 2,
dx = x10 - x11,
dy = y10 - y11,
d2 = dx * dx + dy * dy,
r = r1 - rc,
D = x11 * y10 - x10 * y11,
d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)),
cx0 = (D * dy - dx * d) / d2,
cy0 = (-D * dx - dy * d) / d2,
cx1 = (D * dy + dx * d) / d2,
cy1 = (-D * dx + dy * d) / d2,
dx0 = cx0 - x00,
dy0 = cy0 - y00,
dx1 = cx1 - x00,
dy1 = cy1 - y00;
// Pick the closer of the two intersection points.
// TODO Is there a faster way to determine which intersection to use?
if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
return {
cx: cx0,
cy: cy0,
x01: -ox,
y01: -oy,
x11: cx0 * (r1 / r - 1),
y11: cy0 * (r1 / r - 1)
};
}
function arc() {
var innerRadius = arcInnerRadius,
outerRadius = arcOuterRadius,
cornerRadius = constant$1(0),
padRadius = null,
startAngle = arcStartAngle,
endAngle = arcEndAngle,
padAngle = arcPadAngle,
context = null;
function arc() {
var buffer,
r,
r0 = +innerRadius.apply(this, arguments),
r1 = +outerRadius.apply(this, arguments),
a0 = startAngle.apply(this, arguments) - halfPi$1,
a1 = endAngle.apply(this, arguments) - halfPi$1,
da = Math.abs(a1 - a0),
cw = a1 > a0;
if (!context) context = buffer = path();
// Ensure that the outer radius is always larger than the inner radius.
if (r1 < r0) r = r1, r1 = r0, r0 = r;
// Is it a point?
if (!(r1 > epsilon$1)) context.moveTo(0, 0);
// Or is it a circle or annulus?
else if (da > tau$2 - epsilon$1) {
context.moveTo(r1 * Math.cos(a0), r1 * Math.sin(a0));
context.arc(0, 0, r1, a0, a1, !cw);
if (r0 > epsilon$1) {
context.moveTo(r0 * Math.cos(a1), r0 * Math.sin(a1));
context.arc(0, 0, r0, a1, a0, cw);
}
}
// Or is it a circular or annular sector?
else {
var a01 = a0,
a11 = a1,
a00 = a0,
a10 = a1,
da0 = da,
da1 = da,
ap = padAngle.apply(this, arguments) / 2,
rp = (ap > epsilon$1) && (padRadius ? +padRadius.apply(this, arguments) : Math.sqrt(r0 * r0 + r1 * r1)),
rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
rc0 = rc,
rc1 = rc,
t0,
t1;
// Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
if (rp > epsilon$1) {
var p0 = asin(rp / r0 * Math.sin(ap)),
p1 = asin(rp / r1 * Math.sin(ap));
if ((da0 -= p0 * 2) > epsilon$1) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
else da0 = 0, a00 = a10 = (a0 + a1) / 2;
if ((da1 -= p1 * 2) > epsilon$1) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
else da1 = 0, a01 = a11 = (a0 + a1) / 2;
}
var x01 = r1 * Math.cos(a01),
y01 = r1 * Math.sin(a01),
x10 = r0 * Math.cos(a10),
y10 = r0 * Math.sin(a10);
// Apply rounded corners?
if (rc > epsilon$1) {
var x11 = r1 * Math.cos(a11),
y11 = r1 * Math.sin(a11),
x00 = r0 * Math.cos(a00),
y00 = r0 * Math.sin(a00);
// Restrict the corner radius according to the sector angle.
if (da < pi$2) {
var oc = da0 > epsilon$1 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
ax = x01 - oc[0],
ay = y01 - oc[1],
bx = x11 - oc[0],
by = y11 - oc[1],
kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2),
lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
rc0 = Math.min(rc, (r0 - lc) / (kc - 1));
rc1 = Math.min(rc, (r1 - lc) / (kc + 1));
}
}
// Is the sector collapsed to a line?
if (!(da1 > epsilon$1)) context.moveTo(x01, y01);
// Does the sector’s outer ring have rounded corners?
else if (rc1 > epsilon$1) {
t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, Math.atan2(t0.y01, t0.x01), Math.atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc1, Math.atan2(t0.y01, t0.x01), Math.atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r1, Math.atan2(t0.cy + t0.y11, t0.cx + t0.x11), Math.atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
context.arc(t1.cx, t1.cy, rc1, Math.atan2(t1.y11, t1.x11), Math.atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the outer ring just a circular arc?
else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
// Is there no inner ring, and it’s a circular sector?
// Or perhaps it’s an annular sector collapsed due to padding?
if (!(r0 > epsilon$1) || !(da0 > epsilon$1)) context.lineTo(x10, y10);
// Does the sector’s inner ring (or point) have rounded corners?
else if (rc0 > epsilon$1) {
t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, Math.atan2(t0.y01, t0.x01), Math.atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc0, Math.atan2(t0.y01, t0.x01), Math.atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r0, Math.atan2(t0.cy + t0.y11, t0.cx + t0.x11), Math.atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
context.arc(t1.cx, t1.cy, rc0, Math.atan2(t1.y11, t1.x11), Math.atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the inner ring just a circular arc?
else context.arc(0, 0, r0, a10, a00, cw);
}
context.closePath();
if (buffer) return context = null, buffer + "" || null;
}
arc.centroid = function() {
var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$2 / 2;
return [Math.cos(a) * r, Math.sin(a) * r];
};
arc.innerRadius = function(_) {
return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : innerRadius;
};
arc.outerRadius = function(_) {
return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : outerRadius;
};
arc.cornerRadius = function(_) {
return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : cornerRadius;
};
arc.padRadius = function(_) {
return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), arc) : padRadius;
};
arc.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : startAngle;
};
arc.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : endAngle;
};
arc.padAngle = function(_) {
return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : padAngle;
};
arc.context = function(_) {
return arguments.length ? ((context = _ == null ? null : _), arc) : context;
};
return arc;
}
function Linear(context) {
this._context = context;
}
Linear.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; // proceed
default: this._context.lineTo(x, y); break;
}
}
};
function curveLinear(context) {
return new Linear(context);
}
function x(p) {
return p[0];
}
function y(p) {
return p[1];
}
function line() {
var x$$ = x,
y$$ = y,
defined = constant$1(true),
context = null,
curve = curveLinear,
output = null;
function line(data) {
var i,
n = data.length,
d,
defined0 = false,
buffer;
if (context == null) output = curve(buffer = path());
for (i = 0; i <= n; ++i) {
if (!(i < n && defined(d = data[i], i, data)) === defined0) {
if (defined0 = !defined0) output.lineStart();
else output.lineEnd();
}
if (defined0) output.point(+x$$(d, i, data), +y$$(d, i, data));
}
if (buffer) return output = null, buffer + "" || null;
}
line.x = function(_) {
return arguments.length ? (x$$ = typeof _ === "function" ? _ : constant$1(+_), line) : x$$;
};
line.y = function(_) {
return arguments.length ? (y$$ = typeof _ === "function" ? _ : constant$1(+_), line) : y$$;
};
line.defined = function(_) {
return arguments.length ? (defined = typeof _ === "function" ? _ : constant$1(!!_), line) : defined;
};
line.curve = function(_) {
return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
};
line.context = function(_) {
return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
};
return line;
}
function area$1() {
var x0 = x,
x1 = null,
y0 = constant$1(0),
y1 = y,
defined = constant$1(true),
context = null,
curve = curveLinear,
output = null;
function area(data) {
var i,
j,
k,
n = data.length,
d,
defined0 = false,
buffer,
x0z = new Array(n),
y0z = new Array(n);
if (context == null) output = curve(buffer = path());
for (i = 0; i <= n; ++i) {
if (!(i < n && defined(d = data[i], i, data)) === defined0) {
if (defined0 = !defined0) {
j = i;
output.areaStart();
output.lineStart();
} else {
output.lineEnd();
output.lineStart();
for (k = i - 1; k >= j; --k) {
output.point(x0z[k], y0z[k]);
}
output.lineEnd();
output.areaEnd();
}
}
if (defined0) {
x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
}
}
if (buffer) return output = null, buffer + "" || null;
}
function arealine() {
return line().defined(defined).curve(curve).context(context);
}
area.x = function(_) {
return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$1(+_), x1 = null, area) : x0;
};
area.x0 = function(_) {
return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$1(+_), area) : x0;
};
area.x1 = function(_) {
return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), area) : x1;
};
area.y = function(_) {
return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), y1 = null, area) : y0;
};
area.y0 = function(_) {
return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), area) : y0;
};
area.y1 = function(_) {
return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), area) : y1;
};
area.lineX0 =
area.lineY0 = function() {
return arealine().x(x0).y(y0);
};
area.lineY1 = function() {
return arealine().x(x0).y(y1);
};
area.lineX1 = function() {
return arealine().x(x1).y(y0);
};
area.defined = function(_) {
return arguments.length ? (defined = typeof _ === "function" ? _ : constant$1(!!_), area) : defined;
};
area.curve = function(_) {
return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
};
area.context = function(_) {
return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
};
return area;
}
function descending$1(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
function identity$1(d) {
return d;
}
function pie() {
var value = identity$1,
sortValues = descending$1,
sort = null,
startAngle = constant$1(0),
endAngle = constant$1(tau$2),
padAngle = constant$1(0);
function pie(data) {
var i,
n = data.length,
j,
k,
sum = 0,
index = new Array(n),
arcs = new Array(n),
a0 = +startAngle.apply(this, arguments),
da = Math.min(tau$2, Math.max(-tau$2, endAngle.apply(this, arguments) - a0)),
a1,
p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
pa = p * (da < 0 ? -1 : 1),
v;
for (i = 0; i < n; ++i) {
if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
sum += v;
}
}
// Optionally sort the arcs by previously-computed values or by data.
if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
// Compute the arcs! They are stored in the original data's order.
for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
data: data[j],
index: i,
value: v,
startAngle: a0,
endAngle: a1,
padAngle: p
};
}
return arcs;
}
pie.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant$1(+_), pie) : value;
};
pie.sortValues = function(_) {
return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
};
pie.sort = function(_) {
return arguments.length ? (sort = _, sortValues = null, pie) : sort;
};
pie.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : startAngle;
};
pie.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : endAngle;
};
pie.padAngle = function(_) {
return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : padAngle;
};
return pie;
}
var curveRadialLinear = curveRadial(curveLinear);
function Radial(curve) {
this._curve = curve;
}
Radial.prototype = {
areaStart: function() {
this._curve.areaStart();
},
areaEnd: function() {
this._curve.areaEnd();
},
lineStart: function() {
this._curve.lineStart();
},
lineEnd: function() {
this._curve.lineEnd();
},
point: function(a, r) {
this._curve.point(r * Math.sin(a), r * -Math.cos(a));
}
};
function curveRadial(curve) {
function radial(context) {
return new Radial(curve(context));
}
radial._curve = curve;
return radial;
}
function radialLine(l) {
var c = l.curve;
l.angle = l.x, delete l.x;
l.radius = l.y, delete l.y;
l.curve = function(_) {
return arguments.length ? c(curveRadial(_)) : c()._curve;
};
return l;
}
function radialLine$1() {
return radialLine(line().curve(curveRadialLinear));
}
function radialArea() {
var a = area$1().curve(curveRadialLinear),
c = a.curve,
x0 = a.lineX0,
x1 = a.lineX1,
y0 = a.lineY0,
y1 = a.lineY1;
a.angle = a.x, delete a.x;
a.startAngle = a.x0, delete a.x0;
a.endAngle = a.x1, delete a.x1;
a.radius = a.y, delete a.y;
a.innerRadius = a.y0, delete a.y0;
a.outerRadius = a.y1, delete a.y1;
a.lineStartAngle = function() { return radialLine(x0()); }, delete a.lineX0;
a.lineEndAngle = function() { return radialLine(x1()); }, delete a.lineX1;
a.lineInnerRadius = function() { return radialLine(y0()); }, delete a.lineY0;
a.lineOuterRadius = function() { return radialLine(y1()); }, delete a.lineY1;
a.curve = function(_) {
return arguments.length ? c(curveRadial(_)) : c()._curve;
};
return a;
}
var circle = {
draw: function(context, size) {
var r = Math.sqrt(size / pi$2);
context.moveTo(r, 0);
context.arc(0, 0, r, 0, tau$2);
}
};
var cross$1 = {
draw: function(context, size) {
var r = Math.sqrt(size / 5) / 2;
context.moveTo(-3 * r, -r);
context.lineTo(-r, -r);
context.lineTo(-r, -3 * r);
context.lineTo(r, -3 * r);
context.lineTo(r, -r);
context.lineTo(3 * r, -r);
context.lineTo(3 * r, r);
context.lineTo(r, r);
context.lineTo(r, 3 * r);
context.lineTo(-r, 3 * r);
context.lineTo(-r, r);
context.lineTo(-3 * r, r);
context.closePath();
}
};
var tan30 = Math.sqrt(1 / 3);
var tan30_2 = tan30 * 2;
var diamond = {
draw: function(context, size) {
var y = Math.sqrt(size / tan30_2),
x = y * tan30;
context.moveTo(0, -y);
context.lineTo(x, 0);
context.lineTo(0, y);
context.lineTo(-x, 0);
context.closePath();
}
};
var ka = 0.89081309152928522810;
var kr = Math.sin(pi$2 / 10) / Math.sin(7 * pi$2 / 10);
var kx = Math.sin(tau$2 / 10) * kr;
var ky = -Math.cos(tau$2 / 10) * kr;
var star = {
draw: function(context, size) {
var r = Math.sqrt(size * ka),
x = kx * r,
y = ky * r;
context.moveTo(0, -r);
context.lineTo(x, y);
for (var i = 1; i < 5; ++i) {
var a = tau$2 * i / 5,
c = Math.cos(a),
s = Math.sin(a);
context.lineTo(s * r, -c * r);
context.lineTo(c * x - s * y, s * x + c * y);
}
context.closePath();
}
};
var square = {
draw: function(context, size) {
var w = Math.sqrt(size),
x = -w / 2;
context.rect(x, x, w, w);
}
};
var sqrt3 = Math.sqrt(3);
var triangle = {
draw: function(context, size) {
var y = -Math.sqrt(size / (sqrt3 * 3));
context.moveTo(0, y * 2);
context.lineTo(-sqrt3 * y, -y);
context.lineTo(sqrt3 * y, -y);
context.closePath();
}
};
var c = -0.5;
var s = Math.sqrt(3) / 2;
var k = 1 / Math.sqrt(12);
var a = (k / 2 + 1) * 3;
var wye = {
draw: function(context, size) {
var r = Math.sqrt(size / a),
x0 = r / 2,
y0 = r * k,
x1 = x0,
y1 = r * k + r,
x2 = -x1,
y2 = y1;
context.moveTo(x0, y0);
context.lineTo(x1, y1);
context.lineTo(x2, y2);
context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
context.closePath();
}
};
var symbols = [
circle,
cross$1,
diamond,
square,
star,
triangle,
wye
];
function symbol() {
var type = constant$1(circle),
size = constant$1(64),
context = null;
function symbol() {
var buffer;
if (!context) context = buffer = path();
type.apply(this, arguments).draw(context, +size.apply(this, arguments));
if (buffer) return context = null, buffer + "" || null;
}
symbol.type = function(_) {
return arguments.length ? (type = typeof _ === "function" ? _ : constant$1(_), symbol) : type;
};
symbol.size = function(_) {
return arguments.length ? (size = typeof _ === "function" ? _ : constant$1(+_), symbol) : size;
};
symbol.context = function(_) {
return arguments.length ? (context = _ == null ? null : _, symbol) : context;
};
return symbol;
}
function noop() {}
function point(that, x, y) {
that._context.bezierCurveTo(
(2 * that._x0 + that._x1) / 3,
(2 * that._y0 + that._y1) / 3,
(that._x0 + 2 * that._x1) / 3,
(that._y0 + 2 * that._y1) / 3,
(that._x0 + 4 * that._x1 + x) / 6,
(that._y0 + 4 * that._y1 + y) / 6
);
}
function Basis(context) {
this._context = context;
}
Basis.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 3: point(this, this._x1, this._y1); // proceed
case 2: this._context.lineTo(this._x1, this._y1); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; break;
case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
default: point(this, x, y); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
}
};
function basis(context) {
return new Basis(context);
}
function BasisClosed(context) {
this._context = context;
}
BasisClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 1: {
this._context.moveTo(this._x2, this._y2);
this._context.closePath();
break;
}
case 2: {
this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
this._context.closePath();
break;
}
case 3: {
this.point(this._x2, this._y2);
this.point(this._x3, this._y3);
this.point(this._x4, this._y4);
break;
}
}
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
default: point(this, x, y); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
}
};
function basisClosed(context) {
return new BasisClosed(context);
}
function BasisOpen(context) {
this._context = context;
}
BasisOpen.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 = NaN;
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; break;
case 1: this._point = 2; break;
case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
case 3: this._point = 4; // proceed
default: point(this, x, y); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
}
};
function basisOpen(context) {
return new BasisOpen(context);
}
function Bundle(context, beta) {
this._basis = new Basis(context);
this._beta = beta;
}
Bundle.prototype = {
lineStart: function() {
this._x = [];
this._y = [];
this._basis.lineStart();
},
lineEnd: function() {
var x = this._x,
y = this._y,
j = x.length - 1;
if (j > 0) {
var x0 = x[0],
y0 = y[0],
dx = x[j] - x0,
dy = y[j] - y0,
i = -1,
t;
while (++i <= j) {
t = i / j;
this._basis.point(
this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
);
}
}
this._x = this._y = null;
this._basis.lineEnd();
},
point: function(x, y) {
this._x.push(+x);
this._y.push(+y);
}
};
var bundle = (function custom(beta) {
function bundle(context) {
return beta === 1 ? new Basis(context) : new Bundle(context, beta);
}
bundle.beta = function(beta) {
return custom(+beta);
};
return bundle;
})(0.85);
function point$1(that, x, y) {
that._context.bezierCurveTo(
that._x1 + that._k * (that._x2 - that._x0),
that._y1 + that._k * (that._y2 - that._y0),
that._x2 + that._k * (that._x1 - x),
that._y2 + that._k * (that._y1 - y),
that._x2,
that._y2
);
}
function Cardinal(context, tension) {
this._context = context;
this._k = (1 - tension) / 6;
}
Cardinal.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 2: this._context.lineTo(this._x2, this._y2); break;
case 3: point$1(this, this._x1, this._y1); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
case 2: this._point = 3; // proceed
default: point$1(this, x, y); break;
}
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var cardinal = (function custom(tension) {
function cardinal(context) {
return new Cardinal(context, tension);
}
cardinal.tension = function(tension) {
return custom(+tension);
};
return cardinal;
})(0);
function CardinalClosed(context, tension) {
this._context = context;
this._k = (1 - tension) / 6;
}
CardinalClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 1: {
this._context.moveTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 2: {
this._context.lineTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 3: {
this.point(this._x3, this._y3);
this.point(this._x4, this._y4);
this.point(this._x5, this._y5);
break;
}
}
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
default: point$1(this, x, y); break;
}
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var cardinalClosed = (function custom(tension) {
function cardinal(context) {
return new CardinalClosed(context, tension);
}
cardinal.tension = function(tension) {
return custom(+tension);
};
return cardinal;
})(0);
function CardinalOpen(context, tension) {
this._context = context;
this._k = (1 - tension) / 6;
}
CardinalOpen.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; break;
case 1: this._point = 2; break;
case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
case 3: this._point = 4; // proceed
default: point$1(this, x, y); break;
}
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var cardinalOpen = (function custom(tension) {
function cardinal(context) {
return new CardinalOpen(context, tension);
}
cardinal.tension = function(tension) {
return custom(+tension);
};
return cardinal;
})(0);
function point$2(that, x, y) {
var x1 = that._x1,
y1 = that._y1,
x2 = that._x2,
y2 = that._y2;
if (that._l01_a > epsilon$1) {
var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
n = 3 * that._l01_a * (that._l01_a + that._l12_a);
x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
}
if (that._l23_a > epsilon$1) {
var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
m = 3 * that._l23_a * (that._l23_a + that._l12_a);
x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
}
that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
}
function CatmullRom(context, alpha) {
this._context = context;
this._alpha = alpha;
}
CatmullRom.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._l01_a = this._l12_a = this._l23_a =
this._l01_2a = this._l12_2a = this._l23_2a =
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 2: this._context.lineTo(this._x2, this._y2); break;
case 3: this.point(this, this._x2, this._y2); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) {
var x23 = this._x2 - x,
y23 = this._y2 - y;
this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
}
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; break;
case 2: this._point = 3; // proceed
default: point$2(this, x, y); break;
}
this._l01_a = this._l12_a, this._l12_a = this._l23_a;
this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var catmullRom = (function custom(alpha) {
function catmullRom(context) {
return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
}
catmullRom.alpha = function(alpha) {
return custom(+alpha);
};
return catmullRom;
})(0.5);
function CatmullRomClosed(context, alpha) {
this._context = context;
this._alpha = alpha;
}
CatmullRomClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
this._l01_a = this._l12_a = this._l23_a =
this._l01_2a = this._l12_2a = this._l23_2a =
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 1: {
this._context.moveTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 2: {
this._context.lineTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 3: {
this.point(this._x3, this._y3);
this.point(this._x4, this._y4);
this.point(this._x5, this._y5);
break;
}
}
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) {
var x23 = this._x2 - x,
y23 = this._y2 - y;
this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
}
switch (this._point) {
case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
default: point$2(this, x, y); break;
}
this._l01_a = this._l12_a, this._l12_a = this._l23_a;
this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var catmullRomClosed = (function custom(alpha) {
function catmullRom(context) {
return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
}
catmullRom.alpha = function(alpha) {
return custom(+alpha);
};
return catmullRom;
})(0.5);
function CatmullRomOpen(context, alpha) {
this._context = context;
this._alpha = alpha;
}
CatmullRomOpen.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._l01_a = this._l12_a = this._l23_a =
this._l01_2a = this._l12_2a = this._l23_2a =
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) {
var x23 = this._x2 - x,
y23 = this._y2 - y;
this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
}
switch (this._point) {
case 0: this._point = 1; break;
case 1: this._point = 2; break;
case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
case 3: this._point = 4; // proceed
default: point$2(this, x, y); break;
}
this._l01_a = this._l12_a, this._l12_a = this._l23_a;
this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var catmullRomOpen = (function custom(alpha) {
function catmullRom(context) {
return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
}
catmullRom.alpha = function(alpha) {
return custom(+alpha);
};
return catmullRom;
})(0.5);
function LinearClosed(context) {
this._context = context;
}
LinearClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._point = 0;
},
lineEnd: function() {
if (this._point) this._context.closePath();
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) this._context.lineTo(x, y);
else this._point = 1, this._context.moveTo(x, y);
}
};
function linearClosed(context) {
return new LinearClosed(context);
}
function sign(x) {
return x < 0 ? -1 : 1;
}
// Calculate the slopes of the tangents (Hermite-type interpolation) based on
// the following paper: Steffen, M. 1990. A Simple Method for Monotonic
// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
// NOV(II), P. 443, 1990.
function slope3(that, x2, y2) {
var h0 = that._x1 - that._x0,
h1 = x2 - that._x1,
s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
p = (s0 * h1 + s1 * h0) / (h0 + h1);
return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
}
// Calculate a one-sided slope.
function slope2(that, t) {
var h = that._x1 - that._x0;
return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
}
// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
// "you can express cubic Hermite interpolation in terms of cubic Bézier curves
// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
function point$3(that, t0, t1) {
var x0 = that._x0,
y0 = that._y0,
x1 = that._x1,
y1 = that._y1,
dx = (x1 - x0) / 3;
that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
}
function MonotoneX(context) {
this._context = context;
}
MonotoneX.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 =
this._t0 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 2: this._context.lineTo(this._x1, this._y1); break;
case 3: point$3(this, this._t0, slope2(this, this._t0)); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
var t1 = NaN;
x = +x, y = +y;
if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; break;
case 2: this._point = 3; point$3(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
default: point$3(this, this._t0, t1 = slope3(this, x, y)); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
this._t0 = t1;
}
}
function MonotoneY(context) {
this._context = new ReflectContext(context);
}
(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
MonotoneX.prototype.point.call(this, y, x);
};
function ReflectContext(context) {
this._context = context;
}
ReflectContext.prototype = {
moveTo: function(x, y) { this._context.moveTo(y, x); },
closePath: function() { this._context.closePath(); },
lineTo: function(x, y) { this._context.lineTo(y, x); },
bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
};
function monotoneX(context) {
return new MonotoneX(context);
}
function monotoneY(context) {
return new MonotoneY(context);
}
function Natural(context) {
this._context = context;
}
Natural.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x = [];
this._y = [];
},
lineEnd: function() {
var x = this._x,
y = this._y,
n = x.length;
if (n) {
this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
if (n === 2) {
this._context.lineTo(x[1], y[1]);
} else {
var px = controlPoints(x),
py = controlPoints(y);
for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
}
}
}
if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
this._line = 1 - this._line;
this._x = this._y = null;
},
point: function(x, y) {
this._x.push(+x);
this._y.push(+y);
}
};
// See https://www.particleincell.com/2012/bezier-splines/ for derivation.
function controlPoints(x) {
var i,
n = x.length - 1,
m,
a = new Array(n),
b = new Array(n),
r = new Array(n);
a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
a[n - 1] = r[n - 1] / b[n - 1];
for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
b[n - 1] = (x[n] + a[n - 1]) / 2;
for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
return [a, b];
}
function natural(context) {
return new Natural(context);
}
function Step(context, t) {
this._context = context;
this._t = t;
}
Step.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x = this._y = NaN;
this._point = 0;
},
lineEnd: function() {
if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; // proceed
default: {
if (this._t <= 0) {
this._context.lineTo(this._x, y);
this._context.lineTo(x, y);
} else {
var x1 = this._x * (1 - this._t) + x * this._t;
this._context.lineTo(x1, this._y);
this._context.lineTo(x1, y);
}
break;
}
}
this._x = x, this._y = y;
}
};
function step(context) {
return new Step(context, 0.5);
}
function stepBefore(context) {
return new Step(context, 0);
}
function stepAfter(context) {
return new Step(context, 1);
}
var slice$2 = Array.prototype.slice;
function none(series, order) {
if (!((n = series.length) > 1)) return;
for (var i = 1, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
s0 = s1, s1 = series[order[i]];
for (var j = 0; j < m; ++j) {
s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
}
}
}
function none$1(series) {
var n = series.length, o = new Array(n);
while (--n >= 0) o[n] = n;
return o;
}
function stackValue(d, key) {
return d[key];
}
function stack() {
var keys = constant$1([]),
order = none$1,
offset = none,
value = stackValue;
function stack(data) {
var kz = keys.apply(this, arguments),
i,
m = data.length,
n = kz.length,
sz = new Array(n),
oz;
for (i = 0; i < n; ++i) {
for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
si[j] = sij = [0, +value(data[j], ki, j, data)];
sij.data = data[j];
}
si.key = ki;
}
for (i = 0, oz = order(sz); i < n; ++i) {
sz[oz[i]].index = i;
}
offset(sz, oz);
return sz;
}
stack.keys = function(_) {
return arguments.length ? (keys = typeof _ === "function" ? _ : constant$1(slice$2.call(_)), stack) : keys;
};
stack.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant$1(+_), stack) : value;
};
stack.order = function(_) {
return arguments.length ? (order = _ == null ? none$1 : typeof _ === "function" ? _ : constant$1(slice$2.call(_)), stack) : order;
};
stack.offset = function(_) {
return arguments.length ? (offset = _ == null ? none : _, stack) : offset;
};
return stack;
}
function expand(series, order) {
if (!((n = series.length) > 0)) return;
for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
}
none(series, order);
}
function silhouette(series, order) {
if (!((n = series.length) > 0)) return;
for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
s0[j][1] += s0[j][0] = -y / 2;
}
none(series, order);
}
function wiggle(series, order) {
if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
var si = series[order[i]],
sij0 = si[j][1] || 0,
sij1 = si[j - 1][1] || 0,
s3 = (sij0 - sij1) / 2;
for (var k = 0; k < i; ++k) {
var sk = series[order[k]],
skj0 = sk[j][1] || 0,
skj1 = sk[j - 1][1] || 0;
s3 += skj0 - skj1;
}
s1 += sij0, s2 += s3 * sij0;
}
s0[j - 1][1] += s0[j - 1][0] = y;
if (s1) y -= s2 / s1;
}
s0[j - 1][1] += s0[j - 1][0] = y;
none(series, order);
}
function ascending$1(series) {
var sums = series.map(sum$1);
return none$1(series).sort(function(a, b) { return sums[a] - sums[b]; });
}
function sum$1(series) {
var s = 0, i = -1, n = series.length, v;
while (++i < n) if (v = +series[i][1]) s += v;
return s;
}
function descending$2(series) {
return ascending$1(series).reverse();
}
function insideOut(series) {
var n = series.length,
i,
j,
sums = series.map(sum$1),
order = none$1(series).sort(function(a, b) { return sums[b] - sums[a]; }),
top = 0,
bottom = 0,
tops = [],
bottoms = [];
for (i = 0; i < n; ++i) {
j = order[i];
if (top < bottom) {
top += sums[j];
tops.push(j);
} else {
bottom += sums[j];
bottoms.push(j);
}
}
return bottoms.reverse().concat(tops);
}
function reverse(series) {
return none$1(series).reverse();
}
function define(constructor, factory, prototype) {
constructor.prototype = factory.prototype = prototype;
prototype.constructor = constructor;
}
function extend(parent, definition) {
var prototype = Object.create(parent.prototype);
for (var key in definition) prototype[key] = definition[key];
return prototype;
}
function Color() {}
var darker = 0.7;
var brighter = 1 / darker;
var reHex3 = /^#([0-9a-f]{3})$/;
var reHex6 = /^#([0-9a-f]{6})$/;
var reRgbInteger = /^rgb\(\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*\)$/;
var reRgbPercent = /^rgb\(\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*\)$/;
var reRgbaInteger = /^rgba\(\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*,\s*([-+]?\d+(?:\.\d+)?)\s*\)$/;
var reRgbaPercent = /^rgba\(\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)\s*\)$/;
var reHslPercent = /^hsl\(\s*([-+]?\d+(?:\.\d+)?)\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*\)$/;
var reHslaPercent = /^hsla\(\s*([-+]?\d+(?:\.\d+)?)\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)\s*\)$/;
var named = {
aliceblue: 0xf0f8ff,
antiquewhite: 0xfaebd7,
aqua: 0x00ffff,
aquamarine: 0x7fffd4,
azure: 0xf0ffff,
beige: 0xf5f5dc,
bisque: 0xffe4c4,
black: 0x000000,
blanchedalmond: 0xffebcd,
blue: 0x0000ff,
blueviolet: 0x8a2be2,
brown: 0xa52a2a,
burlywood: 0xdeb887,
cadetblue: 0x5f9ea0,
chartreuse: 0x7fff00,
chocolate: 0xd2691e,
coral: 0xff7f50,
cornflowerblue: 0x6495ed,
cornsilk: 0xfff8dc,
crimson: 0xdc143c,
cyan: 0x00ffff,
darkblue: 0x00008b,
darkcyan: 0x008b8b,
darkgoldenrod: 0xb8860b,
darkgray: 0xa9a9a9,
darkgreen: 0x006400,
darkgrey: 0xa9a9a9,
darkkhaki: 0xbdb76b,
darkmagenta: 0x8b008b,
darkolivegreen: 0x556b2f,
darkorange: 0xff8c00,
darkorchid: 0x9932cc,
darkred: 0x8b0000,
darksalmon: 0xe9967a,
darkseagreen: 0x8fbc8f,
darkslateblue: 0x483d8b,
darkslategray: 0x2f4f4f,
darkslategrey: 0x2f4f4f,
darkturquoise: 0x00ced1,
darkviolet: 0x9400d3,
deeppink: 0xff1493,
deepskyblue: 0x00bfff,
dimgray: 0x696969,
dimgrey: 0x696969,
dodgerblue: 0x1e90ff,
firebrick: 0xb22222,
floralwhite: 0xfffaf0,
forestgreen: 0x228b22,
fuchsia: 0xff00ff,
gainsboro: 0xdcdcdc,
ghostwhite: 0xf8f8ff,
gold: 0xffd700,
goldenrod: 0xdaa520,
gray: 0x808080,
green: 0x008000,
greenyellow: 0xadff2f,
grey: 0x808080,
honeydew: 0xf0fff0,
hotpink: 0xff69b4,
indianred: 0xcd5c5c,
indigo: 0x4b0082,
ivory: 0xfffff0,
khaki: 0xf0e68c,
lavender: 0xe6e6fa,
lavenderblush: 0xfff0f5,
lawngreen: 0x7cfc00,
lemonchiffon: 0xfffacd,
lightblue: 0xadd8e6,
lightcoral: 0xf08080,
lightcyan: 0xe0ffff,
lightgoldenrodyellow: 0xfafad2,
lightgray: 0xd3d3d3,
lightgreen: 0x90ee90,
lightgrey: 0xd3d3d3,
lightpink: 0xffb6c1,
lightsalmon: 0xffa07a,
lightseagreen: 0x20b2aa,
lightskyblue: 0x87cefa,
lightslategray: 0x778899,
lightslategrey: 0x778899,
lightsteelblue: 0xb0c4de,
lightyellow: 0xffffe0,
lime: 0x00ff00,
limegreen: 0x32cd32,
linen: 0xfaf0e6,
magenta: 0xff00ff,
maroon: 0x800000,
mediumaquamarine: 0x66cdaa,
mediumblue: 0x0000cd,
mediumorchid: 0xba55d3,
mediumpurple: 0x9370db,
mediumseagreen: 0x3cb371,
mediumslateblue: 0x7b68ee,
mediumspringgreen: 0x00fa9a,
mediumturquoise: 0x48d1cc,
mediumvioletred: 0xc71585,
midnightblue: 0x191970,
mintcream: 0xf5fffa,
mistyrose: 0xffe4e1,
moccasin: 0xffe4b5,
navajowhite: 0xffdead,
navy: 0x000080,
oldlace: 0xfdf5e6,
olive: 0x808000,
olivedrab: 0x6b8e23,
orange: 0xffa500,
orangered: 0xff4500,
orchid: 0xda70d6,
palegoldenrod: 0xeee8aa,
palegreen: 0x98fb98,
paleturquoise: 0xafeeee,
palevioletred: 0xdb7093,
papayawhip: 0xffefd5,
peachpuff: 0xffdab9,
peru: 0xcd853f,
pink: 0xffc0cb,
plum: 0xdda0dd,
powderblue: 0xb0e0e6,
purple: 0x800080,
rebeccapurple: 0x663399,
red: 0xff0000,
rosybrown: 0xbc8f8f,
royalblue: 0x4169e1,
saddlebrown: 0x8b4513,
salmon: 0xfa8072,
sandybrown: 0xf4a460,
seagreen: 0x2e8b57,
seashell: 0xfff5ee,
sienna: 0xa0522d,
silver: 0xc0c0c0,
skyblue: 0x87ceeb,
slateblue: 0x6a5acd,
slategray: 0x708090,
slategrey: 0x708090,
snow: 0xfffafa,
springgreen: 0x00ff7f,
steelblue: 0x4682b4,
tan: 0xd2b48c,
teal: 0x008080,
thistle: 0xd8bfd8,
tomato: 0xff6347,
turquoise: 0x40e0d0,
violet: 0xee82ee,
wheat: 0xf5deb3,
white: 0xffffff,
whitesmoke: 0xf5f5f5,
yellow: 0xffff00,
yellowgreen: 0x9acd32
};
define(Color, color, {
displayable: function() {
return this.rgb().displayable();
},
toString: function() {
return this.rgb() + "";
}
});
function color(format) {
var m;
format = (format + "").trim().toLowerCase();
return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
: (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
: (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
: (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
: (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
: (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
: (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
: (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
: named.hasOwnProperty(format) ? rgbn(named[format])
: format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
: null;
}
function rgbn(n) {
return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
}
function rgba(r, g, b, a) {
if (a <= 0) r = g = b = NaN;
return new Rgb(r, g, b, a);
}
function rgbConvert(o) {
if (!(o instanceof Color)) o = color(o);
if (!o) return new Rgb;
o = o.rgb();
return new Rgb(o.r, o.g, o.b, o.opacity);
}
function colorRgb(r, g, b, opacity) {
return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
}
function Rgb(r, g, b, opacity) {
this.r = +r;
this.g = +g;
this.b = +b;
this.opacity = +opacity;
}
define(Rgb, colorRgb, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
rgb: function() {
return this;
},
displayable: function() {
return (0 <= this.r && this.r <= 255)
&& (0 <= this.g && this.g <= 255)
&& (0 <= this.b && this.b <= 255)
&& (0 <= this.opacity && this.opacity <= 1);
},
toString: function() {
var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
return (a === 1 ? "rgb(" : "rgba(")
+ Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.b) || 0))
+ (a === 1 ? ")" : ", " + a + ")");
}
}));
function hsla(h, s, l, a) {
if (a <= 0) h = s = l = NaN;
else if (l <= 0 || l >= 1) h = s = NaN;
else if (s <= 0) h = NaN;
return new Hsl(h, s, l, a);
}
function hslConvert(o) {
if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Color)) o = color(o);
if (!o) return new Hsl;
if (o instanceof Hsl) return o;
o = o.rgb();
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
min = Math.min(r, g, b),
max = Math.max(r, g, b),
h = NaN,
s = max - min,
l = (max + min) / 2;
if (s) {
if (r === max) h = (g - b) / s + (g < b) * 6;
else if (g === max) h = (b - r) / s + 2;
else h = (r - g) / s + 4;
s /= l < 0.5 ? max + min : 2 - max - min;
h *= 60;
} else {
s = l > 0 && l < 1 ? 0 : h;
}
return new Hsl(h, s, l, o.opacity);
}
function colorHsl(h, s, l, opacity) {
return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
}
function Hsl(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Hsl, colorHsl, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = this.h % 360 + (this.h < 0) * 360,
s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
l = this.l,
m2 = l + (l < 0.5 ? l : 1 - l) * s,
m1 = 2 * l - m2;
return new Rgb(
hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
hsl2rgb(h, m1, m2),
hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
this.opacity
);
},
displayable: function() {
return (0 <= this.s && this.s <= 1 || isNaN(this.s))
&& (0 <= this.l && this.l <= 1)
&& (0 <= this.opacity && this.opacity <= 1);
}
}));
/* From FvD 13.37, CSS Color Module Level 3 */
function hsl2rgb(h, m1, m2) {
return (h < 60 ? m1 + (m2 - m1) * h / 60
: h < 180 ? m2
: h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
: m1) * 255;
}
var deg2rad = Math.PI / 180;
var rad2deg = 180 / Math.PI;
var Kn = 18;
var Xn = 0.950470;
var Yn = 1;
var Zn = 1.088830;
var t0 = 4 / 29;
var t1 = 6 / 29;
var t2 = 3 * t1 * t1;
var t3 = t1 * t1 * t1;
function labConvert(o) {
if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
if (o instanceof Hcl) {
var h = o.h * deg2rad;
return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
}
if (!(o instanceof Rgb)) o = rgbConvert(o);
var b = rgb2xyz(o.r),
a = rgb2xyz(o.g),
l = rgb2xyz(o.b),
x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
}
function lab(l, a, b, opacity) {
return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
}
function Lab(l, a, b, opacity) {
this.l = +l;
this.a = +a;
this.b = +b;
this.opacity = +opacity;
}
define(Lab, lab, extend(Color, {
brighter: function(k) {
return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
darker: function(k) {
return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
rgb: function() {
var y = (this.l + 16) / 116,
x = isNaN(this.a) ? y : y + this.a / 500,
z = isNaN(this.b) ? y : y - this.b / 200;
y = Yn * lab2xyz(y);
x = Xn * lab2xyz(x);
z = Zn * lab2xyz(z);
return new Rgb(
xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
this.opacity
);
}
}));
function xyz2lab(t) {
return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
}
function lab2xyz(t) {
return t > t1 ? t * t * t : t2 * (t - t0);
}
function xyz2rgb(x) {
return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
}
function rgb2xyz(x) {
return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
function hclConvert(o) {
if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
if (!(o instanceof Lab)) o = labConvert(o);
var h = Math.atan2(o.b, o.a) * rad2deg;
return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
}
function colorHcl(h, c, l, opacity) {
return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
}
function Hcl(h, c, l, opacity) {
this.h = +h;
this.c = +c;
this.l = +l;
this.opacity = +opacity;
}
define(Hcl, colorHcl, extend(Color, {
brighter: function(k) {
return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
},
darker: function(k) {
return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
},
rgb: function() {
return labConvert(this).rgb();
}
}));
var A = -0.14861;
var B = +1.78277;
var C = -0.29227;
var D = -0.90649;
var E = +1.97294;
var ED = E * D;
var EB = E * B;
var BC_DA = B * C - D * A;
function cubehelixConvert(o) {
if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Rgb)) o = rgbConvert(o);
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
bl = b - l,
k = (E * (g - l) - C * bl) / D,
s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
}
function cubehelix(h, s, l, opacity) {
return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
}
function Cubehelix(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Cubehelix, cubehelix, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
l = +this.l,
a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
cosh = Math.cos(h),
sinh = Math.sin(h);
return new Rgb(
255 * (l + a * (A * cosh + B * sinh)),
255 * (l + a * (C * cosh + D * sinh)),
255 * (l + a * (E * cosh)),
this.opacity
);
}
}));
function basis$1(t1, v0, v1, v2, v3) {
var t2 = t1 * t1, t3 = t2 * t1;
return ((1 - 3 * t1 + 3 * t2 - t3) * v0
+ (4 - 6 * t2 + 3 * t3) * v1
+ (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
+ t3 * v3) / 6;
}
function basis$2(values) {
var n = values.length - 1;
return function(t) {
var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
v1 = values[i],
v2 = values[i + 1],
v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
return basis$1((t - i / n) * n, v0, v1, v2, v3);
};
}
function basisClosed$1(values) {
var n = values.length;
return function(t) {
var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
v0 = values[(i + n - 1) % n],
v1 = values[i % n],
v2 = values[(i + 1) % n],
v3 = values[(i + 2) % n];
return basis$1((t - i / n) * n, v0, v1, v2, v3);
};
}
function constant$2(x) {
return function() {
return x;
};
}
function linear$1(a, d) {
return function(t) {
return a + t * d;
};
}
function exponential$1(a, b, y) {
return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
return Math.pow(a + t * b, y);
};
}
function hue(a, b) {
var d = b - a;
return d ? linear$1(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$2(isNaN(a) ? b : a);
}
function gamma(y) {
return (y = +y) === 1 ? nogamma : function(a, b) {
return b - a ? exponential$1(a, b, y) : constant$2(isNaN(a) ? b : a);
};
}
function nogamma(a, b) {
var d = b - a;
return d ? linear$1(a, d) : constant$2(isNaN(a) ? b : a);
}
var interpolateRgb = (function rgbGamma(y) {
var color = gamma(y);
function rgb(start, end) {
var r = color((start = colorRgb(start)).r, (end = colorRgb(end)).r),
g = color(start.g, end.g),
b = color(start.b, end.b),
opacity = color(start.opacity, end.opacity);
return function(t) {
start.r = r(t);
start.g = g(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
rgb.gamma = rgbGamma;
return rgb;
})(1);
function rgbSpline(spline) {
return function(colors) {
var n = colors.length,
r = new Array(n),
g = new Array(n),
b = new Array(n),
i, color;
for (i = 0; i < n; ++i) {
color = colorRgb(colors[i]);
r[i] = color.r || 0;
g[i] = color.g || 0;
b[i] = color.b || 0;
}
r = spline(r);
g = spline(g);
b = spline(b);
color.opacity = 1;
return function(t) {
color.r = r(t);
color.g = g(t);
color.b = b(t);
return color + "";
};
};
}
var rgbBasis = rgbSpline(basis$2);
var rgbBasisClosed = rgbSpline(basisClosed$1);
function array$1(a, b) {
var nb = b ? b.length : 0,
na = a ? Math.min(nb, a.length) : 0,
x = new Array(nb),
c = new Array(nb),
i;
for (i = 0; i < na; ++i) x[i] = interpolate(a[i], b[i]);
for (; i < nb; ++i) c[i] = b[i];
return function(t) {
for (i = 0; i < na; ++i) c[i] = x[i](t);
return c;
};
}
function date(a, b) {
var d = new Date;
return a = +a, b -= a, function(t) {
return d.setTime(a + b * t), d;
};
}
function interpolateNumber(a, b) {
return a = +a, b -= a, function(t) {
return a + b * t;
};
}
function object(a, b) {
var i = {},
c = {},
k;
if (a === null || typeof a !== "object") a = {};
if (b === null || typeof b !== "object") b = {};
for (k in b) {
if (k in a) {
i[k] = interpolate(a[k], b[k]);
} else {
c[k] = b[k];
}
}
return function(t) {
for (k in i) c[k] = i[k](t);
return c;
};
}
var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
var reB = new RegExp(reA.source, "g");
function zero(b) {
return function() {
return b;
};
}
function one(b) {
return function(t) {
return b(t) + "";
};
}
function interpolateString(a, b) {
var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
am, // current match in a
bm, // current match in b
bs, // string preceding current number in b, if any
i = -1, // index in s
s = [], // string constants and placeholders
q = []; // number interpolators
// Coerce inputs to strings.
a = a + "", b = b + "";
// Interpolate pairs of numbers in a & b.
while ((am = reA.exec(a))
&& (bm = reB.exec(b))) {
if ((bs = bm.index) > bi) { // a string precedes the next number in b
bs = b.slice(bi, bs);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
if (s[i]) s[i] += bm; // coalesce with previous string
else s[++i] = bm;
} else { // interpolate non-matching numbers
s[++i] = null;
q.push({i: i, x: interpolateNumber(am, bm)});
}
bi = reB.lastIndex;
}
// Add remains of b.
if (bi < b.length) {
bs = b.slice(bi);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
// Special optimization for only a single match.
// Otherwise, interpolate each of the numbers and rejoin the string.
return s.length < 2 ? (q[0]
? one(q[0].x)
: zero(b))
: (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
}
function interpolate(a, b) {
var t = typeof b, c;
return b == null || t === "boolean" ? constant$2(b)
: (t === "number" ? interpolateNumber
: t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
: b instanceof color ? interpolateRgb
: b instanceof Date ? date
: Array.isArray(b) ? array$1
: isNaN(b) ? object
: interpolateNumber)(a, b);
}
function interpolateRound(a, b) {
return a = +a, b -= a, function(t) {
return Math.round(a + b * t);
};
}
var degrees = 180 / Math.PI;
var identity$2 = {
translateX: 0,
translateY: 0,
rotate: 0,
skewX: 0,
scaleX: 1,
scaleY: 1
};
function decompose(a, b, c, d, e, f) {
var scaleX, scaleY, skewX;
if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
return {
translateX: e,
translateY: f,
rotate: Math.atan2(b, a) * degrees,
skewX: Math.atan(skewX) * degrees,
scaleX: scaleX,
scaleY: scaleY
};
}
var cssNode;
var cssRoot;
var cssView;
var svgNode;
function parseCss(value) {
if (value === "none") return identity$2;
if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
cssNode.style.transform = value;
value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
cssRoot.removeChild(cssNode);
value = value.slice(7, -1).split(",");
return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
}
function parseSvg(value) {
if (value == null) return identity$2;
if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
svgNode.setAttribute("transform", value);
if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
value = value.matrix;
return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
}
function interpolateTransform(parse, pxComma, pxParen, degParen) {
function pop(s) {
return s.length ? s.pop() + " " : "";
}
function translate(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push("translate(", null, pxComma, null, pxParen);
q.push({i: i - 4, x: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(ya, yb)});
} else if (xb || yb) {
s.push("translate(" + xb + pxComma + yb + pxParen);
}
}
function rotate(a, b, s, q) {
if (a !== b) {
if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: interpolateNumber(a, b)});
} else if (b) {
s.push(pop(s) + "rotate(" + b + degParen);
}
}
function skewX(a, b, s, q) {
if (a !== b) {
q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: interpolateNumber(a, b)});
} else if (b) {
s.push(pop(s) + "skewX(" + b + degParen);
}
}
function scale(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push(pop(s) + "scale(", null, ",", null, ")");
q.push({i: i - 4, x: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(ya, yb)});
} else if (xb !== 1 || yb !== 1) {
s.push(pop(s) + "scale(" + xb + "," + yb + ")");
}
}
return function(a, b) {
var s = [], // string constants and placeholders
q = []; // number interpolators
a = parse(a), b = parse(b);
translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
rotate(a.rotate, b.rotate, s, q);
skewX(a.skewX, b.skewX, s, q);
scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
a = b = null; // gc
return function(t) {
var i = -1, n = q.length, o;
while (++i < n) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
};
}
var interpolateTransform$1 = interpolateTransform(parseCss, "px, ", "px)", "deg)");
var interpolateTransform$2 = interpolateTransform(parseSvg, ", ", ")", ")");
var rho = Math.SQRT2;
var rho2 = 2;
var rho4 = 4;
var epsilon2 = 1e-12;
function cosh(x) {
return ((x = Math.exp(x)) + 1 / x) / 2;
}
function sinh(x) {
return ((x = Math.exp(x)) - 1 / x) / 2;
}
function tanh(x) {
return ((x = Math.exp(2 * x)) - 1) / (x + 1);
}
// p0 = [ux0, uy0, w0]
// p1 = [ux1, uy1, w1]
function interpolateZoom(p0, p1) {
var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
dx = ux1 - ux0,
dy = uy1 - uy0,
d2 = dx * dx + dy * dy,
i,
S;
// Special case for u0 ≅ u1.
if (d2 < epsilon2) {
S = Math.log(w1 / w0) / rho;
i = function(t) {
return [
ux0 + t * dx,
uy0 + t * dy,
w0 * Math.exp(rho * t * S)
];
}
}
// General case.
else {
var d1 = Math.sqrt(d2),
b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
S = (r1 - r0) / rho;
i = function(t) {
var s = t * S,
coshr0 = cosh(r0),
u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
return [
ux0 + u * dx,
uy0 + u * dy,
w0 * coshr0 / cosh(rho * s + r0)
];
}
}
i.duration = S * 1000;
return i;
}
function hsl(hue) {
return function(start, end) {
var h = hue((start = colorHsl(start)).h, (end = colorHsl(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hsl$1 = hsl(hue);
var hslLong = hsl(nogamma);
function lab$1(start, end) {
var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
a = nogamma(start.a, end.a),
b = nogamma(start.b, end.b),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.l = l(t);
start.a = a(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
function hcl(hue) {
return function(start, end) {
var h = hue((start = colorHcl(start)).h, (end = colorHcl(end)).h),
c = nogamma(start.c, end.c),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.c = c(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hcl$1 = hcl(hue);
var hclLong = hcl(nogamma);
function cubehelix$1(hue) {
return (function cubehelixGamma(y) {
y = +y;
function cubehelix$$(start, end) {
var h = hue((start = cubehelix(start)).h, (end = cubehelix(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(Math.pow(t, y));
start.opacity = opacity(t);
return start + "";
};
}
cubehelix$$.gamma = cubehelixGamma;
return cubehelix$$;
})(1);
}
var cubehelix$2 = cubehelix$1(hue);
var interpolateCubehelixLong = cubehelix$1(nogamma);
function quantize(interpolator, n) {
var samples = new Array(n);
for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
return samples;
}
var noop$1 = {value: function() {}};
function dispatch() {
for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
_[t] = [];
}
return new Dispatch(_);
}
function Dispatch(_) {
this._ = _;
}
function parseTypenames(typenames, types) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
return {type: t, name: name};
});
}
Dispatch.prototype = dispatch.prototype = {
constructor: Dispatch,
on: function(typename, callback) {
var _ = this._,
T = parseTypenames(typename + "", _),
t,
i = -1,
n = T.length;
// If no callback was specified, return the callback of the given type and name.
if (arguments.length < 2) {
while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
return;
}
// If a type was specified, set the callback for the given type and name.
// Otherwise, if a null callback was specified, remove callbacks of the given name.
if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
while (++i < n) {
if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);
else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null);
}
return this;
},
copy: function() {
var copy = {}, _ = this._;
for (var t in _) copy[t] = _[t].slice();
return new Dispatch(copy);
},
call: function(type, that) {
if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
},
apply: function(type, that, args) {
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
}
};
function get(type, name) {
for (var i = 0, n = type.length, c; i < n; ++i) {
if ((c = type[i]).name === name) {
return c.value;
}
}
}
function set$1(type, name, callback) {
for (var i = 0, n = type.length; i < n; ++i) {
if (type[i].name === name) {
type[i] = noop$1, type = type.slice(0, i).concat(type.slice(i + 1));
break;
}
}
if (callback != null) type.push({name: name, value: callback});
return type;
}
function objectConverter(columns) {
return new Function("d", "return {" + columns.map(function(name, i) {
return JSON.stringify(name) + ": d[" + i + "]";
}).join(",") + "}");
}
function customConverter(columns, f) {
var object = objectConverter(columns);
return function(row, i) {
return f(object(row), i, columns);
};
}
// Compute unique columns in order of discovery.
function inferColumns(rows) {
var columnSet = Object.create(null),
columns = [];
rows.forEach(function(row) {
for (var column in row) {
if (!(column in columnSet)) {
columns.push(columnSet[column] = column);
}
}
});
return columns;
}
function dsv(delimiter) {
var reFormat = new RegExp("[\"" + delimiter + "\n]"),
delimiterCode = delimiter.charCodeAt(0);
function parse(text, f) {
var convert, columns, rows = parseRows(text, function(row, i) {
if (convert) return convert(row, i - 1);
columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
});
rows.columns = columns;
return rows;
}
function parseRows(text, f) {
var EOL = {}, // sentinel value for end-of-line
EOF = {}, // sentinel value for end-of-file
rows = [], // output rows
N = text.length,
I = 0, // current character index
n = 0, // the current line number
t, // the current token
eol; // is the current token followed by EOL?
function token() {
if (I >= N) return EOF; // special case: end of file
if (eol) return eol = false, EOL; // special case: end of line
// special case: quotes
var j = I, c;
if (text.charCodeAt(j) === 34) {
var i = j;
while (i++ < N) {
if (text.charCodeAt(i) === 34) {
if (text.charCodeAt(i + 1) !== 34) break;
++i;
}
}
I = i + 2;
c = text.charCodeAt(i + 1);
if (c === 13) {
eol = true;
if (text.charCodeAt(i + 2) === 10) ++I;
} else if (c === 10) {
eol = true;
}
return text.slice(j + 1, i).replace(/""/g, "\"");
}
// common case: find next delimiter or newline
while (I < N) {
var k = 1;
c = text.charCodeAt(I++);
if (c === 10) eol = true; // \n
else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
else if (c !== delimiterCode) continue;
return text.slice(j, I - k);
}
// special case: last token before EOF
return text.slice(j);
}
while ((t = token()) !== EOF) {
var a = [];
while (t !== EOL && t !== EOF) {
a.push(t);
t = token();
}
if (f && (a = f(a, n++)) == null) continue;
rows.push(a);
}
return rows;
}
function format(rows, columns) {
if (columns == null) columns = inferColumns(rows);
return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
return columns.map(function(column) {
return formatValue(row[column]);
}).join(delimiter);
})).join("\n");
}
function formatRows(rows) {
return rows.map(formatRow).join("\n");
}
function formatRow(row) {
return row.map(formatValue).join(delimiter);
}
function formatValue(text) {
return text == null ? ""
: reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\""
: text;
}
return {
parse: parse,
parseRows: parseRows,
format: format,
formatRows: formatRows
};
}
var csv = dsv(",");
var csvParse = csv.parse;
var csvParseRows = csv.parseRows;
var csvFormat = csv.format;
var csvFormatRows = csv.formatRows;
var tsv = dsv("\t");
var tsvParse = tsv.parse;
var tsvParseRows = tsv.parseRows;
var tsvFormat = tsv.format;
var tsvFormatRows = tsv.formatRows;
function request(url, callback) {
var request,
event = dispatch("beforesend", "progress", "load", "error"),
mimeType,
headers = map$1(),
xhr = new XMLHttpRequest,
user = null,
password = null,
response,
responseType,
timeout = 0;
// If IE does not support CORS, use XDomainRequest.
if (typeof XDomainRequest !== "undefined"
&& !("withCredentials" in xhr)
&& /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
"onload" in xhr
? xhr.onload = xhr.onerror = xhr.ontimeout = respond
: xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); };
function respond(o) {
var status = xhr.status, result;
if (!status && hasResponse(xhr)
|| status >= 200 && status < 300
|| status === 304) {
if (response) {
try {
result = response.call(request, xhr);
} catch (e) {
event.call("error", request, e);
return;
}
} else {
result = xhr;
}
event.call("load", request, result);
} else {
event.call("error", request, o);
}
}
xhr.onprogress = function(e) {
event.call("progress", request, e);
};
request = {
header: function(name, value) {
name = (name + "").toLowerCase();
if (arguments.length < 2) return headers.get(name);
if (value == null) headers.remove(name);
else headers.set(name, value + "");
return request;
},
// If mimeType is non-null and no Accept header is set, a default is used.
mimeType: function(value) {
if (!arguments.length) return mimeType;
mimeType = value == null ? null : value + "";
return request;
},
// Specifies what type the response value should take;
// for instance, arraybuffer, blob, document, or text.
responseType: function(value) {
if (!arguments.length) return responseType;
responseType = value;
return request;
},
timeout: function(value) {
if (!arguments.length) return timeout;
timeout = +value;
return request;
},
user: function(value) {
return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
},
password: function(value) {
return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
},
// Specify how to convert the response content to a specific type;
// changes the callback value on "load" events.
response: function(value) {
response = value;
return request;
},
// Alias for send("GET", …).
get: function(data, callback) {
return request.send("GET", data, callback);
},
// Alias for send("POST", …).
post: function(data, callback) {
return request.send("POST", data, callback);
},
// If callback is non-null, it will be used for error and load events.
send: function(method, data, callback) {
if (!callback && typeof data === "function") callback = data, data = null;
if (callback && callback.length === 1) callback = fixCallback(callback);
xhr.open(method, url, true, user, password);
if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); });
if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
if (responseType != null) xhr.responseType = responseType;
if (timeout > 0) xhr.timeout = timeout;
if (callback) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); });
event.call("beforesend", request, xhr);
xhr.send(data == null ? null : data);
return request;
},
abort: function() {
xhr.abort();
return request;
},
on: function() {
var value = event.on.apply(event, arguments);
return value === event ? request : value;
}
};
return callback
? request.get(callback)
: request;
}
function fixCallback(callback) {
return function(error, xhr) {
callback(error == null ? xhr : null);
};
}
function hasResponse(xhr) {
var type = xhr.responseType;
return type && type !== "text"
? xhr.response // null on error
: xhr.responseText; // "" on error
}
function type(defaultMimeType, response) {
return function(url, callback) {
var r = request(url).mimeType(defaultMimeType).response(response);
return callback ? r.get(callback) : r;
};
}
var html = type("text/html", function(xhr) {
return document.createRange().createContextualFragment(xhr.responseText);
});
var json = type("application/json", function(xhr) {
return JSON.parse(xhr.responseText);
});
var text = type("text/plain", function(xhr) {
return xhr.responseText;
});
var xml = type("application/xml", function(xhr) {
var xml = xhr.responseXML;
if (!xml) throw new Error("parse error");
return xml;
});
function dsv$1(defaultMimeType, parse) {
return function(url, row, callback) {
if (arguments.length < 3) callback = row, row = null;
var r = request(url).mimeType(defaultMimeType);
r.row = function(_) { return arguments.length ? r.response(responseOf(parse, row = _)) : row; };
r.row(row);
return callback ? r.get(callback) : r;
};
}
function responseOf(parse, row) {
return function(request) {
return parse(request.responseText, row);
};
}
var csv$1 = dsv$1("text/csv", csvParse);
var tsv$1 = dsv$1("text/tab-separated-values", tsvParse);
var frame = 0;
var timeout = 0;
var interval = 0;
var pokeDelay = 1000;
var taskHead;
var taskTail;
var clockLast = 0;
var clockNow = 0;
var clockSkew = 0;
var clock = typeof performance === "object" && performance.now ? performance : Date;
var setFrame = typeof requestAnimationFrame === "function"
? (clock === Date ? function(f) { requestAnimationFrame(function() { f(clock.now()); }); } : requestAnimationFrame)
: function(f) { setTimeout(f, 17); };
function now() {
return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
}
function clearNow() {
clockNow = 0;
}
function Timer() {
this._call =
this._time =
this._next = null;
}
Timer.prototype = timer.prototype = {
constructor: Timer,
restart: function(callback, delay, time) {
if (typeof callback !== "function") throw new TypeError("callback is not a function");
time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
if (!this._next && taskTail !== this) {
if (taskTail) taskTail._next = this;
else taskHead = this;
taskTail = this;
}
this._call = callback;
this._time = time;
sleep();
},
stop: function() {
if (this._call) {
this._call = null;
this._time = Infinity;
sleep();
}
}
};
function timer(callback, delay, time) {
var t = new Timer;
t.restart(callback, delay, time);
return t;
}
function timerFlush() {
now(); // Get the current time, if not already set.
++frame; // Pretend we’ve set an alarm, if we haven’t already.
var t = taskHead, e;
while (t) {
if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
t = t._next;
}
--frame;
}
function wake(time) {
clockNow = (clockLast = time || clock.now()) + clockSkew;
frame = timeout = 0;
try {
timerFlush();
} finally {
frame = 0;
nap();
clockNow = 0;
}
}
function poke$1() {
var now = clock.now(), delay = now - clockLast;
if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
}
function nap() {
var t0, t1 = taskHead, t2, time = Infinity;
while (t1) {
if (t1._call) {
if (time > t1._time) time = t1._time;
t0 = t1, t1 = t1._next;
} else {
t2 = t1._next, t1._next = null;
t1 = t0 ? t0._next = t2 : taskHead = t2;
}
}
taskTail = t0;
sleep(time);
}
function sleep(time) {
if (frame) return; // Soonest alarm already set, or will be.
if (timeout) timeout = clearTimeout(timeout);
var delay = time - clockNow;
if (delay > 24) {
if (time < Infinity) timeout = setTimeout(wake, delay);
if (interval) interval = clearInterval(interval);
} else {
if (!interval) interval = setInterval(poke$1, pokeDelay);
frame = 1, setFrame(wake);
}
}
function timeout$1(callback, delay, time) {
var t = new Timer;
delay = delay == null ? 0 : +delay;
t.restart(function(elapsed) {
t.stop();
callback(elapsed + delay);
}, delay, time);
return t;
}
function interval$1(callback, delay, time) {
var t = new Timer, total = delay;
if (delay == null) return t.restart(callback, delay, time), t;
delay = +delay, time = time == null ? now() : +time;
t.restart(function tick(elapsed) {
elapsed += total;
t.restart(tick, total += delay, time);
callback(elapsed);
}, delay, time);
return t;
}
var t0$1 = new Date;
var t1$1 = new Date;
function newInterval(floori, offseti, count, field) {
function interval(date) {
return floori(date = new Date(+date)), date;
}
interval.floor = interval;
interval.ceil = function(date) {
return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
};
interval.round = function(date) {
var d0 = interval(date),
d1 = interval.ceil(date);
return date - d0 < d1 - date ? d0 : d1;
};
interval.offset = function(date, step) {
return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
};
interval.range = function(start, stop, step) {
var range = [];
start = interval.ceil(start);
step = step == null ? 1 : Math.floor(step);
if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop)
return range;
};
interval.filter = function(test) {
return newInterval(function(date) {
while (floori(date), !test(date)) date.setTime(date - 1);
}, function(date, step) {
while (--step >= 0) while (offseti(date, 1), !test(date));
});
};
if (count) {
interval.count = function(start, end) {
t0$1.setTime(+start), t1$1.setTime(+end);
floori(t0$1), floori(t1$1);
return Math.floor(count(t0$1, t1$1));
};
interval.every = function(step) {
step = Math.floor(step);
return !isFinite(step) || !(step > 0) ? null
: !(step > 1) ? interval
: interval.filter(field
? function(d) { return field(d) % step === 0; }
: function(d) { return interval.count(0, d) % step === 0; });
};
}
return interval;
}
var millisecond = newInterval(function() {
// noop
}, function(date, step) {
date.setTime(+date + step);
}, function(start, end) {
return end - start;
});
// An optimized implementation for this simple case.
millisecond.every = function(k) {
k = Math.floor(k);
if (!isFinite(k) || !(k > 0)) return null;
if (!(k > 1)) return millisecond;
return newInterval(function(date) {
date.setTime(Math.floor(date / k) * k);
}, function(date, step) {
date.setTime(+date + step * k);
}, function(start, end) {
return (end - start) / k;
});
};
var milliseconds = millisecond.range;
var durationSecond = 1e3;
var durationMinute = 6e4;
var durationHour = 36e5;
var durationDay = 864e5;
var durationWeek = 6048e5;
var second = newInterval(function(date) {
date.setTime(Math.floor(date / durationSecond) * durationSecond);
}, function(date, step) {
date.setTime(+date + step * durationSecond);
}, function(start, end) {
return (end - start) / durationSecond;
}, function(date) {
return date.getUTCSeconds();
});
var seconds = second.range;
var minute = newInterval(function(date) {
date.setTime(Math.floor(date / durationMinute) * durationMinute);
}, function(date, step) {
date.setTime(+date + step * durationMinute);
}, function(start, end) {
return (end - start) / durationMinute;
}, function(date) {
return date.getMinutes();
});
var minutes = minute.range;
var hour = newInterval(function(date) {
var offset = date.getTimezoneOffset() * durationMinute % durationHour;
if (offset < 0) offset += durationHour;
date.setTime(Math.floor((+date - offset) / durationHour) * durationHour + offset);
}, function(date, step) {
date.setTime(+date + step * durationHour);
}, function(start, end) {
return (end - start) / durationHour;
}, function(date) {
return date.getHours();
});
var hours = hour.range;
var day = newInterval(function(date) {
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setDate(date.getDate() + step);
}, function(start, end) {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay;
}, function(date) {
return date.getDate() - 1;
});
var days = day.range;
function weekday(i) {
return newInterval(function(date) {
date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setDate(date.getDate() + step * 7);
}, function(start, end) {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;
});
}
var timeWeek = weekday(0);
var timeMonday = weekday(1);
var tuesday = weekday(2);
var wednesday = weekday(3);
var thursday = weekday(4);
var friday = weekday(5);
var saturday = weekday(6);
var sundays = timeWeek.range;
var mondays = timeMonday.range;
var tuesdays = tuesday.range;
var wednesdays = wednesday.range;
var thursdays = thursday.range;
var fridays = friday.range;
var saturdays = saturday.range;
var month = newInterval(function(date) {
date.setDate(1);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setMonth(date.getMonth() + step);
}, function(start, end) {
return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
}, function(date) {
return date.getMonth();
});
var months = month.range;
var year = newInterval(function(date) {
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setFullYear(date.getFullYear() + step);
}, function(start, end) {
return end.getFullYear() - start.getFullYear();
}, function(date) {
return date.getFullYear();
});
// An optimized implementation for this simple case.
year.every = function(k) {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
date.setFullYear(Math.floor(date.getFullYear() / k) * k);
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setFullYear(date.getFullYear() + step * k);
});
};
var years = year.range;
var utcMinute = newInterval(function(date) {
date.setUTCSeconds(0, 0);
}, function(date, step) {
date.setTime(+date + step * durationMinute);
}, function(start, end) {
return (end - start) / durationMinute;
}, function(date) {
return date.getUTCMinutes();
});
var utcMinutes = utcMinute.range;
var utcHour = newInterval(function(date) {
date.setUTCMinutes(0, 0, 0);
}, function(date, step) {
date.setTime(+date + step * durationHour);
}, function(start, end) {
return (end - start) / durationHour;
}, function(date) {
return date.getUTCHours();
});
var utcHours = utcHour.range;
var utcDay = newInterval(function(date) {
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCDate(date.getUTCDate() + step);
}, function(start, end) {
return (end - start) / durationDay;
}, function(date) {
return date.getUTCDate() - 1;
});
var utcDays = utcDay.range;
function utcWeekday(i) {
return newInterval(function(date) {
date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCDate(date.getUTCDate() + step * 7);
}, function(start, end) {
return (end - start) / durationWeek;
});
}
var utcWeek = utcWeekday(0);
var utcMonday = utcWeekday(1);
var utcTuesday = utcWeekday(2);
var utcWednesday = utcWeekday(3);
var utcThursday = utcWeekday(4);
var utcFriday = utcWeekday(5);
var utcSaturday = utcWeekday(6);
var utcSundays = utcWeek.range;
var utcMondays = utcMonday.range;
var utcTuesdays = utcTuesday.range;
var utcWednesdays = utcWednesday.range;
var utcThursdays = utcThursday.range;
var utcFridays = utcFriday.range;
var utcSaturdays = utcSaturday.range;
var utcMonth = newInterval(function(date) {
date.setUTCDate(1);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCMonth(date.getUTCMonth() + step);
}, function(start, end) {
return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
}, function(date) {
return date.getUTCMonth();
});
var utcMonths = utcMonth.range;
var utcYear = newInterval(function(date) {
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCFullYear(date.getUTCFullYear() + step);
}, function(start, end) {
return end.getUTCFullYear() - start.getUTCFullYear();
}, function(date) {
return date.getUTCFullYear();
});
// An optimized implementation for this simple case.
utcYear.every = function(k) {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCFullYear(date.getUTCFullYear() + step * k);
});
};
var utcYears = utcYear.range;
// Computes the decimal coefficient and exponent of the specified number x with
// significant digits p, where x is positive and p is in [1, 21] or undefined.
// For example, formatDecimal(1.23) returns ["123", 0].
function formatDecimal(x, p) {
if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
var i, coefficient = x.slice(0, i);
// The string returned by toExponential either has the form \d\.\d+e[-+]\d+
// (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
return [
coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
+x.slice(i + 1)
];
}
function exponent$1(x) {
return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
}
function formatGroup(grouping, thousands) {
return function(value, width) {
var i = value.length,
t = [],
j = 0,
g = grouping[0],
length = 0;
while (i > 0 && g > 0) {
if (length + g + 1 > width) g = Math.max(1, width - length);
t.push(value.substring(i -= g, i + g));
if ((length += g + 1) > width) break;
g = grouping[j = (j + 1) % grouping.length];
}
return t.reverse().join(thousands);
};
}
function formatDefault(x, p) {
x = x.toPrecision(p);
out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
switch (x[i]) {
case ".": i0 = i1 = i; break;
case "0": if (i0 === 0) i0 = i; i1 = i; break;
case "e": break out;
default: if (i0 > 0) i0 = 0; break;
}
}
return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
}
var prefixExponent;
function formatPrefixAuto(x, p) {
var d = formatDecimal(x, p);
if (!d) return x + "";
var coefficient = d[0],
exponent = d[1],
i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
n = coefficient.length;
return i === n ? coefficient
: i > n ? coefficient + new Array(i - n + 1).join("0")
: i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
: "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
}
function formatRounded(x, p) {
var d = formatDecimal(x, p);
if (!d) return x + "";
var coefficient = d[0],
exponent = d[1];
return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
: coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
: coefficient + new Array(exponent - coefficient.length + 2).join("0");
}
var formatTypes = {
"": formatDefault,
"%": function(x, p) { return (x * 100).toFixed(p); },
"b": function(x) { return Math.round(x).toString(2); },
"c": function(x) { return x + ""; },
"d": function(x) { return Math.round(x).toString(10); },
"e": function(x, p) { return x.toExponential(p); },
"f": function(x, p) { return x.toFixed(p); },
"g": function(x, p) { return x.toPrecision(p); },
"o": function(x) { return Math.round(x).toString(8); },
"p": function(x, p) { return formatRounded(x * 100, p); },
"r": formatRounded,
"s": formatPrefixAuto,
"X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
"x": function(x) { return Math.round(x).toString(16); }
};
// [[fill]align][sign][symbol][0][width][,][.precision][type]
var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
function formatSpecifier(specifier) {
return new FormatSpecifier(specifier);
}
function FormatSpecifier(specifier) {
if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
var match,
fill = match[1] || " ",
align = match[2] || ">",
sign = match[3] || "-",
symbol = match[4] || "",
zero = !!match[5],
width = match[6] && +match[6],
comma = !!match[7],
precision = match[8] && +match[8].slice(1),
type = match[9] || "";
// The "n" type is an alias for ",g".
if (type === "n") comma = true, type = "g";
// Map invalid types to the default format.
else if (!formatTypes[type]) type = "";
// If zero fill is specified, padding goes after sign and before digits.
if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
this.fill = fill;
this.align = align;
this.sign = sign;
this.symbol = symbol;
this.zero = zero;
this.width = width;
this.comma = comma;
this.precision = precision;
this.type = type;
}
FormatSpecifier.prototype.toString = function() {
return this.fill
+ this.align
+ this.sign
+ this.symbol
+ (this.zero ? "0" : "")
+ (this.width == null ? "" : Math.max(1, this.width | 0))
+ (this.comma ? "," : "")
+ (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
+ this.type;
};
var prefixes = ["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"];
function identity$3(x) {
return x;
}
function formatLocale(locale) {
var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
currency = locale.currency,
decimal = locale.decimal;
function newFormat(specifier) {
specifier = formatSpecifier(specifier);
var fill = specifier.fill,
align = specifier.align,
sign = specifier.sign,
symbol = specifier.symbol,
zero = specifier.zero,
width = specifier.width,
comma = specifier.comma,
precision = specifier.precision,
type = specifier.type;
// Compute the prefix and suffix.
// For SI-prefix, the suffix is lazily computed.
var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";
// What format function should we use?
// Is this an integer type?
// Can this type generate exponential notation?
var formatType = formatTypes[type],
maybeSuffix = !type || /[defgprs%]/.test(type);
// Set the default precision if not specified,
// or clamp the specified precision to the supported range.
// For significant precision, it must be in [1, 21].
// For fixed precision, it must be in [0, 20].
precision = precision == null ? (type ? 6 : 12)
: /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
: Math.max(0, Math.min(20, precision));
function format(value) {
var valuePrefix = prefix,
valueSuffix = suffix,
i, n, c;
if (type === "c") {
valueSuffix = formatType(value) + valueSuffix;
value = "";
} else {
value = +value;
// Convert negative to positive, and compute the prefix.
// Note that -0 is not less than 0, but 1 / -0 is!
var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true);
// Perform the initial formatting.
value = formatType(value, precision);
// If the original value was negative, it may be rounded to zero during
// formatting; treat this as (positive) zero.
if (valueNegative) {
i = -1, n = value.length;
valueNegative = false;
while (++i < n) {
if (c = value.charCodeAt(i), (48 < c && c < 58)
|| (type === "x" && 96 < c && c < 103)
|| (type === "X" && 64 < c && c < 71)) {
valueNegative = true;
break;
}
}
}
// Compute the prefix and suffix.
valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
// Break the formatted value into the integer “value” part that can be
// grouped, and fractional or exponential “suffix” part that is not.
if (maybeSuffix) {
i = -1, n = value.length;
while (++i < n) {
if (c = value.charCodeAt(i), 48 > c || c > 57) {
valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
value = value.slice(0, i);
break;
}
}
}
}
// If the fill character is not "0", grouping is applied before padding.
if (comma && !zero) value = group(value, Infinity);
// Compute the padding.
var length = valuePrefix.length + value.length + valueSuffix.length,
padding = length < width ? new Array(width - length + 1).join(fill) : "";
// If the fill character is "0", grouping is applied after padding.
if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
// Reconstruct the final output based on the desired alignment.
switch (align) {
case "<": return valuePrefix + value + valueSuffix + padding;
case "=": return valuePrefix + padding + value + valueSuffix;
case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
}
return padding + valuePrefix + value + valueSuffix;
}
format.toString = function() {
return specifier + "";
};
return format;
}
function formatPrefix(specifier, value) {
var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
k = Math.pow(10, -e),
prefix = prefixes[8 + e / 3];
return function(value) {
return f(k * value) + prefix;
};
}
return {
format: newFormat,
formatPrefix: formatPrefix
};
}
var locale;
exports.format;
exports.formatPrefix;
defaultLocale({
decimal: ".",
thousands: ",",
grouping: [3],
currency: ["$", ""]
});
function defaultLocale(definition) {
locale = formatLocale(definition);
exports.format = locale.format;
exports.formatPrefix = locale.formatPrefix;
return locale;
}
function precisionFixed(step) {
return Math.max(0, -exponent$1(Math.abs(step)));
}
function precisionPrefix(step, value) {
return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
}
function precisionRound(step, max) {
step = Math.abs(step), max = Math.abs(max) - step;
return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
}
function localDate(d) {
if (0 <= d.y && d.y < 100) {
var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
date.setFullYear(d.y);
return date;
}
return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
}
function utcDate(d) {
if (0 <= d.y && d.y < 100) {
var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
date.setUTCFullYear(d.y);
return date;
}
return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
}
function newYear(y) {
return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
}
function formatLocale$1(locale) {
var locale_dateTime = locale.dateTime,
locale_date = locale.date,
locale_time = locale.time,
locale_periods = locale.periods,
locale_weekdays = locale.days,
locale_shortWeekdays = locale.shortDays,
locale_months = locale.months,
locale_shortMonths = locale.shortMonths;
var periodRe = formatRe(locale_periods),
periodLookup = formatLookup(locale_periods),
weekdayRe = formatRe(locale_weekdays),
weekdayLookup = formatLookup(locale_weekdays),
shortWeekdayRe = formatRe(locale_shortWeekdays),
shortWeekdayLookup = formatLookup(locale_shortWeekdays),
monthRe = formatRe(locale_months),
monthLookup = formatLookup(locale_months),
shortMonthRe = formatRe(locale_shortMonths),
shortMonthLookup = formatLookup(locale_shortMonths);
var formats = {
"a": formatShortWeekday,
"A": formatWeekday,
"b": formatShortMonth,
"B": formatMonth,
"c": null,
"d": formatDayOfMonth,
"e": formatDayOfMonth,
"H": formatHour24,
"I": formatHour12,
"j": formatDayOfYear,
"L": formatMilliseconds,
"m": formatMonthNumber,
"M": formatMinutes,
"p": formatPeriod,
"S": formatSeconds,
"U": formatWeekNumberSunday,
"w": formatWeekdayNumber,
"W": formatWeekNumberMonday,
"x": null,
"X": null,
"y": formatYear,
"Y": formatFullYear,
"Z": formatZone,
"%": formatLiteralPercent
};
var utcFormats = {
"a": formatUTCShortWeekday,
"A": formatUTCWeekday,
"b": formatUTCShortMonth,
"B": formatUTCMonth,
"c": null,
"d": formatUTCDayOfMonth,
"e": formatUTCDayOfMonth,
"H": formatUTCHour24,
"I": formatUTCHour12,
"j": formatUTCDayOfYear,
"L": formatUTCMilliseconds,
"m": formatUTCMonthNumber,
"M": formatUTCMinutes,
"p": formatUTCPeriod,
"S": formatUTCSeconds,
"U": formatUTCWeekNumberSunday,
"w": formatUTCWeekdayNumber,
"W": formatUTCWeekNumberMonday,
"x": null,
"X": null,
"y": formatUTCYear,
"Y": formatUTCFullYear,
"Z": formatUTCZone,
"%": formatLiteralPercent
};
var parses = {
"a": parseShortWeekday,
"A": parseWeekday,
"b": parseShortMonth,
"B": parseMonth,
"c": parseLocaleDateTime,
"d": parseDayOfMonth,
"e": parseDayOfMonth,
"H": parseHour24,
"I": parseHour24,
"j": parseDayOfYear,
"L": parseMilliseconds,
"m": parseMonthNumber,
"M": parseMinutes,
"p": parsePeriod,
"S": parseSeconds,
"U": parseWeekNumberSunday,
"w": parseWeekdayNumber,
"W": parseWeekNumberMonday,
"x": parseLocaleDate,
"X": parseLocaleTime,
"y": parseYear,
"Y": parseFullYear,
"Z": parseZone,
"%": parseLiteralPercent
};
// These recursive directive definitions must be deferred.
formats.x = newFormat(locale_date, formats);
formats.X = newFormat(locale_time, formats);
formats.c = newFormat(locale_dateTime, formats);
utcFormats.x = newFormat(locale_date, utcFormats);
utcFormats.X = newFormat(locale_time, utcFormats);
utcFormats.c = newFormat(locale_dateTime, utcFormats);
function newFormat(specifier, formats) {
return function(date) {
var string = [],
i = -1,
j = 0,
n = specifier.length,
c,
pad,
format;
if (!(date instanceof Date)) date = new Date(+date);
while (++i < n) {
if (specifier.charCodeAt(i) === 37) {
string.push(specifier.slice(j, i));
if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
else pad = c === "e" ? " " : "0";
if (format = formats[c]) c = format(date, pad);
string.push(c);
j = i + 1;
}
}
string.push(specifier.slice(j, i));
return string.join("");
};
}
function newParse(specifier, newDate) {
return function(string) {
var d = newYear(1900),
i = parseSpecifier(d, specifier, string += "", 0);
if (i != string.length) return null;
// The am-pm flag is 0 for AM, and 1 for PM.
if ("p" in d) d.H = d.H % 12 + d.p * 12;
// Convert day-of-week and week-of-year to day-of-year.
if ("W" in d || "U" in d) {
if (!("w" in d)) d.w = "W" in d ? 1 : 0;
var day = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();
d.m = 0;
d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7;
}
// If a time zone is specified, all fields are interpreted as UTC and then
// offset according to the specified time zone.
if ("Z" in d) {
d.H += d.Z / 100 | 0;
d.M += d.Z % 100;
return utcDate(d);
}
// Otherwise, all fields are in local time.
return newDate(d);
};
}
function parseSpecifier(d, specifier, string, j) {
var i = 0,
n = specifier.length,
m = string.length,
c,
parse;
while (i < n) {
if (j >= m) return -1;
c = specifier.charCodeAt(i++);
if (c === 37) {
c = specifier.charAt(i++);
parse = parses[c in pads ? specifier.charAt(i++) : c];
if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
} else if (c != string.charCodeAt(j++)) {
return -1;
}
}
return j;
}
function parsePeriod(d, string, i) {
var n = periodRe.exec(string.slice(i));
return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseShortWeekday(d, string, i) {
var n = shortWeekdayRe.exec(string.slice(i));
return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseWeekday(d, string, i) {
var n = weekdayRe.exec(string.slice(i));
return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseShortMonth(d, string, i) {
var n = shortMonthRe.exec(string.slice(i));
return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseMonth(d, string, i) {
var n = monthRe.exec(string.slice(i));
return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseLocaleDateTime(d, string, i) {
return parseSpecifier(d, locale_dateTime, string, i);
}
function parseLocaleDate(d, string, i) {
return parseSpecifier(d, locale_date, string, i);
}
function parseLocaleTime(d, string, i) {
return parseSpecifier(d, locale_time, string, i);
}
function formatShortWeekday(d) {
return locale_shortWeekdays[d.getDay()];
}
function formatWeekday(d) {
return locale_weekdays[d.getDay()];
}
function formatShortMonth(d) {
return locale_shortMonths[d.getMonth()];
}
function formatMonth(d) {
return locale_months[d.getMonth()];
}
function formatPeriod(d) {
return locale_periods[+(d.getHours() >= 12)];
}
function formatUTCShortWeekday(d) {
return locale_shortWeekdays[d.getUTCDay()];
}
function formatUTCWeekday(d) {
return locale_weekdays[d.getUTCDay()];
}
function formatUTCShortMonth(d) {
return locale_shortMonths[d.getUTCMonth()];
}
function formatUTCMonth(d) {
return locale_months[d.getUTCMonth()];
}
function formatUTCPeriod(d) {
return locale_periods[+(d.getUTCHours() >= 12)];
}
return {
format: function(specifier) {
var f = newFormat(specifier += "", formats);
f.toString = function() { return specifier; };
return f;
},
parse: function(specifier) {
var p = newParse(specifier += "", localDate);
p.toString = function() { return specifier; };
return p;
},
utcFormat: function(specifier) {
var f = newFormat(specifier += "", utcFormats);
f.toString = function() { return specifier; };
return f;
},
utcParse: function(specifier) {
var p = newParse(specifier, utcDate);
p.toString = function() { return specifier; };
return p;
}
};
}
var pads = {"-": "", "_": " ", "0": "0"};
var numberRe = /^\s*\d+/;
var percentRe = /^%/;
var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
function pad(value, fill, width) {
var sign = value < 0 ? "-" : "",
string = (sign ? -value : value) + "",
length = string.length;
return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
}
function requote(s) {
return s.replace(requoteRe, "\\$&");
}
function formatRe(names) {
return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
}
function formatLookup(names) {
var map = {}, i = -1, n = names.length;
while (++i < n) map[names[i].toLowerCase()] = i;
return map;
}
function parseWeekdayNumber(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 1));
return n ? (d.w = +n[0], i + n[0].length) : -1;
}
function parseWeekNumberSunday(d, string, i) {
var n = numberRe.exec(string.slice(i));
return n ? (d.U = +n[0], i + n[0].length) : -1;
}
function parseWeekNumberMonday(d, string, i) {
var n = numberRe.exec(string.slice(i));
return n ? (d.W = +n[0], i + n[0].length) : -1;
}
function parseFullYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 4));
return n ? (d.y = +n[0], i + n[0].length) : -1;
}
function parseYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
}
function parseZone(d, string, i) {
var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6));
return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
}
function parseMonthNumber(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
}
function parseDayOfMonth(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.d = +n[0], i + n[0].length) : -1;
}
function parseDayOfYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 3));
return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
}
function parseHour24(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.H = +n[0], i + n[0].length) : -1;
}
function parseMinutes(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.M = +n[0], i + n[0].length) : -1;
}
function parseSeconds(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.S = +n[0], i + n[0].length) : -1;
}
function parseMilliseconds(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 3));
return n ? (d.L = +n[0], i + n[0].length) : -1;
}
function parseLiteralPercent(d, string, i) {
var n = percentRe.exec(string.slice(i, i + 1));
return n ? i + n[0].length : -1;
}
function formatDayOfMonth(d, p) {
return pad(d.getDate(), p, 2);
}
function formatHour24(d, p) {
return pad(d.getHours(), p, 2);
}
function formatHour12(d, p) {
return pad(d.getHours() % 12 || 12, p, 2);
}
function formatDayOfYear(d, p) {
return pad(1 + day.count(year(d), d), p, 3);
}
function formatMilliseconds(d, p) {
return pad(d.getMilliseconds(), p, 3);
}
function formatMonthNumber(d, p) {
return pad(d.getMonth() + 1, p, 2);
}
function formatMinutes(d, p) {
return pad(d.getMinutes(), p, 2);
}
function formatSeconds(d, p) {
return pad(d.getSeconds(), p, 2);
}
function formatWeekNumberSunday(d, p) {
return pad(timeWeek.count(year(d), d), p, 2);
}
function formatWeekdayNumber(d) {
return d.getDay();
}
function formatWeekNumberMonday(d, p) {
return pad(timeMonday.count(year(d), d), p, 2);
}
function formatYear(d, p) {
return pad(d.getFullYear() % 100, p, 2);
}
function formatFullYear(d, p) {
return pad(d.getFullYear() % 10000, p, 4);
}
function formatZone(d) {
var z = d.getTimezoneOffset();
return (z > 0 ? "-" : (z *= -1, "+"))
+ pad(z / 60 | 0, "0", 2)
+ pad(z % 60, "0", 2);
}
function formatUTCDayOfMonth(d, p) {
return pad(d.getUTCDate(), p, 2);
}
function formatUTCHour24(d, p) {
return pad(d.getUTCHours(), p, 2);
}
function formatUTCHour12(d, p) {
return pad(d.getUTCHours() % 12 || 12, p, 2);
}
function formatUTCDayOfYear(d, p) {
return pad(1 + utcDay.count(utcYear(d), d), p, 3);
}
function formatUTCMilliseconds(d, p) {
return pad(d.getUTCMilliseconds(), p, 3);
}
function formatUTCMonthNumber(d, p) {
return pad(d.getUTCMonth() + 1, p, 2);
}
function formatUTCMinutes(d, p) {
return pad(d.getUTCMinutes(), p, 2);
}
function formatUTCSeconds(d, p) {
return pad(d.getUTCSeconds(), p, 2);
}
function formatUTCWeekNumberSunday(d, p) {
return pad(utcWeek.count(utcYear(d), d), p, 2);
}
function formatUTCWeekdayNumber(d) {
return d.getUTCDay();
}
function formatUTCWeekNumberMonday(d, p) {
return pad(utcMonday.count(utcYear(d), d), p, 2);
}
function formatUTCYear(d, p) {
return pad(d.getUTCFullYear() % 100, p, 2);
}
function formatUTCFullYear(d, p) {
return pad(d.getUTCFullYear() % 10000, p, 4);
}
function formatUTCZone() {
return "+0000";
}
function formatLiteralPercent() {
return "%";
}
var locale$1;
exports.timeFormat;
exports.timeParse;
exports.utcFormat;
exports.utcParse;
defaultLocale$1({
dateTime: "%x, %X",
date: "%-m/%-d/%Y",
time: "%-I:%M:%S %p",
periods: ["AM", "PM"],
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
});
function defaultLocale$1(definition) {
locale$1 = formatLocale$1(definition);
exports.timeFormat = locale$1.format;
exports.timeParse = locale$1.parse;
exports.utcFormat = locale$1.utcFormat;
exports.utcParse = locale$1.utcParse;
return locale$1;
}
var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
function formatIsoNative(date) {
return date.toISOString();
}
var formatIso = Date.prototype.toISOString
? formatIsoNative
: exports.utcFormat(isoSpecifier);
function parseIsoNative(string) {
var date = new Date(string);
return isNaN(date) ? null : date;
}
var parseIso = +new Date("2000-01-01T00:00:00.000Z")
? parseIsoNative
: exports.utcParse(isoSpecifier);
var array$2 = Array.prototype;
var map$2 = array$2.map;
var slice$3 = array$2.slice;
var implicit = {name: "implicit"};
function ordinal(range) {
var index = map$1(),
domain = [],
unknown = implicit;
range = range == null ? [] : slice$3.call(range);
function scale(d) {
var key = d + "", i = index.get(key);
if (!i) {
if (unknown !== implicit) return unknown;
index.set(key, i = domain.push(d));
}
return range[(i - 1) % range.length];
}
scale.domain = function(_) {
if (!arguments.length) return domain.slice();
domain = [], index = map$1();
var i = -1, n = _.length, d, key;
while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
return scale;
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), scale) : range.slice();
};
scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};
scale.copy = function() {
return ordinal()
.domain(domain)
.range(range)
.unknown(unknown);
};
return scale;
}
function band() {
var scale = ordinal().unknown(undefined),
domain = scale.domain,
ordinalRange = scale.range,
range$$ = [0, 1],
step,
bandwidth,
round = false,
paddingInner = 0,
paddingOuter = 0,
align = 0.5;
delete scale.unknown;
function rescale() {
var n = domain().length,
reverse = range$$[1] < range$$[0],
start = range$$[reverse - 0],
stop = range$$[1 - reverse];
step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
if (round) step = Math.floor(step);
start += (stop - start - step * (n - paddingInner)) * align;
bandwidth = step * (1 - paddingInner);
if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
var values = range(n).map(function(i) { return start + step * i; });
return ordinalRange(reverse ? values.reverse() : values);
}
scale.domain = function(_) {
return arguments.length ? (domain(_), rescale()) : domain();
};
scale.range = function(_) {
return arguments.length ? (range$$ = [+_[0], +_[1]], rescale()) : range$$.slice();
};
scale.rangeRound = function(_) {
return range$$ = [+_[0], +_[1]], round = true, rescale();
};
scale.bandwidth = function() {
return bandwidth;
};
scale.step = function() {
return step;
};
scale.round = function(_) {
return arguments.length ? (round = !!_, rescale()) : round;
};
scale.padding = function(_) {
return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
};
scale.paddingInner = function(_) {
return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
};
scale.paddingOuter = function(_) {
return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;
};
scale.align = function(_) {
return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
};
scale.copy = function() {
return band()
.domain(domain())
.range(range$$)
.round(round)
.paddingInner(paddingInner)
.paddingOuter(paddingOuter)
.align(align);
};
return rescale();
}
function pointish(scale) {
var copy = scale.copy;
scale.padding = scale.paddingOuter;
delete scale.paddingInner;
delete scale.paddingOuter;
scale.copy = function() {
return pointish(copy());
};
return scale;
}
function point$4() {
return pointish(band().paddingInner(1));
}
function constant$3(x) {
return function() {
return x;
};
}
function number$1(x) {
return +x;
}
var unit = [0, 1];
function deinterpolate(a, b) {
return (b -= (a = +a))
? function(x) { return (x - a) / b; }
: constant$3(b);
}
function deinterpolateClamp(deinterpolate) {
return function(a, b) {
var d = deinterpolate(a = +a, b = +b);
return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
};
}
function reinterpolateClamp(reinterpolate) {
return function(a, b) {
var r = reinterpolate(a = +a, b = +b);
return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
};
}
function bimap(domain, range, deinterpolate, reinterpolate) {
var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
return function(x) { return r0(d0(x)); };
}
function polymap(domain, range, deinterpolate, reinterpolate) {
var j = Math.min(domain.length, range.length) - 1,
d = new Array(j),
r = new Array(j),
i = -1;
// Reverse descending domains.
if (domain[j] < domain[0]) {
domain = domain.slice().reverse();
range = range.slice().reverse();
}
while (++i < j) {
d[i] = deinterpolate(domain[i], domain[i + 1]);
r[i] = reinterpolate(range[i], range[i + 1]);
}
return function(x) {
var i = bisectRight(domain, x, 1, j) - 1;
return r[i](d[i](x));
};
}
function copy(source, target) {
return target
.domain(source.domain())
.range(source.range())
.interpolate(source.interpolate())
.clamp(source.clamp());
}
// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
function continuous(deinterpolate$$, reinterpolate) {
var domain = unit,
range = unit,
interpolate$$ = interpolate,
clamp = false,
piecewise,
output,
input;
function rescale() {
piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
output = input = null;
return scale;
}
function scale(x) {
return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate$$) : deinterpolate$$, interpolate$$)))(+x);
}
scale.invert = function(y) {
return (input || (input = piecewise(range, domain, deinterpolate, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
};
scale.domain = function(_) {
return arguments.length ? (domain = map$2.call(_, number$1), rescale()) : domain.slice();
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), rescale()) : range.slice();
};
scale.rangeRound = function(_) {
return range = slice$3.call(_), interpolate$$ = interpolateRound, rescale();
};
scale.clamp = function(_) {
return arguments.length ? (clamp = !!_, rescale()) : clamp;
};
scale.interpolate = function(_) {
return arguments.length ? (interpolate$$ = _, rescale()) : interpolate$$;
};
return rescale();
}
function tickFormat(domain, count, specifier) {
var start = domain[0],
stop = domain[domain.length - 1],
step = tickStep(start, stop, count == null ? 10 : count),
precision;
specifier = formatSpecifier(specifier == null ? ",f" : specifier);
switch (specifier.type) {
case "s": {
var value = Math.max(Math.abs(start), Math.abs(stop));
if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
return exports.formatPrefix(specifier, value);
}
case "":
case "e":
case "g":
case "p":
case "r": {
if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
break;
}
case "f":
case "%": {
if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
break;
}
}
return exports.format(specifier);
}
function linearish(scale) {
var domain = scale.domain;
scale.ticks = function(count) {
var d = domain();
return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
};
scale.tickFormat = function(count, specifier) {
return tickFormat(domain(), count, specifier);
};
scale.nice = function(count) {
var d = domain(),
i = d.length - 1,
n = count == null ? 10 : count,
start = d[0],
stop = d[i],
step = tickStep(start, stop, n);
if (step) {
step = tickStep(Math.floor(start / step) * step, Math.ceil(stop / step) * step, n);
d[0] = Math.floor(start / step) * step;
d[i] = Math.ceil(stop / step) * step;
domain(d);
}
return scale;
};
return scale;
}
function linear$2() {
var scale = continuous(deinterpolate, interpolateNumber);
scale.copy = function() {
return copy(scale, linear$2());
};
return linearish(scale);
}
function identity$4() {
var domain = [0, 1];
function scale(x) {
return +x;
}
scale.invert = scale;
scale.domain = scale.range = function(_) {
return arguments.length ? (domain = map$2.call(_, number$1), scale) : domain.slice();
};
scale.copy = function() {
return identity$4().domain(domain);
};
return linearish(scale);
}
function nice(domain, interval) {
domain = domain.slice();
var i0 = 0,
i1 = domain.length - 1,
x0 = domain[i0],
x1 = domain[i1],
t;
if (x1 < x0) {
t = i0, i0 = i1, i1 = t;
t = x0, x0 = x1, x1 = t;
}
domain[i0] = interval.floor(x0);
domain[i1] = interval.ceil(x1);
return domain;
}
function deinterpolate$1(a, b) {
return (b = Math.log(b / a))
? function(x) { return Math.log(x / a) / b; }
: constant$3(b);
}
function reinterpolate(a, b) {
return a < 0
? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }
: function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };
}
function pow10(x) {
return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
}
function powp(base) {
return base === 10 ? pow10
: base === Math.E ? Math.exp
: function(x) { return Math.pow(base, x); };
}
function logp(base) {
return base === Math.E ? Math.log
: base === 10 && Math.log10
|| base === 2 && Math.log2
|| (base = Math.log(base), function(x) { return Math.log(x) / base; });
}
function reflect(f) {
return function(x) {
return -f(-x);
};
}
function log() {
var scale = continuous(deinterpolate$1, reinterpolate).domain([1, 10]),
domain = scale.domain,
base = 10,
logs = logp(10),
pows = powp(10);
function rescale() {
logs = logp(base), pows = powp(base);
if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);
return scale;
}
scale.base = function(_) {
return arguments.length ? (base = +_, rescale()) : base;
};
scale.domain = function(_) {
return arguments.length ? (domain(_), rescale()) : domain();
};
scale.ticks = function(count) {
var d = domain(),
u = d[0],
v = d[d.length - 1],
r;
if (r = v < u) i = u, u = v, v = i;
var i = logs(u),
j = logs(v),
p,
k,
t,
n = count == null ? 10 : +count,
z = [];
if (!(base % 1) && j - i < n) {
i = Math.round(i) - 1, j = Math.round(j) + 1;
if (u > 0) for (; i < j; ++i) {
for (k = 1, p = pows(i); k < base; ++k) {
t = p * k;
if (t < u) continue;
if (t > v) break;
z.push(t);
}
} else for (; i < j; ++i) {
for (k = base - 1, p = pows(i); k >= 1; --k) {
t = p * k;
if (t < u) continue;
if (t > v) break;
z.push(t);
}
}
} else {
z = ticks(i, j, Math.min(j - i, n)).map(pows);
}
return r ? z.reverse() : z;
};
scale.tickFormat = function(count, specifier) {
if (specifier == null) specifier = base === 10 ? ".0e" : ",";
if (typeof specifier !== "function") specifier = exports.format(specifier);
if (count === Infinity) return specifier;
if (count == null) count = 10;
var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
return function(d) {
var i = d / pows(Math.round(logs(d)));
if (i * base < base - 0.5) i *= base;
return i <= k ? specifier(d) : "";
};
};
scale.nice = function() {
return domain(nice(domain(), {
floor: function(x) { return pows(Math.floor(logs(x))); },
ceil: function(x) { return pows(Math.ceil(logs(x))); }
}));
};
scale.copy = function() {
return copy(scale, log().base(base));
};
return scale;
}
function raise(x, exponent) {
return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
}
function pow() {
var exponent = 1,
scale = continuous(deinterpolate, reinterpolate),
domain = scale.domain;
function deinterpolate(a, b) {
return (b = raise(b, exponent) - (a = raise(a, exponent)))
? function(x) { return (raise(x, exponent) - a) / b; }
: constant$3(b);
}
function reinterpolate(a, b) {
b = raise(b, exponent) - (a = raise(a, exponent));
return function(t) { return raise(a + b * t, 1 / exponent); };
}
scale.exponent = function(_) {
return arguments.length ? (exponent = +_, domain(domain())) : exponent;
};
scale.copy = function() {
return copy(scale, pow().exponent(exponent));
};
return linearish(scale);
}
function sqrt() {
return pow().exponent(0.5);
}
function quantile() {
var domain = [],
range = [],
thresholds = [];
function rescale() {
var i = 0, n = Math.max(1, range.length);
thresholds = new Array(n - 1);
while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
return scale;
}
function scale(x) {
if (!isNaN(x = +x)) return range[bisectRight(thresholds, x)];
}
scale.invertExtent = function(y) {
var i = range.indexOf(y);
return i < 0 ? [NaN, NaN] : [
i > 0 ? thresholds[i - 1] : domain[0],
i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
];
};
scale.domain = function(_) {
if (!arguments.length) return domain.slice();
domain = [];
for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
domain.sort(ascending);
return rescale();
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), rescale()) : range.slice();
};
scale.quantiles = function() {
return thresholds.slice();
};
scale.copy = function() {
return quantile()
.domain(domain)
.range(range);
};
return scale;
}
function quantize$1() {
var x0 = 0,
x1 = 1,
n = 1,
domain = [0.5],
range = [0, 1];
function scale(x) {
if (x <= x) return range[bisectRight(domain, x, 0, n)];
}
function rescale() {
var i = -1;
domain = new Array(n);
while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
return scale;
}
scale.domain = function(_) {
return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
};
scale.range = function(_) {
return arguments.length ? (n = (range = slice$3.call(_)).length - 1, rescale()) : range.slice();
};
scale.invertExtent = function(y) {
var i = range.indexOf(y);
return i < 0 ? [NaN, NaN]
: i < 1 ? [x0, domain[0]]
: i >= n ? [domain[n - 1], x1]
: [domain[i - 1], domain[i]];
};
scale.copy = function() {
return quantize$1()
.domain([x0, x1])
.range(range);
};
return linearish(scale);
}
function threshold$1() {
var domain = [0.5],
range = [0, 1],
n = 1;
function scale(x) {
if (x <= x) return range[bisectRight(domain, x, 0, n)];
}
scale.domain = function(_) {
return arguments.length ? (domain = slice$3.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
};
scale.invertExtent = function(y) {
var i = range.indexOf(y);
return [domain[i - 1], domain[i]];
};
scale.copy = function() {
return threshold$1()
.domain(domain)
.range(range);
};
return scale;
}
var durationSecond$1 = 1000;
var durationMinute$1 = durationSecond$1 * 60;
var durationHour$1 = durationMinute$1 * 60;
var durationDay$1 = durationHour$1 * 24;
var durationWeek$1 = durationDay$1 * 7;
var durationMonth = durationDay$1 * 30;
var durationYear = durationDay$1 * 365;
function date$1(t) {
return new Date(t);
}
function number$2(t) {
return t instanceof Date ? +t : +new Date(+t);
}
function calendar(year, month, week, day, hour, minute, second, millisecond, format) {
var scale = continuous(deinterpolate, interpolateNumber),
invert = scale.invert,
domain = scale.domain;
var formatMillisecond = format(".%L"),
formatSecond = format(":%S"),
formatMinute = format("%I:%M"),
formatHour = format("%I %p"),
formatDay = format("%a %d"),
formatWeek = format("%b %d"),
formatMonth = format("%B"),
formatYear = format("%Y");
var tickIntervals = [
[second, 1, durationSecond$1],
[second, 5, 5 * durationSecond$1],
[second, 15, 15 * durationSecond$1],
[second, 30, 30 * durationSecond$1],
[minute, 1, durationMinute$1],
[minute, 5, 5 * durationMinute$1],
[minute, 15, 15 * durationMinute$1],
[minute, 30, 30 * durationMinute$1],
[ hour, 1, durationHour$1 ],
[ hour, 3, 3 * durationHour$1 ],
[ hour, 6, 6 * durationHour$1 ],
[ hour, 12, 12 * durationHour$1 ],
[ day, 1, durationDay$1 ],
[ day, 2, 2 * durationDay$1 ],
[ week, 1, durationWeek$1 ],
[ month, 1, durationMonth ],
[ month, 3, 3 * durationMonth ],
[ year, 1, durationYear ]
];
function tickFormat(date) {
return (second(date) < date ? formatMillisecond
: minute(date) < date ? formatSecond
: hour(date) < date ? formatMinute
: day(date) < date ? formatHour
: month(date) < date ? (week(date) < date ? formatDay : formatWeek)
: year(date) < date ? formatMonth
: formatYear)(date);
}
function tickInterval(interval, start, stop, step) {
if (interval == null) interval = 10;
// If a desired tick count is specified, pick a reasonable tick interval
// based on the extent of the domain and a rough estimate of tick size.
// Otherwise, assume interval is already a time interval and use it.
if (typeof interval === "number") {
var target = Math.abs(stop - start) / interval,
i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
if (i === tickIntervals.length) {
step = tickStep(start / durationYear, stop / durationYear, interval);
interval = year;
} else if (i) {
i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
step = i[1];
interval = i[0];
} else {
step = tickStep(start, stop, interval);
interval = millisecond;
}
}
return step == null ? interval : interval.every(step);
}
scale.invert = function(y) {
return new Date(invert(y));
};
scale.domain = function(_) {
return arguments.length ? domain(map$2.call(_, number$2)) : domain().map(date$1);
};
scale.ticks = function(interval, step) {
var d = domain(),
t0 = d[0],
t1 = d[d.length - 1],
r = t1 < t0,
t;
if (r) t = t0, t0 = t1, t1 = t;
t = tickInterval(interval, t0, t1, step);
t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
return r ? t.reverse() : t;
};
scale.tickFormat = function(count, specifier) {
return specifier == null ? tickFormat : format(specifier);
};
scale.nice = function(interval, step) {
var d = domain();
return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
? domain(nice(d, interval))
: scale;
};
scale.copy = function() {
return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));
};
return scale;
}
function time() {
return calendar(year, month, timeWeek, day, hour, minute, second, millisecond, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
}
function utcTime() {
return calendar(utcYear, utcMonth, utcWeek, utcDay, utcHour, utcMinute, second, millisecond, exports.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);
}
function colors(s) {
return s.match(/.{6}/g).map(function(x) {
return "#" + x;
});
}
var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6");
var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9");
var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5");
var cubehelix$3 = interpolateCubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
var warm = interpolateCubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
var cool = interpolateCubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
var rainbow = cubehelix();
function rainbow$1(t) {
if (t < 0 || t > 1) t -= Math.floor(t);
var ts = Math.abs(t - 0.5);
rainbow.h = 360 * t - 100;
rainbow.s = 1.5 - 1.5 * ts;
rainbow.l = 0.8 - 0.9 * ts;
return rainbow + "";
}
function ramp(range) {
var n = range.length;
return function(t) {
return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
};
}
var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
function sequential(interpolator) {
var x0 = 0,
x1 = 1,
clamp = false;
function scale(x) {
var t = (x - x0) / (x1 - x0);
return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
}
scale.domain = function(_) {
return arguments.length ? (x0 = +_[0], x1 = +_[1], scale) : [x0, x1];
};
scale.clamp = function(_) {
return arguments.length ? (clamp = !!_, scale) : clamp;
};
scale.interpolator = function(_) {
return arguments.length ? (interpolator = _, scale) : interpolator;
};
scale.copy = function() {
return sequential(interpolator).domain([x0, x1]).clamp(clamp);
};
return linearish(scale);
}
var xhtml = "http://www.w3.org/1999/xhtml";
var namespaces = {
svg: "http://www.w3.org/2000/svg",
xhtml: xhtml,
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/"
};
function namespace(name) {
var prefix = name += "", i = prefix.indexOf(":");
if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
}
function creatorInherit(name) {
return function() {
var document = this.ownerDocument,
uri = this.namespaceURI;
return uri === xhtml && document.documentElement.namespaceURI === xhtml
? document.createElement(name)
: document.createElementNS(uri, name);
};
}
function creatorFixed(fullname) {
return function() {
return this.ownerDocument.createElementNS(fullname.space, fullname.local);
};
}
function creator(name) {
var fullname = namespace(name);
return (fullname.local
? creatorFixed
: creatorInherit)(fullname);
}
var nextId = 0;
function local() {
return new Local;
}
function Local() {
this._ = "@" + (++nextId).toString(36);
}
Local.prototype = local.prototype = {
constructor: Local,
get: function(node) {
var id = this._;
while (!(id in node)) if (!(node = node.parentNode)) return;
return node[id];
},
set: function(node, value) {
return node[this._] = value;
},
remove: function(node) {
return this._ in node && delete node[this._];
},
toString: function() {
return this._;
}
};
var matcher = function(selector) {
return function() {
return this.matches(selector);
};
};
if (typeof document !== "undefined") {
var element = document.documentElement;
if (!element.matches) {
var vendorMatches = element.webkitMatchesSelector
|| element.msMatchesSelector
|| element.mozMatchesSelector
|| element.oMatchesSelector;
matcher = function(selector) {
return function() {
return vendorMatches.call(this, selector);
};
};
}
}
var matcher$1 = matcher;
var filterEvents = {};
exports.event = null;
if (typeof document !== "undefined") {
var element$1 = document.documentElement;
if (!("onmouseenter" in element$1)) {
filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
}
}
function filterContextListener(listener, index, group) {
listener = contextListener(listener, index, group);
return function(event) {
var related = event.relatedTarget;
if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
listener.call(this, event);
}
};
}
function contextListener(listener, index, group) {
return function(event1) {
var event0 = exports.event; // Events can be reentrant (e.g., focus).
exports.event = event1;
try {
listener.call(this, this.__data__, index, group);
} finally {
exports.event = event0;
}
};
}
function parseTypenames$1(typenames) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
return {type: t, name: name};
});
}
function onRemove(typename) {
return function() {
var on = this.__on;
if (!on) return;
for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.capture);
} else {
on[++i] = o;
}
}
if (++i) on.length = i;
else delete this.__on;
};
}
function onAdd(typename, value, capture) {
var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
return function(d, i, group) {
var on = this.__on, o, listener = wrap(value, i, group);
if (on) for (var j = 0, m = on.length; j < m; ++j) {
if ((o = on[j]).type === typename.type && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.capture);
this.addEventListener(o.type, o.listener = listener, o.capture = capture);
o.value = value;
return;
}
}
this.addEventListener(typename.type, listener, capture);
o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
if (!on) this.__on = [o];
else on.push(o);
};
}
function selection_on(typename, value, capture) {
var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
if (arguments.length < 2) {
var on = this.node().__on;
if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
for (i = 0, o = on[j]; i < n; ++i) {
if ((t = typenames[i]).type === o.type && t.name === o.name) {
return o.value;
}
}
}
return;
}
on = value ? onAdd : onRemove;
if (capture == null) capture = false;
for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
return this;
}
function customEvent(event1, listener, that, args) {
var event0 = exports.event;
event1.sourceEvent = exports.event;
exports.event = event1;
try {
return listener.apply(that, args);
} finally {
exports.event = event0;
}
}
function sourceEvent() {
var current = exports.event, source;
while (source = current.sourceEvent) current = source;
return current;
}
function point$5(node, event) {
var svg = node.ownerSVGElement || node;
if (svg.createSVGPoint) {
var point = svg.createSVGPoint();
point.x = event.clientX, point.y = event.clientY;
point = point.matrixTransform(node.getScreenCTM().inverse());
return [point.x, point.y];
}
var rect = node.getBoundingClientRect();
return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
}
function mouse(node) {
var event = sourceEvent();
if (event.changedTouches) event = event.changedTouches[0];
return point$5(node, event);
}
function none$2() {}
function selector(selector) {
return selector == null ? none$2 : function() {
return this.querySelector(selector);
};
}
function selection_select(select) {
if (typeof select !== "function") select = selector(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
}
}
}
return new Selection(subgroups, this._parents);
}
function empty() {
return [];
}
function selectorAll(selector) {
return selector == null ? empty : function() {
return this.querySelectorAll(selector);
};
}
function selection_selectAll(select) {
if (typeof select !== "function") select = selectorAll(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
subgroups.push(select.call(node, node.__data__, i, group));
parents.push(node);
}
}
}
return new Selection(subgroups, parents);
}
function selection_filter(match) {
if (typeof match !== "function") match = matcher$1(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
subgroup.push(node);
}
}
}
return new Selection(subgroups, this._parents);
}
function sparse(update) {
return new Array(update.length);
}
function selection_enter() {
return new Selection(this._enter || this._groups.map(sparse), this._parents);
}
function EnterNode(parent, datum) {
this.ownerDocument = parent.ownerDocument;
this.namespaceURI = parent.namespaceURI;
this._next = null;
this._parent = parent;
this.__data__ = datum;
}
EnterNode.prototype = {
constructor: EnterNode,
appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
querySelector: function(selector) { return this._parent.querySelector(selector); },
querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
};
function constant$4(x) {
return function() {
return x;
};
}
var keyPrefix = "$"; // Protect against keys like “__proto__”.
function bindIndex(parent, group, enter, update, exit, data) {
var i = 0,
node,
groupLength = group.length,
dataLength = data.length;
// Put any non-null nodes that fit into update.
// Put any null nodes into enter.
// Put any remaining data into enter.
for (; i < dataLength; ++i) {
if (node = group[i]) {
node.__data__ = data[i];
update[i] = node;
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
// Put any non-null nodes that don’t fit into exit.
for (; i < groupLength; ++i) {
if (node = group[i]) {
exit[i] = node;
}
}
}
function bindKey(parent, group, enter, update, exit, data, key) {
var i,
node,
nodeByKeyValue = {},
groupLength = group.length,
dataLength = data.length,
keyValues = new Array(groupLength),
keyValue;
// Compute the key for each node.
// If multiple nodes have the same key, the duplicates are added to exit.
for (i = 0; i < groupLength; ++i) {
if (node = group[i]) {
keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
if (keyValue in nodeByKeyValue) {
exit[i] = node;
} else {
nodeByKeyValue[keyValue] = node;
}
}
}
// Compute the key for each datum.
// If there a node associated with this key, join and add it to update.
// If there is not (or the key is a duplicate), add it to enter.
for (i = 0; i < dataLength; ++i) {
keyValue = keyPrefix + key.call(parent, data[i], i, data);
if (node = nodeByKeyValue[keyValue]) {
update[i] = node;
node.__data__ = data[i];
nodeByKeyValue[keyValue] = null;
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
// Add any remaining nodes that were not bound to data to exit.
for (i = 0; i < groupLength; ++i) {
if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
exit[i] = node;
}
}
}
function selection_data(value, key) {
if (!value) {
data = new Array(this.size()), j = -1;
this.each(function(d) { data[++j] = d; });
return data;
}
var bind = key ? bindKey : bindIndex,
parents = this._parents,
groups = this._groups;
if (typeof value !== "function") value = constant$4(value);
for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
var parent = parents[j],
group = groups[j],
groupLength = group.length,
data = value.call(parent, parent && parent.__data__, j, parents),
dataLength = data.length,
enterGroup = enter[j] = new Array(dataLength),
updateGroup = update[j] = new Array(dataLength),
exitGroup = exit[j] = new Array(groupLength);
bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
// Now connect the enter nodes to their following update node, such that
// appendChild can insert the materialized enter node before this node,
// rather than at the end of the parent node.
for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
if (previous = enterGroup[i0]) {
if (i0 >= i1) i1 = i0 + 1;
while (!(next = updateGroup[i1]) && ++i1 < dataLength);
previous._next = next || null;
}
}
}
update = new Selection(update, parents);
update._enter = enter;
update._exit = exit;
return update;
}
function selection_exit() {
return new Selection(this._exit || this._groups.map(sparse), this._parents);
}
function selection_merge(selection) {
for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group0[i] || group1[i]) {
merge[i] = node;
}
}
}
for (; j < m0; ++j) {
merges[j] = groups0[j];
}
return new Selection(merges, this._parents);
}
function selection_order() {
for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
if (node = group[i]) {
if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
next = node;
}
}
}
return this;
}
function selection_sort(compare) {
if (!compare) compare = ascending$2;
function compareNode(a, b) {
return a && b ? compare(a.__data__, b.__data__) : !a - !b;
}
for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group[i]) {
sortgroup[i] = node;
}
}
sortgroup.sort(compareNode);
}
return new Selection(sortgroups, this._parents).order();
}
function ascending$2(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
function selection_call() {
var callback = arguments[0];
arguments[0] = this;
callback.apply(null, arguments);
return this;
}
function selection_nodes() {
var nodes = new Array(this.size()), i = -1;
this.each(function() { nodes[++i] = this; });
return nodes;
}
function selection_node() {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
var node = group[i];
if (node) return node;
}
}
return null;
}
function selection_size() {
var size = 0;
this.each(function() { ++size; });
return size;
}
function selection_empty() {
return !this.node();
}
function selection_each(callback) {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
if (node = group[i]) callback.call(node, node.__data__, i, group);
}
}
return this;
}
function attrRemove(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant(name, value) {
return function() {
this.setAttribute(name, value);
};
}
function attrConstantNS(fullname, value) {
return function() {
this.setAttributeNS(fullname.space, fullname.local, value);
};
}
function attrFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttribute(name);
else this.setAttribute(name, v);
};
}
function attrFunctionNS(fullname, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
else this.setAttributeNS(fullname.space, fullname.local, v);
};
}
function selection_attr(name, value) {
var fullname = namespace(name);
if (arguments.length < 2) {
var node = this.node();
return fullname.local
? node.getAttributeNS(fullname.space, fullname.local)
: node.getAttribute(fullname);
}
return this.each((value == null
? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
? (fullname.local ? attrFunctionNS : attrFunction)
: (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
}
function window(node) {
return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
|| (node.document && node) // node is a Window
|| node.defaultView; // node is a Document
}
function styleRemove(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant(name, value, priority) {
return function() {
this.style.setProperty(name, value, priority);
};
}
function styleFunction(name, value, priority) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.style.removeProperty(name);
else this.style.setProperty(name, v, priority);
};
}
function selection_style(name, value, priority) {
var node;
return arguments.length > 1
? this.each((value == null
? styleRemove : typeof value === "function"
? styleFunction
: styleConstant)(name, value, priority == null ? "" : priority))
: window(node = this.node())
.getComputedStyle(node, null)
.getPropertyValue(name);
}
function propertyRemove(name) {
return function() {
delete this[name];
};
}
function propertyConstant(name, value) {
return function() {
this[name] = value;
};
}
function propertyFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) delete this[name];
else this[name] = v;
};
}
function selection_property(name, value) {
return arguments.length > 1
? this.each((value == null
? propertyRemove : typeof value === "function"
? propertyFunction
: propertyConstant)(name, value))
: this.node()[name];
}
function classArray(string) {
return string.trim().split(/^|\s+/);
}
function classList(node) {
return node.classList || new ClassList(node);
}
function ClassList(node) {
this._node = node;
this._names = classArray(node.getAttribute("class") || "");
}
ClassList.prototype = {
add: function(name) {
var i = this._names.indexOf(name);
if (i < 0) {
this._names.push(name);
this._node.setAttribute("class", this._names.join(" "));
}
},
remove: function(name) {
var i = this._names.indexOf(name);
if (i >= 0) {
this._names.splice(i, 1);
this._node.setAttribute("class", this._names.join(" "));
}
},
contains: function(name) {
return this._names.indexOf(name) >= 0;
}
};
function classedAdd(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.add(names[i]);
}
function classedRemove(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.remove(names[i]);
}
function classedTrue(names) {
return function() {
classedAdd(this, names);
};
}
function classedFalse(names) {
return function() {
classedRemove(this, names);
};
}
function classedFunction(names, value) {
return function() {
(value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
};
}
function selection_classed(name, value) {
var names = classArray(name + "");
if (arguments.length < 2) {
var list = classList(this.node()), i = -1, n = names.length;
while (++i < n) if (!list.contains(names[i])) return false;
return true;
}
return this.each((typeof value === "function"
? classedFunction : value
? classedTrue
: classedFalse)(names, value));
}
function textRemove() {
this.textContent = "";
}
function textConstant(value) {
return function() {
this.textContent = value;
};
}
function textFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.textContent = v == null ? "" : v;
};
}
function selection_text(value) {
return arguments.length
? this.each(value == null
? textRemove : (typeof value === "function"
? textFunction
: textConstant)(value))
: this.node().textContent;
}
function htmlRemove() {
this.innerHTML = "";
}
function htmlConstant(value) {
return function() {
this.innerHTML = value;
};
}
function htmlFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.innerHTML = v == null ? "" : v;
};
}
function selection_html(value) {
return arguments.length
? this.each(value == null
? htmlRemove : (typeof value === "function"
? htmlFunction
: htmlConstant)(value))
: this.node().innerHTML;
}
function raise$1() {
if (this.nextSibling) this.parentNode.appendChild(this);
}
function selection_raise() {
return this.each(raise$1);
}
function lower() {
if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
}
function selection_lower() {
return this.each(lower);
}
function selection_append(name) {
var create = typeof name === "function" ? name : creator(name);
return this.select(function() {
return this.appendChild(create.apply(this, arguments));
});
}
function constantNull() {
return null;
}
function selection_insert(name, before) {
var create = typeof name === "function" ? name : creator(name),
select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
return this.select(function() {
return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
});
}
function remove() {
var parent = this.parentNode;
if (parent) parent.removeChild(this);
}
function selection_remove() {
return this.each(remove);
}
function selection_datum(value) {
return arguments.length
? this.property("__data__", value)
: this.node().__data__;
}
function dispatchEvent(node, type, params) {
var window$$ = window(node),
event = window$$.CustomEvent;
if (event) {
event = new event(type, params);
} else {
event = window$$.document.createEvent("Event");
if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
else event.initEvent(type, false, false);
}
node.dispatchEvent(event);
}
function dispatchConstant(type, params) {
return function() {
return dispatchEvent(this, type, params);
};
}
function dispatchFunction(type, params) {
return function() {
return dispatchEvent(this, type, params.apply(this, arguments));
};
}
function selection_dispatch(type, params) {
return this.each((typeof params === "function"
? dispatchFunction
: dispatchConstant)(type, params));
}
var root = [null];
function Selection(groups, parents) {
this._groups = groups;
this._parents = parents;
}
function selection() {
return new Selection([[document.documentElement]], root);
}
Selection.prototype = selection.prototype = {
constructor: Selection,
select: selection_select,
selectAll: selection_selectAll,
filter: selection_filter,
data: selection_data,
enter: selection_enter,
exit: selection_exit,
merge: selection_merge,
order: selection_order,
sort: selection_sort,
call: selection_call,
nodes: selection_nodes,
node: selection_node,
size: selection_size,
empty: selection_empty,
each: selection_each,
attr: selection_attr,
style: selection_style,
property: selection_property,
classed: selection_classed,
text: selection_text,
html: selection_html,
raise: selection_raise,
lower: selection_lower,
append: selection_append,
insert: selection_insert,
remove: selection_remove,
datum: selection_datum,
on: selection_on,
dispatch: selection_dispatch
};
function select(selector) {
return typeof selector === "string"
? new Selection([[document.querySelector(selector)]], [document.documentElement])
: new Selection([[selector]], root);
}
function selectAll(selector) {
return typeof selector === "string"
? new Selection([document.querySelectorAll(selector)], [document.documentElement])
: new Selection([selector == null ? [] : selector], root);
}
function touch(node, touches, identifier) {
if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
if ((touch = touches[i]).identifier === identifier) {
return point$5(node, touch);
}
}
return null;
}
function touches(node, touches) {
if (touches == null) touches = sourceEvent().touches;
for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
points[i] = point$5(node, touches[i]);
}
return points;
}
var emptyOn = dispatch("start", "end", "interrupt");
var emptyTween = [];
var CREATED = 0;
var SCHEDULED = 1;
var STARTING = 2;
var STARTED = 3;
var ENDING = 4;
var ENDED = 5;
function schedule(node, name, id, index, group, timing) {
var schedules = node.__transition;
if (!schedules) node.__transition = {};
else if (id in schedules) return;
create(node, id, {
name: name,
index: index, // For context during callback.
group: group, // For context during callback.
on: emptyOn,
tween: emptyTween,
time: timing.time,
delay: timing.delay,
duration: timing.duration,
ease: timing.ease,
timer: null,
state: CREATED
});
}
function init(node, id) {
var schedule = node.__transition;
if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
return schedule;
}
function set$2(node, id) {
var schedule = node.__transition;
if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
return schedule;
}
function get$1(node, id) {
var schedule = node.__transition;
if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
return schedule;
}
function create(node, id, self) {
var schedules = node.__transition,
tween;
// Initialize the self timer when the transition is created.
// Note the actual delay is not known until the first callback!
schedules[id] = self;
self.timer = timer(schedule, 0, self.time);
// If the delay is greater than this first sleep, sleep some more;
// otherwise, start immediately.
function schedule(elapsed) {
self.state = SCHEDULED;
if (self.delay <= elapsed) start(elapsed - self.delay);
else self.timer.restart(start, self.delay, self.time);
}
function start(elapsed) {
var i, j, n, o;
for (i in schedules) {
o = schedules[i];
if (o.name !== self.name) continue;
// Interrupt the active transition, if any.
// Dispatch the interrupt event.
if (o.state === STARTED) {
o.state = ENDED;
o.timer.stop();
o.on.call("interrupt", node, node.__data__, o.index, o.group);
delete schedules[i];
}
// Cancel any pre-empted transitions. No interrupt event is dispatched
// because the cancelled transitions never started. Note that this also
// removes this transition from the pending list!
else if (+i < id) {
o.state = ENDED;
o.timer.stop();
delete schedules[i];
}
}
// Defer the first tick to end of the current frame; see mbostock/d3#1576.
// Note the transition may be canceled after start and before the first tick!
// Note this must be scheduled before the start event; see d3/d3-transition#16!
// Assuming this is successful, subsequent callbacks go straight to tick.
timeout$1(function() {
if (self.state === STARTED) {
self.timer.restart(tick, self.delay, self.time);
tick(elapsed);
}
});
// Dispatch the start event.
// Note this must be done before the tween are initialized.
self.state = STARTING;
self.on.call("start", node, node.__data__, self.index, self.group);
if (self.state !== STARTING) return; // interrupted
self.state = STARTED;
// Initialize the tween, deleting null tween.
tween = new Array(n = self.tween.length);
for (i = 0, j = -1; i < n; ++i) {
if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
tween[++j] = o;
}
}
tween.length = j + 1;
}
function tick(elapsed) {
var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.state = ENDING, 1),
i = -1,
n = tween.length;
while (++i < n) {
tween[i].call(null, t);
}
// Dispatch the end event.
if (self.state === ENDING) {
self.state = ENDED;
self.timer.stop();
self.on.call("end", node, node.__data__, self.index, self.group);
for (i in schedules) if (+i !== id) return void delete schedules[id];
delete node.__transition;
}
}
}
function interrupt(node, name) {
var schedules = node.__transition,
schedule,
active,
empty = true,
i;
if (!schedules) return;
name = name == null ? null : name + "";
for (i in schedules) {
if ((schedule = schedules[i]).name !== name) { empty = false; continue; }
active = schedule.state === STARTED;
schedule.state = ENDED;
schedule.timer.stop();
if (active) schedule.on.call("interrupt", node, node.__data__, schedule.index, schedule.group);
delete schedules[i];
}
if (empty) delete node.__transition;
}
function selection_interrupt(name) {
return this.each(function() {
interrupt(this, name);
});
}
function tweenRemove(id, name) {
var tween0, tween1;
return function() {
var schedule = set$2(this, id),
tween = schedule.tween;
// If this node shared tween with the previous node,
// just assign the updated shared tween and we’re done!
// Otherwise, copy-on-write.
if (tween !== tween0) {
tween1 = tween0 = tween;
for (var i = 0, n = tween1.length; i < n; ++i) {
if (tween1[i].name === name) {
tween1 = tween1.slice();
tween1.splice(i, 1);
break;
}
}
}
schedule.tween = tween1;
};
}
function tweenFunction(id, name, value) {
var tween0, tween1;
if (typeof value !== "function") throw new Error;
return function() {
var schedule = set$2(this, id),
tween = schedule.tween;
// If this node shared tween with the previous node,
// just assign the updated shared tween and we’re done!
// Otherwise, copy-on-write.
if (tween !== tween0) {
tween1 = (tween0 = tween).slice();
for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {
if (tween1[i].name === name) {
tween1[i] = t;
break;
}
}
if (i === n) tween1.push(t);
}
schedule.tween = tween1;
};
}
function transition_tween(name, value) {
var id = this._id;
name += "";
if (arguments.length < 2) {
var tween = get$1(this.node(), id).tween;
for (var i = 0, n = tween.length, t; i < n; ++i) {
if ((t = tween[i]).name === name) {
return t.value;
}
}
return null;
}
return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
}
function tweenValue(transition, name, value) {
var id = transition._id;
transition.each(function() {
var schedule = set$2(this, id);
(schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
});
return function(node) {
return get$1(node, id).value[name];
};
}
function interpolate$1(a, b) {
var c;
return (typeof b === "number" ? interpolateNumber
: b instanceof color ? interpolateRgb
: (c = color(b)) ? (b = c, interpolateRgb)
: interpolateString)(a, b);
}
function attrRemove$1(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS$1(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant$1(name, interpolate, value1) {
var value00,
interpolate0;
return function() {
var value0 = this.getAttribute(name);
return value0 === value1 ? null
: value0 === value00 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value1);
};
}
function attrConstantNS$1(fullname, interpolate, value1) {
var value00,
interpolate0;
return function() {
var value0 = this.getAttributeNS(fullname.space, fullname.local);
return value0 === value1 ? null
: value0 === value00 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value1);
};
}
function attrFunction$1(name, interpolate, value) {
var value00,
value10,
interpolate0;
return function() {
var value0, value1 = value(this);
if (value1 == null) return void this.removeAttribute(name);
value0 = this.getAttribute(name);
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function attrFunctionNS$1(fullname, interpolate, value) {
var value00,
value10,
interpolate0;
return function() {
var value0, value1 = value(this);
if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
value0 = this.getAttributeNS(fullname.space, fullname.local);
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function transition_attr(name, value) {
var fullname = namespace(name), i = fullname === "transform" ? interpolateTransform$2 : interpolate$1;
return this.attrTween(name, typeof value === "function"
? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
: value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
: (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value));
}
function attrTweenNS(fullname, value) {
function tween() {
var node = this, i = value.apply(node, arguments);
return i && function(t) {
node.setAttributeNS(fullname.space, fullname.local, i(t));
};
}
tween._value = value;
return tween;
}
function attrTween(name, value) {
function tween() {
var node = this, i = value.apply(node, arguments);
return i && function(t) {
node.setAttribute(name, i(t));
};
}
tween._value = value;
return tween;
}
function transition_attrTween(name, value) {
var key = "attr." + name;
if (arguments.length < 2) return (key = this.tween(key)) && key._value;
if (value == null) return this.tween(key, null);
if (typeof value !== "function") throw new Error;
var fullname = namespace(name);
return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
}
function delayFunction(id, value) {
return function() {
init(this, id).delay = +value.apply(this, arguments);
};
}
function delayConstant(id, value) {
return value = +value, function() {
init(this, id).delay = value;
};
}
function transition_delay(value) {
var id = this._id;
return arguments.length
? this.each((typeof value === "function"
? delayFunction
: delayConstant)(id, value))
: get$1(this.node(), id).delay;
}
function durationFunction(id, value) {
return function() {
set$2(this, id).duration = +value.apply(this, arguments);
};
}
function durationConstant(id, value) {
return value = +value, function() {
set$2(this, id).duration = value;
};
}
function transition_duration(value) {
var id = this._id;
return arguments.length
? this.each((typeof value === "function"
? durationFunction
: durationConstant)(id, value))
: get$1(this.node(), id).duration;
}
function easeConstant(id, value) {
if (typeof value !== "function") throw new Error;
return function() {
set$2(this, id).ease = value;
};
}
function transition_ease(value) {
var id = this._id;
return arguments.length
? this.each(easeConstant(id, value))
: get$1(this.node(), id).ease;
}
function transition_filter(match) {
if (typeof match !== "function") match = matcher$1(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
subgroup.push(node);
}
}
}
return new Transition(subgroups, this._parents, this._name, this._id);
}
function transition_merge(transition) {
if (transition._id !== this._id) throw new Error;
for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group0[i] || group1[i]) {
merge[i] = node;
}
}
}
for (; j < m0; ++j) {
merges[j] = groups0[j];
}
return new Transition(merges, this._parents, this._name, this._id);
}
function start$1(name) {
return (name + "").trim().split(/^|\s+/).every(function(t) {
var i = t.indexOf(".");
if (i >= 0) t = t.slice(0, i);
return !t || t === "start";
});
}
function onFunction(id, name, listener) {
var on0, on1, sit = start$1(name) ? init : set$2;
return function() {
var schedule = sit(this, id),
on = schedule.on;
// If this node shared a dispatch with the previous node,
// just assign the updated shared dispatch and we’re done!
// Otherwise, copy-on-write.
if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
schedule.on = on1;
};
}
function transition_on(name, listener) {
var id = this._id;
return arguments.length < 2
? get$1(this.node(), id).on.on(name)
: this.each(onFunction(id, name, listener));
}
function removeFunction(id) {
return function() {
var parent = this.parentNode;
for (var i in this.__transition) if (+i !== id) return;
if (parent) parent.removeChild(this);
};
}
function transition_remove() {
return this.on("end.remove", removeFunction(this._id));
}
function transition_select(select) {
var name = this._name,
id = this._id;
if (typeof select !== "function") select = selector(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
}
}
}
return new Transition(subgroups, this._parents, name, id);
}
function transition_selectAll(select) {
var name = this._name,
id = this._id;
if (typeof select !== "function") select = selectorAll(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
if (child = children[k]) {
schedule(child, name, id, k, children, inherit);
}
}
subgroups.push(children);
parents.push(node);
}
}
}
return new Transition(subgroups, parents, name, id);
}
var Selection$1 = selection.prototype.constructor;
function transition_selection() {
return new Selection$1(this._groups, this._parents);
}
function styleRemove$1(name, interpolate) {
var value00,
value10,
interpolate0;
return function() {
var style = window(this).getComputedStyle(this, null),
value0 = style.getPropertyValue(name),
value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function styleRemoveEnd(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant$1(name, interpolate, value1) {
var value00,
interpolate0;
return function() {
var value0 = window(this).getComputedStyle(this, null).getPropertyValue(name);
return value0 === value1 ? null
: value0 === value00 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value1);
};
}
function styleFunction$1(name, interpolate, value) {
var value00,
value10,
interpolate0;
return function() {
var style = window(this).getComputedStyle(this, null),
value0 = style.getPropertyValue(name),
value1 = value(this);
if (value1 == null) value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function transition_style(name, value, priority) {
var i = (name += "") === "transform" ? interpolateTransform$1 : interpolate$1;
return value == null ? this
.styleTween(name, styleRemove$1(name, i))
.on("end.style." + name, styleRemoveEnd(name))
: this.styleTween(name, typeof value === "function"
? styleFunction$1(name, i, tweenValue(this, "style." + name, value))
: styleConstant$1(name, i, value), priority);
}
function styleTween(name, value, priority) {
function tween() {
var node = this, i = value.apply(node, arguments);
return i && function(t) {
node.style.setProperty(name, i(t), priority);
};
}
tween._value = value;
return tween;
}
function transition_styleTween(name, value, priority) {
var key = "style." + (name += "");
if (arguments.length < 2) return (key = this.tween(key)) && key._value;
if (value == null) return this.tween(key, null);
if (typeof value !== "function") throw new Error;
return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
}
function textConstant$1(value) {
return function() {
this.textContent = value;
};
}
function textFunction$1(value) {
return function() {
var value1 = value(this);
this.textContent = value1 == null ? "" : value1;
};
}
function transition_text(value) {
return this.tween("text", typeof value === "function"
? textFunction$1(tweenValue(this, "text", value))
: textConstant$1(value == null ? "" : value + ""));
}
function transition_transition() {
var name = this._name,
id0 = this._id,
id1 = newId();
for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
var inherit = get$1(node, id0);
schedule(node, name, id1, i, group, {
time: inherit.time + inherit.delay + inherit.duration,
delay: 0,
duration: inherit.duration,
ease: inherit.ease
});
}
}
}
return new Transition(groups, this._parents, name, id1);
}
var id = 0;
function Transition(groups, parents, name, id) {
this._groups = groups;
this._parents = parents;
this._name = name;
this._id = id;
}
function transition(name) {
return selection().transition(name);
}
function newId() {
return ++id;
}
var selection_prototype = selection.prototype;
Transition.prototype = transition.prototype = {
constructor: Transition,
select: transition_select,
selectAll: transition_selectAll,
filter: transition_filter,
merge: transition_merge,
selection: transition_selection,
transition: transition_transition,
call: selection_prototype.call,
nodes: selection_prototype.nodes,
node: selection_prototype.node,
size: selection_prototype.size,
empty: selection_prototype.empty,
each: selection_prototype.each,
on: transition_on,
attr: transition_attr,
attrTween: transition_attrTween,
style: transition_style,
styleTween: transition_styleTween,
text: transition_text,
remove: transition_remove,
tween: transition_tween,
delay: transition_delay,
duration: transition_duration,
ease: transition_ease
};
var defaultTiming = {
time: null, // Set on use.
delay: 0,
duration: 250,
ease: easeCubicInOut
};
function inherit(node, id) {
var timing;
while (!(timing = node.__transition) || !(timing = timing[id])) {
if (!(node = node.parentNode)) {
return defaultTiming.time = now(), defaultTiming;
}
}
return timing;
}
function selection_transition(name) {
var id,
timing;
if (name instanceof Transition) {
id = name._id, name = name._name;
} else {
id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
}
for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
schedule(node, name, id, i, group, timing || inherit(node, id));
}
}
}
return new Transition(groups, this._parents, name, id);
}
selection.prototype.interrupt = selection_interrupt;
selection.prototype.transition = selection_transition;
var root$1 = [null];
function active(node, name) {
var schedules = node.__transition,
schedule,
i;
if (schedules) {
name = name == null ? null : name + "";
for (i in schedules) {
if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) {
return new Transition([[node]], root$1, name, +i);
}
}
}
return null;
}
var slice$4 = Array.prototype.slice;
function identity$5(x) {
return x;
}
var top = 1;
var right = 2;
var bottom = 3;
var left = 4;
var epsilon$2 = 1e-6;
function translateX(scale0, scale1, d) {
var x = scale0(d);
return "translate(" + (isFinite(x) ? x : scale1(d)) + ",0)";
}
function translateY(scale0, scale1, d) {
var y = scale0(d);
return "translate(0," + (isFinite(y) ? y : scale1(d)) + ")";
}
function center(scale) {
var width = scale.bandwidth() / 2;
return function(d) {
return scale(d) + width;
};
}
function entering() {
return !this.__axis;
}
function axis(orient, scale) {
var tickArguments = [],
tickValues = null,
tickFormat = null,
tickSizeInner = 6,
tickSizeOuter = 6,
tickPadding = 3;
function axis(context) {
var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$5) : tickFormat,
spacing = Math.max(tickSizeInner, 0) + tickPadding,
transform = orient === top || orient === bottom ? translateX : translateY,
range = scale.range(),
range0 = range[0] + 0.5,
range1 = range[range.length - 1] + 0.5,
position = (scale.bandwidth ? center : identity$5)(scale.copy()),
selection = context.selection ? context.selection() : context,
path = selection.selectAll(".domain").data([null]),
tick = selection.selectAll(".tick").data(values, scale).order(),
tickExit = tick.exit(),
tickEnter = tick.enter().append("g").attr("class", "tick"),
line = tick.select("line"),
text = tick.select("text"),
k = orient === top || orient === left ? -1 : 1,
x, y = orient === left || orient === right ? (x = "x", "y") : (x = "y", "x");
path = path.merge(path.enter().insert("path", ".tick")
.attr("class", "domain")
.attr("stroke", "#000"));
tick = tick.merge(tickEnter);
line = line.merge(tickEnter.append("line")
.attr("stroke", "#000")
.attr(x + "2", k * tickSizeInner)
.attr(y + "1", 0.5)
.attr(y + "2", 0.5));
text = text.merge(tickEnter.append("text")
.attr("fill", "#000")
.attr(x, k * spacing)
.attr(y, 0.5)
.attr("dy", orient === top ? "0em" : orient === bottom ? ".71em" : ".32em"));
if (context !== selection) {
path = path.transition(context);
tick = tick.transition(context);
line = line.transition(context);
text = text.transition(context);
tickExit = tickExit.transition(context)
.attr("opacity", epsilon$2)
.attr("transform", function(d) { return transform(position, this.parentNode.__axis || position, d); });
tickEnter
.attr("opacity", epsilon$2)
.attr("transform", function(d) { return transform(this.parentNode.__axis || position, position, d); });
}
tickExit.remove();
path
.attr("d", orient === left || orient == right
? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
: "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
tick
.attr("opacity", 1)
.attr("transform", function(d) { return transform(position, position, d); });
line
.attr(x + "2", k * tickSizeInner);
text
.attr(x, k * spacing)
.text(format);
selection.filter(entering)
.attr("fill", "none")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
selection
.each(function() { this.__axis = position; });
}
axis.scale = function(_) {
return arguments.length ? (scale = _, axis) : scale;
};
axis.ticks = function() {
return tickArguments = slice$4.call(arguments), axis;
};
axis.tickArguments = function(_) {
return arguments.length ? (tickArguments = _ == null ? [] : slice$4.call(_), axis) : tickArguments.slice();
};
axis.tickValues = function(_) {
return arguments.length ? (tickValues = _ == null ? null : slice$4.call(_), axis) : tickValues && tickValues.slice();
};
axis.tickFormat = function(_) {
return arguments.length ? (tickFormat = _, axis) : tickFormat;
};
axis.tickSize = function(_) {
return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
};
axis.tickSizeInner = function(_) {
return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
};
axis.tickSizeOuter = function(_) {
return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
};
axis.tickPadding = function(_) {
return arguments.length ? (tickPadding = +_, axis) : tickPadding;
};
return axis;
}
function axisTop(scale) {
return axis(top, scale);
}
function axisRight(scale) {
return axis(right, scale);
}
function axisBottom(scale) {
return axis(bottom, scale);
}
function axisLeft(scale) {
return axis(left, scale);
}
function defaultSeparation(a, b) {
return a.parent === b.parent ? 1 : 2;
}
function meanX(children) {
return children.reduce(meanXReduce, 0) / children.length;
}
function meanXReduce(x, c) {
return x + c.x;
}
function maxY(children) {
return 1 + children.reduce(maxYReduce, 0);
}
function maxYReduce(y, c) {
return Math.max(y, c.y);
}
function leafLeft(node) {
var children;
while (children = node.children) node = children[0];
return node;
}
function leafRight(node) {
var children;
while (children = node.children) node = children[children.length - 1];
return node;
}
function cluster() {
var separation = defaultSeparation,
dx = 1,
dy = 1,
nodeSize = false;
function cluster(root) {
var previousNode,
x = 0;
// First walk, computing the initial x & y values.
root.eachAfter(function(node) {
var children = node.children;
if (children) {
node.x = meanX(children);
node.y = maxY(children);
} else {
node.x = previousNode ? x += separation(node, previousNode) : 0;
node.y = 0;
previousNode = node;
}
});
var left = leafLeft(root),
right = leafRight(root),
x0 = left.x - separation(left, right) / 2,
x1 = right.x + separation(right, left) / 2;
// Second walk, normalizing x & y to the desired size.
return root.eachAfter(nodeSize ? function(node) {
node.x = (node.x - root.x) * dx;
node.y = (root.y - node.y) * dy;
} : function(node) {
node.x = (node.x - x0) / (x1 - x0) * dx;
node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
});
}
cluster.separation = function(x) {
return arguments.length ? (separation = x, cluster) : separation;
};
cluster.size = function(x) {
return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
};
cluster.nodeSize = function(x) {
return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
};
return cluster;
}
function node_each(callback) {
var node = this, current, next = [node], children, i, n;
do {
current = next.reverse(), next = [];
while (node = current.pop()) {
callback(node), children = node.children;
if (children) for (i = 0, n = children.length; i < n; ++i) {
next.push(children[i]);
}
}
} while (next.length);
return this;
}
function node_eachBefore(callback) {
var node = this, nodes = [node], children, i;
while (node = nodes.pop()) {
callback(node), children = node.children;
if (children) for (i = children.length - 1; i >= 0; --i) {
nodes.push(children[i]);
}
}
return this;
}
function node_eachAfter(callback) {
var node = this, nodes = [node], next = [], children, i, n;
while (node = nodes.pop()) {
next.push(node), children = node.children;
if (children) for (i = 0, n = children.length; i < n; ++i) {
nodes.push(children[i]);
}
}
while (node = next.pop()) {
callback(node);
}
return this;
}
function node_sum(value) {
return this.eachAfter(function(node) {
var sum = +value(node.data) || 0,
children = node.children,
i = children && children.length;
while (--i >= 0) sum += children[i].value;
node.value = sum;
});
}
function node_sort(compare) {
return this.eachBefore(function(node) {
if (node.children) {
node.children.sort(compare);
}
});
}
function node_path(end) {
var start = this,
ancestor = leastCommonAncestor(start, end),
nodes = [start];
while (start !== ancestor) {
start = start.parent;
nodes.push(start);
}
var k = nodes.length;
while (end !== ancestor) {
nodes.splice(k, 0, end);
end = end.parent;
}
return nodes;
}
function leastCommonAncestor(a, b) {
if (a === b) return a;
var aNodes = a.ancestors(),
bNodes = b.ancestors(),
c = null;
a = aNodes.pop();
b = bNodes.pop();
while (a === b) {
c = a;
a = aNodes.pop();
b = bNodes.pop();
}
return c;
}
function node_ancestors() {
var node = this, nodes = [node];
while (node = node.parent) {
nodes.push(node);
}
return nodes;
}
function node_descendants() {
var nodes = [];
this.each(function(node) {
nodes.push(node);
});
return nodes;
}
function node_leaves() {
var leaves = [];
this.eachBefore(function(node) {
if (!node.children) {
leaves.push(node);
}
});
return leaves;
}
function node_links() {
var root = this, links = [];
root.each(function(node) {
if (node !== root) { // Don’t include the root’s parent, if any.
links.push({source: node.parent, target: node});
}
});
return links;
}
function hierarchy(data, children) {
var root = new Node(data),
valued = +data.value && (root.value = data.value),
node,
nodes = [root],
child,
childs,
i,
n;
if (children == null) children = defaultChildren;
while (node = nodes.pop()) {
if (valued) node.value = +node.data.value;
if ((childs = children(node.data)) && (n = childs.length)) {
node.children = new Array(n);
for (i = n - 1; i >= 0; --i) {
nodes.push(child = node.children[i] = new Node(childs[i]));
child.parent = node;
child.depth = node.depth + 1;
}
}
}
return root.eachBefore(computeHeight);
}
function node_copy() {
return hierarchy(this).eachBefore(copyData);
}
function defaultChildren(d) {
return d.children;
}
function copyData(node) {
node.data = node.data.data;
}
function computeHeight(node) {
var height = 0;
do node.height = height;
while ((node = node.parent) && (node.height < ++height));
}
function Node(data) {
this.data = data;
this.depth =
this.height = 0;
this.parent = null;
}
Node.prototype = hierarchy.prototype = {
constructor: Node,
each: node_each,
eachAfter: node_eachAfter,
eachBefore: node_eachBefore,
sum: node_sum,
sort: node_sort,
path: node_path,
ancestors: node_ancestors,
descendants: node_descendants,
leaves: node_leaves,
links: node_links,
copy: node_copy
};
function Node$2(value) {
this._ = value;
this.next = null;
}
function shuffle$1(array) {
var i,
n = (array = array.slice()).length,
head = null,
node = head;
while (n) {
var next = new Node$2(array[n - 1]);
if (node) node = node.next = next;
else node = head = next;
array[i] = array[--n];
}
return {
head: head,
tail: node
};
}
function enclose(circles) {
return encloseN(shuffle$1(circles), []);
}
function encloses(a, b) {
var dx = b.x - a.x,
dy = b.y - a.y,
dr = a.r - b.r;
return dr * dr + 1e-6 > dx * dx + dy * dy;
}
// Returns the smallest circle that contains circles L and intersects circles B.
function encloseN(L, B) {
var circle,
l0 = null,
l1 = L.head,
l2,
p1;
switch (B.length) {
case 1: circle = enclose1(B[0]); break;
case 2: circle = enclose2(B[0], B[1]); break;
case 3: circle = enclose3(B[0], B[1], B[2]); break;
}
while (l1) {
p1 = l1._, l2 = l1.next;
if (!circle || !encloses(circle, p1)) {
// Temporarily truncate L before l1.
if (l0) L.tail = l0, l0.next = null;
else L.head = L.tail = null;
B.push(p1);
circle = encloseN(L, B); // Note: reorders L!
B.pop();
// Move l1 to the front of L and reconnect the truncated list L.
if (L.head) l1.next = L.head, L.head = l1;
else l1.next = null, L.head = L.tail = l1;
l0 = L.tail, l0.next = l2;
} else {
l0 = l1;
}
l1 = l2;
}
L.tail = l0;
return circle;
}
function enclose1(a) {
return {
x: a.x,
y: a.y,
r: a.r
};
}
function enclose2(a, b) {
var x1 = a.x, y1 = a.y, r1 = a.r,
x2 = b.x, y2 = b.y, r2 = b.r,
x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
l = Math.sqrt(x21 * x21 + y21 * y21);
return {
x: (x1 + x2 + x21 / l * r21) / 2,
y: (y1 + y2 + y21 / l * r21) / 2,
r: (l + r1 + r2) / 2
};
}
function enclose3(a, b, c) {
var x1 = a.x, y1 = a.y, r1 = a.r,
x2 = b.x, y2 = b.y, r2 = b.r,
x3 = c.x, y3 = c.y, r3 = c.r,
a2 = 2 * (x1 - x2),
b2 = 2 * (y1 - y2),
c2 = 2 * (r2 - r1),
d2 = x1 * x1 + y1 * y1 - r1 * r1 - x2 * x2 - y2 * y2 + r2 * r2,
a3 = 2 * (x1 - x3),
b3 = 2 * (y1 - y3),
c3 = 2 * (r3 - r1),
d3 = x1 * x1 + y1 * y1 - r1 * r1 - x3 * x3 - y3 * y3 + r3 * r3,
ab = a3 * b2 - a2 * b3,
xa = (b2 * d3 - b3 * d2) / ab - x1,
xb = (b3 * c2 - b2 * c3) / ab,
ya = (a3 * d2 - a2 * d3) / ab - y1,
yb = (a2 * c3 - a3 * c2) / ab,
A = xb * xb + yb * yb - 1,
B = 2 * (xa * xb + ya * yb + r1),
C = xa * xa + ya * ya - r1 * r1,
r = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
return {
x: xa + xb * r + x1,
y: ya + yb * r + y1,
r: r
};
}
function place(a, b, c) {
var ax = a.x,
ay = a.y,
da = b.r + c.r,
db = a.r + c.r,
dx = b.x - ax,
dy = b.y - ay,
dc = dx * dx + dy * dy;
if (dc) {
var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc),
y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
c.x = ax + x * dx + y * dy;
c.y = ay + x * dy - y * dx;
} else {
c.x = ax + db;
c.y = ay;
}
}
function intersects(a, b) {
var dx = b.x - a.x,
dy = b.y - a.y,
dr = a.r + b.r;
return dr * dr > dx * dx + dy * dy;
}
function distance2(circle, x, y) {
var dx = circle.x - x,
dy = circle.y - y;
return dx * dx + dy * dy;
}
function Node$1(circle) {
this._ = circle;
this.next = null;
this.previous = null;
}
function packEnclose(circles) {
if (!(n = circles.length)) return 0;
var a, b, c, n;
// Place the first circle.
a = circles[0], a.x = 0, a.y = 0;
if (!(n > 1)) return a.r;
// Place the second circle.
b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
if (!(n > 2)) return a.r + b.r;
// Place the third circle.
place(b, a, c = circles[2]);
// Initialize the weighted centroid.
var aa = a.r * a.r,
ba = b.r * b.r,
ca = c.r * c.r,
oa = aa + ba + ca,
ox = aa * a.x + ba * b.x + ca * c.x,
oy = aa * a.y + ba * b.y + ca * c.y,
cx, cy, i, j, k, sj, sk;
// Initialize the front-chain using the first three circles a, b and c.
a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
a.next = c.previous = b;
b.next = a.previous = c;
c.next = b.previous = a;
// Attempt to place each remaining circle…
pack: for (i = 3; i < n; ++i) {
place(a._, b._, c = circles[i]), c = new Node$1(c);
// If there are only three elements in the front-chain…
if ((k = a.previous) === (j = b.next)) {
// If the new circle intersects the third circle,
// rotate the front chain to try the next position.
if (intersects(j._, c._)) {
a = b, b = j, --i;
continue pack;
}
}
// Find the closest intersecting circle on the front-chain, if any.
else {
sj = j._.r, sk = k._.r;
do {
if (sj <= sk) {
if (intersects(j._, c._)) {
b = j, a.next = b, b.previous = a, --i;
continue pack;
}
j = j.next, sj += j._.r;
} else {
if (intersects(k._, c._)) {
a = k, a.next = b, b.previous = a, --i;
continue pack;
}
k = k.previous, sk += k._.r;
}
} while (j !== k.next);
}
// Success! Insert the new circle c between a and b.
c.previous = a, c.next = b, a.next = b.previous = b = c;
// Update the weighted centroid.
oa += ca = c._.r * c._.r;
ox += ca * c._.x;
oy += ca * c._.y;
// Compute the new closest circle a to centroid.
aa = distance2(a._, cx = ox / oa, cy = oy / oa);
while ((c = c.next) !== b) {
if ((ca = distance2(c._, cx, cy)) < aa) {
a = c, aa = ca;
}
}
b = a.next;
}
// Compute the enclosing circle of the front chain.
a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
// Translate the circles to put the enclosing circle around the origin.
for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
return c.r;
}
function siblings(circles) {
packEnclose(circles);
return circles;
}
function optional(f) {
return f == null ? null : required(f);
}
function required(f) {
if (typeof f !== "function") throw new Error;
return f;
}
function constantZero() {
return 0;
}
function constant$5(x) {
return function() {
return x;
};
}
function defaultRadius(d) {
return Math.sqrt(d.value);
}
function index() {
var radius = null,
dx = 1,
dy = 1,
padding = constantZero;
function pack(root) {
root.x = dx / 2, root.y = dy / 2;
if (radius) {
root.eachBefore(radiusLeaf(radius))
.eachAfter(packChildren(padding, 0.5))
.eachBefore(translateChild(1));
} else {
root.eachBefore(radiusLeaf(defaultRadius))
.eachAfter(packChildren(constantZero, 1))
.eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
.eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
}
return root;
}
pack.radius = function(x) {
return arguments.length ? (radius = optional(x), pack) : radius;
};
pack.size = function(x) {
return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
};
pack.padding = function(x) {
return arguments.length ? (padding = typeof x === "function" ? x : constant$5(+x), pack) : padding;
};
return pack;
}
function radiusLeaf(radius) {
return function(node) {
if (!node.children) {
node.r = Math.max(0, +radius(node) || 0);
}
};
}
function packChildren(padding, k) {
return function(node) {
if (children = node.children) {
var children,
i,
n = children.length,
r = padding(node) * k || 0,
e;
if (r) for (i = 0; i < n; ++i) children[i].r += r;
e = packEnclose(children);
if (r) for (i = 0; i < n; ++i) children[i].r -= r;
node.r = e + r;
}
};
}
function translateChild(k) {
return function(node) {
var parent = node.parent;
node.r *= k;
if (parent) {
node.x = parent.x + k * node.x;
node.y = parent.y + k * node.y;
}
};
}
function roundNode(node) {
node.x0 = Math.round(node.x0);
node.y0 = Math.round(node.y0);
node.x1 = Math.round(node.x1);
node.y1 = Math.round(node.y1);
}
function treemapDice(parent, x0, y0, x1, y1) {
var nodes = parent.children,
node,
i = -1,
n = nodes.length,
k = parent.value && (x1 - x0) / parent.value;
while (++i < n) {
node = nodes[i], node.y0 = y0, node.y1 = y1;
node.x0 = x0, node.x1 = x0 += node.value * k;
}
}
function partition() {
var dx = 1,
dy = 1,
padding = 0,
round = false;
function partition(root) {
var n = root.height + 1;
root.x0 =
root.y0 = padding;
root.x1 = dx;
root.y1 = dy / n;
root.eachBefore(positionNode(dy, n));
if (round) root.eachBefore(roundNode);
return root;
}
function positionNode(dy, n) {
return function(node) {
if (node.children) {
treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
}
var x0 = node.x0,
y0 = node.y0,
x1 = node.x1 - padding,
y1 = node.y1 - padding;
if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
node.x0 = x0;
node.y0 = y0;
node.x1 = x1;
node.y1 = y1;
};
}
partition.round = function(x) {
return arguments.length ? (round = !!x, partition) : round;
};
partition.size = function(x) {
return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
};
partition.padding = function(x) {
return arguments.length ? (padding = +x, partition) : padding;
};
return partition;
}
var keyPrefix$1 = "$";
var preroot = {depth: -1};
var ambiguous = {};
function defaultId(d) {
return d.id;
}
function defaultParentId(d) {
return d.parentId;
}
function stratify() {
var id = defaultId,
parentId = defaultParentId;
function stratify(data) {
var d,
i,
n = data.length,
root,
parent,
node,
nodes = new Array(n),
nodeId,
nodeKey,
nodeByKey = {};
for (i = 0; i < n; ++i) {
d = data[i], node = nodes[i] = new Node(d);
if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
nodeKey = keyPrefix$1 + (node.id = nodeId);
nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
}
}
for (i = 0; i < n; ++i) {
node = nodes[i], nodeId = parentId(data[i], i, data);
if (nodeId == null || !(nodeId += "")) {
if (root) throw new Error("multiple roots");
root = node;
} else {
parent = nodeByKey[keyPrefix$1 + nodeId];
if (!parent) throw new Error("missing: " + nodeId);
if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
if (parent.children) parent.children.push(node);
else parent.children = [node];
node.parent = parent;
}
}
if (!root) throw new Error("no root");
root.parent = preroot;
root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
root.parent = null;
if (n > 0) throw new Error("cycle");
return root;
}
stratify.id = function(x) {
return arguments.length ? (id = required(x), stratify) : id;
};
stratify.parentId = function(x) {
return arguments.length ? (parentId = required(x), stratify) : parentId;
};
return stratify;
}
function defaultSeparation$1(a, b) {
return a.parent === b.parent ? 1 : 2;
}
// function radialSeparation(a, b) {
// return (a.parent === b.parent ? 1 : 2) / a.depth;
// }
// This function is used to traverse the left contour of a subtree (or
// subforest). It returns the successor of v on this contour. This successor is
// either given by the leftmost child of v or by the thread of v. The function
// returns null if and only if v is on the highest level of its subtree.
function nextLeft(v) {
var children = v.children;
return children ? children[0] : v.t;
}
// This function works analogously to nextLeft.
function nextRight(v) {
var children = v.children;
return children ? children[children.length - 1] : v.t;
}
// Shifts the current subtree rooted at w+. This is done by increasing
// prelim(w+) and mod(w+) by shift.
function moveSubtree(wm, wp, shift) {
var change = shift / (wp.i - wm.i);
wp.c -= change;
wp.s += shift;
wm.c += change;
wp.z += shift;
wp.m += shift;
}
// All other shifts, applied to the smaller subtrees between w- and w+, are
// performed by this function. To prepare the shifts, we have to adjust
// change(w+), shift(w+), and change(w-).
function executeShifts(v) {
var shift = 0,
change = 0,
children = v.children,
i = children.length,
w;
while (--i >= 0) {
w = children[i];
w.z += shift;
w.m += shift;
shift += w.s + (change += w.c);
}
}
// If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
// returns the specified (default) ancestor.
function nextAncestor(vim, v, ancestor) {
return vim.a.parent === v.parent ? vim.a : ancestor;
}
function TreeNode(node, i) {
this._ = node;
this.parent = null;
this.children = null;
this.A = null; // default ancestor
this.a = this; // ancestor
this.z = 0; // prelim
this.m = 0; // mod
this.c = 0; // change
this.s = 0; // shift
this.t = null; // thread
this.i = i; // number
}
TreeNode.prototype = Object.create(Node.prototype);
function treeRoot(root) {
var tree = new TreeNode(root, 0),
node,
nodes = [tree],
child,
children,
i,
n;
while (node = nodes.pop()) {
if (children = node._.children) {
node.children = new Array(n = children.length);
for (i = n - 1; i >= 0; --i) {
nodes.push(child = node.children[i] = new TreeNode(children[i], i));
child.parent = node;
}
}
}
(tree.parent = new TreeNode(null, 0)).children = [tree];
return tree;
}
// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
function tree() {
var separation = defaultSeparation$1,
dx = 1,
dy = 1,
nodeSize = null;
function tree(root) {
var t = treeRoot(root);
// Compute the layout using Buchheim et al.’s algorithm.
t.eachAfter(firstWalk), t.parent.m = -t.z;
t.eachBefore(secondWalk);
// If a fixed node size is specified, scale x and y.
if (nodeSize) root.eachBefore(sizeNode);
// If a fixed tree size is specified, scale x and y based on the extent.
// Compute the left-most, right-most, and depth-most nodes for extents.
else {
var left = root,
right = root,
bottom = root;
root.eachBefore(function(node) {
if (node.x < left.x) left = node;
if (node.x > right.x) right = node;
if (node.depth > bottom.depth) bottom = node;
});
var s = left === right ? 1 : separation(left, right) / 2,
tx = s - left.x,
kx = dx / (right.x + s + tx),
ky = dy / (bottom.depth || 1);
root.eachBefore(function(node) {
node.x = (node.x + tx) * kx;
node.y = node.depth * ky;
});
}
return root;
}
// Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
// applied recursively to the children of v, as well as the function
// APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
// node v is placed to the midpoint of its outermost children.
function firstWalk(v) {
var children = v.children,
siblings = v.parent.children,
w = v.i ? siblings[v.i - 1] : null;
if (children) {
executeShifts(v);
var midpoint = (children[0].z + children[children.length - 1].z) / 2;
if (w) {
v.z = w.z + separation(v._, w._);
v.m = v.z - midpoint;
} else {
v.z = midpoint;
}
} else if (w) {
v.z = w.z + separation(v._, w._);
}
v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
}
// Computes all real x-coordinates by summing up the modifiers recursively.
function secondWalk(v) {
v._.x = v.z + v.parent.m;
v.m += v.parent.m;
}
// The core of the algorithm. Here, a new subtree is combined with the
// previous subtrees. Threads are used to traverse the inside and outside
// contours of the left and right subtree up to the highest common level. The
// vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
// superscript o means outside and i means inside, the subscript - means left
// subtree and + means right subtree. For summing up the modifiers along the
// contour, we use respective variables si+, si-, so-, and so+. Whenever two
// nodes of the inside contours conflict, we compute the left one of the
// greatest uncommon ancestors using the function ANCESTOR and call MOVE
// SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
// Finally, we add a new thread (if necessary).
function apportion(v, w, ancestor) {
if (w) {
var vip = v,
vop = v,
vim = w,
vom = vip.parent.children[0],
sip = vip.m,
sop = vop.m,
sim = vim.m,
som = vom.m,
shift;
while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
vom = nextLeft(vom);
vop = nextRight(vop);
vop.a = v;
shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
if (shift > 0) {
moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
sip += shift;
sop += shift;
}
sim += vim.m;
sip += vip.m;
som += vom.m;
sop += vop.m;
}
if (vim && !nextRight(vop)) {
vop.t = vim;
vop.m += sim - sop;
}
if (vip && !nextLeft(vom)) {
vom.t = vip;
vom.m += sip - som;
ancestor = v;
}
}
return ancestor;
}
function sizeNode(node) {
node.x *= dx;
node.y = node.depth * dy;
}
tree.separation = function(x) {
return arguments.length ? (separation = x, tree) : separation;
};
tree.size = function(x) {
return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
};
tree.nodeSize = function(x) {
return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
};
return tree;
}
function treemapSlice(parent, x0, y0, x1, y1) {
var nodes = parent.children,
node,
i = -1,
n = nodes.length,
k = parent.value && (y1 - y0) / parent.value;
while (++i < n) {
node = nodes[i], node.x0 = x0, node.x1 = x1;
node.y0 = y0, node.y1 = y0 += node.value * k;
}
}
var phi = (1 + Math.sqrt(5)) / 2;
function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
var rows = [],
nodes = parent.children,
row,
nodeValue,
i0 = 0,
i1,
n = nodes.length,
dx, dy,
value = parent.value,
sumValue,
minValue,
maxValue,
newRatio,
minRatio,
alpha,
beta;
while (i0 < n) {
dx = x1 - x0, dy = y1 - y0;
minValue = maxValue = sumValue = nodes[i0].value;
alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
beta = sumValue * sumValue * alpha;
minRatio = Math.max(maxValue / beta, beta / minValue);
// Keep adding nodes while the aspect ratio maintains or improves.
for (i1 = i0 + 1; i1 < n; ++i1) {
sumValue += nodeValue = nodes[i1].value;
if (nodeValue < minValue) minValue = nodeValue;
if (nodeValue > maxValue) maxValue = nodeValue;
beta = sumValue * sumValue * alpha;
newRatio = Math.max(maxValue / beta, beta / minValue);
if (newRatio > minRatio) { sumValue -= nodeValue; break; }
minRatio = newRatio;
}
// Position and record the row orientation.
rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
value -= sumValue, i0 = i1;
}
return rows;
}
var squarify = (function custom(ratio) {
function squarify(parent, x0, y0, x1, y1) {
squarifyRatio(ratio, parent, x0, y0, x1, y1);
}
squarify.ratio = function(x) {
return custom((x = +x) > 1 ? x : 1);
};
return squarify;
})(phi);
function index$1() {
var tile = squarify,
round = false,
dx = 1,
dy = 1,
paddingStack = [0],
paddingInner = constantZero,
paddingTop = constantZero,
paddingRight = constantZero,
paddingBottom = constantZero,
paddingLeft = constantZero;
function treemap(root) {
root.x0 =
root.y0 = 0;
root.x1 = dx;
root.y1 = dy;
root.eachBefore(positionNode);
paddingStack = [0];
if (round) root.eachBefore(roundNode);
return root;
}
function positionNode(node) {
var p = paddingStack[node.depth],
x0 = node.x0 + p,
y0 = node.y0 + p,
x1 = node.x1 - p,
y1 = node.y1 - p;
if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
node.x0 = x0;
node.y0 = y0;
node.x1 = x1;
node.y1 = y1;
if (node.children) {
p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
x0 += paddingLeft(node) - p;
y0 += paddingTop(node) - p;
x1 -= paddingRight(node) - p;
y1 -= paddingBottom(node) - p;
if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
tile(node, x0, y0, x1, y1);
}
}
treemap.round = function(x) {
return arguments.length ? (round = !!x, treemap) : round;
};
treemap.size = function(x) {
return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
};
treemap.tile = function(x) {
return arguments.length ? (tile = required(x), treemap) : tile;
};
treemap.padding = function(x) {
return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
};
treemap.paddingInner = function(x) {
return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$5(+x), treemap) : paddingInner;
};
treemap.paddingOuter = function(x) {
return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
};
treemap.paddingTop = function(x) {
return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$5(+x), treemap) : paddingTop;
};
treemap.paddingRight = function(x) {
return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$5(+x), treemap) : paddingRight;
};
treemap.paddingBottom = function(x) {
return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$5(+x), treemap) : paddingBottom;
};
treemap.paddingLeft = function(x) {
return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$5(+x), treemap) : paddingLeft;
};
return treemap;
}
function binary(parent, x0, y0, x1, y1) {
var nodes = parent.children,
i, n = nodes.length,
sum, sums = new Array(n + 1);
for (sums[0] = sum = i = 0; i < n; ++i) {
sums[i + 1] = sum += nodes[i].value;
}
partition(0, n, parent.value, x0, y0, x1, y1);
function partition(i, j, value, x0, y0, x1, y1) {
if (i >= j - 1) {
var node = nodes[i];
node.x0 = x0, node.y0 = y0;
node.x1 = x1, node.y1 = y1;
return;
}
var valueOffset = sums[i],
valueTarget = (value / 2) + valueOffset,
k = i + 1,
hi = j - 1;
while (k < hi) {
var mid = k + hi >>> 1;
if (sums[mid] < valueTarget) k = mid + 1;
else hi = mid;
}
var valueLeft = sums[k] - valueOffset,
valueRight = value - valueLeft;
if ((y1 - y0) > (x1 - x0)) {
var yk = (y0 * valueRight + y1 * valueLeft) / value;
partition(i, k, valueLeft, x0, y0, x1, yk);
partition(k, j, valueRight, x0, yk, x1, y1);
} else {
var xk = (x0 * valueRight + x1 * valueLeft) / value;
partition(i, k, valueLeft, x0, y0, xk, y1);
partition(k, j, valueRight, xk, y0, x1, y1);
}
}
}
function sliceDice(parent, x0, y0, x1, y1) {
(parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
}
var resquarify = (function custom(ratio) {
function resquarify(parent, x0, y0, x1, y1) {
if ((rows = parent._squarify) && (rows.ratio === ratio)) {
var rows,
row,
nodes,
i,
j = -1,
n,
m = rows.length,
value = parent.value;
while (++j < m) {
row = rows[j], nodes = row.children;
for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
value -= row.value;
}
} else {
parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
rows.ratio = ratio;
}
}
resquarify.ratio = function(x) {
return custom((x = +x) > 1 ? x : 1);
};
return resquarify;
})(phi);
function center$1(x, y) {
var nodes;
if (x == null) x = 0;
if (y == null) y = 0;
function force() {
var i,
n = nodes.length,
node,
sx = 0,
sy = 0;
for (i = 0; i < n; ++i) {
node = nodes[i], sx += node.x, sy += node.y;
}
for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
node = nodes[i], node.x -= sx, node.y -= sy;
}
}
force.initialize = function(_) {
nodes = _;
};
force.x = function(_) {
return arguments.length ? (x = +_, force) : x;
};
force.y = function(_) {
return arguments.length ? (y = +_, force) : y;
};
return force;
}
function constant$6(x) {
return function() {
return x;
};
}
function jiggle() {
return (Math.random() - 0.5) * 1e-6;
}
function x$1(d) {
return d.x + d.vx;
}
function y$1(d) {
return d.y + d.vy;
}
function collide(radius) {
var nodes,
radii,
strength = 1,
iterations = 1;
if (typeof radius !== "function") radius = constant$6(radius == null ? 1 : +radius);
function force() {
var i, n = nodes.length,
tree,
node,
xi,
yi,
ri,
ri2;
for (var k = 0; k < iterations; ++k) {
tree = quadtree(nodes, x$1, y$1).visitAfter(prepare);
for (i = 0; i < n; ++i) {
node = nodes[i];
ri = radii[i], ri2 = ri * ri;
xi = node.x + node.vx;
yi = node.y + node.vy;
tree.visit(apply);
}
}
function apply(quad, x0, y0, x1, y1) {
var data = quad.data, rj = quad.r, r = ri + rj;
if (data) {
if (data.index > i) {
var x = xi - data.x - data.vx,
y = yi - data.y - data.vy,
l = x * x + y * y;
if (l < r * r) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
l = (r - (l = Math.sqrt(l))) / l * strength;
node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
node.vy += (y *= l) * r;
data.vx -= x * (r = 1 - r);
data.vy -= y * r;
}
}
return;
}
return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
}
}
function prepare(quad) {
if (quad.data) return quad.r = radii[quad.data.index];
for (var i = quad.r = 0; i < 4; ++i) {
if (quad[i] && quad[i].r > quad.r) {
quad.r = quad[i].r;
}
}
}
force.initialize = function(_) {
var i, n = (nodes = _).length; radii = new Array(n);
for (i = 0; i < n; ++i) radii[i] = +radius(nodes[i], i, nodes);
};
force.iterations = function(_) {
return arguments.length ? (iterations = +_, force) : iterations;
};
force.strength = function(_) {
return arguments.length ? (strength = +_, force) : strength;
};
force.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant$6(+_), force) : radius;
};
return force;
}
function index$2(d, i) {
return i;
}
function link(links) {
var id = index$2,
strength = defaultStrength,
strengths,
distance = constant$6(30),
distances,
nodes,
count,
bias,
iterations = 1;
if (links == null) links = [];
function defaultStrength(link) {
return 1 / Math.min(count[link.source.index], count[link.target.index]);
}
function force(alpha) {
for (var k = 0, n = links.length; k < iterations; ++k) {
for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
link = links[i], source = link.source, target = link.target;
x = target.x + target.vx - source.x - source.vx || jiggle();
y = target.y + target.vy - source.y - source.vy || jiggle();
l = Math.sqrt(x * x + y * y);
l = (l - distances[i]) / l * alpha * strengths[i];
x *= l, y *= l;
target.vx -= x * (b = bias[i]);
target.vy -= y * b;
source.vx += x * (b = 1 - b);
source.vy += y * b;
}
}
}
function initialize() {
if (!nodes) return;
var i,
n = nodes.length,
m = links.length,
nodeById = map$1(nodes, id),
link;
for (i = 0, count = new Array(n); i < n; ++i) {
count[i] = 0;
}
for (i = 0; i < m; ++i) {
link = links[i], link.index = i;
if (typeof link.source !== "object") link.source = nodeById.get(link.source);
if (typeof link.target !== "object") link.target = nodeById.get(link.target);
++count[link.source.index], ++count[link.target.index];
}
for (i = 0, bias = new Array(m); i < m; ++i) {
link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
}
strengths = new Array(m), initializeStrength();
distances = new Array(m), initializeDistance();
}
function initializeStrength() {
if (!nodes) return;
for (var i = 0, n = links.length; i < n; ++i) {
strengths[i] = +strength(links[i], i, links);
}
}
function initializeDistance() {
if (!nodes) return;
for (var i = 0, n = links.length; i < n; ++i) {
distances[i] = +distance(links[i], i, links);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.links = function(_) {
return arguments.length ? (links = _, initialize(), force) : links;
};
force.id = function(_) {
return arguments.length ? (id = _, force) : id;
};
force.iterations = function(_) {
return arguments.length ? (iterations = +_, force) : iterations;
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initializeStrength(), force) : strength;
};
force.distance = function(_) {
return arguments.length ? (distance = typeof _ === "function" ? _ : constant$6(+_), initializeDistance(), force) : distance;
};
return force;
}
function x$2(d) {
return d.x;
}
function y$2(d) {
return d.y;
}
var initialRadius = 10;
var initialAngle = Math.PI * (3 - Math.sqrt(5));
function simulation(nodes) {
var simulation,
alpha = 1,
alphaMin = 0.001,
alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
alphaTarget = 0,
velocityDecay = 0.6,
forces = map$1(),
stepper = timer(step),
event = dispatch("tick", "end");
if (nodes == null) nodes = [];
function step() {
tick();
event.call("tick", simulation);
if (alpha < alphaMin) {
stepper.stop();
event.call("end", simulation);
}
}
function tick() {
var i, n = nodes.length, node;
alpha += (alphaTarget - alpha) * alphaDecay;
forces.each(function(force) {
force(alpha);
});
for (i = 0; i < n; ++i) {
node = nodes[i];
if (node.fx == null) node.x += node.vx *= velocityDecay;
else node.x = node.fx, node.vx = 0;
if (node.fy == null) node.y += node.vy *= velocityDecay;
else node.y = node.fy, node.vy = 0;
}
}
function initializeNodes() {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.index = i;
if (isNaN(node.x) || isNaN(node.y)) {
var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
node.x = radius * Math.cos(angle);
node.y = radius * Math.sin(angle);
}
if (isNaN(node.vx) || isNaN(node.vy)) {
node.vx = node.vy = 0;
}
}
}
function initializeForce(force) {
if (force.initialize) force.initialize(nodes);
return force;
}
initializeNodes();
return simulation = {
tick: tick,
restart: function() {
return stepper.restart(step), simulation;
},
stop: function() {
return stepper.stop(), simulation;
},
nodes: function(_) {
return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
},
alpha: function(_) {
return arguments.length ? (alpha = +_, simulation) : alpha;
},
alphaMin: function(_) {
return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
},
alphaDecay: function(_) {
return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
},
alphaTarget: function(_) {
return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
},
velocityDecay: function(_) {
return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
},
force: function(name, _) {
return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
},
find: function(x, y, radius) {
var i = 0,
n = nodes.length,
dx,
dy,
d2,
node,
closest;
if (radius == null) radius = Infinity;
else radius *= radius;
for (i = 0; i < n; ++i) {
node = nodes[i];
dx = x - node.x;
dy = y - node.y;
d2 = dx * dx + dy * dy;
if (d2 < radius) closest = node, radius = d2;
}
return closest;
},
on: function(name, _) {
return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
}
};
}
function manyBody() {
var nodes,
node,
alpha,
strength = constant$6(-30),
strengths,
distanceMin2 = 1,
distanceMax2 = Infinity,
theta2 = 0.81;
function force(_) {
var i, n = nodes.length, tree = quadtree(nodes, x$2, y$2).visitAfter(accumulate);
for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
for (i = 0; i < n; ++i) strengths[i] = +strength(nodes[i], i, nodes);
}
function accumulate(quad) {
var strength = 0, q, c, x, y, i;
// For internal nodes, accumulate forces from child quadrants.
if (quad.length) {
for (x = y = i = 0; i < 4; ++i) {
if ((q = quad[i]) && (c = q.value)) {
strength += c, x += c * q.x, y += c * q.y;
}
}
quad.x = x / strength;
quad.y = y / strength;
}
// For leaf nodes, accumulate forces from coincident quadrants.
else {
q = quad;
q.x = q.data.x;
q.y = q.data.y;
do strength += strengths[q.data.index];
while (q = q.next);
}
quad.value = strength;
}
function apply(quad, x1, _, x2) {
if (!quad.value) return true;
var x = quad.x - node.x,
y = quad.y - node.y,
w = x2 - x1,
l = x * x + y * y;
// Apply the Barnes-Hut approximation if possible.
// Limit forces for very close nodes; randomize direction if coincident.
if (w * w / theta2 < l) {
if (l < distanceMax2) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
node.vx += x * quad.value * alpha / l;
node.vy += y * quad.value * alpha / l;
}
return true;
}
// Otherwise, process points directly.
else if (quad.length || l >= distanceMax2) return;
// Limit forces for very close nodes; randomize direction if coincident.
if (quad.data !== node || quad.next) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
}
do if (quad.data !== node) {
w = strengths[quad.data.index] * alpha / l;
node.vx += x * w;
node.vy += y * w;
} while (quad = quad.next);
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
};
force.distanceMin = function(_) {
return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
};
force.distanceMax = function(_) {
return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
};
force.theta = function(_) {
return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
};
return force;
}
function x$3(x) {
var strength = constant$6(0.1),
nodes,
strengths,
xz;
if (typeof x !== "function") x = constant$6(x == null ? 0 : +x);
function force(alpha) {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
xz = new Array(n);
for (i = 0; i < n; ++i) {
strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
};
force.x = function(_) {
return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : x;
};
return force;
}
function y$3(y) {
var strength = constant$6(0.1),
nodes,
strengths,
yz;
if (typeof y !== "function") y = constant$6(y == null ? 0 : +y);
function force(alpha) {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
yz = new Array(n);
for (i = 0; i < n; ++i) {
strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
};
force.y = function(_) {
return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : y;
};
return force;
}
function nopropagation() {
exports.event.stopImmediatePropagation();
}
function noevent() {
exports.event.preventDefault();
exports.event.stopImmediatePropagation();
}
function dragDisable(view) {
var root = view.document.documentElement,
selection = select(view).on("dragstart.drag", noevent, true);
if ("onselectstart" in root) {
selection.on("selectstart.drag", noevent, true);
} else {
root.__noselect = root.style.MozUserSelect;
root.style.MozUserSelect = "none";
}
}
function dragEnable(view, noclick) {
var root = view.document.documentElement,
selection = select(view).on("dragstart.drag", null);
if (noclick) {
selection.on("click.drag", noevent, true);
setTimeout(function() { selection.on("click.drag", null); }, 0);
}
if ("onselectstart" in root) {
selection.on("selectstart.drag", null);
} else {
root.style.MozUserSelect = root.__noselect;
delete root.__noselect;
}
}
function constant$7(x) {
return function() {
return x;
};
}
function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
this.target = target;
this.type = type;
this.subject = subject;
this.identifier = id;
this.active = active;
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this._ = dispatch;
}
DragEvent.prototype.on = function() {
var value = this._.on.apply(this._, arguments);
return value === this._ ? this : value;
};
// Ignore right-click, since that should open the context menu.
function defaultFilter() {
return !exports.event.button;
}
function defaultContainer() {
return this.parentNode;
}
function defaultSubject(d) {
return d == null ? {x: exports.event.x, y: exports.event.y} : d;
}
function drag() {
var filter = defaultFilter,
container = defaultContainer,
subject = defaultSubject,
gestures = {},
listeners = dispatch("start", "drag", "end"),
active = 0,
mousemoving,
touchending;
function drag(selection) {
selection
.on("mousedown.drag", mousedowned)
.on("touchstart.drag", touchstarted)
.on("touchmove.drag", touchmoved)
.on("touchend.drag touchcancel.drag", touchended)
.style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
}
function mousedowned() {
if (touchending || !filter.apply(this, arguments)) return;
var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
if (!gesture) return;
select(exports.event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
dragDisable(exports.event.view);
nopropagation();
mousemoving = false;
gesture("start");
}
function mousemoved() {
noevent();
mousemoving = true;
gestures.mouse("drag");
}
function mouseupped() {
select(exports.event.view).on("mousemove.drag mouseup.drag", null);
dragEnable(exports.event.view, mousemoving);
noevent();
gestures.mouse("end");
}
function touchstarted() {
if (!filter.apply(this, arguments)) return;
var touches = exports.event.changedTouches,
c = container.apply(this, arguments),
n = touches.length, i, gesture;
for (i = 0; i < n; ++i) {
if (gesture = beforestart(touches[i].identifier, c, touch, this, arguments)) {
nopropagation();
gesture("start");
}
}
}
function touchmoved() {
var touches = exports.event.changedTouches,
n = touches.length, i, gesture;
for (i = 0; i < n; ++i) {
if (gesture = gestures[touches[i].identifier]) {
noevent();
gesture("drag");
}
}
}
function touchended() {
var touches = exports.event.changedTouches,
n = touches.length, i, gesture;
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
for (i = 0; i < n; ++i) {
if (gesture = gestures[touches[i].identifier]) {
nopropagation();
gesture("end");
}
}
}
function beforestart(id, container, point, that, args) {
var p = point(container, id), s, dx, dy,
sublisteners = listeners.copy();
if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
if ((exports.event.subject = s = subject.apply(that, args)) == null) return false;
dx = s.x - p[0] || 0;
dy = s.y - p[1] || 0;
return true;
})) return;
return function gesture(type) {
var p0 = p, n;
switch (type) {
case "start": gestures[id] = gesture, n = active++; break;
case "end": delete gestures[id], --active; // nobreak
case "drag": p = point(container, id), n = active; break;
}
customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]);
};
}
drag.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant$7(!!_), drag) : filter;
};
drag.container = function(_) {
return arguments.length ? (container = typeof _ === "function" ? _ : constant$7(_), drag) : container;
};
drag.subject = function(_) {
return arguments.length ? (subject = typeof _ === "function" ? _ : constant$7(_), drag) : subject;
};
drag.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? drag : value;
};
return drag;
}
function constant$8(x) {
return function() {
return x;
};
}
function x$4(d) {
return d[0];
}
function y$4(d) {
return d[1];
}
function RedBlackTree() {
this._ = null; // root node
}
function RedBlackNode(node) {
node.U = // parent node
node.C = // color - true for red, false for black
node.L = // left node
node.R = // right node
node.P = // previous node
node.N = null; // next node
}
RedBlackTree.prototype = {
constructor: RedBlackTree,
insert: function(after, node) {
var parent, grandpa, uncle;
if (after) {
node.P = after;
node.N = after.N;
if (after.N) after.N.P = node;
after.N = node;
if (after.R) {
after = after.R;
while (after.L) after = after.L;
after.L = node;
} else {
after.R = node;
}
parent = after;
} else if (this._) {
after = RedBlackFirst(this._);
node.P = null;
node.N = after;
after.P = after.L = node;
parent = after;
} else {
node.P = node.N = null;
this._ = node;
parent = null;
}
node.L = node.R = null;
node.U = parent;
node.C = true;
after = node;
while (parent && parent.C) {
grandpa = parent.U;
if (parent === grandpa.L) {
uncle = grandpa.R;
if (uncle && uncle.C) {
parent.C = uncle.C = false;
grandpa.C = true;
after = grandpa;
} else {
if (after === parent.R) {
RedBlackRotateLeft(this, parent);
after = parent;
parent = after.U;
}
parent.C = false;
grandpa.C = true;
RedBlackRotateRight(this, grandpa);
}
} else {
uncle = grandpa.L;
if (uncle && uncle.C) {
parent.C = uncle.C = false;
grandpa.C = true;
after = grandpa;
} else {
if (after === parent.L) {
RedBlackRotateRight(this, parent);
after = parent;
parent = after.U;
}
parent.C = false;
grandpa.C = true;
RedBlackRotateLeft(this, grandpa);
}
}
parent = after.U;
}
this._.C = false;
},
remove: function(node) {
if (node.N) node.N.P = node.P;
if (node.P) node.P.N = node.N;
node.N = node.P = null;
var parent = node.U,
sibling,
left = node.L,
right = node.R,
next,
red;
if (!left) next = right;
else if (!right) next = left;
else next = RedBlackFirst(right);
if (parent) {
if (parent.L === node) parent.L = next;
else parent.R = next;
} else {
this._ = next;
}
if (left && right) {
red = next.C;
next.C = node.C;
next.L = left;
left.U = next;
if (next !== right) {
parent = next.U;
next.U = node.U;
node = next.R;
parent.L = node;
next.R = right;
right.U = next;
} else {
next.U = parent;
parent = next;
node = next.R;
}
} else {
red = node.C;
node = next;
}
if (node) node.U = parent;
if (red) return;
if (node && node.C) { node.C = false; return; }
do {
if (node === this._) break;
if (node === parent.L) {
sibling = parent.R;
if (sibling.C) {
sibling.C = false;
parent.C = true;
RedBlackRotateLeft(this, parent);
sibling = parent.R;
}
if ((sibling.L && sibling.L.C)
|| (sibling.R && sibling.R.C)) {
if (!sibling.R || !sibling.R.C) {
sibling.L.C = false;
sibling.C = true;
RedBlackRotateRight(this, sibling);
sibling = parent.R;
}
sibling.C = parent.C;
parent.C = sibling.R.C = false;
RedBlackRotateLeft(this, parent);
node = this._;
break;
}
} else {
sibling = parent.L;
if (sibling.C) {
sibling.C = false;
parent.C = true;
RedBlackRotateRight(this, parent);
sibling = parent.L;
}
if ((sibling.L && sibling.L.C)
|| (sibling.R && sibling.R.C)) {
if (!sibling.L || !sibling.L.C) {
sibling.R.C = false;
sibling.C = true;
RedBlackRotateLeft(this, sibling);
sibling = parent.L;
}
sibling.C = parent.C;
parent.C = sibling.L.C = false;
RedBlackRotateRight(this, parent);
node = this._;
break;
}
}
sibling.C = true;
node = parent;
parent = parent.U;
} while (!node.C);
if (node) node.C = false;
}
};
function RedBlackRotateLeft(tree, node) {
var p = node,
q = node.R,
parent = p.U;
if (parent) {
if (parent.L === p) parent.L = q;
else parent.R = q;
} else {
tree._ = q;
}
q.U = parent;
p.U = q;
p.R = q.L;
if (p.R) p.R.U = p;
q.L = p;
}
function RedBlackRotateRight(tree, node) {
var p = node,
q = node.L,
parent = p.U;
if (parent) {
if (parent.L === p) parent.L = q;
else parent.R = q;
} else {
tree._ = q;
}
q.U = parent;
p.U = q;
p.L = q.R;
if (p.L) p.L.U = p;
q.R = p;
}
function RedBlackFirst(node) {
while (node.L) node = node.L;
return node;
}
function createEdge(left, right, v0, v1) {
var edge = [null, null],
index = edges.push(edge) - 1;
edge.left = left;
edge.right = right;
if (v0) setEdgeEnd(edge, left, right, v0);
if (v1) setEdgeEnd(edge, right, left, v1);
cells[left.index].halfedges.push(index);
cells[right.index].halfedges.push(index);
return edge;
}
function createBorderEdge(left, v0, v1) {
var edge = [v0, v1];
edge.left = left;
return edge;
}
function setEdgeEnd(edge, left, right, vertex) {
if (!edge[0] && !edge[1]) {
edge[0] = vertex;
edge.left = left;
edge.right = right;
} else if (edge.left === right) {
edge[1] = vertex;
} else {
edge[0] = vertex;
}
}
// Liang–Barsky line clipping.
function clipEdge(edge, x0, y0, x1, y1) {
var a = edge[0],
b = edge[1],
ax = a[0],
ay = a[1],
bx = b[0],
by = b[1],
t0 = 0,
t1 = 1,
dx = bx - ax,
dy = by - ay,
r;
r = x0 - ax;
if (!dx && r > 0) return;
r /= dx;
if (dx < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dx > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = x1 - ax;
if (!dx && r < 0) return;
r /= dx;
if (dx < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dx > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
r = y0 - ay;
if (!dy && r > 0) return;
r /= dy;
if (dy < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dy > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = y1 - ay;
if (!dy && r < 0) return;
r /= dy;
if (dy < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dy > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
return true;
}
function connectEdge(edge, x0, y0, x1, y1) {
var v1 = edge[1];
if (v1) return true;
var v0 = edge[0],
left = edge.left,
right = edge.right,
lx = left[0],
ly = left[1],
rx = right[0],
ry = right[1],
fx = (lx + rx) / 2,
fy = (ly + ry) / 2,
fm,
fb;
if (ry === ly) {
if (fx < x0 || fx >= x1) return;
if (lx > rx) {
if (!v0) v0 = [fx, y0];
else if (v0[1] >= y1) return;
v1 = [fx, y1];
} else {
if (!v0) v0 = [fx, y1];
else if (v0[1] < y0) return;
v1 = [fx, y0];
}
} else {
fm = (lx - rx) / (ry - ly);
fb = fy - fm * fx;
if (fm < -1 || fm > 1) {
if (lx > rx) {
if (!v0) v0 = [(y0 - fb) / fm, y0];
else if (v0[1] >= y1) return;
v1 = [(y1 - fb) / fm, y1];
} else {
if (!v0) v0 = [(y1 - fb) / fm, y1];
else if (v0[1] < y0) return;
v1 = [(y0 - fb) / fm, y0];
}
} else {
if (ly < ry) {
if (!v0) v0 = [x0, fm * x0 + fb];
else if (v0[0] >= x1) return;
v1 = [x1, fm * x1 + fb];
} else {
if (!v0) v0 = [x1, fm * x1 + fb];
else if (v0[0] < x0) return;
v1 = [x0, fm * x0 + fb];
}
}
}
edge[0] = v0;
edge[1] = v1;
return true;
}
function clipEdges(x0, y0, x1, y1) {
var i = edges.length,
edge;
while (i--) {
if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
|| !clipEdge(edge, x0, y0, x1, y1)
|| !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$3
|| Math.abs(edge[0][1] - edge[1][1]) > epsilon$3)) {
delete edges[i];
}
}
}
function createCell(site) {
return cells[site.index] = {
site: site,
halfedges: []
};
}
function cellHalfedgeAngle(cell, edge) {
var site = cell.site,
va = edge.left,
vb = edge.right;
if (site === vb) vb = va, va = site;
if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
if (site === va) va = edge[1], vb = edge[0];
else va = edge[0], vb = edge[1];
return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
}
function cellHalfedgeStart(cell, edge) {
return edge[+(edge.left !== cell.site)];
}
function cellHalfedgeEnd(cell, edge) {
return edge[+(edge.left === cell.site)];
}
function sortCellHalfedges() {
for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
var index = new Array(m),
array = new Array(m);
for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
index.sort(function(i, j) { return array[j] - array[i]; });
for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
for (j = 0; j < m; ++j) halfedges[j] = array[j];
}
}
}
function clipCells(x0, y0, x1, y1) {
var nCells = cells.length,
iCell,
cell,
site,
iHalfedge,
halfedges,
nHalfedges,
start,
startX,
startY,
end,
endX,
endY,
cover = true;
for (iCell = 0; iCell < nCells; ++iCell) {
if (cell = cells[iCell]) {
site = cell.site;
halfedges = cell.halfedges;
iHalfedge = halfedges.length;
// Remove any dangling clipped edges.
while (iHalfedge--) {
if (!edges[halfedges[iHalfedge]]) {
halfedges.splice(iHalfedge, 1);
}
}
// Insert any border edges as necessary.
iHalfedge = 0, nHalfedges = halfedges.length;
while (iHalfedge < nHalfedges) {
end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
if (Math.abs(endX - startX) > epsilon$3 || Math.abs(endY - startY) > epsilon$3) {
halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
Math.abs(endX - x0) < epsilon$3 && y1 - endY > epsilon$3 ? [x0, Math.abs(startX - x0) < epsilon$3 ? startY : y1]
: Math.abs(endY - y1) < epsilon$3 && x1 - endX > epsilon$3 ? [Math.abs(startY - y1) < epsilon$3 ? startX : x1, y1]
: Math.abs(endX - x1) < epsilon$3 && endY - y0 > epsilon$3 ? [x1, Math.abs(startX - x1) < epsilon$3 ? startY : y0]
: Math.abs(endY - y0) < epsilon$3 && endX - x0 > epsilon$3 ? [Math.abs(startY - y0) < epsilon$3 ? startX : x0, y0]
: null)) - 1);
++nHalfedges;
}
}
if (nHalfedges) cover = false;
}
}
// If there weren’t any edges, have the closest site cover the extent.
// It doesn’t matter which corner of the extent we measure!
if (cover) {
var dx, dy, d2, dc = Infinity;
for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
if (cell = cells[iCell]) {
site = cell.site;
dx = site[0] - x0;
dy = site[1] - y0;
d2 = dx * dx + dy * dy;
if (d2 < dc) dc = d2, cover = cell;
}
}
if (cover) {
var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
cover.halfedges.push(
edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
edges.push(createBorderEdge(site, v01, v11)) - 1,
edges.push(createBorderEdge(site, v11, v10)) - 1,
edges.push(createBorderEdge(site, v10, v00)) - 1
);
}
}
// Lastly delete any cells with no edges; these were entirely clipped.
for (iCell = 0; iCell < nCells; ++iCell) {
if (cell = cells[iCell]) {
if (!cell.halfedges.length) {
delete cells[iCell];
}
}
}
}
var circlePool = [];
var firstCircle;
function Circle() {
RedBlackNode(this);
this.x =
this.y =
this.arc =
this.site =
this.cy = null;
}
function attachCircle(arc) {
var lArc = arc.P,
rArc = arc.N;
if (!lArc || !rArc) return;
var lSite = lArc.site,
cSite = arc.site,
rSite = rArc.site;
if (lSite === rSite) return;
var bx = cSite[0],
by = cSite[1],
ax = lSite[0] - bx,
ay = lSite[1] - by,
cx = rSite[0] - bx,
cy = rSite[1] - by;
var d = 2 * (ax * cy - ay * cx);
if (d >= -epsilon2$1) return;
var ha = ax * ax + ay * ay,
hc = cx * cx + cy * cy,
x = (cy * ha - ay * hc) / d,
y = (ax * hc - cx * ha) / d;
var circle = circlePool.pop() || new Circle;
circle.arc = arc;
circle.site = cSite;
circle.x = x + bx;
circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
arc.circle = circle;
var before = null,
node = circles._;
while (node) {
if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
if (node.L) node = node.L;
else { before = node.P; break; }
} else {
if (node.R) node = node.R;
else { before = node; break; }
}
}
circles.insert(before, circle);
if (!before) firstCircle = circle;
}
function detachCircle(arc) {
var circle = arc.circle;
if (circle) {
if (!circle.P) firstCircle = circle.N;
circles.remove(circle);
circlePool.push(circle);
RedBlackNode(circle);
arc.circle = null;
}
}
var beachPool = [];
function Beach() {
RedBlackNode(this);
this.edge =
this.site =
this.circle = null;
}
function createBeach(site) {
var beach = beachPool.pop() || new Beach;
beach.site = site;
return beach;
}
function detachBeach(beach) {
detachCircle(beach);
beaches.remove(beach);
beachPool.push(beach);
RedBlackNode(beach);
}
function removeBeach(beach) {
var circle = beach.circle,
x = circle.x,
y = circle.cy,
vertex = [x, y],
previous = beach.P,
next = beach.N,
disappearing = [beach];
detachBeach(beach);
var lArc = previous;
while (lArc.circle
&& Math.abs(x - lArc.circle.x) < epsilon$3
&& Math.abs(y - lArc.circle.cy) < epsilon$3) {
previous = lArc.P;
disappearing.unshift(lArc);
detachBeach(lArc);
lArc = previous;
}
disappearing.unshift(lArc);
detachCircle(lArc);
var rArc = next;
while (rArc.circle
&& Math.abs(x - rArc.circle.x) < epsilon$3
&& Math.abs(y - rArc.circle.cy) < epsilon$3) {
next = rArc.N;
disappearing.push(rArc);
detachBeach(rArc);
rArc = next;
}
disappearing.push(rArc);
detachCircle(rArc);
var nArcs = disappearing.length,
iArc;
for (iArc = 1; iArc < nArcs; ++iArc) {
rArc = disappearing[iArc];
lArc = disappearing[iArc - 1];
setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
}
lArc = disappearing[0];
rArc = disappearing[nArcs - 1];
rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
attachCircle(lArc);
attachCircle(rArc);
}
function addBeach(site) {
var x = site[0],
directrix = site[1],
lArc,
rArc,
dxl,
dxr,
node = beaches._;
while (node) {
dxl = leftBreakPoint(node, directrix) - x;
if (dxl > epsilon$3) node = node.L; else {
dxr = x - rightBreakPoint(node, directrix);
if (dxr > epsilon$3) {
if (!node.R) {
lArc = node;
break;
}
node = node.R;
} else {
if (dxl > -epsilon$3) {
lArc = node.P;
rArc = node;
} else if (dxr > -epsilon$3) {
lArc = node;
rArc = node.N;
} else {
lArc = rArc = node;
}
break;
}
}
}
createCell(site);
var newArc = createBeach(site);
beaches.insert(lArc, newArc);
if (!lArc && !rArc) return;
if (lArc === rArc) {
detachCircle(lArc);
rArc = createBeach(lArc.site);
beaches.insert(newArc, rArc);
newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
attachCircle(lArc);
attachCircle(rArc);
return;
}
if (!rArc) { // && lArc
newArc.edge = createEdge(lArc.site, newArc.site);
return;
}
// else lArc !== rArc
detachCircle(lArc);
detachCircle(rArc);
var lSite = lArc.site,
ax = lSite[0],
ay = lSite[1],
bx = site[0] - ax,
by = site[1] - ay,
rSite = rArc.site,
cx = rSite[0] - ax,
cy = rSite[1] - ay,
d = 2 * (bx * cy - by * cx),
hb = bx * bx + by * by,
hc = cx * cx + cy * cy,
vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
setEdgeEnd(rArc.edge, lSite, rSite, vertex);
newArc.edge = createEdge(lSite, site, null, vertex);
rArc.edge = createEdge(site, rSite, null, vertex);
attachCircle(lArc);
attachCircle(rArc);
}
function leftBreakPoint(arc, directrix) {
var site = arc.site,
rfocx = site[0],
rfocy = site[1],
pby2 = rfocy - directrix;
if (!pby2) return rfocx;
var lArc = arc.P;
if (!lArc) return -Infinity;
site = lArc.site;
var lfocx = site[0],
lfocy = site[1],
plby2 = lfocy - directrix;
if (!plby2) return lfocx;
var hl = lfocx - rfocx,
aby2 = 1 / pby2 - 1 / plby2,
b = hl / plby2;
if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
return (rfocx + lfocx) / 2;
}
function rightBreakPoint(arc, directrix) {
var rArc = arc.N;
if (rArc) return leftBreakPoint(rArc, directrix);
var site = arc.site;
return site[1] === directrix ? site[0] : Infinity;
}
var epsilon$3 = 1e-6;
var epsilon2$1 = 1e-12;
var beaches;
var cells;
var circles;
var edges;
function triangleArea(a, b, c) {
return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
}
function lexicographic(a, b) {
return b[1] - a[1]
|| b[0] - a[0];
}
function Diagram(sites, extent) {
var site = sites.sort(lexicographic).pop(),
x,
y,
circle;
edges = [];
cells = new Array(sites.length);
beaches = new RedBlackTree;
circles = new RedBlackTree;
while (true) {
circle = firstCircle;
if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
if (site[0] !== x || site[1] !== y) {
addBeach(site);
x = site[0], y = site[1];
}
site = sites.pop();
} else if (circle) {
removeBeach(circle.arc);
} else {
break;
}
}
sortCellHalfedges();
if (extent) {
var x0 = +extent[0][0],
y0 = +extent[0][1],
x1 = +extent[1][0],
y1 = +extent[1][1];
clipEdges(x0, y0, x1, y1);
clipCells(x0, y0, x1, y1);
}
this.edges = edges;
this.cells = cells;
beaches =
circles =
edges =
cells = null;
}
Diagram.prototype = {
constructor: Diagram,
polygons: function() {
var edges = this.edges;
return this.cells.map(function(cell) {
var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
polygon.data = cell.site.data;
return polygon;
});
},
triangles: function() {
var triangles = [],
edges = this.edges;
this.cells.forEach(function(cell, i) {
var site = cell.site,
halfedges = cell.halfedges,
j = -1,
m = halfedges.length,
s0,
e1 = edges[halfedges[m - 1]],
s1 = e1.left === site ? e1.right : e1.left;
while (++j < m) {
s0 = s1;
e1 = edges[halfedges[j]];
s1 = e1.left === site ? e1.right : e1.left;
if (i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
triangles.push([site.data, s0.data, s1.data]);
}
}
});
return triangles;
},
links: function() {
return this.edges.filter(function(edge) {
return edge.right;
}).map(function(edge) {
return {
source: edge.left.data,
target: edge.right.data
};
});
}
}
function voronoi() {
var x = x$4,
y = y$4,
extent = null;
function voronoi(data) {
return new Diagram(data.map(function(d, i) {
var s = [Math.round(x(d, i, data) / epsilon$3) * epsilon$3, Math.round(y(d, i, data) / epsilon$3) * epsilon$3];
s.index = i;
s.data = d;
return s;
}), extent);
}
voronoi.polygons = function(data) {
return voronoi(data).polygons();
};
voronoi.links = function(data) {
return voronoi(data).links();
};
voronoi.triangles = function(data) {
return voronoi(data).triangles();
};
voronoi.x = function(_) {
return arguments.length ? (x = typeof _ === "function" ? _ : constant$8(+_), voronoi) : x;
};
voronoi.y = function(_) {
return arguments.length ? (y = typeof _ === "function" ? _ : constant$8(+_), voronoi) : y;
};
voronoi.extent = function(_) {
return arguments.length ? (extent = _ == null ? null : [[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]], voronoi) : extent && [[extent[0][0], extent[0][1]], [extent[1][0], extent[1][1]]];
};
voronoi.size = function(_) {
return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0], extent[1][1]];
};
return voronoi;
}
function constant$9(x) {
return function() {
return x;
};
}
function ZoomEvent(target, type, transform) {
this.target = target;
this.type = type;
this.transform = transform;
}
function Transform(k, x, y) {
this.k = k;
this.x = x;
this.y = y;
}
Transform.prototype = {
constructor: Transform,
scale: function(k) {
return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
},
translate: function(x, y) {
return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
},
apply: function(point) {
return [point[0] * this.k + this.x, point[1] * this.k + this.y];
},
applyX: function(x) {
return x * this.k + this.x;
},
applyY: function(y) {
return y * this.k + this.y;
},
invert: function(location) {
return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
},
invertX: function(x) {
return (x - this.x) / this.k;
},
invertY: function(y) {
return (y - this.y) / this.k;
},
rescaleX: function(x) {
return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
},
rescaleY: function(y) {
return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
},
toString: function() {
return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
}
};
var identity$6 = new Transform(1, 0, 0);
transform.prototype = Transform.prototype;
function transform(node) {
return node.__zoom || identity$6;
}
function nopropagation$1() {
exports.event.stopImmediatePropagation();
}
function noevent$1() {
exports.event.preventDefault();
exports.event.stopImmediatePropagation();
}
// Ignore right-click, since that should open the context menu.
function defaultFilter$1() {
return !exports.event.button;
}
function defaultExtent() {
var e = this, w, h;
if (e instanceof SVGElement) {
e = e.ownerSVGElement || e;
w = e.width.baseVal.value;
h = e.height.baseVal.value;
} else {
w = e.clientWidth;
h = e.clientHeight;
}
return [[0, 0], [w, h]];
}
function defaultTransform() {
return this.__zoom || identity$6;
}
function zoom() {
var filter = defaultFilter$1,
extent = defaultExtent,
k0 = 0,
k1 = Infinity,
x0 = -k1,
x1 = k1,
y0 = x0,
y1 = x1,
duration = 250,
gestures = [],
listeners = dispatch("start", "zoom", "end"),
mousemoving,
mousePoint,
mouseLocation,
touchstarting,
touchending,
touchDelay = 500,
wheelTimer,
wheelDelay = 150;
function zoom(selection) {
selection
.on("wheel.zoom", wheeled)
.on("mousedown.zoom", mousedowned)
.on("dblclick.zoom", dblclicked)
.on("touchstart.zoom", touchstarted)
.on("touchmove.zoom", touchmoved)
.on("touchend.zoom touchcancel.zoom", touchended)
.style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
.property("__zoom", defaultTransform);
}
zoom.transform = function(collection, transform) {
var selection = collection.selection ? collection.selection() : collection;
selection.property("__zoom", defaultTransform);
if (collection !== selection) {
schedule(collection, transform);
} else {
selection.interrupt().each(function() {
gesture(this, arguments)
.start()
.zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform)
.end();
});
}
};
zoom.scaleBy = function(selection, k) {
zoom.scaleTo(selection, function() {
var k0 = this.__zoom.k,
k1 = typeof k === "function" ? k.apply(this, arguments) : k;
return k0 * k1;
});
};
zoom.scaleTo = function(selection, k) {
zoom.transform(selection, function() {
var e = extent.apply(this, arguments),
t0 = this.__zoom,
p0 = centroid(e),
p1 = t0.invert(p0),
k1 = typeof k === "function" ? k.apply(this, arguments) : k;
return constrain(translate(scale(t0, k1), p0, p1), e);
});
};
zoom.translateBy = function(selection, x, y) {
zoom.transform(selection, function() {
return constrain(this.__zoom.translate(
typeof x === "function" ? x.apply(this, arguments) : x,
typeof y === "function" ? y.apply(this, arguments) : y
), extent.apply(this, arguments));
});
};
function scale(transform, k) {
k = Math.max(k0, Math.min(k1, k));
return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
}
function translate(transform, p0, p1) {
var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k;
return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
}
function constrain(transform, extent) {
var dx = Math.min(0, transform.invertX(extent[0][0]) - x0) || Math.max(0, transform.invertX(extent[1][0]) - x1),
dy = Math.min(0, transform.invertY(extent[0][1]) - y0) || Math.max(0, transform.invertY(extent[1][1]) - y1);
return dx || dy ? transform.translate(dx, dy) : transform;
}
function centroid(extent) {
return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
}
function schedule(transition, transform, center) {
transition
.on("start.zoom", function() { gesture(this, arguments).start(); })
.on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
.tween("zoom", function() {
var that = this,
args = arguments,
g = gesture(that, args),
e = extent.apply(that, args),
p = center || centroid(e),
w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
a = that.__zoom,
b = typeof transform === "function" ? transform.apply(that, args) : transform,
i = interpolateZoom(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
return function(t) {
if (t === 1) t = b; // Avoid rounding error on end.
else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }
g.zoom(null, t);
};
});
}
function gesture(that, args) {
for (var i = 0, n = gestures.length, g; i < n; ++i) {
if ((g = gestures[i]).that === that) {
return g;
}
}
return new Gesture(that, args);
}
function Gesture(that, args) {
this.that = that;
this.args = args;
this.index = -1;
this.active = 0;
}
Gesture.prototype = {
start: function() {
if (++this.active === 1) {
this.index = gestures.push(this) - 1;
this.emit("start");
}
return this;
},
zoom: function(key, transform) {
if (mousePoint && key !== "mouse") mouseLocation = transform.invert(mousePoint);
if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
this.that.__zoom = transform;
this.emit("zoom");
return this;
},
end: function() {
if (--this.active === 0) {
gestures.splice(this.index, 1);
mousePoint = mouseLocation = null;
this.index = -1;
this.emit("end");
}
return this;
},
emit: function(type) {
customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
}
};
function wheeled() {
if (!filter.apply(this, arguments)) return;
var g = gesture(this, arguments),
t = this.__zoom,
k = Math.max(k0, Math.min(k1, t.k * Math.pow(2, -exports.event.deltaY * (exports.event.deltaMode ? 120 : 1) / 500)));
// If the mouse is in the same location as before, reuse it.
// If there were recent wheel events, reset the wheel idle timeout.
if (wheelTimer) {
var point = mouse(this);
if (mousePoint[0] !== point[0] || mousePoint[1] !== point[1]) {
mouseLocation = t.invert(mousePoint = point);
}
clearTimeout(wheelTimer);
}
// If this wheel event won’t trigger a transform change, ignore it.
else if (t.k === k) return;
// Otherwise, capture the mouse point and location at the start.
else {
g.extent = extent.apply(this, arguments);
mouseLocation = t.invert(mousePoint = mouse(this));
interrupt(this);
g.start();
}
noevent$1();
wheelTimer = setTimeout(wheelidled, wheelDelay);
g.zoom("mouse", constrain(translate(scale(t, k), mousePoint, mouseLocation), g.extent));
function wheelidled() {
wheelTimer = null;
g.end();
}
}
function mousedowned() {
if (touchending || !filter.apply(this, arguments)) return;
var g = gesture(this, arguments),
v = select(exports.event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true);
dragDisable(exports.event.view);
nopropagation$1();
mousemoving = false;
g.extent = extent.apply(this, arguments);
mouseLocation = this.__zoom.invert(mousePoint = mouse(this));
interrupt(this);
g.start();
function mousemoved() {
noevent$1();
mousemoving = true;
g.zoom("mouse", constrain(translate(g.that.__zoom, mousePoint = mouse(g.that), mouseLocation), g.extent));
}
function mouseupped() {
v.on("mousemove.zoom mouseup.zoom", null);
dragEnable(exports.event.view, mousemoving);
noevent$1();
g.end();
}
}
function dblclicked() {
if (!filter.apply(this, arguments)) return;
var t0 = this.__zoom,
p0 = mouse(this),
p1 = t0.invert(p0),
k1 = t0.k * (exports.event.shiftKey ? 0.5 : 2),
t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments));
noevent$1();
if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
else select(this).call(zoom.transform, t1);
}
function touchstarted() {
if (!filter.apply(this, arguments)) return;
var g = gesture(this, arguments),
touches = exports.event.changedTouches,
n = touches.length, i, t, p;
nopropagation$1();
for (i = 0; i < n; ++i) {
t = touches[i], p = touch(this, touches, t.identifier);
p = [p, this.__zoom.invert(p), t.identifier];
if (!g.touch0) g.touch0 = p;
else if (!g.touch1) g.touch1 = p;
}
if (touchstarting) {
touchstarting = clearTimeout(touchstarting);
if (!g.touch1) return g.end(), dblclicked.apply(this, arguments);
}
if (exports.event.touches.length === n) {
touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
interrupt(this);
g.extent = extent.apply(this, arguments);
g.start();
}
}
function touchmoved() {
var g = gesture(this, arguments),
touches = exports.event.changedTouches,
n = touches.length, i, t, p, l;
noevent$1();
if (touchstarting) touchstarting = clearTimeout(touchstarting);
for (i = 0; i < n; ++i) {
t = touches[i], p = touch(this, touches, t.identifier);
if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
}
t = g.that.__zoom;
if (g.touch1) {
var p0 = g.touch0[0], l0 = g.touch0[1],
p1 = g.touch1[0], l1 = g.touch1[1],
dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
t = scale(t, Math.sqrt(dp / dl));
p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
}
else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
else return;
g.zoom("touch", constrain(translate(t, p, l), g.extent));
}
function touchended() {
var g = gesture(this, arguments),
touches = exports.event.changedTouches,
n = touches.length, i, t;
nopropagation$1();
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() { touchending = null; }, touchDelay);
for (i = 0; i < n; ++i) {
t = touches[i];
if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
}
if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
if (!g.touch0) g.end();
}
zoom.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant$9(!!_), zoom) : filter;
};
zoom.extent = function(_) {
return arguments.length ? (extent = typeof _ === "function" ? _ : constant$9([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
};
zoom.scaleExtent = function(_) {
return arguments.length ? (k0 = +_[0], k1 = +_[1], zoom) : [k0, k1];
};
zoom.translateExtent = function(_) {
return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], zoom) : [[x0, y0], [x1, y1]];
};
zoom.duration = function(_) {
return arguments.length ? (duration = +_, zoom) : duration;
};
zoom.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? zoom : value;
};
return zoom;
}
function constant$10(x) {
return function() {
return x;
};
}
function BrushEvent(target, type, selection) {
this.target = target;
this.type = type;
this.selection = selection;
}
function nopropagation$2() {
exports.event.stopImmediatePropagation();
}
function noevent$2() {
exports.event.preventDefault();
exports.event.stopImmediatePropagation();
}
var MODE_DRAG = {name: "drag"};
var MODE_SPACE = {name: "space"};
var MODE_HANDLE = {name: "handle"};
var MODE_CENTER = {name: "center"};
var X = {
name: "x",
handles: ["e", "w"].map(type$1),
input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; },
output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
};
var Y = {
name: "y",
handles: ["n", "s"].map(type$1),
input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; },
output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
};
var XY = {
name: "xy",
handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type$1),
input: function(xy) { return xy; },
output: function(xy) { return xy; }
};
var cursors = {
overlay: "crosshair",
selection: "move",
n: "ns-resize",
e: "ew-resize",
s: "ns-resize",
w: "ew-resize",
nw: "nwse-resize",
ne: "nesw-resize",
se: "nwse-resize",
sw: "nesw-resize"
};
var flipX = {
e: "w",
w: "e",
nw: "ne",
ne: "nw",
se: "sw",
sw: "se"
};
var flipY = {
n: "s",
s: "n",
nw: "sw",
ne: "se",
se: "ne",
sw: "nw"
};
var signsX = {
overlay: +1,
selection: +1,
n: null,
e: +1,
s: null,
w: -1,
nw: -1,
ne: +1,
se: +1,
sw: -1
};
var signsY = {
overlay: +1,
selection: +1,
n: -1,
e: null,
s: +1,
w: null,
nw: -1,
ne: -1,
se: +1,
sw: +1
};
function type$1(t) {
return {type: t};
}
// Ignore right-click, since that should open the context menu.
function defaultFilter$2() {
return !exports.event.button;
}
function defaultExtent$1() {
var svg = this.ownerSVGElement || this;
return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
}
// Like d3.local, but with the name “__brush” rather than auto-generated.
function local$1(node) {
while (!node.__brush) if (!(node = node.parentNode)) return;
return node.__brush;
}
function empty$1(extent) {
return extent[0][0] === extent[1][0]
|| extent[0][1] === extent[1][1];
}
function brushSelection(node) {
var state = node.__brush;
return state ? state.dim.output(state.selection) : null;
}
function brushX() {
return brush$1(X);
}
function brushY() {
return brush$1(Y);
}
function brush() {
return brush$1(XY);
}
function brush$1(dim) {
var extent = defaultExtent$1,
filter = defaultFilter$2,
listeners = dispatch(brush, "start", "brush", "end"),
handleSize = 6,
touchending;
function brush(group) {
var overlay = group
.property("__brush", initialize)
.selectAll(".overlay")
.data([type$1("overlay")]);
overlay.enter().append("rect")
.attr("class", "overlay")
.attr("pointer-events", "all")
.attr("cursor", cursors.overlay)
.merge(overlay)
.each(function() {
var extent = local$1(this).extent;
select(this)
.attr("x", extent[0][0])
.attr("y", extent[0][1])
.attr("width", extent[1][0] - extent[0][0])
.attr("height", extent[1][1] - extent[0][1]);
});
group.selectAll(".selection")
.data([type$1("selection")])
.enter().append("rect")
.attr("class", "selection")
.attr("cursor", cursors.selection)
.attr("fill", "#777")
.attr("fill-opacity", 0.3)
.attr("stroke", "#fff")
.attr("shape-rendering", "crispEdges");
var handle = group.selectAll(".handle")
.data(dim.handles, function(d) { return d.type; });
handle.exit().remove();
handle.enter().append("rect")
.attr("class", function(d) { return "handle handle--" + d.type; })
.attr("cursor", function(d) { return cursors[d.type]; });
group
.each(redraw)
.attr("fill", "none")
.attr("pointer-events", "all")
.style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
.on("mousedown.brush touchstart.brush", started);
}
brush.move = function(group, selection) {
if (group.selection) {
group
.on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
.on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
.tween("brush", function() {
var that = this,
state = that.__brush,
emit = emitter(that, arguments),
selection0 = state.selection,
selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent),
i = interpolate(selection0, selection1);
function tween(t) {
state.selection = t === 1 && empty$1(selection1) ? null : i(t);
redraw.call(that);
emit.brush();
}
return selection0 && selection1 ? tween : tween(1);
});
} else {
group
.each(function() {
var that = this,
args = arguments,
state = that.__brush,
selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent),
emit = emitter(that, args).beforestart();
interrupt(that);
state.selection = selection1 == null || empty$1(selection1) ? null : selection1;
redraw.call(that);
emit.start().brush().end();
});
}
};
function redraw() {
var group = select(this),
selection = local$1(this).selection;
if (selection) {
group.selectAll(".selection")
.style("display", null)
.attr("x", selection[0][0])
.attr("y", selection[0][1])
.attr("width", selection[1][0] - selection[0][0])
.attr("height", selection[1][1] - selection[0][1]);
group.selectAll(".handle")
.style("display", null)
.attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; })
.attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; })
.attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; })
.attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; });
}
else {
group.selectAll(".selection,.handle")
.style("display", "none")
.attr("x", null)
.attr("y", null)
.attr("width", null)
.attr("height", null);
}
}
function emitter(that, args) {
return that.__brush.emitter || new Emitter(that, args);
}
function Emitter(that, args) {
this.that = that;
this.args = args;
this.state = that.__brush;
this.active = 0;
}
Emitter.prototype = {
beforestart: function() {
if (++this.active === 1) this.state.emitter = this, this.starting = true;
return this;
},
start: function() {
if (this.starting) this.starting = false, this.emit("start");
return this;
},
brush: function() {
this.emit("brush");
return this;
},
end: function() {
if (--this.active === 0) delete this.state.emitter, this.emit("end");
return this;
},
emit: function(type) {
customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
}
};
function started() {
if (exports.event.touches) { if (exports.event.changedTouches.length < exports.event.touches.length) return noevent$2(); }
else if (touchending) return;
if (!filter.apply(this, arguments)) return;
var that = this,
type = exports.event.target.__data__.type,
mode = (exports.event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (exports.event.altKey ? MODE_CENTER : MODE_HANDLE),
signX = dim === Y ? null : signsX[type],
signY = dim === X ? null : signsY[type],
state = local$1(that),
extent = state.extent,
selection = state.selection,
W = extent[0][0], w0, w1,
N = extent[0][1], n0, n1,
E = extent[1][0], e0, e1,
S = extent[1][1], s0, s1,
dx,
dy,
moving,
shifting = signX && signY && exports.event.shiftKey,
lockX,
lockY,
point0 = mouse(that),
point = point0,
emit = emitter(that, arguments).beforestart();
if (type === "overlay") {
state.selection = selection = [
[w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
[e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
];
} else {
w0 = selection[0][0];
n0 = selection[0][1];
e0 = selection[1][0];
s0 = selection[1][1];
}
w1 = w0;
n1 = n0;
e1 = e0;
s1 = s0;
var group = select(that)
.attr("pointer-events", "none");
var overlay = group.selectAll(".overlay")
.attr("cursor", cursors[type]);
if (exports.event.touches) {
group
.on("touchmove.brush", moved, true)
.on("touchend.brush touchcancel.brush", ended, true);
} else {
var view = select(exports.event.view)
.on("keydown.brush", keydowned, true)
.on("keyup.brush", keyupped, true)
.on("mousemove.brush", moved, true)
.on("mouseup.brush", ended, true);
dragDisable(exports.event.view);
}
nopropagation$2();
interrupt(that);
redraw.call(that);
emit.start();
function moved() {
var point1 = mouse(that);
if (shifting && !lockX && !lockY) {
if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
else lockX = true;
}
point = point1;
moving = true;
noevent$2();
move();
}
function move() {
var t;
dx = point[0] - point0[0];
dy = point[1] - point0[1];
switch (mode) {
case MODE_SPACE:
case MODE_DRAG: {
if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
break;
}
case MODE_HANDLE: {
if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
break;
}
case MODE_CENTER: {
if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
break;
}
}
if (e1 < w1) {
signX *= -1;
t = w0, w0 = e0, e0 = t;
t = w1, w1 = e1, e1 = t;
if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
}
if (s1 < n1) {
signY *= -1;
t = n0, n0 = s0, s0 = t;
t = n1, n1 = s1, s1 = t;
if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
}
selection = state.selection; // May be set by brush.move!
if (lockX) w1 = selection[0][0], e1 = selection[1][0];
if (lockY) n1 = selection[0][1], s1 = selection[1][1];
if (selection[0][0] !== w1
|| selection[0][1] !== n1
|| selection[1][0] !== e1
|| selection[1][1] !== s1) {
state.selection = [[w1, n1], [e1, s1]];
redraw.call(that);
emit.brush();
}
}
function ended() {
nopropagation$2();
if (exports.event.touches) {
if (exports.event.touches.length) return;
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
group.on("touchmove.brush touchend.brush touchcancel.brush", null);
} else {
dragEnable(exports.event.view, moving);
view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
}
group.attr("pointer-events", "all");
overlay.attr("cursor", cursors.overlay);
if (empty$1(selection)) state.selection = null, redraw.call(that);
emit.end();
}
function keydowned() {
switch (exports.event.keyCode) {
case 16: { // SHIFT
shifting = signX && signY;
break;
}
case 18: { // ALT
if (mode === MODE_HANDLE) {
if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
mode = MODE_CENTER;
move();
}
break;
}
case 32: { // SPACE; takes priority over ALT
if (mode === MODE_HANDLE || mode === MODE_CENTER) {
if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
mode = MODE_SPACE;
overlay.attr("cursor", cursors.selection);
move();
}
break;
}
default: return;
}
noevent$2();
}
function keyupped() {
switch (exports.event.keyCode) {
case 16: { // SHIFT
if (shifting) {
lockX = lockY = shifting = false;
move();
}
break;
}
case 18: { // ALT
if (mode === MODE_CENTER) {
if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
mode = MODE_HANDLE;
move();
}
break;
}
case 32: { // SPACE
if (mode === MODE_SPACE) {
if (exports.event.altKey) {
if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
mode = MODE_CENTER;
} else {
if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
mode = MODE_HANDLE;
}
overlay.attr("cursor", cursors[type]);
move();
}
break;
}
default: return;
}
noevent$2();
}
}
function initialize() {
var state = this.__brush || {selection: null};
state.extent = extent.apply(this, arguments);
state.dim = dim;
return state;
}
brush.extent = function(_) {
return arguments.length ? (extent = typeof _ === "function" ? _ : constant$10([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent;
};
brush.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant$10(!!_), brush) : filter;
};
brush.handleSize = function(_) {
return arguments.length ? (handleSize = +_, brush) : handleSize;
};
brush.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? brush : value;
};
return brush;
}
var cos = Math.cos;
var sin = Math.sin;
var pi$3 = Math.PI;
var halfPi$2 = pi$3 / 2;
var tau$3 = pi$3 * 2;
var max$1 = Math.max;
function compareValue(compare) {
return function(a, b) {
return compare(
a.source.value + a.target.value,
b.source.value + b.target.value
);
};
}
function chord() {
var padAngle = 0,
sortGroups = null,
sortSubgroups = null,
sortChords = null;
function chord(matrix) {
var n = matrix.length,
groupSums = [],
groupIndex = range(n),
subgroupIndex = [],
chords = [],
groups = chords.groups = new Array(n),
subgroups = new Array(n * n),
k,
x,
x0,
dx,
i,
j;
// Compute the sum.
k = 0, i = -1; while (++i < n) {
x = 0, j = -1; while (++j < n) {
x += matrix[i][j];
}
groupSums.push(x);
subgroupIndex.push(range(n));
k += x;
}
// Sort groups…
if (sortGroups) groupIndex.sort(function(a, b) {
return sortGroups(groupSums[a], groupSums[b]);
});
// Sort subgroups…
if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
d.sort(function(a, b) {
return sortSubgroups(matrix[i][a], matrix[i][b]);
});
});
// Convert the sum to scaling factor for [0, 2pi].
// TODO Allow start and end angle to be specified?
// TODO Allow padding to be specified as percentage?
k = max$1(0, tau$3 - padAngle * n) / k;
dx = k ? padAngle : tau$3 / n;
// Compute the start and end angle for each group and subgroup.
// Note: Opera has a bug reordering object literal properties!
x = 0, i = -1; while (++i < n) {
x0 = x, j = -1; while (++j < n) {
var di = groupIndex[i],
dj = subgroupIndex[di][j],
v = matrix[di][dj],
a0 = x,
a1 = x += v * k;
subgroups[dj * n + di] = {
index: di,
subindex: dj,
startAngle: a0,
endAngle: a1,
value: v
};
}
groups[di] = {
index: di,
startAngle: x0,
endAngle: x,
value: groupSums[di]
};
x += dx;
}
// Generate chords for each (non-empty) subgroup-subgroup link.
i = -1; while (++i < n) {
j = i - 1; while (++j < n) {
var source = subgroups[j * n + i],
target = subgroups[i * n + j];
if (source.value || target.value) {
chords.push(source.value < target.value
? {source: target, target: source}
: {source: source, target: target});
}
}
}
return sortChords ? chords.sort(sortChords) : chords;
}
chord.padAngle = function(_) {
return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle;
};
chord.sortGroups = function(_) {
return arguments.length ? (sortGroups = _, chord) : sortGroups;
};
chord.sortSubgroups = function(_) {
return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
};
chord.sortChords = function(_) {
return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
};
return chord;
}
var slice$5 = Array.prototype.slice;
function constant$11(x) {
return function() {
return x;
};
}
function defaultSource(d) {
return d.source;
}
function defaultTarget(d) {
return d.target;
}
function defaultRadius$1(d) {
return d.radius;
}
function defaultStartAngle(d) {
return d.startAngle;
}
function defaultEndAngle(d) {
return d.endAngle;
}
function ribbon() {
var source = defaultSource,
target = defaultTarget,
radius = defaultRadius$1,
startAngle = defaultStartAngle,
endAngle = defaultEndAngle,
context = null;
function ribbon() {
var buffer,
argv = slice$5.call(arguments),
s = source.apply(this, argv),
t = target.apply(this, argv),
sr = +radius.apply(this, (argv[0] = s, argv)),
sa0 = startAngle.apply(this, argv) - halfPi$2,
sa1 = endAngle.apply(this, argv) - halfPi$2,
sx0 = sr * cos(sa0),
sy0 = sr * sin(sa0),
tr = +radius.apply(this, (argv[0] = t, argv)),
ta0 = startAngle.apply(this, argv) - halfPi$2,
ta1 = endAngle.apply(this, argv) - halfPi$2;
if (!context) context = buffer = path();
context.moveTo(sx0, sy0);
context.arc(0, 0, sr, sa0, sa1);
if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
context.arc(0, 0, tr, ta0, ta1);
}
context.quadraticCurveTo(0, 0, sx0, sy0);
context.closePath();
if (buffer) return context = null, buffer + "" || null;
}
ribbon.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant$11(+_), ribbon) : radius;
};
ribbon.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$11(+_), ribbon) : startAngle;
};
ribbon.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$11(+_), ribbon) : endAngle;
};
ribbon.source = function(_) {
return arguments.length ? (source = _, ribbon) : source;
};
ribbon.target = function(_) {
return arguments.length ? (target = _, ribbon) : target;
};
ribbon.context = function(_) {
return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
};
return ribbon;
}
// Adds floating point numbers with twice the normal precision.
// Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
// Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
// 305–363 (1997).
// Code adapted from GeographicLib by Charles F. F. Karney,
// http://geographiclib.sourceforge.net/
function adder() {
return new Adder;
}
function Adder() {
this.reset();
}
Adder.prototype = {
constructor: Adder,
reset: function() {
this.s = // rounded value
this.t = 0; // exact error
},
add: function(y) {
add$1(temp, y, this.t);
add$1(this, temp.s, this.s);
if (this.s) this.t += temp.t;
else this.s = temp.t;
},
valueOf: function() {
return this.s;
}
};
var temp = new Adder;
function add$1(adder, a, b) {
var x = adder.s = a + b,
bv = x - a,
av = x - bv;
adder.t = (a - av) + (b - bv);
}
var epsilon$4 = 1e-6;
var epsilon2$2 = 1e-12;
var pi$4 = Math.PI;
var halfPi$3 = pi$4 / 2;
var quarterPi = pi$4 / 4;
var tau$4 = pi$4 * 2;
var degrees$1 = 180 / pi$4;
var radians = pi$4 / 180;
var abs = Math.abs;
var atan = Math.atan;
var atan2 = Math.atan2;
var cos$1 = Math.cos;
var ceil = Math.ceil;
var exp = Math.exp;
var log$1 = Math.log;
var pow$1 = Math.pow;
var sin$1 = Math.sin;
var sign$1 = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
var sqrt$1 = Math.sqrt;
var tan = Math.tan;
function acos(x) {
return x > 1 ? 0 : x < -1 ? pi$4 : Math.acos(x);
}
function asin$1(x) {
return x > 1 ? halfPi$3 : x < -1 ? -halfPi$3 : Math.asin(x);
}
function haversin(x) {
return (x = sin$1(x / 2)) * x;
}
function noop$2() {}
function streamGeometry(geometry, stream) {
if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
streamGeometryType[geometry.type](geometry, stream);
}
}
var streamObjectType = {
Feature: function(feature, stream) {
streamGeometry(feature.geometry, stream);
},
FeatureCollection: function(object, stream) {
var features = object.features, i = -1, n = features.length;
while (++i < n) streamGeometry(features[i].geometry, stream);
}
};
var streamGeometryType = {
Sphere: function(object, stream) {
stream.sphere();
},
Point: function(object, stream) {
object = object.coordinates;
stream.point(object[0], object[1], object[2]);
},
MultiPoint: function(object, stream) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
},
LineString: function(object, stream) {
streamLine(object.coordinates, stream, 0);
},
MultiLineString: function(object, stream) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) streamLine(coordinates[i], stream, 0);
},
Polygon: function(object, stream) {
streamPolygon(object.coordinates, stream);
},
MultiPolygon: function(object, stream) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) streamPolygon(coordinates[i], stream);
},
GeometryCollection: function(object, stream) {
var geometries = object.geometries, i = -1, n = geometries.length;
while (++i < n) streamGeometry(geometries[i], stream);
}
};
function streamLine(coordinates, stream, closed) {
var i = -1, n = coordinates.length - closed, coordinate;
stream.lineStart();
while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
stream.lineEnd();
}
function streamPolygon(coordinates, stream) {
var i = -1, n = coordinates.length;
stream.polygonStart();
while (++i < n) streamLine(coordinates[i], stream, 1);
stream.polygonEnd();
}
function stream(object, stream) {
if (object && streamObjectType.hasOwnProperty(object.type)) {
streamObjectType[object.type](object, stream);
} else {
streamGeometry(object, stream);
}
}
var areaRingSum;
var areaSum;
var lambda00;
var phi00;
var lambda0;
var cosPhi0;
var sinPhi0;
var areaStream = {
point: noop$2,
lineStart: noop$2,
lineEnd: noop$2,
polygonStart: function() {
areaRingSum.reset();
areaStream.lineStart = areaRingStart;
areaStream.lineEnd = areaRingEnd;
},
polygonEnd: function() {
var areaRing = +areaRingSum;
areaSum.add(areaRing < 0 ? tau$4 + areaRing : areaRing);
this.lineStart = this.lineEnd = this.point = noop$2;
},
sphere: function() {
areaSum.add(tau$4);
}
};
function areaRingStart() {
areaStream.point = areaPointFirst;
}
function areaRingEnd() {
areaPoint(lambda00, phi00);
}
function areaPointFirst(lambda, phi) {
areaStream.point = areaPoint;
lambda00 = lambda, phi00 = phi;
lambda *= radians, phi *= radians;
lambda0 = lambda, cosPhi0 = cos$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(phi);
}
function areaPoint(lambda, phi) {
lambda *= radians, phi *= radians;
phi = phi / 2 + quarterPi; // half the angular distance from south pole
// Spherical excess E for a spherical triangle with vertices: south pole,
// previous point, current point. Uses a formula derived from Cagnoli’s
// theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
var dLambda = lambda - lambda0,
sdLambda = dLambda >= 0 ? 1 : -1,
adLambda = sdLambda * dLambda,
cosPhi = cos$1(phi),
sinPhi = sin$1(phi),
k = sinPhi0 * sinPhi,
u = cosPhi0 * cosPhi + k * cos$1(adLambda),
v = k * sdLambda * sin$1(adLambda);
areaRingSum.add(atan2(v, u));
// Advance the previous points.
lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
}
function area$2(object) {
if (areaSum) areaSum.reset();
else areaSum = adder(), areaRingSum = adder();
stream(object, areaStream);
return areaSum * 2;
}
function spherical(cartesian) {
return [atan2(cartesian[1], cartesian[0]), asin$1(cartesian[2])];
}
function cartesian(spherical) {
var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi);
return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)];
}
function cartesianDot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
function cartesianCross(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]];
}
// TODO return a
function cartesianAddInPlace(a, b) {
a[0] += b[0], a[1] += b[1], a[2] += b[2];
}
function cartesianScale(vector, k) {
return [vector[0] * k, vector[1] * k, vector[2] * k];
}
// TODO return d
function cartesianNormalizeInPlace(d) {
var l = sqrt$1(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
d[0] /= l, d[1] /= l, d[2] /= l;
}
var lambda0$1;
var phi0;
var lambda1;
var phi1;
var lambda2;
var lambda00$1;
var phi00$1;
var p0;
var deltaSum;
var ranges;
var range$1;
var boundsStream = {
point: boundsPoint,
lineStart: boundsLineStart,
lineEnd: boundsLineEnd,
polygonStart: function() {
boundsStream.point = boundsRingPoint;
boundsStream.lineStart = boundsRingStart;
boundsStream.lineEnd = boundsRingEnd;
deltaSum.reset();
areaStream.polygonStart();
},
polygonEnd: function() {
areaStream.polygonEnd();
boundsStream.point = boundsPoint;
boundsStream.lineStart = boundsLineStart;
boundsStream.lineEnd = boundsLineEnd;
if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
else if (deltaSum > epsilon$4) phi1 = 90;
else if (deltaSum < -epsilon$4) phi0 = -90;
range$1[0] = lambda0$1, range$1[1] = lambda1;
}
};
function boundsPoint(lambda, phi) {
ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
if (phi < phi0) phi0 = phi;
if (phi > phi1) phi1 = phi;
}
function linePoint(lambda, phi) {
var p = cartesian([lambda * radians, phi * radians]);
if (p0) {
var normal = cartesianCross(p0, p),
equatorial = [normal[1], -normal[0], 0],
inflection = cartesianCross(equatorial, normal);
cartesianNormalizeInPlace(inflection);
inflection = spherical(inflection);
var delta = lambda - lambda2,
sign = delta > 0 ? 1 : -1,
lambdai = inflection[0] * degrees$1 * sign,
phii,
antimeridian = abs(delta) > 180;
if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
phii = inflection[1] * degrees$1;
if (phii > phi1) phi1 = phii;
} else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
phii = -inflection[1] * degrees$1;
if (phii < phi0) phi0 = phii;
} else {
if (phi < phi0) phi0 = phi;
if (phi > phi1) phi1 = phi;
}
if (antimeridian) {
if (lambda < lambda2) {
if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
} else {
if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
}
} else {
if (lambda1 >= lambda0$1) {
if (lambda < lambda0$1) lambda0$1 = lambda;
if (lambda > lambda1) lambda1 = lambda;
} else {
if (lambda > lambda2) {
if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
} else {
if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
}
}
}
} else {
boundsPoint(lambda, phi);
}
p0 = p, lambda2 = lambda;
}
function boundsLineStart() {
boundsStream.point = linePoint;
}
function boundsLineEnd() {
range$1[0] = lambda0$1, range$1[1] = lambda1;
boundsStream.point = boundsPoint;
p0 = null;
}
function boundsRingPoint(lambda, phi) {
if (p0) {
var delta = lambda - lambda2;
deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
} else {
lambda00$1 = lambda, phi00$1 = phi;
}
areaStream.point(lambda, phi);
linePoint(lambda, phi);
}
function boundsRingStart() {
areaStream.lineStart();
}
function boundsRingEnd() {
boundsRingPoint(lambda00$1, phi00$1);
areaStream.lineEnd();
if (abs(deltaSum) > epsilon$4) lambda0$1 = -(lambda1 = 180);
range$1[0] = lambda0$1, range$1[1] = lambda1;
p0 = null;
}
// Finds the left-right distance between two longitudes.
// This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
// the distance between ±180° to be 360°.
function angle(lambda0, lambda1) {
return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
}
function rangeCompare(a, b) {
return a[0] - b[0];
}
function rangeContains(range, x) {
return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
}
function bounds(feature) {
var i, n, a, b, merged, deltaMax, delta;
if (deltaSum) deltaSum.reset();
else deltaSum = adder();
phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
ranges = [];
stream(feature, boundsStream);
// First, sort ranges by their minimum longitudes.
if (n = ranges.length) {
ranges.sort(rangeCompare);
// Then, merge any ranges that overlap.
for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
b = ranges[i];
if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
} else {
merged.push(a = b);
}
}
// Finally, find the largest gap between the merged ranges.
// The final bounding box will be the inverse of this gap.
for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
b = merged[i];
if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
}
}
ranges = range$1 = null;
return lambda0$1 === Infinity || phi0 === Infinity
? [[NaN, NaN], [NaN, NaN]]
: [[lambda0$1, phi0], [lambda1, phi1]];
}
var W0;
var W1;
var X0;
var Y0;
var Z0;
var X1;
var Y1;
var Z1;
var X2;
var Y2;
var Z2;
var lambda00$2;
var phi00$2;
var x0;
var y0;
var z0;
// previous point
var centroidStream = {
sphere: noop$2,
point: centroidPoint,
lineStart: centroidLineStart,
lineEnd: centroidLineEnd,
polygonStart: function() {
centroidStream.lineStart = centroidRingStart;
centroidStream.lineEnd = centroidRingEnd;
},
polygonEnd: function() {
centroidStream.lineStart = centroidLineStart;
centroidStream.lineEnd = centroidLineEnd;
}
};
// Arithmetic mean of Cartesian vectors.
function centroidPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos$1(phi);
centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi));
}
function centroidPointCartesian(x, y, z) {
++W0;
X0 += (x - X0) / W0;
Y0 += (y - Y0) / W0;
Z0 += (z - Z0) / W0;
}
function centroidLineStart() {
centroidStream.point = centroidLinePointFirst;
}
function centroidLinePointFirst(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos$1(phi);
x0 = cosPhi * cos$1(lambda);
y0 = cosPhi * sin$1(lambda);
z0 = sin$1(phi);
centroidStream.point = centroidLinePoint;
centroidPointCartesian(x0, y0, z0);
}
function centroidLinePoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos$1(phi),
x = cosPhi * cos$1(lambda),
y = cosPhi * sin$1(lambda),
z = sin$1(phi),
w = atan2(sqrt$1((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
W1 += w;
X1 += w * (x0 + (x0 = x));
Y1 += w * (y0 + (y0 = y));
Z1 += w * (z0 + (z0 = z));
centroidPointCartesian(x0, y0, z0);
}
function centroidLineEnd() {
centroidStream.point = centroidPoint;
}
// See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
// J. Applied Mechanics 42, 239 (1975).
function centroidRingStart() {
centroidStream.point = centroidRingPointFirst;
}
function centroidRingEnd() {
centroidRingPoint(lambda00$2, phi00$2);
centroidStream.point = centroidPoint;
}
function centroidRingPointFirst(lambda, phi) {
lambda00$2 = lambda, phi00$2 = phi;
lambda *= radians, phi *= radians;
centroidStream.point = centroidRingPoint;
var cosPhi = cos$1(phi);
x0 = cosPhi * cos$1(lambda);
y0 = cosPhi * sin$1(lambda);
z0 = sin$1(phi);
centroidPointCartesian(x0, y0, z0);
}
function centroidRingPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos$1(phi),
x = cosPhi * cos$1(lambda),
y = cosPhi * sin$1(lambda),
z = sin$1(phi),
cx = y0 * z - z0 * y,
cy = z0 * x - x0 * z,
cz = x0 * y - y0 * x,
m = sqrt$1(cx * cx + cy * cy + cz * cz),
u = x0 * x + y0 * y + z0 * z,
v = m && -acos(u) / m, // area weight
w = atan2(m, u); // line weight
X2 += v * cx;
Y2 += v * cy;
Z2 += v * cz;
W1 += w;
X1 += w * (x0 + (x0 = x));
Y1 += w * (y0 + (y0 = y));
Z1 += w * (z0 + (z0 = z));
centroidPointCartesian(x0, y0, z0);
}
function centroid$1(object) {
W0 = W1 =
X0 = Y0 = Z0 =
X1 = Y1 = Z1 =
X2 = Y2 = Z2 = 0;
stream(object, centroidStream);
var x = X2,
y = Y2,
z = Z2,
m = x * x + y * y + z * z;
// If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
if (m < epsilon2$2) {
x = X1, y = Y1, z = Z1;
// If the feature has zero length, fall back to arithmetic mean of point vectors.
if (W1 < epsilon$4) x = X0, y = Y0, z = Z0;
m = x * x + y * y + z * z;
// If the feature still has an undefined ccentroid, then return.
if (m < epsilon2$2) return [NaN, NaN];
}
return [atan2(y, x) * degrees$1, asin$1(z / sqrt$1(m)) * degrees$1];
}
function constant$12(x) {
return function() {
return x;
};
}
function compose(a, b) {
function compose(x, y) {
return x = a(x, y), b(x[0], x[1]);
}
if (a.invert && b.invert) compose.invert = function(x, y) {
return x = b.invert(x, y), x && a.invert(x[0], x[1]);
};
return compose;
}
function rotationIdentity(lambda, phi) {
return [lambda > pi$4 ? lambda - tau$4 : lambda < -pi$4 ? lambda + tau$4 : lambda, phi];
}
rotationIdentity.invert = rotationIdentity;
function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
return (deltaLambda %= tau$4) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
: rotationLambda(deltaLambda))
: (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
: rotationIdentity);
}
function forwardRotationLambda(deltaLambda) {
return function(lambda, phi) {
return lambda += deltaLambda, [lambda > pi$4 ? lambda - tau$4 : lambda < -pi$4 ? lambda + tau$4 : lambda, phi];
};
}
function rotationLambda(deltaLambda) {
var rotation = forwardRotationLambda(deltaLambda);
rotation.invert = forwardRotationLambda(-deltaLambda);
return rotation;
}
function rotationPhiGamma(deltaPhi, deltaGamma) {
var cosDeltaPhi = cos$1(deltaPhi),
sinDeltaPhi = sin$1(deltaPhi),
cosDeltaGamma = cos$1(deltaGamma),
sinDeltaGamma = sin$1(deltaGamma);
function rotation(lambda, phi) {
var cosPhi = cos$1(phi),
x = cos$1(lambda) * cosPhi,
y = sin$1(lambda) * cosPhi,
z = sin$1(phi),
k = z * cosDeltaPhi + x * sinDeltaPhi;
return [
atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
asin$1(k * cosDeltaGamma + y * sinDeltaGamma)
];
}
rotation.invert = function(lambda, phi) {
var cosPhi = cos$1(phi),
x = cos$1(lambda) * cosPhi,
y = sin$1(lambda) * cosPhi,
z = sin$1(phi),
k = z * cosDeltaGamma - y * sinDeltaGamma;
return [
atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
asin$1(k * cosDeltaPhi - x * sinDeltaPhi)
];
};
return rotation;
}
function rotation(rotate) {
rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
function forward(coordinates) {
coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
}
forward.invert = function(coordinates) {
coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
};
return forward;
}
// Generates a circle centered at [0°, 0°], with a given radius and precision.
function circleStream(stream, radius, delta, direction, t0, t1) {
if (!delta) return;
var cosRadius = cos$1(radius),
sinRadius = sin$1(radius),
step = direction * delta;
if (t0 == null) {
t0 = radius + direction * tau$4;
t1 = radius - step / 2;
} else {
t0 = circleRadius(cosRadius, t0);
t1 = circleRadius(cosRadius, t1);
if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$4;
}
for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]);
stream.point(point[0], point[1]);
}
}
// Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
function circleRadius(cosRadius, point) {
point = cartesian(point), point[0] -= cosRadius;
cartesianNormalizeInPlace(point);
var radius = acos(-point[1]);
return ((-point[2] < 0 ? -radius : radius) + tau$4 - epsilon$4) % tau$4;
}
function circle$1() {
var center = constant$12([0, 0]),
radius = constant$12(90),
precision = constant$12(6),
ring,
rotate,
stream = {point: point};
function point(x, y) {
ring.push(x = rotate(x, y));
x[0] *= degrees$1, x[1] *= degrees$1;
}
function circle() {
var c = center.apply(this, arguments),
r = radius.apply(this, arguments) * radians,
p = precision.apply(this, arguments) * radians;
ring = [];
rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
circleStream(stream, r, p, 1);
c = {type: "Polygon", coordinates: [ring]};
ring = rotate = null;
return c;
}
circle.center = function(_) {
return arguments.length ? (center = typeof _ === "function" ? _ : constant$12([+_[0], +_[1]]), circle) : center;
};
circle.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant$12(+_), circle) : radius;
};
circle.precision = function(_) {
return arguments.length ? (precision = typeof _ === "function" ? _ : constant$12(+_), circle) : precision;
};
return circle;
}
function clipBuffer() {
var lines = [],
line;
return {
point: function(x, y) {
line.push([x, y]);
},
lineStart: function() {
lines.push(line = []);
},
lineEnd: noop$2,
rejoin: function() {
if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
},
result: function() {
var result = lines;
lines = [];
line = null;
return result;
}
};
}
function clipLine(a, b, x0, y0, x1, y1) {
var ax = a[0],
ay = a[1],
bx = b[0],
by = b[1],
t0 = 0,
t1 = 1,
dx = bx - ax,
dy = by - ay,
r;
r = x0 - ax;
if (!dx && r > 0) return;
r /= dx;
if (dx < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dx > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = x1 - ax;
if (!dx && r < 0) return;
r /= dx;
if (dx < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dx > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
r = y0 - ay;
if (!dy && r > 0) return;
r /= dy;
if (dy < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dy > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = y1 - ay;
if (!dy && r < 0) return;
r /= dy;
if (dy < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dy > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
return true;
}
function pointEqual(a, b) {
return abs(a[0] - b[0]) < epsilon$4 && abs(a[1] - b[1]) < epsilon$4;
}
function Intersection(point, points, other, entry) {
this.x = point;
this.z = points;
this.o = other; // another intersection
this.e = entry; // is an entry?
this.v = false; // visited
this.n = this.p = null; // next & previous
}
// A generalized polygon clipping algorithm: given a polygon that has been cut
// into its visible line segments, and rejoins the segments by interpolating
// along the clip edge.
function clipPolygon(segments, compareIntersection, startInside, interpolate, stream) {
var subject = [],
clip = [],
i,
n;
segments.forEach(function(segment) {
if ((n = segment.length - 1) <= 0) return;
var n, p0 = segment[0], p1 = segment[n], x;
// If the first and last points of a segment are coincident, then treat as a
// closed ring. TODO if all rings are closed, then the winding order of the
// exterior ring should be checked.
if (pointEqual(p0, p1)) {
stream.lineStart();
for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
stream.lineEnd();
return;
}
subject.push(x = new Intersection(p0, segment, null, true));
clip.push(x.o = new Intersection(p0, null, x, false));
subject.push(x = new Intersection(p1, segment, null, false));
clip.push(x.o = new Intersection(p1, null, x, true));
});
if (!subject.length) return;
clip.sort(compareIntersection);
link$1(subject);
link$1(clip);
for (i = 0, n = clip.length; i < n; ++i) {
clip[i].e = startInside = !startInside;
}
var start = subject[0],
points,
point;
while (1) {
// Find first unvisited intersection.
var current = start,
isSubject = true;
while (current.v) if ((current = current.n) === start) return;
points = current.z;
stream.lineStart();
do {
current.v = current.o.v = true;
if (current.e) {
if (isSubject) {
for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
} else {
interpolate(current.x, current.n.x, 1, stream);
}
current = current.n;
} else {
if (isSubject) {
points = current.p.z;
for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
} else {
interpolate(current.x, current.p.x, -1, stream);
}
current = current.p;
}
current = current.o;
points = current.z;
isSubject = !isSubject;
} while (!current.v);
stream.lineEnd();
}
}
function link$1(array) {
if (!(n = array.length)) return;
var n,
i = 0,
a = array[0],
b;
while (++i < n) {
a.n = b = array[i];
b.p = a;
a = b;
}
a.n = b = array[0];
b.p = a;
}
var clipMax = 1e9;
var clipMin = -clipMax;
// TODO Use d3-polygon’s polygonContains here for the ring check?
// TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
function clipExtent(x0, y0, x1, y1) {
function visible(x, y) {
return x0 <= x && x <= x1 && y0 <= y && y <= y1;
}
function interpolate(from, to, direction, stream) {
var a = 0, a1 = 0;
if (from == null
|| (a = corner(from, direction)) !== (a1 = corner(to, direction))
|| comparePoint(from, to) < 0 ^ direction > 0) {
do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
while ((a = (a + direction + 4) % 4) !== a1);
} else {
stream.point(to[0], to[1]);
}
}
function corner(p, direction) {
return abs(p[0] - x0) < epsilon$4 ? direction > 0 ? 0 : 3
: abs(p[0] - x1) < epsilon$4 ? direction > 0 ? 2 : 1
: abs(p[1] - y0) < epsilon$4 ? direction > 0 ? 1 : 0
: direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
}
function compareIntersection(a, b) {
return comparePoint(a.x, b.x);
}
function comparePoint(a, b) {
var ca = corner(a, 1),
cb = corner(b, 1);
return ca !== cb ? ca - cb
: ca === 0 ? b[1] - a[1]
: ca === 1 ? a[0] - b[0]
: ca === 2 ? a[1] - b[1]
: b[0] - a[0];
}
return function(stream) {
var activeStream = stream,
bufferStream = clipBuffer(),
segments,
polygon,
ring,
x__, y__, v__, // first point
x_, y_, v_, // previous point
first,
clean;
var clipStream = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: polygonStart,
polygonEnd: polygonEnd
};
function point(x, y) {
if (visible(x, y)) activeStream.point(x, y);
}
function polygonInside() {
var winding = 0;
for (var i = 0, n = polygon.length; i < n; ++i) {
for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
}
}
return winding;
}
// Buffer geometry within a polygon and then clip it en masse.
function polygonStart() {
activeStream = bufferStream, segments = [], polygon = [], clean = true;
}
function polygonEnd() {
var startInside = polygonInside(),
cleanInside = clean && startInside,
visible = (segments = merge(segments)).length;
if (cleanInside || visible) {
stream.polygonStart();
if (cleanInside) {
stream.lineStart();
interpolate(null, null, 1, stream);
stream.lineEnd();
}
if (visible) {
clipPolygon(segments, compareIntersection, startInside, interpolate, stream);
}
stream.polygonEnd();
}
activeStream = stream, segments = polygon = ring = null;
}
function lineStart() {
clipStream.point = linePoint;
if (polygon) polygon.push(ring = []);
first = true;
v_ = false;
x_ = y_ = NaN;
}
// TODO rather than special-case polygons, simply handle them separately.
// Ideally, coincident intersection points should be jittered to avoid
// clipping issues.
function lineEnd() {
if (segments) {
linePoint(x__, y__);
if (v__ && v_) bufferStream.rejoin();
segments.push(bufferStream.result());
}
clipStream.point = point;
if (v_) activeStream.lineEnd();
}
function linePoint(x, y) {
var v = visible(x, y);
if (polygon) ring.push([x, y]);
if (first) {
x__ = x, y__ = y, v__ = v;
first = false;
if (v) {
activeStream.lineStart();
activeStream.point(x, y);
}
} else {
if (v && v_) activeStream.point(x, y);
else {
var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
if (clipLine(a, b, x0, y0, x1, y1)) {
if (!v_) {
activeStream.lineStart();
activeStream.point(a[0], a[1]);
}
activeStream.point(b[0], b[1]);
if (!v) activeStream.lineEnd();
clean = false;
} else if (v) {
activeStream.lineStart();
activeStream.point(x, y);
clean = false;
}
}
}
x_ = x, y_ = y, v_ = v;
}
return clipStream;
};
}
function extent$1() {
var x0 = 0,
y0 = 0,
x1 = 960,
y1 = 500,
cache,
cacheStream,
clip;
return clip = {
stream: function(stream) {
return cache && cacheStream === stream ? cache : cache = clipExtent(x0, y0, x1, y1)(cacheStream = stream);
},
extent: function(_) {
return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
}
};
}
var lengthSum;
var lambda0$2;
var sinPhi0$1;
var cosPhi0$1;
var lengthStream = {
sphere: noop$2,
point: noop$2,
lineStart: lengthLineStart,
lineEnd: noop$2,
polygonStart: noop$2,
polygonEnd: noop$2
};
function lengthLineStart() {
lengthStream.point = lengthPointFirst;
lengthStream.lineEnd = lengthLineEnd;
}
function lengthLineEnd() {
lengthStream.point = lengthStream.lineEnd = noop$2;
}
function lengthPointFirst(lambda, phi) {
lambda *= radians, phi *= radians;
lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi);
lengthStream.point = lengthPoint;
}
function lengthPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var sinPhi = sin$1(phi),
cosPhi = cos$1(phi),
delta = abs(lambda - lambda0$2),
cosDelta = cos$1(delta),
sinDelta = sin$1(delta),
x = cosPhi * sinDelta,
y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
lengthSum.add(atan2(sqrt$1(x * x + y * y), z));
lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
}
function length$2(object) {
if (lengthSum) lengthSum.reset();
else lengthSum = adder();
stream(object, lengthStream);
return +lengthSum;
}
var coordinates = [null, null];
var object$1 = {type: "LineString", coordinates: coordinates};
function distance(a, b) {
coordinates[0] = a;
coordinates[1] = b;
return length$2(object$1);
}
function graticuleX(y0, y1, dy) {
var y = range(y0, y1 - epsilon$4, dy).concat(y1);
return function(x) { return y.map(function(y) { return [x, y]; }); };
}
function graticuleY(x0, x1, dx) {
var x = range(x0, x1 - epsilon$4, dx).concat(x1);
return function(y) { return x.map(function(x) { return [x, y]; }); };
}
function graticule() {
var x1, x0, X1, X0,
y1, y0, Y1, Y0,
dx = 10, dy = dx, DX = 90, DY = 360,
x, y, X, Y,
precision = 2.5;
function graticule() {
return {type: "MultiLineString", coordinates: lines()};
}
function lines() {
return range(ceil(X0 / DX) * DX, X1, DX).map(X)
.concat(range(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
.concat(range(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$4; }).map(x))
.concat(range(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$4; }).map(y));
}
graticule.lines = function() {
return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; });
};
graticule.outline = function() {
return {
type: "Polygon",
coordinates: [
X(X0).concat(
Y(Y1).slice(1),
X(X1).reverse().slice(1),
Y(Y0).reverse().slice(1))
]
};
};
graticule.extent = function(_) {
if (!arguments.length) return graticule.extentMinor();
return graticule.extentMajor(_).extentMinor(_);
};
graticule.extentMajor = function(_) {
if (!arguments.length) return [[X0, Y0], [X1, Y1]];
X0 = +_[0][0], X1 = +_[1][0];
Y0 = +_[0][1], Y1 = +_[1][1];
if (X0 > X1) _ = X0, X0 = X1, X1 = _;
if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
return graticule.precision(precision);
};
graticule.extentMinor = function(_) {
if (!arguments.length) return [[x0, y0], [x1, y1]];
x0 = +_[0][0], x1 = +_[1][0];
y0 = +_[0][1], y1 = +_[1][1];
if (x0 > x1) _ = x0, x0 = x1, x1 = _;
if (y0 > y1) _ = y0, y0 = y1, y1 = _;
return graticule.precision(precision);
};
graticule.step = function(_) {
if (!arguments.length) return graticule.stepMinor();
return graticule.stepMajor(_).stepMinor(_);
};
graticule.stepMajor = function(_) {
if (!arguments.length) return [DX, DY];
DX = +_[0], DY = +_[1];
return graticule;
};
graticule.stepMinor = function(_) {
if (!arguments.length) return [dx, dy];
dx = +_[0], dy = +_[1];
return graticule;
};
graticule.precision = function(_) {
if (!arguments.length) return precision;
precision = +_;
x = graticuleX(y0, y1, 90);
y = graticuleY(x0, x1, precision);
X = graticuleX(Y0, Y1, 90);
Y = graticuleY(X0, X1, precision);
return graticule;
};
return graticule
.extentMajor([[-180, -90 + epsilon$4], [180, 90 - epsilon$4]])
.extentMinor([[-180, -80 - epsilon$4], [180, 80 + epsilon$4]]);
}
function interpolate$2(a, b) {
var x0 = a[0] * radians,
y0 = a[1] * radians,
x1 = b[0] * radians,
y1 = b[1] * radians,
cy0 = cos$1(y0),
sy0 = sin$1(y0),
cy1 = cos$1(y1),
sy1 = sin$1(y1),
kx0 = cy0 * cos$1(x0),
ky0 = cy0 * sin$1(x0),
kx1 = cy1 * cos$1(x1),
ky1 = cy1 * sin$1(x1),
d = 2 * asin$1(sqrt$1(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
k = sin$1(d);
var interpolate = d ? function(t) {
var B = sin$1(t *= d) / k,
A = sin$1(d - t) / k,
x = A * kx0 + B * kx1,
y = A * ky0 + B * ky1,
z = A * sy0 + B * sy1;
return [
atan2(y, x) * degrees$1,
atan2(z, sqrt$1(x * x + y * y)) * degrees$1
];
} : function() {
return [x0 * degrees$1, y0 * degrees$1];
};
interpolate.distance = d;
return interpolate;
}
function identity$7(x) {
return x;
}
var areaSum$1 = adder();
var areaRingSum$1 = adder();
var x00;
var y00;
var x0$1;
var y0$1;
var areaStream$1 = {
point: noop$2,
lineStart: noop$2,
lineEnd: noop$2,
polygonStart: function() {
areaStream$1.lineStart = areaRingStart$1;
areaStream$1.lineEnd = areaRingEnd$1;
},
polygonEnd: function() {
areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$2;
areaSum$1.add(abs(areaRingSum$1));
areaRingSum$1.reset();
},
result: function() {
var area = areaSum$1 / 2;
areaSum$1.reset();
return area;
}
};
function areaRingStart$1() {
areaStream$1.point = areaPointFirst$1;
}
function areaPointFirst$1(x, y) {
areaStream$1.point = areaPoint$1;
x00 = x0$1 = x, y00 = y0$1 = y;
}
function areaPoint$1(x, y) {
areaRingSum$1.add(y0$1 * x - x0$1 * y);
x0$1 = x, y0$1 = y;
}
function areaRingEnd$1() {
areaPoint$1(x00, y00);
}
var x0$2 = Infinity;
var y0$2 = x0$2;
var x1 = -x0$2;
var y1 = x1;
var boundsStream$1 = {
point: boundsPoint$1,
lineStart: noop$2,
lineEnd: noop$2,
polygonStart: noop$2,
polygonEnd: noop$2,
result: function() {
var bounds = [[x0$2, y0$2], [x1, y1]];
x1 = y1 = -(y0$2 = x0$2 = Infinity);
return bounds;
}
};
function boundsPoint$1(x, y) {
if (x < x0$2) x0$2 = x;
if (x > x1) x1 = x;
if (y < y0$2) y0$2 = y;
if (y > y1) y1 = y;
}
var X0$1 = 0;
var Y0$1 = 0;
var Z0$1 = 0;
var X1$1 = 0;
var Y1$1 = 0;
var Z1$1 = 0;
var X2$1 = 0;
var Y2$1 = 0;
var Z2$1 = 0;
var x00$1;
var y00$1;
var x0$3;
var y0$3;
var centroidStream$1 = {
point: centroidPoint$1,
lineStart: centroidLineStart$1,
lineEnd: centroidLineEnd$1,
polygonStart: function() {
centroidStream$1.lineStart = centroidRingStart$1;
centroidStream$1.lineEnd = centroidRingEnd$1;
},
polygonEnd: function() {
centroidStream$1.point = centroidPoint$1;
centroidStream$1.lineStart = centroidLineStart$1;
centroidStream$1.lineEnd = centroidLineEnd$1;
},
result: function() {
var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
: Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
: Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
: [NaN, NaN];
X0$1 = Y0$1 = Z0$1 =
X1$1 = Y1$1 = Z1$1 =
X2$1 = Y2$1 = Z2$1 = 0;
return centroid;
}
};
function centroidPoint$1(x, y) {
X0$1 += x;
Y0$1 += y;
++Z0$1;
}
function centroidLineStart$1() {
centroidStream$1.point = centroidPointFirstLine;
}
function centroidPointFirstLine(x, y) {
centroidStream$1.point = centroidPointLine;
centroidPoint$1(x0$3 = x, y0$3 = y);
}
function centroidPointLine(x, y) {
var dx = x - x0$3, dy = y - y0$3, z = sqrt$1(dx * dx + dy * dy);
X1$1 += z * (x0$3 + x) / 2;
Y1$1 += z * (y0$3 + y) / 2;
Z1$1 += z;
centroidPoint$1(x0$3 = x, y0$3 = y);
}
function centroidLineEnd$1() {
centroidStream$1.point = centroidPoint$1;
}
function centroidRingStart$1() {
centroidStream$1.point = centroidPointFirstRing;
}
function centroidRingEnd$1() {
centroidPointRing(x00$1, y00$1);
}
function centroidPointFirstRing(x, y) {
centroidStream$1.point = centroidPointRing;
centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
}
function centroidPointRing(x, y) {
var dx = x - x0$3,
dy = y - y0$3,
z = sqrt$1(dx * dx + dy * dy);
X1$1 += z * (x0$3 + x) / 2;
Y1$1 += z * (y0$3 + y) / 2;
Z1$1 += z;
z = y0$3 * x - x0$3 * y;
X2$1 += z * (x0$3 + x);
Y2$1 += z * (y0$3 + y);
Z2$1 += z * 3;
centroidPoint$1(x0$3 = x, y0$3 = y);
}
function PathContext(context) {
var pointRadius = 4.5;
var stream = {
point: point,
// While inside a line, override point to moveTo then lineTo.
lineStart: function() { stream.point = pointLineStart; },
lineEnd: lineEnd,
// While inside a polygon, override lineEnd to closePath.
polygonStart: function() { stream.lineEnd = lineEndPolygon; },
polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
pointRadius: function(_) {
pointRadius = _;
return stream;
},
result: noop$2
};
function point(x, y) {
context.moveTo(x + pointRadius, y);
context.arc(x, y, pointRadius, 0, tau$4);
}
function pointLineStart(x, y) {
context.moveTo(x, y);
stream.point = pointLine;
}
function pointLine(x, y) {
context.lineTo(x, y);
}
function lineEnd() {
stream.point = point;
}
function lineEndPolygon() {
context.closePath();
}
return stream;
}
function PathString() {
var pointCircle = circle$2(4.5),
string = [];
var stream = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
stream.lineEnd = lineEndPolygon;
},
polygonEnd: function() {
stream.lineEnd = lineEnd;
stream.point = point;
},
pointRadius: function(_) {
pointCircle = circle$2(_);
return stream;
},
result: function() {
if (string.length) {
var result = string.join("");
string = [];
return result;
}
}
};
function point(x, y) {
string.push("M", x, ",", y, pointCircle);
}
function pointLineStart(x, y) {
string.push("M", x, ",", y);
stream.point = pointLine;
}
function pointLine(x, y) {
string.push("L", x, ",", y);
}
function lineStart() {
stream.point = pointLineStart;
}
function lineEnd() {
stream.point = point;
}
function lineEndPolygon() {
string.push("Z");
}
return stream;
}
function circle$2(radius) {
return "m0," + radius
+ "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
+ "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
+ "z";
}
function index$3() {
var pointRadius = 4.5,
projection,
projectionStream,
context,
contextStream;
function path(object) {
if (object) {
if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
stream(object, projectionStream(contextStream));
}
return contextStream.result();
}
path.area = function(object) {
stream(object, projectionStream(areaStream$1));
return areaStream$1.result();
};
path.bounds = function(object) {
stream(object, projectionStream(boundsStream$1));
return boundsStream$1.result();
};
path.centroid = function(object) {
stream(object, projectionStream(centroidStream$1));
return centroidStream$1.result();
};
path.projection = function(_) {
return arguments.length ? (projectionStream = (projection = _) == null ? identity$7 : _.stream, path) : projection;
};
path.context = function(_) {
if (!arguments.length) return context;
contextStream = (context = _) == null ? new PathString : new PathContext(_);
if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
return path;
};
path.pointRadius = function(_) {
if (!arguments.length) return pointRadius;
pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
return path;
};
return path.projection(null).context(null);
}
var sum$2 = adder();
function polygonContains(polygon, point) {
var lambda = point[0],
phi = point[1],
normal = [sin$1(lambda), -cos$1(lambda), 0],
angle = 0,
winding = 0;
for (var i = 0, n = polygon.length; i < n; ++i) {
if (!(m = (ring = polygon[i]).length)) continue;
var ring,
m,
point0 = ring[m - 1],
lambda0 = point0[0],
phi0 = point0[1] / 2 + quarterPi,
sinPhi0 = sin$1(phi0),
cosPhi0 = cos$1(phi0);
for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
var point1 = ring[j],
lambda1 = point1[0],
phi1 = point1[1] / 2 + quarterPi,
sinPhi1 = sin$1(phi1),
cosPhi1 = cos$1(phi1),
delta = lambda1 - lambda0,
sign = delta >= 0 ? 1 : -1,
absDelta = sign * delta,
antimeridian = absDelta > pi$4,
k = sinPhi0 * sinPhi1;
sum$2.add(atan2(k * sign * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
angle += antimeridian ? delta + sign * tau$4 : delta;
// Are the longitudes either side of the point’s meridian (lambda),
// and are the latitudes smaller than the parallel (phi)?
if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
var arc = cartesianCross(cartesian(point0), cartesian(point1));
cartesianNormalizeInPlace(arc);
var intersection = cartesianCross(normal, arc);
cartesianNormalizeInPlace(intersection);
var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin$1(intersection[2]);
if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
winding += antimeridian ^ delta >= 0 ? 1 : -1;
}
}
}
}
// First, determine whether the South pole is inside or outside:
//
// It is inside if:
// * the polygon winds around it in a clockwise direction.
// * the polygon does not (cumulatively) wind around it, but has a negative
// (counter-clockwise) area.
//
// Second, count the (signed) number of times a segment crosses a lambda
// from the point to the South pole. If it is zero, then the point is the
// same side as the South pole.
var contains = (angle < -epsilon$4 || angle < epsilon$4 && sum$2 < -epsilon$4) ^ (winding & 1);
sum$2.reset();
return contains;
}
function clip(pointVisible, clipLine, interpolate, start) {
return function(rotate, sink) {
var line = clipLine(sink),
rotatedStart = rotate.invert(start[0], start[1]),
ringBuffer = clipBuffer(),
ringSink = clipLine(ringBuffer),
polygonStarted = false,
polygon,
segments,
ring;
var clip = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
clip.point = pointRing;
clip.lineStart = ringStart;
clip.lineEnd = ringEnd;
segments = [];
polygon = [];
},
polygonEnd: function() {
clip.point = point;
clip.lineStart = lineStart;
clip.lineEnd = lineEnd;
segments = merge(segments);
var startInside = polygonContains(polygon, rotatedStart);
if (segments.length) {
if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
clipPolygon(segments, compareIntersection, startInside, interpolate, sink);
} else if (startInside) {
if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
sink.lineStart();
interpolate(null, null, 1, sink);
sink.lineEnd();
}
if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
segments = polygon = null;
},
sphere: function() {
sink.polygonStart();
sink.lineStart();
interpolate(null, null, 1, sink);
sink.lineEnd();
sink.polygonEnd();
}
};
function point(lambda, phi) {
var point = rotate(lambda, phi);
if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
}
function pointLine(lambda, phi) {
var point = rotate(lambda, phi);
line.point(point[0], point[1]);
}
function lineStart() {
clip.point = pointLine;
line.lineStart();
}
function lineEnd() {
clip.point = point;
line.lineEnd();
}
function pointRing(lambda, phi) {
ring.push([lambda, phi]);
var point = rotate(lambda, phi);
ringSink.point(point[0], point[1]);
}
function ringStart() {
ringSink.lineStart();
ring = [];
}
function ringEnd() {
pointRing(ring[0][0], ring[0][1]);
ringSink.lineEnd();
var clean = ringSink.clean(),
ringSegments = ringBuffer.result(),
i, n = ringSegments.length, m,
segment,
point;
ring.pop();
polygon.push(ring);
ring = null;
if (!n) return;
// No intersections.
if (clean & 1) {
segment = ringSegments[0];
if ((m = segment.length - 1) > 0) {
if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
sink.lineStart();
for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
sink.lineEnd();
}
return;
}
// Rejoin connected segments.
// TODO reuse ringBuffer.rejoin()?
if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
segments.push(ringSegments.filter(validSegment));
}
return clip;
};
}
function validSegment(segment) {
return segment.length > 1;
}
// Intersections are sorted along the clip edge. For both antimeridian cutting
// and circle clipping, the same comparison is used.
function compareIntersection(a, b) {
return ((a = a.x)[0] < 0 ? a[1] - halfPi$3 - epsilon$4 : halfPi$3 - a[1])
- ((b = b.x)[0] < 0 ? b[1] - halfPi$3 - epsilon$4 : halfPi$3 - b[1]);
}
var clipAntimeridian = clip(
function() { return true; },
clipAntimeridianLine,
clipAntimeridianInterpolate,
[-pi$4, -halfPi$3]
);
// Takes a line and cuts into visible segments. Return values: 0 - there were
// intersections or the line was empty; 1 - no intersections; 2 - there were
// intersections, and the first and last segments should be rejoined.
function clipAntimeridianLine(stream) {
var lambda0 = NaN,
phi0 = NaN,
sign0 = NaN,
clean; // no intersections
return {
lineStart: function() {
stream.lineStart();
clean = 1;
},
point: function(lambda1, phi1) {
var sign1 = lambda1 > 0 ? pi$4 : -pi$4,
delta = abs(lambda1 - lambda0);
if (abs(delta - pi$4) < epsilon$4) { // line crosses a pole
stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$3 : -halfPi$3);
stream.point(sign0, phi0);
stream.lineEnd();
stream.lineStart();
stream.point(sign1, phi0);
stream.point(lambda1, phi0);
clean = 0;
} else if (sign0 !== sign1 && delta >= pi$4) { // line crosses antimeridian
if (abs(lambda0 - sign0) < epsilon$4) lambda0 -= sign0 * epsilon$4; // handle degeneracies
if (abs(lambda1 - sign1) < epsilon$4) lambda1 -= sign1 * epsilon$4;
phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
stream.point(sign0, phi0);
stream.lineEnd();
stream.lineStart();
stream.point(sign1, phi0);
clean = 0;
}
stream.point(lambda0 = lambda1, phi0 = phi1);
sign0 = sign1;
},
lineEnd: function() {
stream.lineEnd();
lambda0 = phi0 = NaN;
},
clean: function() {
return 2 - clean; // if intersections, rejoin first and last segments
}
};
}
function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
var cosPhi0,
cosPhi1,
sinLambda0Lambda1 = sin$1(lambda0 - lambda1);
return abs(sinLambda0Lambda1) > epsilon$4
? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
- sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
/ (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
: (phi0 + phi1) / 2;
}
function clipAntimeridianInterpolate(from, to, direction, stream) {
var phi;
if (from == null) {
phi = direction * halfPi$3;
stream.point(-pi$4, phi);
stream.point(0, phi);
stream.point(pi$4, phi);
stream.point(pi$4, 0);
stream.point(pi$4, -phi);
stream.point(0, -phi);
stream.point(-pi$4, -phi);
stream.point(-pi$4, 0);
stream.point(-pi$4, phi);
} else if (abs(from[0] - to[0]) > epsilon$4) {
var lambda = from[0] < to[0] ? pi$4 : -pi$4;
phi = direction * lambda / 2;
stream.point(-lambda, phi);
stream.point(0, phi);
stream.point(lambda, phi);
} else {
stream.point(to[0], to[1]);
}
}
function clipCircle(radius, delta) {
var cr = cos$1(radius),
smallRadius = cr > 0,
notHemisphere = abs(cr) > epsilon$4; // TODO optimise for this common case
function interpolate(from, to, direction, stream) {
circleStream(stream, radius, delta, direction, from, to);
}
function visible(lambda, phi) {
return cos$1(lambda) * cos$1(phi) > cr;
}
// Takes a line and cuts into visible segments. Return values used for polygon
// clipping: 0 - there were intersections or the line was empty; 1 - no
// intersections 2 - there were intersections, and the first and last segments
// should be rejoined.
function clipLine(stream) {
var point0, // previous point
c0, // code for previous point
v0, // visibility of previous point
v00, // visibility of first point
clean; // no intersections
return {
lineStart: function() {
v00 = v0 = false;
clean = 1;
},
point: function(lambda, phi) {
var point1 = [lambda, phi],
point2,
v = visible(lambda, phi),
c = smallRadius
? v ? 0 : code(lambda, phi)
: v ? code(lambda + (lambda < 0 ? pi$4 : -pi$4), phi) : 0;
if (!point0 && (v00 = v0 = v)) stream.lineStart();
// Handle degeneracies.
// TODO ignore if not clipping polygons.
if (v !== v0) {
point2 = intersect(point0, point1);
if (pointEqual(point0, point2) || pointEqual(point1, point2)) {
point1[0] += epsilon$4;
point1[1] += epsilon$4;
v = visible(point1[0], point1[1]);
}
}
if (v !== v0) {
clean = 0;
if (v) {
// outside going in
stream.lineStart();
point2 = intersect(point1, point0);
stream.point(point2[0], point2[1]);
} else {
// inside going out
point2 = intersect(point0, point1);
stream.point(point2[0], point2[1]);
stream.lineEnd();
}
point0 = point2;
} else if (notHemisphere && point0 && smallRadius ^ v) {
var t;
// If the codes for two points are different, or are both zero,
// and there this segment intersects with the small circle.
if (!(c & c0) && (t = intersect(point1, point0, true))) {
clean = 0;
if (smallRadius) {
stream.lineStart();
stream.point(t[0][0], t[0][1]);
stream.point(t[1][0], t[1][1]);
stream.lineEnd();
} else {
stream.point(t[1][0], t[1][1]);
stream.lineEnd();
stream.lineStart();
stream.point(t[0][0], t[0][1]);
}
}
}
if (v && (!point0 || !pointEqual(point0, point1))) {
stream.point(point1[0], point1[1]);
}
point0 = point1, v0 = v, c0 = c;
},
lineEnd: function() {
if (v0) stream.lineEnd();
point0 = null;
},
// Rejoin first and last segments if there were intersections and the first
// and last points were visible.
clean: function() {
return clean | ((v00 && v0) << 1);
}
};
}
// Intersects the great circle between a and b with the clip circle.
function intersect(a, b, two) {
var pa = cartesian(a),
pb = cartesian(b);
// We have two planes, n1.p = d1 and n2.p = d2.
// Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
var n1 = [1, 0, 0], // normal
n2 = cartesianCross(pa, pb),
n2n2 = cartesianDot(n2, n2),
n1n2 = n2[0], // cartesianDot(n1, n2),
determinant = n2n2 - n1n2 * n1n2;
// Two polar points.
if (!determinant) return !two && a;
var c1 = cr * n2n2 / determinant,
c2 = -cr * n1n2 / determinant,
n1xn2 = cartesianCross(n1, n2),
A = cartesianScale(n1, c1),
B = cartesianScale(n2, c2);
cartesianAddInPlace(A, B);
// Solve |p(t)|^2 = 1.
var u = n1xn2,
w = cartesianDot(A, u),
uu = cartesianDot(u, u),
t2 = w * w - uu * (cartesianDot(A, A) - 1);
if (t2 < 0) return;
var t = sqrt$1(t2),
q = cartesianScale(u, (-w - t) / uu);
cartesianAddInPlace(q, A);
q = spherical(q);
if (!two) return q;
// Two intersection points.
var lambda0 = a[0],
lambda1 = b[0],
phi0 = a[1],
phi1 = b[1],
z;
if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
var delta = lambda1 - lambda0,
polar = abs(delta - pi$4) < epsilon$4,
meridian = polar || delta < epsilon$4;
if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
// Check that the first point is between a and b.
if (meridian
? polar
? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$4 ? phi0 : phi1)
: phi0 <= q[1] && q[1] <= phi1
: delta > pi$4 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
var q1 = cartesianScale(u, (-w + t) / uu);
cartesianAddInPlace(q1, A);
return [q, spherical(q1)];
}
}
// Generates a 4-bit vector representing the location of a point relative to
// the small circle's bounding box.
function code(lambda, phi) {
var r = smallRadius ? radius : pi$4 - radius,
code = 0;
if (lambda < -r) code |= 1; // left
else if (lambda > r) code |= 2; // right
if (phi < -r) code |= 4; // below
else if (phi > r) code |= 8; // above
return code;
}
return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$4, radius - pi$4]);
}
function transform$1(prototype) {
return {
stream: transform$2(prototype)
};
}
function transform$2(prototype) {
function T() {}
var p = T.prototype = Object.create(Transform$1.prototype);
for (var k in prototype) p[k] = prototype[k];
return function(stream) {
var t = new T;
t.stream = stream;
return t;
};
}
function Transform$1() {}
Transform$1.prototype = {
point: function(x, y) { this.stream.point(x, y); },
sphere: function() { this.stream.sphere(); },
lineStart: function() { this.stream.lineStart(); },
lineEnd: function() { this.stream.lineEnd(); },
polygonStart: function() { this.stream.polygonStart(); },
polygonEnd: function() { this.stream.polygonEnd(); }
};
var maxDepth = 16;
var cosMinDistance = cos$1(30 * radians);
// cos(minimum angular distance)
function resample(project, delta2) {
return +delta2 ? resample$1(project, delta2) : resampleNone(project);
}
function resampleNone(project) {
return transform$2({
point: function(x, y) {
x = project(x, y);
this.stream.point(x[0], x[1]);
}
});
}
function resample$1(project, delta2) {
function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
var dx = x1 - x0,
dy = y1 - y0,
d2 = dx * dx + dy * dy;
if (d2 > 4 * delta2 && depth--) {
var a = a0 + a1,
b = b0 + b1,
c = c0 + c1,
m = sqrt$1(a * a + b * b + c * c),
phi2 = asin$1(c /= m),
lambda2 = abs(abs(c) - 1) < epsilon$4 || abs(lambda0 - lambda1) < epsilon$4 ? (lambda0 + lambda1) / 2 : atan2(b, a),
p = project(lambda2, phi2),
x2 = p[0],
y2 = p[1],
dx2 = x2 - x0,
dy2 = y2 - y0,
dz = dy * dx2 - dx * dy2;
if (dz * dz / d2 > delta2 // perpendicular projected distance
|| abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
|| a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
stream.point(x2, y2);
resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
}
}
}
return function(stream) {
var lambda00, x00, y00, a00, b00, c00, // first point
lambda0, x0, y0, a0, b0, c0; // previous point
var resampleStream = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
};
function point(x, y) {
x = project(x, y);
stream.point(x[0], x[1]);
}
function lineStart() {
x0 = NaN;
resampleStream.point = linePoint;
stream.lineStart();
}
function linePoint(lambda, phi) {
var c = cartesian([lambda, phi]), p = project(lambda, phi);
resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
stream.point(x0, y0);
}
function lineEnd() {
resampleStream.point = point;
stream.lineEnd();
}
function ringStart() {
lineStart();
resampleStream.point = ringPoint;
resampleStream.lineEnd = ringEnd;
}
function ringPoint(lambda, phi) {
linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
resampleStream.point = linePoint;
}
function ringEnd() {
resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
resampleStream.lineEnd = lineEnd;
lineEnd();
}
return resampleStream;
};
}
var transformRadians = transform$2({
point: function(x, y) {
this.stream.point(x * radians, y * radians);
}
});
function projection(project) {
return projectionMutator(function() { return project; })();
}
function projectionMutator(projectAt) {
var project,
k = 150, // scale
x = 480, y = 250, // translate
dx, dy, lambda = 0, phi = 0, // center
deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
theta = null, preclip = clipAntimeridian, // clip angle
x0 = null, y0, x1, y1, postclip = identity$7, // clip extent
delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
cache,
cacheStream;
function projection(point) {
point = projectRotate(point[0] * radians, point[1] * radians);
return [point[0] * k + dx, dy - point[1] * k];
}
function invert(point) {
point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
return point && [point[0] * degrees$1, point[1] * degrees$1];
}
function projectTransform(x, y) {
return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
}
projection.stream = function(stream) {
return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
};
projection.clipAngle = function(_) {
return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
};
projection.clipExtent = function(_) {
return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$7) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
};
projection.scale = function(_) {
return arguments.length ? (k = +_, recenter()) : k;
};
projection.translate = function(_) {
return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
};
projection.center = function(_) {
return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
};
projection.rotate = function(_) {
return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees$1, deltaPhi * degrees$1, deltaGamma * degrees$1];
};
projection.precision = function(_) {
return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$1(delta2);
};
function recenter() {
projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
var center = project(lambda, phi);
dx = x - center[0] * k;
dy = y + center[1] * k;
return reset();
}
function reset() {
cache = cacheStream = null;
return projection;
}
return function() {
project = projectAt.apply(this, arguments);
projection.invert = project.invert && invert;
return recenter();
};
}
function conicProjection(projectAt) {
var phi0 = 0,
phi1 = pi$4 / 3,
m = projectionMutator(projectAt),
p = m(phi0, phi1);
p.parallels = function(_) {
return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
};
return p;
}
function conicEqualAreaRaw(y0, y1) {
var sy0 = sin$1(y0),
n = (sy0 + sin$1(y1)) / 2,
c = 1 + sy0 * (2 * n - sy0),
r0 = sqrt$1(c) / n;
function project(x, y) {
var r = sqrt$1(c - 2 * n * sin$1(y)) / n;
return [r * sin$1(x *= n), r0 - r * cos$1(x)];
}
project.invert = function(x, y) {
var r0y = r0 - y;
return [atan2(x, r0y) / n, asin$1((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
};
return project;
}
function conicEqualArea() {
return conicProjection(conicEqualAreaRaw)
.scale(151)
.translate([480, 347]);
}
function albers() {
return conicEqualArea()
.parallels([29.5, 45.5])
.scale(1070)
.translate([480, 250])
.rotate([96, 0])
.center([-0.6, 38.7]);
}
// The projections must have mutually exclusive clip regions on the sphere,
// as this will avoid emitting interleaving lines and polygons.
function multiplex(streams) {
var n = streams.length;
return {
point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
};
}
// A composite projection for the United States, configured by default for
// 960×500. Also works quite well at 960×600 with scale 1285. The set of
// standard parallels for each region comes from USGS, which is published here:
// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
function albersUsa() {
var cache,
cacheStream,
lower48 = albers(), lower48Point,
alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
point, pointStream = {point: function(x, y) { point = [x, y]; }};
function albersUsa(coordinates) {
var x = coordinates[0], y = coordinates[1];
return point = null,
(lower48Point.point(x, y), point)
|| (alaskaPoint.point(x, y), point)
|| (hawaiiPoint.point(x, y), point);
}
albersUsa.invert = function(coordinates) {
var k = lower48.scale(),
t = lower48.translate(),
x = (coordinates[0] - t[0]) / k,
y = (coordinates[1] - t[1]) / k;
return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
: y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
: lower48).invert(coordinates);
};
albersUsa.stream = function(stream) {
return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
};
albersUsa.precision = function(_) {
if (!arguments.length) return lower48.precision();
lower48.precision(_), alaska.precision(_), hawaii.precision(_);
return albersUsa;
};
albersUsa.scale = function(_) {
if (!arguments.length) return lower48.scale();
lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
return albersUsa.translate(lower48.translate());
};
albersUsa.translate = function(_) {
if (!arguments.length) return lower48.translate();
var k = lower48.scale(), x = +_[0], y = +_[1];
lower48Point = lower48
.translate(_)
.clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
.stream(pointStream);
alaskaPoint = alaska
.translate([x - 0.307 * k, y + 0.201 * k])
.clipExtent([[x - 0.425 * k + epsilon$4, y + 0.120 * k + epsilon$4], [x - 0.214 * k - epsilon$4, y + 0.234 * k - epsilon$4]])
.stream(pointStream);
hawaiiPoint = hawaii
.translate([x - 0.205 * k, y + 0.212 * k])
.clipExtent([[x - 0.214 * k + epsilon$4, y + 0.166 * k + epsilon$4], [x - 0.115 * k - epsilon$4, y + 0.234 * k - epsilon$4]])
.stream(pointStream);
return albersUsa;
};
return albersUsa.scale(1070);
}
function azimuthalRaw(scale) {
return function(x, y) {
var cx = cos$1(x),
cy = cos$1(y),
k = scale(cx * cy);
return [
k * cy * sin$1(x),
k * sin$1(y)
];
}
}
function azimuthalInvert(angle) {
return function(x, y) {
var z = sqrt$1(x * x + y * y),
c = angle(z),
sc = sin$1(c),
cc = cos$1(c);
return [
atan2(x * sc, z * cc),
asin$1(z && y * sc / z)
];
}
}
var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
return sqrt$1(2 / (1 + cxcy));
});
azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
return 2 * asin$1(z / 2);
});
function azimuthalEqualArea() {
return projection(azimuthalEqualAreaRaw)
.scale(120)
.clipAngle(180 - 1e-3);
}
var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
return (c = acos(c)) && c / sin$1(c);
});
azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
return z;
});
function azimuthalEquidistant() {
return projection(azimuthalEquidistantRaw)
.scale(480 / tau$4)
.clipAngle(180 - 1e-3);
}
function mercatorRaw(lambda, phi) {
return [lambda, log$1(tan((halfPi$3 + phi) / 2))];
}
mercatorRaw.invert = function(x, y) {
return [x, 2 * atan(exp(y)) - halfPi$3];
};
function mercator() {
return mercatorProjection(mercatorRaw);
}
function mercatorProjection(project) {
var m = projection(project),
scale = m.scale,
translate = m.translate,
clipExtent = m.clipExtent,
clipAuto;
m.scale = function(_) {
return arguments.length ? (scale(_), clipAuto && m.clipExtent(null), m) : scale();
};
m.translate = function(_) {
return arguments.length ? (translate(_), clipAuto && m.clipExtent(null), m) : translate();
};
m.clipExtent = function(_) {
if (!arguments.length) return clipAuto ? null : clipExtent();
if (clipAuto = _ == null) {
var k = pi$4 * scale(), t = translate();
_ = [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]];
}
clipExtent(_);
return m;
};
return m.clipExtent(null).scale(961 / tau$4);
}
function tany(y) {
return tan((halfPi$3 + y) / 2);
}
function conicConformalRaw(y0, y1) {
var cy0 = cos$1(y0),
n = y0 === y1 ? sin$1(y0) : log$1(cy0 / cos$1(y1)) / log$1(tany(y1) / tany(y0)),
f = cy0 * pow$1(tany(y0), n) / n;
if (!n) return mercatorRaw;
function project(x, y) {
if (f > 0) { if (y < -halfPi$3 + epsilon$4) y = -halfPi$3 + epsilon$4; }
else { if (y > halfPi$3 - epsilon$4) y = halfPi$3 - epsilon$4; }
var r = f / pow$1(tany(y), n);
return [r * sin$1(n * x), f - r * cos$1(n * x)];
}
project.invert = function(x, y) {
var fy = f - y, r = sign$1(n) * sqrt$1(x * x + fy * fy);
return [atan2(x, fy) / n, 2 * atan(pow$1(f / r, 1 / n)) - halfPi$3];
};
return project;
}
function conicConformal() {
return conicProjection(conicConformalRaw);
}
function equirectangularRaw(lambda, phi) {
return [lambda, phi];
}
equirectangularRaw.invert = equirectangularRaw;
function equirectangular() {
return projection(equirectangularRaw).scale(480 / pi$4);
}
function conicEquidistantRaw(y0, y1) {
var cy0 = cos$1(y0),
n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0),
g = cy0 / n + y0;
if (abs(n) < epsilon$4) return equirectangularRaw;
function project(x, y) {
var gy = g - y, nx = n * x;
return [gy * sin$1(nx), g - gy * cos$1(nx)];
}
project.invert = function(x, y) {
var gy = g - y;
return [atan2(x, gy) / n, g - sign$1(n) * sqrt$1(x * x + gy * gy)];
};
return project;
}
function conicEquidistant() {
return conicProjection(conicEquidistantRaw)
.scale(128)
.translate([480, 280]);
}
function gnomonicRaw(x, y) {
var cy = cos$1(y), k = cos$1(x) * cy;
return [cy * sin$1(x) / k, sin$1(y) / k];
}
gnomonicRaw.invert = azimuthalInvert(atan);
function gnomonic() {
return projection(gnomonicRaw)
.scale(139)
.clipAngle(60);
}
function orthographicRaw(x, y) {
return [cos$1(y) * sin$1(x), sin$1(y)];
}
orthographicRaw.invert = azimuthalInvert(asin$1);
function orthographic() {
return projection(orthographicRaw)
.scale(240)
.clipAngle(90 + epsilon$4);
}
function stereographicRaw(x, y) {
var cy = cos$1(y), k = 1 + cos$1(x) * cy;
return [cy * sin$1(x) / k, sin$1(y) / k];
}
stereographicRaw.invert = azimuthalInvert(function(z) {
return 2 + atan(z);
});
function stereographic() {
return projection(stereographicRaw)
.scale(240)
.clipAngle(142);
}
function transverseMercatorRaw(lambda, phi) {
return [log$1(tan((halfPi$3 + phi) / 2)), -lambda];
}
transverseMercatorRaw.invert = function(x, y) {
return [-y, 2 * atan(exp(x)) - halfPi$3];
};
function transverseMercator() {
var m = mercatorProjection(transverseMercatorRaw),
center = m.center,
rotate = m.rotate;
m.center = function(_) {
return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
};
m.rotate = function(_) {
return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
};
return rotate([0, 0, 90]);
}
exports.version = version;
exports.bisect = bisectRight;
exports.bisectRight = bisectRight;
exports.bisectLeft = bisectLeft;
exports.ascending = ascending;
exports.bisector = bisector;
exports.descending = descending;
exports.deviation = deviation;
exports.extent = extent;
exports.histogram = histogram;
exports.thresholdFreedmanDiaconis = freedmanDiaconis;
exports.thresholdScott = scott;
exports.thresholdSturges = sturges;
exports.max = max;
exports.mean = mean;
exports.median = median;
exports.merge = merge;
exports.min = min;
exports.pairs = pairs;
exports.permute = permute;
exports.quantile = threshold;
exports.range = range;
exports.scan = scan;
exports.shuffle = shuffle;
exports.sum = sum;
exports.ticks = ticks;
exports.tickStep = tickStep;
exports.transpose = transpose;
exports.variance = variance;
exports.zip = zip;
exports.entries = entries;
exports.keys = keys;
exports.values = values;
exports.map = map$1;
exports.set = set;
exports.nest = nest;
exports.randomUniform = uniform;
exports.randomNormal = normal;
exports.randomLogNormal = logNormal;
exports.randomBates = bates;
exports.randomIrwinHall = irwinHall;
exports.randomExponential = exponential;
exports.easeLinear = linear;
exports.easeQuad = quadInOut;
exports.easeQuadIn = quadIn;
exports.easeQuadOut = quadOut;
exports.easeQuadInOut = quadInOut;
exports.easeCubic = easeCubicInOut;
exports.easeCubicIn = cubicIn;
exports.easeCubicOut = cubicOut;
exports.easeCubicInOut = easeCubicInOut;
exports.easePoly = polyInOut;
exports.easePolyIn = polyIn;
exports.easePolyOut = polyOut;
exports.easePolyInOut = polyInOut;
exports.easeSin = sinInOut;
exports.easeSinIn = sinIn;
exports.easeSinOut = sinOut;
exports.easeSinInOut = sinInOut;
exports.easeExp = expInOut;
exports.easeExpIn = expIn;
exports.easeExpOut = expOut;
exports.easeExpInOut = expInOut;
exports.easeCircle = circleInOut;
exports.easeCircleIn = circleIn;
exports.easeCircleOut = circleOut;
exports.easeCircleInOut = circleInOut;
exports.easeBounce = bounceOut;
exports.easeBounceIn = bounceIn;
exports.easeBounceOut = bounceOut;
exports.easeBounceInOut = bounceInOut;
exports.easeBack = backInOut;
exports.easeBackIn = backIn;
exports.easeBackOut = backOut;
exports.easeBackInOut = backInOut;
exports.easeElastic = elasticOut;
exports.easeElasticIn = elasticIn;
exports.easeElasticOut = elasticOut;
exports.easeElasticInOut = elasticInOut;
exports.polygonArea = area;
exports.polygonCentroid = centroid;
exports.polygonHull = hull;
exports.polygonContains = contains;
exports.polygonLength = length$1;
exports.path = path;
exports.quadtree = quadtree;
exports.queue = queue;
exports.arc = arc;
exports.area = area$1;
exports.line = line;
exports.pie = pie;
exports.radialArea = radialArea;
exports.radialLine = radialLine$1;
exports.symbol = symbol;
exports.symbols = symbols;
exports.symbolCircle = circle;
exports.symbolCross = cross$1;
exports.symbolDiamond = diamond;
exports.symbolSquare = square;
exports.symbolStar = star;
exports.symbolTriangle = triangle;
exports.symbolWye = wye;
exports.curveBasisClosed = basisClosed;
exports.curveBasisOpen = basisOpen;
exports.curveBasis = basis;
exports.curveBundle = bundle;
exports.curveCardinalClosed = cardinalClosed;
exports.curveCardinalOpen = cardinalOpen;
exports.curveCardinal = cardinal;
exports.curveCatmullRomClosed = catmullRomClosed;
exports.curveCatmullRomOpen = catmullRomOpen;
exports.curveCatmullRom = catmullRom;
exports.curveLinearClosed = linearClosed;
exports.curveLinear = curveLinear;
exports.curveMonotoneX = monotoneX;
exports.curveMonotoneY = monotoneY;
exports.curveNatural = natural;
exports.curveStep = step;
exports.curveStepAfter = stepAfter;
exports.curveStepBefore = stepBefore;
exports.stack = stack;
exports.stackOffsetExpand = expand;
exports.stackOffsetNone = none;
exports.stackOffsetSilhouette = silhouette;
exports.stackOffsetWiggle = wiggle;
exports.stackOrderAscending = ascending$1;
exports.stackOrderDescending = descending$2;
exports.stackOrderInsideOut = insideOut;
exports.stackOrderNone = none$1;
exports.stackOrderReverse = reverse;
exports.color = color;
exports.rgb = colorRgb;
exports.hsl = colorHsl;
exports.lab = lab;
exports.hcl = colorHcl;
exports.cubehelix = cubehelix;
exports.interpolate = interpolate;
exports.interpolateArray = array$1;
exports.interpolateDate = date;
exports.interpolateNumber = interpolateNumber;
exports.interpolateObject = object;
exports.interpolateRound = interpolateRound;
exports.interpolateString = interpolateString;
exports.interpolateTransformCss = interpolateTransform$1;
exports.interpolateTransformSvg = interpolateTransform$2;
exports.interpolateZoom = interpolateZoom;
exports.interpolateRgb = interpolateRgb;
exports.interpolateRgbBasis = rgbBasis;
exports.interpolateRgbBasisClosed = rgbBasisClosed;
exports.interpolateHsl = hsl$1;
exports.interpolateHslLong = hslLong;
exports.interpolateLab = lab$1;
exports.interpolateHcl = hcl$1;
exports.interpolateHclLong = hclLong;
exports.interpolateCubehelix = cubehelix$2;
exports.interpolateCubehelixLong = interpolateCubehelixLong;
exports.interpolateBasis = basis$2;
exports.interpolateBasisClosed = basisClosed$1;
exports.quantize = quantize;
exports.dispatch = dispatch;
exports.dsvFormat = dsv;
exports.csvParse = csvParse;
exports.csvParseRows = csvParseRows;
exports.csvFormat = csvFormat;
exports.csvFormatRows = csvFormatRows;
exports.tsvParse = tsvParse;
exports.tsvParseRows = tsvParseRows;
exports.tsvFormat = tsvFormat;
exports.tsvFormatRows = tsvFormatRows;
exports.request = request;
exports.html = html;
exports.json = json;
exports.text = text;
exports.xml = xml;
exports.csv = csv$1;
exports.tsv = tsv$1;
exports.now = now;
exports.timer = timer;
exports.timerFlush = timerFlush;
exports.timeout = timeout$1;
exports.interval = interval$1;
exports.timeInterval = newInterval;
exports.timeMillisecond = millisecond;
exports.timeMilliseconds = milliseconds;
exports.timeSecond = second;
exports.timeSeconds = seconds;
exports.timeMinute = minute;
exports.timeMinutes = minutes;
exports.timeHour = hour;
exports.timeHours = hours;
exports.timeDay = day;
exports.timeDays = days;
exports.timeWeek = timeWeek;
exports.timeWeeks = sundays;
exports.timeSunday = timeWeek;
exports.timeSundays = sundays;
exports.timeMonday = timeMonday;
exports.timeMondays = mondays;
exports.timeTuesday = tuesday;
exports.timeTuesdays = tuesdays;
exports.timeWednesday = wednesday;
exports.timeWednesdays = wednesdays;
exports.timeThursday = thursday;
exports.timeThursdays = thursdays;
exports.timeFriday = friday;
exports.timeFridays = fridays;
exports.timeSaturday = saturday;
exports.timeSaturdays = saturdays;
exports.timeMonth = month;
exports.timeMonths = months;
exports.timeYear = year;
exports.timeYears = years;
exports.utcMillisecond = millisecond;
exports.utcMilliseconds = milliseconds;
exports.utcSecond = second;
exports.utcSeconds = seconds;
exports.utcMinute = utcMinute;
exports.utcMinutes = utcMinutes;
exports.utcHour = utcHour;
exports.utcHours = utcHours;
exports.utcDay = utcDay;
exports.utcDays = utcDays;
exports.utcWeek = utcWeek;
exports.utcWeeks = utcSundays;
exports.utcSunday = utcWeek;
exports.utcSundays = utcSundays;
exports.utcMonday = utcMonday;
exports.utcMondays = utcMondays;
exports.utcTuesday = utcTuesday;
exports.utcTuesdays = utcTuesdays;
exports.utcWednesday = utcWednesday;
exports.utcWednesdays = utcWednesdays;
exports.utcThursday = utcThursday;
exports.utcThursdays = utcThursdays;
exports.utcFriday = utcFriday;
exports.utcFridays = utcFridays;
exports.utcSaturday = utcSaturday;
exports.utcSaturdays = utcSaturdays;
exports.utcMonth = utcMonth;
exports.utcMonths = utcMonths;
exports.utcYear = utcYear;
exports.utcYears = utcYears;
exports.formatLocale = formatLocale;
exports.formatDefaultLocale = defaultLocale;
exports.formatSpecifier = formatSpecifier;
exports.precisionFixed = precisionFixed;
exports.precisionPrefix = precisionPrefix;
exports.precisionRound = precisionRound;
exports.isoFormat = formatIso;
exports.isoParse = parseIso;
exports.timeFormatLocale = formatLocale$1;
exports.timeFormatDefaultLocale = defaultLocale$1;
exports.scaleBand = band;
exports.scalePoint = point$4;
exports.scaleIdentity = identity$4;
exports.scaleLinear = linear$2;
exports.scaleLog = log;
exports.scaleOrdinal = ordinal;
exports.scaleImplicit = implicit;
exports.scalePow = pow;
exports.scaleSqrt = sqrt;
exports.scaleQuantile = quantile;
exports.scaleQuantize = quantize$1;
exports.scaleThreshold = threshold$1;
exports.scaleTime = time;
exports.scaleUtc = utcTime;
exports.schemeCategory10 = category10;
exports.schemeCategory20b = category20b;
exports.schemeCategory20c = category20c;
exports.schemeCategory20 = category20;
exports.scaleSequential = sequential;
exports.interpolateCubehelixDefault = cubehelix$3;
exports.interpolateRainbow = rainbow$1;
exports.interpolateWarm = warm;
exports.interpolateCool = cool;
exports.interpolateViridis = viridis;
exports.interpolateMagma = magma;
exports.interpolateInferno = inferno;
exports.interpolatePlasma = plasma;
exports.creator = creator;
exports.customEvent = customEvent;
exports.local = local;
exports.matcher = matcher$1;
exports.mouse = mouse;
exports.namespace = namespace;
exports.namespaces = namespaces;
exports.select = select;
exports.selectAll = selectAll;
exports.selection = selection;
exports.selector = selector;
exports.selectorAll = selectorAll;
exports.touch = touch;
exports.touches = touches;
exports.window = window;
exports.active = active;
exports.interrupt = interrupt;
exports.transition = transition;
exports.axisTop = axisTop;
exports.axisRight = axisRight;
exports.axisBottom = axisBottom;
exports.axisLeft = axisLeft;
exports.cluster = cluster;
exports.hierarchy = hierarchy;
exports.pack = index;
exports.packSiblings = siblings;
exports.packEnclose = enclose;
exports.partition = partition;
exports.stratify = stratify;
exports.tree = tree;
exports.treemap = index$1;
exports.treemapBinary = binary;
exports.treemapDice = treemapDice;
exports.treemapSlice = treemapSlice;
exports.treemapSliceDice = sliceDice;
exports.treemapSquarify = squarify;
exports.treemapResquarify = resquarify;
exports.forceCenter = center$1;
exports.forceCollide = collide;
exports.forceLink = link;
exports.forceManyBody = manyBody;
exports.forceSimulation = simulation;
exports.forceX = x$3;
exports.forceY = y$3;
exports.drag = drag;
exports.dragDisable = dragDisable;
exports.dragEnable = dragEnable;
exports.voronoi = voronoi;
exports.zoom = zoom;
exports.zoomIdentity = identity$6;
exports.zoomTransform = transform;
exports.brush = brush;
exports.brushX = brushX;
exports.brushY = brushY;
exports.brushSelection = brushSelection;
exports.chord = chord;
exports.ribbon = ribbon;
exports.geoAlbers = albers;
exports.geoAlbersUsa = albersUsa;
exports.geoArea = area$2;
exports.geoAzimuthalEqualArea = azimuthalEqualArea;
exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw;
exports.geoAzimuthalEquidistant = azimuthalEquidistant;
exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw;
exports.geoBounds = bounds;
exports.geoCentroid = centroid$1;
exports.geoCircle = circle$1;
exports.geoClipExtent = extent$1;
exports.geoConicConformal = conicConformal;
exports.geoConicConformalRaw = conicConformalRaw;
exports.geoConicEqualArea = conicEqualArea;
exports.geoConicEqualAreaRaw = conicEqualAreaRaw;
exports.geoConicEquidistant = conicEquidistant;
exports.geoConicEquidistantRaw = conicEquidistantRaw;
exports.geoDistance = distance;
exports.geoEquirectangular = equirectangular;
exports.geoEquirectangularRaw = equirectangularRaw;
exports.geoGnomonic = gnomonic;
exports.geoGnomonicRaw = gnomonicRaw;
exports.geoGraticule = graticule;
exports.geoInterpolate = interpolate$2;
exports.geoLength = length$2;
exports.geoMercator = mercator;
exports.geoMercatorRaw = mercatorRaw;
exports.geoOrthographic = orthographic;
exports.geoOrthographicRaw = orthographicRaw;
exports.geoPath = index$3;
exports.geoProjection = projection;
exports.geoProjectionMutator = projectionMutator;
exports.geoRotation = rotation;
exports.geoStereographic = stereographic;
exports.geoStereographicRaw = stereographicRaw;
exports.geoStream = stream;
exports.geoTransform = transform$1;
exports.geoTransverseMercator = transverseMercator;
exports.geoTransverseMercatorRaw = transverseMercatorRaw;
Object.defineProperty(exports, '__esModule', { value: true });
}));
<html><head><meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="siu.css">
<link rel="stylesheet" type="text/css" href="siu-roi.css">
</head>
<body>
<h1>PROTOTYPE HORIZONTAL BEESWARM TO COMPARE ACROSS OUTCOMES</h1>
<h2>Outcomes</h2>
<div><p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere
</p></div>
<div class="selector">Parents: <select id="no-of-parents">
<option value="All">All</option>
<option value="1">1</option>
<option value="2">2</option>
</select></div>
<div class="selector">Children: <select id="no-of-children">
<option value="All">All</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select></div>
<div class="selector">Region: <select id="region">
<option value="All">All</option>
<option value="Auckland">Auckland</option>
<option value="Upper North Island">Upper North Island</option>
<option value="Lower North Island">Lower North Island</option>
<option value="South Island">South Island</option>
</select></div>
<div class="selector">Income: <select id="income">
<option value="All">All</option>
<option value="0 to 15000">0 to 15000</option>
<option value="over 15000">over 15000</option>
</select></div>
<div class="selector">Ethnicity: <select id="ethnicity">
<option value="All">All</option>
<option value="Maori">Maori</option>
<option value="NZEuropean">NZ European</option>
<option value="Other">Other</option>
</select></div>
<div class="selector"><button id="change-button" onclick="resetChart()">Reset</button></div>
<div id="roi-chart"></div>
<h2>Technical reports</h2>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere
</p>
<h2><a href="#">Download the data</a></h2>
<script src="d3.js"></script>
<script src="siu-helper-functions.js"></script>
<script src="roi-pre.js"></script>
</body></html>
var screenWidth = document.documentElement.clientWidth;
var screenHeight = document.documentElement.clientHeight;
var maxWidth = 600;
var preferredWidth = Math.min(600, screenWidth);
var nestedData;
var margin = {top: 30, right: 30, bottom: 10, left: 65},
width = preferredWidth - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
const radius = preferredWidth > 200 ? 5 : 3;
const opacity = {normal: 0.7, focus: 1, muted: 0.2, hidden: 0};
var xScale = d3.scaleLinear()
.rangeRound([0, width]);
var yScale = d3.scaleBand()
.range([height, 0]);
var xAxisTop = d3.axisTop(xScale).tickSize(0);
var xAxisBottom = d3.axisBottom(xScale).tickSize(0);
var familyLine = d3.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.curve(d3.curveLinear);
var colourOutcome = d3.scaleOrdinal()
.range([siuColours.orange10, siuColours.teal10, siuColours.purple10, siuColours.green10, siuColours.greyDark]);
var colourRegion = d3.scaleOrdinal()
.range([siuColours.orange10, siuColours.teal10, siuColours.purple10, siuColours.green10, siuColours.greyDark]);
var svg = d3.select("#roi-chart")
.append("svg")
//.attr("viewBox", "0 0 "+ preferredWidth + " " + (height + margin.top + margin.bottom) )
//.attr("preserveAspectRatio", "xMidYMid meet");
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.on("click", function() {
resetChart();
});
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// LOAD DATA AND CREATE CHARTS
d3.csv("roi2.csv", convertTextToNumbers, function(error, data) {
if (error) throw error;
var averageROI = d3.nest()
.key(function(d) { return d.outcome; } )
.rollup(function(v) { return d3.mean(v, function(d) { return d.roi; } ); } )
.entries(data);
// SET THE SCALES
//xScale.domain(d3.extent(data, function(d) { return d.roi; })).nice();
xScale.domain([
Math.floor(d3.min(data, function(d) { return d.roi; } )),
Math.ceil(d3.max(data, function(d) { return d.roi; } )),
]);
yScale.domain(data.sort(function(a, b) { return b.roi - a.roi; })
.map(function(d) { return d.outcome; }) );
colourOutcome.domain(xScale.domain());
colourRegion.domain(data.sort(function(a, b) { return b.roi - a.roi; })
.map(function(d) { return d.region; }) );
xAxisTop.ticks( (xScale.domain()[1] - xScale.domain()[0] + 1) );
xAxisBottom.ticks( (xScale.domain()[1] - xScale.domain()[0] + 1) );
// DRAW THE LABELS AND GRID LINES
var yLabels = g.selectAll(".y-label")
.data(yScale.domain())
.enter()
.append("text")
.attr("class", "y-label")
.attr("y", function(d) { return yScale(d) + yScale.bandwidth()/2; })
.attr("x", -10)
.text(function(d){ return capitalizeFirstLetter(d); });
var gXAxisTop = g.append("g")
.attr("class", "axis-top")
.attr("transform", "translate(0,0)")
.call(xAxisTop);
const arrowMargin = 10;
gXAxisTop.append("text")
.text("Negative return")
.attr("x", xScale(1) - arrowMargin)
.attr("y", -arrowMargin)
.attr("class", "negative-label");
gXAxisTop.append("text")
.text("Postive return")
.attr("x", xScale(1) + arrowMargin)
.attr("y", -arrowMargin)
.attr("class", "positive-label");
//arrow head
gXAxisTop.append("defs").append("marker")
.attr("id", "arrowhead-bottom")
.attr("class", "axis-arrow")
.attr("markerWidth", "13")
.attr("markerHeight", "13")
.attr("refX", "8")
.attr("refY", "6")
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M1,1 L8,6 L1,11 ");
var arrow = gXAxisTop.append("g")
.attr("class", "axis-arrow")
.attr("transform", "translate(" + xScale(1) + "," + -6 +")");
arrow.append("line")
.attr("class", "axis-arrow")
.attr("x1", arrowMargin)
.attr("y1", 0)
.attr("x2", 100)
.attr("y2", 0)
.attr("marker-end", "url(#arrowhead-bottom)");
arrow.append("line")
.attr("class", "axis-arrow")
.attr("x1", -arrowMargin)
.attr("y1", 0)
.attr("x2", -100)
.attr("y2", 0)
.attr("marker-end", "url(#arrowhead-bottom)");
gXAxisTop.selectAll(".tick").selectAll("text")
.text(function(d) { return d === 1 ? "" : "ROI: " + d; });
var gridLines = g.selectAll(".axis-top").selectAll(".tick")
.append("line")
.attr("class", "gridLine")
.attr("x1", 0)
.attr("y1", function(d) {return d === 1 ? -margin.top : 0; })
.attr("x2", 0)
.attr("y2", height );
var gXAxisBottom = g.append("g")
.attr("class", "axis-bottom")
.attr("transform", "translate(0," + height + ")" )
.call(xAxisBottom);
gXAxisBottom.selectAll(".tick").selectAll("text")
.text(function(d) { return "ROI: " + d; });
var avgLines = g.selectAll(".avg-lines")
.data(averageROI)
.enter()
.append("g")
.attr("class", "avg-line")
.attr("transform", function(d) { return "translate("+ xScale(d.value) + "," + yScale(d.key) + ")"; });
avgLines.append("line")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", 16)
.attr("y2", yScale.bandwidth() -5 );
avgLines.append("text")
.text(function(d) { return "avg: "+ oneDecimalPlace(d.value); } )
.attr("x", 3 )
.attr("y", 13 );
// ENABLE THE DROP DOWN SELECTS
var select = d3.selectAll("select");
select.on("change", function(d) {
var selectedParents = d3.select("#no-of-parents").property("value");
var selectedChildren = d3.select("#no-of-children").property("value");
var selectedRegion = d3.select("#region").property("value");
var selectedIncome = d3.select("#income").property("value");
var selectedEthnicity = d3.select("#ethnicity").property("value");
highlightFamilies(selectedParents, selectedChildren, selectedRegion, selectedIncome, selectedEthnicity);
});
// CREATE THE FORCE, TO LAYOUT THE CIRCLES - IE. SET THE X,Y COORDS.
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) { return xScale(d.roi); }).strength(1))
.force("y", d3.forceY(function(d) { return yScale(d.outcome) + yScale.bandwidth() * yScale.align(); }))
.force("collide", d3.forceCollide(radius+1))
//.on('tick', ticked)
.stop();
for (var i = 0; i < 120; ++i) simulation.tick();
// CREATE THE VORONOI LAYOUT TO ENABLE EASIER SELECTION
var voronoi = d3.voronoi()
.extent([[-margin.left, -margin.top], [width + margin.right, height + margin.top]])
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
voronoiData = voronoi(data).polygons();
// CREATE A NESTED DATASET FOR THE FAMILY LINES
nestedData = d3.nest()
.key(function(d) {return d.data.familyID2;})
.entries(voronoiData);
var lineData = [];
nestedData.forEach(function(d) {
lineData.push({familyID2: d.key, points: [] });
});
lineData.forEach(function(d) {
nestedData.forEach(function(p) {
if (d.familyID2 === p.key) {
var pointsToPush = [];
p.values.forEach(function(v) {
pointsToPush.push({x: v.data.x, y: v.data.y})
});
pointsToPush.sort(function(a, b) {
return a.y - b.y;
});
d.points = pointsToPush;
};
});
});
// DRAW THE FAMILY LINES FIRST TO APPEAR UNDER THE CIRCLES
var gLines = g.selectAll(".g-family-line")
.data(lineData)
.enter()
.append("g")
.attr("class", "g-family-line")
.attr("id",function(d) { return "g-family-line-" + d.familyID2; } );
gLines.append("path")
.attr("id", function(d) { return "family-line-" + d.familyID2; })
.datum(function(d) { return d.points; } )
.attr("class", "family-line")
.attr("d", familyLine)
.style("stroke-opacity", opacity.hidden)
// DRAW THE THE CIRCLES
var cell = g.append("g")
.attr("class", "cells")
.selectAll("g").data(voronoiData)
.enter()
.append("g")
.attr("class", "polys");
cell.append("circle")
.attr("r", radius)
.attr("cx", function(d) { return d.data.x; })
.attr("cy", function(d) { return d.data.y; })
.style("fill", function(d) { return colourRegion(d.data.region); } )
.style("fill-opacity", opacity.normal );
var researchClip = g.append("defs").selectAll("clipPath")
.data(voronoiData)
.enter()
.append("clipPath")
.attr("id", function(d) { return "clip-research-" + d.data.id; })
.append("circle")
.attr("cx", function(d) { return d.data.x; })
.attr("cy", function(d) { return d.data.y; })
.attr("r", radius + 20 );
cell.append("path")
.attr("class", "clipped-paths")
//.style("stroke", "grey")
.attr("d", function(d) { return "M" + d.join("L") + "Z"; })
.attr("clip-path", function(d) { return "url(#clip-research-" + d.data.id + ")"; })
.on("click", showHideCircles);
cell.append("title")
.text(function(d) { return d.data.roi + "%" +
"\nParents: " + d.data.parents +
"\nChildren: " + d.data.children; });
});
// FUNCTIONS
// RESET THE CIRCLE FORMATTING
function resetChart() {
setSelectValues("All", "All", "All", "All", "All");
resetLineCircles();
d3.selectAll(".clipped-paths")
.each(function(d) { d.data.highlighted = false; } );
};
function resetLineCircles() {
d3.selectAll(".family-line")
.style("stroke-opacity", opacity.hidden );
d3.selectAll(".polys")
.selectAll("circle")
.style("stroke", "none")
.style("fill-opacity", opacity.normal );
};
// handle the click
function showHideCircles (d) {
resetLineCircles();
if (d.data.highlighted) {
d3.selectAll(".clipped-paths")
.each(function(d) { d.data.highlighted = false; } );
setSelectValues("All", "All", "All", "All", "All");
} else {
var thisFamily = d.data.familyID2;
d3.selectAll(".clipped-paths").filter(function(d) { return d.data.familyID2 === thisFamily; } )
.each(function(d) { d.data.highlighted = true; } );
d.data.highlighted = true;
highlightFamily(d.data.familyID2);
setSelectValues(d.data.parents, d.data.children, d.data.region, d.data.income, d.data.ethnicity);
};
d3.event.stopPropagation();
} ;
// HIGHLIGHT ALL FAMILIES THAT MATCH THE SELECTED VALUES
function highlightFamilies(noOfParents, noOfChildren, region, income, ethnicity) {
var thisParents = noOfParents;
var thisChildren = noOfChildren;
var thisRegion = region;
var thisIncome = income;
var thisEthnicity = ethnicity;
resetLineCircles();
if (thisParents !== "All" && thisChildren !== "All" && thisRegion !== "All" && thisIncome !== "All" && thisEthnicity !== "All") {
var thisID = "" + thisParents + thisChildren + thisRegion + thisIncome + thisEthnicity;
thisID = thisID.replace(/\s/g, ''); //remove white spaces
highlightFamily(thisID);
} else if (thisParents !== "All" || thisChildren !== "All" || thisRegion !== "All" || thisIncome !== "All" || thisEthnicity !== "All") {
d3.selectAll(".polys")
.selectAll("circle")
.style("stroke", "none")
.style("fill-opacity", opacity.muted);
var filteredSelection = d3.selectAll(".polys")
.selectAll("circle");
if (thisParents !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.parents == thisParents; }) };
if (thisChildren !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.children == thisChildren; }) };
if (thisRegion !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.region == thisRegion; }) };
if (thisIncome !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.income == thisIncome; }) };
if (thisEthnicity !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.ethnicity == thisEthnicity; }) };
filteredSelection
.style("stroke", "black")
.style("fill-opacity", opacity.focus);
};
}; // end of function highlightFamilies
// HIGHLIGHT A CERTAIN FAMILY TYPE
function highlightFamily(familyID) {
var thisID = familyID;
d3.selectAll(".polys")
.selectAll("circle")
.style("stroke", function (d) { return d.data.familyID2 === thisID ? "black" : "none" ; })
.style("fill-opacity", function (d) { return d.data.familyID2 === thisID ? opacity.focus : opacity.muted ; });
d3.selectAll("#family-line-"+thisID)
.style("stroke-opacity", opacity.focus );
}; // end of function highlightFamily
// SET THE DROP DOWN VALUES BASED ON HIGHLIGHED CIRCLES
function setSelectValues(parentToSelect, childrenToSelect, regionToSelect, incomeToSelect, ethnicityToSelect) {
d3.select("#no-of-parents").property("value", parentToSelect);
d3.select("#no-of-children").property("value", childrenToSelect);
d3.select("#region").property("value", regionToSelect);
d3.select("#income").property("value", incomeToSelect);
d3.select("#ethnicity").property("value", ethnicityToSelect);
};
//CONVERT CSV TEXT TO NUMBERS
function convertTextToNumbers(d) {
d.id = +d.id;
d.familyID = +d.familyID;
d.parents = +d.parents;
d.children = +d.children;
d.roi = +d.roi;
return d;
};
// RESIZE LISTENER
addEvent(window, "resize", function(event) {
console.log('resized');
screenWidth = document.documentElement.clientWidth;
screenHeight = document.documentElement.clientHeight;
console.log("w: " + screenWidth + " h: " + screenHeight );
preferredWidth = Math.min(600, screenWidth);
console.log("p: " + preferredWidth);
});
id familyID familyID2 parents children region income ethnicity outcome roi
1 1 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori health 1.536
9 1 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori education 0.844
17 1 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori crime 2.063
25 1 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori income 2.469
33 1 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori housing 1.489
321 2 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other health 1.012
329 2 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other education 0.703
337 2 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other crime 1.544
345 2 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other income 1.274
353 2 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other housing 0.937
161 3 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean health 1.726
169 3 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean education 1.758
177 3 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean crime 1.968
185 3 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean income 1.936
193 3 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean housing 1.043
81 7 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori health 1.675
89 7 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori education 1.698
97 7 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori crime 1.718
105 7 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori income 2.245
113 7 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori housing 0.797
401 8 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other health 1.464
409 8 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other education 1.391
417 8 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other crime 0.967
425 8 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other income 1.755
433 8 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other housing 1.043
241 9 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean health 2.49
249 9 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean education 1.662
257 9 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean crime 0.819
265 9 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean income 2.451
273 9 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean housing 0.832
121 13 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori health 1.2
129 13 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori education 1.758
137 13 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori crime 1.996
145 13 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori income 1.112
153 13 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori housing 2.183
441 14 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other health 0.978
449 14 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other education 2.233
457 14 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other crime 1.865
465 14 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other income 1.994
473 14 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other housing 1.266
281 15 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean health 1.991
289 15 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean education 2.192
297 15 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean crime 1.064
305 15 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean income 1.651
313 15 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean housing 0.766
41 19 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori health 1.162
49 19 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori education 1.483
57 19 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori crime 1.022
65 19 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori income 2.372
73 19 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori housing 0.978
361 20 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other health 2.313
369 20 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other education 1.844
377 20 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other crime 0.977
385 20 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other income 0.706
393 20 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other housing 2.296
201 21 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean health 2.294
209 21 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean education 0.756
217 21 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean crime 1.97
225 21 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean income 1.579
233 21 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean housing 2.239
2 25 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori health 1.521
10 25 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori education 1.389
18 25 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori crime 0.821
26 25 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori income 1.094
34 25 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori housing 1.965
322 26 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other health 1.232
330 26 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other education 2.061
338 26 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other crime 1.353
346 26 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other income 0.903
354 26 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other housing 2.321
162 27 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean health 0.906
170 27 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean education 1.842
178 27 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean crime 1.379
186 27 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean income 2.423
194 27 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean housing 2.404
82 31 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori health 2.186
90 31 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori education 1.157
98 31 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori crime 0.841
106 31 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori income 2.431
114 31 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori housing 1.126
402 32 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other health 0.718
410 32 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other education 2.142
418 32 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other crime 1.568
426 32 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other income 1.062
434 32 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other housing 1.144
242 33 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean health 1.522
250 33 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean education 2.468
258 33 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean crime 1.923
266 33 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean income 1.323
274 33 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean housing 1.476
122 37 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori health 2.006
130 37 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori education 1.149
138 37 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori crime 0.862
146 37 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori income 1.801
154 37 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori housing 1.135
442 38 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other health 0.74
450 38 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other education 1.19
458 38 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other crime 1.208
466 38 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other income 2.383
474 38 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other housing 1.792
282 39 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean health 1.49
290 39 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean education 1.075
298 39 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean crime 2.075
306 39 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean income 2.456
314 39 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean housing 2.289
42 43 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori health 2.289
50 43 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori education 1.418
58 43 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori crime 0.828
66 43 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori income 0.799
74 43 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori housing 2.399
362 44 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other health 1.2
370 44 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other education 1.3
378 44 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other crime 1.284
386 44 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other income 1.105
394 44 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other housing 1.971
202 45 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean health 1.745
210 45 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean education 0.759
218 45 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean crime 1.591
226 45 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean income 1.057
234 45 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean housing 1.672
3 49 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori health 1.269
11 49 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori education 0.78
19 49 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori crime 2.274
27 49 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori income 0.726
35 49 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori housing 1.402
323 50 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other health 1.836
331 50 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other education 1.286
339 50 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other crime 0.745
347 50 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other income 1.19
355 50 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other housing 1.327
163 51 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean health 2.074
171 51 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean education 1.862
179 51 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean crime 1.673
187 51 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean income 1.459
195 51 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean housing 0.972
83 55 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori health 0.741
91 55 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori education 0.94
99 55 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori crime 2.349
107 55 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori income 0.959
115 55 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori housing 1.643
403 56 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other health 1.812
411 56 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other education 1.076
419 56 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other crime 1.797
427 56 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other income 1.842
435 56 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other housing 0.758
243 57 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean health 1.137
251 57 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean education 0.844
259 57 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean crime 2.405
267 57 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean income 1.494
275 57 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean housing 0.844
123 61 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori health 1.815
131 61 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori education 2.391
139 61 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori crime 0.84
147 61 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori income 2.349
155 61 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori housing 1.265
443 62 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other health 1.81
451 62 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other education 1.644
459 62 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other crime 0.916
467 62 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other income 1.011
475 62 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other housing 1.321
283 63 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean health 1.388
291 63 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean education 2.459
299 63 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean crime 2.16
307 63 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean income 1.507
315 63 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean housing 1.007
43 67 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori health 1.924
51 67 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori education 1.727
59 67 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori crime 0.752
67 67 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori income 2.169
75 67 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori housing 2.043
363 68 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other health 1.534
371 68 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other education 2.39
379 68 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other crime 2.391
387 68 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other income 1.689
395 68 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other housing 0.813
203 69 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean health 0.978
211 69 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean education 0.802
219 69 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean crime 1.425
227 69 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean income 0.727
235 69 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean housing 1.483
4 73 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori health 1.313
12 73 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori education 0.848
20 73 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori crime 1.668
28 73 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori income 0.786
36 73 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori housing 1.335
324 74 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other health 1.837
332 74 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other education 1.092
340 74 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other crime 2.257
348 74 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other income 1.428
356 74 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other housing 1.263
164 75 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean health 2.415
172 75 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean education 1.148
180 75 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean crime 2.46
188 75 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean income 2.31
196 75 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean housing 1.164
84 79 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori health 1.928
92 79 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori education 1.425
100 79 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori crime 0.984
108 79 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori income 2.155
116 79 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori housing 2.388
404 80 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other health 1.25
412 80 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other education 1.21
420 80 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other crime 2.085
428 80 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other income 1.217
436 80 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other housing 2.474
244 81 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean health 1.786
252 81 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean education 2.158
260 81 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean crime 2.03
268 81 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean income 2.081
276 81 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean housing 2.057
124 85 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori health 1.359
132 85 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori education 2.441
140 85 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori crime 2.374
148 85 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori income 1.02
156 85 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori housing 1.481
444 86 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other health 1.68
452 86 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other education 0.994
460 86 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other crime 2.4
468 86 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other income 1.04
476 86 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other housing 1.812
284 87 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean health 1.314
292 87 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean education 2.288
300 87 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean crime 2.266
308 87 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean income 1.864
316 87 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean housing 1.994
44 91 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori health 2.264
52 91 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori education 1.27
60 91 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori crime 1.264
68 91 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori income 1.11
76 91 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori housing 1.619
364 92 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other health 1.72
372 92 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other education 0.72
380 92 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other crime 1.139
388 92 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other income 1.977
396 92 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other housing 1.917
204 93 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean health 1.181
212 93 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean education 0.903
220 93 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean crime 1.765
228 93 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean income 1.334
236 93 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean housing 1.223
5 97 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori health 2.443
13 97 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori education 0.82
21 97 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori crime 0.885
29 97 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori income 2.211
37 97 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori housing 1.283
325 98 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other health 1.163
333 98 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other education 1.67
341 98 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other crime 0.772
349 98 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other income 1.782
357 98 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other housing 1.586
165 99 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean health 2.349
173 99 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean education 2.134
181 99 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean crime 1.242
189 99 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean income 1.529
197 99 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean housing 1.961
85 103 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori health 1.738
93 103 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori education 1.562
101 103 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori crime 2.016
109 103 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori income 1.919
117 103 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori housing 0.991
405 104 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other health 1.467
413 104 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other education 0.806
421 104 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other crime 2.422
429 104 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other income 1.042
437 104 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other housing 1.605
245 105 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean health 0.96
253 105 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean education 2.048
261 105 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean crime 2.377
269 105 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean income 2.13
277 105 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean housing 0.916
125 109 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori health 1.049
133 109 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori education 1.561
141 109 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori crime 2.465
149 109 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori income 2.357
157 109 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori housing 2.479
445 110 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other health 2.306
453 110 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other education 2.355
461 110 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other crime 1.142
469 110 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other income 2.06
477 110 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other housing 1.396
285 111 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean health 2.026
293 111 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean education 0.818
301 111 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean crime 1.792
309 111 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean income 1.44
317 111 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean housing 0.826
45 115 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori health 2.156
53 115 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori education 1.904
61 115 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori crime 2.168
69 115 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori income 1.22
77 115 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori housing 2.093
365 116 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other health 2.408
373 116 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other education 1.401
381 116 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other crime 1.698
389 116 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other income 2.394
397 116 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other housing 1.947
205 117 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean health 1.411
213 117 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean education 1.765
221 117 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean crime 1.466
229 117 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean income 0.874
237 117 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean housing 0.873
6 121 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori health 2.484
14 121 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori education 2.171
22 121 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori crime 1.29
30 121 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori income 1.676
38 121 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori housing 1.277
326 122 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other health 1.832
334 122 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other education 1.778
342 122 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other crime 2.49
350 122 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other income 0.932
358 122 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other housing 0.816
166 123 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean health 0.727
174 123 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean education 2.179
182 123 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean crime 1.34
190 123 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean income 1.465
198 123 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean housing 1.444
86 127 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori health 1.117
94 127 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori education 2.196
102 127 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori crime 1.595
110 127 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori income 2.25
118 127 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori housing 1.343
406 128 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other health 1.938
414 128 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other education 2.132
422 128 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other crime 1.057
430 128 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other income 1.473
438 128 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other housing 2.125
246 129 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean health 1.119
254 129 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean education 0.815
262 129 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean crime 2.264
270 129 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean income 1.242
278 129 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean housing 1.123
126 133 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori health 1.258
134 133 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori education 1.325
142 133 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori crime 1.281
150 133 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori income 0.83
158 133 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori housing 1.263
446 134 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other health 2.091
454 134 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other education 1.379
462 134 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other crime 2.33
470 134 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other income 2.069
478 134 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other housing 2.206
286 135 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean health 0.993
294 135 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean education 1.545
302 135 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean crime 1.65
310 135 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean income 1.625
318 135 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean housing 1.783
46 139 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori health 2.31
54 139 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori education 1.076
62 139 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori crime 2.481
70 139 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori income 1.921
78 139 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori housing 0.793
366 140 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other health 1.142
374 140 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other education 0.727
382 140 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other crime 1.644
390 140 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other income 0.93
398 140 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other housing 2.4
206 141 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean health 1.707
214 141 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean education 2.476
222 141 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean crime 2.049
230 141 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean income 1.642
238 141 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean housing 1.068
7 145 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori health 1.578
15 145 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori education 1.8
23 145 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori crime 2.409
31 145 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori income 2.065
39 145 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori housing 1.453
327 146 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other health 2.379
335 146 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other education 1.386
343 146 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other crime 2.3
351 146 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other income 0.955
359 146 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other housing 0.863
167 147 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean health 2.295
175 147 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean education 2
183 147 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean crime 1.221
191 147 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean income 1.374
199 147 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean housing 2.156
87 151 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori health 1.574
95 151 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori education 1.307
103 151 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori crime 1.758
111 151 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori income 0.857
119 151 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori housing 2.111
407 152 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other health 1.045
415 152 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other education 1.824
423 152 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other crime 1.864
431 152 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other income 2.287
439 152 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other housing 1.019
247 153 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean health 0.958
255 153 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean education 0.95
263 153 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean crime 2.154
271 153 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean income 0.933
279 153 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean housing 0.771
127 157 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori health 1.061
135 157 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori education 2.219
143 157 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori crime 2.181
151 157 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori income 0.758
159 157 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori housing 1.728
447 158 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other health 2.262
455 158 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other education 2.298
463 158 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other crime 2.125
471 158 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other income 2.242
479 158 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other housing 2.492
287 159 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean health 0.729
295 159 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean education 1.18
303 159 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean crime 2.088
311 159 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean income 1.605
319 159 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean housing 1.192
47 163 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori health 1.742
55 163 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori education 0.868
63 163 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori crime 2.18
71 163 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori income 1.795
79 163 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori housing 1.936
367 164 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other health 2.087
375 164 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other education 1.781
383 164 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other crime 2.346
391 164 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other income 0.731
399 164 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other housing 2.267
207 165 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean health 0.779
215 165 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean education 2.464
223 165 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean crime 1.933
231 165 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean income 1.323
239 165 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean housing 2.138
8 169 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori health 0.785
16 169 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori education 1.756
24 169 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori crime 0.989
32 169 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori income 0.924
40 169 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori housing 1.811
328 170 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other health 1.198
336 170 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other education 1.736
344 170 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other crime 1.93
352 170 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other income 2.106
360 170 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other housing 2.208
168 171 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean health 2.19
176 171 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean education 1.428
184 171 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean crime 1.722
192 171 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean income 1.369
200 171 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean housing 1.142
88 175 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori health 1.338
96 175 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori education 2.257
104 175 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori crime 1.643
112 175 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori income 2.388
120 175 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori housing 2.474
408 176 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other health 1.849
416 176 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other education 0.826
424 176 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other crime 1.249
432 176 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other income 2.319
440 176 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other housing 2.237
248 177 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean health 1.462
256 177 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean education 1.988
264 177 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean crime 1.546
272 177 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean income 2.11
280 177 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean housing 2.133
128 181 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori health 1.627
136 181 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori education 2.229
144 181 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori crime 2.293
152 181 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori income 1.734
160 181 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori housing 1.975
448 182 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other health 0.785
456 182 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other education 1.507
464 182 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other crime 1.412
472 182 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other income 1.092
480 182 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other housing 1.321
288 183 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean health 2.127
296 183 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean education 1.152
304 183 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean crime 2.05
312 183 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean income 1.71
320 183 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean housing 0.826
48 187 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori health 1.847
56 187 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori education 1.001
64 187 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori crime 0.908
72 187 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori income 1.351
80 187 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori housing 2.371
368 188 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other health 1.779
376 188 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other education 0.762
384 188 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other crime 2.085
392 188 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other income 2.407
400 188 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other housing 1.727
208 189 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean health 2.265
216 189 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean education 1.701
224 189 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean crime 2.225
232 189 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean income 2.497
240 189 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean housing 2.332
481 4 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori health 2.105
489 4 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori education 2.336
497 4 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori crime 1.599
505 4 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori income 2.04
513 4 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori housing 0.871
801 5 11Aucklandover15000Other 1 1 Auckland over 15000 Other health 1.147
809 5 11Aucklandover15000Other 1 1 Auckland over 15000 Other education 2.018
817 5 11Aucklandover15000Other 1 1 Auckland over 15000 Other crime 1.963
825 5 11Aucklandover15000Other 1 1 Auckland over 15000 Other income 1.44
833 5 11Aucklandover15000Other 1 1 Auckland over 15000 Other housing 2.09
641 6 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean health 0.947
649 6 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean education 2.329
657 6 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean crime 1.901
665 6 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean income 1.409
673 6 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean housing 2.316
561 10 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori health 1.999
569 10 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori education 1.387
577 10 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori crime 2.013
585 10 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori income 0.836
593 10 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori housing 1.437
881 11 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other health 1.619
889 11 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other education 0.762
897 11 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other crime 1.589
905 11 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other income 1.263
913 11 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other housing 0.901
721 12 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean health 1.574
729 12 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean education 1.011
737 12 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean crime 2.015
745 12 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean income 1.956
753 12 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean housing 1.886
601 16 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori health 2.136
609 16 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori education 1.682
617 16 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori crime 2.146
625 16 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori income 2.004
633 16 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori housing 1.96
921 17 11SouthIslandover15000Other 1 1 South Island over 15000 Other health 1.743
929 17 11SouthIslandover15000Other 1 1 South Island over 15000 Other education 0.815
937 17 11SouthIslandover15000Other 1 1 South Island over 15000 Other crime 1.881
945 17 11SouthIslandover15000Other 1 1 South Island over 15000 Other income 1.717
953 17 11SouthIslandover15000Other 1 1 South Island over 15000 Other housing 1.723
761 18 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean health 1.85
769 18 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean education 1.928
777 18 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean crime 2.333
785 18 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean income 1.714
793 18 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean housing 1.977
521 22 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori health 2.004
529 22 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori education 2.075
537 22 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori crime 1.287
545 22 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori income 1.376
553 22 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori housing 2.047
841 23 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other health 1.781
849 23 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other education 1.259
857 23 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other crime 1.887
865 23 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other income 2.4
873 23 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other housing 1.425
681 24 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean health 0.993
689 24 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean education 1.058
697 24 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean crime 1.803
705 24 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean income 1.122
713 24 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean housing 2.068
482 28 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori health 1.852
490 28 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori education 2.011
498 28 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori crime 1.315
506 28 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori income 1.293
514 28 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori housing 1.64
802 29 12Aucklandover15000Other 1 2 Auckland over 15000 Other health 2.056
810 29 12Aucklandover15000Other 1 2 Auckland over 15000 Other education 1.539
818 29 12Aucklandover15000Other 1 2 Auckland over 15000 Other crime 1.255
826 29 12Aucklandover15000Other 1 2 Auckland over 15000 Other income 0.784
834 29 12Aucklandover15000Other 1 2 Auckland over 15000 Other housing 2.23
642 30 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean health 1.497
650 30 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean education 1.229
658 30 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean crime 2.087
666 30 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean income 1.83
674 30 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean housing 2.367
562 34 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori health 1.896
570 34 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori education 2.082
578 34 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori crime 1.192
586 34 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori income 0.928
594 34 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori housing 1.936
882 35 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other health 1.889
890 35 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other education 0.887
898 35 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other crime 0.926
906 35 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other income 0.905
914 35 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other housing 1.319
722 36 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean health 0.845
730 36 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean education 1.907
738 36 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean crime 2.31
746 36 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean income 0.987
754 36 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean housing 2.373
602 40 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori health 1.257
610 40 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori education 1.874
618 40 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori crime 1.008
626 40 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori income 0.975
634 40 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori housing 1.447
922 41 12SouthIslandover15000Other 1 2 South Island over 15000 Other health 1.96
930 41 12SouthIslandover15000Other 1 2 South Island over 15000 Other education 1.402
938 41 12SouthIslandover15000Other 1 2 South Island over 15000 Other crime 2.26
946 41 12SouthIslandover15000Other 1 2 South Island over 15000 Other income 1.324
954 41 12SouthIslandover15000Other 1 2 South Island over 15000 Other housing 1.633
762 42 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean health 0.728
770 42 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean education 2.14
778 42 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean crime 2.393
786 42 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean income 2.076
794 42 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean housing 0.832
522 46 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori health 2.441
530 46 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori education 0.922
538 46 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori crime 0.842
546 46 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori income 1.744
554 46 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori housing 1.014
842 47 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other health 1.973
850 47 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other education 0.821
858 47 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other crime 1.539
866 47 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other income 1.645
874 47 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other housing 2.092
682 48 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean health 2.127
690 48 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean education 1.828
698 48 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean crime 1.439
706 48 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean income 1.723
714 48 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean housing 0.889
483 52 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori health 1.503
491 52 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori education 0.871
499 52 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori crime 0.891
507 52 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori income 0.751
515 52 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori housing 2.295
803 53 13Aucklandover15000Other 1 3 Auckland over 15000 Other health 2.439
811 53 13Aucklandover15000Other 1 3 Auckland over 15000 Other education 0.807
819 53 13Aucklandover15000Other 1 3 Auckland over 15000 Other crime 1.961
827 53 13Aucklandover15000Other 1 3 Auckland over 15000 Other income 0.882
835 53 13Aucklandover15000Other 1 3 Auckland over 15000 Other housing 2.497
643 54 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean health 0.896
651 54 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean education 1.417
659 54 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean crime 2.17
667 54 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean income 2.228
675 54 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean housing 1.063
563 58 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori health 1.029
571 58 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori education 0.962
579 58 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori crime 1.593
587 58 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori income 1.63
595 58 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori housing 1.468
883 59 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other health 1.416
891 59 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other education 1.547
899 59 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other crime 0.722
907 59 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other income 1.407
915 59 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other housing 2.479
723 60 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean health 1.119
731 60 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean education 2.18
739 60 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean crime 1.041
747 60 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean income 1.705
755 60 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean housing 2.428
603 64 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori health 0.957
611 64 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori education 1.035
619 64 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori crime 0.874
627 64 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori income 1.103
635 64 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori housing 1.686
923 65 13SouthIslandover15000Other 1 3 South Island over 15000 Other health 2.459
931 65 13SouthIslandover15000Other 1 3 South Island over 15000 Other education 1.351
939 65 13SouthIslandover15000Other 1 3 South Island over 15000 Other crime 1.3
947 65 13SouthIslandover15000Other 1 3 South Island over 15000 Other income 1.354
955 65 13SouthIslandover15000Other 1 3 South Island over 15000 Other housing 1.412
763 66 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean health 1.245
771 66 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean education 1.04
779 66 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean crime 1.451
787 66 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean income 0.841
795 66 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean housing 1.049
523 70 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori health 0.912
531 70 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori education 2.112
539 70 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori crime 0.749
547 70 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori income 1.173
555 70 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori housing 1.412
843 71 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other health 2.284
851 71 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other education 2.184
859 71 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other crime 1.315
867 71 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other income 1.607
875 71 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other housing 2.412
683 72 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean health 2.004
691 72 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean education 1.944
699 72 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean crime 2.201
707 72 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean income 0.763
715 72 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean housing 2.27
484 76 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori health 1.782
492 76 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori education 1.106
500 76 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori crime 2.07
508 76 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori income 0.761
516 76 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori housing 1.449
804 77 14Aucklandover15000Other 1 4 Auckland over 15000 Other health 1.292
812 77 14Aucklandover15000Other 1 4 Auckland over 15000 Other education 1.658
820 77 14Aucklandover15000Other 1 4 Auckland over 15000 Other crime 2.183
828 77 14Aucklandover15000Other 1 4 Auckland over 15000 Other income 1.169
836 77 14Aucklandover15000Other 1 4 Auckland over 15000 Other housing 1.267
644 78 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean health 0.935
652 78 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean education 1.547
660 78 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean crime 0.92
668 78 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean income 1.941
676 78 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean housing 1.322
564 82 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori health 1.781
572 82 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori education 2.048
580 82 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori crime 1.006
588 82 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori income 2.42
596 82 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori housing 2.272
884 83 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other health 1.116
892 83 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other education 2.247
900 83 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other crime 2.239
908 83 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other income 1.726
916 83 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other housing 1.338
724 84 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean health 2.303
732 84 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean education 1.372
740 84 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean crime 1.208
748 84 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean income 1.317
756 84 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean housing 1.933
604 88 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori health 0.736
612 88 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori education 1.52
620 88 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori crime 2.383
628 88 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori income 1.375
636 88 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori housing 1.842
924 89 14SouthIslandover15000Other 1 4 South Island over 15000 Other health 1.923
932 89 14SouthIslandover15000Other 1 4 South Island over 15000 Other education 1.197
940 89 14SouthIslandover15000Other 1 4 South Island over 15000 Other crime 0.715
948 89 14SouthIslandover15000Other 1 4 South Island over 15000 Other income 2.248
956 89 14SouthIslandover15000Other 1 4 South Island over 15000 Other housing 1.659
764 90 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean health 0.915
772 90 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean education 1.46
780 90 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean crime 1.92
788 90 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean income 0.946
796 90 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean housing 1.989
524 94 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori health 2.032
532 94 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori education 1.753
540 94 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori crime 0.776
548 94 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori income 2.166
556 94 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori housing 1.44
844 95 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other health 1.898
852 95 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other education 1.822
860 95 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other crime 2.157
868 95 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other income 1.687
876 95 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other housing 0.818
684 96 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean health 2.474
692 96 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean education 1.829
700 96 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean crime 2.33
708 96 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean income 1.537
716 96 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean housing 1.022
485 100 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori health 1.829
493 100 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori education 2.045
501 100 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori crime 2.23
509 100 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori income 2.437
517 100 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori housing 2.449
805 101 21Aucklandover15000Other 2 1 Auckland over 15000 Other health 1.991
813 101 21Aucklandover15000Other 2 1 Auckland over 15000 Other education 1.037
821 101 21Aucklandover15000Other 2 1 Auckland over 15000 Other crime 1.018
829 101 21Aucklandover15000Other 2 1 Auckland over 15000 Other income 1.494
837 101 21Aucklandover15000Other 2 1 Auckland over 15000 Other housing 1.296
645 102 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean health 1.746
653 102 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean education 1.355
661 102 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean crime 2.116
669 102 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean income 0.956
677 102 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean housing 1.947
565 106 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori health 1.966
573 106 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori education 1.294
581 106 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori crime 2.1
589 106 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori income 1.579
597 106 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori housing 1.373
885 107 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other health 1.114
893 107 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other education 2.146
901 107 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other crime 1.759
909 107 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other income 1.647
917 107 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other housing 1.734
725 108 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean health 0.956
733 108 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean education 1.067
741 108 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean crime 2.238
749 108 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean income 1.928
757 108 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean housing 2.376
605 112 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori health 0.829
613 112 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori education 1.615
621 112 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori crime 1.484
629 112 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori income 0.83
637 112 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori housing 0.952
925 113 21SouthIslandover15000Other 2 1 South Island over 15000 Other health 1.102
933 113 21SouthIslandover15000Other 2 1 South Island over 15000 Other education 1.884
941 113 21SouthIslandover15000Other 2 1 South Island over 15000 Other crime 2.025
949 113 21SouthIslandover15000Other 2 1 South Island over 15000 Other income 1.939
957 113 21SouthIslandover15000Other 2 1 South Island over 15000 Other housing 1.212
765 114 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean health 2.14
773 114 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean education 1.489
781 114 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean crime 1.207
789 114 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean income 1.83
797 114 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean housing 1.876
525 118 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori health 2.253
533 118 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori education 2.099
541 118 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori crime 1.247
549 118 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori income 1.908
557 118 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori housing 1.85
845 119 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other health 2.361
853 119 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other education 2.046
861 119 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other crime 0.843
869 119 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other income 0.89
877 119 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other housing 2.346
685 120 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean health 0.743
693 120 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean education 1.235
701 120 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean crime 2.333
709 120 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean income 0.79
717 120 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean housing 1.397
486 124 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori health 0.842
494 124 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori education 1.759
502 124 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori crime 1.107
510 124 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori income 1.26
518 124 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori housing 0.993
806 125 22Aucklandover15000Other 2 2 Auckland over 15000 Other health 1.627
814 125 22Aucklandover15000Other 2 2 Auckland over 15000 Other education 2.216
822 125 22Aucklandover15000Other 2 2 Auckland over 15000 Other crime 1.88
830 125 22Aucklandover15000Other 2 2 Auckland over 15000 Other income 1.814
838 125 22Aucklandover15000Other 2 2 Auckland over 15000 Other housing 1.01
646 126 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean health 2.3
654 126 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean education 2.41
662 126 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean crime 1.193
670 126 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean income 1.662
678 126 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean housing 1.796
566 130 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori health 1.673
574 130 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori education 1.599
582 130 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori crime 1.84
590 130 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori income 0.878
598 130 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori housing 0.898
886 131 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other health 2.107
894 131 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other education 0.828
902 131 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other crime 1.079
910 131 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other income 1.974
918 131 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other housing 1.615
726 132 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean health 2.309
734 132 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean education 2.025
742 132 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean crime 1.833
750 132 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean income 1.028
758 132 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean housing 1.573
606 136 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori health 2.446
614 136 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori education 1.346
622 136 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori crime 1.194
630 136 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori income 1.362
638 136 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori housing 0.798
926 137 22SouthIslandover15000Other 2 2 South Island over 15000 Other health 1.964
934 137 22SouthIslandover15000Other 2 2 South Island over 15000 Other education 2.416
942 137 22SouthIslandover15000Other 2 2 South Island over 15000 Other crime 0.976
950 137 22SouthIslandover15000Other 2 2 South Island over 15000 Other income 1.983
958 137 22SouthIslandover15000Other 2 2 South Island over 15000 Other housing 1.476
766 138 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean health 1.363
774 138 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean education 1.982
782 138 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean crime 0.971
790 138 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean income 0.801
798 138 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean housing 1.009
526 142 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori health 1.066
534 142 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori education 0.859
542 142 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori crime 1.75
550 142 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori income 2.243
558 142 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori housing 2.374
846 143 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other health 1.745
854 143 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other education 2.378
862 143 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other crime 2.462
870 143 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other income 1.415
878 143 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other housing 1.541
686 144 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean health 2.06
694 144 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean education 0.717
702 144 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean crime 2.293
710 144 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean income 2.26
718 144 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean housing 1.792
487 148 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori health 1.969
495 148 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori education 1.322
503 148 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori crime 2.149
511 148 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori income 1.903
519 148 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori housing 1.048
807 149 23Aucklandover15000Other 2 3 Auckland over 15000 Other health 1.245
815 149 23Aucklandover15000Other 2 3 Auckland over 15000 Other education 1.158
823 149 23Aucklandover15000Other 2 3 Auckland over 15000 Other crime 1.095
831 149 23Aucklandover15000Other 2 3 Auckland over 15000 Other income 2.314
839 149 23Aucklandover15000Other 2 3 Auckland over 15000 Other housing 0.843
647 150 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean health 2.152
655 150 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean education 1.43
663 150 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean crime 2.066
671 150 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean income 1.113
679 150 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean housing 1.571
567 154 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori health 2.453
575 154 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori education 1.645
583 154 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori crime 2.296
591 154 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori income 1.382
599 154 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori housing 2.41
887 155 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other health 1.211
895 155 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other education 2.402
903 155 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other crime 1.6
911 155 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other income 1.084
919 155 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other housing 1.291
727 156 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean health 1.737
735 156 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean education 2.128
743 156 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean crime 0.864
751 156 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean income 2.25
759 156 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean housing 0.89
607 160 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori health 2.406
615 160 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori education 0.716
623 160 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori crime 1.097
631 160 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori income 1.648
639 160 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori housing 0.753
927 161 23SouthIslandover15000Other 2 3 South Island over 15000 Other health 2.009
935 161 23SouthIslandover15000Other 2 3 South Island over 15000 Other education 2.177
943 161 23SouthIslandover15000Other 2 3 South Island over 15000 Other crime 1.032
951 161 23SouthIslandover15000Other 2 3 South Island over 15000 Other income 0.831
959 161 23SouthIslandover15000Other 2 3 South Island over 15000 Other housing 1.486
767 162 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean health 0.931
775 162 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean education 1.423
783 162 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean crime 1.97
791 162 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean income 2.294
799 162 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean housing 0.821
527 166 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori health 1.907
535 166 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori education 0.917
543 166 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori crime 2.434
551 166 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori income 1.741
559 166 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori housing 1.547
847 167 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other health 0.819
855 167 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other education 2.199
863 167 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other crime 1.624
871 167 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other income 0.713
879 167 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other housing 1.746
687 168 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean health 1.076
695 168 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean education 1.923
703 168 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean crime 2.006
711 168 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean income 2.163
719 168 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean housing 1.814
488 172 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori health 2.213
496 172 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori education 1.956
504 172 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori crime 1.961
512 172 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori income 1.61
520 172 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori housing 1.289
808 173 24Aucklandover15000Other 2 4 Auckland over 15000 Other health 1.728
816 173 24Aucklandover15000Other 2 4 Auckland over 15000 Other education 2.418
824 173 24Aucklandover15000Other 2 4 Auckland over 15000 Other crime 2.414
832 173 24Aucklandover15000Other 2 4 Auckland over 15000 Other income 2.335
840 173 24Aucklandover15000Other 2 4 Auckland over 15000 Other housing 2.426
648 174 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean health 0.775
656 174 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean education 1.067
664 174 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean crime 2.39
672 174 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean income 1.874
680 174 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean housing 1.605
568 178 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori health 1.204
576 178 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori education 1.559
584 178 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori crime 0.828
592 178 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori income 1.546
600 178 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori housing 1.01
888 179 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other health 1.285
896 179 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other education 2.024
904 179 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other crime 2.249
912 179 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other income 1.7
920 179 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other housing 1.92
728 180 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean health 1.189
736 180 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean education 1.759
744 180 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean crime 1.582
752 180 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean income 2.361
760 180 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean housing 1.055
608 184 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori health 1.343
616 184 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori education 1.167
624 184 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori crime 1.098
632 184 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori income 1.282
640 184 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori housing 1.413
928 185 24SouthIslandover15000Other 2 4 South Island over 15000 Other health 1.6
936 185 24SouthIslandover15000Other 2 4 South Island over 15000 Other education 0.831
944 185 24SouthIslandover15000Other 2 4 South Island over 15000 Other crime 1.49
952 185 24SouthIslandover15000Other 2 4 South Island over 15000 Other income 1.132
960 185 24SouthIslandover15000Other 2 4 South Island over 15000 Other housing 1.395
768 186 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean health 1.612
776 186 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean education 2.011
784 186 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean crime 1
792 186 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean income 1.689
800 186 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean housing 1.828
528 190 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori health 1.982
536 190 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori education 1.211
544 190 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori crime 2.02
552 190 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori income 2.483
560 190 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori housing 1.038
848 191 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other health 1.14
856 191 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other education 1.121
864 191 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other crime 1.258
872 191 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other income 0.909
880 191 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other housing 1.198
688 192 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean health 1.785
696 192 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean education 1.195
704 192 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean crime 1.8
712 192 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean income 1.477
720 192 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean housing 1.876
var siuColours = { black: "#262638",
purple: "#414258",
purple10: "#5B5C72",
purple20: "#74758B",
purple30: "#8E8FA5",
teal: "#588D97",
teal10: "#72A7B1",
teal20: "#8BC0CA",
teal30: "#A5DAE4",
green: "#315259",
green10: "#4B6C73",
green20: "#64858C",
green30: "#7E9FA6",
orange: "#F47C20",
orange10: "#FF963A",
orange20: "#FFAF53",
orange30: "#FFC96D",
greyDark: "#BDBAC0",
greyLight: "#D1D3D4"
};
function roundUpToNearestFive(n) {
return 5 * ( Math.ceil(n/5) );;
};
function formatNumberWithCommas(n) {
var numberSegment = n.toString().split(".");
numberSegment[0] = numberSegment[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return numberSegment.join(".");
}
//http://trentrichardson.com/2010/04/06/compute-linear-regressions-in-javascript/
function linearRegression(y,x){
var lr = {};
var n = y.length;
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_xx = 0;
var sum_yy = 0;
for (var i = 0; i < y.length; i++) {
sum_x += x[i];
sum_y += y[i];
sum_xy += (x[i]*y[i]);
sum_xx += (x[i]*x[i]);
sum_yy += (y[i]*y[i]);
}
lr['slope'] = (n * sum_xy - sum_x * sum_y) / (n*sum_xx - sum_x * sum_x);
lr['intercept'] = (sum_y - lr.slope * sum_x)/n;
lr['r2'] = Math.pow((n*sum_xy - sum_x*sum_y)/Math.sqrt((n*sum_xx-sum_x*sum_x)*(n*sum_yy-sum_y*sum_y)),2);
return lr;
};
//http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
};
var addEvent = function(object, type, callback) {
if (object == null || typeof(object) == 'undefined') return;
if (object.addEventListener) {
object.addEventListener(type, callback, false);
} else if (object.attachEvent) {
object.attachEvent("on" + type, callback);
} else {
object["on"+type] = callback;
}
};
var oneDecimalPlace = d3.format(".1f");
/*.axis-top path,
.axis-bottom path,
.axis-top line,
.axis-bottom line {
fill: none;
stroke: #D1D3D4;
}*/
.domain {
fill: none;
stroke: none;
}
.axis-arrow {
shape-rendering: auto;
stroke: #D1D3D4;
fill: none;
}
.gridLine {
stroke-dasharray: 2, 2;
stroke: #D1D3D4;
fill: none;
}
.axis-top text,
.axis-bottom text,
.tick text {
font: 10px sans-serif;
fill: #D1D3D4;
}
.cells path {
fill: none;
pointer-events: all;
}
.cells :hover circle {
stroke: #262638;
}
.x-label {
text-anchor: middle;
}
.positive-label {
text-anchor: start;
}
.y-label,
.negative-label {
text-anchor: end;
}
.x-label,
.avg-label
{
text-anchor: middle;
}
.g-family-line,
.family-line {
stroke: #BDBAC0;
fill: none;
}
.selector {
display: inline-block;
margin: 1em;
}
.avg-line line {
stroke: black;
fill: none;
}
.avg-line text {
fill: black;
}
:root {
--siu-black: #262638;
--siu-purple: #414258;
--siu-purple10: #5B5C72;
--siu-purple20: #74758B;
--siu-purple30: #8E8FA5;
--siu-teal: #588D97;
--siu-teal10: #72A7B1;
--siu-teal20: #8BC0CA;
--siu-teal30: #A5DAE4;
--siu-green: #315259;
--siu-green10: #4B6C73;
--siu-green20: #64858C;
--siu-green30: #7E9FA6;
--siu-orange: #F47C20;
--siu-orange10: #FF963A;
--siu-orange20: #FFAF53;
--siu-orange30: #FFC96D;
--siu-greyDark: #BDBAC0;
--siu-greyLight: #D1D3D4;
}
body {
font-family: "Arial", sans-serif;
font-size: 12px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment