Mercurial > hg > index.fcgi > www > www-1
changeset 89:18f8c214169f
add gtc
author | paulo |
---|---|
date | Sun, 19 Feb 2017 19:45:31 -0800 |
parents | 583400dc28a0 |
children | 302eebbf025f |
files | gtc/d3.js gtc/d3.zip gtc/gtc.js gtc/index.html gtc/nv.d3.css gtc/nv.d3.js gtc/simple-statistics.js |
diffstat | 7 files changed, 27164 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gtc/d3.js Sun Feb 19 19:45:31 2017 -0800 1.3 @@ -0,0 +1,9554 @@ 1.4 +!function() { 1.5 + var d3 = { 1.6 + version: "3.5.17" 1.7 + }; 1.8 + var d3_arraySlice = [].slice, d3_array = function(list) { 1.9 + return d3_arraySlice.call(list); 1.10 + }; 1.11 + var d3_document = this.document; 1.12 + function d3_documentElement(node) { 1.13 + return node && (node.ownerDocument || node.document || node).documentElement; 1.14 + } 1.15 + function d3_window(node) { 1.16 + return node && (node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView); 1.17 + } 1.18 + if (d3_document) { 1.19 + try { 1.20 + d3_array(d3_document.documentElement.childNodes)[0].nodeType; 1.21 + } catch (e) { 1.22 + d3_array = function(list) { 1.23 + var i = list.length, array = new Array(i); 1.24 + while (i--) array[i] = list[i]; 1.25 + return array; 1.26 + }; 1.27 + } 1.28 + } 1.29 + if (!Date.now) Date.now = function() { 1.30 + return +new Date(); 1.31 + }; 1.32 + if (d3_document) { 1.33 + try { 1.34 + d3_document.createElement("DIV").style.setProperty("opacity", 0, ""); 1.35 + } catch (error) { 1.36 + var d3_element_prototype = this.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = this.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; 1.37 + d3_element_prototype.setAttribute = function(name, value) { 1.38 + d3_element_setAttribute.call(this, name, value + ""); 1.39 + }; 1.40 + d3_element_prototype.setAttributeNS = function(space, local, value) { 1.41 + d3_element_setAttributeNS.call(this, space, local, value + ""); 1.42 + }; 1.43 + d3_style_prototype.setProperty = function(name, value, priority) { 1.44 + d3_style_setProperty.call(this, name, value + "", priority); 1.45 + }; 1.46 + } 1.47 + } 1.48 + d3.ascending = d3_ascending; 1.49 + function d3_ascending(a, b) { 1.50 + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; 1.51 + } 1.52 + d3.descending = function(a, b) { 1.53 + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; 1.54 + }; 1.55 + d3.min = function(array, f) { 1.56 + var i = -1, n = array.length, a, b; 1.57 + if (arguments.length === 1) { 1.58 + while (++i < n) if ((b = array[i]) != null && b >= b) { 1.59 + a = b; 1.60 + break; 1.61 + } 1.62 + while (++i < n) if ((b = array[i]) != null && a > b) a = b; 1.63 + } else { 1.64 + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { 1.65 + a = b; 1.66 + break; 1.67 + } 1.68 + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; 1.69 + } 1.70 + return a; 1.71 + }; 1.72 + d3.max = function(array, f) { 1.73 + var i = -1, n = array.length, a, b; 1.74 + if (arguments.length === 1) { 1.75 + while (++i < n) if ((b = array[i]) != null && b >= b) { 1.76 + a = b; 1.77 + break; 1.78 + } 1.79 + while (++i < n) if ((b = array[i]) != null && b > a) a = b; 1.80 + } else { 1.81 + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { 1.82 + a = b; 1.83 + break; 1.84 + } 1.85 + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; 1.86 + } 1.87 + return a; 1.88 + }; 1.89 + d3.extent = function(array, f) { 1.90 + var i = -1, n = array.length, a, b, c; 1.91 + if (arguments.length === 1) { 1.92 + while (++i < n) if ((b = array[i]) != null && b >= b) { 1.93 + a = c = b; 1.94 + break; 1.95 + } 1.96 + while (++i < n) if ((b = array[i]) != null) { 1.97 + if (a > b) a = b; 1.98 + if (c < b) c = b; 1.99 + } 1.100 + } else { 1.101 + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { 1.102 + a = c = b; 1.103 + break; 1.104 + } 1.105 + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { 1.106 + if (a > b) a = b; 1.107 + if (c < b) c = b; 1.108 + } 1.109 + } 1.110 + return [ a, c ]; 1.111 + }; 1.112 + function d3_number(x) { 1.113 + return x === null ? NaN : +x; 1.114 + } 1.115 + function d3_numeric(x) { 1.116 + return !isNaN(x); 1.117 + } 1.118 + d3.sum = function(array, f) { 1.119 + var s = 0, n = array.length, a, i = -1; 1.120 + if (arguments.length === 1) { 1.121 + while (++i < n) if (d3_numeric(a = +array[i])) s += a; 1.122 + } else { 1.123 + while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a; 1.124 + } 1.125 + return s; 1.126 + }; 1.127 + d3.mean = function(array, f) { 1.128 + var s = 0, n = array.length, a, i = -1, j = n; 1.129 + if (arguments.length === 1) { 1.130 + while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j; 1.131 + } else { 1.132 + while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j; 1.133 + } 1.134 + if (j) return s / j; 1.135 + }; 1.136 + d3.quantile = function(values, p) { 1.137 + var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; 1.138 + return e ? v + e * (values[h] - v) : v; 1.139 + }; 1.140 + d3.median = function(array, f) { 1.141 + var numbers = [], n = array.length, a, i = -1; 1.142 + if (arguments.length === 1) { 1.143 + while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a); 1.144 + } else { 1.145 + while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a); 1.146 + } 1.147 + if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5); 1.148 + }; 1.149 + d3.variance = function(array, f) { 1.150 + var n = array.length, m = 0, a, d, s = 0, i = -1, j = 0; 1.151 + if (arguments.length === 1) { 1.152 + while (++i < n) { 1.153 + if (d3_numeric(a = d3_number(array[i]))) { 1.154 + d = a - m; 1.155 + m += d / ++j; 1.156 + s += d * (a - m); 1.157 + } 1.158 + } 1.159 + } else { 1.160 + while (++i < n) { 1.161 + if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) { 1.162 + d = a - m; 1.163 + m += d / ++j; 1.164 + s += d * (a - m); 1.165 + } 1.166 + } 1.167 + } 1.168 + if (j > 1) return s / (j - 1); 1.169 + }; 1.170 + d3.deviation = function() { 1.171 + var v = d3.variance.apply(this, arguments); 1.172 + return v ? Math.sqrt(v) : v; 1.173 + }; 1.174 + function d3_bisector(compare) { 1.175 + return { 1.176 + left: function(a, x, lo, hi) { 1.177 + if (arguments.length < 3) lo = 0; 1.178 + if (arguments.length < 4) hi = a.length; 1.179 + while (lo < hi) { 1.180 + var mid = lo + hi >>> 1; 1.181 + if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid; 1.182 + } 1.183 + return lo; 1.184 + }, 1.185 + right: function(a, x, lo, hi) { 1.186 + if (arguments.length < 3) lo = 0; 1.187 + if (arguments.length < 4) hi = a.length; 1.188 + while (lo < hi) { 1.189 + var mid = lo + hi >>> 1; 1.190 + if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1; 1.191 + } 1.192 + return lo; 1.193 + } 1.194 + }; 1.195 + } 1.196 + var d3_bisect = d3_bisector(d3_ascending); 1.197 + d3.bisectLeft = d3_bisect.left; 1.198 + d3.bisect = d3.bisectRight = d3_bisect.right; 1.199 + d3.bisector = function(f) { 1.200 + return d3_bisector(f.length === 1 ? function(d, x) { 1.201 + return d3_ascending(f(d), x); 1.202 + } : f); 1.203 + }; 1.204 + d3.shuffle = function(array, i0, i1) { 1.205 + if ((m = arguments.length) < 3) { 1.206 + i1 = array.length; 1.207 + if (m < 2) i0 = 0; 1.208 + } 1.209 + var m = i1 - i0, t, i; 1.210 + while (m) { 1.211 + i = Math.random() * m-- | 0; 1.212 + t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t; 1.213 + } 1.214 + return array; 1.215 + }; 1.216 + d3.permute = function(array, indexes) { 1.217 + var i = indexes.length, permutes = new Array(i); 1.218 + while (i--) permutes[i] = array[indexes[i]]; 1.219 + return permutes; 1.220 + }; 1.221 + d3.pairs = function(array) { 1.222 + var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n); 1.223 + while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ]; 1.224 + return pairs; 1.225 + }; 1.226 + d3.transpose = function(matrix) { 1.227 + if (!(n = matrix.length)) return []; 1.228 + for (var i = -1, m = d3.min(matrix, d3_transposeLength), transpose = new Array(m); ++i < m; ) { 1.229 + for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n; ) { 1.230 + row[j] = matrix[j][i]; 1.231 + } 1.232 + } 1.233 + return transpose; 1.234 + }; 1.235 + function d3_transposeLength(d) { 1.236 + return d.length; 1.237 + } 1.238 + d3.zip = function() { 1.239 + return d3.transpose(arguments); 1.240 + }; 1.241 + d3.keys = function(map) { 1.242 + var keys = []; 1.243 + for (var key in map) keys.push(key); 1.244 + return keys; 1.245 + }; 1.246 + d3.values = function(map) { 1.247 + var values = []; 1.248 + for (var key in map) values.push(map[key]); 1.249 + return values; 1.250 + }; 1.251 + d3.entries = function(map) { 1.252 + var entries = []; 1.253 + for (var key in map) entries.push({ 1.254 + key: key, 1.255 + value: map[key] 1.256 + }); 1.257 + return entries; 1.258 + }; 1.259 + d3.merge = function(arrays) { 1.260 + var n = arrays.length, m, i = -1, j = 0, merged, array; 1.261 + while (++i < n) j += arrays[i].length; 1.262 + merged = new Array(j); 1.263 + while (--n >= 0) { 1.264 + array = arrays[n]; 1.265 + m = array.length; 1.266 + while (--m >= 0) { 1.267 + merged[--j] = array[m]; 1.268 + } 1.269 + } 1.270 + return merged; 1.271 + }; 1.272 + var abs = Math.abs; 1.273 + d3.range = function(start, stop, step) { 1.274 + if (arguments.length < 3) { 1.275 + step = 1; 1.276 + if (arguments.length < 2) { 1.277 + stop = start; 1.278 + start = 0; 1.279 + } 1.280 + } 1.281 + if ((stop - start) / step === Infinity) throw new Error("infinite range"); 1.282 + var range = [], k = d3_range_integerScale(abs(step)), i = -1, j; 1.283 + start *= k, stop *= k, step *= k; 1.284 + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); 1.285 + return range; 1.286 + }; 1.287 + function d3_range_integerScale(x) { 1.288 + var k = 1; 1.289 + while (x * k % 1) k *= 10; 1.290 + return k; 1.291 + } 1.292 + function d3_class(ctor, properties) { 1.293 + for (var key in properties) { 1.294 + Object.defineProperty(ctor.prototype, key, { 1.295 + value: properties[key], 1.296 + enumerable: false 1.297 + }); 1.298 + } 1.299 + } 1.300 + d3.map = function(object, f) { 1.301 + var map = new d3_Map(); 1.302 + if (object instanceof d3_Map) { 1.303 + object.forEach(function(key, value) { 1.304 + map.set(key, value); 1.305 + }); 1.306 + } else if (Array.isArray(object)) { 1.307 + var i = -1, n = object.length, o; 1.308 + if (arguments.length === 1) while (++i < n) map.set(i, object[i]); else while (++i < n) map.set(f.call(object, o = object[i], i), o); 1.309 + } else { 1.310 + for (var key in object) map.set(key, object[key]); 1.311 + } 1.312 + return map; 1.313 + }; 1.314 + function d3_Map() { 1.315 + this._ = Object.create(null); 1.316 + } 1.317 + var d3_map_proto = "__proto__", d3_map_zero = "\x00"; 1.318 + d3_class(d3_Map, { 1.319 + has: d3_map_has, 1.320 + get: function(key) { 1.321 + return this._[d3_map_escape(key)]; 1.322 + }, 1.323 + set: function(key, value) { 1.324 + return this._[d3_map_escape(key)] = value; 1.325 + }, 1.326 + remove: d3_map_remove, 1.327 + keys: d3_map_keys, 1.328 + values: function() { 1.329 + var values = []; 1.330 + for (var key in this._) values.push(this._[key]); 1.331 + return values; 1.332 + }, 1.333 + entries: function() { 1.334 + var entries = []; 1.335 + for (var key in this._) entries.push({ 1.336 + key: d3_map_unescape(key), 1.337 + value: this._[key] 1.338 + }); 1.339 + return entries; 1.340 + }, 1.341 + size: d3_map_size, 1.342 + empty: d3_map_empty, 1.343 + forEach: function(f) { 1.344 + for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]); 1.345 + } 1.346 + }); 1.347 + function d3_map_escape(key) { 1.348 + return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key; 1.349 + } 1.350 + function d3_map_unescape(key) { 1.351 + return (key += "")[0] === d3_map_zero ? key.slice(1) : key; 1.352 + } 1.353 + function d3_map_has(key) { 1.354 + return d3_map_escape(key) in this._; 1.355 + } 1.356 + function d3_map_remove(key) { 1.357 + return (key = d3_map_escape(key)) in this._ && delete this._[key]; 1.358 + } 1.359 + function d3_map_keys() { 1.360 + var keys = []; 1.361 + for (var key in this._) keys.push(d3_map_unescape(key)); 1.362 + return keys; 1.363 + } 1.364 + function d3_map_size() { 1.365 + var size = 0; 1.366 + for (var key in this._) ++size; 1.367 + return size; 1.368 + } 1.369 + function d3_map_empty() { 1.370 + for (var key in this._) return false; 1.371 + return true; 1.372 + } 1.373 + d3.nest = function() { 1.374 + var nest = {}, keys = [], sortKeys = [], sortValues, rollup; 1.375 + function map(mapType, array, depth) { 1.376 + if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; 1.377 + var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; 1.378 + while (++i < n) { 1.379 + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { 1.380 + values.push(object); 1.381 + } else { 1.382 + valuesByKey.set(keyValue, [ object ]); 1.383 + } 1.384 + } 1.385 + if (mapType) { 1.386 + object = mapType(); 1.387 + setter = function(keyValue, values) { 1.388 + object.set(keyValue, map(mapType, values, depth)); 1.389 + }; 1.390 + } else { 1.391 + object = {}; 1.392 + setter = function(keyValue, values) { 1.393 + object[keyValue] = map(mapType, values, depth); 1.394 + }; 1.395 + } 1.396 + valuesByKey.forEach(setter); 1.397 + return object; 1.398 + } 1.399 + function entries(map, depth) { 1.400 + if (depth >= keys.length) return map; 1.401 + var array = [], sortKey = sortKeys[depth++]; 1.402 + map.forEach(function(key, keyMap) { 1.403 + array.push({ 1.404 + key: key, 1.405 + values: entries(keyMap, depth) 1.406 + }); 1.407 + }); 1.408 + return sortKey ? array.sort(function(a, b) { 1.409 + return sortKey(a.key, b.key); 1.410 + }) : array; 1.411 + } 1.412 + nest.map = function(array, mapType) { 1.413 + return map(mapType, array, 0); 1.414 + }; 1.415 + nest.entries = function(array) { 1.416 + return entries(map(d3.map, array, 0), 0); 1.417 + }; 1.418 + nest.key = function(d) { 1.419 + keys.push(d); 1.420 + return nest; 1.421 + }; 1.422 + nest.sortKeys = function(order) { 1.423 + sortKeys[keys.length - 1] = order; 1.424 + return nest; 1.425 + }; 1.426 + nest.sortValues = function(order) { 1.427 + sortValues = order; 1.428 + return nest; 1.429 + }; 1.430 + nest.rollup = function(f) { 1.431 + rollup = f; 1.432 + return nest; 1.433 + }; 1.434 + return nest; 1.435 + }; 1.436 + d3.set = function(array) { 1.437 + var set = new d3_Set(); 1.438 + if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); 1.439 + return set; 1.440 + }; 1.441 + function d3_Set() { 1.442 + this._ = Object.create(null); 1.443 + } 1.444 + d3_class(d3_Set, { 1.445 + has: d3_map_has, 1.446 + add: function(key) { 1.447 + this._[d3_map_escape(key += "")] = true; 1.448 + return key; 1.449 + }, 1.450 + remove: d3_map_remove, 1.451 + values: d3_map_keys, 1.452 + size: d3_map_size, 1.453 + empty: d3_map_empty, 1.454 + forEach: function(f) { 1.455 + for (var key in this._) f.call(this, d3_map_unescape(key)); 1.456 + } 1.457 + }); 1.458 + d3.behavior = {}; 1.459 + function d3_identity(d) { 1.460 + return d; 1.461 + } 1.462 + d3.rebind = function(target, source) { 1.463 + var i = 1, n = arguments.length, method; 1.464 + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); 1.465 + return target; 1.466 + }; 1.467 + function d3_rebind(target, source, method) { 1.468 + return function() { 1.469 + var value = method.apply(source, arguments); 1.470 + return value === source ? target : value; 1.471 + }; 1.472 + } 1.473 + function d3_vendorSymbol(object, name) { 1.474 + if (name in object) return name; 1.475 + name = name.charAt(0).toUpperCase() + name.slice(1); 1.476 + for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { 1.477 + var prefixName = d3_vendorPrefixes[i] + name; 1.478 + if (prefixName in object) return prefixName; 1.479 + } 1.480 + } 1.481 + var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; 1.482 + function d3_noop() {} 1.483 + d3.dispatch = function() { 1.484 + var dispatch = new d3_dispatch(), i = -1, n = arguments.length; 1.485 + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); 1.486 + return dispatch; 1.487 + }; 1.488 + function d3_dispatch() {} 1.489 + d3_dispatch.prototype.on = function(type, listener) { 1.490 + var i = type.indexOf("."), name = ""; 1.491 + if (i >= 0) { 1.492 + name = type.slice(i + 1); 1.493 + type = type.slice(0, i); 1.494 + } 1.495 + if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); 1.496 + if (arguments.length === 2) { 1.497 + if (listener == null) for (type in this) { 1.498 + if (this.hasOwnProperty(type)) this[type].on(name, null); 1.499 + } 1.500 + return this; 1.501 + } 1.502 + }; 1.503 + function d3_dispatch_event(dispatch) { 1.504 + var listeners = [], listenerByName = new d3_Map(); 1.505 + function event() { 1.506 + var z = listeners, i = -1, n = z.length, l; 1.507 + while (++i < n) if (l = z[i].on) l.apply(this, arguments); 1.508 + return dispatch; 1.509 + } 1.510 + event.on = function(name, listener) { 1.511 + var l = listenerByName.get(name), i; 1.512 + if (arguments.length < 2) return l && l.on; 1.513 + if (l) { 1.514 + l.on = null; 1.515 + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); 1.516 + listenerByName.remove(name); 1.517 + } 1.518 + if (listener) listeners.push(listenerByName.set(name, { 1.519 + on: listener 1.520 + })); 1.521 + return dispatch; 1.522 + }; 1.523 + return event; 1.524 + } 1.525 + d3.event = null; 1.526 + function d3_eventPreventDefault() { 1.527 + d3.event.preventDefault(); 1.528 + } 1.529 + function d3_eventSource() { 1.530 + var e = d3.event, s; 1.531 + while (s = e.sourceEvent) e = s; 1.532 + return e; 1.533 + } 1.534 + function d3_eventDispatch(target) { 1.535 + var dispatch = new d3_dispatch(), i = 0, n = arguments.length; 1.536 + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); 1.537 + dispatch.of = function(thiz, argumentz) { 1.538 + return function(e1) { 1.539 + try { 1.540 + var e0 = e1.sourceEvent = d3.event; 1.541 + e1.target = target; 1.542 + d3.event = e1; 1.543 + dispatch[e1.type].apply(thiz, argumentz); 1.544 + } finally { 1.545 + d3.event = e0; 1.546 + } 1.547 + }; 1.548 + }; 1.549 + return dispatch; 1.550 + } 1.551 + d3.requote = function(s) { 1.552 + return s.replace(d3_requote_re, "\\$&"); 1.553 + }; 1.554 + var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; 1.555 + var d3_subclass = {}.__proto__ ? function(object, prototype) { 1.556 + object.__proto__ = prototype; 1.557 + } : function(object, prototype) { 1.558 + for (var property in prototype) object[property] = prototype[property]; 1.559 + }; 1.560 + function d3_selection(groups) { 1.561 + d3_subclass(groups, d3_selectionPrototype); 1.562 + return groups; 1.563 + } 1.564 + var d3_select = function(s, n) { 1.565 + return n.querySelector(s); 1.566 + }, d3_selectAll = function(s, n) { 1.567 + return n.querySelectorAll(s); 1.568 + }, d3_selectMatches = function(n, s) { 1.569 + var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, "matchesSelector")]; 1.570 + d3_selectMatches = function(n, s) { 1.571 + return d3_selectMatcher.call(n, s); 1.572 + }; 1.573 + return d3_selectMatches(n, s); 1.574 + }; 1.575 + if (typeof Sizzle === "function") { 1.576 + d3_select = function(s, n) { 1.577 + return Sizzle(s, n)[0] || null; 1.578 + }; 1.579 + d3_selectAll = Sizzle; 1.580 + d3_selectMatches = Sizzle.matchesSelector; 1.581 + } 1.582 + d3.selection = function() { 1.583 + return d3.select(d3_document.documentElement); 1.584 + }; 1.585 + var d3_selectionPrototype = d3.selection.prototype = []; 1.586 + d3_selectionPrototype.select = function(selector) { 1.587 + var subgroups = [], subgroup, subnode, group, node; 1.588 + selector = d3_selection_selector(selector); 1.589 + for (var j = -1, m = this.length; ++j < m; ) { 1.590 + subgroups.push(subgroup = []); 1.591 + subgroup.parentNode = (group = this[j]).parentNode; 1.592 + for (var i = -1, n = group.length; ++i < n; ) { 1.593 + if (node = group[i]) { 1.594 + subgroup.push(subnode = selector.call(node, node.__data__, i, j)); 1.595 + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; 1.596 + } else { 1.597 + subgroup.push(null); 1.598 + } 1.599 + } 1.600 + } 1.601 + return d3_selection(subgroups); 1.602 + }; 1.603 + function d3_selection_selector(selector) { 1.604 + return typeof selector === "function" ? selector : function() { 1.605 + return d3_select(selector, this); 1.606 + }; 1.607 + } 1.608 + d3_selectionPrototype.selectAll = function(selector) { 1.609 + var subgroups = [], subgroup, node; 1.610 + selector = d3_selection_selectorAll(selector); 1.611 + for (var j = -1, m = this.length; ++j < m; ) { 1.612 + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { 1.613 + if (node = group[i]) { 1.614 + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); 1.615 + subgroup.parentNode = node; 1.616 + } 1.617 + } 1.618 + } 1.619 + return d3_selection(subgroups); 1.620 + }; 1.621 + function d3_selection_selectorAll(selector) { 1.622 + return typeof selector === "function" ? selector : function() { 1.623 + return d3_selectAll(selector, this); 1.624 + }; 1.625 + } 1.626 + var d3_nsXhtml = "http://www.w3.org/1999/xhtml"; 1.627 + var d3_nsPrefix = { 1.628 + svg: "http://www.w3.org/2000/svg", 1.629 + xhtml: d3_nsXhtml, 1.630 + xlink: "http://www.w3.org/1999/xlink", 1.631 + xml: "http://www.w3.org/XML/1998/namespace", 1.632 + xmlns: "http://www.w3.org/2000/xmlns/" 1.633 + }; 1.634 + d3.ns = { 1.635 + prefix: d3_nsPrefix, 1.636 + qualify: function(name) { 1.637 + var i = name.indexOf(":"), prefix = name; 1.638 + if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); 1.639 + return d3_nsPrefix.hasOwnProperty(prefix) ? { 1.640 + space: d3_nsPrefix[prefix], 1.641 + local: name 1.642 + } : name; 1.643 + } 1.644 + }; 1.645 + d3_selectionPrototype.attr = function(name, value) { 1.646 + if (arguments.length < 2) { 1.647 + if (typeof name === "string") { 1.648 + var node = this.node(); 1.649 + name = d3.ns.qualify(name); 1.650 + return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); 1.651 + } 1.652 + for (value in name) this.each(d3_selection_attr(value, name[value])); 1.653 + return this; 1.654 + } 1.655 + return this.each(d3_selection_attr(name, value)); 1.656 + }; 1.657 + function d3_selection_attr(name, value) { 1.658 + name = d3.ns.qualify(name); 1.659 + function attrNull() { 1.660 + this.removeAttribute(name); 1.661 + } 1.662 + function attrNullNS() { 1.663 + this.removeAttributeNS(name.space, name.local); 1.664 + } 1.665 + function attrConstant() { 1.666 + this.setAttribute(name, value); 1.667 + } 1.668 + function attrConstantNS() { 1.669 + this.setAttributeNS(name.space, name.local, value); 1.670 + } 1.671 + function attrFunction() { 1.672 + var x = value.apply(this, arguments); 1.673 + if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); 1.674 + } 1.675 + function attrFunctionNS() { 1.676 + var x = value.apply(this, arguments); 1.677 + if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); 1.678 + } 1.679 + return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; 1.680 + } 1.681 + function d3_collapse(s) { 1.682 + return s.trim().replace(/\s+/g, " "); 1.683 + } 1.684 + d3_selectionPrototype.classed = function(name, value) { 1.685 + if (arguments.length < 2) { 1.686 + if (typeof name === "string") { 1.687 + var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1; 1.688 + if (value = node.classList) { 1.689 + while (++i < n) if (!value.contains(name[i])) return false; 1.690 + } else { 1.691 + value = node.getAttribute("class"); 1.692 + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; 1.693 + } 1.694 + return true; 1.695 + } 1.696 + for (value in name) this.each(d3_selection_classed(value, name[value])); 1.697 + return this; 1.698 + } 1.699 + return this.each(d3_selection_classed(name, value)); 1.700 + }; 1.701 + function d3_selection_classedRe(name) { 1.702 + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); 1.703 + } 1.704 + function d3_selection_classes(name) { 1.705 + return (name + "").trim().split(/^|\s+/); 1.706 + } 1.707 + function d3_selection_classed(name, value) { 1.708 + name = d3_selection_classes(name).map(d3_selection_classedName); 1.709 + var n = name.length; 1.710 + function classedConstant() { 1.711 + var i = -1; 1.712 + while (++i < n) name[i](this, value); 1.713 + } 1.714 + function classedFunction() { 1.715 + var i = -1, x = value.apply(this, arguments); 1.716 + while (++i < n) name[i](this, x); 1.717 + } 1.718 + return typeof value === "function" ? classedFunction : classedConstant; 1.719 + } 1.720 + function d3_selection_classedName(name) { 1.721 + var re = d3_selection_classedRe(name); 1.722 + return function(node, value) { 1.723 + if (c = node.classList) return value ? c.add(name) : c.remove(name); 1.724 + var c = node.getAttribute("class") || ""; 1.725 + if (value) { 1.726 + re.lastIndex = 0; 1.727 + if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); 1.728 + } else { 1.729 + node.setAttribute("class", d3_collapse(c.replace(re, " "))); 1.730 + } 1.731 + }; 1.732 + } 1.733 + d3_selectionPrototype.style = function(name, value, priority) { 1.734 + var n = arguments.length; 1.735 + if (n < 3) { 1.736 + if (typeof name !== "string") { 1.737 + if (n < 2) value = ""; 1.738 + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); 1.739 + return this; 1.740 + } 1.741 + if (n < 2) { 1.742 + var node = this.node(); 1.743 + return d3_window(node).getComputedStyle(node, null).getPropertyValue(name); 1.744 + } 1.745 + priority = ""; 1.746 + } 1.747 + return this.each(d3_selection_style(name, value, priority)); 1.748 + }; 1.749 + function d3_selection_style(name, value, priority) { 1.750 + function styleNull() { 1.751 + this.style.removeProperty(name); 1.752 + } 1.753 + function styleConstant() { 1.754 + this.style.setProperty(name, value, priority); 1.755 + } 1.756 + function styleFunction() { 1.757 + var x = value.apply(this, arguments); 1.758 + if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); 1.759 + } 1.760 + return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; 1.761 + } 1.762 + d3_selectionPrototype.property = function(name, value) { 1.763 + if (arguments.length < 2) { 1.764 + if (typeof name === "string") return this.node()[name]; 1.765 + for (value in name) this.each(d3_selection_property(value, name[value])); 1.766 + return this; 1.767 + } 1.768 + return this.each(d3_selection_property(name, value)); 1.769 + }; 1.770 + function d3_selection_property(name, value) { 1.771 + function propertyNull() { 1.772 + delete this[name]; 1.773 + } 1.774 + function propertyConstant() { 1.775 + this[name] = value; 1.776 + } 1.777 + function propertyFunction() { 1.778 + var x = value.apply(this, arguments); 1.779 + if (x == null) delete this[name]; else this[name] = x; 1.780 + } 1.781 + return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; 1.782 + } 1.783 + d3_selectionPrototype.text = function(value) { 1.784 + return arguments.length ? this.each(typeof value === "function" ? function() { 1.785 + var v = value.apply(this, arguments); 1.786 + this.textContent = v == null ? "" : v; 1.787 + } : value == null ? function() { 1.788 + this.textContent = ""; 1.789 + } : function() { 1.790 + this.textContent = value; 1.791 + }) : this.node().textContent; 1.792 + }; 1.793 + d3_selectionPrototype.html = function(value) { 1.794 + return arguments.length ? this.each(typeof value === "function" ? function() { 1.795 + var v = value.apply(this, arguments); 1.796 + this.innerHTML = v == null ? "" : v; 1.797 + } : value == null ? function() { 1.798 + this.innerHTML = ""; 1.799 + } : function() { 1.800 + this.innerHTML = value; 1.801 + }) : this.node().innerHTML; 1.802 + }; 1.803 + d3_selectionPrototype.append = function(name) { 1.804 + name = d3_selection_creator(name); 1.805 + return this.select(function() { 1.806 + return this.appendChild(name.apply(this, arguments)); 1.807 + }); 1.808 + }; 1.809 + function d3_selection_creator(name) { 1.810 + function create() { 1.811 + var document = this.ownerDocument, namespace = this.namespaceURI; 1.812 + return namespace === d3_nsXhtml && document.documentElement.namespaceURI === d3_nsXhtml ? document.createElement(name) : document.createElementNS(namespace, name); 1.813 + } 1.814 + function createNS() { 1.815 + return this.ownerDocument.createElementNS(name.space, name.local); 1.816 + } 1.817 + return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? createNS : create; 1.818 + } 1.819 + d3_selectionPrototype.insert = function(name, before) { 1.820 + name = d3_selection_creator(name); 1.821 + before = d3_selection_selector(before); 1.822 + return this.select(function() { 1.823 + return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null); 1.824 + }); 1.825 + }; 1.826 + d3_selectionPrototype.remove = function() { 1.827 + return this.each(d3_selectionRemove); 1.828 + }; 1.829 + function d3_selectionRemove() { 1.830 + var parent = this.parentNode; 1.831 + if (parent) parent.removeChild(this); 1.832 + } 1.833 + d3_selectionPrototype.data = function(value, key) { 1.834 + var i = -1, n = this.length, group, node; 1.835 + if (!arguments.length) { 1.836 + value = new Array(n = (group = this[0]).length); 1.837 + while (++i < n) { 1.838 + if (node = group[i]) { 1.839 + value[i] = node.__data__; 1.840 + } 1.841 + } 1.842 + return value; 1.843 + } 1.844 + function bind(group, groupData) { 1.845 + var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; 1.846 + if (key) { 1.847 + var nodeByKeyValue = new d3_Map(), keyValues = new Array(n), keyValue; 1.848 + for (i = -1; ++i < n; ) { 1.849 + if (node = group[i]) { 1.850 + if (nodeByKeyValue.has(keyValue = key.call(node, node.__data__, i))) { 1.851 + exitNodes[i] = node; 1.852 + } else { 1.853 + nodeByKeyValue.set(keyValue, node); 1.854 + } 1.855 + keyValues[i] = keyValue; 1.856 + } 1.857 + } 1.858 + for (i = -1; ++i < m; ) { 1.859 + if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) { 1.860 + enterNodes[i] = d3_selection_dataNode(nodeData); 1.861 + } else if (node !== true) { 1.862 + updateNodes[i] = node; 1.863 + node.__data__ = nodeData; 1.864 + } 1.865 + nodeByKeyValue.set(keyValue, true); 1.866 + } 1.867 + for (i = -1; ++i < n; ) { 1.868 + if (i in keyValues && nodeByKeyValue.get(keyValues[i]) !== true) { 1.869 + exitNodes[i] = group[i]; 1.870 + } 1.871 + } 1.872 + } else { 1.873 + for (i = -1; ++i < n0; ) { 1.874 + node = group[i]; 1.875 + nodeData = groupData[i]; 1.876 + if (node) { 1.877 + node.__data__ = nodeData; 1.878 + updateNodes[i] = node; 1.879 + } else { 1.880 + enterNodes[i] = d3_selection_dataNode(nodeData); 1.881 + } 1.882 + } 1.883 + for (;i < m; ++i) { 1.884 + enterNodes[i] = d3_selection_dataNode(groupData[i]); 1.885 + } 1.886 + for (;i < n; ++i) { 1.887 + exitNodes[i] = group[i]; 1.888 + } 1.889 + } 1.890 + enterNodes.update = updateNodes; 1.891 + enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; 1.892 + enter.push(enterNodes); 1.893 + update.push(updateNodes); 1.894 + exit.push(exitNodes); 1.895 + } 1.896 + var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); 1.897 + if (typeof value === "function") { 1.898 + while (++i < n) { 1.899 + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); 1.900 + } 1.901 + } else { 1.902 + while (++i < n) { 1.903 + bind(group = this[i], value); 1.904 + } 1.905 + } 1.906 + update.enter = function() { 1.907 + return enter; 1.908 + }; 1.909 + update.exit = function() { 1.910 + return exit; 1.911 + }; 1.912 + return update; 1.913 + }; 1.914 + function d3_selection_dataNode(data) { 1.915 + return { 1.916 + __data__: data 1.917 + }; 1.918 + } 1.919 + d3_selectionPrototype.datum = function(value) { 1.920 + return arguments.length ? this.property("__data__", value) : this.property("__data__"); 1.921 + }; 1.922 + d3_selectionPrototype.filter = function(filter) { 1.923 + var subgroups = [], subgroup, group, node; 1.924 + if (typeof filter !== "function") filter = d3_selection_filter(filter); 1.925 + for (var j = 0, m = this.length; j < m; j++) { 1.926 + subgroups.push(subgroup = []); 1.927 + subgroup.parentNode = (group = this[j]).parentNode; 1.928 + for (var i = 0, n = group.length; i < n; i++) { 1.929 + if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { 1.930 + subgroup.push(node); 1.931 + } 1.932 + } 1.933 + } 1.934 + return d3_selection(subgroups); 1.935 + }; 1.936 + function d3_selection_filter(selector) { 1.937 + return function() { 1.938 + return d3_selectMatches(this, selector); 1.939 + }; 1.940 + } 1.941 + d3_selectionPrototype.order = function() { 1.942 + for (var j = -1, m = this.length; ++j < m; ) { 1.943 + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { 1.944 + if (node = group[i]) { 1.945 + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); 1.946 + next = node; 1.947 + } 1.948 + } 1.949 + } 1.950 + return this; 1.951 + }; 1.952 + d3_selectionPrototype.sort = function(comparator) { 1.953 + comparator = d3_selection_sortComparator.apply(this, arguments); 1.954 + for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); 1.955 + return this.order(); 1.956 + }; 1.957 + function d3_selection_sortComparator(comparator) { 1.958 + if (!arguments.length) comparator = d3_ascending; 1.959 + return function(a, b) { 1.960 + return a && b ? comparator(a.__data__, b.__data__) : !a - !b; 1.961 + }; 1.962 + } 1.963 + d3_selectionPrototype.each = function(callback) { 1.964 + return d3_selection_each(this, function(node, i, j) { 1.965 + callback.call(node, node.__data__, i, j); 1.966 + }); 1.967 + }; 1.968 + function d3_selection_each(groups, callback) { 1.969 + for (var j = 0, m = groups.length; j < m; j++) { 1.970 + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { 1.971 + if (node = group[i]) callback(node, i, j); 1.972 + } 1.973 + } 1.974 + return groups; 1.975 + } 1.976 + d3_selectionPrototype.call = function(callback) { 1.977 + var args = d3_array(arguments); 1.978 + callback.apply(args[0] = this, args); 1.979 + return this; 1.980 + }; 1.981 + d3_selectionPrototype.empty = function() { 1.982 + return !this.node(); 1.983 + }; 1.984 + d3_selectionPrototype.node = function() { 1.985 + for (var j = 0, m = this.length; j < m; j++) { 1.986 + for (var group = this[j], i = 0, n = group.length; i < n; i++) { 1.987 + var node = group[i]; 1.988 + if (node) return node; 1.989 + } 1.990 + } 1.991 + return null; 1.992 + }; 1.993 + d3_selectionPrototype.size = function() { 1.994 + var n = 0; 1.995 + d3_selection_each(this, function() { 1.996 + ++n; 1.997 + }); 1.998 + return n; 1.999 + }; 1.1000 + function d3_selection_enter(selection) { 1.1001 + d3_subclass(selection, d3_selection_enterPrototype); 1.1002 + return selection; 1.1003 + } 1.1004 + var d3_selection_enterPrototype = []; 1.1005 + d3.selection.enter = d3_selection_enter; 1.1006 + d3.selection.enter.prototype = d3_selection_enterPrototype; 1.1007 + d3_selection_enterPrototype.append = d3_selectionPrototype.append; 1.1008 + d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; 1.1009 + d3_selection_enterPrototype.node = d3_selectionPrototype.node; 1.1010 + d3_selection_enterPrototype.call = d3_selectionPrototype.call; 1.1011 + d3_selection_enterPrototype.size = d3_selectionPrototype.size; 1.1012 + d3_selection_enterPrototype.select = function(selector) { 1.1013 + var subgroups = [], subgroup, subnode, upgroup, group, node; 1.1014 + for (var j = -1, m = this.length; ++j < m; ) { 1.1015 + upgroup = (group = this[j]).update; 1.1016 + subgroups.push(subgroup = []); 1.1017 + subgroup.parentNode = group.parentNode; 1.1018 + for (var i = -1, n = group.length; ++i < n; ) { 1.1019 + if (node = group[i]) { 1.1020 + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); 1.1021 + subnode.__data__ = node.__data__; 1.1022 + } else { 1.1023 + subgroup.push(null); 1.1024 + } 1.1025 + } 1.1026 + } 1.1027 + return d3_selection(subgroups); 1.1028 + }; 1.1029 + d3_selection_enterPrototype.insert = function(name, before) { 1.1030 + if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); 1.1031 + return d3_selectionPrototype.insert.call(this, name, before); 1.1032 + }; 1.1033 + function d3_selection_enterInsertBefore(enter) { 1.1034 + var i0, j0; 1.1035 + return function(d, i, j) { 1.1036 + var group = enter[j].update, n = group.length, node; 1.1037 + if (j != j0) j0 = j, i0 = 0; 1.1038 + if (i >= i0) i0 = i + 1; 1.1039 + while (!(node = group[i0]) && ++i0 < n) ; 1.1040 + return node; 1.1041 + }; 1.1042 + } 1.1043 + d3.select = function(node) { 1.1044 + var group; 1.1045 + if (typeof node === "string") { 1.1046 + group = [ d3_select(node, d3_document) ]; 1.1047 + group.parentNode = d3_document.documentElement; 1.1048 + } else { 1.1049 + group = [ node ]; 1.1050 + group.parentNode = d3_documentElement(node); 1.1051 + } 1.1052 + return d3_selection([ group ]); 1.1053 + }; 1.1054 + d3.selectAll = function(nodes) { 1.1055 + var group; 1.1056 + if (typeof nodes === "string") { 1.1057 + group = d3_array(d3_selectAll(nodes, d3_document)); 1.1058 + group.parentNode = d3_document.documentElement; 1.1059 + } else { 1.1060 + group = d3_array(nodes); 1.1061 + group.parentNode = null; 1.1062 + } 1.1063 + return d3_selection([ group ]); 1.1064 + }; 1.1065 + d3_selectionPrototype.on = function(type, listener, capture) { 1.1066 + var n = arguments.length; 1.1067 + if (n < 3) { 1.1068 + if (typeof type !== "string") { 1.1069 + if (n < 2) listener = false; 1.1070 + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); 1.1071 + return this; 1.1072 + } 1.1073 + if (n < 2) return (n = this.node()["__on" + type]) && n._; 1.1074 + capture = false; 1.1075 + } 1.1076 + return this.each(d3_selection_on(type, listener, capture)); 1.1077 + }; 1.1078 + function d3_selection_on(type, listener, capture) { 1.1079 + var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; 1.1080 + if (i > 0) type = type.slice(0, i); 1.1081 + var filter = d3_selection_onFilters.get(type); 1.1082 + if (filter) type = filter, wrap = d3_selection_onFilter; 1.1083 + function onRemove() { 1.1084 + var l = this[name]; 1.1085 + if (l) { 1.1086 + this.removeEventListener(type, l, l.$); 1.1087 + delete this[name]; 1.1088 + } 1.1089 + } 1.1090 + function onAdd() { 1.1091 + var l = wrap(listener, d3_array(arguments)); 1.1092 + onRemove.call(this); 1.1093 + this.addEventListener(type, this[name] = l, l.$ = capture); 1.1094 + l._ = listener; 1.1095 + } 1.1096 + function removeAll() { 1.1097 + var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; 1.1098 + for (var name in this) { 1.1099 + if (match = name.match(re)) { 1.1100 + var l = this[name]; 1.1101 + this.removeEventListener(match[1], l, l.$); 1.1102 + delete this[name]; 1.1103 + } 1.1104 + } 1.1105 + } 1.1106 + return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; 1.1107 + } 1.1108 + var d3_selection_onFilters = d3.map({ 1.1109 + mouseenter: "mouseover", 1.1110 + mouseleave: "mouseout" 1.1111 + }); 1.1112 + if (d3_document) { 1.1113 + d3_selection_onFilters.forEach(function(k) { 1.1114 + if ("on" + k in d3_document) d3_selection_onFilters.remove(k); 1.1115 + }); 1.1116 + } 1.1117 + function d3_selection_onListener(listener, argumentz) { 1.1118 + return function(e) { 1.1119 + var o = d3.event; 1.1120 + d3.event = e; 1.1121 + argumentz[0] = this.__data__; 1.1122 + try { 1.1123 + listener.apply(this, argumentz); 1.1124 + } finally { 1.1125 + d3.event = o; 1.1126 + } 1.1127 + }; 1.1128 + } 1.1129 + function d3_selection_onFilter(listener, argumentz) { 1.1130 + var l = d3_selection_onListener(listener, argumentz); 1.1131 + return function(e) { 1.1132 + var target = this, related = e.relatedTarget; 1.1133 + if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { 1.1134 + l.call(target, e); 1.1135 + } 1.1136 + }; 1.1137 + } 1.1138 + var d3_event_dragSelect, d3_event_dragId = 0; 1.1139 + function d3_event_dragSuppress(node) { 1.1140 + var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window(node)).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault); 1.1141 + if (d3_event_dragSelect == null) { 1.1142 + d3_event_dragSelect = "onselectstart" in node ? false : d3_vendorSymbol(node.style, "userSelect"); 1.1143 + } 1.1144 + if (d3_event_dragSelect) { 1.1145 + var style = d3_documentElement(node).style, select = style[d3_event_dragSelect]; 1.1146 + style[d3_event_dragSelect] = "none"; 1.1147 + } 1.1148 + return function(suppressClick) { 1.1149 + w.on(name, null); 1.1150 + if (d3_event_dragSelect) style[d3_event_dragSelect] = select; 1.1151 + if (suppressClick) { 1.1152 + var off = function() { 1.1153 + w.on(click, null); 1.1154 + }; 1.1155 + w.on(click, function() { 1.1156 + d3_eventPreventDefault(); 1.1157 + off(); 1.1158 + }, true); 1.1159 + setTimeout(off, 0); 1.1160 + } 1.1161 + }; 1.1162 + } 1.1163 + d3.mouse = function(container) { 1.1164 + return d3_mousePoint(container, d3_eventSource()); 1.1165 + }; 1.1166 + var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0; 1.1167 + function d3_mousePoint(container, e) { 1.1168 + if (e.changedTouches) e = e.changedTouches[0]; 1.1169 + var svg = container.ownerSVGElement || container; 1.1170 + if (svg.createSVGPoint) { 1.1171 + var point = svg.createSVGPoint(); 1.1172 + if (d3_mouse_bug44083 < 0) { 1.1173 + var window = d3_window(container); 1.1174 + if (window.scrollX || window.scrollY) { 1.1175 + svg = d3.select("body").append("svg").style({ 1.1176 + position: "absolute", 1.1177 + top: 0, 1.1178 + left: 0, 1.1179 + margin: 0, 1.1180 + padding: 0, 1.1181 + border: "none" 1.1182 + }, "important"); 1.1183 + var ctm = svg[0][0].getScreenCTM(); 1.1184 + d3_mouse_bug44083 = !(ctm.f || ctm.e); 1.1185 + svg.remove(); 1.1186 + } 1.1187 + } 1.1188 + if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX, 1.1189 + point.y = e.clientY; 1.1190 + point = point.matrixTransform(container.getScreenCTM().inverse()); 1.1191 + return [ point.x, point.y ]; 1.1192 + } 1.1193 + var rect = container.getBoundingClientRect(); 1.1194 + return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; 1.1195 + } 1.1196 + d3.touch = function(container, touches, identifier) { 1.1197 + if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches; 1.1198 + if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) { 1.1199 + if ((touch = touches[i]).identifier === identifier) { 1.1200 + return d3_mousePoint(container, touch); 1.1201 + } 1.1202 + } 1.1203 + }; 1.1204 + d3.behavior.drag = function() { 1.1205 + var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_window, "mousemove", "mouseup"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_identity, "touchmove", "touchend"); 1.1206 + function drag() { 1.1207 + this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); 1.1208 + } 1.1209 + function dragstart(id, position, subject, move, end) { 1.1210 + return function() { 1.1211 + var that = this, target = d3.event.target.correspondingElement || d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject(target)).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(target), position0 = position(parent, dragId); 1.1212 + if (origin) { 1.1213 + dragOffset = origin.apply(that, arguments); 1.1214 + dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ]; 1.1215 + } else { 1.1216 + dragOffset = [ 0, 0 ]; 1.1217 + } 1.1218 + dispatch({ 1.1219 + type: "dragstart" 1.1220 + }); 1.1221 + function moved() { 1.1222 + var position1 = position(parent, dragId), dx, dy; 1.1223 + if (!position1) return; 1.1224 + dx = position1[0] - position0[0]; 1.1225 + dy = position1[1] - position0[1]; 1.1226 + dragged |= dx | dy; 1.1227 + position0 = position1; 1.1228 + dispatch({ 1.1229 + type: "drag", 1.1230 + x: position1[0] + dragOffset[0], 1.1231 + y: position1[1] + dragOffset[1], 1.1232 + dx: dx, 1.1233 + dy: dy 1.1234 + }); 1.1235 + } 1.1236 + function ended() { 1.1237 + if (!position(parent, dragId)) return; 1.1238 + dragSubject.on(move + dragName, null).on(end + dragName, null); 1.1239 + dragRestore(dragged); 1.1240 + dispatch({ 1.1241 + type: "dragend" 1.1242 + }); 1.1243 + } 1.1244 + }; 1.1245 + } 1.1246 + drag.origin = function(x) { 1.1247 + if (!arguments.length) return origin; 1.1248 + origin = x; 1.1249 + return drag; 1.1250 + }; 1.1251 + return d3.rebind(drag, event, "on"); 1.1252 + }; 1.1253 + function d3_behavior_dragTouchId() { 1.1254 + return d3.event.changedTouches[0].identifier; 1.1255 + } 1.1256 + d3.touches = function(container, touches) { 1.1257 + if (arguments.length < 2) touches = d3_eventSource().touches; 1.1258 + return touches ? d3_array(touches).map(function(touch) { 1.1259 + var point = d3_mousePoint(container, touch); 1.1260 + point.identifier = touch.identifier; 1.1261 + return point; 1.1262 + }) : []; 1.1263 + }; 1.1264 + var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π; 1.1265 + function d3_sgn(x) { 1.1266 + return x > 0 ? 1 : x < 0 ? -1 : 0; 1.1267 + } 1.1268 + function d3_cross2d(a, b, c) { 1.1269 + return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); 1.1270 + } 1.1271 + function d3_acos(x) { 1.1272 + return x > 1 ? 0 : x < -1 ? π : Math.acos(x); 1.1273 + } 1.1274 + function d3_asin(x) { 1.1275 + return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x); 1.1276 + } 1.1277 + function d3_sinh(x) { 1.1278 + return ((x = Math.exp(x)) - 1 / x) / 2; 1.1279 + } 1.1280 + function d3_cosh(x) { 1.1281 + return ((x = Math.exp(x)) + 1 / x) / 2; 1.1282 + } 1.1283 + function d3_tanh(x) { 1.1284 + return ((x = Math.exp(2 * x)) - 1) / (x + 1); 1.1285 + } 1.1286 + function d3_haversin(x) { 1.1287 + return (x = Math.sin(x / 2)) * x; 1.1288 + } 1.1289 + var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4; 1.1290 + d3.interpolateZoom = function(p0, p1) { 1.1291 + 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; 1.1292 + if (d2 < ε2) { 1.1293 + S = Math.log(w1 / w0) / ρ; 1.1294 + i = function(t) { 1.1295 + return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * t * S) ]; 1.1296 + }; 1.1297 + } else { 1.1298 + var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1); 1.1299 + S = (r1 - r0) / ρ; 1.1300 + i = function(t) { 1.1301 + var s = t * S, coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0)); 1.1302 + return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ]; 1.1303 + }; 1.1304 + } 1.1305 + i.duration = S * 1e3; 1.1306 + return i; 1.1307 + }; 1.1308 + d3.behavior.zoom = function() { 1.1309 + var view = { 1.1310 + x: 0, 1.1311 + y: 0, 1.1312 + k: 1 1.1313 + }, translate0, center0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, duration = 250, zooming = 0, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1; 1.1314 + if (!d3_behavior_zoomWheel) { 1.1315 + d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { 1.1316 + return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); 1.1317 + }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { 1.1318 + return d3.event.wheelDelta; 1.1319 + }, "mousewheel") : (d3_behavior_zoomDelta = function() { 1.1320 + return -d3.event.detail; 1.1321 + }, "MozMousePixelScroll"); 1.1322 + } 1.1323 + function zoom(g) { 1.1324 + g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); 1.1325 + } 1.1326 + zoom.event = function(g) { 1.1327 + g.each(function() { 1.1328 + var dispatch = event.of(this, arguments), view1 = view; 1.1329 + if (d3_transitionInheritId) { 1.1330 + d3.select(this).transition().each("start.zoom", function() { 1.1331 + view = this.__chart__ || { 1.1332 + x: 0, 1.1333 + y: 0, 1.1334 + k: 1 1.1335 + }; 1.1336 + zoomstarted(dispatch); 1.1337 + }).tween("zoom:zoom", function() { 1.1338 + var dx = size[0], dy = size[1], cx = center0 ? center0[0] : dx / 2, cy = center0 ? center0[1] : dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]); 1.1339 + return function(t) { 1.1340 + var l = i(t), k = dx / l[2]; 1.1341 + this.__chart__ = view = { 1.1342 + x: cx - l[0] * k, 1.1343 + y: cy - l[1] * k, 1.1344 + k: k 1.1345 + }; 1.1346 + zoomed(dispatch); 1.1347 + }; 1.1348 + }).each("interrupt.zoom", function() { 1.1349 + zoomended(dispatch); 1.1350 + }).each("end.zoom", function() { 1.1351 + zoomended(dispatch); 1.1352 + }); 1.1353 + } else { 1.1354 + this.__chart__ = view; 1.1355 + zoomstarted(dispatch); 1.1356 + zoomed(dispatch); 1.1357 + zoomended(dispatch); 1.1358 + } 1.1359 + }); 1.1360 + }; 1.1361 + zoom.translate = function(_) { 1.1362 + if (!arguments.length) return [ view.x, view.y ]; 1.1363 + view = { 1.1364 + x: +_[0], 1.1365 + y: +_[1], 1.1366 + k: view.k 1.1367 + }; 1.1368 + rescale(); 1.1369 + return zoom; 1.1370 + }; 1.1371 + zoom.scale = function(_) { 1.1372 + if (!arguments.length) return view.k; 1.1373 + view = { 1.1374 + x: view.x, 1.1375 + y: view.y, 1.1376 + k: null 1.1377 + }; 1.1378 + scaleTo(+_); 1.1379 + rescale(); 1.1380 + return zoom; 1.1381 + }; 1.1382 + zoom.scaleExtent = function(_) { 1.1383 + if (!arguments.length) return scaleExtent; 1.1384 + scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ]; 1.1385 + return zoom; 1.1386 + }; 1.1387 + zoom.center = function(_) { 1.1388 + if (!arguments.length) return center; 1.1389 + center = _ && [ +_[0], +_[1] ]; 1.1390 + return zoom; 1.1391 + }; 1.1392 + zoom.size = function(_) { 1.1393 + if (!arguments.length) return size; 1.1394 + size = _ && [ +_[0], +_[1] ]; 1.1395 + return zoom; 1.1396 + }; 1.1397 + zoom.duration = function(_) { 1.1398 + if (!arguments.length) return duration; 1.1399 + duration = +_; 1.1400 + return zoom; 1.1401 + }; 1.1402 + zoom.x = function(z) { 1.1403 + if (!arguments.length) return x1; 1.1404 + x1 = z; 1.1405 + x0 = z.copy(); 1.1406 + view = { 1.1407 + x: 0, 1.1408 + y: 0, 1.1409 + k: 1 1.1410 + }; 1.1411 + return zoom; 1.1412 + }; 1.1413 + zoom.y = function(z) { 1.1414 + if (!arguments.length) return y1; 1.1415 + y1 = z; 1.1416 + y0 = z.copy(); 1.1417 + view = { 1.1418 + x: 0, 1.1419 + y: 0, 1.1420 + k: 1 1.1421 + }; 1.1422 + return zoom; 1.1423 + }; 1.1424 + function location(p) { 1.1425 + return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ]; 1.1426 + } 1.1427 + function point(l) { 1.1428 + return [ l[0] * view.k + view.x, l[1] * view.k + view.y ]; 1.1429 + } 1.1430 + function scaleTo(s) { 1.1431 + view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); 1.1432 + } 1.1433 + function translateTo(p, l) { 1.1434 + l = point(l); 1.1435 + view.x += p[0] - l[0]; 1.1436 + view.y += p[1] - l[1]; 1.1437 + } 1.1438 + function zoomTo(that, p, l, k) { 1.1439 + that.__chart__ = { 1.1440 + x: view.x, 1.1441 + y: view.y, 1.1442 + k: view.k 1.1443 + }; 1.1444 + scaleTo(Math.pow(2, k)); 1.1445 + translateTo(center0 = p, l); 1.1446 + that = d3.select(that); 1.1447 + if (duration > 0) that = that.transition().duration(duration); 1.1448 + that.call(zoom.event); 1.1449 + } 1.1450 + function rescale() { 1.1451 + if (x1) x1.domain(x0.range().map(function(x) { 1.1452 + return (x - view.x) / view.k; 1.1453 + }).map(x0.invert)); 1.1454 + if (y1) y1.domain(y0.range().map(function(y) { 1.1455 + return (y - view.y) / view.k; 1.1456 + }).map(y0.invert)); 1.1457 + } 1.1458 + function zoomstarted(dispatch) { 1.1459 + if (!zooming++) dispatch({ 1.1460 + type: "zoomstart" 1.1461 + }); 1.1462 + } 1.1463 + function zoomed(dispatch) { 1.1464 + rescale(); 1.1465 + dispatch({ 1.1466 + type: "zoom", 1.1467 + scale: view.k, 1.1468 + translate: [ view.x, view.y ] 1.1469 + }); 1.1470 + } 1.1471 + function zoomended(dispatch) { 1.1472 + if (!--zooming) dispatch({ 1.1473 + type: "zoomend" 1.1474 + }), center0 = null; 1.1475 + } 1.1476 + function mousedowned() { 1.1477 + var that = this, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress(that); 1.1478 + d3_selection_interrupt.call(that); 1.1479 + zoomstarted(dispatch); 1.1480 + function moved() { 1.1481 + dragged = 1; 1.1482 + translateTo(d3.mouse(that), location0); 1.1483 + zoomed(dispatch); 1.1484 + } 1.1485 + function ended() { 1.1486 + subject.on(mousemove, null).on(mouseup, null); 1.1487 + dragRestore(dragged); 1.1488 + zoomended(dispatch); 1.1489 + } 1.1490 + } 1.1491 + function touchstarted() { 1.1492 + var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove" + zoomName, touchend = "touchend" + zoomName, targets = [], subject = d3.select(that), dragRestore = d3_event_dragSuppress(that); 1.1493 + started(); 1.1494 + zoomstarted(dispatch); 1.1495 + subject.on(mousedown, null).on(touchstart, started); 1.1496 + function relocate() { 1.1497 + var touches = d3.touches(that); 1.1498 + scale0 = view.k; 1.1499 + touches.forEach(function(t) { 1.1500 + if (t.identifier in locations0) locations0[t.identifier] = location(t); 1.1501 + }); 1.1502 + return touches; 1.1503 + } 1.1504 + function started() { 1.1505 + var target = d3.event.target; 1.1506 + d3.select(target).on(touchmove, moved).on(touchend, ended); 1.1507 + targets.push(target); 1.1508 + var changed = d3.event.changedTouches; 1.1509 + for (var i = 0, n = changed.length; i < n; ++i) { 1.1510 + locations0[changed[i].identifier] = null; 1.1511 + } 1.1512 + var touches = relocate(), now = Date.now(); 1.1513 + if (touches.length === 1) { 1.1514 + if (now - touchtime < 500) { 1.1515 + var p = touches[0]; 1.1516 + zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1); 1.1517 + d3_eventPreventDefault(); 1.1518 + } 1.1519 + touchtime = now; 1.1520 + } else if (touches.length > 1) { 1.1521 + var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; 1.1522 + distance0 = dx * dx + dy * dy; 1.1523 + } 1.1524 + } 1.1525 + function moved() { 1.1526 + var touches = d3.touches(that), p0, l0, p1, l1; 1.1527 + d3_selection_interrupt.call(that); 1.1528 + for (var i = 0, n = touches.length; i < n; ++i, l1 = null) { 1.1529 + p1 = touches[i]; 1.1530 + if (l1 = locations0[p1.identifier]) { 1.1531 + if (l0) break; 1.1532 + p0 = p1, l0 = l1; 1.1533 + } 1.1534 + } 1.1535 + if (l1) { 1.1536 + var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0); 1.1537 + p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; 1.1538 + l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; 1.1539 + scaleTo(scale1 * scale0); 1.1540 + } 1.1541 + touchtime = null; 1.1542 + translateTo(p0, l0); 1.1543 + zoomed(dispatch); 1.1544 + } 1.1545 + function ended() { 1.1546 + if (d3.event.touches.length) { 1.1547 + var changed = d3.event.changedTouches; 1.1548 + for (var i = 0, n = changed.length; i < n; ++i) { 1.1549 + delete locations0[changed[i].identifier]; 1.1550 + } 1.1551 + for (var identifier in locations0) { 1.1552 + return void relocate(); 1.1553 + } 1.1554 + } 1.1555 + d3.selectAll(targets).on(zoomName, null); 1.1556 + subject.on(mousedown, mousedowned).on(touchstart, touchstarted); 1.1557 + dragRestore(); 1.1558 + zoomended(dispatch); 1.1559 + } 1.1560 + } 1.1561 + function mousewheeled() { 1.1562 + var dispatch = event.of(this, arguments); 1.1563 + if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this), 1.1564 + translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch); 1.1565 + mousewheelTimer = setTimeout(function() { 1.1566 + mousewheelTimer = null; 1.1567 + zoomended(dispatch); 1.1568 + }, 50); 1.1569 + d3_eventPreventDefault(); 1.1570 + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k); 1.1571 + translateTo(center0, translate0); 1.1572 + zoomed(dispatch); 1.1573 + } 1.1574 + function dblclicked() { 1.1575 + var p = d3.mouse(this), k = Math.log(view.k) / Math.LN2; 1.1576 + zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1); 1.1577 + } 1.1578 + return d3.rebind(zoom, event, "on"); 1.1579 + }; 1.1580 + var d3_behavior_zoomInfinity = [ 0, Infinity ], d3_behavior_zoomDelta, d3_behavior_zoomWheel; 1.1581 + d3.color = d3_color; 1.1582 + function d3_color() {} 1.1583 + d3_color.prototype.toString = function() { 1.1584 + return this.rgb() + ""; 1.1585 + }; 1.1586 + d3.hsl = d3_hsl; 1.1587 + function d3_hsl(h, s, l) { 1.1588 + return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l) : arguments.length < 2 ? h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : new d3_hsl(h, s, l); 1.1589 + } 1.1590 + var d3_hslPrototype = d3_hsl.prototype = new d3_color(); 1.1591 + d3_hslPrototype.brighter = function(k) { 1.1592 + k = Math.pow(.7, arguments.length ? k : 1); 1.1593 + return new d3_hsl(this.h, this.s, this.l / k); 1.1594 + }; 1.1595 + d3_hslPrototype.darker = function(k) { 1.1596 + k = Math.pow(.7, arguments.length ? k : 1); 1.1597 + return new d3_hsl(this.h, this.s, k * this.l); 1.1598 + }; 1.1599 + d3_hslPrototype.rgb = function() { 1.1600 + return d3_hsl_rgb(this.h, this.s, this.l); 1.1601 + }; 1.1602 + function d3_hsl_rgb(h, s, l) { 1.1603 + var m1, m2; 1.1604 + h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; 1.1605 + s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; 1.1606 + l = l < 0 ? 0 : l > 1 ? 1 : l; 1.1607 + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; 1.1608 + m1 = 2 * l - m2; 1.1609 + function v(h) { 1.1610 + if (h > 360) h -= 360; else if (h < 0) h += 360; 1.1611 + if (h < 60) return m1 + (m2 - m1) * h / 60; 1.1612 + if (h < 180) return m2; 1.1613 + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; 1.1614 + return m1; 1.1615 + } 1.1616 + function vv(h) { 1.1617 + return Math.round(v(h) * 255); 1.1618 + } 1.1619 + return new d3_rgb(vv(h + 120), vv(h), vv(h - 120)); 1.1620 + } 1.1621 + d3.hcl = d3_hcl; 1.1622 + function d3_hcl(h, c, l) { 1.1623 + return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l) : arguments.length < 2 ? h instanceof d3_hcl ? new d3_hcl(h.h, h.c, h.l) : h instanceof d3_lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : new d3_hcl(h, c, l); 1.1624 + } 1.1625 + var d3_hclPrototype = d3_hcl.prototype = new d3_color(); 1.1626 + d3_hclPrototype.brighter = function(k) { 1.1627 + return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); 1.1628 + }; 1.1629 + d3_hclPrototype.darker = function(k) { 1.1630 + return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); 1.1631 + }; 1.1632 + d3_hclPrototype.rgb = function() { 1.1633 + return d3_hcl_lab(this.h, this.c, this.l).rgb(); 1.1634 + }; 1.1635 + function d3_hcl_lab(h, c, l) { 1.1636 + if (isNaN(h)) h = 0; 1.1637 + if (isNaN(c)) c = 0; 1.1638 + return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); 1.1639 + } 1.1640 + d3.lab = d3_lab; 1.1641 + function d3_lab(l, a, b) { 1.1642 + return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b) : arguments.length < 2 ? l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b) : l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l) : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b) : new d3_lab(l, a, b); 1.1643 + } 1.1644 + var d3_lab_K = 18; 1.1645 + var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; 1.1646 + var d3_labPrototype = d3_lab.prototype = new d3_color(); 1.1647 + d3_labPrototype.brighter = function(k) { 1.1648 + return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); 1.1649 + }; 1.1650 + d3_labPrototype.darker = function(k) { 1.1651 + return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); 1.1652 + }; 1.1653 + d3_labPrototype.rgb = function() { 1.1654 + return d3_lab_rgb(this.l, this.a, this.b); 1.1655 + }; 1.1656 + function d3_lab_rgb(l, a, b) { 1.1657 + var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; 1.1658 + x = d3_lab_xyz(x) * d3_lab_X; 1.1659 + y = d3_lab_xyz(y) * d3_lab_Y; 1.1660 + z = d3_lab_xyz(z) * d3_lab_Z; 1.1661 + return new d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); 1.1662 + } 1.1663 + function d3_lab_hcl(l, a, b) { 1.1664 + return l > 0 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : new d3_hcl(NaN, NaN, l); 1.1665 + } 1.1666 + function d3_lab_xyz(x) { 1.1667 + return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; 1.1668 + } 1.1669 + function d3_xyz_lab(x) { 1.1670 + return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; 1.1671 + } 1.1672 + function d3_xyz_rgb(r) { 1.1673 + return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); 1.1674 + } 1.1675 + d3.rgb = d3_rgb; 1.1676 + function d3_rgb(r, g, b) { 1.1677 + return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b) : arguments.length < 2 ? r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : new d3_rgb(r, g, b); 1.1678 + } 1.1679 + function d3_rgbNumber(value) { 1.1680 + return new d3_rgb(value >> 16, value >> 8 & 255, value & 255); 1.1681 + } 1.1682 + function d3_rgbString(value) { 1.1683 + return d3_rgbNumber(value) + ""; 1.1684 + } 1.1685 + var d3_rgbPrototype = d3_rgb.prototype = new d3_color(); 1.1686 + d3_rgbPrototype.brighter = function(k) { 1.1687 + k = Math.pow(.7, arguments.length ? k : 1); 1.1688 + var r = this.r, g = this.g, b = this.b, i = 30; 1.1689 + if (!r && !g && !b) return new d3_rgb(i, i, i); 1.1690 + if (r && r < i) r = i; 1.1691 + if (g && g < i) g = i; 1.1692 + if (b && b < i) b = i; 1.1693 + return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k)); 1.1694 + }; 1.1695 + d3_rgbPrototype.darker = function(k) { 1.1696 + k = Math.pow(.7, arguments.length ? k : 1); 1.1697 + return new d3_rgb(k * this.r, k * this.g, k * this.b); 1.1698 + }; 1.1699 + d3_rgbPrototype.hsl = function() { 1.1700 + return d3_rgb_hsl(this.r, this.g, this.b); 1.1701 + }; 1.1702 + d3_rgbPrototype.toString = function() { 1.1703 + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); 1.1704 + }; 1.1705 + function d3_rgb_hex(v) { 1.1706 + return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); 1.1707 + } 1.1708 + function d3_rgb_parse(format, rgb, hsl) { 1.1709 + var r = 0, g = 0, b = 0, m1, m2, color; 1.1710 + m1 = /([a-z]+)\((.*)\)/.exec(format = format.toLowerCase()); 1.1711 + if (m1) { 1.1712 + m2 = m1[2].split(","); 1.1713 + switch (m1[1]) { 1.1714 + case "hsl": 1.1715 + { 1.1716 + return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); 1.1717 + } 1.1718 + 1.1719 + case "rgb": 1.1720 + { 1.1721 + return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); 1.1722 + } 1.1723 + } 1.1724 + } 1.1725 + if (color = d3_rgb_names.get(format)) { 1.1726 + return rgb(color.r, color.g, color.b); 1.1727 + } 1.1728 + if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) { 1.1729 + if (format.length === 4) { 1.1730 + r = (color & 3840) >> 4; 1.1731 + r = r >> 4 | r; 1.1732 + g = color & 240; 1.1733 + g = g >> 4 | g; 1.1734 + b = color & 15; 1.1735 + b = b << 4 | b; 1.1736 + } else if (format.length === 7) { 1.1737 + r = (color & 16711680) >> 16; 1.1738 + g = (color & 65280) >> 8; 1.1739 + b = color & 255; 1.1740 + } 1.1741 + } 1.1742 + return rgb(r, g, b); 1.1743 + } 1.1744 + function d3_rgb_hsl(r, g, b) { 1.1745 + var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; 1.1746 + if (d) { 1.1747 + s = l < .5 ? d / (max + min) : d / (2 - max - min); 1.1748 + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; 1.1749 + h *= 60; 1.1750 + } else { 1.1751 + h = NaN; 1.1752 + s = l > 0 && l < 1 ? 0 : h; 1.1753 + } 1.1754 + return new d3_hsl(h, s, l); 1.1755 + } 1.1756 + function d3_rgb_lab(r, g, b) { 1.1757 + r = d3_rgb_xyz(r); 1.1758 + g = d3_rgb_xyz(g); 1.1759 + b = d3_rgb_xyz(b); 1.1760 + var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); 1.1761 + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); 1.1762 + } 1.1763 + function d3_rgb_xyz(r) { 1.1764 + return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); 1.1765 + } 1.1766 + function d3_rgb_parseNumber(c) { 1.1767 + var f = parseFloat(c); 1.1768 + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; 1.1769 + } 1.1770 + var d3_rgb_names = d3.map({ 1.1771 + aliceblue: 15792383, 1.1772 + antiquewhite: 16444375, 1.1773 + aqua: 65535, 1.1774 + aquamarine: 8388564, 1.1775 + azure: 15794175, 1.1776 + beige: 16119260, 1.1777 + bisque: 16770244, 1.1778 + black: 0, 1.1779 + blanchedalmond: 16772045, 1.1780 + blue: 255, 1.1781 + blueviolet: 9055202, 1.1782 + brown: 10824234, 1.1783 + burlywood: 14596231, 1.1784 + cadetblue: 6266528, 1.1785 + chartreuse: 8388352, 1.1786 + chocolate: 13789470, 1.1787 + coral: 16744272, 1.1788 + cornflowerblue: 6591981, 1.1789 + cornsilk: 16775388, 1.1790 + crimson: 14423100, 1.1791 + cyan: 65535, 1.1792 + darkblue: 139, 1.1793 + darkcyan: 35723, 1.1794 + darkgoldenrod: 12092939, 1.1795 + darkgray: 11119017, 1.1796 + darkgreen: 25600, 1.1797 + darkgrey: 11119017, 1.1798 + darkkhaki: 12433259, 1.1799 + darkmagenta: 9109643, 1.1800 + darkolivegreen: 5597999, 1.1801 + darkorange: 16747520, 1.1802 + darkorchid: 10040012, 1.1803 + darkred: 9109504, 1.1804 + darksalmon: 15308410, 1.1805 + darkseagreen: 9419919, 1.1806 + darkslateblue: 4734347, 1.1807 + darkslategray: 3100495, 1.1808 + darkslategrey: 3100495, 1.1809 + darkturquoise: 52945, 1.1810 + darkviolet: 9699539, 1.1811 + deeppink: 16716947, 1.1812 + deepskyblue: 49151, 1.1813 + dimgray: 6908265, 1.1814 + dimgrey: 6908265, 1.1815 + dodgerblue: 2003199, 1.1816 + firebrick: 11674146, 1.1817 + floralwhite: 16775920, 1.1818 + forestgreen: 2263842, 1.1819 + fuchsia: 16711935, 1.1820 + gainsboro: 14474460, 1.1821 + ghostwhite: 16316671, 1.1822 + gold: 16766720, 1.1823 + goldenrod: 14329120, 1.1824 + gray: 8421504, 1.1825 + green: 32768, 1.1826 + greenyellow: 11403055, 1.1827 + grey: 8421504, 1.1828 + honeydew: 15794160, 1.1829 + hotpink: 16738740, 1.1830 + indianred: 13458524, 1.1831 + indigo: 4915330, 1.1832 + ivory: 16777200, 1.1833 + khaki: 15787660, 1.1834 + lavender: 15132410, 1.1835 + lavenderblush: 16773365, 1.1836 + lawngreen: 8190976, 1.1837 + lemonchiffon: 16775885, 1.1838 + lightblue: 11393254, 1.1839 + lightcoral: 15761536, 1.1840 + lightcyan: 14745599, 1.1841 + lightgoldenrodyellow: 16448210, 1.1842 + lightgray: 13882323, 1.1843 + lightgreen: 9498256, 1.1844 + lightgrey: 13882323, 1.1845 + lightpink: 16758465, 1.1846 + lightsalmon: 16752762, 1.1847 + lightseagreen: 2142890, 1.1848 + lightskyblue: 8900346, 1.1849 + lightslategray: 7833753, 1.1850 + lightslategrey: 7833753, 1.1851 + lightsteelblue: 11584734, 1.1852 + lightyellow: 16777184, 1.1853 + lime: 65280, 1.1854 + limegreen: 3329330, 1.1855 + linen: 16445670, 1.1856 + magenta: 16711935, 1.1857 + maroon: 8388608, 1.1858 + mediumaquamarine: 6737322, 1.1859 + mediumblue: 205, 1.1860 + mediumorchid: 12211667, 1.1861 + mediumpurple: 9662683, 1.1862 + mediumseagreen: 3978097, 1.1863 + mediumslateblue: 8087790, 1.1864 + mediumspringgreen: 64154, 1.1865 + mediumturquoise: 4772300, 1.1866 + mediumvioletred: 13047173, 1.1867 + midnightblue: 1644912, 1.1868 + mintcream: 16121850, 1.1869 + mistyrose: 16770273, 1.1870 + moccasin: 16770229, 1.1871 + navajowhite: 16768685, 1.1872 + navy: 128, 1.1873 + oldlace: 16643558, 1.1874 + olive: 8421376, 1.1875 + olivedrab: 7048739, 1.1876 + orange: 16753920, 1.1877 + orangered: 16729344, 1.1878 + orchid: 14315734, 1.1879 + palegoldenrod: 15657130, 1.1880 + palegreen: 10025880, 1.1881 + paleturquoise: 11529966, 1.1882 + palevioletred: 14381203, 1.1883 + papayawhip: 16773077, 1.1884 + peachpuff: 16767673, 1.1885 + peru: 13468991, 1.1886 + pink: 16761035, 1.1887 + plum: 14524637, 1.1888 + powderblue: 11591910, 1.1889 + purple: 8388736, 1.1890 + rebeccapurple: 6697881, 1.1891 + red: 16711680, 1.1892 + rosybrown: 12357519, 1.1893 + royalblue: 4286945, 1.1894 + saddlebrown: 9127187, 1.1895 + salmon: 16416882, 1.1896 + sandybrown: 16032864, 1.1897 + seagreen: 3050327, 1.1898 + seashell: 16774638, 1.1899 + sienna: 10506797, 1.1900 + silver: 12632256, 1.1901 + skyblue: 8900331, 1.1902 + slateblue: 6970061, 1.1903 + slategray: 7372944, 1.1904 + slategrey: 7372944, 1.1905 + snow: 16775930, 1.1906 + springgreen: 65407, 1.1907 + steelblue: 4620980, 1.1908 + tan: 13808780, 1.1909 + teal: 32896, 1.1910 + thistle: 14204888, 1.1911 + tomato: 16737095, 1.1912 + turquoise: 4251856, 1.1913 + violet: 15631086, 1.1914 + wheat: 16113331, 1.1915 + white: 16777215, 1.1916 + whitesmoke: 16119285, 1.1917 + yellow: 16776960, 1.1918 + yellowgreen: 10145074 1.1919 + }); 1.1920 + d3_rgb_names.forEach(function(key, value) { 1.1921 + d3_rgb_names.set(key, d3_rgbNumber(value)); 1.1922 + }); 1.1923 + function d3_functor(v) { 1.1924 + return typeof v === "function" ? v : function() { 1.1925 + return v; 1.1926 + }; 1.1927 + } 1.1928 + d3.functor = d3_functor; 1.1929 + d3.xhr = d3_xhrType(d3_identity); 1.1930 + function d3_xhrType(response) { 1.1931 + return function(url, mimeType, callback) { 1.1932 + if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, 1.1933 + mimeType = null; 1.1934 + return d3_xhr(url, mimeType, response, callback); 1.1935 + }; 1.1936 + } 1.1937 + function d3_xhr(url, mimeType, response, callback) { 1.1938 + var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; 1.1939 + if (this.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); 1.1940 + "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { 1.1941 + request.readyState > 3 && respond(); 1.1942 + }; 1.1943 + function respond() { 1.1944 + var status = request.status, result; 1.1945 + if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) { 1.1946 + try { 1.1947 + result = response.call(xhr, request); 1.1948 + } catch (e) { 1.1949 + dispatch.error.call(xhr, e); 1.1950 + return; 1.1951 + } 1.1952 + dispatch.load.call(xhr, result); 1.1953 + } else { 1.1954 + dispatch.error.call(xhr, request); 1.1955 + } 1.1956 + } 1.1957 + request.onprogress = function(event) { 1.1958 + var o = d3.event; 1.1959 + d3.event = event; 1.1960 + try { 1.1961 + dispatch.progress.call(xhr, request); 1.1962 + } finally { 1.1963 + d3.event = o; 1.1964 + } 1.1965 + }; 1.1966 + xhr.header = function(name, value) { 1.1967 + name = (name + "").toLowerCase(); 1.1968 + if (arguments.length < 2) return headers[name]; 1.1969 + if (value == null) delete headers[name]; else headers[name] = value + ""; 1.1970 + return xhr; 1.1971 + }; 1.1972 + xhr.mimeType = function(value) { 1.1973 + if (!arguments.length) return mimeType; 1.1974 + mimeType = value == null ? null : value + ""; 1.1975 + return xhr; 1.1976 + }; 1.1977 + xhr.responseType = function(value) { 1.1978 + if (!arguments.length) return responseType; 1.1979 + responseType = value; 1.1980 + return xhr; 1.1981 + }; 1.1982 + xhr.response = function(value) { 1.1983 + response = value; 1.1984 + return xhr; 1.1985 + }; 1.1986 + [ "get", "post" ].forEach(function(method) { 1.1987 + xhr[method] = function() { 1.1988 + return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); 1.1989 + }; 1.1990 + }); 1.1991 + xhr.send = function(method, data, callback) { 1.1992 + if (arguments.length === 2 && typeof data === "function") callback = data, data = null; 1.1993 + request.open(method, url, true); 1.1994 + if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; 1.1995 + if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); 1.1996 + if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); 1.1997 + if (responseType != null) request.responseType = responseType; 1.1998 + if (callback != null) xhr.on("error", callback).on("load", function(request) { 1.1999 + callback(null, request); 1.2000 + }); 1.2001 + dispatch.beforesend.call(xhr, request); 1.2002 + request.send(data == null ? null : data); 1.2003 + return xhr; 1.2004 + }; 1.2005 + xhr.abort = function() { 1.2006 + request.abort(); 1.2007 + return xhr; 1.2008 + }; 1.2009 + d3.rebind(xhr, dispatch, "on"); 1.2010 + return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); 1.2011 + } 1.2012 + function d3_xhr_fixCallback(callback) { 1.2013 + return callback.length === 1 ? function(error, request) { 1.2014 + callback(error == null ? request : null); 1.2015 + } : callback; 1.2016 + } 1.2017 + function d3_xhrHasResponse(request) { 1.2018 + var type = request.responseType; 1.2019 + return type && type !== "text" ? request.response : request.responseText; 1.2020 + } 1.2021 + d3.dsv = function(delimiter, mimeType) { 1.2022 + var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); 1.2023 + function dsv(url, row, callback) { 1.2024 + if (arguments.length < 3) callback = row, row = null; 1.2025 + var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback); 1.2026 + xhr.row = function(_) { 1.2027 + return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; 1.2028 + }; 1.2029 + return xhr; 1.2030 + } 1.2031 + function response(request) { 1.2032 + return dsv.parse(request.responseText); 1.2033 + } 1.2034 + function typedResponse(f) { 1.2035 + return function(request) { 1.2036 + return dsv.parse(request.responseText, f); 1.2037 + }; 1.2038 + } 1.2039 + dsv.parse = function(text, f) { 1.2040 + var o; 1.2041 + return dsv.parseRows(text, function(row, i) { 1.2042 + if (o) return o(row, i - 1); 1.2043 + var a = new Function("d", "return {" + row.map(function(name, i) { 1.2044 + return JSON.stringify(name) + ": d[" + i + "]"; 1.2045 + }).join(",") + "}"); 1.2046 + o = f ? function(row, i) { 1.2047 + return f(a(row), i); 1.2048 + } : a; 1.2049 + }); 1.2050 + }; 1.2051 + dsv.parseRows = function(text, f) { 1.2052 + var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; 1.2053 + function token() { 1.2054 + if (I >= N) return EOF; 1.2055 + if (eol) return eol = false, EOL; 1.2056 + var j = I; 1.2057 + if (text.charCodeAt(j) === 34) { 1.2058 + var i = j; 1.2059 + while (i++ < N) { 1.2060 + if (text.charCodeAt(i) === 34) { 1.2061 + if (text.charCodeAt(i + 1) !== 34) break; 1.2062 + ++i; 1.2063 + } 1.2064 + } 1.2065 + I = i + 2; 1.2066 + var c = text.charCodeAt(i + 1); 1.2067 + if (c === 13) { 1.2068 + eol = true; 1.2069 + if (text.charCodeAt(i + 2) === 10) ++I; 1.2070 + } else if (c === 10) { 1.2071 + eol = true; 1.2072 + } 1.2073 + return text.slice(j + 1, i).replace(/""/g, '"'); 1.2074 + } 1.2075 + while (I < N) { 1.2076 + var c = text.charCodeAt(I++), k = 1; 1.2077 + if (c === 10) eol = true; else if (c === 13) { 1.2078 + eol = true; 1.2079 + if (text.charCodeAt(I) === 10) ++I, ++k; 1.2080 + } else if (c !== delimiterCode) continue; 1.2081 + return text.slice(j, I - k); 1.2082 + } 1.2083 + return text.slice(j); 1.2084 + } 1.2085 + while ((t = token()) !== EOF) { 1.2086 + var a = []; 1.2087 + while (t !== EOL && t !== EOF) { 1.2088 + a.push(t); 1.2089 + t = token(); 1.2090 + } 1.2091 + if (f && (a = f(a, n++)) == null) continue; 1.2092 + rows.push(a); 1.2093 + } 1.2094 + return rows; 1.2095 + }; 1.2096 + dsv.format = function(rows) { 1.2097 + if (Array.isArray(rows[0])) return dsv.formatRows(rows); 1.2098 + var fieldSet = new d3_Set(), fields = []; 1.2099 + rows.forEach(function(row) { 1.2100 + for (var field in row) { 1.2101 + if (!fieldSet.has(field)) { 1.2102 + fields.push(fieldSet.add(field)); 1.2103 + } 1.2104 + } 1.2105 + }); 1.2106 + return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { 1.2107 + return fields.map(function(field) { 1.2108 + return formatValue(row[field]); 1.2109 + }).join(delimiter); 1.2110 + })).join("\n"); 1.2111 + }; 1.2112 + dsv.formatRows = function(rows) { 1.2113 + return rows.map(formatRow).join("\n"); 1.2114 + }; 1.2115 + function formatRow(row) { 1.2116 + return row.map(formatValue).join(delimiter); 1.2117 + } 1.2118 + function formatValue(text) { 1.2119 + return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; 1.2120 + } 1.2121 + return dsv; 1.2122 + }; 1.2123 + d3.csv = d3.dsv(",", "text/csv"); 1.2124 + d3.tsv = d3.dsv(" ", "text/tab-separated-values"); 1.2125 + var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { 1.2126 + setTimeout(callback, 17); 1.2127 + }; 1.2128 + d3.timer = function() { 1.2129 + d3_timer.apply(this, arguments); 1.2130 + }; 1.2131 + function d3_timer(callback, delay, then) { 1.2132 + var n = arguments.length; 1.2133 + if (n < 2) delay = 0; 1.2134 + if (n < 3) then = Date.now(); 1.2135 + var time = then + delay, timer = { 1.2136 + c: callback, 1.2137 + t: time, 1.2138 + n: null 1.2139 + }; 1.2140 + if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer; 1.2141 + d3_timer_queueTail = timer; 1.2142 + if (!d3_timer_interval) { 1.2143 + d3_timer_timeout = clearTimeout(d3_timer_timeout); 1.2144 + d3_timer_interval = 1; 1.2145 + d3_timer_frame(d3_timer_step); 1.2146 + } 1.2147 + return timer; 1.2148 + } 1.2149 + function d3_timer_step() { 1.2150 + var now = d3_timer_mark(), delay = d3_timer_sweep() - now; 1.2151 + if (delay > 24) { 1.2152 + if (isFinite(delay)) { 1.2153 + clearTimeout(d3_timer_timeout); 1.2154 + d3_timer_timeout = setTimeout(d3_timer_step, delay); 1.2155 + } 1.2156 + d3_timer_interval = 0; 1.2157 + } else { 1.2158 + d3_timer_interval = 1; 1.2159 + d3_timer_frame(d3_timer_step); 1.2160 + } 1.2161 + } 1.2162 + d3.timer.flush = function() { 1.2163 + d3_timer_mark(); 1.2164 + d3_timer_sweep(); 1.2165 + }; 1.2166 + function d3_timer_mark() { 1.2167 + var now = Date.now(), timer = d3_timer_queueHead; 1.2168 + while (timer) { 1.2169 + if (now >= timer.t && timer.c(now - timer.t)) timer.c = null; 1.2170 + timer = timer.n; 1.2171 + } 1.2172 + return now; 1.2173 + } 1.2174 + function d3_timer_sweep() { 1.2175 + var t0, t1 = d3_timer_queueHead, time = Infinity; 1.2176 + while (t1) { 1.2177 + if (t1.c) { 1.2178 + if (t1.t < time) time = t1.t; 1.2179 + t1 = (t0 = t1).n; 1.2180 + } else { 1.2181 + t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n; 1.2182 + } 1.2183 + } 1.2184 + d3_timer_queueTail = t0; 1.2185 + return time; 1.2186 + } 1.2187 + function d3_format_precision(x, p) { 1.2188 + return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); 1.2189 + } 1.2190 + d3.round = function(x, n) { 1.2191 + return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); 1.2192 + }; 1.2193 + var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); 1.2194 + d3.formatPrefix = function(value, precision) { 1.2195 + var i = 0; 1.2196 + if (value = +value) { 1.2197 + if (value < 0) value *= -1; 1.2198 + if (precision) value = d3.round(value, d3_format_precision(value, precision)); 1.2199 + i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); 1.2200 + i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3)); 1.2201 + } 1.2202 + return d3_formatPrefixes[8 + i / 3]; 1.2203 + }; 1.2204 + function d3_formatPrefix(d, i) { 1.2205 + var k = Math.pow(10, abs(8 - i) * 3); 1.2206 + return { 1.2207 + scale: i > 8 ? function(d) { 1.2208 + return d / k; 1.2209 + } : function(d) { 1.2210 + return d * k; 1.2211 + }, 1.2212 + symbol: d 1.2213 + }; 1.2214 + } 1.2215 + function d3_locale_numberFormat(locale) { 1.2216 + var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping && locale_thousands ? function(value, width) { 1.2217 + var i = value.length, t = [], j = 0, g = locale_grouping[0], length = 0; 1.2218 + while (i > 0 && g > 0) { 1.2219 + if (length + g + 1 > width) g = Math.max(1, width - length); 1.2220 + t.push(value.substring(i -= g, i + g)); 1.2221 + if ((length += g + 1) > width) break; 1.2222 + g = locale_grouping[j = (j + 1) % locale_grouping.length]; 1.2223 + } 1.2224 + return t.reverse().join(locale_thousands); 1.2225 + } : d3_identity; 1.2226 + return function(specifier) { 1.2227 + var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "-", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false, exponent = true; 1.2228 + if (precision) precision = +precision.substring(1); 1.2229 + if (zfill || fill === "0" && align === "=") { 1.2230 + zfill = fill = "0"; 1.2231 + align = "="; 1.2232 + } 1.2233 + switch (type) { 1.2234 + case "n": 1.2235 + comma = true; 1.2236 + type = "g"; 1.2237 + break; 1.2238 + 1.2239 + case "%": 1.2240 + scale = 100; 1.2241 + suffix = "%"; 1.2242 + type = "f"; 1.2243 + break; 1.2244 + 1.2245 + case "p": 1.2246 + scale = 100; 1.2247 + suffix = "%"; 1.2248 + type = "r"; 1.2249 + break; 1.2250 + 1.2251 + case "b": 1.2252 + case "o": 1.2253 + case "x": 1.2254 + case "X": 1.2255 + if (symbol === "#") prefix = "0" + type.toLowerCase(); 1.2256 + 1.2257 + case "c": 1.2258 + exponent = false; 1.2259 + 1.2260 + case "d": 1.2261 + integer = true; 1.2262 + precision = 0; 1.2263 + break; 1.2264 + 1.2265 + case "s": 1.2266 + scale = -1; 1.2267 + type = "r"; 1.2268 + break; 1.2269 + } 1.2270 + if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1]; 1.2271 + if (type == "r" && !precision) type = "g"; 1.2272 + if (precision != null) { 1.2273 + if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); 1.2274 + } 1.2275 + type = d3_format_types.get(type) || d3_format_typeDefault; 1.2276 + var zcomma = zfill && comma; 1.2277 + return function(value) { 1.2278 + var fullSuffix = suffix; 1.2279 + if (integer && value % 1) return ""; 1.2280 + var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign; 1.2281 + if (scale < 0) { 1.2282 + var unit = d3.formatPrefix(value, precision); 1.2283 + value = unit.scale(value); 1.2284 + fullSuffix = unit.symbol + suffix; 1.2285 + } else { 1.2286 + value *= scale; 1.2287 + } 1.2288 + value = type(value, precision); 1.2289 + var i = value.lastIndexOf("."), before, after; 1.2290 + if (i < 0) { 1.2291 + var j = exponent ? value.lastIndexOf("e") : -1; 1.2292 + if (j < 0) before = value, after = ""; else before = value.substring(0, j), after = value.substring(j); 1.2293 + } else { 1.2294 + before = value.substring(0, i); 1.2295 + after = locale_decimal + value.substring(i + 1); 1.2296 + } 1.2297 + if (!zfill && comma) before = formatGroup(before, Infinity); 1.2298 + var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; 1.2299 + if (zcomma) before = formatGroup(padding + before, padding.length ? width - after.length : Infinity); 1.2300 + negative += prefix; 1.2301 + value = before + after; 1.2302 + return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + fullSuffix; 1.2303 + }; 1.2304 + }; 1.2305 + } 1.2306 + var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; 1.2307 + var d3_format_types = d3.map({ 1.2308 + b: function(x) { 1.2309 + return x.toString(2); 1.2310 + }, 1.2311 + c: function(x) { 1.2312 + return String.fromCharCode(x); 1.2313 + }, 1.2314 + o: function(x) { 1.2315 + return x.toString(8); 1.2316 + }, 1.2317 + x: function(x) { 1.2318 + return x.toString(16); 1.2319 + }, 1.2320 + X: function(x) { 1.2321 + return x.toString(16).toUpperCase(); 1.2322 + }, 1.2323 + g: function(x, p) { 1.2324 + return x.toPrecision(p); 1.2325 + }, 1.2326 + e: function(x, p) { 1.2327 + return x.toExponential(p); 1.2328 + }, 1.2329 + f: function(x, p) { 1.2330 + return x.toFixed(p); 1.2331 + }, 1.2332 + r: function(x, p) { 1.2333 + return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); 1.2334 + } 1.2335 + }); 1.2336 + function d3_format_typeDefault(x) { 1.2337 + return x + ""; 1.2338 + } 1.2339 + var d3_time = d3.time = {}, d3_date = Date; 1.2340 + function d3_date_utc() { 1.2341 + this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); 1.2342 + } 1.2343 + d3_date_utc.prototype = { 1.2344 + getDate: function() { 1.2345 + return this._.getUTCDate(); 1.2346 + }, 1.2347 + getDay: function() { 1.2348 + return this._.getUTCDay(); 1.2349 + }, 1.2350 + getFullYear: function() { 1.2351 + return this._.getUTCFullYear(); 1.2352 + }, 1.2353 + getHours: function() { 1.2354 + return this._.getUTCHours(); 1.2355 + }, 1.2356 + getMilliseconds: function() { 1.2357 + return this._.getUTCMilliseconds(); 1.2358 + }, 1.2359 + getMinutes: function() { 1.2360 + return this._.getUTCMinutes(); 1.2361 + }, 1.2362 + getMonth: function() { 1.2363 + return this._.getUTCMonth(); 1.2364 + }, 1.2365 + getSeconds: function() { 1.2366 + return this._.getUTCSeconds(); 1.2367 + }, 1.2368 + getTime: function() { 1.2369 + return this._.getTime(); 1.2370 + }, 1.2371 + getTimezoneOffset: function() { 1.2372 + return 0; 1.2373 + }, 1.2374 + valueOf: function() { 1.2375 + return this._.valueOf(); 1.2376 + }, 1.2377 + setDate: function() { 1.2378 + d3_time_prototype.setUTCDate.apply(this._, arguments); 1.2379 + }, 1.2380 + setDay: function() { 1.2381 + d3_time_prototype.setUTCDay.apply(this._, arguments); 1.2382 + }, 1.2383 + setFullYear: function() { 1.2384 + d3_time_prototype.setUTCFullYear.apply(this._, arguments); 1.2385 + }, 1.2386 + setHours: function() { 1.2387 + d3_time_prototype.setUTCHours.apply(this._, arguments); 1.2388 + }, 1.2389 + setMilliseconds: function() { 1.2390 + d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); 1.2391 + }, 1.2392 + setMinutes: function() { 1.2393 + d3_time_prototype.setUTCMinutes.apply(this._, arguments); 1.2394 + }, 1.2395 + setMonth: function() { 1.2396 + d3_time_prototype.setUTCMonth.apply(this._, arguments); 1.2397 + }, 1.2398 + setSeconds: function() { 1.2399 + d3_time_prototype.setUTCSeconds.apply(this._, arguments); 1.2400 + }, 1.2401 + setTime: function() { 1.2402 + d3_time_prototype.setTime.apply(this._, arguments); 1.2403 + } 1.2404 + }; 1.2405 + var d3_time_prototype = Date.prototype; 1.2406 + function d3_time_interval(local, step, number) { 1.2407 + function round(date) { 1.2408 + var d0 = local(date), d1 = offset(d0, 1); 1.2409 + return date - d0 < d1 - date ? d0 : d1; 1.2410 + } 1.2411 + function ceil(date) { 1.2412 + step(date = local(new d3_date(date - 1)), 1); 1.2413 + return date; 1.2414 + } 1.2415 + function offset(date, k) { 1.2416 + step(date = new d3_date(+date), k); 1.2417 + return date; 1.2418 + } 1.2419 + function range(t0, t1, dt) { 1.2420 + var time = ceil(t0), times = []; 1.2421 + if (dt > 1) { 1.2422 + while (time < t1) { 1.2423 + if (!(number(time) % dt)) times.push(new Date(+time)); 1.2424 + step(time, 1); 1.2425 + } 1.2426 + } else { 1.2427 + while (time < t1) times.push(new Date(+time)), step(time, 1); 1.2428 + } 1.2429 + return times; 1.2430 + } 1.2431 + function range_utc(t0, t1, dt) { 1.2432 + try { 1.2433 + d3_date = d3_date_utc; 1.2434 + var utc = new d3_date_utc(); 1.2435 + utc._ = t0; 1.2436 + return range(utc, t1, dt); 1.2437 + } finally { 1.2438 + d3_date = Date; 1.2439 + } 1.2440 + } 1.2441 + local.floor = local; 1.2442 + local.round = round; 1.2443 + local.ceil = ceil; 1.2444 + local.offset = offset; 1.2445 + local.range = range; 1.2446 + var utc = local.utc = d3_time_interval_utc(local); 1.2447 + utc.floor = utc; 1.2448 + utc.round = d3_time_interval_utc(round); 1.2449 + utc.ceil = d3_time_interval_utc(ceil); 1.2450 + utc.offset = d3_time_interval_utc(offset); 1.2451 + utc.range = range_utc; 1.2452 + return local; 1.2453 + } 1.2454 + function d3_time_interval_utc(method) { 1.2455 + return function(date, k) { 1.2456 + try { 1.2457 + d3_date = d3_date_utc; 1.2458 + var utc = new d3_date_utc(); 1.2459 + utc._ = date; 1.2460 + return method(utc, k)._; 1.2461 + } finally { 1.2462 + d3_date = Date; 1.2463 + } 1.2464 + }; 1.2465 + } 1.2466 + d3_time.year = d3_time_interval(function(date) { 1.2467 + date = d3_time.day(date); 1.2468 + date.setMonth(0, 1); 1.2469 + return date; 1.2470 + }, function(date, offset) { 1.2471 + date.setFullYear(date.getFullYear() + offset); 1.2472 + }, function(date) { 1.2473 + return date.getFullYear(); 1.2474 + }); 1.2475 + d3_time.years = d3_time.year.range; 1.2476 + d3_time.years.utc = d3_time.year.utc.range; 1.2477 + d3_time.day = d3_time_interval(function(date) { 1.2478 + var day = new d3_date(2e3, 0); 1.2479 + day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); 1.2480 + return day; 1.2481 + }, function(date, offset) { 1.2482 + date.setDate(date.getDate() + offset); 1.2483 + }, function(date) { 1.2484 + return date.getDate() - 1; 1.2485 + }); 1.2486 + d3_time.days = d3_time.day.range; 1.2487 + d3_time.days.utc = d3_time.day.utc.range; 1.2488 + d3_time.dayOfYear = function(date) { 1.2489 + var year = d3_time.year(date); 1.2490 + return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); 1.2491 + }; 1.2492 + [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) { 1.2493 + i = 7 - i; 1.2494 + var interval = d3_time[day] = d3_time_interval(function(date) { 1.2495 + (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); 1.2496 + return date; 1.2497 + }, function(date, offset) { 1.2498 + date.setDate(date.getDate() + Math.floor(offset) * 7); 1.2499 + }, function(date) { 1.2500 + var day = d3_time.year(date).getDay(); 1.2501 + return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); 1.2502 + }); 1.2503 + d3_time[day + "s"] = interval.range; 1.2504 + d3_time[day + "s"].utc = interval.utc.range; 1.2505 + d3_time[day + "OfYear"] = function(date) { 1.2506 + var day = d3_time.year(date).getDay(); 1.2507 + return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7); 1.2508 + }; 1.2509 + }); 1.2510 + d3_time.week = d3_time.sunday; 1.2511 + d3_time.weeks = d3_time.sunday.range; 1.2512 + d3_time.weeks.utc = d3_time.sunday.utc.range; 1.2513 + d3_time.weekOfYear = d3_time.sundayOfYear; 1.2514 + function d3_locale_timeFormat(locale) { 1.2515 + var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths; 1.2516 + function d3_time_format(template) { 1.2517 + var n = template.length; 1.2518 + function format(date) { 1.2519 + var string = [], i = -1, j = 0, c, p, f; 1.2520 + while (++i < n) { 1.2521 + if (template.charCodeAt(i) === 37) { 1.2522 + string.push(template.slice(j, i)); 1.2523 + if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); 1.2524 + if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); 1.2525 + string.push(c); 1.2526 + j = i + 1; 1.2527 + } 1.2528 + } 1.2529 + string.push(template.slice(j, i)); 1.2530 + return string.join(""); 1.2531 + } 1.2532 + format.parse = function(string) { 1.2533 + var d = { 1.2534 + y: 1900, 1.2535 + m: 0, 1.2536 + d: 1, 1.2537 + H: 0, 1.2538 + M: 0, 1.2539 + S: 0, 1.2540 + L: 0, 1.2541 + Z: null 1.2542 + }, i = d3_time_parse(d, template, string, 0); 1.2543 + if (i != string.length) return null; 1.2544 + if ("p" in d) d.H = d.H % 12 + d.p * 12; 1.2545 + var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)(); 1.2546 + if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("W" in d || "U" in d) { 1.2547 + if (!("w" in d)) d.w = "W" in d ? 1 : 0; 1.2548 + date.setFullYear(d.y, 0, 1); 1.2549 + date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); 1.2550 + } else date.setFullYear(d.y, d.m, d.d); 1.2551 + date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L); 1.2552 + return localZ ? date._ : date; 1.2553 + }; 1.2554 + format.toString = function() { 1.2555 + return template; 1.2556 + }; 1.2557 + return format; 1.2558 + } 1.2559 + function d3_time_parse(date, template, string, j) { 1.2560 + var c, p, t, i = 0, n = template.length, m = string.length; 1.2561 + while (i < n) { 1.2562 + if (j >= m) return -1; 1.2563 + c = template.charCodeAt(i++); 1.2564 + if (c === 37) { 1.2565 + t = template.charAt(i++); 1.2566 + p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t]; 1.2567 + if (!p || (j = p(date, string, j)) < 0) return -1; 1.2568 + } else if (c != string.charCodeAt(j++)) { 1.2569 + return -1; 1.2570 + } 1.2571 + } 1.2572 + return j; 1.2573 + } 1.2574 + d3_time_format.utc = function(template) { 1.2575 + var local = d3_time_format(template); 1.2576 + function format(date) { 1.2577 + try { 1.2578 + d3_date = d3_date_utc; 1.2579 + var utc = new d3_date(); 1.2580 + utc._ = date; 1.2581 + return local(utc); 1.2582 + } finally { 1.2583 + d3_date = Date; 1.2584 + } 1.2585 + } 1.2586 + format.parse = function(string) { 1.2587 + try { 1.2588 + d3_date = d3_date_utc; 1.2589 + var date = local.parse(string); 1.2590 + return date && date._; 1.2591 + } finally { 1.2592 + d3_date = Date; 1.2593 + } 1.2594 + }; 1.2595 + format.toString = local.toString; 1.2596 + return format; 1.2597 + }; 1.2598 + d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti; 1.2599 + var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths); 1.2600 + locale_periods.forEach(function(p, i) { 1.2601 + d3_time_periodLookup.set(p.toLowerCase(), i); 1.2602 + }); 1.2603 + var d3_time_formats = { 1.2604 + a: function(d) { 1.2605 + return locale_shortDays[d.getDay()]; 1.2606 + }, 1.2607 + A: function(d) { 1.2608 + return locale_days[d.getDay()]; 1.2609 + }, 1.2610 + b: function(d) { 1.2611 + return locale_shortMonths[d.getMonth()]; 1.2612 + }, 1.2613 + B: function(d) { 1.2614 + return locale_months[d.getMonth()]; 1.2615 + }, 1.2616 + c: d3_time_format(locale_dateTime), 1.2617 + d: function(d, p) { 1.2618 + return d3_time_formatPad(d.getDate(), p, 2); 1.2619 + }, 1.2620 + e: function(d, p) { 1.2621 + return d3_time_formatPad(d.getDate(), p, 2); 1.2622 + }, 1.2623 + H: function(d, p) { 1.2624 + return d3_time_formatPad(d.getHours(), p, 2); 1.2625 + }, 1.2626 + I: function(d, p) { 1.2627 + return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); 1.2628 + }, 1.2629 + j: function(d, p) { 1.2630 + return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3); 1.2631 + }, 1.2632 + L: function(d, p) { 1.2633 + return d3_time_formatPad(d.getMilliseconds(), p, 3); 1.2634 + }, 1.2635 + m: function(d, p) { 1.2636 + return d3_time_formatPad(d.getMonth() + 1, p, 2); 1.2637 + }, 1.2638 + M: function(d, p) { 1.2639 + return d3_time_formatPad(d.getMinutes(), p, 2); 1.2640 + }, 1.2641 + p: function(d) { 1.2642 + return locale_periods[+(d.getHours() >= 12)]; 1.2643 + }, 1.2644 + S: function(d, p) { 1.2645 + return d3_time_formatPad(d.getSeconds(), p, 2); 1.2646 + }, 1.2647 + U: function(d, p) { 1.2648 + return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2); 1.2649 + }, 1.2650 + w: function(d) { 1.2651 + return d.getDay(); 1.2652 + }, 1.2653 + W: function(d, p) { 1.2654 + return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2); 1.2655 + }, 1.2656 + x: d3_time_format(locale_date), 1.2657 + X: d3_time_format(locale_time), 1.2658 + y: function(d, p) { 1.2659 + return d3_time_formatPad(d.getFullYear() % 100, p, 2); 1.2660 + }, 1.2661 + Y: function(d, p) { 1.2662 + return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); 1.2663 + }, 1.2664 + Z: d3_time_zone, 1.2665 + "%": function() { 1.2666 + return "%"; 1.2667 + } 1.2668 + }; 1.2669 + var d3_time_parsers = { 1.2670 + a: d3_time_parseWeekdayAbbrev, 1.2671 + A: d3_time_parseWeekday, 1.2672 + b: d3_time_parseMonthAbbrev, 1.2673 + B: d3_time_parseMonth, 1.2674 + c: d3_time_parseLocaleFull, 1.2675 + d: d3_time_parseDay, 1.2676 + e: d3_time_parseDay, 1.2677 + H: d3_time_parseHour24, 1.2678 + I: d3_time_parseHour24, 1.2679 + j: d3_time_parseDayOfYear, 1.2680 + L: d3_time_parseMilliseconds, 1.2681 + m: d3_time_parseMonthNumber, 1.2682 + M: d3_time_parseMinutes, 1.2683 + p: d3_time_parseAmPm, 1.2684 + S: d3_time_parseSeconds, 1.2685 + U: d3_time_parseWeekNumberSunday, 1.2686 + w: d3_time_parseWeekdayNumber, 1.2687 + W: d3_time_parseWeekNumberMonday, 1.2688 + x: d3_time_parseLocaleDate, 1.2689 + X: d3_time_parseLocaleTime, 1.2690 + y: d3_time_parseYear, 1.2691 + Y: d3_time_parseFullYear, 1.2692 + Z: d3_time_parseZone, 1.2693 + "%": d3_time_parseLiteralPercent 1.2694 + }; 1.2695 + function d3_time_parseWeekdayAbbrev(date, string, i) { 1.2696 + d3_time_dayAbbrevRe.lastIndex = 0; 1.2697 + var n = d3_time_dayAbbrevRe.exec(string.slice(i)); 1.2698 + return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; 1.2699 + } 1.2700 + function d3_time_parseWeekday(date, string, i) { 1.2701 + d3_time_dayRe.lastIndex = 0; 1.2702 + var n = d3_time_dayRe.exec(string.slice(i)); 1.2703 + return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; 1.2704 + } 1.2705 + function d3_time_parseMonthAbbrev(date, string, i) { 1.2706 + d3_time_monthAbbrevRe.lastIndex = 0; 1.2707 + var n = d3_time_monthAbbrevRe.exec(string.slice(i)); 1.2708 + return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; 1.2709 + } 1.2710 + function d3_time_parseMonth(date, string, i) { 1.2711 + d3_time_monthRe.lastIndex = 0; 1.2712 + var n = d3_time_monthRe.exec(string.slice(i)); 1.2713 + return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; 1.2714 + } 1.2715 + function d3_time_parseLocaleFull(date, string, i) { 1.2716 + return d3_time_parse(date, d3_time_formats.c.toString(), string, i); 1.2717 + } 1.2718 + function d3_time_parseLocaleDate(date, string, i) { 1.2719 + return d3_time_parse(date, d3_time_formats.x.toString(), string, i); 1.2720 + } 1.2721 + function d3_time_parseLocaleTime(date, string, i) { 1.2722 + return d3_time_parse(date, d3_time_formats.X.toString(), string, i); 1.2723 + } 1.2724 + function d3_time_parseAmPm(date, string, i) { 1.2725 + var n = d3_time_periodLookup.get(string.slice(i, i += 2).toLowerCase()); 1.2726 + return n == null ? -1 : (date.p = n, i); 1.2727 + } 1.2728 + return d3_time_format; 1.2729 + } 1.2730 + var d3_time_formatPads = { 1.2731 + "-": "", 1.2732 + _: " ", 1.2733 + "0": "0" 1.2734 + }, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/; 1.2735 + function d3_time_formatPad(value, fill, width) { 1.2736 + var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; 1.2737 + return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); 1.2738 + } 1.2739 + function d3_time_formatRe(names) { 1.2740 + return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); 1.2741 + } 1.2742 + function d3_time_formatLookup(names) { 1.2743 + var map = new d3_Map(), i = -1, n = names.length; 1.2744 + while (++i < n) map.set(names[i].toLowerCase(), i); 1.2745 + return map; 1.2746 + } 1.2747 + function d3_time_parseWeekdayNumber(date, string, i) { 1.2748 + d3_time_numberRe.lastIndex = 0; 1.2749 + var n = d3_time_numberRe.exec(string.slice(i, i + 1)); 1.2750 + return n ? (date.w = +n[0], i + n[0].length) : -1; 1.2751 + } 1.2752 + function d3_time_parseWeekNumberSunday(date, string, i) { 1.2753 + d3_time_numberRe.lastIndex = 0; 1.2754 + var n = d3_time_numberRe.exec(string.slice(i)); 1.2755 + return n ? (date.U = +n[0], i + n[0].length) : -1; 1.2756 + } 1.2757 + function d3_time_parseWeekNumberMonday(date, string, i) { 1.2758 + d3_time_numberRe.lastIndex = 0; 1.2759 + var n = d3_time_numberRe.exec(string.slice(i)); 1.2760 + return n ? (date.W = +n[0], i + n[0].length) : -1; 1.2761 + } 1.2762 + function d3_time_parseFullYear(date, string, i) { 1.2763 + d3_time_numberRe.lastIndex = 0; 1.2764 + var n = d3_time_numberRe.exec(string.slice(i, i + 4)); 1.2765 + return n ? (date.y = +n[0], i + n[0].length) : -1; 1.2766 + } 1.2767 + function d3_time_parseYear(date, string, i) { 1.2768 + d3_time_numberRe.lastIndex = 0; 1.2769 + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); 1.2770 + return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; 1.2771 + } 1.2772 + function d3_time_parseZone(date, string, i) { 1.2773 + return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5)) ? (date.Z = -string, 1.2774 + i + 5) : -1; 1.2775 + } 1.2776 + function d3_time_expandYear(d) { 1.2777 + return d + (d > 68 ? 1900 : 2e3); 1.2778 + } 1.2779 + function d3_time_parseMonthNumber(date, string, i) { 1.2780 + d3_time_numberRe.lastIndex = 0; 1.2781 + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); 1.2782 + return n ? (date.m = n[0] - 1, i + n[0].length) : -1; 1.2783 + } 1.2784 + function d3_time_parseDay(date, string, i) { 1.2785 + d3_time_numberRe.lastIndex = 0; 1.2786 + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); 1.2787 + return n ? (date.d = +n[0], i + n[0].length) : -1; 1.2788 + } 1.2789 + function d3_time_parseDayOfYear(date, string, i) { 1.2790 + d3_time_numberRe.lastIndex = 0; 1.2791 + var n = d3_time_numberRe.exec(string.slice(i, i + 3)); 1.2792 + return n ? (date.j = +n[0], i + n[0].length) : -1; 1.2793 + } 1.2794 + function d3_time_parseHour24(date, string, i) { 1.2795 + d3_time_numberRe.lastIndex = 0; 1.2796 + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); 1.2797 + return n ? (date.H = +n[0], i + n[0].length) : -1; 1.2798 + } 1.2799 + function d3_time_parseMinutes(date, string, i) { 1.2800 + d3_time_numberRe.lastIndex = 0; 1.2801 + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); 1.2802 + return n ? (date.M = +n[0], i + n[0].length) : -1; 1.2803 + } 1.2804 + function d3_time_parseSeconds(date, string, i) { 1.2805 + d3_time_numberRe.lastIndex = 0; 1.2806 + var n = d3_time_numberRe.exec(string.slice(i, i + 2)); 1.2807 + return n ? (date.S = +n[0], i + n[0].length) : -1; 1.2808 + } 1.2809 + function d3_time_parseMilliseconds(date, string, i) { 1.2810 + d3_time_numberRe.lastIndex = 0; 1.2811 + var n = d3_time_numberRe.exec(string.slice(i, i + 3)); 1.2812 + return n ? (date.L = +n[0], i + n[0].length) : -1; 1.2813 + } 1.2814 + function d3_time_zone(d) { 1.2815 + var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = abs(z) / 60 | 0, zm = abs(z) % 60; 1.2816 + return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); 1.2817 + } 1.2818 + function d3_time_parseLiteralPercent(date, string, i) { 1.2819 + d3_time_percentRe.lastIndex = 0; 1.2820 + var n = d3_time_percentRe.exec(string.slice(i, i + 1)); 1.2821 + return n ? i + n[0].length : -1; 1.2822 + } 1.2823 + function d3_time_formatMulti(formats) { 1.2824 + var n = formats.length, i = -1; 1.2825 + while (++i < n) formats[i][0] = this(formats[i][0]); 1.2826 + return function(date) { 1.2827 + var i = 0, f = formats[i]; 1.2828 + while (!f[1](date)) f = formats[++i]; 1.2829 + return f[0](date); 1.2830 + }; 1.2831 + } 1.2832 + d3.locale = function(locale) { 1.2833 + return { 1.2834 + numberFormat: d3_locale_numberFormat(locale), 1.2835 + timeFormat: d3_locale_timeFormat(locale) 1.2836 + }; 1.2837 + }; 1.2838 + var d3_locale_enUS = d3.locale({ 1.2839 + decimal: ".", 1.2840 + thousands: ",", 1.2841 + grouping: [ 3 ], 1.2842 + currency: [ "$", "" ], 1.2843 + dateTime: "%a %b %e %X %Y", 1.2844 + date: "%m/%d/%Y", 1.2845 + time: "%H:%M:%S", 1.2846 + periods: [ "AM", "PM" ], 1.2847 + days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], 1.2848 + shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], 1.2849 + months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 1.2850 + shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] 1.2851 + }); 1.2852 + d3.format = d3_locale_enUS.numberFormat; 1.2853 + d3.geo = {}; 1.2854 + function d3_adder() {} 1.2855 + d3_adder.prototype = { 1.2856 + s: 0, 1.2857 + t: 0, 1.2858 + add: function(y) { 1.2859 + d3_adderSum(y, this.t, d3_adderTemp); 1.2860 + d3_adderSum(d3_adderTemp.s, this.s, this); 1.2861 + if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; 1.2862 + }, 1.2863 + reset: function() { 1.2864 + this.s = this.t = 0; 1.2865 + }, 1.2866 + valueOf: function() { 1.2867 + return this.s; 1.2868 + } 1.2869 + }; 1.2870 + var d3_adderTemp = new d3_adder(); 1.2871 + function d3_adderSum(a, b, o) { 1.2872 + var x = o.s = a + b, bv = x - a, av = x - bv; 1.2873 + o.t = a - av + (b - bv); 1.2874 + } 1.2875 + d3.geo.stream = function(object, listener) { 1.2876 + if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { 1.2877 + d3_geo_streamObjectType[object.type](object, listener); 1.2878 + } else { 1.2879 + d3_geo_streamGeometry(object, listener); 1.2880 + } 1.2881 + }; 1.2882 + function d3_geo_streamGeometry(geometry, listener) { 1.2883 + if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { 1.2884 + d3_geo_streamGeometryType[geometry.type](geometry, listener); 1.2885 + } 1.2886 + } 1.2887 + var d3_geo_streamObjectType = { 1.2888 + Feature: function(feature, listener) { 1.2889 + d3_geo_streamGeometry(feature.geometry, listener); 1.2890 + }, 1.2891 + FeatureCollection: function(object, listener) { 1.2892 + var features = object.features, i = -1, n = features.length; 1.2893 + while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); 1.2894 + } 1.2895 + }; 1.2896 + var d3_geo_streamGeometryType = { 1.2897 + Sphere: function(object, listener) { 1.2898 + listener.sphere(); 1.2899 + }, 1.2900 + Point: function(object, listener) { 1.2901 + object = object.coordinates; 1.2902 + listener.point(object[0], object[1], object[2]); 1.2903 + }, 1.2904 + MultiPoint: function(object, listener) { 1.2905 + var coordinates = object.coordinates, i = -1, n = coordinates.length; 1.2906 + while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]); 1.2907 + }, 1.2908 + LineString: function(object, listener) { 1.2909 + d3_geo_streamLine(object.coordinates, listener, 0); 1.2910 + }, 1.2911 + MultiLineString: function(object, listener) { 1.2912 + var coordinates = object.coordinates, i = -1, n = coordinates.length; 1.2913 + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); 1.2914 + }, 1.2915 + Polygon: function(object, listener) { 1.2916 + d3_geo_streamPolygon(object.coordinates, listener); 1.2917 + }, 1.2918 + MultiPolygon: function(object, listener) { 1.2919 + var coordinates = object.coordinates, i = -1, n = coordinates.length; 1.2920 + while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); 1.2921 + }, 1.2922 + GeometryCollection: function(object, listener) { 1.2923 + var geometries = object.geometries, i = -1, n = geometries.length; 1.2924 + while (++i < n) d3_geo_streamGeometry(geometries[i], listener); 1.2925 + } 1.2926 + }; 1.2927 + function d3_geo_streamLine(coordinates, listener, closed) { 1.2928 + var i = -1, n = coordinates.length - closed, coordinate; 1.2929 + listener.lineStart(); 1.2930 + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]); 1.2931 + listener.lineEnd(); 1.2932 + } 1.2933 + function d3_geo_streamPolygon(coordinates, listener) { 1.2934 + var i = -1, n = coordinates.length; 1.2935 + listener.polygonStart(); 1.2936 + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); 1.2937 + listener.polygonEnd(); 1.2938 + } 1.2939 + d3.geo.area = function(object) { 1.2940 + d3_geo_areaSum = 0; 1.2941 + d3.geo.stream(object, d3_geo_area); 1.2942 + return d3_geo_areaSum; 1.2943 + }; 1.2944 + var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); 1.2945 + var d3_geo_area = { 1.2946 + sphere: function() { 1.2947 + d3_geo_areaSum += 4 * π; 1.2948 + }, 1.2949 + point: d3_noop, 1.2950 + lineStart: d3_noop, 1.2951 + lineEnd: d3_noop, 1.2952 + polygonStart: function() { 1.2953 + d3_geo_areaRingSum.reset(); 1.2954 + d3_geo_area.lineStart = d3_geo_areaRingStart; 1.2955 + }, 1.2956 + polygonEnd: function() { 1.2957 + var area = 2 * d3_geo_areaRingSum; 1.2958 + d3_geo_areaSum += area < 0 ? 4 * π + area : area; 1.2959 + d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; 1.2960 + } 1.2961 + }; 1.2962 + function d3_geo_areaRingStart() { 1.2963 + var λ00, φ00, λ0, cosφ0, sinφ0; 1.2964 + d3_geo_area.point = function(λ, φ) { 1.2965 + d3_geo_area.point = nextPoint; 1.2966 + λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), 1.2967 + sinφ0 = Math.sin(φ); 1.2968 + }; 1.2969 + function nextPoint(λ, φ) { 1.2970 + λ *= d3_radians; 1.2971 + φ = φ * d3_radians / 2 + π / 4; 1.2972 + var dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ); 1.2973 + d3_geo_areaRingSum.add(Math.atan2(v, u)); 1.2974 + λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; 1.2975 + } 1.2976 + d3_geo_area.lineEnd = function() { 1.2977 + nextPoint(λ00, φ00); 1.2978 + }; 1.2979 + } 1.2980 + function d3_geo_cartesian(spherical) { 1.2981 + var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); 1.2982 + return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; 1.2983 + } 1.2984 + function d3_geo_cartesianDot(a, b) { 1.2985 + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; 1.2986 + } 1.2987 + function d3_geo_cartesianCross(a, b) { 1.2988 + 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] ]; 1.2989 + } 1.2990 + function d3_geo_cartesianAdd(a, b) { 1.2991 + a[0] += b[0]; 1.2992 + a[1] += b[1]; 1.2993 + a[2] += b[2]; 1.2994 + } 1.2995 + function d3_geo_cartesianScale(vector, k) { 1.2996 + return [ vector[0] * k, vector[1] * k, vector[2] * k ]; 1.2997 + } 1.2998 + function d3_geo_cartesianNormalize(d) { 1.2999 + var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); 1.3000 + d[0] /= l; 1.3001 + d[1] /= l; 1.3002 + d[2] /= l; 1.3003 + } 1.3004 + function d3_geo_spherical(cartesian) { 1.3005 + return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; 1.3006 + } 1.3007 + function d3_geo_sphericalEqual(a, b) { 1.3008 + return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε; 1.3009 + } 1.3010 + d3.geo.bounds = function() { 1.3011 + var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; 1.3012 + var bound = { 1.3013 + point: point, 1.3014 + lineStart: lineStart, 1.3015 + lineEnd: lineEnd, 1.3016 + polygonStart: function() { 1.3017 + bound.point = ringPoint; 1.3018 + bound.lineStart = ringStart; 1.3019 + bound.lineEnd = ringEnd; 1.3020 + dλSum = 0; 1.3021 + d3_geo_area.polygonStart(); 1.3022 + }, 1.3023 + polygonEnd: function() { 1.3024 + d3_geo_area.polygonEnd(); 1.3025 + bound.point = point; 1.3026 + bound.lineStart = lineStart; 1.3027 + bound.lineEnd = lineEnd; 1.3028 + if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; 1.3029 + range[0] = λ0, range[1] = λ1; 1.3030 + } 1.3031 + }; 1.3032 + function point(λ, φ) { 1.3033 + ranges.push(range = [ λ0 = λ, λ1 = λ ]); 1.3034 + if (φ < φ0) φ0 = φ; 1.3035 + if (φ > φ1) φ1 = φ; 1.3036 + } 1.3037 + function linePoint(λ, φ) { 1.3038 + var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); 1.3039 + if (p0) { 1.3040 + var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); 1.3041 + d3_geo_cartesianNormalize(inflection); 1.3042 + inflection = d3_geo_spherical(inflection); 1.3043 + var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180; 1.3044 + if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { 1.3045 + var φi = inflection[1] * d3_degrees; 1.3046 + if (φi > φ1) φ1 = φi; 1.3047 + } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { 1.3048 + var φi = -inflection[1] * d3_degrees; 1.3049 + if (φi < φ0) φ0 = φi; 1.3050 + } else { 1.3051 + if (φ < φ0) φ0 = φ; 1.3052 + if (φ > φ1) φ1 = φ; 1.3053 + } 1.3054 + if (antimeridian) { 1.3055 + if (λ < λ_) { 1.3056 + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; 1.3057 + } else { 1.3058 + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; 1.3059 + } 1.3060 + } else { 1.3061 + if (λ1 >= λ0) { 1.3062 + if (λ < λ0) λ0 = λ; 1.3063 + if (λ > λ1) λ1 = λ; 1.3064 + } else { 1.3065 + if (λ > λ_) { 1.3066 + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; 1.3067 + } else { 1.3068 + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; 1.3069 + } 1.3070 + } 1.3071 + } 1.3072 + } else { 1.3073 + point(λ, φ); 1.3074 + } 1.3075 + p0 = p, λ_ = λ; 1.3076 + } 1.3077 + function lineStart() { 1.3078 + bound.point = linePoint; 1.3079 + } 1.3080 + function lineEnd() { 1.3081 + range[0] = λ0, range[1] = λ1; 1.3082 + bound.point = point; 1.3083 + p0 = null; 1.3084 + } 1.3085 + function ringPoint(λ, φ) { 1.3086 + if (p0) { 1.3087 + var dλ = λ - λ_; 1.3088 + dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; 1.3089 + } else λ__ = λ, φ__ = φ; 1.3090 + d3_geo_area.point(λ, φ); 1.3091 + linePoint(λ, φ); 1.3092 + } 1.3093 + function ringStart() { 1.3094 + d3_geo_area.lineStart(); 1.3095 + } 1.3096 + function ringEnd() { 1.3097 + ringPoint(λ__, φ__); 1.3098 + d3_geo_area.lineEnd(); 1.3099 + if (abs(dλSum) > ε) λ0 = -(λ1 = 180); 1.3100 + range[0] = λ0, range[1] = λ1; 1.3101 + p0 = null; 1.3102 + } 1.3103 + function angle(λ0, λ1) { 1.3104 + return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; 1.3105 + } 1.3106 + function compareRanges(a, b) { 1.3107 + return a[0] - b[0]; 1.3108 + } 1.3109 + function withinRange(x, range) { 1.3110 + return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; 1.3111 + } 1.3112 + return function(feature) { 1.3113 + φ1 = λ1 = -(λ0 = φ0 = Infinity); 1.3114 + ranges = []; 1.3115 + d3.geo.stream(feature, bound); 1.3116 + var n = ranges.length; 1.3117 + if (n) { 1.3118 + ranges.sort(compareRanges); 1.3119 + for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { 1.3120 + b = ranges[i]; 1.3121 + if (withinRange(b[0], a) || withinRange(b[1], a)) { 1.3122 + if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; 1.3123 + if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; 1.3124 + } else { 1.3125 + merged.push(a = b); 1.3126 + } 1.3127 + } 1.3128 + var best = -Infinity, dλ; 1.3129 + for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { 1.3130 + b = merged[i]; 1.3131 + if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; 1.3132 + } 1.3133 + } 1.3134 + ranges = range = null; 1.3135 + return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; 1.3136 + }; 1.3137 + }(); 1.3138 + d3.geo.centroid = function(object) { 1.3139 + d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; 1.3140 + d3.geo.stream(object, d3_geo_centroid); 1.3141 + var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; 1.3142 + if (m < ε2) { 1.3143 + x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; 1.3144 + if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; 1.3145 + m = x * x + y * y + z * z; 1.3146 + if (m < ε2) return [ NaN, NaN ]; 1.3147 + } 1.3148 + return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; 1.3149 + }; 1.3150 + var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; 1.3151 + var d3_geo_centroid = { 1.3152 + sphere: d3_noop, 1.3153 + point: d3_geo_centroidPoint, 1.3154 + lineStart: d3_geo_centroidLineStart, 1.3155 + lineEnd: d3_geo_centroidLineEnd, 1.3156 + polygonStart: function() { 1.3157 + d3_geo_centroid.lineStart = d3_geo_centroidRingStart; 1.3158 + }, 1.3159 + polygonEnd: function() { 1.3160 + d3_geo_centroid.lineStart = d3_geo_centroidLineStart; 1.3161 + } 1.3162 + }; 1.3163 + function d3_geo_centroidPoint(λ, φ) { 1.3164 + λ *= d3_radians; 1.3165 + var cosφ = Math.cos(φ *= d3_radians); 1.3166 + d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); 1.3167 + } 1.3168 + function d3_geo_centroidPointXYZ(x, y, z) { 1.3169 + ++d3_geo_centroidW0; 1.3170 + d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; 1.3171 + d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; 1.3172 + d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; 1.3173 + } 1.3174 + function d3_geo_centroidLineStart() { 1.3175 + var x0, y0, z0; 1.3176 + d3_geo_centroid.point = function(λ, φ) { 1.3177 + λ *= d3_radians; 1.3178 + var cosφ = Math.cos(φ *= d3_radians); 1.3179 + x0 = cosφ * Math.cos(λ); 1.3180 + y0 = cosφ * Math.sin(λ); 1.3181 + z0 = Math.sin(φ); 1.3182 + d3_geo_centroid.point = nextPoint; 1.3183 + d3_geo_centroidPointXYZ(x0, y0, z0); 1.3184 + }; 1.3185 + function nextPoint(λ, φ) { 1.3186 + λ *= d3_radians; 1.3187 + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); 1.3188 + d3_geo_centroidW1 += w; 1.3189 + d3_geo_centroidX1 += w * (x0 + (x0 = x)); 1.3190 + d3_geo_centroidY1 += w * (y0 + (y0 = y)); 1.3191 + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); 1.3192 + d3_geo_centroidPointXYZ(x0, y0, z0); 1.3193 + } 1.3194 + } 1.3195 + function d3_geo_centroidLineEnd() { 1.3196 + d3_geo_centroid.point = d3_geo_centroidPoint; 1.3197 + } 1.3198 + function d3_geo_centroidRingStart() { 1.3199 + var λ00, φ00, x0, y0, z0; 1.3200 + d3_geo_centroid.point = function(λ, φ) { 1.3201 + λ00 = λ, φ00 = φ; 1.3202 + d3_geo_centroid.point = nextPoint; 1.3203 + λ *= d3_radians; 1.3204 + var cosφ = Math.cos(φ *= d3_radians); 1.3205 + x0 = cosφ * Math.cos(λ); 1.3206 + y0 = cosφ * Math.sin(λ); 1.3207 + z0 = Math.sin(φ); 1.3208 + d3_geo_centroidPointXYZ(x0, y0, z0); 1.3209 + }; 1.3210 + d3_geo_centroid.lineEnd = function() { 1.3211 + nextPoint(λ00, φ00); 1.3212 + d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; 1.3213 + d3_geo_centroid.point = d3_geo_centroidPoint; 1.3214 + }; 1.3215 + function nextPoint(λ, φ) { 1.3216 + λ *= d3_radians; 1.3217 + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); 1.3218 + d3_geo_centroidX2 += v * cx; 1.3219 + d3_geo_centroidY2 += v * cy; 1.3220 + d3_geo_centroidZ2 += v * cz; 1.3221 + d3_geo_centroidW1 += w; 1.3222 + d3_geo_centroidX1 += w * (x0 + (x0 = x)); 1.3223 + d3_geo_centroidY1 += w * (y0 + (y0 = y)); 1.3224 + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); 1.3225 + d3_geo_centroidPointXYZ(x0, y0, z0); 1.3226 + } 1.3227 + } 1.3228 + function d3_geo_compose(a, b) { 1.3229 + function compose(x, y) { 1.3230 + return x = a(x, y), b(x[0], x[1]); 1.3231 + } 1.3232 + if (a.invert && b.invert) compose.invert = function(x, y) { 1.3233 + return x = b.invert(x, y), x && a.invert(x[0], x[1]); 1.3234 + }; 1.3235 + return compose; 1.3236 + } 1.3237 + function d3_true() { 1.3238 + return true; 1.3239 + } 1.3240 + function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) { 1.3241 + var subject = [], clip = []; 1.3242 + segments.forEach(function(segment) { 1.3243 + if ((n = segment.length - 1) <= 0) return; 1.3244 + var n, p0 = segment[0], p1 = segment[n]; 1.3245 + if (d3_geo_sphericalEqual(p0, p1)) { 1.3246 + listener.lineStart(); 1.3247 + for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); 1.3248 + listener.lineEnd(); 1.3249 + return; 1.3250 + } 1.3251 + var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false); 1.3252 + a.o = b; 1.3253 + subject.push(a); 1.3254 + clip.push(b); 1.3255 + a = new d3_geo_clipPolygonIntersection(p1, segment, null, false); 1.3256 + b = new d3_geo_clipPolygonIntersection(p1, null, a, true); 1.3257 + a.o = b; 1.3258 + subject.push(a); 1.3259 + clip.push(b); 1.3260 + }); 1.3261 + clip.sort(compare); 1.3262 + d3_geo_clipPolygonLinkCircular(subject); 1.3263 + d3_geo_clipPolygonLinkCircular(clip); 1.3264 + if (!subject.length) return; 1.3265 + for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) { 1.3266 + clip[i].e = entry = !entry; 1.3267 + } 1.3268 + var start = subject[0], points, point; 1.3269 + while (1) { 1.3270 + var current = start, isSubject = true; 1.3271 + while (current.v) if ((current = current.n) === start) return; 1.3272 + points = current.z; 1.3273 + listener.lineStart(); 1.3274 + do { 1.3275 + current.v = current.o.v = true; 1.3276 + if (current.e) { 1.3277 + if (isSubject) { 1.3278 + for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]); 1.3279 + } else { 1.3280 + interpolate(current.x, current.n.x, 1, listener); 1.3281 + } 1.3282 + current = current.n; 1.3283 + } else { 1.3284 + if (isSubject) { 1.3285 + points = current.p.z; 1.3286 + for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]); 1.3287 + } else { 1.3288 + interpolate(current.x, current.p.x, -1, listener); 1.3289 + } 1.3290 + current = current.p; 1.3291 + } 1.3292 + current = current.o; 1.3293 + points = current.z; 1.3294 + isSubject = !isSubject; 1.3295 + } while (!current.v); 1.3296 + listener.lineEnd(); 1.3297 + } 1.3298 + } 1.3299 + function d3_geo_clipPolygonLinkCircular(array) { 1.3300 + if (!(n = array.length)) return; 1.3301 + var n, i = 0, a = array[0], b; 1.3302 + while (++i < n) { 1.3303 + a.n = b = array[i]; 1.3304 + b.p = a; 1.3305 + a = b; 1.3306 + } 1.3307 + a.n = b = array[0]; 1.3308 + b.p = a; 1.3309 + } 1.3310 + function d3_geo_clipPolygonIntersection(point, points, other, entry) { 1.3311 + this.x = point; 1.3312 + this.z = points; 1.3313 + this.o = other; 1.3314 + this.e = entry; 1.3315 + this.v = false; 1.3316 + this.n = this.p = null; 1.3317 + } 1.3318 + function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { 1.3319 + return function(rotate, listener) { 1.3320 + var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]); 1.3321 + var clip = { 1.3322 + point: point, 1.3323 + lineStart: lineStart, 1.3324 + lineEnd: lineEnd, 1.3325 + polygonStart: function() { 1.3326 + clip.point = pointRing; 1.3327 + clip.lineStart = ringStart; 1.3328 + clip.lineEnd = ringEnd; 1.3329 + segments = []; 1.3330 + polygon = []; 1.3331 + }, 1.3332 + polygonEnd: function() { 1.3333 + clip.point = point; 1.3334 + clip.lineStart = lineStart; 1.3335 + clip.lineEnd = lineEnd; 1.3336 + segments = d3.merge(segments); 1.3337 + var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon); 1.3338 + if (segments.length) { 1.3339 + if (!polygonStarted) listener.polygonStart(), polygonStarted = true; 1.3340 + d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener); 1.3341 + } else if (clipStartInside) { 1.3342 + if (!polygonStarted) listener.polygonStart(), polygonStarted = true; 1.3343 + listener.lineStart(); 1.3344 + interpolate(null, null, 1, listener); 1.3345 + listener.lineEnd(); 1.3346 + } 1.3347 + if (polygonStarted) listener.polygonEnd(), polygonStarted = false; 1.3348 + segments = polygon = null; 1.3349 + }, 1.3350 + sphere: function() { 1.3351 + listener.polygonStart(); 1.3352 + listener.lineStart(); 1.3353 + interpolate(null, null, 1, listener); 1.3354 + listener.lineEnd(); 1.3355 + listener.polygonEnd(); 1.3356 + } 1.3357 + }; 1.3358 + function point(λ, φ) { 1.3359 + var point = rotate(λ, φ); 1.3360 + if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ); 1.3361 + } 1.3362 + function pointLine(λ, φ) { 1.3363 + var point = rotate(λ, φ); 1.3364 + line.point(point[0], point[1]); 1.3365 + } 1.3366 + function lineStart() { 1.3367 + clip.point = pointLine; 1.3368 + line.lineStart(); 1.3369 + } 1.3370 + function lineEnd() { 1.3371 + clip.point = point; 1.3372 + line.lineEnd(); 1.3373 + } 1.3374 + var segments; 1.3375 + var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring; 1.3376 + function pointRing(λ, φ) { 1.3377 + ring.push([ λ, φ ]); 1.3378 + var point = rotate(λ, φ); 1.3379 + ringListener.point(point[0], point[1]); 1.3380 + } 1.3381 + function ringStart() { 1.3382 + ringListener.lineStart(); 1.3383 + ring = []; 1.3384 + } 1.3385 + function ringEnd() { 1.3386 + pointRing(ring[0][0], ring[0][1]); 1.3387 + ringListener.lineEnd(); 1.3388 + var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; 1.3389 + ring.pop(); 1.3390 + polygon.push(ring); 1.3391 + ring = null; 1.3392 + if (!n) return; 1.3393 + if (clean & 1) { 1.3394 + segment = ringSegments[0]; 1.3395 + var n = segment.length - 1, i = -1, point; 1.3396 + if (n > 0) { 1.3397 + if (!polygonStarted) listener.polygonStart(), polygonStarted = true; 1.3398 + listener.lineStart(); 1.3399 + while (++i < n) listener.point((point = segment[i])[0], point[1]); 1.3400 + listener.lineEnd(); 1.3401 + } 1.3402 + return; 1.3403 + } 1.3404 + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); 1.3405 + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); 1.3406 + } 1.3407 + return clip; 1.3408 + }; 1.3409 + } 1.3410 + function d3_geo_clipSegmentLength1(segment) { 1.3411 + return segment.length > 1; 1.3412 + } 1.3413 + function d3_geo_clipBufferListener() { 1.3414 + var lines = [], line; 1.3415 + return { 1.3416 + lineStart: function() { 1.3417 + lines.push(line = []); 1.3418 + }, 1.3419 + point: function(λ, φ) { 1.3420 + line.push([ λ, φ ]); 1.3421 + }, 1.3422 + lineEnd: d3_noop, 1.3423 + buffer: function() { 1.3424 + var buffer = lines; 1.3425 + lines = []; 1.3426 + line = null; 1.3427 + return buffer; 1.3428 + }, 1.3429 + rejoin: function() { 1.3430 + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); 1.3431 + } 1.3432 + }; 1.3433 + } 1.3434 + function d3_geo_clipSort(a, b) { 1.3435 + return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]); 1.3436 + } 1.3437 + var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]); 1.3438 + function d3_geo_clipAntimeridianLine(listener) { 1.3439 + var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; 1.3440 + return { 1.3441 + lineStart: function() { 1.3442 + listener.lineStart(); 1.3443 + clean = 1; 1.3444 + }, 1.3445 + point: function(λ1, φ1) { 1.3446 + var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0); 1.3447 + if (abs(dλ - π) < ε) { 1.3448 + listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ); 1.3449 + listener.point(sλ0, φ0); 1.3450 + listener.lineEnd(); 1.3451 + listener.lineStart(); 1.3452 + listener.point(sλ1, φ0); 1.3453 + listener.point(λ1, φ0); 1.3454 + clean = 0; 1.3455 + } else if (sλ0 !== sλ1 && dλ >= π) { 1.3456 + if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; 1.3457 + if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; 1.3458 + φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); 1.3459 + listener.point(sλ0, φ0); 1.3460 + listener.lineEnd(); 1.3461 + listener.lineStart(); 1.3462 + listener.point(sλ1, φ0); 1.3463 + clean = 0; 1.3464 + } 1.3465 + listener.point(λ0 = λ1, φ0 = φ1); 1.3466 + sλ0 = sλ1; 1.3467 + }, 1.3468 + lineEnd: function() { 1.3469 + listener.lineEnd(); 1.3470 + λ0 = φ0 = NaN; 1.3471 + }, 1.3472 + clean: function() { 1.3473 + return 2 - clean; 1.3474 + } 1.3475 + }; 1.3476 + } 1.3477 + function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { 1.3478 + var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); 1.3479 + return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; 1.3480 + } 1.3481 + function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { 1.3482 + var φ; 1.3483 + if (from == null) { 1.3484 + φ = direction * halfπ; 1.3485 + listener.point(-π, φ); 1.3486 + listener.point(0, φ); 1.3487 + listener.point(π, φ); 1.3488 + listener.point(π, 0); 1.3489 + listener.point(π, -φ); 1.3490 + listener.point(0, -φ); 1.3491 + listener.point(-π, -φ); 1.3492 + listener.point(-π, 0); 1.3493 + listener.point(-π, φ); 1.3494 + } else if (abs(from[0] - to[0]) > ε) { 1.3495 + var s = from[0] < to[0] ? π : -π; 1.3496 + φ = direction * s / 2; 1.3497 + listener.point(-s, φ); 1.3498 + listener.point(0, φ); 1.3499 + listener.point(s, φ); 1.3500 + } else { 1.3501 + listener.point(to[0], to[1]); 1.3502 + } 1.3503 + } 1.3504 + function d3_geo_pointInPolygon(point, polygon) { 1.3505 + var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0; 1.3506 + d3_geo_areaRingSum.reset(); 1.3507 + for (var i = 0, n = polygon.length; i < n; ++i) { 1.3508 + var ring = polygon[i], m = ring.length; 1.3509 + if (!m) continue; 1.3510 + var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; 1.3511 + while (true) { 1.3512 + if (j === m) j = 0; 1.3513 + point = ring[j]; 1.3514 + var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ; 1.3515 + d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ))); 1.3516 + polarAngle += antimeridian ? dλ + sdλ * τ : dλ; 1.3517 + if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { 1.3518 + var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); 1.3519 + d3_geo_cartesianNormalize(arc); 1.3520 + var intersection = d3_geo_cartesianCross(meridianNormal, arc); 1.3521 + d3_geo_cartesianNormalize(intersection); 1.3522 + var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); 1.3523 + if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) { 1.3524 + winding += antimeridian ^ dλ >= 0 ? 1 : -1; 1.3525 + } 1.3526 + } 1.3527 + if (!j++) break; 1.3528 + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; 1.3529 + } 1.3530 + } 1.3531 + return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < -ε) ^ winding & 1; 1.3532 + } 1.3533 + function d3_geo_clipCircle(radius) { 1.3534 + var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); 1.3535 + return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]); 1.3536 + function visible(λ, φ) { 1.3537 + return Math.cos(λ) * Math.cos(φ) > cr; 1.3538 + } 1.3539 + function clipLine(listener) { 1.3540 + var point0, c0, v0, v00, clean; 1.3541 + return { 1.3542 + lineStart: function() { 1.3543 + v00 = v0 = false; 1.3544 + clean = 1; 1.3545 + }, 1.3546 + point: function(λ, φ) { 1.3547 + var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; 1.3548 + if (!point0 && (v00 = v0 = v)) listener.lineStart(); 1.3549 + if (v !== v0) { 1.3550 + point2 = intersect(point0, point1); 1.3551 + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { 1.3552 + point1[0] += ε; 1.3553 + point1[1] += ε; 1.3554 + v = visible(point1[0], point1[1]); 1.3555 + } 1.3556 + } 1.3557 + if (v !== v0) { 1.3558 + clean = 0; 1.3559 + if (v) { 1.3560 + listener.lineStart(); 1.3561 + point2 = intersect(point1, point0); 1.3562 + listener.point(point2[0], point2[1]); 1.3563 + } else { 1.3564 + point2 = intersect(point0, point1); 1.3565 + listener.point(point2[0], point2[1]); 1.3566 + listener.lineEnd(); 1.3567 + } 1.3568 + point0 = point2; 1.3569 + } else if (notHemisphere && point0 && smallRadius ^ v) { 1.3570 + var t; 1.3571 + if (!(c & c0) && (t = intersect(point1, point0, true))) { 1.3572 + clean = 0; 1.3573 + if (smallRadius) { 1.3574 + listener.lineStart(); 1.3575 + listener.point(t[0][0], t[0][1]); 1.3576 + listener.point(t[1][0], t[1][1]); 1.3577 + listener.lineEnd(); 1.3578 + } else { 1.3579 + listener.point(t[1][0], t[1][1]); 1.3580 + listener.lineEnd(); 1.3581 + listener.lineStart(); 1.3582 + listener.point(t[0][0], t[0][1]); 1.3583 + } 1.3584 + } 1.3585 + } 1.3586 + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { 1.3587 + listener.point(point1[0], point1[1]); 1.3588 + } 1.3589 + point0 = point1, v0 = v, c0 = c; 1.3590 + }, 1.3591 + lineEnd: function() { 1.3592 + if (v0) listener.lineEnd(); 1.3593 + point0 = null; 1.3594 + }, 1.3595 + clean: function() { 1.3596 + return clean | (v00 && v0) << 1; 1.3597 + } 1.3598 + }; 1.3599 + } 1.3600 + function intersect(a, b, two) { 1.3601 + var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); 1.3602 + var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; 1.3603 + if (!determinant) return !two && a; 1.3604 + var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); 1.3605 + d3_geo_cartesianAdd(A, B); 1.3606 + var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); 1.3607 + if (t2 < 0) return; 1.3608 + var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); 1.3609 + d3_geo_cartesianAdd(q, A); 1.3610 + q = d3_geo_spherical(q); 1.3611 + if (!two) return q; 1.3612 + var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; 1.3613 + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; 1.3614 + var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε; 1.3615 + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; 1.3616 + if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { 1.3617 + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); 1.3618 + d3_geo_cartesianAdd(q1, A); 1.3619 + return [ q, d3_geo_spherical(q1) ]; 1.3620 + } 1.3621 + } 1.3622 + function code(λ, φ) { 1.3623 + var r = smallRadius ? radius : π - radius, code = 0; 1.3624 + if (λ < -r) code |= 1; else if (λ > r) code |= 2; 1.3625 + if (φ < -r) code |= 4; else if (φ > r) code |= 8; 1.3626 + return code; 1.3627 + } 1.3628 + } 1.3629 + function d3_geom_clipLine(x0, y0, x1, y1) { 1.3630 + return function(line) { 1.3631 + var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r; 1.3632 + r = x0 - ax; 1.3633 + if (!dx && r > 0) return; 1.3634 + r /= dx; 1.3635 + if (dx < 0) { 1.3636 + if (r < t0) return; 1.3637 + if (r < t1) t1 = r; 1.3638 + } else if (dx > 0) { 1.3639 + if (r > t1) return; 1.3640 + if (r > t0) t0 = r; 1.3641 + } 1.3642 + r = x1 - ax; 1.3643 + if (!dx && r < 0) return; 1.3644 + r /= dx; 1.3645 + if (dx < 0) { 1.3646 + if (r > t1) return; 1.3647 + if (r > t0) t0 = r; 1.3648 + } else if (dx > 0) { 1.3649 + if (r < t0) return; 1.3650 + if (r < t1) t1 = r; 1.3651 + } 1.3652 + r = y0 - ay; 1.3653 + if (!dy && r > 0) return; 1.3654 + r /= dy; 1.3655 + if (dy < 0) { 1.3656 + if (r < t0) return; 1.3657 + if (r < t1) t1 = r; 1.3658 + } else if (dy > 0) { 1.3659 + if (r > t1) return; 1.3660 + if (r > t0) t0 = r; 1.3661 + } 1.3662 + r = y1 - ay; 1.3663 + if (!dy && r < 0) return; 1.3664 + r /= dy; 1.3665 + if (dy < 0) { 1.3666 + if (r > t1) return; 1.3667 + if (r > t0) t0 = r; 1.3668 + } else if (dy > 0) { 1.3669 + if (r < t0) return; 1.3670 + if (r < t1) t1 = r; 1.3671 + } 1.3672 + if (t0 > 0) line.a = { 1.3673 + x: ax + t0 * dx, 1.3674 + y: ay + t0 * dy 1.3675 + }; 1.3676 + if (t1 < 1) line.b = { 1.3677 + x: ax + t1 * dx, 1.3678 + y: ay + t1 * dy 1.3679 + }; 1.3680 + return line; 1.3681 + }; 1.3682 + } 1.3683 + var d3_geo_clipExtentMAX = 1e9; 1.3684 + d3.geo.clipExtent = function() { 1.3685 + var x0, y0, x1, y1, stream, clip, clipExtent = { 1.3686 + stream: function(output) { 1.3687 + if (stream) stream.valid = false; 1.3688 + stream = clip(output); 1.3689 + stream.valid = true; 1.3690 + return stream; 1.3691 + }, 1.3692 + extent: function(_) { 1.3693 + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; 1.3694 + clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]); 1.3695 + if (stream) stream.valid = false, stream = null; 1.3696 + return clipExtent; 1.3697 + } 1.3698 + }; 1.3699 + return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]); 1.3700 + }; 1.3701 + function d3_geo_clipExtent(x0, y0, x1, y1) { 1.3702 + return function(listener) { 1.3703 + var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring; 1.3704 + var clip = { 1.3705 + point: point, 1.3706 + lineStart: lineStart, 1.3707 + lineEnd: lineEnd, 1.3708 + polygonStart: function() { 1.3709 + listener = bufferListener; 1.3710 + segments = []; 1.3711 + polygon = []; 1.3712 + clean = true; 1.3713 + }, 1.3714 + polygonEnd: function() { 1.3715 + listener = listener_; 1.3716 + segments = d3.merge(segments); 1.3717 + var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length; 1.3718 + if (inside || visible) { 1.3719 + listener.polygonStart(); 1.3720 + if (inside) { 1.3721 + listener.lineStart(); 1.3722 + interpolate(null, null, 1, listener); 1.3723 + listener.lineEnd(); 1.3724 + } 1.3725 + if (visible) { 1.3726 + d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener); 1.3727 + } 1.3728 + listener.polygonEnd(); 1.3729 + } 1.3730 + segments = polygon = ring = null; 1.3731 + } 1.3732 + }; 1.3733 + function insidePolygon(p) { 1.3734 + var wn = 0, n = polygon.length, y = p[1]; 1.3735 + for (var i = 0; i < n; ++i) { 1.3736 + for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { 1.3737 + b = v[j]; 1.3738 + if (a[1] <= y) { 1.3739 + if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn; 1.3740 + } else { 1.3741 + if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn; 1.3742 + } 1.3743 + a = b; 1.3744 + } 1.3745 + } 1.3746 + return wn !== 0; 1.3747 + } 1.3748 + function interpolate(from, to, direction, listener) { 1.3749 + var a = 0, a1 = 0; 1.3750 + if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { 1.3751 + do { 1.3752 + listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); 1.3753 + } while ((a = (a + direction + 4) % 4) !== a1); 1.3754 + } else { 1.3755 + listener.point(to[0], to[1]); 1.3756 + } 1.3757 + } 1.3758 + function pointVisible(x, y) { 1.3759 + return x0 <= x && x <= x1 && y0 <= y && y <= y1; 1.3760 + } 1.3761 + function point(x, y) { 1.3762 + if (pointVisible(x, y)) listener.point(x, y); 1.3763 + } 1.3764 + var x__, y__, v__, x_, y_, v_, first, clean; 1.3765 + function lineStart() { 1.3766 + clip.point = linePoint; 1.3767 + if (polygon) polygon.push(ring = []); 1.3768 + first = true; 1.3769 + v_ = false; 1.3770 + x_ = y_ = NaN; 1.3771 + } 1.3772 + function lineEnd() { 1.3773 + if (segments) { 1.3774 + linePoint(x__, y__); 1.3775 + if (v__ && v_) bufferListener.rejoin(); 1.3776 + segments.push(bufferListener.buffer()); 1.3777 + } 1.3778 + clip.point = point; 1.3779 + if (v_) listener.lineEnd(); 1.3780 + } 1.3781 + function linePoint(x, y) { 1.3782 + x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x)); 1.3783 + y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y)); 1.3784 + var v = pointVisible(x, y); 1.3785 + if (polygon) ring.push([ x, y ]); 1.3786 + if (first) { 1.3787 + x__ = x, y__ = y, v__ = v; 1.3788 + first = false; 1.3789 + if (v) { 1.3790 + listener.lineStart(); 1.3791 + listener.point(x, y); 1.3792 + } 1.3793 + } else { 1.3794 + if (v && v_) listener.point(x, y); else { 1.3795 + var l = { 1.3796 + a: { 1.3797 + x: x_, 1.3798 + y: y_ 1.3799 + }, 1.3800 + b: { 1.3801 + x: x, 1.3802 + y: y 1.3803 + } 1.3804 + }; 1.3805 + if (clipLine(l)) { 1.3806 + if (!v_) { 1.3807 + listener.lineStart(); 1.3808 + listener.point(l.a.x, l.a.y); 1.3809 + } 1.3810 + listener.point(l.b.x, l.b.y); 1.3811 + if (!v) listener.lineEnd(); 1.3812 + clean = false; 1.3813 + } else if (v) { 1.3814 + listener.lineStart(); 1.3815 + listener.point(x, y); 1.3816 + clean = false; 1.3817 + } 1.3818 + } 1.3819 + } 1.3820 + x_ = x, y_ = y, v_ = v; 1.3821 + } 1.3822 + return clip; 1.3823 + }; 1.3824 + function corner(p, direction) { 1.3825 + return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; 1.3826 + } 1.3827 + function compare(a, b) { 1.3828 + return comparePoints(a.x, b.x); 1.3829 + } 1.3830 + function comparePoints(a, b) { 1.3831 + var ca = corner(a, 1), cb = corner(b, 1); 1.3832 + 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]; 1.3833 + } 1.3834 + } 1.3835 + function d3_geo_conic(projectAt) { 1.3836 + var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); 1.3837 + p.parallels = function(_) { 1.3838 + if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; 1.3839 + return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); 1.3840 + }; 1.3841 + return p; 1.3842 + } 1.3843 + function d3_geo_conicEqualArea(φ0, φ1) { 1.3844 + var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; 1.3845 + function forward(λ, φ) { 1.3846 + var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; 1.3847 + return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; 1.3848 + } 1.3849 + forward.invert = function(x, y) { 1.3850 + var ρ0_y = ρ0 - y; 1.3851 + return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; 1.3852 + }; 1.3853 + return forward; 1.3854 + } 1.3855 + (d3.geo.conicEqualArea = function() { 1.3856 + return d3_geo_conic(d3_geo_conicEqualArea); 1.3857 + }).raw = d3_geo_conicEqualArea; 1.3858 + d3.geo.albers = function() { 1.3859 + return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); 1.3860 + }; 1.3861 + d3.geo.albersUsa = function() { 1.3862 + var lower48 = d3.geo.albers(); 1.3863 + var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); 1.3864 + var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); 1.3865 + var point, pointStream = { 1.3866 + point: function(x, y) { 1.3867 + point = [ x, y ]; 1.3868 + } 1.3869 + }, lower48Point, alaskaPoint, hawaiiPoint; 1.3870 + function albersUsa(coordinates) { 1.3871 + var x = coordinates[0], y = coordinates[1]; 1.3872 + point = null; 1.3873 + (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); 1.3874 + return point; 1.3875 + } 1.3876 + albersUsa.invert = function(coordinates) { 1.3877 + var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; 1.3878 + return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); 1.3879 + }; 1.3880 + albersUsa.stream = function(stream) { 1.3881 + var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); 1.3882 + return { 1.3883 + point: function(x, y) { 1.3884 + lower48Stream.point(x, y); 1.3885 + alaskaStream.point(x, y); 1.3886 + hawaiiStream.point(x, y); 1.3887 + }, 1.3888 + sphere: function() { 1.3889 + lower48Stream.sphere(); 1.3890 + alaskaStream.sphere(); 1.3891 + hawaiiStream.sphere(); 1.3892 + }, 1.3893 + lineStart: function() { 1.3894 + lower48Stream.lineStart(); 1.3895 + alaskaStream.lineStart(); 1.3896 + hawaiiStream.lineStart(); 1.3897 + }, 1.3898 + lineEnd: function() { 1.3899 + lower48Stream.lineEnd(); 1.3900 + alaskaStream.lineEnd(); 1.3901 + hawaiiStream.lineEnd(); 1.3902 + }, 1.3903 + polygonStart: function() { 1.3904 + lower48Stream.polygonStart(); 1.3905 + alaskaStream.polygonStart(); 1.3906 + hawaiiStream.polygonStart(); 1.3907 + }, 1.3908 + polygonEnd: function() { 1.3909 + lower48Stream.polygonEnd(); 1.3910 + alaskaStream.polygonEnd(); 1.3911 + hawaiiStream.polygonEnd(); 1.3912 + } 1.3913 + }; 1.3914 + }; 1.3915 + albersUsa.precision = function(_) { 1.3916 + if (!arguments.length) return lower48.precision(); 1.3917 + lower48.precision(_); 1.3918 + alaska.precision(_); 1.3919 + hawaii.precision(_); 1.3920 + return albersUsa; 1.3921 + }; 1.3922 + albersUsa.scale = function(_) { 1.3923 + if (!arguments.length) return lower48.scale(); 1.3924 + lower48.scale(_); 1.3925 + alaska.scale(_ * .35); 1.3926 + hawaii.scale(_); 1.3927 + return albersUsa.translate(lower48.translate()); 1.3928 + }; 1.3929 + albersUsa.translate = function(_) { 1.3930 + if (!arguments.length) return lower48.translate(); 1.3931 + var k = lower48.scale(), x = +_[0], y = +_[1]; 1.3932 + lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; 1.3933 + alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; 1.3934 + hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; 1.3935 + return albersUsa; 1.3936 + }; 1.3937 + return albersUsa.scale(1070); 1.3938 + }; 1.3939 + var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { 1.3940 + point: d3_noop, 1.3941 + lineStart: d3_noop, 1.3942 + lineEnd: d3_noop, 1.3943 + polygonStart: function() { 1.3944 + d3_geo_pathAreaPolygon = 0; 1.3945 + d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; 1.3946 + }, 1.3947 + polygonEnd: function() { 1.3948 + d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; 1.3949 + d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2); 1.3950 + } 1.3951 + }; 1.3952 + function d3_geo_pathAreaRingStart() { 1.3953 + var x00, y00, x0, y0; 1.3954 + d3_geo_pathArea.point = function(x, y) { 1.3955 + d3_geo_pathArea.point = nextPoint; 1.3956 + x00 = x0 = x, y00 = y0 = y; 1.3957 + }; 1.3958 + function nextPoint(x, y) { 1.3959 + d3_geo_pathAreaPolygon += y0 * x - x0 * y; 1.3960 + x0 = x, y0 = y; 1.3961 + } 1.3962 + d3_geo_pathArea.lineEnd = function() { 1.3963 + nextPoint(x00, y00); 1.3964 + }; 1.3965 + } 1.3966 + var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; 1.3967 + var d3_geo_pathBounds = { 1.3968 + point: d3_geo_pathBoundsPoint, 1.3969 + lineStart: d3_noop, 1.3970 + lineEnd: d3_noop, 1.3971 + polygonStart: d3_noop, 1.3972 + polygonEnd: d3_noop 1.3973 + }; 1.3974 + function d3_geo_pathBoundsPoint(x, y) { 1.3975 + if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; 1.3976 + if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; 1.3977 + if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; 1.3978 + if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; 1.3979 + } 1.3980 + function d3_geo_pathBuffer() { 1.3981 + var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; 1.3982 + var stream = { 1.3983 + point: point, 1.3984 + lineStart: function() { 1.3985 + stream.point = pointLineStart; 1.3986 + }, 1.3987 + lineEnd: lineEnd, 1.3988 + polygonStart: function() { 1.3989 + stream.lineEnd = lineEndPolygon; 1.3990 + }, 1.3991 + polygonEnd: function() { 1.3992 + stream.lineEnd = lineEnd; 1.3993 + stream.point = point; 1.3994 + }, 1.3995 + pointRadius: function(_) { 1.3996 + pointCircle = d3_geo_pathBufferCircle(_); 1.3997 + return stream; 1.3998 + }, 1.3999 + result: function() { 1.4000 + if (buffer.length) { 1.4001 + var result = buffer.join(""); 1.4002 + buffer = []; 1.4003 + return result; 1.4004 + } 1.4005 + } 1.4006 + }; 1.4007 + function point(x, y) { 1.4008 + buffer.push("M", x, ",", y, pointCircle); 1.4009 + } 1.4010 + function pointLineStart(x, y) { 1.4011 + buffer.push("M", x, ",", y); 1.4012 + stream.point = pointLine; 1.4013 + } 1.4014 + function pointLine(x, y) { 1.4015 + buffer.push("L", x, ",", y); 1.4016 + } 1.4017 + function lineEnd() { 1.4018 + stream.point = point; 1.4019 + } 1.4020 + function lineEndPolygon() { 1.4021 + buffer.push("Z"); 1.4022 + } 1.4023 + return stream; 1.4024 + } 1.4025 + function d3_geo_pathBufferCircle(radius) { 1.4026 + return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; 1.4027 + } 1.4028 + var d3_geo_pathCentroid = { 1.4029 + point: d3_geo_pathCentroidPoint, 1.4030 + lineStart: d3_geo_pathCentroidLineStart, 1.4031 + lineEnd: d3_geo_pathCentroidLineEnd, 1.4032 + polygonStart: function() { 1.4033 + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; 1.4034 + }, 1.4035 + polygonEnd: function() { 1.4036 + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; 1.4037 + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; 1.4038 + d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; 1.4039 + } 1.4040 + }; 1.4041 + function d3_geo_pathCentroidPoint(x, y) { 1.4042 + d3_geo_centroidX0 += x; 1.4043 + d3_geo_centroidY0 += y; 1.4044 + ++d3_geo_centroidZ0; 1.4045 + } 1.4046 + function d3_geo_pathCentroidLineStart() { 1.4047 + var x0, y0; 1.4048 + d3_geo_pathCentroid.point = function(x, y) { 1.4049 + d3_geo_pathCentroid.point = nextPoint; 1.4050 + d3_geo_pathCentroidPoint(x0 = x, y0 = y); 1.4051 + }; 1.4052 + function nextPoint(x, y) { 1.4053 + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); 1.4054 + d3_geo_centroidX1 += z * (x0 + x) / 2; 1.4055 + d3_geo_centroidY1 += z * (y0 + y) / 2; 1.4056 + d3_geo_centroidZ1 += z; 1.4057 + d3_geo_pathCentroidPoint(x0 = x, y0 = y); 1.4058 + } 1.4059 + } 1.4060 + function d3_geo_pathCentroidLineEnd() { 1.4061 + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; 1.4062 + } 1.4063 + function d3_geo_pathCentroidRingStart() { 1.4064 + var x00, y00, x0, y0; 1.4065 + d3_geo_pathCentroid.point = function(x, y) { 1.4066 + d3_geo_pathCentroid.point = nextPoint; 1.4067 + d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); 1.4068 + }; 1.4069 + function nextPoint(x, y) { 1.4070 + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); 1.4071 + d3_geo_centroidX1 += z * (x0 + x) / 2; 1.4072 + d3_geo_centroidY1 += z * (y0 + y) / 2; 1.4073 + d3_geo_centroidZ1 += z; 1.4074 + z = y0 * x - x0 * y; 1.4075 + d3_geo_centroidX2 += z * (x0 + x); 1.4076 + d3_geo_centroidY2 += z * (y0 + y); 1.4077 + d3_geo_centroidZ2 += z * 3; 1.4078 + d3_geo_pathCentroidPoint(x0 = x, y0 = y); 1.4079 + } 1.4080 + d3_geo_pathCentroid.lineEnd = function() { 1.4081 + nextPoint(x00, y00); 1.4082 + }; 1.4083 + } 1.4084 + function d3_geo_pathContext(context) { 1.4085 + var pointRadius = 4.5; 1.4086 + var stream = { 1.4087 + point: point, 1.4088 + lineStart: function() { 1.4089 + stream.point = pointLineStart; 1.4090 + }, 1.4091 + lineEnd: lineEnd, 1.4092 + polygonStart: function() { 1.4093 + stream.lineEnd = lineEndPolygon; 1.4094 + }, 1.4095 + polygonEnd: function() { 1.4096 + stream.lineEnd = lineEnd; 1.4097 + stream.point = point; 1.4098 + }, 1.4099 + pointRadius: function(_) { 1.4100 + pointRadius = _; 1.4101 + return stream; 1.4102 + }, 1.4103 + result: d3_noop 1.4104 + }; 1.4105 + function point(x, y) { 1.4106 + context.moveTo(x + pointRadius, y); 1.4107 + context.arc(x, y, pointRadius, 0, τ); 1.4108 + } 1.4109 + function pointLineStart(x, y) { 1.4110 + context.moveTo(x, y); 1.4111 + stream.point = pointLine; 1.4112 + } 1.4113 + function pointLine(x, y) { 1.4114 + context.lineTo(x, y); 1.4115 + } 1.4116 + function lineEnd() { 1.4117 + stream.point = point; 1.4118 + } 1.4119 + function lineEndPolygon() { 1.4120 + context.closePath(); 1.4121 + } 1.4122 + return stream; 1.4123 + } 1.4124 + function d3_geo_resample(project) { 1.4125 + var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; 1.4126 + function resample(stream) { 1.4127 + return (maxDepth ? resampleRecursive : resampleNone)(stream); 1.4128 + } 1.4129 + function resampleNone(stream) { 1.4130 + return d3_geo_transformPoint(stream, function(x, y) { 1.4131 + x = project(x, y); 1.4132 + stream.point(x[0], x[1]); 1.4133 + }); 1.4134 + } 1.4135 + function resampleRecursive(stream) { 1.4136 + var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; 1.4137 + var resample = { 1.4138 + point: point, 1.4139 + lineStart: lineStart, 1.4140 + lineEnd: lineEnd, 1.4141 + polygonStart: function() { 1.4142 + stream.polygonStart(); 1.4143 + resample.lineStart = ringStart; 1.4144 + }, 1.4145 + polygonEnd: function() { 1.4146 + stream.polygonEnd(); 1.4147 + resample.lineStart = lineStart; 1.4148 + } 1.4149 + }; 1.4150 + function point(x, y) { 1.4151 + x = project(x, y); 1.4152 + stream.point(x[0], x[1]); 1.4153 + } 1.4154 + function lineStart() { 1.4155 + x0 = NaN; 1.4156 + resample.point = linePoint; 1.4157 + stream.lineStart(); 1.4158 + } 1.4159 + function linePoint(λ, φ) { 1.4160 + var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); 1.4161 + resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); 1.4162 + stream.point(x0, y0); 1.4163 + } 1.4164 + function lineEnd() { 1.4165 + resample.point = point; 1.4166 + stream.lineEnd(); 1.4167 + } 1.4168 + function ringStart() { 1.4169 + lineStart(); 1.4170 + resample.point = ringPoint; 1.4171 + resample.lineEnd = ringEnd; 1.4172 + } 1.4173 + function ringPoint(λ, φ) { 1.4174 + linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; 1.4175 + resample.point = linePoint; 1.4176 + } 1.4177 + function ringEnd() { 1.4178 + resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); 1.4179 + resample.lineEnd = lineEnd; 1.4180 + lineEnd(); 1.4181 + } 1.4182 + return resample; 1.4183 + } 1.4184 + function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { 1.4185 + var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; 1.4186 + if (d2 > 4 * δ2 && depth--) { 1.4187 + var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; 1.4188 + if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { 1.4189 + resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); 1.4190 + stream.point(x2, y2); 1.4191 + resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); 1.4192 + } 1.4193 + } 1.4194 + } 1.4195 + resample.precision = function(_) { 1.4196 + if (!arguments.length) return Math.sqrt(δ2); 1.4197 + maxDepth = (δ2 = _ * _) > 0 && 16; 1.4198 + return resample; 1.4199 + }; 1.4200 + return resample; 1.4201 + } 1.4202 + d3.geo.path = function() { 1.4203 + var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; 1.4204 + function path(object) { 1.4205 + if (object) { 1.4206 + if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); 1.4207 + if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); 1.4208 + d3.geo.stream(object, cacheStream); 1.4209 + } 1.4210 + return contextStream.result(); 1.4211 + } 1.4212 + path.area = function(object) { 1.4213 + d3_geo_pathAreaSum = 0; 1.4214 + d3.geo.stream(object, projectStream(d3_geo_pathArea)); 1.4215 + return d3_geo_pathAreaSum; 1.4216 + }; 1.4217 + path.centroid = function(object) { 1.4218 + d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; 1.4219 + d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); 1.4220 + return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; 1.4221 + }; 1.4222 + path.bounds = function(object) { 1.4223 + d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); 1.4224 + d3.geo.stream(object, projectStream(d3_geo_pathBounds)); 1.4225 + return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; 1.4226 + }; 1.4227 + path.projection = function(_) { 1.4228 + if (!arguments.length) return projection; 1.4229 + projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; 1.4230 + return reset(); 1.4231 + }; 1.4232 + path.context = function(_) { 1.4233 + if (!arguments.length) return context; 1.4234 + contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); 1.4235 + if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); 1.4236 + return reset(); 1.4237 + }; 1.4238 + path.pointRadius = function(_) { 1.4239 + if (!arguments.length) return pointRadius; 1.4240 + pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); 1.4241 + return path; 1.4242 + }; 1.4243 + function reset() { 1.4244 + cacheStream = null; 1.4245 + return path; 1.4246 + } 1.4247 + return path.projection(d3.geo.albersUsa()).context(null); 1.4248 + }; 1.4249 + function d3_geo_pathProjectStream(project) { 1.4250 + var resample = d3_geo_resample(function(x, y) { 1.4251 + return project([ x * d3_degrees, y * d3_degrees ]); 1.4252 + }); 1.4253 + return function(stream) { 1.4254 + return d3_geo_projectionRadians(resample(stream)); 1.4255 + }; 1.4256 + } 1.4257 + d3.geo.transform = function(methods) { 1.4258 + return { 1.4259 + stream: function(stream) { 1.4260 + var transform = new d3_geo_transform(stream); 1.4261 + for (var k in methods) transform[k] = methods[k]; 1.4262 + return transform; 1.4263 + } 1.4264 + }; 1.4265 + }; 1.4266 + function d3_geo_transform(stream) { 1.4267 + this.stream = stream; 1.4268 + } 1.4269 + d3_geo_transform.prototype = { 1.4270 + point: function(x, y) { 1.4271 + this.stream.point(x, y); 1.4272 + }, 1.4273 + sphere: function() { 1.4274 + this.stream.sphere(); 1.4275 + }, 1.4276 + lineStart: function() { 1.4277 + this.stream.lineStart(); 1.4278 + }, 1.4279 + lineEnd: function() { 1.4280 + this.stream.lineEnd(); 1.4281 + }, 1.4282 + polygonStart: function() { 1.4283 + this.stream.polygonStart(); 1.4284 + }, 1.4285 + polygonEnd: function() { 1.4286 + this.stream.polygonEnd(); 1.4287 + } 1.4288 + }; 1.4289 + function d3_geo_transformPoint(stream, point) { 1.4290 + return { 1.4291 + point: point, 1.4292 + sphere: function() { 1.4293 + stream.sphere(); 1.4294 + }, 1.4295 + lineStart: function() { 1.4296 + stream.lineStart(); 1.4297 + }, 1.4298 + lineEnd: function() { 1.4299 + stream.lineEnd(); 1.4300 + }, 1.4301 + polygonStart: function() { 1.4302 + stream.polygonStart(); 1.4303 + }, 1.4304 + polygonEnd: function() { 1.4305 + stream.polygonEnd(); 1.4306 + } 1.4307 + }; 1.4308 + } 1.4309 + d3.geo.projection = d3_geo_projection; 1.4310 + d3.geo.projectionMutator = d3_geo_projectionMutator; 1.4311 + function d3_geo_projection(project) { 1.4312 + return d3_geo_projectionMutator(function() { 1.4313 + return project; 1.4314 + })(); 1.4315 + } 1.4316 + function d3_geo_projectionMutator(projectAt) { 1.4317 + var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { 1.4318 + x = project(x, y); 1.4319 + return [ x[0] * k + δx, δy - x[1] * k ]; 1.4320 + }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; 1.4321 + function projection(point) { 1.4322 + point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); 1.4323 + return [ point[0] * k + δx, δy - point[1] * k ]; 1.4324 + } 1.4325 + function invert(point) { 1.4326 + point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); 1.4327 + return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; 1.4328 + } 1.4329 + projection.stream = function(output) { 1.4330 + if (stream) stream.valid = false; 1.4331 + stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output)))); 1.4332 + stream.valid = true; 1.4333 + return stream; 1.4334 + }; 1.4335 + projection.clipAngle = function(_) { 1.4336 + if (!arguments.length) return clipAngle; 1.4337 + preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); 1.4338 + return invalidate(); 1.4339 + }; 1.4340 + projection.clipExtent = function(_) { 1.4341 + if (!arguments.length) return clipExtent; 1.4342 + clipExtent = _; 1.4343 + postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity; 1.4344 + return invalidate(); 1.4345 + }; 1.4346 + projection.scale = function(_) { 1.4347 + if (!arguments.length) return k; 1.4348 + k = +_; 1.4349 + return reset(); 1.4350 + }; 1.4351 + projection.translate = function(_) { 1.4352 + if (!arguments.length) return [ x, y ]; 1.4353 + x = +_[0]; 1.4354 + y = +_[1]; 1.4355 + return reset(); 1.4356 + }; 1.4357 + projection.center = function(_) { 1.4358 + if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; 1.4359 + λ = _[0] % 360 * d3_radians; 1.4360 + φ = _[1] % 360 * d3_radians; 1.4361 + return reset(); 1.4362 + }; 1.4363 + projection.rotate = function(_) { 1.4364 + if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; 1.4365 + δλ = _[0] % 360 * d3_radians; 1.4366 + δφ = _[1] % 360 * d3_radians; 1.4367 + δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; 1.4368 + return reset(); 1.4369 + }; 1.4370 + d3.rebind(projection, projectResample, "precision"); 1.4371 + function reset() { 1.4372 + projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); 1.4373 + var center = project(λ, φ); 1.4374 + δx = x - center[0] * k; 1.4375 + δy = y + center[1] * k; 1.4376 + return invalidate(); 1.4377 + } 1.4378 + function invalidate() { 1.4379 + if (stream) stream.valid = false, stream = null; 1.4380 + return projection; 1.4381 + } 1.4382 + return function() { 1.4383 + project = projectAt.apply(this, arguments); 1.4384 + projection.invert = project.invert && invert; 1.4385 + return reset(); 1.4386 + }; 1.4387 + } 1.4388 + function d3_geo_projectionRadians(stream) { 1.4389 + return d3_geo_transformPoint(stream, function(x, y) { 1.4390 + stream.point(x * d3_radians, y * d3_radians); 1.4391 + }); 1.4392 + } 1.4393 + function d3_geo_equirectangular(λ, φ) { 1.4394 + return [ λ, φ ]; 1.4395 + } 1.4396 + (d3.geo.equirectangular = function() { 1.4397 + return d3_geo_projection(d3_geo_equirectangular); 1.4398 + }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; 1.4399 + d3.geo.rotation = function(rotate) { 1.4400 + rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); 1.4401 + function forward(coordinates) { 1.4402 + coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); 1.4403 + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; 1.4404 + } 1.4405 + forward.invert = function(coordinates) { 1.4406 + coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); 1.4407 + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; 1.4408 + }; 1.4409 + return forward; 1.4410 + }; 1.4411 + function d3_geo_identityRotation(λ, φ) { 1.4412 + return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; 1.4413 + } 1.4414 + d3_geo_identityRotation.invert = d3_geo_equirectangular; 1.4415 + function d3_geo_rotation(δλ, δφ, δγ) { 1.4416 + return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation; 1.4417 + } 1.4418 + function d3_geo_forwardRotationλ(δλ) { 1.4419 + return function(λ, φ) { 1.4420 + return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; 1.4421 + }; 1.4422 + } 1.4423 + function d3_geo_rotationλ(δλ) { 1.4424 + var rotation = d3_geo_forwardRotationλ(δλ); 1.4425 + rotation.invert = d3_geo_forwardRotationλ(-δλ); 1.4426 + return rotation; 1.4427 + } 1.4428 + function d3_geo_rotationφγ(δφ, δγ) { 1.4429 + var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); 1.4430 + function rotation(λ, φ) { 1.4431 + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; 1.4432 + return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; 1.4433 + } 1.4434 + rotation.invert = function(λ, φ) { 1.4435 + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; 1.4436 + return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; 1.4437 + }; 1.4438 + return rotation; 1.4439 + } 1.4440 + d3.geo.circle = function() { 1.4441 + var origin = [ 0, 0 ], angle, precision = 6, interpolate; 1.4442 + function circle() { 1.4443 + var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; 1.4444 + interpolate(null, null, 1, { 1.4445 + point: function(x, y) { 1.4446 + ring.push(x = rotate(x, y)); 1.4447 + x[0] *= d3_degrees, x[1] *= d3_degrees; 1.4448 + } 1.4449 + }); 1.4450 + return { 1.4451 + type: "Polygon", 1.4452 + coordinates: [ ring ] 1.4453 + }; 1.4454 + } 1.4455 + circle.origin = function(x) { 1.4456 + if (!arguments.length) return origin; 1.4457 + origin = x; 1.4458 + return circle; 1.4459 + }; 1.4460 + circle.angle = function(x) { 1.4461 + if (!arguments.length) return angle; 1.4462 + interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); 1.4463 + return circle; 1.4464 + }; 1.4465 + circle.precision = function(_) { 1.4466 + if (!arguments.length) return precision; 1.4467 + interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); 1.4468 + return circle; 1.4469 + }; 1.4470 + return circle.angle(90); 1.4471 + }; 1.4472 + function d3_geo_circleInterpolate(radius, precision) { 1.4473 + var cr = Math.cos(radius), sr = Math.sin(radius); 1.4474 + return function(from, to, direction, listener) { 1.4475 + var step = direction * precision; 1.4476 + if (from != null) { 1.4477 + from = d3_geo_circleAngle(cr, from); 1.4478 + to = d3_geo_circleAngle(cr, to); 1.4479 + if (direction > 0 ? from < to : from > to) from += direction * τ; 1.4480 + } else { 1.4481 + from = radius + direction * τ; 1.4482 + to = radius - .5 * step; 1.4483 + } 1.4484 + for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) { 1.4485 + listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); 1.4486 + } 1.4487 + }; 1.4488 + } 1.4489 + function d3_geo_circleAngle(cr, point) { 1.4490 + var a = d3_geo_cartesian(point); 1.4491 + a[0] -= cr; 1.4492 + d3_geo_cartesianNormalize(a); 1.4493 + var angle = d3_acos(-a[1]); 1.4494 + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); 1.4495 + } 1.4496 + d3.geo.distance = function(a, b) { 1.4497 + var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; 1.4498 + return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); 1.4499 + }; 1.4500 + d3.geo.graticule = function() { 1.4501 + var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; 1.4502 + function graticule() { 1.4503 + return { 1.4504 + type: "MultiLineString", 1.4505 + coordinates: lines() 1.4506 + }; 1.4507 + } 1.4508 + function lines() { 1.4509 + return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { 1.4510 + return abs(x % DX) > ε; 1.4511 + }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { 1.4512 + return abs(y % DY) > ε; 1.4513 + }).map(y)); 1.4514 + } 1.4515 + graticule.lines = function() { 1.4516 + return lines().map(function(coordinates) { 1.4517 + return { 1.4518 + type: "LineString", 1.4519 + coordinates: coordinates 1.4520 + }; 1.4521 + }); 1.4522 + }; 1.4523 + graticule.outline = function() { 1.4524 + return { 1.4525 + type: "Polygon", 1.4526 + coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] 1.4527 + }; 1.4528 + }; 1.4529 + graticule.extent = function(_) { 1.4530 + if (!arguments.length) return graticule.minorExtent(); 1.4531 + return graticule.majorExtent(_).minorExtent(_); 1.4532 + }; 1.4533 + graticule.majorExtent = function(_) { 1.4534 + if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; 1.4535 + X0 = +_[0][0], X1 = +_[1][0]; 1.4536 + Y0 = +_[0][1], Y1 = +_[1][1]; 1.4537 + if (X0 > X1) _ = X0, X0 = X1, X1 = _; 1.4538 + if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; 1.4539 + return graticule.precision(precision); 1.4540 + }; 1.4541 + graticule.minorExtent = function(_) { 1.4542 + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; 1.4543 + x0 = +_[0][0], x1 = +_[1][0]; 1.4544 + y0 = +_[0][1], y1 = +_[1][1]; 1.4545 + if (x0 > x1) _ = x0, x0 = x1, x1 = _; 1.4546 + if (y0 > y1) _ = y0, y0 = y1, y1 = _; 1.4547 + return graticule.precision(precision); 1.4548 + }; 1.4549 + graticule.step = function(_) { 1.4550 + if (!arguments.length) return graticule.minorStep(); 1.4551 + return graticule.majorStep(_).minorStep(_); 1.4552 + }; 1.4553 + graticule.majorStep = function(_) { 1.4554 + if (!arguments.length) return [ DX, DY ]; 1.4555 + DX = +_[0], DY = +_[1]; 1.4556 + return graticule; 1.4557 + }; 1.4558 + graticule.minorStep = function(_) { 1.4559 + if (!arguments.length) return [ dx, dy ]; 1.4560 + dx = +_[0], dy = +_[1]; 1.4561 + return graticule; 1.4562 + }; 1.4563 + graticule.precision = function(_) { 1.4564 + if (!arguments.length) return precision; 1.4565 + precision = +_; 1.4566 + x = d3_geo_graticuleX(y0, y1, 90); 1.4567 + y = d3_geo_graticuleY(x0, x1, precision); 1.4568 + X = d3_geo_graticuleX(Y0, Y1, 90); 1.4569 + Y = d3_geo_graticuleY(X0, X1, precision); 1.4570 + return graticule; 1.4571 + }; 1.4572 + return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); 1.4573 + }; 1.4574 + function d3_geo_graticuleX(y0, y1, dy) { 1.4575 + var y = d3.range(y0, y1 - ε, dy).concat(y1); 1.4576 + return function(x) { 1.4577 + return y.map(function(y) { 1.4578 + return [ x, y ]; 1.4579 + }); 1.4580 + }; 1.4581 + } 1.4582 + function d3_geo_graticuleY(x0, x1, dx) { 1.4583 + var x = d3.range(x0, x1 - ε, dx).concat(x1); 1.4584 + return function(y) { 1.4585 + return x.map(function(x) { 1.4586 + return [ x, y ]; 1.4587 + }); 1.4588 + }; 1.4589 + } 1.4590 + function d3_source(d) { 1.4591 + return d.source; 1.4592 + } 1.4593 + function d3_target(d) { 1.4594 + return d.target; 1.4595 + } 1.4596 + d3.geo.greatArc = function() { 1.4597 + var source = d3_source, source_, target = d3_target, target_; 1.4598 + function greatArc() { 1.4599 + return { 1.4600 + type: "LineString", 1.4601 + coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] 1.4602 + }; 1.4603 + } 1.4604 + greatArc.distance = function() { 1.4605 + return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); 1.4606 + }; 1.4607 + greatArc.source = function(_) { 1.4608 + if (!arguments.length) return source; 1.4609 + source = _, source_ = typeof _ === "function" ? null : _; 1.4610 + return greatArc; 1.4611 + }; 1.4612 + greatArc.target = function(_) { 1.4613 + if (!arguments.length) return target; 1.4614 + target = _, target_ = typeof _ === "function" ? null : _; 1.4615 + return greatArc; 1.4616 + }; 1.4617 + greatArc.precision = function() { 1.4618 + return arguments.length ? greatArc : 0; 1.4619 + }; 1.4620 + return greatArc; 1.4621 + }; 1.4622 + d3.geo.interpolate = function(source, target) { 1.4623 + return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); 1.4624 + }; 1.4625 + function d3_geo_interpolate(x0, y0, x1, y1) { 1.4626 + var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); 1.4627 + var interpolate = d ? function(t) { 1.4628 + var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; 1.4629 + return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; 1.4630 + } : function() { 1.4631 + return [ x0 * d3_degrees, y0 * d3_degrees ]; 1.4632 + }; 1.4633 + interpolate.distance = d; 1.4634 + return interpolate; 1.4635 + } 1.4636 + d3.geo.length = function(object) { 1.4637 + d3_geo_lengthSum = 0; 1.4638 + d3.geo.stream(object, d3_geo_length); 1.4639 + return d3_geo_lengthSum; 1.4640 + }; 1.4641 + var d3_geo_lengthSum; 1.4642 + var d3_geo_length = { 1.4643 + sphere: d3_noop, 1.4644 + point: d3_noop, 1.4645 + lineStart: d3_geo_lengthLineStart, 1.4646 + lineEnd: d3_noop, 1.4647 + polygonStart: d3_noop, 1.4648 + polygonEnd: d3_noop 1.4649 + }; 1.4650 + function d3_geo_lengthLineStart() { 1.4651 + var λ0, sinφ0, cosφ0; 1.4652 + d3_geo_length.point = function(λ, φ) { 1.4653 + λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); 1.4654 + d3_geo_length.point = nextPoint; 1.4655 + }; 1.4656 + d3_geo_length.lineEnd = function() { 1.4657 + d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; 1.4658 + }; 1.4659 + function nextPoint(λ, φ) { 1.4660 + var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); 1.4661 + d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); 1.4662 + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; 1.4663 + } 1.4664 + } 1.4665 + function d3_geo_azimuthal(scale, angle) { 1.4666 + function azimuthal(λ, φ) { 1.4667 + var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); 1.4668 + return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; 1.4669 + } 1.4670 + azimuthal.invert = function(x, y) { 1.4671 + var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); 1.4672 + return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; 1.4673 + }; 1.4674 + return azimuthal; 1.4675 + } 1.4676 + var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { 1.4677 + return Math.sqrt(2 / (1 + cosλcosφ)); 1.4678 + }, function(ρ) { 1.4679 + return 2 * Math.asin(ρ / 2); 1.4680 + }); 1.4681 + (d3.geo.azimuthalEqualArea = function() { 1.4682 + return d3_geo_projection(d3_geo_azimuthalEqualArea); 1.4683 + }).raw = d3_geo_azimuthalEqualArea; 1.4684 + var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { 1.4685 + var c = Math.acos(cosλcosφ); 1.4686 + return c && c / Math.sin(c); 1.4687 + }, d3_identity); 1.4688 + (d3.geo.azimuthalEquidistant = function() { 1.4689 + return d3_geo_projection(d3_geo_azimuthalEquidistant); 1.4690 + }).raw = d3_geo_azimuthalEquidistant; 1.4691 + function d3_geo_conicConformal(φ0, φ1) { 1.4692 + var cosφ0 = Math.cos(φ0), t = function(φ) { 1.4693 + return Math.tan(π / 4 + φ / 2); 1.4694 + }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; 1.4695 + if (!n) return d3_geo_mercator; 1.4696 + function forward(λ, φ) { 1.4697 + if (F > 0) { 1.4698 + if (φ < -halfπ + ε) φ = -halfπ + ε; 1.4699 + } else { 1.4700 + if (φ > halfπ - ε) φ = halfπ - ε; 1.4701 + } 1.4702 + var ρ = F / Math.pow(t(φ), n); 1.4703 + return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; 1.4704 + } 1.4705 + forward.invert = function(x, y) { 1.4706 + var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); 1.4707 + return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ]; 1.4708 + }; 1.4709 + return forward; 1.4710 + } 1.4711 + (d3.geo.conicConformal = function() { 1.4712 + return d3_geo_conic(d3_geo_conicConformal); 1.4713 + }).raw = d3_geo_conicConformal; 1.4714 + function d3_geo_conicEquidistant(φ0, φ1) { 1.4715 + var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; 1.4716 + if (abs(n) < ε) return d3_geo_equirectangular; 1.4717 + function forward(λ, φ) { 1.4718 + var ρ = G - φ; 1.4719 + return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; 1.4720 + } 1.4721 + forward.invert = function(x, y) { 1.4722 + var ρ0_y = G - y; 1.4723 + return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; 1.4724 + }; 1.4725 + return forward; 1.4726 + } 1.4727 + (d3.geo.conicEquidistant = function() { 1.4728 + return d3_geo_conic(d3_geo_conicEquidistant); 1.4729 + }).raw = d3_geo_conicEquidistant; 1.4730 + var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { 1.4731 + return 1 / cosλcosφ; 1.4732 + }, Math.atan); 1.4733 + (d3.geo.gnomonic = function() { 1.4734 + return d3_geo_projection(d3_geo_gnomonic); 1.4735 + }).raw = d3_geo_gnomonic; 1.4736 + function d3_geo_mercator(λ, φ) { 1.4737 + return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; 1.4738 + } 1.4739 + d3_geo_mercator.invert = function(x, y) { 1.4740 + return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ]; 1.4741 + }; 1.4742 + function d3_geo_mercatorProjection(project) { 1.4743 + var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; 1.4744 + m.scale = function() { 1.4745 + var v = scale.apply(m, arguments); 1.4746 + return v === m ? clipAuto ? m.clipExtent(null) : m : v; 1.4747 + }; 1.4748 + m.translate = function() { 1.4749 + var v = translate.apply(m, arguments); 1.4750 + return v === m ? clipAuto ? m.clipExtent(null) : m : v; 1.4751 + }; 1.4752 + m.clipExtent = function(_) { 1.4753 + var v = clipExtent.apply(m, arguments); 1.4754 + if (v === m) { 1.4755 + if (clipAuto = _ == null) { 1.4756 + var k = π * scale(), t = translate(); 1.4757 + clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); 1.4758 + } 1.4759 + } else if (clipAuto) { 1.4760 + v = null; 1.4761 + } 1.4762 + return v; 1.4763 + }; 1.4764 + return m.clipExtent(null); 1.4765 + } 1.4766 + (d3.geo.mercator = function() { 1.4767 + return d3_geo_mercatorProjection(d3_geo_mercator); 1.4768 + }).raw = d3_geo_mercator; 1.4769 + var d3_geo_orthographic = d3_geo_azimuthal(function() { 1.4770 + return 1; 1.4771 + }, Math.asin); 1.4772 + (d3.geo.orthographic = function() { 1.4773 + return d3_geo_projection(d3_geo_orthographic); 1.4774 + }).raw = d3_geo_orthographic; 1.4775 + var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { 1.4776 + return 1 / (1 + cosλcosφ); 1.4777 + }, function(ρ) { 1.4778 + return 2 * Math.atan(ρ); 1.4779 + }); 1.4780 + (d3.geo.stereographic = function() { 1.4781 + return d3_geo_projection(d3_geo_stereographic); 1.4782 + }).raw = d3_geo_stereographic; 1.4783 + function d3_geo_transverseMercator(λ, φ) { 1.4784 + return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ]; 1.4785 + } 1.4786 + d3_geo_transverseMercator.invert = function(x, y) { 1.4787 + return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ]; 1.4788 + }; 1.4789 + (d3.geo.transverseMercator = function() { 1.4790 + var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate; 1.4791 + projection.center = function(_) { 1.4792 + return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ _[1], -_[0] ]); 1.4793 + }; 1.4794 + projection.rotate = function(_) { 1.4795 + return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(), 1.4796 + [ _[0], _[1], _[2] - 90 ]); 1.4797 + }; 1.4798 + return rotate([ 0, 0, 90 ]); 1.4799 + }).raw = d3_geo_transverseMercator; 1.4800 + d3.geom = {}; 1.4801 + function d3_geom_pointX(d) { 1.4802 + return d[0]; 1.4803 + } 1.4804 + function d3_geom_pointY(d) { 1.4805 + return d[1]; 1.4806 + } 1.4807 + d3.geom.hull = function(vertices) { 1.4808 + var x = d3_geom_pointX, y = d3_geom_pointY; 1.4809 + if (arguments.length) return hull(vertices); 1.4810 + function hull(data) { 1.4811 + if (data.length < 3) return []; 1.4812 + var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = []; 1.4813 + for (i = 0; i < n; i++) { 1.4814 + points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]); 1.4815 + } 1.4816 + points.sort(d3_geom_hullOrder); 1.4817 + for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]); 1.4818 + var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints); 1.4819 + var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = []; 1.4820 + for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]); 1.4821 + for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]); 1.4822 + return polygon; 1.4823 + } 1.4824 + hull.x = function(_) { 1.4825 + return arguments.length ? (x = _, hull) : x; 1.4826 + }; 1.4827 + hull.y = function(_) { 1.4828 + return arguments.length ? (y = _, hull) : y; 1.4829 + }; 1.4830 + return hull; 1.4831 + }; 1.4832 + function d3_geom_hullUpper(points) { 1.4833 + var n = points.length, hull = [ 0, 1 ], hs = 2; 1.4834 + for (var i = 2; i < n; i++) { 1.4835 + while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs; 1.4836 + hull[hs++] = i; 1.4837 + } 1.4838 + return hull.slice(0, hs); 1.4839 + } 1.4840 + function d3_geom_hullOrder(a, b) { 1.4841 + return a[0] - b[0] || a[1] - b[1]; 1.4842 + } 1.4843 + d3.geom.polygon = function(coordinates) { 1.4844 + d3_subclass(coordinates, d3_geom_polygonPrototype); 1.4845 + return coordinates; 1.4846 + }; 1.4847 + var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; 1.4848 + d3_geom_polygonPrototype.area = function() { 1.4849 + var i = -1, n = this.length, a, b = this[n - 1], area = 0; 1.4850 + while (++i < n) { 1.4851 + a = b; 1.4852 + b = this[i]; 1.4853 + area += a[1] * b[0] - a[0] * b[1]; 1.4854 + } 1.4855 + return area * .5; 1.4856 + }; 1.4857 + d3_geom_polygonPrototype.centroid = function(k) { 1.4858 + var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; 1.4859 + if (!arguments.length) k = -1 / (6 * this.area()); 1.4860 + while (++i < n) { 1.4861 + a = b; 1.4862 + b = this[i]; 1.4863 + c = a[0] * b[1] - b[0] * a[1]; 1.4864 + x += (a[0] + b[0]) * c; 1.4865 + y += (a[1] + b[1]) * c; 1.4866 + } 1.4867 + return [ x * k, y * k ]; 1.4868 + }; 1.4869 + d3_geom_polygonPrototype.clip = function(subject) { 1.4870 + var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; 1.4871 + while (++i < n) { 1.4872 + input = subject.slice(); 1.4873 + subject.length = 0; 1.4874 + b = this[i]; 1.4875 + c = input[(m = input.length - closed) - 1]; 1.4876 + j = -1; 1.4877 + while (++j < m) { 1.4878 + d = input[j]; 1.4879 + if (d3_geom_polygonInside(d, a, b)) { 1.4880 + if (!d3_geom_polygonInside(c, a, b)) { 1.4881 + subject.push(d3_geom_polygonIntersect(c, d, a, b)); 1.4882 + } 1.4883 + subject.push(d); 1.4884 + } else if (d3_geom_polygonInside(c, a, b)) { 1.4885 + subject.push(d3_geom_polygonIntersect(c, d, a, b)); 1.4886 + } 1.4887 + c = d; 1.4888 + } 1.4889 + if (closed) subject.push(subject[0]); 1.4890 + a = b; 1.4891 + } 1.4892 + return subject; 1.4893 + }; 1.4894 + function d3_geom_polygonInside(p, a, b) { 1.4895 + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); 1.4896 + } 1.4897 + function d3_geom_polygonIntersect(c, d, a, b) { 1.4898 + var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); 1.4899 + return [ x1 + ua * x21, y1 + ua * y21 ]; 1.4900 + } 1.4901 + function d3_geom_polygonClosed(coordinates) { 1.4902 + var a = coordinates[0], b = coordinates[coordinates.length - 1]; 1.4903 + return !(a[0] - b[0] || a[1] - b[1]); 1.4904 + } 1.4905 + var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = []; 1.4906 + function d3_geom_voronoiBeach() { 1.4907 + d3_geom_voronoiRedBlackNode(this); 1.4908 + this.edge = this.site = this.circle = null; 1.4909 + } 1.4910 + function d3_geom_voronoiCreateBeach(site) { 1.4911 + var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach(); 1.4912 + beach.site = site; 1.4913 + return beach; 1.4914 + } 1.4915 + function d3_geom_voronoiDetachBeach(beach) { 1.4916 + d3_geom_voronoiDetachCircle(beach); 1.4917 + d3_geom_voronoiBeaches.remove(beach); 1.4918 + d3_geom_voronoiBeachPool.push(beach); 1.4919 + d3_geom_voronoiRedBlackNode(beach); 1.4920 + } 1.4921 + function d3_geom_voronoiRemoveBeach(beach) { 1.4922 + var circle = beach.circle, x = circle.x, y = circle.cy, vertex = { 1.4923 + x: x, 1.4924 + y: y 1.4925 + }, previous = beach.P, next = beach.N, disappearing = [ beach ]; 1.4926 + d3_geom_voronoiDetachBeach(beach); 1.4927 + var lArc = previous; 1.4928 + while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) { 1.4929 + previous = lArc.P; 1.4930 + disappearing.unshift(lArc); 1.4931 + d3_geom_voronoiDetachBeach(lArc); 1.4932 + lArc = previous; 1.4933 + } 1.4934 + disappearing.unshift(lArc); 1.4935 + d3_geom_voronoiDetachCircle(lArc); 1.4936 + var rArc = next; 1.4937 + while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) { 1.4938 + next = rArc.N; 1.4939 + disappearing.push(rArc); 1.4940 + d3_geom_voronoiDetachBeach(rArc); 1.4941 + rArc = next; 1.4942 + } 1.4943 + disappearing.push(rArc); 1.4944 + d3_geom_voronoiDetachCircle(rArc); 1.4945 + var nArcs = disappearing.length, iArc; 1.4946 + for (iArc = 1; iArc < nArcs; ++iArc) { 1.4947 + rArc = disappearing[iArc]; 1.4948 + lArc = disappearing[iArc - 1]; 1.4949 + d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex); 1.4950 + } 1.4951 + lArc = disappearing[0]; 1.4952 + rArc = disappearing[nArcs - 1]; 1.4953 + rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex); 1.4954 + d3_geom_voronoiAttachCircle(lArc); 1.4955 + d3_geom_voronoiAttachCircle(rArc); 1.4956 + } 1.4957 + function d3_geom_voronoiAddBeach(site) { 1.4958 + var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._; 1.4959 + while (node) { 1.4960 + dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x; 1.4961 + if (dxl > ε) node = node.L; else { 1.4962 + dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix); 1.4963 + if (dxr > ε) { 1.4964 + if (!node.R) { 1.4965 + lArc = node; 1.4966 + break; 1.4967 + } 1.4968 + node = node.R; 1.4969 + } else { 1.4970 + if (dxl > -ε) { 1.4971 + lArc = node.P; 1.4972 + rArc = node; 1.4973 + } else if (dxr > -ε) { 1.4974 + lArc = node; 1.4975 + rArc = node.N; 1.4976 + } else { 1.4977 + lArc = rArc = node; 1.4978 + } 1.4979 + break; 1.4980 + } 1.4981 + } 1.4982 + } 1.4983 + var newArc = d3_geom_voronoiCreateBeach(site); 1.4984 + d3_geom_voronoiBeaches.insert(lArc, newArc); 1.4985 + if (!lArc && !rArc) return; 1.4986 + if (lArc === rArc) { 1.4987 + d3_geom_voronoiDetachCircle(lArc); 1.4988 + rArc = d3_geom_voronoiCreateBeach(lArc.site); 1.4989 + d3_geom_voronoiBeaches.insert(newArc, rArc); 1.4990 + newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site); 1.4991 + d3_geom_voronoiAttachCircle(lArc); 1.4992 + d3_geom_voronoiAttachCircle(rArc); 1.4993 + return; 1.4994 + } 1.4995 + if (!rArc) { 1.4996 + newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site); 1.4997 + return; 1.4998 + } 1.4999 + d3_geom_voronoiDetachCircle(lArc); 1.5000 + d3_geom_voronoiDetachCircle(rArc); 1.5001 + var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = { 1.5002 + x: (cy * hb - by * hc) / d + ax, 1.5003 + y: (bx * hc - cx * hb) / d + ay 1.5004 + }; 1.5005 + d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex); 1.5006 + newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex); 1.5007 + rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex); 1.5008 + d3_geom_voronoiAttachCircle(lArc); 1.5009 + d3_geom_voronoiAttachCircle(rArc); 1.5010 + } 1.5011 + function d3_geom_voronoiLeftBreakPoint(arc, directrix) { 1.5012 + var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix; 1.5013 + if (!pby2) return rfocx; 1.5014 + var lArc = arc.P; 1.5015 + if (!lArc) return -Infinity; 1.5016 + site = lArc.site; 1.5017 + var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix; 1.5018 + if (!plby2) return lfocx; 1.5019 + var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2; 1.5020 + if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx; 1.5021 + return (rfocx + lfocx) / 2; 1.5022 + } 1.5023 + function d3_geom_voronoiRightBreakPoint(arc, directrix) { 1.5024 + var rArc = arc.N; 1.5025 + if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix); 1.5026 + var site = arc.site; 1.5027 + return site.y === directrix ? site.x : Infinity; 1.5028 + } 1.5029 + function d3_geom_voronoiCell(site) { 1.5030 + this.site = site; 1.5031 + this.edges = []; 1.5032 + } 1.5033 + d3_geom_voronoiCell.prototype.prepare = function() { 1.5034 + var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge; 1.5035 + while (iHalfEdge--) { 1.5036 + edge = halfEdges[iHalfEdge].edge; 1.5037 + if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1); 1.5038 + } 1.5039 + halfEdges.sort(d3_geom_voronoiHalfEdgeOrder); 1.5040 + return halfEdges.length; 1.5041 + }; 1.5042 + function d3_geom_voronoiCloseCells(extent) { 1.5043 + var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end; 1.5044 + while (iCell--) { 1.5045 + cell = cells[iCell]; 1.5046 + if (!cell || !cell.prepare()) continue; 1.5047 + halfEdges = cell.edges; 1.5048 + nHalfEdges = halfEdges.length; 1.5049 + iHalfEdge = 0; 1.5050 + while (iHalfEdge < nHalfEdges) { 1.5051 + end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y; 1.5052 + start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y; 1.5053 + if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) { 1.5054 + halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? { 1.5055 + x: x0, 1.5056 + y: abs(x2 - x0) < ε ? y2 : y1 1.5057 + } : abs(y3 - y1) < ε && x1 - x3 > ε ? { 1.5058 + x: abs(y2 - y1) < ε ? x2 : x1, 1.5059 + y: y1 1.5060 + } : abs(x3 - x1) < ε && y3 - y0 > ε ? { 1.5061 + x: x1, 1.5062 + y: abs(x2 - x1) < ε ? y2 : y0 1.5063 + } : abs(y3 - y0) < ε && x3 - x0 > ε ? { 1.5064 + x: abs(y2 - y0) < ε ? x2 : x0, 1.5065 + y: y0 1.5066 + } : null), cell.site, null)); 1.5067 + ++nHalfEdges; 1.5068 + } 1.5069 + } 1.5070 + } 1.5071 + } 1.5072 + function d3_geom_voronoiHalfEdgeOrder(a, b) { 1.5073 + return b.angle - a.angle; 1.5074 + } 1.5075 + function d3_geom_voronoiCircle() { 1.5076 + d3_geom_voronoiRedBlackNode(this); 1.5077 + this.x = this.y = this.arc = this.site = this.cy = null; 1.5078 + } 1.5079 + function d3_geom_voronoiAttachCircle(arc) { 1.5080 + var lArc = arc.P, rArc = arc.N; 1.5081 + if (!lArc || !rArc) return; 1.5082 + var lSite = lArc.site, cSite = arc.site, rSite = rArc.site; 1.5083 + if (lSite === rSite) return; 1.5084 + var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by; 1.5085 + var d = 2 * (ax * cy - ay * cx); 1.5086 + if (d >= -ε2) return; 1.5087 + var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by; 1.5088 + var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle(); 1.5089 + circle.arc = arc; 1.5090 + circle.site = cSite; 1.5091 + circle.x = x + bx; 1.5092 + circle.y = cy + Math.sqrt(x * x + y * y); 1.5093 + circle.cy = cy; 1.5094 + arc.circle = circle; 1.5095 + var before = null, node = d3_geom_voronoiCircles._; 1.5096 + while (node) { 1.5097 + if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) { 1.5098 + if (node.L) node = node.L; else { 1.5099 + before = node.P; 1.5100 + break; 1.5101 + } 1.5102 + } else { 1.5103 + if (node.R) node = node.R; else { 1.5104 + before = node; 1.5105 + break; 1.5106 + } 1.5107 + } 1.5108 + } 1.5109 + d3_geom_voronoiCircles.insert(before, circle); 1.5110 + if (!before) d3_geom_voronoiFirstCircle = circle; 1.5111 + } 1.5112 + function d3_geom_voronoiDetachCircle(arc) { 1.5113 + var circle = arc.circle; 1.5114 + if (circle) { 1.5115 + if (!circle.P) d3_geom_voronoiFirstCircle = circle.N; 1.5116 + d3_geom_voronoiCircles.remove(circle); 1.5117 + d3_geom_voronoiCirclePool.push(circle); 1.5118 + d3_geom_voronoiRedBlackNode(circle); 1.5119 + arc.circle = null; 1.5120 + } 1.5121 + } 1.5122 + function d3_geom_voronoiClipEdges(extent) { 1.5123 + var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e; 1.5124 + while (i--) { 1.5125 + e = edges[i]; 1.5126 + if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) { 1.5127 + e.a = e.b = null; 1.5128 + edges.splice(i, 1); 1.5129 + } 1.5130 + } 1.5131 + } 1.5132 + function d3_geom_voronoiConnectEdge(edge, extent) { 1.5133 + var vb = edge.b; 1.5134 + if (vb) return true; 1.5135 + var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb; 1.5136 + if (ry === ly) { 1.5137 + if (fx < x0 || fx >= x1) return; 1.5138 + if (lx > rx) { 1.5139 + if (!va) va = { 1.5140 + x: fx, 1.5141 + y: y0 1.5142 + }; else if (va.y >= y1) return; 1.5143 + vb = { 1.5144 + x: fx, 1.5145 + y: y1 1.5146 + }; 1.5147 + } else { 1.5148 + if (!va) va = { 1.5149 + x: fx, 1.5150 + y: y1 1.5151 + }; else if (va.y < y0) return; 1.5152 + vb = { 1.5153 + x: fx, 1.5154 + y: y0 1.5155 + }; 1.5156 + } 1.5157 + } else { 1.5158 + fm = (lx - rx) / (ry - ly); 1.5159 + fb = fy - fm * fx; 1.5160 + if (fm < -1 || fm > 1) { 1.5161 + if (lx > rx) { 1.5162 + if (!va) va = { 1.5163 + x: (y0 - fb) / fm, 1.5164 + y: y0 1.5165 + }; else if (va.y >= y1) return; 1.5166 + vb = { 1.5167 + x: (y1 - fb) / fm, 1.5168 + y: y1 1.5169 + }; 1.5170 + } else { 1.5171 + if (!va) va = { 1.5172 + x: (y1 - fb) / fm, 1.5173 + y: y1 1.5174 + }; else if (va.y < y0) return; 1.5175 + vb = { 1.5176 + x: (y0 - fb) / fm, 1.5177 + y: y0 1.5178 + }; 1.5179 + } 1.5180 + } else { 1.5181 + if (ly < ry) { 1.5182 + if (!va) va = { 1.5183 + x: x0, 1.5184 + y: fm * x0 + fb 1.5185 + }; else if (va.x >= x1) return; 1.5186 + vb = { 1.5187 + x: x1, 1.5188 + y: fm * x1 + fb 1.5189 + }; 1.5190 + } else { 1.5191 + if (!va) va = { 1.5192 + x: x1, 1.5193 + y: fm * x1 + fb 1.5194 + }; else if (va.x < x0) return; 1.5195 + vb = { 1.5196 + x: x0, 1.5197 + y: fm * x0 + fb 1.5198 + }; 1.5199 + } 1.5200 + } 1.5201 + } 1.5202 + edge.a = va; 1.5203 + edge.b = vb; 1.5204 + return true; 1.5205 + } 1.5206 + function d3_geom_voronoiEdge(lSite, rSite) { 1.5207 + this.l = lSite; 1.5208 + this.r = rSite; 1.5209 + this.a = this.b = null; 1.5210 + } 1.5211 + function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) { 1.5212 + var edge = new d3_geom_voronoiEdge(lSite, rSite); 1.5213 + d3_geom_voronoiEdges.push(edge); 1.5214 + if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va); 1.5215 + if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb); 1.5216 + d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite)); 1.5217 + d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite)); 1.5218 + return edge; 1.5219 + } 1.5220 + function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) { 1.5221 + var edge = new d3_geom_voronoiEdge(lSite, null); 1.5222 + edge.a = va; 1.5223 + edge.b = vb; 1.5224 + d3_geom_voronoiEdges.push(edge); 1.5225 + return edge; 1.5226 + } 1.5227 + function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) { 1.5228 + if (!edge.a && !edge.b) { 1.5229 + edge.a = vertex; 1.5230 + edge.l = lSite; 1.5231 + edge.r = rSite; 1.5232 + } else if (edge.l === rSite) { 1.5233 + edge.b = vertex; 1.5234 + } else { 1.5235 + edge.a = vertex; 1.5236 + } 1.5237 + } 1.5238 + function d3_geom_voronoiHalfEdge(edge, lSite, rSite) { 1.5239 + var va = edge.a, vb = edge.b; 1.5240 + this.edge = edge; 1.5241 + this.site = lSite; 1.5242 + this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y); 1.5243 + } 1.5244 + d3_geom_voronoiHalfEdge.prototype = { 1.5245 + start: function() { 1.5246 + return this.edge.l === this.site ? this.edge.a : this.edge.b; 1.5247 + }, 1.5248 + end: function() { 1.5249 + return this.edge.l === this.site ? this.edge.b : this.edge.a; 1.5250 + } 1.5251 + }; 1.5252 + function d3_geom_voronoiRedBlackTree() { 1.5253 + this._ = null; 1.5254 + } 1.5255 + function d3_geom_voronoiRedBlackNode(node) { 1.5256 + node.U = node.C = node.L = node.R = node.P = node.N = null; 1.5257 + } 1.5258 + d3_geom_voronoiRedBlackTree.prototype = { 1.5259 + insert: function(after, node) { 1.5260 + var parent, grandpa, uncle; 1.5261 + if (after) { 1.5262 + node.P = after; 1.5263 + node.N = after.N; 1.5264 + if (after.N) after.N.P = node; 1.5265 + after.N = node; 1.5266 + if (after.R) { 1.5267 + after = after.R; 1.5268 + while (after.L) after = after.L; 1.5269 + after.L = node; 1.5270 + } else { 1.5271 + after.R = node; 1.5272 + } 1.5273 + parent = after; 1.5274 + } else if (this._) { 1.5275 + after = d3_geom_voronoiRedBlackFirst(this._); 1.5276 + node.P = null; 1.5277 + node.N = after; 1.5278 + after.P = after.L = node; 1.5279 + parent = after; 1.5280 + } else { 1.5281 + node.P = node.N = null; 1.5282 + this._ = node; 1.5283 + parent = null; 1.5284 + } 1.5285 + node.L = node.R = null; 1.5286 + node.U = parent; 1.5287 + node.C = true; 1.5288 + after = node; 1.5289 + while (parent && parent.C) { 1.5290 + grandpa = parent.U; 1.5291 + if (parent === grandpa.L) { 1.5292 + uncle = grandpa.R; 1.5293 + if (uncle && uncle.C) { 1.5294 + parent.C = uncle.C = false; 1.5295 + grandpa.C = true; 1.5296 + after = grandpa; 1.5297 + } else { 1.5298 + if (after === parent.R) { 1.5299 + d3_geom_voronoiRedBlackRotateLeft(this, parent); 1.5300 + after = parent; 1.5301 + parent = after.U; 1.5302 + } 1.5303 + parent.C = false; 1.5304 + grandpa.C = true; 1.5305 + d3_geom_voronoiRedBlackRotateRight(this, grandpa); 1.5306 + } 1.5307 + } else { 1.5308 + uncle = grandpa.L; 1.5309 + if (uncle && uncle.C) { 1.5310 + parent.C = uncle.C = false; 1.5311 + grandpa.C = true; 1.5312 + after = grandpa; 1.5313 + } else { 1.5314 + if (after === parent.L) { 1.5315 + d3_geom_voronoiRedBlackRotateRight(this, parent); 1.5316 + after = parent; 1.5317 + parent = after.U; 1.5318 + } 1.5319 + parent.C = false; 1.5320 + grandpa.C = true; 1.5321 + d3_geom_voronoiRedBlackRotateLeft(this, grandpa); 1.5322 + } 1.5323 + } 1.5324 + parent = after.U; 1.5325 + } 1.5326 + this._.C = false; 1.5327 + }, 1.5328 + remove: function(node) { 1.5329 + if (node.N) node.N.P = node.P; 1.5330 + if (node.P) node.P.N = node.N; 1.5331 + node.N = node.P = null; 1.5332 + var parent = node.U, sibling, left = node.L, right = node.R, next, red; 1.5333 + if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right); 1.5334 + if (parent) { 1.5335 + if (parent.L === node) parent.L = next; else parent.R = next; 1.5336 + } else { 1.5337 + this._ = next; 1.5338 + } 1.5339 + if (left && right) { 1.5340 + red = next.C; 1.5341 + next.C = node.C; 1.5342 + next.L = left; 1.5343 + left.U = next; 1.5344 + if (next !== right) { 1.5345 + parent = next.U; 1.5346 + next.U = node.U; 1.5347 + node = next.R; 1.5348 + parent.L = node; 1.5349 + next.R = right; 1.5350 + right.U = next; 1.5351 + } else { 1.5352 + next.U = parent; 1.5353 + parent = next; 1.5354 + node = next.R; 1.5355 + } 1.5356 + } else { 1.5357 + red = node.C; 1.5358 + node = next; 1.5359 + } 1.5360 + if (node) node.U = parent; 1.5361 + if (red) return; 1.5362 + if (node && node.C) { 1.5363 + node.C = false; 1.5364 + return; 1.5365 + } 1.5366 + do { 1.5367 + if (node === this._) break; 1.5368 + if (node === parent.L) { 1.5369 + sibling = parent.R; 1.5370 + if (sibling.C) { 1.5371 + sibling.C = false; 1.5372 + parent.C = true; 1.5373 + d3_geom_voronoiRedBlackRotateLeft(this, parent); 1.5374 + sibling = parent.R; 1.5375 + } 1.5376 + if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) { 1.5377 + if (!sibling.R || !sibling.R.C) { 1.5378 + sibling.L.C = false; 1.5379 + sibling.C = true; 1.5380 + d3_geom_voronoiRedBlackRotateRight(this, sibling); 1.5381 + sibling = parent.R; 1.5382 + } 1.5383 + sibling.C = parent.C; 1.5384 + parent.C = sibling.R.C = false; 1.5385 + d3_geom_voronoiRedBlackRotateLeft(this, parent); 1.5386 + node = this._; 1.5387 + break; 1.5388 + } 1.5389 + } else { 1.5390 + sibling = parent.L; 1.5391 + if (sibling.C) { 1.5392 + sibling.C = false; 1.5393 + parent.C = true; 1.5394 + d3_geom_voronoiRedBlackRotateRight(this, parent); 1.5395 + sibling = parent.L; 1.5396 + } 1.5397 + if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) { 1.5398 + if (!sibling.L || !sibling.L.C) { 1.5399 + sibling.R.C = false; 1.5400 + sibling.C = true; 1.5401 + d3_geom_voronoiRedBlackRotateLeft(this, sibling); 1.5402 + sibling = parent.L; 1.5403 + } 1.5404 + sibling.C = parent.C; 1.5405 + parent.C = sibling.L.C = false; 1.5406 + d3_geom_voronoiRedBlackRotateRight(this, parent); 1.5407 + node = this._; 1.5408 + break; 1.5409 + } 1.5410 + } 1.5411 + sibling.C = true; 1.5412 + node = parent; 1.5413 + parent = parent.U; 1.5414 + } while (!node.C); 1.5415 + if (node) node.C = false; 1.5416 + } 1.5417 + }; 1.5418 + function d3_geom_voronoiRedBlackRotateLeft(tree, node) { 1.5419 + var p = node, q = node.R, parent = p.U; 1.5420 + if (parent) { 1.5421 + if (parent.L === p) parent.L = q; else parent.R = q; 1.5422 + } else { 1.5423 + tree._ = q; 1.5424 + } 1.5425 + q.U = parent; 1.5426 + p.U = q; 1.5427 + p.R = q.L; 1.5428 + if (p.R) p.R.U = p; 1.5429 + q.L = p; 1.5430 + } 1.5431 + function d3_geom_voronoiRedBlackRotateRight(tree, node) { 1.5432 + var p = node, q = node.L, parent = p.U; 1.5433 + if (parent) { 1.5434 + if (parent.L === p) parent.L = q; else parent.R = q; 1.5435 + } else { 1.5436 + tree._ = q; 1.5437 + } 1.5438 + q.U = parent; 1.5439 + p.U = q; 1.5440 + p.L = q.R; 1.5441 + if (p.L) p.L.U = p; 1.5442 + q.R = p; 1.5443 + } 1.5444 + function d3_geom_voronoiRedBlackFirst(node) { 1.5445 + while (node.L) node = node.L; 1.5446 + return node; 1.5447 + } 1.5448 + function d3_geom_voronoi(sites, bbox) { 1.5449 + var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle; 1.5450 + d3_geom_voronoiEdges = []; 1.5451 + d3_geom_voronoiCells = new Array(sites.length); 1.5452 + d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree(); 1.5453 + d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree(); 1.5454 + while (true) { 1.5455 + circle = d3_geom_voronoiFirstCircle; 1.5456 + if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) { 1.5457 + if (site.x !== x0 || site.y !== y0) { 1.5458 + d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site); 1.5459 + d3_geom_voronoiAddBeach(site); 1.5460 + x0 = site.x, y0 = site.y; 1.5461 + } 1.5462 + site = sites.pop(); 1.5463 + } else if (circle) { 1.5464 + d3_geom_voronoiRemoveBeach(circle.arc); 1.5465 + } else { 1.5466 + break; 1.5467 + } 1.5468 + } 1.5469 + if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox); 1.5470 + var diagram = { 1.5471 + cells: d3_geom_voronoiCells, 1.5472 + edges: d3_geom_voronoiEdges 1.5473 + }; 1.5474 + d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null; 1.5475 + return diagram; 1.5476 + } 1.5477 + function d3_geom_voronoiVertexOrder(a, b) { 1.5478 + return b.y - a.y || b.x - a.x; 1.5479 + } 1.5480 + d3.geom.voronoi = function(points) { 1.5481 + var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent; 1.5482 + if (points) return voronoi(points); 1.5483 + function voronoi(data) { 1.5484 + var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1]; 1.5485 + d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) { 1.5486 + var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) { 1.5487 + var s = e.start(); 1.5488 + return [ s.x, s.y ]; 1.5489 + }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : []; 1.5490 + polygon.point = data[i]; 1.5491 + }); 1.5492 + return polygons; 1.5493 + } 1.5494 + function sites(data) { 1.5495 + return data.map(function(d, i) { 1.5496 + return { 1.5497 + x: Math.round(fx(d, i) / ε) * ε, 1.5498 + y: Math.round(fy(d, i) / ε) * ε, 1.5499 + i: i 1.5500 + }; 1.5501 + }); 1.5502 + } 1.5503 + voronoi.links = function(data) { 1.5504 + return d3_geom_voronoi(sites(data)).edges.filter(function(edge) { 1.5505 + return edge.l && edge.r; 1.5506 + }).map(function(edge) { 1.5507 + return { 1.5508 + source: data[edge.l.i], 1.5509 + target: data[edge.r.i] 1.5510 + }; 1.5511 + }); 1.5512 + }; 1.5513 + voronoi.triangles = function(data) { 1.5514 + var triangles = []; 1.5515 + d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) { 1.5516 + var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l; 1.5517 + while (++j < m) { 1.5518 + e0 = e1; 1.5519 + s0 = s1; 1.5520 + e1 = edges[j].edge; 1.5521 + s1 = e1.l === site ? e1.r : e1.l; 1.5522 + if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) { 1.5523 + triangles.push([ data[i], data[s0.i], data[s1.i] ]); 1.5524 + } 1.5525 + } 1.5526 + }); 1.5527 + return triangles; 1.5528 + }; 1.5529 + voronoi.x = function(_) { 1.5530 + return arguments.length ? (fx = d3_functor(x = _), voronoi) : x; 1.5531 + }; 1.5532 + voronoi.y = function(_) { 1.5533 + return arguments.length ? (fy = d3_functor(y = _), voronoi) : y; 1.5534 + }; 1.5535 + voronoi.clipExtent = function(_) { 1.5536 + if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent; 1.5537 + clipExtent = _ == null ? d3_geom_voronoiClipExtent : _; 1.5538 + return voronoi; 1.5539 + }; 1.5540 + voronoi.size = function(_) { 1.5541 + if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1]; 1.5542 + return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); 1.5543 + }; 1.5544 + return voronoi; 1.5545 + }; 1.5546 + var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ]; 1.5547 + function d3_geom_voronoiTriangleArea(a, b, c) { 1.5548 + return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y); 1.5549 + } 1.5550 + d3.geom.delaunay = function(vertices) { 1.5551 + return d3.geom.voronoi().triangles(vertices); 1.5552 + }; 1.5553 + d3.geom.quadtree = function(points, x1, y1, x2, y2) { 1.5554 + var x = d3_geom_pointX, y = d3_geom_pointY, compat; 1.5555 + if (compat = arguments.length) { 1.5556 + x = d3_geom_quadtreeCompatX; 1.5557 + y = d3_geom_quadtreeCompatY; 1.5558 + if (compat === 3) { 1.5559 + y2 = y1; 1.5560 + x2 = x1; 1.5561 + y1 = x1 = 0; 1.5562 + } 1.5563 + return quadtree(points); 1.5564 + } 1.5565 + function quadtree(data) { 1.5566 + var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; 1.5567 + if (x1 != null) { 1.5568 + x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; 1.5569 + } else { 1.5570 + x2_ = y2_ = -(x1_ = y1_ = Infinity); 1.5571 + xs = [], ys = []; 1.5572 + n = data.length; 1.5573 + if (compat) for (i = 0; i < n; ++i) { 1.5574 + d = data[i]; 1.5575 + if (d.x < x1_) x1_ = d.x; 1.5576 + if (d.y < y1_) y1_ = d.y; 1.5577 + if (d.x > x2_) x2_ = d.x; 1.5578 + if (d.y > y2_) y2_ = d.y; 1.5579 + xs.push(d.x); 1.5580 + ys.push(d.y); 1.5581 + } else for (i = 0; i < n; ++i) { 1.5582 + var x_ = +fx(d = data[i], i), y_ = +fy(d, i); 1.5583 + if (x_ < x1_) x1_ = x_; 1.5584 + if (y_ < y1_) y1_ = y_; 1.5585 + if (x_ > x2_) x2_ = x_; 1.5586 + if (y_ > y2_) y2_ = y_; 1.5587 + xs.push(x_); 1.5588 + ys.push(y_); 1.5589 + } 1.5590 + } 1.5591 + var dx = x2_ - x1_, dy = y2_ - y1_; 1.5592 + if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; 1.5593 + function insert(n, d, x, y, x1, y1, x2, y2) { 1.5594 + if (isNaN(x) || isNaN(y)) return; 1.5595 + if (n.leaf) { 1.5596 + var nx = n.x, ny = n.y; 1.5597 + if (nx != null) { 1.5598 + if (abs(nx - x) + abs(ny - y) < .01) { 1.5599 + insertChild(n, d, x, y, x1, y1, x2, y2); 1.5600 + } else { 1.5601 + var nPoint = n.point; 1.5602 + n.x = n.y = n.point = null; 1.5603 + insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); 1.5604 + insertChild(n, d, x, y, x1, y1, x2, y2); 1.5605 + } 1.5606 + } else { 1.5607 + n.x = x, n.y = y, n.point = d; 1.5608 + } 1.5609 + } else { 1.5610 + insertChild(n, d, x, y, x1, y1, x2, y2); 1.5611 + } 1.5612 + } 1.5613 + function insertChild(n, d, x, y, x1, y1, x2, y2) { 1.5614 + var xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym, i = below << 1 | right; 1.5615 + n.leaf = false; 1.5616 + n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); 1.5617 + if (right) x1 = xm; else x2 = xm; 1.5618 + if (below) y1 = ym; else y2 = ym; 1.5619 + insert(n, d, x, y, x1, y1, x2, y2); 1.5620 + } 1.5621 + var root = d3_geom_quadtreeNode(); 1.5622 + root.add = function(d) { 1.5623 + insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); 1.5624 + }; 1.5625 + root.visit = function(f) { 1.5626 + d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); 1.5627 + }; 1.5628 + root.find = function(point) { 1.5629 + return d3_geom_quadtreeFind(root, point[0], point[1], x1_, y1_, x2_, y2_); 1.5630 + }; 1.5631 + i = -1; 1.5632 + if (x1 == null) { 1.5633 + while (++i < n) { 1.5634 + insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); 1.5635 + } 1.5636 + --i; 1.5637 + } else data.forEach(root.add); 1.5638 + xs = ys = data = d = null; 1.5639 + return root; 1.5640 + } 1.5641 + quadtree.x = function(_) { 1.5642 + return arguments.length ? (x = _, quadtree) : x; 1.5643 + }; 1.5644 + quadtree.y = function(_) { 1.5645 + return arguments.length ? (y = _, quadtree) : y; 1.5646 + }; 1.5647 + quadtree.extent = function(_) { 1.5648 + if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; 1.5649 + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], 1.5650 + y2 = +_[1][1]; 1.5651 + return quadtree; 1.5652 + }; 1.5653 + quadtree.size = function(_) { 1.5654 + if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; 1.5655 + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; 1.5656 + return quadtree; 1.5657 + }; 1.5658 + return quadtree; 1.5659 + }; 1.5660 + function d3_geom_quadtreeCompatX(d) { 1.5661 + return d.x; 1.5662 + } 1.5663 + function d3_geom_quadtreeCompatY(d) { 1.5664 + return d.y; 1.5665 + } 1.5666 + function d3_geom_quadtreeNode() { 1.5667 + return { 1.5668 + leaf: true, 1.5669 + nodes: [], 1.5670 + point: null, 1.5671 + x: null, 1.5672 + y: null 1.5673 + }; 1.5674 + } 1.5675 + function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { 1.5676 + if (!f(node, x1, y1, x2, y2)) { 1.5677 + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; 1.5678 + if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); 1.5679 + if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); 1.5680 + if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); 1.5681 + if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); 1.5682 + } 1.5683 + } 1.5684 + function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) { 1.5685 + var minDistance2 = Infinity, closestPoint; 1.5686 + (function find(node, x1, y1, x2, y2) { 1.5687 + if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return; 1.5688 + if (point = node.point) { 1.5689 + var point, dx = x - node.x, dy = y - node.y, distance2 = dx * dx + dy * dy; 1.5690 + if (distance2 < minDistance2) { 1.5691 + var distance = Math.sqrt(minDistance2 = distance2); 1.5692 + x0 = x - distance, y0 = y - distance; 1.5693 + x3 = x + distance, y3 = y + distance; 1.5694 + closestPoint = point; 1.5695 + } 1.5696 + } 1.5697 + var children = node.nodes, xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym; 1.5698 + for (var i = below << 1 | right, j = i + 4; i < j; ++i) { 1.5699 + if (node = children[i & 3]) switch (i & 3) { 1.5700 + case 0: 1.5701 + find(node, x1, y1, xm, ym); 1.5702 + break; 1.5703 + 1.5704 + case 1: 1.5705 + find(node, xm, y1, x2, ym); 1.5706 + break; 1.5707 + 1.5708 + case 2: 1.5709 + find(node, x1, ym, xm, y2); 1.5710 + break; 1.5711 + 1.5712 + case 3: 1.5713 + find(node, xm, ym, x2, y2); 1.5714 + break; 1.5715 + } 1.5716 + } 1.5717 + })(root, x0, y0, x3, y3); 1.5718 + return closestPoint; 1.5719 + } 1.5720 + d3.interpolateRgb = d3_interpolateRgb; 1.5721 + function d3_interpolateRgb(a, b) { 1.5722 + a = d3.rgb(a); 1.5723 + b = d3.rgb(b); 1.5724 + var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; 1.5725 + return function(t) { 1.5726 + return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); 1.5727 + }; 1.5728 + } 1.5729 + d3.interpolateObject = d3_interpolateObject; 1.5730 + function d3_interpolateObject(a, b) { 1.5731 + var i = {}, c = {}, k; 1.5732 + for (k in a) { 1.5733 + if (k in b) { 1.5734 + i[k] = d3_interpolate(a[k], b[k]); 1.5735 + } else { 1.5736 + c[k] = a[k]; 1.5737 + } 1.5738 + } 1.5739 + for (k in b) { 1.5740 + if (!(k in a)) { 1.5741 + c[k] = b[k]; 1.5742 + } 1.5743 + } 1.5744 + return function(t) { 1.5745 + for (k in i) c[k] = i[k](t); 1.5746 + return c; 1.5747 + }; 1.5748 + } 1.5749 + d3.interpolateNumber = d3_interpolateNumber; 1.5750 + function d3_interpolateNumber(a, b) { 1.5751 + a = +a, b = +b; 1.5752 + return function(t) { 1.5753 + return a * (1 - t) + b * t; 1.5754 + }; 1.5755 + } 1.5756 + d3.interpolateString = d3_interpolateString; 1.5757 + function d3_interpolateString(a, b) { 1.5758 + var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = []; 1.5759 + a = a + "", b = b + ""; 1.5760 + while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) { 1.5761 + if ((bs = bm.index) > bi) { 1.5762 + bs = b.slice(bi, bs); 1.5763 + if (s[i]) s[i] += bs; else s[++i] = bs; 1.5764 + } 1.5765 + if ((am = am[0]) === (bm = bm[0])) { 1.5766 + if (s[i]) s[i] += bm; else s[++i] = bm; 1.5767 + } else { 1.5768 + s[++i] = null; 1.5769 + q.push({ 1.5770 + i: i, 1.5771 + x: d3_interpolateNumber(am, bm) 1.5772 + }); 1.5773 + } 1.5774 + bi = d3_interpolate_numberB.lastIndex; 1.5775 + } 1.5776 + if (bi < b.length) { 1.5777 + bs = b.slice(bi); 1.5778 + if (s[i]) s[i] += bs; else s[++i] = bs; 1.5779 + } 1.5780 + return s.length < 2 ? q[0] ? (b = q[0].x, function(t) { 1.5781 + return b(t) + ""; 1.5782 + }) : function() { 1.5783 + return b; 1.5784 + } : (b = q.length, function(t) { 1.5785 + for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t); 1.5786 + return s.join(""); 1.5787 + }); 1.5788 + } 1.5789 + var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g"); 1.5790 + d3.interpolate = d3_interpolate; 1.5791 + function d3_interpolate(a, b) { 1.5792 + var i = d3.interpolators.length, f; 1.5793 + while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; 1.5794 + return f; 1.5795 + } 1.5796 + d3.interpolators = [ function(a, b) { 1.5797 + var t = typeof b; 1.5798 + return (t === "string" ? d3_rgb_names.has(b.toLowerCase()) || /^(#|rgb\(|hsl\()/i.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === "object" && isNaN(b) ? d3_interpolateObject : d3_interpolateNumber)(a, b); 1.5799 + } ]; 1.5800 + d3.interpolateArray = d3_interpolateArray; 1.5801 + function d3_interpolateArray(a, b) { 1.5802 + var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; 1.5803 + for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); 1.5804 + for (;i < na; ++i) c[i] = a[i]; 1.5805 + for (;i < nb; ++i) c[i] = b[i]; 1.5806 + return function(t) { 1.5807 + for (i = 0; i < n0; ++i) c[i] = x[i](t); 1.5808 + return c; 1.5809 + }; 1.5810 + } 1.5811 + var d3_ease_default = function() { 1.5812 + return d3_identity; 1.5813 + }; 1.5814 + var d3_ease = d3.map({ 1.5815 + linear: d3_ease_default, 1.5816 + poly: d3_ease_poly, 1.5817 + quad: function() { 1.5818 + return d3_ease_quad; 1.5819 + }, 1.5820 + cubic: function() { 1.5821 + return d3_ease_cubic; 1.5822 + }, 1.5823 + sin: function() { 1.5824 + return d3_ease_sin; 1.5825 + }, 1.5826 + exp: function() { 1.5827 + return d3_ease_exp; 1.5828 + }, 1.5829 + circle: function() { 1.5830 + return d3_ease_circle; 1.5831 + }, 1.5832 + elastic: d3_ease_elastic, 1.5833 + back: d3_ease_back, 1.5834 + bounce: function() { 1.5835 + return d3_ease_bounce; 1.5836 + } 1.5837 + }); 1.5838 + var d3_ease_mode = d3.map({ 1.5839 + "in": d3_identity, 1.5840 + out: d3_ease_reverse, 1.5841 + "in-out": d3_ease_reflect, 1.5842 + "out-in": function(f) { 1.5843 + return d3_ease_reflect(d3_ease_reverse(f)); 1.5844 + } 1.5845 + }); 1.5846 + d3.ease = function(name) { 1.5847 + var i = name.indexOf("-"), t = i >= 0 ? name.slice(0, i) : name, m = i >= 0 ? name.slice(i + 1) : "in"; 1.5848 + t = d3_ease.get(t) || d3_ease_default; 1.5849 + m = d3_ease_mode.get(m) || d3_identity; 1.5850 + return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1)))); 1.5851 + }; 1.5852 + function d3_ease_clamp(f) { 1.5853 + return function(t) { 1.5854 + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); 1.5855 + }; 1.5856 + } 1.5857 + function d3_ease_reverse(f) { 1.5858 + return function(t) { 1.5859 + return 1 - f(1 - t); 1.5860 + }; 1.5861 + } 1.5862 + function d3_ease_reflect(f) { 1.5863 + return function(t) { 1.5864 + return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); 1.5865 + }; 1.5866 + } 1.5867 + function d3_ease_quad(t) { 1.5868 + return t * t; 1.5869 + } 1.5870 + function d3_ease_cubic(t) { 1.5871 + return t * t * t; 1.5872 + } 1.5873 + function d3_ease_cubicInOut(t) { 1.5874 + if (t <= 0) return 0; 1.5875 + if (t >= 1) return 1; 1.5876 + var t2 = t * t, t3 = t2 * t; 1.5877 + return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); 1.5878 + } 1.5879 + function d3_ease_poly(e) { 1.5880 + return function(t) { 1.5881 + return Math.pow(t, e); 1.5882 + }; 1.5883 + } 1.5884 + function d3_ease_sin(t) { 1.5885 + return 1 - Math.cos(t * halfπ); 1.5886 + } 1.5887 + function d3_ease_exp(t) { 1.5888 + return Math.pow(2, 10 * (t - 1)); 1.5889 + } 1.5890 + function d3_ease_circle(t) { 1.5891 + return 1 - Math.sqrt(1 - t * t); 1.5892 + } 1.5893 + function d3_ease_elastic(a, p) { 1.5894 + var s; 1.5895 + if (arguments.length < 2) p = .45; 1.5896 + if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4; 1.5897 + return function(t) { 1.5898 + return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p); 1.5899 + }; 1.5900 + } 1.5901 + function d3_ease_back(s) { 1.5902 + if (!s) s = 1.70158; 1.5903 + return function(t) { 1.5904 + return t * t * ((s + 1) * t - s); 1.5905 + }; 1.5906 + } 1.5907 + function d3_ease_bounce(t) { 1.5908 + return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; 1.5909 + } 1.5910 + d3.interpolateHcl = d3_interpolateHcl; 1.5911 + function d3_interpolateHcl(a, b) { 1.5912 + a = d3.hcl(a); 1.5913 + b = d3.hcl(b); 1.5914 + var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; 1.5915 + if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; 1.5916 + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; 1.5917 + return function(t) { 1.5918 + return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; 1.5919 + }; 1.5920 + } 1.5921 + d3.interpolateHsl = d3_interpolateHsl; 1.5922 + function d3_interpolateHsl(a, b) { 1.5923 + a = d3.hsl(a); 1.5924 + b = d3.hsl(b); 1.5925 + var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; 1.5926 + if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; 1.5927 + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; 1.5928 + return function(t) { 1.5929 + return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; 1.5930 + }; 1.5931 + } 1.5932 + d3.interpolateLab = d3_interpolateLab; 1.5933 + function d3_interpolateLab(a, b) { 1.5934 + a = d3.lab(a); 1.5935 + b = d3.lab(b); 1.5936 + var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; 1.5937 + return function(t) { 1.5938 + return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; 1.5939 + }; 1.5940 + } 1.5941 + d3.interpolateRound = d3_interpolateRound; 1.5942 + function d3_interpolateRound(a, b) { 1.5943 + b -= a; 1.5944 + return function(t) { 1.5945 + return Math.round(a + b * t); 1.5946 + }; 1.5947 + } 1.5948 + d3.transform = function(string) { 1.5949 + var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); 1.5950 + return (d3.transform = function(string) { 1.5951 + if (string != null) { 1.5952 + g.setAttribute("transform", string); 1.5953 + var t = g.transform.baseVal.consolidate(); 1.5954 + } 1.5955 + return new d3_transform(t ? t.matrix : d3_transformIdentity); 1.5956 + })(string); 1.5957 + }; 1.5958 + function d3_transform(m) { 1.5959 + var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; 1.5960 + if (r0[0] * r1[1] < r1[0] * r0[1]) { 1.5961 + r0[0] *= -1; 1.5962 + r0[1] *= -1; 1.5963 + kx *= -1; 1.5964 + kz *= -1; 1.5965 + } 1.5966 + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; 1.5967 + this.translate = [ m.e, m.f ]; 1.5968 + this.scale = [ kx, ky ]; 1.5969 + this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; 1.5970 + } 1.5971 + d3_transform.prototype.toString = function() { 1.5972 + return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; 1.5973 + }; 1.5974 + function d3_transformDot(a, b) { 1.5975 + return a[0] * b[0] + a[1] * b[1]; 1.5976 + } 1.5977 + function d3_transformNormalize(a) { 1.5978 + var k = Math.sqrt(d3_transformDot(a, a)); 1.5979 + if (k) { 1.5980 + a[0] /= k; 1.5981 + a[1] /= k; 1.5982 + } 1.5983 + return k; 1.5984 + } 1.5985 + function d3_transformCombine(a, b, k) { 1.5986 + a[0] += k * b[0]; 1.5987 + a[1] += k * b[1]; 1.5988 + return a; 1.5989 + } 1.5990 + var d3_transformIdentity = { 1.5991 + a: 1, 1.5992 + b: 0, 1.5993 + c: 0, 1.5994 + d: 1, 1.5995 + e: 0, 1.5996 + f: 0 1.5997 + }; 1.5998 + d3.interpolateTransform = d3_interpolateTransform; 1.5999 + function d3_interpolateTransformPop(s) { 1.6000 + return s.length ? s.pop() + "," : ""; 1.6001 + } 1.6002 + function d3_interpolateTranslate(ta, tb, s, q) { 1.6003 + if (ta[0] !== tb[0] || ta[1] !== tb[1]) { 1.6004 + var i = s.push("translate(", null, ",", null, ")"); 1.6005 + q.push({ 1.6006 + i: i - 4, 1.6007 + x: d3_interpolateNumber(ta[0], tb[0]) 1.6008 + }, { 1.6009 + i: i - 2, 1.6010 + x: d3_interpolateNumber(ta[1], tb[1]) 1.6011 + }); 1.6012 + } else if (tb[0] || tb[1]) { 1.6013 + s.push("translate(" + tb + ")"); 1.6014 + } 1.6015 + } 1.6016 + function d3_interpolateRotate(ra, rb, s, q) { 1.6017 + if (ra !== rb) { 1.6018 + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; 1.6019 + q.push({ 1.6020 + i: s.push(d3_interpolateTransformPop(s) + "rotate(", null, ")") - 2, 1.6021 + x: d3_interpolateNumber(ra, rb) 1.6022 + }); 1.6023 + } else if (rb) { 1.6024 + s.push(d3_interpolateTransformPop(s) + "rotate(" + rb + ")"); 1.6025 + } 1.6026 + } 1.6027 + function d3_interpolateSkew(wa, wb, s, q) { 1.6028 + if (wa !== wb) { 1.6029 + q.push({ 1.6030 + i: s.push(d3_interpolateTransformPop(s) + "skewX(", null, ")") - 2, 1.6031 + x: d3_interpolateNumber(wa, wb) 1.6032 + }); 1.6033 + } else if (wb) { 1.6034 + s.push(d3_interpolateTransformPop(s) + "skewX(" + wb + ")"); 1.6035 + } 1.6036 + } 1.6037 + function d3_interpolateScale(ka, kb, s, q) { 1.6038 + if (ka[0] !== kb[0] || ka[1] !== kb[1]) { 1.6039 + var i = s.push(d3_interpolateTransformPop(s) + "scale(", null, ",", null, ")"); 1.6040 + q.push({ 1.6041 + i: i - 4, 1.6042 + x: d3_interpolateNumber(ka[0], kb[0]) 1.6043 + }, { 1.6044 + i: i - 2, 1.6045 + x: d3_interpolateNumber(ka[1], kb[1]) 1.6046 + }); 1.6047 + } else if (kb[0] !== 1 || kb[1] !== 1) { 1.6048 + s.push(d3_interpolateTransformPop(s) + "scale(" + kb + ")"); 1.6049 + } 1.6050 + } 1.6051 + function d3_interpolateTransform(a, b) { 1.6052 + var s = [], q = []; 1.6053 + a = d3.transform(a), b = d3.transform(b); 1.6054 + d3_interpolateTranslate(a.translate, b.translate, s, q); 1.6055 + d3_interpolateRotate(a.rotate, b.rotate, s, q); 1.6056 + d3_interpolateSkew(a.skew, b.skew, s, q); 1.6057 + d3_interpolateScale(a.scale, b.scale, s, q); 1.6058 + a = b = null; 1.6059 + return function(t) { 1.6060 + var i = -1, n = q.length, o; 1.6061 + while (++i < n) s[(o = q[i]).i] = o.x(t); 1.6062 + return s.join(""); 1.6063 + }; 1.6064 + } 1.6065 + function d3_uninterpolateNumber(a, b) { 1.6066 + b = (b -= a = +a) || 1 / b; 1.6067 + return function(x) { 1.6068 + return (x - a) / b; 1.6069 + }; 1.6070 + } 1.6071 + function d3_uninterpolateClamp(a, b) { 1.6072 + b = (b -= a = +a) || 1 / b; 1.6073 + return function(x) { 1.6074 + return Math.max(0, Math.min(1, (x - a) / b)); 1.6075 + }; 1.6076 + } 1.6077 + d3.layout = {}; 1.6078 + d3.layout.bundle = function() { 1.6079 + return function(links) { 1.6080 + var paths = [], i = -1, n = links.length; 1.6081 + while (++i < n) paths.push(d3_layout_bundlePath(links[i])); 1.6082 + return paths; 1.6083 + }; 1.6084 + }; 1.6085 + function d3_layout_bundlePath(link) { 1.6086 + var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; 1.6087 + while (start !== lca) { 1.6088 + start = start.parent; 1.6089 + points.push(start); 1.6090 + } 1.6091 + var k = points.length; 1.6092 + while (end !== lca) { 1.6093 + points.splice(k, 0, end); 1.6094 + end = end.parent; 1.6095 + } 1.6096 + return points; 1.6097 + } 1.6098 + function d3_layout_bundleAncestors(node) { 1.6099 + var ancestors = [], parent = node.parent; 1.6100 + while (parent != null) { 1.6101 + ancestors.push(node); 1.6102 + node = parent; 1.6103 + parent = parent.parent; 1.6104 + } 1.6105 + ancestors.push(node); 1.6106 + return ancestors; 1.6107 + } 1.6108 + function d3_layout_bundleLeastCommonAncestor(a, b) { 1.6109 + if (a === b) return a; 1.6110 + var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; 1.6111 + while (aNode === bNode) { 1.6112 + sharedNode = aNode; 1.6113 + aNode = aNodes.pop(); 1.6114 + bNode = bNodes.pop(); 1.6115 + } 1.6116 + return sharedNode; 1.6117 + } 1.6118 + d3.layout.chord = function() { 1.6119 + var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; 1.6120 + function relayout() { 1.6121 + var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; 1.6122 + chords = []; 1.6123 + groups = []; 1.6124 + k = 0, i = -1; 1.6125 + while (++i < n) { 1.6126 + x = 0, j = -1; 1.6127 + while (++j < n) { 1.6128 + x += matrix[i][j]; 1.6129 + } 1.6130 + groupSums.push(x); 1.6131 + subgroupIndex.push(d3.range(n)); 1.6132 + k += x; 1.6133 + } 1.6134 + if (sortGroups) { 1.6135 + groupIndex.sort(function(a, b) { 1.6136 + return sortGroups(groupSums[a], groupSums[b]); 1.6137 + }); 1.6138 + } 1.6139 + if (sortSubgroups) { 1.6140 + subgroupIndex.forEach(function(d, i) { 1.6141 + d.sort(function(a, b) { 1.6142 + return sortSubgroups(matrix[i][a], matrix[i][b]); 1.6143 + }); 1.6144 + }); 1.6145 + } 1.6146 + k = (τ - padding * n) / k; 1.6147 + x = 0, i = -1; 1.6148 + while (++i < n) { 1.6149 + x0 = x, j = -1; 1.6150 + while (++j < n) { 1.6151 + var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; 1.6152 + subgroups[di + "-" + dj] = { 1.6153 + index: di, 1.6154 + subindex: dj, 1.6155 + startAngle: a0, 1.6156 + endAngle: a1, 1.6157 + value: v 1.6158 + }; 1.6159 + } 1.6160 + groups[di] = { 1.6161 + index: di, 1.6162 + startAngle: x0, 1.6163 + endAngle: x, 1.6164 + value: groupSums[di] 1.6165 + }; 1.6166 + x += padding; 1.6167 + } 1.6168 + i = -1; 1.6169 + while (++i < n) { 1.6170 + j = i - 1; 1.6171 + while (++j < n) { 1.6172 + var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; 1.6173 + if (source.value || target.value) { 1.6174 + chords.push(source.value < target.value ? { 1.6175 + source: target, 1.6176 + target: source 1.6177 + } : { 1.6178 + source: source, 1.6179 + target: target 1.6180 + }); 1.6181 + } 1.6182 + } 1.6183 + } 1.6184 + if (sortChords) resort(); 1.6185 + } 1.6186 + function resort() { 1.6187 + chords.sort(function(a, b) { 1.6188 + return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); 1.6189 + }); 1.6190 + } 1.6191 + chord.matrix = function(x) { 1.6192 + if (!arguments.length) return matrix; 1.6193 + n = (matrix = x) && matrix.length; 1.6194 + chords = groups = null; 1.6195 + return chord; 1.6196 + }; 1.6197 + chord.padding = function(x) { 1.6198 + if (!arguments.length) return padding; 1.6199 + padding = x; 1.6200 + chords = groups = null; 1.6201 + return chord; 1.6202 + }; 1.6203 + chord.sortGroups = function(x) { 1.6204 + if (!arguments.length) return sortGroups; 1.6205 + sortGroups = x; 1.6206 + chords = groups = null; 1.6207 + return chord; 1.6208 + }; 1.6209 + chord.sortSubgroups = function(x) { 1.6210 + if (!arguments.length) return sortSubgroups; 1.6211 + sortSubgroups = x; 1.6212 + chords = null; 1.6213 + return chord; 1.6214 + }; 1.6215 + chord.sortChords = function(x) { 1.6216 + if (!arguments.length) return sortChords; 1.6217 + sortChords = x; 1.6218 + if (chords) resort(); 1.6219 + return chord; 1.6220 + }; 1.6221 + chord.chords = function() { 1.6222 + if (!chords) relayout(); 1.6223 + return chords; 1.6224 + }; 1.6225 + chord.groups = function() { 1.6226 + if (!groups) relayout(); 1.6227 + return groups; 1.6228 + }; 1.6229 + return chord; 1.6230 + }; 1.6231 + d3.layout.force = function() { 1.6232 + var force = {}, event = d3.dispatch("start", "tick", "end"), timer, size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges; 1.6233 + function repulse(node) { 1.6234 + return function(quad, x1, _, x2) { 1.6235 + if (quad.point !== node) { 1.6236 + var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy; 1.6237 + if (dw * dw / theta2 < dn) { 1.6238 + if (dn < chargeDistance2) { 1.6239 + var k = quad.charge / dn; 1.6240 + node.px -= dx * k; 1.6241 + node.py -= dy * k; 1.6242 + } 1.6243 + return true; 1.6244 + } 1.6245 + if (quad.point && dn && dn < chargeDistance2) { 1.6246 + var k = quad.pointCharge / dn; 1.6247 + node.px -= dx * k; 1.6248 + node.py -= dy * k; 1.6249 + } 1.6250 + } 1.6251 + return !quad.charge; 1.6252 + }; 1.6253 + } 1.6254 + force.tick = function() { 1.6255 + if ((alpha *= .99) < .005) { 1.6256 + timer = null; 1.6257 + event.end({ 1.6258 + type: "end", 1.6259 + alpha: alpha = 0 1.6260 + }); 1.6261 + return true; 1.6262 + } 1.6263 + var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; 1.6264 + for (i = 0; i < m; ++i) { 1.6265 + o = links[i]; 1.6266 + s = o.source; 1.6267 + t = o.target; 1.6268 + x = t.x - s.x; 1.6269 + y = t.y - s.y; 1.6270 + if (l = x * x + y * y) { 1.6271 + l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; 1.6272 + x *= l; 1.6273 + y *= l; 1.6274 + t.x -= x * (k = s.weight + t.weight ? s.weight / (s.weight + t.weight) : .5); 1.6275 + t.y -= y * k; 1.6276 + s.x += x * (k = 1 - k); 1.6277 + s.y += y * k; 1.6278 + } 1.6279 + } 1.6280 + if (k = alpha * gravity) { 1.6281 + x = size[0] / 2; 1.6282 + y = size[1] / 2; 1.6283 + i = -1; 1.6284 + if (k) while (++i < n) { 1.6285 + o = nodes[i]; 1.6286 + o.x += (x - o.x) * k; 1.6287 + o.y += (y - o.y) * k; 1.6288 + } 1.6289 + } 1.6290 + if (charge) { 1.6291 + d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); 1.6292 + i = -1; 1.6293 + while (++i < n) { 1.6294 + if (!(o = nodes[i]).fixed) { 1.6295 + q.visit(repulse(o)); 1.6296 + } 1.6297 + } 1.6298 + } 1.6299 + i = -1; 1.6300 + while (++i < n) { 1.6301 + o = nodes[i]; 1.6302 + if (o.fixed) { 1.6303 + o.x = o.px; 1.6304 + o.y = o.py; 1.6305 + } else { 1.6306 + o.x -= (o.px - (o.px = o.x)) * friction; 1.6307 + o.y -= (o.py - (o.py = o.y)) * friction; 1.6308 + } 1.6309 + } 1.6310 + event.tick({ 1.6311 + type: "tick", 1.6312 + alpha: alpha 1.6313 + }); 1.6314 + }; 1.6315 + force.nodes = function(x) { 1.6316 + if (!arguments.length) return nodes; 1.6317 + nodes = x; 1.6318 + return force; 1.6319 + }; 1.6320 + force.links = function(x) { 1.6321 + if (!arguments.length) return links; 1.6322 + links = x; 1.6323 + return force; 1.6324 + }; 1.6325 + force.size = function(x) { 1.6326 + if (!arguments.length) return size; 1.6327 + size = x; 1.6328 + return force; 1.6329 + }; 1.6330 + force.linkDistance = function(x) { 1.6331 + if (!arguments.length) return linkDistance; 1.6332 + linkDistance = typeof x === "function" ? x : +x; 1.6333 + return force; 1.6334 + }; 1.6335 + force.distance = force.linkDistance; 1.6336 + force.linkStrength = function(x) { 1.6337 + if (!arguments.length) return linkStrength; 1.6338 + linkStrength = typeof x === "function" ? x : +x; 1.6339 + return force; 1.6340 + }; 1.6341 + force.friction = function(x) { 1.6342 + if (!arguments.length) return friction; 1.6343 + friction = +x; 1.6344 + return force; 1.6345 + }; 1.6346 + force.charge = function(x) { 1.6347 + if (!arguments.length) return charge; 1.6348 + charge = typeof x === "function" ? x : +x; 1.6349 + return force; 1.6350 + }; 1.6351 + force.chargeDistance = function(x) { 1.6352 + if (!arguments.length) return Math.sqrt(chargeDistance2); 1.6353 + chargeDistance2 = x * x; 1.6354 + return force; 1.6355 + }; 1.6356 + force.gravity = function(x) { 1.6357 + if (!arguments.length) return gravity; 1.6358 + gravity = +x; 1.6359 + return force; 1.6360 + }; 1.6361 + force.theta = function(x) { 1.6362 + if (!arguments.length) return Math.sqrt(theta2); 1.6363 + theta2 = x * x; 1.6364 + return force; 1.6365 + }; 1.6366 + force.alpha = function(x) { 1.6367 + if (!arguments.length) return alpha; 1.6368 + x = +x; 1.6369 + if (alpha) { 1.6370 + if (x > 0) { 1.6371 + alpha = x; 1.6372 + } else { 1.6373 + timer.c = null, timer.t = NaN, timer = null; 1.6374 + event.end({ 1.6375 + type: "end", 1.6376 + alpha: alpha = 0 1.6377 + }); 1.6378 + } 1.6379 + } else if (x > 0) { 1.6380 + event.start({ 1.6381 + type: "start", 1.6382 + alpha: alpha = x 1.6383 + }); 1.6384 + timer = d3_timer(force.tick); 1.6385 + } 1.6386 + return force; 1.6387 + }; 1.6388 + force.start = function() { 1.6389 + var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; 1.6390 + for (i = 0; i < n; ++i) { 1.6391 + (o = nodes[i]).index = i; 1.6392 + o.weight = 0; 1.6393 + } 1.6394 + for (i = 0; i < m; ++i) { 1.6395 + o = links[i]; 1.6396 + if (typeof o.source == "number") o.source = nodes[o.source]; 1.6397 + if (typeof o.target == "number") o.target = nodes[o.target]; 1.6398 + ++o.source.weight; 1.6399 + ++o.target.weight; 1.6400 + } 1.6401 + for (i = 0; i < n; ++i) { 1.6402 + o = nodes[i]; 1.6403 + if (isNaN(o.x)) o.x = position("x", w); 1.6404 + if (isNaN(o.y)) o.y = position("y", h); 1.6405 + if (isNaN(o.px)) o.px = o.x; 1.6406 + if (isNaN(o.py)) o.py = o.y; 1.6407 + } 1.6408 + distances = []; 1.6409 + if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; 1.6410 + strengths = []; 1.6411 + if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; 1.6412 + charges = []; 1.6413 + if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; 1.6414 + function position(dimension, size) { 1.6415 + if (!neighbors) { 1.6416 + neighbors = new Array(n); 1.6417 + for (j = 0; j < n; ++j) { 1.6418 + neighbors[j] = []; 1.6419 + } 1.6420 + for (j = 0; j < m; ++j) { 1.6421 + var o = links[j]; 1.6422 + neighbors[o.source.index].push(o.target); 1.6423 + neighbors[o.target.index].push(o.source); 1.6424 + } 1.6425 + } 1.6426 + var candidates = neighbors[i], j = -1, l = candidates.length, x; 1.6427 + while (++j < l) if (!isNaN(x = candidates[j][dimension])) return x; 1.6428 + return Math.random() * size; 1.6429 + } 1.6430 + return force.resume(); 1.6431 + }; 1.6432 + force.resume = function() { 1.6433 + return force.alpha(.1); 1.6434 + }; 1.6435 + force.stop = function() { 1.6436 + return force.alpha(0); 1.6437 + }; 1.6438 + force.drag = function() { 1.6439 + if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); 1.6440 + if (!arguments.length) return drag; 1.6441 + this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); 1.6442 + }; 1.6443 + function dragmove(d) { 1.6444 + d.px = d3.event.x, d.py = d3.event.y; 1.6445 + force.resume(); 1.6446 + } 1.6447 + return d3.rebind(force, event, "on"); 1.6448 + }; 1.6449 + function d3_layout_forceDragstart(d) { 1.6450 + d.fixed |= 2; 1.6451 + } 1.6452 + function d3_layout_forceDragend(d) { 1.6453 + d.fixed &= ~6; 1.6454 + } 1.6455 + function d3_layout_forceMouseover(d) { 1.6456 + d.fixed |= 4; 1.6457 + d.px = d.x, d.py = d.y; 1.6458 + } 1.6459 + function d3_layout_forceMouseout(d) { 1.6460 + d.fixed &= ~4; 1.6461 + } 1.6462 + function d3_layout_forceAccumulate(quad, alpha, charges) { 1.6463 + var cx = 0, cy = 0; 1.6464 + quad.charge = 0; 1.6465 + if (!quad.leaf) { 1.6466 + var nodes = quad.nodes, n = nodes.length, i = -1, c; 1.6467 + while (++i < n) { 1.6468 + c = nodes[i]; 1.6469 + if (c == null) continue; 1.6470 + d3_layout_forceAccumulate(c, alpha, charges); 1.6471 + quad.charge += c.charge; 1.6472 + cx += c.charge * c.cx; 1.6473 + cy += c.charge * c.cy; 1.6474 + } 1.6475 + } 1.6476 + if (quad.point) { 1.6477 + if (!quad.leaf) { 1.6478 + quad.point.x += Math.random() - .5; 1.6479 + quad.point.y += Math.random() - .5; 1.6480 + } 1.6481 + var k = alpha * charges[quad.point.index]; 1.6482 + quad.charge += quad.pointCharge = k; 1.6483 + cx += k * quad.point.x; 1.6484 + cy += k * quad.point.y; 1.6485 + } 1.6486 + quad.cx = cx / quad.charge; 1.6487 + quad.cy = cy / quad.charge; 1.6488 + } 1.6489 + var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity; 1.6490 + d3.layout.hierarchy = function() { 1.6491 + var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; 1.6492 + function hierarchy(root) { 1.6493 + var stack = [ root ], nodes = [], node; 1.6494 + root.depth = 0; 1.6495 + while ((node = stack.pop()) != null) { 1.6496 + nodes.push(node); 1.6497 + if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) { 1.6498 + var n, childs, child; 1.6499 + while (--n >= 0) { 1.6500 + stack.push(child = childs[n]); 1.6501 + child.parent = node; 1.6502 + child.depth = node.depth + 1; 1.6503 + } 1.6504 + if (value) node.value = 0; 1.6505 + node.children = childs; 1.6506 + } else { 1.6507 + if (value) node.value = +value.call(hierarchy, node, node.depth) || 0; 1.6508 + delete node.children; 1.6509 + } 1.6510 + } 1.6511 + d3_layout_hierarchyVisitAfter(root, function(node) { 1.6512 + var childs, parent; 1.6513 + if (sort && (childs = node.children)) childs.sort(sort); 1.6514 + if (value && (parent = node.parent)) parent.value += node.value; 1.6515 + }); 1.6516 + return nodes; 1.6517 + } 1.6518 + hierarchy.sort = function(x) { 1.6519 + if (!arguments.length) return sort; 1.6520 + sort = x; 1.6521 + return hierarchy; 1.6522 + }; 1.6523 + hierarchy.children = function(x) { 1.6524 + if (!arguments.length) return children; 1.6525 + children = x; 1.6526 + return hierarchy; 1.6527 + }; 1.6528 + hierarchy.value = function(x) { 1.6529 + if (!arguments.length) return value; 1.6530 + value = x; 1.6531 + return hierarchy; 1.6532 + }; 1.6533 + hierarchy.revalue = function(root) { 1.6534 + if (value) { 1.6535 + d3_layout_hierarchyVisitBefore(root, function(node) { 1.6536 + if (node.children) node.value = 0; 1.6537 + }); 1.6538 + d3_layout_hierarchyVisitAfter(root, function(node) { 1.6539 + var parent; 1.6540 + if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0; 1.6541 + if (parent = node.parent) parent.value += node.value; 1.6542 + }); 1.6543 + } 1.6544 + return root; 1.6545 + }; 1.6546 + return hierarchy; 1.6547 + }; 1.6548 + function d3_layout_hierarchyRebind(object, hierarchy) { 1.6549 + d3.rebind(object, hierarchy, "sort", "children", "value"); 1.6550 + object.nodes = object; 1.6551 + object.links = d3_layout_hierarchyLinks; 1.6552 + return object; 1.6553 + } 1.6554 + function d3_layout_hierarchyVisitBefore(node, callback) { 1.6555 + var nodes = [ node ]; 1.6556 + while ((node = nodes.pop()) != null) { 1.6557 + callback(node); 1.6558 + if ((children = node.children) && (n = children.length)) { 1.6559 + var n, children; 1.6560 + while (--n >= 0) nodes.push(children[n]); 1.6561 + } 1.6562 + } 1.6563 + } 1.6564 + function d3_layout_hierarchyVisitAfter(node, callback) { 1.6565 + var nodes = [ node ], nodes2 = []; 1.6566 + while ((node = nodes.pop()) != null) { 1.6567 + nodes2.push(node); 1.6568 + if ((children = node.children) && (n = children.length)) { 1.6569 + var i = -1, n, children; 1.6570 + while (++i < n) nodes.push(children[i]); 1.6571 + } 1.6572 + } 1.6573 + while ((node = nodes2.pop()) != null) { 1.6574 + callback(node); 1.6575 + } 1.6576 + } 1.6577 + function d3_layout_hierarchyChildren(d) { 1.6578 + return d.children; 1.6579 + } 1.6580 + function d3_layout_hierarchyValue(d) { 1.6581 + return d.value; 1.6582 + } 1.6583 + function d3_layout_hierarchySort(a, b) { 1.6584 + return b.value - a.value; 1.6585 + } 1.6586 + function d3_layout_hierarchyLinks(nodes) { 1.6587 + return d3.merge(nodes.map(function(parent) { 1.6588 + return (parent.children || []).map(function(child) { 1.6589 + return { 1.6590 + source: parent, 1.6591 + target: child 1.6592 + }; 1.6593 + }); 1.6594 + })); 1.6595 + } 1.6596 + d3.layout.partition = function() { 1.6597 + var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; 1.6598 + function position(node, x, dx, dy) { 1.6599 + var children = node.children; 1.6600 + node.x = x; 1.6601 + node.y = node.depth * dy; 1.6602 + node.dx = dx; 1.6603 + node.dy = dy; 1.6604 + if (children && (n = children.length)) { 1.6605 + var i = -1, n, c, d; 1.6606 + dx = node.value ? dx / node.value : 0; 1.6607 + while (++i < n) { 1.6608 + position(c = children[i], x, d = c.value * dx, dy); 1.6609 + x += d; 1.6610 + } 1.6611 + } 1.6612 + } 1.6613 + function depth(node) { 1.6614 + var children = node.children, d = 0; 1.6615 + if (children && (n = children.length)) { 1.6616 + var i = -1, n; 1.6617 + while (++i < n) d = Math.max(d, depth(children[i])); 1.6618 + } 1.6619 + return 1 + d; 1.6620 + } 1.6621 + function partition(d, i) { 1.6622 + var nodes = hierarchy.call(this, d, i); 1.6623 + position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); 1.6624 + return nodes; 1.6625 + } 1.6626 + partition.size = function(x) { 1.6627 + if (!arguments.length) return size; 1.6628 + size = x; 1.6629 + return partition; 1.6630 + }; 1.6631 + return d3_layout_hierarchyRebind(partition, hierarchy); 1.6632 + }; 1.6633 + d3.layout.pie = function() { 1.6634 + var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ, padAngle = 0; 1.6635 + function pie(data) { 1.6636 + var n = data.length, values = data.map(function(d, i) { 1.6637 + return +value.call(pie, d, i); 1.6638 + }), a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === "function" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), sum = d3.sum(values), k = sum ? (da - n * pa) / sum : 0, index = d3.range(n), arcs = [], v; 1.6639 + if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { 1.6640 + return values[j] - values[i]; 1.6641 + } : function(i, j) { 1.6642 + return sort(data[i], data[j]); 1.6643 + }); 1.6644 + index.forEach(function(i) { 1.6645 + arcs[i] = { 1.6646 + data: data[i], 1.6647 + value: v = values[i], 1.6648 + startAngle: a, 1.6649 + endAngle: a += v * k + pa, 1.6650 + padAngle: p 1.6651 + }; 1.6652 + }); 1.6653 + return arcs; 1.6654 + } 1.6655 + pie.value = function(_) { 1.6656 + if (!arguments.length) return value; 1.6657 + value = _; 1.6658 + return pie; 1.6659 + }; 1.6660 + pie.sort = function(_) { 1.6661 + if (!arguments.length) return sort; 1.6662 + sort = _; 1.6663 + return pie; 1.6664 + }; 1.6665 + pie.startAngle = function(_) { 1.6666 + if (!arguments.length) return startAngle; 1.6667 + startAngle = _; 1.6668 + return pie; 1.6669 + }; 1.6670 + pie.endAngle = function(_) { 1.6671 + if (!arguments.length) return endAngle; 1.6672 + endAngle = _; 1.6673 + return pie; 1.6674 + }; 1.6675 + pie.padAngle = function(_) { 1.6676 + if (!arguments.length) return padAngle; 1.6677 + padAngle = _; 1.6678 + return pie; 1.6679 + }; 1.6680 + return pie; 1.6681 + }; 1.6682 + var d3_layout_pieSortByValue = {}; 1.6683 + d3.layout.stack = function() { 1.6684 + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; 1.6685 + function stack(data, index) { 1.6686 + if (!(n = data.length)) return data; 1.6687 + var series = data.map(function(d, i) { 1.6688 + return values.call(stack, d, i); 1.6689 + }); 1.6690 + var points = series.map(function(d) { 1.6691 + return d.map(function(v, i) { 1.6692 + return [ x.call(stack, v, i), y.call(stack, v, i) ]; 1.6693 + }); 1.6694 + }); 1.6695 + var orders = order.call(stack, points, index); 1.6696 + series = d3.permute(series, orders); 1.6697 + points = d3.permute(points, orders); 1.6698 + var offsets = offset.call(stack, points, index); 1.6699 + var m = series[0].length, n, i, j, o; 1.6700 + for (j = 0; j < m; ++j) { 1.6701 + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); 1.6702 + for (i = 1; i < n; ++i) { 1.6703 + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); 1.6704 + } 1.6705 + } 1.6706 + return data; 1.6707 + } 1.6708 + stack.values = function(x) { 1.6709 + if (!arguments.length) return values; 1.6710 + values = x; 1.6711 + return stack; 1.6712 + }; 1.6713 + stack.order = function(x) { 1.6714 + if (!arguments.length) return order; 1.6715 + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; 1.6716 + return stack; 1.6717 + }; 1.6718 + stack.offset = function(x) { 1.6719 + if (!arguments.length) return offset; 1.6720 + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; 1.6721 + return stack; 1.6722 + }; 1.6723 + stack.x = function(z) { 1.6724 + if (!arguments.length) return x; 1.6725 + x = z; 1.6726 + return stack; 1.6727 + }; 1.6728 + stack.y = function(z) { 1.6729 + if (!arguments.length) return y; 1.6730 + y = z; 1.6731 + return stack; 1.6732 + }; 1.6733 + stack.out = function(z) { 1.6734 + if (!arguments.length) return out; 1.6735 + out = z; 1.6736 + return stack; 1.6737 + }; 1.6738 + return stack; 1.6739 + }; 1.6740 + function d3_layout_stackX(d) { 1.6741 + return d.x; 1.6742 + } 1.6743 + function d3_layout_stackY(d) { 1.6744 + return d.y; 1.6745 + } 1.6746 + function d3_layout_stackOut(d, y0, y) { 1.6747 + d.y0 = y0; 1.6748 + d.y = y; 1.6749 + } 1.6750 + var d3_layout_stackOrders = d3.map({ 1.6751 + "inside-out": function(data) { 1.6752 + var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { 1.6753 + return max[a] - max[b]; 1.6754 + }), top = 0, bottom = 0, tops = [], bottoms = []; 1.6755 + for (i = 0; i < n; ++i) { 1.6756 + j = index[i]; 1.6757 + if (top < bottom) { 1.6758 + top += sums[j]; 1.6759 + tops.push(j); 1.6760 + } else { 1.6761 + bottom += sums[j]; 1.6762 + bottoms.push(j); 1.6763 + } 1.6764 + } 1.6765 + return bottoms.reverse().concat(tops); 1.6766 + }, 1.6767 + reverse: function(data) { 1.6768 + return d3.range(data.length).reverse(); 1.6769 + }, 1.6770 + "default": d3_layout_stackOrderDefault 1.6771 + }); 1.6772 + var d3_layout_stackOffsets = d3.map({ 1.6773 + silhouette: function(data) { 1.6774 + var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; 1.6775 + for (j = 0; j < m; ++j) { 1.6776 + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; 1.6777 + if (o > max) max = o; 1.6778 + sums.push(o); 1.6779 + } 1.6780 + for (j = 0; j < m; ++j) { 1.6781 + y0[j] = (max - sums[j]) / 2; 1.6782 + } 1.6783 + return y0; 1.6784 + }, 1.6785 + wiggle: function(data) { 1.6786 + var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; 1.6787 + y0[0] = o = o0 = 0; 1.6788 + for (j = 1; j < m; ++j) { 1.6789 + for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; 1.6790 + for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { 1.6791 + for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { 1.6792 + s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; 1.6793 + } 1.6794 + s2 += s3 * data[i][j][1]; 1.6795 + } 1.6796 + y0[j] = o -= s1 ? s2 / s1 * dx : 0; 1.6797 + if (o < o0) o0 = o; 1.6798 + } 1.6799 + for (j = 0; j < m; ++j) y0[j] -= o0; 1.6800 + return y0; 1.6801 + }, 1.6802 + expand: function(data) { 1.6803 + var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; 1.6804 + for (j = 0; j < m; ++j) { 1.6805 + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; 1.6806 + if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; 1.6807 + } 1.6808 + for (j = 0; j < m; ++j) y0[j] = 0; 1.6809 + return y0; 1.6810 + }, 1.6811 + zero: d3_layout_stackOffsetZero 1.6812 + }); 1.6813 + function d3_layout_stackOrderDefault(data) { 1.6814 + return d3.range(data.length); 1.6815 + } 1.6816 + function d3_layout_stackOffsetZero(data) { 1.6817 + var j = -1, m = data[0].length, y0 = []; 1.6818 + while (++j < m) y0[j] = 0; 1.6819 + return y0; 1.6820 + } 1.6821 + function d3_layout_stackMaxIndex(array) { 1.6822 + var i = 1, j = 0, v = array[0][1], k, n = array.length; 1.6823 + for (;i < n; ++i) { 1.6824 + if ((k = array[i][1]) > v) { 1.6825 + j = i; 1.6826 + v = k; 1.6827 + } 1.6828 + } 1.6829 + return j; 1.6830 + } 1.6831 + function d3_layout_stackReduceSum(d) { 1.6832 + return d.reduce(d3_layout_stackSum, 0); 1.6833 + } 1.6834 + function d3_layout_stackSum(p, d) { 1.6835 + return p + d[1]; 1.6836 + } 1.6837 + d3.layout.histogram = function() { 1.6838 + var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; 1.6839 + function histogram(data, i) { 1.6840 + var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; 1.6841 + while (++i < m) { 1.6842 + bin = bins[i] = []; 1.6843 + bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); 1.6844 + bin.y = 0; 1.6845 + } 1.6846 + if (m > 0) { 1.6847 + i = -1; 1.6848 + while (++i < n) { 1.6849 + x = values[i]; 1.6850 + if (x >= range[0] && x <= range[1]) { 1.6851 + bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; 1.6852 + bin.y += k; 1.6853 + bin.push(data[i]); 1.6854 + } 1.6855 + } 1.6856 + } 1.6857 + return bins; 1.6858 + } 1.6859 + histogram.value = function(x) { 1.6860 + if (!arguments.length) return valuer; 1.6861 + valuer = x; 1.6862 + return histogram; 1.6863 + }; 1.6864 + histogram.range = function(x) { 1.6865 + if (!arguments.length) return ranger; 1.6866 + ranger = d3_functor(x); 1.6867 + return histogram; 1.6868 + }; 1.6869 + histogram.bins = function(x) { 1.6870 + if (!arguments.length) return binner; 1.6871 + binner = typeof x === "number" ? function(range) { 1.6872 + return d3_layout_histogramBinFixed(range, x); 1.6873 + } : d3_functor(x); 1.6874 + return histogram; 1.6875 + }; 1.6876 + histogram.frequency = function(x) { 1.6877 + if (!arguments.length) return frequency; 1.6878 + frequency = !!x; 1.6879 + return histogram; 1.6880 + }; 1.6881 + return histogram; 1.6882 + }; 1.6883 + function d3_layout_histogramBinSturges(range, values) { 1.6884 + return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); 1.6885 + } 1.6886 + function d3_layout_histogramBinFixed(range, n) { 1.6887 + var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; 1.6888 + while (++x <= n) f[x] = m * x + b; 1.6889 + return f; 1.6890 + } 1.6891 + function d3_layout_histogramRange(values) { 1.6892 + return [ d3.min(values), d3.max(values) ]; 1.6893 + } 1.6894 + d3.layout.pack = function() { 1.6895 + var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; 1.6896 + function pack(d, i) { 1.6897 + var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { 1.6898 + return radius; 1.6899 + }; 1.6900 + root.x = root.y = 0; 1.6901 + d3_layout_hierarchyVisitAfter(root, function(d) { 1.6902 + d.r = +r(d.value); 1.6903 + }); 1.6904 + d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings); 1.6905 + if (padding) { 1.6906 + var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; 1.6907 + d3_layout_hierarchyVisitAfter(root, function(d) { 1.6908 + d.r += dr; 1.6909 + }); 1.6910 + d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings); 1.6911 + d3_layout_hierarchyVisitAfter(root, function(d) { 1.6912 + d.r -= dr; 1.6913 + }); 1.6914 + } 1.6915 + d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); 1.6916 + return nodes; 1.6917 + } 1.6918 + pack.size = function(_) { 1.6919 + if (!arguments.length) return size; 1.6920 + size = _; 1.6921 + return pack; 1.6922 + }; 1.6923 + pack.radius = function(_) { 1.6924 + if (!arguments.length) return radius; 1.6925 + radius = _ == null || typeof _ === "function" ? _ : +_; 1.6926 + return pack; 1.6927 + }; 1.6928 + pack.padding = function(_) { 1.6929 + if (!arguments.length) return padding; 1.6930 + padding = +_; 1.6931 + return pack; 1.6932 + }; 1.6933 + return d3_layout_hierarchyRebind(pack, hierarchy); 1.6934 + }; 1.6935 + function d3_layout_packSort(a, b) { 1.6936 + return a.value - b.value; 1.6937 + } 1.6938 + function d3_layout_packInsert(a, b) { 1.6939 + var c = a._pack_next; 1.6940 + a._pack_next = b; 1.6941 + b._pack_prev = a; 1.6942 + b._pack_next = c; 1.6943 + c._pack_prev = b; 1.6944 + } 1.6945 + function d3_layout_packSplice(a, b) { 1.6946 + a._pack_next = b; 1.6947 + b._pack_prev = a; 1.6948 + } 1.6949 + function d3_layout_packIntersects(a, b) { 1.6950 + var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; 1.6951 + return .999 * dr * dr > dx * dx + dy * dy; 1.6952 + } 1.6953 + function d3_layout_packSiblings(node) { 1.6954 + if (!(nodes = node.children) || !(n = nodes.length)) return; 1.6955 + var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; 1.6956 + function bound(node) { 1.6957 + xMin = Math.min(node.x - node.r, xMin); 1.6958 + xMax = Math.max(node.x + node.r, xMax); 1.6959 + yMin = Math.min(node.y - node.r, yMin); 1.6960 + yMax = Math.max(node.y + node.r, yMax); 1.6961 + } 1.6962 + nodes.forEach(d3_layout_packLink); 1.6963 + a = nodes[0]; 1.6964 + a.x = -a.r; 1.6965 + a.y = 0; 1.6966 + bound(a); 1.6967 + if (n > 1) { 1.6968 + b = nodes[1]; 1.6969 + b.x = b.r; 1.6970 + b.y = 0; 1.6971 + bound(b); 1.6972 + if (n > 2) { 1.6973 + c = nodes[2]; 1.6974 + d3_layout_packPlace(a, b, c); 1.6975 + bound(c); 1.6976 + d3_layout_packInsert(a, c); 1.6977 + a._pack_prev = c; 1.6978 + d3_layout_packInsert(c, b); 1.6979 + b = a._pack_next; 1.6980 + for (i = 3; i < n; i++) { 1.6981 + d3_layout_packPlace(a, b, c = nodes[i]); 1.6982 + var isect = 0, s1 = 1, s2 = 1; 1.6983 + for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { 1.6984 + if (d3_layout_packIntersects(j, c)) { 1.6985 + isect = 1; 1.6986 + break; 1.6987 + } 1.6988 + } 1.6989 + if (isect == 1) { 1.6990 + for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { 1.6991 + if (d3_layout_packIntersects(k, c)) { 1.6992 + break; 1.6993 + } 1.6994 + } 1.6995 + } 1.6996 + if (isect) { 1.6997 + if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); 1.6998 + i--; 1.6999 + } else { 1.7000 + d3_layout_packInsert(a, c); 1.7001 + b = c; 1.7002 + bound(c); 1.7003 + } 1.7004 + } 1.7005 + } 1.7006 + } 1.7007 + var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; 1.7008 + for (i = 0; i < n; i++) { 1.7009 + c = nodes[i]; 1.7010 + c.x -= cx; 1.7011 + c.y -= cy; 1.7012 + cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); 1.7013 + } 1.7014 + node.r = cr; 1.7015 + nodes.forEach(d3_layout_packUnlink); 1.7016 + } 1.7017 + function d3_layout_packLink(node) { 1.7018 + node._pack_next = node._pack_prev = node; 1.7019 + } 1.7020 + function d3_layout_packUnlink(node) { 1.7021 + delete node._pack_next; 1.7022 + delete node._pack_prev; 1.7023 + } 1.7024 + function d3_layout_packTransform(node, x, y, k) { 1.7025 + var children = node.children; 1.7026 + node.x = x += k * node.x; 1.7027 + node.y = y += k * node.y; 1.7028 + node.r *= k; 1.7029 + if (children) { 1.7030 + var i = -1, n = children.length; 1.7031 + while (++i < n) d3_layout_packTransform(children[i], x, y, k); 1.7032 + } 1.7033 + } 1.7034 + function d3_layout_packPlace(a, b, c) { 1.7035 + var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; 1.7036 + if (db && (dx || dy)) { 1.7037 + var da = b.r + c.r, dc = dx * dx + dy * dy; 1.7038 + da *= da; 1.7039 + db *= db; 1.7040 + var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); 1.7041 + c.x = a.x + x * dx + y * dy; 1.7042 + c.y = a.y + x * dy - y * dx; 1.7043 + } else { 1.7044 + c.x = a.x + db; 1.7045 + c.y = a.y; 1.7046 + } 1.7047 + } 1.7048 + d3.layout.tree = function() { 1.7049 + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = null; 1.7050 + function tree(d, i) { 1.7051 + var nodes = hierarchy.call(this, d, i), root0 = nodes[0], root1 = wrapTree(root0); 1.7052 + d3_layout_hierarchyVisitAfter(root1, firstWalk), root1.parent.m = -root1.z; 1.7053 + d3_layout_hierarchyVisitBefore(root1, secondWalk); 1.7054 + if (nodeSize) d3_layout_hierarchyVisitBefore(root0, sizeNode); else { 1.7055 + var left = root0, right = root0, bottom = root0; 1.7056 + d3_layout_hierarchyVisitBefore(root0, function(node) { 1.7057 + if (node.x < left.x) left = node; 1.7058 + if (node.x > right.x) right = node; 1.7059 + if (node.depth > bottom.depth) bottom = node; 1.7060 + }); 1.7061 + var tx = separation(left, right) / 2 - left.x, kx = size[0] / (right.x + separation(right, left) / 2 + tx), ky = size[1] / (bottom.depth || 1); 1.7062 + d3_layout_hierarchyVisitBefore(root0, function(node) { 1.7063 + node.x = (node.x + tx) * kx; 1.7064 + node.y = node.depth * ky; 1.7065 + }); 1.7066 + } 1.7067 + return nodes; 1.7068 + } 1.7069 + function wrapTree(root0) { 1.7070 + var root1 = { 1.7071 + A: null, 1.7072 + children: [ root0 ] 1.7073 + }, queue = [ root1 ], node1; 1.7074 + while ((node1 = queue.pop()) != null) { 1.7075 + for (var children = node1.children, child, i = 0, n = children.length; i < n; ++i) { 1.7076 + queue.push((children[i] = child = { 1.7077 + _: children[i], 1.7078 + parent: node1, 1.7079 + children: (child = children[i].children) && child.slice() || [], 1.7080 + A: null, 1.7081 + a: null, 1.7082 + z: 0, 1.7083 + m: 0, 1.7084 + c: 0, 1.7085 + s: 0, 1.7086 + t: null, 1.7087 + i: i 1.7088 + }).a = child); 1.7089 + } 1.7090 + } 1.7091 + return root1.children[0]; 1.7092 + } 1.7093 + function firstWalk(v) { 1.7094 + var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null; 1.7095 + if (children.length) { 1.7096 + d3_layout_treeShift(v); 1.7097 + var midpoint = (children[0].z + children[children.length - 1].z) / 2; 1.7098 + if (w) { 1.7099 + v.z = w.z + separation(v._, w._); 1.7100 + v.m = v.z - midpoint; 1.7101 + } else { 1.7102 + v.z = midpoint; 1.7103 + } 1.7104 + } else if (w) { 1.7105 + v.z = w.z + separation(v._, w._); 1.7106 + } 1.7107 + v.parent.A = apportion(v, w, v.parent.A || siblings[0]); 1.7108 + } 1.7109 + function secondWalk(v) { 1.7110 + v._.x = v.z + v.parent.m; 1.7111 + v.m += v.parent.m; 1.7112 + } 1.7113 + function apportion(v, w, ancestor) { 1.7114 + if (w) { 1.7115 + 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; 1.7116 + while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { 1.7117 + vom = d3_layout_treeLeft(vom); 1.7118 + vop = d3_layout_treeRight(vop); 1.7119 + vop.a = v; 1.7120 + shift = vim.z + sim - vip.z - sip + separation(vim._, vip._); 1.7121 + if (shift > 0) { 1.7122 + d3_layout_treeMove(d3_layout_treeAncestor(vim, v, ancestor), v, shift); 1.7123 + sip += shift; 1.7124 + sop += shift; 1.7125 + } 1.7126 + sim += vim.m; 1.7127 + sip += vip.m; 1.7128 + som += vom.m; 1.7129 + sop += vop.m; 1.7130 + } 1.7131 + if (vim && !d3_layout_treeRight(vop)) { 1.7132 + vop.t = vim; 1.7133 + vop.m += sim - sop; 1.7134 + } 1.7135 + if (vip && !d3_layout_treeLeft(vom)) { 1.7136 + vom.t = vip; 1.7137 + vom.m += sip - som; 1.7138 + ancestor = v; 1.7139 + } 1.7140 + } 1.7141 + return ancestor; 1.7142 + } 1.7143 + function sizeNode(node) { 1.7144 + node.x *= size[0]; 1.7145 + node.y = node.depth * size[1]; 1.7146 + } 1.7147 + tree.separation = function(x) { 1.7148 + if (!arguments.length) return separation; 1.7149 + separation = x; 1.7150 + return tree; 1.7151 + }; 1.7152 + tree.size = function(x) { 1.7153 + if (!arguments.length) return nodeSize ? null : size; 1.7154 + nodeSize = (size = x) == null ? sizeNode : null; 1.7155 + return tree; 1.7156 + }; 1.7157 + tree.nodeSize = function(x) { 1.7158 + if (!arguments.length) return nodeSize ? size : null; 1.7159 + nodeSize = (size = x) == null ? null : sizeNode; 1.7160 + return tree; 1.7161 + }; 1.7162 + return d3_layout_hierarchyRebind(tree, hierarchy); 1.7163 + }; 1.7164 + function d3_layout_treeSeparation(a, b) { 1.7165 + return a.parent == b.parent ? 1 : 2; 1.7166 + } 1.7167 + function d3_layout_treeLeft(v) { 1.7168 + var children = v.children; 1.7169 + return children.length ? children[0] : v.t; 1.7170 + } 1.7171 + function d3_layout_treeRight(v) { 1.7172 + var children = v.children, n; 1.7173 + return (n = children.length) ? children[n - 1] : v.t; 1.7174 + } 1.7175 + function d3_layout_treeMove(wm, wp, shift) { 1.7176 + var change = shift / (wp.i - wm.i); 1.7177 + wp.c -= change; 1.7178 + wp.s += shift; 1.7179 + wm.c += change; 1.7180 + wp.z += shift; 1.7181 + wp.m += shift; 1.7182 + } 1.7183 + function d3_layout_treeShift(v) { 1.7184 + var shift = 0, change = 0, children = v.children, i = children.length, w; 1.7185 + while (--i >= 0) { 1.7186 + w = children[i]; 1.7187 + w.z += shift; 1.7188 + w.m += shift; 1.7189 + shift += w.s + (change += w.c); 1.7190 + } 1.7191 + } 1.7192 + function d3_layout_treeAncestor(vim, v, ancestor) { 1.7193 + return vim.a.parent === v.parent ? vim.a : ancestor; 1.7194 + } 1.7195 + d3.layout.cluster = function() { 1.7196 + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; 1.7197 + function cluster(d, i) { 1.7198 + var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; 1.7199 + d3_layout_hierarchyVisitAfter(root, function(node) { 1.7200 + var children = node.children; 1.7201 + if (children && children.length) { 1.7202 + node.x = d3_layout_clusterX(children); 1.7203 + node.y = d3_layout_clusterY(children); 1.7204 + } else { 1.7205 + node.x = previousNode ? x += separation(node, previousNode) : 0; 1.7206 + node.y = 0; 1.7207 + previousNode = node; 1.7208 + } 1.7209 + }); 1.7210 + var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; 1.7211 + d3_layout_hierarchyVisitAfter(root, nodeSize ? function(node) { 1.7212 + node.x = (node.x - root.x) * size[0]; 1.7213 + node.y = (root.y - node.y) * size[1]; 1.7214 + } : function(node) { 1.7215 + node.x = (node.x - x0) / (x1 - x0) * size[0]; 1.7216 + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; 1.7217 + }); 1.7218 + return nodes; 1.7219 + } 1.7220 + cluster.separation = function(x) { 1.7221 + if (!arguments.length) return separation; 1.7222 + separation = x; 1.7223 + return cluster; 1.7224 + }; 1.7225 + cluster.size = function(x) { 1.7226 + if (!arguments.length) return nodeSize ? null : size; 1.7227 + nodeSize = (size = x) == null; 1.7228 + return cluster; 1.7229 + }; 1.7230 + cluster.nodeSize = function(x) { 1.7231 + if (!arguments.length) return nodeSize ? size : null; 1.7232 + nodeSize = (size = x) != null; 1.7233 + return cluster; 1.7234 + }; 1.7235 + return d3_layout_hierarchyRebind(cluster, hierarchy); 1.7236 + }; 1.7237 + function d3_layout_clusterY(children) { 1.7238 + return 1 + d3.max(children, function(child) { 1.7239 + return child.y; 1.7240 + }); 1.7241 + } 1.7242 + function d3_layout_clusterX(children) { 1.7243 + return children.reduce(function(x, child) { 1.7244 + return x + child.x; 1.7245 + }, 0) / children.length; 1.7246 + } 1.7247 + function d3_layout_clusterLeft(node) { 1.7248 + var children = node.children; 1.7249 + return children && children.length ? d3_layout_clusterLeft(children[0]) : node; 1.7250 + } 1.7251 + function d3_layout_clusterRight(node) { 1.7252 + var children = node.children, n; 1.7253 + return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; 1.7254 + } 1.7255 + d3.layout.treemap = function() { 1.7256 + var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); 1.7257 + function scale(children, k) { 1.7258 + var i = -1, n = children.length, child, area; 1.7259 + while (++i < n) { 1.7260 + area = (child = children[i]).value * (k < 0 ? 0 : k); 1.7261 + child.area = isNaN(area) || area <= 0 ? 0 : area; 1.7262 + } 1.7263 + } 1.7264 + function squarify(node) { 1.7265 + var children = node.children; 1.7266 + if (children && children.length) { 1.7267 + var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; 1.7268 + scale(remaining, rect.dx * rect.dy / node.value); 1.7269 + row.area = 0; 1.7270 + while ((n = remaining.length) > 0) { 1.7271 + row.push(child = remaining[n - 1]); 1.7272 + row.area += child.area; 1.7273 + if (mode !== "squarify" || (score = worst(row, u)) <= best) { 1.7274 + remaining.pop(); 1.7275 + best = score; 1.7276 + } else { 1.7277 + row.area -= row.pop().area; 1.7278 + position(row, u, rect, false); 1.7279 + u = Math.min(rect.dx, rect.dy); 1.7280 + row.length = row.area = 0; 1.7281 + best = Infinity; 1.7282 + } 1.7283 + } 1.7284 + if (row.length) { 1.7285 + position(row, u, rect, true); 1.7286 + row.length = row.area = 0; 1.7287 + } 1.7288 + children.forEach(squarify); 1.7289 + } 1.7290 + } 1.7291 + function stickify(node) { 1.7292 + var children = node.children; 1.7293 + if (children && children.length) { 1.7294 + var rect = pad(node), remaining = children.slice(), child, row = []; 1.7295 + scale(remaining, rect.dx * rect.dy / node.value); 1.7296 + row.area = 0; 1.7297 + while (child = remaining.pop()) { 1.7298 + row.push(child); 1.7299 + row.area += child.area; 1.7300 + if (child.z != null) { 1.7301 + position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); 1.7302 + row.length = row.area = 0; 1.7303 + } 1.7304 + } 1.7305 + children.forEach(stickify); 1.7306 + } 1.7307 + } 1.7308 + function worst(row, u) { 1.7309 + var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; 1.7310 + while (++i < n) { 1.7311 + if (!(r = row[i].area)) continue; 1.7312 + if (r < rmin) rmin = r; 1.7313 + if (r > rmax) rmax = r; 1.7314 + } 1.7315 + s *= s; 1.7316 + u *= u; 1.7317 + return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; 1.7318 + } 1.7319 + function position(row, u, rect, flush) { 1.7320 + var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; 1.7321 + if (u == rect.dx) { 1.7322 + if (flush || v > rect.dy) v = rect.dy; 1.7323 + while (++i < n) { 1.7324 + o = row[i]; 1.7325 + o.x = x; 1.7326 + o.y = y; 1.7327 + o.dy = v; 1.7328 + x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); 1.7329 + } 1.7330 + o.z = true; 1.7331 + o.dx += rect.x + rect.dx - x; 1.7332 + rect.y += v; 1.7333 + rect.dy -= v; 1.7334 + } else { 1.7335 + if (flush || v > rect.dx) v = rect.dx; 1.7336 + while (++i < n) { 1.7337 + o = row[i]; 1.7338 + o.x = x; 1.7339 + o.y = y; 1.7340 + o.dx = v; 1.7341 + y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); 1.7342 + } 1.7343 + o.z = false; 1.7344 + o.dy += rect.y + rect.dy - y; 1.7345 + rect.x += v; 1.7346 + rect.dx -= v; 1.7347 + } 1.7348 + } 1.7349 + function treemap(d) { 1.7350 + var nodes = stickies || hierarchy(d), root = nodes[0]; 1.7351 + root.x = root.y = 0; 1.7352 + if (root.value) root.dx = size[0], root.dy = size[1]; else root.dx = root.dy = 0; 1.7353 + if (stickies) hierarchy.revalue(root); 1.7354 + scale([ root ], root.dx * root.dy / root.value); 1.7355 + (stickies ? stickify : squarify)(root); 1.7356 + if (sticky) stickies = nodes; 1.7357 + return nodes; 1.7358 + } 1.7359 + treemap.size = function(x) { 1.7360 + if (!arguments.length) return size; 1.7361 + size = x; 1.7362 + return treemap; 1.7363 + }; 1.7364 + treemap.padding = function(x) { 1.7365 + if (!arguments.length) return padding; 1.7366 + function padFunction(node) { 1.7367 + var p = x.call(treemap, node, node.depth); 1.7368 + return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); 1.7369 + } 1.7370 + function padConstant(node) { 1.7371 + return d3_layout_treemapPad(node, x); 1.7372 + } 1.7373 + var type; 1.7374 + pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], 1.7375 + padConstant) : padConstant; 1.7376 + return treemap; 1.7377 + }; 1.7378 + treemap.round = function(x) { 1.7379 + if (!arguments.length) return round != Number; 1.7380 + round = x ? Math.round : Number; 1.7381 + return treemap; 1.7382 + }; 1.7383 + treemap.sticky = function(x) { 1.7384 + if (!arguments.length) return sticky; 1.7385 + sticky = x; 1.7386 + stickies = null; 1.7387 + return treemap; 1.7388 + }; 1.7389 + treemap.ratio = function(x) { 1.7390 + if (!arguments.length) return ratio; 1.7391 + ratio = x; 1.7392 + return treemap; 1.7393 + }; 1.7394 + treemap.mode = function(x) { 1.7395 + if (!arguments.length) return mode; 1.7396 + mode = x + ""; 1.7397 + return treemap; 1.7398 + }; 1.7399 + return d3_layout_hierarchyRebind(treemap, hierarchy); 1.7400 + }; 1.7401 + function d3_layout_treemapPadNull(node) { 1.7402 + return { 1.7403 + x: node.x, 1.7404 + y: node.y, 1.7405 + dx: node.dx, 1.7406 + dy: node.dy 1.7407 + }; 1.7408 + } 1.7409 + function d3_layout_treemapPad(node, padding) { 1.7410 + var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; 1.7411 + if (dx < 0) { 1.7412 + x += dx / 2; 1.7413 + dx = 0; 1.7414 + } 1.7415 + if (dy < 0) { 1.7416 + y += dy / 2; 1.7417 + dy = 0; 1.7418 + } 1.7419 + return { 1.7420 + x: x, 1.7421 + y: y, 1.7422 + dx: dx, 1.7423 + dy: dy 1.7424 + }; 1.7425 + } 1.7426 + d3.random = { 1.7427 + normal: function(µ, σ) { 1.7428 + var n = arguments.length; 1.7429 + if (n < 2) σ = 1; 1.7430 + if (n < 1) µ = 0; 1.7431 + return function() { 1.7432 + var x, y, r; 1.7433 + do { 1.7434 + x = Math.random() * 2 - 1; 1.7435 + y = Math.random() * 2 - 1; 1.7436 + r = x * x + y * y; 1.7437 + } while (!r || r > 1); 1.7438 + return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); 1.7439 + }; 1.7440 + }, 1.7441 + logNormal: function() { 1.7442 + var random = d3.random.normal.apply(d3, arguments); 1.7443 + return function() { 1.7444 + return Math.exp(random()); 1.7445 + }; 1.7446 + }, 1.7447 + bates: function(m) { 1.7448 + var random = d3.random.irwinHall(m); 1.7449 + return function() { 1.7450 + return random() / m; 1.7451 + }; 1.7452 + }, 1.7453 + irwinHall: function(m) { 1.7454 + return function() { 1.7455 + for (var s = 0, j = 0; j < m; j++) s += Math.random(); 1.7456 + return s; 1.7457 + }; 1.7458 + } 1.7459 + }; 1.7460 + d3.scale = {}; 1.7461 + function d3_scaleExtent(domain) { 1.7462 + var start = domain[0], stop = domain[domain.length - 1]; 1.7463 + return start < stop ? [ start, stop ] : [ stop, start ]; 1.7464 + } 1.7465 + function d3_scaleRange(scale) { 1.7466 + return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); 1.7467 + } 1.7468 + function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { 1.7469 + var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); 1.7470 + return function(x) { 1.7471 + return i(u(x)); 1.7472 + }; 1.7473 + } 1.7474 + function d3_scale_nice(domain, nice) { 1.7475 + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; 1.7476 + if (x1 < x0) { 1.7477 + dx = i0, i0 = i1, i1 = dx; 1.7478 + dx = x0, x0 = x1, x1 = dx; 1.7479 + } 1.7480 + domain[i0] = nice.floor(x0); 1.7481 + domain[i1] = nice.ceil(x1); 1.7482 + return domain; 1.7483 + } 1.7484 + function d3_scale_niceStep(step) { 1.7485 + return step ? { 1.7486 + floor: function(x) { 1.7487 + return Math.floor(x / step) * step; 1.7488 + }, 1.7489 + ceil: function(x) { 1.7490 + return Math.ceil(x / step) * step; 1.7491 + } 1.7492 + } : d3_scale_niceIdentity; 1.7493 + } 1.7494 + var d3_scale_niceIdentity = { 1.7495 + floor: d3_identity, 1.7496 + ceil: d3_identity 1.7497 + }; 1.7498 + function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { 1.7499 + var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; 1.7500 + if (domain[k] < domain[0]) { 1.7501 + domain = domain.slice().reverse(); 1.7502 + range = range.slice().reverse(); 1.7503 + } 1.7504 + while (++j <= k) { 1.7505 + u.push(uninterpolate(domain[j - 1], domain[j])); 1.7506 + i.push(interpolate(range[j - 1], range[j])); 1.7507 + } 1.7508 + return function(x) { 1.7509 + var j = d3.bisect(domain, x, 1, k) - 1; 1.7510 + return i[j](u[j](x)); 1.7511 + }; 1.7512 + } 1.7513 + d3.scale.linear = function() { 1.7514 + return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); 1.7515 + }; 1.7516 + function d3_scale_linear(domain, range, interpolate, clamp) { 1.7517 + var output, input; 1.7518 + function rescale() { 1.7519 + var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; 1.7520 + output = linear(domain, range, uninterpolate, interpolate); 1.7521 + input = linear(range, domain, uninterpolate, d3_interpolate); 1.7522 + return scale; 1.7523 + } 1.7524 + function scale(x) { 1.7525 + return output(x); 1.7526 + } 1.7527 + scale.invert = function(y) { 1.7528 + return input(y); 1.7529 + }; 1.7530 + scale.domain = function(x) { 1.7531 + if (!arguments.length) return domain; 1.7532 + domain = x.map(Number); 1.7533 + return rescale(); 1.7534 + }; 1.7535 + scale.range = function(x) { 1.7536 + if (!arguments.length) return range; 1.7537 + range = x; 1.7538 + return rescale(); 1.7539 + }; 1.7540 + scale.rangeRound = function(x) { 1.7541 + return scale.range(x).interpolate(d3_interpolateRound); 1.7542 + }; 1.7543 + scale.clamp = function(x) { 1.7544 + if (!arguments.length) return clamp; 1.7545 + clamp = x; 1.7546 + return rescale(); 1.7547 + }; 1.7548 + scale.interpolate = function(x) { 1.7549 + if (!arguments.length) return interpolate; 1.7550 + interpolate = x; 1.7551 + return rescale(); 1.7552 + }; 1.7553 + scale.ticks = function(m) { 1.7554 + return d3_scale_linearTicks(domain, m); 1.7555 + }; 1.7556 + scale.tickFormat = function(m, format) { 1.7557 + return d3_scale_linearTickFormat(domain, m, format); 1.7558 + }; 1.7559 + scale.nice = function(m) { 1.7560 + d3_scale_linearNice(domain, m); 1.7561 + return rescale(); 1.7562 + }; 1.7563 + scale.copy = function() { 1.7564 + return d3_scale_linear(domain, range, interpolate, clamp); 1.7565 + }; 1.7566 + return rescale(); 1.7567 + } 1.7568 + function d3_scale_linearRebind(scale, linear) { 1.7569 + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); 1.7570 + } 1.7571 + function d3_scale_linearNice(domain, m) { 1.7572 + d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); 1.7573 + d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); 1.7574 + return domain; 1.7575 + } 1.7576 + function d3_scale_linearTickRange(domain, m) { 1.7577 + if (m == null) m = 10; 1.7578 + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; 1.7579 + if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; 1.7580 + extent[0] = Math.ceil(extent[0] / step) * step; 1.7581 + extent[1] = Math.floor(extent[1] / step) * step + step * .5; 1.7582 + extent[2] = step; 1.7583 + return extent; 1.7584 + } 1.7585 + function d3_scale_linearTicks(domain, m) { 1.7586 + return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); 1.7587 + } 1.7588 + function d3_scale_linearTickFormat(domain, m, format) { 1.7589 + var range = d3_scale_linearTickRange(domain, m); 1.7590 + if (format) { 1.7591 + var match = d3_format_re.exec(format); 1.7592 + match.shift(); 1.7593 + if (match[8] === "s") { 1.7594 + var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1]))); 1.7595 + if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2])); 1.7596 + match[8] = "f"; 1.7597 + format = d3.format(match.join("")); 1.7598 + return function(d) { 1.7599 + return format(prefix.scale(d)) + prefix.symbol; 1.7600 + }; 1.7601 + } 1.7602 + if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range); 1.7603 + format = match.join(""); 1.7604 + } else { 1.7605 + format = ",." + d3_scale_linearPrecision(range[2]) + "f"; 1.7606 + } 1.7607 + return d3.format(format); 1.7608 + } 1.7609 + var d3_scale_linearFormatSignificant = { 1.7610 + s: 1, 1.7611 + g: 1, 1.7612 + p: 1, 1.7613 + r: 1, 1.7614 + e: 1 1.7615 + }; 1.7616 + function d3_scale_linearPrecision(value) { 1.7617 + return -Math.floor(Math.log(value) / Math.LN10 + .01); 1.7618 + } 1.7619 + function d3_scale_linearFormatPrecision(type, range) { 1.7620 + var p = d3_scale_linearPrecision(range[2]); 1.7621 + return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== "e") : p - (type === "%") * 2; 1.7622 + } 1.7623 + d3.scale.log = function() { 1.7624 + return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); 1.7625 + }; 1.7626 + function d3_scale_log(linear, base, positive, domain) { 1.7627 + function log(x) { 1.7628 + return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); 1.7629 + } 1.7630 + function pow(x) { 1.7631 + return positive ? Math.pow(base, x) : -Math.pow(base, -x); 1.7632 + } 1.7633 + function scale(x) { 1.7634 + return linear(log(x)); 1.7635 + } 1.7636 + scale.invert = function(x) { 1.7637 + return pow(linear.invert(x)); 1.7638 + }; 1.7639 + scale.domain = function(x) { 1.7640 + if (!arguments.length) return domain; 1.7641 + positive = x[0] >= 0; 1.7642 + linear.domain((domain = x.map(Number)).map(log)); 1.7643 + return scale; 1.7644 + }; 1.7645 + scale.base = function(_) { 1.7646 + if (!arguments.length) return base; 1.7647 + base = +_; 1.7648 + linear.domain(domain.map(log)); 1.7649 + return scale; 1.7650 + }; 1.7651 + scale.nice = function() { 1.7652 + var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); 1.7653 + linear.domain(niced); 1.7654 + domain = niced.map(pow); 1.7655 + return scale; 1.7656 + }; 1.7657 + scale.ticks = function() { 1.7658 + var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; 1.7659 + if (isFinite(j - i)) { 1.7660 + if (positive) { 1.7661 + for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); 1.7662 + ticks.push(pow(i)); 1.7663 + } else { 1.7664 + ticks.push(pow(i)); 1.7665 + for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); 1.7666 + } 1.7667 + for (i = 0; ticks[i] < u; i++) {} 1.7668 + for (j = ticks.length; ticks[j - 1] > v; j--) {} 1.7669 + ticks = ticks.slice(i, j); 1.7670 + } 1.7671 + return ticks; 1.7672 + }; 1.7673 + scale.tickFormat = function(n, format) { 1.7674 + if (!arguments.length) return d3_scale_logFormat; 1.7675 + if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); 1.7676 + var k = Math.max(1, base * n / scale.ticks().length); 1.7677 + return function(d) { 1.7678 + var i = d / pow(Math.round(log(d))); 1.7679 + if (i * base < base - .5) i *= base; 1.7680 + return i <= k ? format(d) : ""; 1.7681 + }; 1.7682 + }; 1.7683 + scale.copy = function() { 1.7684 + return d3_scale_log(linear.copy(), base, positive, domain); 1.7685 + }; 1.7686 + return d3_scale_linearRebind(scale, linear); 1.7687 + } 1.7688 + var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { 1.7689 + floor: function(x) { 1.7690 + return -Math.ceil(-x); 1.7691 + }, 1.7692 + ceil: function(x) { 1.7693 + return -Math.floor(-x); 1.7694 + } 1.7695 + }; 1.7696 + d3.scale.pow = function() { 1.7697 + return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); 1.7698 + }; 1.7699 + function d3_scale_pow(linear, exponent, domain) { 1.7700 + var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); 1.7701 + function scale(x) { 1.7702 + return linear(powp(x)); 1.7703 + } 1.7704 + scale.invert = function(x) { 1.7705 + return powb(linear.invert(x)); 1.7706 + }; 1.7707 + scale.domain = function(x) { 1.7708 + if (!arguments.length) return domain; 1.7709 + linear.domain((domain = x.map(Number)).map(powp)); 1.7710 + return scale; 1.7711 + }; 1.7712 + scale.ticks = function(m) { 1.7713 + return d3_scale_linearTicks(domain, m); 1.7714 + }; 1.7715 + scale.tickFormat = function(m, format) { 1.7716 + return d3_scale_linearTickFormat(domain, m, format); 1.7717 + }; 1.7718 + scale.nice = function(m) { 1.7719 + return scale.domain(d3_scale_linearNice(domain, m)); 1.7720 + }; 1.7721 + scale.exponent = function(x) { 1.7722 + if (!arguments.length) return exponent; 1.7723 + powp = d3_scale_powPow(exponent = x); 1.7724 + powb = d3_scale_powPow(1 / exponent); 1.7725 + linear.domain(domain.map(powp)); 1.7726 + return scale; 1.7727 + }; 1.7728 + scale.copy = function() { 1.7729 + return d3_scale_pow(linear.copy(), exponent, domain); 1.7730 + }; 1.7731 + return d3_scale_linearRebind(scale, linear); 1.7732 + } 1.7733 + function d3_scale_powPow(e) { 1.7734 + return function(x) { 1.7735 + return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); 1.7736 + }; 1.7737 + } 1.7738 + d3.scale.sqrt = function() { 1.7739 + return d3.scale.pow().exponent(.5); 1.7740 + }; 1.7741 + d3.scale.ordinal = function() { 1.7742 + return d3_scale_ordinal([], { 1.7743 + t: "range", 1.7744 + a: [ [] ] 1.7745 + }); 1.7746 + }; 1.7747 + function d3_scale_ordinal(domain, ranger) { 1.7748 + var index, range, rangeBand; 1.7749 + function scale(x) { 1.7750 + return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length]; 1.7751 + } 1.7752 + function steps(start, step) { 1.7753 + return d3.range(domain.length).map(function(i) { 1.7754 + return start + step * i; 1.7755 + }); 1.7756 + } 1.7757 + scale.domain = function(x) { 1.7758 + if (!arguments.length) return domain; 1.7759 + domain = []; 1.7760 + index = new d3_Map(); 1.7761 + var i = -1, n = x.length, xi; 1.7762 + while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); 1.7763 + return scale[ranger.t].apply(scale, ranger.a); 1.7764 + }; 1.7765 + scale.range = function(x) { 1.7766 + if (!arguments.length) return range; 1.7767 + range = x; 1.7768 + rangeBand = 0; 1.7769 + ranger = { 1.7770 + t: "range", 1.7771 + a: arguments 1.7772 + }; 1.7773 + return scale; 1.7774 + }; 1.7775 + scale.rangePoints = function(x, padding) { 1.7776 + if (arguments.length < 2) padding = 0; 1.7777 + var start = x[0], stop = x[1], step = domain.length < 2 ? (start = (start + stop) / 2, 1.7778 + 0) : (stop - start) / (domain.length - 1 + padding); 1.7779 + range = steps(start + step * padding / 2, step); 1.7780 + rangeBand = 0; 1.7781 + ranger = { 1.7782 + t: "rangePoints", 1.7783 + a: arguments 1.7784 + }; 1.7785 + return scale; 1.7786 + }; 1.7787 + scale.rangeRoundPoints = function(x, padding) { 1.7788 + if (arguments.length < 2) padding = 0; 1.7789 + var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2), 1.7790 + 0) : (stop - start) / (domain.length - 1 + padding) | 0; 1.7791 + range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step); 1.7792 + rangeBand = 0; 1.7793 + ranger = { 1.7794 + t: "rangeRoundPoints", 1.7795 + a: arguments 1.7796 + }; 1.7797 + return scale; 1.7798 + }; 1.7799 + scale.rangeBands = function(x, padding, outerPadding) { 1.7800 + if (arguments.length < 2) padding = 0; 1.7801 + if (arguments.length < 3) outerPadding = padding; 1.7802 + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); 1.7803 + range = steps(start + step * outerPadding, step); 1.7804 + if (reverse) range.reverse(); 1.7805 + rangeBand = step * (1 - padding); 1.7806 + ranger = { 1.7807 + t: "rangeBands", 1.7808 + a: arguments 1.7809 + }; 1.7810 + return scale; 1.7811 + }; 1.7812 + scale.rangeRoundBands = function(x, padding, outerPadding) { 1.7813 + if (arguments.length < 2) padding = 0; 1.7814 + if (arguments.length < 3) outerPadding = padding; 1.7815 + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)); 1.7816 + range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step); 1.7817 + if (reverse) range.reverse(); 1.7818 + rangeBand = Math.round(step * (1 - padding)); 1.7819 + ranger = { 1.7820 + t: "rangeRoundBands", 1.7821 + a: arguments 1.7822 + }; 1.7823 + return scale; 1.7824 + }; 1.7825 + scale.rangeBand = function() { 1.7826 + return rangeBand; 1.7827 + }; 1.7828 + scale.rangeExtent = function() { 1.7829 + return d3_scaleExtent(ranger.a[0]); 1.7830 + }; 1.7831 + scale.copy = function() { 1.7832 + return d3_scale_ordinal(domain, ranger); 1.7833 + }; 1.7834 + return scale.domain(domain); 1.7835 + } 1.7836 + d3.scale.category10 = function() { 1.7837 + return d3.scale.ordinal().range(d3_category10); 1.7838 + }; 1.7839 + d3.scale.category20 = function() { 1.7840 + return d3.scale.ordinal().range(d3_category20); 1.7841 + }; 1.7842 + d3.scale.category20b = function() { 1.7843 + return d3.scale.ordinal().range(d3_category20b); 1.7844 + }; 1.7845 + d3.scale.category20c = function() { 1.7846 + return d3.scale.ordinal().range(d3_category20c); 1.7847 + }; 1.7848 + var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); 1.7849 + var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); 1.7850 + var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); 1.7851 + var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); 1.7852 + d3.scale.quantile = function() { 1.7853 + return d3_scale_quantile([], []); 1.7854 + }; 1.7855 + function d3_scale_quantile(domain, range) { 1.7856 + var thresholds; 1.7857 + function rescale() { 1.7858 + var k = 0, q = range.length; 1.7859 + thresholds = []; 1.7860 + while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); 1.7861 + return scale; 1.7862 + } 1.7863 + function scale(x) { 1.7864 + if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; 1.7865 + } 1.7866 + scale.domain = function(x) { 1.7867 + if (!arguments.length) return domain; 1.7868 + domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending); 1.7869 + return rescale(); 1.7870 + }; 1.7871 + scale.range = function(x) { 1.7872 + if (!arguments.length) return range; 1.7873 + range = x; 1.7874 + return rescale(); 1.7875 + }; 1.7876 + scale.quantiles = function() { 1.7877 + return thresholds; 1.7878 + }; 1.7879 + scale.invertExtent = function(y) { 1.7880 + y = range.indexOf(y); 1.7881 + return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; 1.7882 + }; 1.7883 + scale.copy = function() { 1.7884 + return d3_scale_quantile(domain, range); 1.7885 + }; 1.7886 + return rescale(); 1.7887 + } 1.7888 + d3.scale.quantize = function() { 1.7889 + return d3_scale_quantize(0, 1, [ 0, 1 ]); 1.7890 + }; 1.7891 + function d3_scale_quantize(x0, x1, range) { 1.7892 + var kx, i; 1.7893 + function scale(x) { 1.7894 + return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; 1.7895 + } 1.7896 + function rescale() { 1.7897 + kx = range.length / (x1 - x0); 1.7898 + i = range.length - 1; 1.7899 + return scale; 1.7900 + } 1.7901 + scale.domain = function(x) { 1.7902 + if (!arguments.length) return [ x0, x1 ]; 1.7903 + x0 = +x[0]; 1.7904 + x1 = +x[x.length - 1]; 1.7905 + return rescale(); 1.7906 + }; 1.7907 + scale.range = function(x) { 1.7908 + if (!arguments.length) return range; 1.7909 + range = x; 1.7910 + return rescale(); 1.7911 + }; 1.7912 + scale.invertExtent = function(y) { 1.7913 + y = range.indexOf(y); 1.7914 + y = y < 0 ? NaN : y / kx + x0; 1.7915 + return [ y, y + 1 / kx ]; 1.7916 + }; 1.7917 + scale.copy = function() { 1.7918 + return d3_scale_quantize(x0, x1, range); 1.7919 + }; 1.7920 + return rescale(); 1.7921 + } 1.7922 + d3.scale.threshold = function() { 1.7923 + return d3_scale_threshold([ .5 ], [ 0, 1 ]); 1.7924 + }; 1.7925 + function d3_scale_threshold(domain, range) { 1.7926 + function scale(x) { 1.7927 + if (x <= x) return range[d3.bisect(domain, x)]; 1.7928 + } 1.7929 + scale.domain = function(_) { 1.7930 + if (!arguments.length) return domain; 1.7931 + domain = _; 1.7932 + return scale; 1.7933 + }; 1.7934 + scale.range = function(_) { 1.7935 + if (!arguments.length) return range; 1.7936 + range = _; 1.7937 + return scale; 1.7938 + }; 1.7939 + scale.invertExtent = function(y) { 1.7940 + y = range.indexOf(y); 1.7941 + return [ domain[y - 1], domain[y] ]; 1.7942 + }; 1.7943 + scale.copy = function() { 1.7944 + return d3_scale_threshold(domain, range); 1.7945 + }; 1.7946 + return scale; 1.7947 + } 1.7948 + d3.scale.identity = function() { 1.7949 + return d3_scale_identity([ 0, 1 ]); 1.7950 + }; 1.7951 + function d3_scale_identity(domain) { 1.7952 + function identity(x) { 1.7953 + return +x; 1.7954 + } 1.7955 + identity.invert = identity; 1.7956 + identity.domain = identity.range = function(x) { 1.7957 + if (!arguments.length) return domain; 1.7958 + domain = x.map(identity); 1.7959 + return identity; 1.7960 + }; 1.7961 + identity.ticks = function(m) { 1.7962 + return d3_scale_linearTicks(domain, m); 1.7963 + }; 1.7964 + identity.tickFormat = function(m, format) { 1.7965 + return d3_scale_linearTickFormat(domain, m, format); 1.7966 + }; 1.7967 + identity.copy = function() { 1.7968 + return d3_scale_identity(domain); 1.7969 + }; 1.7970 + return identity; 1.7971 + } 1.7972 + d3.svg = {}; 1.7973 + function d3_zero() { 1.7974 + return 0; 1.7975 + } 1.7976 + d3.svg.arc = function() { 1.7977 + var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, cornerRadius = d3_zero, padRadius = d3_svg_arcAuto, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle, padAngle = d3_svg_arcPadAngle; 1.7978 + function arc() { 1.7979 + var r0 = Math.max(0, +innerRadius.apply(this, arguments)), r1 = Math.max(0, +outerRadius.apply(this, arguments)), a0 = startAngle.apply(this, arguments) - halfπ, a1 = endAngle.apply(this, arguments) - halfπ, da = Math.abs(a1 - a0), cw = a0 > a1 ? 0 : 1; 1.7980 + if (r1 < r0) rc = r1, r1 = r0, r0 = rc; 1.7981 + if (da >= τε) return circleSegment(r1, cw) + (r0 ? circleSegment(r0, 1 - cw) : "") + "Z"; 1.7982 + var rc, cr, rp, ap, p0 = 0, p1 = 0, x0, y0, x1, y1, x2, y2, x3, y3, path = []; 1.7983 + if (ap = (+padAngle.apply(this, arguments) || 0) / 2) { 1.7984 + rp = padRadius === d3_svg_arcAuto ? Math.sqrt(r0 * r0 + r1 * r1) : +padRadius.apply(this, arguments); 1.7985 + if (!cw) p1 *= -1; 1.7986 + if (r1) p1 = d3_asin(rp / r1 * Math.sin(ap)); 1.7987 + if (r0) p0 = d3_asin(rp / r0 * Math.sin(ap)); 1.7988 + } 1.7989 + if (r1) { 1.7990 + x0 = r1 * Math.cos(a0 + p1); 1.7991 + y0 = r1 * Math.sin(a0 + p1); 1.7992 + x1 = r1 * Math.cos(a1 - p1); 1.7993 + y1 = r1 * Math.sin(a1 - p1); 1.7994 + var l1 = Math.abs(a1 - a0 - 2 * p1) <= π ? 0 : 1; 1.7995 + if (p1 && d3_svg_arcSweep(x0, y0, x1, y1) === cw ^ l1) { 1.7996 + var h1 = (a0 + a1) / 2; 1.7997 + x0 = r1 * Math.cos(h1); 1.7998 + y0 = r1 * Math.sin(h1); 1.7999 + x1 = y1 = null; 1.8000 + } 1.8001 + } else { 1.8002 + x0 = y0 = 0; 1.8003 + } 1.8004 + if (r0) { 1.8005 + x2 = r0 * Math.cos(a1 - p0); 1.8006 + y2 = r0 * Math.sin(a1 - p0); 1.8007 + x3 = r0 * Math.cos(a0 + p0); 1.8008 + y3 = r0 * Math.sin(a0 + p0); 1.8009 + var l0 = Math.abs(a0 - a1 + 2 * p0) <= π ? 0 : 1; 1.8010 + if (p0 && d3_svg_arcSweep(x2, y2, x3, y3) === 1 - cw ^ l0) { 1.8011 + var h0 = (a0 + a1) / 2; 1.8012 + x2 = r0 * Math.cos(h0); 1.8013 + y2 = r0 * Math.sin(h0); 1.8014 + x3 = y3 = null; 1.8015 + } 1.8016 + } else { 1.8017 + x2 = y2 = 0; 1.8018 + } 1.8019 + if (da > ε && (rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) { 1.8020 + cr = r0 < r1 ^ cw ? 0 : 1; 1.8021 + var rc1 = rc, rc0 = rc; 1.8022 + if (da < π) { 1.8023 + var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - 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]); 1.8024 + rc0 = Math.min(rc, (r0 - lc) / (kc - 1)); 1.8025 + rc1 = Math.min(rc, (r1 - lc) / (kc + 1)); 1.8026 + } 1.8027 + if (x1 != null) { 1.8028 + var t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw); 1.8029 + if (rc === rc1) { 1.8030 + path.push("M", t30[0], "A", rc1, ",", rc1, " 0 0,", cr, " ", t30[1], "A", r1, ",", r1, " 0 ", 1 - cw ^ d3_svg_arcSweep(t30[1][0], t30[1][1], t12[1][0], t12[1][1]), ",", cw, " ", t12[1], "A", rc1, ",", rc1, " 0 0,", cr, " ", t12[0]); 1.8031 + } else { 1.8032 + path.push("M", t30[0], "A", rc1, ",", rc1, " 0 1,", cr, " ", t12[0]); 1.8033 + } 1.8034 + } else { 1.8035 + path.push("M", x0, ",", y0); 1.8036 + } 1.8037 + if (x3 != null) { 1.8038 + var t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw); 1.8039 + if (rc === rc0) { 1.8040 + path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t21[1], "A", r0, ",", r0, " 0 ", cw ^ d3_svg_arcSweep(t21[1][0], t21[1][1], t03[1][0], t03[1][1]), ",", 1 - cw, " ", t03[1], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]); 1.8041 + } else { 1.8042 + path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]); 1.8043 + } 1.8044 + } else { 1.8045 + path.push("L", x2, ",", y2); 1.8046 + } 1.8047 + } else { 1.8048 + path.push("M", x0, ",", y0); 1.8049 + if (x1 != null) path.push("A", r1, ",", r1, " 0 ", l1, ",", cw, " ", x1, ",", y1); 1.8050 + path.push("L", x2, ",", y2); 1.8051 + if (x3 != null) path.push("A", r0, ",", r0, " 0 ", l0, ",", 1 - cw, " ", x3, ",", y3); 1.8052 + } 1.8053 + path.push("Z"); 1.8054 + return path.join(""); 1.8055 + } 1.8056 + function circleSegment(r1, cw) { 1.8057 + return "M0," + r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + -r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + r1; 1.8058 + } 1.8059 + arc.innerRadius = function(v) { 1.8060 + if (!arguments.length) return innerRadius; 1.8061 + innerRadius = d3_functor(v); 1.8062 + return arc; 1.8063 + }; 1.8064 + arc.outerRadius = function(v) { 1.8065 + if (!arguments.length) return outerRadius; 1.8066 + outerRadius = d3_functor(v); 1.8067 + return arc; 1.8068 + }; 1.8069 + arc.cornerRadius = function(v) { 1.8070 + if (!arguments.length) return cornerRadius; 1.8071 + cornerRadius = d3_functor(v); 1.8072 + return arc; 1.8073 + }; 1.8074 + arc.padRadius = function(v) { 1.8075 + if (!arguments.length) return padRadius; 1.8076 + padRadius = v == d3_svg_arcAuto ? d3_svg_arcAuto : d3_functor(v); 1.8077 + return arc; 1.8078 + }; 1.8079 + arc.startAngle = function(v) { 1.8080 + if (!arguments.length) return startAngle; 1.8081 + startAngle = d3_functor(v); 1.8082 + return arc; 1.8083 + }; 1.8084 + arc.endAngle = function(v) { 1.8085 + if (!arguments.length) return endAngle; 1.8086 + endAngle = d3_functor(v); 1.8087 + return arc; 1.8088 + }; 1.8089 + arc.padAngle = function(v) { 1.8090 + if (!arguments.length) return padAngle; 1.8091 + padAngle = d3_functor(v); 1.8092 + return arc; 1.8093 + }; 1.8094 + arc.centroid = function() { 1.8095 + var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - halfπ; 1.8096 + return [ Math.cos(a) * r, Math.sin(a) * r ]; 1.8097 + }; 1.8098 + return arc; 1.8099 + }; 1.8100 + var d3_svg_arcAuto = "auto"; 1.8101 + function d3_svg_arcInnerRadius(d) { 1.8102 + return d.innerRadius; 1.8103 + } 1.8104 + function d3_svg_arcOuterRadius(d) { 1.8105 + return d.outerRadius; 1.8106 + } 1.8107 + function d3_svg_arcStartAngle(d) { 1.8108 + return d.startAngle; 1.8109 + } 1.8110 + function d3_svg_arcEndAngle(d) { 1.8111 + return d.endAngle; 1.8112 + } 1.8113 + function d3_svg_arcPadAngle(d) { 1.8114 + return d && d.padAngle; 1.8115 + } 1.8116 + function d3_svg_arcSweep(x0, y0, x1, y1) { 1.8117 + return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1; 1.8118 + } 1.8119 + function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) { 1.8120 + var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, 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 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3; 1.8121 + if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1; 1.8122 + return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ]; 1.8123 + } 1.8124 + function d3_svg_line(projection) { 1.8125 + var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; 1.8126 + function line(data) { 1.8127 + var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); 1.8128 + function segment() { 1.8129 + segments.push("M", interpolate(projection(points), tension)); 1.8130 + } 1.8131 + while (++i < n) { 1.8132 + if (defined.call(this, d = data[i], i)) { 1.8133 + points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); 1.8134 + } else if (points.length) { 1.8135 + segment(); 1.8136 + points = []; 1.8137 + } 1.8138 + } 1.8139 + if (points.length) segment(); 1.8140 + return segments.length ? segments.join("") : null; 1.8141 + } 1.8142 + line.x = function(_) { 1.8143 + if (!arguments.length) return x; 1.8144 + x = _; 1.8145 + return line; 1.8146 + }; 1.8147 + line.y = function(_) { 1.8148 + if (!arguments.length) return y; 1.8149 + y = _; 1.8150 + return line; 1.8151 + }; 1.8152 + line.defined = function(_) { 1.8153 + if (!arguments.length) return defined; 1.8154 + defined = _; 1.8155 + return line; 1.8156 + }; 1.8157 + line.interpolate = function(_) { 1.8158 + if (!arguments.length) return interpolateKey; 1.8159 + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; 1.8160 + return line; 1.8161 + }; 1.8162 + line.tension = function(_) { 1.8163 + if (!arguments.length) return tension; 1.8164 + tension = _; 1.8165 + return line; 1.8166 + }; 1.8167 + return line; 1.8168 + } 1.8169 + d3.svg.line = function() { 1.8170 + return d3_svg_line(d3_identity); 1.8171 + }; 1.8172 + var d3_svg_lineInterpolators = d3.map({ 1.8173 + linear: d3_svg_lineLinear, 1.8174 + "linear-closed": d3_svg_lineLinearClosed, 1.8175 + step: d3_svg_lineStep, 1.8176 + "step-before": d3_svg_lineStepBefore, 1.8177 + "step-after": d3_svg_lineStepAfter, 1.8178 + basis: d3_svg_lineBasis, 1.8179 + "basis-open": d3_svg_lineBasisOpen, 1.8180 + "basis-closed": d3_svg_lineBasisClosed, 1.8181 + bundle: d3_svg_lineBundle, 1.8182 + cardinal: d3_svg_lineCardinal, 1.8183 + "cardinal-open": d3_svg_lineCardinalOpen, 1.8184 + "cardinal-closed": d3_svg_lineCardinalClosed, 1.8185 + monotone: d3_svg_lineMonotone 1.8186 + }); 1.8187 + d3_svg_lineInterpolators.forEach(function(key, value) { 1.8188 + value.key = key; 1.8189 + value.closed = /-closed$/.test(key); 1.8190 + }); 1.8191 + function d3_svg_lineLinear(points) { 1.8192 + return points.length > 1 ? points.join("L") : points + "Z"; 1.8193 + } 1.8194 + function d3_svg_lineLinearClosed(points) { 1.8195 + return points.join("L") + "Z"; 1.8196 + } 1.8197 + function d3_svg_lineStep(points) { 1.8198 + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; 1.8199 + while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); 1.8200 + if (n > 1) path.push("H", p[0]); 1.8201 + return path.join(""); 1.8202 + } 1.8203 + function d3_svg_lineStepBefore(points) { 1.8204 + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; 1.8205 + while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); 1.8206 + return path.join(""); 1.8207 + } 1.8208 + function d3_svg_lineStepAfter(points) { 1.8209 + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; 1.8210 + while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); 1.8211 + return path.join(""); 1.8212 + } 1.8213 + function d3_svg_lineCardinalOpen(points, tension) { 1.8214 + return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, -1), d3_svg_lineCardinalTangents(points, tension)); 1.8215 + } 1.8216 + function d3_svg_lineCardinalClosed(points, tension) { 1.8217 + return points.length < 3 ? d3_svg_lineLinearClosed(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), 1.8218 + points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); 1.8219 + } 1.8220 + function d3_svg_lineCardinal(points, tension) { 1.8221 + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); 1.8222 + } 1.8223 + function d3_svg_lineHermite(points, tangents) { 1.8224 + if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { 1.8225 + return d3_svg_lineLinear(points); 1.8226 + } 1.8227 + var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; 1.8228 + if (quad) { 1.8229 + path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; 1.8230 + p0 = points[1]; 1.8231 + pi = 2; 1.8232 + } 1.8233 + if (tangents.length > 1) { 1.8234 + t = tangents[1]; 1.8235 + p = points[pi]; 1.8236 + pi++; 1.8237 + path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; 1.8238 + for (var i = 2; i < tangents.length; i++, pi++) { 1.8239 + p = points[pi]; 1.8240 + t = tangents[i]; 1.8241 + path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; 1.8242 + } 1.8243 + } 1.8244 + if (quad) { 1.8245 + var lp = points[pi]; 1.8246 + path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; 1.8247 + } 1.8248 + return path; 1.8249 + } 1.8250 + function d3_svg_lineCardinalTangents(points, tension) { 1.8251 + var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; 1.8252 + while (++i < n) { 1.8253 + p0 = p1; 1.8254 + p1 = p2; 1.8255 + p2 = points[i]; 1.8256 + tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); 1.8257 + } 1.8258 + return tangents; 1.8259 + } 1.8260 + function d3_svg_lineBasis(points) { 1.8261 + if (points.length < 3) return d3_svg_lineLinear(points); 1.8262 + var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; 1.8263 + points.push(points[n - 1]); 1.8264 + while (++i <= n) { 1.8265 + pi = points[i]; 1.8266 + px.shift(); 1.8267 + px.push(pi[0]); 1.8268 + py.shift(); 1.8269 + py.push(pi[1]); 1.8270 + d3_svg_lineBasisBezier(path, px, py); 1.8271 + } 1.8272 + points.pop(); 1.8273 + path.push("L", pi); 1.8274 + return path.join(""); 1.8275 + } 1.8276 + function d3_svg_lineBasisOpen(points) { 1.8277 + if (points.length < 4) return d3_svg_lineLinear(points); 1.8278 + var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; 1.8279 + while (++i < 3) { 1.8280 + pi = points[i]; 1.8281 + px.push(pi[0]); 1.8282 + py.push(pi[1]); 1.8283 + } 1.8284 + path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); 1.8285 + --i; 1.8286 + while (++i < n) { 1.8287 + pi = points[i]; 1.8288 + px.shift(); 1.8289 + px.push(pi[0]); 1.8290 + py.shift(); 1.8291 + py.push(pi[1]); 1.8292 + d3_svg_lineBasisBezier(path, px, py); 1.8293 + } 1.8294 + return path.join(""); 1.8295 + } 1.8296 + function d3_svg_lineBasisClosed(points) { 1.8297 + var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; 1.8298 + while (++i < 4) { 1.8299 + pi = points[i % n]; 1.8300 + px.push(pi[0]); 1.8301 + py.push(pi[1]); 1.8302 + } 1.8303 + path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; 1.8304 + --i; 1.8305 + while (++i < m) { 1.8306 + pi = points[i % n]; 1.8307 + px.shift(); 1.8308 + px.push(pi[0]); 1.8309 + py.shift(); 1.8310 + py.push(pi[1]); 1.8311 + d3_svg_lineBasisBezier(path, px, py); 1.8312 + } 1.8313 + return path.join(""); 1.8314 + } 1.8315 + function d3_svg_lineBundle(points, tension) { 1.8316 + var n = points.length - 1; 1.8317 + if (n) { 1.8318 + var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; 1.8319 + while (++i <= n) { 1.8320 + p = points[i]; 1.8321 + t = i / n; 1.8322 + p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); 1.8323 + p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); 1.8324 + } 1.8325 + } 1.8326 + return d3_svg_lineBasis(points); 1.8327 + } 1.8328 + function d3_svg_lineDot4(a, b) { 1.8329 + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; 1.8330 + } 1.8331 + var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; 1.8332 + function d3_svg_lineBasisBezier(path, x, y) { 1.8333 + path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); 1.8334 + } 1.8335 + function d3_svg_lineSlope(p0, p1) { 1.8336 + return (p1[1] - p0[1]) / (p1[0] - p0[0]); 1.8337 + } 1.8338 + function d3_svg_lineFiniteDifferences(points) { 1.8339 + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); 1.8340 + while (++i < j) { 1.8341 + m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; 1.8342 + } 1.8343 + m[i] = d; 1.8344 + return m; 1.8345 + } 1.8346 + function d3_svg_lineMonotoneTangents(points) { 1.8347 + var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; 1.8348 + while (++i < j) { 1.8349 + d = d3_svg_lineSlope(points[i], points[i + 1]); 1.8350 + if (abs(d) < ε) { 1.8351 + m[i] = m[i + 1] = 0; 1.8352 + } else { 1.8353 + a = m[i] / d; 1.8354 + b = m[i + 1] / d; 1.8355 + s = a * a + b * b; 1.8356 + if (s > 9) { 1.8357 + s = d * 3 / Math.sqrt(s); 1.8358 + m[i] = s * a; 1.8359 + m[i + 1] = s * b; 1.8360 + } 1.8361 + } 1.8362 + } 1.8363 + i = -1; 1.8364 + while (++i <= j) { 1.8365 + s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); 1.8366 + tangents.push([ s || 0, m[i] * s || 0 ]); 1.8367 + } 1.8368 + return tangents; 1.8369 + } 1.8370 + function d3_svg_lineMonotone(points) { 1.8371 + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); 1.8372 + } 1.8373 + d3.svg.line.radial = function() { 1.8374 + var line = d3_svg_line(d3_svg_lineRadial); 1.8375 + line.radius = line.x, delete line.x; 1.8376 + line.angle = line.y, delete line.y; 1.8377 + return line; 1.8378 + }; 1.8379 + function d3_svg_lineRadial(points) { 1.8380 + var point, i = -1, n = points.length, r, a; 1.8381 + while (++i < n) { 1.8382 + point = points[i]; 1.8383 + r = point[0]; 1.8384 + a = point[1] - halfπ; 1.8385 + point[0] = r * Math.cos(a); 1.8386 + point[1] = r * Math.sin(a); 1.8387 + } 1.8388 + return points; 1.8389 + } 1.8390 + function d3_svg_area(projection) { 1.8391 + var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; 1.8392 + function area(data) { 1.8393 + var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { 1.8394 + return x; 1.8395 + } : d3_functor(x1), fy1 = y0 === y1 ? function() { 1.8396 + return y; 1.8397 + } : d3_functor(y1), x, y; 1.8398 + function segment() { 1.8399 + segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); 1.8400 + } 1.8401 + while (++i < n) { 1.8402 + if (defined.call(this, d = data[i], i)) { 1.8403 + points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); 1.8404 + points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); 1.8405 + } else if (points0.length) { 1.8406 + segment(); 1.8407 + points0 = []; 1.8408 + points1 = []; 1.8409 + } 1.8410 + } 1.8411 + if (points0.length) segment(); 1.8412 + return segments.length ? segments.join("") : null; 1.8413 + } 1.8414 + area.x = function(_) { 1.8415 + if (!arguments.length) return x1; 1.8416 + x0 = x1 = _; 1.8417 + return area; 1.8418 + }; 1.8419 + area.x0 = function(_) { 1.8420 + if (!arguments.length) return x0; 1.8421 + x0 = _; 1.8422 + return area; 1.8423 + }; 1.8424 + area.x1 = function(_) { 1.8425 + if (!arguments.length) return x1; 1.8426 + x1 = _; 1.8427 + return area; 1.8428 + }; 1.8429 + area.y = function(_) { 1.8430 + if (!arguments.length) return y1; 1.8431 + y0 = y1 = _; 1.8432 + return area; 1.8433 + }; 1.8434 + area.y0 = function(_) { 1.8435 + if (!arguments.length) return y0; 1.8436 + y0 = _; 1.8437 + return area; 1.8438 + }; 1.8439 + area.y1 = function(_) { 1.8440 + if (!arguments.length) return y1; 1.8441 + y1 = _; 1.8442 + return area; 1.8443 + }; 1.8444 + area.defined = function(_) { 1.8445 + if (!arguments.length) return defined; 1.8446 + defined = _; 1.8447 + return area; 1.8448 + }; 1.8449 + area.interpolate = function(_) { 1.8450 + if (!arguments.length) return interpolateKey; 1.8451 + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; 1.8452 + interpolateReverse = interpolate.reverse || interpolate; 1.8453 + L = interpolate.closed ? "M" : "L"; 1.8454 + return area; 1.8455 + }; 1.8456 + area.tension = function(_) { 1.8457 + if (!arguments.length) return tension; 1.8458 + tension = _; 1.8459 + return area; 1.8460 + }; 1.8461 + return area; 1.8462 + } 1.8463 + d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; 1.8464 + d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; 1.8465 + d3.svg.area = function() { 1.8466 + return d3_svg_area(d3_identity); 1.8467 + }; 1.8468 + d3.svg.area.radial = function() { 1.8469 + var area = d3_svg_area(d3_svg_lineRadial); 1.8470 + area.radius = area.x, delete area.x; 1.8471 + area.innerRadius = area.x0, delete area.x0; 1.8472 + area.outerRadius = area.x1, delete area.x1; 1.8473 + area.angle = area.y, delete area.y; 1.8474 + area.startAngle = area.y0, delete area.y0; 1.8475 + area.endAngle = area.y1, delete area.y1; 1.8476 + return area; 1.8477 + }; 1.8478 + d3.svg.chord = function() { 1.8479 + var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; 1.8480 + function chord(d, i) { 1.8481 + var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); 1.8482 + return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; 1.8483 + } 1.8484 + function subgroup(self, f, d, i) { 1.8485 + var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) - halfπ, a1 = endAngle.call(self, subgroup, i) - halfπ; 1.8486 + return { 1.8487 + r: r, 1.8488 + a0: a0, 1.8489 + a1: a1, 1.8490 + p0: [ r * Math.cos(a0), r * Math.sin(a0) ], 1.8491 + p1: [ r * Math.cos(a1), r * Math.sin(a1) ] 1.8492 + }; 1.8493 + } 1.8494 + function equals(a, b) { 1.8495 + return a.a0 == b.a0 && a.a1 == b.a1; 1.8496 + } 1.8497 + function arc(r, p, a) { 1.8498 + return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; 1.8499 + } 1.8500 + function curve(r0, p0, r1, p1) { 1.8501 + return "Q 0,0 " + p1; 1.8502 + } 1.8503 + chord.radius = function(v) { 1.8504 + if (!arguments.length) return radius; 1.8505 + radius = d3_functor(v); 1.8506 + return chord; 1.8507 + }; 1.8508 + chord.source = function(v) { 1.8509 + if (!arguments.length) return source; 1.8510 + source = d3_functor(v); 1.8511 + return chord; 1.8512 + }; 1.8513 + chord.target = function(v) { 1.8514 + if (!arguments.length) return target; 1.8515 + target = d3_functor(v); 1.8516 + return chord; 1.8517 + }; 1.8518 + chord.startAngle = function(v) { 1.8519 + if (!arguments.length) return startAngle; 1.8520 + startAngle = d3_functor(v); 1.8521 + return chord; 1.8522 + }; 1.8523 + chord.endAngle = function(v) { 1.8524 + if (!arguments.length) return endAngle; 1.8525 + endAngle = d3_functor(v); 1.8526 + return chord; 1.8527 + }; 1.8528 + return chord; 1.8529 + }; 1.8530 + function d3_svg_chordRadius(d) { 1.8531 + return d.radius; 1.8532 + } 1.8533 + d3.svg.diagonal = function() { 1.8534 + var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; 1.8535 + function diagonal(d, i) { 1.8536 + var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { 1.8537 + x: p0.x, 1.8538 + y: m 1.8539 + }, { 1.8540 + x: p3.x, 1.8541 + y: m 1.8542 + }, p3 ]; 1.8543 + p = p.map(projection); 1.8544 + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; 1.8545 + } 1.8546 + diagonal.source = function(x) { 1.8547 + if (!arguments.length) return source; 1.8548 + source = d3_functor(x); 1.8549 + return diagonal; 1.8550 + }; 1.8551 + diagonal.target = function(x) { 1.8552 + if (!arguments.length) return target; 1.8553 + target = d3_functor(x); 1.8554 + return diagonal; 1.8555 + }; 1.8556 + diagonal.projection = function(x) { 1.8557 + if (!arguments.length) return projection; 1.8558 + projection = x; 1.8559 + return diagonal; 1.8560 + }; 1.8561 + return diagonal; 1.8562 + }; 1.8563 + function d3_svg_diagonalProjection(d) { 1.8564 + return [ d.x, d.y ]; 1.8565 + } 1.8566 + d3.svg.diagonal.radial = function() { 1.8567 + var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; 1.8568 + diagonal.projection = function(x) { 1.8569 + return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; 1.8570 + }; 1.8571 + return diagonal; 1.8572 + }; 1.8573 + function d3_svg_diagonalRadialProjection(projection) { 1.8574 + return function() { 1.8575 + var d = projection.apply(this, arguments), r = d[0], a = d[1] - halfπ; 1.8576 + return [ r * Math.cos(a), r * Math.sin(a) ]; 1.8577 + }; 1.8578 + } 1.8579 + d3.svg.symbol = function() { 1.8580 + var type = d3_svg_symbolType, size = d3_svg_symbolSize; 1.8581 + function symbol(d, i) { 1.8582 + return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); 1.8583 + } 1.8584 + symbol.type = function(x) { 1.8585 + if (!arguments.length) return type; 1.8586 + type = d3_functor(x); 1.8587 + return symbol; 1.8588 + }; 1.8589 + symbol.size = function(x) { 1.8590 + if (!arguments.length) return size; 1.8591 + size = d3_functor(x); 1.8592 + return symbol; 1.8593 + }; 1.8594 + return symbol; 1.8595 + }; 1.8596 + function d3_svg_symbolSize() { 1.8597 + return 64; 1.8598 + } 1.8599 + function d3_svg_symbolType() { 1.8600 + return "circle"; 1.8601 + } 1.8602 + function d3_svg_symbolCircle(size) { 1.8603 + var r = Math.sqrt(size / π); 1.8604 + return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; 1.8605 + } 1.8606 + var d3_svg_symbols = d3.map({ 1.8607 + circle: d3_svg_symbolCircle, 1.8608 + cross: function(size) { 1.8609 + var r = Math.sqrt(size / 5) / 2; 1.8610 + return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; 1.8611 + }, 1.8612 + diamond: function(size) { 1.8613 + var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; 1.8614 + return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; 1.8615 + }, 1.8616 + square: function(size) { 1.8617 + var r = Math.sqrt(size) / 2; 1.8618 + return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; 1.8619 + }, 1.8620 + "triangle-down": function(size) { 1.8621 + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; 1.8622 + return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; 1.8623 + }, 1.8624 + "triangle-up": function(size) { 1.8625 + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; 1.8626 + return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; 1.8627 + } 1.8628 + }); 1.8629 + d3.svg.symbolTypes = d3_svg_symbols.keys(); 1.8630 + var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); 1.8631 + d3_selectionPrototype.transition = function(name) { 1.8632 + var id = d3_transitionInheritId || ++d3_transitionId, ns = d3_transitionNamespace(name), subgroups = [], subgroup, node, transition = d3_transitionInherit || { 1.8633 + time: Date.now(), 1.8634 + ease: d3_ease_cubicInOut, 1.8635 + delay: 0, 1.8636 + duration: 250 1.8637 + }; 1.8638 + for (var j = -1, m = this.length; ++j < m; ) { 1.8639 + subgroups.push(subgroup = []); 1.8640 + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { 1.8641 + if (node = group[i]) d3_transitionNode(node, i, ns, id, transition); 1.8642 + subgroup.push(node); 1.8643 + } 1.8644 + } 1.8645 + return d3_transition(subgroups, ns, id); 1.8646 + }; 1.8647 + d3_selectionPrototype.interrupt = function(name) { 1.8648 + return this.each(name == null ? d3_selection_interrupt : d3_selection_interruptNS(d3_transitionNamespace(name))); 1.8649 + }; 1.8650 + var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace()); 1.8651 + function d3_selection_interruptNS(ns) { 1.8652 + return function() { 1.8653 + var lock, activeId, active; 1.8654 + if ((lock = this[ns]) && (active = lock[activeId = lock.active])) { 1.8655 + active.timer.c = null; 1.8656 + active.timer.t = NaN; 1.8657 + if (--lock.count) delete lock[activeId]; else delete this[ns]; 1.8658 + lock.active += .5; 1.8659 + active.event && active.event.interrupt.call(this, this.__data__, active.index); 1.8660 + } 1.8661 + }; 1.8662 + } 1.8663 + function d3_transition(groups, ns, id) { 1.8664 + d3_subclass(groups, d3_transitionPrototype); 1.8665 + groups.namespace = ns; 1.8666 + groups.id = id; 1.8667 + return groups; 1.8668 + } 1.8669 + var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; 1.8670 + d3_transitionPrototype.call = d3_selectionPrototype.call; 1.8671 + d3_transitionPrototype.empty = d3_selectionPrototype.empty; 1.8672 + d3_transitionPrototype.node = d3_selectionPrototype.node; 1.8673 + d3_transitionPrototype.size = d3_selectionPrototype.size; 1.8674 + d3.transition = function(selection, name) { 1.8675 + return selection && selection.transition ? d3_transitionInheritId ? selection.transition(name) : selection : d3.selection().transition(selection); 1.8676 + }; 1.8677 + d3.transition.prototype = d3_transitionPrototype; 1.8678 + d3_transitionPrototype.select = function(selector) { 1.8679 + var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnode, node; 1.8680 + selector = d3_selection_selector(selector); 1.8681 + for (var j = -1, m = this.length; ++j < m; ) { 1.8682 + subgroups.push(subgroup = []); 1.8683 + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { 1.8684 + if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { 1.8685 + if ("__data__" in node) subnode.__data__ = node.__data__; 1.8686 + d3_transitionNode(subnode, i, ns, id, node[ns][id]); 1.8687 + subgroup.push(subnode); 1.8688 + } else { 1.8689 + subgroup.push(null); 1.8690 + } 1.8691 + } 1.8692 + } 1.8693 + return d3_transition(subgroups, ns, id); 1.8694 + }; 1.8695 + d3_transitionPrototype.selectAll = function(selector) { 1.8696 + var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnodes, node, subnode, transition; 1.8697 + selector = d3_selection_selectorAll(selector); 1.8698 + for (var j = -1, m = this.length; ++j < m; ) { 1.8699 + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { 1.8700 + if (node = group[i]) { 1.8701 + transition = node[ns][id]; 1.8702 + subnodes = selector.call(node, node.__data__, i, j); 1.8703 + subgroups.push(subgroup = []); 1.8704 + for (var k = -1, o = subnodes.length; ++k < o; ) { 1.8705 + if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition); 1.8706 + subgroup.push(subnode); 1.8707 + } 1.8708 + } 1.8709 + } 1.8710 + } 1.8711 + return d3_transition(subgroups, ns, id); 1.8712 + }; 1.8713 + d3_transitionPrototype.filter = function(filter) { 1.8714 + var subgroups = [], subgroup, group, node; 1.8715 + if (typeof filter !== "function") filter = d3_selection_filter(filter); 1.8716 + for (var j = 0, m = this.length; j < m; j++) { 1.8717 + subgroups.push(subgroup = []); 1.8718 + for (var group = this[j], i = 0, n = group.length; i < n; i++) { 1.8719 + if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { 1.8720 + subgroup.push(node); 1.8721 + } 1.8722 + } 1.8723 + } 1.8724 + return d3_transition(subgroups, this.namespace, this.id); 1.8725 + }; 1.8726 + d3_transitionPrototype.tween = function(name, tween) { 1.8727 + var id = this.id, ns = this.namespace; 1.8728 + if (arguments.length < 2) return this.node()[ns][id].tween.get(name); 1.8729 + return d3_selection_each(this, tween == null ? function(node) { 1.8730 + node[ns][id].tween.remove(name); 1.8731 + } : function(node) { 1.8732 + node[ns][id].tween.set(name, tween); 1.8733 + }); 1.8734 + }; 1.8735 + function d3_transition_tween(groups, name, value, tween) { 1.8736 + var id = groups.id, ns = groups.namespace; 1.8737 + return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { 1.8738 + node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j))); 1.8739 + } : (value = tween(value), function(node) { 1.8740 + node[ns][id].tween.set(name, value); 1.8741 + })); 1.8742 + } 1.8743 + d3_transitionPrototype.attr = function(nameNS, value) { 1.8744 + if (arguments.length < 2) { 1.8745 + for (value in nameNS) this.attr(value, nameNS[value]); 1.8746 + return this; 1.8747 + } 1.8748 + var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); 1.8749 + function attrNull() { 1.8750 + this.removeAttribute(name); 1.8751 + } 1.8752 + function attrNullNS() { 1.8753 + this.removeAttributeNS(name.space, name.local); 1.8754 + } 1.8755 + function attrTween(b) { 1.8756 + return b == null ? attrNull : (b += "", function() { 1.8757 + var a = this.getAttribute(name), i; 1.8758 + return a !== b && (i = interpolate(a, b), function(t) { 1.8759 + this.setAttribute(name, i(t)); 1.8760 + }); 1.8761 + }); 1.8762 + } 1.8763 + function attrTweenNS(b) { 1.8764 + return b == null ? attrNullNS : (b += "", function() { 1.8765 + var a = this.getAttributeNS(name.space, name.local), i; 1.8766 + return a !== b && (i = interpolate(a, b), function(t) { 1.8767 + this.setAttributeNS(name.space, name.local, i(t)); 1.8768 + }); 1.8769 + }); 1.8770 + } 1.8771 + return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); 1.8772 + }; 1.8773 + d3_transitionPrototype.attrTween = function(nameNS, tween) { 1.8774 + var name = d3.ns.qualify(nameNS); 1.8775 + function attrTween(d, i) { 1.8776 + var f = tween.call(this, d, i, this.getAttribute(name)); 1.8777 + return f && function(t) { 1.8778 + this.setAttribute(name, f(t)); 1.8779 + }; 1.8780 + } 1.8781 + function attrTweenNS(d, i) { 1.8782 + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); 1.8783 + return f && function(t) { 1.8784 + this.setAttributeNS(name.space, name.local, f(t)); 1.8785 + }; 1.8786 + } 1.8787 + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); 1.8788 + }; 1.8789 + d3_transitionPrototype.style = function(name, value, priority) { 1.8790 + var n = arguments.length; 1.8791 + if (n < 3) { 1.8792 + if (typeof name !== "string") { 1.8793 + if (n < 2) value = ""; 1.8794 + for (priority in name) this.style(priority, name[priority], value); 1.8795 + return this; 1.8796 + } 1.8797 + priority = ""; 1.8798 + } 1.8799 + function styleNull() { 1.8800 + this.style.removeProperty(name); 1.8801 + } 1.8802 + function styleString(b) { 1.8803 + return b == null ? styleNull : (b += "", function() { 1.8804 + var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i; 1.8805 + return a !== b && (i = d3_interpolate(a, b), function(t) { 1.8806 + this.style.setProperty(name, i(t), priority); 1.8807 + }); 1.8808 + }); 1.8809 + } 1.8810 + return d3_transition_tween(this, "style." + name, value, styleString); 1.8811 + }; 1.8812 + d3_transitionPrototype.styleTween = function(name, tween, priority) { 1.8813 + if (arguments.length < 3) priority = ""; 1.8814 + function styleTween(d, i) { 1.8815 + var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name)); 1.8816 + return f && function(t) { 1.8817 + this.style.setProperty(name, f(t), priority); 1.8818 + }; 1.8819 + } 1.8820 + return this.tween("style." + name, styleTween); 1.8821 + }; 1.8822 + d3_transitionPrototype.text = function(value) { 1.8823 + return d3_transition_tween(this, "text", value, d3_transition_text); 1.8824 + }; 1.8825 + function d3_transition_text(b) { 1.8826 + if (b == null) b = ""; 1.8827 + return function() { 1.8828 + this.textContent = b; 1.8829 + }; 1.8830 + } 1.8831 + d3_transitionPrototype.remove = function() { 1.8832 + var ns = this.namespace; 1.8833 + return this.each("end.transition", function() { 1.8834 + var p; 1.8835 + if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this); 1.8836 + }); 1.8837 + }; 1.8838 + d3_transitionPrototype.ease = function(value) { 1.8839 + var id = this.id, ns = this.namespace; 1.8840 + if (arguments.length < 1) return this.node()[ns][id].ease; 1.8841 + if (typeof value !== "function") value = d3.ease.apply(d3, arguments); 1.8842 + return d3_selection_each(this, function(node) { 1.8843 + node[ns][id].ease = value; 1.8844 + }); 1.8845 + }; 1.8846 + d3_transitionPrototype.delay = function(value) { 1.8847 + var id = this.id, ns = this.namespace; 1.8848 + if (arguments.length < 1) return this.node()[ns][id].delay; 1.8849 + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { 1.8850 + node[ns][id].delay = +value.call(node, node.__data__, i, j); 1.8851 + } : (value = +value, function(node) { 1.8852 + node[ns][id].delay = value; 1.8853 + })); 1.8854 + }; 1.8855 + d3_transitionPrototype.duration = function(value) { 1.8856 + var id = this.id, ns = this.namespace; 1.8857 + if (arguments.length < 1) return this.node()[ns][id].duration; 1.8858 + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { 1.8859 + node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j)); 1.8860 + } : (value = Math.max(1, value), function(node) { 1.8861 + node[ns][id].duration = value; 1.8862 + })); 1.8863 + }; 1.8864 + d3_transitionPrototype.each = function(type, listener) { 1.8865 + var id = this.id, ns = this.namespace; 1.8866 + if (arguments.length < 2) { 1.8867 + var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; 1.8868 + try { 1.8869 + d3_transitionInheritId = id; 1.8870 + d3_selection_each(this, function(node, i, j) { 1.8871 + d3_transitionInherit = node[ns][id]; 1.8872 + type.call(node, node.__data__, i, j); 1.8873 + }); 1.8874 + } finally { 1.8875 + d3_transitionInherit = inherit; 1.8876 + d3_transitionInheritId = inheritId; 1.8877 + } 1.8878 + } else { 1.8879 + d3_selection_each(this, function(node) { 1.8880 + var transition = node[ns][id]; 1.8881 + (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener); 1.8882 + }); 1.8883 + } 1.8884 + return this; 1.8885 + }; 1.8886 + d3_transitionPrototype.transition = function() { 1.8887 + var id0 = this.id, id1 = ++d3_transitionId, ns = this.namespace, subgroups = [], subgroup, group, node, transition; 1.8888 + for (var j = 0, m = this.length; j < m; j++) { 1.8889 + subgroups.push(subgroup = []); 1.8890 + for (var group = this[j], i = 0, n = group.length; i < n; i++) { 1.8891 + if (node = group[i]) { 1.8892 + transition = node[ns][id0]; 1.8893 + d3_transitionNode(node, i, ns, id1, { 1.8894 + time: transition.time, 1.8895 + ease: transition.ease, 1.8896 + delay: transition.delay + transition.duration, 1.8897 + duration: transition.duration 1.8898 + }); 1.8899 + } 1.8900 + subgroup.push(node); 1.8901 + } 1.8902 + } 1.8903 + return d3_transition(subgroups, ns, id1); 1.8904 + }; 1.8905 + function d3_transitionNamespace(name) { 1.8906 + return name == null ? "__transition__" : "__transition_" + name + "__"; 1.8907 + } 1.8908 + function d3_transitionNode(node, i, ns, id, inherit) { 1.8909 + var lock = node[ns] || (node[ns] = { 1.8910 + active: 0, 1.8911 + count: 0 1.8912 + }), transition = lock[id], time, timer, duration, ease, tweens; 1.8913 + function schedule(elapsed) { 1.8914 + var delay = transition.delay; 1.8915 + timer.t = delay + time; 1.8916 + if (delay <= elapsed) return start(elapsed - delay); 1.8917 + timer.c = start; 1.8918 + } 1.8919 + function start(elapsed) { 1.8920 + var activeId = lock.active, active = lock[activeId]; 1.8921 + if (active) { 1.8922 + active.timer.c = null; 1.8923 + active.timer.t = NaN; 1.8924 + --lock.count; 1.8925 + delete lock[activeId]; 1.8926 + active.event && active.event.interrupt.call(node, node.__data__, active.index); 1.8927 + } 1.8928 + for (var cancelId in lock) { 1.8929 + if (+cancelId < id) { 1.8930 + var cancel = lock[cancelId]; 1.8931 + cancel.timer.c = null; 1.8932 + cancel.timer.t = NaN; 1.8933 + --lock.count; 1.8934 + delete lock[cancelId]; 1.8935 + } 1.8936 + } 1.8937 + timer.c = tick; 1.8938 + d3_timer(function() { 1.8939 + if (timer.c && tick(elapsed || 1)) { 1.8940 + timer.c = null; 1.8941 + timer.t = NaN; 1.8942 + } 1.8943 + return 1; 1.8944 + }, 0, time); 1.8945 + lock.active = id; 1.8946 + transition.event && transition.event.start.call(node, node.__data__, i); 1.8947 + tweens = []; 1.8948 + transition.tween.forEach(function(key, value) { 1.8949 + if (value = value.call(node, node.__data__, i)) { 1.8950 + tweens.push(value); 1.8951 + } 1.8952 + }); 1.8953 + ease = transition.ease; 1.8954 + duration = transition.duration; 1.8955 + } 1.8956 + function tick(elapsed) { 1.8957 + var t = elapsed / duration, e = ease(t), n = tweens.length; 1.8958 + while (n > 0) { 1.8959 + tweens[--n].call(node, e); 1.8960 + } 1.8961 + if (t >= 1) { 1.8962 + transition.event && transition.event.end.call(node, node.__data__, i); 1.8963 + if (--lock.count) delete lock[id]; else delete node[ns]; 1.8964 + return 1; 1.8965 + } 1.8966 + } 1.8967 + if (!transition) { 1.8968 + time = inherit.time; 1.8969 + timer = d3_timer(schedule, 0, time); 1.8970 + transition = lock[id] = { 1.8971 + tween: new d3_Map(), 1.8972 + time: time, 1.8973 + timer: timer, 1.8974 + delay: inherit.delay, 1.8975 + duration: inherit.duration, 1.8976 + ease: inherit.ease, 1.8977 + index: i 1.8978 + }; 1.8979 + inherit = null; 1.8980 + ++lock.count; 1.8981 + } 1.8982 + } 1.8983 + d3.svg.axis = function() { 1.8984 + var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_; 1.8985 + function axis(g) { 1.8986 + g.each(function() { 1.8987 + var g = d3.select(this); 1.8988 + var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy(); 1.8989 + var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick.order()).style("opacity", 1), tickSpacing = Math.max(innerTickSize, 0) + tickPadding, tickTransform; 1.8990 + var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), 1.8991 + d3.transition(path)); 1.8992 + tickEnter.append("line"); 1.8993 + tickEnter.append("text"); 1.8994 + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"), sign = orient === "top" || orient === "left" ? -1 : 1, x1, x2, y1, y2; 1.8995 + if (orient === "bottom" || orient === "top") { 1.8996 + tickTransform = d3_svg_axisX, x1 = "x", y1 = "y", x2 = "x2", y2 = "y2"; 1.8997 + text.attr("dy", sign < 0 ? "0em" : ".71em").style("text-anchor", "middle"); 1.8998 + pathUpdate.attr("d", "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize); 1.8999 + } else { 1.9000 + tickTransform = d3_svg_axisY, x1 = "y", y1 = "x", x2 = "y2", y2 = "x2"; 1.9001 + text.attr("dy", ".32em").style("text-anchor", sign < 0 ? "end" : "start"); 1.9002 + pathUpdate.attr("d", "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize); 1.9003 + } 1.9004 + lineEnter.attr(y2, sign * innerTickSize); 1.9005 + textEnter.attr(y1, sign * tickSpacing); 1.9006 + lineUpdate.attr(x2, 0).attr(y2, sign * innerTickSize); 1.9007 + textUpdate.attr(x1, 0).attr(y1, sign * tickSpacing); 1.9008 + if (scale1.rangeBand) { 1.9009 + var x = scale1, dx = x.rangeBand() / 2; 1.9010 + scale0 = scale1 = function(d) { 1.9011 + return x(d) + dx; 1.9012 + }; 1.9013 + } else if (scale0.rangeBand) { 1.9014 + scale0 = scale1; 1.9015 + } else { 1.9016 + tickExit.call(tickTransform, scale1, scale0); 1.9017 + } 1.9018 + tickEnter.call(tickTransform, scale0, scale1); 1.9019 + tickUpdate.call(tickTransform, scale1, scale1); 1.9020 + }); 1.9021 + } 1.9022 + axis.scale = function(x) { 1.9023 + if (!arguments.length) return scale; 1.9024 + scale = x; 1.9025 + return axis; 1.9026 + }; 1.9027 + axis.orient = function(x) { 1.9028 + if (!arguments.length) return orient; 1.9029 + orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; 1.9030 + return axis; 1.9031 + }; 1.9032 + axis.ticks = function() { 1.9033 + if (!arguments.length) return tickArguments_; 1.9034 + tickArguments_ = d3_array(arguments); 1.9035 + return axis; 1.9036 + }; 1.9037 + axis.tickValues = function(x) { 1.9038 + if (!arguments.length) return tickValues; 1.9039 + tickValues = x; 1.9040 + return axis; 1.9041 + }; 1.9042 + axis.tickFormat = function(x) { 1.9043 + if (!arguments.length) return tickFormat_; 1.9044 + tickFormat_ = x; 1.9045 + return axis; 1.9046 + }; 1.9047 + axis.tickSize = function(x) { 1.9048 + var n = arguments.length; 1.9049 + if (!n) return innerTickSize; 1.9050 + innerTickSize = +x; 1.9051 + outerTickSize = +arguments[n - 1]; 1.9052 + return axis; 1.9053 + }; 1.9054 + axis.innerTickSize = function(x) { 1.9055 + if (!arguments.length) return innerTickSize; 1.9056 + innerTickSize = +x; 1.9057 + return axis; 1.9058 + }; 1.9059 + axis.outerTickSize = function(x) { 1.9060 + if (!arguments.length) return outerTickSize; 1.9061 + outerTickSize = +x; 1.9062 + return axis; 1.9063 + }; 1.9064 + axis.tickPadding = function(x) { 1.9065 + if (!arguments.length) return tickPadding; 1.9066 + tickPadding = +x; 1.9067 + return axis; 1.9068 + }; 1.9069 + axis.tickSubdivide = function() { 1.9070 + return arguments.length && axis; 1.9071 + }; 1.9072 + return axis; 1.9073 + }; 1.9074 + var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { 1.9075 + top: 1, 1.9076 + right: 1, 1.9077 + bottom: 1, 1.9078 + left: 1 1.9079 + }; 1.9080 + function d3_svg_axisX(selection, x0, x1) { 1.9081 + selection.attr("transform", function(d) { 1.9082 + var v0 = x0(d); 1.9083 + return "translate(" + (isFinite(v0) ? v0 : x1(d)) + ",0)"; 1.9084 + }); 1.9085 + } 1.9086 + function d3_svg_axisY(selection, y0, y1) { 1.9087 + selection.attr("transform", function(d) { 1.9088 + var v0 = y0(d); 1.9089 + return "translate(0," + (isFinite(v0) ? v0 : y1(d)) + ")"; 1.9090 + }); 1.9091 + } 1.9092 + d3.svg.brush = function() { 1.9093 + var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0]; 1.9094 + function brush(g) { 1.9095 + g.each(function() { 1.9096 + var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); 1.9097 + var background = g.selectAll(".background").data([ 0 ]); 1.9098 + background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); 1.9099 + g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move"); 1.9100 + var resize = g.selectAll(".resize").data(resizes, d3_identity); 1.9101 + resize.exit().remove(); 1.9102 + resize.enter().append("g").attr("class", function(d) { 1.9103 + return "resize " + d; 1.9104 + }).style("cursor", function(d) { 1.9105 + return d3_svg_brushCursor[d]; 1.9106 + }).append("rect").attr("x", function(d) { 1.9107 + return /[ew]$/.test(d) ? -3 : null; 1.9108 + }).attr("y", function(d) { 1.9109 + return /^[ns]/.test(d) ? -3 : null; 1.9110 + }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); 1.9111 + resize.style("display", brush.empty() ? "none" : null); 1.9112 + var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range; 1.9113 + if (x) { 1.9114 + range = d3_scaleRange(x); 1.9115 + backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]); 1.9116 + redrawX(gUpdate); 1.9117 + } 1.9118 + if (y) { 1.9119 + range = d3_scaleRange(y); 1.9120 + backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]); 1.9121 + redrawY(gUpdate); 1.9122 + } 1.9123 + redraw(gUpdate); 1.9124 + }); 1.9125 + } 1.9126 + brush.event = function(g) { 1.9127 + g.each(function() { 1.9128 + var event_ = event.of(this, arguments), extent1 = { 1.9129 + x: xExtent, 1.9130 + y: yExtent, 1.9131 + i: xExtentDomain, 1.9132 + j: yExtentDomain 1.9133 + }, extent0 = this.__chart__ || extent1; 1.9134 + this.__chart__ = extent1; 1.9135 + if (d3_transitionInheritId) { 1.9136 + d3.select(this).transition().each("start.brush", function() { 1.9137 + xExtentDomain = extent0.i; 1.9138 + yExtentDomain = extent0.j; 1.9139 + xExtent = extent0.x; 1.9140 + yExtent = extent0.y; 1.9141 + event_({ 1.9142 + type: "brushstart" 1.9143 + }); 1.9144 + }).tween("brush:brush", function() { 1.9145 + var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y); 1.9146 + xExtentDomain = yExtentDomain = null; 1.9147 + return function(t) { 1.9148 + xExtent = extent1.x = xi(t); 1.9149 + yExtent = extent1.y = yi(t); 1.9150 + event_({ 1.9151 + type: "brush", 1.9152 + mode: "resize" 1.9153 + }); 1.9154 + }; 1.9155 + }).each("end.brush", function() { 1.9156 + xExtentDomain = extent1.i; 1.9157 + yExtentDomain = extent1.j; 1.9158 + event_({ 1.9159 + type: "brush", 1.9160 + mode: "resize" 1.9161 + }); 1.9162 + event_({ 1.9163 + type: "brushend" 1.9164 + }); 1.9165 + }); 1.9166 + } else { 1.9167 + event_({ 1.9168 + type: "brushstart" 1.9169 + }); 1.9170 + event_({ 1.9171 + type: "brush", 1.9172 + mode: "resize" 1.9173 + }); 1.9174 + event_({ 1.9175 + type: "brushend" 1.9176 + }); 1.9177 + } 1.9178 + }); 1.9179 + }; 1.9180 + function redraw(g) { 1.9181 + g.selectAll(".resize").attr("transform", function(d) { 1.9182 + return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")"; 1.9183 + }); 1.9184 + } 1.9185 + function redrawX(g) { 1.9186 + g.select(".extent").attr("x", xExtent[0]); 1.9187 + g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]); 1.9188 + } 1.9189 + function redrawY(g) { 1.9190 + g.select(".extent").attr("y", yExtent[0]); 1.9191 + g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]); 1.9192 + } 1.9193 + function brushstart() { 1.9194 + var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(target), center, origin = d3.mouse(target), offset; 1.9195 + var w = d3.select(d3_window(target)).on("keydown.brush", keydown).on("keyup.brush", keyup); 1.9196 + if (d3.event.changedTouches) { 1.9197 + w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); 1.9198 + } else { 1.9199 + w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); 1.9200 + } 1.9201 + g.interrupt().selectAll("*").interrupt(); 1.9202 + if (dragging) { 1.9203 + origin[0] = xExtent[0] - origin[0]; 1.9204 + origin[1] = yExtent[0] - origin[1]; 1.9205 + } else if (resizing) { 1.9206 + var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); 1.9207 + offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ]; 1.9208 + origin[0] = xExtent[ex]; 1.9209 + origin[1] = yExtent[ey]; 1.9210 + } else if (d3.event.altKey) center = origin.slice(); 1.9211 + g.style("pointer-events", "none").selectAll(".resize").style("display", null); 1.9212 + d3.select("body").style("cursor", eventTarget.style("cursor")); 1.9213 + event_({ 1.9214 + type: "brushstart" 1.9215 + }); 1.9216 + brushmove(); 1.9217 + function keydown() { 1.9218 + if (d3.event.keyCode == 32) { 1.9219 + if (!dragging) { 1.9220 + center = null; 1.9221 + origin[0] -= xExtent[1]; 1.9222 + origin[1] -= yExtent[1]; 1.9223 + dragging = 2; 1.9224 + } 1.9225 + d3_eventPreventDefault(); 1.9226 + } 1.9227 + } 1.9228 + function keyup() { 1.9229 + if (d3.event.keyCode == 32 && dragging == 2) { 1.9230 + origin[0] += xExtent[1]; 1.9231 + origin[1] += yExtent[1]; 1.9232 + dragging = 0; 1.9233 + d3_eventPreventDefault(); 1.9234 + } 1.9235 + } 1.9236 + function brushmove() { 1.9237 + var point = d3.mouse(target), moved = false; 1.9238 + if (offset) { 1.9239 + point[0] += offset[0]; 1.9240 + point[1] += offset[1]; 1.9241 + } 1.9242 + if (!dragging) { 1.9243 + if (d3.event.altKey) { 1.9244 + if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ]; 1.9245 + origin[0] = xExtent[+(point[0] < center[0])]; 1.9246 + origin[1] = yExtent[+(point[1] < center[1])]; 1.9247 + } else center = null; 1.9248 + } 1.9249 + if (resizingX && move1(point, x, 0)) { 1.9250 + redrawX(g); 1.9251 + moved = true; 1.9252 + } 1.9253 + if (resizingY && move1(point, y, 1)) { 1.9254 + redrawY(g); 1.9255 + moved = true; 1.9256 + } 1.9257 + if (moved) { 1.9258 + redraw(g); 1.9259 + event_({ 1.9260 + type: "brush", 1.9261 + mode: dragging ? "move" : "resize" 1.9262 + }); 1.9263 + } 1.9264 + } 1.9265 + function move1(point, scale, i) { 1.9266 + var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max; 1.9267 + if (dragging) { 1.9268 + r0 -= position; 1.9269 + r1 -= size + position; 1.9270 + } 1.9271 + min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i]; 1.9272 + if (dragging) { 1.9273 + max = (min += position) + size; 1.9274 + } else { 1.9275 + if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); 1.9276 + if (position < min) { 1.9277 + max = min; 1.9278 + min = position; 1.9279 + } else { 1.9280 + max = position; 1.9281 + } 1.9282 + } 1.9283 + if (extent[0] != min || extent[1] != max) { 1.9284 + if (i) yExtentDomain = null; else xExtentDomain = null; 1.9285 + extent[0] = min; 1.9286 + extent[1] = max; 1.9287 + return true; 1.9288 + } 1.9289 + } 1.9290 + function brushend() { 1.9291 + brushmove(); 1.9292 + g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); 1.9293 + d3.select("body").style("cursor", null); 1.9294 + w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); 1.9295 + dragRestore(); 1.9296 + event_({ 1.9297 + type: "brushend" 1.9298 + }); 1.9299 + } 1.9300 + } 1.9301 + brush.x = function(z) { 1.9302 + if (!arguments.length) return x; 1.9303 + x = z; 1.9304 + resizes = d3_svg_brushResizes[!x << 1 | !y]; 1.9305 + return brush; 1.9306 + }; 1.9307 + brush.y = function(z) { 1.9308 + if (!arguments.length) return y; 1.9309 + y = z; 1.9310 + resizes = d3_svg_brushResizes[!x << 1 | !y]; 1.9311 + return brush; 1.9312 + }; 1.9313 + brush.clamp = function(z) { 1.9314 + if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null; 1.9315 + if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z; 1.9316 + return brush; 1.9317 + }; 1.9318 + brush.extent = function(z) { 1.9319 + var x0, x1, y0, y1, t; 1.9320 + if (!arguments.length) { 1.9321 + if (x) { 1.9322 + if (xExtentDomain) { 1.9323 + x0 = xExtentDomain[0], x1 = xExtentDomain[1]; 1.9324 + } else { 1.9325 + x0 = xExtent[0], x1 = xExtent[1]; 1.9326 + if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); 1.9327 + if (x1 < x0) t = x0, x0 = x1, x1 = t; 1.9328 + } 1.9329 + } 1.9330 + if (y) { 1.9331 + if (yExtentDomain) { 1.9332 + y0 = yExtentDomain[0], y1 = yExtentDomain[1]; 1.9333 + } else { 1.9334 + y0 = yExtent[0], y1 = yExtent[1]; 1.9335 + if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); 1.9336 + if (y1 < y0) t = y0, y0 = y1, y1 = t; 1.9337 + } 1.9338 + } 1.9339 + return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; 1.9340 + } 1.9341 + if (x) { 1.9342 + x0 = z[0], x1 = z[1]; 1.9343 + if (y) x0 = x0[0], x1 = x1[0]; 1.9344 + xExtentDomain = [ x0, x1 ]; 1.9345 + if (x.invert) x0 = x(x0), x1 = x(x1); 1.9346 + if (x1 < x0) t = x0, x0 = x1, x1 = t; 1.9347 + if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ]; 1.9348 + } 1.9349 + if (y) { 1.9350 + y0 = z[0], y1 = z[1]; 1.9351 + if (x) y0 = y0[1], y1 = y1[1]; 1.9352 + yExtentDomain = [ y0, y1 ]; 1.9353 + if (y.invert) y0 = y(y0), y1 = y(y1); 1.9354 + if (y1 < y0) t = y0, y0 = y1, y1 = t; 1.9355 + if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ]; 1.9356 + } 1.9357 + return brush; 1.9358 + }; 1.9359 + brush.clear = function() { 1.9360 + if (!brush.empty()) { 1.9361 + xExtent = [ 0, 0 ], yExtent = [ 0, 0 ]; 1.9362 + xExtentDomain = yExtentDomain = null; 1.9363 + } 1.9364 + return brush; 1.9365 + }; 1.9366 + brush.empty = function() { 1.9367 + return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1]; 1.9368 + }; 1.9369 + return d3.rebind(brush, event, "on"); 1.9370 + }; 1.9371 + var d3_svg_brushCursor = { 1.9372 + n: "ns-resize", 1.9373 + e: "ew-resize", 1.9374 + s: "ns-resize", 1.9375 + w: "ew-resize", 1.9376 + nw: "nwse-resize", 1.9377 + ne: "nesw-resize", 1.9378 + se: "nwse-resize", 1.9379 + sw: "nesw-resize" 1.9380 + }; 1.9381 + var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; 1.9382 + var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat; 1.9383 + var d3_time_formatUtc = d3_time_format.utc; 1.9384 + var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ"); 1.9385 + d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; 1.9386 + function d3_time_formatIsoNative(date) { 1.9387 + return date.toISOString(); 1.9388 + } 1.9389 + d3_time_formatIsoNative.parse = function(string) { 1.9390 + var date = new Date(string); 1.9391 + return isNaN(date) ? null : date; 1.9392 + }; 1.9393 + d3_time_formatIsoNative.toString = d3_time_formatIso.toString; 1.9394 + d3_time.second = d3_time_interval(function(date) { 1.9395 + return new d3_date(Math.floor(date / 1e3) * 1e3); 1.9396 + }, function(date, offset) { 1.9397 + date.setTime(date.getTime() + Math.floor(offset) * 1e3); 1.9398 + }, function(date) { 1.9399 + return date.getSeconds(); 1.9400 + }); 1.9401 + d3_time.seconds = d3_time.second.range; 1.9402 + d3_time.seconds.utc = d3_time.second.utc.range; 1.9403 + d3_time.minute = d3_time_interval(function(date) { 1.9404 + return new d3_date(Math.floor(date / 6e4) * 6e4); 1.9405 + }, function(date, offset) { 1.9406 + date.setTime(date.getTime() + Math.floor(offset) * 6e4); 1.9407 + }, function(date) { 1.9408 + return date.getMinutes(); 1.9409 + }); 1.9410 + d3_time.minutes = d3_time.minute.range; 1.9411 + d3_time.minutes.utc = d3_time.minute.utc.range; 1.9412 + d3_time.hour = d3_time_interval(function(date) { 1.9413 + var timezone = date.getTimezoneOffset() / 60; 1.9414 + return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); 1.9415 + }, function(date, offset) { 1.9416 + date.setTime(date.getTime() + Math.floor(offset) * 36e5); 1.9417 + }, function(date) { 1.9418 + return date.getHours(); 1.9419 + }); 1.9420 + d3_time.hours = d3_time.hour.range; 1.9421 + d3_time.hours.utc = d3_time.hour.utc.range; 1.9422 + d3_time.month = d3_time_interval(function(date) { 1.9423 + date = d3_time.day(date); 1.9424 + date.setDate(1); 1.9425 + return date; 1.9426 + }, function(date, offset) { 1.9427 + date.setMonth(date.getMonth() + offset); 1.9428 + }, function(date) { 1.9429 + return date.getMonth(); 1.9430 + }); 1.9431 + d3_time.months = d3_time.month.range; 1.9432 + d3_time.months.utc = d3_time.month.utc.range; 1.9433 + function d3_time_scale(linear, methods, format) { 1.9434 + function scale(x) { 1.9435 + return linear(x); 1.9436 + } 1.9437 + scale.invert = function(x) { 1.9438 + return d3_time_scaleDate(linear.invert(x)); 1.9439 + }; 1.9440 + scale.domain = function(x) { 1.9441 + if (!arguments.length) return linear.domain().map(d3_time_scaleDate); 1.9442 + linear.domain(x); 1.9443 + return scale; 1.9444 + }; 1.9445 + function tickMethod(extent, count) { 1.9446 + var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target); 1.9447 + return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) { 1.9448 + return d / 31536e6; 1.9449 + }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i]; 1.9450 + } 1.9451 + scale.nice = function(interval, skip) { 1.9452 + var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval); 1.9453 + if (method) interval = method[0], skip = method[1]; 1.9454 + function skipped(date) { 1.9455 + return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length; 1.9456 + } 1.9457 + return scale.domain(d3_scale_nice(domain, skip > 1 ? { 1.9458 + floor: function(date) { 1.9459 + while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1); 1.9460 + return date; 1.9461 + }, 1.9462 + ceil: function(date) { 1.9463 + while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1); 1.9464 + return date; 1.9465 + } 1.9466 + } : interval)); 1.9467 + }; 1.9468 + scale.ticks = function(interval, skip) { 1.9469 + var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ { 1.9470 + range: interval 1.9471 + }, skip ]; 1.9472 + if (method) interval = method[0], skip = method[1]; 1.9473 + return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip); 1.9474 + }; 1.9475 + scale.tickFormat = function() { 1.9476 + return format; 1.9477 + }; 1.9478 + scale.copy = function() { 1.9479 + return d3_time_scale(linear.copy(), methods, format); 1.9480 + }; 1.9481 + return d3_scale_linearRebind(scale, linear); 1.9482 + } 1.9483 + function d3_time_scaleDate(t) { 1.9484 + return new Date(t); 1.9485 + } 1.9486 + var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; 1.9487 + var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [ d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5 ], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3 ], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [ d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ]; 1.9488 + var d3_time_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) { 1.9489 + return d.getMilliseconds(); 1.9490 + } ], [ ":%S", function(d) { 1.9491 + return d.getSeconds(); 1.9492 + } ], [ "%I:%M", function(d) { 1.9493 + return d.getMinutes(); 1.9494 + } ], [ "%I %p", function(d) { 1.9495 + return d.getHours(); 1.9496 + } ], [ "%a %d", function(d) { 1.9497 + return d.getDay() && d.getDate() != 1; 1.9498 + } ], [ "%b %d", function(d) { 1.9499 + return d.getDate() != 1; 1.9500 + } ], [ "%B", function(d) { 1.9501 + return d.getMonth(); 1.9502 + } ], [ "%Y", d3_true ] ]); 1.9503 + var d3_time_scaleMilliseconds = { 1.9504 + range: function(start, stop, step) { 1.9505 + return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate); 1.9506 + }, 1.9507 + floor: d3_identity, 1.9508 + ceil: d3_identity 1.9509 + }; 1.9510 + d3_time_scaleLocalMethods.year = d3_time.year; 1.9511 + d3_time.scale = function() { 1.9512 + return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); 1.9513 + }; 1.9514 + var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) { 1.9515 + return [ m[0].utc, m[1] ]; 1.9516 + }); 1.9517 + var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) { 1.9518 + return d.getUTCMilliseconds(); 1.9519 + } ], [ ":%S", function(d) { 1.9520 + return d.getUTCSeconds(); 1.9521 + } ], [ "%I:%M", function(d) { 1.9522 + return d.getUTCMinutes(); 1.9523 + } ], [ "%I %p", function(d) { 1.9524 + return d.getUTCHours(); 1.9525 + } ], [ "%a %d", function(d) { 1.9526 + return d.getUTCDay() && d.getUTCDate() != 1; 1.9527 + } ], [ "%b %d", function(d) { 1.9528 + return d.getUTCDate() != 1; 1.9529 + } ], [ "%B", function(d) { 1.9530 + return d.getUTCMonth(); 1.9531 + } ], [ "%Y", d3_true ] ]); 1.9532 + d3_time_scaleUtcMethods.year = d3_time.year.utc; 1.9533 + d3_time.scale.utc = function() { 1.9534 + return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat); 1.9535 + }; 1.9536 + d3.text = d3_xhrType(function(request) { 1.9537 + return request.responseText; 1.9538 + }); 1.9539 + d3.json = function(url, callback) { 1.9540 + return d3_xhr(url, "application/json", d3_json, callback); 1.9541 + }; 1.9542 + function d3_json(request) { 1.9543 + return JSON.parse(request.responseText); 1.9544 + } 1.9545 + d3.html = function(url, callback) { 1.9546 + return d3_xhr(url, "text/html", d3_html, callback); 1.9547 + }; 1.9548 + function d3_html(request) { 1.9549 + var range = d3_document.createRange(); 1.9550 + range.selectNode(d3_document.body); 1.9551 + return range.createContextualFragment(request.responseText); 1.9552 + } 1.9553 + d3.xml = d3_xhrType(function(request) { 1.9554 + return request.responseXML; 1.9555 + }); 1.9556 + if (typeof define === "function" && define.amd) this.d3 = d3, define(d3); else if (typeof module === "object" && module.exports) module.exports = d3; else this.d3 = d3; 1.9557 +}(); 1.9558 \ No newline at end of file
2.1 Binary file gtc/d3.zip has changed
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/gtc/gtc.js Sun Feb 19 19:45:31 2017 -0800 3.3 @@ -0,0 +1,139 @@ 3.4 +var myChart; 3.5 +var myData; 3.6 +var showCorrBtn = document.getElementById('showcorr'); 3.7 + 3.8 +nv.addGraph(function() { 3.9 + myChart = nv.models.scatterChart() 3.10 + .showLegend(false) 3.11 + .showDistX(true) 3.12 + .showDistY(true) 3.13 + .xDomain([-1, 1]) 3.14 + .yDomain([-1, 1]) 3.15 + .duration(350) 3.16 + .color(d3.scale.category10().range()); 3.17 + myChart.tooltip.contentGenerator(function(data) { 3.18 + return '(' + data.point.x.toFixed(2) + ', ' + data.point.y.toFixed(2) + ')'; 3.19 + }); 3.20 + 3.21 + myChart.xAxis.tickFormat(d3.format('.02f')); 3.22 + myChart.yAxis.tickFormat(d3.format('.02f')); 3.23 + 3.24 + reload(); 3.25 + 3.26 + return myChart; 3.27 +}); 3.28 + 3.29 + 3.30 +function randomData(groups, points) { 3.31 + var data = [], 3.32 + shapes = ['circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'], 3.33 + random = d3.random.normal(); 3.34 + 3.35 + for (i = 0; i < groups; i++) { 3.36 + data.push({ 3.37 + key: 'Group ' + i, 3.38 + values: [] 3.39 + }); 3.40 + 3.41 + for (j = 0; j < points; j++) { 3.42 + data[i].values.push({ 3.43 + x: random(), 3.44 + y: random(), 3.45 + size: Math.random(), 3.46 + shape: (Math.random() > 0.95) ? shapes[j % 6] : 'circle' 3.47 + }); 3.48 + } 3.49 + } 3.50 + 3.51 + return data; 3.52 +} 3.53 + 3.54 +function myDataGen() { 3.55 + var data = []; 3.56 + var values = []; 3.57 + var n = 25; 3.58 + var m = 2*Math.random() - 1.0; 3.59 + var dv = Math.random(); 3.60 + var normal = d3.random.normal(0.0, dv) 3.61 + 3.62 + for (i = 0; i < n; i++) { 3.63 + var x = i/n + 0.5*normal() - 0.5; 3.64 + var y = m*x + normal(); 3.65 + values.push({ 3.66 + x: x, 3.67 + y: y, 3.68 + size: 2.0, 3.69 + shape: 'circle', 3.70 + }); 3.71 + } 3.72 + 3.73 + data.push({ 3.74 + //key: 'Points', 3.75 + values: values, 3.76 + //slope: m, 3.77 + //intercept: 0.001, 3.78 + }) 3.79 + 3.80 + return data; 3.81 +} 3.82 + 3.83 +function corr(values) { 3.84 + var x_a = []; 3.85 + var y_a = []; 3.86 + 3.87 + for (i = 0; i < values.length; i++) { 3.88 + x_a.push(values[i].x); 3.89 + y_a.push(values[i].y); 3.90 + } 3.91 + 3.92 + return ss.sampleCorrelation(x_a, y_a); 3.93 +} 3.94 + 3.95 +function lr(values) { 3.96 + var x_y = []; 3.97 + 3.98 + for (i = 0; i < values.length; i++) { 3.99 + x_y.push([values[i].x, values[i].y]); 3.100 + } 3.101 + 3.102 + return ss.linearRegression(x_y); 3.103 +} 3.104 + 3.105 +function print_corr() { 3.106 + console.log('corr = ' + corr(myData[0].values)) 3.107 +} 3.108 + 3.109 +function print_lr() { 3.110 + var lro = lr(myData[0].values); 3.111 + console.log('m = ' + lro.m); 3.112 + console.log('b = ' + lro.b); 3.113 +} 3.114 + 3.115 +function add_lr(lro, data) { 3.116 + data.push({ 3.117 + values: [], 3.118 + slope: lro.m, 3.119 + intercept: lro.b, 3.120 + }) 3.121 +} 3.122 + 3.123 +function show_corr() { 3.124 + var ans = corr(myData[0].values); 3.125 + showCorrBtn.textContent = ans.toFixed(2); 3.126 + showCorrBtn.onclick = reload; 3.127 +} 3.128 + 3.129 +function reload() { 3.130 + myData = myDataGen(); 3.131 + add_lr(lr(myData[0].values), myData); 3.132 + showCorrBtn.disabled = false; 3.133 + showCorrBtn.textContent = 'Show Correlation'; 3.134 + showCorrBtn.onclick = show_corr; 3.135 + 3.136 + d3.select('#chart svg') 3.137 + .style('height', '95%') 3.138 + .datum(myData) 3.139 + .call(myChart); 3.140 + 3.141 + nv.utils.windowResize(myChart.update); 3.142 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/gtc/index.html Sun Feb 19 19:45:31 2017 -0800 4.3 @@ -0,0 +1,18 @@ 4.4 +<html> 4.5 +<head> 4.6 + <meta charset="utf-8"> 4.7 +</head> 4.8 +<body> 4.9 +<div id="chart"> 4.10 + <svg></svg> 4.11 +</div> 4.12 +<div> 4.13 + <button id="showcorr">Show correlation</button> 4.14 +</div> 4.15 +<link href="nv.d3.css" rel="stylesheet"> 4.16 +<script src="d3.js"></script> 4.17 +<script src="nv.d3.js"></script> 4.18 +<script src="simple-statistics.js"></script> 4.19 +<script src="gtc.js"></script> 4.20 +</body> 4.21 +</html>
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/gtc/nv.d3.css Sun Feb 19 19:45:31 2017 -0800 5.3 @@ -0,0 +1,641 @@ 5.4 +/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-06-15 */ 5.5 +.nvd3 .nv-axis { 5.6 + pointer-events:none; 5.7 + opacity: 1; 5.8 +} 5.9 + 5.10 +.nvd3 .nv-axis path { 5.11 + fill: none; 5.12 + stroke: #000; 5.13 + stroke-opacity: .75; 5.14 + shape-rendering: crispEdges; 5.15 +} 5.16 + 5.17 +.nvd3 .nv-axis path.domain { 5.18 + stroke-opacity: .75; 5.19 +} 5.20 + 5.21 +.nvd3 .nv-axis.nv-x path.domain { 5.22 + stroke-opacity: 0; 5.23 +} 5.24 + 5.25 +.nvd3 .nv-axis line { 5.26 + fill: none; 5.27 + stroke: #e5e5e5; 5.28 + shape-rendering: crispEdges; 5.29 +} 5.30 + 5.31 +.nvd3 .nv-axis .zero line, 5.32 + /*this selector may not be necessary*/ .nvd3 .nv-axis line.zero { 5.33 + stroke-opacity: .75; 5.34 +} 5.35 + 5.36 +.nvd3 .nv-axis .nv-axisMaxMin text { 5.37 + font-weight: bold; 5.38 +} 5.39 + 5.40 +.nvd3 .x .nv-axis .nv-axisMaxMin text, 5.41 +.nvd3 .x2 .nv-axis .nv-axisMaxMin text, 5.42 +.nvd3 .x3 .nv-axis .nv-axisMaxMin text { 5.43 + text-anchor: middle 5.44 +} 5.45 + 5.46 +.nvd3 .nv-axis.nv-disabled { 5.47 + opacity: 0; 5.48 +} 5.49 + 5.50 +.nvd3 .nv-bars rect { 5.51 + fill-opacity: .75; 5.52 + 5.53 + transition: fill-opacity 250ms linear; 5.54 + -moz-transition: fill-opacity 250ms linear; 5.55 + -webkit-transition: fill-opacity 250ms linear; 5.56 +} 5.57 + 5.58 +.nvd3 .nv-bars rect.hover { 5.59 + fill-opacity: 1; 5.60 +} 5.61 + 5.62 +.nvd3 .nv-bars .hover rect { 5.63 + fill: lightblue; 5.64 +} 5.65 + 5.66 +.nvd3 .nv-bars text { 5.67 + fill: rgba(0,0,0,0); 5.68 +} 5.69 + 5.70 +.nvd3 .nv-bars .hover text { 5.71 + fill: rgba(0,0,0,1); 5.72 +} 5.73 + 5.74 +.nvd3 .nv-multibar .nv-groups rect, 5.75 +.nvd3 .nv-multibarHorizontal .nv-groups rect, 5.76 +.nvd3 .nv-discretebar .nv-groups rect { 5.77 + stroke-opacity: 0; 5.78 + 5.79 + transition: fill-opacity 250ms linear; 5.80 + -moz-transition: fill-opacity 250ms linear; 5.81 + -webkit-transition: fill-opacity 250ms linear; 5.82 +} 5.83 + 5.84 +.nvd3 .nv-multibar .nv-groups rect:hover, 5.85 +.nvd3 .nv-multibarHorizontal .nv-groups rect:hover, 5.86 +.nvd3 .nv-candlestickBar .nv-ticks rect:hover, 5.87 +.nvd3 .nv-discretebar .nv-groups rect:hover { 5.88 + fill-opacity: 1; 5.89 +} 5.90 + 5.91 +.nvd3 .nv-discretebar .nv-groups text, 5.92 +.nvd3 .nv-multibarHorizontal .nv-groups text { 5.93 + font-weight: bold; 5.94 + fill: rgba(0,0,0,1); 5.95 + stroke: rgba(0,0,0,0); 5.96 +} 5.97 + 5.98 +/* boxplot CSS */ 5.99 +.nvd3 .nv-boxplot circle { 5.100 + fill-opacity: 0.5; 5.101 +} 5.102 + 5.103 +.nvd3 .nv-boxplot circle:hover { 5.104 + fill-opacity: 1; 5.105 +} 5.106 + 5.107 +.nvd3 .nv-boxplot rect:hover { 5.108 + fill-opacity: 1; 5.109 +} 5.110 + 5.111 +.nvd3 line.nv-boxplot-median { 5.112 + stroke: black; 5.113 +} 5.114 + 5.115 +.nv-boxplot-tick:hover { 5.116 + stroke-width: 2.5px; 5.117 +} 5.118 +/* bullet */ 5.119 +.nvd3.nv-bullet { font: 10px sans-serif; } 5.120 +.nvd3.nv-bullet .nv-measure { fill-opacity: .8; } 5.121 +.nvd3.nv-bullet .nv-measure:hover { fill-opacity: 1; } 5.122 +.nvd3.nv-bullet .nv-marker { stroke: #000; stroke-width: 2px; } 5.123 +.nvd3.nv-bullet .nv-markerTriangle { stroke: #000; fill: #fff; stroke-width: 1.5px; } 5.124 +.nvd3.nv-bullet .nv-tick line { stroke: #666; stroke-width: .5px; } 5.125 +.nvd3.nv-bullet .nv-range.nv-s0 { fill: #eee; } 5.126 +.nvd3.nv-bullet .nv-range.nv-s1 { fill: #ddd; } 5.127 +.nvd3.nv-bullet .nv-range.nv-s2 { fill: #ccc; } 5.128 +.nvd3.nv-bullet .nv-title { font-size: 14px; font-weight: bold; } 5.129 +.nvd3.nv-bullet .nv-subtitle { fill: #999; } 5.130 + 5.131 + 5.132 +.nvd3.nv-bullet .nv-range { 5.133 + fill: #bababa; 5.134 + fill-opacity: .4; 5.135 +} 5.136 +.nvd3.nv-bullet .nv-range:hover { 5.137 + fill-opacity: .7; 5.138 +} 5.139 + 5.140 +.nvd3.nv-candlestickBar .nv-ticks .nv-tick { 5.141 + stroke-width: 1px; 5.142 +} 5.143 + 5.144 +.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover { 5.145 + stroke-width: 2px; 5.146 +} 5.147 + 5.148 +.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect { 5.149 + stroke: #2ca02c; 5.150 + fill: #2ca02c; 5.151 +} 5.152 + 5.153 +.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect { 5.154 + stroke: #d62728; 5.155 + fill: #d62728; 5.156 +} 5.157 + 5.158 +.with-transitions .nv-candlestickBar .nv-ticks .nv-tick { 5.159 + transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 5.160 + -moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 5.161 + -webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 5.162 + 5.163 +} 5.164 + 5.165 +.nvd3.nv-candlestickBar .nv-ticks line { 5.166 + stroke: #333; 5.167 +} 5.168 + 5.169 + 5.170 +.nvd3 .nv-legend .nv-disabled rect { 5.171 + /*fill-opacity: 0;*/ 5.172 +} 5.173 + 5.174 +.nvd3 .nv-check-box .nv-box { 5.175 + fill-opacity:0; 5.176 + stroke-width:2; 5.177 +} 5.178 + 5.179 +.nvd3 .nv-check-box .nv-check { 5.180 + fill-opacity:0; 5.181 + stroke-width:4; 5.182 +} 5.183 + 5.184 +.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check { 5.185 + fill-opacity:0; 5.186 + stroke-opacity:0; 5.187 +} 5.188 + 5.189 +.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check { 5.190 + opacity: 0; 5.191 +} 5.192 + 5.193 +/* line plus bar */ 5.194 +.nvd3.nv-linePlusBar .nv-bar rect { 5.195 + fill-opacity: .75; 5.196 +} 5.197 + 5.198 +.nvd3.nv-linePlusBar .nv-bar rect:hover { 5.199 + fill-opacity: 1; 5.200 +} 5.201 +.nvd3 .nv-groups path.nv-line { 5.202 + fill: none; 5.203 +} 5.204 + 5.205 +.nvd3 .nv-groups path.nv-area { 5.206 + stroke: none; 5.207 +} 5.208 + 5.209 +.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point { 5.210 + fill-opacity: 0; 5.211 + stroke-opacity: 0; 5.212 +} 5.213 + 5.214 +.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point { 5.215 + fill-opacity: .5 !important; 5.216 + stroke-opacity: .5 !important; 5.217 +} 5.218 + 5.219 + 5.220 +.with-transitions .nvd3 .nv-groups .nv-point { 5.221 + transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 5.222 + -moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 5.223 + -webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 5.224 + 5.225 +} 5.226 + 5.227 +.nvd3.nv-scatter .nv-groups .nv-point.hover, 5.228 +.nvd3 .nv-groups .nv-point.hover { 5.229 + stroke-width: 7px; 5.230 + fill-opacity: .95 !important; 5.231 + stroke-opacity: .95 !important; 5.232 +} 5.233 + 5.234 + 5.235 +.nvd3 .nv-point-paths path { 5.236 + stroke: #aaa; 5.237 + stroke-opacity: 0; 5.238 + fill: #eee; 5.239 + fill-opacity: 0; 5.240 +} 5.241 + 5.242 + 5.243 + 5.244 +.nvd3 .nv-indexLine { 5.245 + cursor: ew-resize; 5.246 +} 5.247 + 5.248 +/******************** 5.249 + * SVG CSS 5.250 + */ 5.251 + 5.252 +/******************** 5.253 + Default CSS for an svg element nvd3 used 5.254 +*/ 5.255 +svg.nvd3-svg { 5.256 + -webkit-touch-callout: none; 5.257 + -webkit-user-select: none; 5.258 + -khtml-user-select: none; 5.259 + -ms-user-select: none; 5.260 + -moz-user-select: none; 5.261 + user-select: none; 5.262 + display: block; 5.263 + width:100%; 5.264 + height:100%; 5.265 +} 5.266 + 5.267 +/******************** 5.268 + Box shadow and border radius styling 5.269 +*/ 5.270 +.nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip { 5.271 + -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); 5.272 + -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); 5.273 + box-shadow: 0 5px 10px rgba(0,0,0,.2); 5.274 + 5.275 + -webkit-border-radius: 5px; 5.276 + -moz-border-radius: 5px; 5.277 + border-radius: 5px; 5.278 +} 5.279 + 5.280 + 5.281 +.nvd3 text { 5.282 + font: normal 12px Arial; 5.283 +} 5.284 + 5.285 +.nvd3 .title { 5.286 + font: bold 14px Arial; 5.287 +} 5.288 + 5.289 +.nvd3 .nv-background { 5.290 + fill: white; 5.291 + fill-opacity: 0; 5.292 +} 5.293 + 5.294 +.nvd3.nv-noData { 5.295 + font-size: 18px; 5.296 + font-weight: bold; 5.297 +} 5.298 + 5.299 + 5.300 +/********** 5.301 +* Brush 5.302 +*/ 5.303 + 5.304 +.nv-brush .extent { 5.305 + fill-opacity: .125; 5.306 + shape-rendering: crispEdges; 5.307 +} 5.308 + 5.309 +.nv-brush .resize path { 5.310 + fill: #eee; 5.311 + stroke: #666; 5.312 +} 5.313 + 5.314 + 5.315 +/********** 5.316 +* Legend 5.317 +*/ 5.318 + 5.319 +.nvd3 .nv-legend .nv-series { 5.320 + cursor: pointer; 5.321 +} 5.322 + 5.323 +.nvd3 .nv-legend .nv-disabled circle { 5.324 + fill-opacity: 0; 5.325 +} 5.326 + 5.327 +/* focus */ 5.328 +.nvd3 .nv-brush .extent { 5.329 + fill-opacity: 0 !important; 5.330 +} 5.331 + 5.332 +.nvd3 .nv-brushBackground rect { 5.333 + stroke: #000; 5.334 + stroke-width: .4; 5.335 + fill: #fff; 5.336 + fill-opacity: .7; 5.337 +} 5.338 + 5.339 + 5.340 +.nvd3.nv-ohlcBar .nv-ticks .nv-tick { 5.341 + stroke-width: 1px; 5.342 +} 5.343 + 5.344 +.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover { 5.345 + stroke-width: 2px; 5.346 +} 5.347 + 5.348 +.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive { 5.349 + stroke: #2ca02c; 5.350 +} 5.351 + 5.352 +.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative { 5.353 + stroke: #d62728; 5.354 +} 5.355 + 5.356 + 5.357 +.nvd3 .background path { 5.358 + fill: none; 5.359 + stroke: #EEE; 5.360 + stroke-opacity: .4; 5.361 + shape-rendering: crispEdges; 5.362 +} 5.363 + 5.364 +.nvd3 .foreground path { 5.365 + fill: none; 5.366 + stroke-opacity: .7; 5.367 +} 5.368 + 5.369 +.nvd3 .nv-parallelCoordinates-brush .extent 5.370 +{ 5.371 + fill: #fff; 5.372 + fill-opacity: .6; 5.373 + stroke: gray; 5.374 + shape-rendering: crispEdges; 5.375 +} 5.376 + 5.377 +.nvd3 .nv-parallelCoordinates .hover { 5.378 + fill-opacity: 1; 5.379 + stroke-width: 3px; 5.380 +} 5.381 + 5.382 + 5.383 +.nvd3 .missingValuesline line { 5.384 + fill: none; 5.385 + stroke: black; 5.386 + stroke-width: 1; 5.387 + stroke-opacity: 1; 5.388 + stroke-dasharray: 5, 5; 5.389 +} 5.390 +.nvd3.nv-pie path { 5.391 + stroke-opacity: 0; 5.392 + transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; 5.393 + -moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; 5.394 + -webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; 5.395 + 5.396 +} 5.397 + 5.398 +.nvd3.nv-pie .nv-pie-title { 5.399 + font-size: 24px; 5.400 + fill: rgba(19, 196, 249, 0.59); 5.401 +} 5.402 + 5.403 +.nvd3.nv-pie .nv-slice text { 5.404 + stroke: #000; 5.405 + stroke-width: 0; 5.406 +} 5.407 + 5.408 +.nvd3.nv-pie path { 5.409 + stroke: #fff; 5.410 + stroke-width: 1px; 5.411 + stroke-opacity: 1; 5.412 +} 5.413 + 5.414 +.nvd3.nv-pie .hover path { 5.415 + fill-opacity: .7; 5.416 +} 5.417 +.nvd3.nv-pie .nv-label { 5.418 + pointer-events: none; 5.419 +} 5.420 +.nvd3.nv-pie .nv-label rect { 5.421 + fill-opacity: 0; 5.422 + stroke-opacity: 0; 5.423 +} 5.424 + 5.425 +/* scatter */ 5.426 +.nvd3 .nv-groups .nv-point.hover { 5.427 + stroke-width: 20px; 5.428 + stroke-opacity: .5; 5.429 +} 5.430 + 5.431 +.nvd3 .nv-scatter .nv-point.hover { 5.432 + fill-opacity: 1; 5.433 +} 5.434 +.nv-noninteractive { 5.435 + pointer-events: none; 5.436 +} 5.437 + 5.438 +.nv-distx, .nv-disty { 5.439 + pointer-events: none; 5.440 +} 5.441 + 5.442 +/* sparkline */ 5.443 +.nvd3.nv-sparkline path { 5.444 + fill: none; 5.445 +} 5.446 + 5.447 +.nvd3.nv-sparklineplus g.nv-hoverValue { 5.448 + pointer-events: none; 5.449 +} 5.450 + 5.451 +.nvd3.nv-sparklineplus .nv-hoverValue line { 5.452 + stroke: #333; 5.453 + stroke-width: 1.5px; 5.454 +} 5.455 + 5.456 +.nvd3.nv-sparklineplus, 5.457 +.nvd3.nv-sparklineplus g { 5.458 + pointer-events: all; 5.459 +} 5.460 + 5.461 +.nvd3 .nv-hoverArea { 5.462 + fill-opacity: 0; 5.463 + stroke-opacity: 0; 5.464 +} 5.465 + 5.466 +.nvd3.nv-sparklineplus .nv-xValue, 5.467 +.nvd3.nv-sparklineplus .nv-yValue { 5.468 + stroke-width: 0; 5.469 + font-size: .9em; 5.470 + font-weight: normal; 5.471 +} 5.472 + 5.473 +.nvd3.nv-sparklineplus .nv-yValue { 5.474 + stroke: #f66; 5.475 +} 5.476 + 5.477 +.nvd3.nv-sparklineplus .nv-maxValue { 5.478 + stroke: #2ca02c; 5.479 + fill: #2ca02c; 5.480 +} 5.481 + 5.482 +.nvd3.nv-sparklineplus .nv-minValue { 5.483 + stroke: #d62728; 5.484 + fill: #d62728; 5.485 +} 5.486 + 5.487 +.nvd3.nv-sparklineplus .nv-currentValue { 5.488 + font-weight: bold; 5.489 + font-size: 1.1em; 5.490 +} 5.491 +/* stacked area */ 5.492 +.nvd3.nv-stackedarea path.nv-area { 5.493 + fill-opacity: .7; 5.494 + stroke-opacity: 0; 5.495 + transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; 5.496 + -moz-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; 5.497 + -webkit-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; 5.498 +} 5.499 + 5.500 +.nvd3.nv-stackedarea path.nv-area.hover { 5.501 + fill-opacity: .9; 5.502 +} 5.503 + 5.504 + 5.505 +.nvd3.nv-stackedarea .nv-groups .nv-point { 5.506 + stroke-opacity: 0; 5.507 + fill-opacity: 0; 5.508 +} 5.509 + 5.510 + 5.511 +.nvtooltip { 5.512 + position: absolute; 5.513 + background-color: rgba(255,255,255,1.0); 5.514 + color: rgba(0,0,0,1.0); 5.515 + padding: 1px; 5.516 + border: 1px solid rgba(0,0,0,.2); 5.517 + z-index: 10000; 5.518 + display: block; 5.519 + 5.520 + font-family: Arial; 5.521 + font-size: 13px; 5.522 + text-align: left; 5.523 + pointer-events: none; 5.524 + 5.525 + white-space: nowrap; 5.526 + 5.527 + -webkit-touch-callout: none; 5.528 + -webkit-user-select: none; 5.529 + -khtml-user-select: none; 5.530 + -moz-user-select: none; 5.531 + -ms-user-select: none; 5.532 + user-select: none; 5.533 +} 5.534 + 5.535 +.nvtooltip { 5.536 + background: rgba(255,255,255, 0.8); 5.537 + border: 1px solid rgba(0,0,0,0.5); 5.538 + border-radius: 4px; 5.539 +} 5.540 + 5.541 +/*Give tooltips that old fade in transition by 5.542 + putting a "with-transitions" class on the container div. 5.543 +*/ 5.544 +.nvtooltip.with-transitions, .with-transitions .nvtooltip { 5.545 + transition: opacity 50ms linear; 5.546 + -moz-transition: opacity 50ms linear; 5.547 + -webkit-transition: opacity 50ms linear; 5.548 + 5.549 + transition-delay: 200ms; 5.550 + -moz-transition-delay: 200ms; 5.551 + -webkit-transition-delay: 200ms; 5.552 +} 5.553 + 5.554 +.nvtooltip.x-nvtooltip, 5.555 +.nvtooltip.y-nvtooltip { 5.556 + padding: 8px; 5.557 +} 5.558 + 5.559 +.nvtooltip h3 { 5.560 + margin: 0; 5.561 + padding: 4px 14px; 5.562 + line-height: 18px; 5.563 + font-weight: normal; 5.564 + background-color: rgba(247,247,247,0.75); 5.565 + color: rgba(0,0,0,1.0); 5.566 + text-align: center; 5.567 + 5.568 + border-bottom: 1px solid #ebebeb; 5.569 + 5.570 + -webkit-border-radius: 5px 5px 0 0; 5.571 + -moz-border-radius: 5px 5px 0 0; 5.572 + border-radius: 5px 5px 0 0; 5.573 +} 5.574 + 5.575 +.nvtooltip p { 5.576 + margin: 0; 5.577 + padding: 5px 14px; 5.578 + text-align: center; 5.579 +} 5.580 + 5.581 +.nvtooltip span { 5.582 + display: inline-block; 5.583 + margin: 2px 0; 5.584 +} 5.585 + 5.586 +.nvtooltip table { 5.587 + margin: 6px; 5.588 + border-spacing:0; 5.589 +} 5.590 + 5.591 + 5.592 +.nvtooltip table td { 5.593 + padding: 2px 9px 2px 0; 5.594 + vertical-align: middle; 5.595 +} 5.596 + 5.597 +.nvtooltip table td.key { 5.598 + font-weight:normal; 5.599 +} 5.600 +.nvtooltip table td.value { 5.601 + text-align: right; 5.602 + font-weight: bold; 5.603 +} 5.604 + 5.605 +.nvtooltip table tr.highlight td { 5.606 + padding: 1px 9px 1px 0; 5.607 + border-bottom-style: solid; 5.608 + border-bottom-width: 1px; 5.609 + border-top-style: solid; 5.610 + border-top-width: 1px; 5.611 +} 5.612 + 5.613 +.nvtooltip table td.legend-color-guide div { 5.614 + width: 8px; 5.615 + height: 8px; 5.616 + vertical-align: middle; 5.617 +} 5.618 + 5.619 +.nvtooltip table td.legend-color-guide div { 5.620 + width: 12px; 5.621 + height: 12px; 5.622 + border: 1px solid #999; 5.623 +} 5.624 + 5.625 +.nvtooltip .footer { 5.626 + padding: 3px; 5.627 + text-align: center; 5.628 +} 5.629 + 5.630 +.nvtooltip-pending-removal { 5.631 + pointer-events: none; 5.632 + display: none; 5.633 +} 5.634 + 5.635 + 5.636 +/**** 5.637 +Interactive Layer 5.638 +*/ 5.639 +.nvd3 .nv-interactiveGuideLine { 5.640 + pointer-events:none; 5.641 +} 5.642 +.nvd3 line.nv-guideline { 5.643 + stroke: #ccc; 5.644 +} 5.645 \ No newline at end of file
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/gtc/nv.d3.js Sun Feb 19 19:45:31 2017 -0800 6.3 @@ -0,0 +1,13298 @@ 6.4 +/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-06-15 */ 6.5 +(function(){ 6.6 + 6.7 +// set up main nv object 6.8 +var nv = {}; 6.9 + 6.10 +// the major global objects under the nv namespace 6.11 +nv.dev = false; //set false when in production 6.12 +nv.tooltip = nv.tooltip || {}; // For the tooltip system 6.13 +nv.utils = nv.utils || {}; // Utility subsystem 6.14 +nv.models = nv.models || {}; //stores all the possible models/components 6.15 +nv.charts = {}; //stores all the ready to use charts 6.16 +nv.logs = {}; //stores some statistics and potential error messages 6.17 +nv.dom = {}; //DOM manipulation functions 6.18 + 6.19 +nv.dispatch = d3.dispatch('render_start', 'render_end'); 6.20 + 6.21 +// Function bind polyfill 6.22 +// Needed ONLY for phantomJS as it's missing until version 2.0 which is unreleased as of this comment 6.23 +// https://github.com/ariya/phantomjs/issues/10522 6.24 +// http://kangax.github.io/compat-table/es5/#Function.prototype.bind 6.25 +// phantomJS is used for running the test suite 6.26 +if (!Function.prototype.bind) { 6.27 + Function.prototype.bind = function (oThis) { 6.28 + if (typeof this !== "function") { 6.29 + // closest thing possible to the ECMAScript 5 internal IsCallable function 6.30 + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 6.31 + } 6.32 + 6.33 + var aArgs = Array.prototype.slice.call(arguments, 1), 6.34 + fToBind = this, 6.35 + fNOP = function () {}, 6.36 + fBound = function () { 6.37 + return fToBind.apply(this instanceof fNOP && oThis 6.38 + ? this 6.39 + : oThis, 6.40 + aArgs.concat(Array.prototype.slice.call(arguments))); 6.41 + }; 6.42 + 6.43 + fNOP.prototype = this.prototype; 6.44 + fBound.prototype = new fNOP(); 6.45 + return fBound; 6.46 + }; 6.47 +} 6.48 + 6.49 +// Development render timers - disabled if dev = false 6.50 +if (nv.dev) { 6.51 + nv.dispatch.on('render_start', function(e) { 6.52 + nv.logs.startTime = +new Date(); 6.53 + }); 6.54 + 6.55 + nv.dispatch.on('render_end', function(e) { 6.56 + nv.logs.endTime = +new Date(); 6.57 + nv.logs.totalTime = nv.logs.endTime - nv.logs.startTime; 6.58 + nv.log('total', nv.logs.totalTime); // used for development, to keep track of graph generation times 6.59 + }); 6.60 +} 6.61 + 6.62 +// Logs all arguments, and returns the last so you can test things in place 6.63 +// Note: in IE8 console.log is an object not a function, and if modernizr is used 6.64 +// then calling Function.prototype.bind with with anything other than a function 6.65 +// causes a TypeError to be thrown. 6.66 +nv.log = function() { 6.67 + if (nv.dev && window.console && console.log && console.log.apply) 6.68 + console.log.apply(console, arguments); 6.69 + else if (nv.dev && window.console && typeof console.log == "function" && Function.prototype.bind) { 6.70 + var log = Function.prototype.bind.call(console.log, console); 6.71 + log.apply(console, arguments); 6.72 + } 6.73 + return arguments[arguments.length - 1]; 6.74 +}; 6.75 + 6.76 +// print console warning, should be used by deprecated functions 6.77 +nv.deprecated = function(name, info) { 6.78 + if (console && console.warn) { 6.79 + console.warn('nvd3 warning: `' + name + '` has been deprecated. ', info || ''); 6.80 + } 6.81 +}; 6.82 + 6.83 +// The nv.render function is used to queue up chart rendering 6.84 +// in non-blocking async functions. 6.85 +// When all queued charts are done rendering, nv.dispatch.render_end is invoked. 6.86 +nv.render = function render(step) { 6.87 + // number of graphs to generate in each timeout loop 6.88 + step = step || 1; 6.89 + 6.90 + nv.render.active = true; 6.91 + nv.dispatch.render_start(); 6.92 + 6.93 + var renderLoop = function() { 6.94 + var chart, graph; 6.95 + 6.96 + for (var i = 0; i < step && (graph = nv.render.queue[i]); i++) { 6.97 + chart = graph.generate(); 6.98 + if (typeof graph.callback == typeof(Function)) graph.callback(chart); 6.99 + } 6.100 + 6.101 + nv.render.queue.splice(0, i); 6.102 + 6.103 + if (nv.render.queue.length) { 6.104 + setTimeout(renderLoop); 6.105 + } 6.106 + else { 6.107 + nv.dispatch.render_end(); 6.108 + nv.render.active = false; 6.109 + } 6.110 + }; 6.111 + 6.112 + setTimeout(renderLoop); 6.113 +}; 6.114 + 6.115 +nv.render.active = false; 6.116 +nv.render.queue = []; 6.117 + 6.118 +/* 6.119 +Adds a chart to the async rendering queue. This method can take arguments in two forms: 6.120 +nv.addGraph({ 6.121 + generate: <Function> 6.122 + callback: <Function> 6.123 +}) 6.124 + 6.125 +or 6.126 + 6.127 +nv.addGraph(<generate Function>, <callback Function>) 6.128 + 6.129 +The generate function should contain code that creates the NVD3 model, sets options 6.130 +on it, adds data to an SVG element, and invokes the chart model. The generate function 6.131 +should return the chart model. See examples/lineChart.html for a usage example. 6.132 + 6.133 +The callback function is optional, and it is called when the generate function completes. 6.134 +*/ 6.135 +nv.addGraph = function(obj) { 6.136 + if (typeof arguments[0] === typeof(Function)) { 6.137 + obj = {generate: arguments[0], callback: arguments[1]}; 6.138 + } 6.139 + 6.140 + nv.render.queue.push(obj); 6.141 + 6.142 + if (!nv.render.active) { 6.143 + nv.render(); 6.144 + } 6.145 +}; 6.146 + 6.147 +// Node/CommonJS exports 6.148 +if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') { 6.149 + module.exports = nv; 6.150 +} 6.151 + 6.152 +if (typeof(window) !== 'undefined') { 6.153 + window.nv = nv; 6.154 +} 6.155 +/* Facade for queueing DOM write operations 6.156 + * with Fastdom (https://github.com/wilsonpage/fastdom) 6.157 + * if available. 6.158 + * This could easily be extended to support alternate 6.159 + * implementations in the future. 6.160 + */ 6.161 +nv.dom.write = function(callback) { 6.162 + if (window.fastdom !== undefined) { 6.163 + return fastdom.write(callback); 6.164 + } 6.165 + return callback(); 6.166 +}; 6.167 + 6.168 +/* Facade for queueing DOM read operations 6.169 + * with Fastdom (https://github.com/wilsonpage/fastdom) 6.170 + * if available. 6.171 + * This could easily be extended to support alternate 6.172 + * implementations in the future. 6.173 + */ 6.174 +nv.dom.read = function(callback) { 6.175 + if (window.fastdom !== undefined) { 6.176 + return fastdom.read(callback); 6.177 + } 6.178 + return callback(); 6.179 +};/* Utility class to handle creation of an interactive layer. 6.180 + This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch 6.181 + containing the X-coordinate. It can also render a vertical line where the mouse is located. 6.182 + 6.183 + dispatch.elementMousemove is the important event to latch onto. It is fired whenever the mouse moves over 6.184 + the rectangle. The dispatch is given one object which contains the mouseX/Y location. 6.185 + It also has 'pointXValue', which is the conversion of mouseX to the x-axis scale. 6.186 + */ 6.187 +nv.interactiveGuideline = function() { 6.188 + "use strict"; 6.189 + 6.190 + var tooltip = nv.models.tooltip(); 6.191 + tooltip.duration(0).hideDelay(0)._isInteractiveLayer(true).hidden(false); 6.192 + 6.193 + //Public settings 6.194 + var width = null; 6.195 + var height = null; 6.196 + 6.197 + //Please pass in the bounding chart's top and left margins 6.198 + //This is important for calculating the correct mouseX/Y positions. 6.199 + var margin = {left: 0, top: 0} 6.200 + , xScale = d3.scale.linear() 6.201 + , dispatch = d3.dispatch('elementMousemove', 'elementMouseout', 'elementClick', 'elementDblclick') 6.202 + , showGuideLine = true; 6.203 + //Must pass in the bounding chart's <svg> container. 6.204 + //The mousemove event is attached to this container. 6.205 + var svgContainer = null; 6.206 + 6.207 + // check if IE by looking for activeX 6.208 + var isMSIE = "ActiveXObject" in window; 6.209 + 6.210 + 6.211 + function layer(selection) { 6.212 + selection.each(function(data) { 6.213 + var container = d3.select(this); 6.214 + var availableWidth = (width || 960), availableHeight = (height || 400); 6.215 + var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer") 6.216 + .data([data]); 6.217 + var wrapEnter = wrap.enter() 6.218 + .append("g").attr("class", " nv-wrap nv-interactiveLineLayer"); 6.219 + wrapEnter.append("g").attr("class","nv-interactiveGuideLine"); 6.220 + 6.221 + if (!svgContainer) { 6.222 + return; 6.223 + } 6.224 + 6.225 + function mouseHandler() { 6.226 + var d3mouse = d3.mouse(this); 6.227 + var mouseX = d3mouse[0]; 6.228 + var mouseY = d3mouse[1]; 6.229 + var subtractMargin = true; 6.230 + var mouseOutAnyReason = false; 6.231 + if (isMSIE) { 6.232 + /* 6.233 + D3.js (or maybe SVG.getScreenCTM) has a nasty bug in Internet Explorer 10. 6.234 + d3.mouse() returns incorrect X,Y mouse coordinates when mouse moving 6.235 + over a rect in IE 10. 6.236 + However, d3.event.offsetX/Y also returns the mouse coordinates 6.237 + relative to the triggering <rect>. So we use offsetX/Y on IE. 6.238 + */ 6.239 + mouseX = d3.event.offsetX; 6.240 + mouseY = d3.event.offsetY; 6.241 + 6.242 + /* 6.243 + On IE, if you attach a mouse event listener to the <svg> container, 6.244 + it will actually trigger it for all the child elements (like <path>, <circle>, etc). 6.245 + When this happens on IE, the offsetX/Y is set to where ever the child element 6.246 + is located. 6.247 + As a result, we do NOT need to subtract margins to figure out the mouse X/Y 6.248 + position under this scenario. Removing the line below *will* cause 6.249 + the interactive layer to not work right on IE. 6.250 + */ 6.251 + if(d3.event.target.tagName !== "svg") { 6.252 + subtractMargin = false; 6.253 + } 6.254 + 6.255 + if (d3.event.target.className.baseVal.match("nv-legend")) { 6.256 + mouseOutAnyReason = true; 6.257 + } 6.258 + 6.259 + } 6.260 + 6.261 + if(subtractMargin) { 6.262 + mouseX -= margin.left; 6.263 + mouseY -= margin.top; 6.264 + } 6.265 + 6.266 + /* If mouseX/Y is outside of the chart's bounds, 6.267 + trigger a mouseOut event. 6.268 + */ 6.269 + if (mouseX < 0 || mouseY < 0 6.270 + || mouseX > availableWidth || mouseY > availableHeight 6.271 + || (d3.event.relatedTarget && d3.event.relatedTarget.ownerSVGElement === undefined) 6.272 + || mouseOutAnyReason 6.273 + ) { 6.274 + 6.275 + if (isMSIE) { 6.276 + if (d3.event.relatedTarget 6.277 + && d3.event.relatedTarget.ownerSVGElement === undefined 6.278 + && (d3.event.relatedTarget.className === undefined 6.279 + || d3.event.relatedTarget.className.match(tooltip.nvPointerEventsClass))) { 6.280 + 6.281 + return; 6.282 + } 6.283 + } 6.284 + dispatch.elementMouseout({ 6.285 + mouseX: mouseX, 6.286 + mouseY: mouseY 6.287 + }); 6.288 + layer.renderGuideLine(null); //hide the guideline 6.289 + tooltip.hidden(true); 6.290 + return; 6.291 + } else { 6.292 + tooltip.hidden(false); 6.293 + } 6.294 + 6.295 + var pointXValue = xScale.invert(mouseX); 6.296 + dispatch.elementMousemove({ 6.297 + mouseX: mouseX, 6.298 + mouseY: mouseY, 6.299 + pointXValue: pointXValue 6.300 + }); 6.301 + 6.302 + //If user double clicks the layer, fire a elementDblclick 6.303 + if (d3.event.type === "dblclick") { 6.304 + dispatch.elementDblclick({ 6.305 + mouseX: mouseX, 6.306 + mouseY: mouseY, 6.307 + pointXValue: pointXValue 6.308 + }); 6.309 + } 6.310 + 6.311 + // if user single clicks the layer, fire elementClick 6.312 + if (d3.event.type === 'click') { 6.313 + dispatch.elementClick({ 6.314 + mouseX: mouseX, 6.315 + mouseY: mouseY, 6.316 + pointXValue: pointXValue 6.317 + }); 6.318 + } 6.319 + } 6.320 + 6.321 + svgContainer 6.322 + .on("touchmove",mouseHandler) 6.323 + .on("mousemove",mouseHandler, true) 6.324 + .on("mouseout" ,mouseHandler,true) 6.325 + .on("dblclick" ,mouseHandler) 6.326 + .on("click", mouseHandler) 6.327 + ; 6.328 + 6.329 + layer.guideLine = null; 6.330 + //Draws a vertical guideline at the given X postion. 6.331 + layer.renderGuideLine = function(x) { 6.332 + if (!showGuideLine) return; 6.333 + if (layer.guideLine && layer.guideLine.attr("x1") === x) return; 6.334 + nv.dom.write(function() { 6.335 + var line = wrap.select(".nv-interactiveGuideLine") 6.336 + .selectAll("line") 6.337 + .data((x != null) ? [nv.utils.NaNtoZero(x)] : [], String); 6.338 + line.enter() 6.339 + .append("line") 6.340 + .attr("class", "nv-guideline") 6.341 + .attr("x1", function(d) { return d;}) 6.342 + .attr("x2", function(d) { return d;}) 6.343 + .attr("y1", availableHeight) 6.344 + .attr("y2",0); 6.345 + line.exit().remove(); 6.346 + }); 6.347 + } 6.348 + }); 6.349 + } 6.350 + 6.351 + layer.dispatch = dispatch; 6.352 + layer.tooltip = tooltip; 6.353 + 6.354 + layer.margin = function(_) { 6.355 + if (!arguments.length) return margin; 6.356 + margin.top = typeof _.top != 'undefined' ? _.top : margin.top; 6.357 + margin.left = typeof _.left != 'undefined' ? _.left : margin.left; 6.358 + return layer; 6.359 + }; 6.360 + 6.361 + layer.width = function(_) { 6.362 + if (!arguments.length) return width; 6.363 + width = _; 6.364 + return layer; 6.365 + }; 6.366 + 6.367 + layer.height = function(_) { 6.368 + if (!arguments.length) return height; 6.369 + height = _; 6.370 + return layer; 6.371 + }; 6.372 + 6.373 + layer.xScale = function(_) { 6.374 + if (!arguments.length) return xScale; 6.375 + xScale = _; 6.376 + return layer; 6.377 + }; 6.378 + 6.379 + layer.showGuideLine = function(_) { 6.380 + if (!arguments.length) return showGuideLine; 6.381 + showGuideLine = _; 6.382 + return layer; 6.383 + }; 6.384 + 6.385 + layer.svgContainer = function(_) { 6.386 + if (!arguments.length) return svgContainer; 6.387 + svgContainer = _; 6.388 + return layer; 6.389 + }; 6.390 + 6.391 + return layer; 6.392 +}; 6.393 + 6.394 +/* Utility class that uses d3.bisect to find the index in a given array, where a search value can be inserted. 6.395 + This is different from normal bisectLeft; this function finds the nearest index to insert the search value. 6.396 + 6.397 + For instance, lets say your array is [1,2,3,5,10,30], and you search for 28. 6.398 + Normal d3.bisectLeft will return 4, because 28 is inserted after the number 10. But interactiveBisect will return 5 6.399 + because 28 is closer to 30 than 10. 6.400 + 6.401 + Unit tests can be found in: interactiveBisectTest.html 6.402 + 6.403 + Has the following known issues: 6.404 + * Will not work if the data points move backwards (ie, 10,9,8,7, etc) or if the data points are in random order. 6.405 + * Won't work if there are duplicate x coordinate values. 6.406 + */ 6.407 +nv.interactiveBisect = function (values, searchVal, xAccessor) { 6.408 + "use strict"; 6.409 + if (! (values instanceof Array)) { 6.410 + return null; 6.411 + } 6.412 + var _xAccessor; 6.413 + if (typeof xAccessor !== 'function') { 6.414 + _xAccessor = function(d) { 6.415 + return d.x; 6.416 + } 6.417 + } else { 6.418 + _xAccessor = xAccessor; 6.419 + } 6.420 + var _cmp = function(d, v) { 6.421 + // Accessors are no longer passed the index of the element along with 6.422 + // the element itself when invoked by d3.bisector. 6.423 + // 6.424 + // Starting at D3 v3.4.4, d3.bisector() started inspecting the 6.425 + // function passed to determine if it should consider it an accessor 6.426 + // or a comparator. This meant that accessors that take two arguments 6.427 + // (expecting an index as the second parameter) are treated as 6.428 + // comparators where the second argument is the search value against 6.429 + // which the first argument is compared. 6.430 + return _xAccessor(d) - v; 6.431 + }; 6.432 + 6.433 + var bisect = d3.bisector(_cmp).left; 6.434 + var index = d3.max([0, bisect(values,searchVal) - 1]); 6.435 + var currentValue = _xAccessor(values[index]); 6.436 + 6.437 + if (typeof currentValue === 'undefined') { 6.438 + currentValue = index; 6.439 + } 6.440 + 6.441 + if (currentValue === searchVal) { 6.442 + return index; //found exact match 6.443 + } 6.444 + 6.445 + var nextIndex = d3.min([index+1, values.length - 1]); 6.446 + var nextValue = _xAccessor(values[nextIndex]); 6.447 + 6.448 + if (typeof nextValue === 'undefined') { 6.449 + nextValue = nextIndex; 6.450 + } 6.451 + 6.452 + if (Math.abs(nextValue - searchVal) >= Math.abs(currentValue - searchVal)) { 6.453 + return index; 6.454 + } else { 6.455 + return nextIndex 6.456 + } 6.457 +}; 6.458 + 6.459 +/* 6.460 + Returns the index in the array "values" that is closest to searchVal. 6.461 + Only returns an index if searchVal is within some "threshold". 6.462 + Otherwise, returns null. 6.463 + */ 6.464 +nv.nearestValueIndex = function (values, searchVal, threshold) { 6.465 + "use strict"; 6.466 + var yDistMax = Infinity, indexToHighlight = null; 6.467 + values.forEach(function(d,i) { 6.468 + var delta = Math.abs(searchVal - d); 6.469 + if ( d != null && delta <= yDistMax && delta < threshold) { 6.470 + yDistMax = delta; 6.471 + indexToHighlight = i; 6.472 + } 6.473 + }); 6.474 + return indexToHighlight; 6.475 +}; 6.476 +/* Tooltip rendering model for nvd3 charts. 6.477 + window.nv.models.tooltip is the updated,new way to render tooltips. 6.478 + 6.479 + window.nv.tooltip.show is the old tooltip code. 6.480 + window.nv.tooltip.* also has various helper methods. 6.481 + */ 6.482 +(function() { 6.483 + "use strict"; 6.484 + 6.485 + /* Model which can be instantiated to handle tooltip rendering. 6.486 + Example usage: 6.487 + var tip = nv.models.tooltip().gravity('w').distance(23) 6.488 + .data(myDataObject); 6.489 + 6.490 + tip(); //just invoke the returned function to render tooltip. 6.491 + */ 6.492 + nv.models.tooltip = function() { 6.493 + 6.494 + /* 6.495 + Tooltip data. If data is given in the proper format, a consistent tooltip is generated. 6.496 + Example Format of data: 6.497 + { 6.498 + key: "Date", 6.499 + value: "August 2009", 6.500 + series: [ 6.501 + {key: "Series 1", value: "Value 1", color: "#000"}, 6.502 + {key: "Series 2", value: "Value 2", color: "#00f"} 6.503 + ] 6.504 + } 6.505 + */ 6.506 + var data = null; 6.507 + var gravity = 'w' //Can be 'n','s','e','w'. Determines how tooltip is positioned. 6.508 + , distance = 25 //Distance to offset tooltip from the mouse location. 6.509 + , snapDistance = 0 //Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect) 6.510 + , fixedTop = null //If not null, this fixes the top position of the tooltip. 6.511 + , classes = null //Attaches additional CSS classes to the tooltip DIV that is created. 6.512 + , chartContainer = null //Parent dom element of the SVG that holds the chart. 6.513 + , hidden = true // start off hidden, toggle with hide/show functions below 6.514 + , hideDelay = 400 // delay before the tooltip hides after calling hide() 6.515 + , tooltip = null // d3 select of tooltipElem below 6.516 + , tooltipElem = null //actual DOM element representing the tooltip. 6.517 + , position = {left: null, top: null} //Relative position of the tooltip inside chartContainer. 6.518 + , offset = {left: 0, top: 0} //Offset of tooltip against the pointer 6.519 + , enabled = true //True -> tooltips are rendered. False -> don't render tooltips. 6.520 + , duration = 100 // duration for tooltip movement 6.521 + , headerEnabled = true 6.522 + ; 6.523 + 6.524 + // set to true by interactive layer to adjust tooltip positions 6.525 + // eventually we should probably fix interactive layer to get the position better. 6.526 + // for now this is needed if you want to set chartContainer for normal tooltips, else it "fixes" it to broken 6.527 + var isInteractiveLayer = false; 6.528 + 6.529 + //Generates a unique id when you create a new tooltip() object 6.530 + var id = "nvtooltip-" + Math.floor(Math.random() * 100000); 6.531 + 6.532 + //CSS class to specify whether element should not have mouse events. 6.533 + var nvPointerEventsClass = "nv-pointer-events-none"; 6.534 + 6.535 + //Format function for the tooltip values column 6.536 + var valueFormatter = function(d,i) { 6.537 + return d; 6.538 + }; 6.539 + 6.540 + //Format function for the tooltip header value. 6.541 + var headerFormatter = function(d) { 6.542 + return d; 6.543 + }; 6.544 + 6.545 + var keyFormatter = function(d, i) { 6.546 + return d; 6.547 + }; 6.548 + 6.549 + //By default, the tooltip model renders a beautiful table inside a DIV. 6.550 + //You can override this function if a custom tooltip is desired. 6.551 + var contentGenerator = function(d) { 6.552 + if (d === null) { 6.553 + return ''; 6.554 + } 6.555 + 6.556 + var table = d3.select(document.createElement("table")); 6.557 + if (headerEnabled) { 6.558 + var theadEnter = table.selectAll("thead") 6.559 + .data([d]) 6.560 + .enter().append("thead"); 6.561 + 6.562 + theadEnter.append("tr") 6.563 + .append("td") 6.564 + .attr("colspan", 3) 6.565 + .append("strong") 6.566 + .classed("x-value", true) 6.567 + .html(headerFormatter(d.value)); 6.568 + } 6.569 + 6.570 + var tbodyEnter = table.selectAll("tbody") 6.571 + .data([d]) 6.572 + .enter().append("tbody"); 6.573 + 6.574 + var trowEnter = tbodyEnter.selectAll("tr") 6.575 + .data(function(p) { return p.series}) 6.576 + .enter() 6.577 + .append("tr") 6.578 + .classed("highlight", function(p) { return p.highlight}); 6.579 + 6.580 + trowEnter.append("td") 6.581 + .classed("legend-color-guide",true) 6.582 + .append("div") 6.583 + .style("background-color", function(p) { return p.color}); 6.584 + 6.585 + trowEnter.append("td") 6.586 + .classed("key",true) 6.587 + .html(function(p, i) {return keyFormatter(p.key, i)}); 6.588 + 6.589 + trowEnter.append("td") 6.590 + .classed("value",true) 6.591 + .html(function(p, i) { return valueFormatter(p.value, i) }); 6.592 + 6.593 + 6.594 + trowEnter.selectAll("td").each(function(p) { 6.595 + if (p.highlight) { 6.596 + var opacityScale = d3.scale.linear().domain([0,1]).range(["#fff",p.color]); 6.597 + var opacity = 0.6; 6.598 + d3.select(this) 6.599 + .style("border-bottom-color", opacityScale(opacity)) 6.600 + .style("border-top-color", opacityScale(opacity)) 6.601 + ; 6.602 + } 6.603 + }); 6.604 + 6.605 + var html = table.node().outerHTML; 6.606 + if (d.footer !== undefined) 6.607 + html += "<div class='footer'>" + d.footer + "</div>"; 6.608 + return html; 6.609 + 6.610 + }; 6.611 + 6.612 + var dataSeriesExists = function(d) { 6.613 + if (d && d.series) { 6.614 + if (d.series instanceof Array) { 6.615 + return !!d.series.length; 6.616 + } 6.617 + // if object, it's okay just convert to array of the object 6.618 + if (d.series instanceof Object) { 6.619 + d.series = [d.series]; 6.620 + return true; 6.621 + } 6.622 + } 6.623 + return false; 6.624 + }; 6.625 + 6.626 + var calcTooltipPosition = function(pos) { 6.627 + if (!tooltipElem) return; 6.628 + 6.629 + nv.dom.read(function() { 6.630 + var height = parseInt(tooltipElem.offsetHeight, 10), 6.631 + width = parseInt(tooltipElem.offsetWidth, 10), 6.632 + windowWidth = nv.utils.windowSize().width, 6.633 + windowHeight = nv.utils.windowSize().height, 6.634 + scrollTop = window.pageYOffset, 6.635 + scrollLeft = window.pageXOffset, 6.636 + left, top; 6.637 + 6.638 + windowHeight = window.innerWidth >= document.body.scrollWidth ? windowHeight : windowHeight - 16; 6.639 + windowWidth = window.innerHeight >= document.body.scrollHeight ? windowWidth : windowWidth - 16; 6.640 + 6.641 + 6.642 + //Helper functions to find the total offsets of a given DOM element. 6.643 + //Looks up the entire ancestry of an element, up to the first relatively positioned element. 6.644 + var tooltipTop = function ( Elem ) { 6.645 + var offsetTop = top; 6.646 + do { 6.647 + if( !isNaN( Elem.offsetTop ) ) { 6.648 + offsetTop += (Elem.offsetTop); 6.649 + } 6.650 + Elem = Elem.offsetParent; 6.651 + } while( Elem ); 6.652 + return offsetTop; 6.653 + }; 6.654 + var tooltipLeft = function ( Elem ) { 6.655 + var offsetLeft = left; 6.656 + do { 6.657 + if( !isNaN( Elem.offsetLeft ) ) { 6.658 + offsetLeft += (Elem.offsetLeft); 6.659 + } 6.660 + Elem = Elem.offsetParent; 6.661 + } while( Elem ); 6.662 + return offsetLeft; 6.663 + }; 6.664 + 6.665 + // calculate position based on gravity 6.666 + var tLeft, tTop; 6.667 + switch (gravity) { 6.668 + case 'e': 6.669 + left = pos[0] - width - distance; 6.670 + top = pos[1] - (height / 2); 6.671 + tLeft = tooltipLeft(tooltipElem); 6.672 + tTop = tooltipTop(tooltipElem); 6.673 + if (tLeft < scrollLeft) left = pos[0] + distance > scrollLeft ? pos[0] + distance : scrollLeft - tLeft + left; 6.674 + if (tTop < scrollTop) top = scrollTop - tTop + top; 6.675 + if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height; 6.676 + break; 6.677 + case 'w': 6.678 + left = pos[0] + distance; 6.679 + top = pos[1] - (height / 2); 6.680 + tLeft = tooltipLeft(tooltipElem); 6.681 + tTop = tooltipTop(tooltipElem); 6.682 + if (tLeft + width > windowWidth) left = pos[0] - width - distance; 6.683 + if (tTop < scrollTop) top = scrollTop + 5; 6.684 + if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height; 6.685 + break; 6.686 + case 'n': 6.687 + left = pos[0] - (width / 2) - 5; 6.688 + top = pos[1] + distance; 6.689 + tLeft = tooltipLeft(tooltipElem); 6.690 + tTop = tooltipTop(tooltipElem); 6.691 + if (tLeft < scrollLeft) left = scrollLeft + 5; 6.692 + if (tLeft + width > windowWidth) left = left - width/2 + 5; 6.693 + if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height; 6.694 + break; 6.695 + case 's': 6.696 + left = pos[0] - (width / 2); 6.697 + top = pos[1] - height - distance; 6.698 + tLeft = tooltipLeft(tooltipElem); 6.699 + tTop = tooltipTop(tooltipElem); 6.700 + if (tLeft < scrollLeft) left = scrollLeft + 5; 6.701 + if (tLeft + width > windowWidth) left = left - width/2 + 5; 6.702 + if (scrollTop > tTop) top = scrollTop; 6.703 + break; 6.704 + case 'none': 6.705 + left = pos[0]; 6.706 + top = pos[1] - distance; 6.707 + tLeft = tooltipLeft(tooltipElem); 6.708 + tTop = tooltipTop(tooltipElem); 6.709 + break; 6.710 + } 6.711 + 6.712 + // adjust tooltip offsets 6.713 + left -= offset.left; 6.714 + top -= offset.top; 6.715 + 6.716 + // using tooltip.style('transform') returns values un-usable for tween 6.717 + var box = tooltipElem.getBoundingClientRect(); 6.718 + var scrollTop = window.pageYOffset || document.documentElement.scrollTop; 6.719 + var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; 6.720 + var old_translate = 'translate(' + (box.left + scrollLeft) + 'px, ' + (box.top + scrollTop) + 'px)'; 6.721 + var new_translate = 'translate(' + left + 'px, ' + top + 'px)'; 6.722 + var translateInterpolator = d3.interpolateString(old_translate, new_translate); 6.723 + 6.724 + var is_hidden = tooltip.style('opacity') < 0.1; 6.725 + 6.726 + // delay hiding a bit to avoid flickering 6.727 + if (hidden) { 6.728 + tooltip 6.729 + .transition() 6.730 + .delay(hideDelay) 6.731 + .duration(0) 6.732 + .style('opacity', 0); 6.733 + } else { 6.734 + tooltip 6.735 + .interrupt() // cancel running transitions 6.736 + .transition() 6.737 + .duration(is_hidden ? 0 : duration) 6.738 + // using tween since some versions of d3 can't auto-tween a translate on a div 6.739 + .styleTween('transform', function (d) { 6.740 + return translateInterpolator; 6.741 + }, 'important') 6.742 + // Safari has its own `-webkit-transform` and does not support `transform` 6.743 + // transform tooltip without transition only in Safari 6.744 + .style('-webkit-transform', new_translate) 6.745 + .style('opacity', 1); 6.746 + } 6.747 + 6.748 + 6.749 + 6.750 + }); 6.751 + }; 6.752 + 6.753 + //In situations where the chart is in a 'viewBox', re-position the tooltip based on how far chart is zoomed. 6.754 + function convertViewBoxRatio() { 6.755 + if (chartContainer) { 6.756 + var svg = d3.select(chartContainer); 6.757 + if (svg.node().tagName !== "svg") { 6.758 + svg = svg.select("svg"); 6.759 + } 6.760 + var viewBox = (svg.node()) ? svg.attr('viewBox') : null; 6.761 + if (viewBox) { 6.762 + viewBox = viewBox.split(' '); 6.763 + var ratio = parseInt(svg.style('width'), 10) / viewBox[2]; 6.764 + 6.765 + position.left = position.left * ratio; 6.766 + position.top = position.top * ratio; 6.767 + } 6.768 + } 6.769 + } 6.770 + 6.771 + //Creates new tooltip container, or uses existing one on DOM. 6.772 + function initTooltip() { 6.773 + if (!tooltip) { 6.774 + var body; 6.775 + if (chartContainer) { 6.776 + body = chartContainer; 6.777 + } else { 6.778 + body = document.body; 6.779 + } 6.780 + //Create new tooltip div if it doesn't exist on DOM. 6.781 + tooltip = d3.select(body).append("div") 6.782 + .attr("class", "nvtooltip " + (classes ? classes : "xy-tooltip")) 6.783 + .attr("id", id); 6.784 + tooltip.style("top", 0).style("left", 0); 6.785 + tooltip.style('opacity', 0); 6.786 + tooltip.selectAll("div, table, td, tr").classed(nvPointerEventsClass, true); 6.787 + tooltip.classed(nvPointerEventsClass, true); 6.788 + tooltipElem = tooltip.node(); 6.789 + } 6.790 + } 6.791 + 6.792 + //Draw the tooltip onto the DOM. 6.793 + function nvtooltip() { 6.794 + if (!enabled) return; 6.795 + if (!dataSeriesExists(data)) return; 6.796 + 6.797 + convertViewBoxRatio(); 6.798 + 6.799 + var left = position.left; 6.800 + var top = (fixedTop !== null) ? fixedTop : position.top; 6.801 + 6.802 + nv.dom.write(function () { 6.803 + initTooltip(); 6.804 + // generate data and set it into tooltip 6.805 + // Bonus - If you override contentGenerator and return falsey you can use something like 6.806 + // React or Knockout to bind the data for your tooltip 6.807 + var newContent = contentGenerator(data); 6.808 + if (newContent) { 6.809 + tooltipElem.innerHTML = newContent; 6.810 + } 6.811 + 6.812 + if (chartContainer && isInteractiveLayer) { 6.813 + nv.dom.read(function() { 6.814 + var svgComp = chartContainer.getElementsByTagName("svg")[0]; 6.815 + var svgOffset = {left:0,top:0}; 6.816 + if (svgComp) { 6.817 + var svgBound = svgComp.getBoundingClientRect(); 6.818 + var chartBound = chartContainer.getBoundingClientRect(); 6.819 + var svgBoundTop = svgBound.top; 6.820 + 6.821 + //Defensive code. Sometimes, svgBoundTop can be a really negative 6.822 + // number, like -134254. That's a bug. 6.823 + // If such a number is found, use zero instead. FireFox bug only 6.824 + if (svgBoundTop < 0) { 6.825 + var containerBound = chartContainer.getBoundingClientRect(); 6.826 + svgBoundTop = (Math.abs(svgBoundTop) > containerBound.height) ? 0 : svgBoundTop; 6.827 + } 6.828 + svgOffset.top = Math.abs(svgBoundTop - chartBound.top); 6.829 + svgOffset.left = Math.abs(svgBound.left - chartBound.left); 6.830 + } 6.831 + //If the parent container is an overflow <div> with scrollbars, subtract the scroll offsets. 6.832 + //You need to also add any offset between the <svg> element and its containing <div> 6.833 + //Finally, add any offset of the containing <div> on the whole page. 6.834 + left += chartContainer.offsetLeft + svgOffset.left - 2*chartContainer.scrollLeft; 6.835 + top += chartContainer.offsetTop + svgOffset.top - 2*chartContainer.scrollTop; 6.836 + 6.837 + if (snapDistance && snapDistance > 0) { 6.838 + top = Math.floor(top/snapDistance) * snapDistance; 6.839 + } 6.840 + calcTooltipPosition([left,top]); 6.841 + }); 6.842 + } else { 6.843 + calcTooltipPosition([left,top]); 6.844 + } 6.845 + }); 6.846 + 6.847 + return nvtooltip; 6.848 + } 6.849 + 6.850 + nvtooltip.nvPointerEventsClass = nvPointerEventsClass; 6.851 + nvtooltip.options = nv.utils.optionsFunc.bind(nvtooltip); 6.852 + 6.853 + nvtooltip._options = Object.create({}, { 6.854 + // simple read/write options 6.855 + duration: {get: function(){return duration;}, set: function(_){duration=_;}}, 6.856 + gravity: {get: function(){return gravity;}, set: function(_){gravity=_;}}, 6.857 + distance: {get: function(){return distance;}, set: function(_){distance=_;}}, 6.858 + snapDistance: {get: function(){return snapDistance;}, set: function(_){snapDistance=_;}}, 6.859 + classes: {get: function(){return classes;}, set: function(_){classes=_;}}, 6.860 + chartContainer: {get: function(){return chartContainer;}, set: function(_){chartContainer=_;}}, 6.861 + fixedTop: {get: function(){return fixedTop;}, set: function(_){fixedTop=_;}}, 6.862 + enabled: {get: function(){return enabled;}, set: function(_){enabled=_;}}, 6.863 + hideDelay: {get: function(){return hideDelay;}, set: function(_){hideDelay=_;}}, 6.864 + contentGenerator: {get: function(){return contentGenerator;}, set: function(_){contentGenerator=_;}}, 6.865 + valueFormatter: {get: function(){return valueFormatter;}, set: function(_){valueFormatter=_;}}, 6.866 + headerFormatter: {get: function(){return headerFormatter;}, set: function(_){headerFormatter=_;}}, 6.867 + keyFormatter: {get: function(){return keyFormatter;}, set: function(_){keyFormatter=_;}}, 6.868 + headerEnabled: {get: function(){return headerEnabled;}, set: function(_){headerEnabled=_;}}, 6.869 + 6.870 + // internal use only, set by interactive layer to adjust position. 6.871 + _isInteractiveLayer: {get: function(){return isInteractiveLayer;}, set: function(_){isInteractiveLayer=!!_;}}, 6.872 + 6.873 + // options with extra logic 6.874 + position: {get: function(){return position;}, set: function(_){ 6.875 + position.left = _.left !== undefined ? _.left : position.left; 6.876 + position.top = _.top !== undefined ? _.top : position.top; 6.877 + }}, 6.878 + offset: {get: function(){return offset;}, set: function(_){ 6.879 + offset.left = _.left !== undefined ? _.left : offset.left; 6.880 + offset.top = _.top !== undefined ? _.top : offset.top; 6.881 + }}, 6.882 + hidden: {get: function(){return hidden;}, set: function(_){ 6.883 + if (hidden != _) { 6.884 + hidden = !!_; 6.885 + nvtooltip(); 6.886 + } 6.887 + }}, 6.888 + data: {get: function(){return data;}, set: function(_){ 6.889 + // if showing a single data point, adjust data format with that 6.890 + if (_.point) { 6.891 + _.value = _.point.x; 6.892 + _.series = _.series || {}; 6.893 + _.series.value = _.point.y; 6.894 + _.series.color = _.point.color || _.series.color; 6.895 + } 6.896 + data = _; 6.897 + }}, 6.898 + 6.899 + // read only properties 6.900 + tooltipElem: {get: function(){return tooltipElem;}, set: function(_){}}, 6.901 + id: {get: function(){return id;}, set: function(_){}} 6.902 + }); 6.903 + 6.904 + nv.utils.initOptions(nvtooltip); 6.905 + return nvtooltip; 6.906 + }; 6.907 + 6.908 +})(); 6.909 + 6.910 + 6.911 +/* 6.912 +Gets the browser window size 6.913 + 6.914 +Returns object with height and width properties 6.915 + */ 6.916 +nv.utils.windowSize = function() { 6.917 + // Sane defaults 6.918 + var size = {width: 640, height: 480}; 6.919 + 6.920 + // Most recent browsers use 6.921 + if (window.innerWidth && window.innerHeight) { 6.922 + size.width = window.innerWidth; 6.923 + size.height = window.innerHeight; 6.924 + return (size); 6.925 + } 6.926 + 6.927 + // IE can use depending on mode it is in 6.928 + if (document.compatMode=='CSS1Compat' && 6.929 + document.documentElement && 6.930 + document.documentElement.offsetWidth ) { 6.931 + 6.932 + size.width = document.documentElement.offsetWidth; 6.933 + size.height = document.documentElement.offsetHeight; 6.934 + return (size); 6.935 + } 6.936 + 6.937 + // Earlier IE uses Doc.body 6.938 + if (document.body && document.body.offsetWidth) { 6.939 + size.width = document.body.offsetWidth; 6.940 + size.height = document.body.offsetHeight; 6.941 + return (size); 6.942 + } 6.943 + 6.944 + return (size); 6.945 +}; 6.946 + 6.947 +/* 6.948 +Binds callback function to run when window is resized 6.949 + */ 6.950 +nv.utils.windowResize = function(handler) { 6.951 + if (window.addEventListener) { 6.952 + window.addEventListener('resize', handler); 6.953 + } else { 6.954 + nv.log("ERROR: Failed to bind to window.resize with: ", handler); 6.955 + } 6.956 + // return object with clear function to remove the single added callback. 6.957 + return { 6.958 + callback: handler, 6.959 + clear: function() { 6.960 + window.removeEventListener('resize', handler); 6.961 + } 6.962 + } 6.963 +}; 6.964 + 6.965 + 6.966 +/* 6.967 +Backwards compatible way to implement more d3-like coloring of graphs. 6.968 +Can take in nothing, an array, or a function/scale 6.969 +To use a normal scale, get the range and pass that because we must be able 6.970 +to take two arguments and use the index to keep backward compatibility 6.971 +*/ 6.972 +nv.utils.getColor = function(color) { 6.973 + //if you pass in nothing, get default colors back 6.974 + if (color === undefined) { 6.975 + return nv.utils.defaultColor(); 6.976 + 6.977 + //if passed an array, turn it into a color scale 6.978 + // use isArray, instanceof fails if d3 range is created in an iframe 6.979 + } else if(Array.isArray(color)) { 6.980 + var color_scale = d3.scale.ordinal().range(color); 6.981 + return function(d, i) { 6.982 + var key = i === undefined ? d : i; 6.983 + return d.color || color_scale(key); 6.984 + }; 6.985 + 6.986 + //if passed a function or scale, return it, or whatever it may be 6.987 + //external libs, such as angularjs-nvd3-directives use this 6.988 + } else { 6.989 + //can't really help it if someone passes rubbish as color 6.990 + return color; 6.991 + } 6.992 +}; 6.993 + 6.994 + 6.995 +/* 6.996 +Default color chooser uses a color scale of 20 colors from D3 6.997 + https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors 6.998 + */ 6.999 +nv.utils.defaultColor = function() { 6.1000 + // get range of the scale so we'll turn it into our own function. 6.1001 + return nv.utils.getColor(d3.scale.category20().range()); 6.1002 +}; 6.1003 + 6.1004 + 6.1005 +/* 6.1006 +Returns a color function that takes the result of 'getKey' for each series and 6.1007 +looks for a corresponding color from the dictionary 6.1008 +*/ 6.1009 +nv.utils.customTheme = function(dictionary, getKey, defaultColors) { 6.1010 + // use default series.key if getKey is undefined 6.1011 + getKey = getKey || function(series) { return series.key }; 6.1012 + defaultColors = defaultColors || d3.scale.category20().range(); 6.1013 + 6.1014 + // start at end of default color list and walk back to index 0 6.1015 + var defIndex = defaultColors.length; 6.1016 + 6.1017 + return function(series, index) { 6.1018 + var key = getKey(series); 6.1019 + if (typeof dictionary[key] === 'function') { 6.1020 + return dictionary[key](); 6.1021 + } else if (dictionary[key] !== undefined) { 6.1022 + return dictionary[key]; 6.1023 + } else { 6.1024 + // no match in dictionary, use a default color 6.1025 + if (!defIndex) { 6.1026 + // used all the default colors, start over 6.1027 + defIndex = defaultColors.length; 6.1028 + } 6.1029 + defIndex = defIndex - 1; 6.1030 + return defaultColors[defIndex]; 6.1031 + } 6.1032 + }; 6.1033 +}; 6.1034 + 6.1035 + 6.1036 +/* 6.1037 +From the PJAX example on d3js.org, while this is not really directly needed 6.1038 +it's a very cool method for doing pjax, I may expand upon it a little bit, 6.1039 +open to suggestions on anything that may be useful 6.1040 +*/ 6.1041 +nv.utils.pjax = function(links, content) { 6.1042 + 6.1043 + var load = function(href) { 6.1044 + d3.html(href, function(fragment) { 6.1045 + var target = d3.select(content).node(); 6.1046 + target.parentNode.replaceChild( 6.1047 + d3.select(fragment).select(content).node(), 6.1048 + target); 6.1049 + nv.utils.pjax(links, content); 6.1050 + }); 6.1051 + }; 6.1052 + 6.1053 + d3.selectAll(links).on("click", function() { 6.1054 + history.pushState(this.href, this.textContent, this.href); 6.1055 + load(this.href); 6.1056 + d3.event.preventDefault(); 6.1057 + }); 6.1058 + 6.1059 + d3.select(window).on("popstate", function() { 6.1060 + if (d3.event.state) { 6.1061 + load(d3.event.state); 6.1062 + } 6.1063 + }); 6.1064 +}; 6.1065 + 6.1066 + 6.1067 +/* 6.1068 +For when we want to approximate the width in pixels for an SVG:text element. 6.1069 +Most common instance is when the element is in a display:none; container. 6.1070 +Forumla is : text.length * font-size * constant_factor 6.1071 +*/ 6.1072 +nv.utils.calcApproxTextWidth = function (svgTextElem) { 6.1073 + if (typeof svgTextElem.style === 'function' 6.1074 + && typeof svgTextElem.text === 'function') { 6.1075 + 6.1076 + var fontSize = parseInt(svgTextElem.style("font-size").replace("px",""), 10); 6.1077 + var textLength = svgTextElem.text().length; 6.1078 + return textLength * fontSize * 0.5; 6.1079 + } 6.1080 + return 0; 6.1081 +}; 6.1082 + 6.1083 + 6.1084 +/* 6.1085 +Numbers that are undefined, null or NaN, convert them to zeros. 6.1086 +*/ 6.1087 +nv.utils.NaNtoZero = function(n) { 6.1088 + if (typeof n !== 'number' 6.1089 + || isNaN(n) 6.1090 + || n === null 6.1091 + || n === Infinity 6.1092 + || n === -Infinity) { 6.1093 + 6.1094 + return 0; 6.1095 + } 6.1096 + return n; 6.1097 +}; 6.1098 + 6.1099 +/* 6.1100 +Add a way to watch for d3 transition ends to d3 6.1101 +*/ 6.1102 +d3.selection.prototype.watchTransition = function(renderWatch){ 6.1103 + var args = [this].concat([].slice.call(arguments, 1)); 6.1104 + return renderWatch.transition.apply(renderWatch, args); 6.1105 +}; 6.1106 + 6.1107 + 6.1108 +/* 6.1109 +Helper object to watch when d3 has rendered something 6.1110 +*/ 6.1111 +nv.utils.renderWatch = function(dispatch, duration) { 6.1112 + if (!(this instanceof nv.utils.renderWatch)) { 6.1113 + return new nv.utils.renderWatch(dispatch, duration); 6.1114 + } 6.1115 + 6.1116 + var _duration = duration !== undefined ? duration : 250; 6.1117 + var renderStack = []; 6.1118 + var self = this; 6.1119 + 6.1120 + this.models = function(models) { 6.1121 + models = [].slice.call(arguments, 0); 6.1122 + models.forEach(function(model){ 6.1123 + model.__rendered = false; 6.1124 + (function(m){ 6.1125 + m.dispatch.on('renderEnd', function(arg){ 6.1126 + m.__rendered = true; 6.1127 + self.renderEnd('model'); 6.1128 + }); 6.1129 + })(model); 6.1130 + 6.1131 + if (renderStack.indexOf(model) < 0) { 6.1132 + renderStack.push(model); 6.1133 + } 6.1134 + }); 6.1135 + return this; 6.1136 + }; 6.1137 + 6.1138 + this.reset = function(duration) { 6.1139 + if (duration !== undefined) { 6.1140 + _duration = duration; 6.1141 + } 6.1142 + renderStack = []; 6.1143 + }; 6.1144 + 6.1145 + this.transition = function(selection, args, duration) { 6.1146 + args = arguments.length > 1 ? [].slice.call(arguments, 1) : []; 6.1147 + 6.1148 + if (args.length > 1) { 6.1149 + duration = args.pop(); 6.1150 + } else { 6.1151 + duration = _duration !== undefined ? _duration : 250; 6.1152 + } 6.1153 + selection.__rendered = false; 6.1154 + 6.1155 + if (renderStack.indexOf(selection) < 0) { 6.1156 + renderStack.push(selection); 6.1157 + } 6.1158 + 6.1159 + if (duration === 0) { 6.1160 + selection.__rendered = true; 6.1161 + selection.delay = function() { return this; }; 6.1162 + selection.duration = function() { return this; }; 6.1163 + return selection; 6.1164 + } else { 6.1165 + if (selection.length === 0) { 6.1166 + selection.__rendered = true; 6.1167 + } else if (selection.every( function(d){ return !d.length; } )) { 6.1168 + selection.__rendered = true; 6.1169 + } else { 6.1170 + selection.__rendered = false; 6.1171 + } 6.1172 + 6.1173 + var n = 0; 6.1174 + return selection 6.1175 + .transition() 6.1176 + .duration(duration) 6.1177 + .each(function(){ ++n; }) 6.1178 + .each('end', function(d, i) { 6.1179 + if (--n === 0) { 6.1180 + selection.__rendered = true; 6.1181 + self.renderEnd.apply(this, args); 6.1182 + } 6.1183 + }); 6.1184 + } 6.1185 + }; 6.1186 + 6.1187 + this.renderEnd = function() { 6.1188 + if (renderStack.every( function(d){ return d.__rendered; } )) { 6.1189 + renderStack.forEach( function(d){ d.__rendered = false; }); 6.1190 + dispatch.renderEnd.apply(this, arguments); 6.1191 + } 6.1192 + } 6.1193 + 6.1194 +}; 6.1195 + 6.1196 + 6.1197 +/* 6.1198 +Takes multiple objects and combines them into the first one (dst) 6.1199 +example: nv.utils.deepExtend({a: 1}, {a: 2, b: 3}, {c: 4}); 6.1200 +gives: {a: 2, b: 3, c: 4} 6.1201 +*/ 6.1202 +nv.utils.deepExtend = function(dst){ 6.1203 + var sources = arguments.length > 1 ? [].slice.call(arguments, 1) : []; 6.1204 + sources.forEach(function(source) { 6.1205 + for (var key in source) { 6.1206 + var isArray = dst[key] instanceof Array; 6.1207 + var isObject = typeof dst[key] === 'object'; 6.1208 + var srcObj = typeof source[key] === 'object'; 6.1209 + 6.1210 + if (isObject && !isArray && srcObj) { 6.1211 + nv.utils.deepExtend(dst[key], source[key]); 6.1212 + } else { 6.1213 + dst[key] = source[key]; 6.1214 + } 6.1215 + } 6.1216 + }); 6.1217 +}; 6.1218 + 6.1219 + 6.1220 +/* 6.1221 +state utility object, used to track d3 states in the models 6.1222 +*/ 6.1223 +nv.utils.state = function(){ 6.1224 + if (!(this instanceof nv.utils.state)) { 6.1225 + return new nv.utils.state(); 6.1226 + } 6.1227 + var state = {}; 6.1228 + var _self = this; 6.1229 + var _setState = function(){}; 6.1230 + var _getState = function(){ return {}; }; 6.1231 + var init = null; 6.1232 + var changed = null; 6.1233 + 6.1234 + this.dispatch = d3.dispatch('change', 'set'); 6.1235 + 6.1236 + this.dispatch.on('set', function(state){ 6.1237 + _setState(state, true); 6.1238 + }); 6.1239 + 6.1240 + this.getter = function(fn){ 6.1241 + _getState = fn; 6.1242 + return this; 6.1243 + }; 6.1244 + 6.1245 + this.setter = function(fn, callback) { 6.1246 + if (!callback) { 6.1247 + callback = function(){}; 6.1248 + } 6.1249 + _setState = function(state, update){ 6.1250 + fn(state); 6.1251 + if (update) { 6.1252 + callback(); 6.1253 + } 6.1254 + }; 6.1255 + return this; 6.1256 + }; 6.1257 + 6.1258 + this.init = function(state){ 6.1259 + init = init || {}; 6.1260 + nv.utils.deepExtend(init, state); 6.1261 + }; 6.1262 + 6.1263 + var _set = function(){ 6.1264 + var settings = _getState(); 6.1265 + 6.1266 + if (JSON.stringify(settings) === JSON.stringify(state)) { 6.1267 + return false; 6.1268 + } 6.1269 + 6.1270 + for (var key in settings) { 6.1271 + if (state[key] === undefined) { 6.1272 + state[key] = {}; 6.1273 + } 6.1274 + state[key] = settings[key]; 6.1275 + changed = true; 6.1276 + } 6.1277 + return true; 6.1278 + }; 6.1279 + 6.1280 + this.update = function(){ 6.1281 + if (init) { 6.1282 + _setState(init, false); 6.1283 + init = null; 6.1284 + } 6.1285 + if (_set.call(this)) { 6.1286 + this.dispatch.change(state); 6.1287 + } 6.1288 + }; 6.1289 + 6.1290 +}; 6.1291 + 6.1292 + 6.1293 +/* 6.1294 +Snippet of code you can insert into each nv.models.* to give you the ability to 6.1295 +do things like: 6.1296 +chart.options({ 6.1297 + showXAxis: true, 6.1298 + tooltips: true 6.1299 +}); 6.1300 + 6.1301 +To enable in the chart: 6.1302 +chart.options = nv.utils.optionsFunc.bind(chart); 6.1303 +*/ 6.1304 +nv.utils.optionsFunc = function(args) { 6.1305 + if (args) { 6.1306 + d3.map(args).forEach((function(key,value) { 6.1307 + if (typeof this[key] === "function") { 6.1308 + this[key](value); 6.1309 + } 6.1310 + }).bind(this)); 6.1311 + } 6.1312 + return this; 6.1313 +}; 6.1314 + 6.1315 + 6.1316 +/* 6.1317 +numTicks: requested number of ticks 6.1318 +data: the chart data 6.1319 + 6.1320 +returns the number of ticks to actually use on X axis, based on chart data 6.1321 +to avoid duplicate ticks with the same value 6.1322 +*/ 6.1323 +nv.utils.calcTicksX = function(numTicks, data) { 6.1324 + // find max number of values from all data streams 6.1325 + var numValues = 1; 6.1326 + var i = 0; 6.1327 + for (i; i < data.length; i += 1) { 6.1328 + var stream_len = data[i] && data[i].values ? data[i].values.length : 0; 6.1329 + numValues = stream_len > numValues ? stream_len : numValues; 6.1330 + } 6.1331 + nv.log("Requested number of ticks: ", numTicks); 6.1332 + nv.log("Calculated max values to be: ", numValues); 6.1333 + // make sure we don't have more ticks than values to avoid duplicates 6.1334 + numTicks = numTicks > numValues ? numTicks = numValues - 1 : numTicks; 6.1335 + // make sure we have at least one tick 6.1336 + numTicks = numTicks < 1 ? 1 : numTicks; 6.1337 + // make sure it's an integer 6.1338 + numTicks = Math.floor(numTicks); 6.1339 + nv.log("Calculating tick count as: ", numTicks); 6.1340 + return numTicks; 6.1341 +}; 6.1342 + 6.1343 + 6.1344 +/* 6.1345 +returns number of ticks to actually use on Y axis, based on chart data 6.1346 +*/ 6.1347 +nv.utils.calcTicksY = function(numTicks, data) { 6.1348 + // currently uses the same logic but we can adjust here if needed later 6.1349 + return nv.utils.calcTicksX(numTicks, data); 6.1350 +}; 6.1351 + 6.1352 + 6.1353 +/* 6.1354 +Add a particular option from an options object onto chart 6.1355 +Options exposed on a chart are a getter/setter function that returns chart 6.1356 +on set to mimic typical d3 option chaining, e.g. svg.option1('a').option2('b'); 6.1357 + 6.1358 +option objects should be generated via Object.create() to provide 6.1359 +the option of manipulating data via get/set functions. 6.1360 +*/ 6.1361 +nv.utils.initOption = function(chart, name) { 6.1362 + // if it's a call option, just call it directly, otherwise do get/set 6.1363 + if (chart._calls && chart._calls[name]) { 6.1364 + chart[name] = chart._calls[name]; 6.1365 + } else { 6.1366 + chart[name] = function (_) { 6.1367 + if (!arguments.length) return chart._options[name]; 6.1368 + chart._overrides[name] = true; 6.1369 + chart._options[name] = _; 6.1370 + return chart; 6.1371 + }; 6.1372 + // calling the option as _option will ignore if set by option already 6.1373 + // so nvd3 can set options internally but the stop if set manually 6.1374 + chart['_' + name] = function(_) { 6.1375 + if (!arguments.length) return chart._options[name]; 6.1376 + if (!chart._overrides[name]) { 6.1377 + chart._options[name] = _; 6.1378 + } 6.1379 + return chart; 6.1380 + } 6.1381 + } 6.1382 +}; 6.1383 + 6.1384 + 6.1385 +/* 6.1386 +Add all options in an options object to the chart 6.1387 +*/ 6.1388 +nv.utils.initOptions = function(chart) { 6.1389 + chart._overrides = chart._overrides || {}; 6.1390 + var ops = Object.getOwnPropertyNames(chart._options || {}); 6.1391 + var calls = Object.getOwnPropertyNames(chart._calls || {}); 6.1392 + ops = ops.concat(calls); 6.1393 + for (var i in ops) { 6.1394 + nv.utils.initOption(chart, ops[i]); 6.1395 + } 6.1396 +}; 6.1397 + 6.1398 + 6.1399 +/* 6.1400 +Inherit options from a D3 object 6.1401 +d3.rebind makes calling the function on target actually call it on source 6.1402 +Also use _d3options so we can track what we inherit for documentation and chained inheritance 6.1403 +*/ 6.1404 +nv.utils.inheritOptionsD3 = function(target, d3_source, oplist) { 6.1405 + target._d3options = oplist.concat(target._d3options || []); 6.1406 + oplist.unshift(d3_source); 6.1407 + oplist.unshift(target); 6.1408 + d3.rebind.apply(this, oplist); 6.1409 +}; 6.1410 + 6.1411 + 6.1412 +/* 6.1413 +Remove duplicates from an array 6.1414 +*/ 6.1415 +nv.utils.arrayUnique = function(a) { 6.1416 + return a.sort().filter(function(item, pos) { 6.1417 + return !pos || item != a[pos - 1]; 6.1418 + }); 6.1419 +}; 6.1420 + 6.1421 + 6.1422 +/* 6.1423 +Keeps a list of custom symbols to draw from in addition to d3.svg.symbol 6.1424 +Necessary since d3 doesn't let you extend its list -_- 6.1425 +Add new symbols by doing nv.utils.symbols.set('name', function(size){...}); 6.1426 +*/ 6.1427 +nv.utils.symbolMap = d3.map(); 6.1428 + 6.1429 + 6.1430 +/* 6.1431 +Replaces d3.svg.symbol so that we can look both there and our own map 6.1432 + */ 6.1433 +nv.utils.symbol = function() { 6.1434 + var type, 6.1435 + size = 64; 6.1436 + function symbol(d,i) { 6.1437 + var t = type.call(this,d,i); 6.1438 + var s = size.call(this,d,i); 6.1439 + if (d3.svg.symbolTypes.indexOf(t) !== -1) { 6.1440 + return d3.svg.symbol().type(t).size(s)(); 6.1441 + } else { 6.1442 + return nv.utils.symbolMap.get(t)(s); 6.1443 + } 6.1444 + } 6.1445 + symbol.type = function(_) { 6.1446 + if (!arguments.length) return type; 6.1447 + type = d3.functor(_); 6.1448 + return symbol; 6.1449 + }; 6.1450 + symbol.size = function(_) { 6.1451 + if (!arguments.length) return size; 6.1452 + size = d3.functor(_); 6.1453 + return symbol; 6.1454 + }; 6.1455 + return symbol; 6.1456 +}; 6.1457 + 6.1458 + 6.1459 +/* 6.1460 +Inherit option getter/setter functions from source to target 6.1461 +d3.rebind makes calling the function on target actually call it on source 6.1462 +Also track via _inherited and _d3options so we can track what we inherit 6.1463 +for documentation generation purposes and chained inheritance 6.1464 +*/ 6.1465 +nv.utils.inheritOptions = function(target, source) { 6.1466 + // inherit all the things 6.1467 + var ops = Object.getOwnPropertyNames(source._options || {}); 6.1468 + var calls = Object.getOwnPropertyNames(source._calls || {}); 6.1469 + var inherited = source._inherited || []; 6.1470 + var d3ops = source._d3options || []; 6.1471 + var args = ops.concat(calls).concat(inherited).concat(d3ops); 6.1472 + args.unshift(source); 6.1473 + args.unshift(target); 6.1474 + d3.rebind.apply(this, args); 6.1475 + // pass along the lists to keep track of them, don't allow duplicates 6.1476 + target._inherited = nv.utils.arrayUnique(ops.concat(calls).concat(inherited).concat(ops).concat(target._inherited || [])); 6.1477 + target._d3options = nv.utils.arrayUnique(d3ops.concat(target._d3options || [])); 6.1478 +}; 6.1479 + 6.1480 + 6.1481 +/* 6.1482 +Runs common initialize code on the svg before the chart builds 6.1483 +*/ 6.1484 +nv.utils.initSVG = function(svg) { 6.1485 + svg.classed({'nvd3-svg':true}); 6.1486 +}; 6.1487 + 6.1488 + 6.1489 +/* 6.1490 +Sanitize and provide default for the container height. 6.1491 +*/ 6.1492 +nv.utils.sanitizeHeight = function(height, container) { 6.1493 + return (height || parseInt(container.style('height'), 10) || 400); 6.1494 +}; 6.1495 + 6.1496 + 6.1497 +/* 6.1498 +Sanitize and provide default for the container width. 6.1499 +*/ 6.1500 +nv.utils.sanitizeWidth = function(width, container) { 6.1501 + return (width || parseInt(container.style('width'), 10) || 960); 6.1502 +}; 6.1503 + 6.1504 + 6.1505 +/* 6.1506 +Calculate the available height for a chart. 6.1507 +*/ 6.1508 +nv.utils.availableHeight = function(height, container, margin) { 6.1509 + return nv.utils.sanitizeHeight(height, container) - margin.top - margin.bottom; 6.1510 +}; 6.1511 + 6.1512 +/* 6.1513 +Calculate the available width for a chart. 6.1514 +*/ 6.1515 +nv.utils.availableWidth = function(width, container, margin) { 6.1516 + return nv.utils.sanitizeWidth(width, container) - margin.left - margin.right; 6.1517 +}; 6.1518 + 6.1519 +/* 6.1520 +Clear any rendered chart components and display a chart's 'noData' message 6.1521 +*/ 6.1522 +nv.utils.noData = function(chart, container) { 6.1523 + var opt = chart.options(), 6.1524 + margin = opt.margin(), 6.1525 + noData = opt.noData(), 6.1526 + data = (noData == null) ? ["No Data Available."] : [noData], 6.1527 + height = nv.utils.availableHeight(opt.height(), container, margin), 6.1528 + width = nv.utils.availableWidth(opt.width(), container, margin), 6.1529 + x = margin.left + width/2, 6.1530 + y = margin.top + height/2; 6.1531 + 6.1532 + //Remove any previously created chart components 6.1533 + container.selectAll('g').remove(); 6.1534 + 6.1535 + var noDataText = container.selectAll('.nv-noData').data(data); 6.1536 + 6.1537 + noDataText.enter().append('text') 6.1538 + .attr('class', 'nvd3 nv-noData') 6.1539 + .attr('dy', '-.7em') 6.1540 + .style('text-anchor', 'middle'); 6.1541 + 6.1542 + noDataText 6.1543 + .attr('x', x) 6.1544 + .attr('y', y) 6.1545 + .text(function(t){ return t; }); 6.1546 +}; 6.1547 + 6.1548 +nv.models.axis = function() { 6.1549 + "use strict"; 6.1550 + 6.1551 + //============================================================ 6.1552 + // Public Variables with Default Settings 6.1553 + //------------------------------------------------------------ 6.1554 + 6.1555 + var axis = d3.svg.axis(); 6.1556 + var scale = d3.scale.linear(); 6.1557 + 6.1558 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.1559 + , width = 75 //only used for tickLabel currently 6.1560 + , height = 60 //only used for tickLabel currently 6.1561 + , axisLabelText = null 6.1562 + , showMaxMin = true //TODO: showMaxMin should be disabled on all ordinal scaled axes 6.1563 + , rotateLabels = 0 6.1564 + , rotateYLabel = true 6.1565 + , staggerLabels = false 6.1566 + , isOrdinal = false 6.1567 + , ticks = null 6.1568 + , axisLabelDistance = 0 6.1569 + , duration = 250 6.1570 + , dispatch = d3.dispatch('renderEnd') 6.1571 + ; 6.1572 + axis 6.1573 + .scale(scale) 6.1574 + .orient('bottom') 6.1575 + .tickFormat(function(d) { return d }) 6.1576 + ; 6.1577 + 6.1578 + //============================================================ 6.1579 + // Private Variables 6.1580 + //------------------------------------------------------------ 6.1581 + 6.1582 + var scale0; 6.1583 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.1584 + 6.1585 + function chart(selection) { 6.1586 + renderWatch.reset(); 6.1587 + selection.each(function(data) { 6.1588 + var container = d3.select(this); 6.1589 + nv.utils.initSVG(container); 6.1590 + 6.1591 + // Setup containers and skeleton of chart 6.1592 + var wrap = container.selectAll('g.nv-wrap.nv-axis').data([data]); 6.1593 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-axis'); 6.1594 + var gEnter = wrapEnter.append('g'); 6.1595 + var g = wrap.select('g'); 6.1596 + 6.1597 + if (ticks !== null) 6.1598 + axis.ticks(ticks); 6.1599 + else if (axis.orient() == 'top' || axis.orient() == 'bottom') 6.1600 + axis.ticks(Math.abs(scale.range()[1] - scale.range()[0]) / 100); 6.1601 + 6.1602 + //TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component 6.1603 + g.watchTransition(renderWatch, 'axis').call(axis); 6.1604 + 6.1605 + scale0 = scale0 || axis.scale(); 6.1606 + 6.1607 + var fmt = axis.tickFormat(); 6.1608 + if (fmt == null) { 6.1609 + fmt = scale0.tickFormat(); 6.1610 + } 6.1611 + 6.1612 + var axisLabel = g.selectAll('text.nv-axislabel') 6.1613 + .data([axisLabelText || null]); 6.1614 + axisLabel.exit().remove(); 6.1615 + 6.1616 + var xLabelMargin; 6.1617 + var axisMaxMin; 6.1618 + var w; 6.1619 + switch (axis.orient()) { 6.1620 + case 'top': 6.1621 + axisLabel.enter().append('text').attr('class', 'nv-axislabel'); 6.1622 + if (scale.range().length < 2) { 6.1623 + w = 0; 6.1624 + } else if (scale.range().length === 2) { 6.1625 + w = scale.range()[1]; 6.1626 + } else { 6.1627 + w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]); 6.1628 + } 6.1629 + axisLabel 6.1630 + .attr('text-anchor', 'middle') 6.1631 + .attr('y', 0) 6.1632 + .attr('x', w/2); 6.1633 + if (showMaxMin) { 6.1634 + axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') 6.1635 + .data(scale.domain()); 6.1636 + axisMaxMin.enter().append('g').attr('class',function(d,i){ 6.1637 + return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ') 6.1638 + }).append('text'); 6.1639 + axisMaxMin.exit().remove(); 6.1640 + axisMaxMin 6.1641 + .attr('transform', function(d,i) { 6.1642 + return 'translate(' + nv.utils.NaNtoZero(scale(d)) + ',0)' 6.1643 + }) 6.1644 + .select('text') 6.1645 + .attr('dy', '-0.5em') 6.1646 + .attr('y', -axis.tickPadding()) 6.1647 + .attr('text-anchor', 'middle') 6.1648 + .text(function(d,i) { 6.1649 + var v = fmt(d); 6.1650 + return ('' + v).match('NaN') ? '' : v; 6.1651 + }); 6.1652 + axisMaxMin.watchTransition(renderWatch, 'min-max top') 6.1653 + .attr('transform', function(d,i) { 6.1654 + return 'translate(' + nv.utils.NaNtoZero(scale.range()[i]) + ',0)' 6.1655 + }); 6.1656 + } 6.1657 + break; 6.1658 + case 'bottom': 6.1659 + xLabelMargin = axisLabelDistance + 36; 6.1660 + var maxTextWidth = 30; 6.1661 + var textHeight = 0; 6.1662 + var xTicks = g.selectAll('g').select("text"); 6.1663 + var rotateLabelsRule = ''; 6.1664 + if (rotateLabels%360) { 6.1665 + //Calculate the longest xTick width 6.1666 + xTicks.each(function(d,i){ 6.1667 + var box = this.getBoundingClientRect(); 6.1668 + var width = box.width; 6.1669 + textHeight = box.height; 6.1670 + if(width > maxTextWidth) maxTextWidth = width; 6.1671 + }); 6.1672 + rotateLabelsRule = 'rotate(' + rotateLabels + ' 0,' + (textHeight/2 + axis.tickPadding()) + ')'; 6.1673 + //Convert to radians before calculating sin. Add 30 to margin for healthy padding. 6.1674 + var sin = Math.abs(Math.sin(rotateLabels*Math.PI/180)); 6.1675 + xLabelMargin = (sin ? sin*maxTextWidth : maxTextWidth)+30; 6.1676 + //Rotate all xTicks 6.1677 + xTicks 6.1678 + .attr('transform', rotateLabelsRule) 6.1679 + .style('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end'); 6.1680 + } 6.1681 + axisLabel.enter().append('text').attr('class', 'nv-axislabel'); 6.1682 + if (scale.range().length < 2) { 6.1683 + w = 0; 6.1684 + } else if (scale.range().length === 2) { 6.1685 + w = scale.range()[1]; 6.1686 + } else { 6.1687 + w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]); 6.1688 + } 6.1689 + axisLabel 6.1690 + .attr('text-anchor', 'middle') 6.1691 + .attr('y', xLabelMargin) 6.1692 + .attr('x', w/2); 6.1693 + if (showMaxMin) { 6.1694 + //if (showMaxMin && !isOrdinal) { 6.1695 + axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') 6.1696 + //.data(scale.domain()) 6.1697 + .data([scale.domain()[0], scale.domain()[scale.domain().length - 1]]); 6.1698 + axisMaxMin.enter().append('g').attr('class',function(d,i){ 6.1699 + return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ') 6.1700 + }).append('text'); 6.1701 + axisMaxMin.exit().remove(); 6.1702 + axisMaxMin 6.1703 + .attr('transform', function(d,i) { 6.1704 + return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)' 6.1705 + }) 6.1706 + .select('text') 6.1707 + .attr('dy', '.71em') 6.1708 + .attr('y', axis.tickPadding()) 6.1709 + .attr('transform', rotateLabelsRule) 6.1710 + .style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle') 6.1711 + .text(function(d,i) { 6.1712 + var v = fmt(d); 6.1713 + return ('' + v).match('NaN') ? '' : v; 6.1714 + }); 6.1715 + axisMaxMin.watchTransition(renderWatch, 'min-max bottom') 6.1716 + .attr('transform', function(d,i) { 6.1717 + return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)' 6.1718 + }); 6.1719 + } 6.1720 + if (staggerLabels) 6.1721 + xTicks 6.1722 + .attr('transform', function(d,i) { 6.1723 + return 'translate(0,' + (i % 2 == 0 ? '0' : '12') + ')' 6.1724 + }); 6.1725 + 6.1726 + break; 6.1727 + case 'right': 6.1728 + axisLabel.enter().append('text').attr('class', 'nv-axislabel'); 6.1729 + axisLabel 6.1730 + .style('text-anchor', rotateYLabel ? 'middle' : 'begin') 6.1731 + .attr('transform', rotateYLabel ? 'rotate(90)' : '') 6.1732 + .attr('y', rotateYLabel ? (-Math.max(margin.right, width) + 12) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart 6.1733 + .attr('x', rotateYLabel ? (d3.max(scale.range()) / 2) : axis.tickPadding()); 6.1734 + if (showMaxMin) { 6.1735 + axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') 6.1736 + .data(scale.domain()); 6.1737 + axisMaxMin.enter().append('g').attr('class',function(d,i){ 6.1738 + return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ') 6.1739 + }).append('text') 6.1740 + .style('opacity', 0); 6.1741 + axisMaxMin.exit().remove(); 6.1742 + axisMaxMin 6.1743 + .attr('transform', function(d,i) { 6.1744 + return 'translate(0,' + nv.utils.NaNtoZero(scale(d)) + ')' 6.1745 + }) 6.1746 + .select('text') 6.1747 + .attr('dy', '.32em') 6.1748 + .attr('y', 0) 6.1749 + .attr('x', axis.tickPadding()) 6.1750 + .style('text-anchor', 'start') 6.1751 + .text(function(d, i) { 6.1752 + var v = fmt(d); 6.1753 + return ('' + v).match('NaN') ? '' : v; 6.1754 + }); 6.1755 + axisMaxMin.watchTransition(renderWatch, 'min-max right') 6.1756 + .attr('transform', function(d,i) { 6.1757 + return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')' 6.1758 + }) 6.1759 + .select('text') 6.1760 + .style('opacity', 1); 6.1761 + } 6.1762 + break; 6.1763 + case 'left': 6.1764 + /* 6.1765 + //For dynamically placing the label. Can be used with dynamically-sized chart axis margins 6.1766 + var yTicks = g.selectAll('g').select("text"); 6.1767 + yTicks.each(function(d,i){ 6.1768 + var labelPadding = this.getBoundingClientRect().width + axis.tickPadding() + 16; 6.1769 + if(labelPadding > width) width = labelPadding; 6.1770 + }); 6.1771 + */ 6.1772 + axisLabel.enter().append('text').attr('class', 'nv-axislabel'); 6.1773 + axisLabel 6.1774 + .style('text-anchor', rotateYLabel ? 'middle' : 'end') 6.1775 + .attr('transform', rotateYLabel ? 'rotate(-90)' : '') 6.1776 + .attr('y', rotateYLabel ? (-Math.max(margin.left, width) + 25 - (axisLabelDistance || 0)) : -10) 6.1777 + .attr('x', rotateYLabel ? (-d3.max(scale.range()) / 2) : -axis.tickPadding()); 6.1778 + if (showMaxMin) { 6.1779 + axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') 6.1780 + .data(scale.domain()); 6.1781 + axisMaxMin.enter().append('g').attr('class',function(d,i){ 6.1782 + return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ') 6.1783 + }).append('text') 6.1784 + .style('opacity', 0); 6.1785 + axisMaxMin.exit().remove(); 6.1786 + axisMaxMin 6.1787 + .attr('transform', function(d,i) { 6.1788 + return 'translate(0,' + nv.utils.NaNtoZero(scale0(d)) + ')' 6.1789 + }) 6.1790 + .select('text') 6.1791 + .attr('dy', '.32em') 6.1792 + .attr('y', 0) 6.1793 + .attr('x', -axis.tickPadding()) 6.1794 + .attr('text-anchor', 'end') 6.1795 + .text(function(d,i) { 6.1796 + var v = fmt(d); 6.1797 + return ('' + v).match('NaN') ? '' : v; 6.1798 + }); 6.1799 + axisMaxMin.watchTransition(renderWatch, 'min-max right') 6.1800 + .attr('transform', function(d,i) { 6.1801 + return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')' 6.1802 + }) 6.1803 + .select('text') 6.1804 + .style('opacity', 1); 6.1805 + } 6.1806 + break; 6.1807 + } 6.1808 + axisLabel.text(function(d) { return d }); 6.1809 + 6.1810 + if (showMaxMin && (axis.orient() === 'left' || axis.orient() === 'right')) { 6.1811 + //check if max and min overlap other values, if so, hide the values that overlap 6.1812 + g.selectAll('g') // the g's wrapping each tick 6.1813 + .each(function(d,i) { 6.1814 + d3.select(this).select('text').attr('opacity', 1); 6.1815 + if (scale(d) < scale.range()[1] + 10 || scale(d) > scale.range()[0] - 10) { // 10 is assuming text height is 16... if d is 0, leave it! 6.1816 + if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL 6.1817 + d3.select(this).attr('opacity', 0); 6.1818 + 6.1819 + d3.select(this).select('text').attr('opacity', 0); // Don't remove the ZERO line!! 6.1820 + } 6.1821 + }); 6.1822 + 6.1823 + //if Max and Min = 0 only show min, Issue #281 6.1824 + if (scale.domain()[0] == scale.domain()[1] && scale.domain()[0] == 0) { 6.1825 + wrap.selectAll('g.nv-axisMaxMin').style('opacity', function (d, i) { 6.1826 + return !i ? 1 : 0 6.1827 + }); 6.1828 + } 6.1829 + } 6.1830 + 6.1831 + if (showMaxMin && (axis.orient() === 'top' || axis.orient() === 'bottom')) { 6.1832 + var maxMinRange = []; 6.1833 + wrap.selectAll('g.nv-axisMaxMin') 6.1834 + .each(function(d,i) { 6.1835 + try { 6.1836 + if (i) // i== 1, max position 6.1837 + maxMinRange.push(scale(d) - this.getBoundingClientRect().width - 4); //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case) 6.1838 + else // i==0, min position 6.1839 + maxMinRange.push(scale(d) + this.getBoundingClientRect().width + 4) 6.1840 + }catch (err) { 6.1841 + if (i) // i== 1, max position 6.1842 + maxMinRange.push(scale(d) - 4); //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case) 6.1843 + else // i==0, min position 6.1844 + maxMinRange.push(scale(d) + 4); 6.1845 + } 6.1846 + }); 6.1847 + // the g's wrapping each tick 6.1848 + g.selectAll('g').each(function(d, i) { 6.1849 + if (scale(d) < maxMinRange[0] || scale(d) > maxMinRange[1]) { 6.1850 + if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL 6.1851 + d3.select(this).remove(); 6.1852 + else 6.1853 + d3.select(this).select('text').remove(); // Don't remove the ZERO line!! 6.1854 + } 6.1855 + }); 6.1856 + } 6.1857 + 6.1858 + //Highlight zero tick line 6.1859 + g.selectAll('.tick') 6.1860 + .filter(function (d) { 6.1861 + /* 6.1862 + The filter needs to return only ticks at or near zero. 6.1863 + Numbers like 0.00001 need to count as zero as well, 6.1864 + and the arithmetic trick below solves that. 6.1865 + */ 6.1866 + return !parseFloat(Math.round(d * 100000) / 1000000) && (d !== undefined) 6.1867 + }) 6.1868 + .classed('zero', true); 6.1869 + 6.1870 + //store old scales for use in transitions on update 6.1871 + scale0 = scale.copy(); 6.1872 + 6.1873 + }); 6.1874 + 6.1875 + renderWatch.renderEnd('axis immediate'); 6.1876 + return chart; 6.1877 + } 6.1878 + 6.1879 + //============================================================ 6.1880 + // Expose Public Variables 6.1881 + //------------------------------------------------------------ 6.1882 + 6.1883 + // expose chart's sub-components 6.1884 + chart.axis = axis; 6.1885 + chart.dispatch = dispatch; 6.1886 + 6.1887 + chart.options = nv.utils.optionsFunc.bind(chart); 6.1888 + chart._options = Object.create({}, { 6.1889 + // simple options, just get/set the necessary values 6.1890 + axisLabelDistance: {get: function(){return axisLabelDistance;}, set: function(_){axisLabelDistance=_;}}, 6.1891 + staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, 6.1892 + rotateLabels: {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}}, 6.1893 + rotateYLabel: {get: function(){return rotateYLabel;}, set: function(_){rotateYLabel=_;}}, 6.1894 + showMaxMin: {get: function(){return showMaxMin;}, set: function(_){showMaxMin=_;}}, 6.1895 + axisLabel: {get: function(){return axisLabelText;}, set: function(_){axisLabelText=_;}}, 6.1896 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.1897 + ticks: {get: function(){return ticks;}, set: function(_){ticks=_;}}, 6.1898 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.1899 + 6.1900 + // options that require extra logic in the setter 6.1901 + margin: {get: function(){return margin;}, set: function(_){ 6.1902 + margin.top = _.top !== undefined ? _.top : margin.top; 6.1903 + margin.right = _.right !== undefined ? _.right : margin.right; 6.1904 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.1905 + margin.left = _.left !== undefined ? _.left : margin.left; 6.1906 + }}, 6.1907 + duration: {get: function(){return duration;}, set: function(_){ 6.1908 + duration=_; 6.1909 + renderWatch.reset(duration); 6.1910 + }}, 6.1911 + scale: {get: function(){return scale;}, set: function(_){ 6.1912 + scale = _; 6.1913 + axis.scale(scale); 6.1914 + isOrdinal = typeof scale.rangeBands === 'function'; 6.1915 + nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']); 6.1916 + }} 6.1917 + }); 6.1918 + 6.1919 + nv.utils.initOptions(chart); 6.1920 + nv.utils.inheritOptionsD3(chart, axis, ['orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat']); 6.1921 + nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']); 6.1922 + 6.1923 + return chart; 6.1924 +}; 6.1925 +nv.models.boxPlot = function() { 6.1926 + "use strict"; 6.1927 + 6.1928 + //============================================================ 6.1929 + // Public Variables with Default Settings 6.1930 + //------------------------------------------------------------ 6.1931 + 6.1932 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.1933 + , width = 960 6.1934 + , height = 500 6.1935 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.1936 + , x = d3.scale.ordinal() 6.1937 + , y = d3.scale.linear() 6.1938 + , getX = function(d) { return d.x } 6.1939 + , getY = function(d) { return d.y } 6.1940 + , color = nv.utils.defaultColor() 6.1941 + , container = null 6.1942 + , xDomain 6.1943 + , yDomain 6.1944 + , xRange 6.1945 + , yRange 6.1946 + , dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') 6.1947 + , duration = 250 6.1948 + , maxBoxWidth = null 6.1949 + ; 6.1950 + 6.1951 + //============================================================ 6.1952 + // Private Variables 6.1953 + //------------------------------------------------------------ 6.1954 + 6.1955 + var x0, y0; 6.1956 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.1957 + 6.1958 + function chart(selection) { 6.1959 + renderWatch.reset(); 6.1960 + selection.each(function(data) { 6.1961 + var availableWidth = width - margin.left - margin.right, 6.1962 + availableHeight = height - margin.top - margin.bottom; 6.1963 + 6.1964 + container = d3.select(this); 6.1965 + nv.utils.initSVG(container); 6.1966 + 6.1967 + // Setup Scales 6.1968 + x .domain(xDomain || data.map(function(d,i) { return getX(d,i); })) 6.1969 + .rangeBands(xRange || [0, availableWidth], .1); 6.1970 + 6.1971 + // if we know yDomain, no need to calculate 6.1972 + var yData = [] 6.1973 + if (!yDomain) { 6.1974 + // (y-range is based on quartiles, whiskers and outliers) 6.1975 + 6.1976 + // lower values 6.1977 + var yMin = d3.min(data.map(function(d) { 6.1978 + var min_arr = []; 6.1979 + 6.1980 + min_arr.push(d.values.Q1); 6.1981 + if (d.values.hasOwnProperty('whisker_low') && d.values.whisker_low !== null) { min_arr.push(d.values.whisker_low); } 6.1982 + if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { min_arr = min_arr.concat(d.values.outliers); } 6.1983 + 6.1984 + return d3.min(min_arr); 6.1985 + })); 6.1986 + 6.1987 + // upper values 6.1988 + var yMax = d3.max(data.map(function(d) { 6.1989 + var max_arr = []; 6.1990 + 6.1991 + max_arr.push(d.values.Q3); 6.1992 + if (d.values.hasOwnProperty('whisker_high') && d.values.whisker_high !== null) { max_arr.push(d.values.whisker_high); } 6.1993 + if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { max_arr = max_arr.concat(d.values.outliers); } 6.1994 + 6.1995 + return d3.max(max_arr); 6.1996 + })); 6.1997 + 6.1998 + yData = [ yMin, yMax ] ; 6.1999 + } 6.2000 + 6.2001 + y.domain(yDomain || yData); 6.2002 + y.range(yRange || [availableHeight, 0]); 6.2003 + 6.2004 + //store old scales if they exist 6.2005 + x0 = x0 || x; 6.2006 + y0 = y0 || y.copy().range([y(0),y(0)]); 6.2007 + 6.2008 + // Setup containers and skeleton of chart 6.2009 + var wrap = container.selectAll('g.nv-wrap').data([data]); 6.2010 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap'); 6.2011 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.2012 + 6.2013 + var boxplots = wrap.selectAll('.nv-boxplot').data(function(d) { return d }); 6.2014 + var boxEnter = boxplots.enter().append('g').style('stroke-opacity', 1e-6).style('fill-opacity', 1e-6); 6.2015 + boxplots 6.2016 + .attr('class', 'nv-boxplot') 6.2017 + .attr('transform', function(d,i,j) { return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05) + ', 0)'; }) 6.2018 + .classed('hover', function(d) { return d.hover }); 6.2019 + boxplots 6.2020 + .watchTransition(renderWatch, 'nv-boxplot: boxplots') 6.2021 + .style('stroke-opacity', 1) 6.2022 + .style('fill-opacity', .75) 6.2023 + .delay(function(d,i) { return i * duration / data.length }) 6.2024 + .attr('transform', function(d,i) { 6.2025 + return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05) + ', 0)'; 6.2026 + }); 6.2027 + boxplots.exit().remove(); 6.2028 + 6.2029 + // ----- add the SVG elements for each boxPlot ----- 6.2030 + 6.2031 + // conditionally append whisker lines 6.2032 + boxEnter.each(function(d,i) { 6.2033 + var box = d3.select(this); 6.2034 + 6.2035 + ['low', 'high'].forEach(function(key) { 6.2036 + if (d.values.hasOwnProperty('whisker_' + key) && d.values['whisker_' + key] !== null) { 6.2037 + box.append('line') 6.2038 + .style('stroke', (d.color) ? d.color : color(d,i)) 6.2039 + .attr('class', 'nv-boxplot-whisker nv-boxplot-' + key); 6.2040 + 6.2041 + box.append('line') 6.2042 + .style('stroke', (d.color) ? d.color : color(d,i)) 6.2043 + .attr('class', 'nv-boxplot-tick nv-boxplot-' + key); 6.2044 + } 6.2045 + }); 6.2046 + }); 6.2047 + 6.2048 + // outliers 6.2049 + // TODO: support custom colors here 6.2050 + var outliers = boxplots.selectAll('.nv-boxplot-outlier').data(function(d) { 6.2051 + if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { return d.values.outliers; } 6.2052 + else { return []; } 6.2053 + }); 6.2054 + outliers.enter().append('circle') 6.2055 + .style('fill', function(d,i,j) { return color(d,j) }).style('stroke', function(d,i,j) { return color(d,j) }) 6.2056 + .on('mouseover', function(d,i,j) { 6.2057 + d3.select(this).classed('hover', true); 6.2058 + dispatch.elementMouseover({ 6.2059 + series: { key: d, color: color(d,j) }, 6.2060 + e: d3.event 6.2061 + }); 6.2062 + }) 6.2063 + .on('mouseout', function(d,i,j) { 6.2064 + d3.select(this).classed('hover', false); 6.2065 + dispatch.elementMouseout({ 6.2066 + series: { key: d, color: color(d,j) }, 6.2067 + e: d3.event 6.2068 + }); 6.2069 + }) 6.2070 + .on('mousemove', function(d,i) { 6.2071 + dispatch.elementMousemove({e: d3.event}); 6.2072 + }); 6.2073 + 6.2074 + outliers.attr('class', 'nv-boxplot-outlier'); 6.2075 + outliers 6.2076 + .watchTransition(renderWatch, 'nv-boxplot: nv-boxplot-outlier') 6.2077 + .attr('cx', x.rangeBand() * .45) 6.2078 + .attr('cy', function(d,i,j) { return y(d); }) 6.2079 + .attr('r', '3'); 6.2080 + outliers.exit().remove(); 6.2081 + 6.2082 + var box_width = function() { return (maxBoxWidth === null ? x.rangeBand() * .9 : Math.min(75, x.rangeBand() * .9)); }; 6.2083 + var box_left = function() { return x.rangeBand() * .45 - box_width()/2; }; 6.2084 + var box_right = function() { return x.rangeBand() * .45 + box_width()/2; }; 6.2085 + 6.2086 + // update whisker lines and ticks 6.2087 + ['low', 'high'].forEach(function(key) { 6.2088 + var endpoint = (key === 'low') ? 'Q1' : 'Q3'; 6.2089 + 6.2090 + boxplots.select('line.nv-boxplot-whisker.nv-boxplot-' + key) 6.2091 + .watchTransition(renderWatch, 'nv-boxplot: boxplots') 6.2092 + .attr('x1', x.rangeBand() * .45 ) 6.2093 + .attr('y1', function(d,i) { return y(d.values['whisker_' + key]); }) 6.2094 + .attr('x2', x.rangeBand() * .45 ) 6.2095 + .attr('y2', function(d,i) { return y(d.values[endpoint]); }); 6.2096 + 6.2097 + boxplots.select('line.nv-boxplot-tick.nv-boxplot-' + key) 6.2098 + .watchTransition(renderWatch, 'nv-boxplot: boxplots') 6.2099 + .attr('x1', box_left ) 6.2100 + .attr('y1', function(d,i) { return y(d.values['whisker_' + key]); }) 6.2101 + .attr('x2', box_right ) 6.2102 + .attr('y2', function(d,i) { return y(d.values['whisker_' + key]); }); 6.2103 + }); 6.2104 + 6.2105 + ['low', 'high'].forEach(function(key) { 6.2106 + boxEnter.selectAll('.nv-boxplot-' + key) 6.2107 + .on('mouseover', function(d,i,j) { 6.2108 + d3.select(this).classed('hover', true); 6.2109 + dispatch.elementMouseover({ 6.2110 + series: { key: d.values['whisker_' + key], color: color(d,j) }, 6.2111 + e: d3.event 6.2112 + }); 6.2113 + }) 6.2114 + .on('mouseout', function(d,i,j) { 6.2115 + d3.select(this).classed('hover', false); 6.2116 + dispatch.elementMouseout({ 6.2117 + series: { key: d.values['whisker_' + key], color: color(d,j) }, 6.2118 + e: d3.event 6.2119 + }); 6.2120 + }) 6.2121 + .on('mousemove', function(d,i) { 6.2122 + dispatch.elementMousemove({e: d3.event}); 6.2123 + }); 6.2124 + }); 6.2125 + 6.2126 + // boxes 6.2127 + boxEnter.append('rect') 6.2128 + .attr('class', 'nv-boxplot-box') 6.2129 + // tooltip events 6.2130 + .on('mouseover', function(d,i) { 6.2131 + d3.select(this).classed('hover', true); 6.2132 + dispatch.elementMouseover({ 6.2133 + key: d.label, 6.2134 + value: d.label, 6.2135 + series: [ 6.2136 + { key: 'Q3', value: d.values.Q3, color: d.color || color(d,i) }, 6.2137 + { key: 'Q2', value: d.values.Q2, color: d.color || color(d,i) }, 6.2138 + { key: 'Q1', value: d.values.Q1, color: d.color || color(d,i) } 6.2139 + ], 6.2140 + data: d, 6.2141 + index: i, 6.2142 + e: d3.event 6.2143 + }); 6.2144 + }) 6.2145 + .on('mouseout', function(d,i) { 6.2146 + d3.select(this).classed('hover', false); 6.2147 + dispatch.elementMouseout({ 6.2148 + key: d.label, 6.2149 + value: d.label, 6.2150 + series: [ 6.2151 + { key: 'Q3', value: d.values.Q3, color: d.color || color(d,i) }, 6.2152 + { key: 'Q2', value: d.values.Q2, color: d.color || color(d,i) }, 6.2153 + { key: 'Q1', value: d.values.Q1, color: d.color || color(d,i) } 6.2154 + ], 6.2155 + data: d, 6.2156 + index: i, 6.2157 + e: d3.event 6.2158 + }); 6.2159 + }) 6.2160 + .on('mousemove', function(d,i) { 6.2161 + dispatch.elementMousemove({e: d3.event}); 6.2162 + }); 6.2163 + 6.2164 + // box transitions 6.2165 + boxplots.select('rect.nv-boxplot-box') 6.2166 + .watchTransition(renderWatch, 'nv-boxplot: boxes') 6.2167 + .attr('y', function(d,i) { return y(d.values.Q3); }) 6.2168 + .attr('width', box_width) 6.2169 + .attr('x', box_left ) 6.2170 + 6.2171 + .attr('height', function(d,i) { return Math.abs(y(d.values.Q3) - y(d.values.Q1)) || 1 }) 6.2172 + .style('fill', function(d,i) { return d.color || color(d,i) }) 6.2173 + .style('stroke', function(d,i) { return d.color || color(d,i) }); 6.2174 + 6.2175 + // median line 6.2176 + boxEnter.append('line').attr('class', 'nv-boxplot-median'); 6.2177 + 6.2178 + boxplots.select('line.nv-boxplot-median') 6.2179 + .watchTransition(renderWatch, 'nv-boxplot: boxplots line') 6.2180 + .attr('x1', box_left) 6.2181 + .attr('y1', function(d,i) { return y(d.values.Q2); }) 6.2182 + .attr('x2', box_right) 6.2183 + .attr('y2', function(d,i) { return y(d.values.Q2); }); 6.2184 + 6.2185 + //store old scales for use in transitions on update 6.2186 + x0 = x.copy(); 6.2187 + y0 = y.copy(); 6.2188 + }); 6.2189 + 6.2190 + renderWatch.renderEnd('nv-boxplot immediate'); 6.2191 + return chart; 6.2192 + } 6.2193 + 6.2194 + //============================================================ 6.2195 + // Expose Public Variables 6.2196 + //------------------------------------------------------------ 6.2197 + 6.2198 + chart.dispatch = dispatch; 6.2199 + chart.options = nv.utils.optionsFunc.bind(chart); 6.2200 + 6.2201 + chart._options = Object.create({}, { 6.2202 + // simple options, just get/set the necessary values 6.2203 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.2204 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.2205 + maxBoxWidth: {get: function(){return maxBoxWidth;}, set: function(_){maxBoxWidth=_;}}, 6.2206 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.2207 + y: {get: function(){return getY;}, set: function(_){getY=_;}}, 6.2208 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.2209 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.2210 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.2211 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.2212 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.2213 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.2214 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.2215 + // rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}}, 6.2216 + 6.2217 + // options that require extra logic in the setter 6.2218 + margin: {get: function(){return margin;}, set: function(_){ 6.2219 + margin.top = _.top !== undefined ? _.top : margin.top; 6.2220 + margin.right = _.right !== undefined ? _.right : margin.right; 6.2221 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.2222 + margin.left = _.left !== undefined ? _.left : margin.left; 6.2223 + }}, 6.2224 + color: {get: function(){return color;}, set: function(_){ 6.2225 + color = nv.utils.getColor(_); 6.2226 + }}, 6.2227 + duration: {get: function(){return duration;}, set: function(_){ 6.2228 + duration = _; 6.2229 + renderWatch.reset(duration); 6.2230 + }} 6.2231 + }); 6.2232 + 6.2233 + nv.utils.initOptions(chart); 6.2234 + 6.2235 + return chart; 6.2236 +}; 6.2237 +nv.models.boxPlotChart = function() { 6.2238 + "use strict"; 6.2239 + 6.2240 + //============================================================ 6.2241 + // Public Variables with Default Settings 6.2242 + //------------------------------------------------------------ 6.2243 + 6.2244 + var boxplot = nv.models.boxPlot() 6.2245 + , xAxis = nv.models.axis() 6.2246 + , yAxis = nv.models.axis() 6.2247 + ; 6.2248 + 6.2249 + var margin = {top: 15, right: 10, bottom: 50, left: 60} 6.2250 + , width = null 6.2251 + , height = null 6.2252 + , color = nv.utils.getColor() 6.2253 + , showXAxis = true 6.2254 + , showYAxis = true 6.2255 + , rightAlignYAxis = false 6.2256 + , staggerLabels = false 6.2257 + , tooltip = nv.models.tooltip() 6.2258 + , x 6.2259 + , y 6.2260 + , noData = "No Data Available." 6.2261 + , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'beforeUpdate', 'renderEnd') 6.2262 + , duration = 250 6.2263 + ; 6.2264 + 6.2265 + xAxis 6.2266 + .orient('bottom') 6.2267 + .showMaxMin(false) 6.2268 + .tickFormat(function(d) { return d }) 6.2269 + ; 6.2270 + yAxis 6.2271 + .orient((rightAlignYAxis) ? 'right' : 'left') 6.2272 + .tickFormat(d3.format(',.1f')) 6.2273 + ; 6.2274 + 6.2275 + tooltip.duration(0); 6.2276 + 6.2277 + //============================================================ 6.2278 + // Private Variables 6.2279 + //------------------------------------------------------------ 6.2280 + 6.2281 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.2282 + 6.2283 + function chart(selection) { 6.2284 + renderWatch.reset(); 6.2285 + renderWatch.models(boxplot); 6.2286 + if (showXAxis) renderWatch.models(xAxis); 6.2287 + if (showYAxis) renderWatch.models(yAxis); 6.2288 + 6.2289 + selection.each(function(data) { 6.2290 + var container = d3.select(this), 6.2291 + that = this; 6.2292 + nv.utils.initSVG(container); 6.2293 + var availableWidth = (width || parseInt(container.style('width')) || 960) 6.2294 + - margin.left - margin.right, 6.2295 + availableHeight = (height || parseInt(container.style('height')) || 400) 6.2296 + - margin.top - margin.bottom; 6.2297 + 6.2298 + chart.update = function() { 6.2299 + dispatch.beforeUpdate(); 6.2300 + container.transition().duration(duration).call(chart); 6.2301 + }; 6.2302 + chart.container = this; 6.2303 + 6.2304 + // Display No Data message if there's nothing to show. (quartiles required at minimum) 6.2305 + if (!data || !data.length || 6.2306 + !data.filter(function(d) { return d.values.hasOwnProperty("Q1") && d.values.hasOwnProperty("Q2") && d.values.hasOwnProperty("Q3"); }).length) { 6.2307 + var noDataText = container.selectAll('.nv-noData').data([noData]); 6.2308 + 6.2309 + noDataText.enter().append('text') 6.2310 + .attr('class', 'nvd3 nv-noData') 6.2311 + .attr('dy', '-.7em') 6.2312 + .style('text-anchor', 'middle'); 6.2313 + 6.2314 + noDataText 6.2315 + .attr('x', margin.left + availableWidth / 2) 6.2316 + .attr('y', margin.top + availableHeight / 2) 6.2317 + .text(function(d) { return d }); 6.2318 + 6.2319 + return chart; 6.2320 + } else { 6.2321 + container.selectAll('.nv-noData').remove(); 6.2322 + } 6.2323 + 6.2324 + // Setup Scales 6.2325 + x = boxplot.xScale(); 6.2326 + y = boxplot.yScale().clamp(true); 6.2327 + 6.2328 + // Setup containers and skeleton of chart 6.2329 + var wrap = container.selectAll('g.nv-wrap.nv-boxPlotWithAxes').data([data]); 6.2330 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-boxPlotWithAxes').append('g'); 6.2331 + var defsEnter = gEnter.append('defs'); 6.2332 + var g = wrap.select('g'); 6.2333 + 6.2334 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.2335 + gEnter.append('g').attr('class', 'nv-y nv-axis') 6.2336 + .append('g').attr('class', 'nv-zeroLine') 6.2337 + .append('line'); 6.2338 + 6.2339 + gEnter.append('g').attr('class', 'nv-barsWrap'); 6.2340 + 6.2341 + g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.2342 + 6.2343 + if (rightAlignYAxis) { 6.2344 + g.select(".nv-y.nv-axis") 6.2345 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.2346 + } 6.2347 + 6.2348 + // Main Chart Component(s) 6.2349 + boxplot 6.2350 + .width(availableWidth) 6.2351 + .height(availableHeight); 6.2352 + 6.2353 + var barsWrap = g.select('.nv-barsWrap') 6.2354 + .datum(data.filter(function(d) { return !d.disabled })) 6.2355 + 6.2356 + barsWrap.transition().call(boxplot); 6.2357 + 6.2358 + 6.2359 + defsEnter.append('clipPath') 6.2360 + .attr('id', 'nv-x-label-clip-' + boxplot.id()) 6.2361 + .append('rect'); 6.2362 + 6.2363 + g.select('#nv-x-label-clip-' + boxplot.id() + ' rect') 6.2364 + .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1)) 6.2365 + .attr('height', 16) 6.2366 + .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 )); 6.2367 + 6.2368 + // Setup Axes 6.2369 + if (showXAxis) { 6.2370 + xAxis 6.2371 + .scale(x) 6.2372 + .ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.2373 + .tickSize(-availableHeight, 0); 6.2374 + 6.2375 + g.select('.nv-x.nv-axis').attr('transform', 'translate(0,' + y.range()[0] + ')'); 6.2376 + g.select('.nv-x.nv-axis').call(xAxis); 6.2377 + 6.2378 + var xTicks = g.select('.nv-x.nv-axis').selectAll('g'); 6.2379 + if (staggerLabels) { 6.2380 + xTicks 6.2381 + .selectAll('text') 6.2382 + .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')' }) 6.2383 + } 6.2384 + } 6.2385 + 6.2386 + if (showYAxis) { 6.2387 + yAxis 6.2388 + .scale(y) 6.2389 + .ticks( Math.floor(availableHeight/36) ) // can't use nv.utils.calcTicksY with Object data 6.2390 + .tickSize( -availableWidth, 0); 6.2391 + 6.2392 + g.select('.nv-y.nv-axis').call(yAxis); 6.2393 + } 6.2394 + 6.2395 + // Zero line 6.2396 + g.select(".nv-zeroLine line") 6.2397 + .attr("x1",0) 6.2398 + .attr("x2",availableWidth) 6.2399 + .attr("y1", y(0)) 6.2400 + .attr("y2", y(0)) 6.2401 + ; 6.2402 + 6.2403 + //============================================================ 6.2404 + // Event Handling/Dispatching (in chart's scope) 6.2405 + //------------------------------------------------------------ 6.2406 + }); 6.2407 + 6.2408 + renderWatch.renderEnd('nv-boxplot chart immediate'); 6.2409 + return chart; 6.2410 + } 6.2411 + 6.2412 + //============================================================ 6.2413 + // Event Handling/Dispatching (out of chart's scope) 6.2414 + //------------------------------------------------------------ 6.2415 + 6.2416 + boxplot.dispatch.on('elementMouseover.tooltip', function(evt) { 6.2417 + tooltip.data(evt).hidden(false); 6.2418 + }); 6.2419 + 6.2420 + boxplot.dispatch.on('elementMouseout.tooltip', function(evt) { 6.2421 + tooltip.data(evt).hidden(true); 6.2422 + }); 6.2423 + 6.2424 + boxplot.dispatch.on('elementMousemove.tooltip', function(evt) { 6.2425 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.2426 + }); 6.2427 + 6.2428 + //============================================================ 6.2429 + // Expose Public Variables 6.2430 + //------------------------------------------------------------ 6.2431 + 6.2432 + chart.dispatch = dispatch; 6.2433 + chart.boxplot = boxplot; 6.2434 + chart.xAxis = xAxis; 6.2435 + chart.yAxis = yAxis; 6.2436 + chart.tooltip = tooltip; 6.2437 + 6.2438 + chart.options = nv.utils.optionsFunc.bind(chart); 6.2439 + 6.2440 + chart._options = Object.create({}, { 6.2441 + // simple options, just get/set the necessary values 6.2442 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.2443 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.2444 + staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, 6.2445 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.2446 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.2447 + tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}}, 6.2448 + tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}}, 6.2449 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.2450 + 6.2451 + // options that require extra logic in the setter 6.2452 + margin: {get: function(){return margin;}, set: function(_){ 6.2453 + margin.top = _.top !== undefined ? _.top : margin.top; 6.2454 + margin.right = _.right !== undefined ? _.right : margin.right; 6.2455 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.2456 + margin.left = _.left !== undefined ? _.left : margin.left; 6.2457 + }}, 6.2458 + duration: {get: function(){return duration;}, set: function(_){ 6.2459 + duration = _; 6.2460 + renderWatch.reset(duration); 6.2461 + boxplot.duration(duration); 6.2462 + xAxis.duration(duration); 6.2463 + yAxis.duration(duration); 6.2464 + }}, 6.2465 + color: {get: function(){return color;}, set: function(_){ 6.2466 + color = nv.utils.getColor(_); 6.2467 + boxplot.color(color); 6.2468 + }}, 6.2469 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.2470 + rightAlignYAxis = _; 6.2471 + yAxis.orient( (_) ? 'right' : 'left'); 6.2472 + }} 6.2473 + }); 6.2474 + 6.2475 + nv.utils.inheritOptions(chart, boxplot); 6.2476 + nv.utils.initOptions(chart); 6.2477 + 6.2478 + return chart; 6.2479 +} 6.2480 +// Chart design based on the recommendations of Stephen Few. Implementation 6.2481 +// based on the work of Clint Ivy, Jamie Love, and Jason Davies. 6.2482 +// http://projects.instantcognition.com/protovis/bulletchart/ 6.2483 + 6.2484 +nv.models.bullet = function() { 6.2485 + "use strict"; 6.2486 + 6.2487 + //============================================================ 6.2488 + // Public Variables with Default Settings 6.2489 + //------------------------------------------------------------ 6.2490 + 6.2491 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.2492 + , orient = 'left' // TODO top & bottom 6.2493 + , reverse = false 6.2494 + , ranges = function(d) { return d.ranges } 6.2495 + , markers = function(d) { return d.markers ? d.markers : [0] } 6.2496 + , measures = function(d) { return d.measures } 6.2497 + , rangeLabels = function(d) { return d.rangeLabels ? d.rangeLabels : [] } 6.2498 + , markerLabels = function(d) { return d.markerLabels ? d.markerLabels : [] } 6.2499 + , measureLabels = function(d) { return d.measureLabels ? d.measureLabels : [] } 6.2500 + , forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.) 6.2501 + , width = 380 6.2502 + , height = 30 6.2503 + , container = null 6.2504 + , tickFormat = null 6.2505 + , color = nv.utils.getColor(['#1f77b4']) 6.2506 + , dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove') 6.2507 + ; 6.2508 + 6.2509 + function chart(selection) { 6.2510 + selection.each(function(d, i) { 6.2511 + var availableWidth = width - margin.left - margin.right, 6.2512 + availableHeight = height - margin.top - margin.bottom; 6.2513 + 6.2514 + container = d3.select(this); 6.2515 + nv.utils.initSVG(container); 6.2516 + 6.2517 + var rangez = ranges.call(this, d, i).slice().sort(d3.descending), 6.2518 + markerz = markers.call(this, d, i).slice().sort(d3.descending), 6.2519 + measurez = measures.call(this, d, i).slice().sort(d3.descending), 6.2520 + rangeLabelz = rangeLabels.call(this, d, i).slice(), 6.2521 + markerLabelz = markerLabels.call(this, d, i).slice(), 6.2522 + measureLabelz = measureLabels.call(this, d, i).slice(); 6.2523 + 6.2524 + // Setup Scales 6.2525 + // Compute the new x-scale. 6.2526 + var x1 = d3.scale.linear() 6.2527 + .domain( d3.extent(d3.merge([forceX, rangez])) ) 6.2528 + .range(reverse ? [availableWidth, 0] : [0, availableWidth]); 6.2529 + 6.2530 + // Retrieve the old x-scale, if this is an update. 6.2531 + var x0 = this.__chart__ || d3.scale.linear() 6.2532 + .domain([0, Infinity]) 6.2533 + .range(x1.range()); 6.2534 + 6.2535 + // Stash the new scale. 6.2536 + this.__chart__ = x1; 6.2537 + 6.2538 + var rangeMin = d3.min(rangez), //rangez[2] 6.2539 + rangeMax = d3.max(rangez), //rangez[0] 6.2540 + rangeAvg = rangez[1]; 6.2541 + 6.2542 + // Setup containers and skeleton of chart 6.2543 + var wrap = container.selectAll('g.nv-wrap.nv-bullet').data([d]); 6.2544 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bullet'); 6.2545 + var gEnter = wrapEnter.append('g'); 6.2546 + var g = wrap.select('g'); 6.2547 + 6.2548 + gEnter.append('rect').attr('class', 'nv-range nv-rangeMax'); 6.2549 + gEnter.append('rect').attr('class', 'nv-range nv-rangeAvg'); 6.2550 + gEnter.append('rect').attr('class', 'nv-range nv-rangeMin'); 6.2551 + gEnter.append('rect').attr('class', 'nv-measure'); 6.2552 + 6.2553 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.2554 + 6.2555 + var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0) 6.2556 + w1 = function(d) { return Math.abs(x1(d) - x1(0)) }; 6.2557 + var xp0 = function(d) { return d < 0 ? x0(d) : x0(0) }, 6.2558 + xp1 = function(d) { return d < 0 ? x1(d) : x1(0) }; 6.2559 + 6.2560 + g.select('rect.nv-rangeMax') 6.2561 + .attr('height', availableHeight) 6.2562 + .attr('width', w1(rangeMax > 0 ? rangeMax : rangeMin)) 6.2563 + .attr('x', xp1(rangeMax > 0 ? rangeMax : rangeMin)) 6.2564 + .datum(rangeMax > 0 ? rangeMax : rangeMin) 6.2565 + 6.2566 + g.select('rect.nv-rangeAvg') 6.2567 + .attr('height', availableHeight) 6.2568 + .attr('width', w1(rangeAvg)) 6.2569 + .attr('x', xp1(rangeAvg)) 6.2570 + .datum(rangeAvg) 6.2571 + 6.2572 + g.select('rect.nv-rangeMin') 6.2573 + .attr('height', availableHeight) 6.2574 + .attr('width', w1(rangeMax)) 6.2575 + .attr('x', xp1(rangeMax)) 6.2576 + .attr('width', w1(rangeMax > 0 ? rangeMin : rangeMax)) 6.2577 + .attr('x', xp1(rangeMax > 0 ? rangeMin : rangeMax)) 6.2578 + .datum(rangeMax > 0 ? rangeMin : rangeMax) 6.2579 + 6.2580 + g.select('rect.nv-measure') 6.2581 + .style('fill', color) 6.2582 + .attr('height', availableHeight / 3) 6.2583 + .attr('y', availableHeight / 3) 6.2584 + .attr('width', measurez < 0 ? 6.2585 + x1(0) - x1(measurez[0]) 6.2586 + : x1(measurez[0]) - x1(0)) 6.2587 + .attr('x', xp1(measurez)) 6.2588 + .on('mouseover', function() { 6.2589 + dispatch.elementMouseover({ 6.2590 + value: measurez[0], 6.2591 + label: measureLabelz[0] || 'Current', 6.2592 + color: d3.select(this).style("fill") 6.2593 + }) 6.2594 + }) 6.2595 + .on('mousemove', function() { 6.2596 + dispatch.elementMousemove({ 6.2597 + value: measurez[0], 6.2598 + label: measureLabelz[0] || 'Current', 6.2599 + color: d3.select(this).style("fill") 6.2600 + }) 6.2601 + }) 6.2602 + .on('mouseout', function() { 6.2603 + dispatch.elementMouseout({ 6.2604 + value: measurez[0], 6.2605 + label: measureLabelz[0] || 'Current', 6.2606 + color: d3.select(this).style("fill") 6.2607 + }) 6.2608 + }); 6.2609 + 6.2610 + var h3 = availableHeight / 6; 6.2611 + 6.2612 + var markerData = markerz.map( function(marker, index) { 6.2613 + return {value: marker, label: markerLabelz[index]} 6.2614 + }); 6.2615 + gEnter 6.2616 + .selectAll("path.nv-markerTriangle") 6.2617 + .data(markerData) 6.2618 + .enter() 6.2619 + .append('path') 6.2620 + .attr('class', 'nv-markerTriangle') 6.2621 + .attr('transform', function(d) { return 'translate(' + x1(d.value) + ',' + (availableHeight / 2) + ')' }) 6.2622 + .attr('d', 'M0,' + h3 + 'L' + h3 + ',' + (-h3) + ' ' + (-h3) + ',' + (-h3) + 'Z') 6.2623 + .on('mouseover', function(d) { 6.2624 + dispatch.elementMouseover({ 6.2625 + value: d.value, 6.2626 + label: d.label || 'Previous', 6.2627 + color: d3.select(this).style("fill"), 6.2628 + pos: [x1(d.value), availableHeight/2] 6.2629 + }) 6.2630 + 6.2631 + }) 6.2632 + .on('mousemove', function(d) { 6.2633 + dispatch.elementMousemove({ 6.2634 + value: d.value, 6.2635 + label: d.label || 'Previous', 6.2636 + color: d3.select(this).style("fill") 6.2637 + }) 6.2638 + }) 6.2639 + .on('mouseout', function(d, i) { 6.2640 + dispatch.elementMouseout({ 6.2641 + value: d.value, 6.2642 + label: d.label || 'Previous', 6.2643 + color: d3.select(this).style("fill") 6.2644 + }) 6.2645 + }); 6.2646 + 6.2647 + wrap.selectAll('.nv-range') 6.2648 + .on('mouseover', function(d,i) { 6.2649 + var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum"); 6.2650 + dispatch.elementMouseover({ 6.2651 + value: d, 6.2652 + label: label, 6.2653 + color: d3.select(this).style("fill") 6.2654 + }) 6.2655 + }) 6.2656 + .on('mousemove', function() { 6.2657 + dispatch.elementMousemove({ 6.2658 + value: measurez[0], 6.2659 + label: measureLabelz[0] || 'Previous', 6.2660 + color: d3.select(this).style("fill") 6.2661 + }) 6.2662 + }) 6.2663 + .on('mouseout', function(d,i) { 6.2664 + var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum"); 6.2665 + dispatch.elementMouseout({ 6.2666 + value: d, 6.2667 + label: label, 6.2668 + color: d3.select(this).style("fill") 6.2669 + }) 6.2670 + }); 6.2671 + }); 6.2672 + 6.2673 + return chart; 6.2674 + } 6.2675 + 6.2676 + //============================================================ 6.2677 + // Expose Public Variables 6.2678 + //------------------------------------------------------------ 6.2679 + 6.2680 + chart.dispatch = dispatch; 6.2681 + chart.options = nv.utils.optionsFunc.bind(chart); 6.2682 + 6.2683 + chart._options = Object.create({}, { 6.2684 + // simple options, just get/set the necessary values 6.2685 + ranges: {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good) 6.2686 + markers: {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal) 6.2687 + measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast) 6.2688 + forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, 6.2689 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.2690 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.2691 + tickFormat: {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}}, 6.2692 + 6.2693 + // options that require extra logic in the setter 6.2694 + margin: {get: function(){return margin;}, set: function(_){ 6.2695 + margin.top = _.top !== undefined ? _.top : margin.top; 6.2696 + margin.right = _.right !== undefined ? _.right : margin.right; 6.2697 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.2698 + margin.left = _.left !== undefined ? _.left : margin.left; 6.2699 + }}, 6.2700 + orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom 6.2701 + orient = _; 6.2702 + reverse = orient == 'right' || orient == 'bottom'; 6.2703 + }}, 6.2704 + color: {get: function(){return color;}, set: function(_){ 6.2705 + color = nv.utils.getColor(_); 6.2706 + }} 6.2707 + }); 6.2708 + 6.2709 + nv.utils.initOptions(chart); 6.2710 + return chart; 6.2711 +}; 6.2712 + 6.2713 + 6.2714 + 6.2715 +// Chart design based on the recommendations of Stephen Few. Implementation 6.2716 +// based on the work of Clint Ivy, Jamie Love, and Jason Davies. 6.2717 +// http://projects.instantcognition.com/protovis/bulletchart/ 6.2718 +nv.models.bulletChart = function() { 6.2719 + "use strict"; 6.2720 + 6.2721 + //============================================================ 6.2722 + // Public Variables with Default Settings 6.2723 + //------------------------------------------------------------ 6.2724 + 6.2725 + var bullet = nv.models.bullet(); 6.2726 + var tooltip = nv.models.tooltip(); 6.2727 + 6.2728 + var orient = 'left' // TODO top & bottom 6.2729 + , reverse = false 6.2730 + , margin = {top: 5, right: 40, bottom: 20, left: 120} 6.2731 + , ranges = function(d) { return d.ranges } 6.2732 + , markers = function(d) { return d.markers ? d.markers : [0] } 6.2733 + , measures = function(d) { return d.measures } 6.2734 + , width = null 6.2735 + , height = 55 6.2736 + , tickFormat = null 6.2737 + , ticks = null 6.2738 + , noData = null 6.2739 + , dispatch = d3.dispatch('tooltipShow', 'tooltipHide') 6.2740 + ; 6.2741 + 6.2742 + tooltip.duration(0).headerEnabled(false); 6.2743 + 6.2744 + function chart(selection) { 6.2745 + selection.each(function(d, i) { 6.2746 + var container = d3.select(this); 6.2747 + nv.utils.initSVG(container); 6.2748 + 6.2749 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.2750 + availableHeight = height - margin.top - margin.bottom, 6.2751 + that = this; 6.2752 + 6.2753 + chart.update = function() { chart(selection) }; 6.2754 + chart.container = this; 6.2755 + 6.2756 + // Display No Data message if there's nothing to show. 6.2757 + if (!d || !ranges.call(this, d, i)) { 6.2758 + nv.utils.noData(chart, container) 6.2759 + return chart; 6.2760 + } else { 6.2761 + container.selectAll('.nv-noData').remove(); 6.2762 + } 6.2763 + 6.2764 + var rangez = ranges.call(this, d, i).slice().sort(d3.descending), 6.2765 + markerz = markers.call(this, d, i).slice().sort(d3.descending), 6.2766 + measurez = measures.call(this, d, i).slice().sort(d3.descending); 6.2767 + 6.2768 + // Setup containers and skeleton of chart 6.2769 + var wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]); 6.2770 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart'); 6.2771 + var gEnter = wrapEnter.append('g'); 6.2772 + var g = wrap.select('g'); 6.2773 + 6.2774 + gEnter.append('g').attr('class', 'nv-bulletWrap'); 6.2775 + gEnter.append('g').attr('class', 'nv-titles'); 6.2776 + 6.2777 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.2778 + 6.2779 + // Compute the new x-scale. 6.2780 + var x1 = d3.scale.linear() 6.2781 + .domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) // TODO: need to allow forceX and forceY, and xDomain, yDomain 6.2782 + .range(reverse ? [availableWidth, 0] : [0, availableWidth]); 6.2783 + 6.2784 + // Retrieve the old x-scale, if this is an update. 6.2785 + var x0 = this.__chart__ || d3.scale.linear() 6.2786 + .domain([0, Infinity]) 6.2787 + .range(x1.range()); 6.2788 + 6.2789 + // Stash the new scale. 6.2790 + this.__chart__ = x1; 6.2791 + 6.2792 + var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0) 6.2793 + w1 = function(d) { return Math.abs(x1(d) - x1(0)) }; 6.2794 + 6.2795 + var title = gEnter.select('.nv-titles').append('g') 6.2796 + .attr('text-anchor', 'end') 6.2797 + .attr('transform', 'translate(-6,' + (height - margin.top - margin.bottom) / 2 + ')'); 6.2798 + title.append('text') 6.2799 + .attr('class', 'nv-title') 6.2800 + .text(function(d) { return d.title; }); 6.2801 + 6.2802 + title.append('text') 6.2803 + .attr('class', 'nv-subtitle') 6.2804 + .attr('dy', '1em') 6.2805 + .text(function(d) { return d.subtitle; }); 6.2806 + 6.2807 + bullet 6.2808 + .width(availableWidth) 6.2809 + .height(availableHeight) 6.2810 + 6.2811 + var bulletWrap = g.select('.nv-bulletWrap'); 6.2812 + d3.transition(bulletWrap).call(bullet); 6.2813 + 6.2814 + // Compute the tick format. 6.2815 + var format = tickFormat || x1.tickFormat( availableWidth / 100 ); 6.2816 + 6.2817 + // Update the tick groups. 6.2818 + var tick = g.selectAll('g.nv-tick') 6.2819 + .data(x1.ticks( ticks ? ticks : (availableWidth / 50) ), function(d) { 6.2820 + return this.textContent || format(d); 6.2821 + }); 6.2822 + 6.2823 + // Initialize the ticks with the old scale, x0. 6.2824 + var tickEnter = tick.enter().append('g') 6.2825 + .attr('class', 'nv-tick') 6.2826 + .attr('transform', function(d) { return 'translate(' + x0(d) + ',0)' }) 6.2827 + .style('opacity', 1e-6); 6.2828 + 6.2829 + tickEnter.append('line') 6.2830 + .attr('y1', availableHeight) 6.2831 + .attr('y2', availableHeight * 7 / 6); 6.2832 + 6.2833 + tickEnter.append('text') 6.2834 + .attr('text-anchor', 'middle') 6.2835 + .attr('dy', '1em') 6.2836 + .attr('y', availableHeight * 7 / 6) 6.2837 + .text(format); 6.2838 + 6.2839 + // Transition the updating ticks to the new scale, x1. 6.2840 + var tickUpdate = d3.transition(tick) 6.2841 + .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' }) 6.2842 + .style('opacity', 1); 6.2843 + 6.2844 + tickUpdate.select('line') 6.2845 + .attr('y1', availableHeight) 6.2846 + .attr('y2', availableHeight * 7 / 6); 6.2847 + 6.2848 + tickUpdate.select('text') 6.2849 + .attr('y', availableHeight * 7 / 6); 6.2850 + 6.2851 + // Transition the exiting ticks to the new scale, x1. 6.2852 + d3.transition(tick.exit()) 6.2853 + .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' }) 6.2854 + .style('opacity', 1e-6) 6.2855 + .remove(); 6.2856 + }); 6.2857 + 6.2858 + d3.timer.flush(); 6.2859 + return chart; 6.2860 + } 6.2861 + 6.2862 + //============================================================ 6.2863 + // Event Handling/Dispatching (out of chart's scope) 6.2864 + //------------------------------------------------------------ 6.2865 + 6.2866 + bullet.dispatch.on('elementMouseover.tooltip', function(evt) { 6.2867 + evt['series'] = { 6.2868 + key: evt.label, 6.2869 + value: evt.value, 6.2870 + color: evt.color 6.2871 + }; 6.2872 + tooltip.data(evt).hidden(false); 6.2873 + }); 6.2874 + 6.2875 + bullet.dispatch.on('elementMouseout.tooltip', function(evt) { 6.2876 + tooltip.hidden(true); 6.2877 + }); 6.2878 + 6.2879 + bullet.dispatch.on('elementMousemove.tooltip', function(evt) { 6.2880 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.2881 + }); 6.2882 + 6.2883 + //============================================================ 6.2884 + // Expose Public Variables 6.2885 + //------------------------------------------------------------ 6.2886 + 6.2887 + chart.bullet = bullet; 6.2888 + chart.dispatch = dispatch; 6.2889 + chart.tooltip = tooltip; 6.2890 + 6.2891 + chart.options = nv.utils.optionsFunc.bind(chart); 6.2892 + 6.2893 + chart._options = Object.create({}, { 6.2894 + // simple options, just get/set the necessary values 6.2895 + ranges: {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good) 6.2896 + markers: {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal) 6.2897 + measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast) 6.2898 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.2899 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.2900 + tickFormat: {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}}, 6.2901 + ticks: {get: function(){return ticks;}, set: function(_){ticks=_;}}, 6.2902 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.2903 + 6.2904 + // deprecated options 6.2905 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.2906 + // deprecated after 1.7.1 6.2907 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.2908 + tooltip.enabled(!!_); 6.2909 + }}, 6.2910 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.2911 + // deprecated after 1.7.1 6.2912 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.2913 + tooltip.contentGenerator(_); 6.2914 + }}, 6.2915 + 6.2916 + // options that require extra logic in the setter 6.2917 + margin: {get: function(){return margin;}, set: function(_){ 6.2918 + margin.top = _.top !== undefined ? _.top : margin.top; 6.2919 + margin.right = _.right !== undefined ? _.right : margin.right; 6.2920 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.2921 + margin.left = _.left !== undefined ? _.left : margin.left; 6.2922 + }}, 6.2923 + orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom 6.2924 + orient = _; 6.2925 + reverse = orient == 'right' || orient == 'bottom'; 6.2926 + }} 6.2927 + }); 6.2928 + 6.2929 + nv.utils.inheritOptions(chart, bullet); 6.2930 + nv.utils.initOptions(chart); 6.2931 + 6.2932 + return chart; 6.2933 +}; 6.2934 + 6.2935 + 6.2936 + 6.2937 +nv.models.candlestickBar = function() { 6.2938 + "use strict"; 6.2939 + 6.2940 + //============================================================ 6.2941 + // Public Variables with Default Settings 6.2942 + //------------------------------------------------------------ 6.2943 + 6.2944 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.2945 + , width = null 6.2946 + , height = null 6.2947 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.2948 + , container 6.2949 + , x = d3.scale.linear() 6.2950 + , y = d3.scale.linear() 6.2951 + , getX = function(d) { return d.x } 6.2952 + , getY = function(d) { return d.y } 6.2953 + , getOpen = function(d) { return d.open } 6.2954 + , getClose = function(d) { return d.close } 6.2955 + , getHigh = function(d) { return d.high } 6.2956 + , getLow = function(d) { return d.low } 6.2957 + , forceX = [] 6.2958 + , forceY = [] 6.2959 + , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart 6.2960 + , clipEdge = true 6.2961 + , color = nv.utils.defaultColor() 6.2962 + , interactive = false 6.2963 + , xDomain 6.2964 + , yDomain 6.2965 + , xRange 6.2966 + , yRange 6.2967 + , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove') 6.2968 + ; 6.2969 + 6.2970 + //============================================================ 6.2971 + // Private Variables 6.2972 + //------------------------------------------------------------ 6.2973 + 6.2974 + function chart(selection) { 6.2975 + selection.each(function(data) { 6.2976 + container = d3.select(this); 6.2977 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.2978 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.2979 + 6.2980 + nv.utils.initSVG(container); 6.2981 + 6.2982 + // Width of the candlestick bars. 6.2983 + var barWidth = (availableWidth / data[0].values.length) * .45; 6.2984 + 6.2985 + // Setup Scales 6.2986 + x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) )); 6.2987 + 6.2988 + if (padData) 6.2989 + x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); 6.2990 + else 6.2991 + x.range(xRange || [5 + barWidth / 2, availableWidth - barWidth / 2 - 5]); 6.2992 + 6.2993 + y.domain(yDomain || [ 6.2994 + d3.min(data[0].values.map(getLow).concat(forceY)), 6.2995 + d3.max(data[0].values.map(getHigh).concat(forceY)) 6.2996 + ] 6.2997 + ).range(yRange || [availableHeight, 0]); 6.2998 + 6.2999 + // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point 6.3000 + if (x.domain()[0] === x.domain()[1]) 6.3001 + x.domain()[0] ? 6.3002 + x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) 6.3003 + : x.domain([-1,1]); 6.3004 + 6.3005 + if (y.domain()[0] === y.domain()[1]) 6.3006 + y.domain()[0] ? 6.3007 + y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) 6.3008 + : y.domain([-1,1]); 6.3009 + 6.3010 + // Setup containers and skeleton of chart 6.3011 + var wrap = d3.select(this).selectAll('g.nv-wrap.nv-candlestickBar').data([data[0].values]); 6.3012 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-candlestickBar'); 6.3013 + var defsEnter = wrapEnter.append('defs'); 6.3014 + var gEnter = wrapEnter.append('g'); 6.3015 + var g = wrap.select('g'); 6.3016 + 6.3017 + gEnter.append('g').attr('class', 'nv-ticks'); 6.3018 + 6.3019 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.3020 + 6.3021 + container 6.3022 + .on('click', function(d,i) { 6.3023 + dispatch.chartClick({ 6.3024 + data: d, 6.3025 + index: i, 6.3026 + pos: d3.event, 6.3027 + id: id 6.3028 + }); 6.3029 + }); 6.3030 + 6.3031 + defsEnter.append('clipPath') 6.3032 + .attr('id', 'nv-chart-clip-path-' + id) 6.3033 + .append('rect'); 6.3034 + 6.3035 + wrap.select('#nv-chart-clip-path-' + id + ' rect') 6.3036 + .attr('width', availableWidth) 6.3037 + .attr('height', availableHeight); 6.3038 + 6.3039 + g .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : ''); 6.3040 + 6.3041 + var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick') 6.3042 + .data(function(d) { return d }); 6.3043 + ticks.exit().remove(); 6.3044 + 6.3045 + // The colors are currently controlled by CSS. 6.3046 + var tickGroups = ticks.enter().append('g') 6.3047 + .attr('class', function(d, i, j) { return (getOpen(d, i) > getClose(d, i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i}); 6.3048 + 6.3049 + var lines = tickGroups.append('line') 6.3050 + .attr('class', 'nv-candlestick-lines') 6.3051 + .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; }) 6.3052 + .attr('x1', 0) 6.3053 + .attr('y1', function(d, i) { return y(getHigh(d, i)); }) 6.3054 + .attr('x2', 0) 6.3055 + .attr('y2', function(d, i) { return y(getLow(d, i)); }); 6.3056 + 6.3057 + var rects = tickGroups.append('rect') 6.3058 + .attr('class', 'nv-candlestick-rects nv-bars') 6.3059 + .attr('transform', function(d, i) { 6.3060 + return 'translate(' + (x(getX(d, i)) - barWidth/2) + ',' 6.3061 + + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0)) 6.3062 + + ')'; 6.3063 + }) 6.3064 + .attr('x', 0) 6.3065 + .attr('y', 0) 6.3066 + .attr('width', barWidth) 6.3067 + .attr('height', function(d, i) { 6.3068 + var open = getOpen(d, i); 6.3069 + var close = getClose(d, i); 6.3070 + return open > close ? y(close) - y(open) : y(open) - y(close); 6.3071 + }); 6.3072 + 6.3073 + container.selectAll('.nv-candlestick-lines').transition() 6.3074 + .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; }) 6.3075 + .attr('x1', 0) 6.3076 + .attr('y1', function(d, i) { return y(getHigh(d, i)); }) 6.3077 + .attr('x2', 0) 6.3078 + .attr('y2', function(d, i) { return y(getLow(d, i)); }); 6.3079 + 6.3080 + container.selectAll('.nv-candlestick-rects').transition() 6.3081 + .attr('transform', function(d, i) { 6.3082 + return 'translate(' + (x(getX(d, i)) - barWidth/2) + ',' 6.3083 + + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0)) 6.3084 + + ')'; 6.3085 + }) 6.3086 + .attr('x', 0) 6.3087 + .attr('y', 0) 6.3088 + .attr('width', barWidth) 6.3089 + .attr('height', function(d, i) { 6.3090 + var open = getOpen(d, i); 6.3091 + var close = getClose(d, i); 6.3092 + return open > close ? y(close) - y(open) : y(open) - y(close); 6.3093 + }); 6.3094 + }); 6.3095 + 6.3096 + return chart; 6.3097 + } 6.3098 + 6.3099 + 6.3100 + //Create methods to allow outside functions to highlight a specific bar. 6.3101 + chart.highlightPoint = function(pointIndex, isHoverOver) { 6.3102 + chart.clearHighlights(); 6.3103 + container.select(".nv-candlestickBar .nv-tick-0-" + pointIndex) 6.3104 + .classed("hover", isHoverOver) 6.3105 + ; 6.3106 + }; 6.3107 + 6.3108 + chart.clearHighlights = function() { 6.3109 + container.select(".nv-candlestickBar .nv-tick.hover") 6.3110 + .classed("hover", false) 6.3111 + ; 6.3112 + }; 6.3113 + 6.3114 + //============================================================ 6.3115 + // Expose Public Variables 6.3116 + //------------------------------------------------------------ 6.3117 + 6.3118 + chart.dispatch = dispatch; 6.3119 + chart.options = nv.utils.optionsFunc.bind(chart); 6.3120 + 6.3121 + chart._options = Object.create({}, { 6.3122 + // simple options, just get/set the necessary values 6.3123 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.3124 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.3125 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.3126 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.3127 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.3128 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.3129 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.3130 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.3131 + forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, 6.3132 + forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, 6.3133 + padData: {get: function(){return padData;}, set: function(_){padData=_;}}, 6.3134 + clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, 6.3135 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.3136 + interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, 6.3137 + 6.3138 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.3139 + y: {get: function(){return getY;}, set: function(_){getY=_;}}, 6.3140 + open: {get: function(){return getOpen();}, set: function(_){getOpen=_;}}, 6.3141 + close: {get: function(){return getClose();}, set: function(_){getClose=_;}}, 6.3142 + high: {get: function(){return getHigh;}, set: function(_){getHigh=_;}}, 6.3143 + low: {get: function(){return getLow;}, set: function(_){getLow=_;}}, 6.3144 + 6.3145 + // options that require extra logic in the setter 6.3146 + margin: {get: function(){return margin;}, set: function(_){ 6.3147 + margin.top = _.top != undefined ? _.top : margin.top; 6.3148 + margin.right = _.right != undefined ? _.right : margin.right; 6.3149 + margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom; 6.3150 + margin.left = _.left != undefined ? _.left : margin.left; 6.3151 + }}, 6.3152 + color: {get: function(){return color;}, set: function(_){ 6.3153 + color = nv.utils.getColor(_); 6.3154 + }} 6.3155 + }); 6.3156 + 6.3157 + nv.utils.initOptions(chart); 6.3158 + return chart; 6.3159 +}; 6.3160 + 6.3161 +nv.models.cumulativeLineChart = function() { 6.3162 + "use strict"; 6.3163 + 6.3164 + //============================================================ 6.3165 + // Public Variables with Default Settings 6.3166 + //------------------------------------------------------------ 6.3167 + 6.3168 + var lines = nv.models.line() 6.3169 + , xAxis = nv.models.axis() 6.3170 + , yAxis = nv.models.axis() 6.3171 + , legend = nv.models.legend() 6.3172 + , controls = nv.models.legend() 6.3173 + , interactiveLayer = nv.interactiveGuideline() 6.3174 + , tooltip = nv.models.tooltip() 6.3175 + ; 6.3176 + 6.3177 + var margin = {top: 30, right: 30, bottom: 50, left: 60} 6.3178 + , color = nv.utils.defaultColor() 6.3179 + , width = null 6.3180 + , height = null 6.3181 + , showLegend = true 6.3182 + , showXAxis = true 6.3183 + , showYAxis = true 6.3184 + , rightAlignYAxis = false 6.3185 + , showControls = true 6.3186 + , useInteractiveGuideline = false 6.3187 + , rescaleY = true 6.3188 + , x //can be accessed via chart.xScale() 6.3189 + , y //can be accessed via chart.yScale() 6.3190 + , id = lines.id() 6.3191 + , state = nv.utils.state() 6.3192 + , defaultState = null 6.3193 + , noData = null 6.3194 + , average = function(d) { return d.average } 6.3195 + , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd') 6.3196 + , transitionDuration = 250 6.3197 + , duration = 250 6.3198 + , noErrorCheck = false //if set to TRUE, will bypass an error check in the indexify function. 6.3199 + ; 6.3200 + 6.3201 + state.index = 0; 6.3202 + state.rescaleY = rescaleY; 6.3203 + 6.3204 + xAxis.orient('bottom').tickPadding(7); 6.3205 + yAxis.orient((rightAlignYAxis) ? 'right' : 'left'); 6.3206 + 6.3207 + tooltip.valueFormatter(function(d, i) { 6.3208 + return yAxis.tickFormat()(d, i); 6.3209 + }).headerFormatter(function(d, i) { 6.3210 + return xAxis.tickFormat()(d, i); 6.3211 + }); 6.3212 + 6.3213 + controls.updateState(false); 6.3214 + 6.3215 + //============================================================ 6.3216 + // Private Variables 6.3217 + //------------------------------------------------------------ 6.3218 + 6.3219 + var dx = d3.scale.linear() 6.3220 + , index = {i: 0, x: 0} 6.3221 + , renderWatch = nv.utils.renderWatch(dispatch, duration) 6.3222 + ; 6.3223 + 6.3224 + var stateGetter = function(data) { 6.3225 + return function(){ 6.3226 + return { 6.3227 + active: data.map(function(d) { return !d.disabled }), 6.3228 + index: index.i, 6.3229 + rescaleY: rescaleY 6.3230 + }; 6.3231 + } 6.3232 + }; 6.3233 + 6.3234 + var stateSetter = function(data) { 6.3235 + return function(state) { 6.3236 + if (state.index !== undefined) 6.3237 + index.i = state.index; 6.3238 + if (state.rescaleY !== undefined) 6.3239 + rescaleY = state.rescaleY; 6.3240 + if (state.active !== undefined) 6.3241 + data.forEach(function(series,i) { 6.3242 + series.disabled = !state.active[i]; 6.3243 + }); 6.3244 + } 6.3245 + }; 6.3246 + 6.3247 + function chart(selection) { 6.3248 + renderWatch.reset(); 6.3249 + renderWatch.models(lines); 6.3250 + if (showXAxis) renderWatch.models(xAxis); 6.3251 + if (showYAxis) renderWatch.models(yAxis); 6.3252 + selection.each(function(data) { 6.3253 + var container = d3.select(this); 6.3254 + nv.utils.initSVG(container); 6.3255 + container.classed('nv-chart-' + id, true); 6.3256 + var that = this; 6.3257 + 6.3258 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.3259 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.3260 + 6.3261 + chart.update = function() { 6.3262 + if (duration === 0) 6.3263 + container.call(chart); 6.3264 + else 6.3265 + container.transition().duration(duration).call(chart) 6.3266 + }; 6.3267 + chart.container = this; 6.3268 + 6.3269 + state 6.3270 + .setter(stateSetter(data), chart.update) 6.3271 + .getter(stateGetter(data)) 6.3272 + .update(); 6.3273 + 6.3274 + // DEPRECATED set state.disableddisabled 6.3275 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.3276 + 6.3277 + if (!defaultState) { 6.3278 + var key; 6.3279 + defaultState = {}; 6.3280 + for (key in state) { 6.3281 + if (state[key] instanceof Array) 6.3282 + defaultState[key] = state[key].slice(0); 6.3283 + else 6.3284 + defaultState[key] = state[key]; 6.3285 + } 6.3286 + } 6.3287 + 6.3288 + var indexDrag = d3.behavior.drag() 6.3289 + .on('dragstart', dragStart) 6.3290 + .on('drag', dragMove) 6.3291 + .on('dragend', dragEnd); 6.3292 + 6.3293 + 6.3294 + function dragStart(d,i) { 6.3295 + d3.select(chart.container) 6.3296 + .style('cursor', 'ew-resize'); 6.3297 + } 6.3298 + 6.3299 + function dragMove(d,i) { 6.3300 + index.x = d3.event.x; 6.3301 + index.i = Math.round(dx.invert(index.x)); 6.3302 + updateZero(); 6.3303 + } 6.3304 + 6.3305 + function dragEnd(d,i) { 6.3306 + d3.select(chart.container) 6.3307 + .style('cursor', 'auto'); 6.3308 + 6.3309 + // update state and send stateChange with new index 6.3310 + state.index = index.i; 6.3311 + dispatch.stateChange(state); 6.3312 + } 6.3313 + 6.3314 + // Display No Data message if there's nothing to show. 6.3315 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.3316 + nv.utils.noData(chart, container) 6.3317 + return chart; 6.3318 + } else { 6.3319 + container.selectAll('.nv-noData').remove(); 6.3320 + } 6.3321 + 6.3322 + // Setup Scales 6.3323 + x = lines.xScale(); 6.3324 + y = lines.yScale(); 6.3325 + 6.3326 + if (!rescaleY) { 6.3327 + var seriesDomains = data 6.3328 + .filter(function(series) { return !series.disabled }) 6.3329 + .map(function(series,i) { 6.3330 + var initialDomain = d3.extent(series.values, lines.y()); 6.3331 + 6.3332 + //account for series being disabled when losing 95% or more 6.3333 + if (initialDomain[0] < -.95) initialDomain[0] = -.95; 6.3334 + 6.3335 + return [ 6.3336 + (initialDomain[0] - initialDomain[1]) / (1 + initialDomain[1]), 6.3337 + (initialDomain[1] - initialDomain[0]) / (1 + initialDomain[0]) 6.3338 + ]; 6.3339 + }); 6.3340 + 6.3341 + var completeDomain = [ 6.3342 + d3.min(seriesDomains, function(d) { return d[0] }), 6.3343 + d3.max(seriesDomains, function(d) { return d[1] }) 6.3344 + ]; 6.3345 + 6.3346 + lines.yDomain(completeDomain); 6.3347 + } else { 6.3348 + lines.yDomain(null); 6.3349 + } 6.3350 + 6.3351 + dx.domain([0, data[0].values.length - 1]) //Assumes all series have same length 6.3352 + .range([0, availableWidth]) 6.3353 + .clamp(true); 6.3354 + 6.3355 + var data = indexify(index.i, data); 6.3356 + 6.3357 + // Setup containers and skeleton of chart 6.3358 + var interactivePointerEvents = (useInteractiveGuideline) ? "none" : "all"; 6.3359 + var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]); 6.3360 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-cumulativeLine').append('g'); 6.3361 + var g = wrap.select('g'); 6.3362 + 6.3363 + gEnter.append('g').attr('class', 'nv-interactive'); 6.3364 + gEnter.append('g').attr('class', 'nv-x nv-axis').style("pointer-events","none"); 6.3365 + gEnter.append('g').attr('class', 'nv-y nv-axis'); 6.3366 + gEnter.append('g').attr('class', 'nv-background'); 6.3367 + gEnter.append('g').attr('class', 'nv-linesWrap').style("pointer-events",interactivePointerEvents); 6.3368 + gEnter.append('g').attr('class', 'nv-avgLinesWrap').style("pointer-events","none"); 6.3369 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.3370 + gEnter.append('g').attr('class', 'nv-controlsWrap'); 6.3371 + 6.3372 + // Legend 6.3373 + if (showLegend) { 6.3374 + legend.width(availableWidth); 6.3375 + 6.3376 + g.select('.nv-legendWrap') 6.3377 + .datum(data) 6.3378 + .call(legend); 6.3379 + 6.3380 + if ( margin.top != legend.height()) { 6.3381 + margin.top = legend.height(); 6.3382 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.3383 + } 6.3384 + 6.3385 + g.select('.nv-legendWrap') 6.3386 + .attr('transform', 'translate(0,' + (-margin.top) +')') 6.3387 + } 6.3388 + 6.3389 + // Controls 6.3390 + if (showControls) { 6.3391 + var controlsData = [ 6.3392 + { key: 'Re-scale y-axis', disabled: !rescaleY } 6.3393 + ]; 6.3394 + 6.3395 + controls 6.3396 + .width(140) 6.3397 + .color(['#444', '#444', '#444']) 6.3398 + .rightAlign(false) 6.3399 + .margin({top: 5, right: 0, bottom: 5, left: 20}) 6.3400 + ; 6.3401 + 6.3402 + g.select('.nv-controlsWrap') 6.3403 + .datum(controlsData) 6.3404 + .attr('transform', 'translate(0,' + (-margin.top) +')') 6.3405 + .call(controls); 6.3406 + } 6.3407 + 6.3408 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.3409 + 6.3410 + if (rightAlignYAxis) { 6.3411 + g.select(".nv-y.nv-axis") 6.3412 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.3413 + } 6.3414 + 6.3415 + // Show error if series goes below 100% 6.3416 + var tempDisabled = data.filter(function(d) { return d.tempDisabled }); 6.3417 + 6.3418 + wrap.select('.tempDisabled').remove(); //clean-up and prevent duplicates 6.3419 + if (tempDisabled.length) { 6.3420 + wrap.append('text').attr('class', 'tempDisabled') 6.3421 + .attr('x', availableWidth / 2) 6.3422 + .attr('y', '-.71em') 6.3423 + .style('text-anchor', 'end') 6.3424 + .text(tempDisabled.map(function(d) { return d.key }).join(', ') + ' values cannot be calculated for this time period.'); 6.3425 + } 6.3426 + 6.3427 + //Set up interactive layer 6.3428 + if (useInteractiveGuideline) { 6.3429 + interactiveLayer 6.3430 + .width(availableWidth) 6.3431 + .height(availableHeight) 6.3432 + .margin({left:margin.left,top:margin.top}) 6.3433 + .svgContainer(container) 6.3434 + .xScale(x); 6.3435 + wrap.select(".nv-interactive").call(interactiveLayer); 6.3436 + } 6.3437 + 6.3438 + gEnter.select('.nv-background') 6.3439 + .append('rect'); 6.3440 + 6.3441 + g.select('.nv-background rect') 6.3442 + .attr('width', availableWidth) 6.3443 + .attr('height', availableHeight); 6.3444 + 6.3445 + lines 6.3446 + //.x(function(d) { return d.x }) 6.3447 + .y(function(d) { return d.display.y }) 6.3448 + .width(availableWidth) 6.3449 + .height(availableHeight) 6.3450 + .color(data.map(function(d,i) { 6.3451 + return d.color || color(d, i); 6.3452 + }).filter(function(d,i) { return !data[i].disabled && !data[i].tempDisabled; })); 6.3453 + 6.3454 + var linesWrap = g.select('.nv-linesWrap') 6.3455 + .datum(data.filter(function(d) { return !d.disabled && !d.tempDisabled })); 6.3456 + 6.3457 + linesWrap.call(lines); 6.3458 + 6.3459 + //Store a series index number in the data array. 6.3460 + data.forEach(function(d,i) { 6.3461 + d.seriesIndex = i; 6.3462 + }); 6.3463 + 6.3464 + var avgLineData = data.filter(function(d) { 6.3465 + return !d.disabled && !!average(d); 6.3466 + }); 6.3467 + 6.3468 + var avgLines = g.select(".nv-avgLinesWrap").selectAll("line") 6.3469 + .data(avgLineData, function(d) { return d.key; }); 6.3470 + 6.3471 + var getAvgLineY = function(d) { 6.3472 + //If average lines go off the svg element, clamp them to the svg bounds. 6.3473 + var yVal = y(average(d)); 6.3474 + if (yVal < 0) return 0; 6.3475 + if (yVal > availableHeight) return availableHeight; 6.3476 + return yVal; 6.3477 + }; 6.3478 + 6.3479 + avgLines.enter() 6.3480 + .append('line') 6.3481 + .style('stroke-width',2) 6.3482 + .style('stroke-dasharray','10,10') 6.3483 + .style('stroke',function (d,i) { 6.3484 + return lines.color()(d,d.seriesIndex); 6.3485 + }) 6.3486 + .attr('x1',0) 6.3487 + .attr('x2',availableWidth) 6.3488 + .attr('y1', getAvgLineY) 6.3489 + .attr('y2', getAvgLineY); 6.3490 + 6.3491 + avgLines 6.3492 + .style('stroke-opacity',function(d){ 6.3493 + //If average lines go offscreen, make them transparent 6.3494 + var yVal = y(average(d)); 6.3495 + if (yVal < 0 || yVal > availableHeight) return 0; 6.3496 + return 1; 6.3497 + }) 6.3498 + .attr('x1',0) 6.3499 + .attr('x2',availableWidth) 6.3500 + .attr('y1', getAvgLineY) 6.3501 + .attr('y2', getAvgLineY); 6.3502 + 6.3503 + avgLines.exit().remove(); 6.3504 + 6.3505 + //Create index line 6.3506 + var indexLine = linesWrap.selectAll('.nv-indexLine') 6.3507 + .data([index]); 6.3508 + indexLine.enter().append('rect').attr('class', 'nv-indexLine') 6.3509 + .attr('width', 3) 6.3510 + .attr('x', -2) 6.3511 + .attr('fill', 'red') 6.3512 + .attr('fill-opacity', .5) 6.3513 + .style("pointer-events","all") 6.3514 + .call(indexDrag); 6.3515 + 6.3516 + indexLine 6.3517 + .attr('transform', function(d) { return 'translate(' + dx(d.i) + ',0)' }) 6.3518 + .attr('height', availableHeight); 6.3519 + 6.3520 + // Setup Axes 6.3521 + if (showXAxis) { 6.3522 + xAxis 6.3523 + .scale(x) 6.3524 + ._ticks( nv.utils.calcTicksX(availableWidth/70, data) ) 6.3525 + .tickSize(-availableHeight, 0); 6.3526 + 6.3527 + g.select('.nv-x.nv-axis') 6.3528 + .attr('transform', 'translate(0,' + y.range()[0] + ')'); 6.3529 + g.select('.nv-x.nv-axis') 6.3530 + .call(xAxis); 6.3531 + } 6.3532 + 6.3533 + if (showYAxis) { 6.3534 + yAxis 6.3535 + .scale(y) 6.3536 + ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) 6.3537 + .tickSize( -availableWidth, 0); 6.3538 + 6.3539 + g.select('.nv-y.nv-axis') 6.3540 + .call(yAxis); 6.3541 + } 6.3542 + 6.3543 + //============================================================ 6.3544 + // Event Handling/Dispatching (in chart's scope) 6.3545 + //------------------------------------------------------------ 6.3546 + 6.3547 + function updateZero() { 6.3548 + indexLine 6.3549 + .data([index]); 6.3550 + 6.3551 + //When dragging the index line, turn off line transitions. 6.3552 + // Then turn them back on when done dragging. 6.3553 + var oldDuration = chart.duration(); 6.3554 + chart.duration(0); 6.3555 + chart.update(); 6.3556 + chart.duration(oldDuration); 6.3557 + } 6.3558 + 6.3559 + g.select('.nv-background rect') 6.3560 + .on('click', function() { 6.3561 + index.x = d3.mouse(this)[0]; 6.3562 + index.i = Math.round(dx.invert(index.x)); 6.3563 + 6.3564 + // update state and send stateChange with new index 6.3565 + state.index = index.i; 6.3566 + dispatch.stateChange(state); 6.3567 + 6.3568 + updateZero(); 6.3569 + }); 6.3570 + 6.3571 + lines.dispatch.on('elementClick', function(e) { 6.3572 + index.i = e.pointIndex; 6.3573 + index.x = dx(index.i); 6.3574 + 6.3575 + // update state and send stateChange with new index 6.3576 + state.index = index.i; 6.3577 + dispatch.stateChange(state); 6.3578 + 6.3579 + updateZero(); 6.3580 + }); 6.3581 + 6.3582 + controls.dispatch.on('legendClick', function(d,i) { 6.3583 + d.disabled = !d.disabled; 6.3584 + rescaleY = !d.disabled; 6.3585 + 6.3586 + state.rescaleY = rescaleY; 6.3587 + dispatch.stateChange(state); 6.3588 + chart.update(); 6.3589 + }); 6.3590 + 6.3591 + legend.dispatch.on('stateChange', function(newState) { 6.3592 + for (var key in newState) 6.3593 + state[key] = newState[key]; 6.3594 + dispatch.stateChange(state); 6.3595 + chart.update(); 6.3596 + }); 6.3597 + 6.3598 + interactiveLayer.dispatch.on('elementMousemove', function(e) { 6.3599 + lines.clearHighlights(); 6.3600 + var singlePoint, pointIndex, pointXLocation, allData = []; 6.3601 + 6.3602 + data 6.3603 + .filter(function(series, i) { 6.3604 + series.seriesIndex = i; 6.3605 + return !series.disabled; 6.3606 + }) 6.3607 + .forEach(function(series,i) { 6.3608 + pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); 6.3609 + lines.highlightPoint(i, pointIndex, true); 6.3610 + var point = series.values[pointIndex]; 6.3611 + if (typeof point === 'undefined') return; 6.3612 + if (typeof singlePoint === 'undefined') singlePoint = point; 6.3613 + if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); 6.3614 + allData.push({ 6.3615 + key: series.key, 6.3616 + value: chart.y()(point, pointIndex), 6.3617 + color: color(series,series.seriesIndex) 6.3618 + }); 6.3619 + }); 6.3620 + 6.3621 + //Highlight the tooltip entry based on which point the mouse is closest to. 6.3622 + if (allData.length > 2) { 6.3623 + var yValue = chart.yScale().invert(e.mouseY); 6.3624 + var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]); 6.3625 + var threshold = 0.03 * domainExtent; 6.3626 + var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold); 6.3627 + if (indexToHighlight !== null) 6.3628 + allData[indexToHighlight].highlight = true; 6.3629 + } 6.3630 + 6.3631 + var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex), pointIndex); 6.3632 + interactiveLayer.tooltip 6.3633 + .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top}) 6.3634 + .chartContainer(that.parentNode) 6.3635 + .valueFormatter(function(d,i) { 6.3636 + return yAxis.tickFormat()(d); 6.3637 + }) 6.3638 + .data( 6.3639 + { 6.3640 + value: xValue, 6.3641 + series: allData 6.3642 + } 6.3643 + )(); 6.3644 + 6.3645 + interactiveLayer.renderGuideLine(pointXLocation); 6.3646 + }); 6.3647 + 6.3648 + interactiveLayer.dispatch.on("elementMouseout",function(e) { 6.3649 + lines.clearHighlights(); 6.3650 + }); 6.3651 + 6.3652 + // Update chart from a state object passed to event handler 6.3653 + dispatch.on('changeState', function(e) { 6.3654 + if (typeof e.disabled !== 'undefined') { 6.3655 + data.forEach(function(series,i) { 6.3656 + series.disabled = e.disabled[i]; 6.3657 + }); 6.3658 + 6.3659 + state.disabled = e.disabled; 6.3660 + } 6.3661 + 6.3662 + if (typeof e.index !== 'undefined') { 6.3663 + index.i = e.index; 6.3664 + index.x = dx(index.i); 6.3665 + 6.3666 + state.index = e.index; 6.3667 + 6.3668 + indexLine 6.3669 + .data([index]); 6.3670 + } 6.3671 + 6.3672 + if (typeof e.rescaleY !== 'undefined') { 6.3673 + rescaleY = e.rescaleY; 6.3674 + } 6.3675 + 6.3676 + chart.update(); 6.3677 + }); 6.3678 + 6.3679 + }); 6.3680 + 6.3681 + renderWatch.renderEnd('cumulativeLineChart immediate'); 6.3682 + 6.3683 + return chart; 6.3684 + } 6.3685 + 6.3686 + //============================================================ 6.3687 + // Event Handling/Dispatching (out of chart's scope) 6.3688 + //------------------------------------------------------------ 6.3689 + 6.3690 + lines.dispatch.on('elementMouseover.tooltip', function(evt) { 6.3691 + var point = { 6.3692 + x: chart.x()(evt.point), 6.3693 + y: chart.y()(evt.point), 6.3694 + color: evt.point.color 6.3695 + }; 6.3696 + evt.point = point; 6.3697 + tooltip.data(evt).position(evt.pos).hidden(false); 6.3698 + }); 6.3699 + 6.3700 + lines.dispatch.on('elementMouseout.tooltip', function(evt) { 6.3701 + tooltip.hidden(true) 6.3702 + }); 6.3703 + 6.3704 + //============================================================ 6.3705 + // Functions 6.3706 + //------------------------------------------------------------ 6.3707 + 6.3708 + var indexifyYGetter = null; 6.3709 + /* Normalize the data according to an index point. */ 6.3710 + function indexify(idx, data) { 6.3711 + if (!indexifyYGetter) indexifyYGetter = lines.y(); 6.3712 + return data.map(function(line, i) { 6.3713 + if (!line.values) { 6.3714 + return line; 6.3715 + } 6.3716 + var indexValue = line.values[idx]; 6.3717 + if (indexValue == null) { 6.3718 + return line; 6.3719 + } 6.3720 + var v = indexifyYGetter(indexValue, idx); 6.3721 + 6.3722 + //TODO: implement check below, and disable series if series loses 100% or more cause divide by 0 issue 6.3723 + if (v < -.95 && !noErrorCheck) { 6.3724 + //if a series loses more than 100%, calculations fail.. anything close can cause major distortion (but is mathematically correct till it hits 100) 6.3725 + 6.3726 + line.tempDisabled = true; 6.3727 + return line; 6.3728 + } 6.3729 + 6.3730 + line.tempDisabled = false; 6.3731 + 6.3732 + line.values = line.values.map(function(point, pointIndex) { 6.3733 + point.display = {'y': (indexifyYGetter(point, pointIndex) - v) / (1 + v) }; 6.3734 + return point; 6.3735 + }); 6.3736 + 6.3737 + return line; 6.3738 + }) 6.3739 + } 6.3740 + 6.3741 + //============================================================ 6.3742 + // Expose Public Variables 6.3743 + //------------------------------------------------------------ 6.3744 + 6.3745 + // expose chart's sub-components 6.3746 + chart.dispatch = dispatch; 6.3747 + chart.lines = lines; 6.3748 + chart.legend = legend; 6.3749 + chart.controls = controls; 6.3750 + chart.xAxis = xAxis; 6.3751 + chart.yAxis = yAxis; 6.3752 + chart.interactiveLayer = interactiveLayer; 6.3753 + chart.state = state; 6.3754 + chart.tooltip = tooltip; 6.3755 + 6.3756 + chart.options = nv.utils.optionsFunc.bind(chart); 6.3757 + 6.3758 + chart._options = Object.create({}, { 6.3759 + // simple options, just get/set the necessary values 6.3760 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.3761 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.3762 + rescaleY: {get: function(){return rescaleY;}, set: function(_){rescaleY=_;}}, 6.3763 + showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, 6.3764 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.3765 + average: {get: function(){return average;}, set: function(_){average=_;}}, 6.3766 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.3767 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.3768 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.3769 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.3770 + noErrorCheck: {get: function(){return noErrorCheck;}, set: function(_){noErrorCheck=_;}}, 6.3771 + 6.3772 + // deprecated options 6.3773 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.3774 + // deprecated after 1.7.1 6.3775 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.3776 + tooltip.enabled(!!_); 6.3777 + }}, 6.3778 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.3779 + // deprecated after 1.7.1 6.3780 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.3781 + tooltip.contentGenerator(_); 6.3782 + }}, 6.3783 + 6.3784 + // options that require extra logic in the setter 6.3785 + margin: {get: function(){return margin;}, set: function(_){ 6.3786 + margin.top = _.top !== undefined ? _.top : margin.top; 6.3787 + margin.right = _.right !== undefined ? _.right : margin.right; 6.3788 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.3789 + margin.left = _.left !== undefined ? _.left : margin.left; 6.3790 + }}, 6.3791 + color: {get: function(){return color;}, set: function(_){ 6.3792 + color = nv.utils.getColor(_); 6.3793 + legend.color(color); 6.3794 + }}, 6.3795 + useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ 6.3796 + useInteractiveGuideline = _; 6.3797 + if (_ === true) { 6.3798 + chart.interactive(false); 6.3799 + chart.useVoronoi(false); 6.3800 + } 6.3801 + }}, 6.3802 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.3803 + rightAlignYAxis = _; 6.3804 + yAxis.orient( (_) ? 'right' : 'left'); 6.3805 + }}, 6.3806 + duration: {get: function(){return duration;}, set: function(_){ 6.3807 + duration = _; 6.3808 + lines.duration(duration); 6.3809 + xAxis.duration(duration); 6.3810 + yAxis.duration(duration); 6.3811 + renderWatch.reset(duration); 6.3812 + }} 6.3813 + }); 6.3814 + 6.3815 + nv.utils.inheritOptions(chart, lines); 6.3816 + nv.utils.initOptions(chart); 6.3817 + 6.3818 + return chart; 6.3819 +}; 6.3820 +//TODO: consider deprecating by adding necessary features to multiBar model 6.3821 +nv.models.discreteBar = function() { 6.3822 + "use strict"; 6.3823 + 6.3824 + //============================================================ 6.3825 + // Public Variables with Default Settings 6.3826 + //------------------------------------------------------------ 6.3827 + 6.3828 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.3829 + , width = 960 6.3830 + , height = 500 6.3831 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.3832 + , container 6.3833 + , x = d3.scale.ordinal() 6.3834 + , y = d3.scale.linear() 6.3835 + , getX = function(d) { return d.x } 6.3836 + , getY = function(d) { return d.y } 6.3837 + , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove 6.3838 + , color = nv.utils.defaultColor() 6.3839 + , showValues = false 6.3840 + , valueFormat = d3.format(',.2f') 6.3841 + , xDomain 6.3842 + , yDomain 6.3843 + , xRange 6.3844 + , yRange 6.3845 + , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') 6.3846 + , rectClass = 'discreteBar' 6.3847 + , duration = 250 6.3848 + ; 6.3849 + 6.3850 + //============================================================ 6.3851 + // Private Variables 6.3852 + //------------------------------------------------------------ 6.3853 + 6.3854 + var x0, y0; 6.3855 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.3856 + 6.3857 + function chart(selection) { 6.3858 + renderWatch.reset(); 6.3859 + selection.each(function(data) { 6.3860 + var availableWidth = width - margin.left - margin.right, 6.3861 + availableHeight = height - margin.top - margin.bottom; 6.3862 + 6.3863 + container = d3.select(this); 6.3864 + nv.utils.initSVG(container); 6.3865 + 6.3866 + //add series index to each data point for reference 6.3867 + data.forEach(function(series, i) { 6.3868 + series.values.forEach(function(point) { 6.3869 + point.series = i; 6.3870 + }); 6.3871 + }); 6.3872 + 6.3873 + // Setup Scales 6.3874 + // remap and flatten the data for use in calculating the scales' domains 6.3875 + var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate 6.3876 + data.map(function(d) { 6.3877 + return d.values.map(function(d,i) { 6.3878 + return { x: getX(d,i), y: getY(d,i), y0: d.y0 } 6.3879 + }) 6.3880 + }); 6.3881 + 6.3882 + x .domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x })) 6.3883 + .rangeBands(xRange || [0, availableWidth], .1); 6.3884 + y .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY))); 6.3885 + 6.3886 + // If showValues, pad the Y axis range to account for label height 6.3887 + if (showValues) y.range(yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]); 6.3888 + else y.range(yRange || [availableHeight, 0]); 6.3889 + 6.3890 + //store old scales if they exist 6.3891 + x0 = x0 || x; 6.3892 + y0 = y0 || y.copy().range([y(0),y(0)]); 6.3893 + 6.3894 + // Setup containers and skeleton of chart 6.3895 + var wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([data]); 6.3896 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discretebar'); 6.3897 + var gEnter = wrapEnter.append('g'); 6.3898 + var g = wrap.select('g'); 6.3899 + 6.3900 + gEnter.append('g').attr('class', 'nv-groups'); 6.3901 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.3902 + 6.3903 + //TODO: by definition, the discrete bar should not have multiple groups, will modify/remove later 6.3904 + var groups = wrap.select('.nv-groups').selectAll('.nv-group') 6.3905 + .data(function(d) { return d }, function(d) { return d.key }); 6.3906 + groups.enter().append('g') 6.3907 + .style('stroke-opacity', 1e-6) 6.3908 + .style('fill-opacity', 1e-6); 6.3909 + groups.exit() 6.3910 + .watchTransition(renderWatch, 'discreteBar: exit groups') 6.3911 + .style('stroke-opacity', 1e-6) 6.3912 + .style('fill-opacity', 1e-6) 6.3913 + .remove(); 6.3914 + groups 6.3915 + .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) 6.3916 + .classed('hover', function(d) { return d.hover }); 6.3917 + groups 6.3918 + .watchTransition(renderWatch, 'discreteBar: groups') 6.3919 + .style('stroke-opacity', 1) 6.3920 + .style('fill-opacity', .75); 6.3921 + 6.3922 + var bars = groups.selectAll('g.nv-bar') 6.3923 + .data(function(d) { return d.values }); 6.3924 + bars.exit().remove(); 6.3925 + 6.3926 + var barsEnter = bars.enter().append('g') 6.3927 + .attr('transform', function(d,i,j) { 6.3928 + return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')' 6.3929 + }) 6.3930 + .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here 6.3931 + d3.select(this).classed('hover', true); 6.3932 + dispatch.elementMouseover({ 6.3933 + data: d, 6.3934 + index: i, 6.3935 + color: d3.select(this).style("fill") 6.3936 + }); 6.3937 + }) 6.3938 + .on('mouseout', function(d,i) { 6.3939 + d3.select(this).classed('hover', false); 6.3940 + dispatch.elementMouseout({ 6.3941 + data: d, 6.3942 + index: i, 6.3943 + color: d3.select(this).style("fill") 6.3944 + }); 6.3945 + }) 6.3946 + .on('mousemove', function(d,i) { 6.3947 + dispatch.elementMousemove({ 6.3948 + data: d, 6.3949 + index: i, 6.3950 + color: d3.select(this).style("fill") 6.3951 + }); 6.3952 + }) 6.3953 + .on('click', function(d,i) { 6.3954 + dispatch.elementClick({ 6.3955 + data: d, 6.3956 + index: i, 6.3957 + color: d3.select(this).style("fill") 6.3958 + }); 6.3959 + d3.event.stopPropagation(); 6.3960 + }) 6.3961 + .on('dblclick', function(d,i) { 6.3962 + dispatch.elementDblClick({ 6.3963 + data: d, 6.3964 + index: i, 6.3965 + color: d3.select(this).style("fill") 6.3966 + }); 6.3967 + d3.event.stopPropagation(); 6.3968 + }); 6.3969 + 6.3970 + barsEnter.append('rect') 6.3971 + .attr('height', 0) 6.3972 + .attr('width', x.rangeBand() * .9 / data.length ) 6.3973 + 6.3974 + if (showValues) { 6.3975 + barsEnter.append('text') 6.3976 + .attr('text-anchor', 'middle') 6.3977 + ; 6.3978 + 6.3979 + bars.select('text') 6.3980 + .text(function(d,i) { return valueFormat(getY(d,i)) }) 6.3981 + .watchTransition(renderWatch, 'discreteBar: bars text') 6.3982 + .attr('x', x.rangeBand() * .9 / 2) 6.3983 + .attr('y', function(d,i) { return getY(d,i) < 0 ? y(getY(d,i)) - y(0) + 12 : -4 }) 6.3984 + 6.3985 + ; 6.3986 + } else { 6.3987 + bars.selectAll('text').remove(); 6.3988 + } 6.3989 + 6.3990 + bars 6.3991 + .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive' }) 6.3992 + .style('fill', function(d,i) { return d.color || color(d,i) }) 6.3993 + .style('stroke', function(d,i) { return d.color || color(d,i) }) 6.3994 + .select('rect') 6.3995 + .attr('class', rectClass) 6.3996 + .watchTransition(renderWatch, 'discreteBar: bars rect') 6.3997 + .attr('width', x.rangeBand() * .9 / data.length); 6.3998 + bars.watchTransition(renderWatch, 'discreteBar: bars') 6.3999 + //.delay(function(d,i) { return i * 1200 / data[0].values.length }) 6.4000 + .attr('transform', function(d,i) { 6.4001 + var left = x(getX(d,i)) + x.rangeBand() * .05, 6.4002 + top = getY(d,i) < 0 ? 6.4003 + y(0) : 6.4004 + y(0) - y(getY(d,i)) < 1 ? 6.4005 + y(0) - 1 : //make 1 px positive bars show up above y=0 6.4006 + y(getY(d,i)); 6.4007 + 6.4008 + return 'translate(' + left + ', ' + top + ')' 6.4009 + }) 6.4010 + .select('rect') 6.4011 + .attr('height', function(d,i) { 6.4012 + return Math.max(Math.abs(y(getY(d,i)) - y((yDomain && yDomain[0]) || 0)) || 1) 6.4013 + }); 6.4014 + 6.4015 + 6.4016 + //store old scales for use in transitions on update 6.4017 + x0 = x.copy(); 6.4018 + y0 = y.copy(); 6.4019 + 6.4020 + }); 6.4021 + 6.4022 + renderWatch.renderEnd('discreteBar immediate'); 6.4023 + return chart; 6.4024 + } 6.4025 + 6.4026 + //============================================================ 6.4027 + // Expose Public Variables 6.4028 + //------------------------------------------------------------ 6.4029 + 6.4030 + chart.dispatch = dispatch; 6.4031 + chart.options = nv.utils.optionsFunc.bind(chart); 6.4032 + 6.4033 + chart._options = Object.create({}, { 6.4034 + // simple options, just get/set the necessary values 6.4035 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.4036 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.4037 + forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, 6.4038 + showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}}, 6.4039 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.4040 + y: {get: function(){return getY;}, set: function(_){getY=_;}}, 6.4041 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.4042 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.4043 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.4044 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.4045 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.4046 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.4047 + valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}}, 6.4048 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.4049 + rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}}, 6.4050 + 6.4051 + // options that require extra logic in the setter 6.4052 + margin: {get: function(){return margin;}, set: function(_){ 6.4053 + margin.top = _.top !== undefined ? _.top : margin.top; 6.4054 + margin.right = _.right !== undefined ? _.right : margin.right; 6.4055 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.4056 + margin.left = _.left !== undefined ? _.left : margin.left; 6.4057 + }}, 6.4058 + color: {get: function(){return color;}, set: function(_){ 6.4059 + color = nv.utils.getColor(_); 6.4060 + }}, 6.4061 + duration: {get: function(){return duration;}, set: function(_){ 6.4062 + duration = _; 6.4063 + renderWatch.reset(duration); 6.4064 + }} 6.4065 + }); 6.4066 + 6.4067 + nv.utils.initOptions(chart); 6.4068 + 6.4069 + return chart; 6.4070 +}; 6.4071 + 6.4072 +nv.models.discreteBarChart = function() { 6.4073 + "use strict"; 6.4074 + 6.4075 + //============================================================ 6.4076 + // Public Variables with Default Settings 6.4077 + //------------------------------------------------------------ 6.4078 + 6.4079 + var discretebar = nv.models.discreteBar() 6.4080 + , xAxis = nv.models.axis() 6.4081 + , yAxis = nv.models.axis() 6.4082 + , tooltip = nv.models.tooltip() 6.4083 + ; 6.4084 + 6.4085 + var margin = {top: 15, right: 10, bottom: 50, left: 60} 6.4086 + , width = null 6.4087 + , height = null 6.4088 + , color = nv.utils.getColor() 6.4089 + , showXAxis = true 6.4090 + , showYAxis = true 6.4091 + , rightAlignYAxis = false 6.4092 + , staggerLabels = false 6.4093 + , x 6.4094 + , y 6.4095 + , noData = null 6.4096 + , dispatch = d3.dispatch('beforeUpdate','renderEnd') 6.4097 + , duration = 250 6.4098 + ; 6.4099 + 6.4100 + xAxis 6.4101 + .orient('bottom') 6.4102 + .showMaxMin(false) 6.4103 + .tickFormat(function(d) { return d }) 6.4104 + ; 6.4105 + yAxis 6.4106 + .orient((rightAlignYAxis) ? 'right' : 'left') 6.4107 + .tickFormat(d3.format(',.1f')) 6.4108 + ; 6.4109 + 6.4110 + tooltip 6.4111 + .duration(0) 6.4112 + .headerEnabled(false) 6.4113 + .valueFormatter(function(d, i) { 6.4114 + return yAxis.tickFormat()(d, i); 6.4115 + }) 6.4116 + .keyFormatter(function(d, i) { 6.4117 + return xAxis.tickFormat()(d, i); 6.4118 + }); 6.4119 + 6.4120 + //============================================================ 6.4121 + // Private Variables 6.4122 + //------------------------------------------------------------ 6.4123 + 6.4124 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.4125 + 6.4126 + function chart(selection) { 6.4127 + renderWatch.reset(); 6.4128 + renderWatch.models(discretebar); 6.4129 + if (showXAxis) renderWatch.models(xAxis); 6.4130 + if (showYAxis) renderWatch.models(yAxis); 6.4131 + 6.4132 + selection.each(function(data) { 6.4133 + var container = d3.select(this), 6.4134 + that = this; 6.4135 + nv.utils.initSVG(container); 6.4136 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.4137 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.4138 + 6.4139 + chart.update = function() { 6.4140 + dispatch.beforeUpdate(); 6.4141 + container.transition().duration(duration).call(chart); 6.4142 + }; 6.4143 + chart.container = this; 6.4144 + 6.4145 + // Display No Data message if there's nothing to show. 6.4146 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.4147 + nv.utils.noData(chart, container); 6.4148 + return chart; 6.4149 + } else { 6.4150 + container.selectAll('.nv-noData').remove(); 6.4151 + } 6.4152 + 6.4153 + // Setup Scales 6.4154 + x = discretebar.xScale(); 6.4155 + y = discretebar.yScale().clamp(true); 6.4156 + 6.4157 + // Setup containers and skeleton of chart 6.4158 + var wrap = container.selectAll('g.nv-wrap.nv-discreteBarWithAxes').data([data]); 6.4159 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discreteBarWithAxes').append('g'); 6.4160 + var defsEnter = gEnter.append('defs'); 6.4161 + var g = wrap.select('g'); 6.4162 + 6.4163 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.4164 + gEnter.append('g').attr('class', 'nv-y nv-axis') 6.4165 + .append('g').attr('class', 'nv-zeroLine') 6.4166 + .append('line'); 6.4167 + 6.4168 + gEnter.append('g').attr('class', 'nv-barsWrap'); 6.4169 + 6.4170 + g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.4171 + 6.4172 + if (rightAlignYAxis) { 6.4173 + g.select(".nv-y.nv-axis") 6.4174 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.4175 + } 6.4176 + 6.4177 + // Main Chart Component(s) 6.4178 + discretebar 6.4179 + .width(availableWidth) 6.4180 + .height(availableHeight); 6.4181 + 6.4182 + var barsWrap = g.select('.nv-barsWrap') 6.4183 + .datum(data.filter(function(d) { return !d.disabled })); 6.4184 + 6.4185 + barsWrap.transition().call(discretebar); 6.4186 + 6.4187 + 6.4188 + defsEnter.append('clipPath') 6.4189 + .attr('id', 'nv-x-label-clip-' + discretebar.id()) 6.4190 + .append('rect'); 6.4191 + 6.4192 + g.select('#nv-x-label-clip-' + discretebar.id() + ' rect') 6.4193 + .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1)) 6.4194 + .attr('height', 16) 6.4195 + .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 )); 6.4196 + 6.4197 + // Setup Axes 6.4198 + if (showXAxis) { 6.4199 + xAxis 6.4200 + .scale(x) 6.4201 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.4202 + .tickSize(-availableHeight, 0); 6.4203 + 6.4204 + g.select('.nv-x.nv-axis') 6.4205 + .attr('transform', 'translate(0,' + (y.range()[0] + ((discretebar.showValues() && y.domain()[0] < 0) ? 16 : 0)) + ')'); 6.4206 + g.select('.nv-x.nv-axis').call(xAxis); 6.4207 + 6.4208 + var xTicks = g.select('.nv-x.nv-axis').selectAll('g'); 6.4209 + if (staggerLabels) { 6.4210 + xTicks 6.4211 + .selectAll('text') 6.4212 + .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')' }) 6.4213 + } 6.4214 + } 6.4215 + 6.4216 + if (showYAxis) { 6.4217 + yAxis 6.4218 + .scale(y) 6.4219 + ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) 6.4220 + .tickSize( -availableWidth, 0); 6.4221 + 6.4222 + g.select('.nv-y.nv-axis').call(yAxis); 6.4223 + } 6.4224 + 6.4225 + // Zero line 6.4226 + g.select(".nv-zeroLine line") 6.4227 + .attr("x1",0) 6.4228 + .attr("x2",availableWidth) 6.4229 + .attr("y1", y(0)) 6.4230 + .attr("y2", y(0)) 6.4231 + ; 6.4232 + }); 6.4233 + 6.4234 + renderWatch.renderEnd('discreteBar chart immediate'); 6.4235 + return chart; 6.4236 + } 6.4237 + 6.4238 + //============================================================ 6.4239 + // Event Handling/Dispatching (out of chart's scope) 6.4240 + //------------------------------------------------------------ 6.4241 + 6.4242 + discretebar.dispatch.on('elementMouseover.tooltip', function(evt) { 6.4243 + evt['series'] = { 6.4244 + key: chart.x()(evt.data), 6.4245 + value: chart.y()(evt.data), 6.4246 + color: evt.color 6.4247 + }; 6.4248 + tooltip.data(evt).hidden(false); 6.4249 + }); 6.4250 + 6.4251 + discretebar.dispatch.on('elementMouseout.tooltip', function(evt) { 6.4252 + tooltip.hidden(true); 6.4253 + }); 6.4254 + 6.4255 + discretebar.dispatch.on('elementMousemove.tooltip', function(evt) { 6.4256 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.4257 + }); 6.4258 + 6.4259 + //============================================================ 6.4260 + // Expose Public Variables 6.4261 + //------------------------------------------------------------ 6.4262 + 6.4263 + chart.dispatch = dispatch; 6.4264 + chart.discretebar = discretebar; 6.4265 + chart.xAxis = xAxis; 6.4266 + chart.yAxis = yAxis; 6.4267 + chart.tooltip = tooltip; 6.4268 + 6.4269 + chart.options = nv.utils.optionsFunc.bind(chart); 6.4270 + 6.4271 + chart._options = Object.create({}, { 6.4272 + // simple options, just get/set the necessary values 6.4273 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.4274 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.4275 + staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, 6.4276 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.4277 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.4278 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.4279 + 6.4280 + // deprecated options 6.4281 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.4282 + // deprecated after 1.7.1 6.4283 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.4284 + tooltip.enabled(!!_); 6.4285 + }}, 6.4286 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.4287 + // deprecated after 1.7.1 6.4288 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.4289 + tooltip.contentGenerator(_); 6.4290 + }}, 6.4291 + 6.4292 + // options that require extra logic in the setter 6.4293 + margin: {get: function(){return margin;}, set: function(_){ 6.4294 + margin.top = _.top !== undefined ? _.top : margin.top; 6.4295 + margin.right = _.right !== undefined ? _.right : margin.right; 6.4296 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.4297 + margin.left = _.left !== undefined ? _.left : margin.left; 6.4298 + }}, 6.4299 + duration: {get: function(){return duration;}, set: function(_){ 6.4300 + duration = _; 6.4301 + renderWatch.reset(duration); 6.4302 + discretebar.duration(duration); 6.4303 + xAxis.duration(duration); 6.4304 + yAxis.duration(duration); 6.4305 + }}, 6.4306 + color: {get: function(){return color;}, set: function(_){ 6.4307 + color = nv.utils.getColor(_); 6.4308 + discretebar.color(color); 6.4309 + }}, 6.4310 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.4311 + rightAlignYAxis = _; 6.4312 + yAxis.orient( (_) ? 'right' : 'left'); 6.4313 + }} 6.4314 + }); 6.4315 + 6.4316 + nv.utils.inheritOptions(chart, discretebar); 6.4317 + nv.utils.initOptions(chart); 6.4318 + 6.4319 + return chart; 6.4320 +} 6.4321 + 6.4322 +nv.models.distribution = function() { 6.4323 + "use strict"; 6.4324 + //============================================================ 6.4325 + // Public Variables with Default Settings 6.4326 + //------------------------------------------------------------ 6.4327 + 6.4328 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.4329 + , width = 400 //technically width or height depending on x or y.... 6.4330 + , size = 8 6.4331 + , axis = 'x' // 'x' or 'y'... horizontal or vertical 6.4332 + , getData = function(d) { return d[axis] } // defaults d.x or d.y 6.4333 + , color = nv.utils.defaultColor() 6.4334 + , scale = d3.scale.linear() 6.4335 + , domain 6.4336 + , duration = 250 6.4337 + , dispatch = d3.dispatch('renderEnd') 6.4338 + ; 6.4339 + 6.4340 + //============================================================ 6.4341 + 6.4342 + 6.4343 + //============================================================ 6.4344 + // Private Variables 6.4345 + //------------------------------------------------------------ 6.4346 + 6.4347 + var scale0; 6.4348 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.4349 + 6.4350 + //============================================================ 6.4351 + 6.4352 + 6.4353 + function chart(selection) { 6.4354 + renderWatch.reset(); 6.4355 + selection.each(function(data) { 6.4356 + var availableLength = width - (axis === 'x' ? margin.left + margin.right : margin.top + margin.bottom), 6.4357 + naxis = axis == 'x' ? 'y' : 'x', 6.4358 + container = d3.select(this); 6.4359 + nv.utils.initSVG(container); 6.4360 + 6.4361 + //------------------------------------------------------------ 6.4362 + // Setup Scales 6.4363 + 6.4364 + scale0 = scale0 || scale; 6.4365 + 6.4366 + //------------------------------------------------------------ 6.4367 + 6.4368 + 6.4369 + //------------------------------------------------------------ 6.4370 + // Setup containers and skeleton of chart 6.4371 + 6.4372 + var wrap = container.selectAll('g.nv-distribution').data([data]); 6.4373 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-distribution'); 6.4374 + var gEnter = wrapEnter.append('g'); 6.4375 + var g = wrap.select('g'); 6.4376 + 6.4377 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') 6.4378 + 6.4379 + //------------------------------------------------------------ 6.4380 + 6.4381 + 6.4382 + var distWrap = g.selectAll('g.nv-dist') 6.4383 + .data(function(d) { return d }, function(d) { return d.key }); 6.4384 + 6.4385 + distWrap.enter().append('g'); 6.4386 + distWrap 6.4387 + .attr('class', function(d,i) { return 'nv-dist nv-series-' + i }) 6.4388 + .style('stroke', function(d,i) { return color(d, i) }); 6.4389 + 6.4390 + var dist = distWrap.selectAll('line.nv-dist' + axis) 6.4391 + .data(function(d) { return d.values }) 6.4392 + dist.enter().append('line') 6.4393 + .attr(axis + '1', function(d,i) { return scale0(getData(d,i)) }) 6.4394 + .attr(axis + '2', function(d,i) { return scale0(getData(d,i)) }) 6.4395 + renderWatch.transition(distWrap.exit().selectAll('line.nv-dist' + axis), 'dist exit') 6.4396 + // .transition() 6.4397 + .attr(axis + '1', function(d,i) { return scale(getData(d,i)) }) 6.4398 + .attr(axis + '2', function(d,i) { return scale(getData(d,i)) }) 6.4399 + .style('stroke-opacity', 0) 6.4400 + .remove(); 6.4401 + dist 6.4402 + .attr('class', function(d,i) { return 'nv-dist' + axis + ' nv-dist' + axis + '-' + i }) 6.4403 + .attr(naxis + '1', 0) 6.4404 + .attr(naxis + '2', size); 6.4405 + renderWatch.transition(dist, 'dist') 6.4406 + // .transition() 6.4407 + .attr(axis + '1', function(d,i) { return scale(getData(d,i)) }) 6.4408 + .attr(axis + '2', function(d,i) { return scale(getData(d,i)) }) 6.4409 + 6.4410 + 6.4411 + scale0 = scale.copy(); 6.4412 + 6.4413 + }); 6.4414 + renderWatch.renderEnd('distribution immediate'); 6.4415 + return chart; 6.4416 + } 6.4417 + 6.4418 + 6.4419 + //============================================================ 6.4420 + // Expose Public Variables 6.4421 + //------------------------------------------------------------ 6.4422 + chart.options = nv.utils.optionsFunc.bind(chart); 6.4423 + chart.dispatch = dispatch; 6.4424 + 6.4425 + chart.margin = function(_) { 6.4426 + if (!arguments.length) return margin; 6.4427 + margin.top = typeof _.top != 'undefined' ? _.top : margin.top; 6.4428 + margin.right = typeof _.right != 'undefined' ? _.right : margin.right; 6.4429 + margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom; 6.4430 + margin.left = typeof _.left != 'undefined' ? _.left : margin.left; 6.4431 + return chart; 6.4432 + }; 6.4433 + 6.4434 + chart.width = function(_) { 6.4435 + if (!arguments.length) return width; 6.4436 + width = _; 6.4437 + return chart; 6.4438 + }; 6.4439 + 6.4440 + chart.axis = function(_) { 6.4441 + if (!arguments.length) return axis; 6.4442 + axis = _; 6.4443 + return chart; 6.4444 + }; 6.4445 + 6.4446 + chart.size = function(_) { 6.4447 + if (!arguments.length) return size; 6.4448 + size = _; 6.4449 + return chart; 6.4450 + }; 6.4451 + 6.4452 + chart.getData = function(_) { 6.4453 + if (!arguments.length) return getData; 6.4454 + getData = d3.functor(_); 6.4455 + return chart; 6.4456 + }; 6.4457 + 6.4458 + chart.scale = function(_) { 6.4459 + if (!arguments.length) return scale; 6.4460 + scale = _; 6.4461 + return chart; 6.4462 + }; 6.4463 + 6.4464 + chart.color = function(_) { 6.4465 + if (!arguments.length) return color; 6.4466 + color = nv.utils.getColor(_); 6.4467 + return chart; 6.4468 + }; 6.4469 + 6.4470 + chart.duration = function(_) { 6.4471 + if (!arguments.length) return duration; 6.4472 + duration = _; 6.4473 + renderWatch.reset(duration); 6.4474 + return chart; 6.4475 + }; 6.4476 + //============================================================ 6.4477 + 6.4478 + 6.4479 + return chart; 6.4480 +} 6.4481 +nv.models.furiousLegend = function() { 6.4482 + "use strict"; 6.4483 + 6.4484 + //============================================================ 6.4485 + // Public Variables with Default Settings 6.4486 + //------------------------------------------------------------ 6.4487 + 6.4488 + var margin = {top: 5, right: 0, bottom: 5, left: 0} 6.4489 + , width = 400 6.4490 + , height = 20 6.4491 + , getKey = function(d) { return d.key } 6.4492 + , color = nv.utils.getColor() 6.4493 + , align = true 6.4494 + , padding = 28 //define how much space between legend items. - recommend 32 for furious version 6.4495 + , rightAlign = true 6.4496 + , updateState = true //If true, legend will update data.disabled and trigger a 'stateChange' dispatch. 6.4497 + , radioButtonMode = false //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time) 6.4498 + , expanded = false 6.4499 + , dispatch = d3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange') 6.4500 + , vers = 'classic' //Options are "classic" and "furious" 6.4501 + ; 6.4502 + 6.4503 + function chart(selection) { 6.4504 + selection.each(function(data) { 6.4505 + var availableWidth = width - margin.left - margin.right, 6.4506 + container = d3.select(this); 6.4507 + nv.utils.initSVG(container); 6.4508 + 6.4509 + // Setup containers and skeleton of chart 6.4510 + var wrap = container.selectAll('g.nv-legend').data([data]); 6.4511 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g'); 6.4512 + var g = wrap.select('g'); 6.4513 + 6.4514 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.4515 + 6.4516 + var series = g.selectAll('.nv-series') 6.4517 + .data(function(d) { 6.4518 + if(vers != 'furious') return d; 6.4519 + 6.4520 + return d.filter(function(n) { 6.4521 + return expanded ? true : !n.disengaged; 6.4522 + }); 6.4523 + }); 6.4524 + var seriesEnter = series.enter().append('g').attr('class', 'nv-series') 6.4525 + 6.4526 + var seriesShape; 6.4527 + 6.4528 + if(vers == 'classic') { 6.4529 + seriesEnter.append('circle') 6.4530 + .style('stroke-width', 2) 6.4531 + .attr('class','nv-legend-symbol') 6.4532 + .attr('r', 5); 6.4533 + 6.4534 + seriesShape = series.select('circle'); 6.4535 + } else if (vers == 'furious') { 6.4536 + seriesEnter.append('rect') 6.4537 + .style('stroke-width', 2) 6.4538 + .attr('class','nv-legend-symbol') 6.4539 + .attr('rx', 3) 6.4540 + .attr('ry', 3); 6.4541 + 6.4542 + seriesShape = series.select('rect'); 6.4543 + 6.4544 + seriesEnter.append('g') 6.4545 + .attr('class', 'nv-check-box') 6.4546 + .property('innerHTML','<path d="M0.5,5 L22.5,5 L22.5,26.5 L0.5,26.5 L0.5,5 Z" class="nv-box"></path><path d="M5.5,12.8618467 L11.9185089,19.2803556 L31,0.198864511" class="nv-check"></path>') 6.4547 + .attr('transform', 'translate(-10,-8)scale(0.5)'); 6.4548 + 6.4549 + var seriesCheckbox = series.select('.nv-check-box'); 6.4550 + 6.4551 + seriesCheckbox.each(function(d,i) { 6.4552 + d3.select(this).selectAll('path') 6.4553 + .attr('stroke', setTextColor(d,i)); 6.4554 + }); 6.4555 + } 6.4556 + 6.4557 + seriesEnter.append('text') 6.4558 + .attr('text-anchor', 'start') 6.4559 + .attr('class','nv-legend-text') 6.4560 + .attr('dy', '.32em') 6.4561 + .attr('dx', '8'); 6.4562 + 6.4563 + var seriesText = series.select('text.nv-legend-text'); 6.4564 + 6.4565 + series 6.4566 + .on('mouseover', function(d,i) { 6.4567 + dispatch.legendMouseover(d,i); //TODO: Make consistent with other event objects 6.4568 + }) 6.4569 + .on('mouseout', function(d,i) { 6.4570 + dispatch.legendMouseout(d,i); 6.4571 + }) 6.4572 + .on('click', function(d,i) { 6.4573 + dispatch.legendClick(d,i); 6.4574 + // make sure we re-get data in case it was modified 6.4575 + var data = series.data(); 6.4576 + if (updateState) { 6.4577 + if(vers =='classic') { 6.4578 + if (radioButtonMode) { 6.4579 + //Radio button mode: set every series to disabled, 6.4580 + // and enable the clicked series. 6.4581 + data.forEach(function(series) { series.disabled = true}); 6.4582 + d.disabled = false; 6.4583 + } 6.4584 + else { 6.4585 + d.disabled = !d.disabled; 6.4586 + if (data.every(function(series) { return series.disabled})) { 6.4587 + //the default behavior of NVD3 legends is, if every single series 6.4588 + // is disabled, turn all series' back on. 6.4589 + data.forEach(function(series) { series.disabled = false}); 6.4590 + } 6.4591 + } 6.4592 + } else if(vers == 'furious') { 6.4593 + if(expanded) { 6.4594 + d.disengaged = !d.disengaged; 6.4595 + d.userDisabled = d.userDisabled == undefined ? !!d.disabled : d.userDisabled; 6.4596 + d.disabled = d.disengaged || d.userDisabled; 6.4597 + } else if (!expanded) { 6.4598 + d.disabled = !d.disabled; 6.4599 + d.userDisabled = d.disabled; 6.4600 + var engaged = data.filter(function(d) { return !d.disengaged; }); 6.4601 + if (engaged.every(function(series) { return series.userDisabled })) { 6.4602 + //the default behavior of NVD3 legends is, if every single series 6.4603 + // is disabled, turn all series' back on. 6.4604 + data.forEach(function(series) { 6.4605 + series.disabled = series.userDisabled = false; 6.4606 + }); 6.4607 + } 6.4608 + } 6.4609 + } 6.4610 + dispatch.stateChange({ 6.4611 + disabled: data.map(function(d) { return !!d.disabled }), 6.4612 + disengaged: data.map(function(d) { return !!d.disengaged }) 6.4613 + }); 6.4614 + 6.4615 + } 6.4616 + }) 6.4617 + .on('dblclick', function(d,i) { 6.4618 + if(vers == 'furious' && expanded) return; 6.4619 + dispatch.legendDblclick(d,i); 6.4620 + if (updateState) { 6.4621 + // make sure we re-get data in case it was modified 6.4622 + var data = series.data(); 6.4623 + //the default behavior of NVD3 legends, when double clicking one, 6.4624 + // is to set all other series' to false, and make the double clicked series enabled. 6.4625 + data.forEach(function(series) { 6.4626 + series.disabled = true; 6.4627 + if(vers == 'furious') series.userDisabled = series.disabled; 6.4628 + }); 6.4629 + d.disabled = false; 6.4630 + if(vers == 'furious') d.userDisabled = d.disabled; 6.4631 + dispatch.stateChange({ 6.4632 + disabled: data.map(function(d) { return !!d.disabled }) 6.4633 + }); 6.4634 + } 6.4635 + }); 6.4636 + 6.4637 + series.classed('nv-disabled', function(d) { return d.userDisabled }); 6.4638 + series.exit().remove(); 6.4639 + 6.4640 + seriesText 6.4641 + .attr('fill', setTextColor) 6.4642 + .text(getKey); 6.4643 + 6.4644 + //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option) 6.4645 + // NEW ALIGNING CODE, TODO: clean up 6.4646 + 6.4647 + var versPadding; 6.4648 + switch(vers) { 6.4649 + case 'furious' : 6.4650 + versPadding = 23; 6.4651 + break; 6.4652 + case 'classic' : 6.4653 + versPadding = 20; 6.4654 + } 6.4655 + 6.4656 + if (align) { 6.4657 + 6.4658 + var seriesWidths = []; 6.4659 + series.each(function(d,i) { 6.4660 + var legendText = d3.select(this).select('text'); 6.4661 + var nodeTextLength; 6.4662 + try { 6.4663 + nodeTextLength = legendText.node().getComputedTextLength(); 6.4664 + // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead 6.4665 + if(nodeTextLength <= 0) throw Error(); 6.4666 + } 6.4667 + catch(e) { 6.4668 + nodeTextLength = nv.utils.calcApproxTextWidth(legendText); 6.4669 + } 6.4670 + 6.4671 + seriesWidths.push(nodeTextLength + padding); 6.4672 + }); 6.4673 + 6.4674 + var seriesPerRow = 0; 6.4675 + var legendWidth = 0; 6.4676 + var columnWidths = []; 6.4677 + 6.4678 + while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) { 6.4679 + columnWidths[seriesPerRow] = seriesWidths[seriesPerRow]; 6.4680 + legendWidth += seriesWidths[seriesPerRow++]; 6.4681 + } 6.4682 + if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row 6.4683 + 6.4684 + while ( legendWidth > availableWidth && seriesPerRow > 1 ) { 6.4685 + columnWidths = []; 6.4686 + seriesPerRow--; 6.4687 + 6.4688 + for (var k = 0; k < seriesWidths.length; k++) { 6.4689 + if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) ) 6.4690 + columnWidths[k % seriesPerRow] = seriesWidths[k]; 6.4691 + } 6.4692 + 6.4693 + legendWidth = columnWidths.reduce(function(prev, cur, index, array) { 6.4694 + return prev + cur; 6.4695 + }); 6.4696 + } 6.4697 + 6.4698 + var xPositions = []; 6.4699 + for (var i = 0, curX = 0; i < seriesPerRow; i++) { 6.4700 + xPositions[i] = curX; 6.4701 + curX += columnWidths[i]; 6.4702 + } 6.4703 + 6.4704 + series 6.4705 + .attr('transform', function(d, i) { 6.4706 + return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * versPadding) + ')'; 6.4707 + }); 6.4708 + 6.4709 + //position legend as far right as possible within the total width 6.4710 + if (rightAlign) { 6.4711 + g.attr('transform', 'translate(' + (width - margin.right - legendWidth) + ',' + margin.top + ')'); 6.4712 + } 6.4713 + else { 6.4714 + g.attr('transform', 'translate(0' + ',' + margin.top + ')'); 6.4715 + } 6.4716 + 6.4717 + height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * versPadding); 6.4718 + 6.4719 + } else { 6.4720 + 6.4721 + var ypos = 5, 6.4722 + newxpos = 5, 6.4723 + maxwidth = 0, 6.4724 + xpos; 6.4725 + series 6.4726 + .attr('transform', function(d, i) { 6.4727 + var length = d3.select(this).select('text').node().getComputedTextLength() + padding; 6.4728 + xpos = newxpos; 6.4729 + 6.4730 + if (width < margin.left + margin.right + xpos + length) { 6.4731 + newxpos = xpos = 5; 6.4732 + ypos += versPadding; 6.4733 + } 6.4734 + 6.4735 + newxpos += length; 6.4736 + if (newxpos > maxwidth) maxwidth = newxpos; 6.4737 + 6.4738 + return 'translate(' + xpos + ',' + ypos + ')'; 6.4739 + }); 6.4740 + 6.4741 + //position legend as far right as possible within the total width 6.4742 + g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')'); 6.4743 + 6.4744 + height = margin.top + margin.bottom + ypos + 15; 6.4745 + } 6.4746 + 6.4747 + if(vers == 'furious') { 6.4748 + // Size rectangles after text is placed 6.4749 + seriesShape 6.4750 + .attr('width', function(d,i) { 6.4751 + return seriesText[0][i].getComputedTextLength() + 27; 6.4752 + }) 6.4753 + .attr('height', 18) 6.4754 + .attr('y', -9) 6.4755 + .attr('x', -15) 6.4756 + } 6.4757 + 6.4758 + seriesShape 6.4759 + .style('fill', setBGColor) 6.4760 + .style('stroke', function(d,i) { return d.color || color(d, i) }); 6.4761 + }); 6.4762 + 6.4763 + function setTextColor(d,i) { 6.4764 + if(vers != 'furious') return '#000'; 6.4765 + if(expanded) { 6.4766 + return d.disengaged ? color(d,i) : '#fff'; 6.4767 + } else if (!expanded) { 6.4768 + return !!d.disabled ? color(d,i) : '#fff'; 6.4769 + } 6.4770 + } 6.4771 + 6.4772 + function setBGColor(d,i) { 6.4773 + if(expanded && vers == 'furious') { 6.4774 + return d.disengaged ? '#fff' : color(d,i); 6.4775 + } else { 6.4776 + return !!d.disabled ? '#fff' : color(d,i); 6.4777 + } 6.4778 + } 6.4779 + 6.4780 + return chart; 6.4781 + } 6.4782 + 6.4783 + //============================================================ 6.4784 + // Expose Public Variables 6.4785 + //------------------------------------------------------------ 6.4786 + 6.4787 + chart.dispatch = dispatch; 6.4788 + chart.options = nv.utils.optionsFunc.bind(chart); 6.4789 + 6.4790 + chart._options = Object.create({}, { 6.4791 + // simple options, just get/set the necessary values 6.4792 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.4793 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.4794 + key: {get: function(){return getKey;}, set: function(_){getKey=_;}}, 6.4795 + align: {get: function(){return align;}, set: function(_){align=_;}}, 6.4796 + rightAlign: {get: function(){return rightAlign;}, set: function(_){rightAlign=_;}}, 6.4797 + padding: {get: function(){return padding;}, set: function(_){padding=_;}}, 6.4798 + updateState: {get: function(){return updateState;}, set: function(_){updateState=_;}}, 6.4799 + radioButtonMode: {get: function(){return radioButtonMode;}, set: function(_){radioButtonMode=_;}}, 6.4800 + expanded: {get: function(){return expanded;}, set: function(_){expanded=_;}}, 6.4801 + vers: {get: function(){return vers;}, set: function(_){vers=_;}}, 6.4802 + 6.4803 + // options that require extra logic in the setter 6.4804 + margin: {get: function(){return margin;}, set: function(_){ 6.4805 + margin.top = _.top !== undefined ? _.top : margin.top; 6.4806 + margin.right = _.right !== undefined ? _.right : margin.right; 6.4807 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.4808 + margin.left = _.left !== undefined ? _.left : margin.left; 6.4809 + }}, 6.4810 + color: {get: function(){return color;}, set: function(_){ 6.4811 + color = nv.utils.getColor(_); 6.4812 + }} 6.4813 + }); 6.4814 + 6.4815 + nv.utils.initOptions(chart); 6.4816 + 6.4817 + return chart; 6.4818 +}; 6.4819 +//TODO: consider deprecating and using multibar with single series for this 6.4820 +nv.models.historicalBar = function() { 6.4821 + "use strict"; 6.4822 + 6.4823 + //============================================================ 6.4824 + // Public Variables with Default Settings 6.4825 + //------------------------------------------------------------ 6.4826 + 6.4827 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.4828 + , width = null 6.4829 + , height = null 6.4830 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.4831 + , container = null 6.4832 + , x = d3.scale.linear() 6.4833 + , y = d3.scale.linear() 6.4834 + , getX = function(d) { return d.x } 6.4835 + , getY = function(d) { return d.y } 6.4836 + , forceX = [] 6.4837 + , forceY = [0] 6.4838 + , padData = false 6.4839 + , clipEdge = true 6.4840 + , color = nv.utils.defaultColor() 6.4841 + , xDomain 6.4842 + , yDomain 6.4843 + , xRange 6.4844 + , yRange 6.4845 + , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') 6.4846 + , interactive = true 6.4847 + ; 6.4848 + 6.4849 + var renderWatch = nv.utils.renderWatch(dispatch, 0); 6.4850 + 6.4851 + function chart(selection) { 6.4852 + selection.each(function(data) { 6.4853 + renderWatch.reset(); 6.4854 + 6.4855 + container = d3.select(this); 6.4856 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.4857 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.4858 + 6.4859 + nv.utils.initSVG(container); 6.4860 + 6.4861 + // Setup Scales 6.4862 + x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) )); 6.4863 + 6.4864 + if (padData) 6.4865 + x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); 6.4866 + else 6.4867 + x.range(xRange || [0, availableWidth]); 6.4868 + 6.4869 + y.domain(yDomain || d3.extent(data[0].values.map(getY).concat(forceY) )) 6.4870 + .range(yRange || [availableHeight, 0]); 6.4871 + 6.4872 + // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point 6.4873 + if (x.domain()[0] === x.domain()[1]) 6.4874 + x.domain()[0] ? 6.4875 + x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) 6.4876 + : x.domain([-1,1]); 6.4877 + 6.4878 + if (y.domain()[0] === y.domain()[1]) 6.4879 + y.domain()[0] ? 6.4880 + y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) 6.4881 + : y.domain([-1,1]); 6.4882 + 6.4883 + // Setup containers and skeleton of chart 6.4884 + var wrap = container.selectAll('g.nv-wrap.nv-historicalBar-' + id).data([data[0].values]); 6.4885 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBar-' + id); 6.4886 + var defsEnter = wrapEnter.append('defs'); 6.4887 + var gEnter = wrapEnter.append('g'); 6.4888 + var g = wrap.select('g'); 6.4889 + 6.4890 + gEnter.append('g').attr('class', 'nv-bars'); 6.4891 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.4892 + 6.4893 + container 6.4894 + .on('click', function(d,i) { 6.4895 + dispatch.chartClick({ 6.4896 + data: d, 6.4897 + index: i, 6.4898 + pos: d3.event, 6.4899 + id: id 6.4900 + }); 6.4901 + }); 6.4902 + 6.4903 + defsEnter.append('clipPath') 6.4904 + .attr('id', 'nv-chart-clip-path-' + id) 6.4905 + .append('rect'); 6.4906 + 6.4907 + wrap.select('#nv-chart-clip-path-' + id + ' rect') 6.4908 + .attr('width', availableWidth) 6.4909 + .attr('height', availableHeight); 6.4910 + 6.4911 + g.attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : ''); 6.4912 + 6.4913 + var bars = wrap.select('.nv-bars').selectAll('.nv-bar') 6.4914 + .data(function(d) { return d }, function(d,i) {return getX(d,i)}); 6.4915 + bars.exit().remove(); 6.4916 + 6.4917 + bars.enter().append('rect') 6.4918 + .attr('x', 0 ) 6.4919 + .attr('y', function(d,i) { return nv.utils.NaNtoZero(y(Math.max(0, getY(d,i)))) }) 6.4920 + .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.abs(y(getY(d,i)) - y(0))) }) 6.4921 + .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; }) 6.4922 + .on('mouseover', function(d,i) { 6.4923 + if (!interactive) return; 6.4924 + d3.select(this).classed('hover', true); 6.4925 + dispatch.elementMouseover({ 6.4926 + data: d, 6.4927 + index: i, 6.4928 + color: d3.select(this).style("fill") 6.4929 + }); 6.4930 + 6.4931 + }) 6.4932 + .on('mouseout', function(d,i) { 6.4933 + if (!interactive) return; 6.4934 + d3.select(this).classed('hover', false); 6.4935 + dispatch.elementMouseout({ 6.4936 + data: d, 6.4937 + index: i, 6.4938 + color: d3.select(this).style("fill") 6.4939 + }); 6.4940 + }) 6.4941 + .on('mousemove', function(d,i) { 6.4942 + if (!interactive) return; 6.4943 + dispatch.elementMousemove({ 6.4944 + data: d, 6.4945 + index: i, 6.4946 + color: d3.select(this).style("fill") 6.4947 + }); 6.4948 + }) 6.4949 + .on('click', function(d,i) { 6.4950 + if (!interactive) return; 6.4951 + dispatch.elementClick({ 6.4952 + data: d, 6.4953 + index: i, 6.4954 + color: d3.select(this).style("fill") 6.4955 + }); 6.4956 + d3.event.stopPropagation(); 6.4957 + }) 6.4958 + .on('dblclick', function(d,i) { 6.4959 + if (!interactive) return; 6.4960 + dispatch.elementDblClick({ 6.4961 + data: d, 6.4962 + index: i, 6.4963 + color: d3.select(this).style("fill") 6.4964 + }); 6.4965 + d3.event.stopPropagation(); 6.4966 + }); 6.4967 + 6.4968 + bars 6.4969 + .attr('fill', function(d,i) { return color(d, i); }) 6.4970 + .attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i }) 6.4971 + .watchTransition(renderWatch, 'bars') 6.4972 + .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; }) 6.4973 + //TODO: better width calculations that don't assume always uniform data spacing;w 6.4974 + .attr('width', (availableWidth / data[0].values.length) * .9 ); 6.4975 + 6.4976 + bars.watchTransition(renderWatch, 'bars') 6.4977 + .attr('y', function(d,i) { 6.4978 + var rval = getY(d,i) < 0 ? 6.4979 + y(0) : 6.4980 + y(0) - y(getY(d,i)) < 1 ? 6.4981 + y(0) - 1 : 6.4982 + y(getY(d,i)); 6.4983 + return nv.utils.NaNtoZero(rval); 6.4984 + }) 6.4985 + .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.max(Math.abs(y(getY(d,i)) - y(0)),1)) }); 6.4986 + 6.4987 + }); 6.4988 + 6.4989 + renderWatch.renderEnd('historicalBar immediate'); 6.4990 + return chart; 6.4991 + } 6.4992 + 6.4993 + //Create methods to allow outside functions to highlight a specific bar. 6.4994 + chart.highlightPoint = function(pointIndex, isHoverOver) { 6.4995 + container 6.4996 + .select(".nv-bars .nv-bar-0-" + pointIndex) 6.4997 + .classed("hover", isHoverOver) 6.4998 + ; 6.4999 + }; 6.5000 + 6.5001 + chart.clearHighlights = function() { 6.5002 + container 6.5003 + .select(".nv-bars .nv-bar.hover") 6.5004 + .classed("hover", false) 6.5005 + ; 6.5006 + }; 6.5007 + 6.5008 + //============================================================ 6.5009 + // Expose Public Variables 6.5010 + //------------------------------------------------------------ 6.5011 + 6.5012 + chart.dispatch = dispatch; 6.5013 + chart.options = nv.utils.optionsFunc.bind(chart); 6.5014 + 6.5015 + chart._options = Object.create({}, { 6.5016 + // simple options, just get/set the necessary values 6.5017 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.5018 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.5019 + forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, 6.5020 + forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, 6.5021 + padData: {get: function(){return padData;}, set: function(_){padData=_;}}, 6.5022 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.5023 + y: {get: function(){return getY;}, set: function(_){getY=_;}}, 6.5024 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.5025 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.5026 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.5027 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.5028 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.5029 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.5030 + clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, 6.5031 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.5032 + interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, 6.5033 + 6.5034 + // options that require extra logic in the setter 6.5035 + margin: {get: function(){return margin;}, set: function(_){ 6.5036 + margin.top = _.top !== undefined ? _.top : margin.top; 6.5037 + margin.right = _.right !== undefined ? _.right : margin.right; 6.5038 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.5039 + margin.left = _.left !== undefined ? _.left : margin.left; 6.5040 + }}, 6.5041 + color: {get: function(){return color;}, set: function(_){ 6.5042 + color = nv.utils.getColor(_); 6.5043 + }} 6.5044 + }); 6.5045 + 6.5046 + nv.utils.initOptions(chart); 6.5047 + 6.5048 + return chart; 6.5049 +}; 6.5050 + 6.5051 +nv.models.historicalBarChart = function(bar_model) { 6.5052 + "use strict"; 6.5053 + 6.5054 + //============================================================ 6.5055 + // Public Variables with Default Settings 6.5056 + //------------------------------------------------------------ 6.5057 + 6.5058 + var bars = bar_model || nv.models.historicalBar() 6.5059 + , xAxis = nv.models.axis() 6.5060 + , yAxis = nv.models.axis() 6.5061 + , legend = nv.models.legend() 6.5062 + , interactiveLayer = nv.interactiveGuideline() 6.5063 + , tooltip = nv.models.tooltip() 6.5064 + ; 6.5065 + 6.5066 + 6.5067 + var margin = {top: 30, right: 90, bottom: 50, left: 90} 6.5068 + , color = nv.utils.defaultColor() 6.5069 + , width = null 6.5070 + , height = null 6.5071 + , showLegend = false 6.5072 + , showXAxis = true 6.5073 + , showYAxis = true 6.5074 + , rightAlignYAxis = false 6.5075 + , useInteractiveGuideline = false 6.5076 + , x 6.5077 + , y 6.5078 + , state = {} 6.5079 + , defaultState = null 6.5080 + , noData = null 6.5081 + , dispatch = d3.dispatch('tooltipHide', 'stateChange', 'changeState', 'renderEnd') 6.5082 + , transitionDuration = 250 6.5083 + ; 6.5084 + 6.5085 + xAxis.orient('bottom').tickPadding(7); 6.5086 + yAxis.orient( (rightAlignYAxis) ? 'right' : 'left'); 6.5087 + tooltip 6.5088 + .duration(0) 6.5089 + .headerEnabled(false) 6.5090 + .valueFormatter(function(d, i) { 6.5091 + return yAxis.tickFormat()(d, i); 6.5092 + }) 6.5093 + .headerFormatter(function(d, i) { 6.5094 + return xAxis.tickFormat()(d, i); 6.5095 + }); 6.5096 + 6.5097 + 6.5098 + //============================================================ 6.5099 + // Private Variables 6.5100 + //------------------------------------------------------------ 6.5101 + 6.5102 + var renderWatch = nv.utils.renderWatch(dispatch, 0); 6.5103 + 6.5104 + function chart(selection) { 6.5105 + selection.each(function(data) { 6.5106 + renderWatch.reset(); 6.5107 + renderWatch.models(bars); 6.5108 + if (showXAxis) renderWatch.models(xAxis); 6.5109 + if (showYAxis) renderWatch.models(yAxis); 6.5110 + 6.5111 + var container = d3.select(this), 6.5112 + that = this; 6.5113 + nv.utils.initSVG(container); 6.5114 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.5115 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.5116 + 6.5117 + chart.update = function() { container.transition().duration(transitionDuration).call(chart) }; 6.5118 + chart.container = this; 6.5119 + 6.5120 + //set state.disabled 6.5121 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.5122 + 6.5123 + if (!defaultState) { 6.5124 + var key; 6.5125 + defaultState = {}; 6.5126 + for (key in state) { 6.5127 + if (state[key] instanceof Array) 6.5128 + defaultState[key] = state[key].slice(0); 6.5129 + else 6.5130 + defaultState[key] = state[key]; 6.5131 + } 6.5132 + } 6.5133 + 6.5134 + // Display noData message if there's nothing to show. 6.5135 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.5136 + nv.utils.noData(chart, container) 6.5137 + return chart; 6.5138 + } else { 6.5139 + container.selectAll('.nv-noData').remove(); 6.5140 + } 6.5141 + 6.5142 + // Setup Scales 6.5143 + x = bars.xScale(); 6.5144 + y = bars.yScale(); 6.5145 + 6.5146 + // Setup containers and skeleton of chart 6.5147 + var wrap = container.selectAll('g.nv-wrap.nv-historicalBarChart').data([data]); 6.5148 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBarChart').append('g'); 6.5149 + var g = wrap.select('g'); 6.5150 + 6.5151 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.5152 + gEnter.append('g').attr('class', 'nv-y nv-axis'); 6.5153 + gEnter.append('g').attr('class', 'nv-barsWrap'); 6.5154 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.5155 + gEnter.append('g').attr('class', 'nv-interactive'); 6.5156 + 6.5157 + // Legend 6.5158 + if (showLegend) { 6.5159 + legend.width(availableWidth); 6.5160 + 6.5161 + g.select('.nv-legendWrap') 6.5162 + .datum(data) 6.5163 + .call(legend); 6.5164 + 6.5165 + if ( margin.top != legend.height()) { 6.5166 + margin.top = legend.height(); 6.5167 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.5168 + } 6.5169 + 6.5170 + wrap.select('.nv-legendWrap') 6.5171 + .attr('transform', 'translate(0,' + (-margin.top) +')') 6.5172 + } 6.5173 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.5174 + 6.5175 + if (rightAlignYAxis) { 6.5176 + g.select(".nv-y.nv-axis") 6.5177 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.5178 + } 6.5179 + 6.5180 + //Set up interactive layer 6.5181 + if (useInteractiveGuideline) { 6.5182 + interactiveLayer 6.5183 + .width(availableWidth) 6.5184 + .height(availableHeight) 6.5185 + .margin({left:margin.left, top:margin.top}) 6.5186 + .svgContainer(container) 6.5187 + .xScale(x); 6.5188 + wrap.select(".nv-interactive").call(interactiveLayer); 6.5189 + } 6.5190 + bars 6.5191 + .width(availableWidth) 6.5192 + .height(availableHeight) 6.5193 + .color(data.map(function(d,i) { 6.5194 + return d.color || color(d, i); 6.5195 + }).filter(function(d,i) { return !data[i].disabled })); 6.5196 + 6.5197 + var barsWrap = g.select('.nv-barsWrap') 6.5198 + .datum(data.filter(function(d) { return !d.disabled })); 6.5199 + barsWrap.transition().call(bars); 6.5200 + 6.5201 + // Setup Axes 6.5202 + if (showXAxis) { 6.5203 + xAxis 6.5204 + .scale(x) 6.5205 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.5206 + .tickSize(-availableHeight, 0); 6.5207 + 6.5208 + g.select('.nv-x.nv-axis') 6.5209 + .attr('transform', 'translate(0,' + y.range()[0] + ')'); 6.5210 + g.select('.nv-x.nv-axis') 6.5211 + .transition() 6.5212 + .call(xAxis); 6.5213 + } 6.5214 + 6.5215 + if (showYAxis) { 6.5216 + yAxis 6.5217 + .scale(y) 6.5218 + ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) 6.5219 + .tickSize( -availableWidth, 0); 6.5220 + 6.5221 + g.select('.nv-y.nv-axis') 6.5222 + .transition() 6.5223 + .call(yAxis); 6.5224 + } 6.5225 + 6.5226 + //============================================================ 6.5227 + // Event Handling/Dispatching (in chart's scope) 6.5228 + //------------------------------------------------------------ 6.5229 + 6.5230 + interactiveLayer.dispatch.on('elementMousemove', function(e) { 6.5231 + bars.clearHighlights(); 6.5232 + 6.5233 + var singlePoint, pointIndex, pointXLocation, allData = []; 6.5234 + data 6.5235 + .filter(function(series, i) { 6.5236 + series.seriesIndex = i; 6.5237 + return !series.disabled; 6.5238 + }) 6.5239 + .forEach(function(series,i) { 6.5240 + pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); 6.5241 + bars.highlightPoint(pointIndex,true); 6.5242 + var point = series.values[pointIndex]; 6.5243 + if (point === undefined) return; 6.5244 + if (singlePoint === undefined) singlePoint = point; 6.5245 + if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); 6.5246 + allData.push({ 6.5247 + key: series.key, 6.5248 + value: chart.y()(point, pointIndex), 6.5249 + color: color(series,series.seriesIndex), 6.5250 + data: series.values[pointIndex] 6.5251 + }); 6.5252 + }); 6.5253 + 6.5254 + var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); 6.5255 + interactiveLayer.tooltip 6.5256 + .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top}) 6.5257 + .chartContainer(that.parentNode) 6.5258 + .valueFormatter(function(d,i) { 6.5259 + return yAxis.tickFormat()(d); 6.5260 + }) 6.5261 + .data({ 6.5262 + value: xValue, 6.5263 + index: pointIndex, 6.5264 + series: allData 6.5265 + })(); 6.5266 + 6.5267 + interactiveLayer.renderGuideLine(pointXLocation); 6.5268 + 6.5269 + }); 6.5270 + 6.5271 + interactiveLayer.dispatch.on("elementMouseout",function(e) { 6.5272 + dispatch.tooltipHide(); 6.5273 + bars.clearHighlights(); 6.5274 + }); 6.5275 + 6.5276 + legend.dispatch.on('legendClick', function(d,i) { 6.5277 + d.disabled = !d.disabled; 6.5278 + 6.5279 + if (!data.filter(function(d) { return !d.disabled }).length) { 6.5280 + data.map(function(d) { 6.5281 + d.disabled = false; 6.5282 + wrap.selectAll('.nv-series').classed('disabled', false); 6.5283 + return d; 6.5284 + }); 6.5285 + } 6.5286 + 6.5287 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.5288 + dispatch.stateChange(state); 6.5289 + 6.5290 + selection.transition().call(chart); 6.5291 + }); 6.5292 + 6.5293 + legend.dispatch.on('legendDblclick', function(d) { 6.5294 + //Double clicking should always enable current series, and disabled all others. 6.5295 + data.forEach(function(d) { 6.5296 + d.disabled = true; 6.5297 + }); 6.5298 + d.disabled = false; 6.5299 + 6.5300 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.5301 + dispatch.stateChange(state); 6.5302 + chart.update(); 6.5303 + }); 6.5304 + 6.5305 + dispatch.on('changeState', function(e) { 6.5306 + if (typeof e.disabled !== 'undefined') { 6.5307 + data.forEach(function(series,i) { 6.5308 + series.disabled = e.disabled[i]; 6.5309 + }); 6.5310 + 6.5311 + state.disabled = e.disabled; 6.5312 + } 6.5313 + 6.5314 + chart.update(); 6.5315 + }); 6.5316 + }); 6.5317 + 6.5318 + renderWatch.renderEnd('historicalBarChart immediate'); 6.5319 + return chart; 6.5320 + } 6.5321 + 6.5322 + //============================================================ 6.5323 + // Event Handling/Dispatching (out of chart's scope) 6.5324 + //------------------------------------------------------------ 6.5325 + 6.5326 + bars.dispatch.on('elementMouseover.tooltip', function(evt) { 6.5327 + evt['series'] = { 6.5328 + key: chart.x()(evt.data), 6.5329 + value: chart.y()(evt.data), 6.5330 + color: evt.color 6.5331 + }; 6.5332 + tooltip.data(evt).hidden(false); 6.5333 + }); 6.5334 + 6.5335 + bars.dispatch.on('elementMouseout.tooltip', function(evt) { 6.5336 + tooltip.hidden(true); 6.5337 + }); 6.5338 + 6.5339 + bars.dispatch.on('elementMousemove.tooltip', function(evt) { 6.5340 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.5341 + }); 6.5342 + 6.5343 + //============================================================ 6.5344 + // Expose Public Variables 6.5345 + //------------------------------------------------------------ 6.5346 + 6.5347 + // expose chart's sub-components 6.5348 + chart.dispatch = dispatch; 6.5349 + chart.bars = bars; 6.5350 + chart.legend = legend; 6.5351 + chart.xAxis = xAxis; 6.5352 + chart.yAxis = yAxis; 6.5353 + chart.interactiveLayer = interactiveLayer; 6.5354 + chart.tooltip = tooltip; 6.5355 + 6.5356 + chart.options = nv.utils.optionsFunc.bind(chart); 6.5357 + 6.5358 + chart._options = Object.create({}, { 6.5359 + // simple options, just get/set the necessary values 6.5360 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.5361 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.5362 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.5363 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.5364 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.5365 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.5366 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.5367 + 6.5368 + // deprecated options 6.5369 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.5370 + // deprecated after 1.7.1 6.5371 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.5372 + tooltip.enabled(!!_); 6.5373 + }}, 6.5374 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.5375 + // deprecated after 1.7.1 6.5376 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.5377 + tooltip.contentGenerator(_); 6.5378 + }}, 6.5379 + 6.5380 + // options that require extra logic in the setter 6.5381 + margin: {get: function(){return margin;}, set: function(_){ 6.5382 + margin.top = _.top !== undefined ? _.top : margin.top; 6.5383 + margin.right = _.right !== undefined ? _.right : margin.right; 6.5384 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.5385 + margin.left = _.left !== undefined ? _.left : margin.left; 6.5386 + }}, 6.5387 + color: {get: function(){return color;}, set: function(_){ 6.5388 + color = nv.utils.getColor(_); 6.5389 + legend.color(color); 6.5390 + bars.color(color); 6.5391 + }}, 6.5392 + duration: {get: function(){return transitionDuration;}, set: function(_){ 6.5393 + transitionDuration=_; 6.5394 + renderWatch.reset(transitionDuration); 6.5395 + yAxis.duration(transitionDuration); 6.5396 + xAxis.duration(transitionDuration); 6.5397 + }}, 6.5398 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.5399 + rightAlignYAxis = _; 6.5400 + yAxis.orient( (_) ? 'right' : 'left'); 6.5401 + }}, 6.5402 + useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ 6.5403 + useInteractiveGuideline = _; 6.5404 + if (_ === true) { 6.5405 + chart.interactive(false); 6.5406 + } 6.5407 + }} 6.5408 + }); 6.5409 + 6.5410 + nv.utils.inheritOptions(chart, bars); 6.5411 + nv.utils.initOptions(chart); 6.5412 + 6.5413 + return chart; 6.5414 +}; 6.5415 + 6.5416 + 6.5417 +// ohlcChart is just a historical chart with ohlc bars and some tweaks 6.5418 +nv.models.ohlcBarChart = function() { 6.5419 + var chart = nv.models.historicalBarChart(nv.models.ohlcBar()); 6.5420 + 6.5421 + // special default tooltip since we show multiple values per x 6.5422 + chart.useInteractiveGuideline(true); 6.5423 + chart.interactiveLayer.tooltip.contentGenerator(function(data) { 6.5424 + // we assume only one series exists for this chart 6.5425 + var d = data.series[0].data; 6.5426 + // match line colors as defined in nv.d3.css 6.5427 + var color = d.open < d.close ? "2ca02c" : "d62728"; 6.5428 + return '' + 6.5429 + '<h3 style="color: #' + color + '">' + data.value + '</h3>' + 6.5430 + '<table>' + 6.5431 + '<tr><td>open:</td><td>' + chart.yAxis.tickFormat()(d.open) + '</td></tr>' + 6.5432 + '<tr><td>close:</td><td>' + chart.yAxis.tickFormat()(d.close) + '</td></tr>' + 6.5433 + '<tr><td>high</td><td>' + chart.yAxis.tickFormat()(d.high) + '</td></tr>' + 6.5434 + '<tr><td>low:</td><td>' + chart.yAxis.tickFormat()(d.low) + '</td></tr>' + 6.5435 + '</table>'; 6.5436 + }); 6.5437 + return chart; 6.5438 +}; 6.5439 + 6.5440 +// candlestickChart is just a historical chart with candlestick bars and some tweaks 6.5441 +nv.models.candlestickBarChart = function() { 6.5442 + var chart = nv.models.historicalBarChart(nv.models.candlestickBar()); 6.5443 + 6.5444 + // special default tooltip since we show multiple values per x 6.5445 + chart.useInteractiveGuideline(true); 6.5446 + chart.interactiveLayer.tooltip.contentGenerator(function(data) { 6.5447 + // we assume only one series exists for this chart 6.5448 + var d = data.series[0].data; 6.5449 + // match line colors as defined in nv.d3.css 6.5450 + var color = d.open < d.close ? "2ca02c" : "d62728"; 6.5451 + return '' + 6.5452 + '<h3 style="color: #' + color + '">' + data.value + '</h3>' + 6.5453 + '<table>' + 6.5454 + '<tr><td>open:</td><td>' + chart.yAxis.tickFormat()(d.open) + '</td></tr>' + 6.5455 + '<tr><td>close:</td><td>' + chart.yAxis.tickFormat()(d.close) + '</td></tr>' + 6.5456 + '<tr><td>high</td><td>' + chart.yAxis.tickFormat()(d.high) + '</td></tr>' + 6.5457 + '<tr><td>low:</td><td>' + chart.yAxis.tickFormat()(d.low) + '</td></tr>' + 6.5458 + '</table>'; 6.5459 + }); 6.5460 + return chart; 6.5461 +}; 6.5462 +nv.models.legend = function() { 6.5463 + "use strict"; 6.5464 + 6.5465 + //============================================================ 6.5466 + // Public Variables with Default Settings 6.5467 + //------------------------------------------------------------ 6.5468 + 6.5469 + var margin = {top: 5, right: 0, bottom: 5, left: 0} 6.5470 + , width = 400 6.5471 + , height = 20 6.5472 + , getKey = function(d) { return d.key } 6.5473 + , color = nv.utils.getColor() 6.5474 + , align = true 6.5475 + , padding = 32 //define how much space between legend items. - recommend 32 for furious version 6.5476 + , rightAlign = true 6.5477 + , updateState = true //If true, legend will update data.disabled and trigger a 'stateChange' dispatch. 6.5478 + , radioButtonMode = false //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time) 6.5479 + , expanded = false 6.5480 + , dispatch = d3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange') 6.5481 + , vers = 'classic' //Options are "classic" and "furious" 6.5482 + ; 6.5483 + 6.5484 + function chart(selection) { 6.5485 + selection.each(function(data) { 6.5486 + var availableWidth = width - margin.left - margin.right, 6.5487 + container = d3.select(this); 6.5488 + nv.utils.initSVG(container); 6.5489 + 6.5490 + // Setup containers and skeleton of chart 6.5491 + var wrap = container.selectAll('g.nv-legend').data([data]); 6.5492 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g'); 6.5493 + var g = wrap.select('g'); 6.5494 + 6.5495 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.5496 + 6.5497 + var series = g.selectAll('.nv-series') 6.5498 + .data(function(d) { 6.5499 + if(vers != 'furious') return d; 6.5500 + 6.5501 + return d.filter(function(n) { 6.5502 + return expanded ? true : !n.disengaged; 6.5503 + }); 6.5504 + }); 6.5505 + 6.5506 + var seriesEnter = series.enter().append('g').attr('class', 'nv-series'); 6.5507 + var seriesShape; 6.5508 + 6.5509 + var versPadding; 6.5510 + switch(vers) { 6.5511 + case 'furious' : 6.5512 + versPadding = 23; 6.5513 + break; 6.5514 + case 'classic' : 6.5515 + versPadding = 20; 6.5516 + } 6.5517 + 6.5518 + if(vers == 'classic') { 6.5519 + seriesEnter.append('circle') 6.5520 + .style('stroke-width', 2) 6.5521 + .attr('class','nv-legend-symbol') 6.5522 + .attr('r', 5); 6.5523 + 6.5524 + seriesShape = series.select('circle'); 6.5525 + } else if (vers == 'furious') { 6.5526 + seriesEnter.append('rect') 6.5527 + .style('stroke-width', 2) 6.5528 + .attr('class','nv-legend-symbol') 6.5529 + .attr('rx', 3) 6.5530 + .attr('ry', 3); 6.5531 + 6.5532 + seriesShape = series.select('.nv-legend-symbol'); 6.5533 + 6.5534 + seriesEnter.append('g') 6.5535 + .attr('class', 'nv-check-box') 6.5536 + .property('innerHTML','<path d="M0.5,5 L22.5,5 L22.5,26.5 L0.5,26.5 L0.5,5 Z" class="nv-box"></path><path d="M5.5,12.8618467 L11.9185089,19.2803556 L31,0.198864511" class="nv-check"></path>') 6.5537 + .attr('transform', 'translate(-10,-8)scale(0.5)'); 6.5538 + 6.5539 + var seriesCheckbox = series.select('.nv-check-box'); 6.5540 + 6.5541 + seriesCheckbox.each(function(d,i) { 6.5542 + d3.select(this).selectAll('path') 6.5543 + .attr('stroke', setTextColor(d,i)); 6.5544 + }); 6.5545 + } 6.5546 + 6.5547 + seriesEnter.append('text') 6.5548 + .attr('text-anchor', 'start') 6.5549 + .attr('class','nv-legend-text') 6.5550 + .attr('dy', '.32em') 6.5551 + .attr('dx', '8'); 6.5552 + 6.5553 + var seriesText = series.select('text.nv-legend-text'); 6.5554 + 6.5555 + series 6.5556 + .on('mouseover', function(d,i) { 6.5557 + dispatch.legendMouseover(d,i); //TODO: Make consistent with other event objects 6.5558 + }) 6.5559 + .on('mouseout', function(d,i) { 6.5560 + dispatch.legendMouseout(d,i); 6.5561 + }) 6.5562 + .on('click', function(d,i) { 6.5563 + dispatch.legendClick(d,i); 6.5564 + // make sure we re-get data in case it was modified 6.5565 + var data = series.data(); 6.5566 + if (updateState) { 6.5567 + if(vers =='classic') { 6.5568 + if (radioButtonMode) { 6.5569 + //Radio button mode: set every series to disabled, 6.5570 + // and enable the clicked series. 6.5571 + data.forEach(function(series) { series.disabled = true}); 6.5572 + d.disabled = false; 6.5573 + } 6.5574 + else { 6.5575 + d.disabled = !d.disabled; 6.5576 + if (data.every(function(series) { return series.disabled})) { 6.5577 + //the default behavior of NVD3 legends is, if every single series 6.5578 + // is disabled, turn all series' back on. 6.5579 + data.forEach(function(series) { series.disabled = false}); 6.5580 + } 6.5581 + } 6.5582 + } else if(vers == 'furious') { 6.5583 + if(expanded) { 6.5584 + d.disengaged = !d.disengaged; 6.5585 + d.userDisabled = d.userDisabled == undefined ? !!d.disabled : d.userDisabled; 6.5586 + d.disabled = d.disengaged || d.userDisabled; 6.5587 + } else if (!expanded) { 6.5588 + d.disabled = !d.disabled; 6.5589 + d.userDisabled = d.disabled; 6.5590 + var engaged = data.filter(function(d) { return !d.disengaged; }); 6.5591 + if (engaged.every(function(series) { return series.userDisabled })) { 6.5592 + //the default behavior of NVD3 legends is, if every single series 6.5593 + // is disabled, turn all series' back on. 6.5594 + data.forEach(function(series) { 6.5595 + series.disabled = series.userDisabled = false; 6.5596 + }); 6.5597 + } 6.5598 + } 6.5599 + } 6.5600 + dispatch.stateChange({ 6.5601 + disabled: data.map(function(d) { return !!d.disabled }), 6.5602 + disengaged: data.map(function(d) { return !!d.disengaged }) 6.5603 + }); 6.5604 + 6.5605 + } 6.5606 + }) 6.5607 + .on('dblclick', function(d,i) { 6.5608 + if(vers == 'furious' && expanded) return; 6.5609 + dispatch.legendDblclick(d,i); 6.5610 + if (updateState) { 6.5611 + // make sure we re-get data in case it was modified 6.5612 + var data = series.data(); 6.5613 + //the default behavior of NVD3 legends, when double clicking one, 6.5614 + // is to set all other series' to false, and make the double clicked series enabled. 6.5615 + data.forEach(function(series) { 6.5616 + series.disabled = true; 6.5617 + if(vers == 'furious') series.userDisabled = series.disabled; 6.5618 + }); 6.5619 + d.disabled = false; 6.5620 + if(vers == 'furious') d.userDisabled = d.disabled; 6.5621 + dispatch.stateChange({ 6.5622 + disabled: data.map(function(d) { return !!d.disabled }) 6.5623 + }); 6.5624 + } 6.5625 + }); 6.5626 + 6.5627 + series.classed('nv-disabled', function(d) { return d.userDisabled }); 6.5628 + series.exit().remove(); 6.5629 + 6.5630 + seriesText 6.5631 + .attr('fill', setTextColor) 6.5632 + .text(getKey); 6.5633 + 6.5634 + //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option) 6.5635 + // NEW ALIGNING CODE, TODO: clean up 6.5636 + var legendWidth = 0; 6.5637 + if (align) { 6.5638 + 6.5639 + var seriesWidths = []; 6.5640 + series.each(function(d,i) { 6.5641 + var legendText = d3.select(this).select('text'); 6.5642 + var nodeTextLength; 6.5643 + try { 6.5644 + nodeTextLength = legendText.node().getComputedTextLength(); 6.5645 + // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead 6.5646 + if(nodeTextLength <= 0) throw Error(); 6.5647 + } 6.5648 + catch(e) { 6.5649 + nodeTextLength = nv.utils.calcApproxTextWidth(legendText); 6.5650 + } 6.5651 + 6.5652 + seriesWidths.push(nodeTextLength + padding); 6.5653 + }); 6.5654 + 6.5655 + var seriesPerRow = 0; 6.5656 + var columnWidths = []; 6.5657 + legendWidth = 0; 6.5658 + 6.5659 + while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) { 6.5660 + columnWidths[seriesPerRow] = seriesWidths[seriesPerRow]; 6.5661 + legendWidth += seriesWidths[seriesPerRow++]; 6.5662 + } 6.5663 + if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row 6.5664 + 6.5665 + while ( legendWidth > availableWidth && seriesPerRow > 1 ) { 6.5666 + columnWidths = []; 6.5667 + seriesPerRow--; 6.5668 + 6.5669 + for (var k = 0; k < seriesWidths.length; k++) { 6.5670 + if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) ) 6.5671 + columnWidths[k % seriesPerRow] = seriesWidths[k]; 6.5672 + } 6.5673 + 6.5674 + legendWidth = columnWidths.reduce(function(prev, cur, index, array) { 6.5675 + return prev + cur; 6.5676 + }); 6.5677 + } 6.5678 + 6.5679 + var xPositions = []; 6.5680 + for (var i = 0, curX = 0; i < seriesPerRow; i++) { 6.5681 + xPositions[i] = curX; 6.5682 + curX += columnWidths[i]; 6.5683 + } 6.5684 + 6.5685 + series 6.5686 + .attr('transform', function(d, i) { 6.5687 + return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * versPadding) + ')'; 6.5688 + }); 6.5689 + 6.5690 + //position legend as far right as possible within the total width 6.5691 + if (rightAlign) { 6.5692 + g.attr('transform', 'translate(' + (width - margin.right - legendWidth) + ',' + margin.top + ')'); 6.5693 + } 6.5694 + else { 6.5695 + g.attr('transform', 'translate(0' + ',' + margin.top + ')'); 6.5696 + } 6.5697 + 6.5698 + height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * versPadding); 6.5699 + 6.5700 + } else { 6.5701 + 6.5702 + var ypos = 5, 6.5703 + newxpos = 5, 6.5704 + maxwidth = 0, 6.5705 + xpos; 6.5706 + series 6.5707 + .attr('transform', function(d, i) { 6.5708 + var length = d3.select(this).select('text').node().getComputedTextLength() + padding; 6.5709 + xpos = newxpos; 6.5710 + 6.5711 + if (width < margin.left + margin.right + xpos + length) { 6.5712 + newxpos = xpos = 5; 6.5713 + ypos += versPadding; 6.5714 + } 6.5715 + 6.5716 + newxpos += length; 6.5717 + if (newxpos > maxwidth) maxwidth = newxpos; 6.5718 + 6.5719 + if(legendWidth < xpos + maxwidth) { 6.5720 + legendWidth = xpos + maxwidth; 6.5721 + } 6.5722 + return 'translate(' + xpos + ',' + ypos + ')'; 6.5723 + }); 6.5724 + 6.5725 + //position legend as far right as possible within the total width 6.5726 + g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')'); 6.5727 + 6.5728 + height = margin.top + margin.bottom + ypos + 15; 6.5729 + } 6.5730 + 6.5731 + if(vers == 'furious') { 6.5732 + // Size rectangles after text is placed 6.5733 + seriesShape 6.5734 + .attr('width', function(d,i) { 6.5735 + return seriesText[0][i].getComputedTextLength() + 27; 6.5736 + }) 6.5737 + .attr('height', 18) 6.5738 + .attr('y', -9) 6.5739 + .attr('x', -15); 6.5740 + 6.5741 + // The background for the expanded legend (UI) 6.5742 + gEnter.insert('rect',':first-child') 6.5743 + .attr('class', 'nv-legend-bg') 6.5744 + .attr('fill', '#eee') 6.5745 + // .attr('stroke', '#444') 6.5746 + .attr('opacity',0); 6.5747 + 6.5748 + var seriesBG = g.select('.nv-legend-bg'); 6.5749 + 6.5750 + seriesBG 6.5751 + .transition().duration(300) 6.5752 + .attr('x', -versPadding ) 6.5753 + .attr('width', legendWidth + versPadding - 12) 6.5754 + .attr('height', height + 10) 6.5755 + .attr('y', -margin.top - 10) 6.5756 + .attr('opacity', expanded ? 1 : 0); 6.5757 + 6.5758 + 6.5759 + } 6.5760 + 6.5761 + seriesShape 6.5762 + .style('fill', setBGColor) 6.5763 + .style('fill-opacity', setBGOpacity) 6.5764 + .style('stroke', setBGColor); 6.5765 + }); 6.5766 + 6.5767 + function setTextColor(d,i) { 6.5768 + if(vers != 'furious') return '#000'; 6.5769 + if(expanded) { 6.5770 + return d.disengaged ? '#000' : '#fff'; 6.5771 + } else if (!expanded) { 6.5772 + if(!d.color) d.color = color(d,i); 6.5773 + return !!d.disabled ? d.color : '#fff'; 6.5774 + } 6.5775 + } 6.5776 + 6.5777 + function setBGColor(d,i) { 6.5778 + if(expanded && vers == 'furious') { 6.5779 + return d.disengaged ? '#eee' : d.color || color(d,i); 6.5780 + } else { 6.5781 + return d.color || color(d,i); 6.5782 + } 6.5783 + } 6.5784 + 6.5785 + 6.5786 + function setBGOpacity(d,i) { 6.5787 + if(expanded && vers == 'furious') { 6.5788 + return 1; 6.5789 + } else { 6.5790 + return !!d.disabled ? 0 : 1; 6.5791 + } 6.5792 + } 6.5793 + 6.5794 + return chart; 6.5795 + } 6.5796 + 6.5797 + //============================================================ 6.5798 + // Expose Public Variables 6.5799 + //------------------------------------------------------------ 6.5800 + 6.5801 + chart.dispatch = dispatch; 6.5802 + chart.options = nv.utils.optionsFunc.bind(chart); 6.5803 + 6.5804 + chart._options = Object.create({}, { 6.5805 + // simple options, just get/set the necessary values 6.5806 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.5807 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.5808 + key: {get: function(){return getKey;}, set: function(_){getKey=_;}}, 6.5809 + align: {get: function(){return align;}, set: function(_){align=_;}}, 6.5810 + rightAlign: {get: function(){return rightAlign;}, set: function(_){rightAlign=_;}}, 6.5811 + padding: {get: function(){return padding;}, set: function(_){padding=_;}}, 6.5812 + updateState: {get: function(){return updateState;}, set: function(_){updateState=_;}}, 6.5813 + radioButtonMode: {get: function(){return radioButtonMode;}, set: function(_){radioButtonMode=_;}}, 6.5814 + expanded: {get: function(){return expanded;}, set: function(_){expanded=_;}}, 6.5815 + vers: {get: function(){return vers;}, set: function(_){vers=_;}}, 6.5816 + 6.5817 + // options that require extra logic in the setter 6.5818 + margin: {get: function(){return margin;}, set: function(_){ 6.5819 + margin.top = _.top !== undefined ? _.top : margin.top; 6.5820 + margin.right = _.right !== undefined ? _.right : margin.right; 6.5821 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.5822 + margin.left = _.left !== undefined ? _.left : margin.left; 6.5823 + }}, 6.5824 + color: {get: function(){return color;}, set: function(_){ 6.5825 + color = nv.utils.getColor(_); 6.5826 + }} 6.5827 + }); 6.5828 + 6.5829 + nv.utils.initOptions(chart); 6.5830 + 6.5831 + return chart; 6.5832 +}; 6.5833 + 6.5834 +nv.models.line = function() { 6.5835 + "use strict"; 6.5836 + //============================================================ 6.5837 + // Public Variables with Default Settings 6.5838 + //------------------------------------------------------------ 6.5839 + 6.5840 + var scatter = nv.models.scatter() 6.5841 + ; 6.5842 + 6.5843 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.5844 + , width = 960 6.5845 + , height = 500 6.5846 + , container = null 6.5847 + , strokeWidth = 1.5 6.5848 + , color = nv.utils.defaultColor() // a function that returns a color 6.5849 + , getX = function(d) { return d.x } // accessor to get the x value from a data point 6.5850 + , getY = function(d) { return d.y } // accessor to get the y value from a data point 6.5851 + , defined = function(d,i) { return !isNaN(getY(d,i)) && getY(d,i) !== null } // allows a line to be not continuous when it is not defined 6.5852 + , isArea = function(d) { return d.area } // decides if a line is an area or just a line 6.5853 + , clipEdge = false // if true, masks lines within x and y scale 6.5854 + , x //can be accessed via chart.xScale() 6.5855 + , y //can be accessed via chart.yScale() 6.5856 + , interpolate = "linear" // controls the line interpolation 6.5857 + , duration = 250 6.5858 + , dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout', 'renderEnd') 6.5859 + ; 6.5860 + 6.5861 + scatter 6.5862 + .pointSize(16) // default size 6.5863 + .pointDomain([16,256]) //set to speed up calculation, needs to be unset if there is a custom size accessor 6.5864 + ; 6.5865 + 6.5866 + //============================================================ 6.5867 + 6.5868 + 6.5869 + //============================================================ 6.5870 + // Private Variables 6.5871 + //------------------------------------------------------------ 6.5872 + 6.5873 + var x0, y0 //used to store previous scales 6.5874 + , renderWatch = nv.utils.renderWatch(dispatch, duration) 6.5875 + ; 6.5876 + 6.5877 + //============================================================ 6.5878 + 6.5879 + 6.5880 + function chart(selection) { 6.5881 + renderWatch.reset(); 6.5882 + renderWatch.models(scatter); 6.5883 + selection.each(function(data) { 6.5884 + container = d3.select(this); 6.5885 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.5886 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.5887 + nv.utils.initSVG(container); 6.5888 + 6.5889 + // Setup Scales 6.5890 + x = scatter.xScale(); 6.5891 + y = scatter.yScale(); 6.5892 + 6.5893 + x0 = x0 || x; 6.5894 + y0 = y0 || y; 6.5895 + 6.5896 + // Setup containers and skeleton of chart 6.5897 + var wrap = container.selectAll('g.nv-wrap.nv-line').data([data]); 6.5898 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-line'); 6.5899 + var defsEnter = wrapEnter.append('defs'); 6.5900 + var gEnter = wrapEnter.append('g'); 6.5901 + var g = wrap.select('g'); 6.5902 + 6.5903 + gEnter.append('g').attr('class', 'nv-groups'); 6.5904 + gEnter.append('g').attr('class', 'nv-scatterWrap'); 6.5905 + 6.5906 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.5907 + 6.5908 + scatter 6.5909 + .width(availableWidth) 6.5910 + .height(availableHeight); 6.5911 + 6.5912 + var scatterWrap = wrap.select('.nv-scatterWrap'); 6.5913 + scatterWrap.call(scatter); 6.5914 + 6.5915 + defsEnter.append('clipPath') 6.5916 + .attr('id', 'nv-edge-clip-' + scatter.id()) 6.5917 + .append('rect'); 6.5918 + 6.5919 + wrap.select('#nv-edge-clip-' + scatter.id() + ' rect') 6.5920 + .attr('width', availableWidth) 6.5921 + .attr('height', (availableHeight > 0) ? availableHeight : 0); 6.5922 + 6.5923 + g .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : ''); 6.5924 + scatterWrap 6.5925 + .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : ''); 6.5926 + 6.5927 + var groups = wrap.select('.nv-groups').selectAll('.nv-group') 6.5928 + .data(function(d) { return d }, function(d) { return d.key }); 6.5929 + groups.enter().append('g') 6.5930 + .style('stroke-opacity', 1e-6) 6.5931 + .style('stroke-width', function(d) { return d.strokeWidth || strokeWidth }) 6.5932 + .style('fill-opacity', 1e-6); 6.5933 + 6.5934 + groups.exit().remove(); 6.5935 + 6.5936 + groups 6.5937 + .attr('class', function(d,i) { 6.5938 + return (d.classed || '') + ' nv-group nv-series-' + i; 6.5939 + }) 6.5940 + .classed('hover', function(d) { return d.hover }) 6.5941 + .style('fill', function(d,i){ return color(d, i) }) 6.5942 + .style('stroke', function(d,i){ return color(d, i)}); 6.5943 + groups.watchTransition(renderWatch, 'line: groups') 6.5944 + .style('stroke-opacity', 1) 6.5945 + .style('fill-opacity', function(d) { return d.fillOpacity || .5}); 6.5946 + 6.5947 + var areaPaths = groups.selectAll('path.nv-area') 6.5948 + .data(function(d) { return isArea(d) ? [d] : [] }); // this is done differently than lines because I need to check if series is an area 6.5949 + areaPaths.enter().append('path') 6.5950 + .attr('class', 'nv-area') 6.5951 + .attr('d', function(d) { 6.5952 + return d3.svg.area() 6.5953 + .interpolate(interpolate) 6.5954 + .defined(defined) 6.5955 + .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) }) 6.5956 + .y0(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) }) 6.5957 + .y1(function(d,i) { return y0( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) }) 6.5958 + //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this 6.5959 + .apply(this, [d.values]) 6.5960 + }); 6.5961 + groups.exit().selectAll('path.nv-area') 6.5962 + .remove(); 6.5963 + 6.5964 + areaPaths.watchTransition(renderWatch, 'line: areaPaths') 6.5965 + .attr('d', function(d) { 6.5966 + return d3.svg.area() 6.5967 + .interpolate(interpolate) 6.5968 + .defined(defined) 6.5969 + .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) }) 6.5970 + .y0(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) }) 6.5971 + .y1(function(d,i) { return y( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) }) 6.5972 + //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this 6.5973 + .apply(this, [d.values]) 6.5974 + }); 6.5975 + 6.5976 + var linePaths = groups.selectAll('path.nv-line') 6.5977 + .data(function(d) { return [d.values] }); 6.5978 + 6.5979 + linePaths.enter().append('path') 6.5980 + .attr('class', 'nv-line') 6.5981 + .attr('d', 6.5982 + d3.svg.line() 6.5983 + .interpolate(interpolate) 6.5984 + .defined(defined) 6.5985 + .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) }) 6.5986 + .y(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) }) 6.5987 + ); 6.5988 + 6.5989 + linePaths.watchTransition(renderWatch, 'line: linePaths') 6.5990 + .attr('d', 6.5991 + d3.svg.line() 6.5992 + .interpolate(interpolate) 6.5993 + .defined(defined) 6.5994 + .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) }) 6.5995 + .y(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) }) 6.5996 + ); 6.5997 + 6.5998 + //store old scales for use in transitions on update 6.5999 + x0 = x.copy(); 6.6000 + y0 = y.copy(); 6.6001 + }); 6.6002 + renderWatch.renderEnd('line immediate'); 6.6003 + return chart; 6.6004 + } 6.6005 + 6.6006 + 6.6007 + //============================================================ 6.6008 + // Expose Public Variables 6.6009 + //------------------------------------------------------------ 6.6010 + 6.6011 + chart.dispatch = dispatch; 6.6012 + chart.scatter = scatter; 6.6013 + // Pass through events 6.6014 + scatter.dispatch.on('elementClick', function(){ dispatch.elementClick.apply(this, arguments); }); 6.6015 + scatter.dispatch.on('elementMouseover', function(){ dispatch.elementMouseover.apply(this, arguments); }); 6.6016 + scatter.dispatch.on('elementMouseout', function(){ dispatch.elementMouseout.apply(this, arguments); }); 6.6017 + 6.6018 + chart.options = nv.utils.optionsFunc.bind(chart); 6.6019 + 6.6020 + chart._options = Object.create({}, { 6.6021 + // simple options, just get/set the necessary values 6.6022 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.6023 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.6024 + defined: {get: function(){return defined;}, set: function(_){defined=_;}}, 6.6025 + interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}}, 6.6026 + clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, 6.6027 + 6.6028 + // options that require extra logic in the setter 6.6029 + margin: {get: function(){return margin;}, set: function(_){ 6.6030 + margin.top = _.top !== undefined ? _.top : margin.top; 6.6031 + margin.right = _.right !== undefined ? _.right : margin.right; 6.6032 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.6033 + margin.left = _.left !== undefined ? _.left : margin.left; 6.6034 + }}, 6.6035 + duration: {get: function(){return duration;}, set: function(_){ 6.6036 + duration = _; 6.6037 + renderWatch.reset(duration); 6.6038 + scatter.duration(duration); 6.6039 + }}, 6.6040 + isArea: {get: function(){return isArea;}, set: function(_){ 6.6041 + isArea = d3.functor(_); 6.6042 + }}, 6.6043 + x: {get: function(){return getX;}, set: function(_){ 6.6044 + getX = _; 6.6045 + scatter.x(_); 6.6046 + }}, 6.6047 + y: {get: function(){return getY;}, set: function(_){ 6.6048 + getY = _; 6.6049 + scatter.y(_); 6.6050 + }}, 6.6051 + color: {get: function(){return color;}, set: function(_){ 6.6052 + color = nv.utils.getColor(_); 6.6053 + scatter.color(color); 6.6054 + }} 6.6055 + }); 6.6056 + 6.6057 + nv.utils.inheritOptions(chart, scatter); 6.6058 + nv.utils.initOptions(chart); 6.6059 + 6.6060 + return chart; 6.6061 +}; 6.6062 +nv.models.lineChart = function() { 6.6063 + "use strict"; 6.6064 + 6.6065 + //============================================================ 6.6066 + // Public Variables with Default Settings 6.6067 + //------------------------------------------------------------ 6.6068 + 6.6069 + var lines = nv.models.line() 6.6070 + , xAxis = nv.models.axis() 6.6071 + , yAxis = nv.models.axis() 6.6072 + , legend = nv.models.legend() 6.6073 + , interactiveLayer = nv.interactiveGuideline() 6.6074 + , tooltip = nv.models.tooltip() 6.6075 + ; 6.6076 + 6.6077 + var margin = {top: 30, right: 20, bottom: 50, left: 60} 6.6078 + , color = nv.utils.defaultColor() 6.6079 + , width = null 6.6080 + , height = null 6.6081 + , showLegend = true 6.6082 + , showXAxis = true 6.6083 + , showYAxis = true 6.6084 + , rightAlignYAxis = false 6.6085 + , useInteractiveGuideline = false 6.6086 + , x 6.6087 + , y 6.6088 + , state = nv.utils.state() 6.6089 + , defaultState = null 6.6090 + , noData = null 6.6091 + , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd') 6.6092 + , duration = 250 6.6093 + ; 6.6094 + 6.6095 + // set options on sub-objects for this chart 6.6096 + xAxis.orient('bottom').tickPadding(7); 6.6097 + yAxis.orient(rightAlignYAxis ? 'right' : 'left'); 6.6098 + tooltip.valueFormatter(function(d, i) { 6.6099 + return yAxis.tickFormat()(d, i); 6.6100 + }).headerFormatter(function(d, i) { 6.6101 + return xAxis.tickFormat()(d, i); 6.6102 + }); 6.6103 + 6.6104 + 6.6105 + //============================================================ 6.6106 + // Private Variables 6.6107 + //------------------------------------------------------------ 6.6108 + 6.6109 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.6110 + 6.6111 + var stateGetter = function(data) { 6.6112 + return function(){ 6.6113 + return { 6.6114 + active: data.map(function(d) { return !d.disabled }) 6.6115 + }; 6.6116 + } 6.6117 + }; 6.6118 + 6.6119 + var stateSetter = function(data) { 6.6120 + return function(state) { 6.6121 + if (state.active !== undefined) 6.6122 + data.forEach(function(series,i) { 6.6123 + series.disabled = !state.active[i]; 6.6124 + }); 6.6125 + } 6.6126 + }; 6.6127 + 6.6128 + function chart(selection) { 6.6129 + renderWatch.reset(); 6.6130 + renderWatch.models(lines); 6.6131 + if (showXAxis) renderWatch.models(xAxis); 6.6132 + if (showYAxis) renderWatch.models(yAxis); 6.6133 + 6.6134 + selection.each(function(data) { 6.6135 + var container = d3.select(this), 6.6136 + that = this; 6.6137 + nv.utils.initSVG(container); 6.6138 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.6139 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.6140 + 6.6141 + chart.update = function() { 6.6142 + if (duration === 0) 6.6143 + container.call(chart); 6.6144 + else 6.6145 + container.transition().duration(duration).call(chart) 6.6146 + }; 6.6147 + chart.container = this; 6.6148 + 6.6149 + state 6.6150 + .setter(stateSetter(data), chart.update) 6.6151 + .getter(stateGetter(data)) 6.6152 + .update(); 6.6153 + 6.6154 + // DEPRECATED set state.disableddisabled 6.6155 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.6156 + 6.6157 + if (!defaultState) { 6.6158 + var key; 6.6159 + defaultState = {}; 6.6160 + for (key in state) { 6.6161 + if (state[key] instanceof Array) 6.6162 + defaultState[key] = state[key].slice(0); 6.6163 + else 6.6164 + defaultState[key] = state[key]; 6.6165 + } 6.6166 + } 6.6167 + 6.6168 + // Display noData message if there's nothing to show. 6.6169 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.6170 + nv.utils.noData(chart, container) 6.6171 + return chart; 6.6172 + } else { 6.6173 + container.selectAll('.nv-noData').remove(); 6.6174 + } 6.6175 + 6.6176 + 6.6177 + // Setup Scales 6.6178 + x = lines.xScale(); 6.6179 + y = lines.yScale(); 6.6180 + 6.6181 + // Setup containers and skeleton of chart 6.6182 + var wrap = container.selectAll('g.nv-wrap.nv-lineChart').data([data]); 6.6183 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineChart').append('g'); 6.6184 + var g = wrap.select('g'); 6.6185 + 6.6186 + gEnter.append("rect").style("opacity",0); 6.6187 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.6188 + gEnter.append('g').attr('class', 'nv-y nv-axis'); 6.6189 + gEnter.append('g').attr('class', 'nv-linesWrap'); 6.6190 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.6191 + gEnter.append('g').attr('class', 'nv-interactive'); 6.6192 + 6.6193 + g.select("rect") 6.6194 + .attr("width",availableWidth) 6.6195 + .attr("height",(availableHeight > 0) ? availableHeight : 0); 6.6196 + 6.6197 + // Legend 6.6198 + if (showLegend) { 6.6199 + legend.width(availableWidth); 6.6200 + 6.6201 + g.select('.nv-legendWrap') 6.6202 + .datum(data) 6.6203 + .call(legend); 6.6204 + 6.6205 + if ( margin.top != legend.height()) { 6.6206 + margin.top = legend.height(); 6.6207 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.6208 + } 6.6209 + 6.6210 + wrap.select('.nv-legendWrap') 6.6211 + .attr('transform', 'translate(0,' + (-margin.top) +')') 6.6212 + } 6.6213 + 6.6214 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.6215 + 6.6216 + if (rightAlignYAxis) { 6.6217 + g.select(".nv-y.nv-axis") 6.6218 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.6219 + } 6.6220 + 6.6221 + //Set up interactive layer 6.6222 + if (useInteractiveGuideline) { 6.6223 + interactiveLayer 6.6224 + .width(availableWidth) 6.6225 + .height(availableHeight) 6.6226 + .margin({left:margin.left, top:margin.top}) 6.6227 + .svgContainer(container) 6.6228 + .xScale(x); 6.6229 + wrap.select(".nv-interactive").call(interactiveLayer); 6.6230 + } 6.6231 + 6.6232 + lines 6.6233 + .width(availableWidth) 6.6234 + .height(availableHeight) 6.6235 + .color(data.map(function(d,i) { 6.6236 + return d.color || color(d, i); 6.6237 + }).filter(function(d,i) { return !data[i].disabled })); 6.6238 + 6.6239 + 6.6240 + var linesWrap = g.select('.nv-linesWrap') 6.6241 + .datum(data.filter(function(d) { return !d.disabled })); 6.6242 + 6.6243 + linesWrap.call(lines); 6.6244 + 6.6245 + // Setup Axes 6.6246 + if (showXAxis) { 6.6247 + xAxis 6.6248 + .scale(x) 6.6249 + ._ticks(nv.utils.calcTicksX(availableWidth/100, data) ) 6.6250 + .tickSize(-availableHeight, 0); 6.6251 + 6.6252 + g.select('.nv-x.nv-axis') 6.6253 + .attr('transform', 'translate(0,' + y.range()[0] + ')'); 6.6254 + g.select('.nv-x.nv-axis') 6.6255 + .call(xAxis); 6.6256 + } 6.6257 + 6.6258 + if (showYAxis) { 6.6259 + yAxis 6.6260 + .scale(y) 6.6261 + ._ticks(nv.utils.calcTicksY(availableHeight/36, data) ) 6.6262 + .tickSize( -availableWidth, 0); 6.6263 + 6.6264 + g.select('.nv-y.nv-axis') 6.6265 + .call(yAxis); 6.6266 + } 6.6267 + 6.6268 + //============================================================ 6.6269 + // Event Handling/Dispatching (in chart's scope) 6.6270 + //------------------------------------------------------------ 6.6271 + 6.6272 + legend.dispatch.on('stateChange', function(newState) { 6.6273 + for (var key in newState) 6.6274 + state[key] = newState[key]; 6.6275 + dispatch.stateChange(state); 6.6276 + chart.update(); 6.6277 + }); 6.6278 + 6.6279 + interactiveLayer.dispatch.on('elementMousemove', function(e) { 6.6280 + lines.clearHighlights(); 6.6281 + var singlePoint, pointIndex, pointXLocation, allData = []; 6.6282 + data 6.6283 + .filter(function(series, i) { 6.6284 + series.seriesIndex = i; 6.6285 + return !series.disabled; 6.6286 + }) 6.6287 + .forEach(function(series,i) { 6.6288 + pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); 6.6289 + var point = series.values[pointIndex]; 6.6290 + var pointYValue = chart.y()(point, pointIndex); 6.6291 + if (pointYValue != null) { 6.6292 + lines.highlightPoint(i, pointIndex, true); 6.6293 + } 6.6294 + if (point === undefined) return; 6.6295 + if (singlePoint === undefined) singlePoint = point; 6.6296 + if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); 6.6297 + allData.push({ 6.6298 + key: series.key, 6.6299 + value: pointYValue, 6.6300 + color: color(series,series.seriesIndex) 6.6301 + }); 6.6302 + }); 6.6303 + //Highlight the tooltip entry based on which point the mouse is closest to. 6.6304 + if (allData.length > 2) { 6.6305 + var yValue = chart.yScale().invert(e.mouseY); 6.6306 + var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]); 6.6307 + var threshold = 0.03 * domainExtent; 6.6308 + var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold); 6.6309 + if (indexToHighlight !== null) 6.6310 + allData[indexToHighlight].highlight = true; 6.6311 + } 6.6312 + 6.6313 + var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); 6.6314 + interactiveLayer.tooltip 6.6315 + .position({left: e.mouseX + margin.left, top: e.mouseY + margin.top}) 6.6316 + .chartContainer(that.parentNode) 6.6317 + .valueFormatter(function(d,i) { 6.6318 + return d == null ? "N/A" : yAxis.tickFormat()(d); 6.6319 + }) 6.6320 + .data({ 6.6321 + value: xValue, 6.6322 + index: pointIndex, 6.6323 + series: allData 6.6324 + })(); 6.6325 + 6.6326 + interactiveLayer.renderGuideLine(pointXLocation); 6.6327 + 6.6328 + }); 6.6329 + 6.6330 + interactiveLayer.dispatch.on('elementClick', function(e) { 6.6331 + var pointXLocation, allData = []; 6.6332 + 6.6333 + data.filter(function(series, i) { 6.6334 + series.seriesIndex = i; 6.6335 + return !series.disabled; 6.6336 + }).forEach(function(series) { 6.6337 + var pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); 6.6338 + var point = series.values[pointIndex]; 6.6339 + if (typeof point === 'undefined') return; 6.6340 + if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); 6.6341 + var yPos = chart.yScale()(chart.y()(point,pointIndex)); 6.6342 + allData.push({ 6.6343 + point: point, 6.6344 + pointIndex: pointIndex, 6.6345 + pos: [pointXLocation, yPos], 6.6346 + seriesIndex: series.seriesIndex, 6.6347 + series: series 6.6348 + }); 6.6349 + }); 6.6350 + 6.6351 + lines.dispatch.elementClick(allData); 6.6352 + }); 6.6353 + 6.6354 + interactiveLayer.dispatch.on("elementMouseout",function(e) { 6.6355 + lines.clearHighlights(); 6.6356 + }); 6.6357 + 6.6358 + dispatch.on('changeState', function(e) { 6.6359 + if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) { 6.6360 + data.forEach(function(series,i) { 6.6361 + series.disabled = e.disabled[i]; 6.6362 + }); 6.6363 + 6.6364 + state.disabled = e.disabled; 6.6365 + } 6.6366 + 6.6367 + chart.update(); 6.6368 + }); 6.6369 + 6.6370 + }); 6.6371 + 6.6372 + renderWatch.renderEnd('lineChart immediate'); 6.6373 + return chart; 6.6374 + } 6.6375 + 6.6376 + //============================================================ 6.6377 + // Event Handling/Dispatching (out of chart's scope) 6.6378 + //------------------------------------------------------------ 6.6379 + 6.6380 + lines.dispatch.on('elementMouseover.tooltip', function(evt) { 6.6381 + tooltip.data(evt).position(evt.pos).hidden(false); 6.6382 + }); 6.6383 + 6.6384 + lines.dispatch.on('elementMouseout.tooltip', function(evt) { 6.6385 + tooltip.hidden(true) 6.6386 + }); 6.6387 + 6.6388 + //============================================================ 6.6389 + // Expose Public Variables 6.6390 + //------------------------------------------------------------ 6.6391 + 6.6392 + // expose chart's sub-components 6.6393 + chart.dispatch = dispatch; 6.6394 + chart.lines = lines; 6.6395 + chart.legend = legend; 6.6396 + chart.xAxis = xAxis; 6.6397 + chart.yAxis = yAxis; 6.6398 + chart.interactiveLayer = interactiveLayer; 6.6399 + chart.tooltip = tooltip; 6.6400 + 6.6401 + chart.dispatch = dispatch; 6.6402 + chart.options = nv.utils.optionsFunc.bind(chart); 6.6403 + 6.6404 + chart._options = Object.create({}, { 6.6405 + // simple options, just get/set the necessary values 6.6406 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.6407 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.6408 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.6409 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.6410 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.6411 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.6412 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.6413 + 6.6414 + // deprecated options 6.6415 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.6416 + // deprecated after 1.7.1 6.6417 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.6418 + tooltip.enabled(!!_); 6.6419 + }}, 6.6420 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.6421 + // deprecated after 1.7.1 6.6422 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.6423 + tooltip.contentGenerator(_); 6.6424 + }}, 6.6425 + 6.6426 + // options that require extra logic in the setter 6.6427 + margin: {get: function(){return margin;}, set: function(_){ 6.6428 + margin.top = _.top !== undefined ? _.top : margin.top; 6.6429 + margin.right = _.right !== undefined ? _.right : margin.right; 6.6430 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.6431 + margin.left = _.left !== undefined ? _.left : margin.left; 6.6432 + }}, 6.6433 + duration: {get: function(){return duration;}, set: function(_){ 6.6434 + duration = _; 6.6435 + renderWatch.reset(duration); 6.6436 + lines.duration(duration); 6.6437 + xAxis.duration(duration); 6.6438 + yAxis.duration(duration); 6.6439 + }}, 6.6440 + color: {get: function(){return color;}, set: function(_){ 6.6441 + color = nv.utils.getColor(_); 6.6442 + legend.color(color); 6.6443 + lines.color(color); 6.6444 + }}, 6.6445 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.6446 + rightAlignYAxis = _; 6.6447 + yAxis.orient( rightAlignYAxis ? 'right' : 'left'); 6.6448 + }}, 6.6449 + useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ 6.6450 + useInteractiveGuideline = _; 6.6451 + if (useInteractiveGuideline) { 6.6452 + lines.interactive(false); 6.6453 + lines.useVoronoi(false); 6.6454 + } 6.6455 + }} 6.6456 + }); 6.6457 + 6.6458 + nv.utils.inheritOptions(chart, lines); 6.6459 + nv.utils.initOptions(chart); 6.6460 + 6.6461 + return chart; 6.6462 +}; 6.6463 +nv.models.linePlusBarChart = function() { 6.6464 + "use strict"; 6.6465 + 6.6466 + //============================================================ 6.6467 + // Public Variables with Default Settings 6.6468 + //------------------------------------------------------------ 6.6469 + 6.6470 + var lines = nv.models.line() 6.6471 + , lines2 = nv.models.line() 6.6472 + , bars = nv.models.historicalBar() 6.6473 + , bars2 = nv.models.historicalBar() 6.6474 + , xAxis = nv.models.axis() 6.6475 + , x2Axis = nv.models.axis() 6.6476 + , y1Axis = nv.models.axis() 6.6477 + , y2Axis = nv.models.axis() 6.6478 + , y3Axis = nv.models.axis() 6.6479 + , y4Axis = nv.models.axis() 6.6480 + , legend = nv.models.legend() 6.6481 + , brush = d3.svg.brush() 6.6482 + , tooltip = nv.models.tooltip() 6.6483 + ; 6.6484 + 6.6485 + var margin = {top: 30, right: 30, bottom: 30, left: 60} 6.6486 + , margin2 = {top: 0, right: 30, bottom: 20, left: 60} 6.6487 + , width = null 6.6488 + , height = null 6.6489 + , getX = function(d) { return d.x } 6.6490 + , getY = function(d) { return d.y } 6.6491 + , color = nv.utils.defaultColor() 6.6492 + , showLegend = true 6.6493 + , focusEnable = true 6.6494 + , focusShowAxisY = false 6.6495 + , focusShowAxisX = true 6.6496 + , focusHeight = 50 6.6497 + , extent 6.6498 + , brushExtent = null 6.6499 + , x 6.6500 + , x2 6.6501 + , y1 6.6502 + , y2 6.6503 + , y3 6.6504 + , y4 6.6505 + , noData = null 6.6506 + , dispatch = d3.dispatch('brush', 'stateChange', 'changeState') 6.6507 + , transitionDuration = 0 6.6508 + , state = nv.utils.state() 6.6509 + , defaultState = null 6.6510 + , legendLeftAxisHint = ' (left axis)' 6.6511 + , legendRightAxisHint = ' (right axis)' 6.6512 + ; 6.6513 + 6.6514 + lines.clipEdge(true); 6.6515 + lines2.interactive(false); 6.6516 + xAxis.orient('bottom').tickPadding(5); 6.6517 + y1Axis.orient('left'); 6.6518 + y2Axis.orient('right'); 6.6519 + x2Axis.orient('bottom').tickPadding(5); 6.6520 + y3Axis.orient('left'); 6.6521 + y4Axis.orient('right'); 6.6522 + 6.6523 + tooltip.headerEnabled(true).headerFormatter(function(d, i) { 6.6524 + return xAxis.tickFormat()(d, i); 6.6525 + }); 6.6526 + 6.6527 + //============================================================ 6.6528 + // Private Variables 6.6529 + //------------------------------------------------------------ 6.6530 + 6.6531 + var stateGetter = function(data) { 6.6532 + return function(){ 6.6533 + return { 6.6534 + active: data.map(function(d) { return !d.disabled }) 6.6535 + }; 6.6536 + } 6.6537 + }; 6.6538 + 6.6539 + var stateSetter = function(data) { 6.6540 + return function(state) { 6.6541 + if (state.active !== undefined) 6.6542 + data.forEach(function(series,i) { 6.6543 + series.disabled = !state.active[i]; 6.6544 + }); 6.6545 + } 6.6546 + }; 6.6547 + 6.6548 + function chart(selection) { 6.6549 + selection.each(function(data) { 6.6550 + var container = d3.select(this), 6.6551 + that = this; 6.6552 + nv.utils.initSVG(container); 6.6553 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.6554 + availableHeight1 = nv.utils.availableHeight(height, container, margin) 6.6555 + - (focusEnable ? focusHeight : 0), 6.6556 + availableHeight2 = focusHeight - margin2.top - margin2.bottom; 6.6557 + 6.6558 + chart.update = function() { container.transition().duration(transitionDuration).call(chart); }; 6.6559 + chart.container = this; 6.6560 + 6.6561 + state 6.6562 + .setter(stateSetter(data), chart.update) 6.6563 + .getter(stateGetter(data)) 6.6564 + .update(); 6.6565 + 6.6566 + // DEPRECATED set state.disableddisabled 6.6567 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.6568 + 6.6569 + if (!defaultState) { 6.6570 + var key; 6.6571 + defaultState = {}; 6.6572 + for (key in state) { 6.6573 + if (state[key] instanceof Array) 6.6574 + defaultState[key] = state[key].slice(0); 6.6575 + else 6.6576 + defaultState[key] = state[key]; 6.6577 + } 6.6578 + } 6.6579 + 6.6580 + // Display No Data message if there's nothing to show. 6.6581 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.6582 + nv.utils.noData(chart, container) 6.6583 + return chart; 6.6584 + } else { 6.6585 + container.selectAll('.nv-noData').remove(); 6.6586 + } 6.6587 + 6.6588 + // Setup Scales 6.6589 + var dataBars = data.filter(function(d) { return !d.disabled && d.bar }); 6.6590 + var dataLines = data.filter(function(d) { return !d.bar }); // removed the !d.disabled clause here to fix Issue #240 6.6591 + 6.6592 + x = bars.xScale(); 6.6593 + x2 = x2Axis.scale(); 6.6594 + y1 = bars.yScale(); 6.6595 + y2 = lines.yScale(); 6.6596 + y3 = bars2.yScale(); 6.6597 + y4 = lines2.yScale(); 6.6598 + 6.6599 + var series1 = data 6.6600 + .filter(function(d) { return !d.disabled && d.bar }) 6.6601 + .map(function(d) { 6.6602 + return d.values.map(function(d,i) { 6.6603 + return { x: getX(d,i), y: getY(d,i) } 6.6604 + }) 6.6605 + }); 6.6606 + 6.6607 + var series2 = data 6.6608 + .filter(function(d) { return !d.disabled && !d.bar }) 6.6609 + .map(function(d) { 6.6610 + return d.values.map(function(d,i) { 6.6611 + return { x: getX(d,i), y: getY(d,i) } 6.6612 + }) 6.6613 + }); 6.6614 + 6.6615 + x.range([0, availableWidth]); 6.6616 + 6.6617 + x2 .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } )) 6.6618 + .range([0, availableWidth]); 6.6619 + 6.6620 + // Setup containers and skeleton of chart 6.6621 + var wrap = container.selectAll('g.nv-wrap.nv-linePlusBar').data([data]); 6.6622 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-linePlusBar').append('g'); 6.6623 + var g = wrap.select('g'); 6.6624 + 6.6625 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.6626 + 6.6627 + // this is the main chart 6.6628 + var focusEnter = gEnter.append('g').attr('class', 'nv-focus'); 6.6629 + focusEnter.append('g').attr('class', 'nv-x nv-axis'); 6.6630 + focusEnter.append('g').attr('class', 'nv-y1 nv-axis'); 6.6631 + focusEnter.append('g').attr('class', 'nv-y2 nv-axis'); 6.6632 + focusEnter.append('g').attr('class', 'nv-barsWrap'); 6.6633 + focusEnter.append('g').attr('class', 'nv-linesWrap'); 6.6634 + 6.6635 + // context chart is where you can focus in 6.6636 + var contextEnter = gEnter.append('g').attr('class', 'nv-context'); 6.6637 + contextEnter.append('g').attr('class', 'nv-x nv-axis'); 6.6638 + contextEnter.append('g').attr('class', 'nv-y1 nv-axis'); 6.6639 + contextEnter.append('g').attr('class', 'nv-y2 nv-axis'); 6.6640 + contextEnter.append('g').attr('class', 'nv-barsWrap'); 6.6641 + contextEnter.append('g').attr('class', 'nv-linesWrap'); 6.6642 + contextEnter.append('g').attr('class', 'nv-brushBackground'); 6.6643 + contextEnter.append('g').attr('class', 'nv-x nv-brush'); 6.6644 + 6.6645 + //============================================================ 6.6646 + // Legend 6.6647 + //------------------------------------------------------------ 6.6648 + 6.6649 + if (showLegend) { 6.6650 + var legendWidth = legend.align() ? availableWidth / 2 : availableWidth; 6.6651 + var legendXPosition = legend.align() ? legendWidth : 0; 6.6652 + 6.6653 + legend.width(legendWidth); 6.6654 + 6.6655 + g.select('.nv-legendWrap') 6.6656 + .datum(data.map(function(series) { 6.6657 + series.originalKey = series.originalKey === undefined ? series.key : series.originalKey; 6.6658 + series.key = series.originalKey + (series.bar ? legendLeftAxisHint : legendRightAxisHint); 6.6659 + return series; 6.6660 + })) 6.6661 + .call(legend); 6.6662 + 6.6663 + if ( margin.top != legend.height()) { 6.6664 + margin.top = legend.height(); 6.6665 + // FIXME: shouldn't this be "- (focusEnabled ? focusHeight : 0)"? 6.6666 + availableHeight1 = nv.utils.availableHeight(height, container, margin) - focusHeight; 6.6667 + } 6.6668 + 6.6669 + g.select('.nv-legendWrap') 6.6670 + .attr('transform', 'translate(' + legendXPosition + ',' + (-margin.top) +')'); 6.6671 + } 6.6672 + 6.6673 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.6674 + 6.6675 + //============================================================ 6.6676 + // Context chart (focus chart) components 6.6677 + //------------------------------------------------------------ 6.6678 + 6.6679 + // hide or show the focus context chart 6.6680 + g.select('.nv-context').style('display', focusEnable ? 'initial' : 'none'); 6.6681 + 6.6682 + bars2 6.6683 + .width(availableWidth) 6.6684 + .height(availableHeight2) 6.6685 + .color(data.map(function (d, i) { 6.6686 + return d.color || color(d, i); 6.6687 + }).filter(function (d, i) { 6.6688 + return !data[i].disabled && data[i].bar 6.6689 + })); 6.6690 + lines2 6.6691 + .width(availableWidth) 6.6692 + .height(availableHeight2) 6.6693 + .color(data.map(function (d, i) { 6.6694 + return d.color || color(d, i); 6.6695 + }).filter(function (d, i) { 6.6696 + return !data[i].disabled && !data[i].bar 6.6697 + })); 6.6698 + 6.6699 + var bars2Wrap = g.select('.nv-context .nv-barsWrap') 6.6700 + .datum(dataBars.length ? dataBars : [ 6.6701 + {values: []} 6.6702 + ]); 6.6703 + var lines2Wrap = g.select('.nv-context .nv-linesWrap') 6.6704 + .datum(!dataLines[0].disabled ? dataLines : [ 6.6705 + {values: []} 6.6706 + ]); 6.6707 + 6.6708 + g.select('.nv-context') 6.6709 + .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')'); 6.6710 + 6.6711 + bars2Wrap.transition().call(bars2); 6.6712 + lines2Wrap.transition().call(lines2); 6.6713 + 6.6714 + // context (focus chart) axis controls 6.6715 + if (focusShowAxisX) { 6.6716 + x2Axis 6.6717 + ._ticks( nv.utils.calcTicksX(availableWidth / 100, data)) 6.6718 + .tickSize(-availableHeight2, 0); 6.6719 + g.select('.nv-context .nv-x.nv-axis') 6.6720 + .attr('transform', 'translate(0,' + y3.range()[0] + ')'); 6.6721 + g.select('.nv-context .nv-x.nv-axis').transition() 6.6722 + .call(x2Axis); 6.6723 + } 6.6724 + 6.6725 + if (focusShowAxisY) { 6.6726 + y3Axis 6.6727 + .scale(y3) 6.6728 + ._ticks( availableHeight2 / 36 ) 6.6729 + .tickSize( -availableWidth, 0); 6.6730 + y4Axis 6.6731 + .scale(y4) 6.6732 + ._ticks( availableHeight2 / 36 ) 6.6733 + .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none 6.6734 + 6.6735 + g.select('.nv-context .nv-y3.nv-axis') 6.6736 + .style('opacity', dataBars.length ? 1 : 0) 6.6737 + .attr('transform', 'translate(0,' + x2.range()[0] + ')'); 6.6738 + g.select('.nv-context .nv-y2.nv-axis') 6.6739 + .style('opacity', dataLines.length ? 1 : 0) 6.6740 + .attr('transform', 'translate(' + x2.range()[1] + ',0)'); 6.6741 + 6.6742 + g.select('.nv-context .nv-y1.nv-axis').transition() 6.6743 + .call(y3Axis); 6.6744 + g.select('.nv-context .nv-y2.nv-axis').transition() 6.6745 + .call(y4Axis); 6.6746 + } 6.6747 + 6.6748 + // Setup Brush 6.6749 + brush.x(x2).on('brush', onBrush); 6.6750 + 6.6751 + if (brushExtent) brush.extent(brushExtent); 6.6752 + 6.6753 + var brushBG = g.select('.nv-brushBackground').selectAll('g') 6.6754 + .data([brushExtent || brush.extent()]); 6.6755 + 6.6756 + var brushBGenter = brushBG.enter() 6.6757 + .append('g'); 6.6758 + 6.6759 + brushBGenter.append('rect') 6.6760 + .attr('class', 'left') 6.6761 + .attr('x', 0) 6.6762 + .attr('y', 0) 6.6763 + .attr('height', availableHeight2); 6.6764 + 6.6765 + brushBGenter.append('rect') 6.6766 + .attr('class', 'right') 6.6767 + .attr('x', 0) 6.6768 + .attr('y', 0) 6.6769 + .attr('height', availableHeight2); 6.6770 + 6.6771 + var gBrush = g.select('.nv-x.nv-brush') 6.6772 + .call(brush); 6.6773 + gBrush.selectAll('rect') 6.6774 + //.attr('y', -5) 6.6775 + .attr('height', availableHeight2); 6.6776 + gBrush.selectAll('.resize').append('path').attr('d', resizePath); 6.6777 + 6.6778 + //============================================================ 6.6779 + // Event Handling/Dispatching (in chart's scope) 6.6780 + //------------------------------------------------------------ 6.6781 + 6.6782 + legend.dispatch.on('stateChange', function(newState) { 6.6783 + for (var key in newState) 6.6784 + state[key] = newState[key]; 6.6785 + dispatch.stateChange(state); 6.6786 + chart.update(); 6.6787 + }); 6.6788 + 6.6789 + // Update chart from a state object passed to event handler 6.6790 + dispatch.on('changeState', function(e) { 6.6791 + if (typeof e.disabled !== 'undefined') { 6.6792 + data.forEach(function(series,i) { 6.6793 + series.disabled = e.disabled[i]; 6.6794 + }); 6.6795 + state.disabled = e.disabled; 6.6796 + } 6.6797 + chart.update(); 6.6798 + }); 6.6799 + 6.6800 + //============================================================ 6.6801 + // Functions 6.6802 + //------------------------------------------------------------ 6.6803 + 6.6804 + // Taken from crossfilter (http://square.github.com/crossfilter/) 6.6805 + function resizePath(d) { 6.6806 + var e = +(d == 'e'), 6.6807 + x = e ? 1 : -1, 6.6808 + y = availableHeight2 / 3; 6.6809 + return 'M' + (.5 * x) + ',' + y 6.6810 + + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6) 6.6811 + + 'V' + (2 * y - 6) 6.6812 + + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y) 6.6813 + + 'Z' 6.6814 + + 'M' + (2.5 * x) + ',' + (y + 8) 6.6815 + + 'V' + (2 * y - 8) 6.6816 + + 'M' + (4.5 * x) + ',' + (y + 8) 6.6817 + + 'V' + (2 * y - 8); 6.6818 + } 6.6819 + 6.6820 + 6.6821 + function updateBrushBG() { 6.6822 + if (!brush.empty()) brush.extent(brushExtent); 6.6823 + brushBG 6.6824 + .data([brush.empty() ? x2.domain() : brushExtent]) 6.6825 + .each(function(d,i) { 6.6826 + var leftWidth = x2(d[0]) - x2.range()[0], 6.6827 + rightWidth = x2.range()[1] - x2(d[1]); 6.6828 + d3.select(this).select('.left') 6.6829 + .attr('width', leftWidth < 0 ? 0 : leftWidth); 6.6830 + 6.6831 + d3.select(this).select('.right') 6.6832 + .attr('x', x2(d[1])) 6.6833 + .attr('width', rightWidth < 0 ? 0 : rightWidth); 6.6834 + }); 6.6835 + } 6.6836 + 6.6837 + function onBrush() { 6.6838 + brushExtent = brush.empty() ? null : brush.extent(); 6.6839 + extent = brush.empty() ? x2.domain() : brush.extent(); 6.6840 + dispatch.brush({extent: extent, brush: brush}); 6.6841 + updateBrushBG(); 6.6842 + 6.6843 + // Prepare Main (Focus) Bars and Lines 6.6844 + bars 6.6845 + .width(availableWidth) 6.6846 + .height(availableHeight1) 6.6847 + .color(data.map(function(d,i) { 6.6848 + return d.color || color(d, i); 6.6849 + }).filter(function(d,i) { return !data[i].disabled && data[i].bar })); 6.6850 + 6.6851 + lines 6.6852 + .width(availableWidth) 6.6853 + .height(availableHeight1) 6.6854 + .color(data.map(function(d,i) { 6.6855 + return d.color || color(d, i); 6.6856 + }).filter(function(d,i) { return !data[i].disabled && !data[i].bar })); 6.6857 + 6.6858 + var focusBarsWrap = g.select('.nv-focus .nv-barsWrap') 6.6859 + .datum(!dataBars.length ? [{values:[]}] : 6.6860 + dataBars 6.6861 + .map(function(d,i) { 6.6862 + return { 6.6863 + key: d.key, 6.6864 + values: d.values.filter(function(d,i) { 6.6865 + return bars.x()(d,i) >= extent[0] && bars.x()(d,i) <= extent[1]; 6.6866 + }) 6.6867 + } 6.6868 + }) 6.6869 + ); 6.6870 + 6.6871 + var focusLinesWrap = g.select('.nv-focus .nv-linesWrap') 6.6872 + .datum(dataLines[0].disabled ? [{values:[]}] : 6.6873 + dataLines 6.6874 + .map(function(d,i) { 6.6875 + return { 6.6876 + area: d.area, 6.6877 + fillOpacity: d.fillOpacity, 6.6878 + key: d.key, 6.6879 + values: d.values.filter(function(d,i) { 6.6880 + return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; 6.6881 + }) 6.6882 + } 6.6883 + }) 6.6884 + ); 6.6885 + 6.6886 + // Update Main (Focus) X Axis 6.6887 + if (dataBars.length) { 6.6888 + x = bars.xScale(); 6.6889 + } else { 6.6890 + x = lines.xScale(); 6.6891 + } 6.6892 + 6.6893 + xAxis 6.6894 + .scale(x) 6.6895 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.6896 + .tickSize(-availableHeight1, 0); 6.6897 + 6.6898 + xAxis.domain([Math.ceil(extent[0]), Math.floor(extent[1])]); 6.6899 + 6.6900 + g.select('.nv-x.nv-axis').transition().duration(transitionDuration) 6.6901 + .call(xAxis); 6.6902 + 6.6903 + // Update Main (Focus) Bars and Lines 6.6904 + focusBarsWrap.transition().duration(transitionDuration).call(bars); 6.6905 + focusLinesWrap.transition().duration(transitionDuration).call(lines); 6.6906 + 6.6907 + // Setup and Update Main (Focus) Y Axes 6.6908 + g.select('.nv-focus .nv-x.nv-axis') 6.6909 + .attr('transform', 'translate(0,' + y1.range()[0] + ')'); 6.6910 + 6.6911 + y1Axis 6.6912 + .scale(y1) 6.6913 + ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) ) 6.6914 + .tickSize(-availableWidth, 0); 6.6915 + y2Axis 6.6916 + .scale(y2) 6.6917 + ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) ) 6.6918 + .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none 6.6919 + 6.6920 + g.select('.nv-focus .nv-y1.nv-axis') 6.6921 + .style('opacity', dataBars.length ? 1 : 0); 6.6922 + g.select('.nv-focus .nv-y2.nv-axis') 6.6923 + .style('opacity', dataLines.length && !dataLines[0].disabled ? 1 : 0) 6.6924 + .attr('transform', 'translate(' + x.range()[1] + ',0)'); 6.6925 + 6.6926 + g.select('.nv-focus .nv-y1.nv-axis').transition().duration(transitionDuration) 6.6927 + .call(y1Axis); 6.6928 + g.select('.nv-focus .nv-y2.nv-axis').transition().duration(transitionDuration) 6.6929 + .call(y2Axis); 6.6930 + } 6.6931 + 6.6932 + onBrush(); 6.6933 + 6.6934 + }); 6.6935 + 6.6936 + return chart; 6.6937 + } 6.6938 + 6.6939 + //============================================================ 6.6940 + // Event Handling/Dispatching (out of chart's scope) 6.6941 + //------------------------------------------------------------ 6.6942 + 6.6943 + lines.dispatch.on('elementMouseover.tooltip', function(evt) { 6.6944 + tooltip 6.6945 + .duration(100) 6.6946 + .valueFormatter(function(d, i) { 6.6947 + return y2Axis.tickFormat()(d, i); 6.6948 + }) 6.6949 + .data(evt) 6.6950 + .position(evt.pos) 6.6951 + .hidden(false); 6.6952 + }); 6.6953 + 6.6954 + lines.dispatch.on('elementMouseout.tooltip', function(evt) { 6.6955 + tooltip.hidden(true) 6.6956 + }); 6.6957 + 6.6958 + bars.dispatch.on('elementMouseover.tooltip', function(evt) { 6.6959 + evt.value = chart.x()(evt.data); 6.6960 + evt['series'] = { 6.6961 + value: chart.y()(evt.data), 6.6962 + color: evt.color 6.6963 + }; 6.6964 + tooltip 6.6965 + .duration(0) 6.6966 + .valueFormatter(function(d, i) { 6.6967 + return y1Axis.tickFormat()(d, i); 6.6968 + }) 6.6969 + .data(evt) 6.6970 + .hidden(false); 6.6971 + }); 6.6972 + 6.6973 + bars.dispatch.on('elementMouseout.tooltip', function(evt) { 6.6974 + tooltip.hidden(true); 6.6975 + }); 6.6976 + 6.6977 + bars.dispatch.on('elementMousemove.tooltip', function(evt) { 6.6978 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.6979 + }); 6.6980 + 6.6981 + //============================================================ 6.6982 + 6.6983 + 6.6984 + //============================================================ 6.6985 + // Expose Public Variables 6.6986 + //------------------------------------------------------------ 6.6987 + 6.6988 + // expose chart's sub-components 6.6989 + chart.dispatch = dispatch; 6.6990 + chart.legend = legend; 6.6991 + chart.lines = lines; 6.6992 + chart.lines2 = lines2; 6.6993 + chart.bars = bars; 6.6994 + chart.bars2 = bars2; 6.6995 + chart.xAxis = xAxis; 6.6996 + chart.x2Axis = x2Axis; 6.6997 + chart.y1Axis = y1Axis; 6.6998 + chart.y2Axis = y2Axis; 6.6999 + chart.y3Axis = y3Axis; 6.7000 + chart.y4Axis = y4Axis; 6.7001 + chart.tooltip = tooltip; 6.7002 + 6.7003 + chart.options = nv.utils.optionsFunc.bind(chart); 6.7004 + 6.7005 + chart._options = Object.create({}, { 6.7006 + // simple options, just get/set the necessary values 6.7007 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.7008 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.7009 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.7010 + brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}}, 6.7011 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.7012 + focusEnable: {get: function(){return focusEnable;}, set: function(_){focusEnable=_;}}, 6.7013 + focusHeight: {get: function(){return focusHeight;}, set: function(_){focusHeight=_;}}, 6.7014 + focusShowAxisX: {get: function(){return focusShowAxisX;}, set: function(_){focusShowAxisX=_;}}, 6.7015 + focusShowAxisY: {get: function(){return focusShowAxisY;}, set: function(_){focusShowAxisY=_;}}, 6.7016 + legendLeftAxisHint: {get: function(){return legendLeftAxisHint;}, set: function(_){legendLeftAxisHint=_;}}, 6.7017 + legendRightAxisHint: {get: function(){return legendRightAxisHint;}, set: function(_){legendRightAxisHint=_;}}, 6.7018 + 6.7019 + // deprecated options 6.7020 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.7021 + // deprecated after 1.7.1 6.7022 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.7023 + tooltip.enabled(!!_); 6.7024 + }}, 6.7025 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.7026 + // deprecated after 1.7.1 6.7027 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.7028 + tooltip.contentGenerator(_); 6.7029 + }}, 6.7030 + 6.7031 + // options that require extra logic in the setter 6.7032 + margin: {get: function(){return margin;}, set: function(_){ 6.7033 + margin.top = _.top !== undefined ? _.top : margin.top; 6.7034 + margin.right = _.right !== undefined ? _.right : margin.right; 6.7035 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.7036 + margin.left = _.left !== undefined ? _.left : margin.left; 6.7037 + }}, 6.7038 + duration: {get: function(){return transitionDuration;}, set: function(_){ 6.7039 + transitionDuration = _; 6.7040 + }}, 6.7041 + color: {get: function(){return color;}, set: function(_){ 6.7042 + color = nv.utils.getColor(_); 6.7043 + legend.color(color); 6.7044 + }}, 6.7045 + x: {get: function(){return getX;}, set: function(_){ 6.7046 + getX = _; 6.7047 + lines.x(_); 6.7048 + lines2.x(_); 6.7049 + bars.x(_); 6.7050 + bars2.x(_); 6.7051 + }}, 6.7052 + y: {get: function(){return getY;}, set: function(_){ 6.7053 + getY = _; 6.7054 + lines.y(_); 6.7055 + lines2.y(_); 6.7056 + bars.y(_); 6.7057 + bars2.y(_); 6.7058 + }} 6.7059 + }); 6.7060 + 6.7061 + nv.utils.inheritOptions(chart, lines); 6.7062 + nv.utils.initOptions(chart); 6.7063 + 6.7064 + return chart; 6.7065 +}; 6.7066 +nv.models.lineWithFocusChart = function() { 6.7067 + "use strict"; 6.7068 + 6.7069 + //============================================================ 6.7070 + // Public Variables with Default Settings 6.7071 + //------------------------------------------------------------ 6.7072 + 6.7073 + var lines = nv.models.line() 6.7074 + , lines2 = nv.models.line() 6.7075 + , xAxis = nv.models.axis() 6.7076 + , yAxis = nv.models.axis() 6.7077 + , x2Axis = nv.models.axis() 6.7078 + , y2Axis = nv.models.axis() 6.7079 + , legend = nv.models.legend() 6.7080 + , brush = d3.svg.brush() 6.7081 + , tooltip = nv.models.tooltip() 6.7082 + , interactiveLayer = nv.interactiveGuideline() 6.7083 + ; 6.7084 + 6.7085 + var margin = {top: 30, right: 30, bottom: 30, left: 60} 6.7086 + , margin2 = {top: 0, right: 30, bottom: 20, left: 60} 6.7087 + , color = nv.utils.defaultColor() 6.7088 + , width = null 6.7089 + , height = null 6.7090 + , height2 = 50 6.7091 + , useInteractiveGuideline = false 6.7092 + , x 6.7093 + , y 6.7094 + , x2 6.7095 + , y2 6.7096 + , showLegend = true 6.7097 + , brushExtent = null 6.7098 + , noData = null 6.7099 + , dispatch = d3.dispatch('brush', 'stateChange', 'changeState') 6.7100 + , transitionDuration = 250 6.7101 + , state = nv.utils.state() 6.7102 + , defaultState = null 6.7103 + ; 6.7104 + 6.7105 + lines.clipEdge(true).duration(0); 6.7106 + lines2.interactive(false); 6.7107 + xAxis.orient('bottom').tickPadding(5); 6.7108 + yAxis.orient('left'); 6.7109 + x2Axis.orient('bottom').tickPadding(5); 6.7110 + y2Axis.orient('left'); 6.7111 + 6.7112 + tooltip.valueFormatter(function(d, i) { 6.7113 + return yAxis.tickFormat()(d, i); 6.7114 + }).headerFormatter(function(d, i) { 6.7115 + return xAxis.tickFormat()(d, i); 6.7116 + }); 6.7117 + 6.7118 + //============================================================ 6.7119 + // Private Variables 6.7120 + //------------------------------------------------------------ 6.7121 + 6.7122 + var stateGetter = function(data) { 6.7123 + return function(){ 6.7124 + return { 6.7125 + active: data.map(function(d) { return !d.disabled }) 6.7126 + }; 6.7127 + } 6.7128 + }; 6.7129 + 6.7130 + var stateSetter = function(data) { 6.7131 + return function(state) { 6.7132 + if (state.active !== undefined) 6.7133 + data.forEach(function(series,i) { 6.7134 + series.disabled = !state.active[i]; 6.7135 + }); 6.7136 + } 6.7137 + }; 6.7138 + 6.7139 + function chart(selection) { 6.7140 + selection.each(function(data) { 6.7141 + var container = d3.select(this), 6.7142 + that = this; 6.7143 + nv.utils.initSVG(container); 6.7144 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.7145 + availableHeight1 = nv.utils.availableHeight(height, container, margin) - height2, 6.7146 + availableHeight2 = height2 - margin2.top - margin2.bottom; 6.7147 + 6.7148 + chart.update = function() { container.transition().duration(transitionDuration).call(chart) }; 6.7149 + chart.container = this; 6.7150 + 6.7151 + state 6.7152 + .setter(stateSetter(data), chart.update) 6.7153 + .getter(stateGetter(data)) 6.7154 + .update(); 6.7155 + 6.7156 + // DEPRECATED set state.disableddisabled 6.7157 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.7158 + 6.7159 + if (!defaultState) { 6.7160 + var key; 6.7161 + defaultState = {}; 6.7162 + for (key in state) { 6.7163 + if (state[key] instanceof Array) 6.7164 + defaultState[key] = state[key].slice(0); 6.7165 + else 6.7166 + defaultState[key] = state[key]; 6.7167 + } 6.7168 + } 6.7169 + 6.7170 + // Display No Data message if there's nothing to show. 6.7171 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.7172 + nv.utils.noData(chart, container) 6.7173 + return chart; 6.7174 + } else { 6.7175 + container.selectAll('.nv-noData').remove(); 6.7176 + } 6.7177 + 6.7178 + // Setup Scales 6.7179 + x = lines.xScale(); 6.7180 + y = lines.yScale(); 6.7181 + x2 = lines2.xScale(); 6.7182 + y2 = lines2.yScale(); 6.7183 + 6.7184 + // Setup containers and skeleton of chart 6.7185 + var wrap = container.selectAll('g.nv-wrap.nv-lineWithFocusChart').data([data]); 6.7186 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineWithFocusChart').append('g'); 6.7187 + var g = wrap.select('g'); 6.7188 + 6.7189 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.7190 + 6.7191 + var focusEnter = gEnter.append('g').attr('class', 'nv-focus'); 6.7192 + focusEnter.append('g').attr('class', 'nv-x nv-axis'); 6.7193 + focusEnter.append('g').attr('class', 'nv-y nv-axis'); 6.7194 + focusEnter.append('g').attr('class', 'nv-linesWrap'); 6.7195 + focusEnter.append('g').attr('class', 'nv-interactive'); 6.7196 + 6.7197 + var contextEnter = gEnter.append('g').attr('class', 'nv-context'); 6.7198 + contextEnter.append('g').attr('class', 'nv-x nv-axis'); 6.7199 + contextEnter.append('g').attr('class', 'nv-y nv-axis'); 6.7200 + contextEnter.append('g').attr('class', 'nv-linesWrap'); 6.7201 + contextEnter.append('g').attr('class', 'nv-brushBackground'); 6.7202 + contextEnter.append('g').attr('class', 'nv-x nv-brush'); 6.7203 + 6.7204 + // Legend 6.7205 + if (showLegend) { 6.7206 + legend.width(availableWidth); 6.7207 + 6.7208 + g.select('.nv-legendWrap') 6.7209 + .datum(data) 6.7210 + .call(legend); 6.7211 + 6.7212 + if ( margin.top != legend.height()) { 6.7213 + margin.top = legend.height(); 6.7214 + availableHeight1 = nv.utils.availableHeight(height, container, margin) - height2; 6.7215 + } 6.7216 + 6.7217 + g.select('.nv-legendWrap') 6.7218 + .attr('transform', 'translate(0,' + (-margin.top) +')') 6.7219 + } 6.7220 + 6.7221 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.7222 + 6.7223 + 6.7224 + //Set up interactive layer 6.7225 + if (useInteractiveGuideline) { 6.7226 + interactiveLayer 6.7227 + .width(availableWidth) 6.7228 + .height(availableHeight1) 6.7229 + .margin({left:margin.left, top:margin.top}) 6.7230 + .svgContainer(container) 6.7231 + .xScale(x); 6.7232 + wrap.select(".nv-interactive").call(interactiveLayer); 6.7233 + } 6.7234 + 6.7235 + // Main Chart Component(s) 6.7236 + lines 6.7237 + .width(availableWidth) 6.7238 + .height(availableHeight1) 6.7239 + .color( 6.7240 + data 6.7241 + .map(function(d,i) { 6.7242 + return d.color || color(d, i); 6.7243 + }) 6.7244 + .filter(function(d,i) { 6.7245 + return !data[i].disabled; 6.7246 + }) 6.7247 + ); 6.7248 + 6.7249 + lines2 6.7250 + .defined(lines.defined()) 6.7251 + .width(availableWidth) 6.7252 + .height(availableHeight2) 6.7253 + .color( 6.7254 + data 6.7255 + .map(function(d,i) { 6.7256 + return d.color || color(d, i); 6.7257 + }) 6.7258 + .filter(function(d,i) { 6.7259 + return !data[i].disabled; 6.7260 + }) 6.7261 + ); 6.7262 + 6.7263 + g.select('.nv-context') 6.7264 + .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')') 6.7265 + 6.7266 + var contextLinesWrap = g.select('.nv-context .nv-linesWrap') 6.7267 + .datum(data.filter(function(d) { return !d.disabled })) 6.7268 + 6.7269 + d3.transition(contextLinesWrap).call(lines2); 6.7270 + 6.7271 + // Setup Main (Focus) Axes 6.7272 + xAxis 6.7273 + .scale(x) 6.7274 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.7275 + .tickSize(-availableHeight1, 0); 6.7276 + 6.7277 + yAxis 6.7278 + .scale(y) 6.7279 + ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) ) 6.7280 + .tickSize( -availableWidth, 0); 6.7281 + 6.7282 + g.select('.nv-focus .nv-x.nv-axis') 6.7283 + .attr('transform', 'translate(0,' + availableHeight1 + ')'); 6.7284 + 6.7285 + // Setup Brush 6.7286 + brush 6.7287 + .x(x2) 6.7288 + .on('brush', function() { 6.7289 + onBrush(); 6.7290 + }); 6.7291 + 6.7292 + if (brushExtent) brush.extent(brushExtent); 6.7293 + 6.7294 + var brushBG = g.select('.nv-brushBackground').selectAll('g') 6.7295 + .data([brushExtent || brush.extent()]) 6.7296 + 6.7297 + var brushBGenter = brushBG.enter() 6.7298 + .append('g'); 6.7299 + 6.7300 + brushBGenter.append('rect') 6.7301 + .attr('class', 'left') 6.7302 + .attr('x', 0) 6.7303 + .attr('y', 0) 6.7304 + .attr('height', availableHeight2); 6.7305 + 6.7306 + brushBGenter.append('rect') 6.7307 + .attr('class', 'right') 6.7308 + .attr('x', 0) 6.7309 + .attr('y', 0) 6.7310 + .attr('height', availableHeight2); 6.7311 + 6.7312 + var gBrush = g.select('.nv-x.nv-brush') 6.7313 + .call(brush); 6.7314 + gBrush.selectAll('rect') 6.7315 + .attr('height', availableHeight2); 6.7316 + gBrush.selectAll('.resize').append('path').attr('d', resizePath); 6.7317 + 6.7318 + onBrush(); 6.7319 + 6.7320 + // Setup Secondary (Context) Axes 6.7321 + x2Axis 6.7322 + .scale(x2) 6.7323 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.7324 + .tickSize(-availableHeight2, 0); 6.7325 + 6.7326 + g.select('.nv-context .nv-x.nv-axis') 6.7327 + .attr('transform', 'translate(0,' + y2.range()[0] + ')'); 6.7328 + d3.transition(g.select('.nv-context .nv-x.nv-axis')) 6.7329 + .call(x2Axis); 6.7330 + 6.7331 + y2Axis 6.7332 + .scale(y2) 6.7333 + ._ticks( nv.utils.calcTicksY(availableHeight2/36, data) ) 6.7334 + .tickSize( -availableWidth, 0); 6.7335 + 6.7336 + d3.transition(g.select('.nv-context .nv-y.nv-axis')) 6.7337 + .call(y2Axis); 6.7338 + 6.7339 + g.select('.nv-context .nv-x.nv-axis') 6.7340 + .attr('transform', 'translate(0,' + y2.range()[0] + ')'); 6.7341 + 6.7342 + //============================================================ 6.7343 + // Event Handling/Dispatching (in chart's scope) 6.7344 + //------------------------------------------------------------ 6.7345 + 6.7346 + legend.dispatch.on('stateChange', function(newState) { 6.7347 + for (var key in newState) 6.7348 + state[key] = newState[key]; 6.7349 + dispatch.stateChange(state); 6.7350 + chart.update(); 6.7351 + }); 6.7352 + 6.7353 + interactiveLayer.dispatch.on('elementMousemove', function(e) { 6.7354 + lines.clearHighlights(); 6.7355 + var singlePoint, pointIndex, pointXLocation, allData = []; 6.7356 + data 6.7357 + .filter(function(series, i) { 6.7358 + series.seriesIndex = i; 6.7359 + return !series.disabled; 6.7360 + }) 6.7361 + .forEach(function(series,i) { 6.7362 + var extent = brush.empty() ? x2.domain() : brush.extent(); 6.7363 + var currentValues = series.values.filter(function(d,i) { 6.7364 + return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; 6.7365 + }); 6.7366 + 6.7367 + pointIndex = nv.interactiveBisect(currentValues, e.pointXValue, lines.x()); 6.7368 + var point = currentValues[pointIndex]; 6.7369 + var pointYValue = chart.y()(point, pointIndex); 6.7370 + if (pointYValue != null) { 6.7371 + lines.highlightPoint(i, pointIndex, true); 6.7372 + } 6.7373 + if (point === undefined) return; 6.7374 + if (singlePoint === undefined) singlePoint = point; 6.7375 + if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); 6.7376 + allData.push({ 6.7377 + key: series.key, 6.7378 + value: chart.y()(point, pointIndex), 6.7379 + color: color(series,series.seriesIndex) 6.7380 + }); 6.7381 + }); 6.7382 + //Highlight the tooltip entry based on which point the mouse is closest to. 6.7383 + if (allData.length > 2) { 6.7384 + var yValue = chart.yScale().invert(e.mouseY); 6.7385 + var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]); 6.7386 + var threshold = 0.03 * domainExtent; 6.7387 + var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold); 6.7388 + if (indexToHighlight !== null) 6.7389 + allData[indexToHighlight].highlight = true; 6.7390 + } 6.7391 + 6.7392 + var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); 6.7393 + interactiveLayer.tooltip 6.7394 + .position({left: e.mouseX + margin.left, top: e.mouseY + margin.top}) 6.7395 + .chartContainer(that.parentNode) 6.7396 + .valueFormatter(function(d,i) { 6.7397 + return d == null ? "N/A" : yAxis.tickFormat()(d); 6.7398 + }) 6.7399 + .data({ 6.7400 + value: xValue, 6.7401 + index: pointIndex, 6.7402 + series: allData 6.7403 + })(); 6.7404 + 6.7405 + interactiveLayer.renderGuideLine(pointXLocation); 6.7406 + 6.7407 + }); 6.7408 + 6.7409 + interactiveLayer.dispatch.on("elementMouseout",function(e) { 6.7410 + lines.clearHighlights(); 6.7411 + }); 6.7412 + 6.7413 + dispatch.on('changeState', function(e) { 6.7414 + if (typeof e.disabled !== 'undefined') { 6.7415 + data.forEach(function(series,i) { 6.7416 + series.disabled = e.disabled[i]; 6.7417 + }); 6.7418 + } 6.7419 + chart.update(); 6.7420 + }); 6.7421 + 6.7422 + //============================================================ 6.7423 + // Functions 6.7424 + //------------------------------------------------------------ 6.7425 + 6.7426 + // Taken from crossfilter (http://square.github.com/crossfilter/) 6.7427 + function resizePath(d) { 6.7428 + var e = +(d == 'e'), 6.7429 + x = e ? 1 : -1, 6.7430 + y = availableHeight2 / 3; 6.7431 + return 'M' + (.5 * x) + ',' + y 6.7432 + + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6) 6.7433 + + 'V' + (2 * y - 6) 6.7434 + + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y) 6.7435 + + 'Z' 6.7436 + + 'M' + (2.5 * x) + ',' + (y + 8) 6.7437 + + 'V' + (2 * y - 8) 6.7438 + + 'M' + (4.5 * x) + ',' + (y + 8) 6.7439 + + 'V' + (2 * y - 8); 6.7440 + } 6.7441 + 6.7442 + 6.7443 + function updateBrushBG() { 6.7444 + if (!brush.empty()) brush.extent(brushExtent); 6.7445 + brushBG 6.7446 + .data([brush.empty() ? x2.domain() : brushExtent]) 6.7447 + .each(function(d,i) { 6.7448 + var leftWidth = x2(d[0]) - x.range()[0], 6.7449 + rightWidth = availableWidth - x2(d[1]); 6.7450 + d3.select(this).select('.left') 6.7451 + .attr('width', leftWidth < 0 ? 0 : leftWidth); 6.7452 + 6.7453 + d3.select(this).select('.right') 6.7454 + .attr('x', x2(d[1])) 6.7455 + .attr('width', rightWidth < 0 ? 0 : rightWidth); 6.7456 + }); 6.7457 + } 6.7458 + 6.7459 + 6.7460 + function onBrush() { 6.7461 + brushExtent = brush.empty() ? null : brush.extent(); 6.7462 + var extent = brush.empty() ? x2.domain() : brush.extent(); 6.7463 + 6.7464 + //The brush extent cannot be less than one. If it is, don't update the line chart. 6.7465 + if (Math.abs(extent[0] - extent[1]) <= 1) { 6.7466 + return; 6.7467 + } 6.7468 + 6.7469 + dispatch.brush({extent: extent, brush: brush}); 6.7470 + 6.7471 + 6.7472 + updateBrushBG(); 6.7473 + 6.7474 + // Update Main (Focus) 6.7475 + var focusLinesWrap = g.select('.nv-focus .nv-linesWrap') 6.7476 + .datum( 6.7477 + data 6.7478 + .filter(function(d) { return !d.disabled }) 6.7479 + .map(function(d,i) { 6.7480 + return { 6.7481 + key: d.key, 6.7482 + area: d.area, 6.7483 + values: d.values.filter(function(d,i) { 6.7484 + return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; 6.7485 + }) 6.7486 + } 6.7487 + }) 6.7488 + ); 6.7489 + focusLinesWrap.transition().duration(transitionDuration).call(lines); 6.7490 + 6.7491 + 6.7492 + // Update Main (Focus) Axes 6.7493 + g.select('.nv-focus .nv-x.nv-axis').transition().duration(transitionDuration) 6.7494 + .call(xAxis); 6.7495 + g.select('.nv-focus .nv-y.nv-axis').transition().duration(transitionDuration) 6.7496 + .call(yAxis); 6.7497 + } 6.7498 + }); 6.7499 + 6.7500 + return chart; 6.7501 + } 6.7502 + 6.7503 + //============================================================ 6.7504 + // Event Handling/Dispatching (out of chart's scope) 6.7505 + //------------------------------------------------------------ 6.7506 + 6.7507 + lines.dispatch.on('elementMouseover.tooltip', function(evt) { 6.7508 + tooltip.data(evt).position(evt.pos).hidden(false); 6.7509 + }); 6.7510 + 6.7511 + lines.dispatch.on('elementMouseout.tooltip', function(evt) { 6.7512 + tooltip.hidden(true) 6.7513 + }); 6.7514 + 6.7515 + //============================================================ 6.7516 + // Expose Public Variables 6.7517 + //------------------------------------------------------------ 6.7518 + 6.7519 + // expose chart's sub-components 6.7520 + chart.dispatch = dispatch; 6.7521 + chart.legend = legend; 6.7522 + chart.lines = lines; 6.7523 + chart.lines2 = lines2; 6.7524 + chart.xAxis = xAxis; 6.7525 + chart.yAxis = yAxis; 6.7526 + chart.x2Axis = x2Axis; 6.7527 + chart.y2Axis = y2Axis; 6.7528 + chart.interactiveLayer = interactiveLayer; 6.7529 + chart.tooltip = tooltip; 6.7530 + 6.7531 + chart.options = nv.utils.optionsFunc.bind(chart); 6.7532 + 6.7533 + chart._options = Object.create({}, { 6.7534 + // simple options, just get/set the necessary values 6.7535 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.7536 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.7537 + focusHeight: {get: function(){return height2;}, set: function(_){height2=_;}}, 6.7538 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.7539 + brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}}, 6.7540 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.7541 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.7542 + 6.7543 + // deprecated options 6.7544 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.7545 + // deprecated after 1.7.1 6.7546 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.7547 + tooltip.enabled(!!_); 6.7548 + }}, 6.7549 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.7550 + // deprecated after 1.7.1 6.7551 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.7552 + tooltip.contentGenerator(_); 6.7553 + }}, 6.7554 + 6.7555 + // options that require extra logic in the setter 6.7556 + margin: {get: function(){return margin;}, set: function(_){ 6.7557 + margin.top = _.top !== undefined ? _.top : margin.top; 6.7558 + margin.right = _.right !== undefined ? _.right : margin.right; 6.7559 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.7560 + margin.left = _.left !== undefined ? _.left : margin.left; 6.7561 + }}, 6.7562 + color: {get: function(){return color;}, set: function(_){ 6.7563 + color = nv.utils.getColor(_); 6.7564 + legend.color(color); 6.7565 + // line color is handled above? 6.7566 + }}, 6.7567 + interpolate: {get: function(){return lines.interpolate();}, set: function(_){ 6.7568 + lines.interpolate(_); 6.7569 + lines2.interpolate(_); 6.7570 + }}, 6.7571 + xTickFormat: {get: function(){return xAxis.tickFormat();}, set: function(_){ 6.7572 + xAxis.tickFormat(_); 6.7573 + x2Axis.tickFormat(_); 6.7574 + }}, 6.7575 + yTickFormat: {get: function(){return yAxis.tickFormat();}, set: function(_){ 6.7576 + yAxis.tickFormat(_); 6.7577 + y2Axis.tickFormat(_); 6.7578 + }}, 6.7579 + duration: {get: function(){return transitionDuration;}, set: function(_){ 6.7580 + transitionDuration=_; 6.7581 + yAxis.duration(transitionDuration); 6.7582 + y2Axis.duration(transitionDuration); 6.7583 + xAxis.duration(transitionDuration); 6.7584 + x2Axis.duration(transitionDuration); 6.7585 + }}, 6.7586 + x: {get: function(){return lines.x();}, set: function(_){ 6.7587 + lines.x(_); 6.7588 + lines2.x(_); 6.7589 + }}, 6.7590 + y: {get: function(){return lines.y();}, set: function(_){ 6.7591 + lines.y(_); 6.7592 + lines2.y(_); 6.7593 + }}, 6.7594 + useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ 6.7595 + useInteractiveGuideline = _; 6.7596 + if (useInteractiveGuideline) { 6.7597 + lines.interactive(false); 6.7598 + lines.useVoronoi(false); 6.7599 + } 6.7600 + }} 6.7601 + }); 6.7602 + 6.7603 + nv.utils.inheritOptions(chart, lines); 6.7604 + nv.utils.initOptions(chart); 6.7605 + 6.7606 + return chart; 6.7607 +}; 6.7608 + 6.7609 +nv.models.multiBar = function() { 6.7610 + "use strict"; 6.7611 + 6.7612 + //============================================================ 6.7613 + // Public Variables with Default Settings 6.7614 + //------------------------------------------------------------ 6.7615 + 6.7616 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.7617 + , width = 960 6.7618 + , height = 500 6.7619 + , x = d3.scale.ordinal() 6.7620 + , y = d3.scale.linear() 6.7621 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.7622 + , container = null 6.7623 + , getX = function(d) { return d.x } 6.7624 + , getY = function(d) { return d.y } 6.7625 + , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove 6.7626 + , clipEdge = true 6.7627 + , stacked = false 6.7628 + , stackOffset = 'zero' // options include 'silhouette', 'wiggle', 'expand', 'zero', or a custom function 6.7629 + , color = nv.utils.defaultColor() 6.7630 + , hideable = false 6.7631 + , barColor = null // adding the ability to set the color for each rather than the whole group 6.7632 + , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled 6.7633 + , duration = 500 6.7634 + , xDomain 6.7635 + , yDomain 6.7636 + , xRange 6.7637 + , yRange 6.7638 + , groupSpacing = 0.1 6.7639 + , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') 6.7640 + ; 6.7641 + 6.7642 + //============================================================ 6.7643 + // Private Variables 6.7644 + //------------------------------------------------------------ 6.7645 + 6.7646 + var x0, y0 //used to store previous scales 6.7647 + , renderWatch = nv.utils.renderWatch(dispatch, duration) 6.7648 + ; 6.7649 + 6.7650 + var last_datalength = 0; 6.7651 + 6.7652 + function chart(selection) { 6.7653 + renderWatch.reset(); 6.7654 + selection.each(function(data) { 6.7655 + var availableWidth = width - margin.left - margin.right, 6.7656 + availableHeight = height - margin.top - margin.bottom; 6.7657 + 6.7658 + container = d3.select(this); 6.7659 + nv.utils.initSVG(container); 6.7660 + var nonStackableCount = 0; 6.7661 + // This function defines the requirements for render complete 6.7662 + var endFn = function(d, i) { 6.7663 + if (d.series === data.length - 1 && i === data[0].values.length - 1) 6.7664 + return true; 6.7665 + return false; 6.7666 + }; 6.7667 + 6.7668 + if(hideable && data.length) hideable = [{ 6.7669 + values: data[0].values.map(function(d) { 6.7670 + return { 6.7671 + x: d.x, 6.7672 + y: 0, 6.7673 + series: d.series, 6.7674 + size: 0.01 6.7675 + };} 6.7676 + )}]; 6.7677 + 6.7678 + if (stacked) { 6.7679 + var parsed = d3.layout.stack() 6.7680 + .offset(stackOffset) 6.7681 + .values(function(d){ return d.values }) 6.7682 + .y(getY) 6.7683 + (!data.length && hideable ? hideable : data); 6.7684 + 6.7685 + parsed.forEach(function(series, i){ 6.7686 + // if series is non-stackable, use un-parsed data 6.7687 + if (series.nonStackable) { 6.7688 + data[i].nonStackableSeries = nonStackableCount++; 6.7689 + parsed[i] = data[i]; 6.7690 + } else { 6.7691 + // don't stack this seires on top of the nonStackable seriees 6.7692 + if (i > 0 && parsed[i - 1].nonStackable){ 6.7693 + parsed[i].values.map(function(d,j){ 6.7694 + d.y0 -= parsed[i - 1].values[j].y; 6.7695 + d.y1 = d.y0 + d.y; 6.7696 + }); 6.7697 + } 6.7698 + } 6.7699 + }); 6.7700 + data = parsed; 6.7701 + } 6.7702 + //add series index and key to each data point for reference 6.7703 + data.forEach(function(series, i) { 6.7704 + series.values.forEach(function(point) { 6.7705 + point.series = i; 6.7706 + point.key = series.key; 6.7707 + }); 6.7708 + }); 6.7709 + 6.7710 + // HACK for negative value stacking 6.7711 + if (stacked) { 6.7712 + data[0].values.map(function(d,i) { 6.7713 + var posBase = 0, negBase = 0; 6.7714 + data.map(function(d, idx) { 6.7715 + if (!data[idx].nonStackable) { 6.7716 + var f = d.values[i] 6.7717 + f.size = Math.abs(f.y); 6.7718 + if (f.y<0) { 6.7719 + f.y1 = negBase; 6.7720 + negBase = negBase - f.size; 6.7721 + } else 6.7722 + { 6.7723 + f.y1 = f.size + posBase; 6.7724 + posBase = posBase + f.size; 6.7725 + } 6.7726 + } 6.7727 + 6.7728 + }); 6.7729 + }); 6.7730 + } 6.7731 + // Setup Scales 6.7732 + // remap and flatten the data for use in calculating the scales' domains 6.7733 + var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate 6.7734 + data.map(function(d, idx) { 6.7735 + return d.values.map(function(d,i) { 6.7736 + return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1, idx:idx } 6.7737 + }) 6.7738 + }); 6.7739 + 6.7740 + x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x })) 6.7741 + .rangeBands(xRange || [0, availableWidth], groupSpacing); 6.7742 + 6.7743 + y.domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { 6.7744 + var domain = d.y; 6.7745 + // increase the domain range if this series is stackable 6.7746 + if (stacked && !data[d.idx].nonStackable) { 6.7747 + if (d.y > 0){ 6.7748 + domain = d.y1 6.7749 + } else { 6.7750 + domain = d.y1 + d.y 6.7751 + } 6.7752 + } 6.7753 + return domain; 6.7754 + }).concat(forceY))) 6.7755 + .range(yRange || [availableHeight, 0]); 6.7756 + 6.7757 + // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point 6.7758 + if (x.domain()[0] === x.domain()[1]) 6.7759 + x.domain()[0] ? 6.7760 + x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) 6.7761 + : x.domain([-1,1]); 6.7762 + 6.7763 + if (y.domain()[0] === y.domain()[1]) 6.7764 + y.domain()[0] ? 6.7765 + y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) 6.7766 + : y.domain([-1,1]); 6.7767 + 6.7768 + x0 = x0 || x; 6.7769 + y0 = y0 || y; 6.7770 + 6.7771 + // Setup containers and skeleton of chart 6.7772 + var wrap = container.selectAll('g.nv-wrap.nv-multibar').data([data]); 6.7773 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibar'); 6.7774 + var defsEnter = wrapEnter.append('defs'); 6.7775 + var gEnter = wrapEnter.append('g'); 6.7776 + var g = wrap.select('g'); 6.7777 + 6.7778 + gEnter.append('g').attr('class', 'nv-groups'); 6.7779 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.7780 + 6.7781 + defsEnter.append('clipPath') 6.7782 + .attr('id', 'nv-edge-clip-' + id) 6.7783 + .append('rect'); 6.7784 + wrap.select('#nv-edge-clip-' + id + ' rect') 6.7785 + .attr('width', availableWidth) 6.7786 + .attr('height', availableHeight); 6.7787 + 6.7788 + g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : ''); 6.7789 + 6.7790 + var groups = wrap.select('.nv-groups').selectAll('.nv-group') 6.7791 + .data(function(d) { return d }, function(d,i) { return i }); 6.7792 + groups.enter().append('g') 6.7793 + .style('stroke-opacity', 1e-6) 6.7794 + .style('fill-opacity', 1e-6); 6.7795 + 6.7796 + var exitTransition = renderWatch 6.7797 + .transition(groups.exit().selectAll('rect.nv-bar'), 'multibarExit', Math.min(100, duration)) 6.7798 + .attr('y', function(d, i, j) { 6.7799 + var yVal = y0(0) || 0; 6.7800 + if (stacked) { 6.7801 + if (data[d.series] && !data[d.series].nonStackable) { 6.7802 + yVal = y0(d.y0); 6.7803 + } 6.7804 + } 6.7805 + return yVal; 6.7806 + }) 6.7807 + .attr('height', 0) 6.7808 + .remove(); 6.7809 + if (exitTransition.delay) 6.7810 + exitTransition.delay(function(d,i) { 6.7811 + var delay = i * (duration / (last_datalength + 1)) - i; 6.7812 + return delay; 6.7813 + }); 6.7814 + groups 6.7815 + .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) 6.7816 + .classed('hover', function(d) { return d.hover }) 6.7817 + .style('fill', function(d,i){ return color(d, i) }) 6.7818 + .style('stroke', function(d,i){ return color(d, i) }); 6.7819 + groups 6.7820 + .style('stroke-opacity', 1) 6.7821 + .style('fill-opacity', 0.75); 6.7822 + 6.7823 + var bars = groups.selectAll('rect.nv-bar') 6.7824 + .data(function(d) { return (hideable && !data.length) ? hideable.values : d.values }); 6.7825 + bars.exit().remove(); 6.7826 + 6.7827 + var barsEnter = bars.enter().append('rect') 6.7828 + .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'}) 6.7829 + .attr('x', function(d,i,j) { 6.7830 + return stacked && !data[j].nonStackable ? 0 : (j * x.rangeBand() / data.length ) 6.7831 + }) 6.7832 + .attr('y', function(d,i,j) { return y0(stacked && !data[j].nonStackable ? d.y0 : 0) || 0 }) 6.7833 + .attr('height', 0) 6.7834 + .attr('width', function(d,i,j) { return x.rangeBand() / (stacked && !data[j].nonStackable ? 1 : data.length) }) 6.7835 + .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; }) 6.7836 + ; 6.7837 + bars 6.7838 + .style('fill', function(d,i,j){ return color(d, j, i); }) 6.7839 + .style('stroke', function(d,i,j){ return color(d, j, i); }) 6.7840 + .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here 6.7841 + d3.select(this).classed('hover', true); 6.7842 + dispatch.elementMouseover({ 6.7843 + data: d, 6.7844 + index: i, 6.7845 + color: d3.select(this).style("fill") 6.7846 + }); 6.7847 + }) 6.7848 + .on('mouseout', function(d,i) { 6.7849 + d3.select(this).classed('hover', false); 6.7850 + dispatch.elementMouseout({ 6.7851 + data: d, 6.7852 + index: i, 6.7853 + color: d3.select(this).style("fill") 6.7854 + }); 6.7855 + }) 6.7856 + .on('mousemove', function(d,i) { 6.7857 + dispatch.elementMousemove({ 6.7858 + data: d, 6.7859 + index: i, 6.7860 + color: d3.select(this).style("fill") 6.7861 + }); 6.7862 + }) 6.7863 + .on('click', function(d,i) { 6.7864 + dispatch.elementClick({ 6.7865 + data: d, 6.7866 + index: i, 6.7867 + color: d3.select(this).style("fill") 6.7868 + }); 6.7869 + d3.event.stopPropagation(); 6.7870 + }) 6.7871 + .on('dblclick', function(d,i) { 6.7872 + dispatch.elementDblClick({ 6.7873 + data: d, 6.7874 + index: i, 6.7875 + color: d3.select(this).style("fill") 6.7876 + }); 6.7877 + d3.event.stopPropagation(); 6.7878 + }); 6.7879 + bars 6.7880 + .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'}) 6.7881 + .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; }) 6.7882 + 6.7883 + if (barColor) { 6.7884 + if (!disabled) disabled = data.map(function() { return true }); 6.7885 + bars 6.7886 + .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }) 6.7887 + .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }); 6.7888 + } 6.7889 + 6.7890 + var barSelection = 6.7891 + bars.watchTransition(renderWatch, 'multibar', Math.min(250, duration)) 6.7892 + .delay(function(d,i) { 6.7893 + return i * duration / data[0].values.length; 6.7894 + }); 6.7895 + if (stacked){ 6.7896 + barSelection 6.7897 + .attr('y', function(d,i,j) { 6.7898 + var yVal = 0; 6.7899 + // if stackable, stack it on top of the previous series 6.7900 + if (!data[j].nonStackable) { 6.7901 + yVal = y(d.y1); 6.7902 + } else { 6.7903 + if (getY(d,i) < 0){ 6.7904 + yVal = y(0); 6.7905 + } else { 6.7906 + if (y(0) - y(getY(d,i)) < -1){ 6.7907 + yVal = y(0) - 1; 6.7908 + } else { 6.7909 + yVal = y(getY(d, i)) || 0; 6.7910 + } 6.7911 + } 6.7912 + } 6.7913 + return yVal; 6.7914 + }) 6.7915 + .attr('height', function(d,i,j) { 6.7916 + if (!data[j].nonStackable) { 6.7917 + return Math.max(Math.abs(y(d.y+d.y0) - y(d.y0)), 1); 6.7918 + } else { 6.7919 + return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0; 6.7920 + } 6.7921 + }) 6.7922 + .attr('x', function(d,i,j) { 6.7923 + var width = 0; 6.7924 + if (data[j].nonStackable) { 6.7925 + width = d.series * x.rangeBand() / data.length; 6.7926 + if (data.length !== nonStackableCount){ 6.7927 + width = data[j].nonStackableSeries * x.rangeBand()/(nonStackableCount*2); 6.7928 + } 6.7929 + } 6.7930 + return width; 6.7931 + }) 6.7932 + .attr('width', function(d,i,j){ 6.7933 + if (!data[j].nonStackable) { 6.7934 + return x.rangeBand(); 6.7935 + } else { 6.7936 + // if all series are nonStacable, take the full width 6.7937 + var width = (x.rangeBand() / nonStackableCount); 6.7938 + // otherwise, nonStackable graph will be only taking the half-width 6.7939 + // of the x rangeBand 6.7940 + if (data.length !== nonStackableCount) { 6.7941 + width = x.rangeBand()/(nonStackableCount*2); 6.7942 + } 6.7943 + return width; 6.7944 + } 6.7945 + }); 6.7946 + } 6.7947 + else { 6.7948 + barSelection 6.7949 + .attr('x', function(d,i) { 6.7950 + return d.series * x.rangeBand() / data.length; 6.7951 + }) 6.7952 + .attr('width', x.rangeBand() / data.length) 6.7953 + .attr('y', function(d,i) { 6.7954 + return getY(d,i) < 0 ? 6.7955 + y(0) : 6.7956 + y(0) - y(getY(d,i)) < 1 ? 6.7957 + y(0) - 1 : 6.7958 + y(getY(d,i)) || 0; 6.7959 + }) 6.7960 + .attr('height', function(d,i) { 6.7961 + return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0; 6.7962 + }); 6.7963 + } 6.7964 + 6.7965 + //store old scales for use in transitions on update 6.7966 + x0 = x.copy(); 6.7967 + y0 = y.copy(); 6.7968 + 6.7969 + // keep track of the last data value length for transition calculations 6.7970 + if (data[0] && data[0].values) { 6.7971 + last_datalength = data[0].values.length; 6.7972 + } 6.7973 + 6.7974 + }); 6.7975 + 6.7976 + renderWatch.renderEnd('multibar immediate'); 6.7977 + 6.7978 + return chart; 6.7979 + } 6.7980 + 6.7981 + //============================================================ 6.7982 + // Expose Public Variables 6.7983 + //------------------------------------------------------------ 6.7984 + 6.7985 + chart.dispatch = dispatch; 6.7986 + 6.7987 + chart.options = nv.utils.optionsFunc.bind(chart); 6.7988 + 6.7989 + chart._options = Object.create({}, { 6.7990 + // simple options, just get/set the necessary values 6.7991 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.7992 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.7993 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.7994 + y: {get: function(){return getY;}, set: function(_){getY=_;}}, 6.7995 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.7996 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.7997 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.7998 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.7999 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.8000 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.8001 + forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, 6.8002 + stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}}, 6.8003 + stackOffset: {get: function(){return stackOffset;}, set: function(_){stackOffset=_;}}, 6.8004 + clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, 6.8005 + disabled: {get: function(){return disabled;}, set: function(_){disabled=_;}}, 6.8006 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.8007 + hideable: {get: function(){return hideable;}, set: function(_){hideable=_;}}, 6.8008 + groupSpacing:{get: function(){return groupSpacing;}, set: function(_){groupSpacing=_;}}, 6.8009 + 6.8010 + // options that require extra logic in the setter 6.8011 + margin: {get: function(){return margin;}, set: function(_){ 6.8012 + margin.top = _.top !== undefined ? _.top : margin.top; 6.8013 + margin.right = _.right !== undefined ? _.right : margin.right; 6.8014 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.8015 + margin.left = _.left !== undefined ? _.left : margin.left; 6.8016 + }}, 6.8017 + duration: {get: function(){return duration;}, set: function(_){ 6.8018 + duration = _; 6.8019 + renderWatch.reset(duration); 6.8020 + }}, 6.8021 + color: {get: function(){return color;}, set: function(_){ 6.8022 + color = nv.utils.getColor(_); 6.8023 + }}, 6.8024 + barColor: {get: function(){return barColor;}, set: function(_){ 6.8025 + barColor = _ ? nv.utils.getColor(_) : null; 6.8026 + }} 6.8027 + }); 6.8028 + 6.8029 + nv.utils.initOptions(chart); 6.8030 + 6.8031 + return chart; 6.8032 +}; 6.8033 +nv.models.multiBarChart = function() { 6.8034 + "use strict"; 6.8035 + 6.8036 + //============================================================ 6.8037 + // Public Variables with Default Settings 6.8038 + //------------------------------------------------------------ 6.8039 + 6.8040 + var multibar = nv.models.multiBar() 6.8041 + , xAxis = nv.models.axis() 6.8042 + , yAxis = nv.models.axis() 6.8043 + , legend = nv.models.legend() 6.8044 + , controls = nv.models.legend() 6.8045 + , tooltip = nv.models.tooltip() 6.8046 + ; 6.8047 + 6.8048 + var margin = {top: 30, right: 20, bottom: 50, left: 60} 6.8049 + , width = null 6.8050 + , height = null 6.8051 + , color = nv.utils.defaultColor() 6.8052 + , showControls = true 6.8053 + , controlLabels = {} 6.8054 + , showLegend = true 6.8055 + , showXAxis = true 6.8056 + , showYAxis = true 6.8057 + , rightAlignYAxis = false 6.8058 + , reduceXTicks = true // if false a tick will show for every data point 6.8059 + , staggerLabels = false 6.8060 + , rotateLabels = 0 6.8061 + , x //can be accessed via chart.xScale() 6.8062 + , y //can be accessed via chart.yScale() 6.8063 + , state = nv.utils.state() 6.8064 + , defaultState = null 6.8065 + , noData = null 6.8066 + , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd') 6.8067 + , controlWidth = function() { return showControls ? 180 : 0 } 6.8068 + , duration = 250 6.8069 + ; 6.8070 + 6.8071 + state.stacked = false // DEPRECATED Maintained for backward compatibility 6.8072 + 6.8073 + multibar.stacked(false); 6.8074 + xAxis 6.8075 + .orient('bottom') 6.8076 + .tickPadding(7) 6.8077 + .showMaxMin(false) 6.8078 + .tickFormat(function(d) { return d }) 6.8079 + ; 6.8080 + yAxis 6.8081 + .orient((rightAlignYAxis) ? 'right' : 'left') 6.8082 + .tickFormat(d3.format(',.1f')) 6.8083 + ; 6.8084 + 6.8085 + tooltip 6.8086 + .duration(0) 6.8087 + .valueFormatter(function(d, i) { 6.8088 + return yAxis.tickFormat()(d, i); 6.8089 + }) 6.8090 + .headerFormatter(function(d, i) { 6.8091 + return xAxis.tickFormat()(d, i); 6.8092 + }); 6.8093 + 6.8094 + controls.updateState(false); 6.8095 + 6.8096 + //============================================================ 6.8097 + // Private Variables 6.8098 + //------------------------------------------------------------ 6.8099 + 6.8100 + var renderWatch = nv.utils.renderWatch(dispatch); 6.8101 + var stacked = false; 6.8102 + 6.8103 + var stateGetter = function(data) { 6.8104 + return function(){ 6.8105 + return { 6.8106 + active: data.map(function(d) { return !d.disabled }), 6.8107 + stacked: stacked 6.8108 + }; 6.8109 + } 6.8110 + }; 6.8111 + 6.8112 + var stateSetter = function(data) { 6.8113 + return function(state) { 6.8114 + if (state.stacked !== undefined) 6.8115 + stacked = state.stacked; 6.8116 + if (state.active !== undefined) 6.8117 + data.forEach(function(series,i) { 6.8118 + series.disabled = !state.active[i]; 6.8119 + }); 6.8120 + } 6.8121 + }; 6.8122 + 6.8123 + function chart(selection) { 6.8124 + renderWatch.reset(); 6.8125 + renderWatch.models(multibar); 6.8126 + if (showXAxis) renderWatch.models(xAxis); 6.8127 + if (showYAxis) renderWatch.models(yAxis); 6.8128 + 6.8129 + selection.each(function(data) { 6.8130 + var container = d3.select(this), 6.8131 + that = this; 6.8132 + nv.utils.initSVG(container); 6.8133 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.8134 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.8135 + 6.8136 + chart.update = function() { 6.8137 + if (duration === 0) 6.8138 + container.call(chart); 6.8139 + else 6.8140 + container.transition() 6.8141 + .duration(duration) 6.8142 + .call(chart); 6.8143 + }; 6.8144 + chart.container = this; 6.8145 + 6.8146 + state 6.8147 + .setter(stateSetter(data), chart.update) 6.8148 + .getter(stateGetter(data)) 6.8149 + .update(); 6.8150 + 6.8151 + // DEPRECATED set state.disableddisabled 6.8152 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.8153 + 6.8154 + if (!defaultState) { 6.8155 + var key; 6.8156 + defaultState = {}; 6.8157 + for (key in state) { 6.8158 + if (state[key] instanceof Array) 6.8159 + defaultState[key] = state[key].slice(0); 6.8160 + else 6.8161 + defaultState[key] = state[key]; 6.8162 + } 6.8163 + } 6.8164 + 6.8165 + // Display noData message if there's nothing to show. 6.8166 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.8167 + nv.utils.noData(chart, container) 6.8168 + return chart; 6.8169 + } else { 6.8170 + container.selectAll('.nv-noData').remove(); 6.8171 + } 6.8172 + 6.8173 + // Setup Scales 6.8174 + x = multibar.xScale(); 6.8175 + y = multibar.yScale(); 6.8176 + 6.8177 + // Setup containers and skeleton of chart 6.8178 + var wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]); 6.8179 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend').append('g'); 6.8180 + var g = wrap.select('g'); 6.8181 + 6.8182 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.8183 + gEnter.append('g').attr('class', 'nv-y nv-axis'); 6.8184 + gEnter.append('g').attr('class', 'nv-barsWrap'); 6.8185 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.8186 + gEnter.append('g').attr('class', 'nv-controlsWrap'); 6.8187 + 6.8188 + // Legend 6.8189 + if (showLegend) { 6.8190 + legend.width(availableWidth - controlWidth()); 6.8191 + 6.8192 + g.select('.nv-legendWrap') 6.8193 + .datum(data) 6.8194 + .call(legend); 6.8195 + 6.8196 + if ( margin.top != legend.height()) { 6.8197 + margin.top = legend.height(); 6.8198 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.8199 + } 6.8200 + 6.8201 + g.select('.nv-legendWrap') 6.8202 + .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')'); 6.8203 + } 6.8204 + 6.8205 + // Controls 6.8206 + if (showControls) { 6.8207 + var controlsData = [ 6.8208 + { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() }, 6.8209 + { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() } 6.8210 + ]; 6.8211 + 6.8212 + controls.width(controlWidth()).color(['#444', '#444', '#444']); 6.8213 + g.select('.nv-controlsWrap') 6.8214 + .datum(controlsData) 6.8215 + .attr('transform', 'translate(0,' + (-margin.top) +')') 6.8216 + .call(controls); 6.8217 + } 6.8218 + 6.8219 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.8220 + if (rightAlignYAxis) { 6.8221 + g.select(".nv-y.nv-axis") 6.8222 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.8223 + } 6.8224 + 6.8225 + // Main Chart Component(s) 6.8226 + multibar 6.8227 + .disabled(data.map(function(series) { return series.disabled })) 6.8228 + .width(availableWidth) 6.8229 + .height(availableHeight) 6.8230 + .color(data.map(function(d,i) { 6.8231 + return d.color || color(d, i); 6.8232 + }).filter(function(d,i) { return !data[i].disabled })); 6.8233 + 6.8234 + 6.8235 + var barsWrap = g.select('.nv-barsWrap') 6.8236 + .datum(data.filter(function(d) { return !d.disabled })); 6.8237 + 6.8238 + barsWrap.call(multibar); 6.8239 + 6.8240 + // Setup Axes 6.8241 + if (showXAxis) { 6.8242 + xAxis 6.8243 + .scale(x) 6.8244 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.8245 + .tickSize(-availableHeight, 0); 6.8246 + 6.8247 + g.select('.nv-x.nv-axis') 6.8248 + .attr('transform', 'translate(0,' + y.range()[0] + ')'); 6.8249 + g.select('.nv-x.nv-axis') 6.8250 + .call(xAxis); 6.8251 + 6.8252 + var xTicks = g.select('.nv-x.nv-axis > g').selectAll('g'); 6.8253 + 6.8254 + xTicks 6.8255 + .selectAll('line, text') 6.8256 + .style('opacity', 1) 6.8257 + 6.8258 + if (staggerLabels) { 6.8259 + var getTranslate = function(x,y) { 6.8260 + return "translate(" + x + "," + y + ")"; 6.8261 + }; 6.8262 + 6.8263 + var staggerUp = 5, staggerDown = 17; //pixels to stagger by 6.8264 + // Issue #140 6.8265 + xTicks 6.8266 + .selectAll("text") 6.8267 + .attr('transform', function(d,i,j) { 6.8268 + return getTranslate(0, (j % 2 == 0 ? staggerUp : staggerDown)); 6.8269 + }); 6.8270 + 6.8271 + var totalInBetweenTicks = d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length; 6.8272 + g.selectAll(".nv-x.nv-axis .nv-axisMaxMin text") 6.8273 + .attr("transform", function(d,i) { 6.8274 + return getTranslate(0, (i === 0 || totalInBetweenTicks % 2 !== 0) ? staggerDown : staggerUp); 6.8275 + }); 6.8276 + } 6.8277 + 6.8278 + if (reduceXTicks) 6.8279 + xTicks 6.8280 + .filter(function(d,i) { 6.8281 + return i % Math.ceil(data[0].values.length / (availableWidth / 100)) !== 0; 6.8282 + }) 6.8283 + .selectAll('text, line') 6.8284 + .style('opacity', 0); 6.8285 + 6.8286 + if(rotateLabels) 6.8287 + xTicks 6.8288 + .selectAll('.tick text') 6.8289 + .attr('transform', 'rotate(' + rotateLabels + ' 0,0)') 6.8290 + .style('text-anchor', rotateLabels > 0 ? 'start' : 'end'); 6.8291 + 6.8292 + g.select('.nv-x.nv-axis').selectAll('g.nv-axisMaxMin text') 6.8293 + .style('opacity', 1); 6.8294 + } 6.8295 + 6.8296 + if (showYAxis) { 6.8297 + yAxis 6.8298 + .scale(y) 6.8299 + ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) 6.8300 + .tickSize( -availableWidth, 0); 6.8301 + 6.8302 + g.select('.nv-y.nv-axis') 6.8303 + .call(yAxis); 6.8304 + } 6.8305 + 6.8306 + //============================================================ 6.8307 + // Event Handling/Dispatching (in chart's scope) 6.8308 + //------------------------------------------------------------ 6.8309 + 6.8310 + legend.dispatch.on('stateChange', function(newState) { 6.8311 + for (var key in newState) 6.8312 + state[key] = newState[key]; 6.8313 + dispatch.stateChange(state); 6.8314 + chart.update(); 6.8315 + }); 6.8316 + 6.8317 + controls.dispatch.on('legendClick', function(d,i) { 6.8318 + if (!d.disabled) return; 6.8319 + controlsData = controlsData.map(function(s) { 6.8320 + s.disabled = true; 6.8321 + return s; 6.8322 + }); 6.8323 + d.disabled = false; 6.8324 + 6.8325 + switch (d.key) { 6.8326 + case 'Grouped': 6.8327 + case controlLabels.grouped: 6.8328 + multibar.stacked(false); 6.8329 + break; 6.8330 + case 'Stacked': 6.8331 + case controlLabels.stacked: 6.8332 + multibar.stacked(true); 6.8333 + break; 6.8334 + } 6.8335 + 6.8336 + state.stacked = multibar.stacked(); 6.8337 + dispatch.stateChange(state); 6.8338 + chart.update(); 6.8339 + }); 6.8340 + 6.8341 + // Update chart from a state object passed to event handler 6.8342 + dispatch.on('changeState', function(e) { 6.8343 + if (typeof e.disabled !== 'undefined') { 6.8344 + data.forEach(function(series,i) { 6.8345 + series.disabled = e.disabled[i]; 6.8346 + }); 6.8347 + state.disabled = e.disabled; 6.8348 + } 6.8349 + if (typeof e.stacked !== 'undefined') { 6.8350 + multibar.stacked(e.stacked); 6.8351 + state.stacked = e.stacked; 6.8352 + stacked = e.stacked; 6.8353 + } 6.8354 + chart.update(); 6.8355 + }); 6.8356 + }); 6.8357 + 6.8358 + renderWatch.renderEnd('multibarchart immediate'); 6.8359 + return chart; 6.8360 + } 6.8361 + 6.8362 + //============================================================ 6.8363 + // Event Handling/Dispatching (out of chart's scope) 6.8364 + //------------------------------------------------------------ 6.8365 + 6.8366 + multibar.dispatch.on('elementMouseover.tooltip', function(evt) { 6.8367 + evt.value = chart.x()(evt.data); 6.8368 + evt['series'] = { 6.8369 + key: evt.data.key, 6.8370 + value: chart.y()(evt.data), 6.8371 + color: evt.color 6.8372 + }; 6.8373 + tooltip.data(evt).hidden(false); 6.8374 + }); 6.8375 + 6.8376 + multibar.dispatch.on('elementMouseout.tooltip', function(evt) { 6.8377 + tooltip.hidden(true); 6.8378 + }); 6.8379 + 6.8380 + multibar.dispatch.on('elementMousemove.tooltip', function(evt) { 6.8381 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.8382 + }); 6.8383 + 6.8384 + //============================================================ 6.8385 + // Expose Public Variables 6.8386 + //------------------------------------------------------------ 6.8387 + 6.8388 + // expose chart's sub-components 6.8389 + chart.dispatch = dispatch; 6.8390 + chart.multibar = multibar; 6.8391 + chart.legend = legend; 6.8392 + chart.controls = controls; 6.8393 + chart.xAxis = xAxis; 6.8394 + chart.yAxis = yAxis; 6.8395 + chart.state = state; 6.8396 + chart.tooltip = tooltip; 6.8397 + 6.8398 + chart.options = nv.utils.optionsFunc.bind(chart); 6.8399 + 6.8400 + chart._options = Object.create({}, { 6.8401 + // simple options, just get/set the necessary values 6.8402 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.8403 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.8404 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.8405 + showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, 6.8406 + controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}}, 6.8407 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.8408 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.8409 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.8410 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.8411 + reduceXTicks: {get: function(){return reduceXTicks;}, set: function(_){reduceXTicks=_;}}, 6.8412 + rotateLabels: {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}}, 6.8413 + staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, 6.8414 + 6.8415 + // deprecated options 6.8416 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.8417 + // deprecated after 1.7.1 6.8418 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.8419 + tooltip.enabled(!!_); 6.8420 + }}, 6.8421 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.8422 + // deprecated after 1.7.1 6.8423 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.8424 + tooltip.contentGenerator(_); 6.8425 + }}, 6.8426 + 6.8427 + // options that require extra logic in the setter 6.8428 + margin: {get: function(){return margin;}, set: function(_){ 6.8429 + margin.top = _.top !== undefined ? _.top : margin.top; 6.8430 + margin.right = _.right !== undefined ? _.right : margin.right; 6.8431 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.8432 + margin.left = _.left !== undefined ? _.left : margin.left; 6.8433 + }}, 6.8434 + duration: {get: function(){return duration;}, set: function(_){ 6.8435 + duration = _; 6.8436 + multibar.duration(duration); 6.8437 + xAxis.duration(duration); 6.8438 + yAxis.duration(duration); 6.8439 + renderWatch.reset(duration); 6.8440 + }}, 6.8441 + color: {get: function(){return color;}, set: function(_){ 6.8442 + color = nv.utils.getColor(_); 6.8443 + legend.color(color); 6.8444 + }}, 6.8445 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.8446 + rightAlignYAxis = _; 6.8447 + yAxis.orient( rightAlignYAxis ? 'right' : 'left'); 6.8448 + }}, 6.8449 + barColor: {get: function(){return multibar.barColor;}, set: function(_){ 6.8450 + multibar.barColor(_); 6.8451 + legend.color(function(d,i) {return d3.rgb('#ccc').darker(i * 1.5).toString();}) 6.8452 + }} 6.8453 + }); 6.8454 + 6.8455 + nv.utils.inheritOptions(chart, multibar); 6.8456 + nv.utils.initOptions(chart); 6.8457 + 6.8458 + return chart; 6.8459 +}; 6.8460 + 6.8461 +nv.models.multiBarHorizontal = function() { 6.8462 + "use strict"; 6.8463 + 6.8464 + //============================================================ 6.8465 + // Public Variables with Default Settings 6.8466 + //------------------------------------------------------------ 6.8467 + 6.8468 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.8469 + , width = 960 6.8470 + , height = 500 6.8471 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.8472 + , container = null 6.8473 + , x = d3.scale.ordinal() 6.8474 + , y = d3.scale.linear() 6.8475 + , getX = function(d) { return d.x } 6.8476 + , getY = function(d) { return d.y } 6.8477 + , getYerr = function(d) { return d.yErr } 6.8478 + , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove 6.8479 + , color = nv.utils.defaultColor() 6.8480 + , barColor = null // adding the ability to set the color for each rather than the whole group 6.8481 + , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled 6.8482 + , stacked = false 6.8483 + , showValues = false 6.8484 + , showBarLabels = false 6.8485 + , valuePadding = 60 6.8486 + , groupSpacing = 0.1 6.8487 + , valueFormat = d3.format(',.2f') 6.8488 + , delay = 1200 6.8489 + , xDomain 6.8490 + , yDomain 6.8491 + , xRange 6.8492 + , yRange 6.8493 + , duration = 250 6.8494 + , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') 6.8495 + ; 6.8496 + 6.8497 + //============================================================ 6.8498 + // Private Variables 6.8499 + //------------------------------------------------------------ 6.8500 + 6.8501 + var x0, y0; //used to store previous scales 6.8502 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.8503 + 6.8504 + function chart(selection) { 6.8505 + renderWatch.reset(); 6.8506 + selection.each(function(data) { 6.8507 + var availableWidth = width - margin.left - margin.right, 6.8508 + availableHeight = height - margin.top - margin.bottom; 6.8509 + 6.8510 + container = d3.select(this); 6.8511 + nv.utils.initSVG(container); 6.8512 + 6.8513 + if (stacked) 6.8514 + data = d3.layout.stack() 6.8515 + .offset('zero') 6.8516 + .values(function(d){ return d.values }) 6.8517 + .y(getY) 6.8518 + (data); 6.8519 + 6.8520 + //add series index and key to each data point for reference 6.8521 + data.forEach(function(series, i) { 6.8522 + series.values.forEach(function(point) { 6.8523 + point.series = i; 6.8524 + point.key = series.key; 6.8525 + }); 6.8526 + }); 6.8527 + 6.8528 + // HACK for negative value stacking 6.8529 + if (stacked) 6.8530 + data[0].values.map(function(d,i) { 6.8531 + var posBase = 0, negBase = 0; 6.8532 + data.map(function(d) { 6.8533 + var f = d.values[i] 6.8534 + f.size = Math.abs(f.y); 6.8535 + if (f.y<0) { 6.8536 + f.y1 = negBase - f.size; 6.8537 + negBase = negBase - f.size; 6.8538 + } else 6.8539 + { 6.8540 + f.y1 = posBase; 6.8541 + posBase = posBase + f.size; 6.8542 + } 6.8543 + }); 6.8544 + }); 6.8545 + 6.8546 + // Setup Scales 6.8547 + // remap and flatten the data for use in calculating the scales' domains 6.8548 + var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate 6.8549 + data.map(function(d) { 6.8550 + return d.values.map(function(d,i) { 6.8551 + return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1 } 6.8552 + }) 6.8553 + }); 6.8554 + 6.8555 + x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x })) 6.8556 + .rangeBands(xRange || [0, availableHeight], groupSpacing); 6.8557 + 6.8558 + y.domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return stacked ? (d.y > 0 ? d.y1 + d.y : d.y1 ) : d.y }).concat(forceY))) 6.8559 + 6.8560 + if (showValues && !stacked) 6.8561 + y.range(yRange || [(y.domain()[0] < 0 ? valuePadding : 0), availableWidth - (y.domain()[1] > 0 ? valuePadding : 0) ]); 6.8562 + else 6.8563 + y.range(yRange || [0, availableWidth]); 6.8564 + 6.8565 + x0 = x0 || x; 6.8566 + y0 = y0 || d3.scale.linear().domain(y.domain()).range([y(0),y(0)]); 6.8567 + 6.8568 + // Setup containers and skeleton of chart 6.8569 + var wrap = d3.select(this).selectAll('g.nv-wrap.nv-multibarHorizontal').data([data]); 6.8570 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibarHorizontal'); 6.8571 + var defsEnter = wrapEnter.append('defs'); 6.8572 + var gEnter = wrapEnter.append('g'); 6.8573 + var g = wrap.select('g'); 6.8574 + 6.8575 + gEnter.append('g').attr('class', 'nv-groups'); 6.8576 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.8577 + 6.8578 + var groups = wrap.select('.nv-groups').selectAll('.nv-group') 6.8579 + .data(function(d) { return d }, function(d,i) { return i }); 6.8580 + groups.enter().append('g') 6.8581 + .style('stroke-opacity', 1e-6) 6.8582 + .style('fill-opacity', 1e-6); 6.8583 + groups.exit().watchTransition(renderWatch, 'multibarhorizontal: exit groups') 6.8584 + .style('stroke-opacity', 1e-6) 6.8585 + .style('fill-opacity', 1e-6) 6.8586 + .remove(); 6.8587 + groups 6.8588 + .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) 6.8589 + .classed('hover', function(d) { return d.hover }) 6.8590 + .style('fill', function(d,i){ return color(d, i) }) 6.8591 + .style('stroke', function(d,i){ return color(d, i) }); 6.8592 + groups.watchTransition(renderWatch, 'multibarhorizontal: groups') 6.8593 + .style('stroke-opacity', 1) 6.8594 + .style('fill-opacity', .75); 6.8595 + 6.8596 + var bars = groups.selectAll('g.nv-bar') 6.8597 + .data(function(d) { return d.values }); 6.8598 + bars.exit().remove(); 6.8599 + 6.8600 + var barsEnter = bars.enter().append('g') 6.8601 + .attr('transform', function(d,i,j) { 6.8602 + return 'translate(' + y0(stacked ? d.y0 : 0) + ',' + (stacked ? 0 : (j * x.rangeBand() / data.length ) + x(getX(d,i))) + ')' 6.8603 + }); 6.8604 + 6.8605 + barsEnter.append('rect') 6.8606 + .attr('width', 0) 6.8607 + .attr('height', x.rangeBand() / (stacked ? 1 : data.length) ) 6.8608 + 6.8609 + bars 6.8610 + .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here 6.8611 + d3.select(this).classed('hover', true); 6.8612 + dispatch.elementMouseover({ 6.8613 + data: d, 6.8614 + index: i, 6.8615 + color: d3.select(this).style("fill") 6.8616 + }); 6.8617 + }) 6.8618 + .on('mouseout', function(d,i) { 6.8619 + d3.select(this).classed('hover', false); 6.8620 + dispatch.elementMouseout({ 6.8621 + data: d, 6.8622 + index: i, 6.8623 + color: d3.select(this).style("fill") 6.8624 + }); 6.8625 + }) 6.8626 + .on('mouseout', function(d,i) { 6.8627 + dispatch.elementMouseout({ 6.8628 + data: d, 6.8629 + index: i, 6.8630 + color: d3.select(this).style("fill") 6.8631 + }); 6.8632 + }) 6.8633 + .on('mousemove', function(d,i) { 6.8634 + dispatch.elementMousemove({ 6.8635 + data: d, 6.8636 + index: i, 6.8637 + color: d3.select(this).style("fill") 6.8638 + }); 6.8639 + }) 6.8640 + .on('click', function(d,i) { 6.8641 + dispatch.elementClick({ 6.8642 + data: d, 6.8643 + index: i, 6.8644 + color: d3.select(this).style("fill") 6.8645 + }); 6.8646 + d3.event.stopPropagation(); 6.8647 + }) 6.8648 + .on('dblclick', function(d,i) { 6.8649 + dispatch.elementDblClick({ 6.8650 + data: d, 6.8651 + index: i, 6.8652 + color: d3.select(this).style("fill") 6.8653 + }); 6.8654 + d3.event.stopPropagation(); 6.8655 + }); 6.8656 + 6.8657 + if (getYerr(data[0],0)) { 6.8658 + barsEnter.append('polyline'); 6.8659 + 6.8660 + bars.select('polyline') 6.8661 + .attr('fill', 'none') 6.8662 + .attr('points', function(d,i) { 6.8663 + var xerr = getYerr(d,i) 6.8664 + , mid = 0.8 * x.rangeBand() / ((stacked ? 1 : data.length) * 2); 6.8665 + xerr = xerr.length ? xerr : [-Math.abs(xerr), Math.abs(xerr)]; 6.8666 + xerr = xerr.map(function(e) { return y(e) - y(0); }); 6.8667 + var a = [[xerr[0],-mid], [xerr[0],mid], [xerr[0],0], [xerr[1],0], [xerr[1],-mid], [xerr[1],mid]]; 6.8668 + return a.map(function (path) { return path.join(',') }).join(' '); 6.8669 + }) 6.8670 + .attr('transform', function(d,i) { 6.8671 + var mid = x.rangeBand() / ((stacked ? 1 : data.length) * 2); 6.8672 + return 'translate(' + (getY(d,i) < 0 ? 0 : y(getY(d,i)) - y(0)) + ', ' + mid + ')' 6.8673 + }); 6.8674 + } 6.8675 + 6.8676 + barsEnter.append('text'); 6.8677 + 6.8678 + if (showValues && !stacked) { 6.8679 + bars.select('text') 6.8680 + .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'end' : 'start' }) 6.8681 + .attr('y', x.rangeBand() / (data.length * 2)) 6.8682 + .attr('dy', '.32em') 6.8683 + .text(function(d,i) { 6.8684 + var t = valueFormat(getY(d,i)) 6.8685 + , yerr = getYerr(d,i); 6.8686 + if (yerr === undefined) 6.8687 + return t; 6.8688 + if (!yerr.length) 6.8689 + return t + '±' + valueFormat(Math.abs(yerr)); 6.8690 + return t + '+' + valueFormat(Math.abs(yerr[1])) + '-' + valueFormat(Math.abs(yerr[0])); 6.8691 + }); 6.8692 + bars.watchTransition(renderWatch, 'multibarhorizontal: bars') 6.8693 + .select('text') 6.8694 + .attr('x', function(d,i) { return getY(d,i) < 0 ? -4 : y(getY(d,i)) - y(0) + 4 }) 6.8695 + } else { 6.8696 + bars.selectAll('text').text(''); 6.8697 + } 6.8698 + 6.8699 + if (showBarLabels && !stacked) { 6.8700 + barsEnter.append('text').classed('nv-bar-label',true); 6.8701 + bars.select('text.nv-bar-label') 6.8702 + .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'start' : 'end' }) 6.8703 + .attr('y', x.rangeBand() / (data.length * 2)) 6.8704 + .attr('dy', '.32em') 6.8705 + .text(function(d,i) { return getX(d,i) }); 6.8706 + bars.watchTransition(renderWatch, 'multibarhorizontal: bars') 6.8707 + .select('text.nv-bar-label') 6.8708 + .attr('x', function(d,i) { return getY(d,i) < 0 ? y(0) - y(getY(d,i)) + 4 : -4 }); 6.8709 + } 6.8710 + else { 6.8711 + bars.selectAll('text.nv-bar-label').text(''); 6.8712 + } 6.8713 + 6.8714 + bars 6.8715 + .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'}) 6.8716 + 6.8717 + if (barColor) { 6.8718 + if (!disabled) disabled = data.map(function() { return true }); 6.8719 + bars 6.8720 + .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }) 6.8721 + .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }); 6.8722 + } 6.8723 + 6.8724 + if (stacked) 6.8725 + bars.watchTransition(renderWatch, 'multibarhorizontal: bars') 6.8726 + .attr('transform', function(d,i) { 6.8727 + return 'translate(' + y(d.y1) + ',' + x(getX(d,i)) + ')' 6.8728 + }) 6.8729 + .select('rect') 6.8730 + .attr('width', function(d,i) { 6.8731 + return Math.abs(y(getY(d,i) + d.y0) - y(d.y0)) 6.8732 + }) 6.8733 + .attr('height', x.rangeBand() ); 6.8734 + else 6.8735 + bars.watchTransition(renderWatch, 'multibarhorizontal: bars') 6.8736 + .attr('transform', function(d,i) { 6.8737 + //TODO: stacked must be all positive or all negative, not both? 6.8738 + return 'translate(' + 6.8739 + (getY(d,i) < 0 ? y(getY(d,i)) : y(0)) 6.8740 + + ',' + 6.8741 + (d.series * x.rangeBand() / data.length 6.8742 + + 6.8743 + x(getX(d,i)) ) 6.8744 + + ')' 6.8745 + }) 6.8746 + .select('rect') 6.8747 + .attr('height', x.rangeBand() / data.length ) 6.8748 + .attr('width', function(d,i) { 6.8749 + return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) 6.8750 + }); 6.8751 + 6.8752 + //store old scales for use in transitions on update 6.8753 + x0 = x.copy(); 6.8754 + y0 = y.copy(); 6.8755 + 6.8756 + }); 6.8757 + 6.8758 + renderWatch.renderEnd('multibarHorizontal immediate'); 6.8759 + return chart; 6.8760 + } 6.8761 + 6.8762 + //============================================================ 6.8763 + // Expose Public Variables 6.8764 + //------------------------------------------------------------ 6.8765 + 6.8766 + chart.dispatch = dispatch; 6.8767 + 6.8768 + chart.options = nv.utils.optionsFunc.bind(chart); 6.8769 + 6.8770 + chart._options = Object.create({}, { 6.8771 + // simple options, just get/set the necessary values 6.8772 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.8773 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.8774 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.8775 + y: {get: function(){return getY;}, set: function(_){getY=_;}}, 6.8776 + yErr: {get: function(){return getYerr;}, set: function(_){getYerr=_;}}, 6.8777 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.8778 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.8779 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.8780 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.8781 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.8782 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.8783 + forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, 6.8784 + stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}}, 6.8785 + showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}}, 6.8786 + // this shows the group name, seems pointless? 6.8787 + //showBarLabels: {get: function(){return showBarLabels;}, set: function(_){showBarLabels=_;}}, 6.8788 + disabled: {get: function(){return disabled;}, set: function(_){disabled=_;}}, 6.8789 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.8790 + valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}}, 6.8791 + valuePadding: {get: function(){return valuePadding;}, set: function(_){valuePadding=_;}}, 6.8792 + groupSpacing:{get: function(){return groupSpacing;}, set: function(_){groupSpacing=_;}}, 6.8793 + 6.8794 + // options that require extra logic in the setter 6.8795 + margin: {get: function(){return margin;}, set: function(_){ 6.8796 + margin.top = _.top !== undefined ? _.top : margin.top; 6.8797 + margin.right = _.right !== undefined ? _.right : margin.right; 6.8798 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.8799 + margin.left = _.left !== undefined ? _.left : margin.left; 6.8800 + }}, 6.8801 + duration: {get: function(){return duration;}, set: function(_){ 6.8802 + duration = _; 6.8803 + renderWatch.reset(duration); 6.8804 + }}, 6.8805 + color: {get: function(){return color;}, set: function(_){ 6.8806 + color = nv.utils.getColor(_); 6.8807 + }}, 6.8808 + barColor: {get: function(){return barColor;}, set: function(_){ 6.8809 + barColor = _ ? nv.utils.getColor(_) : null; 6.8810 + }} 6.8811 + }); 6.8812 + 6.8813 + nv.utils.initOptions(chart); 6.8814 + 6.8815 + return chart; 6.8816 +}; 6.8817 + 6.8818 +nv.models.multiBarHorizontalChart = function() { 6.8819 + "use strict"; 6.8820 + 6.8821 + //============================================================ 6.8822 + // Public Variables with Default Settings 6.8823 + //------------------------------------------------------------ 6.8824 + 6.8825 + var multibar = nv.models.multiBarHorizontal() 6.8826 + , xAxis = nv.models.axis() 6.8827 + , yAxis = nv.models.axis() 6.8828 + , legend = nv.models.legend().height(30) 6.8829 + , controls = nv.models.legend().height(30) 6.8830 + , tooltip = nv.models.tooltip() 6.8831 + ; 6.8832 + 6.8833 + var margin = {top: 30, right: 20, bottom: 50, left: 60} 6.8834 + , width = null 6.8835 + , height = null 6.8836 + , color = nv.utils.defaultColor() 6.8837 + , showControls = true 6.8838 + , controlLabels = {} 6.8839 + , showLegend = true 6.8840 + , showXAxis = true 6.8841 + , showYAxis = true 6.8842 + , stacked = false 6.8843 + , x //can be accessed via chart.xScale() 6.8844 + , y //can be accessed via chart.yScale() 6.8845 + , state = nv.utils.state() 6.8846 + , defaultState = null 6.8847 + , noData = null 6.8848 + , dispatch = d3.dispatch('stateChange', 'changeState','renderEnd') 6.8849 + , controlWidth = function() { return showControls ? 180 : 0 } 6.8850 + , duration = 250 6.8851 + ; 6.8852 + 6.8853 + state.stacked = false; // DEPRECATED Maintained for backward compatibility 6.8854 + 6.8855 + multibar.stacked(stacked); 6.8856 + 6.8857 + xAxis 6.8858 + .orient('left') 6.8859 + .tickPadding(5) 6.8860 + .showMaxMin(false) 6.8861 + .tickFormat(function(d) { return d }) 6.8862 + ; 6.8863 + yAxis 6.8864 + .orient('bottom') 6.8865 + .tickFormat(d3.format(',.1f')) 6.8866 + ; 6.8867 + 6.8868 + tooltip 6.8869 + .duration(0) 6.8870 + .valueFormatter(function(d, i) { 6.8871 + return yAxis.tickFormat()(d, i); 6.8872 + }) 6.8873 + .headerFormatter(function(d, i) { 6.8874 + return xAxis.tickFormat()(d, i); 6.8875 + }); 6.8876 + 6.8877 + controls.updateState(false); 6.8878 + 6.8879 + //============================================================ 6.8880 + // Private Variables 6.8881 + //------------------------------------------------------------ 6.8882 + 6.8883 + var stateGetter = function(data) { 6.8884 + return function(){ 6.8885 + return { 6.8886 + active: data.map(function(d) { return !d.disabled }), 6.8887 + stacked: stacked 6.8888 + }; 6.8889 + } 6.8890 + }; 6.8891 + 6.8892 + var stateSetter = function(data) { 6.8893 + return function(state) { 6.8894 + if (state.stacked !== undefined) 6.8895 + stacked = state.stacked; 6.8896 + if (state.active !== undefined) 6.8897 + data.forEach(function(series,i) { 6.8898 + series.disabled = !state.active[i]; 6.8899 + }); 6.8900 + } 6.8901 + }; 6.8902 + 6.8903 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.8904 + 6.8905 + function chart(selection) { 6.8906 + renderWatch.reset(); 6.8907 + renderWatch.models(multibar); 6.8908 + if (showXAxis) renderWatch.models(xAxis); 6.8909 + if (showYAxis) renderWatch.models(yAxis); 6.8910 + 6.8911 + selection.each(function(data) { 6.8912 + var container = d3.select(this), 6.8913 + that = this; 6.8914 + nv.utils.initSVG(container); 6.8915 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.8916 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.8917 + 6.8918 + chart.update = function() { container.transition().duration(duration).call(chart) }; 6.8919 + chart.container = this; 6.8920 + 6.8921 + stacked = multibar.stacked(); 6.8922 + 6.8923 + state 6.8924 + .setter(stateSetter(data), chart.update) 6.8925 + .getter(stateGetter(data)) 6.8926 + .update(); 6.8927 + 6.8928 + // DEPRECATED set state.disableddisabled 6.8929 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.8930 + 6.8931 + if (!defaultState) { 6.8932 + var key; 6.8933 + defaultState = {}; 6.8934 + for (key in state) { 6.8935 + if (state[key] instanceof Array) 6.8936 + defaultState[key] = state[key].slice(0); 6.8937 + else 6.8938 + defaultState[key] = state[key]; 6.8939 + } 6.8940 + } 6.8941 + 6.8942 + // Display No Data message if there's nothing to show. 6.8943 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.8944 + nv.utils.noData(chart, container) 6.8945 + return chart; 6.8946 + } else { 6.8947 + container.selectAll('.nv-noData').remove(); 6.8948 + } 6.8949 + 6.8950 + // Setup Scales 6.8951 + x = multibar.xScale(); 6.8952 + y = multibar.yScale(); 6.8953 + 6.8954 + // Setup containers and skeleton of chart 6.8955 + var wrap = container.selectAll('g.nv-wrap.nv-multiBarHorizontalChart').data([data]); 6.8956 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarHorizontalChart').append('g'); 6.8957 + var g = wrap.select('g'); 6.8958 + 6.8959 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.8960 + gEnter.append('g').attr('class', 'nv-y nv-axis') 6.8961 + .append('g').attr('class', 'nv-zeroLine') 6.8962 + .append('line'); 6.8963 + gEnter.append('g').attr('class', 'nv-barsWrap'); 6.8964 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.8965 + gEnter.append('g').attr('class', 'nv-controlsWrap'); 6.8966 + 6.8967 + // Legend 6.8968 + if (showLegend) { 6.8969 + legend.width(availableWidth - controlWidth()); 6.8970 + 6.8971 + g.select('.nv-legendWrap') 6.8972 + .datum(data) 6.8973 + .call(legend); 6.8974 + 6.8975 + if ( margin.top != legend.height()) { 6.8976 + margin.top = legend.height(); 6.8977 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.8978 + } 6.8979 + 6.8980 + g.select('.nv-legendWrap') 6.8981 + .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')'); 6.8982 + } 6.8983 + 6.8984 + // Controls 6.8985 + if (showControls) { 6.8986 + var controlsData = [ 6.8987 + { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() }, 6.8988 + { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() } 6.8989 + ]; 6.8990 + 6.8991 + controls.width(controlWidth()).color(['#444', '#444', '#444']); 6.8992 + g.select('.nv-controlsWrap') 6.8993 + .datum(controlsData) 6.8994 + .attr('transform', 'translate(0,' + (-margin.top) +')') 6.8995 + .call(controls); 6.8996 + } 6.8997 + 6.8998 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.8999 + 6.9000 + // Main Chart Component(s) 6.9001 + multibar 6.9002 + .disabled(data.map(function(series) { return series.disabled })) 6.9003 + .width(availableWidth) 6.9004 + .height(availableHeight) 6.9005 + .color(data.map(function(d,i) { 6.9006 + return d.color || color(d, i); 6.9007 + }).filter(function(d,i) { return !data[i].disabled })); 6.9008 + 6.9009 + var barsWrap = g.select('.nv-barsWrap') 6.9010 + .datum(data.filter(function(d) { return !d.disabled })); 6.9011 + 6.9012 + barsWrap.transition().call(multibar); 6.9013 + 6.9014 + // Setup Axes 6.9015 + if (showXAxis) { 6.9016 + xAxis 6.9017 + .scale(x) 6.9018 + ._ticks( nv.utils.calcTicksY(availableHeight/24, data) ) 6.9019 + .tickSize(-availableWidth, 0); 6.9020 + 6.9021 + g.select('.nv-x.nv-axis').call(xAxis); 6.9022 + 6.9023 + var xTicks = g.select('.nv-x.nv-axis').selectAll('g'); 6.9024 + 6.9025 + xTicks 6.9026 + .selectAll('line, text'); 6.9027 + } 6.9028 + 6.9029 + if (showYAxis) { 6.9030 + yAxis 6.9031 + .scale(y) 6.9032 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.9033 + .tickSize( -availableHeight, 0); 6.9034 + 6.9035 + g.select('.nv-y.nv-axis') 6.9036 + .attr('transform', 'translate(0,' + availableHeight + ')'); 6.9037 + g.select('.nv-y.nv-axis').call(yAxis); 6.9038 + } 6.9039 + 6.9040 + // Zero line 6.9041 + g.select(".nv-zeroLine line") 6.9042 + .attr("x1", y(0)) 6.9043 + .attr("x2", y(0)) 6.9044 + .attr("y1", 0) 6.9045 + .attr("y2", -availableHeight) 6.9046 + ; 6.9047 + 6.9048 + //============================================================ 6.9049 + // Event Handling/Dispatching (in chart's scope) 6.9050 + //------------------------------------------------------------ 6.9051 + 6.9052 + legend.dispatch.on('stateChange', function(newState) { 6.9053 + for (var key in newState) 6.9054 + state[key] = newState[key]; 6.9055 + dispatch.stateChange(state); 6.9056 + chart.update(); 6.9057 + }); 6.9058 + 6.9059 + controls.dispatch.on('legendClick', function(d,i) { 6.9060 + if (!d.disabled) return; 6.9061 + controlsData = controlsData.map(function(s) { 6.9062 + s.disabled = true; 6.9063 + return s; 6.9064 + }); 6.9065 + d.disabled = false; 6.9066 + 6.9067 + switch (d.key) { 6.9068 + case 'Grouped': 6.9069 + multibar.stacked(false); 6.9070 + break; 6.9071 + case 'Stacked': 6.9072 + multibar.stacked(true); 6.9073 + break; 6.9074 + } 6.9075 + 6.9076 + state.stacked = multibar.stacked(); 6.9077 + dispatch.stateChange(state); 6.9078 + stacked = multibar.stacked(); 6.9079 + 6.9080 + chart.update(); 6.9081 + }); 6.9082 + 6.9083 + // Update chart from a state object passed to event handler 6.9084 + dispatch.on('changeState', function(e) { 6.9085 + 6.9086 + if (typeof e.disabled !== 'undefined') { 6.9087 + data.forEach(function(series,i) { 6.9088 + series.disabled = e.disabled[i]; 6.9089 + }); 6.9090 + 6.9091 + state.disabled = e.disabled; 6.9092 + } 6.9093 + 6.9094 + if (typeof e.stacked !== 'undefined') { 6.9095 + multibar.stacked(e.stacked); 6.9096 + state.stacked = e.stacked; 6.9097 + stacked = e.stacked; 6.9098 + } 6.9099 + 6.9100 + chart.update(); 6.9101 + }); 6.9102 + }); 6.9103 + renderWatch.renderEnd('multibar horizontal chart immediate'); 6.9104 + return chart; 6.9105 + } 6.9106 + 6.9107 + //============================================================ 6.9108 + // Event Handling/Dispatching (out of chart's scope) 6.9109 + //------------------------------------------------------------ 6.9110 + 6.9111 + multibar.dispatch.on('elementMouseover.tooltip', function(evt) { 6.9112 + evt.value = chart.x()(evt.data); 6.9113 + evt['series'] = { 6.9114 + key: evt.data.key, 6.9115 + value: chart.y()(evt.data), 6.9116 + color: evt.color 6.9117 + }; 6.9118 + tooltip.data(evt).hidden(false); 6.9119 + }); 6.9120 + 6.9121 + multibar.dispatch.on('elementMouseout.tooltip', function(evt) { 6.9122 + tooltip.hidden(true); 6.9123 + }); 6.9124 + 6.9125 + multibar.dispatch.on('elementMousemove.tooltip', function(evt) { 6.9126 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.9127 + }); 6.9128 + 6.9129 + //============================================================ 6.9130 + // Expose Public Variables 6.9131 + //------------------------------------------------------------ 6.9132 + 6.9133 + // expose chart's sub-components 6.9134 + chart.dispatch = dispatch; 6.9135 + chart.multibar = multibar; 6.9136 + chart.legend = legend; 6.9137 + chart.controls = controls; 6.9138 + chart.xAxis = xAxis; 6.9139 + chart.yAxis = yAxis; 6.9140 + chart.state = state; 6.9141 + chart.tooltip = tooltip; 6.9142 + 6.9143 + chart.options = nv.utils.optionsFunc.bind(chart); 6.9144 + 6.9145 + chart._options = Object.create({}, { 6.9146 + // simple options, just get/set the necessary values 6.9147 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.9148 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.9149 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.9150 + showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, 6.9151 + controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}}, 6.9152 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.9153 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.9154 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.9155 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.9156 + 6.9157 + // deprecated options 6.9158 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.9159 + // deprecated after 1.7.1 6.9160 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.9161 + tooltip.enabled(!!_); 6.9162 + }}, 6.9163 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.9164 + // deprecated after 1.7.1 6.9165 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.9166 + tooltip.contentGenerator(_); 6.9167 + }}, 6.9168 + 6.9169 + // options that require extra logic in the setter 6.9170 + margin: {get: function(){return margin;}, set: function(_){ 6.9171 + margin.top = _.top !== undefined ? _.top : margin.top; 6.9172 + margin.right = _.right !== undefined ? _.right : margin.right; 6.9173 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.9174 + margin.left = _.left !== undefined ? _.left : margin.left; 6.9175 + }}, 6.9176 + duration: {get: function(){return duration;}, set: function(_){ 6.9177 + duration = _; 6.9178 + renderWatch.reset(duration); 6.9179 + multibar.duration(duration); 6.9180 + xAxis.duration(duration); 6.9181 + yAxis.duration(duration); 6.9182 + }}, 6.9183 + color: {get: function(){return color;}, set: function(_){ 6.9184 + color = nv.utils.getColor(_); 6.9185 + legend.color(color); 6.9186 + }}, 6.9187 + barColor: {get: function(){return multibar.barColor;}, set: function(_){ 6.9188 + multibar.barColor(_); 6.9189 + legend.color(function(d,i) {return d3.rgb('#ccc').darker(i * 1.5).toString();}) 6.9190 + }} 6.9191 + }); 6.9192 + 6.9193 + nv.utils.inheritOptions(chart, multibar); 6.9194 + nv.utils.initOptions(chart); 6.9195 + 6.9196 + return chart; 6.9197 +}; 6.9198 +nv.models.multiChart = function() { 6.9199 + "use strict"; 6.9200 + 6.9201 + //============================================================ 6.9202 + // Public Variables with Default Settings 6.9203 + //------------------------------------------------------------ 6.9204 + 6.9205 + var margin = {top: 30, right: 20, bottom: 50, left: 60}, 6.9206 + color = nv.utils.defaultColor(), 6.9207 + width = null, 6.9208 + height = null, 6.9209 + showLegend = true, 6.9210 + noData = null, 6.9211 + yDomain1, 6.9212 + yDomain2, 6.9213 + getX = function(d) { return d.x }, 6.9214 + getY = function(d) { return d.y}, 6.9215 + interpolate = 'monotone', 6.9216 + useVoronoi = true 6.9217 + ; 6.9218 + 6.9219 + //============================================================ 6.9220 + // Private Variables 6.9221 + //------------------------------------------------------------ 6.9222 + 6.9223 + var x = d3.scale.linear(), 6.9224 + yScale1 = d3.scale.linear(), 6.9225 + yScale2 = d3.scale.linear(), 6.9226 + 6.9227 + lines1 = nv.models.line().yScale(yScale1), 6.9228 + lines2 = nv.models.line().yScale(yScale2), 6.9229 + 6.9230 + bars1 = nv.models.multiBar().stacked(false).yScale(yScale1), 6.9231 + bars2 = nv.models.multiBar().stacked(false).yScale(yScale2), 6.9232 + 6.9233 + stack1 = nv.models.stackedArea().yScale(yScale1), 6.9234 + stack2 = nv.models.stackedArea().yScale(yScale2), 6.9235 + 6.9236 + xAxis = nv.models.axis().scale(x).orient('bottom').tickPadding(5), 6.9237 + yAxis1 = nv.models.axis().scale(yScale1).orient('left'), 6.9238 + yAxis2 = nv.models.axis().scale(yScale2).orient('right'), 6.9239 + 6.9240 + legend = nv.models.legend().height(30), 6.9241 + tooltip = nv.models.tooltip(), 6.9242 + dispatch = d3.dispatch(); 6.9243 + 6.9244 + function chart(selection) { 6.9245 + selection.each(function(data) { 6.9246 + var container = d3.select(this), 6.9247 + that = this; 6.9248 + nv.utils.initSVG(container); 6.9249 + 6.9250 + chart.update = function() { container.transition().call(chart); }; 6.9251 + chart.container = this; 6.9252 + 6.9253 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.9254 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.9255 + 6.9256 + var dataLines1 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 1}); 6.9257 + var dataLines2 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 2}); 6.9258 + var dataBars1 = data.filter(function(d) {return d.type == 'bar' && d.yAxis == 1}); 6.9259 + var dataBars2 = data.filter(function(d) {return d.type == 'bar' && d.yAxis == 2}); 6.9260 + var dataStack1 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 1}); 6.9261 + var dataStack2 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 2}); 6.9262 + 6.9263 + // Display noData message if there's nothing to show. 6.9264 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.9265 + nv.utils.noData(chart, container); 6.9266 + return chart; 6.9267 + } else { 6.9268 + container.selectAll('.nv-noData').remove(); 6.9269 + } 6.9270 + 6.9271 + var series1 = data.filter(function(d) {return !d.disabled && d.yAxis == 1}) 6.9272 + .map(function(d) { 6.9273 + return d.values.map(function(d,i) { 6.9274 + return { x: d.x, y: d.y } 6.9275 + }) 6.9276 + }); 6.9277 + 6.9278 + var series2 = data.filter(function(d) {return !d.disabled && d.yAxis == 2}) 6.9279 + .map(function(d) { 6.9280 + return d.values.map(function(d,i) { 6.9281 + return { x: d.x, y: d.y } 6.9282 + }) 6.9283 + }); 6.9284 + 6.9285 + x .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } )) 6.9286 + .range([0, availableWidth]); 6.9287 + 6.9288 + var wrap = container.selectAll('g.wrap.multiChart').data([data]); 6.9289 + var gEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 multiChart').append('g'); 6.9290 + 6.9291 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.9292 + gEnter.append('g').attr('class', 'nv-y1 nv-axis'); 6.9293 + gEnter.append('g').attr('class', 'nv-y2 nv-axis'); 6.9294 + gEnter.append('g').attr('class', 'lines1Wrap'); 6.9295 + gEnter.append('g').attr('class', 'lines2Wrap'); 6.9296 + gEnter.append('g').attr('class', 'bars1Wrap'); 6.9297 + gEnter.append('g').attr('class', 'bars2Wrap'); 6.9298 + gEnter.append('g').attr('class', 'stack1Wrap'); 6.9299 + gEnter.append('g').attr('class', 'stack2Wrap'); 6.9300 + gEnter.append('g').attr('class', 'legendWrap'); 6.9301 + 6.9302 + var g = wrap.select('g'); 6.9303 + 6.9304 + var color_array = data.map(function(d,i) { 6.9305 + return data[i].color || color(d, i); 6.9306 + }); 6.9307 + 6.9308 + if (showLegend) { 6.9309 + var legendWidth = legend.align() ? availableWidth / 2 : availableWidth; 6.9310 + var legendXPosition = legend.align() ? legendWidth : 0; 6.9311 + 6.9312 + legend.width(legendWidth); 6.9313 + legend.color(color_array); 6.9314 + 6.9315 + g.select('.legendWrap') 6.9316 + .datum(data.map(function(series) { 6.9317 + series.originalKey = series.originalKey === undefined ? series.key : series.originalKey; 6.9318 + series.key = series.originalKey + (series.yAxis == 1 ? '' : ' (right axis)'); 6.9319 + return series; 6.9320 + })) 6.9321 + .call(legend); 6.9322 + 6.9323 + if ( margin.top != legend.height()) { 6.9324 + margin.top = legend.height(); 6.9325 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.9326 + } 6.9327 + 6.9328 + g.select('.legendWrap') 6.9329 + .attr('transform', 'translate(' + legendXPosition + ',' + (-margin.top) +')'); 6.9330 + } 6.9331 + 6.9332 + lines1 6.9333 + .width(availableWidth) 6.9334 + .height(availableHeight) 6.9335 + .interpolate(interpolate) 6.9336 + .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'line'})); 6.9337 + lines2 6.9338 + .width(availableWidth) 6.9339 + .height(availableHeight) 6.9340 + .interpolate(interpolate) 6.9341 + .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'line'})); 6.9342 + bars1 6.9343 + .width(availableWidth) 6.9344 + .height(availableHeight) 6.9345 + .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'bar'})); 6.9346 + bars2 6.9347 + .width(availableWidth) 6.9348 + .height(availableHeight) 6.9349 + .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'bar'})); 6.9350 + stack1 6.9351 + .width(availableWidth) 6.9352 + .height(availableHeight) 6.9353 + .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'area'})); 6.9354 + stack2 6.9355 + .width(availableWidth) 6.9356 + .height(availableHeight) 6.9357 + .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'area'})); 6.9358 + 6.9359 + g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.9360 + 6.9361 + var lines1Wrap = g.select('.lines1Wrap') 6.9362 + .datum(dataLines1.filter(function(d){return !d.disabled})); 6.9363 + var bars1Wrap = g.select('.bars1Wrap') 6.9364 + .datum(dataBars1.filter(function(d){return !d.disabled})); 6.9365 + var stack1Wrap = g.select('.stack1Wrap') 6.9366 + .datum(dataStack1.filter(function(d){return !d.disabled})); 6.9367 + var lines2Wrap = g.select('.lines2Wrap') 6.9368 + .datum(dataLines2.filter(function(d){return !d.disabled})); 6.9369 + var bars2Wrap = g.select('.bars2Wrap') 6.9370 + .datum(dataBars2.filter(function(d){return !d.disabled})); 6.9371 + var stack2Wrap = g.select('.stack2Wrap') 6.9372 + .datum(dataStack2.filter(function(d){return !d.disabled})); 6.9373 + 6.9374 + var extraValue1 = dataStack1.length ? dataStack1.map(function(a){return a.values}).reduce(function(a,b){ 6.9375 + return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}}) 6.9376 + }).concat([{x:0, y:0}]) : []; 6.9377 + var extraValue2 = dataStack2.length ? dataStack2.map(function(a){return a.values}).reduce(function(a,b){ 6.9378 + return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}}) 6.9379 + }).concat([{x:0, y:0}]) : []; 6.9380 + 6.9381 + yScale1 .domain(yDomain1 || d3.extent(d3.merge(series1).concat(extraValue1), function(d) { return d.y } )) 6.9382 + .range([0, availableHeight]); 6.9383 + 6.9384 + yScale2 .domain(yDomain2 || d3.extent(d3.merge(series2).concat(extraValue2), function(d) { return d.y } )) 6.9385 + .range([0, availableHeight]); 6.9386 + 6.9387 + lines1.yDomain(yScale1.domain()); 6.9388 + bars1.yDomain(yScale1.domain()); 6.9389 + stack1.yDomain(yScale1.domain()); 6.9390 + 6.9391 + lines2.yDomain(yScale2.domain()); 6.9392 + bars2.yDomain(yScale2.domain()); 6.9393 + stack2.yDomain(yScale2.domain()); 6.9394 + 6.9395 + if(dataStack1.length){d3.transition(stack1Wrap).call(stack1);} 6.9396 + if(dataStack2.length){d3.transition(stack2Wrap).call(stack2);} 6.9397 + 6.9398 + if(dataBars1.length){d3.transition(bars1Wrap).call(bars1);} 6.9399 + if(dataBars2.length){d3.transition(bars2Wrap).call(bars2);} 6.9400 + 6.9401 + if(dataLines1.length){d3.transition(lines1Wrap).call(lines1);} 6.9402 + if(dataLines2.length){d3.transition(lines2Wrap).call(lines2);} 6.9403 + 6.9404 + xAxis 6.9405 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.9406 + .tickSize(-availableHeight, 0); 6.9407 + 6.9408 + g.select('.nv-x.nv-axis') 6.9409 + .attr('transform', 'translate(0,' + availableHeight + ')'); 6.9410 + d3.transition(g.select('.nv-x.nv-axis')) 6.9411 + .call(xAxis); 6.9412 + 6.9413 + yAxis1 6.9414 + ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) 6.9415 + .tickSize( -availableWidth, 0); 6.9416 + 6.9417 + 6.9418 + d3.transition(g.select('.nv-y1.nv-axis')) 6.9419 + .call(yAxis1); 6.9420 + 6.9421 + yAxis2 6.9422 + ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) 6.9423 + .tickSize( -availableWidth, 0); 6.9424 + 6.9425 + d3.transition(g.select('.nv-y2.nv-axis')) 6.9426 + .call(yAxis2); 6.9427 + 6.9428 + g.select('.nv-y1.nv-axis') 6.9429 + .classed('nv-disabled', series1.length ? false : true) 6.9430 + .attr('transform', 'translate(' + x.range()[0] + ',0)'); 6.9431 + 6.9432 + g.select('.nv-y2.nv-axis') 6.9433 + .classed('nv-disabled', series2.length ? false : true) 6.9434 + .attr('transform', 'translate(' + x.range()[1] + ',0)'); 6.9435 + 6.9436 + legend.dispatch.on('stateChange', function(newState) { 6.9437 + chart.update(); 6.9438 + }); 6.9439 + 6.9440 + //============================================================ 6.9441 + // Event Handling/Dispatching 6.9442 + //------------------------------------------------------------ 6.9443 + 6.9444 + function mouseover_line(evt) { 6.9445 + var yaxis = data[evt.seriesIndex].yAxis === 2 ? yAxis2 : yAxis1; 6.9446 + evt.value = evt.point.x; 6.9447 + evt.series = { 6.9448 + value: evt.point.y, 6.9449 + color: evt.point.color 6.9450 + }; 6.9451 + tooltip 6.9452 + .duration(100) 6.9453 + .valueFormatter(function(d, i) { 6.9454 + return yaxis.tickFormat()(d, i); 6.9455 + }) 6.9456 + .data(evt) 6.9457 + .position(evt.pos) 6.9458 + .hidden(false); 6.9459 + } 6.9460 + 6.9461 + function mouseover_stack(evt) { 6.9462 + var yaxis = data[evt.seriesIndex].yAxis === 2 ? yAxis2 : yAxis1; 6.9463 + evt.point['x'] = stack1.x()(evt.point); 6.9464 + evt.point['y'] = stack1.y()(evt.point); 6.9465 + tooltip 6.9466 + .duration(100) 6.9467 + .valueFormatter(function(d, i) { 6.9468 + return yaxis.tickFormat()(d, i); 6.9469 + }) 6.9470 + .data(evt) 6.9471 + .position(evt.pos) 6.9472 + .hidden(false); 6.9473 + } 6.9474 + 6.9475 + function mouseover_bar(evt) { 6.9476 + var yaxis = data[evt.data.series].yAxis === 2 ? yAxis2 : yAxis1; 6.9477 + 6.9478 + evt.value = bars1.x()(evt.data); 6.9479 + evt['series'] = { 6.9480 + value: bars1.y()(evt.data), 6.9481 + color: evt.color 6.9482 + }; 6.9483 + tooltip 6.9484 + .duration(0) 6.9485 + .valueFormatter(function(d, i) { 6.9486 + return yaxis.tickFormat()(d, i); 6.9487 + }) 6.9488 + .data(evt) 6.9489 + .hidden(false); 6.9490 + } 6.9491 + 6.9492 + lines1.dispatch.on('elementMouseover.tooltip', mouseover_line); 6.9493 + lines2.dispatch.on('elementMouseover.tooltip', mouseover_line); 6.9494 + lines1.dispatch.on('elementMouseout.tooltip', function(evt) { 6.9495 + tooltip.hidden(true) 6.9496 + }); 6.9497 + lines2.dispatch.on('elementMouseout.tooltip', function(evt) { 6.9498 + tooltip.hidden(true) 6.9499 + }); 6.9500 + 6.9501 + stack1.dispatch.on('elementMouseover.tooltip', mouseover_stack); 6.9502 + stack2.dispatch.on('elementMouseover.tooltip', mouseover_stack); 6.9503 + stack1.dispatch.on('elementMouseout.tooltip', function(evt) { 6.9504 + tooltip.hidden(true) 6.9505 + }); 6.9506 + stack2.dispatch.on('elementMouseout.tooltip', function(evt) { 6.9507 + tooltip.hidden(true) 6.9508 + }); 6.9509 + 6.9510 + bars1.dispatch.on('elementMouseover.tooltip', mouseover_bar); 6.9511 + bars2.dispatch.on('elementMouseover.tooltip', mouseover_bar); 6.9512 + 6.9513 + bars1.dispatch.on('elementMouseout.tooltip', function(evt) { 6.9514 + tooltip.hidden(true); 6.9515 + }); 6.9516 + bars2.dispatch.on('elementMouseout.tooltip', function(evt) { 6.9517 + tooltip.hidden(true); 6.9518 + }); 6.9519 + bars1.dispatch.on('elementMousemove.tooltip', function(evt) { 6.9520 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.9521 + }); 6.9522 + bars2.dispatch.on('elementMousemove.tooltip', function(evt) { 6.9523 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.9524 + }); 6.9525 + 6.9526 + }); 6.9527 + 6.9528 + return chart; 6.9529 + } 6.9530 + 6.9531 + //============================================================ 6.9532 + // Global getters and setters 6.9533 + //------------------------------------------------------------ 6.9534 + 6.9535 + chart.dispatch = dispatch; 6.9536 + chart.lines1 = lines1; 6.9537 + chart.lines2 = lines2; 6.9538 + chart.bars1 = bars1; 6.9539 + chart.bars2 = bars2; 6.9540 + chart.stack1 = stack1; 6.9541 + chart.stack2 = stack2; 6.9542 + chart.xAxis = xAxis; 6.9543 + chart.yAxis1 = yAxis1; 6.9544 + chart.yAxis2 = yAxis2; 6.9545 + chart.tooltip = tooltip; 6.9546 + 6.9547 + chart.options = nv.utils.optionsFunc.bind(chart); 6.9548 + 6.9549 + chart._options = Object.create({}, { 6.9550 + // simple options, just get/set the necessary values 6.9551 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.9552 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.9553 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.9554 + yDomain1: {get: function(){return yDomain1;}, set: function(_){yDomain1=_;}}, 6.9555 + yDomain2: {get: function(){return yDomain2;}, set: function(_){yDomain2=_;}}, 6.9556 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.9557 + interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}}, 6.9558 + 6.9559 + // deprecated options 6.9560 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.9561 + // deprecated after 1.7.1 6.9562 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.9563 + tooltip.enabled(!!_); 6.9564 + }}, 6.9565 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.9566 + // deprecated after 1.7.1 6.9567 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.9568 + tooltip.contentGenerator(_); 6.9569 + }}, 6.9570 + 6.9571 + // options that require extra logic in the setter 6.9572 + margin: {get: function(){return margin;}, set: function(_){ 6.9573 + margin.top = _.top !== undefined ? _.top : margin.top; 6.9574 + margin.right = _.right !== undefined ? _.right : margin.right; 6.9575 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.9576 + margin.left = _.left !== undefined ? _.left : margin.left; 6.9577 + }}, 6.9578 + color: {get: function(){return color;}, set: function(_){ 6.9579 + color = nv.utils.getColor(_); 6.9580 + }}, 6.9581 + x: {get: function(){return getX;}, set: function(_){ 6.9582 + getX = _; 6.9583 + lines1.x(_); 6.9584 + lines2.x(_); 6.9585 + bars1.x(_); 6.9586 + bars2.x(_); 6.9587 + stack1.x(_); 6.9588 + stack2.x(_); 6.9589 + }}, 6.9590 + y: {get: function(){return getY;}, set: function(_){ 6.9591 + getY = _; 6.9592 + lines1.y(_); 6.9593 + lines2.y(_); 6.9594 + stack1.y(_); 6.9595 + stack2.y(_); 6.9596 + bars1.y(_); 6.9597 + bars2.y(_); 6.9598 + }}, 6.9599 + useVoronoi: {get: function(){return useVoronoi;}, set: function(_){ 6.9600 + useVoronoi=_; 6.9601 + lines1.useVoronoi(_); 6.9602 + lines2.useVoronoi(_); 6.9603 + stack1.useVoronoi(_); 6.9604 + stack2.useVoronoi(_); 6.9605 + }} 6.9606 + }); 6.9607 + 6.9608 + nv.utils.initOptions(chart); 6.9609 + 6.9610 + return chart; 6.9611 +}; 6.9612 + 6.9613 + 6.9614 +nv.models.ohlcBar = function() { 6.9615 + "use strict"; 6.9616 + 6.9617 + //============================================================ 6.9618 + // Public Variables with Default Settings 6.9619 + //------------------------------------------------------------ 6.9620 + 6.9621 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.9622 + , width = null 6.9623 + , height = null 6.9624 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.9625 + , container = null 6.9626 + , x = d3.scale.linear() 6.9627 + , y = d3.scale.linear() 6.9628 + , getX = function(d) { return d.x } 6.9629 + , getY = function(d) { return d.y } 6.9630 + , getOpen = function(d) { return d.open } 6.9631 + , getClose = function(d) { return d.close } 6.9632 + , getHigh = function(d) { return d.high } 6.9633 + , getLow = function(d) { return d.low } 6.9634 + , forceX = [] 6.9635 + , forceY = [] 6.9636 + , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart 6.9637 + , clipEdge = true 6.9638 + , color = nv.utils.defaultColor() 6.9639 + , interactive = false 6.9640 + , xDomain 6.9641 + , yDomain 6.9642 + , xRange 6.9643 + , yRange 6.9644 + , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove') 6.9645 + ; 6.9646 + 6.9647 + //============================================================ 6.9648 + // Private Variables 6.9649 + //------------------------------------------------------------ 6.9650 + 6.9651 + function chart(selection) { 6.9652 + selection.each(function(data) { 6.9653 + container = d3.select(this); 6.9654 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.9655 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.9656 + 6.9657 + nv.utils.initSVG(container); 6.9658 + 6.9659 + // ohlc bar width. 6.9660 + var w = (availableWidth / data[0].values.length) * .9; 6.9661 + 6.9662 + // Setup Scales 6.9663 + x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) )); 6.9664 + 6.9665 + if (padData) 6.9666 + x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); 6.9667 + else 6.9668 + x.range(xRange || [5 + w/2, availableWidth - w/2 - 5]); 6.9669 + 6.9670 + y.domain(yDomain || [ 6.9671 + d3.min(data[0].values.map(getLow).concat(forceY)), 6.9672 + d3.max(data[0].values.map(getHigh).concat(forceY)) 6.9673 + ] 6.9674 + ).range(yRange || [availableHeight, 0]); 6.9675 + 6.9676 + // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point 6.9677 + if (x.domain()[0] === x.domain()[1]) 6.9678 + x.domain()[0] ? 6.9679 + x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) 6.9680 + : x.domain([-1,1]); 6.9681 + 6.9682 + if (y.domain()[0] === y.domain()[1]) 6.9683 + y.domain()[0] ? 6.9684 + y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) 6.9685 + : y.domain([-1,1]); 6.9686 + 6.9687 + // Setup containers and skeleton of chart 6.9688 + var wrap = d3.select(this).selectAll('g.nv-wrap.nv-ohlcBar').data([data[0].values]); 6.9689 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-ohlcBar'); 6.9690 + var defsEnter = wrapEnter.append('defs'); 6.9691 + var gEnter = wrapEnter.append('g'); 6.9692 + var g = wrap.select('g'); 6.9693 + 6.9694 + gEnter.append('g').attr('class', 'nv-ticks'); 6.9695 + 6.9696 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.9697 + 6.9698 + container 6.9699 + .on('click', function(d,i) { 6.9700 + dispatch.chartClick({ 6.9701 + data: d, 6.9702 + index: i, 6.9703 + pos: d3.event, 6.9704 + id: id 6.9705 + }); 6.9706 + }); 6.9707 + 6.9708 + defsEnter.append('clipPath') 6.9709 + .attr('id', 'nv-chart-clip-path-' + id) 6.9710 + .append('rect'); 6.9711 + 6.9712 + wrap.select('#nv-chart-clip-path-' + id + ' rect') 6.9713 + .attr('width', availableWidth) 6.9714 + .attr('height', availableHeight); 6.9715 + 6.9716 + g .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : ''); 6.9717 + 6.9718 + var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick') 6.9719 + .data(function(d) { return d }); 6.9720 + ticks.exit().remove(); 6.9721 + 6.9722 + ticks.enter().append('path') 6.9723 + .attr('class', function(d,i,j) { return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i }) 6.9724 + .attr('d', function(d,i) { 6.9725 + return 'm0,0l0,' 6.9726 + + (y(getOpen(d,i)) 6.9727 + - y(getHigh(d,i))) 6.9728 + + 'l' 6.9729 + + (-w/2) 6.9730 + + ',0l' 6.9731 + + (w/2) 6.9732 + + ',0l0,' 6.9733 + + (y(getLow(d,i)) - y(getOpen(d,i))) 6.9734 + + 'l0,' 6.9735 + + (y(getClose(d,i)) 6.9736 + - y(getLow(d,i))) 6.9737 + + 'l' 6.9738 + + (w/2) 6.9739 + + ',0l' 6.9740 + + (-w/2) 6.9741 + + ',0z'; 6.9742 + }) 6.9743 + .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; }) 6.9744 + .attr('fill', function(d,i) { return color[0]; }) 6.9745 + .attr('stroke', function(d,i) { return color[0]; }) 6.9746 + .attr('x', 0 ) 6.9747 + .attr('y', function(d,i) { return y(Math.max(0, getY(d,i))) }) 6.9748 + .attr('height', function(d,i) { return Math.abs(y(getY(d,i)) - y(0)) }); 6.9749 + 6.9750 + // the bar colors are controlled by CSS currently 6.9751 + ticks.attr('class', function(d,i,j) { 6.9752 + return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i; 6.9753 + }); 6.9754 + 6.9755 + d3.transition(ticks) 6.9756 + .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; }) 6.9757 + .attr('d', function(d,i) { 6.9758 + var w = (availableWidth / data[0].values.length) * .9; 6.9759 + return 'm0,0l0,' 6.9760 + + (y(getOpen(d,i)) 6.9761 + - y(getHigh(d,i))) 6.9762 + + 'l' 6.9763 + + (-w/2) 6.9764 + + ',0l' 6.9765 + + (w/2) 6.9766 + + ',0l0,' 6.9767 + + (y(getLow(d,i)) 6.9768 + - y(getOpen(d,i))) 6.9769 + + 'l0,' 6.9770 + + (y(getClose(d,i)) 6.9771 + - y(getLow(d,i))) 6.9772 + + 'l' 6.9773 + + (w/2) 6.9774 + + ',0l' 6.9775 + + (-w/2) 6.9776 + + ',0z'; 6.9777 + }); 6.9778 + }); 6.9779 + 6.9780 + return chart; 6.9781 + } 6.9782 + 6.9783 + 6.9784 + //Create methods to allow outside functions to highlight a specific bar. 6.9785 + chart.highlightPoint = function(pointIndex, isHoverOver) { 6.9786 + chart.clearHighlights(); 6.9787 + container.select(".nv-ohlcBar .nv-tick-0-" + pointIndex) 6.9788 + .classed("hover", isHoverOver) 6.9789 + ; 6.9790 + }; 6.9791 + 6.9792 + chart.clearHighlights = function() { 6.9793 + container.select(".nv-ohlcBar .nv-tick.hover") 6.9794 + .classed("hover", false) 6.9795 + ; 6.9796 + }; 6.9797 + 6.9798 + //============================================================ 6.9799 + // Expose Public Variables 6.9800 + //------------------------------------------------------------ 6.9801 + 6.9802 + chart.dispatch = dispatch; 6.9803 + chart.options = nv.utils.optionsFunc.bind(chart); 6.9804 + 6.9805 + chart._options = Object.create({}, { 6.9806 + // simple options, just get/set the necessary values 6.9807 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.9808 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.9809 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.9810 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.9811 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.9812 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.9813 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.9814 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.9815 + forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, 6.9816 + forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, 6.9817 + padData: {get: function(){return padData;}, set: function(_){padData=_;}}, 6.9818 + clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, 6.9819 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.9820 + interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, 6.9821 + 6.9822 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.9823 + y: {get: function(){return getY;}, set: function(_){getY=_;}}, 6.9824 + open: {get: function(){return getOpen();}, set: function(_){getOpen=_;}}, 6.9825 + close: {get: function(){return getClose();}, set: function(_){getClose=_;}}, 6.9826 + high: {get: function(){return getHigh;}, set: function(_){getHigh=_;}}, 6.9827 + low: {get: function(){return getLow;}, set: function(_){getLow=_;}}, 6.9828 + 6.9829 + // options that require extra logic in the setter 6.9830 + margin: {get: function(){return margin;}, set: function(_){ 6.9831 + margin.top = _.top != undefined ? _.top : margin.top; 6.9832 + margin.right = _.right != undefined ? _.right : margin.right; 6.9833 + margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom; 6.9834 + margin.left = _.left != undefined ? _.left : margin.left; 6.9835 + }}, 6.9836 + color: {get: function(){return color;}, set: function(_){ 6.9837 + color = nv.utils.getColor(_); 6.9838 + }} 6.9839 + }); 6.9840 + 6.9841 + nv.utils.initOptions(chart); 6.9842 + return chart; 6.9843 +}; 6.9844 +// Code adapted from Jason Davies' "Parallel Coordinates" 6.9845 +// http://bl.ocks.org/jasondavies/1341281 6.9846 +nv.models.parallelCoordinates = function() { 6.9847 + "use strict"; 6.9848 + 6.9849 + //============================================================ 6.9850 + // Public Variables with Default Settings 6.9851 + //------------------------------------------------------------ 6.9852 + 6.9853 + var margin = {top: 30, right: 0, bottom: 10, left: 0} 6.9854 + , width = null 6.9855 + , height = null 6.9856 + , x = d3.scale.ordinal() 6.9857 + , y = {} 6.9858 + , dimensionNames = [] 6.9859 + , dimensionFormats = [] 6.9860 + , color = nv.utils.defaultColor() 6.9861 + , filters = [] 6.9862 + , active = [] 6.9863 + , dragging = [] 6.9864 + , lineTension = 1 6.9865 + , dispatch = d3.dispatch('brush', 'elementMouseover', 'elementMouseout') 6.9866 + ; 6.9867 + 6.9868 + //============================================================ 6.9869 + // Private Variables 6.9870 + //------------------------------------------------------------ 6.9871 + 6.9872 + function chart(selection) { 6.9873 + selection.each(function(data) { 6.9874 + var container = d3.select(this); 6.9875 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.9876 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.9877 + 6.9878 + nv.utils.initSVG(container); 6.9879 + 6.9880 + active = data; //set all active before first brush call 6.9881 + 6.9882 + // Setup Scales 6.9883 + x.rangePoints([0, availableWidth], 1).domain(dimensionNames); 6.9884 + 6.9885 + //Set as true if all values on an axis are missing. 6.9886 + var onlyNanValues = {}; 6.9887 + // Extract the list of dimensions and create a scale for each. 6.9888 + dimensionNames.forEach(function(d) { 6.9889 + var extent = d3.extent(data, function(p) { return +p[d]; }); 6.9890 + onlyNanValues[d] = false; 6.9891 + //If there is no values to display on an axis, set the extent to 0 6.9892 + if (extent[0] === undefined) { 6.9893 + onlyNanValues[d] = true; 6.9894 + extent[0] = 0; 6.9895 + extent[1] = 0; 6.9896 + } 6.9897 + //Scale axis if there is only one value 6.9898 + if (extent[0] === extent[1]) { 6.9899 + extent[0] = extent[0] - 1; 6.9900 + extent[1] = extent[1] + 1; 6.9901 + } 6.9902 + //Use 90% of (availableHeight - 12) for the axis range, 12 reprensenting the space necessary to display "undefined values" text. 6.9903 + //The remaining 10% are used to display the missingValue line. 6.9904 + y[d] = d3.scale.linear() 6.9905 + .domain(extent) 6.9906 + .range([(availableHeight - 12) * 0.9, 0]); 6.9907 + 6.9908 + y[d].brush = d3.svg.brush().y(y[d]).on('brush', brush); 6.9909 + 6.9910 + return d != 'name'; 6.9911 + }); 6.9912 + 6.9913 + // Setup containers and skeleton of chart 6.9914 + var wrap = container.selectAll('g.nv-wrap.nv-parallelCoordinates').data([data]); 6.9915 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-parallelCoordinates'); 6.9916 + var gEnter = wrapEnter.append('g'); 6.9917 + var g = wrap.select('g'); 6.9918 + 6.9919 + gEnter.append('g').attr('class', 'nv-parallelCoordinates background'); 6.9920 + gEnter.append('g').attr('class', 'nv-parallelCoordinates foreground'); 6.9921 + gEnter.append('g').attr('class', 'nv-parallelCoordinates missingValuesline'); 6.9922 + 6.9923 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.9924 + 6.9925 + var line = d3.svg.line().interpolate('cardinal').tension(lineTension), 6.9926 + axis = d3.svg.axis().orient('left'), 6.9927 + axisDrag = d3.behavior.drag() 6.9928 + .on('dragstart', dragStart) 6.9929 + .on('drag', dragMove) 6.9930 + .on('dragend', dragEnd); 6.9931 + 6.9932 + //Add missing value line at the bottom of the chart 6.9933 + var missingValuesline, missingValueslineText; 6.9934 + var step = x.range()[1] - x.range()[0]; 6.9935 + var axisWithMissingValues = []; 6.9936 + var lineData = [0 + step / 2, availableHeight - 12, availableWidth - step / 2, availableHeight - 12]; 6.9937 + missingValuesline = wrap.select('.missingValuesline').selectAll('line').data([lineData]); 6.9938 + missingValuesline.enter().append('line'); 6.9939 + missingValuesline.exit().remove(); 6.9940 + missingValuesline.attr("x1", function(d) { return d[0]; }) 6.9941 + .attr("y1", function(d) { return d[1]; }) 6.9942 + .attr("x2", function(d) { return d[2]; }) 6.9943 + .attr("y2", function(d) { return d[3]; }); 6.9944 + 6.9945 + //Add the text "undefined values" under the missing value line 6.9946 + missingValueslineText = wrap.select('.missingValuesline').selectAll('text').data(["undefined values"]); 6.9947 + missingValueslineText.append('text').data(["undefined values"]); 6.9948 + missingValueslineText.enter().append('text'); 6.9949 + missingValueslineText.exit().remove(); 6.9950 + missingValueslineText.attr("y", availableHeight) 6.9951 + //To have the text right align with the missingValues line, substract 92 representing the text size. 6.9952 + .attr("x", availableWidth - 92 - step / 2) 6.9953 + .text(function(d) { return d; }); 6.9954 + 6.9955 + // Add grey background lines for context. 6.9956 + var background = wrap.select('.background').selectAll('path').data(data); 6.9957 + background.enter().append('path'); 6.9958 + background.exit().remove(); 6.9959 + background.attr('d', path); 6.9960 + 6.9961 + // Add blue foreground lines for focus. 6.9962 + var foreground = wrap.select('.foreground').selectAll('path').data(data); 6.9963 + foreground.enter().append('path') 6.9964 + foreground.exit().remove(); 6.9965 + foreground.attr('d', path).attr('stroke', color); 6.9966 + foreground.on("mouseover", function (d, i) { 6.9967 + d3.select(this).classed('hover', true); 6.9968 + dispatch.elementMouseover({ 6.9969 + label: d.name, 6.9970 + data: d.data, 6.9971 + index: i, 6.9972 + pos: [d3.mouse(this.parentNode)[0], d3.mouse(this.parentNode)[1]] 6.9973 + }); 6.9974 + 6.9975 + }); 6.9976 + foreground.on("mouseout", function (d, i) { 6.9977 + d3.select(this).classed('hover', false); 6.9978 + dispatch.elementMouseout({ 6.9979 + label: d.name, 6.9980 + data: d.data, 6.9981 + index: i 6.9982 + }); 6.9983 + }); 6.9984 + 6.9985 + // Add a group element for each dimension. 6.9986 + var dimensions = g.selectAll('.dimension').data(dimensionNames); 6.9987 + var dimensionsEnter = dimensions.enter().append('g').attr('class', 'nv-parallelCoordinates dimension'); 6.9988 + dimensionsEnter.append('g').attr('class', 'nv-parallelCoordinates nv-axis'); 6.9989 + dimensionsEnter.append('g').attr('class', 'nv-parallelCoordinates-brush'); 6.9990 + dimensionsEnter.append('text').attr('class', 'nv-parallelCoordinates nv-label'); 6.9991 + 6.9992 + dimensions.attr('transform', function(d) { return 'translate(' + x(d) + ',0)'; }); 6.9993 + dimensions.exit().remove(); 6.9994 + 6.9995 + // Add an axis and title. 6.9996 + dimensions.select('.nv-label') 6.9997 + .style("cursor", "move") 6.9998 + .attr('dy', '-1em') 6.9999 + .attr('text-anchor', 'middle') 6.10000 + .text(String) 6.10001 + .on("mouseover", function(d, i) { 6.10002 + dispatch.elementMouseover({ 6.10003 + dim: d, 6.10004 + pos: [d3.mouse(this.parentNode.parentNode)[0], d3.mouse(this.parentNode.parentNode)[1]] 6.10005 + }); 6.10006 + }) 6.10007 + .on("mouseout", function(d, i) { 6.10008 + dispatch.elementMouseout({ 6.10009 + dim: d 6.10010 + }); 6.10011 + }) 6.10012 + .call(axisDrag); 6.10013 + 6.10014 + dimensions.select('.nv-axis') 6.10015 + .each(function (d, i) { 6.10016 + d3.select(this).call(axis.scale(y[d]).tickFormat(d3.format(dimensionFormats[i]))); 6.10017 + }); 6.10018 + 6.10019 + dimensions.select('.nv-parallelCoordinates-brush') 6.10020 + .each(function (d) { 6.10021 + d3.select(this).call(y[d].brush); 6.10022 + }) 6.10023 + .selectAll('rect') 6.10024 + .attr('x', -8) 6.10025 + .attr('width', 16); 6.10026 + 6.10027 + // Returns the path for a given data point. 6.10028 + function path(d) { 6.10029 + return line(dimensionNames.map(function (p) { 6.10030 + //If value if missing, put the value on the missing value line 6.10031 + if(isNaN(d[p]) || isNaN(parseFloat(d[p]))) { 6.10032 + var domain = y[p].domain(); 6.10033 + var range = y[p].range(); 6.10034 + var min = domain[0] - (domain[1] - domain[0]) / 9; 6.10035 + 6.10036 + //If it's not already the case, allow brush to select undefined values 6.10037 + if(axisWithMissingValues.indexOf(p) < 0) { 6.10038 + 6.10039 + var newscale = d3.scale.linear().domain([min, domain[1]]).range([availableHeight - 12, range[1]]); 6.10040 + y[p].brush.y(newscale); 6.10041 + axisWithMissingValues.push(p); 6.10042 + } 6.10043 + 6.10044 + return [x(p), y[p](min)]; 6.10045 + } 6.10046 + 6.10047 + //If parallelCoordinate contain missing values show the missing values line otherwise, hide it. 6.10048 + if(axisWithMissingValues.length > 0) { 6.10049 + missingValuesline.style("display", "inline"); 6.10050 + missingValueslineText.style("display", "inline"); 6.10051 + } else { 6.10052 + missingValuesline.style("display", "none"); 6.10053 + missingValueslineText.style("display", "none"); 6.10054 + } 6.10055 + 6.10056 + return [x(p), y[p](d[p])]; 6.10057 + })); 6.10058 + } 6.10059 + 6.10060 + // Handles a brush event, toggling the display of foreground lines. 6.10061 + function brush() { 6.10062 + var actives = dimensionNames.filter(function(p) { return !y[p].brush.empty(); }), 6.10063 + extents = actives.map(function(p) { return y[p].brush.extent(); }); 6.10064 + 6.10065 + filters = []; //erase current filters 6.10066 + actives.forEach(function(d,i) { 6.10067 + filters[i] = { 6.10068 + dimension: d, 6.10069 + extent: extents[i] 6.10070 + } 6.10071 + }); 6.10072 + 6.10073 + active = []; //erase current active list 6.10074 + foreground.style('display', function(d) { 6.10075 + var isActive = actives.every(function(p, i) { 6.10076 + if(isNaN(d[p]) && extents[i][0] == y[p].brush.y().domain()[0]) return true; 6.10077 + return extents[i][0] <= d[p] && d[p] <= extents[i][1]; 6.10078 + }); 6.10079 + if (isActive) active.push(d); 6.10080 + return isActive ? null : 'none'; 6.10081 + }); 6.10082 + 6.10083 + dispatch.brush({ 6.10084 + filters: filters, 6.10085 + active: active 6.10086 + }); 6.10087 + } 6.10088 + 6.10089 + function dragStart(d, i) { 6.10090 + dragging[d] = this.parentNode.__origin__ = x(d); 6.10091 + background.attr("visibility", "hidden"); 6.10092 + 6.10093 + } 6.10094 + 6.10095 + function dragMove(d, i) { 6.10096 + dragging[d] = Math.min(availableWidth, Math.max(0, this.parentNode.__origin__ += d3.event.x)); 6.10097 + foreground.attr("d", path); 6.10098 + dimensionNames.sort(function (a, b) { return position(a) - position(b); }); 6.10099 + x.domain(dimensionNames); 6.10100 + dimensions.attr("transform", function(d) { return "translate(" + position(d) + ")"; }); 6.10101 + } 6.10102 + 6.10103 + function dragEnd(d, i) { 6.10104 + delete this.parentNode.__origin__; 6.10105 + delete dragging[d]; 6.10106 + d3.select(this.parentNode).attr("transform", "translate(" + x(d) + ")"); 6.10107 + foreground 6.10108 + .attr("d", path); 6.10109 + background 6.10110 + .attr("d", path) 6.10111 + .attr("visibility", null); 6.10112 + 6.10113 + } 6.10114 + 6.10115 + function position(d) { 6.10116 + var v = dragging[d]; 6.10117 + return v == null ? x(d) : v; 6.10118 + } 6.10119 + }); 6.10120 + 6.10121 + return chart; 6.10122 + } 6.10123 + 6.10124 + //============================================================ 6.10125 + // Expose Public Variables 6.10126 + //------------------------------------------------------------ 6.10127 + 6.10128 + chart.dispatch = dispatch; 6.10129 + chart.options = nv.utils.optionsFunc.bind(chart); 6.10130 + 6.10131 + chart._options = Object.create({}, { 6.10132 + // simple options, just get/set the necessary values 6.10133 + width: {get: function(){return width;}, set: function(_){width= _;}}, 6.10134 + height: {get: function(){return height;}, set: function(_){height= _;}}, 6.10135 + dimensionNames: {get: function() { return dimensionNames;}, set: function(_){dimensionNames= _;}}, 6.10136 + dimensionFormats : {get: function(){return dimensionFormats;}, set: function (_){dimensionFormats=_;}}, 6.10137 + lineTension: {get: function(){return lineTension;}, set: function(_){lineTension = _;}}, 6.10138 + 6.10139 + // deprecated options 6.10140 + dimensions: {get: function (){return dimensionNames;}, set: function(_){ 6.10141 + // deprecated after 1.8.1 6.10142 + nv.deprecated('dimensions', 'use dimensionNames instead'); 6.10143 + dimensionNames = _; 6.10144 + }}, 6.10145 + 6.10146 + // options that require extra logic in the setter 6.10147 + margin: {get: function(){return margin;}, set: function(_){ 6.10148 + margin.top = _.top !== undefined ? _.top : margin.top; 6.10149 + margin.right = _.right !== undefined ? _.right : margin.right; 6.10150 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.10151 + margin.left = _.left !== undefined ? _.left : margin.left; 6.10152 + }}, 6.10153 + color: {get: function(){return color;}, set: function(_){ 6.10154 + color = nv.utils.getColor(_); 6.10155 + }} 6.10156 + }); 6.10157 + 6.10158 + nv.utils.initOptions(chart); 6.10159 + return chart; 6.10160 +}; 6.10161 +nv.models.pie = function() { 6.10162 + "use strict"; 6.10163 + 6.10164 + //============================================================ 6.10165 + // Public Variables with Default Settings 6.10166 + //------------------------------------------------------------ 6.10167 + 6.10168 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.10169 + , width = 500 6.10170 + , height = 500 6.10171 + , getX = function(d) { return d.x } 6.10172 + , getY = function(d) { return d.y } 6.10173 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.10174 + , container = null 6.10175 + , color = nv.utils.defaultColor() 6.10176 + , valueFormat = d3.format(',.2f') 6.10177 + , showLabels = true 6.10178 + , labelsOutside = false 6.10179 + , labelType = "key" 6.10180 + , labelThreshold = .02 //if slice percentage is under this, don't show label 6.10181 + , donut = false 6.10182 + , title = false 6.10183 + , growOnHover = true 6.10184 + , titleOffset = 0 6.10185 + , labelSunbeamLayout = false 6.10186 + , startAngle = false 6.10187 + , padAngle = false 6.10188 + , endAngle = false 6.10189 + , cornerRadius = 0 6.10190 + , donutRatio = 0.5 6.10191 + , arcsRadius = [] 6.10192 + , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') 6.10193 + ; 6.10194 + 6.10195 + var arcs = []; 6.10196 + var arcsOver = []; 6.10197 + 6.10198 + //============================================================ 6.10199 + // chart function 6.10200 + //------------------------------------------------------------ 6.10201 + 6.10202 + var renderWatch = nv.utils.renderWatch(dispatch); 6.10203 + 6.10204 + function chart(selection) { 6.10205 + renderWatch.reset(); 6.10206 + selection.each(function(data) { 6.10207 + var availableWidth = width - margin.left - margin.right 6.10208 + , availableHeight = height - margin.top - margin.bottom 6.10209 + , radius = Math.min(availableWidth, availableHeight) / 2 6.10210 + , arcsRadiusOuter = [] 6.10211 + , arcsRadiusInner = [] 6.10212 + ; 6.10213 + 6.10214 + container = d3.select(this) 6.10215 + if (arcsRadius.length === 0) { 6.10216 + var outer = radius - radius / 5; 6.10217 + var inner = donutRatio * radius; 6.10218 + for (var i = 0; i < data[0].length; i++) { 6.10219 + arcsRadiusOuter.push(outer); 6.10220 + arcsRadiusInner.push(inner); 6.10221 + } 6.10222 + } else { 6.10223 + arcsRadiusOuter = arcsRadius.map(function (d) { return (d.outer - d.outer / 5) * radius; }); 6.10224 + arcsRadiusInner = arcsRadius.map(function (d) { return (d.inner - d.inner / 5) * radius; }); 6.10225 + donutRatio = d3.min(arcsRadius.map(function (d) { return (d.inner - d.inner / 5); })); 6.10226 + } 6.10227 + nv.utils.initSVG(container); 6.10228 + 6.10229 + // Setup containers and skeleton of chart 6.10230 + var wrap = container.selectAll('.nv-wrap.nv-pie').data(data); 6.10231 + var wrapEnter = wrap.enter().append('g').attr('class','nvd3 nv-wrap nv-pie nv-chart-' + id); 6.10232 + var gEnter = wrapEnter.append('g'); 6.10233 + var g = wrap.select('g'); 6.10234 + var g_pie = gEnter.append('g').attr('class', 'nv-pie'); 6.10235 + gEnter.append('g').attr('class', 'nv-pieLabels'); 6.10236 + 6.10237 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.10238 + g.select('.nv-pie').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'); 6.10239 + g.select('.nv-pieLabels').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'); 6.10240 + 6.10241 + // 6.10242 + container.on('click', function(d,i) { 6.10243 + dispatch.chartClick({ 6.10244 + data: d, 6.10245 + index: i, 6.10246 + pos: d3.event, 6.10247 + id: id 6.10248 + }); 6.10249 + }); 6.10250 + 6.10251 + arcs = []; 6.10252 + arcsOver = []; 6.10253 + for (var i = 0; i < data[0].length; i++) { 6.10254 + 6.10255 + var arc = d3.svg.arc().outerRadius(arcsRadiusOuter[i]); 6.10256 + var arcOver = d3.svg.arc().outerRadius(arcsRadiusOuter[i] + 5); 6.10257 + 6.10258 + if (startAngle !== false) { 6.10259 + arc.startAngle(startAngle); 6.10260 + arcOver.startAngle(startAngle); 6.10261 + } 6.10262 + if (endAngle !== false) { 6.10263 + arc.endAngle(endAngle); 6.10264 + arcOver.endAngle(endAngle); 6.10265 + } 6.10266 + if (donut) { 6.10267 + arc.innerRadius(arcsRadiusInner[i]); 6.10268 + arcOver.innerRadius(arcsRadiusInner[i]); 6.10269 + } 6.10270 + 6.10271 + if (arc.cornerRadius && cornerRadius) { 6.10272 + arc.cornerRadius(cornerRadius); 6.10273 + arcOver.cornerRadius(cornerRadius); 6.10274 + } 6.10275 + 6.10276 + arcs.push(arc); 6.10277 + arcsOver.push(arcOver); 6.10278 + } 6.10279 + 6.10280 + // Setup the Pie chart and choose the data element 6.10281 + var pie = d3.layout.pie() 6.10282 + .sort(null) 6.10283 + .value(function(d) { return d.disabled ? 0 : getY(d) }); 6.10284 + 6.10285 + // padAngle added in d3 3.5 6.10286 + if (pie.padAngle && padAngle) { 6.10287 + pie.padAngle(padAngle); 6.10288 + } 6.10289 + 6.10290 + // if title is specified and donut, put it in the middle 6.10291 + if (donut && title) { 6.10292 + g_pie.append("text").attr('class', 'nv-pie-title'); 6.10293 + 6.10294 + wrap.select('.nv-pie-title') 6.10295 + .style("text-anchor", "middle") 6.10296 + .text(function (d) { 6.10297 + return title; 6.10298 + }) 6.10299 + .style("font-size", (Math.min(availableWidth, availableHeight)) * donutRatio * 2 / (title.length + 2) + "px") 6.10300 + .attr("dy", "0.35em") // trick to vertically center text 6.10301 + .attr('transform', function(d, i) { 6.10302 + return 'translate(0, '+ titleOffset + ')'; 6.10303 + }); 6.10304 + } 6.10305 + 6.10306 + var slices = wrap.select('.nv-pie').selectAll('.nv-slice').data(pie); 6.10307 + var pieLabels = wrap.select('.nv-pieLabels').selectAll('.nv-label').data(pie); 6.10308 + 6.10309 + slices.exit().remove(); 6.10310 + pieLabels.exit().remove(); 6.10311 + 6.10312 + var ae = slices.enter().append('g'); 6.10313 + ae.attr('class', 'nv-slice'); 6.10314 + ae.on('mouseover', function(d, i) { 6.10315 + d3.select(this).classed('hover', true); 6.10316 + if (growOnHover) { 6.10317 + d3.select(this).select("path").transition() 6.10318 + .duration(70) 6.10319 + .attr("d", arcsOver[i]); 6.10320 + } 6.10321 + dispatch.elementMouseover({ 6.10322 + data: d.data, 6.10323 + index: i, 6.10324 + color: d3.select(this).style("fill") 6.10325 + }); 6.10326 + }); 6.10327 + ae.on('mouseout', function(d, i) { 6.10328 + d3.select(this).classed('hover', false); 6.10329 + if (growOnHover) { 6.10330 + d3.select(this).select("path").transition() 6.10331 + .duration(50) 6.10332 + .attr("d", arcs[i]); 6.10333 + } 6.10334 + dispatch.elementMouseout({data: d.data, index: i}); 6.10335 + }); 6.10336 + ae.on('mousemove', function(d, i) { 6.10337 + dispatch.elementMousemove({data: d.data, index: i}); 6.10338 + }); 6.10339 + ae.on('click', function(d, i) { 6.10340 + dispatch.elementClick({ 6.10341 + data: d.data, 6.10342 + index: i, 6.10343 + color: d3.select(this).style("fill") 6.10344 + }); 6.10345 + }); 6.10346 + ae.on('dblclick', function(d, i) { 6.10347 + dispatch.elementDblClick({ 6.10348 + data: d.data, 6.10349 + index: i, 6.10350 + color: d3.select(this).style("fill") 6.10351 + }); 6.10352 + }); 6.10353 + 6.10354 + slices.attr('fill', function(d,i) { return color(d.data, i); }); 6.10355 + slices.attr('stroke', function(d,i) { return color(d.data, i); }); 6.10356 + 6.10357 + var paths = ae.append('path').each(function(d) { 6.10358 + this._current = d; 6.10359 + }); 6.10360 + 6.10361 + slices.select('path') 6.10362 + .transition() 6.10363 + .attr('d', function (d, i) { return arcs[i](d); }) 6.10364 + .attrTween('d', arcTween); 6.10365 + 6.10366 + if (showLabels) { 6.10367 + // This does the normal label 6.10368 + var labelsArc = []; 6.10369 + for (var i = 0; i < data[0].length; i++) { 6.10370 + labelsArc.push(arcs[i]); 6.10371 + 6.10372 + if (labelsOutside) { 6.10373 + if (donut) { 6.10374 + labelsArc[i] = d3.svg.arc().outerRadius(arcs[i].outerRadius()); 6.10375 + if (startAngle !== false) labelsArc[i].startAngle(startAngle); 6.10376 + if (endAngle !== false) labelsArc[i].endAngle(endAngle); 6.10377 + } 6.10378 + } else if (!donut) { 6.10379 + labelsArc[i].innerRadius(0); 6.10380 + } 6.10381 + } 6.10382 + 6.10383 + pieLabels.enter().append("g").classed("nv-label",true).each(function(d,i) { 6.10384 + var group = d3.select(this); 6.10385 + 6.10386 + group.attr('transform', function (d, i) { 6.10387 + if (labelSunbeamLayout) { 6.10388 + d.outerRadius = arcsRadiusOuter[i] + 10; // Set Outer Coordinate 6.10389 + d.innerRadius = arcsRadiusOuter[i] + 15; // Set Inner Coordinate 6.10390 + var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI); 6.10391 + if ((d.startAngle + d.endAngle) / 2 < Math.PI) { 6.10392 + rotateAngle -= 90; 6.10393 + } else { 6.10394 + rotateAngle += 90; 6.10395 + } 6.10396 + return 'translate(' + labelsArc[i].centroid(d) + ') rotate(' + rotateAngle + ')'; 6.10397 + } else { 6.10398 + d.outerRadius = radius + 10; // Set Outer Coordinate 6.10399 + d.innerRadius = radius + 15; // Set Inner Coordinate 6.10400 + return 'translate(' + labelsArc[i].centroid(d) + ')' 6.10401 + } 6.10402 + }); 6.10403 + 6.10404 + group.append('rect') 6.10405 + .style('stroke', '#fff') 6.10406 + .style('fill', '#fff') 6.10407 + .attr("rx", 3) 6.10408 + .attr("ry", 3); 6.10409 + 6.10410 + group.append('text') 6.10411 + .style('text-anchor', labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle') //center the text on it's origin or begin/end if orthogonal aligned 6.10412 + .style('fill', '#000') 6.10413 + }); 6.10414 + 6.10415 + var labelLocationHash = {}; 6.10416 + var avgHeight = 14; 6.10417 + var avgWidth = 140; 6.10418 + var createHashKey = function(coordinates) { 6.10419 + return Math.floor(coordinates[0]/avgWidth) * avgWidth + ',' + Math.floor(coordinates[1]/avgHeight) * avgHeight; 6.10420 + }; 6.10421 + 6.10422 + pieLabels.watchTransition(renderWatch, 'pie labels').attr('transform', function (d, i) { 6.10423 + if (labelSunbeamLayout) { 6.10424 + d.outerRadius = arcsRadiusOuter[i] + 10; // Set Outer Coordinate 6.10425 + d.innerRadius = arcsRadiusOuter[i] + 15; // Set Inner Coordinate 6.10426 + var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI); 6.10427 + if ((d.startAngle + d.endAngle) / 2 < Math.PI) { 6.10428 + rotateAngle -= 90; 6.10429 + } else { 6.10430 + rotateAngle += 90; 6.10431 + } 6.10432 + return 'translate(' + labelsArc[i].centroid(d) + ') rotate(' + rotateAngle + ')'; 6.10433 + } else { 6.10434 + d.outerRadius = radius + 10; // Set Outer Coordinate 6.10435 + d.innerRadius = radius + 15; // Set Inner Coordinate 6.10436 + 6.10437 + /* 6.10438 + Overlapping pie labels are not good. What this attempts to do is, prevent overlapping. 6.10439 + Each label location is hashed, and if a hash collision occurs, we assume an overlap. 6.10440 + Adjust the label's y-position to remove the overlap. 6.10441 + */ 6.10442 + var center = labelsArc[i].centroid(d); 6.10443 + if (d.value) { 6.10444 + var hashKey = createHashKey(center); 6.10445 + if (labelLocationHash[hashKey]) { 6.10446 + center[1] -= avgHeight; 6.10447 + } 6.10448 + labelLocationHash[createHashKey(center)] = true; 6.10449 + } 6.10450 + return 'translate(' + center + ')' 6.10451 + } 6.10452 + }); 6.10453 + 6.10454 + pieLabels.select(".nv-label text") 6.10455 + .style('text-anchor', function(d,i) { 6.10456 + //center the text on it's origin or begin/end if orthogonal aligned 6.10457 + return labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle'; 6.10458 + }) 6.10459 + .text(function(d, i) { 6.10460 + var percent = (d.endAngle - d.startAngle) / (2 * Math.PI); 6.10461 + var label = ''; 6.10462 + if (!d.value || percent < labelThreshold) return ''; 6.10463 + 6.10464 + if(typeof labelType === 'function') { 6.10465 + label = labelType(d, i, { 6.10466 + 'key': getX(d.data), 6.10467 + 'value': getY(d.data), 6.10468 + 'percent': valueFormat(percent) 6.10469 + }); 6.10470 + } else { 6.10471 + switch (labelType) { 6.10472 + case 'key': 6.10473 + label = getX(d.data); 6.10474 + break; 6.10475 + case 'value': 6.10476 + label = valueFormat(getY(d.data)); 6.10477 + break; 6.10478 + case 'percent': 6.10479 + label = d3.format('%')(percent); 6.10480 + break; 6.10481 + } 6.10482 + } 6.10483 + return label; 6.10484 + }) 6.10485 + ; 6.10486 + } 6.10487 + 6.10488 + 6.10489 + // Computes the angle of an arc, converting from radians to degrees. 6.10490 + function angle(d) { 6.10491 + var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90; 6.10492 + return a > 90 ? a - 180 : a; 6.10493 + } 6.10494 + 6.10495 + function arcTween(a, idx) { 6.10496 + a.endAngle = isNaN(a.endAngle) ? 0 : a.endAngle; 6.10497 + a.startAngle = isNaN(a.startAngle) ? 0 : a.startAngle; 6.10498 + if (!donut) a.innerRadius = 0; 6.10499 + var i = d3.interpolate(this._current, a); 6.10500 + this._current = i(0); 6.10501 + return function (t) { 6.10502 + return arcs[idx](i(t)); 6.10503 + }; 6.10504 + } 6.10505 + }); 6.10506 + 6.10507 + renderWatch.renderEnd('pie immediate'); 6.10508 + return chart; 6.10509 + } 6.10510 + 6.10511 + //============================================================ 6.10512 + // Expose Public Variables 6.10513 + //------------------------------------------------------------ 6.10514 + 6.10515 + chart.dispatch = dispatch; 6.10516 + chart.options = nv.utils.optionsFunc.bind(chart); 6.10517 + 6.10518 + chart._options = Object.create({}, { 6.10519 + // simple options, just get/set the necessary values 6.10520 + arcsRadius: { get: function () { return arcsRadius; }, set: function (_) { arcsRadius = _; } }, 6.10521 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.10522 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.10523 + showLabels: {get: function(){return showLabels;}, set: function(_){showLabels=_;}}, 6.10524 + title: {get: function(){return title;}, set: function(_){title=_;}}, 6.10525 + titleOffset: {get: function(){return titleOffset;}, set: function(_){titleOffset=_;}}, 6.10526 + labelThreshold: {get: function(){return labelThreshold;}, set: function(_){labelThreshold=_;}}, 6.10527 + valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}}, 6.10528 + x: {get: function(){return getX;}, set: function(_){getX=_;}}, 6.10529 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.10530 + endAngle: {get: function(){return endAngle;}, set: function(_){endAngle=_;}}, 6.10531 + startAngle: {get: function(){return startAngle;}, set: function(_){startAngle=_;}}, 6.10532 + padAngle: {get: function(){return padAngle;}, set: function(_){padAngle=_;}}, 6.10533 + cornerRadius: {get: function(){return cornerRadius;}, set: function(_){cornerRadius=_;}}, 6.10534 + donutRatio: {get: function(){return donutRatio;}, set: function(_){donutRatio=_;}}, 6.10535 + labelsOutside: {get: function(){return labelsOutside;}, set: function(_){labelsOutside=_;}}, 6.10536 + labelSunbeamLayout: {get: function(){return labelSunbeamLayout;}, set: function(_){labelSunbeamLayout=_;}}, 6.10537 + donut: {get: function(){return donut;}, set: function(_){donut=_;}}, 6.10538 + growOnHover: {get: function(){return growOnHover;}, set: function(_){growOnHover=_;}}, 6.10539 + 6.10540 + // depreciated after 1.7.1 6.10541 + pieLabelsOutside: {get: function(){return labelsOutside;}, set: function(_){ 6.10542 + labelsOutside=_; 6.10543 + nv.deprecated('pieLabelsOutside', 'use labelsOutside instead'); 6.10544 + }}, 6.10545 + // depreciated after 1.7.1 6.10546 + donutLabelsOutside: {get: function(){return labelsOutside;}, set: function(_){ 6.10547 + labelsOutside=_; 6.10548 + nv.deprecated('donutLabelsOutside', 'use labelsOutside instead'); 6.10549 + }}, 6.10550 + // deprecated after 1.7.1 6.10551 + labelFormat: {get: function(){ return valueFormat;}, set: function(_) { 6.10552 + valueFormat=_; 6.10553 + nv.deprecated('labelFormat','use valueFormat instead'); 6.10554 + }}, 6.10555 + 6.10556 + // options that require extra logic in the setter 6.10557 + margin: {get: function(){return margin;}, set: function(_){ 6.10558 + margin.top = typeof _.top != 'undefined' ? _.top : margin.top; 6.10559 + margin.right = typeof _.right != 'undefined' ? _.right : margin.right; 6.10560 + margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom; 6.10561 + margin.left = typeof _.left != 'undefined' ? _.left : margin.left; 6.10562 + }}, 6.10563 + y: {get: function(){return getY;}, set: function(_){ 6.10564 + getY=d3.functor(_); 6.10565 + }}, 6.10566 + color: {get: function(){return color;}, set: function(_){ 6.10567 + color=nv.utils.getColor(_); 6.10568 + }}, 6.10569 + labelType: {get: function(){return labelType;}, set: function(_){ 6.10570 + labelType= _ || 'key'; 6.10571 + }} 6.10572 + }); 6.10573 + 6.10574 + nv.utils.initOptions(chart); 6.10575 + return chart; 6.10576 +}; 6.10577 +nv.models.pieChart = function() { 6.10578 + "use strict"; 6.10579 + 6.10580 + //============================================================ 6.10581 + // Public Variables with Default Settings 6.10582 + //------------------------------------------------------------ 6.10583 + 6.10584 + var pie = nv.models.pie(); 6.10585 + var legend = nv.models.legend(); 6.10586 + var tooltip = nv.models.tooltip(); 6.10587 + 6.10588 + var margin = {top: 30, right: 20, bottom: 20, left: 20} 6.10589 + , width = null 6.10590 + , height = null 6.10591 + , showLegend = true 6.10592 + , legendPosition = "top" 6.10593 + , color = nv.utils.defaultColor() 6.10594 + , state = nv.utils.state() 6.10595 + , defaultState = null 6.10596 + , noData = null 6.10597 + , duration = 250 6.10598 + , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd') 6.10599 + ; 6.10600 + 6.10601 + tooltip 6.10602 + .headerEnabled(false) 6.10603 + .duration(0) 6.10604 + .valueFormatter(function(d, i) { 6.10605 + return pie.valueFormat()(d, i); 6.10606 + }); 6.10607 + 6.10608 + //============================================================ 6.10609 + // Private Variables 6.10610 + //------------------------------------------------------------ 6.10611 + 6.10612 + var renderWatch = nv.utils.renderWatch(dispatch); 6.10613 + 6.10614 + var stateGetter = function(data) { 6.10615 + return function(){ 6.10616 + return { 6.10617 + active: data.map(function(d) { return !d.disabled }) 6.10618 + }; 6.10619 + } 6.10620 + }; 6.10621 + 6.10622 + var stateSetter = function(data) { 6.10623 + return function(state) { 6.10624 + if (state.active !== undefined) { 6.10625 + data.forEach(function (series, i) { 6.10626 + series.disabled = !state.active[i]; 6.10627 + }); 6.10628 + } 6.10629 + } 6.10630 + }; 6.10631 + 6.10632 + //============================================================ 6.10633 + // Chart function 6.10634 + //------------------------------------------------------------ 6.10635 + 6.10636 + function chart(selection) { 6.10637 + renderWatch.reset(); 6.10638 + renderWatch.models(pie); 6.10639 + 6.10640 + selection.each(function(data) { 6.10641 + var container = d3.select(this); 6.10642 + nv.utils.initSVG(container); 6.10643 + 6.10644 + var that = this; 6.10645 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.10646 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.10647 + 6.10648 + chart.update = function() { container.transition().call(chart); }; 6.10649 + chart.container = this; 6.10650 + 6.10651 + state.setter(stateSetter(data), chart.update) 6.10652 + .getter(stateGetter(data)) 6.10653 + .update(); 6.10654 + 6.10655 + //set state.disabled 6.10656 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.10657 + 6.10658 + if (!defaultState) { 6.10659 + var key; 6.10660 + defaultState = {}; 6.10661 + for (key in state) { 6.10662 + if (state[key] instanceof Array) 6.10663 + defaultState[key] = state[key].slice(0); 6.10664 + else 6.10665 + defaultState[key] = state[key]; 6.10666 + } 6.10667 + } 6.10668 + 6.10669 + // Display No Data message if there's nothing to show. 6.10670 + if (!data || !data.length) { 6.10671 + nv.utils.noData(chart, container); 6.10672 + return chart; 6.10673 + } else { 6.10674 + container.selectAll('.nv-noData').remove(); 6.10675 + } 6.10676 + 6.10677 + // Setup containers and skeleton of chart 6.10678 + var wrap = container.selectAll('g.nv-wrap.nv-pieChart').data([data]); 6.10679 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-pieChart').append('g'); 6.10680 + var g = wrap.select('g'); 6.10681 + 6.10682 + gEnter.append('g').attr('class', 'nv-pieWrap'); 6.10683 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.10684 + 6.10685 + // Legend 6.10686 + if (showLegend) { 6.10687 + if (legendPosition === "top") { 6.10688 + legend.width( availableWidth ).key(pie.x()); 6.10689 + 6.10690 + wrap.select('.nv-legendWrap') 6.10691 + .datum(data) 6.10692 + .call(legend); 6.10693 + 6.10694 + if ( margin.top != legend.height()) { 6.10695 + margin.top = legend.height(); 6.10696 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.10697 + } 6.10698 + 6.10699 + wrap.select('.nv-legendWrap') 6.10700 + .attr('transform', 'translate(0,' + (-margin.top) +')'); 6.10701 + } else if (legendPosition === "right") { 6.10702 + var legendWidth = nv.models.legend().width(); 6.10703 + if (availableWidth / 2 < legendWidth) { 6.10704 + legendWidth = (availableWidth / 2) 6.10705 + } 6.10706 + legend.height(availableHeight).key(pie.x()); 6.10707 + legend.width(legendWidth); 6.10708 + availableWidth -= legend.width(); 6.10709 + 6.10710 + wrap.select('.nv-legendWrap') 6.10711 + .datum(data) 6.10712 + .call(legend) 6.10713 + .attr('transform', 'translate(' + (availableWidth) +',0)'); 6.10714 + } 6.10715 + } 6.10716 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.10717 + 6.10718 + // Main Chart Component(s) 6.10719 + pie.width(availableWidth).height(availableHeight); 6.10720 + var pieWrap = g.select('.nv-pieWrap').datum([data]); 6.10721 + d3.transition(pieWrap).call(pie); 6.10722 + 6.10723 + //============================================================ 6.10724 + // Event Handling/Dispatching (in chart's scope) 6.10725 + //------------------------------------------------------------ 6.10726 + 6.10727 + legend.dispatch.on('stateChange', function(newState) { 6.10728 + for (var key in newState) { 6.10729 + state[key] = newState[key]; 6.10730 + } 6.10731 + dispatch.stateChange(state); 6.10732 + chart.update(); 6.10733 + }); 6.10734 + 6.10735 + // Update chart from a state object passed to event handler 6.10736 + dispatch.on('changeState', function(e) { 6.10737 + if (typeof e.disabled !== 'undefined') { 6.10738 + data.forEach(function(series,i) { 6.10739 + series.disabled = e.disabled[i]; 6.10740 + }); 6.10741 + state.disabled = e.disabled; 6.10742 + } 6.10743 + chart.update(); 6.10744 + }); 6.10745 + }); 6.10746 + 6.10747 + renderWatch.renderEnd('pieChart immediate'); 6.10748 + return chart; 6.10749 + } 6.10750 + 6.10751 + //============================================================ 6.10752 + // Event Handling/Dispatching (out of chart's scope) 6.10753 + //------------------------------------------------------------ 6.10754 + 6.10755 + pie.dispatch.on('elementMouseover.tooltip', function(evt) { 6.10756 + evt['series'] = { 6.10757 + key: chart.x()(evt.data), 6.10758 + value: chart.y()(evt.data), 6.10759 + color: evt.color 6.10760 + }; 6.10761 + tooltip.data(evt).hidden(false); 6.10762 + }); 6.10763 + 6.10764 + pie.dispatch.on('elementMouseout.tooltip', function(evt) { 6.10765 + tooltip.hidden(true); 6.10766 + }); 6.10767 + 6.10768 + pie.dispatch.on('elementMousemove.tooltip', function(evt) { 6.10769 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.10770 + }); 6.10771 + 6.10772 + //============================================================ 6.10773 + // Expose Public Variables 6.10774 + //------------------------------------------------------------ 6.10775 + 6.10776 + // expose chart's sub-components 6.10777 + chart.legend = legend; 6.10778 + chart.dispatch = dispatch; 6.10779 + chart.pie = pie; 6.10780 + chart.tooltip = tooltip; 6.10781 + chart.options = nv.utils.optionsFunc.bind(chart); 6.10782 + 6.10783 + // use Object get/set functionality to map between vars and chart functions 6.10784 + chart._options = Object.create({}, { 6.10785 + // simple options, just get/set the necessary values 6.10786 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.10787 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.10788 + legendPosition: {get: function(){return legendPosition;}, set: function(_){legendPosition=_;}}, 6.10789 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.10790 + 6.10791 + // deprecated options 6.10792 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.10793 + // deprecated after 1.7.1 6.10794 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.10795 + tooltip.enabled(!!_); 6.10796 + }}, 6.10797 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.10798 + // deprecated after 1.7.1 6.10799 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.10800 + tooltip.contentGenerator(_); 6.10801 + }}, 6.10802 + 6.10803 + // options that require extra logic in the setter 6.10804 + color: {get: function(){return color;}, set: function(_){ 6.10805 + color = _; 6.10806 + legend.color(color); 6.10807 + pie.color(color); 6.10808 + }}, 6.10809 + duration: {get: function(){return duration;}, set: function(_){ 6.10810 + duration = _; 6.10811 + renderWatch.reset(duration); 6.10812 + }}, 6.10813 + margin: {get: function(){return margin;}, set: function(_){ 6.10814 + margin.top = _.top !== undefined ? _.top : margin.top; 6.10815 + margin.right = _.right !== undefined ? _.right : margin.right; 6.10816 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.10817 + margin.left = _.left !== undefined ? _.left : margin.left; 6.10818 + }} 6.10819 + }); 6.10820 + nv.utils.inheritOptions(chart, pie); 6.10821 + nv.utils.initOptions(chart); 6.10822 + return chart; 6.10823 +}; 6.10824 + 6.10825 +nv.models.scatter = function() { 6.10826 + "use strict"; 6.10827 + 6.10828 + //============================================================ 6.10829 + // Public Variables with Default Settings 6.10830 + //------------------------------------------------------------ 6.10831 + 6.10832 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.10833 + , width = null 6.10834 + , height = null 6.10835 + , color = nv.utils.defaultColor() // chooses color 6.10836 + , id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't select one 6.10837 + , container = null 6.10838 + , x = d3.scale.linear() 6.10839 + , y = d3.scale.linear() 6.10840 + , z = d3.scale.linear() //linear because d3.svg.shape.size is treated as area 6.10841 + , getX = function(d) { return d.x } // accessor to get the x value 6.10842 + , getY = function(d) { return d.y } // accessor to get the y value 6.10843 + , getSize = function(d) { return d.size || 1} // accessor to get the point size 6.10844 + , getShape = function(d) { return d.shape || 'circle' } // accessor to get point shape 6.10845 + , forceX = [] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.) 6.10846 + , forceY = [] // List of numbers to Force into the Y scale 6.10847 + , forceSize = [] // List of numbers to Force into the Size scale 6.10848 + , interactive = true // If true, plots a voronoi overlay for advanced point intersection 6.10849 + , pointActive = function(d) { return !d.notActive } // any points that return false will be filtered out 6.10850 + , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart 6.10851 + , padDataOuter = .1 //outerPadding to imitate ordinal scale outer padding 6.10852 + , clipEdge = false // if true, masks points within x and y scale 6.10853 + , clipVoronoi = true // if true, masks each point with a circle... can turn off to slightly increase performance 6.10854 + , showVoronoi = false // display the voronoi areas 6.10855 + , clipRadius = function() { return 25 } // function to get the radius for voronoi point clips 6.10856 + , xDomain = null // Override x domain (skips the calculation from data) 6.10857 + , yDomain = null // Override y domain 6.10858 + , xRange = null // Override x range 6.10859 + , yRange = null // Override y range 6.10860 + , sizeDomain = null // Override point size domain 6.10861 + , sizeRange = null 6.10862 + , singlePoint = false 6.10863 + , dispatch = d3.dispatch('elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'renderEnd') 6.10864 + , useVoronoi = true 6.10865 + , duration = 250 6.10866 + ; 6.10867 + 6.10868 + 6.10869 + //============================================================ 6.10870 + // Private Variables 6.10871 + //------------------------------------------------------------ 6.10872 + 6.10873 + var x0, y0, z0 // used to store previous scales 6.10874 + , timeoutID 6.10875 + , needsUpdate = false // Flag for when the points are visually updating, but the interactive layer is behind, to disable tooltips 6.10876 + , renderWatch = nv.utils.renderWatch(dispatch, duration) 6.10877 + , _sizeRange_def = [16, 256] 6.10878 + ; 6.10879 + 6.10880 + function chart(selection) { 6.10881 + renderWatch.reset(); 6.10882 + selection.each(function(data) { 6.10883 + container = d3.select(this); 6.10884 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.10885 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.10886 + 6.10887 + nv.utils.initSVG(container); 6.10888 + 6.10889 + //add series index to each data point for reference 6.10890 + data.forEach(function(series, i) { 6.10891 + series.values.forEach(function(point) { 6.10892 + point.series = i; 6.10893 + }); 6.10894 + }); 6.10895 + 6.10896 + // Setup Scales 6.10897 + // remap and flatten the data for use in calculating the scales' domains 6.10898 + var seriesData = (xDomain && yDomain && sizeDomain) ? [] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance 6.10899 + d3.merge( 6.10900 + data.map(function(d) { 6.10901 + return d.values.map(function(d,i) { 6.10902 + return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) } 6.10903 + }) 6.10904 + }) 6.10905 + ); 6.10906 + 6.10907 + x .domain(xDomain || d3.extent(seriesData.map(function(d) { return d.x; }).concat(forceX))) 6.10908 + 6.10909 + if (padData && data[0]) 6.10910 + x.range(xRange || [(availableWidth * padDataOuter + availableWidth) / (2 *data[0].values.length), availableWidth - availableWidth * (1 + padDataOuter) / (2 * data[0].values.length) ]); 6.10911 + //x.range([availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); 6.10912 + else 6.10913 + x.range(xRange || [0, availableWidth]); 6.10914 + 6.10915 + y .domain(yDomain || d3.extent(seriesData.map(function(d) { return d.y }).concat(forceY))) 6.10916 + .range(yRange || [availableHeight, 0]); 6.10917 + 6.10918 + z .domain(sizeDomain || d3.extent(seriesData.map(function(d) { return d.size }).concat(forceSize))) 6.10919 + .range(sizeRange || _sizeRange_def); 6.10920 + 6.10921 + // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point 6.10922 + singlePoint = x.domain()[0] === x.domain()[1] || y.domain()[0] === y.domain()[1]; 6.10923 + 6.10924 + if (x.domain()[0] === x.domain()[1]) 6.10925 + x.domain()[0] ? 6.10926 + x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) 6.10927 + : x.domain([-1,1]); 6.10928 + 6.10929 + if (y.domain()[0] === y.domain()[1]) 6.10930 + y.domain()[0] ? 6.10931 + y.domain([y.domain()[0] - y.domain()[0] * 0.01, y.domain()[1] + y.domain()[1] * 0.01]) 6.10932 + : y.domain([-1,1]); 6.10933 + 6.10934 + if ( isNaN(x.domain()[0])) { 6.10935 + x.domain([-1,1]); 6.10936 + } 6.10937 + 6.10938 + if ( isNaN(y.domain()[0])) { 6.10939 + y.domain([-1,1]); 6.10940 + } 6.10941 + 6.10942 + x0 = x0 || x; 6.10943 + y0 = y0 || y; 6.10944 + z0 = z0 || z; 6.10945 + 6.10946 + // Setup containers and skeleton of chart 6.10947 + var wrap = container.selectAll('g.nv-wrap.nv-scatter').data([data]); 6.10948 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatter nv-chart-' + id); 6.10949 + var defsEnter = wrapEnter.append('defs'); 6.10950 + var gEnter = wrapEnter.append('g'); 6.10951 + var g = wrap.select('g'); 6.10952 + 6.10953 + wrap.classed('nv-single-point', singlePoint); 6.10954 + gEnter.append('g').attr('class', 'nv-groups'); 6.10955 + gEnter.append('g').attr('class', 'nv-point-paths'); 6.10956 + wrapEnter.append('g').attr('class', 'nv-point-clips'); 6.10957 + 6.10958 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.10959 + 6.10960 + defsEnter.append('clipPath') 6.10961 + .attr('id', 'nv-edge-clip-' + id) 6.10962 + .append('rect'); 6.10963 + 6.10964 + wrap.select('#nv-edge-clip-' + id + ' rect') 6.10965 + .attr('width', availableWidth) 6.10966 + .attr('height', (availableHeight > 0) ? availableHeight : 0); 6.10967 + 6.10968 + g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : ''); 6.10969 + 6.10970 + function updateInteractiveLayer() { 6.10971 + // Always clear needs-update flag regardless of whether or not 6.10972 + // we will actually do anything (avoids needless invocations). 6.10973 + needsUpdate = false; 6.10974 + 6.10975 + if (!interactive) return false; 6.10976 + 6.10977 + // inject series and point index for reference into voronoi 6.10978 + if (useVoronoi === true) { 6.10979 + var vertices = d3.merge(data.map(function(group, groupIndex) { 6.10980 + return group.values 6.10981 + .map(function(point, pointIndex) { 6.10982 + // *Adding noise to make duplicates very unlikely 6.10983 + // *Injecting series and point index for reference 6.10984 + /* *Adding a 'jitter' to the points, because there's an issue in d3.geom.voronoi. 6.10985 + */ 6.10986 + var pX = getX(point,pointIndex); 6.10987 + var pY = getY(point,pointIndex); 6.10988 + 6.10989 + return [x(pX)+ Math.random() * 1e-4, 6.10990 + y(pY)+ Math.random() * 1e-4, 6.10991 + groupIndex, 6.10992 + pointIndex, point]; //temp hack to add noise until I think of a better way so there are no duplicates 6.10993 + }) 6.10994 + .filter(function(pointArray, pointIndex) { 6.10995 + return pointActive(pointArray[4], pointIndex); // Issue #237.. move filter to after map, so pointIndex is correct! 6.10996 + }) 6.10997 + }) 6.10998 + ); 6.10999 + 6.11000 + if (vertices.length == 0) return false; // No active points, we're done 6.11001 + if (vertices.length < 3) { 6.11002 + // Issue #283 - Adding 2 dummy points to the voronoi b/c voronoi requires min 3 points to work 6.11003 + vertices.push([x.range()[0] - 20, y.range()[0] - 20, null, null]); 6.11004 + vertices.push([x.range()[1] + 20, y.range()[1] + 20, null, null]); 6.11005 + vertices.push([x.range()[0] - 20, y.range()[0] + 20, null, null]); 6.11006 + vertices.push([x.range()[1] + 20, y.range()[1] - 20, null, null]); 6.11007 + } 6.11008 + 6.11009 + // keep voronoi sections from going more than 10 outside of graph 6.11010 + // to avoid overlap with other things like legend etc 6.11011 + var bounds = d3.geom.polygon([ 6.11012 + [-10,-10], 6.11013 + [-10,height + 10], 6.11014 + [width + 10,height + 10], 6.11015 + [width + 10,-10] 6.11016 + ]); 6.11017 + 6.11018 + var voronoi = d3.geom.voronoi(vertices).map(function(d, i) { 6.11019 + return { 6.11020 + 'data': bounds.clip(d), 6.11021 + 'series': vertices[i][2], 6.11022 + 'point': vertices[i][3] 6.11023 + } 6.11024 + }); 6.11025 + 6.11026 + // nuke all voronoi paths on reload and recreate them 6.11027 + wrap.select('.nv-point-paths').selectAll('path').remove(); 6.11028 + var pointPaths = wrap.select('.nv-point-paths').selectAll('path').data(voronoi); 6.11029 + var vPointPaths = pointPaths 6.11030 + .enter().append("svg:path") 6.11031 + .attr("d", function(d) { 6.11032 + if (!d || !d.data || d.data.length === 0) 6.11033 + return 'M 0 0'; 6.11034 + else 6.11035 + return "M" + d.data.join(",") + "Z"; 6.11036 + }) 6.11037 + .attr("id", function(d,i) { 6.11038 + return "nv-path-"+i; }) 6.11039 + .attr("clip-path", function(d,i) { return "url(#nv-clip-"+i+")"; }) 6.11040 + ; 6.11041 + 6.11042 + // good for debugging point hover issues 6.11043 + if (showVoronoi) { 6.11044 + vPointPaths.style("fill", d3.rgb(230, 230, 230)) 6.11045 + .style('fill-opacity', 0.4) 6.11046 + .style('stroke-opacity', 1) 6.11047 + .style("stroke", d3.rgb(200,200,200)); 6.11048 + } 6.11049 + 6.11050 + if (clipVoronoi) { 6.11051 + // voronoi sections are already set to clip, 6.11052 + // just create the circles with the IDs they expect 6.11053 + wrap.select('.nv-point-clips').selectAll('clipPath').remove(); 6.11054 + wrap.select('.nv-point-clips').selectAll("clipPath") 6.11055 + .data(vertices) 6.11056 + .enter().append("svg:clipPath") 6.11057 + .attr("id", function(d, i) { return "nv-clip-"+i;}) 6.11058 + .append("svg:circle") 6.11059 + .attr('cx', function(d) { return d[0]; }) 6.11060 + .attr('cy', function(d) { return d[1]; }) 6.11061 + .attr('r', clipRadius); 6.11062 + } 6.11063 + 6.11064 + var mouseEventCallback = function(d, mDispatch) { 6.11065 + if (needsUpdate) return 0; 6.11066 + var series = data[d.series]; 6.11067 + if (series === undefined) return; 6.11068 + var point = series.values[d.point]; 6.11069 + point['color'] = color(series, d.series); 6.11070 + 6.11071 + // standardize attributes for tooltip. 6.11072 + point['x'] = getX(point); 6.11073 + point['y'] = getY(point); 6.11074 + 6.11075 + // can't just get box of event node since it's actually a voronoi polygon 6.11076 + var box = container.node().getBoundingClientRect(); 6.11077 + var scrollTop = window.pageYOffset || document.documentElement.scrollTop; 6.11078 + var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; 6.11079 + 6.11080 + var pos = { 6.11081 + left: x(getX(point, d.point)) + box.left + scrollLeft + margin.left + 10, 6.11082 + top: y(getY(point, d.point)) + box.top + scrollTop + margin.top + 10 6.11083 + }; 6.11084 + 6.11085 + mDispatch({ 6.11086 + point: point, 6.11087 + series: series, 6.11088 + pos: pos, 6.11089 + seriesIndex: d.series, 6.11090 + pointIndex: d.point 6.11091 + }); 6.11092 + }; 6.11093 + 6.11094 + pointPaths 6.11095 + .on('click', function(d) { 6.11096 + mouseEventCallback(d, dispatch.elementClick); 6.11097 + }) 6.11098 + .on('dblclick', function(d) { 6.11099 + mouseEventCallback(d, dispatch.elementDblClick); 6.11100 + }) 6.11101 + .on('mouseover', function(d) { 6.11102 + mouseEventCallback(d, dispatch.elementMouseover); 6.11103 + }) 6.11104 + .on('mouseout', function(d, i) { 6.11105 + mouseEventCallback(d, dispatch.elementMouseout); 6.11106 + }); 6.11107 + 6.11108 + } else { 6.11109 + // add event handlers to points instead voronoi paths 6.11110 + wrap.select('.nv-groups').selectAll('.nv-group') 6.11111 + .selectAll('.nv-point') 6.11112 + //.data(dataWithPoints) 6.11113 + //.style('pointer-events', 'auto') // recativate events, disabled by css 6.11114 + .on('click', function(d,i) { 6.11115 + //nv.log('test', d, i); 6.11116 + if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point 6.11117 + var series = data[d.series], 6.11118 + point = series.values[i]; 6.11119 + 6.11120 + dispatch.elementClick({ 6.11121 + point: point, 6.11122 + series: series, 6.11123 + pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top], 6.11124 + seriesIndex: d.series, 6.11125 + pointIndex: i 6.11126 + }); 6.11127 + }) 6.11128 + .on('dblclick', function(d,i) { 6.11129 + if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point 6.11130 + var series = data[d.series], 6.11131 + point = series.values[i]; 6.11132 + 6.11133 + dispatch.elementDblClick({ 6.11134 + point: point, 6.11135 + series: series, 6.11136 + pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top], 6.11137 + seriesIndex: d.series, 6.11138 + pointIndex: i 6.11139 + }); 6.11140 + }) 6.11141 + .on('mouseover', function(d,i) { 6.11142 + if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point 6.11143 + var series = data[d.series], 6.11144 + point = series.values[i]; 6.11145 + 6.11146 + dispatch.elementMouseover({ 6.11147 + point: point, 6.11148 + series: series, 6.11149 + pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top], 6.11150 + seriesIndex: d.series, 6.11151 + pointIndex: i, 6.11152 + color: color(d, i) 6.11153 + }); 6.11154 + }) 6.11155 + .on('mouseout', function(d,i) { 6.11156 + if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point 6.11157 + var series = data[d.series], 6.11158 + point = series.values[i]; 6.11159 + 6.11160 + dispatch.elementMouseout({ 6.11161 + point: point, 6.11162 + series: series, 6.11163 + seriesIndex: d.series, 6.11164 + pointIndex: i, 6.11165 + color: color(d, i) 6.11166 + }); 6.11167 + }); 6.11168 + } 6.11169 + } 6.11170 + 6.11171 + needsUpdate = true; 6.11172 + var groups = wrap.select('.nv-groups').selectAll('.nv-group') 6.11173 + .data(function(d) { return d }, function(d) { return d.key }); 6.11174 + groups.enter().append('g') 6.11175 + .style('stroke-opacity', 1e-6) 6.11176 + .style('fill-opacity', 1e-6); 6.11177 + groups.exit() 6.11178 + .remove(); 6.11179 + groups 6.11180 + .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) 6.11181 + .classed('hover', function(d) { return d.hover }); 6.11182 + groups.watchTransition(renderWatch, 'scatter: groups') 6.11183 + .style('fill', function(d,i) { return color(d, i) }) 6.11184 + .style('stroke', function(d,i) { return color(d, i) }) 6.11185 + .style('stroke-opacity', 1) 6.11186 + .style('fill-opacity', .5); 6.11187 + 6.11188 + // create the points, maintaining their IDs from the original data set 6.11189 + var points = groups.selectAll('path.nv-point') 6.11190 + .data(function(d) { 6.11191 + return d.values.map( 6.11192 + function (point, pointIndex) { 6.11193 + return [point, pointIndex] 6.11194 + }).filter( 6.11195 + function(pointArray, pointIndex) { 6.11196 + return pointActive(pointArray[0], pointIndex) 6.11197 + }) 6.11198 + }); 6.11199 + points.enter().append('path') 6.11200 + .style('fill', function (d) { return d.color }) 6.11201 + .style('stroke', function (d) { return d.color }) 6.11202 + .attr('transform', function(d) { 6.11203 + return 'translate(' + x0(getX(d[0],d[1])) + ',' + y0(getY(d[0],d[1])) + ')' 6.11204 + }) 6.11205 + .attr('d', 6.11206 + nv.utils.symbol() 6.11207 + .type(function(d) { return getShape(d[0]); }) 6.11208 + .size(function(d) { return z(getSize(d[0],d[1])) }) 6.11209 + ); 6.11210 + points.exit().remove(); 6.11211 + groups.exit().selectAll('path.nv-point') 6.11212 + .watchTransition(renderWatch, 'scatter exit') 6.11213 + .attr('transform', function(d) { 6.11214 + return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')' 6.11215 + }) 6.11216 + .remove(); 6.11217 + points.each(function(d) { 6.11218 + d3.select(this) 6.11219 + .classed('nv-point', true) 6.11220 + .classed('nv-point-' + d[1], true) 6.11221 + .classed('nv-noninteractive', !interactive) 6.11222 + .classed('hover',false) 6.11223 + ; 6.11224 + }); 6.11225 + points 6.11226 + .watchTransition(renderWatch, 'scatter points') 6.11227 + .attr('transform', function(d) { 6.11228 + //nv.log(d, getX(d[0],d[1]), x(getX(d[0],d[1]))); 6.11229 + return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')' 6.11230 + }) 6.11231 + .attr('d', 6.11232 + nv.utils.symbol() 6.11233 + .type(function(d) { return getShape(d[0]); }) 6.11234 + .size(function(d) { return z(getSize(d[0],d[1])) }) 6.11235 + ); 6.11236 + 6.11237 + // Delay updating the invisible interactive layer for smoother animation 6.11238 + clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer 6.11239 + timeoutID = setTimeout(updateInteractiveLayer, 300); 6.11240 + //updateInteractiveLayer(); 6.11241 + 6.11242 + //store old scales for use in transitions on update 6.11243 + x0 = x.copy(); 6.11244 + y0 = y.copy(); 6.11245 + z0 = z.copy(); 6.11246 + 6.11247 + }); 6.11248 + renderWatch.renderEnd('scatter immediate'); 6.11249 + return chart; 6.11250 + } 6.11251 + 6.11252 + //============================================================ 6.11253 + // Expose Public Variables 6.11254 + //------------------------------------------------------------ 6.11255 + 6.11256 + chart.dispatch = dispatch; 6.11257 + chart.options = nv.utils.optionsFunc.bind(chart); 6.11258 + 6.11259 + // utility function calls provided by this chart 6.11260 + chart._calls = new function() { 6.11261 + this.clearHighlights = function () { 6.11262 + nv.dom.write(function() { 6.11263 + container.selectAll(".nv-point.hover").classed("hover", false); 6.11264 + }); 6.11265 + return null; 6.11266 + }; 6.11267 + this.highlightPoint = function (seriesIndex, pointIndex, isHoverOver) { 6.11268 + nv.dom.write(function() { 6.11269 + container.select(" .nv-series-" + seriesIndex + " .nv-point-" + pointIndex) 6.11270 + .classed("hover", isHoverOver); 6.11271 + }); 6.11272 + }; 6.11273 + }; 6.11274 + 6.11275 + // trigger calls from events too 6.11276 + dispatch.on('elementMouseover.point', function(d) { 6.11277 + if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,true); 6.11278 + }); 6.11279 + 6.11280 + dispatch.on('elementMouseout.point', function(d) { 6.11281 + if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,false); 6.11282 + }); 6.11283 + 6.11284 + chart._options = Object.create({}, { 6.11285 + // simple options, just get/set the necessary values 6.11286 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.11287 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.11288 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.11289 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.11290 + pointScale: {get: function(){return z;}, set: function(_){z=_;}}, 6.11291 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.11292 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.11293 + pointDomain: {get: function(){return sizeDomain;}, set: function(_){sizeDomain=_;}}, 6.11294 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.11295 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.11296 + pointRange: {get: function(){return sizeRange;}, set: function(_){sizeRange=_;}}, 6.11297 + forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, 6.11298 + forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, 6.11299 + forcePoint: {get: function(){return forceSize;}, set: function(_){forceSize=_;}}, 6.11300 + interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, 6.11301 + pointActive: {get: function(){return pointActive;}, set: function(_){pointActive=_;}}, 6.11302 + padDataOuter: {get: function(){return padDataOuter;}, set: function(_){padDataOuter=_;}}, 6.11303 + padData: {get: function(){return padData;}, set: function(_){padData=_;}}, 6.11304 + clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, 6.11305 + clipVoronoi: {get: function(){return clipVoronoi;}, set: function(_){clipVoronoi=_;}}, 6.11306 + clipRadius: {get: function(){return clipRadius;}, set: function(_){clipRadius=_;}}, 6.11307 + showVoronoi: {get: function(){return showVoronoi;}, set: function(_){showVoronoi=_;}}, 6.11308 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.11309 + 6.11310 + 6.11311 + // simple functor options 6.11312 + x: {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}}, 6.11313 + y: {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}}, 6.11314 + pointSize: {get: function(){return getSize;}, set: function(_){getSize = d3.functor(_);}}, 6.11315 + pointShape: {get: function(){return getShape;}, set: function(_){getShape = d3.functor(_);}}, 6.11316 + 6.11317 + // options that require extra logic in the setter 6.11318 + margin: {get: function(){return margin;}, set: function(_){ 6.11319 + margin.top = _.top !== undefined ? _.top : margin.top; 6.11320 + margin.right = _.right !== undefined ? _.right : margin.right; 6.11321 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.11322 + margin.left = _.left !== undefined ? _.left : margin.left; 6.11323 + }}, 6.11324 + duration: {get: function(){return duration;}, set: function(_){ 6.11325 + duration = _; 6.11326 + renderWatch.reset(duration); 6.11327 + }}, 6.11328 + color: {get: function(){return color;}, set: function(_){ 6.11329 + color = nv.utils.getColor(_); 6.11330 + }}, 6.11331 + useVoronoi: {get: function(){return useVoronoi;}, set: function(_){ 6.11332 + useVoronoi = _; 6.11333 + if (useVoronoi === false) { 6.11334 + clipVoronoi = false; 6.11335 + } 6.11336 + }} 6.11337 + }); 6.11338 + 6.11339 + nv.utils.initOptions(chart); 6.11340 + return chart; 6.11341 +}; 6.11342 + 6.11343 +nv.models.scatterChart = function() { 6.11344 + "use strict"; 6.11345 + 6.11346 + //============================================================ 6.11347 + // Public Variables with Default Settings 6.11348 + //------------------------------------------------------------ 6.11349 + 6.11350 + var scatter = nv.models.scatter() 6.11351 + , xAxis = nv.models.axis() 6.11352 + , yAxis = nv.models.axis() 6.11353 + , legend = nv.models.legend() 6.11354 + , distX = nv.models.distribution() 6.11355 + , distY = nv.models.distribution() 6.11356 + , tooltip = nv.models.tooltip() 6.11357 + ; 6.11358 + 6.11359 + var margin = {top: 30, right: 20, bottom: 50, left: 75} 6.11360 + , width = null 6.11361 + , height = null 6.11362 + , container = null 6.11363 + , color = nv.utils.defaultColor() 6.11364 + , x = scatter.xScale() 6.11365 + , y = scatter.yScale() 6.11366 + , showDistX = false 6.11367 + , showDistY = false 6.11368 + , showLegend = true 6.11369 + , showXAxis = true 6.11370 + , showYAxis = true 6.11371 + , rightAlignYAxis = false 6.11372 + , state = nv.utils.state() 6.11373 + , defaultState = null 6.11374 + , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd') 6.11375 + , noData = null 6.11376 + , duration = 250 6.11377 + ; 6.11378 + 6.11379 + scatter.xScale(x).yScale(y); 6.11380 + xAxis.orient('bottom').tickPadding(10); 6.11381 + yAxis 6.11382 + .orient((rightAlignYAxis) ? 'right' : 'left') 6.11383 + .tickPadding(10) 6.11384 + ; 6.11385 + distX.axis('x'); 6.11386 + distY.axis('y'); 6.11387 + tooltip 6.11388 + .headerFormatter(function(d, i) { 6.11389 + return xAxis.tickFormat()(d, i); 6.11390 + }) 6.11391 + .valueFormatter(function(d, i) { 6.11392 + return yAxis.tickFormat()(d, i); 6.11393 + }); 6.11394 + 6.11395 + //============================================================ 6.11396 + // Private Variables 6.11397 + //------------------------------------------------------------ 6.11398 + 6.11399 + var x0, y0 6.11400 + , renderWatch = nv.utils.renderWatch(dispatch, duration); 6.11401 + 6.11402 + var stateGetter = function(data) { 6.11403 + return function(){ 6.11404 + return { 6.11405 + active: data.map(function(d) { return !d.disabled }) 6.11406 + }; 6.11407 + } 6.11408 + }; 6.11409 + 6.11410 + var stateSetter = function(data) { 6.11411 + return function(state) { 6.11412 + if (state.active !== undefined) 6.11413 + data.forEach(function(series,i) { 6.11414 + series.disabled = !state.active[i]; 6.11415 + }); 6.11416 + } 6.11417 + }; 6.11418 + 6.11419 + function chart(selection) { 6.11420 + renderWatch.reset(); 6.11421 + renderWatch.models(scatter); 6.11422 + if (showXAxis) renderWatch.models(xAxis); 6.11423 + if (showYAxis) renderWatch.models(yAxis); 6.11424 + if (showDistX) renderWatch.models(distX); 6.11425 + if (showDistY) renderWatch.models(distY); 6.11426 + 6.11427 + selection.each(function(data) { 6.11428 + var that = this; 6.11429 + 6.11430 + container = d3.select(this); 6.11431 + nv.utils.initSVG(container); 6.11432 + 6.11433 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.11434 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.11435 + 6.11436 + chart.update = function() { 6.11437 + if (duration === 0) 6.11438 + container.call(chart); 6.11439 + else 6.11440 + container.transition().duration(duration).call(chart); 6.11441 + }; 6.11442 + chart.container = this; 6.11443 + 6.11444 + state 6.11445 + .setter(stateSetter(data), chart.update) 6.11446 + .getter(stateGetter(data)) 6.11447 + .update(); 6.11448 + 6.11449 + // DEPRECATED set state.disableddisabled 6.11450 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.11451 + 6.11452 + if (!defaultState) { 6.11453 + var key; 6.11454 + defaultState = {}; 6.11455 + for (key in state) { 6.11456 + if (state[key] instanceof Array) 6.11457 + defaultState[key] = state[key].slice(0); 6.11458 + else 6.11459 + defaultState[key] = state[key]; 6.11460 + } 6.11461 + } 6.11462 + 6.11463 + // Display noData message if there's nothing to show. 6.11464 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.11465 + nv.utils.noData(chart, container); 6.11466 + renderWatch.renderEnd('scatter immediate'); 6.11467 + return chart; 6.11468 + } else { 6.11469 + container.selectAll('.nv-noData').remove(); 6.11470 + } 6.11471 + 6.11472 + // Setup Scales 6.11473 + x = scatter.xScale(); 6.11474 + y = scatter.yScale(); 6.11475 + 6.11476 + // Setup containers and skeleton of chart 6.11477 + var wrap = container.selectAll('g.nv-wrap.nv-scatterChart').data([data]); 6.11478 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatterChart nv-chart-' + scatter.id()); 6.11479 + var gEnter = wrapEnter.append('g'); 6.11480 + var g = wrap.select('g'); 6.11481 + 6.11482 + // background for pointer events 6.11483 + gEnter.append('rect').attr('class', 'nvd3 nv-background').style("pointer-events","none"); 6.11484 + 6.11485 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.11486 + gEnter.append('g').attr('class', 'nv-y nv-axis'); 6.11487 + gEnter.append('g').attr('class', 'nv-scatterWrap'); 6.11488 + gEnter.append('g').attr('class', 'nv-regressionLinesWrap'); 6.11489 + gEnter.append('g').attr('class', 'nv-distWrap'); 6.11490 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.11491 + 6.11492 + if (rightAlignYAxis) { 6.11493 + g.select(".nv-y.nv-axis") 6.11494 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.11495 + } 6.11496 + 6.11497 + // Legend 6.11498 + if (showLegend) { 6.11499 + var legendWidth = availableWidth; 6.11500 + legend.width(legendWidth); 6.11501 + 6.11502 + wrap.select('.nv-legendWrap') 6.11503 + .datum(data) 6.11504 + .call(legend); 6.11505 + 6.11506 + if ( margin.top != legend.height()) { 6.11507 + margin.top = legend.height(); 6.11508 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.11509 + } 6.11510 + 6.11511 + wrap.select('.nv-legendWrap') 6.11512 + .attr('transform', 'translate(0' + ',' + (-margin.top) +')'); 6.11513 + } 6.11514 + 6.11515 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.11516 + 6.11517 + // Main Chart Component(s) 6.11518 + scatter 6.11519 + .width(availableWidth) 6.11520 + .height(availableHeight) 6.11521 + .color(data.map(function(d,i) { 6.11522 + d.color = d.color || color(d, i); 6.11523 + return d.color; 6.11524 + }).filter(function(d,i) { return !data[i].disabled })); 6.11525 + 6.11526 + wrap.select('.nv-scatterWrap') 6.11527 + .datum(data.filter(function(d) { return !d.disabled })) 6.11528 + .call(scatter); 6.11529 + 6.11530 + 6.11531 + wrap.select('.nv-regressionLinesWrap') 6.11532 + .attr('clip-path', 'url(#nv-edge-clip-' + scatter.id() + ')'); 6.11533 + 6.11534 + var regWrap = wrap.select('.nv-regressionLinesWrap').selectAll('.nv-regLines') 6.11535 + .data(function (d) { 6.11536 + return d; 6.11537 + }); 6.11538 + 6.11539 + regWrap.enter().append('g').attr('class', 'nv-regLines'); 6.11540 + 6.11541 + var regLine = regWrap.selectAll('.nv-regLine') 6.11542 + .data(function (d) { 6.11543 + return [d] 6.11544 + }); 6.11545 + 6.11546 + regLine.enter() 6.11547 + .append('line').attr('class', 'nv-regLine') 6.11548 + .style('stroke-opacity', 0); 6.11549 + 6.11550 + // don't add lines unless we have slope and intercept to use 6.11551 + regLine.filter(function(d) { 6.11552 + return d.intercept && d.slope; 6.11553 + }) 6.11554 + .watchTransition(renderWatch, 'scatterPlusLineChart: regline') 6.11555 + .attr('x1', x.range()[0]) 6.11556 + .attr('x2', x.range()[1]) 6.11557 + .attr('y1', function (d, i) { 6.11558 + return y(x.domain()[0] * d.slope + d.intercept) 6.11559 + }) 6.11560 + .attr('y2', function (d, i) { 6.11561 + return y(x.domain()[1] * d.slope + d.intercept) 6.11562 + }) 6.11563 + .style('stroke', function (d, i, j) { 6.11564 + return color(d, j) 6.11565 + }) 6.11566 + .style('stroke-opacity', function (d, i) { 6.11567 + return (d.disabled || typeof d.slope === 'undefined' || typeof d.intercept === 'undefined') ? 0 : 1 6.11568 + }); 6.11569 + 6.11570 + // Setup Axes 6.11571 + if (showXAxis) { 6.11572 + xAxis 6.11573 + .scale(x) 6.11574 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.11575 + .tickSize( -availableHeight , 0); 6.11576 + 6.11577 + g.select('.nv-x.nv-axis') 6.11578 + .attr('transform', 'translate(0,' + y.range()[0] + ')') 6.11579 + .call(xAxis); 6.11580 + } 6.11581 + 6.11582 + if (showYAxis) { 6.11583 + yAxis 6.11584 + .scale(y) 6.11585 + ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) 6.11586 + .tickSize( -availableWidth, 0); 6.11587 + 6.11588 + g.select('.nv-y.nv-axis') 6.11589 + .call(yAxis); 6.11590 + } 6.11591 + 6.11592 + 6.11593 + if (showDistX) { 6.11594 + distX 6.11595 + .getData(scatter.x()) 6.11596 + .scale(x) 6.11597 + .width(availableWidth) 6.11598 + .color(data.map(function(d,i) { 6.11599 + return d.color || color(d, i); 6.11600 + }).filter(function(d,i) { return !data[i].disabled })); 6.11601 + gEnter.select('.nv-distWrap').append('g') 6.11602 + .attr('class', 'nv-distributionX'); 6.11603 + g.select('.nv-distributionX') 6.11604 + .attr('transform', 'translate(0,' + y.range()[0] + ')') 6.11605 + .datum(data.filter(function(d) { return !d.disabled })) 6.11606 + .call(distX); 6.11607 + } 6.11608 + 6.11609 + if (showDistY) { 6.11610 + distY 6.11611 + .getData(scatter.y()) 6.11612 + .scale(y) 6.11613 + .width(availableHeight) 6.11614 + .color(data.map(function(d,i) { 6.11615 + return d.color || color(d, i); 6.11616 + }).filter(function(d,i) { return !data[i].disabled })); 6.11617 + gEnter.select('.nv-distWrap').append('g') 6.11618 + .attr('class', 'nv-distributionY'); 6.11619 + g.select('.nv-distributionY') 6.11620 + .attr('transform', 'translate(' + (rightAlignYAxis ? availableWidth : -distY.size() ) + ',0)') 6.11621 + .datum(data.filter(function(d) { return !d.disabled })) 6.11622 + .call(distY); 6.11623 + } 6.11624 + 6.11625 + //============================================================ 6.11626 + // Event Handling/Dispatching (in chart's scope) 6.11627 + //------------------------------------------------------------ 6.11628 + 6.11629 + legend.dispatch.on('stateChange', function(newState) { 6.11630 + for (var key in newState) 6.11631 + state[key] = newState[key]; 6.11632 + dispatch.stateChange(state); 6.11633 + chart.update(); 6.11634 + }); 6.11635 + 6.11636 + // Update chart from a state object passed to event handler 6.11637 + dispatch.on('changeState', function(e) { 6.11638 + if (typeof e.disabled !== 'undefined') { 6.11639 + data.forEach(function(series,i) { 6.11640 + series.disabled = e.disabled[i]; 6.11641 + }); 6.11642 + state.disabled = e.disabled; 6.11643 + } 6.11644 + chart.update(); 6.11645 + }); 6.11646 + 6.11647 + // mouseover needs availableHeight so we just keep scatter mouse events inside the chart block 6.11648 + scatter.dispatch.on('elementMouseout.tooltip', function(evt) { 6.11649 + tooltip.hidden(true); 6.11650 + container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex) 6.11651 + .attr('y1', 0); 6.11652 + container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex) 6.11653 + .attr('x2', distY.size()); 6.11654 + }); 6.11655 + 6.11656 + scatter.dispatch.on('elementMouseover.tooltip', function(evt) { 6.11657 + container.select('.nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex) 6.11658 + .attr('y1', evt.pos.top - availableHeight - margin.top); 6.11659 + container.select('.nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex) 6.11660 + .attr('x2', evt.pos.left + distX.size() - margin.left); 6.11661 + tooltip.position(evt.pos).data(evt).hidden(false); 6.11662 + }); 6.11663 + 6.11664 + //store old scales for use in transitions on update 6.11665 + x0 = x.copy(); 6.11666 + y0 = y.copy(); 6.11667 + 6.11668 + }); 6.11669 + 6.11670 + renderWatch.renderEnd('scatter with line immediate'); 6.11671 + return chart; 6.11672 + } 6.11673 + 6.11674 + //============================================================ 6.11675 + // Expose Public Variables 6.11676 + //------------------------------------------------------------ 6.11677 + 6.11678 + // expose chart's sub-components 6.11679 + chart.dispatch = dispatch; 6.11680 + chart.scatter = scatter; 6.11681 + chart.legend = legend; 6.11682 + chart.xAxis = xAxis; 6.11683 + chart.yAxis = yAxis; 6.11684 + chart.distX = distX; 6.11685 + chart.distY = distY; 6.11686 + chart.tooltip = tooltip; 6.11687 + 6.11688 + chart.options = nv.utils.optionsFunc.bind(chart); 6.11689 + chart._options = Object.create({}, { 6.11690 + // simple options, just get/set the necessary values 6.11691 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.11692 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.11693 + container: {get: function(){return container;}, set: function(_){container=_;}}, 6.11694 + showDistX: {get: function(){return showDistX;}, set: function(_){showDistX=_;}}, 6.11695 + showDistY: {get: function(){return showDistY;}, set: function(_){showDistY=_;}}, 6.11696 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.11697 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.11698 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.11699 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.11700 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.11701 + duration: {get: function(){return duration;}, set: function(_){duration=_;}}, 6.11702 + 6.11703 + // deprecated options 6.11704 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.11705 + // deprecated after 1.7.1 6.11706 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.11707 + tooltip.enabled(!!_); 6.11708 + }}, 6.11709 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.11710 + // deprecated after 1.7.1 6.11711 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.11712 + tooltip.contentGenerator(_); 6.11713 + }}, 6.11714 + tooltipXContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.11715 + // deprecated after 1.7.1 6.11716 + nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.'); 6.11717 + }}, 6.11718 + tooltipYContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.11719 + // deprecated after 1.7.1 6.11720 + nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.'); 6.11721 + }}, 6.11722 + 6.11723 + // options that require extra logic in the setter 6.11724 + margin: {get: function(){return margin;}, set: function(_){ 6.11725 + margin.top = _.top !== undefined ? _.top : margin.top; 6.11726 + margin.right = _.right !== undefined ? _.right : margin.right; 6.11727 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.11728 + margin.left = _.left !== undefined ? _.left : margin.left; 6.11729 + }}, 6.11730 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.11731 + rightAlignYAxis = _; 6.11732 + yAxis.orient( (_) ? 'right' : 'left'); 6.11733 + }}, 6.11734 + color: {get: function(){return color;}, set: function(_){ 6.11735 + color = nv.utils.getColor(_); 6.11736 + legend.color(color); 6.11737 + distX.color(color); 6.11738 + distY.color(color); 6.11739 + }} 6.11740 + }); 6.11741 + 6.11742 + nv.utils.inheritOptions(chart, scatter); 6.11743 + nv.utils.initOptions(chart); 6.11744 + return chart; 6.11745 +}; 6.11746 + 6.11747 +nv.models.sparkline = function() { 6.11748 + "use strict"; 6.11749 + 6.11750 + //============================================================ 6.11751 + // Public Variables with Default Settings 6.11752 + //------------------------------------------------------------ 6.11753 + 6.11754 + var margin = {top: 2, right: 0, bottom: 2, left: 0} 6.11755 + , width = 400 6.11756 + , height = 32 6.11757 + , container = null 6.11758 + , animate = true 6.11759 + , x = d3.scale.linear() 6.11760 + , y = d3.scale.linear() 6.11761 + , getX = function(d) { return d.x } 6.11762 + , getY = function(d) { return d.y } 6.11763 + , color = nv.utils.getColor(['#000']) 6.11764 + , xDomain 6.11765 + , yDomain 6.11766 + , xRange 6.11767 + , yRange 6.11768 + ; 6.11769 + 6.11770 + function chart(selection) { 6.11771 + selection.each(function(data) { 6.11772 + var availableWidth = width - margin.left - margin.right, 6.11773 + availableHeight = height - margin.top - margin.bottom; 6.11774 + 6.11775 + container = d3.select(this); 6.11776 + nv.utils.initSVG(container); 6.11777 + 6.11778 + // Setup Scales 6.11779 + x .domain(xDomain || d3.extent(data, getX )) 6.11780 + .range(xRange || [0, availableWidth]); 6.11781 + 6.11782 + y .domain(yDomain || d3.extent(data, getY )) 6.11783 + .range(yRange || [availableHeight, 0]); 6.11784 + 6.11785 + // Setup containers and skeleton of chart 6.11786 + var wrap = container.selectAll('g.nv-wrap.nv-sparkline').data([data]); 6.11787 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparkline'); 6.11788 + var gEnter = wrapEnter.append('g'); 6.11789 + var g = wrap.select('g'); 6.11790 + 6.11791 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') 6.11792 + 6.11793 + var paths = wrap.selectAll('path') 6.11794 + .data(function(d) { return [d] }); 6.11795 + paths.enter().append('path'); 6.11796 + paths.exit().remove(); 6.11797 + paths 6.11798 + .style('stroke', function(d,i) { return d.color || color(d, i) }) 6.11799 + .attr('d', d3.svg.line() 6.11800 + .x(function(d,i) { return x(getX(d,i)) }) 6.11801 + .y(function(d,i) { return y(getY(d,i)) }) 6.11802 + ); 6.11803 + 6.11804 + // TODO: Add CURRENT data point (Need Min, Mac, Current / Most recent) 6.11805 + var points = wrap.selectAll('circle.nv-point') 6.11806 + .data(function(data) { 6.11807 + var yValues = data.map(function(d, i) { return getY(d,i); }); 6.11808 + function pointIndex(index) { 6.11809 + if (index != -1) { 6.11810 + var result = data[index]; 6.11811 + result.pointIndex = index; 6.11812 + return result; 6.11813 + } else { 6.11814 + return null; 6.11815 + } 6.11816 + } 6.11817 + var maxPoint = pointIndex(yValues.lastIndexOf(y.domain()[1])), 6.11818 + minPoint = pointIndex(yValues.indexOf(y.domain()[0])), 6.11819 + currentPoint = pointIndex(yValues.length - 1); 6.11820 + return [minPoint, maxPoint, currentPoint].filter(function (d) {return d != null;}); 6.11821 + }); 6.11822 + points.enter().append('circle'); 6.11823 + points.exit().remove(); 6.11824 + points 6.11825 + .attr('cx', function(d,i) { return x(getX(d,d.pointIndex)) }) 6.11826 + .attr('cy', function(d,i) { return y(getY(d,d.pointIndex)) }) 6.11827 + .attr('r', 2) 6.11828 + .attr('class', function(d,i) { 6.11829 + return getX(d, d.pointIndex) == x.domain()[1] ? 'nv-point nv-currentValue' : 6.11830 + getY(d, d.pointIndex) == y.domain()[0] ? 'nv-point nv-minValue' : 'nv-point nv-maxValue' 6.11831 + }); 6.11832 + }); 6.11833 + 6.11834 + return chart; 6.11835 + } 6.11836 + 6.11837 + //============================================================ 6.11838 + // Expose Public Variables 6.11839 + //------------------------------------------------------------ 6.11840 + 6.11841 + chart.options = nv.utils.optionsFunc.bind(chart); 6.11842 + 6.11843 + chart._options = Object.create({}, { 6.11844 + // simple options, just get/set the necessary values 6.11845 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.11846 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.11847 + xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, 6.11848 + yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, 6.11849 + xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, 6.11850 + yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, 6.11851 + xScale: {get: function(){return x;}, set: function(_){x=_;}}, 6.11852 + yScale: {get: function(){return y;}, set: function(_){y=_;}}, 6.11853 + animate: {get: function(){return animate;}, set: function(_){animate=_;}}, 6.11854 + 6.11855 + //functor options 6.11856 + x: {get: function(){return getX;}, set: function(_){getX=d3.functor(_);}}, 6.11857 + y: {get: function(){return getY;}, set: function(_){getY=d3.functor(_);}}, 6.11858 + 6.11859 + // options that require extra logic in the setter 6.11860 + margin: {get: function(){return margin;}, set: function(_){ 6.11861 + margin.top = _.top !== undefined ? _.top : margin.top; 6.11862 + margin.right = _.right !== undefined ? _.right : margin.right; 6.11863 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.11864 + margin.left = _.left !== undefined ? _.left : margin.left; 6.11865 + }}, 6.11866 + color: {get: function(){return color;}, set: function(_){ 6.11867 + color = nv.utils.getColor(_); 6.11868 + }} 6.11869 + }); 6.11870 + 6.11871 + nv.utils.initOptions(chart); 6.11872 + return chart; 6.11873 +}; 6.11874 + 6.11875 +nv.models.sparklinePlus = function() { 6.11876 + "use strict"; 6.11877 + 6.11878 + //============================================================ 6.11879 + // Public Variables with Default Settings 6.11880 + //------------------------------------------------------------ 6.11881 + 6.11882 + var sparkline = nv.models.sparkline(); 6.11883 + 6.11884 + var margin = {top: 15, right: 100, bottom: 10, left: 50} 6.11885 + , width = null 6.11886 + , height = null 6.11887 + , x 6.11888 + , y 6.11889 + , index = [] 6.11890 + , paused = false 6.11891 + , xTickFormat = d3.format(',r') 6.11892 + , yTickFormat = d3.format(',.2f') 6.11893 + , showLastValue = true 6.11894 + , alignValue = true 6.11895 + , rightAlignValue = false 6.11896 + , noData = null 6.11897 + ; 6.11898 + 6.11899 + function chart(selection) { 6.11900 + selection.each(function(data) { 6.11901 + var container = d3.select(this); 6.11902 + nv.utils.initSVG(container); 6.11903 + 6.11904 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.11905 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.11906 + 6.11907 + chart.update = function() { container.call(chart); }; 6.11908 + chart.container = this; 6.11909 + 6.11910 + // Display No Data message if there's nothing to show. 6.11911 + if (!data || !data.length) { 6.11912 + nv.utils.noData(chart, container) 6.11913 + return chart; 6.11914 + } else { 6.11915 + container.selectAll('.nv-noData').remove(); 6.11916 + } 6.11917 + 6.11918 + var currentValue = sparkline.y()(data[data.length-1], data.length-1); 6.11919 + 6.11920 + // Setup Scales 6.11921 + x = sparkline.xScale(); 6.11922 + y = sparkline.yScale(); 6.11923 + 6.11924 + // Setup containers and skeleton of chart 6.11925 + var wrap = container.selectAll('g.nv-wrap.nv-sparklineplus').data([data]); 6.11926 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparklineplus'); 6.11927 + var gEnter = wrapEnter.append('g'); 6.11928 + var g = wrap.select('g'); 6.11929 + 6.11930 + gEnter.append('g').attr('class', 'nv-sparklineWrap'); 6.11931 + gEnter.append('g').attr('class', 'nv-valueWrap'); 6.11932 + gEnter.append('g').attr('class', 'nv-hoverArea'); 6.11933 + 6.11934 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.11935 + 6.11936 + // Main Chart Component(s) 6.11937 + var sparklineWrap = g.select('.nv-sparklineWrap'); 6.11938 + 6.11939 + sparkline.width(availableWidth).height(availableHeight); 6.11940 + sparklineWrap.call(sparkline); 6.11941 + 6.11942 + if (showLastValue) { 6.11943 + var valueWrap = g.select('.nv-valueWrap'); 6.11944 + var value = valueWrap.selectAll('.nv-currentValue') 6.11945 + .data([currentValue]); 6.11946 + 6.11947 + value.enter().append('text').attr('class', 'nv-currentValue') 6.11948 + .attr('dx', rightAlignValue ? -8 : 8) 6.11949 + .attr('dy', '.9em') 6.11950 + .style('text-anchor', rightAlignValue ? 'end' : 'start'); 6.11951 + 6.11952 + value 6.11953 + .attr('x', availableWidth + (rightAlignValue ? margin.right : 0)) 6.11954 + .attr('y', alignValue ? function (d) { 6.11955 + return y(d) 6.11956 + } : 0) 6.11957 + .style('fill', sparkline.color()(data[data.length - 1], data.length - 1)) 6.11958 + .text(yTickFormat(currentValue)); 6.11959 + } 6.11960 + 6.11961 + gEnter.select('.nv-hoverArea').append('rect') 6.11962 + .on('mousemove', sparklineHover) 6.11963 + .on('click', function() { paused = !paused }) 6.11964 + .on('mouseout', function() { index = []; updateValueLine(); }); 6.11965 + 6.11966 + g.select('.nv-hoverArea rect') 6.11967 + .attr('transform', function(d) { return 'translate(' + -margin.left + ',' + -margin.top + ')' }) 6.11968 + .attr('width', availableWidth + margin.left + margin.right) 6.11969 + .attr('height', availableHeight + margin.top); 6.11970 + 6.11971 + //index is currently global (within the chart), may or may not keep it that way 6.11972 + function updateValueLine() { 6.11973 + if (paused) return; 6.11974 + 6.11975 + var hoverValue = g.selectAll('.nv-hoverValue').data(index); 6.11976 + 6.11977 + var hoverEnter = hoverValue.enter() 6.11978 + .append('g').attr('class', 'nv-hoverValue') 6.11979 + .style('stroke-opacity', 0) 6.11980 + .style('fill-opacity', 0); 6.11981 + 6.11982 + hoverValue.exit() 6.11983 + .transition().duration(250) 6.11984 + .style('stroke-opacity', 0) 6.11985 + .style('fill-opacity', 0) 6.11986 + .remove(); 6.11987 + 6.11988 + hoverValue 6.11989 + .attr('transform', function(d) { return 'translate(' + x(sparkline.x()(data[d],d)) + ',0)' }) 6.11990 + .transition().duration(250) 6.11991 + .style('stroke-opacity', 1) 6.11992 + .style('fill-opacity', 1); 6.11993 + 6.11994 + if (!index.length) return; 6.11995 + 6.11996 + hoverEnter.append('line') 6.11997 + .attr('x1', 0) 6.11998 + .attr('y1', -margin.top) 6.11999 + .attr('x2', 0) 6.12000 + .attr('y2', availableHeight); 6.12001 + 6.12002 + hoverEnter.append('text').attr('class', 'nv-xValue') 6.12003 + .attr('x', -6) 6.12004 + .attr('y', -margin.top) 6.12005 + .attr('text-anchor', 'end') 6.12006 + .attr('dy', '.9em'); 6.12007 + 6.12008 + g.select('.nv-hoverValue .nv-xValue') 6.12009 + .text(xTickFormat(sparkline.x()(data[index[0]], index[0]))); 6.12010 + 6.12011 + hoverEnter.append('text').attr('class', 'nv-yValue') 6.12012 + .attr('x', 6) 6.12013 + .attr('y', -margin.top) 6.12014 + .attr('text-anchor', 'start') 6.12015 + .attr('dy', '.9em'); 6.12016 + 6.12017 + g.select('.nv-hoverValue .nv-yValue') 6.12018 + .text(yTickFormat(sparkline.y()(data[index[0]], index[0]))); 6.12019 + } 6.12020 + 6.12021 + function sparklineHover() { 6.12022 + if (paused) return; 6.12023 + 6.12024 + var pos = d3.mouse(this)[0] - margin.left; 6.12025 + 6.12026 + function getClosestIndex(data, x) { 6.12027 + var distance = Math.abs(sparkline.x()(data[0], 0) - x); 6.12028 + var closestIndex = 0; 6.12029 + for (var i = 0; i < data.length; i++){ 6.12030 + if (Math.abs(sparkline.x()(data[i], i) - x) < distance) { 6.12031 + distance = Math.abs(sparkline.x()(data[i], i) - x); 6.12032 + closestIndex = i; 6.12033 + } 6.12034 + } 6.12035 + return closestIndex; 6.12036 + } 6.12037 + 6.12038 + index = [getClosestIndex(data, Math.round(x.invert(pos)))]; 6.12039 + updateValueLine(); 6.12040 + } 6.12041 + 6.12042 + }); 6.12043 + 6.12044 + return chart; 6.12045 + } 6.12046 + 6.12047 + //============================================================ 6.12048 + // Expose Public Variables 6.12049 + //------------------------------------------------------------ 6.12050 + 6.12051 + // expose chart's sub-components 6.12052 + chart.sparkline = sparkline; 6.12053 + 6.12054 + chart.options = nv.utils.optionsFunc.bind(chart); 6.12055 + 6.12056 + chart._options = Object.create({}, { 6.12057 + // simple options, just get/set the necessary values 6.12058 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.12059 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.12060 + xTickFormat: {get: function(){return xTickFormat;}, set: function(_){xTickFormat=_;}}, 6.12061 + yTickFormat: {get: function(){return yTickFormat;}, set: function(_){yTickFormat=_;}}, 6.12062 + showLastValue: {get: function(){return showLastValue;}, set: function(_){showLastValue=_;}}, 6.12063 + alignValue: {get: function(){return alignValue;}, set: function(_){alignValue=_;}}, 6.12064 + rightAlignValue: {get: function(){return rightAlignValue;}, set: function(_){rightAlignValue=_;}}, 6.12065 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.12066 + 6.12067 + // options that require extra logic in the setter 6.12068 + margin: {get: function(){return margin;}, set: function(_){ 6.12069 + margin.top = _.top !== undefined ? _.top : margin.top; 6.12070 + margin.right = _.right !== undefined ? _.right : margin.right; 6.12071 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.12072 + margin.left = _.left !== undefined ? _.left : margin.left; 6.12073 + }} 6.12074 + }); 6.12075 + 6.12076 + nv.utils.inheritOptions(chart, sparkline); 6.12077 + nv.utils.initOptions(chart); 6.12078 + 6.12079 + return chart; 6.12080 +}; 6.12081 + 6.12082 +nv.models.stackedArea = function() { 6.12083 + "use strict"; 6.12084 + 6.12085 + //============================================================ 6.12086 + // Public Variables with Default Settings 6.12087 + //------------------------------------------------------------ 6.12088 + 6.12089 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.12090 + , width = 960 6.12091 + , height = 500 6.12092 + , color = nv.utils.defaultColor() // a function that computes the color 6.12093 + , id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't selet one 6.12094 + , container = null 6.12095 + , getX = function(d) { return d.x } // accessor to get the x value from a data point 6.12096 + , getY = function(d) { return d.y } // accessor to get the y value from a data point 6.12097 + , style = 'stack' 6.12098 + , offset = 'zero' 6.12099 + , order = 'default' 6.12100 + , interpolate = 'linear' // controls the line interpolation 6.12101 + , clipEdge = false // if true, masks lines within x and y scale 6.12102 + , x //can be accessed via chart.xScale() 6.12103 + , y //can be accessed via chart.yScale() 6.12104 + , scatter = nv.models.scatter() 6.12105 + , duration = 250 6.12106 + , dispatch = d3.dispatch('areaClick', 'areaMouseover', 'areaMouseout','renderEnd', 'elementClick', 'elementMouseover', 'elementMouseout') 6.12107 + ; 6.12108 + 6.12109 + scatter 6.12110 + .pointSize(2.2) // default size 6.12111 + .pointDomain([2.2, 2.2]) // all the same size by default 6.12112 + ; 6.12113 + 6.12114 + /************************************ 6.12115 + * offset: 6.12116 + * 'wiggle' (stream) 6.12117 + * 'zero' (stacked) 6.12118 + * 'expand' (normalize to 100%) 6.12119 + * 'silhouette' (simple centered) 6.12120 + * 6.12121 + * order: 6.12122 + * 'inside-out' (stream) 6.12123 + * 'default' (input order) 6.12124 + ************************************/ 6.12125 + 6.12126 + var renderWatch = nv.utils.renderWatch(dispatch, duration); 6.12127 + 6.12128 + function chart(selection) { 6.12129 + renderWatch.reset(); 6.12130 + renderWatch.models(scatter); 6.12131 + selection.each(function(data) { 6.12132 + var availableWidth = width - margin.left - margin.right, 6.12133 + availableHeight = height - margin.top - margin.bottom; 6.12134 + 6.12135 + container = d3.select(this); 6.12136 + nv.utils.initSVG(container); 6.12137 + 6.12138 + // Setup Scales 6.12139 + x = scatter.xScale(); 6.12140 + y = scatter.yScale(); 6.12141 + 6.12142 + var dataRaw = data; 6.12143 + // Injecting point index into each point because d3.layout.stack().out does not give index 6.12144 + data.forEach(function(aseries, i) { 6.12145 + aseries.seriesIndex = i; 6.12146 + aseries.values = aseries.values.map(function(d, j) { 6.12147 + d.index = j; 6.12148 + d.seriesIndex = i; 6.12149 + return d; 6.12150 + }); 6.12151 + }); 6.12152 + 6.12153 + var dataFiltered = data.filter(function(series) { 6.12154 + return !series.disabled; 6.12155 + }); 6.12156 + 6.12157 + data = d3.layout.stack() 6.12158 + .order(order) 6.12159 + .offset(offset) 6.12160 + .values(function(d) { return d.values }) //TODO: make values customizeable in EVERY model in this fashion 6.12161 + .x(getX) 6.12162 + .y(getY) 6.12163 + .out(function(d, y0, y) { 6.12164 + d.display = { 6.12165 + y: y, 6.12166 + y0: y0 6.12167 + }; 6.12168 + }) 6.12169 + (dataFiltered); 6.12170 + 6.12171 + // Setup containers and skeleton of chart 6.12172 + var wrap = container.selectAll('g.nv-wrap.nv-stackedarea').data([data]); 6.12173 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedarea'); 6.12174 + var defsEnter = wrapEnter.append('defs'); 6.12175 + var gEnter = wrapEnter.append('g'); 6.12176 + var g = wrap.select('g'); 6.12177 + 6.12178 + gEnter.append('g').attr('class', 'nv-areaWrap'); 6.12179 + gEnter.append('g').attr('class', 'nv-scatterWrap'); 6.12180 + 6.12181 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.12182 + 6.12183 + // If the user has not specified forceY, make sure 0 is included in the domain 6.12184 + // Otherwise, use user-specified values for forceY 6.12185 + if (scatter.forceY().length == 0) { 6.12186 + scatter.forceY().push(0); 6.12187 + } 6.12188 + 6.12189 + scatter 6.12190 + .width(availableWidth) 6.12191 + .height(availableHeight) 6.12192 + .x(getX) 6.12193 + .y(function(d) { return d.display.y + d.display.y0 }) 6.12194 + .forceY([0]) 6.12195 + .color(data.map(function(d,i) { 6.12196 + return d.color || color(d, d.seriesIndex); 6.12197 + })); 6.12198 + 6.12199 + var scatterWrap = g.select('.nv-scatterWrap') 6.12200 + .datum(data); 6.12201 + 6.12202 + scatterWrap.call(scatter); 6.12203 + 6.12204 + defsEnter.append('clipPath') 6.12205 + .attr('id', 'nv-edge-clip-' + id) 6.12206 + .append('rect'); 6.12207 + 6.12208 + wrap.select('#nv-edge-clip-' + id + ' rect') 6.12209 + .attr('width', availableWidth) 6.12210 + .attr('height', availableHeight); 6.12211 + 6.12212 + g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : ''); 6.12213 + 6.12214 + var area = d3.svg.area() 6.12215 + .x(function(d,i) { return x(getX(d,i)) }) 6.12216 + .y0(function(d) { 6.12217 + return y(d.display.y0) 6.12218 + }) 6.12219 + .y1(function(d) { 6.12220 + return y(d.display.y + d.display.y0) 6.12221 + }) 6.12222 + .interpolate(interpolate); 6.12223 + 6.12224 + var zeroArea = d3.svg.area() 6.12225 + .x(function(d,i) { return x(getX(d,i)) }) 6.12226 + .y0(function(d) { return y(d.display.y0) }) 6.12227 + .y1(function(d) { return y(d.display.y0) }); 6.12228 + 6.12229 + var path = g.select('.nv-areaWrap').selectAll('path.nv-area') 6.12230 + .data(function(d) { return d }); 6.12231 + 6.12232 + path.enter().append('path').attr('class', function(d,i) { return 'nv-area nv-area-' + i }) 6.12233 + .attr('d', function(d,i){ 6.12234 + return zeroArea(d.values, d.seriesIndex); 6.12235 + }) 6.12236 + .on('mouseover', function(d,i) { 6.12237 + d3.select(this).classed('hover', true); 6.12238 + dispatch.areaMouseover({ 6.12239 + point: d, 6.12240 + series: d.key, 6.12241 + pos: [d3.event.pageX, d3.event.pageY], 6.12242 + seriesIndex: d.seriesIndex 6.12243 + }); 6.12244 + }) 6.12245 + .on('mouseout', function(d,i) { 6.12246 + d3.select(this).classed('hover', false); 6.12247 + dispatch.areaMouseout({ 6.12248 + point: d, 6.12249 + series: d.key, 6.12250 + pos: [d3.event.pageX, d3.event.pageY], 6.12251 + seriesIndex: d.seriesIndex 6.12252 + }); 6.12253 + }) 6.12254 + .on('click', function(d,i) { 6.12255 + d3.select(this).classed('hover', false); 6.12256 + dispatch.areaClick({ 6.12257 + point: d, 6.12258 + series: d.key, 6.12259 + pos: [d3.event.pageX, d3.event.pageY], 6.12260 + seriesIndex: d.seriesIndex 6.12261 + }); 6.12262 + }); 6.12263 + 6.12264 + path.exit().remove(); 6.12265 + path.style('fill', function(d,i){ 6.12266 + return d.color || color(d, d.seriesIndex) 6.12267 + }) 6.12268 + .style('stroke', function(d,i){ return d.color || color(d, d.seriesIndex) }); 6.12269 + path.watchTransition(renderWatch,'stackedArea path') 6.12270 + .attr('d', function(d,i) { 6.12271 + return area(d.values,i) 6.12272 + }); 6.12273 + 6.12274 + //============================================================ 6.12275 + // Event Handling/Dispatching (in chart's scope) 6.12276 + //------------------------------------------------------------ 6.12277 + 6.12278 + scatter.dispatch.on('elementMouseover.area', function(e) { 6.12279 + g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', true); 6.12280 + }); 6.12281 + scatter.dispatch.on('elementMouseout.area', function(e) { 6.12282 + g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', false); 6.12283 + }); 6.12284 + 6.12285 + //Special offset functions 6.12286 + chart.d3_stackedOffset_stackPercent = function(stackData) { 6.12287 + var n = stackData.length, //How many series 6.12288 + m = stackData[0].length, //how many points per series 6.12289 + i, 6.12290 + j, 6.12291 + o, 6.12292 + y0 = []; 6.12293 + 6.12294 + for (j = 0; j < m; ++j) { //Looping through all points 6.12295 + for (i = 0, o = 0; i < dataRaw.length; i++) { //looping through all series 6.12296 + o += getY(dataRaw[i].values[j]); //total y value of all series at a certian point in time. 6.12297 + } 6.12298 + 6.12299 + if (o) for (i = 0; i < n; i++) { //(total y value of all series at point in time i) != 0 6.12300 + stackData[i][j][1] /= o; 6.12301 + } else { //(total y value of all series at point in time i) == 0 6.12302 + for (i = 0; i < n; i++) { 6.12303 + stackData[i][j][1] = 0; 6.12304 + } 6.12305 + } 6.12306 + } 6.12307 + for (j = 0; j < m; ++j) y0[j] = 0; 6.12308 + return y0; 6.12309 + }; 6.12310 + 6.12311 + }); 6.12312 + 6.12313 + renderWatch.renderEnd('stackedArea immediate'); 6.12314 + return chart; 6.12315 + } 6.12316 + 6.12317 + //============================================================ 6.12318 + // Global getters and setters 6.12319 + //------------------------------------------------------------ 6.12320 + 6.12321 + chart.dispatch = dispatch; 6.12322 + chart.scatter = scatter; 6.12323 + 6.12324 + scatter.dispatch.on('elementClick', function(){ dispatch.elementClick.apply(this, arguments); }); 6.12325 + scatter.dispatch.on('elementMouseover', function(){ dispatch.elementMouseover.apply(this, arguments); }); 6.12326 + scatter.dispatch.on('elementMouseout', function(){ dispatch.elementMouseout.apply(this, arguments); }); 6.12327 + 6.12328 + chart.interpolate = function(_) { 6.12329 + if (!arguments.length) return interpolate; 6.12330 + interpolate = _; 6.12331 + return chart; 6.12332 + }; 6.12333 + 6.12334 + chart.duration = function(_) { 6.12335 + if (!arguments.length) return duration; 6.12336 + duration = _; 6.12337 + renderWatch.reset(duration); 6.12338 + scatter.duration(duration); 6.12339 + return chart; 6.12340 + }; 6.12341 + 6.12342 + chart.dispatch = dispatch; 6.12343 + chart.scatter = scatter; 6.12344 + chart.options = nv.utils.optionsFunc.bind(chart); 6.12345 + 6.12346 + chart._options = Object.create({}, { 6.12347 + // simple options, just get/set the necessary values 6.12348 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.12349 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.12350 + clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, 6.12351 + offset: {get: function(){return offset;}, set: function(_){offset=_;}}, 6.12352 + order: {get: function(){return order;}, set: function(_){order=_;}}, 6.12353 + interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}}, 6.12354 + 6.12355 + // simple functor options 6.12356 + x: {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}}, 6.12357 + y: {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}}, 6.12358 + 6.12359 + // options that require extra logic in the setter 6.12360 + margin: {get: function(){return margin;}, set: function(_){ 6.12361 + margin.top = _.top !== undefined ? _.top : margin.top; 6.12362 + margin.right = _.right !== undefined ? _.right : margin.right; 6.12363 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.12364 + margin.left = _.left !== undefined ? _.left : margin.left; 6.12365 + }}, 6.12366 + color: {get: function(){return color;}, set: function(_){ 6.12367 + color = nv.utils.getColor(_); 6.12368 + }}, 6.12369 + style: {get: function(){return style;}, set: function(_){ 6.12370 + style = _; 6.12371 + switch (style) { 6.12372 + case 'stack': 6.12373 + chart.offset('zero'); 6.12374 + chart.order('default'); 6.12375 + break; 6.12376 + case 'stream': 6.12377 + chart.offset('wiggle'); 6.12378 + chart.order('inside-out'); 6.12379 + break; 6.12380 + case 'stream-center': 6.12381 + chart.offset('silhouette'); 6.12382 + chart.order('inside-out'); 6.12383 + break; 6.12384 + case 'expand': 6.12385 + chart.offset('expand'); 6.12386 + chart.order('default'); 6.12387 + break; 6.12388 + case 'stack_percent': 6.12389 + chart.offset(chart.d3_stackedOffset_stackPercent); 6.12390 + chart.order('default'); 6.12391 + break; 6.12392 + } 6.12393 + }}, 6.12394 + duration: {get: function(){return duration;}, set: function(_){ 6.12395 + duration = _; 6.12396 + renderWatch.reset(duration); 6.12397 + scatter.duration(duration); 6.12398 + }} 6.12399 + }); 6.12400 + 6.12401 + nv.utils.inheritOptions(chart, scatter); 6.12402 + nv.utils.initOptions(chart); 6.12403 + 6.12404 + return chart; 6.12405 +}; 6.12406 + 6.12407 +nv.models.stackedAreaChart = function() { 6.12408 + "use strict"; 6.12409 + 6.12410 + //============================================================ 6.12411 + // Public Variables with Default Settings 6.12412 + //------------------------------------------------------------ 6.12413 + 6.12414 + var stacked = nv.models.stackedArea() 6.12415 + , xAxis = nv.models.axis() 6.12416 + , yAxis = nv.models.axis() 6.12417 + , legend = nv.models.legend() 6.12418 + , controls = nv.models.legend() 6.12419 + , interactiveLayer = nv.interactiveGuideline() 6.12420 + , tooltip = nv.models.tooltip() 6.12421 + ; 6.12422 + 6.12423 + var margin = {top: 30, right: 25, bottom: 50, left: 60} 6.12424 + , width = null 6.12425 + , height = null 6.12426 + , color = nv.utils.defaultColor() 6.12427 + , showControls = true 6.12428 + , showLegend = true 6.12429 + , showXAxis = true 6.12430 + , showYAxis = true 6.12431 + , rightAlignYAxis = false 6.12432 + , useInteractiveGuideline = false 6.12433 + , x //can be accessed via chart.xScale() 6.12434 + , y //can be accessed via chart.yScale() 6.12435 + , state = nv.utils.state() 6.12436 + , defaultState = null 6.12437 + , noData = null 6.12438 + , dispatch = d3.dispatch('stateChange', 'changeState','renderEnd') 6.12439 + , controlWidth = 250 6.12440 + , controlOptions = ['Stacked','Stream','Expanded'] 6.12441 + , controlLabels = {} 6.12442 + , duration = 250 6.12443 + ; 6.12444 + 6.12445 + state.style = stacked.style(); 6.12446 + xAxis.orient('bottom').tickPadding(7); 6.12447 + yAxis.orient((rightAlignYAxis) ? 'right' : 'left'); 6.12448 + 6.12449 + tooltip 6.12450 + .headerFormatter(function(d, i) { 6.12451 + return xAxis.tickFormat()(d, i); 6.12452 + }) 6.12453 + .valueFormatter(function(d, i) { 6.12454 + return yAxis.tickFormat()(d, i); 6.12455 + }); 6.12456 + 6.12457 + interactiveLayer.tooltip 6.12458 + .headerFormatter(function(d, i) { 6.12459 + return xAxis.tickFormat()(d, i); 6.12460 + }) 6.12461 + .valueFormatter(function(d, i) { 6.12462 + return yAxis.tickFormat()(d, i); 6.12463 + }); 6.12464 + 6.12465 + var oldYTickFormat = null, 6.12466 + oldValueFormatter = null; 6.12467 + 6.12468 + controls.updateState(false); 6.12469 + 6.12470 + //============================================================ 6.12471 + // Private Variables 6.12472 + //------------------------------------------------------------ 6.12473 + 6.12474 + var renderWatch = nv.utils.renderWatch(dispatch); 6.12475 + var style = stacked.style(); 6.12476 + 6.12477 + var stateGetter = function(data) { 6.12478 + return function(){ 6.12479 + return { 6.12480 + active: data.map(function(d) { return !d.disabled }), 6.12481 + style: stacked.style() 6.12482 + }; 6.12483 + } 6.12484 + }; 6.12485 + 6.12486 + var stateSetter = function(data) { 6.12487 + return function(state) { 6.12488 + if (state.style !== undefined) 6.12489 + style = state.style; 6.12490 + if (state.active !== undefined) 6.12491 + data.forEach(function(series,i) { 6.12492 + series.disabled = !state.active[i]; 6.12493 + }); 6.12494 + } 6.12495 + }; 6.12496 + 6.12497 + var percentFormatter = d3.format('%'); 6.12498 + 6.12499 + function chart(selection) { 6.12500 + renderWatch.reset(); 6.12501 + renderWatch.models(stacked); 6.12502 + if (showXAxis) renderWatch.models(xAxis); 6.12503 + if (showYAxis) renderWatch.models(yAxis); 6.12504 + 6.12505 + selection.each(function(data) { 6.12506 + var container = d3.select(this), 6.12507 + that = this; 6.12508 + nv.utils.initSVG(container); 6.12509 + 6.12510 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.12511 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.12512 + 6.12513 + chart.update = function() { container.transition().duration(duration).call(chart); }; 6.12514 + chart.container = this; 6.12515 + 6.12516 + state 6.12517 + .setter(stateSetter(data), chart.update) 6.12518 + .getter(stateGetter(data)) 6.12519 + .update(); 6.12520 + 6.12521 + // DEPRECATED set state.disabled 6.12522 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.12523 + 6.12524 + if (!defaultState) { 6.12525 + var key; 6.12526 + defaultState = {}; 6.12527 + for (key in state) { 6.12528 + if (state[key] instanceof Array) 6.12529 + defaultState[key] = state[key].slice(0); 6.12530 + else 6.12531 + defaultState[key] = state[key]; 6.12532 + } 6.12533 + } 6.12534 + 6.12535 + // Display No Data message if there's nothing to show. 6.12536 + if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { 6.12537 + nv.utils.noData(chart, container) 6.12538 + return chart; 6.12539 + } else { 6.12540 + container.selectAll('.nv-noData').remove(); 6.12541 + } 6.12542 + 6.12543 + // Setup Scales 6.12544 + x = stacked.xScale(); 6.12545 + y = stacked.yScale(); 6.12546 + 6.12547 + // Setup containers and skeleton of chart 6.12548 + var wrap = container.selectAll('g.nv-wrap.nv-stackedAreaChart').data([data]); 6.12549 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedAreaChart').append('g'); 6.12550 + var g = wrap.select('g'); 6.12551 + 6.12552 + gEnter.append("rect").style("opacity",0); 6.12553 + gEnter.append('g').attr('class', 'nv-x nv-axis'); 6.12554 + gEnter.append('g').attr('class', 'nv-y nv-axis'); 6.12555 + gEnter.append('g').attr('class', 'nv-stackedWrap'); 6.12556 + gEnter.append('g').attr('class', 'nv-legendWrap'); 6.12557 + gEnter.append('g').attr('class', 'nv-controlsWrap'); 6.12558 + gEnter.append('g').attr('class', 'nv-interactive'); 6.12559 + 6.12560 + g.select("rect").attr("width",availableWidth).attr("height",availableHeight); 6.12561 + 6.12562 + // Legend 6.12563 + if (showLegend) { 6.12564 + var legendWidth = (showControls) ? availableWidth - controlWidth : availableWidth; 6.12565 + 6.12566 + legend.width(legendWidth); 6.12567 + g.select('.nv-legendWrap').datum(data).call(legend); 6.12568 + 6.12569 + if ( margin.top != legend.height()) { 6.12570 + margin.top = legend.height(); 6.12571 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.12572 + } 6.12573 + 6.12574 + g.select('.nv-legendWrap') 6.12575 + .attr('transform', 'translate(' + (availableWidth-legendWidth) + ',' + (-margin.top) +')'); 6.12576 + } 6.12577 + 6.12578 + // Controls 6.12579 + if (showControls) { 6.12580 + var controlsData = [ 6.12581 + { 6.12582 + key: controlLabels.stacked || 'Stacked', 6.12583 + metaKey: 'Stacked', 6.12584 + disabled: stacked.style() != 'stack', 6.12585 + style: 'stack' 6.12586 + }, 6.12587 + { 6.12588 + key: controlLabels.stream || 'Stream', 6.12589 + metaKey: 'Stream', 6.12590 + disabled: stacked.style() != 'stream', 6.12591 + style: 'stream' 6.12592 + }, 6.12593 + { 6.12594 + key: controlLabels.expanded || 'Expanded', 6.12595 + metaKey: 'Expanded', 6.12596 + disabled: stacked.style() != 'expand', 6.12597 + style: 'expand' 6.12598 + }, 6.12599 + { 6.12600 + key: controlLabels.stack_percent || 'Stack %', 6.12601 + metaKey: 'Stack_Percent', 6.12602 + disabled: stacked.style() != 'stack_percent', 6.12603 + style: 'stack_percent' 6.12604 + } 6.12605 + ]; 6.12606 + 6.12607 + controlWidth = (controlOptions.length/3) * 260; 6.12608 + controlsData = controlsData.filter(function(d) { 6.12609 + return controlOptions.indexOf(d.metaKey) !== -1; 6.12610 + }); 6.12611 + 6.12612 + controls 6.12613 + .width( controlWidth ) 6.12614 + .color(['#444', '#444', '#444']); 6.12615 + 6.12616 + g.select('.nv-controlsWrap') 6.12617 + .datum(controlsData) 6.12618 + .call(controls); 6.12619 + 6.12620 + if ( margin.top != Math.max(controls.height(), legend.height()) ) { 6.12621 + margin.top = Math.max(controls.height(), legend.height()); 6.12622 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.12623 + } 6.12624 + 6.12625 + g.select('.nv-controlsWrap') 6.12626 + .attr('transform', 'translate(0,' + (-margin.top) +')'); 6.12627 + } 6.12628 + 6.12629 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.12630 + 6.12631 + if (rightAlignYAxis) { 6.12632 + g.select(".nv-y.nv-axis") 6.12633 + .attr("transform", "translate(" + availableWidth + ",0)"); 6.12634 + } 6.12635 + 6.12636 + //Set up interactive layer 6.12637 + if (useInteractiveGuideline) { 6.12638 + interactiveLayer 6.12639 + .width(availableWidth) 6.12640 + .height(availableHeight) 6.12641 + .margin({left: margin.left, top: margin.top}) 6.12642 + .svgContainer(container) 6.12643 + .xScale(x); 6.12644 + wrap.select(".nv-interactive").call(interactiveLayer); 6.12645 + } 6.12646 + 6.12647 + stacked 6.12648 + .width(availableWidth) 6.12649 + .height(availableHeight); 6.12650 + 6.12651 + var stackedWrap = g.select('.nv-stackedWrap') 6.12652 + .datum(data); 6.12653 + 6.12654 + stackedWrap.transition().call(stacked); 6.12655 + 6.12656 + // Setup Axes 6.12657 + if (showXAxis) { 6.12658 + xAxis.scale(x) 6.12659 + ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) 6.12660 + .tickSize( -availableHeight, 0); 6.12661 + 6.12662 + g.select('.nv-x.nv-axis') 6.12663 + .attr('transform', 'translate(0,' + availableHeight + ')'); 6.12664 + 6.12665 + g.select('.nv-x.nv-axis') 6.12666 + .transition().duration(0) 6.12667 + .call(xAxis); 6.12668 + } 6.12669 + 6.12670 + if (showYAxis) { 6.12671 + var ticks; 6.12672 + if (stacked.offset() === 'wiggle') { 6.12673 + ticks = 0; 6.12674 + } 6.12675 + else { 6.12676 + ticks = nv.utils.calcTicksY(availableHeight/36, data); 6.12677 + } 6.12678 + yAxis.scale(y) 6.12679 + ._ticks(ticks) 6.12680 + .tickSize(-availableWidth, 0); 6.12681 + 6.12682 + if (stacked.style() === 'expand' || stacked.style() === 'stack_percent') { 6.12683 + var currentFormat = yAxis.tickFormat(); 6.12684 + 6.12685 + if ( !oldYTickFormat || currentFormat !== percentFormatter ) 6.12686 + oldYTickFormat = currentFormat; 6.12687 + 6.12688 + //Forces the yAxis to use percentage in 'expand' mode. 6.12689 + yAxis.tickFormat(percentFormatter); 6.12690 + } 6.12691 + else { 6.12692 + if (oldYTickFormat) { 6.12693 + yAxis.tickFormat(oldYTickFormat); 6.12694 + oldYTickFormat = null; 6.12695 + } 6.12696 + } 6.12697 + 6.12698 + g.select('.nv-y.nv-axis') 6.12699 + .transition().duration(0) 6.12700 + .call(yAxis); 6.12701 + } 6.12702 + 6.12703 + //============================================================ 6.12704 + // Event Handling/Dispatching (in chart's scope) 6.12705 + //------------------------------------------------------------ 6.12706 + 6.12707 + stacked.dispatch.on('areaClick.toggle', function(e) { 6.12708 + if (data.filter(function(d) { return !d.disabled }).length === 1) 6.12709 + data.forEach(function(d) { 6.12710 + d.disabled = false; 6.12711 + }); 6.12712 + else 6.12713 + data.forEach(function(d,i) { 6.12714 + d.disabled = (i != e.seriesIndex); 6.12715 + }); 6.12716 + 6.12717 + state.disabled = data.map(function(d) { return !!d.disabled }); 6.12718 + dispatch.stateChange(state); 6.12719 + 6.12720 + chart.update(); 6.12721 + }); 6.12722 + 6.12723 + legend.dispatch.on('stateChange', function(newState) { 6.12724 + for (var key in newState) 6.12725 + state[key] = newState[key]; 6.12726 + dispatch.stateChange(state); 6.12727 + chart.update(); 6.12728 + }); 6.12729 + 6.12730 + controls.dispatch.on('legendClick', function(d,i) { 6.12731 + if (!d.disabled) return; 6.12732 + 6.12733 + controlsData = controlsData.map(function(s) { 6.12734 + s.disabled = true; 6.12735 + return s; 6.12736 + }); 6.12737 + d.disabled = false; 6.12738 + 6.12739 + stacked.style(d.style); 6.12740 + 6.12741 + 6.12742 + state.style = stacked.style(); 6.12743 + dispatch.stateChange(state); 6.12744 + 6.12745 + chart.update(); 6.12746 + }); 6.12747 + 6.12748 + interactiveLayer.dispatch.on('elementMousemove', function(e) { 6.12749 + stacked.clearHighlights(); 6.12750 + var singlePoint, pointIndex, pointXLocation, allData = []; 6.12751 + data 6.12752 + .filter(function(series, i) { 6.12753 + series.seriesIndex = i; 6.12754 + return !series.disabled; 6.12755 + }) 6.12756 + .forEach(function(series,i) { 6.12757 + pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); 6.12758 + var point = series.values[pointIndex]; 6.12759 + var pointYValue = chart.y()(point, pointIndex); 6.12760 + if (pointYValue != null) { 6.12761 + stacked.highlightPoint(i, pointIndex, true); 6.12762 + } 6.12763 + if (typeof point === 'undefined') return; 6.12764 + if (typeof singlePoint === 'undefined') singlePoint = point; 6.12765 + if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); 6.12766 + 6.12767 + //If we are in 'expand' mode, use the stacked percent value instead of raw value. 6.12768 + var tooltipValue = (stacked.style() == 'expand') ? point.display.y : chart.y()(point,pointIndex); 6.12769 + allData.push({ 6.12770 + key: series.key, 6.12771 + value: tooltipValue, 6.12772 + color: color(series,series.seriesIndex), 6.12773 + stackedValue: point.display 6.12774 + }); 6.12775 + }); 6.12776 + 6.12777 + allData.reverse(); 6.12778 + 6.12779 + //Highlight the tooltip entry based on which stack the mouse is closest to. 6.12780 + if (allData.length > 2) { 6.12781 + var yValue = chart.yScale().invert(e.mouseY); 6.12782 + var yDistMax = Infinity, indexToHighlight = null; 6.12783 + allData.forEach(function(series,i) { 6.12784 + 6.12785 + //To handle situation where the stacked area chart is negative, we need to use absolute values 6.12786 + //when checking if the mouse Y value is within the stack area. 6.12787 + yValue = Math.abs(yValue); 6.12788 + var stackedY0 = Math.abs(series.stackedValue.y0); 6.12789 + var stackedY = Math.abs(series.stackedValue.y); 6.12790 + if ( yValue >= stackedY0 && yValue <= (stackedY + stackedY0)) 6.12791 + { 6.12792 + indexToHighlight = i; 6.12793 + return; 6.12794 + } 6.12795 + }); 6.12796 + if (indexToHighlight != null) 6.12797 + allData[indexToHighlight].highlight = true; 6.12798 + } 6.12799 + 6.12800 + var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); 6.12801 + 6.12802 + var valueFormatter = interactiveLayer.tooltip.valueFormatter(); 6.12803 + // Keeps track of the tooltip valueFormatter if the chart changes to expanded view 6.12804 + if (stacked.style() === 'expand' || stacked.style() === 'stack_percent') { 6.12805 + if ( !oldValueFormatter ) { 6.12806 + oldValueFormatter = valueFormatter; 6.12807 + } 6.12808 + //Forces the tooltip to use percentage in 'expand' mode. 6.12809 + valueFormatter = d3.format(".1%"); 6.12810 + } 6.12811 + else { 6.12812 + if (oldValueFormatter) { 6.12813 + valueFormatter = oldValueFormatter; 6.12814 + oldValueFormatter = null; 6.12815 + } 6.12816 + } 6.12817 + 6.12818 + interactiveLayer.tooltip 6.12819 + .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top}) 6.12820 + .chartContainer(that.parentNode) 6.12821 + .valueFormatter(valueFormatter) 6.12822 + .data( 6.12823 + { 6.12824 + value: xValue, 6.12825 + series: allData 6.12826 + } 6.12827 + )(); 6.12828 + 6.12829 + interactiveLayer.renderGuideLine(pointXLocation); 6.12830 + 6.12831 + }); 6.12832 + 6.12833 + interactiveLayer.dispatch.on("elementMouseout",function(e) { 6.12834 + stacked.clearHighlights(); 6.12835 + }); 6.12836 + 6.12837 + // Update chart from a state object passed to event handler 6.12838 + dispatch.on('changeState', function(e) { 6.12839 + 6.12840 + if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) { 6.12841 + data.forEach(function(series,i) { 6.12842 + series.disabled = e.disabled[i]; 6.12843 + }); 6.12844 + 6.12845 + state.disabled = e.disabled; 6.12846 + } 6.12847 + 6.12848 + if (typeof e.style !== 'undefined') { 6.12849 + stacked.style(e.style); 6.12850 + style = e.style; 6.12851 + } 6.12852 + 6.12853 + chart.update(); 6.12854 + }); 6.12855 + 6.12856 + }); 6.12857 + 6.12858 + renderWatch.renderEnd('stacked Area chart immediate'); 6.12859 + return chart; 6.12860 + } 6.12861 + 6.12862 + //============================================================ 6.12863 + // Event Handling/Dispatching (out of chart's scope) 6.12864 + //------------------------------------------------------------ 6.12865 + 6.12866 + stacked.dispatch.on('elementMouseover.tooltip', function(evt) { 6.12867 + evt.point['x'] = stacked.x()(evt.point); 6.12868 + evt.point['y'] = stacked.y()(evt.point); 6.12869 + tooltip.data(evt).position(evt.pos).hidden(false); 6.12870 + }); 6.12871 + 6.12872 + stacked.dispatch.on('elementMouseout.tooltip', function(evt) { 6.12873 + tooltip.hidden(true) 6.12874 + }); 6.12875 + 6.12876 + //============================================================ 6.12877 + // Expose Public Variables 6.12878 + //------------------------------------------------------------ 6.12879 + 6.12880 + // expose chart's sub-components 6.12881 + chart.dispatch = dispatch; 6.12882 + chart.stacked = stacked; 6.12883 + chart.legend = legend; 6.12884 + chart.controls = controls; 6.12885 + chart.xAxis = xAxis; 6.12886 + chart.yAxis = yAxis; 6.12887 + chart.interactiveLayer = interactiveLayer; 6.12888 + chart.tooltip = tooltip; 6.12889 + 6.12890 + chart.dispatch = dispatch; 6.12891 + chart.options = nv.utils.optionsFunc.bind(chart); 6.12892 + 6.12893 + chart._options = Object.create({}, { 6.12894 + // simple options, just get/set the necessary values 6.12895 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.12896 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.12897 + showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, 6.12898 + showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, 6.12899 + showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, 6.12900 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.12901 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.12902 + showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, 6.12903 + controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}}, 6.12904 + controlOptions: {get: function(){return controlOptions;}, set: function(_){controlOptions=_;}}, 6.12905 + 6.12906 + // deprecated options 6.12907 + tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ 6.12908 + // deprecated after 1.7.1 6.12909 + nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); 6.12910 + tooltip.enabled(!!_); 6.12911 + }}, 6.12912 + tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ 6.12913 + // deprecated after 1.7.1 6.12914 + nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); 6.12915 + tooltip.contentGenerator(_); 6.12916 + }}, 6.12917 + 6.12918 + // options that require extra logic in the setter 6.12919 + margin: {get: function(){return margin;}, set: function(_){ 6.12920 + margin.top = _.top !== undefined ? _.top : margin.top; 6.12921 + margin.right = _.right !== undefined ? _.right : margin.right; 6.12922 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.12923 + margin.left = _.left !== undefined ? _.left : margin.left; 6.12924 + }}, 6.12925 + duration: {get: function(){return duration;}, set: function(_){ 6.12926 + duration = _; 6.12927 + renderWatch.reset(duration); 6.12928 + stacked.duration(duration); 6.12929 + xAxis.duration(duration); 6.12930 + yAxis.duration(duration); 6.12931 + }}, 6.12932 + color: {get: function(){return color;}, set: function(_){ 6.12933 + color = nv.utils.getColor(_); 6.12934 + legend.color(color); 6.12935 + stacked.color(color); 6.12936 + }}, 6.12937 + rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ 6.12938 + rightAlignYAxis = _; 6.12939 + yAxis.orient( rightAlignYAxis ? 'right' : 'left'); 6.12940 + }}, 6.12941 + useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ 6.12942 + useInteractiveGuideline = !!_; 6.12943 + chart.interactive(!_); 6.12944 + chart.useVoronoi(!_); 6.12945 + stacked.scatter.interactive(!_); 6.12946 + }} 6.12947 + }); 6.12948 + 6.12949 + nv.utils.inheritOptions(chart, stacked); 6.12950 + nv.utils.initOptions(chart); 6.12951 + 6.12952 + return chart; 6.12953 +}; 6.12954 +// based on http://bl.ocks.org/kerryrodden/477c1bfb081b783f80ad 6.12955 +nv.models.sunburst = function() { 6.12956 + "use strict"; 6.12957 + 6.12958 + //============================================================ 6.12959 + // Public Variables with Default Settings 6.12960 + //------------------------------------------------------------ 6.12961 + 6.12962 + var margin = {top: 0, right: 0, bottom: 0, left: 0} 6.12963 + , width = null 6.12964 + , height = null 6.12965 + , mode = "count" 6.12966 + , modes = {count: function(d) { return 1; }, size: function(d) { return d.size }} 6.12967 + , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one 6.12968 + , container = null 6.12969 + , color = nv.utils.defaultColor() 6.12970 + , duration = 500 6.12971 + , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMousemove', 'elementMouseover', 'elementMouseout', 'renderEnd') 6.12972 + ; 6.12973 + 6.12974 + var x = d3.scale.linear().range([0, 2 * Math.PI]); 6.12975 + var y = d3.scale.sqrt(); 6.12976 + 6.12977 + var partition = d3.layout.partition() 6.12978 + .sort(null) 6.12979 + .value(function(d) { return 1; }); 6.12980 + 6.12981 + var arc = d3.svg.arc() 6.12982 + .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); }) 6.12983 + .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); }) 6.12984 + .innerRadius(function(d) { return Math.max(0, y(d.y)); }) 6.12985 + .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); }); 6.12986 + 6.12987 + // Keep track of the current and previous node being displayed as the root. 6.12988 + var node, prevNode; 6.12989 + // Keep track of the root node 6.12990 + var rootNode; 6.12991 + 6.12992 + //============================================================ 6.12993 + // chart function 6.12994 + //------------------------------------------------------------ 6.12995 + 6.12996 + var renderWatch = nv.utils.renderWatch(dispatch); 6.12997 + 6.12998 + function chart(selection) { 6.12999 + renderWatch.reset(); 6.13000 + selection.each(function(data) { 6.13001 + container = d3.select(this); 6.13002 + var availableWidth = nv.utils.availableWidth(width, container, margin); 6.13003 + var availableHeight = nv.utils.availableHeight(height, container, margin); 6.13004 + var radius = Math.min(availableWidth, availableHeight) / 2; 6.13005 + var path; 6.13006 + 6.13007 + nv.utils.initSVG(container); 6.13008 + 6.13009 + // Setup containers and skeleton of chart 6.13010 + var wrap = container.selectAll('.nv-wrap.nv-sunburst').data(data); 6.13011 + var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sunburst nv-chart-' + id); 6.13012 + 6.13013 + var g = wrapEnter.selectAll('nv-sunburst'); 6.13014 + 6.13015 + wrap.attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'); 6.13016 + 6.13017 + container.on('click', function (d, i) { 6.13018 + dispatch.chartClick({ 6.13019 + data: d, 6.13020 + index: i, 6.13021 + pos: d3.event, 6.13022 + id: id 6.13023 + }); 6.13024 + }); 6.13025 + 6.13026 + y.range([0, radius]); 6.13027 + 6.13028 + node = node || data; 6.13029 + rootNode = data[0]; 6.13030 + partition.value(modes[mode] || modes["count"]); 6.13031 + path = g.data(partition.nodes).enter() 6.13032 + .append("path") 6.13033 + .attr("d", arc) 6.13034 + .style("fill", function (d) { 6.13035 + return color((d.children ? d : d.parent).name); 6.13036 + }) 6.13037 + .style("stroke", "#FFF") 6.13038 + .on("click", function(d) { 6.13039 + if (prevNode !== node && node !== d) prevNode = node; 6.13040 + node = d; 6.13041 + path.transition() 6.13042 + .duration(duration) 6.13043 + .attrTween("d", arcTweenZoom(d)); 6.13044 + }) 6.13045 + .each(stash) 6.13046 + .on("dblclick", function(d) { 6.13047 + if (prevNode.parent == d) { 6.13048 + path.transition() 6.13049 + .duration(duration) 6.13050 + .attrTween("d", arcTweenZoom(rootNode)); 6.13051 + } 6.13052 + }) 6.13053 + .each(stash) 6.13054 + .on('mouseover', function(d,i){ 6.13055 + d3.select(this).classed('hover', true).style('opacity', 0.8); 6.13056 + dispatch.elementMouseover({ 6.13057 + data: d, 6.13058 + color: d3.select(this).style("fill") 6.13059 + }); 6.13060 + }) 6.13061 + .on('mouseout', function(d,i){ 6.13062 + d3.select(this).classed('hover', false).style('opacity', 1); 6.13063 + dispatch.elementMouseout({ 6.13064 + data: d 6.13065 + }); 6.13066 + }) 6.13067 + .on('mousemove', function(d,i){ 6.13068 + dispatch.elementMousemove({ 6.13069 + data: d 6.13070 + }); 6.13071 + }); 6.13072 + 6.13073 + 6.13074 + 6.13075 + // Setup for switching data: stash the old values for transition. 6.13076 + function stash(d) { 6.13077 + d.x0 = d.x; 6.13078 + d.dx0 = d.dx; 6.13079 + } 6.13080 + 6.13081 + // When switching data: interpolate the arcs in data space. 6.13082 + function arcTweenData(a, i) { 6.13083 + var oi = d3.interpolate({x: a.x0, dx: a.dx0}, a); 6.13084 + 6.13085 + function tween(t) { 6.13086 + var b = oi(t); 6.13087 + a.x0 = b.x; 6.13088 + a.dx0 = b.dx; 6.13089 + return arc(b); 6.13090 + } 6.13091 + 6.13092 + if (i == 0) { 6.13093 + // If we are on the first arc, adjust the x domain to match the root node 6.13094 + // at the current zoom level. (We only need to do this once.) 6.13095 + var xd = d3.interpolate(x.domain(), [node.x, node.x + node.dx]); 6.13096 + return function (t) { 6.13097 + x.domain(xd(t)); 6.13098 + return tween(t); 6.13099 + }; 6.13100 + } else { 6.13101 + return tween; 6.13102 + } 6.13103 + } 6.13104 + 6.13105 + // When zooming: interpolate the scales. 6.13106 + function arcTweenZoom(d) { 6.13107 + var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]), 6.13108 + yd = d3.interpolate(y.domain(), [d.y, 1]), 6.13109 + yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]); 6.13110 + return function (d, i) { 6.13111 + return i 6.13112 + ? function (t) { 6.13113 + return arc(d); 6.13114 + } 6.13115 + : function (t) { 6.13116 + x.domain(xd(t)); 6.13117 + y.domain(yd(t)).range(yr(t)); 6.13118 + return arc(d); 6.13119 + }; 6.13120 + }; 6.13121 + } 6.13122 + 6.13123 + }); 6.13124 + 6.13125 + renderWatch.renderEnd('sunburst immediate'); 6.13126 + return chart; 6.13127 + } 6.13128 + 6.13129 + //============================================================ 6.13130 + // Expose Public Variables 6.13131 + //------------------------------------------------------------ 6.13132 + 6.13133 + chart.dispatch = dispatch; 6.13134 + chart.options = nv.utils.optionsFunc.bind(chart); 6.13135 + 6.13136 + chart._options = Object.create({}, { 6.13137 + // simple options, just get/set the necessary values 6.13138 + width: {get: function(){return width;}, set: function(_){width=_;}}, 6.13139 + height: {get: function(){return height;}, set: function(_){height=_;}}, 6.13140 + mode: {get: function(){return mode;}, set: function(_){mode=_;}}, 6.13141 + id: {get: function(){return id;}, set: function(_){id=_;}}, 6.13142 + duration: {get: function(){return duration;}, set: function(_){duration=_;}}, 6.13143 + 6.13144 + // options that require extra logic in the setter 6.13145 + margin: {get: function(){return margin;}, set: function(_){ 6.13146 + margin.top = _.top != undefined ? _.top : margin.top; 6.13147 + margin.right = _.right != undefined ? _.right : margin.right; 6.13148 + margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom; 6.13149 + margin.left = _.left != undefined ? _.left : margin.left; 6.13150 + }}, 6.13151 + color: {get: function(){return color;}, set: function(_){ 6.13152 + color=nv.utils.getColor(_); 6.13153 + }} 6.13154 + }); 6.13155 + 6.13156 + nv.utils.initOptions(chart); 6.13157 + return chart; 6.13158 +}; 6.13159 +nv.models.sunburstChart = function() { 6.13160 + "use strict"; 6.13161 + 6.13162 + //============================================================ 6.13163 + // Public Variables with Default Settings 6.13164 + //------------------------------------------------------------ 6.13165 + 6.13166 + var sunburst = nv.models.sunburst(); 6.13167 + var tooltip = nv.models.tooltip(); 6.13168 + 6.13169 + var margin = {top: 30, right: 20, bottom: 20, left: 20} 6.13170 + , width = null 6.13171 + , height = null 6.13172 + , color = nv.utils.defaultColor() 6.13173 + , id = Math.round(Math.random() * 100000) 6.13174 + , defaultState = null 6.13175 + , noData = null 6.13176 + , duration = 250 6.13177 + , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd') 6.13178 + ; 6.13179 + 6.13180 + //============================================================ 6.13181 + // Private Variables 6.13182 + //------------------------------------------------------------ 6.13183 + 6.13184 + var renderWatch = nv.utils.renderWatch(dispatch); 6.13185 + tooltip.headerEnabled(false).duration(0).valueFormatter(function(d, i) { 6.13186 + return d; 6.13187 + }); 6.13188 + 6.13189 + //============================================================ 6.13190 + // Chart function 6.13191 + //------------------------------------------------------------ 6.13192 + 6.13193 + function chart(selection) { 6.13194 + renderWatch.reset(); 6.13195 + renderWatch.models(sunburst); 6.13196 + 6.13197 + selection.each(function(data) { 6.13198 + var container = d3.select(this); 6.13199 + nv.utils.initSVG(container); 6.13200 + 6.13201 + var that = this; 6.13202 + var availableWidth = nv.utils.availableWidth(width, container, margin), 6.13203 + availableHeight = nv.utils.availableHeight(height, container, margin); 6.13204 + 6.13205 + chart.update = function() { 6.13206 + if (duration === 0) 6.13207 + container.call(chart); 6.13208 + else 6.13209 + container.transition().duration(duration).call(chart) 6.13210 + }; 6.13211 + chart.container = this; 6.13212 + 6.13213 + // Display No Data message if there's nothing to show. 6.13214 + if (!data || !data.length) { 6.13215 + nv.utils.noData(chart, container); 6.13216 + return chart; 6.13217 + } else { 6.13218 + container.selectAll('.nv-noData').remove(); 6.13219 + } 6.13220 + 6.13221 + // Setup containers and skeleton of chart 6.13222 + var wrap = container.selectAll('g.nv-wrap.nv-sunburstChart').data(data); 6.13223 + var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sunburstChart').append('g'); 6.13224 + var g = wrap.select('g'); 6.13225 + 6.13226 + gEnter.append('g').attr('class', 'nv-sunburstWrap'); 6.13227 + 6.13228 + wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); 6.13229 + 6.13230 + // Main Chart Component(s) 6.13231 + sunburst.width(availableWidth).height(availableHeight); 6.13232 + var sunWrap = g.select('.nv-sunburstWrap').datum(data); 6.13233 + d3.transition(sunWrap).call(sunburst); 6.13234 + 6.13235 + }); 6.13236 + 6.13237 + renderWatch.renderEnd('sunburstChart immediate'); 6.13238 + return chart; 6.13239 + } 6.13240 + 6.13241 + //============================================================ 6.13242 + // Event Handling/Dispatching (out of chart's scope) 6.13243 + //------------------------------------------------------------ 6.13244 + 6.13245 + sunburst.dispatch.on('elementMouseover.tooltip', function(evt) { 6.13246 + evt['series'] = { 6.13247 + key: evt.data.name, 6.13248 + value: evt.data.size, 6.13249 + color: evt.color 6.13250 + }; 6.13251 + tooltip.data(evt).hidden(false); 6.13252 + }); 6.13253 + 6.13254 + sunburst.dispatch.on('elementMouseout.tooltip', function(evt) { 6.13255 + tooltip.hidden(true); 6.13256 + }); 6.13257 + 6.13258 + sunburst.dispatch.on('elementMousemove.tooltip', function(evt) { 6.13259 + tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); 6.13260 + }); 6.13261 + 6.13262 + //============================================================ 6.13263 + // Expose Public Variables 6.13264 + //------------------------------------------------------------ 6.13265 + 6.13266 + // expose chart's sub-components 6.13267 + chart.dispatch = dispatch; 6.13268 + chart.sunburst = sunburst; 6.13269 + chart.tooltip = tooltip; 6.13270 + chart.options = nv.utils.optionsFunc.bind(chart); 6.13271 + 6.13272 + // use Object get/set functionality to map between vars and chart functions 6.13273 + chart._options = Object.create({}, { 6.13274 + // simple options, just get/set the necessary values 6.13275 + noData: {get: function(){return noData;}, set: function(_){noData=_;}}, 6.13276 + defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, 6.13277 + 6.13278 + // options that require extra logic in the setter 6.13279 + color: {get: function(){return color;}, set: function(_){ 6.13280 + color = _; 6.13281 + sunburst.color(color); 6.13282 + }}, 6.13283 + duration: {get: function(){return duration;}, set: function(_){ 6.13284 + duration = _; 6.13285 + renderWatch.reset(duration); 6.13286 + sunburst.duration(duration); 6.13287 + }}, 6.13288 + margin: {get: function(){return margin;}, set: function(_){ 6.13289 + margin.top = _.top !== undefined ? _.top : margin.top; 6.13290 + margin.right = _.right !== undefined ? _.right : margin.right; 6.13291 + margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; 6.13292 + margin.left = _.left !== undefined ? _.left : margin.left; 6.13293 + }} 6.13294 + }); 6.13295 + nv.utils.inheritOptions(chart, sunburst); 6.13296 + nv.utils.initOptions(chart); 6.13297 + return chart; 6.13298 +}; 6.13299 + 6.13300 +nv.version = "1.8.1"; 6.13301 +})(); 6.13302 \ No newline at end of file
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/gtc/simple-statistics.js Sun Feb 19 19:45:31 2017 -0800 7.3 @@ -0,0 +1,3514 @@ 7.4 +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ss = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 7.5 +/* @flow */ 7.6 +'use strict'; 7.7 + 7.8 +// # simple-statistics 7.9 +// 7.10 +// A simple, literate statistics system. 7.11 + 7.12 +var ss = module.exports = {}; 7.13 + 7.14 +// Linear Regression 7.15 +ss.linearRegression = require(21); 7.16 +ss.linearRegressionLine = require(22); 7.17 +ss.standardDeviation = require(54); 7.18 +ss.rSquared = require(43); 7.19 +ss.mode = require(32); 7.20 +ss.modeSorted = require(33); 7.21 +ss.min = require(29); 7.22 +ss.max = require(23); 7.23 +ss.minSorted = require(30); 7.24 +ss.maxSorted = require(24); 7.25 +ss.sum = require(56); 7.26 +ss.sumSimple = require(58); 7.27 +ss.product = require(39); 7.28 +ss.quantile = require(40); 7.29 +ss.quantileSorted = require(41); 7.30 +ss.iqr = ss.interquartileRange = require(19); 7.31 +ss.medianAbsoluteDeviation = ss.mad = require(27); 7.32 +ss.chunk = require(8); 7.33 +ss.shuffle = require(51); 7.34 +ss.shuffleInPlace = require(52); 7.35 +ss.sample = require(45); 7.36 +ss.ckmeans = require(9); 7.37 +ss.uniqueCountSorted = require(61); 7.38 +ss.sumNthPowerDeviations = require(57); 7.39 +ss.equalIntervalBreaks = require(14); 7.40 + 7.41 +// sample statistics 7.42 +ss.sampleCovariance = require(47); 7.43 +ss.sampleCorrelation = require(46); 7.44 +ss.sampleVariance = require(50); 7.45 +ss.sampleStandardDeviation = require(49); 7.46 +ss.sampleSkewness = require(48); 7.47 + 7.48 +// combinatorics 7.49 +ss.permutationsHeap = require(36); 7.50 +ss.combinations = require(10); 7.51 +ss.combinationsReplacement = require(11); 7.52 + 7.53 +// measures of centrality 7.54 +ss.geometricMean = require(17); 7.55 +ss.harmonicMean = require(18); 7.56 +ss.mean = ss.average = require(25); 7.57 +ss.median = require(26); 7.58 +ss.medianSorted = require(28); 7.59 + 7.60 +ss.rootMeanSquare = ss.rms = require(44); 7.61 +ss.variance = require(62); 7.62 +ss.tTest = require(59); 7.63 +ss.tTestTwoSample = require(60); 7.64 +// ss.jenks = require('./src/jenks'); 7.65 + 7.66 +// Classifiers 7.67 +ss.bayesian = require(2); 7.68 +ss.perceptron = require(35); 7.69 + 7.70 +// Distribution-related methods 7.71 +ss.epsilon = require(13); // We make ε available to the test suite. 7.72 +ss.factorial = require(16); 7.73 +ss.bernoulliDistribution = require(3); 7.74 +ss.binomialDistribution = require(4); 7.75 +ss.poissonDistribution = require(37); 7.76 +ss.chiSquaredGoodnessOfFit = require(7); 7.77 + 7.78 +// Normal distribution 7.79 +ss.zScore = require(63); 7.80 +ss.cumulativeStdNormalProbability = require(12); 7.81 +ss.standardNormalTable = require(55); 7.82 +ss.errorFunction = ss.erf = require(15); 7.83 +ss.inverseErrorFunction = require(20); 7.84 +ss.probit = require(38); 7.85 +ss.mixin = require(31); 7.86 + 7.87 +// Root-finding methods 7.88 +ss.bisect = require(5); 7.89 + 7.90 +},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"2":2,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"3":3,"30":30,"31":31,"32":32,"33":33,"35":35,"36":36,"37":37,"38":38,"39":39,"4":4,"40":40,"41":41,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"49":49,"5":5,"50":50,"51":51,"52":52,"54":54,"55":55,"56":56,"57":57,"58":58,"59":59,"60":60,"61":61,"62":62,"63":63,"7":7,"8":8,"9":9}],2:[function(require,module,exports){ 7.91 +'use strict'; 7.92 +/* @flow */ 7.93 + 7.94 +/** 7.95 + * [Bayesian Classifier](http://en.wikipedia.org/wiki/Naive_Bayes_classifier) 7.96 + * 7.97 + * This is a naïve bayesian classifier that takes 7.98 + * singly-nested objects. 7.99 + * 7.100 + * @class 7.101 + * @example 7.102 + * var bayes = new BayesianClassifier(); 7.103 + * bayes.train({ 7.104 + * species: 'Cat' 7.105 + * }, 'animal'); 7.106 + * var result = bayes.score({ 7.107 + * species: 'Cat' 7.108 + * }) 7.109 + * // result 7.110 + * // { 7.111 + * // animal: 1 7.112 + * // } 7.113 + */ 7.114 +function BayesianClassifier() { 7.115 + // The number of items that are currently 7.116 + // classified in the model 7.117 + this.totalCount = 0; 7.118 + // Every item classified in the model 7.119 + this.data = {}; 7.120 +} 7.121 + 7.122 +/** 7.123 + * Train the classifier with a new item, which has a single 7.124 + * dimension of Javascript literal keys and values. 7.125 + * 7.126 + * @param {Object} item an object with singly-deep properties 7.127 + * @param {string} category the category this item belongs to 7.128 + * @return {undefined} adds the item to the classifier 7.129 + */ 7.130 +BayesianClassifier.prototype.train = function(item, category) { 7.131 + // If the data object doesn't have any values 7.132 + // for this category, create a new object for it. 7.133 + if (!this.data[category]) { 7.134 + this.data[category] = {}; 7.135 + } 7.136 + 7.137 + // Iterate through each key in the item. 7.138 + for (var k in item) { 7.139 + var v = item[k]; 7.140 + // Initialize the nested object `data[category][k][item[k]]` 7.141 + // with an object of keys that equal 0. 7.142 + if (this.data[category][k] === undefined) { 7.143 + this.data[category][k] = {}; 7.144 + } 7.145 + if (this.data[category][k][v] === undefined) { 7.146 + this.data[category][k][v] = 0; 7.147 + } 7.148 + 7.149 + // And increment the key for this key/value combination. 7.150 + this.data[category][k][v]++; 7.151 + } 7.152 + 7.153 + // Increment the number of items classified 7.154 + this.totalCount++; 7.155 +}; 7.156 + 7.157 +/** 7.158 + * Generate a score of how well this item matches all 7.159 + * possible categories based on its attributes 7.160 + * 7.161 + * @param {Object} item an item in the same format as with train 7.162 + * @returns {Object} of probabilities that this item belongs to a 7.163 + * given category. 7.164 + */ 7.165 +BayesianClassifier.prototype.score = function(item) { 7.166 + // Initialize an empty array of odds per category. 7.167 + var odds = {}, category; 7.168 + // Iterate through each key in the item, 7.169 + // then iterate through each category that has been used 7.170 + // in previous calls to `.train()` 7.171 + for (var k in item) { 7.172 + var v = item[k]; 7.173 + for (category in this.data) { 7.174 + // Create an empty object for storing key - value combinations 7.175 + // for this category. 7.176 + odds[category] = {}; 7.177 + 7.178 + // If this item doesn't even have a property, it counts for nothing, 7.179 + // but if it does have the property that we're looking for from 7.180 + // the item to categorize, it counts based on how popular it is 7.181 + // versus the whole population. 7.182 + if (this.data[category][k]) { 7.183 + odds[category][k + '_' + v] = (this.data[category][k][v] || 0) / this.totalCount; 7.184 + } else { 7.185 + odds[category][k + '_' + v] = 0; 7.186 + } 7.187 + } 7.188 + } 7.189 + 7.190 + // Set up a new object that will contain sums of these odds by category 7.191 + var oddsSums = {}; 7.192 + 7.193 + for (category in odds) { 7.194 + // Tally all of the odds for each category-combination pair - 7.195 + // the non-existence of a category does not add anything to the 7.196 + // score. 7.197 + oddsSums[category] = 0; 7.198 + for (var combination in odds[category]) { 7.199 + oddsSums[category] += odds[category][combination]; 7.200 + } 7.201 + } 7.202 + 7.203 + return oddsSums; 7.204 +}; 7.205 + 7.206 +module.exports = BayesianClassifier; 7.207 + 7.208 +},{}],3:[function(require,module,exports){ 7.209 +'use strict'; 7.210 +/* @flow */ 7.211 + 7.212 +var binomialDistribution = require(4); 7.213 + 7.214 +/** 7.215 + * The [Bernoulli distribution](http://en.wikipedia.org/wiki/Bernoulli_distribution) 7.216 + * is the probability discrete 7.217 + * distribution of a random variable which takes value 1 with success 7.218 + * probability `p` and value 0 with failure 7.219 + * probability `q` = 1 - `p`. It can be used, for example, to represent the 7.220 + * toss of a coin, where "1" is defined to mean "heads" and "0" is defined 7.221 + * to mean "tails" (or vice versa). It is 7.222 + * a special case of a Binomial Distribution 7.223 + * where `n` = 1. 7.224 + * 7.225 + * @param {number} p input value, between 0 and 1 inclusive 7.226 + * @returns {number} value of bernoulli distribution at this point 7.227 + * @example 7.228 + * bernoulliDistribution(0.5); // => { '0': 0.5, '1': 0.5 } 7.229 + */ 7.230 +function bernoulliDistribution(p/*: number */) { 7.231 + // Check that `p` is a valid probability (0 ≤ p ≤ 1) 7.232 + if (p < 0 || p > 1 ) { return NaN; } 7.233 + 7.234 + return binomialDistribution(1, p); 7.235 +} 7.236 + 7.237 +module.exports = bernoulliDistribution; 7.238 + 7.239 +},{"4":4}],4:[function(require,module,exports){ 7.240 +'use strict'; 7.241 +/* @flow */ 7.242 + 7.243 +var epsilon = require(13); 7.244 +var factorial = require(16); 7.245 + 7.246 +/** 7.247 + * The [Binomial Distribution](http://en.wikipedia.org/wiki/Binomial_distribution) is the discrete probability 7.248 + * distribution of the number of successes in a sequence of n independent yes/no experiments, each of which yields 7.249 + * success with probability `probability`. Such a success/failure experiment is also called a Bernoulli experiment or 7.250 + * Bernoulli trial; when trials = 1, the Binomial Distribution is a Bernoulli Distribution. 7.251 + * 7.252 + * @param {number} trials number of trials to simulate 7.253 + * @param {number} probability 7.254 + * @returns {Object} output 7.255 + */ 7.256 +function binomialDistribution( 7.257 + trials/*: number */, 7.258 + probability/*: number */)/*: ?Object */ { 7.259 + // Check that `p` is a valid probability (0 ≤ p ≤ 1), 7.260 + // that `n` is an integer, strictly positive. 7.261 + if (probability < 0 || probability > 1 || 7.262 + trials <= 0 || trials % 1 !== 0) { 7.263 + return undefined; 7.264 + } 7.265 + 7.266 + // We initialize `x`, the random variable, and `accumulator`, an accumulator 7.267 + // for the cumulative distribution function to 0. `distribution_functions` 7.268 + // is the object we'll return with the `probability_of_x` and the 7.269 + // `cumulativeProbability_of_x`, as well as the calculated mean & 7.270 + // variance. We iterate until the `cumulativeProbability_of_x` is 7.271 + // within `epsilon` of 1.0. 7.272 + var x = 0, 7.273 + cumulativeProbability = 0, 7.274 + cells = {}; 7.275 + 7.276 + // This algorithm iterates through each potential outcome, 7.277 + // until the `cumulativeProbability` is very close to 1, at 7.278 + // which point we've defined the vast majority of outcomes 7.279 + do { 7.280 + // a [probability mass function](https://en.wikipedia.org/wiki/Probability_mass_function) 7.281 + cells[x] = factorial(trials) / 7.282 + (factorial(x) * factorial(trials - x)) * 7.283 + (Math.pow(probability, x) * Math.pow(1 - probability, trials - x)); 7.284 + cumulativeProbability += cells[x]; 7.285 + x++; 7.286 + // when the cumulativeProbability is nearly 1, we've calculated 7.287 + // the useful range of this distribution 7.288 + } while (cumulativeProbability < 1 - epsilon); 7.289 + 7.290 + return cells; 7.291 +} 7.292 + 7.293 +module.exports = binomialDistribution; 7.294 + 7.295 +},{"13":13,"16":16}],5:[function(require,module,exports){ 7.296 +'use strict'; 7.297 +/* @flow */ 7.298 + 7.299 +var sign = require(53); 7.300 +/** 7.301 + * [Bisection method](https://en.wikipedia.org/wiki/Bisection_method) is a root-finding 7.302 + * method that repeatedly bisects an interval to find the root. 7.303 + * 7.304 + * This function returns a numerical approximation to the exact value. 7.305 + * 7.306 + * @param {Function} func input function 7.307 + * @param {Number} start - start of interval 7.308 + * @param {Number} end - end of interval 7.309 + * @param {Number} maxIterations - the maximum number of iterations 7.310 + * @param {Number} errorTolerance - the error tolerance 7.311 + * @returns {Number} estimated root value 7.312 + * @throws {TypeError} Argument func must be a function 7.313 + * 7.314 + * @example 7.315 + * bisect(Math.cos,0,4,100,0.003); // => 1.572265625 7.316 + */ 7.317 +function bisect( 7.318 + func/*: (x: any) => number */, 7.319 + start/*: number */, 7.320 + end/*: number */, 7.321 + maxIterations/*: number */, 7.322 + errorTolerance/*: number */)/*:number*/ { 7.323 + 7.324 + if (typeof func !== 'function') throw new TypeError('func must be a function'); 7.325 + 7.326 + for (var i = 0; i < maxIterations; i++) { 7.327 + var output = (start + end) / 2; 7.328 + 7.329 + if (func(output) === 0 || Math.abs((end - start) / 2) < errorTolerance) { 7.330 + return output; 7.331 + } 7.332 + 7.333 + if (sign(func(output)) === sign(func(start))) { 7.334 + start = output; 7.335 + } else { 7.336 + end = output; 7.337 + } 7.338 + } 7.339 + 7.340 + throw new Error('maximum number of iterations exceeded'); 7.341 +} 7.342 + 7.343 +module.exports = bisect; 7.344 + 7.345 +},{"53":53}],6:[function(require,module,exports){ 7.346 +'use strict'; 7.347 +/* @flow */ 7.348 + 7.349 +/** 7.350 + * **Percentage Points of the χ2 (Chi-Squared) Distribution** 7.351 + * 7.352 + * The [χ2 (Chi-Squared) Distribution](http://en.wikipedia.org/wiki/Chi-squared_distribution) is used in the common 7.353 + * chi-squared tests for goodness of fit of an observed distribution to a theoretical one, the independence of two 7.354 + * criteria of classification of qualitative data, and in confidence interval estimation for a population standard 7.355 + * deviation of a normal distribution from a sample standard deviation. 7.356 + * 7.357 + * Values from Appendix 1, Table III of William W. Hines & Douglas C. Montgomery, "Probability and Statistics in 7.358 + * Engineering and Management Science", Wiley (1980). 7.359 + */ 7.360 +var chiSquaredDistributionTable = { '1': 7.361 + { '0.995': 0, 7.362 + '0.99': 0, 7.363 + '0.975': 0, 7.364 + '0.95': 0, 7.365 + '0.9': 0.02, 7.366 + '0.5': 0.45, 7.367 + '0.1': 2.71, 7.368 + '0.05': 3.84, 7.369 + '0.025': 5.02, 7.370 + '0.01': 6.63, 7.371 + '0.005': 7.88 }, 7.372 + '2': 7.373 + { '0.995': 0.01, 7.374 + '0.99': 0.02, 7.375 + '0.975': 0.05, 7.376 + '0.95': 0.1, 7.377 + '0.9': 0.21, 7.378 + '0.5': 1.39, 7.379 + '0.1': 4.61, 7.380 + '0.05': 5.99, 7.381 + '0.025': 7.38, 7.382 + '0.01': 9.21, 7.383 + '0.005': 10.6 }, 7.384 + '3': 7.385 + { '0.995': 0.07, 7.386 + '0.99': 0.11, 7.387 + '0.975': 0.22, 7.388 + '0.95': 0.35, 7.389 + '0.9': 0.58, 7.390 + '0.5': 2.37, 7.391 + '0.1': 6.25, 7.392 + '0.05': 7.81, 7.393 + '0.025': 9.35, 7.394 + '0.01': 11.34, 7.395 + '0.005': 12.84 }, 7.396 + '4': 7.397 + { '0.995': 0.21, 7.398 + '0.99': 0.3, 7.399 + '0.975': 0.48, 7.400 + '0.95': 0.71, 7.401 + '0.9': 1.06, 7.402 + '0.5': 3.36, 7.403 + '0.1': 7.78, 7.404 + '0.05': 9.49, 7.405 + '0.025': 11.14, 7.406 + '0.01': 13.28, 7.407 + '0.005': 14.86 }, 7.408 + '5': 7.409 + { '0.995': 0.41, 7.410 + '0.99': 0.55, 7.411 + '0.975': 0.83, 7.412 + '0.95': 1.15, 7.413 + '0.9': 1.61, 7.414 + '0.5': 4.35, 7.415 + '0.1': 9.24, 7.416 + '0.05': 11.07, 7.417 + '0.025': 12.83, 7.418 + '0.01': 15.09, 7.419 + '0.005': 16.75 }, 7.420 + '6': 7.421 + { '0.995': 0.68, 7.422 + '0.99': 0.87, 7.423 + '0.975': 1.24, 7.424 + '0.95': 1.64, 7.425 + '0.9': 2.2, 7.426 + '0.5': 5.35, 7.427 + '0.1': 10.65, 7.428 + '0.05': 12.59, 7.429 + '0.025': 14.45, 7.430 + '0.01': 16.81, 7.431 + '0.005': 18.55 }, 7.432 + '7': 7.433 + { '0.995': 0.99, 7.434 + '0.99': 1.25, 7.435 + '0.975': 1.69, 7.436 + '0.95': 2.17, 7.437 + '0.9': 2.83, 7.438 + '0.5': 6.35, 7.439 + '0.1': 12.02, 7.440 + '0.05': 14.07, 7.441 + '0.025': 16.01, 7.442 + '0.01': 18.48, 7.443 + '0.005': 20.28 }, 7.444 + '8': 7.445 + { '0.995': 1.34, 7.446 + '0.99': 1.65, 7.447 + '0.975': 2.18, 7.448 + '0.95': 2.73, 7.449 + '0.9': 3.49, 7.450 + '0.5': 7.34, 7.451 + '0.1': 13.36, 7.452 + '0.05': 15.51, 7.453 + '0.025': 17.53, 7.454 + '0.01': 20.09, 7.455 + '0.005': 21.96 }, 7.456 + '9': 7.457 + { '0.995': 1.73, 7.458 + '0.99': 2.09, 7.459 + '0.975': 2.7, 7.460 + '0.95': 3.33, 7.461 + '0.9': 4.17, 7.462 + '0.5': 8.34, 7.463 + '0.1': 14.68, 7.464 + '0.05': 16.92, 7.465 + '0.025': 19.02, 7.466 + '0.01': 21.67, 7.467 + '0.005': 23.59 }, 7.468 + '10': 7.469 + { '0.995': 2.16, 7.470 + '0.99': 2.56, 7.471 + '0.975': 3.25, 7.472 + '0.95': 3.94, 7.473 + '0.9': 4.87, 7.474 + '0.5': 9.34, 7.475 + '0.1': 15.99, 7.476 + '0.05': 18.31, 7.477 + '0.025': 20.48, 7.478 + '0.01': 23.21, 7.479 + '0.005': 25.19 }, 7.480 + '11': 7.481 + { '0.995': 2.6, 7.482 + '0.99': 3.05, 7.483 + '0.975': 3.82, 7.484 + '0.95': 4.57, 7.485 + '0.9': 5.58, 7.486 + '0.5': 10.34, 7.487 + '0.1': 17.28, 7.488 + '0.05': 19.68, 7.489 + '0.025': 21.92, 7.490 + '0.01': 24.72, 7.491 + '0.005': 26.76 }, 7.492 + '12': 7.493 + { '0.995': 3.07, 7.494 + '0.99': 3.57, 7.495 + '0.975': 4.4, 7.496 + '0.95': 5.23, 7.497 + '0.9': 6.3, 7.498 + '0.5': 11.34, 7.499 + '0.1': 18.55, 7.500 + '0.05': 21.03, 7.501 + '0.025': 23.34, 7.502 + '0.01': 26.22, 7.503 + '0.005': 28.3 }, 7.504 + '13': 7.505 + { '0.995': 3.57, 7.506 + '0.99': 4.11, 7.507 + '0.975': 5.01, 7.508 + '0.95': 5.89, 7.509 + '0.9': 7.04, 7.510 + '0.5': 12.34, 7.511 + '0.1': 19.81, 7.512 + '0.05': 22.36, 7.513 + '0.025': 24.74, 7.514 + '0.01': 27.69, 7.515 + '0.005': 29.82 }, 7.516 + '14': 7.517 + { '0.995': 4.07, 7.518 + '0.99': 4.66, 7.519 + '0.975': 5.63, 7.520 + '0.95': 6.57, 7.521 + '0.9': 7.79, 7.522 + '0.5': 13.34, 7.523 + '0.1': 21.06, 7.524 + '0.05': 23.68, 7.525 + '0.025': 26.12, 7.526 + '0.01': 29.14, 7.527 + '0.005': 31.32 }, 7.528 + '15': 7.529 + { '0.995': 4.6, 7.530 + '0.99': 5.23, 7.531 + '0.975': 6.27, 7.532 + '0.95': 7.26, 7.533 + '0.9': 8.55, 7.534 + '0.5': 14.34, 7.535 + '0.1': 22.31, 7.536 + '0.05': 25, 7.537 + '0.025': 27.49, 7.538 + '0.01': 30.58, 7.539 + '0.005': 32.8 }, 7.540 + '16': 7.541 + { '0.995': 5.14, 7.542 + '0.99': 5.81, 7.543 + '0.975': 6.91, 7.544 + '0.95': 7.96, 7.545 + '0.9': 9.31, 7.546 + '0.5': 15.34, 7.547 + '0.1': 23.54, 7.548 + '0.05': 26.3, 7.549 + '0.025': 28.85, 7.550 + '0.01': 32, 7.551 + '0.005': 34.27 }, 7.552 + '17': 7.553 + { '0.995': 5.7, 7.554 + '0.99': 6.41, 7.555 + '0.975': 7.56, 7.556 + '0.95': 8.67, 7.557 + '0.9': 10.09, 7.558 + '0.5': 16.34, 7.559 + '0.1': 24.77, 7.560 + '0.05': 27.59, 7.561 + '0.025': 30.19, 7.562 + '0.01': 33.41, 7.563 + '0.005': 35.72 }, 7.564 + '18': 7.565 + { '0.995': 6.26, 7.566 + '0.99': 7.01, 7.567 + '0.975': 8.23, 7.568 + '0.95': 9.39, 7.569 + '0.9': 10.87, 7.570 + '0.5': 17.34, 7.571 + '0.1': 25.99, 7.572 + '0.05': 28.87, 7.573 + '0.025': 31.53, 7.574 + '0.01': 34.81, 7.575 + '0.005': 37.16 }, 7.576 + '19': 7.577 + { '0.995': 6.84, 7.578 + '0.99': 7.63, 7.579 + '0.975': 8.91, 7.580 + '0.95': 10.12, 7.581 + '0.9': 11.65, 7.582 + '0.5': 18.34, 7.583 + '0.1': 27.2, 7.584 + '0.05': 30.14, 7.585 + '0.025': 32.85, 7.586 + '0.01': 36.19, 7.587 + '0.005': 38.58 }, 7.588 + '20': 7.589 + { '0.995': 7.43, 7.590 + '0.99': 8.26, 7.591 + '0.975': 9.59, 7.592 + '0.95': 10.85, 7.593 + '0.9': 12.44, 7.594 + '0.5': 19.34, 7.595 + '0.1': 28.41, 7.596 + '0.05': 31.41, 7.597 + '0.025': 34.17, 7.598 + '0.01': 37.57, 7.599 + '0.005': 40 }, 7.600 + '21': 7.601 + { '0.995': 8.03, 7.602 + '0.99': 8.9, 7.603 + '0.975': 10.28, 7.604 + '0.95': 11.59, 7.605 + '0.9': 13.24, 7.606 + '0.5': 20.34, 7.607 + '0.1': 29.62, 7.608 + '0.05': 32.67, 7.609 + '0.025': 35.48, 7.610 + '0.01': 38.93, 7.611 + '0.005': 41.4 }, 7.612 + '22': 7.613 + { '0.995': 8.64, 7.614 + '0.99': 9.54, 7.615 + '0.975': 10.98, 7.616 + '0.95': 12.34, 7.617 + '0.9': 14.04, 7.618 + '0.5': 21.34, 7.619 + '0.1': 30.81, 7.620 + '0.05': 33.92, 7.621 + '0.025': 36.78, 7.622 + '0.01': 40.29, 7.623 + '0.005': 42.8 }, 7.624 + '23': 7.625 + { '0.995': 9.26, 7.626 + '0.99': 10.2, 7.627 + '0.975': 11.69, 7.628 + '0.95': 13.09, 7.629 + '0.9': 14.85, 7.630 + '0.5': 22.34, 7.631 + '0.1': 32.01, 7.632 + '0.05': 35.17, 7.633 + '0.025': 38.08, 7.634 + '0.01': 41.64, 7.635 + '0.005': 44.18 }, 7.636 + '24': 7.637 + { '0.995': 9.89, 7.638 + '0.99': 10.86, 7.639 + '0.975': 12.4, 7.640 + '0.95': 13.85, 7.641 + '0.9': 15.66, 7.642 + '0.5': 23.34, 7.643 + '0.1': 33.2, 7.644 + '0.05': 36.42, 7.645 + '0.025': 39.36, 7.646 + '0.01': 42.98, 7.647 + '0.005': 45.56 }, 7.648 + '25': 7.649 + { '0.995': 10.52, 7.650 + '0.99': 11.52, 7.651 + '0.975': 13.12, 7.652 + '0.95': 14.61, 7.653 + '0.9': 16.47, 7.654 + '0.5': 24.34, 7.655 + '0.1': 34.28, 7.656 + '0.05': 37.65, 7.657 + '0.025': 40.65, 7.658 + '0.01': 44.31, 7.659 + '0.005': 46.93 }, 7.660 + '26': 7.661 + { '0.995': 11.16, 7.662 + '0.99': 12.2, 7.663 + '0.975': 13.84, 7.664 + '0.95': 15.38, 7.665 + '0.9': 17.29, 7.666 + '0.5': 25.34, 7.667 + '0.1': 35.56, 7.668 + '0.05': 38.89, 7.669 + '0.025': 41.92, 7.670 + '0.01': 45.64, 7.671 + '0.005': 48.29 }, 7.672 + '27': 7.673 + { '0.995': 11.81, 7.674 + '0.99': 12.88, 7.675 + '0.975': 14.57, 7.676 + '0.95': 16.15, 7.677 + '0.9': 18.11, 7.678 + '0.5': 26.34, 7.679 + '0.1': 36.74, 7.680 + '0.05': 40.11, 7.681 + '0.025': 43.19, 7.682 + '0.01': 46.96, 7.683 + '0.005': 49.65 }, 7.684 + '28': 7.685 + { '0.995': 12.46, 7.686 + '0.99': 13.57, 7.687 + '0.975': 15.31, 7.688 + '0.95': 16.93, 7.689 + '0.9': 18.94, 7.690 + '0.5': 27.34, 7.691 + '0.1': 37.92, 7.692 + '0.05': 41.34, 7.693 + '0.025': 44.46, 7.694 + '0.01': 48.28, 7.695 + '0.005': 50.99 }, 7.696 + '29': 7.697 + { '0.995': 13.12, 7.698 + '0.99': 14.26, 7.699 + '0.975': 16.05, 7.700 + '0.95': 17.71, 7.701 + '0.9': 19.77, 7.702 + '0.5': 28.34, 7.703 + '0.1': 39.09, 7.704 + '0.05': 42.56, 7.705 + '0.025': 45.72, 7.706 + '0.01': 49.59, 7.707 + '0.005': 52.34 }, 7.708 + '30': 7.709 + { '0.995': 13.79, 7.710 + '0.99': 14.95, 7.711 + '0.975': 16.79, 7.712 + '0.95': 18.49, 7.713 + '0.9': 20.6, 7.714 + '0.5': 29.34, 7.715 + '0.1': 40.26, 7.716 + '0.05': 43.77, 7.717 + '0.025': 46.98, 7.718 + '0.01': 50.89, 7.719 + '0.005': 53.67 }, 7.720 + '40': 7.721 + { '0.995': 20.71, 7.722 + '0.99': 22.16, 7.723 + '0.975': 24.43, 7.724 + '0.95': 26.51, 7.725 + '0.9': 29.05, 7.726 + '0.5': 39.34, 7.727 + '0.1': 51.81, 7.728 + '0.05': 55.76, 7.729 + '0.025': 59.34, 7.730 + '0.01': 63.69, 7.731 + '0.005': 66.77 }, 7.732 + '50': 7.733 + { '0.995': 27.99, 7.734 + '0.99': 29.71, 7.735 + '0.975': 32.36, 7.736 + '0.95': 34.76, 7.737 + '0.9': 37.69, 7.738 + '0.5': 49.33, 7.739 + '0.1': 63.17, 7.740 + '0.05': 67.5, 7.741 + '0.025': 71.42, 7.742 + '0.01': 76.15, 7.743 + '0.005': 79.49 }, 7.744 + '60': 7.745 + { '0.995': 35.53, 7.746 + '0.99': 37.48, 7.747 + '0.975': 40.48, 7.748 + '0.95': 43.19, 7.749 + '0.9': 46.46, 7.750 + '0.5': 59.33, 7.751 + '0.1': 74.4, 7.752 + '0.05': 79.08, 7.753 + '0.025': 83.3, 7.754 + '0.01': 88.38, 7.755 + '0.005': 91.95 }, 7.756 + '70': 7.757 + { '0.995': 43.28, 7.758 + '0.99': 45.44, 7.759 + '0.975': 48.76, 7.760 + '0.95': 51.74, 7.761 + '0.9': 55.33, 7.762 + '0.5': 69.33, 7.763 + '0.1': 85.53, 7.764 + '0.05': 90.53, 7.765 + '0.025': 95.02, 7.766 + '0.01': 100.42, 7.767 + '0.005': 104.22 }, 7.768 + '80': 7.769 + { '0.995': 51.17, 7.770 + '0.99': 53.54, 7.771 + '0.975': 57.15, 7.772 + '0.95': 60.39, 7.773 + '0.9': 64.28, 7.774 + '0.5': 79.33, 7.775 + '0.1': 96.58, 7.776 + '0.05': 101.88, 7.777 + '0.025': 106.63, 7.778 + '0.01': 112.33, 7.779 + '0.005': 116.32 }, 7.780 + '90': 7.781 + { '0.995': 59.2, 7.782 + '0.99': 61.75, 7.783 + '0.975': 65.65, 7.784 + '0.95': 69.13, 7.785 + '0.9': 73.29, 7.786 + '0.5': 89.33, 7.787 + '0.1': 107.57, 7.788 + '0.05': 113.14, 7.789 + '0.025': 118.14, 7.790 + '0.01': 124.12, 7.791 + '0.005': 128.3 }, 7.792 + '100': 7.793 + { '0.995': 67.33, 7.794 + '0.99': 70.06, 7.795 + '0.975': 74.22, 7.796 + '0.95': 77.93, 7.797 + '0.9': 82.36, 7.798 + '0.5': 99.33, 7.799 + '0.1': 118.5, 7.800 + '0.05': 124.34, 7.801 + '0.025': 129.56, 7.802 + '0.01': 135.81, 7.803 + '0.005': 140.17 } }; 7.804 + 7.805 +module.exports = chiSquaredDistributionTable; 7.806 + 7.807 +},{}],7:[function(require,module,exports){ 7.808 +'use strict'; 7.809 +/* @flow */ 7.810 + 7.811 +var mean = require(25); 7.812 +var chiSquaredDistributionTable = require(6); 7.813 + 7.814 +/** 7.815 + * The [χ2 (Chi-Squared) Goodness-of-Fit Test](http://en.wikipedia.org/wiki/Goodness_of_fit#Pearson.27s_chi-squared_test) 7.816 + * uses a measure of goodness of fit which is the sum of differences between observed and expected outcome frequencies 7.817 + * (that is, counts of observations), each squared and divided by the number of observations expected given the 7.818 + * hypothesized distribution. The resulting χ2 statistic, `chiSquared`, can be compared to the chi-squared distribution 7.819 + * to determine the goodness of fit. In order to determine the degrees of freedom of the chi-squared distribution, one 7.820 + * takes the total number of observed frequencies and subtracts the number of estimated parameters. The test statistic 7.821 + * follows, approximately, a chi-square distribution with (k − c) degrees of freedom where `k` is the number of non-empty 7.822 + * cells and `c` is the number of estimated parameters for the distribution. 7.823 + * 7.824 + * @param {Array<number>} data 7.825 + * @param {Function} distributionType a function that returns a point in a distribution: 7.826 + * for instance, binomial, bernoulli, or poisson 7.827 + * @param {number} significance 7.828 + * @returns {number} chi squared goodness of fit 7.829 + * @example 7.830 + * // Data from Poisson goodness-of-fit example 10-19 in William W. Hines & Douglas C. Montgomery, 7.831 + * // "Probability and Statistics in Engineering and Management Science", Wiley (1980). 7.832 + * var data1019 = [ 7.833 + * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7.834 + * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7.835 + * 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7.836 + * 2, 2, 2, 2, 2, 2, 2, 2, 2, 7.837 + * 3, 3, 3, 3 7.838 + * ]; 7.839 + * ss.chiSquaredGoodnessOfFit(data1019, ss.poissonDistribution, 0.05)); //= false 7.840 + */ 7.841 +function chiSquaredGoodnessOfFit( 7.842 + data/*: Array<number> */, 7.843 + distributionType/*: Function */, 7.844 + significance/*: number */)/*: boolean */ { 7.845 + // Estimate from the sample data, a weighted mean. 7.846 + var inputMean = mean(data), 7.847 + // Calculated value of the χ2 statistic. 7.848 + chiSquared = 0, 7.849 + // Degrees of freedom, calculated as (number of class intervals - 7.850 + // number of hypothesized distribution parameters estimated - 1) 7.851 + degreesOfFreedom, 7.852 + // Number of hypothesized distribution parameters estimated, expected to be supplied in the distribution test. 7.853 + // Lose one degree of freedom for estimating `lambda` from the sample data. 7.854 + c = 1, 7.855 + // The hypothesized distribution. 7.856 + // Generate the hypothesized distribution. 7.857 + hypothesizedDistribution = distributionType(inputMean), 7.858 + observedFrequencies = [], 7.859 + expectedFrequencies = [], 7.860 + k; 7.861 + 7.862 + // Create an array holding a histogram from the sample data, of 7.863 + // the form `{ value: numberOfOcurrences }` 7.864 + for (var i = 0; i < data.length; i++) { 7.865 + if (observedFrequencies[data[i]] === undefined) { 7.866 + observedFrequencies[data[i]] = 0; 7.867 + } 7.868 + observedFrequencies[data[i]]++; 7.869 + } 7.870 + 7.871 + // The histogram we created might be sparse - there might be gaps 7.872 + // between values. So we iterate through the histogram, making 7.873 + // sure that instead of undefined, gaps have 0 values. 7.874 + for (i = 0; i < observedFrequencies.length; i++) { 7.875 + if (observedFrequencies[i] === undefined) { 7.876 + observedFrequencies[i] = 0; 7.877 + } 7.878 + } 7.879 + 7.880 + // Create an array holding a histogram of expected data given the 7.881 + // sample size and hypothesized distribution. 7.882 + for (k in hypothesizedDistribution) { 7.883 + if (k in observedFrequencies) { 7.884 + expectedFrequencies[+k] = hypothesizedDistribution[k] * data.length; 7.885 + } 7.886 + } 7.887 + 7.888 + // Working backward through the expected frequencies, collapse classes 7.889 + // if less than three observations are expected for a class. 7.890 + // This transformation is applied to the observed frequencies as well. 7.891 + for (k = expectedFrequencies.length - 1; k >= 0; k--) { 7.892 + if (expectedFrequencies[k] < 3) { 7.893 + expectedFrequencies[k - 1] += expectedFrequencies[k]; 7.894 + expectedFrequencies.pop(); 7.895 + 7.896 + observedFrequencies[k - 1] += observedFrequencies[k]; 7.897 + observedFrequencies.pop(); 7.898 + } 7.899 + } 7.900 + 7.901 + // Iterate through the squared differences between observed & expected 7.902 + // frequencies, accumulating the `chiSquared` statistic. 7.903 + for (k = 0; k < observedFrequencies.length; k++) { 7.904 + chiSquared += Math.pow( 7.905 + observedFrequencies[k] - expectedFrequencies[k], 2) / 7.906 + expectedFrequencies[k]; 7.907 + } 7.908 + 7.909 + // Calculate degrees of freedom for this test and look it up in the 7.910 + // `chiSquaredDistributionTable` in order to 7.911 + // accept or reject the goodness-of-fit of the hypothesized distribution. 7.912 + degreesOfFreedom = observedFrequencies.length - c - 1; 7.913 + return chiSquaredDistributionTable[degreesOfFreedom][significance] < chiSquared; 7.914 +} 7.915 + 7.916 +module.exports = chiSquaredGoodnessOfFit; 7.917 + 7.918 +},{"25":25,"6":6}],8:[function(require,module,exports){ 7.919 +'use strict'; 7.920 +/* @flow */ 7.921 + 7.922 +/** 7.923 + * Split an array into chunks of a specified size. This function 7.924 + * has the same behavior as [PHP's array_chunk](http://php.net/manual/en/function.array-chunk.php) 7.925 + * function, and thus will insert smaller-sized chunks at the end if 7.926 + * the input size is not divisible by the chunk size. 7.927 + * 7.928 + * `sample` is expected to be an array, and `chunkSize` a number. 7.929 + * The `sample` array can contain any kind of data. 7.930 + * 7.931 + * @param {Array} sample any array of values 7.932 + * @param {number} chunkSize size of each output array 7.933 + * @returns {Array<Array>} a chunked array 7.934 + * @example 7.935 + * chunk([1, 2, 3, 4, 5, 6], 2); 7.936 + * // => [[1, 2], [3, 4], [5, 6]] 7.937 + */ 7.938 +function chunk(sample/*:Array<any>*/, chunkSize/*:number*/)/*:?Array<Array<any>>*/ { 7.939 + 7.940 + // a list of result chunks, as arrays in an array 7.941 + var output = []; 7.942 + 7.943 + // `chunkSize` must be zero or higher - otherwise the loop below, 7.944 + // in which we call `start += chunkSize`, will loop infinitely. 7.945 + // So, we'll detect and throw in that case to indicate 7.946 + // invalid input. 7.947 + if (chunkSize <= 0) { 7.948 + throw new Error('chunk size must be a positive integer'); 7.949 + } 7.950 + 7.951 + // `start` is the index at which `.slice` will start selecting 7.952 + // new array elements 7.953 + for (var start = 0; start < sample.length; start += chunkSize) { 7.954 + 7.955 + // for each chunk, slice that part of the array and add it 7.956 + // to the output. The `.slice` function does not change 7.957 + // the original array. 7.958 + output.push(sample.slice(start, start + chunkSize)); 7.959 + } 7.960 + return output; 7.961 +} 7.962 + 7.963 +module.exports = chunk; 7.964 + 7.965 +},{}],9:[function(require,module,exports){ 7.966 +'use strict'; 7.967 +/* @flow */ 7.968 + 7.969 +var uniqueCountSorted = require(61), 7.970 + numericSort = require(34); 7.971 + 7.972 +/** 7.973 + * Create a new column x row matrix. 7.974 + * 7.975 + * @private 7.976 + * @param {number} columns 7.977 + * @param {number} rows 7.978 + * @return {Array<Array<number>>} matrix 7.979 + * @example 7.980 + * makeMatrix(10, 10); 7.981 + */ 7.982 +function makeMatrix(columns, rows) { 7.983 + var matrix = []; 7.984 + for (var i = 0; i < columns; i++) { 7.985 + var column = []; 7.986 + for (var j = 0; j < rows; j++) { 7.987 + column.push(0); 7.988 + } 7.989 + matrix.push(column); 7.990 + } 7.991 + return matrix; 7.992 +} 7.993 + 7.994 +/** 7.995 + * Generates incrementally computed values based on the sums and sums of 7.996 + * squares for the data array 7.997 + * 7.998 + * @private 7.999 + * @param {number} j 7.1000 + * @param {number} i 7.1001 + * @param {Array<number>} sums 7.1002 + * @param {Array<number>} sumsOfSquares 7.1003 + * @return {number} 7.1004 + * @example 7.1005 + * ssq(0, 1, [-1, 0, 2], [1, 1, 5]); 7.1006 + */ 7.1007 +function ssq(j, i, sums, sumsOfSquares) { 7.1008 + var sji; // s(j, i) 7.1009 + if (j > 0) { 7.1010 + var muji = (sums[i] - sums[j - 1]) / (i - j + 1); // mu(j, i) 7.1011 + sji = sumsOfSquares[i] - sumsOfSquares[j - 1] - (i - j + 1) * muji * muji; 7.1012 + } else { 7.1013 + sji = sumsOfSquares[i] - sums[i] * sums[i] / (i + 1); 7.1014 + } 7.1015 + if (sji < 0) { 7.1016 + return 0; 7.1017 + } 7.1018 + return sji; 7.1019 +} 7.1020 + 7.1021 +/** 7.1022 + * Function that recursively divides and conquers computations 7.1023 + * for cluster j 7.1024 + * 7.1025 + * @private 7.1026 + * @param {number} iMin Minimum index in cluster to be computed 7.1027 + * @param {number} iMax Maximum index in cluster to be computed 7.1028 + * @param {number} cluster Index of the cluster currently being computed 7.1029 + * @param {Array<Array<number>>} matrix 7.1030 + * @param {Array<Array<number>>} backtrackMatrix 7.1031 + * @param {Array<number>} sums 7.1032 + * @param {Array<number>} sumsOfSquares 7.1033 + */ 7.1034 +function fillMatrixColumn(iMin, iMax, cluster, matrix, backtrackMatrix, sums, sumsOfSquares) { 7.1035 + if (iMin > iMax) { 7.1036 + return; 7.1037 + } 7.1038 + 7.1039 + // Start at midpoint between iMin and iMax 7.1040 + var i = Math.floor((iMin + iMax) / 2); 7.1041 + 7.1042 + matrix[cluster][i] = matrix[cluster - 1][i - 1]; 7.1043 + backtrackMatrix[cluster][i] = i; 7.1044 + 7.1045 + var jlow = cluster; // the lower end for j 7.1046 + 7.1047 + if (iMin > cluster) { 7.1048 + jlow = Math.max(jlow, backtrackMatrix[cluster][iMin - 1] || 0); 7.1049 + } 7.1050 + jlow = Math.max(jlow, backtrackMatrix[cluster - 1][i] || 0); 7.1051 + 7.1052 + var jhigh = i - 1; // the upper end for j 7.1053 + if (iMax < matrix.length - 1) { 7.1054 + jhigh = Math.min(jhigh, backtrackMatrix[cluster][iMax + 1] || 0); 7.1055 + } 7.1056 + 7.1057 + var sji; 7.1058 + var sjlowi; 7.1059 + var ssqjlow; 7.1060 + var ssqj; 7.1061 + for (var j = jhigh; j >= jlow; --j) { 7.1062 + sji = ssq(j, i, sums, sumsOfSquares); 7.1063 + 7.1064 + if (sji + matrix[cluster - 1][jlow - 1] >= matrix[cluster][i]) { 7.1065 + break; 7.1066 + } 7.1067 + 7.1068 + // Examine the lower bound of the cluster border 7.1069 + sjlowi = ssq(jlow, i, sums, sumsOfSquares); 7.1070 + 7.1071 + ssqjlow = sjlowi + matrix[cluster - 1][jlow - 1]; 7.1072 + 7.1073 + if (ssqjlow < matrix[cluster][i]) { 7.1074 + // Shrink the lower bound 7.1075 + matrix[cluster][i] = ssqjlow; 7.1076 + backtrackMatrix[cluster][i] = jlow; 7.1077 + } 7.1078 + jlow++; 7.1079 + 7.1080 + ssqj = sji + matrix[cluster - 1][j - 1]; 7.1081 + if (ssqj < matrix[cluster][i]) { 7.1082 + matrix[cluster][i] = ssqj; 7.1083 + backtrackMatrix[cluster][i] = j; 7.1084 + } 7.1085 + } 7.1086 + 7.1087 + fillMatrixColumn(iMin, i - 1, cluster, matrix, backtrackMatrix, sums, sumsOfSquares); 7.1088 + fillMatrixColumn(i + 1, iMax, cluster, matrix, backtrackMatrix, sums, sumsOfSquares); 7.1089 +} 7.1090 + 7.1091 +/** 7.1092 + * Initializes the main matrices used in Ckmeans and kicks 7.1093 + * off the divide and conquer cluster computation strategy 7.1094 + * 7.1095 + * @private 7.1096 + * @param {Array<number>} data sorted array of values 7.1097 + * @param {Array<Array<number>>} matrix 7.1098 + * @param {Array<Array<number>>} backtrackMatrix 7.1099 + */ 7.1100 +function fillMatrices(data, matrix, backtrackMatrix) { 7.1101 + var nValues = matrix[0].length; 7.1102 + 7.1103 + // Shift values by the median to improve numeric stability 7.1104 + var shift = data[Math.floor(nValues / 2)]; 7.1105 + 7.1106 + // Cumulative sum and cumulative sum of squares for all values in data array 7.1107 + var sums = []; 7.1108 + var sumsOfSquares = []; 7.1109 + 7.1110 + // Initialize first column in matrix & backtrackMatrix 7.1111 + for (var i = 0, shiftedValue; i < nValues; ++i) { 7.1112 + shiftedValue = data[i] - shift; 7.1113 + if (i === 0) { 7.1114 + sums.push(shiftedValue); 7.1115 + sumsOfSquares.push(shiftedValue * shiftedValue); 7.1116 + } else { 7.1117 + sums.push(sums[i - 1] + shiftedValue); 7.1118 + sumsOfSquares.push(sumsOfSquares[i - 1] + shiftedValue * shiftedValue); 7.1119 + } 7.1120 + 7.1121 + // Initialize for cluster = 0 7.1122 + matrix[0][i] = ssq(0, i, sums, sumsOfSquares); 7.1123 + backtrackMatrix[0][i] = 0; 7.1124 + } 7.1125 + 7.1126 + // Initialize the rest of the columns 7.1127 + var iMin; 7.1128 + for (var cluster = 1; cluster < matrix.length; ++cluster) { 7.1129 + if (cluster < matrix.length - 1) { 7.1130 + iMin = cluster; 7.1131 + } else { 7.1132 + // No need to compute matrix[K-1][0] ... matrix[K-1][N-2] 7.1133 + iMin = nValues - 1; 7.1134 + } 7.1135 + 7.1136 + fillMatrixColumn(iMin, nValues - 1, cluster, matrix, backtrackMatrix, sums, sumsOfSquares); 7.1137 + } 7.1138 +} 7.1139 + 7.1140 +/** 7.1141 + * Ckmeans clustering is an improvement on heuristic-based clustering 7.1142 + * approaches like Jenks. The algorithm was developed in 7.1143 + * [Haizhou Wang and Mingzhou Song](http://journal.r-project.org/archive/2011-2/RJournal_2011-2_Wang+Song.pdf) 7.1144 + * as a [dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming) approach 7.1145 + * to the problem of clustering numeric data into groups with the least 7.1146 + * within-group sum-of-squared-deviations. 7.1147 + * 7.1148 + * Minimizing the difference within groups - what Wang & Song refer to as 7.1149 + * `withinss`, or within sum-of-squares, means that groups are optimally 7.1150 + * homogenous within and the data is split into representative groups. 7.1151 + * This is very useful for visualization, where you may want to represent 7.1152 + * a continuous variable in discrete color or style groups. This function 7.1153 + * can provide groups that emphasize differences between data. 7.1154 + * 7.1155 + * Being a dynamic approach, this algorithm is based on two matrices that 7.1156 + * store incrementally-computed values for squared deviations and backtracking 7.1157 + * indexes. 7.1158 + * 7.1159 + * This implementation is based on Ckmeans 3.4.6, which introduced a new divide 7.1160 + * and conquer approach that improved runtime from O(kn^2) to O(kn log(n)). 7.1161 + * 7.1162 + * Unlike the [original implementation](https://cran.r-project.org/web/packages/Ckmeans.1d.dp/index.html), 7.1163 + * this implementation does not include any code to automatically determine 7.1164 + * the optimal number of clusters: this information needs to be explicitly 7.1165 + * provided. 7.1166 + * 7.1167 + * ### References 7.1168 + * _Ckmeans.1d.dp: Optimal k-means Clustering in One Dimension by Dynamic 7.1169 + * Programming_ Haizhou Wang and Mingzhou Song ISSN 2073-4859 7.1170 + * 7.1171 + * from The R Journal Vol. 3/2, December 2011 7.1172 + * @param {Array<number>} data input data, as an array of number values 7.1173 + * @param {number} nClusters number of desired classes. This cannot be 7.1174 + * greater than the number of values in the data array. 7.1175 + * @returns {Array<Array<number>>} clustered input 7.1176 + * @example 7.1177 + * ckmeans([-1, 2, -1, 2, 4, 5, 6, -1, 2, -1], 3); 7.1178 + * // The input, clustered into groups of similar numbers. 7.1179 + * //= [[-1, -1, -1, -1], [2, 2, 2], [4, 5, 6]]); 7.1180 + */ 7.1181 +function ckmeans(data/*: Array<number> */, nClusters/*: number */)/*: Array<Array<number>> */ { 7.1182 + 7.1183 + if (nClusters > data.length) { 7.1184 + throw new Error('Cannot generate more classes than there are data values'); 7.1185 + } 7.1186 + 7.1187 + var sorted = numericSort(data), 7.1188 + // we'll use this as the maximum number of clusters 7.1189 + uniqueCount = uniqueCountSorted(sorted); 7.1190 + 7.1191 + // if all of the input values are identical, there's one cluster 7.1192 + // with all of the input in it. 7.1193 + if (uniqueCount === 1) { 7.1194 + return [sorted]; 7.1195 + } 7.1196 + 7.1197 + // named 'S' originally 7.1198 + var matrix = makeMatrix(nClusters, sorted.length), 7.1199 + // named 'J' originally 7.1200 + backtrackMatrix = makeMatrix(nClusters, sorted.length); 7.1201 + 7.1202 + // This is a dynamic programming way to solve the problem of minimizing 7.1203 + // within-cluster sum of squares. It's similar to linear regression 7.1204 + // in this way, and this calculation incrementally computes the 7.1205 + // sum of squares that are later read. 7.1206 + fillMatrices(sorted, matrix, backtrackMatrix); 7.1207 + 7.1208 + // The real work of Ckmeans clustering happens in the matrix generation: 7.1209 + // the generated matrices encode all possible clustering combinations, and 7.1210 + // once they're generated we can solve for the best clustering groups 7.1211 + // very quickly. 7.1212 + var clusters = [], 7.1213 + clusterRight = backtrackMatrix[0].length - 1; 7.1214 + 7.1215 + // Backtrack the clusters from the dynamic programming matrix. This 7.1216 + // starts at the bottom-right corner of the matrix (if the top-left is 0, 0), 7.1217 + // and moves the cluster target with the loop. 7.1218 + for (var cluster = backtrackMatrix.length - 1; cluster >= 0; cluster--) { 7.1219 + 7.1220 + var clusterLeft = backtrackMatrix[cluster][clusterRight]; 7.1221 + 7.1222 + // fill the cluster from the sorted input by taking a slice of the 7.1223 + // array. the backtrack matrix makes this easy - it stores the 7.1224 + // indexes where the cluster should start and end. 7.1225 + clusters[cluster] = sorted.slice(clusterLeft, clusterRight + 1); 7.1226 + 7.1227 + if (cluster > 0) { 7.1228 + clusterRight = clusterLeft - 1; 7.1229 + } 7.1230 + } 7.1231 + 7.1232 + return clusters; 7.1233 +} 7.1234 + 7.1235 +module.exports = ckmeans; 7.1236 + 7.1237 +},{"34":34,"61":61}],10:[function(require,module,exports){ 7.1238 +/* @flow */ 7.1239 +'use strict'; 7.1240 +/** 7.1241 + * Implementation of Combinations 7.1242 + * Combinations are unique subsets of a collection - in this case, k elements from a collection at a time. 7.1243 + * https://en.wikipedia.org/wiki/Combination 7.1244 + * @param {Array} elements any type of data 7.1245 + * @param {int} k the number of objects in each group (without replacement) 7.1246 + * @returns {Array<Array>} array of permutations 7.1247 + * @example 7.1248 + * combinations([1, 2, 3], 2); // => [[1,2], [1,3], [2,3]] 7.1249 + */ 7.1250 + 7.1251 +function combinations(elements /*: Array<any> */, k/*: number */) { 7.1252 + var i; 7.1253 + var subI; 7.1254 + var combinationList = []; 7.1255 + var subsetCombinations; 7.1256 + var next; 7.1257 + 7.1258 + for (i = 0; i < elements.length; i++) { 7.1259 + if (k === 1) { 7.1260 + combinationList.push([elements[i]]) 7.1261 + } else { 7.1262 + subsetCombinations = combinations(elements.slice( i + 1, elements.length ), k - 1); 7.1263 + for (subI = 0; subI < subsetCombinations.length; subI++) { 7.1264 + next = subsetCombinations[subI]; 7.1265 + next.unshift(elements[i]); 7.1266 + combinationList.push(next); 7.1267 + } 7.1268 + } 7.1269 + } 7.1270 + return combinationList; 7.1271 +} 7.1272 + 7.1273 +module.exports = combinations; 7.1274 + 7.1275 +},{}],11:[function(require,module,exports){ 7.1276 +/* @flow */ 7.1277 +'use strict'; 7.1278 + 7.1279 +/** 7.1280 + * Implementation of [Combinations](https://en.wikipedia.org/wiki/Combination) with replacement 7.1281 + * Combinations are unique subsets of a collection - in this case, k elements from a collection at a time. 7.1282 + * 'With replacement' means that a given element can be chosen multiple times. 7.1283 + * Unlike permutation, order doesn't matter for combinations. 7.1284 + * 7.1285 + * @param {Array} elements any type of data 7.1286 + * @param {int} k the number of objects in each group (without replacement) 7.1287 + * @returns {Array<Array>} array of permutations 7.1288 + * @example 7.1289 + * combinationsReplacement([1, 2], 2); // => [[1, 1], [1, 2], [2, 2]] 7.1290 + */ 7.1291 +function combinationsReplacement( 7.1292 + elements /*: Array<any> */, 7.1293 + k /*: number */) { 7.1294 + 7.1295 + var combinationList = []; 7.1296 + 7.1297 + for (var i = 0; i < elements.length; i++) { 7.1298 + if (k === 1) { 7.1299 + // If we're requested to find only one element, we don't need 7.1300 + // to recurse: just push `elements[i]` onto the list of combinations. 7.1301 + combinationList.push([elements[i]]) 7.1302 + } else { 7.1303 + // Otherwise, recursively find combinations, given `k - 1`. Note that 7.1304 + // we request `k - 1`, so if you were looking for k=3 combinations, we're 7.1305 + // requesting k=2. This -1 gets reversed in the for loop right after this 7.1306 + // code, since we concatenate `elements[i]` onto the selected combinations, 7.1307 + // bringing `k` back up to your requested level. 7.1308 + // This recursion may go many levels deep, since it only stops once 7.1309 + // k=1. 7.1310 + var subsetCombinations = combinationsReplacement( 7.1311 + elements.slice(i, elements.length), 7.1312 + k - 1); 7.1313 + 7.1314 + for (var j = 0; j < subsetCombinations.length; j++) { 7.1315 + combinationList.push([elements[i]] 7.1316 + .concat(subsetCombinations[j])); 7.1317 + } 7.1318 + } 7.1319 + } 7.1320 + 7.1321 + return combinationList; 7.1322 +} 7.1323 + 7.1324 +module.exports = combinationsReplacement; 7.1325 + 7.1326 +},{}],12:[function(require,module,exports){ 7.1327 +'use strict'; 7.1328 +/* @flow */ 7.1329 + 7.1330 +var standardNormalTable = require(55); 7.1331 + 7.1332 +/** 7.1333 + * **[Cumulative Standard Normal Probability](http://en.wikipedia.org/wiki/Standard_normal_table)** 7.1334 + * 7.1335 + * Since probability tables cannot be 7.1336 + * printed for every normal distribution, as there are an infinite variety 7.1337 + * of normal distributions, it is common practice to convert a normal to a 7.1338 + * standard normal and then use the standard normal table to find probabilities. 7.1339 + * 7.1340 + * You can use `.5 + .5 * errorFunction(x / Math.sqrt(2))` to calculate the probability 7.1341 + * instead of looking it up in a table. 7.1342 + * 7.1343 + * @param {number} z 7.1344 + * @returns {number} cumulative standard normal probability 7.1345 + */ 7.1346 +function cumulativeStdNormalProbability(z /*:number */)/*:number */ { 7.1347 + 7.1348 + // Calculate the position of this value. 7.1349 + var absZ = Math.abs(z), 7.1350 + // Each row begins with a different 7.1351 + // significant digit: 0.5, 0.6, 0.7, and so on. Each value in the table 7.1352 + // corresponds to a range of 0.01 in the input values, so the value is 7.1353 + // multiplied by 100. 7.1354 + index = Math.min(Math.round(absZ * 100), standardNormalTable.length - 1); 7.1355 + 7.1356 + // The index we calculate must be in the table as a positive value, 7.1357 + // but we still pay attention to whether the input is positive 7.1358 + // or negative, and flip the output value as a last step. 7.1359 + if (z >= 0) { 7.1360 + return standardNormalTable[index]; 7.1361 + } else { 7.1362 + // due to floating-point arithmetic, values in the table with 7.1363 + // 4 significant figures can nevertheless end up as repeating 7.1364 + // fractions when they're computed here. 7.1365 + return +(1 - standardNormalTable[index]).toFixed(4); 7.1366 + } 7.1367 +} 7.1368 + 7.1369 +module.exports = cumulativeStdNormalProbability; 7.1370 + 7.1371 +},{"55":55}],13:[function(require,module,exports){ 7.1372 +'use strict'; 7.1373 +/* @flow */ 7.1374 + 7.1375 +/** 7.1376 + * We use `ε`, epsilon, as a stopping criterion when we want to iterate 7.1377 + * until we're "close enough". Epsilon is a very small number: for 7.1378 + * simple statistics, that number is **0.0001** 7.1379 + * 7.1380 + * This is used in calculations like the binomialDistribution, in which 7.1381 + * the process of finding a value is [iterative](https://en.wikipedia.org/wiki/Iterative_method): 7.1382 + * it progresses until it is close enough. 7.1383 + * 7.1384 + * Below is an example of using epsilon in [gradient descent](https://en.wikipedia.org/wiki/Gradient_descent), 7.1385 + * where we're trying to find a local minimum of a function's derivative, 7.1386 + * given by the `fDerivative` method. 7.1387 + * 7.1388 + * @example 7.1389 + * // From calculation, we expect that the local minimum occurs at x=9/4 7.1390 + * var x_old = 0; 7.1391 + * // The algorithm starts at x=6 7.1392 + * var x_new = 6; 7.1393 + * var stepSize = 0.01; 7.1394 + * 7.1395 + * function fDerivative(x) { 7.1396 + * return 4 * Math.pow(x, 3) - 9 * Math.pow(x, 2); 7.1397 + * } 7.1398 + * 7.1399 + * // The loop runs until the difference between the previous 7.1400 + * // value and the current value is smaller than epsilon - a rough 7.1401 + * // meaure of 'close enough' 7.1402 + * while (Math.abs(x_new - x_old) > ss.epsilon) { 7.1403 + * x_old = x_new; 7.1404 + * x_new = x_old - stepSize * fDerivative(x_old); 7.1405 + * } 7.1406 + * 7.1407 + * console.log('Local minimum occurs at', x_new); 7.1408 + */ 7.1409 +var epsilon = 0.0001; 7.1410 + 7.1411 +module.exports = epsilon; 7.1412 + 7.1413 +},{}],14:[function(require,module,exports){ 7.1414 +'use strict'; 7.1415 +/* @flow */ 7.1416 + 7.1417 +var max = require(23), 7.1418 + min = require(29); 7.1419 + 7.1420 +/** 7.1421 + * Given an array of data, this will find the extent of the 7.1422 + * data and return an array of breaks that can be used 7.1423 + * to categorize the data into a number of classes. The 7.1424 + * returned array will always be 1 longer than the number of 7.1425 + * classes because it includes the minimum value. 7.1426 + * 7.1427 + * @param {Array<number>} data input data, as an array of number values 7.1428 + * @param {number} nClasses number of desired classes 7.1429 + * @returns {Array<number>} array of class break positions 7.1430 + * @example 7.1431 + * equalIntervalBreaks([1, 2, 3, 4, 5, 6], 4); //= [1, 2.25, 3.5, 4.75, 6] 7.1432 + */ 7.1433 +function equalIntervalBreaks(data/*: Array<number> */, nClasses/*:number*/)/*: Array<number> */ { 7.1434 + 7.1435 + if (data.length <= 1) { 7.1436 + return data; 7.1437 + } 7.1438 + 7.1439 + var theMin = min(data), 7.1440 + theMax = max(data); 7.1441 + 7.1442 + // the first break will always be the minimum value 7.1443 + // in the dataset 7.1444 + var breaks = [theMin]; 7.1445 + 7.1446 + // The size of each break is the full range of the data 7.1447 + // divided by the number of classes requested 7.1448 + var breakSize = (theMax - theMin) / nClasses; 7.1449 + 7.1450 + // In the case of nClasses = 1, this loop won't run 7.1451 + // and the returned breaks will be [min, max] 7.1452 + for (var i = 1; i < nClasses; i++) { 7.1453 + breaks.push(breaks[0] + breakSize * i); 7.1454 + } 7.1455 + 7.1456 + // the last break will always be the 7.1457 + // maximum. 7.1458 + breaks.push(theMax); 7.1459 + 7.1460 + return breaks; 7.1461 +} 7.1462 + 7.1463 +module.exports = equalIntervalBreaks; 7.1464 + 7.1465 +},{"23":23,"29":29}],15:[function(require,module,exports){ 7.1466 +'use strict'; 7.1467 +/* @flow */ 7.1468 + 7.1469 +/** 7.1470 + * **[Gaussian error function](http://en.wikipedia.org/wiki/Error_function)** 7.1471 + * 7.1472 + * The `errorFunction(x/(sd * Math.sqrt(2)))` is the probability that a value in a 7.1473 + * normal distribution with standard deviation sd is within x of the mean. 7.1474 + * 7.1475 + * This function returns a numerical approximation to the exact value. 7.1476 + * 7.1477 + * @param {number} x input 7.1478 + * @return {number} error estimation 7.1479 + * @example 7.1480 + * errorFunction(1).toFixed(2); // => '0.84' 7.1481 + */ 7.1482 +function errorFunction(x/*: number */)/*: number */ { 7.1483 + var t = 1 / (1 + 0.5 * Math.abs(x)); 7.1484 + var tau = t * Math.exp(-Math.pow(x, 2) - 7.1485 + 1.26551223 + 7.1486 + 1.00002368 * t + 7.1487 + 0.37409196 * Math.pow(t, 2) + 7.1488 + 0.09678418 * Math.pow(t, 3) - 7.1489 + 0.18628806 * Math.pow(t, 4) + 7.1490 + 0.27886807 * Math.pow(t, 5) - 7.1491 + 1.13520398 * Math.pow(t, 6) + 7.1492 + 1.48851587 * Math.pow(t, 7) - 7.1493 + 0.82215223 * Math.pow(t, 8) + 7.1494 + 0.17087277 * Math.pow(t, 9)); 7.1495 + if (x >= 0) { 7.1496 + return 1 - tau; 7.1497 + } else { 7.1498 + return tau - 1; 7.1499 + } 7.1500 +} 7.1501 + 7.1502 +module.exports = errorFunction; 7.1503 + 7.1504 +},{}],16:[function(require,module,exports){ 7.1505 +'use strict'; 7.1506 +/* @flow */ 7.1507 + 7.1508 +/** 7.1509 + * A [Factorial](https://en.wikipedia.org/wiki/Factorial), usually written n!, is the product of all positive 7.1510 + * integers less than or equal to n. Often factorial is implemented 7.1511 + * recursively, but this iterative approach is significantly faster 7.1512 + * and simpler. 7.1513 + * 7.1514 + * @param {number} n input 7.1515 + * @returns {number} factorial: n! 7.1516 + * @example 7.1517 + * factorial(5); // => 120 7.1518 + */ 7.1519 +function factorial(n /*: number */)/*: number */ { 7.1520 + 7.1521 + // factorial is mathematically undefined for negative numbers 7.1522 + if (n < 0) { return NaN; } 7.1523 + 7.1524 + // typically you'll expand the factorial function going down, like 7.1525 + // 5! = 5 * 4 * 3 * 2 * 1. This is going in the opposite direction, 7.1526 + // counting from 2 up to the number in question, and since anything 7.1527 + // multiplied by 1 is itself, the loop only needs to start at 2. 7.1528 + var accumulator = 1; 7.1529 + for (var i = 2; i <= n; i++) { 7.1530 + // for each number up to and including the number `n`, multiply 7.1531 + // the accumulator my that number. 7.1532 + accumulator *= i; 7.1533 + } 7.1534 + return accumulator; 7.1535 +} 7.1536 + 7.1537 +module.exports = factorial; 7.1538 + 7.1539 +},{}],17:[function(require,module,exports){ 7.1540 +'use strict'; 7.1541 +/* @flow */ 7.1542 + 7.1543 +/** 7.1544 + * The [Geometric Mean](https://en.wikipedia.org/wiki/Geometric_mean) is 7.1545 + * a mean function that is more useful for numbers in different 7.1546 + * ranges. 7.1547 + * 7.1548 + * This is the nth root of the input numbers multiplied by each other. 7.1549 + * 7.1550 + * The geometric mean is often useful for 7.1551 + * **[proportional growth](https://en.wikipedia.org/wiki/Geometric_mean#Proportional_growth)**: given 7.1552 + * growth rates for multiple years, like _80%, 16.66% and 42.85%_, a simple 7.1553 + * mean will incorrectly estimate an average growth rate, whereas a geometric 7.1554 + * mean will correctly estimate a growth rate that, over those years, 7.1555 + * will yield the same end value. 7.1556 + * 7.1557 + * This runs on `O(n)`, linear time in respect to the array 7.1558 + * 7.1559 + * @param {Array<number>} x input array 7.1560 + * @returns {number} geometric mean 7.1561 + * @example 7.1562 + * var growthRates = [1.80, 1.166666, 1.428571]; 7.1563 + * var averageGrowth = geometricMean(growthRates); 7.1564 + * var averageGrowthRates = [averageGrowth, averageGrowth, averageGrowth]; 7.1565 + * var startingValue = 10; 7.1566 + * var startingValueMean = 10; 7.1567 + * growthRates.forEach(function(rate) { 7.1568 + * startingValue *= rate; 7.1569 + * }); 7.1570 + * averageGrowthRates.forEach(function(rate) { 7.1571 + * startingValueMean *= rate; 7.1572 + * }); 7.1573 + * startingValueMean === startingValue; 7.1574 + */ 7.1575 +function geometricMean(x /*: Array<number> */) { 7.1576 + // The mean of no numbers is null 7.1577 + if (x.length === 0) { return undefined; } 7.1578 + 7.1579 + // the starting value. 7.1580 + var value = 1; 7.1581 + 7.1582 + for (var i = 0; i < x.length; i++) { 7.1583 + // the geometric mean is only valid for positive numbers 7.1584 + if (x[i] <= 0) { return undefined; } 7.1585 + 7.1586 + // repeatedly multiply the value by each number 7.1587 + value *= x[i]; 7.1588 + } 7.1589 + 7.1590 + return Math.pow(value, 1 / x.length); 7.1591 +} 7.1592 + 7.1593 +module.exports = geometricMean; 7.1594 + 7.1595 +},{}],18:[function(require,module,exports){ 7.1596 +'use strict'; 7.1597 +/* @flow */ 7.1598 + 7.1599 +/** 7.1600 + * The [Harmonic Mean](https://en.wikipedia.org/wiki/Harmonic_mean) is 7.1601 + * a mean function typically used to find the average of rates. 7.1602 + * This mean is calculated by taking the reciprocal of the arithmetic mean 7.1603 + * of the reciprocals of the input numbers. 7.1604 + * 7.1605 + * This is a [measure of central tendency](https://en.wikipedia.org/wiki/Central_tendency): 7.1606 + * a method of finding a typical or central value of a set of numbers. 7.1607 + * 7.1608 + * This runs on `O(n)`, linear time in respect to the array. 7.1609 + * 7.1610 + * @param {Array<number>} x input 7.1611 + * @returns {number} harmonic mean 7.1612 + * @example 7.1613 + * harmonicMean([2, 3]).toFixed(2) // => '2.40' 7.1614 + */ 7.1615 +function harmonicMean(x /*: Array<number> */) { 7.1616 + // The mean of no numbers is null 7.1617 + if (x.length === 0) { return undefined; } 7.1618 + 7.1619 + var reciprocalSum = 0; 7.1620 + 7.1621 + for (var i = 0; i < x.length; i++) { 7.1622 + // the harmonic mean is only valid for positive numbers 7.1623 + if (x[i] <= 0) { return undefined; } 7.1624 + 7.1625 + reciprocalSum += 1 / x[i]; 7.1626 + } 7.1627 + 7.1628 + // divide n by the the reciprocal sum 7.1629 + return x.length / reciprocalSum; 7.1630 +} 7.1631 + 7.1632 +module.exports = harmonicMean; 7.1633 + 7.1634 +},{}],19:[function(require,module,exports){ 7.1635 +'use strict'; 7.1636 +/* @flow */ 7.1637 + 7.1638 +var quantile = require(40); 7.1639 + 7.1640 +/** 7.1641 + * The [Interquartile range](http://en.wikipedia.org/wiki/Interquartile_range) is 7.1642 + * a measure of statistical dispersion, or how scattered, spread, or 7.1643 + * concentrated a distribution is. It's computed as the difference between 7.1644 + * the third quartile and first quartile. 7.1645 + * 7.1646 + * @param {Array<number>} sample 7.1647 + * @returns {number} interquartile range: the span between lower and upper quartile, 7.1648 + * 0.25 and 0.75 7.1649 + * @example 7.1650 + * interquartileRange([0, 1, 2, 3]); // => 2 7.1651 + */ 7.1652 +function interquartileRange(sample/*: Array<number> */) { 7.1653 + // Interquartile range is the span between the upper quartile, 7.1654 + // at `0.75`, and lower quartile, `0.25` 7.1655 + var q1 = quantile(sample, 0.75), 7.1656 + q2 = quantile(sample, 0.25); 7.1657 + 7.1658 + if (typeof q1 === 'number' && typeof q2 === 'number') { 7.1659 + return q1 - q2; 7.1660 + } 7.1661 +} 7.1662 + 7.1663 +module.exports = interquartileRange; 7.1664 + 7.1665 +},{"40":40}],20:[function(require,module,exports){ 7.1666 +'use strict'; 7.1667 +/* @flow */ 7.1668 + 7.1669 +/** 7.1670 + * The Inverse [Gaussian error function](http://en.wikipedia.org/wiki/Error_function) 7.1671 + * returns a numerical approximation to the value that would have caused 7.1672 + * `errorFunction()` to return x. 7.1673 + * 7.1674 + * @param {number} x value of error function 7.1675 + * @returns {number} estimated inverted value 7.1676 + */ 7.1677 +function inverseErrorFunction(x/*: number */)/*: number */ { 7.1678 + var a = (8 * (Math.PI - 3)) / (3 * Math.PI * (4 - Math.PI)); 7.1679 + 7.1680 + var inv = Math.sqrt(Math.sqrt( 7.1681 + Math.pow(2 / (Math.PI * a) + Math.log(1 - x * x) / 2, 2) - 7.1682 + Math.log(1 - x * x) / a) - 7.1683 + (2 / (Math.PI * a) + Math.log(1 - x * x) / 2)); 7.1684 + 7.1685 + if (x >= 0) { 7.1686 + return inv; 7.1687 + } else { 7.1688 + return -inv; 7.1689 + } 7.1690 +} 7.1691 + 7.1692 +module.exports = inverseErrorFunction; 7.1693 + 7.1694 +},{}],21:[function(require,module,exports){ 7.1695 +'use strict'; 7.1696 +/* @flow */ 7.1697 + 7.1698 +/** 7.1699 + * [Simple linear regression](http://en.wikipedia.org/wiki/Simple_linear_regression) 7.1700 + * is a simple way to find a fitted line 7.1701 + * between a set of coordinates. This algorithm finds the slope and y-intercept of a regression line 7.1702 + * using the least sum of squares. 7.1703 + * 7.1704 + * @param {Array<Array<number>>} data an array of two-element of arrays, 7.1705 + * like `[[0, 1], [2, 3]]` 7.1706 + * @returns {Object} object containing slope and intersect of regression line 7.1707 + * @example 7.1708 + * linearRegression([[0, 0], [1, 1]]); // => { m: 1, b: 0 } 7.1709 + */ 7.1710 +function linearRegression(data/*: Array<Array<number>> */)/*: { m: number, b: number } */ { 7.1711 + 7.1712 + var m, b; 7.1713 + 7.1714 + // Store data length in a local variable to reduce 7.1715 + // repeated object property lookups 7.1716 + var dataLength = data.length; 7.1717 + 7.1718 + //if there's only one point, arbitrarily choose a slope of 0 7.1719 + //and a y-intercept of whatever the y of the initial point is 7.1720 + if (dataLength === 1) { 7.1721 + m = 0; 7.1722 + b = data[0][1]; 7.1723 + } else { 7.1724 + // Initialize our sums and scope the `m` and `b` 7.1725 + // variables that define the line. 7.1726 + var sumX = 0, sumY = 0, 7.1727 + sumXX = 0, sumXY = 0; 7.1728 + 7.1729 + // Use local variables to grab point values 7.1730 + // with minimal object property lookups 7.1731 + var point, x, y; 7.1732 + 7.1733 + // Gather the sum of all x values, the sum of all 7.1734 + // y values, and the sum of x^2 and (x*y) for each 7.1735 + // value. 7.1736 + // 7.1737 + // In math notation, these would be SS_x, SS_y, SS_xx, and SS_xy 7.1738 + for (var i = 0; i < dataLength; i++) { 7.1739 + point = data[i]; 7.1740 + x = point[0]; 7.1741 + y = point[1]; 7.1742 + 7.1743 + sumX += x; 7.1744 + sumY += y; 7.1745 + 7.1746 + sumXX += x * x; 7.1747 + sumXY += x * y; 7.1748 + } 7.1749 + 7.1750 + // `m` is the slope of the regression line 7.1751 + m = ((dataLength * sumXY) - (sumX * sumY)) / 7.1752 + ((dataLength * sumXX) - (sumX * sumX)); 7.1753 + 7.1754 + // `b` is the y-intercept of the line. 7.1755 + b = (sumY / dataLength) - ((m * sumX) / dataLength); 7.1756 + } 7.1757 + 7.1758 + // Return both values as an object. 7.1759 + return { 7.1760 + m: m, 7.1761 + b: b 7.1762 + }; 7.1763 +} 7.1764 + 7.1765 + 7.1766 +module.exports = linearRegression; 7.1767 + 7.1768 +},{}],22:[function(require,module,exports){ 7.1769 +'use strict'; 7.1770 +/* @flow */ 7.1771 + 7.1772 +/** 7.1773 + * Given the output of `linearRegression`: an object 7.1774 + * with `m` and `b` values indicating slope and intercept, 7.1775 + * respectively, generate a line function that translates 7.1776 + * x values into y values. 7.1777 + * 7.1778 + * @param {Object} mb object with `m` and `b` members, representing 7.1779 + * slope and intersect of desired line 7.1780 + * @returns {Function} method that computes y-value at any given 7.1781 + * x-value on the line. 7.1782 + * @example 7.1783 + * var l = linearRegressionLine(linearRegression([[0, 0], [1, 1]])); 7.1784 + * l(0) // = 0 7.1785 + * l(2) // = 2 7.1786 + * linearRegressionLine({ b: 0, m: 1 })(1); // => 1 7.1787 + * linearRegressionLine({ b: 1, m: 1 })(1); // => 2 7.1788 + */ 7.1789 +function linearRegressionLine(mb/*: { b: number, m: number }*/)/*: Function */ { 7.1790 + // Return a function that computes a `y` value for each 7.1791 + // x value it is given, based on the values of `b` and `a` 7.1792 + // that we just computed. 7.1793 + return function(x) { 7.1794 + return mb.b + (mb.m * x); 7.1795 + }; 7.1796 +} 7.1797 + 7.1798 +module.exports = linearRegressionLine; 7.1799 + 7.1800 +},{}],23:[function(require,module,exports){ 7.1801 +'use strict'; 7.1802 +/* @flow */ 7.1803 + 7.1804 +/** 7.1805 + * This computes the maximum number in an array. 7.1806 + * 7.1807 + * This runs on `O(n)`, linear time in respect to the array 7.1808 + * 7.1809 + * @param {Array<number>} x input 7.1810 + * @returns {number} maximum value 7.1811 + * @example 7.1812 + * max([1, 2, 3, 4]); 7.1813 + * // => 4 7.1814 + */ 7.1815 +function max(x /*: Array<number> */) /*:number*/ { 7.1816 + var value; 7.1817 + for (var i = 0; i < x.length; i++) { 7.1818 + // On the first iteration of this loop, max is 7.1819 + // NaN and is thus made the maximum element in the array 7.1820 + if (value === undefined || x[i] > value) { 7.1821 + value = x[i]; 7.1822 + } 7.1823 + } 7.1824 + if (value === undefined) { 7.1825 + return NaN; 7.1826 + } 7.1827 + return value; 7.1828 +} 7.1829 + 7.1830 +module.exports = max; 7.1831 + 7.1832 +},{}],24:[function(require,module,exports){ 7.1833 +'use strict'; 7.1834 +/* @flow */ 7.1835 + 7.1836 +/** 7.1837 + * The maximum is the highest number in the array. With a sorted array, 7.1838 + * the last element in the array is always the largest, so this calculation 7.1839 + * can be done in one step, or constant time. 7.1840 + * 7.1841 + * @param {Array<number>} x input 7.1842 + * @returns {number} maximum value 7.1843 + * @example 7.1844 + * maxSorted([-100, -10, 1, 2, 5]); // => 5 7.1845 + */ 7.1846 +function maxSorted(x /*: Array<number> */)/*:number*/ { 7.1847 + return x[x.length - 1]; 7.1848 +} 7.1849 + 7.1850 +module.exports = maxSorted; 7.1851 + 7.1852 +},{}],25:[function(require,module,exports){ 7.1853 +'use strict'; 7.1854 +/* @flow */ 7.1855 + 7.1856 +var sum = require(56); 7.1857 + 7.1858 +/** 7.1859 + * The mean, _also known as average_, 7.1860 + * is the sum of all values over the number of values. 7.1861 + * This is a [measure of central tendency](https://en.wikipedia.org/wiki/Central_tendency): 7.1862 + * a method of finding a typical or central value of a set of numbers. 7.1863 + * 7.1864 + * This runs on `O(n)`, linear time in respect to the array 7.1865 + * 7.1866 + * @param {Array<number>} x input values 7.1867 + * @returns {number} mean 7.1868 + * @example 7.1869 + * mean([0, 10]); // => 5 7.1870 + */ 7.1871 +function mean(x /*: Array<number> */)/*:number*/ { 7.1872 + // The mean of no numbers is null 7.1873 + if (x.length === 0) { return NaN; } 7.1874 + 7.1875 + return sum(x) / x.length; 7.1876 +} 7.1877 + 7.1878 +module.exports = mean; 7.1879 + 7.1880 +},{"56":56}],26:[function(require,module,exports){ 7.1881 +'use strict'; 7.1882 +/* @flow */ 7.1883 + 7.1884 +var quantile = require(40); 7.1885 + 7.1886 +/** 7.1887 + * The [median](http://en.wikipedia.org/wiki/Median) is 7.1888 + * the middle number of a list. This is often a good indicator of 'the middle' 7.1889 + * when there are outliers that skew the `mean()` value. 7.1890 + * This is a [measure of central tendency](https://en.wikipedia.org/wiki/Central_tendency): 7.1891 + * a method of finding a typical or central value of a set of numbers. 7.1892 + * 7.1893 + * The median isn't necessarily one of the elements in the list: the value 7.1894 + * can be the average of two elements if the list has an even length 7.1895 + * and the two central values are different. 7.1896 + * 7.1897 + * @param {Array<number>} x input 7.1898 + * @returns {number} median value 7.1899 + * @example 7.1900 + * median([10, 2, 5, 100, 2, 1]); // => 3.5 7.1901 + */ 7.1902 +function median(x /*: Array<number> */)/*:number*/ { 7.1903 + return +quantile(x, 0.5); 7.1904 +} 7.1905 + 7.1906 +module.exports = median; 7.1907 + 7.1908 +},{"40":40}],27:[function(require,module,exports){ 7.1909 +'use strict'; 7.1910 +/* @flow */ 7.1911 + 7.1912 +var median = require(26); 7.1913 + 7.1914 +/** 7.1915 + * The [Median Absolute Deviation](http://en.wikipedia.org/wiki/Median_absolute_deviation) is 7.1916 + * a robust measure of statistical 7.1917 + * dispersion. It is more resilient to outliers than the standard deviation. 7.1918 + * 7.1919 + * @param {Array<number>} x input array 7.1920 + * @returns {number} median absolute deviation 7.1921 + * @example 7.1922 + * medianAbsoluteDeviation([1, 1, 2, 2, 4, 6, 9]); // => 1 7.1923 + */ 7.1924 +function medianAbsoluteDeviation(x /*: Array<number> */) { 7.1925 + // The mad of nothing is null 7.1926 + var medianValue = median(x), 7.1927 + medianAbsoluteDeviations = []; 7.1928 + 7.1929 + // Make a list of absolute deviations from the median 7.1930 + for (var i = 0; i < x.length; i++) { 7.1931 + medianAbsoluteDeviations.push(Math.abs(x[i] - medianValue)); 7.1932 + } 7.1933 + 7.1934 + // Find the median value of that list 7.1935 + return median(medianAbsoluteDeviations); 7.1936 +} 7.1937 + 7.1938 +module.exports = medianAbsoluteDeviation; 7.1939 + 7.1940 +},{"26":26}],28:[function(require,module,exports){ 7.1941 +'use strict'; 7.1942 +/* @flow */ 7.1943 + 7.1944 +var quantileSorted = require(41); 7.1945 + 7.1946 +/** 7.1947 + * The [median](http://en.wikipedia.org/wiki/Median) is 7.1948 + * the middle number of a list. This is often a good indicator of 'the middle' 7.1949 + * when there are outliers that skew the `mean()` value. 7.1950 + * This is a [measure of central tendency](https://en.wikipedia.org/wiki/Central_tendency): 7.1951 + * a method of finding a typical or central value of a set of numbers. 7.1952 + * 7.1953 + * The median isn't necessarily one of the elements in the list: the value 7.1954 + * can be the average of two elements if the list has an even length 7.1955 + * and the two central values are different. 7.1956 + * 7.1957 + * @param {Array<number>} sorted input 7.1958 + * @returns {number} median value 7.1959 + * @example 7.1960 + * medianSorted([10, 2, 5, 100, 2, 1]); // => 52.5 7.1961 + */ 7.1962 +function medianSorted(sorted /*: Array<number> */)/*:number*/ { 7.1963 + return quantileSorted(sorted, 0.5); 7.1964 +} 7.1965 + 7.1966 +module.exports = medianSorted; 7.1967 + 7.1968 +},{"41":41}],29:[function(require,module,exports){ 7.1969 +'use strict'; 7.1970 +/* @flow */ 7.1971 + 7.1972 +/** 7.1973 + * The min is the lowest number in the array. This runs on `O(n)`, linear time in respect to the array 7.1974 + * 7.1975 + * @param {Array<number>} x input 7.1976 + * @returns {number} minimum value 7.1977 + * @example 7.1978 + * min([1, 5, -10, 100, 2]); // => -10 7.1979 + */ 7.1980 +function min(x /*: Array<number> */)/*:number*/ { 7.1981 + var value; 7.1982 + for (var i = 0; i < x.length; i++) { 7.1983 + // On the first iteration of this loop, min is 7.1984 + // NaN and is thus made the minimum element in the array 7.1985 + if (value === undefined || x[i] < value) { 7.1986 + value = x[i]; 7.1987 + } 7.1988 + } 7.1989 + if (value === undefined) { 7.1990 + return NaN; 7.1991 + } 7.1992 + return value; 7.1993 +} 7.1994 + 7.1995 +module.exports = min; 7.1996 + 7.1997 +},{}],30:[function(require,module,exports){ 7.1998 +'use strict'; 7.1999 +/* @flow */ 7.2000 + 7.2001 +/** 7.2002 + * The minimum is the lowest number in the array. With a sorted array, 7.2003 + * the first element in the array is always the smallest, so this calculation 7.2004 + * can be done in one step, or constant time. 7.2005 + * 7.2006 + * @param {Array<number>} x input 7.2007 + * @returns {number} minimum value 7.2008 + * @example 7.2009 + * minSorted([-100, -10, 1, 2, 5]); // => -100 7.2010 + */ 7.2011 +function minSorted(x /*: Array<number> */)/*:number*/ { 7.2012 + return x[0]; 7.2013 +} 7.2014 + 7.2015 +module.exports = minSorted; 7.2016 + 7.2017 +},{}],31:[function(require,module,exports){ 7.2018 +'use strict'; 7.2019 +/* @flow */ 7.2020 + 7.2021 +/** 7.2022 + * **Mixin** simple_statistics to a single Array instance if provided 7.2023 + * or the Array native object if not. This is an optional 7.2024 + * feature that lets you treat simple_statistics as a native feature 7.2025 + * of Javascript. 7.2026 + * 7.2027 + * @param {Object} ss simple statistics 7.2028 + * @param {Array} [array=] a single array instance which will be augmented 7.2029 + * with the extra methods. If omitted, mixin will apply to all arrays 7.2030 + * by changing the global `Array.prototype`. 7.2031 + * @returns {*} the extended Array, or Array.prototype if no object 7.2032 + * is given. 7.2033 + * 7.2034 + * @example 7.2035 + * var myNumbers = [1, 2, 3]; 7.2036 + * mixin(ss, myNumbers); 7.2037 + * console.log(myNumbers.sum()); // 6 7.2038 + */ 7.2039 +function mixin(ss /*: Object */, array /*: ?Array<any> */)/*: any */ { 7.2040 + var support = !!(Object.defineProperty && Object.defineProperties); 7.2041 + // Coverage testing will never test this error. 7.2042 + /* istanbul ignore next */ 7.2043 + if (!support) { 7.2044 + throw new Error('without defineProperty, simple-statistics cannot be mixed in'); 7.2045 + } 7.2046 + 7.2047 + // only methods which work on basic arrays in a single step 7.2048 + // are supported 7.2049 + var arrayMethods = ['median', 'standardDeviation', 'sum', 'product', 7.2050 + 'sampleSkewness', 7.2051 + 'mean', 'min', 'max', 'quantile', 'geometricMean', 7.2052 + 'harmonicMean', 'root_mean_square']; 7.2053 + 7.2054 + // create a closure with a method name so that a reference 7.2055 + // like `arrayMethods[i]` doesn't follow the loop increment 7.2056 + function wrap(method) { 7.2057 + return function() { 7.2058 + // cast any arguments into an array, since they're 7.2059 + // natively objects 7.2060 + var args = Array.prototype.slice.apply(arguments); 7.2061 + // make the first argument the array itself 7.2062 + args.unshift(this); 7.2063 + // return the result of the ss method 7.2064 + return ss[method].apply(ss, args); 7.2065 + }; 7.2066 + } 7.2067 + 7.2068 + // select object to extend 7.2069 + var extending; 7.2070 + if (array) { 7.2071 + // create a shallow copy of the array so that our internal 7.2072 + // operations do not change it by reference 7.2073 + extending = array.slice(); 7.2074 + } else { 7.2075 + extending = Array.prototype; 7.2076 + } 7.2077 + 7.2078 + // for each array function, define a function that gets 7.2079 + // the array as the first argument. 7.2080 + // We use [defineProperty](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty) 7.2081 + // because it allows these properties to be non-enumerable: 7.2082 + // `for (var in x)` loops will not run into problems with this 7.2083 + // implementation. 7.2084 + for (var i = 0; i < arrayMethods.length; i++) { 7.2085 + Object.defineProperty(extending, arrayMethods[i], { 7.2086 + value: wrap(arrayMethods[i]), 7.2087 + configurable: true, 7.2088 + enumerable: false, 7.2089 + writable: true 7.2090 + }); 7.2091 + } 7.2092 + 7.2093 + return extending; 7.2094 +} 7.2095 + 7.2096 +module.exports = mixin; 7.2097 + 7.2098 +},{}],32:[function(require,module,exports){ 7.2099 +'use strict'; 7.2100 +/* @flow */ 7.2101 + 7.2102 +var numericSort = require(34), 7.2103 + modeSorted = require(33); 7.2104 + 7.2105 +/** 7.2106 + * The [mode](http://bit.ly/W5K4Yt) is the number that appears in a list the highest number of times. 7.2107 + * There can be multiple modes in a list: in the event of a tie, this 7.2108 + * algorithm will return the most recently seen mode. 7.2109 + * 7.2110 + * This is a [measure of central tendency](https://en.wikipedia.org/wiki/Central_tendency): 7.2111 + * a method of finding a typical or central value of a set of numbers. 7.2112 + * 7.2113 + * This runs on `O(nlog(n))` because it needs to sort the array internally 7.2114 + * before running an `O(n)` search to find the mode. 7.2115 + * 7.2116 + * @param {Array<number>} x input 7.2117 + * @returns {number} mode 7.2118 + * @example 7.2119 + * mode([0, 0, 1]); // => 0 7.2120 + */ 7.2121 +function mode(x /*: Array<number> */)/*:number*/ { 7.2122 + // Sorting the array lets us iterate through it below and be sure 7.2123 + // that every time we see a new number it's new and we'll never 7.2124 + // see the same number twice 7.2125 + return modeSorted(numericSort(x)); 7.2126 +} 7.2127 + 7.2128 +module.exports = mode; 7.2129 + 7.2130 +},{"33":33,"34":34}],33:[function(require,module,exports){ 7.2131 +'use strict'; 7.2132 +/* @flow */ 7.2133 + 7.2134 +/** 7.2135 + * The [mode](http://bit.ly/W5K4Yt) is the number that appears in a list the highest number of times. 7.2136 + * There can be multiple modes in a list: in the event of a tie, this 7.2137 + * algorithm will return the most recently seen mode. 7.2138 + * 7.2139 + * This is a [measure of central tendency](https://en.wikipedia.org/wiki/Central_tendency): 7.2140 + * a method of finding a typical or central value of a set of numbers. 7.2141 + * 7.2142 + * This runs in `O(n)` because the input is sorted. 7.2143 + * 7.2144 + * @param {Array<number>} sorted input 7.2145 + * @returns {number} mode 7.2146 + * @example 7.2147 + * modeSorted([0, 0, 1]); // => 0 7.2148 + */ 7.2149 +function modeSorted(sorted /*: Array<number> */)/*:number*/ { 7.2150 + 7.2151 + // Handle edge cases: 7.2152 + // The mode of an empty list is NaN 7.2153 + if (sorted.length === 0) { return NaN; } 7.2154 + else if (sorted.length === 1) { return sorted[0]; } 7.2155 + 7.2156 + // This assumes it is dealing with an array of size > 1, since size 7.2157 + // 0 and 1 are handled immediately. Hence it starts at index 1 in the 7.2158 + // array. 7.2159 + var last = sorted[0], 7.2160 + // store the mode as we find new modes 7.2161 + value = NaN, 7.2162 + // store how many times we've seen the mode 7.2163 + maxSeen = 0, 7.2164 + // how many times the current candidate for the mode 7.2165 + // has been seen 7.2166 + seenThis = 1; 7.2167 + 7.2168 + // end at sorted.length + 1 to fix the case in which the mode is 7.2169 + // the highest number that occurs in the sequence. the last iteration 7.2170 + // compares sorted[i], which is undefined, to the highest number 7.2171 + // in the series 7.2172 + for (var i = 1; i < sorted.length + 1; i++) { 7.2173 + // we're seeing a new number pass by 7.2174 + if (sorted[i] !== last) { 7.2175 + // the last number is the new mode since we saw it more 7.2176 + // often than the old one 7.2177 + if (seenThis > maxSeen) { 7.2178 + maxSeen = seenThis; 7.2179 + value = last; 7.2180 + } 7.2181 + seenThis = 1; 7.2182 + last = sorted[i]; 7.2183 + // if this isn't a new number, it's one more occurrence of 7.2184 + // the potential mode 7.2185 + } else { seenThis++; } 7.2186 + } 7.2187 + return value; 7.2188 +} 7.2189 + 7.2190 +module.exports = modeSorted; 7.2191 + 7.2192 +},{}],34:[function(require,module,exports){ 7.2193 +'use strict'; 7.2194 +/* @flow */ 7.2195 + 7.2196 +/** 7.2197 + * Sort an array of numbers by their numeric value, ensuring that the 7.2198 + * array is not changed in place. 7.2199 + * 7.2200 + * This is necessary because the default behavior of .sort 7.2201 + * in JavaScript is to sort arrays as string values 7.2202 + * 7.2203 + * [1, 10, 12, 102, 20].sort() 7.2204 + * // output 7.2205 + * [1, 10, 102, 12, 20] 7.2206 + * 7.2207 + * @param {Array<number>} array input array 7.2208 + * @return {Array<number>} sorted array 7.2209 + * @private 7.2210 + * @example 7.2211 + * numericSort([3, 2, 1]) // => [1, 2, 3] 7.2212 + */ 7.2213 +function numericSort(array /*: Array<number> */) /*: Array<number> */ { 7.2214 + return array 7.2215 + // ensure the array is not changed in-place 7.2216 + .slice() 7.2217 + // comparator function that treats input as numeric 7.2218 + .sort(function(a, b) { 7.2219 + return a - b; 7.2220 + }); 7.2221 +} 7.2222 + 7.2223 +module.exports = numericSort; 7.2224 + 7.2225 +},{}],35:[function(require,module,exports){ 7.2226 +'use strict'; 7.2227 +/* @flow */ 7.2228 + 7.2229 +/** 7.2230 + * This is a single-layer [Perceptron Classifier](http://en.wikipedia.org/wiki/Perceptron) that takes 7.2231 + * arrays of numbers and predicts whether they should be classified 7.2232 + * as either 0 or 1 (negative or positive examples). 7.2233 + * @class 7.2234 + * @example 7.2235 + * // Create the model 7.2236 + * var p = new PerceptronModel(); 7.2237 + * // Train the model with input with a diagonal boundary. 7.2238 + * for (var i = 0; i < 5; i++) { 7.2239 + * p.train([1, 1], 1); 7.2240 + * p.train([0, 1], 0); 7.2241 + * p.train([1, 0], 0); 7.2242 + * p.train([0, 0], 0); 7.2243 + * } 7.2244 + * p.predict([0, 0]); // 0 7.2245 + * p.predict([0, 1]); // 0 7.2246 + * p.predict([1, 0]); // 0 7.2247 + * p.predict([1, 1]); // 1 7.2248 + */ 7.2249 +function PerceptronModel() { 7.2250 + // The weights, or coefficients of the model; 7.2251 + // weights are only populated when training with data. 7.2252 + this.weights = []; 7.2253 + // The bias term, or intercept; it is also a weight but 7.2254 + // it's stored separately for convenience as it is always 7.2255 + // multiplied by one. 7.2256 + this.bias = 0; 7.2257 +} 7.2258 + 7.2259 +/** 7.2260 + * **Predict**: Use an array of features with the weight array and bias 7.2261 + * to predict whether an example is labeled 0 or 1. 7.2262 + * 7.2263 + * @param {Array<number>} features an array of features as numbers 7.2264 + * @returns {number} 1 if the score is over 0, otherwise 0 7.2265 + */ 7.2266 +PerceptronModel.prototype.predict = function(features) { 7.2267 + 7.2268 + // Only predict if previously trained 7.2269 + // on the same size feature array(s). 7.2270 + if (features.length !== this.weights.length) { return null; } 7.2271 + 7.2272 + // Calculate the sum of features times weights, 7.2273 + // with the bias added (implicitly times one). 7.2274 + var score = 0; 7.2275 + for (var i = 0; i < this.weights.length; i++) { 7.2276 + score += this.weights[i] * features[i]; 7.2277 + } 7.2278 + score += this.bias; 7.2279 + 7.2280 + // Classify as 1 if the score is over 0, otherwise 0. 7.2281 + if (score > 0) { 7.2282 + return 1; 7.2283 + } else { 7.2284 + return 0; 7.2285 + } 7.2286 +}; 7.2287 + 7.2288 +/** 7.2289 + * **Train** the classifier with a new example, which is 7.2290 + * a numeric array of features and a 0 or 1 label. 7.2291 + * 7.2292 + * @param {Array<number>} features an array of features as numbers 7.2293 + * @param {number} label either 0 or 1 7.2294 + * @returns {PerceptronModel} this 7.2295 + */ 7.2296 +PerceptronModel.prototype.train = function(features, label) { 7.2297 + // Require that only labels of 0 or 1 are considered. 7.2298 + if (label !== 0 && label !== 1) { return null; } 7.2299 + // The length of the feature array determines 7.2300 + // the length of the weight array. 7.2301 + // The perceptron will continue learning as long as 7.2302 + // it keeps seeing feature arrays of the same length. 7.2303 + // When it sees a new data shape, it initializes. 7.2304 + if (features.length !== this.weights.length) { 7.2305 + this.weights = features; 7.2306 + this.bias = 1; 7.2307 + } 7.2308 + // Make a prediction based on current weights. 7.2309 + var prediction = this.predict(features); 7.2310 + // Update the weights if the prediction is wrong. 7.2311 + if (prediction !== label) { 7.2312 + var gradient = label - prediction; 7.2313 + for (var i = 0; i < this.weights.length; i++) { 7.2314 + this.weights[i] += gradient * features[i]; 7.2315 + } 7.2316 + this.bias += gradient; 7.2317 + } 7.2318 + return this; 7.2319 +}; 7.2320 + 7.2321 +module.exports = PerceptronModel; 7.2322 + 7.2323 +},{}],36:[function(require,module,exports){ 7.2324 +/* @flow */ 7.2325 + 7.2326 +'use strict'; 7.2327 + 7.2328 +/** 7.2329 + * Implementation of [Heap's Algorithm](https://en.wikipedia.org/wiki/Heap%27s_algorithm) 7.2330 + * for generating permutations. 7.2331 + * 7.2332 + * @param {Array} elements any type of data 7.2333 + * @returns {Array<Array>} array of permutations 7.2334 + */ 7.2335 +function permutationsHeap/*:: <T> */(elements /*: Array<T> */)/*: Array<Array<T>> */ { 7.2336 + var indexes = new Array(elements.length); 7.2337 + var permutations = [elements.slice()]; 7.2338 + 7.2339 + for (var i = 0; i < elements.length; i++) { 7.2340 + indexes[i] = 0; 7.2341 + } 7.2342 + 7.2343 + for (i = 0; i < elements.length;) { 7.2344 + if (indexes[i] < i) { 7.2345 + 7.2346 + // At odd indexes, swap from indexes[i] instead 7.2347 + // of from the beginning of the array 7.2348 + var swapFrom = 0; 7.2349 + if (i % 2 !== 0) { 7.2350 + swapFrom = indexes[i]; 7.2351 + } 7.2352 + 7.2353 + // swap between swapFrom and i, using 7.2354 + // a temporary variable as storage. 7.2355 + var temp = elements[swapFrom]; 7.2356 + elements[swapFrom] = elements[i]; 7.2357 + elements[i] = temp; 7.2358 + 7.2359 + permutations.push(elements.slice()); 7.2360 + indexes[i]++; 7.2361 + i = 0; 7.2362 + 7.2363 + } else { 7.2364 + indexes[i] = 0; 7.2365 + i++; 7.2366 + } 7.2367 + } 7.2368 + 7.2369 + return permutations; 7.2370 +} 7.2371 + 7.2372 +module.exports = permutationsHeap; 7.2373 + 7.2374 +},{}],37:[function(require,module,exports){ 7.2375 +'use strict'; 7.2376 +/* @flow */ 7.2377 + 7.2378 +var epsilon = require(13); 7.2379 +var factorial = require(16); 7.2380 + 7.2381 +/** 7.2382 + * The [Poisson Distribution](http://en.wikipedia.org/wiki/Poisson_distribution) 7.2383 + * is a discrete probability distribution that expresses the probability 7.2384 + * of a given number of events occurring in a fixed interval of time 7.2385 + * and/or space if these events occur with a known average rate and 7.2386 + * independently of the time since the last event. 7.2387 + * 7.2388 + * The Poisson Distribution is characterized by the strictly positive 7.2389 + * mean arrival or occurrence rate, `λ`. 7.2390 + * 7.2391 + * @param {number} lambda location poisson distribution 7.2392 + * @returns {number} value of poisson distribution at that point 7.2393 + */ 7.2394 +function poissonDistribution(lambda/*: number */) { 7.2395 + // Check that lambda is strictly positive 7.2396 + if (lambda <= 0) { return undefined; } 7.2397 + 7.2398 + // our current place in the distribution 7.2399 + var x = 0, 7.2400 + // and we keep track of the current cumulative probability, in 7.2401 + // order to know when to stop calculating chances. 7.2402 + cumulativeProbability = 0, 7.2403 + // the calculated cells to be returned 7.2404 + cells = {}; 7.2405 + 7.2406 + // This algorithm iterates through each potential outcome, 7.2407 + // until the `cumulativeProbability` is very close to 1, at 7.2408 + // which point we've defined the vast majority of outcomes 7.2409 + do { 7.2410 + // a [probability mass function](https://en.wikipedia.org/wiki/Probability_mass_function) 7.2411 + cells[x] = (Math.pow(Math.E, -lambda) * Math.pow(lambda, x)) / factorial(x); 7.2412 + cumulativeProbability += cells[x]; 7.2413 + x++; 7.2414 + // when the cumulativeProbability is nearly 1, we've calculated 7.2415 + // the useful range of this distribution 7.2416 + } while (cumulativeProbability < 1 - epsilon); 7.2417 + 7.2418 + return cells; 7.2419 +} 7.2420 + 7.2421 +module.exports = poissonDistribution; 7.2422 + 7.2423 +},{"13":13,"16":16}],38:[function(require,module,exports){ 7.2424 +'use strict'; 7.2425 +/* @flow */ 7.2426 + 7.2427 +var epsilon = require(13); 7.2428 +var inverseErrorFunction = require(20); 7.2429 + 7.2430 +/** 7.2431 + * The [Probit](http://en.wikipedia.org/wiki/Probit) 7.2432 + * is the inverse of cumulativeStdNormalProbability(), 7.2433 + * and is also known as the normal quantile function. 7.2434 + * 7.2435 + * It returns the number of standard deviations from the mean 7.2436 + * where the p'th quantile of values can be found in a normal distribution. 7.2437 + * So, for example, probit(0.5 + 0.6827/2) ≈ 1 because 68.27% of values are 7.2438 + * normally found within 1 standard deviation above or below the mean. 7.2439 + * 7.2440 + * @param {number} p 7.2441 + * @returns {number} probit 7.2442 + */ 7.2443 +function probit(p /*: number */)/*: number */ { 7.2444 + if (p === 0) { 7.2445 + p = epsilon; 7.2446 + } else if (p >= 1) { 7.2447 + p = 1 - epsilon; 7.2448 + } 7.2449 + return Math.sqrt(2) * inverseErrorFunction(2 * p - 1); 7.2450 +} 7.2451 + 7.2452 +module.exports = probit; 7.2453 + 7.2454 +},{"13":13,"20":20}],39:[function(require,module,exports){ 7.2455 +'use strict'; 7.2456 +/* @flow */ 7.2457 + 7.2458 +/** 7.2459 + * The [product](https://en.wikipedia.org/wiki/Product_(mathematics)) of an array 7.2460 + * is the result of multiplying all numbers together, starting using one as the multiplicative identity. 7.2461 + * 7.2462 + * This runs on `O(n)`, linear time in respect to the array 7.2463 + * 7.2464 + * @param {Array<number>} x input 7.2465 + * @return {number} product of all input numbers 7.2466 + * @example 7.2467 + * product([1, 2, 3, 4]); // => 24 7.2468 + */ 7.2469 +function product(x/*: Array<number> */)/*: number */ { 7.2470 + var value = 1; 7.2471 + for (var i = 0; i < x.length; i++) { 7.2472 + value *= x[i]; 7.2473 + } 7.2474 + return value; 7.2475 +} 7.2476 + 7.2477 +module.exports = product; 7.2478 + 7.2479 +},{}],40:[function(require,module,exports){ 7.2480 +'use strict'; 7.2481 +/* @flow */ 7.2482 + 7.2483 +var quantileSorted = require(41); 7.2484 +var quickselect = require(42); 7.2485 + 7.2486 +/** 7.2487 + * The [quantile](https://en.wikipedia.org/wiki/Quantile): 7.2488 + * this is a population quantile, since we assume to know the entire 7.2489 + * dataset in this library. This is an implementation of the 7.2490 + * [Quantiles of a Population](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population) 7.2491 + * algorithm from wikipedia. 7.2492 + * 7.2493 + * Sample is a one-dimensional array of numbers, 7.2494 + * and p is either a decimal number from 0 to 1 or an array of decimal 7.2495 + * numbers from 0 to 1. 7.2496 + * In terms of a k/q quantile, p = k/q - it's just dealing with fractions or dealing 7.2497 + * with decimal values. 7.2498 + * When p is an array, the result of the function is also an array containing the appropriate 7.2499 + * quantiles in input order 7.2500 + * 7.2501 + * @param {Array<number>} sample a sample from the population 7.2502 + * @param {number} p the desired quantile, as a number between 0 and 1 7.2503 + * @returns {number} quantile 7.2504 + * @example 7.2505 + * quantile([3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20], 0.5); // => 9 7.2506 + */ 7.2507 +function quantile(sample /*: Array<number> */, p /*: Array<number> | number */) { 7.2508 + var copy = sample.slice(); 7.2509 + 7.2510 + if (Array.isArray(p)) { 7.2511 + // rearrange elements so that each element corresponding to a requested 7.2512 + // quantile is on a place it would be if the array was fully sorted 7.2513 + multiQuantileSelect(copy, p); 7.2514 + // Initialize the result array 7.2515 + var results = []; 7.2516 + // For each requested quantile 7.2517 + for (var i = 0; i < p.length; i++) { 7.2518 + results[i] = quantileSorted(copy, p[i]); 7.2519 + } 7.2520 + return results; 7.2521 + } else { 7.2522 + var idx = quantileIndex(copy.length, p); 7.2523 + quantileSelect(copy, idx, 0, copy.length - 1); 7.2524 + return quantileSorted(copy, p); 7.2525 + } 7.2526 +} 7.2527 + 7.2528 +function quantileSelect(arr, k, left, right) { 7.2529 + if (k % 1 === 0) { 7.2530 + quickselect(arr, k, left, right); 7.2531 + } else { 7.2532 + k = Math.floor(k); 7.2533 + quickselect(arr, k, left, right); 7.2534 + quickselect(arr, k + 1, k + 1, right); 7.2535 + } 7.2536 +} 7.2537 + 7.2538 +function multiQuantileSelect(arr, p) { 7.2539 + var indices = [0]; 7.2540 + for (var i = 0; i < p.length; i++) { 7.2541 + indices.push(quantileIndex(arr.length, p[i])); 7.2542 + } 7.2543 + indices.push(arr.length - 1); 7.2544 + indices.sort(compare); 7.2545 + 7.2546 + var stack = [0, indices.length - 1]; 7.2547 + 7.2548 + while (stack.length) { 7.2549 + var r = Math.ceil(stack.pop()); 7.2550 + var l = Math.floor(stack.pop()); 7.2551 + if (r - l <= 1) continue; 7.2552 + 7.2553 + var m = Math.floor((l + r) / 2); 7.2554 + quantileSelect(arr, indices[m], indices[l], indices[r]); 7.2555 + 7.2556 + stack.push(l, m, m, r); 7.2557 + } 7.2558 +} 7.2559 + 7.2560 +function compare(a, b) { 7.2561 + return a - b; 7.2562 +} 7.2563 + 7.2564 +function quantileIndex(len /*: number */, p /*: number */)/*:number*/ { 7.2565 + var idx = len * p; 7.2566 + if (p === 1) { 7.2567 + // If p is 1, directly return the last index 7.2568 + return len - 1; 7.2569 + } else if (p === 0) { 7.2570 + // If p is 0, directly return the first index 7.2571 + return 0; 7.2572 + } else if (idx % 1 !== 0) { 7.2573 + // If index is not integer, return the next index in array 7.2574 + return Math.ceil(idx) - 1; 7.2575 + } else if (len % 2 === 0) { 7.2576 + // If the list has even-length, we'll return the middle of two indices 7.2577 + // around quantile to indicate that we need an average value of the two 7.2578 + return idx - 0.5; 7.2579 + } else { 7.2580 + // Finally, in the simple case of an integer index 7.2581 + // with an odd-length list, return the index 7.2582 + return idx; 7.2583 + } 7.2584 +} 7.2585 + 7.2586 +module.exports = quantile; 7.2587 + 7.2588 +},{"41":41,"42":42}],41:[function(require,module,exports){ 7.2589 +'use strict'; 7.2590 +/* @flow */ 7.2591 + 7.2592 +/** 7.2593 + * This is the internal implementation of quantiles: when you know 7.2594 + * that the order is sorted, you don't need to re-sort it, and the computations 7.2595 + * are faster. 7.2596 + * 7.2597 + * @param {Array<number>} sample input data 7.2598 + * @param {number} p desired quantile: a number between 0 to 1, inclusive 7.2599 + * @returns {number} quantile value 7.2600 + * @example 7.2601 + * quantileSorted([3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20], 0.5); // => 9 7.2602 + */ 7.2603 +function quantileSorted(sample /*: Array<number> */, p /*: number */)/*:number*/ { 7.2604 + var idx = sample.length * p; 7.2605 + if (p < 0 || p > 1) { 7.2606 + return NaN; 7.2607 + } else if (p === 1) { 7.2608 + // If p is 1, directly return the last element 7.2609 + return sample[sample.length - 1]; 7.2610 + } else if (p === 0) { 7.2611 + // If p is 0, directly return the first element 7.2612 + return sample[0]; 7.2613 + } else if (idx % 1 !== 0) { 7.2614 + // If p is not integer, return the next element in array 7.2615 + return sample[Math.ceil(idx) - 1]; 7.2616 + } else if (sample.length % 2 === 0) { 7.2617 + // If the list has even-length, we'll take the average of this number 7.2618 + // and the next value, if there is one 7.2619 + return (sample[idx - 1] + sample[idx]) / 2; 7.2620 + } else { 7.2621 + // Finally, in the simple case of an integer value 7.2622 + // with an odd-length list, return the sample value at the index. 7.2623 + return sample[idx]; 7.2624 + } 7.2625 +} 7.2626 + 7.2627 +module.exports = quantileSorted; 7.2628 + 7.2629 +},{}],42:[function(require,module,exports){ 7.2630 +'use strict'; 7.2631 +/* @flow */ 7.2632 + 7.2633 +module.exports = quickselect; 7.2634 + 7.2635 +/** 7.2636 + * Rearrange items in `arr` so that all items in `[left, k]` range are the smallest. 7.2637 + * The `k`-th element will have the `(k - left + 1)`-th smallest value in `[left, right]`. 7.2638 + * 7.2639 + * Implements Floyd-Rivest selection algorithm https://en.wikipedia.org/wiki/Floyd-Rivest_algorithm 7.2640 + * 7.2641 + * @private 7.2642 + * @param {Array<number>} arr input array 7.2643 + * @param {number} k pivot index 7.2644 + * @param {number} left left index 7.2645 + * @param {number} right right index 7.2646 + * @returns {undefined} 7.2647 + * @example 7.2648 + * var arr = [65, 28, 59, 33, 21, 56, 22, 95, 50, 12, 90, 53, 28, 77, 39]; 7.2649 + * quickselect(arr, 8); 7.2650 + * // = [39, 28, 28, 33, 21, 12, 22, 50, 53, 56, 59, 65, 90, 77, 95] 7.2651 + */ 7.2652 +function quickselect(arr /*: Array<number> */, k /*: number */, left /*: number */, right /*: number */) { 7.2653 + left = left || 0; 7.2654 + right = right || (arr.length - 1); 7.2655 + 7.2656 + while (right > left) { 7.2657 + // 600 and 0.5 are arbitrary constants chosen in the original paper to minimize execution time 7.2658 + if (right - left > 600) { 7.2659 + var n = right - left + 1; 7.2660 + var m = k - left + 1; 7.2661 + var z = Math.log(n); 7.2662 + var s = 0.5 * Math.exp(2 * z / 3); 7.2663 + var sd = 0.5 * Math.sqrt(z * s * (n - s) / n); 7.2664 + if (m - n / 2 < 0) sd *= -1; 7.2665 + var newLeft = Math.max(left, Math.floor(k - m * s / n + sd)); 7.2666 + var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd)); 7.2667 + quickselect(arr, k, newLeft, newRight); 7.2668 + } 7.2669 + 7.2670 + var t = arr[k]; 7.2671 + var i = left; 7.2672 + var j = right; 7.2673 + 7.2674 + swap(arr, left, k); 7.2675 + if (arr[right] > t) swap(arr, left, right); 7.2676 + 7.2677 + while (i < j) { 7.2678 + swap(arr, i, j); 7.2679 + i++; 7.2680 + j--; 7.2681 + while (arr[i] < t) i++; 7.2682 + while (arr[j] > t) j--; 7.2683 + } 7.2684 + 7.2685 + if (arr[left] === t) swap(arr, left, j); 7.2686 + else { 7.2687 + j++; 7.2688 + swap(arr, j, right); 7.2689 + } 7.2690 + 7.2691 + if (j <= k) left = j + 1; 7.2692 + if (k <= j) right = j - 1; 7.2693 + } 7.2694 +} 7.2695 + 7.2696 +function swap(arr, i, j) { 7.2697 + var tmp = arr[i]; 7.2698 + arr[i] = arr[j]; 7.2699 + arr[j] = tmp; 7.2700 +} 7.2701 + 7.2702 +},{}],43:[function(require,module,exports){ 7.2703 +'use strict'; 7.2704 +/* @flow */ 7.2705 + 7.2706 +/** 7.2707 + * The [R Squared](http://en.wikipedia.org/wiki/Coefficient_of_determination) 7.2708 + * value of data compared with a function `f` 7.2709 + * is the sum of the squared differences between the prediction 7.2710 + * and the actual value. 7.2711 + * 7.2712 + * @param {Array<Array<number>>} data input data: this should be doubly-nested 7.2713 + * @param {Function} func function called on `[i][0]` values within the dataset 7.2714 + * @returns {number} r-squared value 7.2715 + * @example 7.2716 + * var samples = [[0, 0], [1, 1]]; 7.2717 + * var regressionLine = linearRegressionLine(linearRegression(samples)); 7.2718 + * rSquared(samples, regressionLine); // = 1 this line is a perfect fit 7.2719 + */ 7.2720 +function rSquared(data /*: Array<Array<number>> */, func /*: Function */) /*: number */ { 7.2721 + if (data.length < 2) { return 1; } 7.2722 + 7.2723 + // Compute the average y value for the actual 7.2724 + // data set in order to compute the 7.2725 + // _total sum of squares_ 7.2726 + var sum = 0, average; 7.2727 + for (var i = 0; i < data.length; i++) { 7.2728 + sum += data[i][1]; 7.2729 + } 7.2730 + average = sum / data.length; 7.2731 + 7.2732 + // Compute the total sum of squares - the 7.2733 + // squared difference between each point 7.2734 + // and the average of all points. 7.2735 + var sumOfSquares = 0; 7.2736 + for (var j = 0; j < data.length; j++) { 7.2737 + sumOfSquares += Math.pow(average - data[j][1], 2); 7.2738 + } 7.2739 + 7.2740 + // Finally estimate the error: the squared 7.2741 + // difference between the estimate and the actual data 7.2742 + // value at each point. 7.2743 + var err = 0; 7.2744 + for (var k = 0; k < data.length; k++) { 7.2745 + err += Math.pow(data[k][1] - func(data[k][0]), 2); 7.2746 + } 7.2747 + 7.2748 + // As the error grows larger, its ratio to the 7.2749 + // sum of squares increases and the r squared 7.2750 + // value grows lower. 7.2751 + return 1 - err / sumOfSquares; 7.2752 +} 7.2753 + 7.2754 +module.exports = rSquared; 7.2755 + 7.2756 +},{}],44:[function(require,module,exports){ 7.2757 +'use strict'; 7.2758 +/* @flow */ 7.2759 + 7.2760 +/** 7.2761 + * The Root Mean Square (RMS) is 7.2762 + * a mean function used as a measure of the magnitude of a set 7.2763 + * of numbers, regardless of their sign. 7.2764 + * This is the square root of the mean of the squares of the 7.2765 + * input numbers. 7.2766 + * This runs on `O(n)`, linear time in respect to the array 7.2767 + * 7.2768 + * @param {Array<number>} x input 7.2769 + * @returns {number} root mean square 7.2770 + * @example 7.2771 + * rootMeanSquare([-1, 1, -1, 1]); // => 1 7.2772 + */ 7.2773 +function rootMeanSquare(x /*: Array<number> */)/*:number*/ { 7.2774 + if (x.length === 0) { return NaN; } 7.2775 + 7.2776 + var sumOfSquares = 0; 7.2777 + for (var i = 0; i < x.length; i++) { 7.2778 + sumOfSquares += Math.pow(x[i], 2); 7.2779 + } 7.2780 + 7.2781 + return Math.sqrt(sumOfSquares / x.length); 7.2782 +} 7.2783 + 7.2784 +module.exports = rootMeanSquare; 7.2785 + 7.2786 +},{}],45:[function(require,module,exports){ 7.2787 +'use strict'; 7.2788 +/* @flow */ 7.2789 + 7.2790 +var shuffle = require(51); 7.2791 + 7.2792 +/** 7.2793 + * Create a [simple random sample](http://en.wikipedia.org/wiki/Simple_random_sample) 7.2794 + * from a given array of `n` elements. 7.2795 + * 7.2796 + * The sampled values will be in any order, not necessarily the order 7.2797 + * they appear in the input. 7.2798 + * 7.2799 + * @param {Array} array input array. can contain any type 7.2800 + * @param {number} n count of how many elements to take 7.2801 + * @param {Function} [randomSource=Math.random] an optional source of entropy 7.2802 + * instead of Math.random 7.2803 + * @return {Array} subset of n elements in original array 7.2804 + * @example 7.2805 + * var values = [1, 2, 4, 5, 6, 7, 8, 9]; 7.2806 + * sample(values, 3); // returns 3 random values, like [2, 5, 8]; 7.2807 + */ 7.2808 +function sample/*:: <T> */( 7.2809 + array /*: Array<T> */, 7.2810 + n /*: number */, 7.2811 + randomSource /*: Function */) /*: Array<T> */ { 7.2812 + // shuffle the original array using a fisher-yates shuffle 7.2813 + var shuffled = shuffle(array, randomSource); 7.2814 + 7.2815 + // and then return a subset of it - the first `n` elements. 7.2816 + return shuffled.slice(0, n); 7.2817 +} 7.2818 + 7.2819 +module.exports = sample; 7.2820 + 7.2821 +},{"51":51}],46:[function(require,module,exports){ 7.2822 +'use strict'; 7.2823 +/* @flow */ 7.2824 + 7.2825 +var sampleCovariance = require(47); 7.2826 +var sampleStandardDeviation = require(49); 7.2827 + 7.2828 +/** 7.2829 + * The [correlation](http://en.wikipedia.org/wiki/Correlation_and_dependence) is 7.2830 + * a measure of how correlated two datasets are, between -1 and 1 7.2831 + * 7.2832 + * @param {Array<number>} x first input 7.2833 + * @param {Array<number>} y second input 7.2834 + * @returns {number} sample correlation 7.2835 + * @example 7.2836 + * sampleCorrelation([1, 2, 3, 4, 5, 6], [2, 2, 3, 4, 5, 60]).toFixed(2); 7.2837 + * // => '0.69' 7.2838 + */ 7.2839 +function sampleCorrelation(x/*: Array<number> */, y/*: Array<number> */)/*:number*/ { 7.2840 + var cov = sampleCovariance(x, y), 7.2841 + xstd = sampleStandardDeviation(x), 7.2842 + ystd = sampleStandardDeviation(y); 7.2843 + 7.2844 + return cov / xstd / ystd; 7.2845 +} 7.2846 + 7.2847 +module.exports = sampleCorrelation; 7.2848 + 7.2849 +},{"47":47,"49":49}],47:[function(require,module,exports){ 7.2850 +'use strict'; 7.2851 +/* @flow */ 7.2852 + 7.2853 +var mean = require(25); 7.2854 + 7.2855 +/** 7.2856 + * [Sample covariance](https://en.wikipedia.org/wiki/Sample_mean_and_sampleCovariance) of two datasets: 7.2857 + * how much do the two datasets move together? 7.2858 + * x and y are two datasets, represented as arrays of numbers. 7.2859 + * 7.2860 + * @param {Array<number>} x first input 7.2861 + * @param {Array<number>} y second input 7.2862 + * @returns {number} sample covariance 7.2863 + * @example 7.2864 + * sampleCovariance([1, 2, 3, 4, 5, 6], [6, 5, 4, 3, 2, 1]); // => -3.5 7.2865 + */ 7.2866 +function sampleCovariance(x /*:Array<number>*/, y /*:Array<number>*/)/*:number*/ { 7.2867 + 7.2868 + // The two datasets must have the same length which must be more than 1 7.2869 + if (x.length <= 1 || x.length !== y.length) { 7.2870 + return NaN; 7.2871 + } 7.2872 + 7.2873 + // determine the mean of each dataset so that we can judge each 7.2874 + // value of the dataset fairly as the difference from the mean. this 7.2875 + // way, if one dataset is [1, 2, 3] and [2, 3, 4], their covariance 7.2876 + // does not suffer because of the difference in absolute values 7.2877 + var xmean = mean(x), 7.2878 + ymean = mean(y), 7.2879 + sum = 0; 7.2880 + 7.2881 + // for each pair of values, the covariance increases when their 7.2882 + // difference from the mean is associated - if both are well above 7.2883 + // or if both are well below 7.2884 + // the mean, the covariance increases significantly. 7.2885 + for (var i = 0; i < x.length; i++) { 7.2886 + sum += (x[i] - xmean) * (y[i] - ymean); 7.2887 + } 7.2888 + 7.2889 + // this is Bessels' Correction: an adjustment made to sample statistics 7.2890 + // that allows for the reduced degree of freedom entailed in calculating 7.2891 + // values from samples rather than complete populations. 7.2892 + var besselsCorrection = x.length - 1; 7.2893 + 7.2894 + // the covariance is weighted by the length of the datasets. 7.2895 + return sum / besselsCorrection; 7.2896 +} 7.2897 + 7.2898 +module.exports = sampleCovariance; 7.2899 + 7.2900 +},{"25":25}],48:[function(require,module,exports){ 7.2901 +'use strict'; 7.2902 +/* @flow */ 7.2903 + 7.2904 +var sumNthPowerDeviations = require(57); 7.2905 +var sampleStandardDeviation = require(49); 7.2906 + 7.2907 +/** 7.2908 + * [Skewness](http://en.wikipedia.org/wiki/Skewness) is 7.2909 + * a measure of the extent to which a probability distribution of a 7.2910 + * real-valued random variable "leans" to one side of the mean. 7.2911 + * The skewness value can be positive or negative, or even undefined. 7.2912 + * 7.2913 + * Implementation is based on the adjusted Fisher-Pearson standardized 7.2914 + * moment coefficient, which is the version found in Excel and several 7.2915 + * statistical packages including Minitab, SAS and SPSS. 7.2916 + * 7.2917 + * @param {Array<number>} x input 7.2918 + * @returns {number} sample skewness 7.2919 + * @example 7.2920 + * sampleSkewness([2, 4, 6, 3, 1]); // => 0.590128656384365 7.2921 + */ 7.2922 +function sampleSkewness(x /*: Array<number> */)/*:number*/ { 7.2923 + // The skewness of less than three arguments is null 7.2924 + var theSampleStandardDeviation = sampleStandardDeviation(x); 7.2925 + 7.2926 + if (isNaN(theSampleStandardDeviation) || x.length < 3) { 7.2927 + return NaN; 7.2928 + } 7.2929 + 7.2930 + var n = x.length, 7.2931 + cubedS = Math.pow(theSampleStandardDeviation, 3), 7.2932 + sumCubedDeviations = sumNthPowerDeviations(x, 3); 7.2933 + 7.2934 + return n * sumCubedDeviations / ((n - 1) * (n - 2) * cubedS); 7.2935 +} 7.2936 + 7.2937 +module.exports = sampleSkewness; 7.2938 + 7.2939 +},{"49":49,"57":57}],49:[function(require,module,exports){ 7.2940 +'use strict'; 7.2941 +/* @flow */ 7.2942 + 7.2943 +var sampleVariance = require(50); 7.2944 + 7.2945 +/** 7.2946 + * The [standard deviation](http://en.wikipedia.org/wiki/Standard_deviation) 7.2947 + * is the square root of the variance. 7.2948 + * 7.2949 + * @param {Array<number>} x input array 7.2950 + * @returns {number} sample standard deviation 7.2951 + * @example 7.2952 + * sampleStandardDeviation([2, 4, 4, 4, 5, 5, 7, 9]).toFixed(2); 7.2953 + * // => '2.14' 7.2954 + */ 7.2955 +function sampleStandardDeviation(x/*:Array<number>*/)/*:number*/ { 7.2956 + // The standard deviation of no numbers is null 7.2957 + var sampleVarianceX = sampleVariance(x); 7.2958 + if (isNaN(sampleVarianceX)) { return NaN; } 7.2959 + return Math.sqrt(sampleVarianceX); 7.2960 +} 7.2961 + 7.2962 +module.exports = sampleStandardDeviation; 7.2963 + 7.2964 +},{"50":50}],50:[function(require,module,exports){ 7.2965 +'use strict'; 7.2966 +/* @flow */ 7.2967 + 7.2968 +var sumNthPowerDeviations = require(57); 7.2969 + 7.2970 +/* 7.2971 + * The [sample variance](https://en.wikipedia.org/wiki/Variance#Sample_variance) 7.2972 + * is the sum of squared deviations from the mean. The sample variance 7.2973 + * is distinguished from the variance by the usage of [Bessel's Correction](https://en.wikipedia.org/wiki/Bessel's_correction): 7.2974 + * instead of dividing the sum of squared deviations by the length of the input, 7.2975 + * it is divided by the length minus one. This corrects the bias in estimating 7.2976 + * a value from a set that you don't know if full. 7.2977 + * 7.2978 + * References: 7.2979 + * * [Wolfram MathWorld on Sample Variance](http://mathworld.wolfram.com/SampleVariance.html) 7.2980 + * 7.2981 + * @param {Array<number>} x input array 7.2982 + * @return {number} sample variance 7.2983 + * @example 7.2984 + * sampleVariance([1, 2, 3, 4, 5]); // => 2.5 7.2985 + */ 7.2986 +function sampleVariance(x /*: Array<number> */)/*:number*/ { 7.2987 + // The variance of no numbers is null 7.2988 + if (x.length <= 1) { return NaN; } 7.2989 + 7.2990 + var sumSquaredDeviationsValue = sumNthPowerDeviations(x, 2); 7.2991 + 7.2992 + // this is Bessels' Correction: an adjustment made to sample statistics 7.2993 + // that allows for the reduced degree of freedom entailed in calculating 7.2994 + // values from samples rather than complete populations. 7.2995 + var besselsCorrection = x.length - 1; 7.2996 + 7.2997 + // Find the mean value of that list 7.2998 + return sumSquaredDeviationsValue / besselsCorrection; 7.2999 +} 7.3000 + 7.3001 +module.exports = sampleVariance; 7.3002 + 7.3003 +},{"57":57}],51:[function(require,module,exports){ 7.3004 +'use strict'; 7.3005 +/* @flow */ 7.3006 + 7.3007 +var shuffleInPlace = require(52); 7.3008 + 7.3009 +/* 7.3010 + * A [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) 7.3011 + * is a fast way to create a random permutation of a finite set. This is 7.3012 + * a function around `shuffle_in_place` that adds the guarantee that 7.3013 + * it will not modify its input. 7.3014 + * 7.3015 + * @param {Array} sample an array of any kind of element 7.3016 + * @param {Function} [randomSource=Math.random] an optional entropy source 7.3017 + * @return {Array} shuffled version of input 7.3018 + * @example 7.3019 + * var shuffled = shuffle([1, 2, 3, 4]); 7.3020 + * shuffled; // = [2, 3, 1, 4] or any other random permutation 7.3021 + */ 7.3022 +function shuffle/*::<T>*/(sample/*:Array<T>*/, randomSource/*:Function*/) { 7.3023 + // slice the original array so that it is not modified 7.3024 + sample = sample.slice(); 7.3025 + 7.3026 + // and then shuffle that shallow-copied array, in place 7.3027 + return shuffleInPlace(sample.slice(), randomSource); 7.3028 +} 7.3029 + 7.3030 +module.exports = shuffle; 7.3031 + 7.3032 +},{"52":52}],52:[function(require,module,exports){ 7.3033 +'use strict'; 7.3034 +/* @flow */ 7.3035 + 7.3036 +/* 7.3037 + * A [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) 7.3038 + * in-place - which means that it **will change the order of the original 7.3039 + * array by reference**. 7.3040 + * 7.3041 + * This is an algorithm that generates a random [permutation](https://en.wikipedia.org/wiki/Permutation) 7.3042 + * of a set. 7.3043 + * 7.3044 + * @param {Array} sample input array 7.3045 + * @param {Function} [randomSource=Math.random] an optional source of entropy 7.3046 + * @returns {Array} sample 7.3047 + * @example 7.3048 + * var sample = [1, 2, 3, 4]; 7.3049 + * shuffleInPlace(sample); 7.3050 + * // sample is shuffled to a value like [2, 1, 4, 3] 7.3051 + */ 7.3052 +function shuffleInPlace(sample/*:Array<any>*/, randomSource/*:Function*/)/*:Array<any>*/ { 7.3053 + 7.3054 + 7.3055 + // a custom random number source can be provided if you want to use 7.3056 + // a fixed seed or another random number generator, like 7.3057 + // [random-js](https://www.npmjs.org/package/random-js) 7.3058 + randomSource = randomSource || Math.random; 7.3059 + 7.3060 + // store the current length of the sample to determine 7.3061 + // when no elements remain to shuffle. 7.3062 + var length = sample.length; 7.3063 + 7.3064 + // temporary is used to hold an item when it is being 7.3065 + // swapped between indices. 7.3066 + var temporary; 7.3067 + 7.3068 + // The index to swap at each stage. 7.3069 + var index; 7.3070 + 7.3071 + // While there are still items to shuffle 7.3072 + while (length > 0) { 7.3073 + // chose a random index within the subset of the array 7.3074 + // that is not yet shuffled 7.3075 + index = Math.floor(randomSource() * length--); 7.3076 + 7.3077 + // store the value that we'll move temporarily 7.3078 + temporary = sample[length]; 7.3079 + 7.3080 + // swap the value at `sample[length]` with `sample[index]` 7.3081 + sample[length] = sample[index]; 7.3082 + sample[index] = temporary; 7.3083 + } 7.3084 + 7.3085 + return sample; 7.3086 +} 7.3087 + 7.3088 +module.exports = shuffleInPlace; 7.3089 + 7.3090 +},{}],53:[function(require,module,exports){ 7.3091 +'use strict'; 7.3092 +/* @flow */ 7.3093 + 7.3094 +/** 7.3095 + * [Sign](https://en.wikipedia.org/wiki/Sign_function) is a function 7.3096 + * that extracts the sign of a real number 7.3097 + * 7.3098 + * @param {Number} x input value 7.3099 + * @returns {Number} sign value either 1, 0 or -1 7.3100 + * @throws {TypeError} if the input argument x is not a number 7.3101 + * @private 7.3102 + * 7.3103 + * @example 7.3104 + * sign(2); // => 1 7.3105 + */ 7.3106 +function sign(x/*: number */)/*: number */ { 7.3107 + if (typeof x === 'number') { 7.3108 + if (x < 0) { 7.3109 + return -1; 7.3110 + } else if (x === 0) { 7.3111 + return 0 7.3112 + } else { 7.3113 + return 1; 7.3114 + } 7.3115 + } else { 7.3116 + throw new TypeError('not a number'); 7.3117 + } 7.3118 +} 7.3119 + 7.3120 +module.exports = sign; 7.3121 + 7.3122 +},{}],54:[function(require,module,exports){ 7.3123 +'use strict'; 7.3124 +/* @flow */ 7.3125 + 7.3126 +var variance = require(62); 7.3127 + 7.3128 +/** 7.3129 + * The [standard deviation](http://en.wikipedia.org/wiki/Standard_deviation) 7.3130 + * is the square root of the variance. It's useful for measuring the amount 7.3131 + * of variation or dispersion in a set of values. 7.3132 + * 7.3133 + * Standard deviation is only appropriate for full-population knowledge: for 7.3134 + * samples of a population, {@link sampleStandardDeviation} is 7.3135 + * more appropriate. 7.3136 + * 7.3137 + * @param {Array<number>} x input 7.3138 + * @returns {number} standard deviation 7.3139 + * @example 7.3140 + * variance([2, 4, 4, 4, 5, 5, 7, 9]); // => 4 7.3141 + * standardDeviation([2, 4, 4, 4, 5, 5, 7, 9]); // => 2 7.3142 + */ 7.3143 +function standardDeviation(x /*: Array<number> */)/*:number*/ { 7.3144 + // The standard deviation of no numbers is null 7.3145 + var v = variance(x); 7.3146 + if (isNaN(v)) { return 0; } 7.3147 + return Math.sqrt(v); 7.3148 +} 7.3149 + 7.3150 +module.exports = standardDeviation; 7.3151 + 7.3152 +},{"62":62}],55:[function(require,module,exports){ 7.3153 +'use strict'; 7.3154 +/* @flow */ 7.3155 + 7.3156 +var SQRT_2PI = Math.sqrt(2 * Math.PI); 7.3157 + 7.3158 +function cumulativeDistribution(z) { 7.3159 + var sum = z, 7.3160 + tmp = z; 7.3161 + 7.3162 + // 15 iterations are enough for 4-digit precision 7.3163 + for (var i = 1; i < 15; i++) { 7.3164 + tmp *= z * z / (2 * i + 1); 7.3165 + sum += tmp; 7.3166 + } 7.3167 + return Math.round((0.5 + (sum / SQRT_2PI) * Math.exp(-z * z / 2)) * 1e4) / 1e4; 7.3168 +} 7.3169 + 7.3170 +/** 7.3171 + * A standard normal table, also called the unit normal table or Z table, 7.3172 + * is a mathematical table for the values of Φ (phi), which are the values of 7.3173 + * the cumulative distribution function of the normal distribution. 7.3174 + * It is used to find the probability that a statistic is observed below, 7.3175 + * above, or between values on the standard normal distribution, and by 7.3176 + * extension, any normal distribution. 7.3177 + * 7.3178 + * The probabilities are calculated using the 7.3179 + * [Cumulative distribution function](https://en.wikipedia.org/wiki/Normal_distribution#Cumulative_distribution_function). 7.3180 + * The table used is the cumulative, and not cumulative from 0 to mean 7.3181 + * (even though the latter has 5 digits precision, instead of 4). 7.3182 + */ 7.3183 +var standardNormalTable/*: Array<number> */ = []; 7.3184 + 7.3185 +for (var z = 0; z <= 3.09; z += 0.01) { 7.3186 + standardNormalTable.push(cumulativeDistribution(z)); 7.3187 +} 7.3188 + 7.3189 +module.exports = standardNormalTable; 7.3190 + 7.3191 +},{}],56:[function(require,module,exports){ 7.3192 +'use strict'; 7.3193 +/* @flow */ 7.3194 + 7.3195 +/** 7.3196 + * Our default sum is the [Kahan summation algorithm](https://en.wikipedia.org/wiki/Kahan_summation_algorithm) is 7.3197 + * a method for computing the sum of a list of numbers while correcting 7.3198 + * for floating-point errors. Traditionally, sums are calculated as many 7.3199 + * successive additions, each one with its own floating-point roundoff. These 7.3200 + * losses in precision add up as the number of numbers increases. This alternative 7.3201 + * algorithm is more accurate than the simple way of calculating sums by simple 7.3202 + * addition. 7.3203 + * 7.3204 + * This runs on `O(n)`, linear time in respect to the array 7.3205 + * 7.3206 + * @param {Array<number>} x input 7.3207 + * @return {number} sum of all input numbers 7.3208 + * @example 7.3209 + * sum([1, 2, 3]); // => 6 7.3210 + */ 7.3211 +function sum(x/*: Array<number> */)/*: number */ { 7.3212 + 7.3213 + // like the traditional sum algorithm, we keep a running 7.3214 + // count of the current sum. 7.3215 + var sum = 0; 7.3216 + 7.3217 + // but we also keep three extra variables as bookkeeping: 7.3218 + // most importantly, an error correction value. This will be a very 7.3219 + // small number that is the opposite of the floating point precision loss. 7.3220 + var errorCompensation = 0; 7.3221 + 7.3222 + // this will be each number in the list corrected with the compensation value. 7.3223 + var correctedCurrentValue; 7.3224 + 7.3225 + // and this will be the next sum 7.3226 + var nextSum; 7.3227 + 7.3228 + for (var i = 0; i < x.length; i++) { 7.3229 + // first correct the value that we're going to add to the sum 7.3230 + correctedCurrentValue = x[i] - errorCompensation; 7.3231 + 7.3232 + // compute the next sum. sum is likely a much larger number 7.3233 + // than correctedCurrentValue, so we'll lose precision here, 7.3234 + // and measure how much precision is lost in the next step 7.3235 + nextSum = sum + correctedCurrentValue; 7.3236 + 7.3237 + // we intentionally didn't assign sum immediately, but stored 7.3238 + // it for now so we can figure out this: is (sum + nextValue) - nextValue 7.3239 + // not equal to 0? ideally it would be, but in practice it won't: 7.3240 + // it will be some very small number. that's what we record 7.3241 + // as errorCompensation. 7.3242 + errorCompensation = nextSum - sum - correctedCurrentValue; 7.3243 + 7.3244 + // now that we've computed how much we'll correct for in the next 7.3245 + // loop, start treating the nextSum as the current sum. 7.3246 + sum = nextSum; 7.3247 + } 7.3248 + 7.3249 + return sum; 7.3250 +} 7.3251 + 7.3252 +module.exports = sum; 7.3253 + 7.3254 +},{}],57:[function(require,module,exports){ 7.3255 +'use strict'; 7.3256 +/* @flow */ 7.3257 + 7.3258 +var mean = require(25); 7.3259 + 7.3260 +/** 7.3261 + * The sum of deviations to the Nth power. 7.3262 + * When n=2 it's the sum of squared deviations. 7.3263 + * When n=3 it's the sum of cubed deviations. 7.3264 + * 7.3265 + * @param {Array<number>} x 7.3266 + * @param {number} n power 7.3267 + * @returns {number} sum of nth power deviations 7.3268 + * @example 7.3269 + * var input = [1, 2, 3]; 7.3270 + * // since the variance of a set is the mean squared 7.3271 + * // deviations, we can calculate that with sumNthPowerDeviations: 7.3272 + * var variance = sumNthPowerDeviations(input) / input.length; 7.3273 + */ 7.3274 +function sumNthPowerDeviations(x/*: Array<number> */, n/*: number */)/*:number*/ { 7.3275 + var meanValue = mean(x), 7.3276 + sum = 0; 7.3277 + 7.3278 + for (var i = 0; i < x.length; i++) { 7.3279 + sum += Math.pow(x[i] - meanValue, n); 7.3280 + } 7.3281 + 7.3282 + return sum; 7.3283 +} 7.3284 + 7.3285 +module.exports = sumNthPowerDeviations; 7.3286 + 7.3287 +},{"25":25}],58:[function(require,module,exports){ 7.3288 +'use strict'; 7.3289 +/* @flow */ 7.3290 + 7.3291 +/** 7.3292 + * The simple [sum](https://en.wikipedia.org/wiki/Summation) of an array 7.3293 + * is the result of adding all numbers together, starting from zero. 7.3294 + * 7.3295 + * This runs on `O(n)`, linear time in respect to the array 7.3296 + * 7.3297 + * @param {Array<number>} x input 7.3298 + * @return {number} sum of all input numbers 7.3299 + * @example 7.3300 + * sumSimple([1, 2, 3]); // => 6 7.3301 + */ 7.3302 +function sumSimple(x/*: Array<number> */)/*: number */ { 7.3303 + var value = 0; 7.3304 + for (var i = 0; i < x.length; i++) { 7.3305 + value += x[i]; 7.3306 + } 7.3307 + return value; 7.3308 +} 7.3309 + 7.3310 +module.exports = sumSimple; 7.3311 + 7.3312 +},{}],59:[function(require,module,exports){ 7.3313 +'use strict'; 7.3314 +/* @flow */ 7.3315 + 7.3316 +var standardDeviation = require(54); 7.3317 +var mean = require(25); 7.3318 + 7.3319 +/** 7.3320 + * This is to compute [a one-sample t-test](https://en.wikipedia.org/wiki/Student%27s_t-test#One-sample_t-test), comparing the mean 7.3321 + * of a sample to a known value, x. 7.3322 + * 7.3323 + * in this case, we're trying to determine whether the 7.3324 + * population mean is equal to the value that we know, which is `x` 7.3325 + * here. usually the results here are used to look up a 7.3326 + * [p-value](http://en.wikipedia.org/wiki/P-value), which, for 7.3327 + * a certain level of significance, will let you determine that the 7.3328 + * null hypothesis can or cannot be rejected. 7.3329 + * 7.3330 + * @param {Array<number>} sample an array of numbers as input 7.3331 + * @param {number} x expected value of the population mean 7.3332 + * @returns {number} value 7.3333 + * @example 7.3334 + * tTest([1, 2, 3, 4, 5, 6], 3.385).toFixed(2); // => '0.16' 7.3335 + */ 7.3336 +function tTest(sample/*: Array<number> */, x/*: number */)/*:number*/ { 7.3337 + // The mean of the sample 7.3338 + var sampleMean = mean(sample); 7.3339 + 7.3340 + // The standard deviation of the sample 7.3341 + var sd = standardDeviation(sample); 7.3342 + 7.3343 + // Square root the length of the sample 7.3344 + var rootN = Math.sqrt(sample.length); 7.3345 + 7.3346 + // returning the t value 7.3347 + return (sampleMean - x) / (sd / rootN); 7.3348 +} 7.3349 + 7.3350 +module.exports = tTest; 7.3351 + 7.3352 +},{"25":25,"54":54}],60:[function(require,module,exports){ 7.3353 +'use strict'; 7.3354 +/* @flow */ 7.3355 + 7.3356 +var mean = require(25); 7.3357 +var sampleVariance = require(50); 7.3358 + 7.3359 +/** 7.3360 + * This is to compute [two sample t-test](http://en.wikipedia.org/wiki/Student's_t-test). 7.3361 + * Tests whether "mean(X)-mean(Y) = difference", ( 7.3362 + * in the most common case, we often have `difference == 0` to test if two samples 7.3363 + * are likely to be taken from populations with the same mean value) with 7.3364 + * no prior knowledge on standard deviations of both samples 7.3365 + * other than the fact that they have the same standard deviation. 7.3366 + * 7.3367 + * Usually the results here are used to look up a 7.3368 + * [p-value](http://en.wikipedia.org/wiki/P-value), which, for 7.3369 + * a certain level of significance, will let you determine that the 7.3370 + * null hypothesis can or cannot be rejected. 7.3371 + * 7.3372 + * `diff` can be omitted if it equals 0. 7.3373 + * 7.3374 + * [This is used to confirm or deny](http://www.monarchlab.org/Lab/Research/Stats/2SampleT.aspx) 7.3375 + * a null hypothesis that the two populations that have been sampled into 7.3376 + * `sampleX` and `sampleY` are equal to each other. 7.3377 + * 7.3378 + * @param {Array<number>} sampleX a sample as an array of numbers 7.3379 + * @param {Array<number>} sampleY a sample as an array of numbers 7.3380 + * @param {number} [difference=0] 7.3381 + * @returns {number} test result 7.3382 + * @example 7.3383 + * ss.tTestTwoSample([1, 2, 3, 4], [3, 4, 5, 6], 0); //= -2.1908902300206643 7.3384 + */ 7.3385 +function tTestTwoSample( 7.3386 + sampleX/*: Array<number> */, 7.3387 + sampleY/*: Array<number> */, 7.3388 + difference/*: number */) { 7.3389 + var n = sampleX.length, 7.3390 + m = sampleY.length; 7.3391 + 7.3392 + // If either sample doesn't actually have any values, we can't 7.3393 + // compute this at all, so we return `null`. 7.3394 + if (!n || !m) { return null; } 7.3395 + 7.3396 + // default difference (mu) is zero 7.3397 + if (!difference) { 7.3398 + difference = 0; 7.3399 + } 7.3400 + 7.3401 + var meanX = mean(sampleX), 7.3402 + meanY = mean(sampleY), 7.3403 + sampleVarianceX = sampleVariance(sampleX), 7.3404 + sampleVarianceY = sampleVariance(sampleY); 7.3405 + 7.3406 + if (typeof meanX === 'number' && 7.3407 + typeof meanY === 'number' && 7.3408 + typeof sampleVarianceX === 'number' && 7.3409 + typeof sampleVarianceY === 'number') { 7.3410 + var weightedVariance = ((n - 1) * sampleVarianceX + 7.3411 + (m - 1) * sampleVarianceY) / (n + m - 2); 7.3412 + 7.3413 + return (meanX - meanY - difference) / 7.3414 + Math.sqrt(weightedVariance * (1 / n + 1 / m)); 7.3415 + } 7.3416 +} 7.3417 + 7.3418 +module.exports = tTestTwoSample; 7.3419 + 7.3420 +},{"25":25,"50":50}],61:[function(require,module,exports){ 7.3421 +'use strict'; 7.3422 +/* @flow */ 7.3423 + 7.3424 +/** 7.3425 + * For a sorted input, counting the number of unique values 7.3426 + * is possible in constant time and constant memory. This is 7.3427 + * a simple implementation of the algorithm. 7.3428 + * 7.3429 + * Values are compared with `===`, so objects and non-primitive objects 7.3430 + * are not handled in any special way. 7.3431 + * 7.3432 + * @param {Array} input an array of primitive values. 7.3433 + * @returns {number} count of unique values 7.3434 + * @example 7.3435 + * uniqueCountSorted([1, 2, 3]); // => 3 7.3436 + * uniqueCountSorted([1, 1, 1]); // => 1 7.3437 + */ 7.3438 +function uniqueCountSorted(input/*: Array<any>*/)/*: number */ { 7.3439 + var uniqueValueCount = 0, 7.3440 + lastSeenValue; 7.3441 + for (var i = 0; i < input.length; i++) { 7.3442 + if (i === 0 || input[i] !== lastSeenValue) { 7.3443 + lastSeenValue = input[i]; 7.3444 + uniqueValueCount++; 7.3445 + } 7.3446 + } 7.3447 + return uniqueValueCount; 7.3448 +} 7.3449 + 7.3450 +module.exports = uniqueCountSorted; 7.3451 + 7.3452 +},{}],62:[function(require,module,exports){ 7.3453 +'use strict'; 7.3454 +/* @flow */ 7.3455 + 7.3456 +var sumNthPowerDeviations = require(57); 7.3457 + 7.3458 +/** 7.3459 + * The [variance](http://en.wikipedia.org/wiki/Variance) 7.3460 + * is the sum of squared deviations from the mean. 7.3461 + * 7.3462 + * This is an implementation of variance, not sample variance: 7.3463 + * see the `sampleVariance` method if you want a sample measure. 7.3464 + * 7.3465 + * @param {Array<number>} x a population 7.3466 + * @returns {number} variance: a value greater than or equal to zero. 7.3467 + * zero indicates that all values are identical. 7.3468 + * @example 7.3469 + * variance([1, 2, 3, 4, 5, 6]); // => 2.9166666666666665 7.3470 + */ 7.3471 +function variance(x/*: Array<number> */)/*:number*/ { 7.3472 + // The variance of no numbers is null 7.3473 + if (x.length === 0) { return NaN; } 7.3474 + 7.3475 + // Find the mean of squared deviations between the 7.3476 + // mean value and each value. 7.3477 + return sumNthPowerDeviations(x, 2) / x.length; 7.3478 +} 7.3479 + 7.3480 +module.exports = variance; 7.3481 + 7.3482 +},{"57":57}],63:[function(require,module,exports){ 7.3483 +'use strict'; 7.3484 +/* @flow */ 7.3485 + 7.3486 +/** 7.3487 + * The [Z-Score, or Standard Score](http://en.wikipedia.org/wiki/Standard_score). 7.3488 + * 7.3489 + * The standard score is the number of standard deviations an observation 7.3490 + * or datum is above or below the mean. Thus, a positive standard score 7.3491 + * represents a datum above the mean, while a negative standard score 7.3492 + * represents a datum below the mean. It is a dimensionless quantity 7.3493 + * obtained by subtracting the population mean from an individual raw 7.3494 + * score and then dividing the difference by the population standard 7.3495 + * deviation. 7.3496 + * 7.3497 + * The z-score is only defined if one knows the population parameters; 7.3498 + * if one only has a sample set, then the analogous computation with 7.3499 + * sample mean and sample standard deviation yields the 7.3500 + * Student's t-statistic. 7.3501 + * 7.3502 + * @param {number} x 7.3503 + * @param {number} mean 7.3504 + * @param {number} standardDeviation 7.3505 + * @return {number} z score 7.3506 + * @example 7.3507 + * zScore(78, 80, 5); // => -0.4 7.3508 + */ 7.3509 +function zScore(x/*:number*/, mean/*:number*/, standardDeviation/*:number*/)/*:number*/ { 7.3510 + return (x - mean) / standardDeviation; 7.3511 +} 7.3512 + 7.3513 +module.exports = zScore; 7.3514 + 7.3515 +},{}]},{},[1])(1) 7.3516 +}); 7.3517 +//# sourceMappingURL=simple-statistics.js.map