Created
October 1, 2016 09:58
-
-
Save dselivanov/ebca527e1e13e157522401b110ea1a61 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
d3 = function() { | |
var d3 = { | |
version: "3.2.7" | |
}; | |
if (!Date.now) Date.now = function() { | |
return +new Date(); | |
}; | |
var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window; | |
try { | |
d3_document.createElement("div").style.setProperty("opacity", 0, ""); | |
} catch (error) { | |
var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; | |
d3_element_prototype.setAttribute = function(name, value) { | |
d3_element_setAttribute.call(this, name, value + ""); | |
}; | |
d3_element_prototype.setAttributeNS = function(space, local, value) { | |
d3_element_setAttributeNS.call(this, space, local, value + ""); | |
}; | |
d3_style_prototype.setProperty = function(name, value, priority) { | |
d3_style_setProperty.call(this, name, value + "", priority); | |
}; | |
} | |
d3.ascending = function(a, b) { | |
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; | |
}; | |
d3.descending = function(a, b) { | |
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; | |
}; | |
d3.min = function(array, f) { | |
var i = -1, n = array.length, a, b; | |
if (arguments.length === 1) { | |
while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; | |
while (++i < n) if ((b = array[i]) != null && a > b) a = b; | |
} else { | |
while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; | |
while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; | |
} | |
return a; | |
}; | |
d3.max = function(array, f) { | |
var i = -1, n = array.length, a, b; | |
if (arguments.length === 1) { | |
while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; | |
while (++i < n) if ((b = array[i]) != null && b > a) a = b; | |
} else { | |
while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; | |
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; | |
} | |
return a; | |
}; | |
d3.extent = function(array, f) { | |
var i = -1, n = array.length, a, b, c; | |
if (arguments.length === 1) { | |
while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined; | |
while (++i < n) if ((b = array[i]) != null) { | |
if (a > b) a = b; | |
if (c < b) c = b; | |
} | |
} else { | |
while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined; | |
while (++i < n) if ((b = f.call(array, array[i], i)) != null) { | |
if (a > b) a = b; | |
if (c < b) c = b; | |
} | |
} | |
return [ a, c ]; | |
}; | |
d3.sum = function(array, f) { | |
var s = 0, n = array.length, a, i = -1; | |
if (arguments.length === 1) { | |
while (++i < n) if (!isNaN(a = +array[i])) s += a; | |
} else { | |
while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; | |
} | |
return s; | |
}; | |
function d3_number(x) { | |
return x != null && !isNaN(x); | |
} | |
d3.mean = function(array, f) { | |
var n = array.length, a, m = 0, i = -1, j = 0; | |
if (arguments.length === 1) { | |
while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; | |
} else { | |
while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; | |
} | |
return j ? m : undefined; | |
}; | |
d3.quantile = function(values, p) { | |
var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; | |
return e ? v + e * (values[h] - v) : v; | |
}; | |
d3.median = function(array, f) { | |
if (arguments.length > 1) array = array.map(f); | |
array = array.filter(d3_number); | |
return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; | |
}; | |
d3.bisector = function(f) { | |
return { | |
left: function(a, x, lo, hi) { | |
if (arguments.length < 3) lo = 0; | |
if (arguments.length < 4) hi = a.length; | |
while (lo < hi) { | |
var mid = lo + hi >>> 1; | |
if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; | |
} | |
return lo; | |
}, | |
right: function(a, x, lo, hi) { | |
if (arguments.length < 3) lo = 0; | |
if (arguments.length < 4) hi = a.length; | |
while (lo < hi) { | |
var mid = lo + hi >>> 1; | |
if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; | |
} | |
return lo; | |
} | |
}; | |
}; | |
var d3_bisector = d3.bisector(function(d) { | |
return d; | |
}); | |
d3.bisectLeft = d3_bisector.left; | |
d3.bisect = d3.bisectRight = d3_bisector.right; | |
d3.shuffle = function(array) { | |
var m = array.length, t, i; | |
while (m) { | |
i = Math.random() * m-- | 0; | |
t = array[m], array[m] = array[i], array[i] = t; | |
} | |
return array; | |
}; | |
d3.permute = function(array, indexes) { | |
var permutes = [], i = -1, n = indexes.length; | |
while (++i < n) permutes[i] = array[indexes[i]]; | |
return permutes; | |
}; | |
d3.zip = function() { | |
if (!(n = arguments.length)) return []; | |
for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { | |
for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { | |
zip[j] = arguments[j][i]; | |
} | |
} | |
return zips; | |
}; | |
function d3_zipLength(d) { | |
return d.length; | |
} | |
d3.transpose = function(matrix) { | |
return d3.zip.apply(d3, matrix); | |
}; | |
d3.keys = function(map) { | |
var keys = []; | |
for (var key in map) keys.push(key); | |
return keys; | |
}; | |
d3.values = function(map) { | |
var values = []; | |
for (var key in map) values.push(map[key]); | |
return values; | |
}; | |
d3.entries = function(map) { | |
var entries = []; | |
for (var key in map) entries.push({ | |
key: key, | |
value: map[key] | |
}); | |
return entries; | |
}; | |
d3.merge = function(arrays) { | |
return Array.prototype.concat.apply([], arrays); | |
}; | |
d3.range = function(start, stop, step) { | |
if (arguments.length < 3) { | |
step = 1; | |
if (arguments.length < 2) { | |
stop = start; | |
start = 0; | |
} | |
} | |
if ((stop - start) / step === Infinity) throw new Error("infinite range"); | |
var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; | |
start *= k, stop *= k, step *= k; | |
if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); | |
return range; | |
}; | |
function d3_range_integerScale(x) { | |
var k = 1; | |
while (x * k % 1) k *= 10; | |
return k; | |
} | |
function d3_class(ctor, properties) { | |
try { | |
for (var key in properties) { | |
Object.defineProperty(ctor.prototype, key, { | |
value: properties[key], | |
enumerable: false | |
}); | |
} | |
} catch (e) { | |
ctor.prototype = properties; | |
} | |
} | |
d3.map = function(object) { | |
var map = new d3_Map(); | |
for (var key in object) map.set(key, object[key]); | |
return map; | |
}; | |
function d3_Map() {} | |
d3_class(d3_Map, { | |
has: function(key) { | |
return d3_map_prefix + key in this; | |
}, | |
get: function(key) { | |
return this[d3_map_prefix + key]; | |
}, | |
set: function(key, value) { | |
return this[d3_map_prefix + key] = value; | |
}, | |
remove: function(key) { | |
key = d3_map_prefix + key; | |
return key in this && delete this[key]; | |
}, | |
keys: function() { | |
var keys = []; | |
this.forEach(function(key) { | |
keys.push(key); | |
}); | |
return keys; | |
}, | |
values: function() { | |
var values = []; | |
this.forEach(function(key, value) { | |
values.push(value); | |
}); | |
return values; | |
}, | |
entries: function() { | |
var entries = []; | |
this.forEach(function(key, value) { | |
entries.push({ | |
key: key, | |
value: value | |
}); | |
}); | |
return entries; | |
}, | |
forEach: function(f) { | |
for (var key in this) { | |
if (key.charCodeAt(0) === d3_map_prefixCode) { | |
f.call(this, key.substring(1), this[key]); | |
} | |
} | |
} | |
}); | |
var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); | |
d3.nest = function() { | |
var nest = {}, keys = [], sortKeys = [], sortValues, rollup; | |
function map(mapType, array, depth) { | |
if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; | |
var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; | |
while (++i < n) { | |
if (values = valuesByKey.get(keyValue = key(object = array[i]))) { | |
values.push(object); | |
} else { | |
valuesByKey.set(keyValue, [ object ]); | |
} | |
} | |
if (mapType) { | |
object = mapType(); | |
setter = function(keyValue, values) { | |
object.set(keyValue, map(mapType, values, depth)); | |
}; | |
} else { | |
object = {}; | |
setter = function(keyValue, values) { | |
object[keyValue] = map(mapType, values, depth); | |
}; | |
} | |
valuesByKey.forEach(setter); | |
return object; | |
} | |
function entries(map, depth) { | |
if (depth >= keys.length) return map; | |
var array = [], sortKey = sortKeys[depth++]; | |
map.forEach(function(key, keyMap) { | |
array.push({ | |
key: key, | |
values: entries(keyMap, depth) | |
}); | |
}); | |
return sortKey ? array.sort(function(a, b) { | |
return sortKey(a.key, b.key); | |
}) : array; | |
} | |
nest.map = function(array, mapType) { | |
return map(mapType, array, 0); | |
}; | |
nest.entries = function(array) { | |
return entries(map(d3.map, array, 0), 0); | |
}; | |
nest.key = function(d) { | |
keys.push(d); | |
return nest; | |
}; | |
nest.sortKeys = function(order) { | |
sortKeys[keys.length - 1] = order; | |
return nest; | |
}; | |
nest.sortValues = function(order) { | |
sortValues = order; | |
return nest; | |
}; | |
nest.rollup = function(f) { | |
rollup = f; | |
return nest; | |
}; | |
return nest; | |
}; | |
d3.set = function(array) { | |
var set = new d3_Set(); | |
if (array) for (var i = 0; i < array.length; i++) set.add(array[i]); | |
return set; | |
}; | |
function d3_Set() {} | |
d3_class(d3_Set, { | |
has: function(value) { | |
return d3_map_prefix + value in this; | |
}, | |
add: function(value) { | |
this[d3_map_prefix + value] = true; | |
return value; | |
}, | |
remove: function(value) { | |
value = d3_map_prefix + value; | |
return value in this && delete this[value]; | |
}, | |
values: function() { | |
var values = []; | |
this.forEach(function(value) { | |
values.push(value); | |
}); | |
return values; | |
}, | |
forEach: function(f) { | |
for (var value in this) { | |
if (value.charCodeAt(0) === d3_map_prefixCode) { | |
f.call(this, value.substring(1)); | |
} | |
} | |
} | |
}); | |
d3.behavior = {}; | |
d3.rebind = function(target, source) { | |
var i = 1, n = arguments.length, method; | |
while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); | |
return target; | |
}; | |
function d3_rebind(target, source, method) { | |
return function() { | |
var value = method.apply(source, arguments); | |
return value === source ? target : value; | |
}; | |
} | |
function d3_vendorSymbol(object, name) { | |
if (name in object) return name; | |
name = name.charAt(0).toUpperCase() + name.substring(1); | |
for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { | |
var prefixName = d3_vendorPrefixes[i] + name; | |
if (prefixName in object) return prefixName; | |
} | |
} | |
var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; | |
var d3_array = d3_arraySlice; | |
function d3_arrayCopy(pseudoarray) { | |
var i = -1, n = pseudoarray.length, array = []; | |
while (++i < n) array.push(pseudoarray[i]); | |
return array; | |
} | |
function d3_arraySlice(pseudoarray) { | |
return Array.prototype.slice.call(pseudoarray); | |
} | |
try { | |
d3_array(d3_documentElement.childNodes)[0].nodeType; | |
} catch (e) { | |
d3_array = d3_arrayCopy; | |
} | |
function d3_noop() {} | |
d3.dispatch = function() { | |
var dispatch = new d3_dispatch(), i = -1, n = arguments.length; | |
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); | |
return dispatch; | |
}; | |
function d3_dispatch() {} | |
d3_dispatch.prototype.on = function(type, listener) { | |
var i = type.indexOf("."), name = ""; | |
if (i >= 0) { | |
name = type.substring(i + 1); | |
type = type.substring(0, i); | |
} | |
if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); | |
if (arguments.length === 2) { | |
if (listener == null) for (type in this) { | |
if (this.hasOwnProperty(type)) this[type].on(name, null); | |
} | |
return this; | |
} | |
}; | |
function d3_dispatch_event(dispatch) { | |
var listeners = [], listenerByName = new d3_Map(); | |
function event() { | |
var z = listeners, i = -1, n = z.length, l; | |
while (++i < n) if (l = z[i].on) l.apply(this, arguments); | |
return dispatch; | |
} | |
event.on = function(name, listener) { | |
var l = listenerByName.get(name), i; | |
if (arguments.length < 2) return l && l.on; | |
if (l) { | |
l.on = null; | |
listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); | |
listenerByName.remove(name); | |
} | |
if (listener) listeners.push(listenerByName.set(name, { | |
on: listener | |
})); | |
return dispatch; | |
}; | |
return event; | |
} | |
d3.event = null; | |
function d3_eventPreventDefault() { | |
d3.event.preventDefault(); | |
} | |
function d3_eventSource() { | |
var e = d3.event, s; | |
while (s = e.sourceEvent) e = s; | |
return e; | |
} | |
function d3_eventDispatch(target) { | |
var dispatch = new d3_dispatch(), i = 0, n = arguments.length; | |
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); | |
dispatch.of = function(thiz, argumentz) { | |
return function(e1) { | |
try { | |
var e0 = e1.sourceEvent = d3.event; | |
e1.target = target; | |
d3.event = e1; | |
dispatch[e1.type].apply(thiz, argumentz); | |
} finally { | |
d3.event = e0; | |
} | |
}; | |
}; | |
return dispatch; | |
} | |
d3.requote = function(s) { | |
return s.replace(d3_requote_re, "\\$&"); | |
}; | |
var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; | |
var d3_subclass = {}.__proto__ ? function(object, prototype) { | |
object.__proto__ = prototype; | |
} : function(object, prototype) { | |
for (var property in prototype) object[property] = prototype[property]; | |
}; | |
function d3_selection(groups) { | |
d3_subclass(groups, d3_selectionPrototype); | |
return groups; | |
} | |
var d3_select = function(s, n) { | |
return n.querySelector(s); | |
}, d3_selectAll = function(s, n) { | |
return n.querySelectorAll(s); | |
}, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { | |
return d3_selectMatcher.call(n, s); | |
}; | |
if (typeof Sizzle === "function") { | |
d3_select = function(s, n) { | |
return Sizzle(s, n)[0] || null; | |
}; | |
d3_selectAll = function(s, n) { | |
return Sizzle.uniqueSort(Sizzle(s, n)); | |
}; | |
d3_selectMatches = Sizzle.matchesSelector; | |
} | |
d3.selection = function() { | |
return d3_selectionRoot; | |
}; | |
var d3_selectionPrototype = d3.selection.prototype = []; | |
d3_selectionPrototype.select = function(selector) { | |
var subgroups = [], subgroup, subnode, group, node; | |
selector = d3_selection_selector(selector); | |
for (var j = -1, m = this.length; ++j < m; ) { | |
subgroups.push(subgroup = []); | |
subgroup.parentNode = (group = this[j]).parentNode; | |
for (var i = -1, n = group.length; ++i < n; ) { | |
if (node = group[i]) { | |
subgroup.push(subnode = selector.call(node, node.__data__, i, j)); | |
if (subnode && "__data__" in node) subnode.__data__ = node.__data__; | |
} else { | |
subgroup.push(null); | |
} | |
} | |
} | |
return d3_selection(subgroups); | |
}; | |
function d3_selection_selector(selector) { | |
return typeof selector === "function" ? selector : function() { | |
return d3_select(selector, this); | |
}; | |
} | |
d3_selectionPrototype.selectAll = function(selector) { | |
var subgroups = [], subgroup, node; | |
selector = d3_selection_selectorAll(selector); | |
for (var j = -1, m = this.length; ++j < m; ) { | |
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { | |
if (node = group[i]) { | |
subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); | |
subgroup.parentNode = node; | |
} | |
} | |
} | |
return d3_selection(subgroups); | |
}; | |
function d3_selection_selectorAll(selector) { | |
return typeof selector === "function" ? selector : function() { | |
return d3_selectAll(selector, this); | |
}; | |
} | |
var d3_nsPrefix = { | |
svg: "http://www.w3.org/2000/svg", | |
xhtml: "http://www.w3.org/1999/xhtml", | |
xlink: "http://www.w3.org/1999/xlink", | |
xml: "http://www.w3.org/XML/1998/namespace", | |
xmlns: "http://www.w3.org/2000/xmlns/" | |
}; | |
d3.ns = { | |
prefix: d3_nsPrefix, | |
qualify: function(name) { | |
var i = name.indexOf(":"), prefix = name; | |
if (i >= 0) { | |
prefix = name.substring(0, i); | |
name = name.substring(i + 1); | |
} | |
return d3_nsPrefix.hasOwnProperty(prefix) ? { | |
space: d3_nsPrefix[prefix], | |
local: name | |
} : name; | |
} | |
}; | |
d3_selectionPrototype.attr = function(name, value) { | |
if (arguments.length < 2) { | |
if (typeof name === "string") { | |
var node = this.node(); | |
name = d3.ns.qualify(name); | |
return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); | |
} | |
for (value in name) this.each(d3_selection_attr(value, name[value])); | |
return this; | |
} | |
return this.each(d3_selection_attr(name, value)); | |
}; | |
function d3_selection_attr(name, value) { | |
name = d3.ns.qualify(name); | |
function attrNull() { | |
this.removeAttribute(name); | |
} | |
function attrNullNS() { | |
this.removeAttributeNS(name.space, name.local); | |
} | |
function attrConstant() { | |
this.setAttribute(name, value); | |
} | |
function attrConstantNS() { | |
this.setAttributeNS(name.space, name.local, value); | |
} | |
function attrFunction() { | |
var x = value.apply(this, arguments); | |
if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); | |
} | |
function attrFunctionNS() { | |
var x = value.apply(this, arguments); | |
if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); | |
} | |
return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; | |
} | |
function d3_collapse(s) { | |
return s.trim().replace(/\s+/g, " "); | |
} | |
d3_selectionPrototype.classed = function(name, value) { | |
if (arguments.length < 2) { | |
if (typeof name === "string") { | |
var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; | |
if (value = node.classList) { | |
while (++i < n) if (!value.contains(name[i])) return false; | |
} else { | |
value = node.getAttribute("class"); | |
while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; | |
} | |
return true; | |
} | |
for (value in name) this.each(d3_selection_classed(value, name[value])); | |
return this; | |
} | |
return this.each(d3_selection_classed(name, value)); | |
}; | |
function d3_selection_classedRe(name) { | |
return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); | |
} | |
function d3_selection_classed(name, value) { | |
name = name.trim().split(/\s+/).map(d3_selection_classedName); | |
var n = name.length; | |
function classedConstant() { | |
var i = -1; | |
while (++i < n) name[i](this, value); | |
} | |
function classedFunction() { | |
var i = -1, x = value.apply(this, arguments); | |
while (++i < n) name[i](this, x); | |
} | |
return typeof value === "function" ? classedFunction : classedConstant; | |
} | |
function d3_selection_classedName(name) { | |
var re = d3_selection_classedRe(name); | |
return function(node, value) { | |
if (c = node.classList) return value ? c.add(name) : c.remove(name); | |
var c = node.getAttribute("class") || ""; | |
if (value) { | |
re.lastIndex = 0; | |
if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); | |
} else { | |
node.setAttribute("class", d3_collapse(c.replace(re, " "))); | |
} | |
}; | |
} | |
d3_selectionPrototype.style = function(name, value, priority) { | |
var n = arguments.length; | |
if (n < 3) { | |
if (typeof name !== "string") { | |
if (n < 2) value = ""; | |
for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); | |
return this; | |
} | |
if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); | |
priority = ""; | |
} | |
return this.each(d3_selection_style(name, value, priority)); | |
}; | |
function d3_selection_style(name, value, priority) { | |
function styleNull() { | |
this.style.removeProperty(name); | |
} | |
function styleConstant() { | |
this.style.setProperty(name, value, priority); | |
} | |
function styleFunction() { | |
var x = value.apply(this, arguments); | |
if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); | |
} | |
return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; | |
} | |
d3_selectionPrototype.property = function(name, value) { | |
if (arguments.length < 2) { | |
if (typeof name === "string") return this.node()[name]; | |
for (value in name) this.each(d3_selection_property(value, name[value])); | |
return this; | |
} | |
return this.each(d3_selection_property(name, value)); | |
}; | |
function d3_selection_property(name, value) { | |
function propertyNull() { | |
delete this[name]; | |
} | |
function propertyConstant() { | |
this[name] = value; | |
} | |
function propertyFunction() { | |
var x = value.apply(this, arguments); | |
if (x == null) delete this[name]; else this[name] = x; | |
} | |
return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; | |
} | |
d3_selectionPrototype.text = function(value) { | |
return arguments.length ? this.each(typeof value === "function" ? function() { | |
var v = value.apply(this, arguments); | |
this.textContent = v == null ? "" : v; | |
} : value == null ? function() { | |
this.textContent = ""; | |
} : function() { | |
this.textContent = value; | |
}) : this.node().textContent; | |
}; | |
d3_selectionPrototype.html = function(value) { | |
return arguments.length ? this.each(typeof value === "function" ? function() { | |
var v = value.apply(this, arguments); | |
this.innerHTML = v == null ? "" : v; | |
} : value == null ? function() { | |
this.innerHTML = ""; | |
} : function() { | |
this.innerHTML = value; | |
}) : this.node().innerHTML; | |
}; | |
d3_selectionPrototype.append = function(name) { | |
name = d3_selection_creator(name); | |
return this.select(function() { | |
return this.appendChild(name.apply(this, arguments)); | |
}); | |
}; | |
function d3_selection_creator(name) { | |
return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { | |
return d3_document.createElementNS(name.space, name.local); | |
} : function() { | |
return d3_document.createElementNS(this.namespaceURI, name); | |
}; | |
} | |
d3_selectionPrototype.insert = function(name, before) { | |
name = d3_selection_creator(name); | |
before = d3_selection_selector(before); | |
return this.select(function() { | |
return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)); | |
}); | |
}; | |
d3_selectionPrototype.remove = function() { | |
return this.each(function() { | |
var parent = this.parentNode; | |
if (parent) parent.removeChild(this); | |
}); | |
}; | |
d3_selectionPrototype.data = function(value, key) { | |
var i = -1, n = this.length, group, node; | |
if (!arguments.length) { | |
value = new Array(n = (group = this[0]).length); | |
while (++i < n) { | |
if (node = group[i]) { | |
value[i] = node.__data__; | |
} | |
} | |
return value; | |
} | |
function bind(group, groupData) { | |
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; | |
if (key) { | |
var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; | |
for (i = -1; ++i < n; ) { | |
keyValue = key.call(node = group[i], node.__data__, i); | |
if (nodeByKeyValue.has(keyValue)) { | |
exitNodes[i] = node; | |
} else { | |
nodeByKeyValue.set(keyValue, node); | |
} | |
keyValues.push(keyValue); | |
} | |
for (i = -1; ++i < m; ) { | |
keyValue = key.call(groupData, nodeData = groupData[i], i); | |
if (node = nodeByKeyValue.get(keyValue)) { | |
updateNodes[i] = node; | |
node.__data__ = nodeData; | |
} else if (!dataByKeyValue.has(keyValue)) { | |
enterNodes[i] = d3_selection_dataNode(nodeData); | |
} | |
dataByKeyValue.set(keyValue, nodeData); | |
nodeByKeyValue.remove(keyValue); | |
} | |
for (i = -1; ++i < n; ) { | |
if (nodeByKeyValue.has(keyValues[i])) { | |
exitNodes[i] = group[i]; | |
} | |
} | |
} else { | |
for (i = -1; ++i < n0; ) { | |
node = group[i]; | |
nodeData = groupData[i]; | |
if (node) { | |
node.__data__ = nodeData; | |
updateNodes[i] = node; | |
} else { | |
enterNodes[i] = d3_selection_dataNode(nodeData); | |
} | |
} | |
for (;i < m; ++i) { | |
enterNodes[i] = d3_selection_dataNode(groupData[i]); | |
} | |
for (;i < n; ++i) { | |
exitNodes[i] = group[i]; | |
} | |
} | |
enterNodes.update = updateNodes; | |
enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; | |
enter.push(enterNodes); | |
update.push(updateNodes); | |
exit.push(exitNodes); | |
} | |
var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); | |
if (typeof value === "function") { | |
while (++i < n) { | |
bind(group = this[i], value.call(group, group.parentNode.__data__, i)); | |
} | |
} else { | |
while (++i < n) { | |
bind(group = this[i], value); | |
} | |
} | |
update.enter = function() { | |
return enter; | |
}; | |
update.exit = function() { | |
return exit; | |
}; | |
return update; | |
}; | |
function d3_selection_dataNode(data) { | |
return { | |
__data__: data | |
}; | |
} | |
d3_selectionPrototype.datum = function(value) { | |
return arguments.length ? this.property("__data__", value) : this.property("__data__"); | |
}; | |
d3_selectionPrototype.filter = function(filter) { | |
var subgroups = [], subgroup, group, node; | |
if (typeof filter !== "function") filter = d3_selection_filter(filter); | |
for (var j = 0, m = this.length; j < m; j++) { | |
subgroups.push(subgroup = []); | |
subgroup.parentNode = (group = this[j]).parentNode; | |
for (var i = 0, n = group.length; i < n; i++) { | |
if ((node = group[i]) && filter.call(node, node.__data__, i)) { | |
subgroup.push(node); | |
} | |
} | |
} | |
return d3_selection(subgroups); | |
}; | |
function d3_selection_filter(selector) { | |
return function() { | |
return d3_selectMatches(this, selector); | |
}; | |
} | |
d3_selectionPrototype.order = function() { | |
for (var j = -1, m = this.length; ++j < m; ) { | |
for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { | |
if (node = group[i]) { | |
if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); | |
next = node; | |
} | |
} | |
} | |
return this; | |
}; | |
d3_selectionPrototype.sort = function(comparator) { | |
comparator = d3_selection_sortComparator.apply(this, arguments); | |
for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); | |
return this.order(); | |
}; | |
function d3_selection_sortComparator(comparator) { | |
if (!arguments.length) comparator = d3.ascending; | |
return function(a, b) { | |
return !a - !b || comparator(a.__data__, b.__data__); | |
}; | |
} | |
d3_selectionPrototype.each = function(callback) { | |
return d3_selection_each(this, function(node, i, j) { | |
callback.call(node, node.__data__, i, j); | |
}); | |
}; | |
function d3_selection_each(groups, callback) { | |
for (var j = 0, m = groups.length; j < m; j++) { | |
for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { | |
if (node = group[i]) callback(node, i, j); | |
} | |
} | |
return groups; | |
} | |
d3_selectionPrototype.call = function(callback) { | |
var args = d3_array(arguments); | |
callback.apply(args[0] = this, args); | |
return this; | |
}; | |
d3_selectionPrototype.empty = function() { | |
return !this.node(); | |
}; | |
d3_selectionPrototype.node = function() { | |
for (var j = 0, m = this.length; j < m; j++) { | |
for (var group = this[j], i = 0, n = group.length; i < n; i++) { | |
var node = group[i]; | |
if (node) return node; | |
} | |
} | |
return null; | |
}; | |
d3_selectionPrototype.size = function() { | |
var n = 0; | |
this.each(function() { | |
++n; | |
}); | |
return n; | |
}; | |
function d3_selection_enter(selection) { | |
d3_subclass(selection, d3_selection_enterPrototype); | |
return selection; | |
} | |
var d3_selection_enterPrototype = []; | |
d3.selection.enter = d3_selection_enter; | |
d3.selection.enter.prototype = d3_selection_enterPrototype; | |
d3_selection_enterPrototype.append = d3_selectionPrototype.append; | |
d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; | |
d3_selection_enterPrototype.node = d3_selectionPrototype.node; | |
d3_selection_enterPrototype.call = d3_selectionPrototype.call; | |
d3_selection_enterPrototype.size = d3_selectionPrototype.size; | |
d3_selection_enterPrototype.select = function(selector) { | |
var subgroups = [], subgroup, subnode, upgroup, group, node; | |
for (var j = -1, m = this.length; ++j < m; ) { | |
upgroup = (group = this[j]).update; | |
subgroups.push(subgroup = []); | |
subgroup.parentNode = group.parentNode; | |
for (var i = -1, n = group.length; ++i < n; ) { | |
if (node = group[i]) { | |
subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); | |
subnode.__data__ = node.__data__; | |
} else { | |
subgroup.push(null); | |
} | |
} | |
} | |
return d3_selection(subgroups); | |
}; | |
d3_selection_enterPrototype.insert = function(name, before) { | |
if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); | |
return d3_selectionPrototype.insert.call(this, name, before); | |
}; | |
function d3_selection_enterInsertBefore(enter) { | |
var i0, j0; | |
return function(d, i, j) { | |
var group = enter[j].update, n = group.length, node; | |
if (j != j0) j0 = j, i0 = 0; | |
if (i >= i0) i0 = i + 1; | |
while (!(node = group[i0]) && ++i0 < n) ; | |
return node; | |
}; | |
} | |
d3_selectionPrototype.transition = function() { | |
var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || { | |
time: Date.now(), | |
ease: d3_ease_cubicInOut, | |
delay: 0, | |
duration: 250 | |
}; | |
for (var j = -1, m = this.length; ++j < m; ) { | |
subgroups.push(subgroup = []); | |
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { | |
if (node = group[i]) d3_transitionNode(node, i, id, transition); | |
subgroup.push(node); | |
} | |
} | |
return d3_transition(subgroups, id); | |
}; | |
d3.select = function(node) { | |
var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; | |
group.parentNode = d3_documentElement; | |
return d3_selection([ group ]); | |
}; | |
d3.selectAll = function(nodes) { | |
var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); | |
group.parentNode = d3_documentElement; | |
return d3_selection([ group ]); | |
}; | |
var d3_selectionRoot = d3.select(d3_documentElement); | |
d3_selectionPrototype.on = function(type, listener, capture) { | |
var n = arguments.length; | |
if (n < 3) { | |
if (typeof type !== "string") { | |
if (n < 2) listener = false; | |
for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); | |
return this; | |
} | |
if (n < 2) return (n = this.node()["__on" + type]) && n._; | |
capture = false; | |
} | |
return this.each(d3_selection_on(type, listener, capture)); | |
}; | |
function d3_selection_on(type, listener, capture) { | |
var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; | |
if (i > 0) type = type.substring(0, i); | |
var filter = d3_selection_onFilters.get(type); | |
if (filter) type = filter, wrap = d3_selection_onFilter; | |
function onRemove() { | |
var l = this[name]; | |
if (l) { | |
this.removeEventListener(type, l, l.$); | |
delete this[name]; | |
} | |
} | |
function onAdd() { | |
var l = wrap(listener, d3_array(arguments)); | |
onRemove.call(this); | |
this.addEventListener(type, this[name] = l, l.$ = capture); | |
l._ = listener; | |
} | |
function removeAll() { | |
var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; | |
for (var name in this) { | |
if (match = name.match(re)) { | |
var l = this[name]; | |
this.removeEventListener(match[1], l, l.$); | |
delete this[name]; | |
} | |
} | |
} | |
return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; | |
} | |
var d3_selection_onFilters = d3.map({ | |
mouseenter: "mouseover", | |
mouseleave: "mouseout" | |
}); | |
d3_selection_onFilters.forEach(function(k) { | |
if ("on" + k in d3_document) d3_selection_onFilters.remove(k); | |
}); | |
function d3_selection_onListener(listener, argumentz) { | |
return function(e) { | |
var o = d3.event; | |
d3.event = e; | |
argumentz[0] = this.__data__; | |
try { | |
listener.apply(this, argumentz); | |
} finally { | |
d3.event = o; | |
} | |
}; | |
} | |
function d3_selection_onFilter(listener, argumentz) { | |
var l = d3_selection_onListener(listener, argumentz); | |
return function(e) { | |
var target = this, related = e.relatedTarget; | |
if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { | |
l.call(target, e); | |
} | |
}; | |
} | |
var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; | |
function d3_event_dragSuppress() { | |
var name = ".dragsuppress-" + ++d3_event_dragId, touchmove = "touchmove" + name, selectstart = "selectstart" + name, dragstart = "dragstart" + name, click = "click" + name, w = d3.select(d3_window).on(touchmove, d3_eventPreventDefault).on(selectstart, d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style = d3_documentElement.style, select = style[d3_event_dragSelect]; | |
style[d3_event_dragSelect] = "none"; | |
return function(suppressClick) { | |
w.on(name, null); | |
style[d3_event_dragSelect] = select; | |
if (suppressClick) { | |
function off() { | |
w.on(click, null); | |
} | |
w.on(click, function() { | |
d3_eventPreventDefault(); | |
off(); | |
}, true); | |
setTimeout(off, 0); | |
} | |
}; | |
} | |
d3.mouse = function(container) { | |
return d3_mousePoint(container, d3_eventSource()); | |
}; | |
var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; | |
function d3_mousePoint(container, e) { | |
var svg = container.ownerSVGElement || container; | |
if (svg.createSVGPoint) { | |
var point = svg.createSVGPoint(); | |
if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { | |
svg = d3.select("body").append("svg").style({ | |
position: "absolute", | |
top: 0, | |
left: 0, | |
margin: 0, | |
padding: 0, | |
border: "none" | |
}, "important"); | |
var ctm = svg[0][0].getScreenCTM(); | |
d3_mouse_bug44083 = !(ctm.f || ctm.e); | |
svg.remove(); | |
} | |
if (d3_mouse_bug44083) { | |
point.x = e.pageX; | |
point.y = e.pageY; | |
} else { | |
point.x = e.clientX; | |
point.y = e.clientY; | |
} | |
point = point.matrixTransform(container.getScreenCTM().inverse()); | |
return [ point.x, point.y ]; | |
} | |
var rect = container.getBoundingClientRect(); | |
return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; | |
} | |
d3.touches = function(container, touches) { | |
if (arguments.length < 2) touches = d3_eventSource().touches; | |
return touches ? d3_array(touches).map(function(touch) { | |
var point = d3_mousePoint(container, touch); | |
point.identifier = touch.identifier; | |
return point; | |
}) : []; | |
}; | |
d3.behavior.drag = function() { | |
var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); | |
function drag() { | |
this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); | |
} | |
function touchid() { | |
return d3.event.changedTouches[0].identifier; | |
} | |
function touchposition(parent, id) { | |
return d3.touches(parent).filter(function(p) { | |
return p.identifier === id; | |
})[0]; | |
} | |
function dragstart(id, position, move, end) { | |
return function() { | |
var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress(); | |
if (origin) { | |
offset = origin.apply(target, arguments); | |
offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; | |
} else { | |
offset = [ 0, 0 ]; | |
} | |
event_({ | |
type: "dragstart" | |
}); | |
function moved() { | |
if (!parent) return ended(); | |
var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; | |
dragged |= dx | dy; | |
origin_ = p; | |
event_({ | |
type: "drag", | |
x: p[0] + offset[0], | |
y: p[1] + offset[1], | |
dx: dx, | |
dy: dy | |
}); | |
} | |
function ended() { | |
w.on(move + "." + drag, null).on(end + "." + drag, null); | |
dragRestore(dragged && d3.event.target === eventTarget); | |
event_({ | |
type: "dragend" | |
}); | |
} | |
}; | |
} | |
drag.origin = function(x) { | |
if (!arguments.length) return origin; | |
origin = x; | |
return drag; | |
}; | |
return d3.rebind(drag, event, "on"); | |
}; | |
d3.behavior.zoom = function() { | |
var translate = [ 0, 0 ], translate0, scale = 1, scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime; | |
function zoom() { | |
this.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on("touchstart.zoom", touchstarted); | |
} | |
zoom.translate = function(x) { | |
if (!arguments.length) return translate; | |
translate = x.map(Number); | |
rescale(); | |
return zoom; | |
}; | |
zoom.scale = function(x) { | |
if (!arguments.length) return scale; | |
scale = +x; | |
rescale(); | |
return zoom; | |
}; | |
zoom.scaleExtent = function(x) { | |
if (!arguments.length) return scaleExtent; | |
scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); | |
return zoom; | |
}; | |
zoom.x = function(z) { | |
if (!arguments.length) return x1; | |
x1 = z; | |
x0 = z.copy(); | |
translate = [ 0, 0 ]; | |
scale = 1; | |
return zoom; | |
}; | |
zoom.y = function(z) { | |
if (!arguments.length) return y1; | |
y1 = z; | |
y0 = z.copy(); | |
translate = [ 0, 0 ]; | |
scale = 1; | |
return zoom; | |
}; | |
function location(p) { | |
return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; | |
} | |
function point(l) { | |
return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; | |
} | |
function scaleTo(s) { | |
scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); | |
} | |
function translateTo(p, l) { | |
l = point(l); | |
translate[0] += p[0] - l[0]; | |
translate[1] += p[1] - l[1]; | |
} | |
function rescale() { | |
if (x1) x1.domain(x0.range().map(function(x) { | |
return (x - translate[0]) / scale; | |
}).map(x0.invert)); | |
if (y1) y1.domain(y0.range().map(function(y) { | |
return (y - translate[1]) / scale; | |
}).map(y0.invert)); | |
} | |
function dispatch(event) { | |
rescale(); | |
event({ | |
type: "zoom", | |
scale: scale, | |
translate: translate | |
}); | |
} | |
function mousedowned() { | |
var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress(); | |
function moved() { | |
dragged = 1; | |
translateTo(d3.mouse(target), l); | |
dispatch(event_); | |
} | |
function ended() { | |
w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); | |
dragRestore(dragged && d3.event.target === eventTarget); | |
} | |
} | |
function touchstarted() { | |
var target = this, event_ = event.of(target, arguments), touches = d3.touches(target), locations = {}, distance0 = 0, scale0 = scale, now = Date.now(), name = "zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove." + name, touchend = "touchend." + name, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null), dragRestore = d3_event_dragSuppress(); | |
touches.forEach(function(t) { | |
locations[t.identifier] = location(t); | |
}); | |
if (touches.length === 1) { | |
if (now - touchtime < 500) { | |
var p = touches[0], l = location(touches[0]); | |
scaleTo(scale * 2); | |
translateTo(p, l); | |
d3_eventPreventDefault(); | |
dispatch(event_); | |
} | |
touchtime = now; | |
} else if (touches.length > 1) { | |
var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; | |
distance0 = dx * dx + dy * dy; | |
} | |
function moved() { | |
var touches = d3.touches(target), p0 = touches[0], l0 = locations[p0.identifier]; | |
if (p1 = touches[1]) { | |
var p1, l1 = locations[p1.identifier], scale1 = d3.event.scale; | |
if (scale1 == null) { | |
var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1; | |
scale1 = distance0 && Math.sqrt(distance1 / distance0); | |
} | |
p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; | |
l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; | |
scaleTo(scale1 * scale0); | |
} | |
touchtime = null; | |
translateTo(p0, l0); | |
dispatch(event_); | |
} | |
function ended() { | |
w.on(touchmove, null).on(touchend, null); | |
t.on(mousedown, mousedowned); | |
dragRestore(); | |
} | |
} | |
function mousewheeled() { | |
d3_eventPreventDefault(); | |
if (!translate0) translate0 = location(d3.mouse(this)); | |
scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); | |
translateTo(d3.mouse(this), translate0); | |
dispatch(event.of(this, arguments)); | |
} | |
function mousewheelreset() { | |
translate0 = null; | |
} | |
function dblclicked() { | |
var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; | |
scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); | |
translateTo(p, l); | |
dispatch(event.of(this, arguments)); | |
} | |
return d3.rebind(zoom, event, "on"); | |
}; | |
var d3_behavior_zoomInfinity = [ 0, Infinity ]; | |
var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { | |
return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); | |
}, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { | |
return d3.event.wheelDelta; | |
}, "mousewheel") : (d3_behavior_zoomDelta = function() { | |
return -d3.event.detail; | |
}, "MozMousePixelScroll"); | |
function d3_Color() {} | |
d3_Color.prototype.toString = function() { | |
return this.rgb() + ""; | |
}; | |
d3.hsl = function(h, s, l) { | |
return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); | |
}; | |
function d3_hsl(h, s, l) { | |
return new d3_Hsl(h, s, l); | |
} | |
function d3_Hsl(h, s, l) { | |
this.h = h; | |
this.s = s; | |
this.l = l; | |
} | |
var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); | |
d3_hslPrototype.brighter = function(k) { | |
k = Math.pow(.7, arguments.length ? k : 1); | |
return d3_hsl(this.h, this.s, this.l / k); | |
}; | |
d3_hslPrototype.darker = function(k) { | |
k = Math.pow(.7, arguments.length ? k : 1); | |
return d3_hsl(this.h, this.s, k * this.l); | |
}; | |
d3_hslPrototype.rgb = function() { | |
return d3_hsl_rgb(this.h, this.s, this.l); | |
}; | |
function d3_hsl_rgb(h, s, l) { | |
var m1, m2; | |
h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; | |
s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; | |
l = l < 0 ? 0 : l > 1 ? 1 : l; | |
m2 = l <= .5 ? l * (1 + s) : l + s - l * s; | |
m1 = 2 * l - m2; | |
function v(h) { | |
if (h > 360) h -= 360; else if (h < 0) h += 360; | |
if (h < 60) return m1 + (m2 - m1) * h / 60; | |
if (h < 180) return m2; | |
if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; | |
return m1; | |
} | |
function vv(h) { | |
return Math.round(v(h) * 255); | |
} | |
return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); | |
} | |
var π = Math.PI, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π; | |
function d3_sgn(x) { | |
return x > 0 ? 1 : x < 0 ? -1 : 0; | |
} | |
function d3_acos(x) { | |
return x > 1 ? 0 : x < -1 ? π : Math.acos(x); | |
} | |
function d3_asin(x) { | |
return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x); | |
} | |
function d3_sinh(x) { | |
return (Math.exp(x) - Math.exp(-x)) / 2; | |
} | |
function d3_cosh(x) { | |
return (Math.exp(x) + Math.exp(-x)) / 2; | |
} | |
function d3_haversin(x) { | |
return (x = Math.sin(x / 2)) * x; | |
} | |
d3.hcl = function(h, c, l) { | |
return arguments.length === 1 ? h instanceof d3_Hcl ? 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) : d3_hcl(+h, +c, +l); | |
}; | |
function d3_hcl(h, c, l) { | |
return new d3_Hcl(h, c, l); | |
} | |
function d3_Hcl(h, c, l) { | |
this.h = h; | |
this.c = c; | |
this.l = l; | |
} | |
var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); | |
d3_hclPrototype.brighter = function(k) { | |
return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); | |
}; | |
d3_hclPrototype.darker = function(k) { | |
return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); | |
}; | |
d3_hclPrototype.rgb = function() { | |
return d3_hcl_lab(this.h, this.c, this.l).rgb(); | |
}; | |
function d3_hcl_lab(h, c, l) { | |
if (isNaN(h)) h = 0; | |
if (isNaN(c)) c = 0; | |
return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); | |
} | |
d3.lab = function(l, a, b) { | |
return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); | |
}; | |
function d3_lab(l, a, b) { | |
return new d3_Lab(l, a, b); | |
} | |
function d3_Lab(l, a, b) { | |
this.l = l; | |
this.a = a; | |
this.b = b; | |
} | |
var d3_lab_K = 18; | |
var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; | |
var d3_labPrototype = d3_Lab.prototype = new d3_Color(); | |
d3_labPrototype.brighter = function(k) { | |
return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); | |
}; | |
d3_labPrototype.darker = function(k) { | |
return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); | |
}; | |
d3_labPrototype.rgb = function() { | |
return d3_lab_rgb(this.l, this.a, this.b); | |
}; | |
function d3_lab_rgb(l, a, b) { | |
var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; | |
x = d3_lab_xyz(x) * d3_lab_X; | |
y = d3_lab_xyz(y) * d3_lab_Y; | |
z = d3_lab_xyz(z) * d3_lab_Z; | |
return 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)); | |
} | |
function d3_lab_hcl(l, a, b) { | |
return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l); | |
} | |
function d3_lab_xyz(x) { | |
return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; | |
} | |
function d3_xyz_lab(x) { | |
return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; | |
} | |
function d3_xyz_rgb(r) { | |
return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); | |
} | |
d3.rgb = function(r, g, b) { | |
return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); | |
}; | |
function d3_rgbNumber(value) { | |
return d3_rgb(value >> 16, value >> 8 & 255, value & 255); | |
} | |
function d3_rgbString(value) { | |
return d3_rgbNumber(value) + ""; | |
} | |
function d3_rgb(r, g, b) { | |
return new d3_Rgb(r, g, b); | |
} | |
function d3_Rgb(r, g, b) { | |
this.r = r; | |
this.g = g; | |
this.b = b; | |
} | |
var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); | |
d3_rgbPrototype.brighter = function(k) { | |
k = Math.pow(.7, arguments.length ? k : 1); | |
var r = this.r, g = this.g, b = this.b, i = 30; | |
if (!r && !g && !b) return d3_rgb(i, i, i); | |
if (r && r < i) r = i; | |
if (g && g < i) g = i; | |
if (b && b < i) b = i; | |
return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k))); | |
}; | |
d3_rgbPrototype.darker = function(k) { | |
k = Math.pow(.7, arguments.length ? k : 1); | |
return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b)); | |
}; | |
d3_rgbPrototype.hsl = function() { | |
return d3_rgb_hsl(this.r, this.g, this.b); | |
}; | |
d3_rgbPrototype.toString = function() { | |
return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); | |
}; | |
function d3_rgb_hex(v) { | |
return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); | |
} | |
function d3_rgb_parse(format, rgb, hsl) { | |
var r = 0, g = 0, b = 0, m1, m2, name; | |
m1 = /([a-z]+)\((.*)\)/i.exec(format); | |
if (m1) { | |
m2 = m1[2].split(","); | |
switch (m1[1]) { | |
case "hsl": | |
{ | |
return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); | |
} | |
case "rgb": | |
{ | |
return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); | |
} | |
} | |
} | |
if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); | |
if (format != null && format.charAt(0) === "#") { | |
if (format.length === 4) { | |
r = format.charAt(1); | |
r += r; | |
g = format.charAt(2); | |
g += g; | |
b = format.charAt(3); | |
b += b; | |
} else if (format.length === 7) { | |
r = format.substring(1, 3); | |
g = format.substring(3, 5); | |
b = format.substring(5, 7); | |
} | |
r = parseInt(r, 16); | |
g = parseInt(g, 16); | |
b = parseInt(b, 16); | |
} | |
return rgb(r, g, b); | |
} | |
function d3_rgb_hsl(r, g, b) { | |
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; | |
if (d) { | |
s = l < .5 ? d / (max + min) : d / (2 - max - min); | |
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; | |
h *= 60; | |
} else { | |
h = NaN; | |
s = l > 0 && l < 1 ? 0 : h; | |
} | |
return d3_hsl(h, s, l); | |
} | |
function d3_rgb_lab(r, g, b) { | |
r = d3_rgb_xyz(r); | |
g = d3_rgb_xyz(g); | |
b = d3_rgb_xyz(b); | |
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); | |
return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); | |
} | |
function d3_rgb_xyz(r) { | |
return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); | |
} | |
function d3_rgb_parseNumber(c) { | |
var f = parseFloat(c); | |
return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; | |
} | |
var d3_rgb_names = d3.map({ | |
aliceblue: 15792383, | |
antiquewhite: 16444375, | |
aqua: 65535, | |
aquamarine: 8388564, | |
azure: 15794175, | |
beige: 16119260, | |
bisque: 16770244, | |
black: 0, | |
blanchedalmond: 16772045, | |
blue: 255, | |
blueviolet: 9055202, | |
brown: 10824234, | |
burlywood: 14596231, | |
cadetblue: 6266528, | |
chartreuse: 8388352, | |
chocolate: 13789470, | |
coral: 16744272, | |
cornflowerblue: 6591981, | |
cornsilk: 16775388, | |
crimson: 14423100, | |
cyan: 65535, | |
darkblue: 139, | |
darkcyan: 35723, | |
darkgoldenrod: 12092939, | |
darkgray: 11119017, | |
darkgreen: 25600, | |
darkgrey: 11119017, | |
darkkhaki: 12433259, | |
darkmagenta: 9109643, | |
darkolivegreen: 5597999, | |
darkorange: 16747520, | |
darkorchid: 10040012, | |
darkred: 9109504, | |
darksalmon: 15308410, | |
darkseagreen: 9419919, | |
darkslateblue: 4734347, | |
darkslategray: 3100495, | |
darkslategrey: 3100495, | |
darkturquoise: 52945, | |
darkviolet: 9699539, | |
deeppink: 16716947, | |
deepskyblue: 49151, | |
dimgray: 6908265, | |
dimgrey: 6908265, | |
dodgerblue: 2003199, | |
firebrick: 11674146, | |
floralwhite: 16775920, | |
forestgreen: 2263842, | |
fuchsia: 16711935, | |
gainsboro: 14474460, | |
ghostwhite: 16316671, | |
gold: 16766720, | |
goldenrod: 14329120, | |
gray: 8421504, | |
green: 32768, | |
greenyellow: 11403055, | |
grey: 8421504, | |
honeydew: 15794160, | |
hotpink: 16738740, | |
indianred: 13458524, | |
indigo: 4915330, | |
ivory: 16777200, | |
khaki: 15787660, | |
lavender: 15132410, | |
lavenderblush: 16773365, | |
lawngreen: 8190976, | |
lemonchiffon: 16775885, | |
lightblue: 11393254, | |
lightcoral: 15761536, | |
lightcyan: 14745599, | |
lightgoldenrodyellow: 16448210, | |
lightgray: 13882323, | |
lightgreen: 9498256, | |
lightgrey: 13882323, | |
lightpink: 16758465, | |
lightsalmon: 16752762, | |
lightseagreen: 2142890, | |
lightskyblue: 8900346, | |
lightslategray: 7833753, | |
lightslategrey: 7833753, | |
lightsteelblue: 11584734, | |
lightyellow: 16777184, | |
lime: 65280, | |
limegreen: 3329330, | |
linen: 16445670, | |
magenta: 16711935, | |
maroon: 8388608, | |
mediumaquamarine: 6737322, | |
mediumblue: 205, | |
mediumorchid: 12211667, | |
mediumpurple: 9662683, | |
mediumseagreen: 3978097, | |
mediumslateblue: 8087790, | |
mediumspringgreen: 64154, | |
mediumturquoise: 4772300, | |
mediumvioletred: 13047173, | |
midnightblue: 1644912, | |
mintcream: 16121850, | |
mistyrose: 16770273, | |
moccasin: 16770229, | |
navajowhite: 16768685, | |
navy: 128, | |
oldlace: 16643558, | |
olive: 8421376, | |
olivedrab: 7048739, | |
orange: 16753920, | |
orangered: 16729344, | |
orchid: 14315734, | |
palegoldenrod: 15657130, | |
palegreen: 10025880, | |
paleturquoise: 11529966, | |
palevioletred: 14381203, | |
papayawhip: 16773077, | |
peachpuff: 16767673, | |
peru: 13468991, | |
pink: 16761035, | |
plum: 14524637, | |
powderblue: 11591910, | |
purple: 8388736, | |
red: 16711680, | |
rosybrown: 12357519, | |
royalblue: 4286945, | |
saddlebrown: 9127187, | |
salmon: 16416882, | |
sandybrown: 16032864, | |
seagreen: 3050327, | |
seashell: 16774638, | |
sienna: 10506797, | |
silver: 12632256, | |
skyblue: 8900331, | |
slateblue: 6970061, | |
slategray: 7372944, | |
slategrey: 7372944, | |
snow: 16775930, | |
springgreen: 65407, | |
steelblue: 4620980, | |
tan: 13808780, | |
teal: 32896, | |
thistle: 14204888, | |
tomato: 16737095, | |
turquoise: 4251856, | |
violet: 15631086, | |
wheat: 16113331, | |
white: 16777215, | |
whitesmoke: 16119285, | |
yellow: 16776960, | |
yellowgreen: 10145074 | |
}); | |
d3_rgb_names.forEach(function(key, value) { | |
d3_rgb_names.set(key, d3_rgbNumber(value)); | |
}); | |
function d3_functor(v) { | |
return typeof v === "function" ? v : function() { | |
return v; | |
}; | |
} | |
d3.functor = d3_functor; | |
function d3_identity(d) { | |
return d; | |
} | |
d3.xhr = d3_xhrType(d3_identity); | |
function d3_xhrType(response) { | |
return function(url, mimeType, callback) { | |
if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, | |
mimeType = null; | |
return d3_xhr(url, mimeType, response, callback); | |
}; | |
} | |
function d3_xhr(url, mimeType, response, callback) { | |
var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; | |
if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); | |
"onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { | |
request.readyState > 3 && respond(); | |
}; | |
function respond() { | |
var status = request.status, result; | |
if (!status && request.responseText || status >= 200 && status < 300 || status === 304) { | |
try { | |
result = response.call(xhr, request); | |
} catch (e) { | |
dispatch.error.call(xhr, e); | |
return; | |
} | |
dispatch.load.call(xhr, result); | |
} else { | |
dispatch.error.call(xhr, request); | |
} | |
} | |
request.onprogress = function(event) { | |
var o = d3.event; | |
d3.event = event; | |
try { | |
dispatch.progress.call(xhr, request); | |
} finally { | |
d3.event = o; | |
} | |
}; | |
xhr.header = function(name, value) { | |
name = (name + "").toLowerCase(); | |
if (arguments.length < 2) return headers[name]; | |
if (value == null) delete headers[name]; else headers[name] = value + ""; | |
return xhr; | |
}; | |
xhr.mimeType = function(value) { | |
if (!arguments.length) return mimeType; | |
mimeType = value == null ? null : value + ""; | |
return xhr; | |
}; | |
xhr.responseType = function(value) { | |
if (!arguments.length) return responseType; | |
responseType = value; | |
return xhr; | |
}; | |
xhr.response = function(value) { | |
response = value; | |
return xhr; | |
}; | |
[ "get", "post" ].forEach(function(method) { | |
xhr[method] = function() { | |
return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); | |
}; | |
}); | |
xhr.send = function(method, data, callback) { | |
if (arguments.length === 2 && typeof data === "function") callback = data, data = null; | |
request.open(method, url, true); | |
if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; | |
if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); | |
if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); | |
if (responseType != null) request.responseType = responseType; | |
if (callback != null) xhr.on("error", callback).on("load", function(request) { | |
callback(null, request); | |
}); | |
request.send(data == null ? null : data); | |
return xhr; | |
}; | |
xhr.abort = function() { | |
request.abort(); | |
return xhr; | |
}; | |
d3.rebind(xhr, dispatch, "on"); | |
return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); | |
} | |
function d3_xhr_fixCallback(callback) { | |
return callback.length === 1 ? function(error, request) { | |
callback(error == null ? request : null); | |
} : callback; | |
} | |
d3.dsv = function(delimiter, mimeType) { | |
var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); | |
function dsv(url, row, callback) { | |
if (arguments.length < 3) callback = row, row = null; | |
var xhr = d3.xhr(url, mimeType, callback); | |
xhr.row = function(_) { | |
return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; | |
}; | |
return xhr.row(row); | |
} | |
function response(request) { | |
return dsv.parse(request.responseText); | |
} | |
function typedResponse(f) { | |
return function(request) { | |
return dsv.parse(request.responseText, f); | |
}; | |
} | |
dsv.parse = function(text, f) { | |
var o; | |
return dsv.parseRows(text, function(row, i) { | |
if (o) return o(row, i - 1); | |
var a = new Function("d", "return {" + row.map(function(name, i) { | |
return JSON.stringify(name) + ": d[" + i + "]"; | |
}).join(",") + "}"); | |
o = f ? function(row, i) { | |
return f(a(row), i); | |
} : a; | |
}); | |
}; | |
dsv.parseRows = function(text, f) { | |
var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; | |
function token() { | |
if (I >= N) return EOF; | |
if (eol) return eol = false, EOL; | |
var j = I; | |
if (text.charCodeAt(j) === 34) { | |
var i = j; | |
while (i++ < N) { | |
if (text.charCodeAt(i) === 34) { | |
if (text.charCodeAt(i + 1) !== 34) break; | |
++i; | |
} | |
} | |
I = i + 2; | |
var c = text.charCodeAt(i + 1); | |
if (c === 13) { | |
eol = true; | |
if (text.charCodeAt(i + 2) === 10) ++I; | |
} else if (c === 10) { | |
eol = true; | |
} | |
return text.substring(j + 1, i).replace(/""/g, '"'); | |
} | |
while (I < N) { | |
var c = text.charCodeAt(I++), k = 1; | |
if (c === 10) eol = true; else if (c === 13) { | |
eol = true; | |
if (text.charCodeAt(I) === 10) ++I, ++k; | |
} else if (c !== delimiterCode) continue; | |
return text.substring(j, I - k); | |
} | |
return text.substring(j); | |
} | |
while ((t = token()) !== EOF) { | |
var a = []; | |
while (t !== EOL && t !== EOF) { | |
a.push(t); | |
t = token(); | |
} | |
if (f && !(a = f(a, n++))) continue; | |
rows.push(a); | |
} | |
return rows; | |
}; | |
dsv.format = function(rows) { | |
if (Array.isArray(rows[0])) return dsv.formatRows(rows); | |
var fieldSet = new d3_Set(), fields = []; | |
rows.forEach(function(row) { | |
for (var field in row) { | |
if (!fieldSet.has(field)) { | |
fields.push(fieldSet.add(field)); | |
} | |
} | |
}); | |
return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { | |
return fields.map(function(field) { | |
return formatValue(row[field]); | |
}).join(delimiter); | |
})).join("\n"); | |
}; | |
dsv.formatRows = function(rows) { | |
return rows.map(formatRow).join("\n"); | |
}; | |
function formatRow(row) { | |
return row.map(formatValue).join(delimiter); | |
} | |
function formatValue(text) { | |
return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; | |
} | |
return dsv; | |
}; | |
d3.csv = d3.dsv(",", "text/csv"); | |
d3.tsv = d3.dsv(" ", "text/tab-separated-values"); | |
var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { | |
setTimeout(callback, 17); | |
}; | |
d3.timer = function(callback, delay, then) { | |
var n = arguments.length; | |
if (n < 2) delay = 0; | |
if (n < 3) then = Date.now(); | |
var time = then + delay, timer = { | |
callback: callback, | |
time: time, | |
next: null | |
}; | |
if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead = timer; | |
d3_timer_queueTail = timer; | |
if (!d3_timer_interval) { | |
d3_timer_timeout = clearTimeout(d3_timer_timeout); | |
d3_timer_interval = 1; | |
d3_timer_frame(d3_timer_step); | |
} | |
}; | |
function d3_timer_step() { | |
var now = d3_timer_mark(), delay = d3_timer_sweep() - now; | |
if (delay > 24) { | |
if (isFinite(delay)) { | |
clearTimeout(d3_timer_timeout); | |
d3_timer_timeout = setTimeout(d3_timer_step, delay); | |
} | |
d3_timer_interval = 0; | |
} else { | |
d3_timer_interval = 1; | |
d3_timer_frame(d3_timer_step); | |
} | |
} | |
d3.timer.flush = function() { | |
d3_timer_mark(); | |
d3_timer_sweep(); | |
}; | |
function d3_timer_replace(callback, delay, then) { | |
var n = arguments.length; | |
if (n < 2) delay = 0; | |
if (n < 3) then = Date.now(); | |
d3_timer_active.callback = callback; | |
d3_timer_active.time = then + delay; | |
} | |
function d3_timer_mark() { | |
var now = Date.now(); | |
d3_timer_active = d3_timer_queueHead; | |
while (d3_timer_active) { | |
if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time); | |
d3_timer_active = d3_timer_active.next; | |
} | |
return now; | |
} | |
function d3_timer_sweep() { | |
var t0, t1 = d3_timer_queueHead, time = Infinity; | |
while (t1) { | |
if (t1.flush) { | |
t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next; | |
} else { | |
if (t1.time < time) time = t1.time; | |
t1 = (t0 = t1).next; | |
} | |
} | |
d3_timer_queueTail = t0; | |
return time; | |
} | |
var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$"; | |
var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); | |
d3.formatPrefix = function(value, precision) { | |
var i = 0; | |
if (value) { | |
if (value < 0) value *= -1; | |
if (precision) value = d3.round(value, d3_format_precision(value, precision)); | |
i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); | |
i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); | |
} | |
return d3_formatPrefixes[8 + i / 3]; | |
}; | |
function d3_formatPrefix(d, i) { | |
var k = Math.pow(10, Math.abs(8 - i) * 3); | |
return { | |
scale: i > 8 ? function(d) { | |
return d / k; | |
} : function(d) { | |
return d * k; | |
}, | |
symbol: d | |
}; | |
} | |
d3.round = function(x, n) { | |
return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); | |
}; | |
d3.format = function(specifier) { | |
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, suffix = "", integer = false; | |
if (precision) precision = +precision.substring(1); | |
if (zfill || fill === "0" && align === "=") { | |
zfill = fill = "0"; | |
align = "="; | |
if (comma) width -= Math.floor((width - 1) / 4); | |
} | |
switch (type) { | |
case "n": | |
comma = true; | |
type = "g"; | |
break; | |
case "%": | |
scale = 100; | |
suffix = "%"; | |
type = "f"; | |
break; | |
case "p": | |
scale = 100; | |
suffix = "%"; | |
type = "r"; | |
break; | |
case "b": | |
case "o": | |
case "x": | |
case "X": | |
if (symbol === "#") symbol = "0" + type.toLowerCase(); | |
case "c": | |
case "d": | |
integer = true; | |
precision = 0; | |
break; | |
case "s": | |
scale = -1; | |
type = "r"; | |
break; | |
} | |
if (symbol === "#") symbol = ""; else if (symbol === "$") symbol = d3_format_currencySymbol; | |
if (type == "r" && !precision) type = "g"; | |
if (precision != null) { | |
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)); | |
} | |
type = d3_format_types.get(type) || d3_format_typeDefault; | |
var zcomma = zfill && comma; | |
return function(value) { | |
if (integer && value % 1) return ""; | |
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; | |
if (scale < 0) { | |
var prefix = d3.formatPrefix(value, precision); | |
value = prefix.scale(value); | |
suffix = prefix.symbol; | |
} else { | |
value *= scale; | |
} | |
value = type(value, precision); | |
var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint + value.substring(i + 1); | |
if (!zfill && comma) before = d3_format_group(before); | |
var length = symbol.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; | |
if (zcomma) before = d3_format_group(padding + before); | |
negative += symbol; | |
value = before + after; | |
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)) + suffix; | |
}; | |
}; | |
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; | |
var d3_format_types = d3.map({ | |
b: function(x) { | |
return x.toString(2); | |
}, | |
c: function(x) { | |
return String.fromCharCode(x); | |
}, | |
o: function(x) { | |
return x.toString(8); | |
}, | |
x: function(x) { | |
return x.toString(16); | |
}, | |
X: function(x) { | |
return x.toString(16).toUpperCase(); | |
}, | |
g: function(x, p) { | |
return x.toPrecision(p); | |
}, | |
e: function(x, p) { | |
return x.toExponential(p); | |
}, | |
f: function(x, p) { | |
return x.toFixed(p); | |
}, | |
r: function(x, p) { | |
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)))); | |
} | |
}); | |
function d3_format_precision(x, p) { | |
return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); | |
} | |
function d3_format_typeDefault(x) { | |
return x + ""; | |
} | |
var d3_format_group = d3_identity; | |
if (d3_format_grouping) { | |
var d3_format_groupingLength = d3_format_grouping.length; | |
d3_format_group = function(value) { | |
var i = value.length, t = [], j = 0, g = d3_format_grouping[0]; | |
while (i > 0 && g > 0) { | |
t.push(value.substring(i -= g, i + g)); | |
g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; | |
} | |
return t.reverse().join(d3_format_thousandsSeparator); | |
}; | |
} | |
d3.geo = {}; | |
function d3_adder() {} | |
d3_adder.prototype = { | |
s: 0, | |
t: 0, | |
add: function(y) { | |
d3_adderSum(y, this.t, d3_adderTemp); | |
d3_adderSum(d3_adderTemp.s, this.s, this); | |
if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; | |
}, | |
reset: function() { | |
this.s = this.t = 0; | |
}, | |
valueOf: function() { | |
return this.s; | |
} | |
}; | |
var d3_adderTemp = new d3_adder(); | |
function d3_adderSum(a, b, o) { | |
var x = o.s = a + b, bv = x - a, av = x - bv; | |
o.t = a - av + (b - bv); | |
} | |
d3.geo.stream = function(object, listener) { | |
if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { | |
d3_geo_streamObjectType[object.type](object, listener); | |
} else { | |
d3_geo_streamGeometry(object, listener); | |
} | |
}; | |
function d3_geo_streamGeometry(geometry, listener) { | |
if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { | |
d3_geo_streamGeometryType[geometry.type](geometry, listener); | |
} | |
} | |
var d3_geo_streamObjectType = { | |
Feature: function(feature, listener) { | |
d3_geo_streamGeometry(feature.geometry, listener); | |
}, | |
FeatureCollection: function(object, listener) { | |
var features = object.features, i = -1, n = features.length; | |
while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); | |
} | |
}; | |
var d3_geo_streamGeometryType = { | |
Sphere: function(object, listener) { | |
listener.sphere(); | |
}, | |
Point: function(object, listener) { | |
var coordinate = object.coordinates; | |
listener.point(coordinate[0], coordinate[1]); | |
}, | |
MultiPoint: function(object, listener) { | |
var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; | |
while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); | |
}, | |
LineString: function(object, listener) { | |
d3_geo_streamLine(object.coordinates, listener, 0); | |
}, | |
MultiLineString: function(object, listener) { | |
var coordinates = object.coordinates, i = -1, n = coordinates.length; | |
while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); | |
}, | |
Polygon: function(object, listener) { | |
d3_geo_streamPolygon(object.coordinates, listener); | |
}, | |
MultiPolygon: function(object, listener) { | |
var coordinates = object.coordinates, i = -1, n = coordinates.length; | |
while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); | |
}, | |
GeometryCollection: function(object, listener) { | |
var geometries = object.geometries, i = -1, n = geometries.length; | |
while (++i < n) d3_geo_streamGeometry(geometries[i], listener); | |
} | |
}; | |
function d3_geo_streamLine(coordinates, listener, closed) { | |
var i = -1, n = coordinates.length - closed, coordinate; | |
listener.lineStart(); | |
while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); | |
listener.lineEnd(); | |
} | |
function d3_geo_streamPolygon(coordinates, listener) { | |
var i = -1, n = coordinates.length; | |
listener.polygonStart(); | |
while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); | |
listener.polygonEnd(); | |
} | |
d3.geo.area = function(object) { | |
d3_geo_areaSum = 0; | |
d3.geo.stream(object, d3_geo_area); | |
return d3_geo_areaSum; | |
}; | |
var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); | |
var d3_geo_area = { | |
sphere: function() { | |
d3_geo_areaSum += 4 * π; | |
}, | |
point: d3_noop, | |
lineStart: d3_noop, | |
lineEnd: d3_noop, | |
polygonStart: function() { | |
d3_geo_areaRingSum.reset(); | |
d3_geo_area.lineStart = d3_geo_areaRingStart; | |
}, | |
polygonEnd: function() { | |
var area = 2 * d3_geo_areaRingSum; | |
d3_geo_areaSum += area < 0 ? 4 * π + area : area; | |
d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; | |
} | |
}; | |
function d3_geo_areaRingStart() { | |
var λ00, φ00, λ0, cosφ0, sinφ0; | |
d3_geo_area.point = function(λ, φ) { | |
d3_geo_area.point = nextPoint; | |
λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), | |
sinφ0 = Math.sin(φ); | |
}; | |
function nextPoint(λ, φ) { | |
λ *= d3_radians; | |
φ = φ * d3_radians / 2 + π / 4; | |
var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); | |
d3_geo_areaRingSum.add(Math.atan2(v, u)); | |
λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; | |
} | |
d3_geo_area.lineEnd = function() { | |
nextPoint(λ00, φ00); | |
}; | |
} | |
function d3_geo_cartesian(spherical) { | |
var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); | |
return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; | |
} | |
function d3_geo_cartesianDot(a, b) { | |
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; | |
} | |
function d3_geo_cartesianCross(a, b) { | |
return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; | |
} | |
function d3_geo_cartesianAdd(a, b) { | |
a[0] += b[0]; | |
a[1] += b[1]; | |
a[2] += b[2]; | |
} | |
function d3_geo_cartesianScale(vector, k) { | |
return [ vector[0] * k, vector[1] * k, vector[2] * k ]; | |
} | |
function d3_geo_cartesianNormalize(d) { | |
var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); | |
d[0] /= l; | |
d[1] /= l; | |
d[2] /= l; | |
} | |
function d3_geo_spherical(cartesian) { | |
return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; | |
} | |
function d3_geo_sphericalEqual(a, b) { | |
return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; | |
} | |
d3.geo.bounds = function() { | |
var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; | |
var bound = { | |
point: point, | |
lineStart: lineStart, | |
lineEnd: lineEnd, | |
polygonStart: function() { | |
bound.point = ringPoint; | |
bound.lineStart = ringStart; | |
bound.lineEnd = ringEnd; | |
dλSum = 0; | |
d3_geo_area.polygonStart(); | |
}, | |
polygonEnd: function() { | |
d3_geo_area.polygonEnd(); | |
bound.point = point; | |
bound.lineStart = lineStart; | |
bound.lineEnd = lineEnd; | |
if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; | |
range[0] = λ0, range[1] = λ1; | |
} | |
}; | |
function point(λ, φ) { | |
ranges.push(range = [ λ0 = λ, λ1 = λ ]); | |
if (φ < φ0) φ0 = φ; | |
if (φ > φ1) φ1 = φ; | |
} | |
function linePoint(λ, φ) { | |
var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); | |
if (p0) { | |
var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); | |
d3_geo_cartesianNormalize(inflection); | |
inflection = d3_geo_spherical(inflection); | |
var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = Math.abs(dλ) > 180; | |
if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { | |
var φi = inflection[1] * d3_degrees; | |
if (φi > φ1) φ1 = φi; | |
} else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { | |
var φi = -inflection[1] * d3_degrees; | |
if (φi < φ0) φ0 = φi; | |
} else { | |
if (φ < φ0) φ0 = φ; | |
if (φ > φ1) φ1 = φ; | |
} | |
if (antimeridian) { | |
if (λ < λ_) { | |
if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; | |
} else { | |
if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; | |
} | |
} else { | |
if (λ1 >= λ0) { | |
if (λ < λ0) λ0 = λ; | |
if (λ > λ1) λ1 = λ; | |
} else { | |
if (λ > λ_) { | |
if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; | |
} else { | |
if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; | |
} | |
} | |
} | |
} else { | |
point(λ, φ); | |
} | |
p0 = p, λ_ = λ; | |
} | |
function lineStart() { | |
bound.point = linePoint; | |
} | |
function lineEnd() { | |
range[0] = λ0, range[1] = λ1; | |
bound.point = point; | |
p0 = null; | |
} | |
function ringPoint(λ, φ) { | |
if (p0) { | |
var dλ = λ - λ_; | |
dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; | |
} else λ__ = λ, φ__ = φ; | |
d3_geo_area.point(λ, φ); | |
linePoint(λ, φ); | |
} | |
function ringStart() { | |
d3_geo_area.lineStart(); | |
} | |
function ringEnd() { | |
ringPoint(λ__, φ__); | |
d3_geo_area.lineEnd(); | |
if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180); | |
range[0] = λ0, range[1] = λ1; | |
p0 = null; | |
} | |
function angle(λ0, λ1) { | |
return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; | |
} | |
function compareRanges(a, b) { | |
return a[0] - b[0]; | |
} | |
function withinRange(x, range) { | |
return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; | |
} | |
return function(feature) { | |
φ1 = λ1 = -(λ0 = φ0 = Infinity); | |
ranges = []; | |
d3.geo.stream(feature, bound); | |
var n = ranges.length; | |
if (n) { | |
ranges.sort(compareRanges); | |
for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { | |
b = ranges[i]; | |
if (withinRange(b[0], a) || withinRange(b[1], a)) { | |
if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; | |
if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; | |
} else { | |
merged.push(a = b); | |
} | |
} | |
var best = -Infinity, dλ; | |
for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { | |
b = merged[i]; | |
if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; | |
} | |
} | |
ranges = range = null; | |
return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; | |
}; | |
}(); | |
d3.geo.centroid = function(object) { | |
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; | |
d3.geo.stream(object, d3_geo_centroid); | |
var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; | |
if (m < ε2) { | |
x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; | |
if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; | |
m = x * x + y * y + z * z; | |
if (m < ε2) return [ NaN, NaN ]; | |
} | |
return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; | |
}; | |
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; | |
var d3_geo_centroid = { | |
sphere: d3_noop, | |
point: d3_geo_centroidPoint, | |
lineStart: d3_geo_centroidLineStart, | |
lineEnd: d3_geo_centroidLineEnd, | |
polygonStart: function() { | |
d3_geo_centroid.lineStart = d3_geo_centroidRingStart; | |
}, | |
polygonEnd: function() { | |
d3_geo_centroid.lineStart = d3_geo_centroidLineStart; | |
} | |
}; | |
function d3_geo_centroidPoint(λ, φ) { | |
λ *= d3_radians; | |
var cosφ = Math.cos(φ *= d3_radians); | |
d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); | |
} | |
function d3_geo_centroidPointXYZ(x, y, z) { | |
++d3_geo_centroidW0; | |
d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; | |
d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; | |
d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; | |
} | |
function d3_geo_centroidLineStart() { | |
var x0, y0, z0; | |
d3_geo_centroid.point = function(λ, φ) { | |
λ *= d3_radians; | |
var cosφ = Math.cos(φ *= d3_radians); | |
x0 = cosφ * Math.cos(λ); | |
y0 = cosφ * Math.sin(λ); | |
z0 = Math.sin(φ); | |
d3_geo_centroid.point = nextPoint; | |
d3_geo_centroidPointXYZ(x0, y0, z0); | |
}; | |
function nextPoint(λ, φ) { | |
λ *= d3_radians; | |
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); | |
d3_geo_centroidW1 += w; | |
d3_geo_centroidX1 += w * (x0 + (x0 = x)); | |
d3_geo_centroidY1 += w * (y0 + (y0 = y)); | |
d3_geo_centroidZ1 += w * (z0 + (z0 = z)); | |
d3_geo_centroidPointXYZ(x0, y0, z0); | |
} | |
} | |
function d3_geo_centroidLineEnd() { | |
d3_geo_centroid.point = d3_geo_centroidPoint; | |
} | |
function d3_geo_centroidRingStart() { | |
var λ00, φ00, x0, y0, z0; | |
d3_geo_centroid.point = function(λ, φ) { | |
λ00 = λ, φ00 = φ; | |
d3_geo_centroid.point = nextPoint; | |
λ *= d3_radians; | |
var cosφ = Math.cos(φ *= d3_radians); | |
x0 = cosφ * Math.cos(λ); | |
y0 = cosφ * Math.sin(λ); | |
z0 = Math.sin(φ); | |
d3_geo_centroidPointXYZ(x0, y0, z0); | |
}; | |
d3_geo_centroid.lineEnd = function() { | |
nextPoint(λ00, φ00); | |
d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; | |
d3_geo_centroid.point = d3_geo_centroidPoint; | |
}; | |
function nextPoint(λ, φ) { | |
λ *= d3_radians; | |
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); | |
d3_geo_centroidX2 += v * cx; | |
d3_geo_centroidY2 += v * cy; | |
d3_geo_centroidZ2 += v * cz; | |
d3_geo_centroidW1 += w; | |
d3_geo_centroidX1 += w * (x0 + (x0 = x)); | |
d3_geo_centroidY1 += w * (y0 + (y0 = y)); | |
d3_geo_centroidZ1 += w * (z0 + (z0 = z)); | |
d3_geo_centroidPointXYZ(x0, y0, z0); | |
} | |
} | |
function d3_true() { | |
return true; | |
} | |
function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { | |
var subject = [], clip = []; | |
segments.forEach(function(segment) { | |
if ((n = segment.length - 1) <= 0) return; | |
var n, p0 = segment[0], p1 = segment[n]; | |
if (d3_geo_sphericalEqual(p0, p1)) { | |
listener.lineStart(); | |
for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); | |
listener.lineEnd(); | |
return; | |
} | |
var a = { | |
point: p0, | |
points: segment, | |
other: null, | |
visited: false, | |
entry: true, | |
subject: true | |
}, b = { | |
point: p0, | |
points: [ p0 ], | |
other: a, | |
visited: false, | |
entry: false, | |
subject: false | |
}; | |
a.other = b; | |
subject.push(a); | |
clip.push(b); | |
a = { | |
point: p1, | |
points: [ p1 ], | |
other: null, | |
visited: false, | |
entry: false, | |
subject: true | |
}; | |
b = { | |
point: p1, | |
points: [ p1 ], | |
other: a, | |
visited: false, | |
entry: true, | |
subject: false | |
}; | |
a.other = b; | |
subject.push(a); | |
clip.push(b); | |
}); | |
clip.sort(compare); | |
d3_geo_clipPolygonLinkCircular(subject); | |
d3_geo_clipPolygonLinkCircular(clip); | |
if (!subject.length) return; | |
if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) { | |
clip[i].entry = e = !e; | |
} | |
var start = subject[0], current, points, point; | |
while (1) { | |
current = start; | |
while (current.visited) if ((current = current.next) === start) return; | |
points = current.points; | |
listener.lineStart(); | |
do { | |
current.visited = current.other.visited = true; | |
if (current.entry) { | |
if (current.subject) { | |
for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); | |
} else { | |
interpolate(current.point, current.next.point, 1, listener); | |
} | |
current = current.next; | |
} else { | |
if (current.subject) { | |
points = current.prev.points; | |
for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); | |
} else { | |
interpolate(current.point, current.prev.point, -1, listener); | |
} | |
current = current.prev; | |
} | |
current = current.other; | |
points = current.points; | |
} while (!current.visited); | |
listener.lineEnd(); | |
} | |
} | |
function d3_geo_clipPolygonLinkCircular(array) { | |
if (!(n = array.length)) return; | |
var n, i = 0, a = array[0], b; | |
while (++i < n) { | |
a.next = b = array[i]; | |
b.prev = a; | |
a = b; | |
} | |
a.next = b = array[0]; | |
b.prev = a; | |
} | |
function d3_geo_clip(pointVisible, clipLine, interpolate, polygonContains) { | |
return function(listener) { | |
var line = clipLine(listener); | |
var clip = { | |
point: point, | |
lineStart: lineStart, | |
lineEnd: lineEnd, | |
polygonStart: function() { | |
clip.point = pointRing; | |
clip.lineStart = ringStart; | |
clip.lineEnd = ringEnd; | |
segments = []; | |
polygon = []; | |
listener.polygonStart(); | |
}, | |
polygonEnd: function() { | |
clip.point = point; | |
clip.lineStart = lineStart; | |
clip.lineEnd = lineEnd; | |
segments = d3.merge(segments); | |
if (segments.length) { | |
d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); | |
} else if (polygonContains(polygon)) { | |
listener.lineStart(); | |
interpolate(null, null, 1, listener); | |
listener.lineEnd(); | |
} | |
listener.polygonEnd(); | |
segments = polygon = null; | |
}, | |
sphere: function() { | |
listener.polygonStart(); | |
listener.lineStart(); | |
interpolate(null, null, 1, listener); | |
listener.lineEnd(); | |
listener.polygonEnd(); | |
} | |
}; | |
function point(λ, φ) { | |
if (pointVisible(λ, φ)) listener.point(λ, φ); | |
} | |
function pointLine(λ, φ) { | |
line.point(λ, φ); | |
} | |
function lineStart() { | |
clip.point = pointLine; | |
line.lineStart(); | |
} | |
function lineEnd() { | |
clip.point = point; | |
line.lineEnd(); | |
} | |
var segments; | |
var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; | |
function pointRing(λ, φ) { | |
ringListener.point(λ, φ); | |
ring.push([ λ, φ ]); | |
} | |
function ringStart() { | |
ringListener.lineStart(); | |
ring = []; | |
} | |
function ringEnd() { | |
pointRing(ring[0][0], ring[0][1]); | |
ringListener.lineEnd(); | |
var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; | |
ring.pop(); | |
polygon.push(ring); | |
ring = null; | |
if (!n) return; | |
if (clean & 1) { | |
segment = ringSegments[0]; | |
var n = segment.length - 1, i = -1, point; | |
listener.lineStart(); | |
while (++i < n) listener.point((point = segment[i])[0], point[1]); | |
listener.lineEnd(); | |
return; | |
} | |
if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); | |
segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); | |
} | |
return clip; | |
}; | |
} | |
function d3_geo_clipSegmentLength1(segment) { | |
return segment.length > 1; | |
} | |
function d3_geo_clipBufferListener() { | |
var lines = [], line; | |
return { | |
lineStart: function() { | |
lines.push(line = []); | |
}, | |
point: function(λ, φ) { | |
line.push([ λ, φ ]); | |
}, | |
lineEnd: d3_noop, | |
buffer: function() { | |
var buffer = lines; | |
lines = []; | |
line = null; | |
return buffer; | |
}, | |
rejoin: function() { | |
if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); | |
} | |
}; | |
} | |
function d3_geo_clipSort(a, b) { | |
return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); | |
} | |
function d3_geo_pointInPolygon(point, polygon) { | |
var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, polar = false, southPole = false, winding = 0; | |
d3_geo_areaRingSum.reset(); | |
for (var i = 0, n = polygon.length; i < n; ++i) { | |
var ring = polygon[i], m = ring.length; | |
if (!m) continue; | |
var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; | |
while (true) { | |
if (j === m) j = 0; | |
point = ring[j]; | |
var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, antimeridian = Math.abs(dλ) > π, k = sinφ0 * sinφ; | |
d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosφ0 * cosφ + k * Math.cos(dλ))); | |
if (Math.abs(φ) < ε) southPole = true; | |
polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * π : dλ; | |
if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { | |
var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); | |
d3_geo_cartesianNormalize(arc); | |
var intersection = d3_geo_cartesianCross(meridianNormal, arc); | |
d3_geo_cartesianNormalize(intersection); | |
var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); | |
if (parallel > φarc) { | |
winding += antimeridian ^ dλ >= 0 ? 1 : -1; | |
} | |
} | |
if (!j++) break; | |
λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; | |
} | |
if (Math.abs(polarAngle) > ε) polar = true; | |
} | |
return (!southPole && !polar && d3_geo_areaRingSum < 0 || polarAngle < -ε) ^ winding & 1; | |
} | |
var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianPolygonContains); | |
function d3_geo_clipAntimeridianLine(listener) { | |
var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; | |
return { | |
lineStart: function() { | |
listener.lineStart(); | |
clean = 1; | |
}, | |
point: function(λ1, φ1) { | |
var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); | |
if (Math.abs(dλ - π) < ε) { | |
listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); | |
listener.point(sλ0, φ0); | |
listener.lineEnd(); | |
listener.lineStart(); | |
listener.point(sλ1, φ0); | |
listener.point(λ1, φ0); | |
clean = 0; | |
} else if (sλ0 !== sλ1 && dλ >= π) { | |
if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; | |
if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; | |
φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); | |
listener.point(sλ0, φ0); | |
listener.lineEnd(); | |
listener.lineStart(); | |
listener.point(sλ1, φ0); | |
clean = 0; | |
} | |
listener.point(λ0 = λ1, φ0 = φ1); | |
sλ0 = sλ1; | |
}, | |
lineEnd: function() { | |
listener.lineEnd(); | |
λ0 = φ0 = NaN; | |
}, | |
clean: function() { | |
return 2 - clean; | |
} | |
}; | |
} | |
function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { | |
var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); | |
return Math.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; | |
} | |
function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { | |
var φ; | |
if (from == null) { | |
φ = direction * π / 2; | |
listener.point(-π, φ); | |
listener.point(0, φ); | |
listener.point(π, φ); | |
listener.point(π, 0); | |
listener.point(π, -φ); | |
listener.point(0, -φ); | |
listener.point(-π, -φ); | |
listener.point(-π, 0); | |
listener.point(-π, φ); | |
} else if (Math.abs(from[0] - to[0]) > ε) { | |
var s = (from[0] < to[0] ? 1 : -1) * π; | |
φ = direction * s / 2; | |
listener.point(-s, φ); | |
listener.point(0, φ); | |
listener.point(s, φ); | |
} else { | |
listener.point(to[0], to[1]); | |
} | |
} | |
var d3_geo_clipAntimeridianPoint = [ -π, 0 ]; | |
function d3_geo_clipAntimeridianPolygonContains(polygon) { | |
return d3_geo_pointInPolygon(d3_geo_clipAntimeridianPoint, polygon); | |
} | |
function d3_geo_clipCircle(radius) { | |
var cr = Math.cos(radius), smallRadius = cr > 0, point = [ radius, 0 ], notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); | |
return d3_geo_clip(visible, clipLine, interpolate, polygonContains); | |
function visible(λ, φ) { | |
return Math.cos(λ) * Math.cos(φ) > cr; | |
} | |
function clipLine(listener) { | |
var point0, c0, v0, v00, clean; | |
return { | |
lineStart: function() { | |
v00 = v0 = false; | |
clean = 1; | |
}, | |
point: function(λ, φ) { | |
var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; | |
if (!point0 && (v00 = v0 = v)) listener.lineStart(); | |
if (v !== v0) { | |
point2 = intersect(point0, point1); | |
if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { | |
point1[0] += ε; | |
point1[1] += ε; | |
v = visible(point1[0], point1[1]); | |
} | |
} | |
if (v !== v0) { | |
clean = 0; | |
if (v) { | |
listener.lineStart(); | |
point2 = intersect(point1, point0); | |
listener.point(point2[0], point2[1]); | |
} else { | |
point2 = intersect(point0, point1); | |
listener.point(point2[0], point2[1]); | |
listener.lineEnd(); | |
} | |
point0 = point2; | |
} else if (notHemisphere && point0 && smallRadius ^ v) { | |
var t; | |
if (!(c & c0) && (t = intersect(point1, point0, true))) { | |
clean = 0; | |
if (smallRadius) { | |
listener.lineStart(); | |
listener.point(t[0][0], t[0][1]); | |
listener.point(t[1][0], t[1][1]); | |
listener.lineEnd(); | |
} else { | |
listener.point(t[1][0], t[1][1]); | |
listener.lineEnd(); | |
listener.lineStart(); | |
listener.point(t[0][0], t[0][1]); | |
} | |
} | |
} | |
if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { | |
listener.point(point1[0], point1[1]); | |
} | |
point0 = point1, v0 = v, c0 = c; | |
}, | |
lineEnd: function() { | |
if (v0) listener.lineEnd(); | |
point0 = null; | |
}, | |
clean: function() { | |
return clean | (v00 && v0) << 1; | |
} | |
}; | |
} | |
function intersect(a, b, two) { | |
var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); | |
var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; | |
if (!determinant) return !two && a; | |
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); | |
d3_geo_cartesianAdd(A, B); | |
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); | |
if (t2 < 0) return; | |
var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); | |
d3_geo_cartesianAdd(q, A); | |
q = d3_geo_spherical(q); | |
if (!two) return q; | |
var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; | |
if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; | |
var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε; | |
if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; | |
if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { | |
var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); | |
d3_geo_cartesianAdd(q1, A); | |
return [ q, d3_geo_spherical(q1) ]; | |
} | |
} | |
function code(λ, φ) { | |
var r = smallRadius ? radius : π - radius, code = 0; | |
if (λ < -r) code |= 1; else if (λ > r) code |= 2; | |
if (φ < -r) code |= 4; else if (φ > r) code |= 8; | |
return code; | |
} | |
function polygonContains(polygon) { | |
return d3_geo_pointInPolygon(point, polygon); | |
} | |
} | |
var d3_geo_clipViewMAX = 1e9; | |
function d3_geo_clipView(x0, y0, x1, y1) { | |
return function(listener) { | |
var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; | |
var clip = { | |
point: point, | |
lineStart: lineStart, | |
lineEnd: lineEnd, | |
polygonStart: function() { | |
listener = bufferListener; | |
segments = []; | |
polygon = []; | |
}, | |
polygonEnd: function() { | |
listener = listener_; | |
if ((segments = d3.merge(segments)).length) { | |
listener.polygonStart(); | |
d3_geo_clipPolygon(segments, compare, inside, interpolate, listener); | |
listener.polygonEnd(); | |
} else if (insidePolygon([ x0, y0 ])) { | |
listener.polygonStart(), listener.lineStart(); | |
interpolate(null, null, 1, listener); | |
listener.lineEnd(), listener.polygonEnd(); | |
} | |
segments = polygon = ring = null; | |
} | |
}; | |
function inside(point) { | |
var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]); | |
return i; | |
} | |
function insidePolygon(p) { | |
var wn = 0, n = polygon.length, y = p[1]; | |
for (var i = 0; i < n; ++i) { | |
for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { | |
b = v[j]; | |
if (a[1] <= y) { | |
if (b[1] > y && isLeft(a, b, p) > 0) ++wn; | |
} else { | |
if (b[1] <= y && isLeft(a, b, p) < 0) --wn; | |
} | |
a = b; | |
} | |
} | |
return wn !== 0; | |
} | |
function isLeft(a, b, c) { | |
return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); | |
} | |
function interpolate(from, to, direction, listener) { | |
var a = 0, a1 = 0; | |
if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { | |
do { | |
listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); | |
} while ((a = (a + direction + 4) % 4) !== a1); | |
} else { | |
listener.point(to[0], to[1]); | |
} | |
} | |
function visible(x, y) { | |
return x0 <= x && x <= x1 && y0 <= y && y <= y1; | |
} | |
function point(x, y) { | |
if (visible(x, y)) listener.point(x, y); | |
} | |
var x__, y__, v__, x_, y_, v_, first; | |
function lineStart() { | |
clip.point = linePoint; | |
if (polygon) polygon.push(ring = []); | |
first = true; | |
v_ = false; | |
x_ = y_ = NaN; | |
} | |
function lineEnd() { | |
if (segments) { | |
linePoint(x__, y__); | |
if (v__ && v_) bufferListener.rejoin(); | |
segments.push(bufferListener.buffer()); | |
} | |
clip.point = point; | |
if (v_) listener.lineEnd(); | |
} | |
function linePoint(x, y) { | |
x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); | |
y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); | |
var v = visible(x, y); | |
if (polygon) ring.push([ x, y ]); | |
if (first) { | |
x__ = x, y__ = y, v__ = v; | |
first = false; | |
if (v) { | |
listener.lineStart(); | |
listener.point(x, y); | |
} | |
} else { | |
if (v && v_) listener.point(x, y); else { | |
var a = [ x_, y_ ], b = [ x, y ]; | |
if (clipLine(a, b)) { | |
if (!v_) { | |
listener.lineStart(); | |
listener.point(a[0], a[1]); | |
} | |
listener.point(b[0], b[1]); | |
if (!v) listener.lineEnd(); | |
} else if (v) { | |
listener.lineStart(); | |
listener.point(x, y); | |
} | |
} | |
} | |
x_ = x, y_ = y, v_ = v; | |
} | |
return clip; | |
}; | |
function corner(p, direction) { | |
return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; | |
} | |
function compare(a, b) { | |
return comparePoints(a.point, b.point); | |
} | |
function comparePoints(a, b) { | |
var ca = corner(a, 1), cb = corner(b, 1); | |
return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; | |
} | |
function clipLine(a, b) { | |
var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; | |
if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; | |
if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { | |
if (t[1] < 1) { | |
b[0] = a[0] + t[1] * dx; | |
b[1] = a[1] + t[1] * dy; | |
} | |
if (t[0] > 0) { | |
a[0] += t[0] * dx; | |
a[1] += t[0] * dy; | |
} | |
return true; | |
} | |
return false; | |
} | |
} | |
function d3_geo_clipViewT(num, denominator, t) { | |
if (Math.abs(denominator) < ε) return num <= 0; | |
var u = num / denominator; | |
if (denominator > 0) { | |
if (u > t[1]) return false; | |
if (u > t[0]) t[0] = u; | |
} else { | |
if (u < t[0]) return false; | |
if (u < t[1]) t[1] = u; | |
} | |
return true; | |
} | |
function d3_geo_compose(a, b) { | |
function compose(x, y) { | |
return x = a(x, y), b(x[0], x[1]); | |
} | |
if (a.invert && b.invert) compose.invert = function(x, y) { | |
return x = b.invert(x, y), x && a.invert(x[0], x[1]); | |
}; | |
return compose; | |
} | |
function d3_geo_conic(projectAt) { | |
var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); | |
p.parallels = function(_) { | |
if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; | |
return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); | |
}; | |
return p; | |
} | |
function d3_geo_conicEqualArea(φ0, φ1) { | |
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; | |
function forward(λ, φ) { | |
var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; | |
return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; | |
} | |
forward.invert = function(x, y) { | |
var ρ0_y = ρ0 - y; | |
return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; | |
}; | |
return forward; | |
} | |
(d3.geo.conicEqualArea = function() { | |
return d3_geo_conic(d3_geo_conicEqualArea); | |
}).raw = d3_geo_conicEqualArea; | |
d3.geo.albers = function() { | |
return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); | |
}; | |
d3.geo.albersUsa = function() { | |
var lower48 = d3.geo.albers(); | |
var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); | |
var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); | |
var point, pointStream = { | |
point: function(x, y) { | |
point = [ x, y ]; | |
} | |
}, lower48Point, alaskaPoint, hawaiiPoint; | |
function albersUsa(coordinates) { | |
var x = coordinates[0], y = coordinates[1]; | |
point = null; | |
(lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); | |
return point; | |
} | |
albersUsa.invert = function(coordinates) { | |
var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; | |
return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); | |
}; | |
albersUsa.stream = function(stream) { | |
var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); | |
return { | |
point: function(x, y) { | |
lower48Stream.point(x, y); | |
alaskaStream.point(x, y); | |
hawaiiStream.point(x, y); | |
}, | |
sphere: function() { | |
lower48Stream.sphere(); | |
alaskaStream.sphere(); | |
hawaiiStream.sphere(); | |
}, | |
lineStart: function() { | |
lower48Stream.lineStart(); | |
alaskaStream.lineStart(); | |
hawaiiStream.lineStart(); | |
}, | |
lineEnd: function() { | |
lower48Stream.lineEnd(); | |
alaskaStream.lineEnd(); | |
hawaiiStream.lineEnd(); | |
}, | |
polygonStart: function() { | |
lower48Stream.polygonStart(); | |
alaskaStream.polygonStart(); | |
hawaiiStream.polygonStart(); | |
}, | |
polygonEnd: function() { | |
lower48Stream.polygonEnd(); | |
alaskaStream.polygonEnd(); | |
hawaiiStream.polygonEnd(); | |
} | |
}; | |
}; | |
albersUsa.precision = function(_) { | |
if (!arguments.length) return lower48.precision(); | |
lower48.precision(_); | |
alaska.precision(_); | |
hawaii.precision(_); | |
return albersUsa; | |
}; | |
albersUsa.scale = function(_) { | |
if (!arguments.length) return lower48.scale(); | |
lower48.scale(_); | |
alaska.scale(_ * .35); | |
hawaii.scale(_); | |
return albersUsa.translate(lower48.translate()); | |
}; | |
albersUsa.translate = function(_) { | |
if (!arguments.length) return lower48.translate(); | |
var k = lower48.scale(), x = +_[0], y = +_[1]; | |
lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; | |
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; | |
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; | |
return albersUsa; | |
}; | |
return albersUsa.scale(1070); | |
}; | |
var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { | |
point: d3_noop, | |
lineStart: d3_noop, | |
lineEnd: d3_noop, | |
polygonStart: function() { | |
d3_geo_pathAreaPolygon = 0; | |
d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; | |
}, | |
polygonEnd: function() { | |
d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; | |
d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); | |
} | |
}; | |
function d3_geo_pathAreaRingStart() { | |
var x00, y00, x0, y0; | |
d3_geo_pathArea.point = function(x, y) { | |
d3_geo_pathArea.point = nextPoint; | |
x00 = x0 = x, y00 = y0 = y; | |
}; | |
function nextPoint(x, y) { | |
d3_geo_pathAreaPolygon += y0 * x - x0 * y; | |
x0 = x, y0 = y; | |
} | |
d3_geo_pathArea.lineEnd = function() { | |
nextPoint(x00, y00); | |
}; | |
} | |
var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; | |
var d3_geo_pathBounds = { | |
point: d3_geo_pathBoundsPoint, | |
lineStart: d3_noop, | |
lineEnd: d3_noop, | |
polygonStart: d3_noop, | |
polygonEnd: d3_noop | |
}; | |
function d3_geo_pathBoundsPoint(x, y) { | |
if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; | |
if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; | |
if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; | |
if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; | |
} | |
function d3_geo_pathBuffer() { | |
var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; | |
var stream = { | |
point: point, | |
lineStart: function() { | |
stream.point = pointLineStart; | |
}, | |
lineEnd: lineEnd, | |
polygonStart: function() { | |
stream.lineEnd = lineEndPolygon; | |
}, | |
polygonEnd: function() { | |
stream.lineEnd = lineEnd; | |
stream.point = point; | |
}, | |
pointRadius: function(_) { | |
pointCircle = d3_geo_pathBufferCircle(_); | |
return stream; | |
}, | |
result: function() { | |
if (buffer.length) { | |
var result = buffer.join(""); | |
buffer = []; | |
return result; | |
} | |
} | |
}; | |
function point(x, y) { | |
buffer.push("M", x, ",", y, pointCircle); | |
} | |
function pointLineStart(x, y) { | |
buffer.push("M", x, ",", y); | |
stream.point = pointLine; | |
} | |
function pointLine(x, y) { | |
buffer.push("L", x, ",", y); | |
} | |
function lineEnd() { | |
stream.point = point; | |
} | |
function lineEndPolygon() { | |
buffer.push("Z"); | |
} | |
return stream; | |
} | |
function d3_geo_pathBufferCircle(radius) { | |
return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; | |
} | |
var d3_geo_pathCentroid = { | |
point: d3_geo_pathCentroidPoint, | |
lineStart: d3_geo_pathCentroidLineStart, | |
lineEnd: d3_geo_pathCentroidLineEnd, | |
polygonStart: function() { | |
d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; | |
}, | |
polygonEnd: function() { | |
d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; | |
d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; | |
d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; | |
} | |
}; | |
function d3_geo_pathCentroidPoint(x, y) { | |
d3_geo_centroidX0 += x; | |
d3_geo_centroidY0 += y; | |
++d3_geo_centroidZ0; | |
} | |
function d3_geo_pathCentroidLineStart() { | |
var x0, y0; | |
d3_geo_pathCentroid.point = function(x, y) { | |
d3_geo_pathCentroid.point = nextPoint; | |
d3_geo_pathCentroidPoint(x0 = x, y0 = y); | |
}; | |
function nextPoint(x, y) { | |
var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); | |
d3_geo_centroidX1 += z * (x0 + x) / 2; | |
d3_geo_centroidY1 += z * (y0 + y) / 2; | |
d3_geo_centroidZ1 += z; | |
d3_geo_pathCentroidPoint(x0 = x, y0 = y); | |
} | |
} | |
function d3_geo_pathCentroidLineEnd() { | |
d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; | |
} | |
function d3_geo_pathCentroidRingStart() { | |
var x00, y00, x0, y0; | |
d3_geo_pathCentroid.point = function(x, y) { | |
d3_geo_pathCentroid.point = nextPoint; | |
d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); | |
}; | |
function nextPoint(x, y) { | |
var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); | |
d3_geo_centroidX1 += z * (x0 + x) / 2; | |
d3_geo_centroidY1 += z * (y0 + y) / 2; | |
d3_geo_centroidZ1 += z; | |
z = y0 * x - x0 * y; | |
d3_geo_centroidX2 += z * (x0 + x); | |
d3_geo_centroidY2 += z * (y0 + y); | |
d3_geo_centroidZ2 += z * 3; | |
d3_geo_pathCentroidPoint(x0 = x, y0 = y); | |
} | |
d3_geo_pathCentroid.lineEnd = function() { | |
nextPoint(x00, y00); | |
}; | |
} | |
function d3_geo_pathContext(context) { | |
var pointRadius = 4.5; | |
var stream = { | |
point: point, | |
lineStart: function() { | |
stream.point = pointLineStart; | |
}, | |
lineEnd: lineEnd, | |
polygonStart: function() { | |
stream.lineEnd = lineEndPolygon; | |
}, | |
polygonEnd: function() { | |
stream.lineEnd = lineEnd; | |
stream.point = point; | |
}, | |
pointRadius: function(_) { | |
pointRadius = _; | |
return stream; | |
}, | |
result: d3_noop | |
}; | |
function point(x, y) { | |
context.moveTo(x, y); | |
context.arc(x, y, pointRadius, 0, 2 * π); | |
} | |
function pointLineStart(x, y) { | |
context.moveTo(x, y); | |
stream.point = pointLine; | |
} | |
function pointLine(x, y) { | |
context.lineTo(x, y); | |
} | |
function lineEnd() { | |
stream.point = point; | |
} | |
function lineEndPolygon() { | |
context.closePath(); | |
} | |
return stream; | |
} | |
function d3_geo_resample(project) { | |
var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; | |
function resample(stream) { | |
var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; | |
var resample = { | |
point: point, | |
lineStart: lineStart, | |
lineEnd: lineEnd, | |
polygonStart: function() { | |
stream.polygonStart(); | |
resample.lineStart = ringStart; | |
}, | |
polygonEnd: function() { | |
stream.polygonEnd(); | |
resample.lineStart = lineStart; | |
} | |
}; | |
function point(x, y) { | |
x = project(x, y); | |
stream.point(x[0], x[1]); | |
} | |
function lineStart() { | |
x0 = NaN; | |
resample.point = linePoint; | |
stream.lineStart(); | |
} | |
function linePoint(λ, φ) { | |
var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); | |
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); | |
stream.point(x0, y0); | |
} | |
function lineEnd() { | |
resample.point = point; | |
stream.lineEnd(); | |
} | |
function ringStart() { | |
lineStart(); | |
resample.point = ringPoint; | |
resample.lineEnd = ringEnd; | |
} | |
function ringPoint(λ, φ) { | |
linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; | |
resample.point = linePoint; | |
} | |
function ringEnd() { | |
resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); | |
resample.lineEnd = lineEnd; | |
lineEnd(); | |
} | |
return resample; | |
} | |
function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { | |
var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; | |
if (d2 > 4 * δ2 && depth--) { | |
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 = Math.abs(Math.abs(c) - 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; | |
if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { | |
resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); | |
stream.point(x2, y2); | |
resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); | |
} | |
} | |
} | |
resample.precision = function(_) { | |
if (!arguments.length) return Math.sqrt(δ2); | |
maxDepth = (δ2 = _ * _) > 0 && 16; | |
return resample; | |
}; | |
return resample; | |
} | |
d3.geo.path = function() { | |
var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; | |
function path(object) { | |
if (object) { | |
if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); | |
if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); | |
d3.geo.stream(object, cacheStream); | |
} | |
return contextStream.result(); | |
} | |
path.area = function(object) { | |
d3_geo_pathAreaSum = 0; | |
d3.geo.stream(object, projectStream(d3_geo_pathArea)); | |
return d3_geo_pathAreaSum; | |
}; | |
path.centroid = function(object) { | |
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; | |
d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); | |
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 ]; | |
}; | |
path.bounds = function(object) { | |
d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); | |
d3.geo.stream(object, projectStream(d3_geo_pathBounds)); | |
return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; | |
}; | |
path.projection = function(_) { | |
if (!arguments.length) return projection; | |
projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; | |
return reset(); | |
}; | |
path.context = function(_) { | |
if (!arguments.length) return context; | |
contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); | |
if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); | |
return reset(); | |
}; | |
path.pointRadius = function(_) { | |
if (!arguments.length) return pointRadius; | |
pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); | |
return path; | |
}; | |
function reset() { | |
cacheStream = null; | |
return path; | |
} | |
return path.projection(d3.geo.albersUsa()).context(null); | |
}; | |
function d3_geo_pathProjectStream(project) { | |
var resample = d3_geo_resample(function(λ, φ) { | |
return project([ λ * d3_degrees, φ * d3_degrees ]); | |
}); | |
return function(stream) { | |
stream = resample(stream); | |
return { | |
point: function(λ, φ) { | |
stream.point(λ * d3_radians, φ * d3_radians); | |
}, | |
sphere: function() { | |
stream.sphere(); | |
}, | |
lineStart: function() { | |
stream.lineStart(); | |
}, | |
lineEnd: function() { | |
stream.lineEnd(); | |
}, | |
polygonStart: function() { | |
stream.polygonStart(); | |
}, | |
polygonEnd: function() { | |
stream.polygonEnd(); | |
} | |
}; | |
}; | |
} | |
d3.geo.projection = d3_geo_projection; | |
d3.geo.projectionMutator = d3_geo_projectionMutator; | |
function d3_geo_projection(project) { | |
return d3_geo_projectionMutator(function() { | |
return project; | |
})(); | |
} | |
function d3_geo_projectionMutator(projectAt) { | |
var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { | |
x = project(x, y); | |
return [ x[0] * k + δx, δy - x[1] * k ]; | |
}), 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; | |
function projection(point) { | |
point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); | |
return [ point[0] * k + δx, δy - point[1] * k ]; | |
} | |
function invert(point) { | |
point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); | |
return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; | |
} | |
projection.stream = function(output) { | |
if (stream) stream.valid = false; | |
stream = d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(output)))); | |
stream.valid = true; | |
return stream; | |
}; | |
projection.clipAngle = function(_) { | |
if (!arguments.length) return clipAngle; | |
preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); | |
return invalidate(); | |
}; | |
projection.clipExtent = function(_) { | |
if (!arguments.length) return clipExtent; | |
clipExtent = _; | |
postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); | |
return invalidate(); | |
}; | |
projection.scale = function(_) { | |
if (!arguments.length) return k; | |
k = +_; | |
return reset(); | |
}; | |
projection.translate = function(_) { | |
if (!arguments.length) return [ x, y ]; | |
x = +_[0]; | |
y = +_[1]; | |
return reset(); | |
}; | |
projection.center = function(_) { | |
if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; | |
λ = _[0] % 360 * d3_radians; | |
φ = _[1] % 360 * d3_radians; | |
return reset(); | |
}; | |
projection.rotate = function(_) { | |
if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; | |
δλ = _[0] % 360 * d3_radians; | |
δφ = _[1] % 360 * d3_radians; | |
δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; | |
return reset(); | |
}; | |
d3.rebind(projection, projectResample, "precision"); | |
function reset() { | |
projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); | |
var center = project(λ, φ); | |
δx = x - center[0] * k; | |
δy = y + center[1] * k; | |
return invalidate(); | |
} | |
function invalidate() { | |
if (stream) { | |
stream.valid = false; | |
stream = null; | |
} | |
return projection; | |
} | |
return function() { | |
project = projectAt.apply(this, arguments); | |
projection.invert = project.invert && invert; | |
return reset(); | |
}; | |
} | |
function d3_geo_projectionRadiansRotate(rotate, stream) { | |
return { | |
point: function(x, y) { | |
y = rotate(x * d3_radians, y * d3_radians), x = y[0]; | |
stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); | |
}, | |
sphere: function() { | |
stream.sphere(); | |
}, | |
lineStart: function() { | |
stream.lineStart(); | |
}, | |
lineEnd: function() { | |
stream.lineEnd(); | |
}, | |
polygonStart: function() { | |
stream.polygonStart(); | |
}, | |
polygonEnd: function() { | |
stream.polygonEnd(); | |
} | |
}; | |
} | |
function d3_geo_equirectangular(λ, φ) { | |
return [ λ, φ ]; | |
} | |
(d3.geo.equirectangular = function() { | |
return d3_geo_projection(d3_geo_equirectangular); | |
}).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; | |
d3.geo.rotation = function(rotate) { | |
rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); | |
function forward(coordinates) { | |
coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); | |
return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; | |
} | |
forward.invert = function(coordinates) { | |
coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); | |
return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; | |
}; | |
return forward; | |
}; | |
function d3_geo_rotation(δλ, δφ, δγ) { | |
return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular; | |
} | |
function d3_geo_forwardRotationλ(δλ) { | |
return function(λ, φ) { | |
return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ]; | |
}; | |
} | |
function d3_geo_rotationλ(δλ) { | |
var rotation = d3_geo_forwardRotationλ(δλ); | |
rotation.invert = d3_geo_forwardRotationλ(-δλ); | |
return rotation; | |
} | |
function d3_geo_rotationφγ(δφ, δγ) { | |
var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); | |
function rotation(λ, φ) { | |
var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; | |
return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; | |
} | |
rotation.invert = function(λ, φ) { | |
var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; | |
return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; | |
}; | |
return rotation; | |
} | |
d3.geo.circle = function() { | |
var origin = [ 0, 0 ], angle, precision = 6, interpolate; | |
function circle() { | |
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 = []; | |
interpolate(null, null, 1, { | |
point: function(x, y) { | |
ring.push(x = rotate(x, y)); | |
x[0] *= d3_degrees, x[1] *= d3_degrees; | |
} | |
}); | |
return { | |
type: "Polygon", | |
coordinates: [ ring ] | |
}; | |
} | |
circle.origin = function(x) { | |
if (!arguments.length) return origin; | |
origin = x; | |
return circle; | |
}; | |
circle.angle = function(x) { | |
if (!arguments.length) return angle; | |
interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); | |
return circle; | |
}; | |
circle.precision = function(_) { | |
if (!arguments.length) return precision; | |
interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); | |
return circle; | |
}; | |
return circle.angle(90); | |
}; | |
function d3_geo_circleInterpolate(radius, precision) { | |
var cr = Math.cos(radius), sr = Math.sin(radius); | |
return function(from, to, direction, listener) { | |
if (from != null) { | |
from = d3_geo_circleAngle(cr, from); | |
to = d3_geo_circleAngle(cr, to); | |
if (direction > 0 ? from < to : from > to) from += direction * 2 * π; | |
} else { | |
from = radius + direction * 2 * π; | |
to = radius; | |
} | |
var point; | |
for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { | |
listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); | |
} | |
}; | |
} | |
function d3_geo_circleAngle(cr, point) { | |
var a = d3_geo_cartesian(point); | |
a[0] -= cr; | |
d3_geo_cartesianNormalize(a); | |
var angle = d3_acos(-a[1]); | |
return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); | |
} | |
d3.geo.distance = function(a, b) { | |
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; | |
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Δλ); | |
}; | |
d3.geo.graticule = function() { | |
var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; | |
function graticule() { | |
return { | |
type: "MultiLineString", | |
coordinates: lines() | |
}; | |
} | |
function lines() { | |
return 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) { | |
return Math.abs(x % DX) > ε; | |
}).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { | |
return Math.abs(y % DY) > ε; | |
}).map(y)); | |
} | |
graticule.lines = function() { | |
return lines().map(function(coordinates) { | |
return { | |
type: "LineString", | |
coordinates: coordinates | |
}; | |
}); | |
}; | |
graticule.outline = function() { | |
return { | |
type: "Polygon", | |
coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] | |
}; | |
}; | |
graticule.extent = function(_) { | |
if (!arguments.length) return graticule.minorExtent(); | |
return graticule.majorExtent(_).minorExtent(_); | |
}; | |
graticule.majorExtent = function(_) { | |
if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; | |
X0 = +_[0][0], X1 = +_[1][0]; | |
Y0 = +_[0][1], Y1 = +_[1][1]; | |
if (X0 > X1) _ = X0, X0 = X1, X1 = _; | |
if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; | |
return graticule.precision(precision); | |
}; | |
graticule.minorExtent = function(_) { | |
if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; | |
x0 = +_[0][0], x1 = +_[1][0]; | |
y0 = +_[0][1], y1 = +_[1][1]; | |
if (x0 > x1) _ = x0, x0 = x1, x1 = _; | |
if (y0 > y1) _ = y0, y0 = y1, y1 = _; | |
return graticule.precision(precision); | |
}; | |
graticule.step = function(_) { | |
if (!arguments.length) return graticule.minorStep(); | |
return graticule.majorStep(_).minorStep(_); | |
}; | |
graticule.majorStep = function(_) { | |
if (!arguments.length) return [ DX, DY ]; | |
DX = +_[0], DY = +_[1]; | |
return graticule; | |
}; | |
graticule.minorStep = function(_) { | |
if (!arguments.length) return [ dx, dy ]; | |
dx = +_[0], dy = +_[1]; | |
return graticule; | |
}; | |
graticule.precision = function(_) { | |
if (!arguments.length) return precision; | |
precision = +_; | |
x = d3_geo_graticuleX(y0, y1, 90); | |
y = d3_geo_graticuleY(x0, x1, precision); | |
X = d3_geo_graticuleX(Y0, Y1, 90); | |
Y = d3_geo_graticuleY(X0, X1, precision); | |
return graticule; | |
}; | |
return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); | |
}; | |
function d3_geo_graticuleX(y0, y1, dy) { | |
var y = d3.range(y0, y1 - ε, dy).concat(y1); | |
return function(x) { | |
return y.map(function(y) { | |
return [ x, y ]; | |
}); | |
}; | |
} | |
function d3_geo_graticuleY(x0, x1, dx) { | |
var x = d3.range(x0, x1 - ε, dx).concat(x1); | |
return function(y) { | |
return x.map(function(x) { | |
return [ x, y ]; | |
}); | |
}; | |
} | |
function d3_source(d) { | |
return d.source; | |
} | |
function d3_target(d) { | |
return d.target; | |
} | |
d3.geo.greatArc = function() { | |
var source = d3_source, source_, target = d3_target, target_; | |
function greatArc() { | |
return { | |
type: "LineString", | |
coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] | |
}; | |
} | |
greatArc.distance = function() { | |
return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); | |
}; | |
greatArc.source = function(_) { | |
if (!arguments.length) return source; | |
source = _, source_ = typeof _ === "function" ? null : _; | |
return greatArc; | |
}; | |
greatArc.target = function(_) { | |
if (!arguments.length) return target; | |
target = _, target_ = typeof _ === "function" ? null : _; | |
return greatArc; | |
}; | |
greatArc.precision = function() { | |
return arguments.length ? greatArc : 0; | |
}; | |
return greatArc; | |
}; | |
d3.geo.interpolate = function(source, target) { | |
return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); | |
}; | |
function d3_geo_interpolate(x0, y0, x1, y1) { | |
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); | |
var interpolate = d ? function(t) { | |
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; | |
return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; | |
} : function() { | |
return [ x0 * d3_degrees, y0 * d3_degrees ]; | |
}; | |
interpolate.distance = d; | |
return interpolate; | |
} | |
d3.geo.length = function(object) { | |
d3_geo_lengthSum = 0; | |
d3.geo.stream(object, d3_geo_length); | |
return d3_geo_lengthSum; | |
}; | |
var d3_geo_lengthSum; | |
var d3_geo_length = { | |
sphere: d3_noop, | |
point: d3_noop, | |
lineStart: d3_geo_lengthLineStart, | |
lineEnd: d3_noop, | |
polygonStart: d3_noop, | |
polygonEnd: d3_noop | |
}; | |
function d3_geo_lengthLineStart() { | |
var λ0, sinφ0, cosφ0; | |
d3_geo_length.point = function(λ, φ) { | |
λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); | |
d3_geo_length.point = nextPoint; | |
}; | |
d3_geo_length.lineEnd = function() { | |
d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; | |
}; | |
function nextPoint(λ, φ) { | |
var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); | |
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Δλ); | |
λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; | |
} | |
} | |
function d3_geo_azimuthal(scale, angle) { | |
function azimuthal(λ, φ) { | |
var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); | |
return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; | |
} | |
azimuthal.invert = function(x, y) { | |
var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); | |
return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; | |
}; | |
return azimuthal; | |
} | |
var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { | |
return Math.sqrt(2 / (1 + cosλcosφ)); | |
}, function(ρ) { | |
return 2 * Math.asin(ρ / 2); | |
}); | |
(d3.geo.azimuthalEqualArea = function() { | |
return d3_geo_projection(d3_geo_azimuthalEqualArea); | |
}).raw = d3_geo_azimuthalEqualArea; | |
var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { | |
var c = Math.acos(cosλcosφ); | |
return c && c / Math.sin(c); | |
}, d3_identity); | |
(d3.geo.azimuthalEquidistant = function() { | |
return d3_geo_projection(d3_geo_azimuthalEquidistant); | |
}).raw = d3_geo_azimuthalEquidistant; | |
function d3_geo_conicConformal(φ0, φ1) { | |
var cosφ0 = Math.cos(φ0), t = function(φ) { | |
return Math.tan(π / 4 + φ / 2); | |
}, 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; | |
if (!n) return d3_geo_mercator; | |
function forward(λ, φ) { | |
var ρ = Math.abs(Math.abs(φ) - π / 2) < ε ? 0 : F / Math.pow(t(φ), n); | |
return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; | |
} | |
forward.invert = function(x, y) { | |
var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); | |
return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - π / 2 ]; | |
}; | |
return forward; | |
} | |
(d3.geo.conicConformal = function() { | |
return d3_geo_conic(d3_geo_conicConformal); | |
}).raw = d3_geo_conicConformal; | |
function d3_geo_conicEquidistant(φ0, φ1) { | |
var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; | |
if (Math.abs(n) < ε) return d3_geo_equirectangular; | |
function forward(λ, φ) { | |
var ρ = G - φ; | |
return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; | |
} | |
forward.invert = function(x, y) { | |
var ρ0_y = G - y; | |
return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; | |
}; | |
return forward; | |
} | |
(d3.geo.conicEquidistant = function() { | |
return d3_geo_conic(d3_geo_conicEquidistant); | |
}).raw = d3_geo_conicEquidistant; | |
var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { | |
return 1 / cosλcosφ; | |
}, Math.atan); | |
(d3.geo.gnomonic = function() { | |
return d3_geo_projection(d3_geo_gnomonic); | |
}).raw = d3_geo_gnomonic; | |
function d3_geo_mercator(λ, φ) { | |
return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; | |
} | |
d3_geo_mercator.invert = function(x, y) { | |
return [ x, 2 * Math.atan(Math.exp(y)) - π / 2 ]; | |
}; | |
function d3_geo_mercatorProjection(project) { | |
var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; | |
m.scale = function() { | |
var v = scale.apply(m, arguments); | |
return v === m ? clipAuto ? m.clipExtent(null) : m : v; | |
}; | |
m.translate = function() { | |
var v = translate.apply(m, arguments); | |
return v === m ? clipAuto ? m.clipExtent(null) : m : v; | |
}; | |
m.clipExtent = function(_) { | |
var v = clipExtent.apply(m, arguments); | |
if (v === m) { | |
if (clipAuto = _ == null) { | |
var k = π * scale(), t = translate(); | |
clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); | |
} | |
} else if (clipAuto) { | |
v = null; | |
} | |
return v; | |
}; | |
return m.clipExtent(null); | |
} | |
(d3.geo.mercator = function() { | |
return d3_geo_mercatorProjection(d3_geo_mercator); | |
}).raw = d3_geo_mercator; | |
var d3_geo_orthographic = d3_geo_azimuthal(function() { | |
return 1; | |
}, Math.asin); | |
(d3.geo.orthographic = function() { | |
return d3_geo_projection(d3_geo_orthographic); | |
}).raw = d3_geo_orthographic; | |
var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { | |
return 1 / (1 + cosλcosφ); | |
}, function(ρ) { | |
return 2 * Math.atan(ρ); | |
}); | |
(d3.geo.stereographic = function() { | |
return d3_geo_projection(d3_geo_stereographic); | |
}).raw = d3_geo_stereographic; | |
function d3_geo_transverseMercator(λ, φ) { | |
var B = Math.cos(φ) * Math.sin(λ); | |
return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ]; | |
} | |
d3_geo_transverseMercator.invert = function(x, y) { | |
return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ]; | |
}; | |
(d3.geo.transverseMercator = function() { | |
return d3_geo_mercatorProjection(d3_geo_transverseMercator); | |
}).raw = d3_geo_transverseMercator; | |
d3.geom = {}; | |
d3.svg = {}; | |
function d3_svg_line(projection) { | |
var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; | |
function line(data) { | |
var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); | |
function segment() { | |
segments.push("M", interpolate(projection(points), tension)); | |
} | |
while (++i < n) { | |
if (defined.call(this, d = data[i], i)) { | |
points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); | |
} else if (points.length) { | |
segment(); | |
points = []; | |
} | |
} | |
if (points.length) segment(); | |
return segments.length ? segments.join("") : null; | |
} | |
line.x = function(_) { | |
if (!arguments.length) return x; | |
x = _; | |
return line; | |
}; | |
line.y = function(_) { | |
if (!arguments.length) return y; | |
y = _; | |
return line; | |
}; | |
line.defined = function(_) { | |
if (!arguments.length) return defined; | |
defined = _; | |
return line; | |
}; | |
line.interpolate = function(_) { | |
if (!arguments.length) return interpolateKey; | |
if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; | |
return line; | |
}; | |
line.tension = function(_) { | |
if (!arguments.length) return tension; | |
tension = _; | |
return line; | |
}; | |
return line; | |
} | |
d3.svg.line = function() { | |
return d3_svg_line(d3_identity); | |
}; | |
function d3_svg_lineX(d) { | |
return d[0]; | |
} | |
function d3_svg_lineY(d) { | |
return d[1]; | |
} | |
var d3_svg_lineInterpolators = d3.map({ | |
linear: d3_svg_lineLinear, | |
"linear-closed": d3_svg_lineLinearClosed, | |
step: d3_svg_lineStep, | |
"step-before": d3_svg_lineStepBefore, | |
"step-after": d3_svg_lineStepAfter, | |
basis: d3_svg_lineBasis, | |
"basis-open": d3_svg_lineBasisOpen, | |
"basis-closed": d3_svg_lineBasisClosed, | |
bundle: d3_svg_lineBundle, | |
cardinal: d3_svg_lineCardinal, | |
"cardinal-open": d3_svg_lineCardinalOpen, | |
"cardinal-closed": d3_svg_lineCardinalClosed, | |
monotone: d3_svg_lineMonotone | |
}); | |
d3_svg_lineInterpolators.forEach(function(key, value) { | |
value.key = key; | |
value.closed = /-closed$/.test(key); | |
}); | |
function d3_svg_lineLinear(points) { | |
return points.join("L"); | |
} | |
function d3_svg_lineLinearClosed(points) { | |
return d3_svg_lineLinear(points) + "Z"; | |
} | |
function d3_svg_lineStep(points) { | |
var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; | |
while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); | |
if (n > 1) path.push("H", p[0]); | |
return path.join(""); | |
} | |
function d3_svg_lineStepBefore(points) { | |
var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; | |
while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); | |
return path.join(""); | |
} | |
function d3_svg_lineStepAfter(points) { | |
var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; | |
while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); | |
return path.join(""); | |
} | |
function d3_svg_lineCardinalOpen(points, tension) { | |
return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); | |
} | |
function d3_svg_lineCardinalClosed(points, tension) { | |
return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), | |
points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); | |
} | |
function d3_svg_lineCardinal(points, tension) { | |
return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); | |
} | |
function d3_svg_lineHermite(points, tangents) { | |
if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { | |
return d3_svg_lineLinear(points); | |
} | |
var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; | |
if (quad) { | |
path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; | |
p0 = points[1]; | |
pi = 2; | |
} | |
if (tangents.length > 1) { | |
t = tangents[1]; | |
p = points[pi]; | |
pi++; | |
path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; | |
for (var i = 2; i < tangents.length; i++, pi++) { | |
p = points[pi]; | |
t = tangents[i]; | |
path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; | |
} | |
} | |
if (quad) { | |
var lp = points[pi]; | |
path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; | |
} | |
return path; | |
} | |
function d3_svg_lineCardinalTangents(points, tension) { | |
var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; | |
while (++i < n) { | |
p0 = p1; | |
p1 = p2; | |
p2 = points[i]; | |
tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); | |
} | |
return tangents; | |
} | |
function d3_svg_lineBasis(points) { | |
if (points.length < 3) return d3_svg_lineLinear(points); | |
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) ]; | |
points.push(points[n - 1]); | |
while (++i <= n) { | |
pi = points[i]; | |
px.shift(); | |
px.push(pi[0]); | |
py.shift(); | |
py.push(pi[1]); | |
d3_svg_lineBasisBezier(path, px, py); | |
} | |
points.pop(); | |
path.push("L", pi); | |
return path.join(""); | |
} | |
function d3_svg_lineBasisOpen(points) { | |
if (points.length < 4) return d3_svg_lineLinear(points); | |
var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; | |
while (++i < 3) { | |
pi = points[i]; | |
px.push(pi[0]); | |
py.push(pi[1]); | |
} | |
path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); | |
--i; | |
while (++i < n) { | |
pi = points[i]; | |
px.shift(); | |
px.push(pi[0]); | |
py.shift(); | |
py.push(pi[1]); | |
d3_svg_lineBasisBezier(path, px, py); | |
} | |
return path.join(""); | |
} | |
function d3_svg_lineBasisClosed(points) { | |
var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; | |
while (++i < 4) { | |
pi = points[i % n]; | |
px.push(pi[0]); | |
py.push(pi[1]); | |
} | |
path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; | |
--i; | |
while (++i < m) { | |
pi = points[i % n]; | |
px.shift(); | |
px.push(pi[0]); | |
py.shift(); | |
py.push(pi[1]); | |
d3_svg_lineBasisBezier(path, px, py); | |
} | |
return path.join(""); | |
} | |
function d3_svg_lineBundle(points, tension) { | |
var n = points.length - 1; | |
if (n) { | |
var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; | |
while (++i <= n) { | |
p = points[i]; | |
t = i / n; | |
p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); | |
p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); | |
} | |
} | |
return d3_svg_lineBasis(points); | |
} | |
function d3_svg_lineDot4(a, b) { | |
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; | |
} | |
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 ]; | |
function d3_svg_lineBasisBezier(path, x, y) { | |
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)); | |
} | |
function d3_svg_lineSlope(p0, p1) { | |
return (p1[1] - p0[1]) / (p1[0] - p0[0]); | |
} | |
function d3_svg_lineFiniteDifferences(points) { | |
var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); | |
while (++i < j) { | |
m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; | |
} | |
m[i] = d; | |
return m; | |
} | |
function d3_svg_lineMonotoneTangents(points) { | |
var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; | |
while (++i < j) { | |
d = d3_svg_lineSlope(points[i], points[i + 1]); | |
if (Math.abs(d) < 1e-6) { | |
m[i] = m[i + 1] = 0; | |
} else { | |
a = m[i] / d; | |
b = m[i + 1] / d; | |
s = a * a + b * b; | |
if (s > 9) { | |
s = d * 3 / Math.sqrt(s); | |
m[i] = s * a; | |
m[i + 1] = s * b; | |
} | |
} | |
} | |
i = -1; | |
while (++i <= j) { | |
s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); | |
tangents.push([ s || 0, m[i] * s || 0 ]); | |
} | |
return tangents; | |
} | |
function d3_svg_lineMonotone(points) { | |
return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); | |
} | |
d3.geom.hull = function(vertices) { | |
var x = d3_svg_lineX, y = d3_svg_lineY; | |
if (arguments.length) return hull(vertices); | |
function hull(data) { | |
if (data.length < 3) return []; | |
var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; | |
if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, | |
vertices = []; i < n; ++i) { | |
vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); | |
} | |
for (i = 1; i < n; ++i) { | |
if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1] && vertices[i][0] < vertices[h][0]) h = i; | |
} | |
for (i = 0; i < n; ++i) { | |
if (i === h) continue; | |
y1 = vertices[i][1] - vertices[h][1]; | |
x1 = vertices[i][0] - vertices[h][0]; | |
points.push({ | |
angle: Math.atan2(y1, x1), | |
index: i | |
}); | |
} | |
points.sort(function(a, b) { | |
return a.angle - b.angle; | |
}); | |
a = points[0].angle; | |
v = points[0].index; | |
u = 0; | |
for (i = 1; i < plen; ++i) { | |
j = points[i].index; | |
if (a == points[i].angle) { | |
x1 = vertices[v][0] - vertices[h][0]; | |
y1 = vertices[v][1] - vertices[h][1]; | |
x2 = vertices[j][0] - vertices[h][0]; | |
y2 = vertices[j][1] - vertices[h][1]; | |
if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { | |
points[i].index = -1; | |
continue; | |
} else { | |
points[u].index = -1; | |
} | |
} | |
a = points[i].angle; | |
u = i; | |
v = j; | |
} | |
stack.push(h); | |
for (i = 0, j = 0; i < 2; ++j) { | |
if (points[j].index > -1) { | |
stack.push(points[j].index); | |
i++; | |
} | |
} | |
sp = stack.length; | |
for (;j < plen; ++j) { | |
if (points[j].index < 0) continue; | |
while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { | |
--sp; | |
} | |
stack[sp++] = points[j].index; | |
} | |
var poly = []; | |
for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]); | |
return poly; | |
} | |
hull.x = function(_) { | |
return arguments.length ? (x = _, hull) : x; | |
}; | |
hull.y = function(_) { | |
return arguments.length ? (y = _, hull) : y; | |
}; | |
return hull; | |
}; | |
function d3_geom_hullCCW(i1, i2, i3, v) { | |
var t, a, b, c, d, e, f; | |
t = v[i1]; | |
a = t[0]; | |
b = t[1]; | |
t = v[i2]; | |
c = t[0]; | |
d = t[1]; | |
t = v[i3]; | |
e = t[0]; | |
f = t[1]; | |
return (f - b) * (c - a) - (d - b) * (e - a) > 0; | |
} | |
d3.geom.polygon = function(coordinates) { | |
d3_subclass(coordinates, d3_geom_polygonPrototype); | |
return coordinates; | |
}; | |
var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; | |
d3_geom_polygonPrototype.area = function() { | |
var i = -1, n = this.length, a, b = this[n - 1], area = 0; | |
while (++i < n) { | |
a = b; | |
b = this[i]; | |
area += a[1] * b[0] - a[0] * b[1]; | |
} | |
return area * .5; | |
}; | |
d3_geom_polygonPrototype.centroid = function(k) { | |
var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; | |
if (!arguments.length) k = -1 / (6 * this.area()); | |
while (++i < n) { | |
a = b; | |
b = this[i]; | |
c = a[0] * b[1] - b[0] * a[1]; | |
x += (a[0] + b[0]) * c; | |
y += (a[1] + b[1]) * c; | |
} | |
return [ x * k, y * k ]; | |
}; | |
d3_geom_polygonPrototype.clip = function(subject) { | |
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; | |
while (++i < n) { | |
input = subject.slice(); | |
subject.length = 0; | |
b = this[i]; | |
c = input[(m = input.length - closed) - 1]; | |
j = -1; | |
while (++j < m) { | |
d = input[j]; | |
if (d3_geom_polygonInside(d, a, b)) { | |
if (!d3_geom_polygonInside(c, a, b)) { | |
subject.push(d3_geom_polygonIntersect(c, d, a, b)); | |
} | |
subject.push(d); | |
} else if (d3_geom_polygonInside(c, a, b)) { | |
subject.push(d3_geom_polygonIntersect(c, d, a, b)); | |
} | |
c = d; | |
} | |
if (closed) subject.push(subject[0]); | |
a = b; | |
} | |
return subject; | |
}; | |
function d3_geom_polygonInside(p, a, b) { | |
return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); | |
} | |
function d3_geom_polygonIntersect(c, d, a, b) { | |
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); | |
return [ x1 + ua * x21, y1 + ua * y21 ]; | |
} | |
function d3_geom_polygonClosed(coordinates) { | |
var a = coordinates[0], b = coordinates[coordinates.length - 1]; | |
return !(a[0] - b[0] || a[1] - b[1]); | |
} | |
d3.geom.delaunay = function(vertices) { | |
var edges = vertices.map(function() { | |
return []; | |
}), triangles = []; | |
d3_geom_voronoiTessellate(vertices, function(e) { | |
edges[e.region.l.index].push(vertices[e.region.r.index]); | |
}); | |
edges.forEach(function(edge, i) { | |
var v = vertices[i], cx = v[0], cy = v[1]; | |
edge.forEach(function(v) { | |
v.angle = Math.atan2(v[0] - cx, v[1] - cy); | |
}); | |
edge.sort(function(a, b) { | |
return a.angle - b.angle; | |
}); | |
for (var j = 0, m = edge.length - 1; j < m; j++) { | |
triangles.push([ v, edge[j], edge[j + 1] ]); | |
} | |
}); | |
return triangles; | |
}; | |
d3.geom.voronoi = function(points) { | |
var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null; | |
if (arguments.length) return voronoi(points); | |
function voronoi(data) { | |
var points, polygons = data.map(function() { | |
return []; | |
}), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6; | |
if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), | |
i = 0; i < n; ++i) { | |
points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; | |
} | |
d3_geom_voronoiTessellate(points, function(e) { | |
var s1, s2, x1, x2, y1, y2; | |
if (e.a === 1 && e.b >= 0) { | |
s1 = e.ep.r; | |
s2 = e.ep.l; | |
} else { | |
s1 = e.ep.l; | |
s2 = e.ep.r; | |
} | |
if (e.a === 1) { | |
y1 = s1 ? s1.y : -Z; | |
x1 = e.c - e.b * y1; | |
y2 = s2 ? s2.y : Z; | |
x2 = e.c - e.b * y2; | |
} else { | |
x1 = s1 ? s1.x : -Z; | |
y1 = e.c - e.a * x1; | |
x2 = s2 ? s2.x : Z; | |
y2 = e.c - e.a * x2; | |
} | |
var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; | |
polygons[e.region.l.index].push(v1, v2); | |
polygons[e.region.r.index].push(v1, v2); | |
}); | |
polygons = polygons.map(function(polygon, i) { | |
var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) { | |
return Math.atan2(v[0] - cx, v[1] - cy); | |
}), order = d3.range(polygon.length).sort(function(a, b) { | |
return angle[a] - angle[b]; | |
}); | |
return order.filter(function(d, i) { | |
return !i || angle[d] - angle[order[i - 1]] > ε; | |
}).map(function(d) { | |
return polygon[d]; | |
}); | |
}); | |
polygons.forEach(function(polygon, i) { | |
var n = polygon.length; | |
if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); | |
if (n > 2) return; | |
var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; | |
if (Math.abs(dy) < ε) { | |
var y = y0 < y1 ? -Z : Z; | |
polygon.push([ -Z, y ], [ Z, y ]); | |
} else if (dx < ε) { | |
var x = x0 < x1 ? -Z : Z; | |
polygon.push([ x, -Z ], [ x, Z ]); | |
} else { | |
var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; | |
if (Math.abs(z) < ε) { | |
polygon.push([ dy < 0 ? y : -y, y ]); | |
} else { | |
if (z > 0) y *= -1; | |
polygon.push([ -Z, y ], [ Z, y ]); | |
} | |
} | |
}); | |
if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]); | |
for (i = 0; i < n; ++i) polygons[i].point = data[i]; | |
return polygons; | |
} | |
voronoi.x = function(_) { | |
return arguments.length ? (x = _, voronoi) : x; | |
}; | |
voronoi.y = function(_) { | |
return arguments.length ? (y = _, voronoi) : y; | |
}; | |
voronoi.clipExtent = function(_) { | |
if (!arguments.length) return clipPolygon && [ clipPolygon[0], clipPolygon[2] ]; | |
if (_ == null) clipPolygon = null; else { | |
var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; | |
clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ] ]); | |
} | |
return voronoi; | |
}; | |
voronoi.size = function(_) { | |
if (!arguments.length) return clipPolygon && clipPolygon[2]; | |
return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); | |
}; | |
voronoi.links = function(data) { | |
var points, graph = data.map(function() { | |
return []; | |
}), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; | |
if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), | |
i = 0; i < n; ++i) { | |
points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; | |
} | |
d3_geom_voronoiTessellate(points, function(e) { | |
var l = e.region.l.index, r = e.region.r.index; | |
if (graph[l][r]) return; | |
graph[l][r] = graph[r][l] = true; | |
links.push({ | |
source: data[l], | |
target: data[r] | |
}); | |
}); | |
return links; | |
}; | |
voronoi.triangles = function(data) { | |
if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data); | |
var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n = data.length; | |
while (++i < n) { | |
(points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d; | |
} | |
return d3.geom.delaunay(points).map(function(triangle) { | |
return triangle.map(function(point) { | |
return point.data; | |
}); | |
}); | |
}; | |
return voronoi; | |
}; | |
var d3_geom_voronoiOpposite = { | |
l: "r", | |
r: "l" | |
}; | |
function d3_geom_voronoiTessellate(points, callback) { | |
var Sites = { | |
list: points.map(function(v, i) { | |
return { | |
index: i, | |
x: v[0], | |
y: v[1] | |
}; | |
}).sort(function(a, b) { | |
return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; | |
}), | |
bottomSite: null | |
}; | |
var EdgeList = { | |
list: [], | |
leftEnd: null, | |
rightEnd: null, | |
init: function() { | |
EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); | |
EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); | |
EdgeList.leftEnd.r = EdgeList.rightEnd; | |
EdgeList.rightEnd.l = EdgeList.leftEnd; | |
EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); | |
}, | |
createHalfEdge: function(edge, side) { | |
return { | |
edge: edge, | |
side: side, | |
vertex: null, | |
l: null, | |
r: null | |
}; | |
}, | |
insert: function(lb, he) { | |
he.l = lb; | |
he.r = lb.r; | |
lb.r.l = he; | |
lb.r = he; | |
}, | |
leftBound: function(p) { | |
var he = EdgeList.leftEnd; | |
do { | |
he = he.r; | |
} while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); | |
he = he.l; | |
return he; | |
}, | |
del: function(he) { | |
he.l.r = he.r; | |
he.r.l = he.l; | |
he.edge = null; | |
}, | |
right: function(he) { | |
return he.r; | |
}, | |
left: function(he) { | |
return he.l; | |
}, | |
leftRegion: function(he) { | |
return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; | |
}, | |
rightRegion: function(he) { | |
return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]]; | |
} | |
}; | |
var Geom = { | |
bisect: function(s1, s2) { | |
var newEdge = { | |
region: { | |
l: s1, | |
r: s2 | |
}, | |
ep: { | |
l: null, | |
r: null | |
} | |
}; | |
var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; | |
newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; | |
if (adx > ady) { | |
newEdge.a = 1; | |
newEdge.b = dy / dx; | |
newEdge.c /= dx; | |
} else { | |
newEdge.b = 1; | |
newEdge.a = dx / dy; | |
newEdge.c /= dy; | |
} | |
return newEdge; | |
}, | |
intersect: function(el1, el2) { | |
var e1 = el1.edge, e2 = el2.edge; | |
if (!e1 || !e2 || e1.region.r == e2.region.r) { | |
return null; | |
} | |
var d = e1.a * e2.b - e1.b * e2.a; | |
if (Math.abs(d) < 1e-10) { | |
return null; | |
} | |
var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; | |
if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { | |
el = el1; | |
e = e1; | |
} else { | |
el = el2; | |
e = e2; | |
} | |
var rightOfSite = xint >= e.region.r.x; | |
if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { | |
return null; | |
} | |
return { | |
x: xint, | |
y: yint | |
}; | |
}, | |
rightOf: function(he, p) { | |
var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; | |
if (rightOfSite && he.side === "l") { | |
return 1; | |
} | |
if (!rightOfSite && he.side === "r") { | |
return 0; | |
} | |
if (e.a === 1) { | |
var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; | |
if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { | |
above = fast = dyp >= e.b * dxp; | |
} else { | |
above = p.x + p.y * e.b > e.c; | |
if (e.b < 0) { | |
above = !above; | |
} | |
if (!above) { | |
fast = 1; | |
} | |
} | |
if (!fast) { | |
var dxs = topsite.x - e.region.l.x; | |
above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); | |
if (e.b < 0) { | |
above = !above; | |
} | |
} | |
} else { | |
var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; | |
above = t1 * t1 > t2 * t2 + t3 * t3; | |
} | |
return he.side === "l" ? above : !above; | |
}, | |
endPoint: function(edge, side, site) { | |
edge.ep[side] = site; | |
if (!edge.ep[d3_geom_voronoiOpposite[side]]) return; | |
callback(edge); | |
}, | |
distance: function(s, t) { | |
var dx = s.x - t.x, dy = s.y - t.y; | |
return Math.sqrt(dx * dx + dy * dy); | |
} | |
}; | |
var EventQueue = { | |
list: [], | |
insert: function(he, site, offset) { | |
he.vertex = site; | |
he.ystar = site.y + offset; | |
for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { | |
var next = list[i]; | |
if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { | |
continue; | |
} else { | |
break; | |
} | |
} | |
list.splice(i, 0, he); | |
}, | |
del: function(he) { | |
for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} | |
ls.splice(i, 1); | |
}, | |
empty: function() { | |
return EventQueue.list.length === 0; | |
}, | |
nextEvent: function(he) { | |
for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { | |
if (ls[i] == he) return ls[i + 1]; | |
} | |
return null; | |
}, | |
min: function() { | |
var elem = EventQueue.list[0]; | |
return { | |
x: elem.vertex.x, | |
y: elem.ystar | |
}; | |
}, | |
extractMin: function() { | |
return EventQueue.list.shift(); | |
} | |
}; | |
EdgeList.init(); | |
Sites.bottomSite = Sites.list.shift(); | |
var newSite = Sites.list.shift(), newIntStar; | |
var lbnd, rbnd, llbnd, rrbnd, bisector; | |
var bot, top, temp, p, v; | |
var e, pm; | |
while (true) { | |
if (!EventQueue.empty()) { | |
newIntStar = EventQueue.min(); | |
} | |
if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { | |
lbnd = EdgeList.leftBound(newSite); | |
rbnd = EdgeList.right(lbnd); | |
bot = EdgeList.rightRegion(lbnd); | |
e = Geom.bisect(bot, newSite); | |
bisector = EdgeList.createHalfEdge(e, "l"); | |
EdgeList.insert(lbnd, bisector); | |
p = Geom.intersect(lbnd, bisector); | |
if (p) { | |
EventQueue.del(lbnd); | |
EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); | |
} | |
lbnd = bisector; | |
bisector = EdgeList.createHalfEdge(e, "r"); | |
EdgeList.insert(lbnd, bisector); | |
p = Geom.intersect(bisector, rbnd); | |
if (p) { | |
EventQueue.insert(bisector, p, Geom.distance(p, newSite)); | |
} | |
newSite = Sites.list.shift(); | |
} else if (!EventQueue.empty()) { | |
lbnd = EventQueue.extractMin(); | |
llbnd = EdgeList.left(lbnd); | |
rbnd = EdgeList.right(lbnd); | |
rrbnd = EdgeList.right(rbnd); | |
bot = EdgeList.leftRegion(lbnd); | |
top = EdgeList.rightRegion(rbnd); | |
v = lbnd.vertex; | |
Geom.endPoint(lbnd.edge, lbnd.side, v); | |
Geom.endPoint(rbnd.edge, rbnd.side, v); | |
EdgeList.del(lbnd); | |
EventQueue.del(rbnd); | |
EdgeList.del(rbnd); | |
pm = "l"; | |
if (bot.y > top.y) { | |
temp = bot; | |
bot = top; | |
top = temp; | |
pm = "r"; | |
} | |
e = Geom.bisect(bot, top); | |
bisector = EdgeList.createHalfEdge(e, pm); | |
EdgeList.insert(llbnd, bisector); | |
Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v); | |
p = Geom.intersect(llbnd, bisector); | |
if (p) { | |
EventQueue.del(llbnd); | |
EventQueue.insert(llbnd, p, Geom.distance(p, bot)); | |
} | |
p = Geom.intersect(bisector, rrbnd); | |
if (p) { | |
EventQueue.insert(bisector, p, Geom.distance(p, bot)); | |
} | |
} else { | |
break; | |
} | |
} | |
for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { | |
callback(lbnd.edge); | |
} | |
} | |
d3.geom.quadtree = function(points, x1, y1, x2, y2) { | |
var x = d3_svg_lineX, y = d3_svg_lineY, compat; | |
if (compat = arguments.length) { | |
x = d3_geom_quadtreeCompatX; | |
y = d3_geom_quadtreeCompatY; | |
if (compat === 3) { | |
y2 = y1; | |
x2 = x1; | |
y1 = x1 = 0; | |
} | |
return quadtree(points); | |
} | |
function quadtree(data) { | |
var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; | |
if (x1 != null) { | |
x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; | |
} else { | |
x2_ = y2_ = -(x1_ = y1_ = Infinity); | |
xs = [], ys = []; | |
n = data.length; | |
if (compat) for (i = 0; i < n; ++i) { | |
d = data[i]; | |
if (d.x < x1_) x1_ = d.x; | |
if (d.y < y1_) y1_ = d.y; | |
if (d.x > x2_) x2_ = d.x; | |
if (d.y > y2_) y2_ = d.y; | |
xs.push(d.x); | |
ys.push(d.y); | |
} else for (i = 0; i < n; ++i) { | |
var x_ = +fx(d = data[i], i), y_ = +fy(d, i); | |
if (x_ < x1_) x1_ = x_; | |
if (y_ < y1_) y1_ = y_; | |
if (x_ > x2_) x2_ = x_; | |
if (y_ > y2_) y2_ = y_; | |
xs.push(x_); | |
ys.push(y_); | |
} | |
} | |
var dx = x2_ - x1_, dy = y2_ - y1_; | |
if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; | |
function insert(n, d, x, y, x1, y1, x2, y2) { | |
if (isNaN(x) || isNaN(y)) return; | |
if (n.leaf) { | |
var nx = n.x, ny = n.y; | |
if (nx != null) { | |
if (Math.abs(nx - x) + Math.abs(ny - y) < .01) { | |
insertChild(n, d, x, y, x1, y1, x2, y2); | |
} else { | |
var nPoint = n.point; | |
n.x = n.y = n.point = null; | |
insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); | |
insertChild(n, d, x, y, x1, y1, x2, y2); | |
} | |
} else { | |
n.x = x, n.y = y, n.point = d; | |
} | |
} else { | |
insertChild(n, d, x, y, x1, y1, x2, y2); | |
} | |
} | |
function insertChild(n, d, x, y, x1, y1, x2, y2) { | |
var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right; | |
n.leaf = false; | |
n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); | |
if (right) x1 = sx; else x2 = sx; | |
if (bottom) y1 = sy; else y2 = sy; | |
insert(n, d, x, y, x1, y1, x2, y2); | |
} | |
var root = d3_geom_quadtreeNode(); | |
root.add = function(d) { | |
insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); | |
}; | |
root.visit = function(f) { | |
d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); | |
}; | |
i = -1; | |
if (x1 == null) { | |
while (++i < n) { | |
insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); | |
} | |
--i; | |
} else data.forEach(root.add); | |
xs = ys = data = d = null; | |
return root; | |
} | |
quadtree.x = function(_) { | |
return arguments.length ? (x = _, quadtree) : x; | |
}; | |
quadtree.y = function(_) { | |
return arguments.length ? (y = _, quadtree) : y; | |
}; | |
quadtree.extent = function(_) { | |
if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; | |
if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], | |
y2 = +_[1][1]; | |
return quadtree; | |
}; | |
quadtree.size = function(_) { | |
if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; | |
if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; | |
return quadtree; | |
}; | |
return quadtree; | |
}; | |
function d3_geom_quadtreeCompatX(d) { | |
return d.x; | |
} | |
function d3_geom_quadtreeCompatY(d) { | |
return d.y; | |
} | |
function d3_geom_quadtreeNode() { | |
return { | |
leaf: true, | |
nodes: [], | |
point: null, | |
x: null, | |
y: null | |
}; | |
} | |
function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { | |
if (!f(node, x1, y1, x2, y2)) { | |
var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; | |
if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); | |
if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); | |
if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); | |
if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); | |
} | |
} | |
d3.interpolateRgb = d3_interpolateRgb; | |
function d3_interpolateRgb(a, b) { | |
a = d3.rgb(a); | |
b = d3.rgb(b); | |
var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; | |
return function(t) { | |
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)); | |
}; | |
} | |
d3.interpolateObject = d3_interpolateObject; | |
function d3_interpolateObject(a, b) { | |
var i = {}, c = {}, k; | |
for (k in a) { | |
if (k in b) { | |
i[k] = d3_interpolate(a[k], b[k]); | |
} else { | |
c[k] = a[k]; | |
} | |
} | |
for (k in b) { | |
if (!(k in a)) { | |
c[k] = b[k]; | |
} | |
} | |
return function(t) { | |
for (k in i) c[k] = i[k](t); | |
return c; | |
}; | |
} | |
d3.interpolateNumber = d3_interpolateNumber; | |
function d3_interpolateNumber(a, b) { | |
b -= a = +a; | |
return function(t) { | |
return a + b * t; | |
}; | |
} | |
d3.interpolateString = d3_interpolateString; | |
function d3_interpolateString(a, b) { | |
var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; | |
a = a + "", b = b + ""; | |
d3_interpolate_number.lastIndex = 0; | |
for (i = 0; m = d3_interpolate_number.exec(b); ++i) { | |
if (m.index) s.push(b.substring(s0, s1 = m.index)); | |
q.push({ | |
i: s.length, | |
x: m[0] | |
}); | |
s.push(null); | |
s0 = d3_interpolate_number.lastIndex; | |
} | |
if (s0 < b.length) s.push(b.substring(s0)); | |
for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { | |
o = q[i]; | |
if (o.x == m[0]) { | |
if (o.i) { | |
if (s[o.i + 1] == null) { | |
s[o.i - 1] += o.x; | |
s.splice(o.i, 1); | |
for (j = i + 1; j < n; ++j) q[j].i--; | |
} else { | |
s[o.i - 1] += o.x + s[o.i + 1]; | |
s.splice(o.i, 2); | |
for (j = i + 1; j < n; ++j) q[j].i -= 2; | |
} | |
} else { | |
if (s[o.i + 1] == null) { | |
s[o.i] = o.x; | |
} else { | |
s[o.i] = o.x + s[o.i + 1]; | |
s.splice(o.i + 1, 1); | |
for (j = i + 1; j < n; ++j) q[j].i--; | |
} | |
} | |
q.splice(i, 1); | |
n--; | |
i--; | |
} else { | |
o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); | |
} | |
} | |
while (i < n) { | |
o = q.pop(); | |
if (s[o.i + 1] == null) { | |
s[o.i] = o.x; | |
} else { | |
s[o.i] = o.x + s[o.i + 1]; | |
s.splice(o.i + 1, 1); | |
} | |
n--; | |
} | |
if (s.length === 1) { | |
return s[0] == null ? (o = q[0].x, function(t) { | |
return o(t) + ""; | |
}) : function() { | |
return b; | |
}; | |
} | |
return function(t) { | |
for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); | |
return s.join(""); | |
}; | |
} | |
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; | |
d3.interpolate = d3_interpolate; | |
function d3_interpolate(a, b) { | |
var i = d3.interpolators.length, f; | |
while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; | |
return f; | |
} | |
d3.interpolators = [ function(a, b) { | |
var t = typeof b; | |
return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t === "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject : d3_interpolateNumber)(a, b); | |
} ]; | |
d3.interpolateArray = d3_interpolateArray; | |
function d3_interpolateArray(a, b) { | |
var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; | |
for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); | |
for (;i < na; ++i) c[i] = a[i]; | |
for (;i < nb; ++i) c[i] = b[i]; | |
return function(t) { | |
for (i = 0; i < n0; ++i) c[i] = x[i](t); | |
return c; | |
}; | |
} | |
var d3_ease_default = function() { | |
return d3_identity; | |
}; | |
var d3_ease = d3.map({ | |
linear: d3_ease_default, | |
poly: d3_ease_poly, | |
quad: function() { | |
return d3_ease_quad; | |
}, | |
cubic: function() { | |
return d3_ease_cubic; | |
}, | |
sin: function() { | |
return d3_ease_sin; | |
}, | |
exp: function() { | |
return d3_ease_exp; | |
}, | |
circle: function() { | |
return d3_ease_circle; | |
}, | |
elastic: d3_ease_elastic, | |
back: d3_ease_back, | |
bounce: function() { | |
return d3_ease_bounce; | |
} | |
}); | |
var d3_ease_mode = d3.map({ | |
"in": d3_identity, | |
out: d3_ease_reverse, | |
"in-out": d3_ease_reflect, | |
"out-in": function(f) { | |
return d3_ease_reflect(d3_ease_reverse(f)); | |
} | |
}); | |
d3.ease = function(name) { | |
var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; | |
t = d3_ease.get(t) || d3_ease_default; | |
m = d3_ease_mode.get(m) || d3_identity; | |
return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); | |
}; | |
function d3_ease_clamp(f) { | |
return function(t) { | |
return t <= 0 ? 0 : t >= 1 ? 1 : f(t); | |
}; | |
} | |
function d3_ease_reverse(f) { | |
return function(t) { | |
return 1 - f(1 - t); | |
}; | |
} | |
function d3_ease_reflect(f) { | |
return function(t) { | |
return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); | |
}; | |
} | |
function d3_ease_quad(t) { | |
return t * t; | |
} | |
function d3_ease_cubic(t) { | |
return t * t * t; | |
} | |
function d3_ease_cubicInOut(t) { | |
if (t <= 0) return 0; | |
if (t >= 1) return 1; | |
var t2 = t * t, t3 = t2 * t; | |
return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); | |
} | |
function d3_ease_poly(e) { | |
return function(t) { | |
return Math.pow(t, e); | |
}; | |
} | |
function d3_ease_sin(t) { | |
return 1 - Math.cos(t * π / 2); | |
} | |
function d3_ease_exp(t) { | |
return Math.pow(2, 10 * (t - 1)); | |
} | |
function d3_ease_circle(t) { | |
return 1 - Math.sqrt(1 - t * t); | |
} | |
function d3_ease_elastic(a, p) { | |
var s; | |
if (arguments.length < 2) p = .45; | |
if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4; | |
return function(t) { | |
return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); | |
}; | |
} | |
function d3_ease_back(s) { | |
if (!s) s = 1.70158; | |
return function(t) { | |
return t * t * ((s + 1) * t - s); | |
}; | |
} | |
function d3_ease_bounce(t) { | |
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; | |
} | |
d3.interpolateHcl = d3_interpolateHcl; | |
function d3_interpolateHcl(a, b) { | |
a = d3.hcl(a); | |
b = d3.hcl(b); | |
var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; | |
if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; | |
if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; | |
return function(t) { | |
return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; | |
}; | |
} | |
d3.interpolateHsl = d3_interpolateHsl; | |
function d3_interpolateHsl(a, b) { | |
a = d3.hsl(a); | |
b = d3.hsl(b); | |
var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; | |
if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; | |
if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; | |
return function(t) { | |
return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; | |
}; | |
} | |
d3.interpolateLab = d3_interpolateLab; | |
function d3_interpolateLab(a, b) { | |
a = d3.lab(a); | |
b = d3.lab(b); | |
var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; | |
return function(t) { | |
return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; | |
}; | |
} | |
d3.interpolateRound = d3_interpolateRound; | |
function d3_interpolateRound(a, b) { | |
b -= a; | |
return function(t) { | |
return Math.round(a + b * t); | |
}; | |
} | |
d3.transform = function(string) { | |
var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); | |
return (d3.transform = function(string) { | |
if (string != null) { | |
g.setAttribute("transform", string); | |
var t = g.transform.baseVal.consolidate(); | |
} | |
return new d3_transform(t ? t.matrix : d3_transformIdentity); | |
})(string); | |
}; | |
function d3_transform(m) { | |
var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; | |
if (r0[0] * r1[1] < r1[0] * r0[1]) { | |
r0[0] *= -1; | |
r0[1] *= -1; | |
kx *= -1; | |
kz *= -1; | |
} | |
this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; | |
this.translate = [ m.e, m.f ]; | |
this.scale = [ kx, ky ]; | |
this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; | |
} | |
d3_transform.prototype.toString = function() { | |
return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; | |
}; | |
function d3_transformDot(a, b) { | |
return a[0] * b[0] + a[1] * b[1]; | |
} | |
function d3_transformNormalize(a) { | |
var k = Math.sqrt(d3_transformDot(a, a)); | |
if (k) { | |
a[0] /= k; | |
a[1] /= k; | |
} | |
return k; | |
} | |
function d3_transformCombine(a, b, k) { | |
a[0] += k * b[0]; | |
a[1] += k * b[1]; | |
return a; | |
} | |
var d3_transformIdentity = { | |
a: 1, | |
b: 0, | |
c: 0, | |
d: 1, | |
e: 0, | |
f: 0 | |
}; | |
d3.interpolateTransform = d3_interpolateTransform; | |
function d3_interpolateTransform(a, b) { | |
var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; | |
if (ta[0] != tb[0] || ta[1] != tb[1]) { | |
s.push("translate(", null, ",", null, ")"); | |
q.push({ | |
i: 1, | |
x: d3_interpolateNumber(ta[0], tb[0]) | |
}, { | |
i: 3, | |
x: d3_interpolateNumber(ta[1], tb[1]) | |
}); | |
} else if (tb[0] || tb[1]) { | |
s.push("translate(" + tb + ")"); | |
} else { | |
s.push(""); | |
} | |
if (ra != rb) { | |
if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; | |
q.push({ | |
i: s.push(s.pop() + "rotate(", null, ")") - 2, | |
x: d3_interpolateNumber(ra, rb) | |
}); | |
} else if (rb) { | |
s.push(s.pop() + "rotate(" + rb + ")"); | |
} | |
if (wa != wb) { | |
q.push({ | |
i: s.push(s.pop() + "skewX(", null, ")") - 2, | |
x: d3_interpolateNumber(wa, wb) | |
}); | |
} else if (wb) { | |
s.push(s.pop() + "skewX(" + wb + ")"); | |
} | |
if (ka[0] != kb[0] || ka[1] != kb[1]) { | |
n = s.push(s.pop() + "scale(", null, ",", null, ")"); | |
q.push({ | |
i: n - 4, | |
x: d3_interpolateNumber(ka[0], kb[0]) | |
}, { | |
i: n - 2, | |
x: d3_interpolateNumber(ka[1], kb[1]) | |
}); | |
} else if (kb[0] != 1 || kb[1] != 1) { | |
s.push(s.pop() + "scale(" + kb + ")"); | |
} | |
n = q.length; | |
return function(t) { | |
var i = -1, o; | |
while (++i < n) s[(o = q[i]).i] = o.x(t); | |
return s.join(""); | |
}; | |
} | |
function d3_uninterpolateNumber(a, b) { | |
b = b - (a = +a) ? 1 / (b - a) : 0; | |
return function(x) { | |
return (x - a) * b; | |
}; | |
} | |
function d3_uninterpolateClamp(a, b) { | |
b = b - (a = +a) ? 1 / (b - a) : 0; | |
return function(x) { | |
return Math.max(0, Math.min(1, (x - a) * b)); | |
}; | |
} | |
d3.layout = {}; | |
d3.layout.bundle = function() { | |
return function(links) { | |
var paths = [], i = -1, n = links.length; | |
while (++i < n) paths.push(d3_layout_bundlePath(links[i])); | |
return paths; | |
}; | |
}; | |
function d3_layout_bundlePath(link) { | |
var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; | |
while (start !== lca) { | |
start = start.parent; | |
points.push(start); | |
} | |
var k = points.length; | |
while (end !== lca) { | |
points.splice(k, 0, end); | |
end = end.parent; | |
} | |
return points; | |
} | |
function d3_layout_bundleAncestors(node) { | |
var ancestors = [], parent = node.parent; | |
while (parent != null) { | |
ancestors.push(node); | |
node = parent; | |
parent = parent.parent; | |
} | |
ancestors.push(node); | |
return ancestors; | |
} | |
function d3_layout_bundleLeastCommonAncestor(a, b) { | |
if (a === b) return a; | |
var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; | |
while (aNode === bNode) { | |
sharedNode = aNode; | |
aNode = aNodes.pop(); | |
bNode = bNodes.pop(); | |
} | |
return sharedNode; | |
} | |
d3.layout.chord = function() { | |
var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; | |
function relayout() { | |
var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; | |
chords = []; | |
groups = []; | |
k = 0, i = -1; | |
while (++i < n) { | |
x = 0, j = -1; | |
while (++j < n) { | |
x += matrix[i][j]; | |
} | |
groupSums.push(x); | |
subgroupIndex.push(d3.range(n)); | |
k += x; | |
} | |
if (sortGroups) { | |
groupIndex.sort(function(a, b) { | |
return sortGroups(groupSums[a], groupSums[b]); | |
}); | |
} | |
if (sortSubgroups) { | |
subgroupIndex.forEach(function(d, i) { | |
d.sort(function(a, b) { | |
return sortSubgroups(matrix[i][a], matrix[i][b]); | |
}); | |
}); | |
} | |
k = (2 * π - padding * n) / k; | |
x = 0, i = -1; | |
while (++i < n) { | |
x0 = x, j = -1; | |
while (++j < n) { | |
var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; | |
subgroups[di + "-" + dj] = { | |
index: di, | |
subindex: dj, | |
startAngle: a0, | |
endAngle: a1, | |
value: v | |
}; | |
} | |
groups[di] = { | |
index: di, | |
startAngle: x0, | |
endAngle: x, | |
value: (x - x0) / k | |
}; | |
x += padding; | |
} | |
i = -1; | |
while (++i < n) { | |
j = i - 1; | |
while (++j < n) { | |
var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; | |
if (source.value || target.value) { | |
chords.push(source.value < target.value ? { | |
source: target, | |
target: source | |
} : { | |
source: source, | |
target: target | |
}); | |
} | |
} | |
} | |
if (sortChords) resort(); | |
} | |
function resort() { | |
chords.sort(function(a, b) { | |
return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); | |
}); | |
} | |
chord.matrix = function(x) { | |
if (!arguments.length) return matrix; | |
n = (matrix = x) && matrix.length; | |
chords = groups = null; | |
return chord; | |
}; | |
chord.padding = function(x) { | |
if (!arguments.length) return padding; | |
padding = x; | |
chords = groups = null; | |
return chord; | |
}; | |
chord.sortGroups = function(x) { | |
if (!arguments.length) return sortGroups; | |
sortGroups = x; | |
chords = groups = null; | |
return chord; | |
}; | |
chord.sortSubgroups = function(x) { | |
if (!arguments.length) return sortSubgroups; | |
sortSubgroups = x; | |
chords = null; | |
return chord; | |
}; | |
chord.sortChords = function(x) { | |
if (!arguments.length) return sortChords; | |
sortChords = x; | |
if (chords) resort(); | |
return chord; | |
}; | |
chord.chords = function() { | |
if (!chords) relayout(); | |
return chords; | |
}; | |
chord.groups = function() { | |
if (!groups) relayout(); | |
return groups; | |
}; | |
return chord; | |
}; | |
d3.layout.force = function() { | |
var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; | |
function repulse(node) { | |
return function(quad, x1, _, x2) { | |
if (quad.point !== node) { | |
var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); | |
if ((x2 - x1) * dn < theta) { | |
var k = quad.charge * dn * dn; | |
node.px -= dx * k; | |
node.py -= dy * k; | |
return true; | |
} | |
if (quad.point && isFinite(dn)) { | |
var k = quad.pointCharge * dn * dn; | |
node.px -= dx * k; | |
node.py -= dy * k; | |
} | |
} | |
return !quad.charge; | |
}; | |
} | |
force.tick = function() { | |
if ((alpha *= .99) < .005) { | |
event.end({ | |
type: "end", | |
alpha: alpha = 0 | |
}); | |
return true; | |
} | |
var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; | |
for (i = 0; i < m; ++i) { | |
o = links[i]; | |
s = o.source; | |
t = o.target; | |
x = t.x - s.x; | |
y = t.y - s.y; | |
if (l = x * x + y * y) { | |
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; | |
x *= l; | |
y *= l; | |
t.x -= x * (k = s.weight / (t.weight + s.weight)); | |
t.y -= y * k; | |
s.x += x * (k = 1 - k); | |
s.y += y * k; | |
} | |
} | |
if (k = alpha * gravity) { | |
x = size[0] / 2; | |
y = size[1] / 2; | |
i = -1; | |
if (k) while (++i < n) { | |
o = nodes[i]; | |
o.x += (x - o.x) * k; | |
o.y += (y - o.y) * k; | |
} | |
} | |
if (charge) { | |
d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); | |
i = -1; | |
while (++i < n) { | |
if (!(o = nodes[i]).fixed) { | |
q.visit(repulse(o)); | |
} | |
} | |
} | |
i = -1; | |
while (++i < n) { | |
o = nodes[i]; | |
if (o.fixed) { | |
o.x = o.px; | |
o.y = o.py; | |
} else { | |
o.x -= (o.px - (o.px = o.x)) * friction; | |
o.y -= (o.py - (o.py = o.y)) * friction; | |
} | |
} | |
event.tick({ | |
type: "tick", | |
alpha: alpha | |
}); | |
}; | |
force.nodes = function(x) { | |
if (!arguments.length) return nodes; | |
nodes = x; | |
return force; | |
}; | |
force.links = function(x) { | |
if (!arguments.length) return links; | |
links = x; | |
return force; | |
}; | |
force.size = function(x) { | |
if (!arguments.length) return size; | |
size = x; | |
return force; | |
}; | |
force.linkDistance = function(x) { | |
if (!arguments.length) return linkDistance; | |
linkDistance = typeof x === "function" ? x : +x; | |
return force; | |
}; | |
force.distance = force.linkDistance; | |
force.linkStrength = function(x) { | |
if (!arguments.length) return linkStrength; | |
linkStrength = typeof x === "function" ? x : +x; | |
return force; | |
}; | |
force.friction = function(x) { | |
if (!arguments.length) return friction; | |
friction = +x; | |
return force; | |
}; | |
force.charge = function(x) { | |
if (!arguments.length) return charge; | |
charge = typeof x === "function" ? x : +x; | |
return force; | |
}; | |
force.gravity = function(x) { | |
if (!arguments.length) return gravity; | |
gravity = +x; | |
return force; | |
}; | |
force.theta = function(x) { | |
if (!arguments.length) return theta; | |
theta = +x; | |
return force; | |
}; | |
force.alpha = function(x) { | |
if (!arguments.length) return alpha; | |
x = +x; | |
if (alpha) { | |
if (x > 0) alpha = x; else alpha = 0; | |
} else if (x > 0) { | |
event.start({ | |
type: "start", | |
alpha: alpha = x | |
}); | |
d3.timer(force.tick); | |
} | |
return force; | |
}; | |
force.start = function() { | |
var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; | |
for (i = 0; i < n; ++i) { | |
(o = nodes[i]).index = i; | |
o.weight = 0; | |
} | |
for (i = 0; i < m; ++i) { | |
o = links[i]; | |
if (typeof o.source == "number") o.source = nodes[o.source]; | |
if (typeof o.target == "number") o.target = nodes[o.target]; | |
++o.source.weight; | |
++o.target.weight; | |
} | |
for (i = 0; i < n; ++i) { | |
o = nodes[i]; | |
if (isNaN(o.x)) o.x = position("x", w); | |
if (isNaN(o.y)) o.y = position("y", h); | |
if (isNaN(o.px)) o.px = o.x; | |
if (isNaN(o.py)) o.py = o.y; | |
} | |
distances = []; | |
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; | |
strengths = []; | |
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; | |
charges = []; | |
if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; | |
function position(dimension, size) { | |
var neighbors = neighbor(i), j = -1, m = neighbors.length, x; | |
while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; | |
return Math.random() * size; | |
} | |
function neighbor() { | |
if (!neighbors) { | |
neighbors = []; | |
for (j = 0; j < n; ++j) { | |
neighbors[j] = []; | |
} | |
for (j = 0; j < m; ++j) { | |
var o = links[j]; | |
neighbors[o.source.index].push(o.target); | |
neighbors[o.target.index].push(o.source); | |
} | |
} | |
return neighbors[i]; | |
} | |
return force.resume(); | |
}; | |
force.resume = function() { | |
return force.alpha(.1); | |
}; | |
force.stop = function() { | |
return force.alpha(0); | |
}; | |
force.drag = function() { | |
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); | |
if (!arguments.length) return drag; | |
this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); | |
}; | |
function dragmove(d) { | |
d.px = d3.event.x, d.py = d3.event.y; | |
force.resume(); | |
} | |
return d3.rebind(force, event, "on"); | |
}; | |
function d3_layout_forceDragstart(d) { | |
d.fixed |= 2; | |
} | |
function d3_layout_forceDragend(d) { | |
d.fixed &= ~6; | |
} | |
function d3_layout_forceMouseover(d) { | |
d.fixed |= 4; | |
d.px = d.x, d.py = d.y; | |
} | |
function d3_layout_forceMouseout(d) { | |
d.fixed &= ~4; | |
} | |
function d3_layout_forceAccumulate(quad, alpha, charges) { | |
var cx = 0, cy = 0; | |
quad.charge = 0; | |
if (!quad.leaf) { | |
var nodes = quad.nodes, n = nodes.length, i = -1, c; | |
while (++i < n) { | |
c = nodes[i]; | |
if (c == null) continue; | |
d3_layout_forceAccumulate(c, alpha, charges); | |
quad.charge += c.charge; | |
cx += c.charge * c.cx; | |
cy += c.charge * c.cy; | |
} | |
} | |
if (quad.point) { | |
if (!quad.leaf) { | |
quad.point.x += Math.random() - .5; | |
quad.point.y += Math.random() - .5; | |
} | |
var k = alpha * charges[quad.point.index]; | |
quad.charge += quad.pointCharge = k; | |
cx += k * quad.point.x; | |
cy += k * quad.point.y; | |
} | |
quad.cx = cx / quad.charge; | |
quad.cy = cy / quad.charge; | |
} | |
var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; | |
d3.layout.hierarchy = function() { | |
var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; | |
function recurse(node, depth, nodes) { | |
var childs = children.call(hierarchy, node, depth); | |
node.depth = depth; | |
nodes.push(node); | |
if (childs && (n = childs.length)) { | |
var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; | |
while (++i < n) { | |
d = recurse(childs[i], j, nodes); | |
d.parent = node; | |
c.push(d); | |
v += d.value; | |
} | |
if (sort) c.sort(sort); | |
if (value) node.value = v; | |
} else if (value) { | |
node.value = +value.call(hierarchy, node, depth) || 0; | |
} | |
return node; | |
} | |
function revalue(node, depth) { | |
var children = node.children, v = 0; | |
if (children && (n = children.length)) { | |
var i = -1, n, j = depth + 1; | |
while (++i < n) v += revalue(children[i], j); | |
} else if (value) { | |
v = +value.call(hierarchy, node, depth) || 0; | |
} | |
if (value) node.value = v; | |
return v; | |
} | |
function hierarchy(d) { | |
var nodes = []; | |
recurse(d, 0, nodes); | |
return nodes; | |
} | |
hierarchy.sort = function(x) { | |
if (!arguments.length) return sort; | |
sort = x; | |
return hierarchy; | |
}; | |
hierarchy.children = function(x) { | |
if (!arguments.length) return children; | |
children = x; | |
return hierarchy; | |
}; | |
hierarchy.value = function(x) { | |
if (!arguments.length) return value; | |
value = x; | |
return hierarchy; | |
}; | |
hierarchy.revalue = function(root) { | |
revalue(root, 0); | |
return root; | |
}; | |
return hierarchy; | |
}; | |
function d3_layout_hierarchyRebind(object, hierarchy) { | |
d3.rebind(object, hierarchy, "sort", "children", "value"); | |
object.nodes = object; | |
object.links = d3_layout_hierarchyLinks; | |
return object; | |
} | |
function d3_layout_hierarchyChildren(d) { | |
return d.children; | |
} | |
function d3_layout_hierarchyValue(d) { | |
return d.value; | |
} | |
function d3_layout_hierarchySort(a, b) { | |
return b.value - a.value; | |
} | |
function d3_layout_hierarchyLinks(nodes) { | |
return d3.merge(nodes.map(function(parent) { | |
return (parent.children || []).map(function(child) { | |
return { | |
source: parent, | |
target: child | |
}; | |
}); | |
})); | |
} | |
d3.layout.partition = function() { | |
var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; | |
function position(node, x, dx, dy) { | |
var children = node.children; | |
node.x = x; | |
node.y = node.depth * dy; | |
node.dx = dx; | |
node.dy = dy; | |
if (children && (n = children.length)) { | |
var i = -1, n, c, d; | |
dx = node.value ? dx / node.value : 0; | |
while (++i < n) { | |
position(c = children[i], x, d = c.value * dx, dy); | |
x += d; | |
} | |
} | |
} | |
function depth(node) { | |
var children = node.children, d = 0; | |
if (children && (n = children.length)) { | |
var i = -1, n; | |
while (++i < n) d = Math.max(d, depth(children[i])); | |
} | |
return 1 + d; | |
} | |
function partition(d, i) { | |
var nodes = hierarchy.call(this, d, i); | |
position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); | |
return nodes; | |
} | |
partition.size = function(x) { | |
if (!arguments.length) return size; | |
size = x; | |
return partition; | |
}; | |
return d3_layout_hierarchyRebind(partition, hierarchy); | |
}; | |
d3.layout.pie = function() { | |
var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π; | |
function pie(data) { | |
var values = data.map(function(d, i) { | |
return +value.call(pie, d, i); | |
}); | |
var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); | |
var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values); | |
var index = d3.range(data.length); | |
if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { | |
return values[j] - values[i]; | |
} : function(i, j) { | |
return sort(data[i], data[j]); | |
}); | |
var arcs = []; | |
index.forEach(function(i) { | |
var d; | |
arcs[i] = { | |
data: data[i], | |
value: d = values[i], | |
startAngle: a, | |
endAngle: a += d * k | |
}; | |
}); | |
return arcs; | |
} | |
pie.value = function(x) { | |
if (!arguments.length) return value; | |
value = x; | |
return pie; | |
}; | |
pie.sort = function(x) { | |
if (!arguments.length) return sort; | |
sort = x; | |
return pie; | |
}; | |
pie.startAngle = function(x) { | |
if (!arguments.length) return startAngle; | |
startAngle = x; | |
return pie; | |
}; | |
pie.endAngle = function(x) { | |
if (!arguments.length) return endAngle; | |
endAngle = x; | |
return pie; | |
}; | |
return pie; | |
}; | |
var d3_layout_pieSortByValue = {}; | |
d3.layout.stack = function() { | |
var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; | |
function stack(data, index) { | |
var series = data.map(function(d, i) { | |
return values.call(stack, d, i); | |
}); | |
var points = series.map(function(d) { | |
return d.map(function(v, i) { | |
return [ x.call(stack, v, i), y.call(stack, v, i) ]; | |
}); | |
}); | |
var orders = order.call(stack, points, index); | |
series = d3.permute(series, orders); | |
points = d3.permute(points, orders); | |
var offsets = offset.call(stack, points, index); | |
var n = series.length, m = series[0].length, i, j, o; | |
for (j = 0; j < m; ++j) { | |
out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); | |
for (i = 1; i < n; ++i) { | |
out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); | |
} | |
} | |
return data; | |
} | |
stack.values = function(x) { | |
if (!arguments.length) return values; | |
values = x; | |
return stack; | |
}; | |
stack.order = function(x) { | |
if (!arguments.length) return order; | |
order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; | |
return stack; | |
}; | |
stack.offset = function(x) { | |
if (!arguments.length) return offset; | |
offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; | |
return stack; | |
}; | |
stack.x = function(z) { | |
if (!arguments.length) return x; | |
x = z; | |
return stack; | |
}; | |
stack.y = function(z) { | |
if (!arguments.length) return y; | |
y = z; | |
return stack; | |
}; | |
stack.out = function(z) { | |
if (!arguments.length) return out; | |
out = z; | |
return stack; | |
}; | |
return stack; | |
}; | |
function d3_layout_stackX(d) { | |
return d.x; | |
} | |
function d3_layout_stackY(d) { | |
return d.y; | |
} | |
function d3_layout_stackOut(d, y0, y) { | |
d.y0 = y0; | |
d.y = y; | |
} | |
var d3_layout_stackOrders = d3.map({ | |
"inside-out": function(data) { | |
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) { | |
return max[a] - max[b]; | |
}), top = 0, bottom = 0, tops = [], bottoms = []; | |
for (i = 0; i < n; ++i) { | |
j = index[i]; | |
if (top < bottom) { | |
top += sums[j]; | |
tops.push(j); | |
} else { | |
bottom += sums[j]; | |
bottoms.push(j); | |
} | |
} | |
return bottoms.reverse().concat(tops); | |
}, | |
reverse: function(data) { | |
return d3.range(data.length).reverse(); | |
}, | |
"default": d3_layout_stackOrderDefault | |
}); | |
var d3_layout_stackOffsets = d3.map({ | |
silhouette: function(data) { | |
var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; | |
for (j = 0; j < m; ++j) { | |
for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; | |
if (o > max) max = o; | |
sums.push(o); | |
} | |
for (j = 0; j < m; ++j) { | |
y0[j] = (max - sums[j]) / 2; | |
} | |
return y0; | |
}, | |
wiggle: function(data) { | |
var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; | |
y0[0] = o = o0 = 0; | |
for (j = 1; j < m; ++j) { | |
for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; | |
for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { | |
for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { | |
s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; | |
} | |
s2 += s3 * data[i][j][1]; | |
} | |
y0[j] = o -= s1 ? s2 / s1 * dx : 0; | |
if (o < o0) o0 = o; | |
} | |
for (j = 0; j < m; ++j) y0[j] -= o0; | |
return y0; | |
}, | |
expand: function(data) { | |
var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; | |
for (j = 0; j < m; ++j) { | |
for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; | |
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; | |
} | |
for (j = 0; j < m; ++j) y0[j] = 0; | |
return y0; | |
}, | |
zero: d3_layout_stackOffsetZero | |
}); | |
function d3_layout_stackOrderDefault(data) { | |
return d3.range(data.length); | |
} | |
function d3_layout_stackOffsetZero(data) { | |
var j = -1, m = data[0].length, y0 = []; | |
while (++j < m) y0[j] = 0; | |
return y0; | |
} | |
function d3_layout_stackMaxIndex(array) { | |
var i = 1, j = 0, v = array[0][1], k, n = array.length; | |
for (;i < n; ++i) { | |
if ((k = array[i][1]) > v) { | |
j = i; | |
v = k; | |
} | |
} | |
return j; | |
} | |
function d3_layout_stackReduceSum(d) { | |
return d.reduce(d3_layout_stackSum, 0); | |
} | |
function d3_layout_stackSum(p, d) { | |
return p + d[1]; | |
} | |
d3.layout.histogram = function() { | |
var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; | |
function histogram(data, i) { | |
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; | |
while (++i < m) { | |
bin = bins[i] = []; | |
bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); | |
bin.y = 0; | |
} | |
if (m > 0) { | |
i = -1; | |
while (++i < n) { | |
x = values[i]; | |
if (x >= range[0] && x <= range[1]) { | |
bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; | |
bin.y += k; | |
bin.push(data[i]); | |
} | |
} | |
} | |
return bins; | |
} | |
histogram.value = function(x) { | |
if (!arguments.length) return valuer; | |
valuer = x; | |
return histogram; | |
}; | |
histogram.range = function(x) { | |
if (!arguments.length) return ranger; | |
ranger = d3_functor(x); | |
return histogram; | |
}; | |
histogram.bins = function(x) { | |
if (!arguments.length) return binner; | |
binner = typeof x === "number" ? function(range) { | |
return d3_layout_histogramBinFixed(range, x); | |
} : d3_functor(x); | |
return histogram; | |
}; | |
histogram.frequency = function(x) { | |
if (!arguments.length) return frequency; | |
frequency = !!x; | |
return histogram; | |
}; | |
return histogram; | |
}; | |
function d3_layout_histogramBinSturges(range, values) { | |
return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); | |
} | |
function d3_layout_histogramBinFixed(range, n) { | |
var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; | |
while (++x <= n) f[x] = m * x + b; | |
return f; | |
} | |
function d3_layout_histogramRange(values) { | |
return [ d3.min(values), d3.max(values) ]; | |
} | |
d3.layout.tree = function() { | |
var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; | |
function tree(d, i) { | |
var nodes = hierarchy.call(this, d, i), root = nodes[0]; | |
function firstWalk(node, previousSibling) { | |
var children = node.children, layout = node._tree; | |
if (children && (n = children.length)) { | |
var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; | |
while (++i < n) { | |
child = children[i]; | |
firstWalk(child, previousChild); | |
ancestor = apportion(child, previousChild, ancestor); | |
previousChild = child; | |
} | |
d3_layout_treeShift(node); | |
var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); | |
if (previousSibling) { | |
layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); | |
layout.mod = layout.prelim - midpoint; | |
} else { | |
layout.prelim = midpoint; | |
} | |
} else { | |
if (previousSibling) { | |
layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); | |
} | |
} | |
} | |
function secondWalk(node, x) { | |
node.x = node._tree.prelim + x; | |
var children = node.children; | |
if (children && (n = children.length)) { | |
var i = -1, n; | |
x += node._tree.mod; | |
while (++i < n) { | |
secondWalk(children[i], x); | |
} | |
} | |
} | |
function apportion(node, previousSibling, ancestor) { | |
if (previousSibling) { | |
var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; | |
while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { | |
vom = d3_layout_treeLeft(vom); | |
vop = d3_layout_treeRight(vop); | |
vop._tree.ancestor = node; | |
shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); | |
if (shift > 0) { | |
d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); | |
sip += shift; | |
sop += shift; | |
} | |
sim += vim._tree.mod; | |
sip += vip._tree.mod; | |
som += vom._tree.mod; | |
sop += vop._tree.mod; | |
} | |
if (vim && !d3_layout_treeRight(vop)) { | |
vop._tree.thread = vim; | |
vop._tree.mod += sim - sop; | |
} | |
if (vip && !d3_layout_treeLeft(vom)) { | |
vom._tree.thread = vip; | |
vom._tree.mod += sip - som; | |
ancestor = node; | |
} | |
} | |
return ancestor; | |
} | |
d3_layout_treeVisitAfter(root, function(node, previousSibling) { | |
node._tree = { | |
ancestor: node, | |
prelim: 0, | |
mod: 0, | |
change: 0, | |
shift: 0, | |
number: previousSibling ? previousSibling._tree.number + 1 : 0 | |
}; | |
}); | |
firstWalk(root); | |
secondWalk(root, -root._tree.prelim); | |
var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; | |
d3_layout_treeVisitAfter(root, nodeSize ? function(node) { | |
node.x *= size[0]; | |
node.y = node.depth * size[1]; | |
delete node._tree; | |
} : function(node) { | |
node.x = (node.x - x0) / (x1 - x0) * size[0]; | |
node.y = node.depth / y1 * size[1]; | |
delete node._tree; | |
}); | |
return nodes; | |
} | |
tree.separation = function(x) { | |
if (!arguments.length) return separation; | |
separation = x; | |
return tree; | |
}; | |
tree.size = function(x) { | |
if (!arguments.length) return nodeSize ? null : size; | |
nodeSize = (size = x) == null; | |
return tree; | |
}; | |
tree.nodeSize = function(x) { | |
if (!arguments.length) return nodeSize ? size : null; | |
nodeSize = (size = x) != null; | |
return tree; | |
}; | |
return d3_layout_hierarchyRebind(tree, hierarchy); | |
}; | |
function d3_layout_treeSeparation(a, b) { | |
return a.parent == b.parent ? 1 : 2; | |
} | |
function d3_layout_treeLeft(node) { | |
var children = node.children; | |
return children && children.length ? children[0] : node._tree.thread; | |
} | |
function d3_layout_treeRight(node) { | |
var children = node.children, n; | |
return children && (n = children.length) ? children[n - 1] : node._tree.thread; | |
} | |
function d3_layout_treeSearch(node, compare) { | |
var children = node.children; | |
if (children && (n = children.length)) { | |
var child, n, i = -1; | |
while (++i < n) { | |
if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { | |
node = child; | |
} | |
} | |
} | |
return node; | |
} | |
function d3_layout_treeRightmost(a, b) { | |
return a.x - b.x; | |
} | |
function d3_layout_treeLeftmost(a, b) { | |
return b.x - a.x; | |
} | |
function d3_layout_treeDeepest(a, b) { | |
return a.depth - b.depth; | |
} | |
function d3_layout_treeVisitAfter(node, callback) { | |
function visit(node, previousSibling) { | |
var children = node.children; | |
if (children && (n = children.length)) { | |
var child, previousChild = null, i = -1, n; | |
while (++i < n) { | |
child = children[i]; | |
visit(child, previousChild); | |
previousChild = child; | |
} | |
} | |
callback(node, previousSibling); | |
} | |
visit(node, null); | |
} | |
function d3_layout_treeShift(node) { | |
var shift = 0, change = 0, children = node.children, i = children.length, child; | |
while (--i >= 0) { | |
child = children[i]._tree; | |
child.prelim += shift; | |
child.mod += shift; | |
shift += child.shift + (change += child.change); | |
} | |
} | |
function d3_layout_treeMove(ancestor, node, shift) { | |
ancestor = ancestor._tree; | |
node = node._tree; | |
var change = shift / (node.number - ancestor.number); | |
ancestor.change += change; | |
node.change -= change; | |
node.shift += shift; | |
node.prelim += shift; | |
node.mod += shift; | |
} | |
function d3_layout_treeAncestor(vim, node, ancestor) { | |
return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; | |
} | |
d3.layout.pack = function() { | |
var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; | |
function pack(d, i) { | |
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() { | |
return radius; | |
}; | |
root.x = root.y = 0; | |
d3_layout_treeVisitAfter(root, function(d) { | |
d.r = +r(d.value); | |
}); | |
d3_layout_treeVisitAfter(root, d3_layout_packSiblings); | |
if (padding) { | |
var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; | |
d3_layout_treeVisitAfter(root, function(d) { | |
d.r += dr; | |
}); | |
d3_layout_treeVisitAfter(root, d3_layout_packSiblings); | |
d3_layout_treeVisitAfter(root, function(d) { | |
d.r -= dr; | |
}); | |
} | |
d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); | |
return nodes; | |
} | |
pack.size = function(_) { | |
if (!arguments.length) return size; | |
size = _; | |
return pack; | |
}; | |
pack.radius = function(_) { | |
if (!arguments.length) return radius; | |
radius = _ == null || typeof _ === "function" ? _ : +_; | |
return pack; | |
}; | |
pack.padding = function(_) { | |
if (!arguments.length) return padding; | |
padding = +_; | |
return pack; | |
}; | |
return d3_layout_hierarchyRebind(pack, hierarchy); | |
}; | |
function d3_layout_packSort(a, b) { | |
return a.value - b.value; | |
} | |
function d3_layout_packInsert(a, b) { | |
var c = a._pack_next; | |
a._pack_next = b; | |
b._pack_prev = a; | |
b._pack_next = c; | |
c._pack_prev = b; | |
} | |
function d3_layout_packSplice(a, b) { | |
a._pack_next = b; | |
b._pack_prev = a; | |
} | |
function d3_layout_packIntersects(a, b) { | |
var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; | |
return .999 * dr * dr > dx * dx + dy * dy; | |
} | |
function d3_layout_packSiblings(node) { | |
if (!(nodes = node.children) || !(n = nodes.length)) return; | |
var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; | |
function bound(node) { | |
xMin = Math.min(node.x - node.r, xMin); | |
xMax = Math.max(node.x + node.r, xMax); | |
yMin = Math.min(node.y - node.r, yMin); | |
yMax = Math.max(node.y + node.r, yMax); | |
} | |
nodes.forEach(d3_layout_packLink); | |
a = nodes[0]; | |
a.x = -a.r; | |
a.y = 0; | |
bound(a); | |
if (n > 1) { | |
b = nodes[1]; | |
b.x = b.r; | |
b.y = 0; | |
bound(b); | |
if (n > 2) { | |
c = nodes[2]; | |
d3_layout_packPlace(a, b, c); | |
bound(c); | |
d3_layout_packInsert(a, c); | |
a._pack_prev = c; | |
d3_layout_packInsert(c, b); | |
b = a._pack_next; | |
for (i = 3; i < n; i++) { | |
d3_layout_packPlace(a, b, c = nodes[i]); | |
var isect = 0, s1 = 1, s2 = 1; | |
for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { | |
if (d3_layout_packIntersects(j, c)) { | |
isect = 1; | |
break; | |
} | |
} | |
if (isect == 1) { | |
for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { | |
if (d3_layout_packIntersects(k, c)) { | |
break; | |
} | |
} | |
} | |
if (isect) { | |
if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); | |
i--; | |
} else { | |
d3_layout_packInsert(a, c); | |
b = c; | |
bound(c); | |
} | |
} | |
} | |
} | |
var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; | |
for (i = 0; i < n; i++) { | |
c = nodes[i]; | |
c.x -= cx; | |
c.y -= cy; | |
cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); | |
} | |
node.r = cr; | |
nodes.forEach(d3_layout_packUnlink); | |
} | |
function d3_layout_packLink(node) { | |
node._pack_next = node._pack_prev = node; | |
} | |
function d3_layout_packUnlink(node) { | |
delete node._pack_next; | |
delete node._pack_prev; | |
} | |
function d3_layout_packTransform(node, x, y, k) { | |
var children = node.children; | |
node.x = x += k * node.x; | |
node.y = y += k * node.y; | |
node.r *= k; | |
if (children) { | |
var i = -1, n = children.length; | |
while (++i < n) d3_layout_packTransform(children[i], x, y, k); | |
} | |
} | |
function d3_layout_packPlace(a, b, c) { | |
var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; | |
if (db && (dx || dy)) { | |
var da = b.r + c.r, dc = dx * dx + dy * dy; | |
da *= da; | |
db *= db; | |
var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); | |
c.x = a.x + x * dx + y * dy; | |
c.y = a.y + x * dy - y * dx; | |
} else { | |
c.x = a.x + db; | |
c.y = a.y; | |
} | |
} | |
d3.layout.cluster = function() { | |
var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; | |
function cluster(d, i) { | |
var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; | |
d3_layout_treeVisitAfter(root, function(node) { | |
var children = node.children; | |
if (children && children.length) { | |
node.x = d3_layout_clusterX(children); | |
node.y = d3_layout_clusterY(children); | |
} else { | |
node.x = previousNode ? x += separation(node, previousNode) : 0; | |
node.y = 0; | |
previousNode = node; | |
} | |
}); | |
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; | |
d3_layout_treeVisitAfter(root, nodeSize ? function(node) { | |
node.x = (node.x - root.x) * size[0]; | |
node.y = (root.y - node.y) * size[1]; | |
} : function(node) { | |
node.x = (node.x - x0) / (x1 - x0) * size[0]; | |
node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; | |
}); | |
return nodes; | |
} | |
cluster.separation = function(x) { | |
if (!arguments.length) return separation; | |
separation = x; | |
return cluster; | |
}; | |
cluster.size = function(x) { | |
if (!arguments.length) return nodeSize ? null : size; | |
nodeSize = (size = x) == null; | |
return cluster; | |
}; | |
cluster.nodeSize = function(x) { | |
if (!arguments.length) return nodeSize ? size : null; | |
nodeSize = (size = x) != null; | |
return cluster; | |
}; | |
return d3_layout_hierarchyRebind(cluster, hierarchy); | |
}; | |
function d3_layout_clusterY(children) { | |
return 1 + d3.max(children, function(child) { | |
return child.y; | |
}); | |
} | |
function d3_layout_clusterX(children) { | |
return children.reduce(function(x, child) { | |
return x + child.x; | |
}, 0) / children.length; | |
} | |
function d3_layout_clusterLeft(node) { | |
var children = node.children; | |
return children && children.length ? d3_layout_clusterLeft(children[0]) : node; | |
} | |
function d3_layout_clusterRight(node) { | |
var children = node.children, n; | |
return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; | |
} | |
d3.layout.treemap = function() { | |
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)); | |
function scale(children, k) { | |
var i = -1, n = children.length, child, area; | |
while (++i < n) { | |
area = (child = children[i]).value * (k < 0 ? 0 : k); | |
child.area = isNaN(area) || area <= 0 ? 0 : area; | |
} | |
} | |
function squarify(node) { | |
var children = node.children; | |
if (children && children.length) { | |
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; | |
scale(remaining, rect.dx * rect.dy / node.value); | |
row.area = 0; | |
while ((n = remaining.length) > 0) { | |
row.push(child = remaining[n - 1]); | |
row.area += child.area; | |
if (mode !== "squarify" || (score = worst(row, u)) <= best) { | |
remaining.pop(); | |
best = score; | |
} else { | |
row.area -= row.pop().area; | |
position(row, u, rect, false); | |
u = Math.min(rect.dx, rect.dy); | |
row.length = row.area = 0; | |
best = Infinity; | |
} | |
} | |
if (row.length) { | |
position(row, u, rect, true); | |
row.length = row.area = 0; | |
} | |
children.forEach(squarify); | |
} | |
} | |
function stickify(node) { | |
var children = node.children; | |
if (children && children.length) { | |
var rect = pad(node), remaining = children.slice(), child, row = []; | |
scale(remaining, rect.dx * rect.dy / node.value); | |
row.area = 0; | |
while (child = remaining.pop()) { | |
row.push(child); | |
row.area += child.area; | |
if (child.z != null) { | |
position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); | |
row.length = row.area = 0; | |
} | |
} | |
children.forEach(stickify); | |
} | |
} | |
function worst(row, u) { | |
var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; | |
while (++i < n) { | |
if (!(r = row[i].area)) continue; | |
if (r < rmin) rmin = r; | |
if (r > rmax) rmax = r; | |
} | |
s *= s; | |
u *= u; | |
return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; | |
} | |
function position(row, u, rect, flush) { | |
var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; | |
if (u == rect.dx) { | |
if (flush || v > rect.dy) v = rect.dy; | |
while (++i < n) { | |
o = row[i]; | |
o.x = x; | |
o.y = y; | |
o.dy = v; | |
x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); | |
} | |
o.z = true; | |
o.dx += rect.x + rect.dx - x; | |
rect.y += v; | |
rect.dy -= v; | |
} else { | |
if (flush || v > rect.dx) v = rect.dx; | |
while (++i < n) { | |
o = row[i]; | |
o.x = x; | |
o.y = y; | |
o.dx = v; | |
y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); | |
} | |
o.z = false; | |
o.dy += rect.y + rect.dy - y; | |
rect.x += v; | |
rect.dx -= v; | |
} | |
} | |
function treemap(d) { | |
var nodes = stickies || hierarchy(d), root = nodes[0]; | |
root.x = 0; | |
root.y = 0; | |
root.dx = size[0]; | |
root.dy = size[1]; | |
if (stickies) hierarchy.revalue(root); | |
scale([ root ], root.dx * root.dy / root.value); | |
(stickies ? stickify : squarify)(root); | |
if (sticky) stickies = nodes; | |
return nodes; | |
} | |
treemap.size = function(x) { | |
if (!arguments.length) return size; | |
size = x; | |
return treemap; | |
}; | |
treemap.padding = function(x) { | |
if (!arguments.length) return padding; | |
function padFunction(node) { | |
var p = x.call(treemap, node, node.depth); | |
return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); | |
} | |
function padConstant(node) { | |
return d3_layout_treemapPad(node, x); | |
} | |
var type; | |
pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], | |
padConstant) : padConstant; | |
return treemap; | |
}; | |
treemap.round = function(x) { | |
if (!arguments.length) return round != Number; | |
round = x ? Math.round : Number; | |
return treemap; | |
}; | |
treemap.sticky = function(x) { | |
if (!arguments.length) return sticky; | |
sticky = x; | |
stickies = null; | |
return treemap; | |
}; | |
treemap.ratio = function(x) { | |
if (!arguments.length) return ratio; | |
ratio = x; | |
return treemap; | |
}; | |
treemap.mode = function(x) { | |
if (!arguments.length) return mode; | |
mode = x + ""; | |
return treemap; | |
}; | |
return d3_layout_hierarchyRebind(treemap, hierarchy); | |
}; | |
function d3_layout_treemapPadNull(node) { | |
return { | |
x: node.x, | |
y: node.y, | |
dx: node.dx, | |
dy: node.dy | |
}; | |
} | |
function d3_layout_treemapPad(node, padding) { | |
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]; | |
if (dx < 0) { | |
x += dx / 2; | |
dx = 0; | |
} | |
if (dy < 0) { | |
y += dy / 2; | |
dy = 0; | |
} | |
return { | |
x: x, | |
y: y, | |
dx: dx, | |
dy: dy | |
}; | |
} | |
d3.random = { | |
normal: function(µ, σ) { | |
var n = arguments.length; | |
if (n < 2) σ = 1; | |
if (n < 1) µ = 0; | |
return function() { | |
var x, y, r; | |
do { | |
x = Math.random() * 2 - 1; | |
y = Math.random() * 2 - 1; | |
r = x * x + y * y; | |
} while (!r || r > 1); | |
return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); | |
}; | |
}, | |
logNormal: function() { | |
var random = d3.random.normal.apply(d3, arguments); | |
return function() { | |
return Math.exp(random()); | |
}; | |
}, | |
irwinHall: function(m) { | |
return function() { | |
for (var s = 0, j = 0; j < m; j++) s += Math.random(); | |
return s / m; | |
}; | |
} | |
}; | |
d3.scale = {}; | |
function d3_scaleExtent(domain) { | |
var start = domain[0], stop = domain[domain.length - 1]; | |
return start < stop ? [ start, stop ] : [ stop, start ]; | |
} | |
function d3_scaleRange(scale) { | |
return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); | |
} | |
function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { | |
var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); | |
return function(x) { | |
return i(u(x)); | |
}; | |
} | |
function d3_scale_nice(domain, nice) { | |
var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; | |
if (x1 < x0) { | |
dx = i0, i0 = i1, i1 = dx; | |
dx = x0, x0 = x1, x1 = dx; | |
} | |
domain[i0] = nice.floor(x0); | |
domain[i1] = nice.ceil(x1); | |
return domain; | |
} | |
function d3_scale_niceStep(step) { | |
return step ? { | |
floor: function(x) { | |
return Math.floor(x / step) * step; | |
}, | |
ceil: function(x) { | |
return Math.ceil(x / step) * step; | |
} | |
} : d3_scale_niceIdentity; | |
} | |
var d3_scale_niceIdentity = { | |
floor: d3_identity, | |
ceil: d3_identity | |
}; | |
function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { | |
var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; | |
if (domain[k] < domain[0]) { | |
domain = domain.slice().reverse(); | |
range = range.slice().reverse(); | |
} | |
while (++j <= k) { | |
u.push(uninterpolate(domain[j - 1], domain[j])); | |
i.push(interpolate(range[j - 1], range[j])); | |
} | |
return function(x) { | |
var j = d3.bisect(domain, x, 1, k) - 1; | |
return i[j](u[j](x)); | |
}; | |
} | |
d3.scale.linear = function() { | |
return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); | |
}; | |
function d3_scale_linear(domain, range, interpolate, clamp) { | |
var output, input; | |
function rescale() { | |
var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; | |
output = linear(domain, range, uninterpolate, interpolate); | |
input = linear(range, domain, uninterpolate, d3_interpolate); | |
return scale; | |
} | |
function scale(x) { | |
return output(x); | |
} | |
scale.invert = function(y) { | |
return input(y); | |
}; | |
scale.domain = function(x) { | |
if (!arguments.length) return domain; | |
domain = x.map(Number); | |
return rescale(); | |
}; | |
scale.range = function(x) { | |
if (!arguments.length) return range; | |
range = x; | |
return rescale(); | |
}; | |
scale.rangeRound = function(x) { | |
return scale.range(x).interpolate(d3_interpolateRound); | |
}; | |
scale.clamp = function(x) { | |
if (!arguments.length) return clamp; | |
clamp = x; | |
return rescale(); | |
}; | |
scale.interpolate = function(x) { | |
if (!arguments.length) return interpolate; | |
interpolate = x; | |
return rescale(); | |
}; | |
scale.ticks = function(m) { | |
return d3_scale_linearTicks(domain, m); | |
}; | |
scale.tickFormat = function(m, format) { | |
return d3_scale_linearTickFormat(domain, m, format); | |
}; | |
scale.nice = function(m) { | |
d3_scale_linearNice(domain, m); | |
return rescale(); | |
}; | |
scale.copy = function() { | |
return d3_scale_linear(domain, range, interpolate, clamp); | |
}; | |
return rescale(); | |
} | |
function d3_scale_linearRebind(scale, linear) { | |
return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); | |
} | |
function d3_scale_linearNice(domain, m) { | |
return d3_scale_nice(domain, d3_scale_niceStep(m ? d3_scale_linearTickRange(domain, m)[2] : d3_scale_linearNiceStep(domain))); | |
} | |
function d3_scale_linearNiceStep(domain) { | |
var extent = d3_scaleExtent(domain), span = extent[1] - extent[0]; | |
return Math.pow(10, Math.round(Math.log(span) / Math.LN10) - 1); | |
} | |
function d3_scale_linearTickRange(domain, m) { | |
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; | |
if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; | |
extent[0] = Math.ceil(extent[0] / step) * step; | |
extent[1] = Math.floor(extent[1] / step) * step + step * .5; | |
extent[2] = step; | |
return extent; | |
} | |
function d3_scale_linearTicks(domain, m) { | |
return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); | |
} | |
function d3_scale_linearTickFormat(domain, m, format) { | |
var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01); | |
return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { | |
return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join(""); | |
}) : ",." + precision + "f"); | |
} | |
d3.scale.log = function() { | |
return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); | |
}; | |
function d3_scale_log(linear, base, positive, domain) { | |
function log(x) { | |
return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); | |
} | |
function pow(x) { | |
return positive ? Math.pow(base, x) : -Math.pow(base, -x); | |
} | |
function scale(x) { | |
return linear(log(x)); | |
} | |
scale.invert = function(x) { | |
return pow(linear.invert(x)); | |
}; | |
scale.domain = function(x) { | |
if (!arguments.length) return domain; | |
positive = x[0] >= 0; | |
linear.domain((domain = x.map(Number)).map(log)); | |
return scale; | |
}; | |
scale.base = function(_) { | |
if (!arguments.length) return base; | |
base = +_; | |
linear.domain(domain.map(log)); | |
return scale; | |
}; | |
scale.nice = function() { | |
var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); | |
linear.domain(niced); | |
domain = niced.map(pow); | |
return scale; | |
}; | |
scale.ticks = function() { | |
var extent = d3_scaleExtent(domain), ticks = []; | |
if (extent.every(isFinite)) { | |
var u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; | |
if (positive) { | |
for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); | |
ticks.push(pow(i)); | |
} else { | |
ticks.push(pow(i)); | |
for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); | |
} | |
for (i = 0; ticks[i] < u; i++) {} | |
for (j = ticks.length; ticks[j - 1] > v; j--) {} | |
ticks = ticks.slice(i, j); | |
} | |
return ticks; | |
}; | |
scale.tickFormat = function(n, format) { | |
if (!arguments.length) return d3_scale_logFormat; | |
if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); | |
var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, | |
Math.floor), e; | |
return function(d) { | |
return d / pow(f(log(d) + e)) <= k ? format(d) : ""; | |
}; | |
}; | |
scale.copy = function() { | |
return d3_scale_log(linear.copy(), base, positive, domain); | |
}; | |
return d3_scale_linearRebind(scale, linear); | |
} | |
var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { | |
floor: function(x) { | |
return -Math.ceil(-x); | |
}, | |
ceil: function(x) { | |
return -Math.floor(-x); | |
} | |
}; | |
d3.scale.pow = function() { | |
return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); | |
}; | |
function d3_scale_pow(linear, exponent, domain) { | |
var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); | |
function scale(x) { | |
return linear(powp(x)); | |
} | |
scale.invert = function(x) { | |
return powb(linear.invert(x)); | |
}; | |
scale.domain = function(x) { | |
if (!arguments.length) return domain; | |
linear.domain((domain = x.map(Number)).map(powp)); | |
return scale; | |
}; | |
scale.ticks = function(m) { | |
return d3_scale_linearTicks(domain, m); | |
}; | |
scale.tickFormat = function(m, format) { | |
return d3_scale_linearTickFormat(domain, m, format); | |
}; | |
scale.nice = function(m) { | |
return scale.domain(d3_scale_linearNice(domain, m)); | |
}; | |
scale.exponent = function(x) { | |
if (!arguments.length) return exponent; | |
powp = d3_scale_powPow(exponent = x); | |
powb = d3_scale_powPow(1 / exponent); | |
linear.domain(domain.map(powp)); | |
return scale; | |
}; | |
scale.copy = function() { | |
return d3_scale_pow(linear.copy(), exponent, domain); | |
}; | |
return d3_scale_linearRebind(scale, linear); | |
} | |
function d3_scale_powPow(e) { | |
return function(x) { | |
return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); | |
}; | |
} | |
d3.scale.sqrt = function() { | |
return d3.scale.pow().exponent(.5); | |
}; | |
d3.scale.ordinal = function() { | |
return d3_scale_ordinal([], { | |
t: "range", | |
a: [ [] ] | |
}); | |
}; | |
function d3_scale_ordinal(domain, ranger) { | |
var index, range, rangeBand; | |
function scale(x) { | |
return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; | |
} | |
function steps(start, step) { | |
return d3.range(domain.length).map(function(i) { | |
return start + step * i; | |
}); | |
} | |
scale.domain = function(x) { | |
if (!arguments.length) return domain; | |
domain = []; | |
index = new d3_Map(); | |
var i = -1, n = x.length, xi; | |
while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); | |
return scale[ranger.t].apply(scale, ranger.a); | |
}; | |
scale.range = function(x) { | |
if (!arguments.length) return range; | |
range = x; | |
rangeBand = 0; | |
ranger = { | |
t: "range", | |
a: arguments | |
}; | |
return scale; | |
}; | |
scale.rangePoints = function(x, padding) { | |
if (arguments.length < 2) padding = 0; | |
var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); | |
range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); | |
rangeBand = 0; | |
ranger = { | |
t: "rangePoints", | |
a: arguments | |
}; | |
return scale; | |
}; | |
scale.rangeBands = function(x, padding, outerPadding) { | |
if (arguments.length < 2) padding = 0; | |
if (arguments.length < 3) outerPadding = padding; | |
var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); | |
range = steps(start + step * outerPadding, step); | |
if (reverse) range.reverse(); | |
rangeBand = step * (1 - padding); | |
ranger = { | |
t: "rangeBands", | |
a: arguments | |
}; | |
return scale; | |
}; | |
scale.rangeRoundBands = function(x, padding, outerPadding) { | |
if (arguments.length < 2) padding = 0; | |
if (arguments.length < 3) outerPadding = padding; | |
var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; | |
range = steps(start + Math.round(error / 2), step); | |
if (reverse) range.reverse(); | |
rangeBand = Math.round(step * (1 - padding)); | |
ranger = { | |
t: "rangeRoundBands", | |
a: arguments | |
}; | |
return scale; | |
}; | |
scale.rangeBand = function() { | |
return rangeBand; | |
}; | |
scale.rangeExtent = function() { | |
return d3_scaleExtent(ranger.a[0]); | |
}; | |
scale.copy = function() { | |
return d3_scale_ordinal(domain, ranger); | |
}; | |
return scale.domain(domain); | |
} | |
d3.scale.category10 = function() { | |
return d3.scale.ordinal().range(d3_category10); | |
}; | |
d3.scale.category20 = function() { | |
return d3.scale.ordinal().range(d3_category20); | |
}; | |
d3.scale.category20b = function() { | |
return d3.scale.ordinal().range(d3_category20b); | |
}; | |
d3.scale.category20c = function() { | |
return d3.scale.ordinal().range(d3_category20c); | |
}; | |
var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); | |
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); | |
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); | |
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); | |
d3.scale.quantile = function() { | |
return d3_scale_quantile([], []); | |
}; | |
function d3_scale_quantile(domain, range) { | |
var thresholds; | |
function rescale() { | |
var k = 0, q = range.length; | |
thresholds = []; | |
while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); | |
return scale; | |
} | |
function scale(x) { | |
if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; | |
} | |
scale.domain = function(x) { | |
if (!arguments.length) return domain; | |
domain = x.filter(function(d) { | |
return !isNaN(d); | |
}).sort(d3.ascending); | |
return rescale(); | |
}; | |
scale.range = function(x) { | |
if (!arguments.length) return range; | |
range = x; | |
return rescale(); | |
}; | |
scale.quantiles = function() { | |
return thresholds; | |
}; | |
scale.invertExtent = function(y) { | |
y = range.indexOf(y); | |
return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; | |
}; | |
scale.copy = function() { | |
return d3_scale_quantile(domain, range); | |
}; | |
return rescale(); | |
} | |
d3.scale.quantize = function() { | |
return d3_scale_quantize(0, 1, [ 0, 1 ]); | |
}; | |
function d3_scale_quantize(x0, x1, range) { | |
var kx, i; | |
function scale(x) { | |
return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; | |
} | |
function rescale() { | |
kx = range.length / (x1 - x0); | |
i = range.length - 1; | |
return scale; | |
} | |
scale.domain = function(x) { | |
if (!arguments.length) return [ x0, x1 ]; | |
x0 = +x[0]; | |
x1 = +x[x.length - 1]; | |
return rescale(); | |
}; | |
scale.range = function(x) { | |
if (!arguments.length) return range; | |
range = x; | |
return rescale(); | |
}; | |
scale.invertExtent = function(y) { | |
y = range.indexOf(y); | |
y = y < 0 ? NaN : y / kx + x0; | |
return [ y, y + 1 / kx ]; | |
}; | |
scale.copy = function() { | |
return d3_scale_quantize(x0, x1, range); | |
}; | |
return rescale(); | |
} | |
d3.scale.threshold = function() { | |
return d3_scale_threshold([ .5 ], [ 0, 1 ]); | |
}; | |
function d3_scale_threshold(domain, range) { | |
function scale(x) { | |
if (x <= x) return range[d3.bisect(domain, x)]; | |
} | |
scale.domain = function(_) { | |
if (!arguments.length) return domain; | |
domain = _; | |
return scale; | |
}; | |
scale.range = function(_) { | |
if (!arguments.length) return range; | |
range = _; | |
return scale; | |
}; | |
scale.invertExtent = function(y) { | |
y = range.indexOf(y); | |
return [ domain[y - 1], domain[y] ]; | |
}; | |
scale.copy = function() { | |
return d3_scale_threshold(domain, range); | |
}; | |
return scale; | |
} | |
d3.scale.identity = function() { | |
return d3_scale_identity([ 0, 1 ]); | |
}; | |
function d3_scale_identity(domain) { | |
function identity(x) { | |
return +x; | |
} | |
identity.invert = identity; | |
identity.domain = identity.range = function(x) { | |
if (!arguments.length) return domain; | |
domain = x.map(identity); | |
return identity; | |
}; | |
identity.ticks = function(m) { | |
return d3_scale_linearTicks(domain, m); | |
}; | |
identity.tickFormat = function(m, format) { | |
return d3_scale_linearTickFormat(domain, m, format); | |
}; | |
identity.copy = function() { | |
return d3_scale_identity(domain); | |
}; | |
return identity; | |
} | |
d3.svg.arc = function() { | |
var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; | |
function arc() { | |
var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, | |
a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); | |
return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; | |
} | |
arc.innerRadius = function(v) { | |
if (!arguments.length) return innerRadius; | |
innerRadius = d3_functor(v); | |
return arc; | |
}; | |
arc.outerRadius = function(v) { | |
if (!arguments.length) return outerRadius; | |
outerRadius = d3_functor(v); | |
return arc; | |
}; | |
arc.startAngle = function(v) { | |
if (!arguments.length) return startAngle; | |
startAngle = d3_functor(v); | |
return arc; | |
}; | |
arc.endAngle = function(v) { | |
if (!arguments.length) return endAngle; | |
endAngle = d3_functor(v); | |
return arc; | |
}; | |
arc.centroid = function() { | |
var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; | |
return [ Math.cos(a) * r, Math.sin(a) * r ]; | |
}; | |
return arc; | |
}; | |
var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6; | |
function d3_svg_arcInnerRadius(d) { | |
return d.innerRadius; | |
} | |
function d3_svg_arcOuterRadius(d) { | |
return d.outerRadius; | |
} | |
function d3_svg_arcStartAngle(d) { | |
return d.startAngle; | |
} | |
function d3_svg_arcEndAngle(d) { | |
return d.endAngle; | |
} | |
d3.svg.line.radial = function() { | |
var line = d3_svg_line(d3_svg_lineRadial); | |
line.radius = line.x, delete line.x; | |
line.angle = line.y, delete line.y; | |
return line; | |
}; | |
function d3_svg_lineRadial(points) { | |
var point, i = -1, n = points.length, r, a; | |
while (++i < n) { | |
point = points[i]; | |
r = point[0]; | |
a = point[1] + d3_svg_arcOffset; | |
point[0] = r * Math.cos(a); | |
point[1] = r * Math.sin(a); | |
} | |
return points; | |
} | |
function d3_svg_area(projection) { | |
var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; | |
function area(data) { | |
var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { | |
return x; | |
} : d3_functor(x1), fy1 = y0 === y1 ? function() { | |
return y; | |
} : d3_functor(y1), x, y; | |
function segment() { | |
segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); | |
} | |
while (++i < n) { | |
if (defined.call(this, d = data[i], i)) { | |
points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); | |
points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); | |
} else if (points0.length) { | |
segment(); | |
points0 = []; | |
points1 = []; | |
} | |
} | |
if (points0.length) segment(); | |
return segments.length ? segments.join("") : null; | |
} | |
area.x = function(_) { | |
if (!arguments.length) return x1; | |
x0 = x1 = _; | |
return area; | |
}; | |
area.x0 = function(_) { | |
if (!arguments.length) return x0; | |
x0 = _; | |
return area; | |
}; | |
area.x1 = function(_) { | |
if (!arguments.length) return x1; | |
x1 = _; | |
return area; | |
}; | |
area.y = function(_) { | |
if (!arguments.length) return y1; | |
y0 = y1 = _; | |
return area; | |
}; | |
area.y0 = function(_) { | |
if (!arguments.length) return y0; | |
y0 = _; | |
return area; | |
}; | |
area.y1 = function(_) { | |
if (!arguments.length) return y1; | |
y1 = _; | |
return area; | |
}; | |
area.defined = function(_) { | |
if (!arguments.length) return defined; | |
defined = _; | |
return area; | |
}; | |
area.interpolate = function(_) { | |
if (!arguments.length) return interpolateKey; | |
if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; | |
interpolateReverse = interpolate.reverse || interpolate; | |
L = interpolate.closed ? "M" : "L"; | |
return area; | |
}; | |
area.tension = function(_) { | |
if (!arguments.length) return tension; | |
tension = _; | |
return area; | |
}; | |
return area; | |
} | |
d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; | |
d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; | |
d3.svg.area = function() { | |
return d3_svg_area(d3_identity); | |
}; | |
d3.svg.area.radial = function() { | |
var area = d3_svg_area(d3_svg_lineRadial); | |
area.radius = area.x, delete area.x; | |
area.innerRadius = area.x0, delete area.x0; | |
area.outerRadius = area.x1, delete area.x1; | |
area.angle = area.y, delete area.y; | |
area.startAngle = area.y0, delete area.y0; | |
area.endAngle = area.y1, delete area.y1; | |
return area; | |
}; | |
d3.svg.chord = function() { | |
var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; | |
function chord(d, i) { | |
var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); | |
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"; | |
} | |
function subgroup(self, f, d, i) { | |
var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; | |
return { | |
r: r, | |
a0: a0, | |
a1: a1, | |
p0: [ r * Math.cos(a0), r * Math.sin(a0) ], | |
p1: [ r * Math.cos(a1), r * Math.sin(a1) ] | |
}; | |
} | |
function equals(a, b) { | |
return a.a0 == b.a0 && a.a1 == b.a1; | |
} | |
function arc(r, p, a) { | |
return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; | |
} | |
function curve(r0, p0, r1, p1) { | |
return "Q 0,0 " + p1; | |
} | |
chord.radius = function(v) { | |
if (!arguments.length) return radius; | |
radius = d3_functor(v); | |
return chord; | |
}; | |
chord.source = function(v) { | |
if (!arguments.length) return source; | |
source = d3_functor(v); | |
return chord; | |
}; | |
chord.target = function(v) { | |
if (!arguments.length) return target; | |
target = d3_functor(v); | |
return chord; | |
}; | |
chord.startAngle = function(v) { | |
if (!arguments.length) return startAngle; | |
startAngle = d3_functor(v); | |
return chord; | |
}; | |
chord.endAngle = function(v) { | |
if (!arguments.length) return endAngle; | |
endAngle = d3_functor(v); | |
return chord; | |
}; | |
return chord; | |
}; | |
function d3_svg_chordRadius(d) { | |
return d.radius; | |
} | |
d3.svg.diagonal = function() { | |
var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; | |
function diagonal(d, i) { | |
var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { | |
x: p0.x, | |
y: m | |
}, { | |
x: p3.x, | |
y: m | |
}, p3 ]; | |
p = p.map(projection); | |
return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; | |
} | |
diagonal.source = function(x) { | |
if (!arguments.length) return source; | |
source = d3_functor(x); | |
return diagonal; | |
}; | |
diagonal.target = function(x) { | |
if (!arguments.length) return target; | |
target = d3_functor(x); | |
return diagonal; | |
}; | |
diagonal.projection = function(x) { | |
if (!arguments.length) return projection; | |
projection = x; | |
return diagonal; | |
}; | |
return diagonal; | |
}; | |
function d3_svg_diagonalProjection(d) { | |
return [ d.x, d.y ]; | |
} | |
d3.svg.diagonal.radial = function() { | |
var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; | |
diagonal.projection = function(x) { | |
return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; | |
}; | |
return diagonal; | |
}; | |
function d3_svg_diagonalRadialProjection(projection) { | |
return function() { | |
var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; | |
return [ r * Math.cos(a), r * Math.sin(a) ]; | |
}; | |
} | |
d3.svg.symbol = function() { | |
var type = d3_svg_symbolType, size = d3_svg_symbolSize; | |
function symbol(d, i) { | |
return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); | |
} | |
symbol.type = function(x) { | |
if (!arguments.length) return type; | |
type = d3_functor(x); | |
return symbol; | |
}; | |
symbol.size = function(x) { | |
if (!arguments.length) return size; | |
size = d3_functor(x); | |
return symbol; | |
}; | |
return symbol; | |
}; | |
function d3_svg_symbolSize() { | |
return 64; | |
} | |
function d3_svg_symbolType() { | |
return "circle"; | |
} | |
function d3_svg_symbolCircle(size) { | |
var r = Math.sqrt(size / π); | |
return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; | |
} | |
var d3_svg_symbols = d3.map({ | |
circle: d3_svg_symbolCircle, | |
cross: function(size) { | |
var r = Math.sqrt(size / 5) / 2; | |
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"; | |
}, | |
diamond: function(size) { | |
var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; | |
return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; | |
}, | |
square: function(size) { | |
var r = Math.sqrt(size) / 2; | |
return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; | |
}, | |
"triangle-down": function(size) { | |
var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; | |
return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; | |
}, | |
"triangle-up": function(size) { | |
var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; | |
return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; | |
} | |
}); | |
d3.svg.symbolTypes = d3_svg_symbols.keys(); | |
var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); | |
function d3_transition(groups, id) { | |
d3_subclass(groups, d3_transitionPrototype); | |
groups.id = id; | |
return groups; | |
} | |
var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; | |
d3_transitionPrototype.call = d3_selectionPrototype.call; | |
d3_transitionPrototype.empty = d3_selectionPrototype.empty; | |
d3_transitionPrototype.node = d3_selectionPrototype.node; | |
d3_transitionPrototype.size = d3_selectionPrototype.size; | |
d3.transition = function(selection) { | |
return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); | |
}; | |
d3.transition.prototype = d3_transitionPrototype; | |
d3_transitionPrototype.select = function(selector) { | |
var id = this.id, subgroups = [], subgroup, subnode, node; | |
selector = d3_selection_selector(selector); | |
for (var j = -1, m = this.length; ++j < m; ) { | |
subgroups.push(subgroup = []); | |
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { | |
if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { | |
if ("__data__" in node) subnode.__data__ = node.__data__; | |
d3_transitionNode(subnode, i, id, node.__transition__[id]); | |
subgroup.push(subnode); | |
} else { | |
subgroup.push(null); | |
} | |
} | |
} | |
return d3_transition(subgroups, id); | |
}; | |
d3_transitionPrototype.selectAll = function(selector) { | |
var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; | |
selector = d3_selection_selectorAll(selector); | |
for (var j = -1, m = this.length; ++j < m; ) { | |
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { | |
if (node = group[i]) { | |
transition = node.__transition__[id]; | |
subnodes = selector.call(node, node.__data__, i, j); | |
subgroups.push(subgroup = []); | |
for (var k = -1, o = subnodes.length; ++k < o; ) { | |
if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition); | |
subgroup.push(subnode); | |
} | |
} | |
} | |
} | |
return d3_transition(subgroups, id); | |
}; | |
d3_transitionPrototype.filter = function(filter) { | |
var subgroups = [], subgroup, group, node; | |
if (typeof filter !== "function") filter = d3_selection_filter(filter); | |
for (var j = 0, m = this.length; j < m; j++) { | |
subgroups.push(subgroup = []); | |
for (var group = this[j], i = 0, n = group.length; i < n; i++) { | |
if ((node = group[i]) && filter.call(node, node.__data__, i)) { | |
subgroup.push(node); | |
} | |
} | |
} | |
return d3_transition(subgroups, this.id); | |
}; | |
d3_transitionPrototype.tween = function(name, tween) { | |
var id = this.id; | |
if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); | |
return d3_selection_each(this, tween == null ? function(node) { | |
node.__transition__[id].tween.remove(name); | |
} : function(node) { | |
node.__transition__[id].tween.set(name, tween); | |
}); | |
}; | |
function d3_transition_tween(groups, name, value, tween) { | |
var id = groups.id; | |
return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { | |
node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); | |
} : (value = tween(value), function(node) { | |
node.__transition__[id].tween.set(name, value); | |
})); | |
} | |
d3_transitionPrototype.attr = function(nameNS, value) { | |
if (arguments.length < 2) { | |
for (value in nameNS) this.attr(value, nameNS[value]); | |
return this; | |
} | |
var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); | |
function attrNull() { | |
this.removeAttribute(name); | |
} | |
function attrNullNS() { | |
this.removeAttributeNS(name.space, name.local); | |
} | |
function attrTween(b) { | |
return b == null ? attrNull : (b += "", function() { | |
var a = this.getAttribute(name), i; | |
return a !== b && (i = interpolate(a, b), function(t) { | |
this.setAttribute(name, i(t)); | |
}); | |
}); | |
} | |
function attrTweenNS(b) { | |
return b == null ? attrNullNS : (b += "", function() { | |
var a = this.getAttributeNS(name.space, name.local), i; | |
return a !== b && (i = interpolate(a, b), function(t) { | |
this.setAttributeNS(name.space, name.local, i(t)); | |
}); | |
}); | |
} | |
return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); | |
}; | |
d3_transitionPrototype.attrTween = function(nameNS, tween) { | |
var name = d3.ns.qualify(nameNS); | |
function attrTween(d, i) { | |
var f = tween.call(this, d, i, this.getAttribute(name)); | |
return f && function(t) { | |
this.setAttribute(name, f(t)); | |
}; | |
} | |
function attrTweenNS(d, i) { | |
var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); | |
return f && function(t) { | |
this.setAttributeNS(name.space, name.local, f(t)); | |
}; | |
} | |
return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); | |
}; | |
d3_transitionPrototype.style = function(name, value, priority) { | |
var n = arguments.length; | |
if (n < 3) { | |
if (typeof name !== "string") { | |
if (n < 2) value = ""; | |
for (priority in name) this.style(priority, name[priority], value); | |
return this; | |
} | |
priority = ""; | |
} | |
function styleNull() { | |
this.style.removeProperty(name); | |
} | |
function styleString(b) { | |
return b == null ? styleNull : (b += "", function() { | |
var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; | |
return a !== b && (i = d3_interpolate(a, b), function(t) { | |
this.style.setProperty(name, i(t), priority); | |
}); | |
}); | |
} | |
return d3_transition_tween(this, "style." + name, value, styleString); | |
}; | |
d3_transitionPrototype.styleTween = function(name, tween, priority) { | |
if (arguments.length < 3) priority = ""; | |
function styleTween(d, i) { | |
var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); | |
return f && function(t) { | |
this.style.setProperty(name, f(t), priority); | |
}; | |
} | |
return this.tween("style." + name, styleTween); | |
}; | |
d3_transitionPrototype.text = function(value) { | |
return d3_transition_tween(this, "text", value, d3_transition_text); | |
}; | |
function d3_transition_text(b) { | |
if (b == null) b = ""; | |
return function() { | |
this.textContent = b; | |
}; | |
} | |
d3_transitionPrototype.remove = function() { | |
return this.each("end.transition", function() { | |
var p; | |
if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); | |
}); | |
}; | |
d3_transitionPrototype.ease = function(value) { | |
var id = this.id; | |
if (arguments.length < 1) return this.node().__transition__[id].ease; | |
if (typeof value !== "function") value = d3.ease.apply(d3, arguments); | |
return d3_selection_each(this, function(node) { | |
node.__transition__[id].ease = value; | |
}); | |
}; | |
d3_transitionPrototype.delay = function(value) { | |
var id = this.id; | |
return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { | |
node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; | |
} : (value |= 0, function(node) { | |
node.__transition__[id].delay = value; | |
})); | |
}; | |
d3_transitionPrototype.duration = function(value) { | |
var id = this.id; | |
return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { | |
node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); | |
} : (value = Math.max(1, value | 0), function(node) { | |
node.__transition__[id].duration = value; | |
})); | |
}; | |
d3_transitionPrototype.each = function(type, listener) { | |
var id = this.id; | |
if (arguments.length < 2) { | |
var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; | |
d3_transitionInheritId = id; | |
d3_selection_each(this, function(node, i, j) { | |
d3_transitionInherit = node.__transition__[id]; | |
type.call(node, node.__data__, i, j); | |
}); | |
d3_transitionInherit = inherit; | |
d3_transitionInheritId = inheritId; | |
} else { | |
d3_selection_each(this, function(node) { | |
var transition = node.__transition__[id]; | |
(transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener); | |
}); | |
} | |
return this; | |
}; | |
d3_transitionPrototype.transition = function() { | |
var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; | |
for (var j = 0, m = this.length; j < m; j++) { | |
subgroups.push(subgroup = []); | |
for (var group = this[j], i = 0, n = group.length; i < n; i++) { | |
if (node = group[i]) { | |
transition = Object.create(node.__transition__[id0]); | |
transition.delay += transition.duration; | |
d3_transitionNode(node, i, id1, transition); | |
} | |
subgroup.push(node); | |
} | |
} | |
return d3_transition(subgroups, id1); | |
}; | |
function d3_transitionNode(node, i, id, inherit) { | |
var lock = node.__transition__ || (node.__transition__ = { | |
active: 0, | |
count: 0 | |
}), transition = lock[id]; | |
if (!transition) { | |
var time = inherit.time; | |
transition = lock[id] = { | |
tween: new d3_Map(), | |
time: time, | |
ease: inherit.ease, | |
delay: inherit.delay, | |
duration: inherit.duration | |
}; | |
++lock.count; | |
d3.timer(function(elapsed) { | |
var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = []; | |
if (delay <= elapsed) return start(elapsed); | |
d3_timer_replace(start, delay, time); | |
function start(elapsed) { | |
if (lock.active > id) return stop(); | |
lock.active = id; | |
transition.event && transition.event.start.call(node, d, i); | |
transition.tween.forEach(function(key, value) { | |
if (value = value.call(node, d, i)) { | |
tweened.push(value); | |
} | |
}); | |
if (tick(elapsed)) return 1; | |
d3_timer_replace(tick, 0, time); | |
} | |
function tick(elapsed) { | |
if (lock.active !== id) return stop(); | |
var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; | |
while (n > 0) { | |
tweened[--n].call(node, e); | |
} | |
if (t >= 1) { | |
stop(); | |
transition.event && transition.event.end.call(node, d, i); | |
return 1; | |
} | |
} | |
function stop() { | |
if (--lock.count) delete lock[id]; else delete node.__transition__; | |
return 1; | |
} | |
}, 0, time); | |
} | |
} | |
d3.svg.axis = function() { | |
var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; | |
function axis(g) { | |
g.each(function() { | |
var g = d3.select(this); | |
var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; | |
var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); | |
var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; | |
var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), | |
d3.transition(path)); | |
var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; | |
this.__chart__ = scale1; | |
tickEnter.append("line"); | |
tickEnter.append("text"); | |
var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); | |
switch (orient) { | |
case "bottom": | |
{ | |
tickTransform = d3_svg_axisX; | |
subtickEnter.attr("y2", tickMinorSize); | |
subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); | |
lineEnter.attr("y2", tickMajorSize); | |
textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); | |
lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); | |
textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); | |
text.attr("dy", ".71em").style("text-anchor", "middle"); | |
pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); | |
break; | |
} | |
case "top": | |
{ | |
tickTransform = d3_svg_axisX; | |
subtickEnter.attr("y2", -tickMinorSize); | |
subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); | |
lineEnter.attr("y2", -tickMajorSize); | |
textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); | |
lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); | |
textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); | |
text.attr("dy", "0em").style("text-anchor", "middle"); | |
pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); | |
break; | |
} | |
case "left": | |
{ | |
tickTransform = d3_svg_axisY; | |
subtickEnter.attr("x2", -tickMinorSize); | |
subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); | |
lineEnter.attr("x2", -tickMajorSize); | |
textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); | |
lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); | |
textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); | |
text.attr("dy", ".32em").style("text-anchor", "end"); | |
pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); | |
break; | |
} | |
case "right": | |
{ | |
tickTransform = d3_svg_axisY; | |
subtickEnter.attr("x2", tickMinorSize); | |
subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); | |
lineEnter.attr("x2", tickMajorSize); | |
textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); | |
lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); | |
textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); | |
text.attr("dy", ".32em").style("text-anchor", "start"); | |
pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); | |
break; | |
} | |
} | |
if (scale.rangeBand) { | |
var dx = scale1.rangeBand() / 2, x = function(d) { | |
return scale1(d) + dx; | |
}; | |
tickEnter.call(tickTransform, x); | |
tickUpdate.call(tickTransform, x); | |
} else { | |
tickEnter.call(tickTransform, scale0); | |
tickUpdate.call(tickTransform, scale1); | |
tickExit.call(tickTransform, scale1); | |
subtickEnter.call(tickTransform, scale0); | |
subtickUpdate.call(tickTransform, scale1); | |
subtickExit.call(tickTransform, scale1); | |
} | |
}); | |
} | |
axis.scale = function(x) { | |
if (!arguments.length) return scale; | |
scale = x; | |
return axis; | |
}; | |
axis.orient = function(x) { | |
if (!arguments.length) return orient; | |
orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; | |
return axis; | |
}; | |
axis.ticks = function() { | |
if (!arguments.length) return tickArguments_; | |
tickArguments_ = arguments; | |
return axis; | |
}; | |
axis.tickValues = function(x) { | |
if (!arguments.length) return tickValues; | |
tickValues = x; | |
return axis; | |
}; | |
axis.tickFormat = function(x) { | |
if (!arguments.length) return tickFormat_; | |
tickFormat_ = x; | |
return axis; | |
}; | |
axis.tickSize = function(x, y) { | |
if (!arguments.length) return tickMajorSize; | |
var n = arguments.length - 1; | |
tickMajorSize = +x; | |
tickMinorSize = n > 1 ? +y : tickMajorSize; | |
tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; | |
return axis; | |
}; | |
axis.tickPadding = function(x) { | |
if (!arguments.length) return tickPadding; | |
tickPadding = +x; | |
return axis; | |
}; | |
axis.tickSubdivide = function(x) { | |
if (!arguments.length) return tickSubdivide; | |
tickSubdivide = +x; | |
return axis; | |
}; | |
return axis; | |
}; | |
var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { | |
top: 1, | |
right: 1, | |
bottom: 1, | |
left: 1 | |
}; | |
function d3_svg_axisX(selection, x) { | |
selection.attr("transform", function(d) { | |
return "translate(" + x(d) + ",0)"; | |
}); | |
} | |
function d3_svg_axisY(selection, y) { | |
selection.attr("transform", function(d) { | |
return "translate(0," + y(d) + ")"; | |
}); | |
} | |
function d3_svg_axisSubdivide(scale, ticks, m) { | |
subticks = []; | |
if (m && ticks.length > 1) { | |
var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; | |
while (++i < n) { | |
for (j = m; --j > 0; ) { | |
if ((v = +ticks[i] - j * d) >= extent[0]) { | |
subticks.push(v); | |
} | |
} | |
} | |
for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { | |
subticks.push(v); | |
} | |
} | |
return subticks; | |
} | |
d3.svg.brush = function() { | |
var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], clamp = [ true, true ], extentDomain; | |
function brush(g) { | |
g.each(function() { | |
var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; | |
g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); | |
bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); | |
fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); | |
tz.enter().append("g").attr("class", function(d) { | |
return "resize " + d; | |
}).style("cursor", function(d) { | |
return d3_svg_brushCursor[d]; | |
}).append("rect").attr("x", function(d) { | |
return /[ew]$/.test(d) ? -3 : null; | |
}).attr("y", function(d) { | |
return /^[ns]/.test(d) ? -3 : null; | |
}).attr("width", 6).attr("height", 6).style("visibility", "hidden"); | |
tz.style("display", brush.empty() ? "none" : null); | |
tz.exit().remove(); | |
if (x) { | |
e = d3_scaleRange(x); | |
bg.attr("x", e[0]).attr("width", e[1] - e[0]); | |
redrawX(g); | |
} | |
if (y) { | |
e = d3_scaleRange(y); | |
bg.attr("y", e[0]).attr("height", e[1] - e[0]); | |
redrawY(g); | |
} | |
redraw(g); | |
}); | |
} | |
function redraw(g) { | |
g.selectAll(".resize").attr("transform", function(d) { | |
return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; | |
}); | |
} | |
function redrawX(g) { | |
g.select(".extent").attr("x", extent[0][0]); | |
g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); | |
} | |
function redrawY(g) { | |
g.select(".extent").attr("y", extent[0][1]); | |
g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); | |
} | |
function brushstart() { | |
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(), center, origin = mouse(), offset; | |
var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); | |
if (d3.event.changedTouches) { | |
w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); | |
} else { | |
w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); | |
} | |
if (dragging) { | |
origin[0] = extent[0][0] - origin[0]; | |
origin[1] = extent[0][1] - origin[1]; | |
} else if (resizing) { | |
var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); | |
offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; | |
origin[0] = extent[ex][0]; | |
origin[1] = extent[ey][1]; | |
} else if (d3.event.altKey) center = origin.slice(); | |
g.style("pointer-events", "none").selectAll(".resize").style("display", null); | |
d3.select("body").style("cursor", eventTarget.style("cursor")); | |
event_({ | |
type: "brushstart" | |
}); | |
brushmove(); | |
function mouse() { | |
var touches = d3.event.changedTouches; | |
return touches ? d3.touches(target, touches)[0] : d3.mouse(target); | |
} | |
function keydown() { | |
if (d3.event.keyCode == 32) { | |
if (!dragging) { | |
center = null; | |
origin[0] -= extent[1][0]; | |
origin[1] -= extent[1][1]; | |
dragging = 2; | |
} | |
d3_eventPreventDefault(); | |
} | |
} | |
function keyup() { | |
if (d3.event.keyCode == 32 && dragging == 2) { | |
origin[0] += extent[1][0]; | |
origin[1] += extent[1][1]; | |
dragging = 0; | |
d3_eventPreventDefault(); | |
} | |
} | |
function brushmove() { | |
var point = mouse(), moved = false; | |
if (offset) { | |
point[0] += offset[0]; | |
point[1] += offset[1]; | |
} | |
if (!dragging) { | |
if (d3.event.altKey) { | |
if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; | |
origin[0] = extent[+(point[0] < center[0])][0]; | |
origin[1] = extent[+(point[1] < center[1])][1]; | |
} else center = null; | |
} | |
if (resizingX && move1(point, x, 0)) { | |
redrawX(g); | |
moved = true; | |
} | |
if (resizingY && move1(point, y, 1)) { | |
redrawY(g); | |
moved = true; | |
} | |
if (moved) { | |
redraw(g); | |
event_({ | |
type: "brush", | |
mode: dragging ? "move" : "resize" | |
}); | |
} | |
} | |
function move1(point, scale, i) { | |
var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; | |
if (dragging) { | |
r0 -= position; | |
r1 -= size + position; | |
} | |
min = clamp[i] ? Math.max(r0, Math.min(r1, point[i])) : point[i]; | |
if (dragging) { | |
max = (min += position) + size; | |
} else { | |
if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); | |
if (position < min) { | |
max = min; | |
min = position; | |
} else { | |
max = position; | |
} | |
} | |
if (extent[0][i] !== min || extent[1][i] !== max) { | |
extentDomain = null; | |
extent[0][i] = min; | |
extent[1][i] = max; | |
return true; | |
} | |
} | |
function brushend() { | |
brushmove(); | |
g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); | |
d3.select("body").style("cursor", null); | |
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); | |
dragRestore(); | |
event_({ | |
type: "brushend" | |
}); | |
} | |
} | |
brush.x = function(z) { | |
if (!arguments.length) return x; | |
x = z; | |
resizes = d3_svg_brushResizes[!x << 1 | !y]; | |
return brush; | |
}; | |
brush.y = function(z) { | |
if (!arguments.length) return y; | |
y = z; | |
resizes = d3_svg_brushResizes[!x << 1 | !y]; | |
return brush; | |
}; | |
brush.clamp = function(z) { | |
if (!arguments.length) return x && y ? clamp : x || y ? clamp[+!x] : null; | |
if (x && y) clamp = [ !!z[0], !!z[1] ]; else if (x || y) clamp[+!x] = !!z; | |
return brush; | |
}; | |
brush.extent = function(z) { | |
var x0, x1, y0, y1, t; | |
if (!arguments.length) { | |
z = extentDomain || extent; | |
if (x) { | |
x0 = z[0][0], x1 = z[1][0]; | |
if (!extentDomain) { | |
x0 = extent[0][0], x1 = extent[1][0]; | |
if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); | |
if (x1 < x0) t = x0, x0 = x1, x1 = t; | |
} | |
} | |
if (y) { | |
y0 = z[0][1], y1 = z[1][1]; | |
if (!extentDomain) { | |
y0 = extent[0][1], y1 = extent[1][1]; | |
if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); | |
if (y1 < y0) t = y0, y0 = y1, y1 = t; | |
} | |
} | |
return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; | |
} | |
extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; | |
if (x) { | |
x0 = z[0], x1 = z[1]; | |
if (y) x0 = x0[0], x1 = x1[0]; | |
extentDomain[0][0] = x0, extentDomain[1][0] = x1; | |
if (x.invert) x0 = x(x0), x1 = x(x1); | |
if (x1 < x0) t = x0, x0 = x1, x1 = t; | |
extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; | |
} | |
if (y) { | |
y0 = z[0], y1 = z[1]; | |
if (x) y0 = y0[1], y1 = y1[1]; | |
extentDomain[0][1] = y0, extentDomain[1][1] = y1; | |
if (y.invert) y0 = y(y0), y1 = y(y1); | |
if (y1 < y0) t = y0, y0 = y1, y1 = t; | |
extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; | |
} | |
return brush; | |
}; | |
brush.clear = function() { | |
extentDomain = null; | |
extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; | |
return brush; | |
}; | |
brush.empty = function() { | |
return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; | |
}; | |
return d3.rebind(brush, event, "on"); | |
}; | |
var d3_svg_brushCursor = { | |
n: "ns-resize", | |
e: "ew-resize", | |
s: "ns-resize", | |
w: "ew-resize", | |
nw: "nwse-resize", | |
ne: "nesw-resize", | |
se: "nwse-resize", | |
sw: "nesw-resize" | |
}; | |
var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; | |
d3.time = {}; | |
var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; | |
function d3_time_utc() { | |
this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); | |
} | |
d3_time_utc.prototype = { | |
getDate: function() { | |
return this._.getUTCDate(); | |
}, | |
getDay: function() { | |
return this._.getUTCDay(); | |
}, | |
getFullYear: function() { | |
return this._.getUTCFullYear(); | |
}, | |
getHours: function() { | |
return this._.getUTCHours(); | |
}, | |
getMilliseconds: function() { | |
return this._.getUTCMilliseconds(); | |
}, | |
getMinutes: function() { | |
return this._.getUTCMinutes(); | |
}, | |
getMonth: function() { | |
return this._.getUTCMonth(); | |
}, | |
getSeconds: function() { | |
return this._.getUTCSeconds(); | |
}, | |
getTime: function() { | |
return this._.getTime(); | |
}, | |
getTimezoneOffset: function() { | |
return 0; | |
}, | |
valueOf: function() { | |
return this._.valueOf(); | |
}, | |
setDate: function() { | |
d3_time_prototype.setUTCDate.apply(this._, arguments); | |
}, | |
setDay: function() { | |
d3_time_prototype.setUTCDay.apply(this._, arguments); | |
}, | |
setFullYear: function() { | |
d3_time_prototype.setUTCFullYear.apply(this._, arguments); | |
}, | |
setHours: function() { | |
d3_time_prototype.setUTCHours.apply(this._, arguments); | |
}, | |
setMilliseconds: function() { | |
d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); | |
}, | |
setMinutes: function() { | |
d3_time_prototype.setUTCMinutes.apply(this._, arguments); | |
}, | |
setMonth: function() { | |
d3_time_prototype.setUTCMonth.apply(this._, arguments); | |
}, | |
setSeconds: function() { | |
d3_time_prototype.setUTCSeconds.apply(this._, arguments); | |
}, | |
setTime: function() { | |
d3_time_prototype.setTime.apply(this._, arguments); | |
} | |
}; | |
var d3_time_prototype = Date.prototype; | |
var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; | |
var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; | |
function d3_time_interval(local, step, number) { | |
function round(date) { | |
var d0 = local(date), d1 = offset(d0, 1); | |
return date - d0 < d1 - date ? d0 : d1; | |
} | |
function ceil(date) { | |
step(date = local(new d3_time(date - 1)), 1); | |
return date; | |
} | |
function offset(date, k) { | |
step(date = new d3_time(+date), k); | |
return date; | |
} | |
function range(t0, t1, dt) { | |
var time = ceil(t0), times = []; | |
if (dt > 1) { | |
while (time < t1) { | |
if (!(number(time) % dt)) times.push(new Date(+time)); | |
step(time, 1); | |
} | |
} else { | |
while (time < t1) times.push(new Date(+time)), step(time, 1); | |
} | |
return times; | |
} | |
function range_utc(t0, t1, dt) { | |
try { | |
d3_time = d3_time_utc; | |
var utc = new d3_time_utc(); | |
utc._ = t0; | |
return range(utc, t1, dt); | |
} finally { | |
d3_time = Date; | |
} | |
} | |
local.floor = local; | |
local.round = round; | |
local.ceil = ceil; | |
local.offset = offset; | |
local.range = range; | |
var utc = local.utc = d3_time_interval_utc(local); | |
utc.floor = utc; | |
utc.round = d3_time_interval_utc(round); | |
utc.ceil = d3_time_interval_utc(ceil); | |
utc.offset = d3_time_interval_utc(offset); | |
utc.range = range_utc; | |
return local; | |
} | |
function d3_time_interval_utc(method) { | |
return function(date, k) { | |
try { | |
d3_time = d3_time_utc; | |
var utc = new d3_time_utc(); | |
utc._ = date; | |
return method(utc, k)._; | |
} finally { | |
d3_time = Date; | |
} | |
}; | |
} | |
d3.time.year = d3_time_interval(function(date) { | |
date = d3.time.day(date); | |
date.setMonth(0, 1); | |
return date; | |
}, function(date, offset) { | |
date.setFullYear(date.getFullYear() + offset); | |
}, function(date) { | |
return date.getFullYear(); | |
}); | |
d3.time.years = d3.time.year.range; | |
d3.time.years.utc = d3.time.year.utc.range; | |
d3.time.day = d3_time_interval(function(date) { | |
var day = new d3_time(2e3, 0); | |
day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); | |
return day; | |
}, function(date, offset) { | |
date.setDate(date.getDate() + offset); | |
}, function(date) { | |
return date.getDate() - 1; | |
}); | |
d3.time.days = d3.time.day.range; | |
d3.time.days.utc = d3.time.day.utc.range; | |
d3.time.dayOfYear = function(date) { | |
var year = d3.time.year(date); | |
return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); | |
}; | |
d3_time_daySymbols.forEach(function(day, i) { | |
day = day.toLowerCase(); | |
i = 7 - i; | |
var interval = d3.time[day] = d3_time_interval(function(date) { | |
(date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); | |
return date; | |
}, function(date, offset) { | |
date.setDate(date.getDate() + Math.floor(offset) * 7); | |
}, function(date) { | |
var day = d3.time.year(date).getDay(); | |
return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); | |
}); | |
d3.time[day + "s"] = interval.range; | |
d3.time[day + "s"].utc = interval.utc.range; | |
d3.time[day + "OfYear"] = function(date) { | |
var day = d3.time.year(date).getDay(); | |
return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); | |
}; | |
}); | |
d3.time.week = d3.time.sunday; | |
d3.time.weeks = d3.time.sunday.range; | |
d3.time.weeks.utc = d3.time.sunday.utc.range; | |
d3.time.weekOfYear = d3.time.sundayOfYear; | |
d3.time.format = function(template) { | |
var n = template.length; | |
function format(date) { | |
var string = [], i = -1, j = 0, c, p, f; | |
while (++i < n) { | |
if (template.charCodeAt(i) === 37) { | |
string.push(template.substring(j, i)); | |
if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); | |
if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); | |
string.push(c); | |
j = i + 1; | |
} | |
} | |
string.push(template.substring(j, i)); | |
return string.join(""); | |
} | |
format.parse = function(string) { | |
var d = { | |
y: 1900, | |
m: 0, | |
d: 1, | |
H: 0, | |
M: 0, | |
S: 0, | |
L: 0 | |
}, i = d3_time_parse(d, template, string, 0); | |
if (i != string.length) return null; | |
if ("p" in d) d.H = d.H % 12 + d.p * 12; | |
var date = new d3_time(); | |
if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { | |
date.setFullYear(d.y, 0, 1); | |
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); | |
} else date.setFullYear(d.y, d.m, d.d); | |
date.setHours(d.H, d.M, d.S, d.L); | |
return date; | |
}; | |
format.toString = function() { | |
return template; | |
}; | |
return format; | |
}; | |
function d3_time_parse(date, template, string, j) { | |
var c, p, i = 0, n = template.length, m = string.length; | |
while (i < n) { | |
if (j >= m) return -1; | |
c = template.charCodeAt(i++); | |
if (c === 37) { | |
p = d3_time_parsers[template.charAt(i++)]; | |
if (!p || (j = p(date, string, j)) < 0) return -1; | |
} else if (c != string.charCodeAt(j++)) { | |
return -1; | |
} | |
} | |
return j; | |
} | |
function d3_time_formatRe(names) { | |
return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); | |
} | |
function d3_time_formatLookup(names) { | |
var map = new d3_Map(), i = -1, n = names.length; | |
while (++i < n) map.set(names[i].toLowerCase(), i); | |
return map; | |
} | |
function d3_time_formatPad(value, fill, width) { | |
var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; | |
return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); | |
} | |
var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup = d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup = d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/; | |
var d3_time_formatPads = { | |
"-": "", | |
_: " ", | |
"0": "0" | |
}; | |
var d3_time_formats = { | |
a: function(d) { | |
return d3_time_dayAbbreviations[d.getDay()]; | |
}, | |
A: function(d) { | |
return d3_time_days[d.getDay()]; | |
}, | |
b: function(d) { | |
return d3_time_monthAbbreviations[d.getMonth()]; | |
}, | |
B: function(d) { | |
return d3_time_months[d.getMonth()]; | |
}, | |
c: d3.time.format(d3_time_formatDateTime), | |
d: function(d, p) { | |
return d3_time_formatPad(d.getDate(), p, 2); | |
}, | |
e: function(d, p) { | |
return d3_time_formatPad(d.getDate(), p, 2); | |
}, | |
H: function(d, p) { | |
return d3_time_formatPad(d.getHours(), p, 2); | |
}, | |
I: function(d, p) { | |
return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); | |
}, | |
j: function(d, p) { | |
return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3); | |
}, | |
L: function(d, p) { | |
return d3_time_formatPad(d.getMilliseconds(), p, 3); | |
}, | |
m: function(d, p) { | |
return d3_time_formatPad(d.getMonth() + 1, p, 2); | |
}, | |
M: function(d, p) { | |
return d3_time_formatPad(d.getMinutes(), p, 2); | |
}, | |
p: function(d) { | |
return d.getHours() >= 12 ? "PM" : "AM"; | |
}, | |
S: function(d, p) { | |
return d3_time_formatPad(d.getSeconds(), p, 2); | |
}, | |
U: function(d, p) { | |
return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2); | |
}, | |
w: function(d) { | |
return d.getDay(); | |
}, | |
W: function(d, p) { | |
return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2); | |
}, | |
x: d3.time.format(d3_time_formatDate), | |
X: d3.time.format(d3_time_formatTime), | |
y: function(d, p) { | |
return d3_time_formatPad(d.getFullYear() % 100, p, 2); | |
}, | |
Y: function(d, p) { | |
return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); | |
}, | |
Z: d3_time_zone, | |
"%": function() { | |
return "%"; | |
} | |
}; | |
var d3_time_parsers = { | |
a: d3_time_parseWeekdayAbbrev, | |
A: d3_time_parseWeekday, | |
b: d3_time_parseMonthAbbrev, | |
B: d3_time_parseMonth, | |
c: d3_time_parseLocaleFull, | |
d: d3_time_parseDay, | |
e: d3_time_parseDay, | |
H: d3_time_parseHour24, | |
I: d3_time_parseHour24, | |
j: d3_time_parseDayOfYear, | |
L: d3_time_parseMilliseconds, | |
m: d3_time_parseMonthNumber, | |
M: d3_time_parseMinutes, | |
p: d3_time_parseAmPm, | |
S: d3_time_parseSeconds, | |
U: d3_time_parseWeekNumberSunday, | |
w: d3_time_parseWeekdayNumber, | |
W: d3_time_parseWeekNumberMonday, | |
x: d3_time_parseLocaleDate, | |
X: d3_time_parseLocaleTime, | |
y: d3_time_parseYear, | |
Y: d3_time_parseFullYear, | |
"%": d3_time_parseLiteralPercent | |
}; | |
function d3_time_parseWeekdayAbbrev(date, string, i) { | |
d3_time_dayAbbrevRe.lastIndex = 0; | |
var n = d3_time_dayAbbrevRe.exec(string.substring(i)); | |
return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; | |
} | |
function d3_time_parseWeekday(date, string, i) { | |
d3_time_dayRe.lastIndex = 0; | |
var n = d3_time_dayRe.exec(string.substring(i)); | |
return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; | |
} | |
function d3_time_parseWeekdayNumber(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 1)); | |
return n ? (date.w = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseWeekNumberSunday(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i)); | |
return n ? (date.U = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseWeekNumberMonday(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i)); | |
return n ? (date.W = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseMonthAbbrev(date, string, i) { | |
d3_time_monthAbbrevRe.lastIndex = 0; | |
var n = d3_time_monthAbbrevRe.exec(string.substring(i)); | |
return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; | |
} | |
function d3_time_parseMonth(date, string, i) { | |
d3_time_monthRe.lastIndex = 0; | |
var n = d3_time_monthRe.exec(string.substring(i)); | |
return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; | |
} | |
function d3_time_parseLocaleFull(date, string, i) { | |
return d3_time_parse(date, d3_time_formats.c.toString(), string, i); | |
} | |
function d3_time_parseLocaleDate(date, string, i) { | |
return d3_time_parse(date, d3_time_formats.x.toString(), string, i); | |
} | |
function d3_time_parseLocaleTime(date, string, i) { | |
return d3_time_parse(date, d3_time_formats.X.toString(), string, i); | |
} | |
function d3_time_parseFullYear(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 4)); | |
return n ? (date.y = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseYear(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); | |
return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; | |
} | |
function d3_time_expandYear(d) { | |
return d + (d > 68 ? 1900 : 2e3); | |
} | |
function d3_time_parseMonthNumber(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); | |
return n ? (date.m = n[0] - 1, i + n[0].length) : -1; | |
} | |
function d3_time_parseDay(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); | |
return n ? (date.d = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseDayOfYear(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 3)); | |
return n ? (date.j = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseHour24(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); | |
return n ? (date.H = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseMinutes(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); | |
return n ? (date.M = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseSeconds(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); | |
return n ? (date.S = +n[0], i + n[0].length) : -1; | |
} | |
function d3_time_parseMilliseconds(date, string, i) { | |
d3_time_numberRe.lastIndex = 0; | |
var n = d3_time_numberRe.exec(string.substring(i, i + 3)); | |
return n ? (date.L = +n[0], i + n[0].length) : -1; | |
} | |
var d3_time_numberRe = /^\s*\d+/; | |
function d3_time_parseAmPm(date, string, i) { | |
var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); | |
return n == null ? -1 : (date.p = n, i); | |
} | |
var d3_time_amPmLookup = d3.map({ | |
am: 0, | |
pm: 1 | |
}); | |
function d3_time_zone(d) { | |
var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; | |
return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); | |
} | |
function d3_time_parseLiteralPercent(date, string, i) { | |
d3_time_percentRe.lastIndex = 0; | |
var n = d3_time_percentRe.exec(string.substring(i, i + 1)); | |
return n ? i + n[0].length : -1; | |
} | |
d3.time.format.utc = function(template) { | |
var local = d3.time.format(template); | |
function format(date) { | |
try { | |
d3_time = d3_time_utc; | |
var utc = new d3_time(); | |
utc._ = date; | |
return local(utc); | |
} finally { | |
d3_time = Date; | |
} | |
} | |
format.parse = function(string) { | |
try { | |
d3_time = d3_time_utc; | |
var date = local.parse(string); | |
return date && date._; | |
} finally { | |
d3_time = Date; | |
} | |
}; | |
format.toString = local.toString; | |
return format; | |
}; | |
var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); | |
d3.time.format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; | |
function d3_time_formatIsoNative(date) { | |
return date.toISOString(); | |
} | |
d3_time_formatIsoNative.parse = function(string) { | |
var date = new Date(string); | |
return isNaN(date) ? null : date; | |
}; | |
d3_time_formatIsoNative.toString = d3_time_formatIso.toString; | |
d3.time.second = d3_time_interval(function(date) { | |
return new d3_time(Math.floor(date / 1e3) * 1e3); | |
}, function(date, offset) { | |
date.setTime(date.getTime() + Math.floor(offset) * 1e3); | |
}, function(date) { | |
return date.getSeconds(); | |
}); | |
d3.time.seconds = d3.time.second.range; | |
d3.time.seconds.utc = d3.time.second.utc.range; | |
d3.time.minute = d3_time_interval(function(date) { | |
return new d3_time(Math.floor(date / 6e4) * 6e4); | |
}, function(date, offset) { | |
date.setTime(date.getTime() + Math.floor(offset) * 6e4); | |
}, function(date) { | |
return date.getMinutes(); | |
}); | |
d3.time.minutes = d3.time.minute.range; | |
d3.time.minutes.utc = d3.time.minute.utc.range; | |
d3.time.hour = d3_time_interval(function(date) { | |
var timezone = date.getTimezoneOffset() / 60; | |
return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); | |
}, function(date, offset) { | |
date.setTime(date.getTime() + Math.floor(offset) * 36e5); | |
}, function(date) { | |
return date.getHours(); | |
}); | |
d3.time.hours = d3.time.hour.range; | |
d3.time.hours.utc = d3.time.hour.utc.range; | |
d3.time.month = d3_time_interval(function(date) { | |
date = d3.time.day(date); | |
date.setDate(1); | |
return date; | |
}, function(date, offset) { | |
date.setMonth(date.getMonth() + offset); | |
}, function(date) { | |
return date.getMonth(); | |
}); | |
d3.time.months = d3.time.month.range; | |
d3.time.months.utc = d3.time.month.utc.range; | |
function d3_time_scale(linear, methods, format) { | |
function scale(x) { | |
return linear(x); | |
} | |
scale.invert = function(x) { | |
return d3_time_scaleDate(linear.invert(x)); | |
}; | |
scale.domain = function(x) { | |
if (!arguments.length) return linear.domain().map(d3_time_scaleDate); | |
linear.domain(x); | |
return scale; | |
}; | |
scale.nice = function(m) { | |
return scale.domain(d3_scale_nice(scale.domain(), m)); | |
}; | |
scale.ticks = function(m, k) { | |
var extent = d3_scaleExtent(scale.domain()); | |
if (typeof m !== "function") { | |
var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); | |
if (i == d3_time_scaleSteps.length) return methods.year(extent, m); | |
if (!i) return linear.ticks(m).map(d3_time_scaleDate); | |
if (target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target) --i; | |
m = methods[i]; | |
k = m[1]; | |
m = m[0].range; | |
} | |
return m(extent[0], new Date(+extent[1] + 1), k); | |
}; | |
scale.tickFormat = function() { | |
return format; | |
}; | |
scale.copy = function() { | |
return d3_time_scale(linear.copy(), methods, format); | |
}; | |
return d3_scale_linearRebind(scale, linear); | |
} | |
function d3_time_scaleDate(t) { | |
return new Date(t); | |
} | |
function d3_time_scaleFormat(formats) { | |
return function(date) { | |
var i = formats.length - 1, f = formats[i]; | |
while (!f[1](date)) f = formats[--i]; | |
return f[0](date); | |
}; | |
} | |
function d3_time_scaleSetYear(y) { | |
var d = new Date(y, 0, 1); | |
d.setFullYear(y); | |
return d; | |
} | |
function d3_time_scaleGetYear(d) { | |
var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); | |
return y + (d - d0) / (d1 - d0); | |
} | |
var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; | |
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 ] ]; | |
var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) { | |
return d.getMonth(); | |
} ], [ d3.time.format("%b %d"), function(d) { | |
return d.getDate() != 1; | |
} ], [ d3.time.format("%a %d"), function(d) { | |
return d.getDay() && d.getDate() != 1; | |
} ], [ d3.time.format("%I %p"), function(d) { | |
return d.getHours(); | |
} ], [ d3.time.format("%I:%M"), function(d) { | |
return d.getMinutes(); | |
} ], [ d3.time.format(":%S"), function(d) { | |
return d.getSeconds(); | |
} ], [ d3.time.format(".%L"), function(d) { | |
return d.getMilliseconds(); | |
} ] ]; | |
var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); | |
d3_time_scaleLocalMethods.year = function(extent, m) { | |
return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); | |
}; | |
d3.time.scale = function() { | |
return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); | |
}; | |
var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { | |
return [ m[0].utc, m[1] ]; | |
}); | |
var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) { | |
return d.getUTCMonth(); | |
} ], [ d3.time.format.utc("%b %d"), function(d) { | |
return d.getUTCDate() != 1; | |
} ], [ d3.time.format.utc("%a %d"), function(d) { | |
return d.getUTCDay() && d.getUTCDate() != 1; | |
} ], [ d3.time.format.utc("%I %p"), function(d) { | |
return d.getUTCHours(); | |
} ], [ d3.time.format.utc("%I:%M"), function(d) { | |
return d.getUTCMinutes(); | |
} ], [ d3.time.format.utc(":%S"), function(d) { | |
return d.getUTCSeconds(); | |
} ], [ d3.time.format.utc(".%L"), function(d) { | |
return d.getUTCMilliseconds(); | |
} ] ]; | |
var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); | |
function d3_time_scaleUTCSetYear(y) { | |
var d = new Date(Date.UTC(y, 0, 1)); | |
d.setUTCFullYear(y); | |
return d; | |
} | |
function d3_time_scaleUTCGetYear(d) { | |
var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); | |
return y + (d - d0) / (d1 - d0); | |
} | |
d3_time_scaleUTCMethods.year = function(extent, m) { | |
return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); | |
}; | |
d3.time.scale.utc = function() { | |
return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); | |
}; | |
d3.text = d3_xhrType(function(request) { | |
return request.responseText; | |
}); | |
d3.json = function(url, callback) { | |
return d3_xhr(url, "application/json", d3_json, callback); | |
}; | |
function d3_json(request) { | |
return JSON.parse(request.responseText); | |
} | |
d3.html = function(url, callback) { | |
return d3_xhr(url, "text/html", d3_html, callback); | |
}; | |
function d3_html(request) { | |
var range = d3_document.createRange(); | |
range.selectNode(d3_document.body); | |
return range.createContextualFragment(request.responseText); | |
} | |
d3.xml = d3_xhrType(function(request) { | |
return request.responseXML; | |
}); | |
return d3; | |
}(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<title>LDAvis</title> | |
<script src="d3.v3.js"></script> | |
<script src="ldavis.js"></script> | |
<link rel="stylesheet" type="text/css" href="lda.css"> | |
</head> | |
<body> | |
<div id = "lda"></div> | |
<script> | |
var vis = new LDAvis("#lda", "lda.json"); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
path { | |
fill: none; | |
stroke: none; | |
} | |
.xaxis .tick.major { | |
fill: black; | |
stroke: black; | |
stroke-width: 0.1; | |
opacity: 0.7; | |
} | |
.slideraxis { | |
fill: black; | |
stroke: black; | |
stroke-width: 0.4; | |
opacity: 1; | |
} | |
text { | |
font-family: sans-serif; | |
font-size: 11px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"mdsDat": { | |
"x": [ -0.16702, -0.15826, 0.098847, 0.23484, -0.0084093 ], | |
"y": [ 0.13489, -0.14564, 0.15282, -0.069152, -0.072911 ], | |
"topics": [ 1, 2, 3, 4, 5 ], | |
"Freq": [ 22.927, 22.886, 18.632, 18.375, 17.179 ], | |
"cluster": [ 1, 1, 1, 1, 1 ] | |
}, | |
"tinfo": { | |
"Term": [ "staff", "pain", "room", "great", "care", "waiting", "nurse", "insurance", "nurses", "bill", "told", "people", "hospital", "hours", "ER", "patients", "rude", "blood", "dr", "doctor", "worst", "wait", "asked", "place", "minutes", "best", "caring", "professional", "hour", "pay", "desk", "crying", "chair", "wheelchair", "sat", "boyfriend", "restroom", "guard", "seat", "handed", "cup", "vomit", "rolled", "corner", "pointed", "fianc", "pack", "gloves", "asks", "escorted", "pissed", "bathroom", "hall", "didn", "yell", "towel", "daughters", "wearing", "pants", "approached", "ct", "kidney", "mri", "antibiotics", "medications", "cat", "stones", "oxygen", "pills", "morphine", "gallbladder", "anxiety", "disease", "relief", "bp", "uti", "infection", "fluid", "lungs", "clot", "addict", "symptoms", "scans", "dose", "neurologist", "gall", "gi", "abdomen", "cyst", "ruptured", "hate", "slow", "suck", "grandma", "reputation", "disgrace", "disrespect", "bigger", "animal", "heads", "students", "reality", "frankly", "forbid", "train", "survive", "people's", "jail", "urge", "understaffed", "witnessed", "lazy", "slowest", "rudeness", "racist", "mental", "career", "ignore", "sucks", "rights", "friendly", "excellent", "wonderful", "attentive", "compassionate", "efficient", "pleasant", "impressed", "thorough", "fantastic", "grateful", "courteous", "outstanding", "great", "pleased", "kindness", "prompt", "thankful", "awesome", "informative", "maternity", "helpful", "respectful", "responsive", "knowledgeable", "technicians", "appreciated", "housekeeping", "stays", "kudos", "pay", "billing", "bills", "stitches", "billed", "cost", "charged", "payment", "covered", "collections", "provider", "paid", "letter", "collection", "agency", "fracture", "financial", "accept", "incident", "claim", "account", "copay", "mail", "medicare", "payments", "afford", "rip", "outrageous", "balance", "scam", "needle", "lady", "male", "blanket", "scan", "attack", "prescribed", "caused", "stone", "unfriendly", "caring", "amazing", "professional", "notch", "exceptional", "team", "insurance", "bill", "company", "network", "card", "paying", "dollars", "hallway", "tone", "lunch", "nausea", "credit", "girl", "meds", "medication", "ekg", "arrogant", "comfortable", "wheel", "mins", "abdominal", "ignorant", "special", "room", "walked", "midnight", "gown", "severe", "migraine", "rating", "delivered", "charges", "yelling", "heart", "cancer", "patients", "you're", "best", "waited", "front", "pain", "test", "they're", "waiting", "pm", "hour", "nurse", "absolute", "sitting", "stomach", "stroke", "rude", "calls", "minutes", "vitals", "chest", "worst", "people", "star", "unprofessional", "aren't", "icu", "money", "place", "sad", "asked", "door", "dont", "staff", "urgent", "treat", "bed", "finally", "it's", "services", "guy", "tests", "kind", "sit", "woman", "medicine", "shame", "nursing", "joke", "care", "nurses", "department", "left", "hours", "days", "blood", "horrible", "love", "office", "dr", "uncaring", "visit", "patient", "hospital", "sick", "clinic", "pains", "wait", "will", "physician", "doctor", "told", "staff", "good", "diagnosed", "ER", "charge", "broken", "half", "triage", "nice", "received", "security", "experience", "ER", "appointment", "told", "admitted", "amount", "wait", "hours", "life", "day", "called", "hospitals", "medical", "doctors", "terrible", "recommend", "hospital", "surgery", "call", "bad", "clean", "ER", "check", "wrong", "hospital", "doctor", "nurses", "doctors", "better", "ER", "care", "iv", "time", "floor", "care", "dr", "will", "treated", "ER", "service", "blood", "going", "well", "pain", "morning", "waiting", "doctor", "hospital", "time", "called", "husband", "going", "surgery", "admitted", "health", "time", "help", "emergency", "service", "time", "treated", "nurse", "times", "told", "long", "people", "help", "time", "treatment", "family", "will", "family", "emergency", "good", "received", "nurses", "doctors", "minutes", "going", "hospital", "medical", "medical", "going", "will", "i'm", "room", "hours", "day", "place" ], | |
"logprob": [ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -5.2139, -5.947, -6.0272, -6.3465, -5.4186, -6.8583, -6.912, -6.9752, -7.1457, -7.4203, -7.4203, -7.462, -7.5863, -7.5984, -7.6356, -7.6483, -7.6612, -7.6612, -7.6875, -7.6875, -7.8304, -6.1283, -6.6976, -7.9972, -7.9972, -7.9972, -8.0342, -8.0532, -8.0726, -8.1125, -5.2839, -5.4678, -5.899, -5.9805, -6.1933, -6.468, -6.5897, -6.5986, -6.64, -6.6832, -6.698, -6.7232, -6.7917, -6.7972, -6.8537, -6.9136, -5.1817, -6.9905, -7.0039, -7.0107, -7.1258, -5.354, -7.1807, -7.1807, -7.1888, -7.2218, -7.2735, -7.3095, -7.3661, -7.3956, -6.2629, -5.8163, -7.1992, -7.5734, -7.6042, -7.8114, -7.8913, -7.9557, -7.9782, -8.0011, -8.0011, -8.0246, -8.0246, -8.0246, -8.0486, -8.1244, -8.1244, -8.2064, -8.2353, -6.7335, -7.4066, -6.7077, -8.0246, -8.0246, -8.0486, -6.8081, -8.1783, -7.3813, -6.2919, -7.4066, -4.7896, -4.803, -4.9761, -5.6088, -5.87, -5.94, -6.012, -6.0383, -6.0931, -6.2655, -6.3258, -6.3303, -6.3901, -3.7637, -6.6983, -6.7311, -6.7581, -6.7719, -5.6023, -7.097, -7.1564, -5.0652, -7.2639, -7.3844, -6.1473, -7.3973, -7.4236, -7.4925, -7.5068, -7.5665, -4.737, -5.0022, -5.6379, -5.7885, -5.7968, -5.8136, -5.8837, -6.1653, -6.5235, -6.5705, -6.6199, -5.4824, -6.7266, -6.7337, -6.8783, -6.9032, -6.9201, -6.9201, -6.9817, -6.9909, -7.067, -7.087, -7.1282, -7.1712, -7.2393, -7.2999, -7.3511, -7.3511, -7.3777, -7.3777, -6.8818, -5.4395, -6.4765, -6.7747, -5.174, -5.4988, -6.1814, -6.5001, -6.2054, -7.4592, -4.693, -5.0576, -4.664, -6.6983, -6.7113, -5.5236, -3.9792, -4.1414, -5.7116, -6.2755, -6.5235, -6.1298, -6.3694, -6.0348, -7.4203, -7.4944, -6.4369, -6.4515, -6.5987, -5.0235, -5.1579, -6.3077, -7.1685, -5.5519, -6.6926, -6.2824, -6.0101, -7.5584, -6.7929, -3.4133, -5.2764, -7.1852, -7.1933, -4.9455, -6.7755, -6.366, -6.8072, -6.5064, -7.2097, -4.7946, -6.4369, -4.1385, -5.5203, -4.5676, -4.6674, -5.3241, -3.2446, -5.0605, -6.219, -3.8556, -5.0593, -4.4667, -3.4662, -6.6224, -5.4724, -5.7193, -6.0303, -4.3398, -6.1221, -4.4635, -6.1396, -5.2343, -4.3506, -3.8365, -5.5619, -5.631, -6.8011, -5.598, -5.2246, -4.2536, -6.4076, -4.3074, -5.7485, -5.881, -3.2222, -5.3858, -5.2952, -5.1445, -4.7304, -4.7222, -5.4407, -6.1255, -5.1871, -4.9749, -5.7523, -5.9826, -5.6198, -6.727, -5.4161, -5.8508, -3.3489, -3.7765, -5.4525, -4.5418, -3.7897, -4.6932, -4.482, -4.8924, -5.7786, -5.7427, -4.2144, -6.727, -4.6217, -4.553, -3.2492, -5.3609, -5.8023, -5.9661, -4.356, -4.1617, -5.3785, -3.7614, -3.997, -3.8362, -4.4119, -5.8361, -2.9469, -5.6076, -5.5409, -5.5862, -5.4915, -4.9082, -4.8862, -5.8814, -4.3272, -2.8704, -5.9145, -4.1496, -4.7275, -5.9462, -4.4997, -4.1547, -5.1103, -4.8058, -4.8746, -5.4437, -4.5522, -4.6571, -5.4729, -5.1658, -3.5272, -5.0499, -4.8468, -5.0087, -5.5, -3.266, -5.3755, -5.2742, -3.6395, -4.0329, -4.5118, -4.5562, -5.0786, -3.6353, -4.2422, -5.4031, -4.4302, -5.2143, -4.1721, -4.5397, -4.4924, -4.9846, -3.8108, -5.0135, -4.9789, -4.8272, -4.7972, -4.4731, -5.6063, -4.7179, -4.4504, -4.1983, -4.6112, -4.9947, -5.2671, -4.9561, -5.0245, -5.2389, -5.3286, -4.5081, -5.1187, -5.1551, -5.1431, -4.7341, -4.968, -4.8692, -5.0124, -4.8234, -5.212, -5.0151, -5.1065, -5.0004, -5.3444, -5.1969, -5.1111, -5.2336, -5.3658, -5.1233, -5.2455, -5.1095, -5.2761, -5.3604, -5.2494, -5.0554, -5.1588, -5.1619, -5.4253, -5.2458, -5.3203, -5.1312, -5.3475, -5.4604, -5.4663 ], | |
"loglift": [ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1.4724, 1.4719, 1.4718, 1.4714, 1.4709, 1.4705, 1.4703, 1.4702, 1.4697, 1.4687, 1.4687, 1.4685, 1.4679, 1.4679, 1.4677, 1.4676, 1.4675, 1.4675, 1.4674, 1.4674, 1.4665, 1.4659, 1.4659, 1.4654, 1.4654, 1.4654, 1.4651, 1.465, 1.4648, 1.4645, 1.4741, 1.474, 1.4737, 1.4736, 1.4734, 1.473, 1.4728, 1.4728, 1.4727, 1.4726, 1.4726, 1.4725, 1.4724, 1.4724, 1.4722, 1.4721, 1.472, 1.4719, 1.4719, 1.4718, 1.4715, 1.4715, 1.4713, 1.4713, 1.4713, 1.4712, 1.471, 1.4709, 1.4707, 1.4705, 1.6787, 1.6767, 1.6762, 1.6743, 1.6741, 1.6727, 1.6721, 1.6716, 1.6714, 1.6712, 1.6712, 1.671, 1.671, 1.671, 1.6707, 1.67, 1.67, 1.6691, 1.6688, 1.6652, 1.6625, 1.6535, 1.6484, 1.6477, 1.6467, 1.6435, 1.6422, 1.64, 1.6382, 1.6377, 1.6938, 1.6938, 1.6937, 1.6933, 1.6931, 1.693, 1.6929, 1.6929, 1.6928, 1.6925, 1.6924, 1.6924, 1.6923, 1.692, 1.6916, 1.6916, 1.6915, 1.6914, 1.6912, 1.6904, 1.6902, 1.69, 1.6897, 1.6892, 1.6891, 1.6891, 1.689, 1.6886, 1.6885, 1.6882, 1.7611, 1.761, 1.7606, 1.7604, 1.7604, 1.7604, 1.7603, 1.7599, 1.7592, 1.7591, 1.759, 1.7587, 1.7587, 1.7587, 1.7583, 1.7582, 1.7581, 1.7581, 1.7579, 1.7579, 1.7576, 1.7575, 1.7574, 1.7572, 1.7569, 1.7566, 1.7563, 1.7563, 1.7562, 1.7562, 1.4582, 1.4422, 1.4514, 1.4544, 1.4699, 1.4665, 1.4704, 1.4689, 1.4643, 1.6359, 1.6872, 1.6829, 1.6708, 1.6855, 1.6854, 1.6719, 1.7552, 1.756, 1.7531, 1.7552, 1.7537, 1.7487, 1.7498, 1.4432, 1.4582, 1.4571, 1.4579, 1.7488, 1.4298, 1.4146, 1.4184, 1.4532, 1.6276, 1.6442, 1.4306, 1.4093, 1.4321, 1.6323, 1.6779, 1.2625, 1.3596, 1.4449, 1.4445, 1.38, 1.4618, 1.568, 1.6777, 1.7271, 1.4443, 1.3575, 1.442, 1.4428, 1.5196, 1.5414, 1.2596, 1.3056, 1.2174, 1.3427, 1.5338, 1.1778, 1.2675, 1.2129, 1.1239, 1.547, 1.2788, 1.3747, 1.4025, 1.3238, 1.6746, 1.1721, 1.3397, 1.3233, 1.2975, 1.235, 1.4227, 1.4159, 1.5389, 1.5461, 1.5795, 1.2255, 1.4916, 1.094, 1.2864, 1.4012, 1.2337, 1.5583, 1.3131, 1.1838, 1.1134, 1.1969, 1.5246, 1.3346, 1.2204, 1.4003, 1.2678, 1.304, 1.2785, 1.5034, 1.444, 1.3327, 1.0194, 1.098, 1.4651, 1.0025, 0.8331, 1.0685, 0.9986, 1.0558, 1.4806, 1.498, 0.9172, 1.4744, 1.2127, 0.9244, 0.5673, 1.1124, 1.5022, 1.3113, 0.8224, 0.7393, 1.3711, 0.645, 0.6914, 0.6197, 1.0598, 1.2716, 0.3269, 1.4388, 1.4132, 1.1508, 1.1157, 1.1807, 1.1754, 1.2479, 0.9581, 0.4033, 1.5244, 0.5388, 1.0889, 1.529, 0.6787, 0.4681, 0.8914, 0.7692, 0.7686, 1.0298, 0.8253, 0.6149, 1.0215, 1.1919, 0.2893, 0.8328, 0.9177, 0.7531, 1.3588, 0.0078, 0.9405, 0.8886, 0.177, 0.3734, 0.3627, 0.7159, 0.7383, -0.3616, 0.1261, 0.8829, 0.2184, 1.1309, 0.1962, 0.5919, 0.4086, 0.6088, -0.5371, 0.7835, 0.5017, 0.4583, 0.7262, -0.0111, 1.0299, 0.3155, -0.044, -0.3818, 0.0375, 0.6485, 0.6416, 0.3293, 0.8583, 0.5774, 0.9793, 0.1405, 0.4575, 0.6871, 0.6539, -0.0855, 0.6253, -0.2792, 0.6482, -0.135, 0.7148, 0.0565, 0.4697, -0.3518, 0.6325, 0.7785, -0.2101, 0.7418, 0.4765, 0.3484, 0.8161, -0.2351, -0.0041, 0.2752, 0.0361, -1.2389, 0.2187, 0.2156, -0.1398, -0.3448, 0.3145, -0.4554, -0.7247, 0.1146, 0.0127 ], | |
"Freq": [ 6553, 6512, 5259, 2411, 7153, 3678, 5730, 1824, 4311, 1550, 5193, 3540, 12420, 5546, 21372, 2126, 1958, 2351, 3334, 6886, 1989, 3181, 2545, 2355, 2014, 1254, 956, 1001, 1927, 850, 704.06, 338.24, 312.17, 226.84, 573.69, 135.98, 128.87, 120.96, 102, 77.509, 77.509, 74.348, 65.657, 64.867, 62.497, 61.707, 60.917, 60.917, 59.336, 59.336, 51.435, 282.14, 159.68, 43.534, 43.534, 43.534, 41.954, 41.164, 40.374, 38.794, 655.31, 545.18, 354.24, 326.51, 263.92, 200.53, 177.55, 175.97, 168.84, 161.71, 159.33, 155.37, 145.07, 144.28, 136.36, 128.43, 725.83, 118.92, 117.34, 116.55, 103.87, 610.94, 98.325, 98.325, 97.532, 94.363, 89.609, 86.44, 81.686, 79.309, 200.41, 313.25, 78.578, 54.048, 52.413, 42.601, 39.33, 36.877, 36.059, 35.241, 35.241, 34.424, 34.424, 34.424, 33.606, 31.153, 31.153, 28.7, 27.882, 125.18, 63.86, 128.46, 34.424, 34.424, 33.606, 116.19, 29.518, 65.495, 194.69, 63.86, 862.53, 850.99, 715.77, 380.19, 292.79, 273, 254.04, 247.44, 234.25, 197.14, 185.6, 184.78, 174.06, 2406, 127.88, 123.76, 120.46, 118.81, 382.66, 85.833, 80.886, 654.75, 72.641, 64.395, 221.88, 63.571, 61.922, 57.799, 56.975, 53.676, 849.87, 651.94, 345.23, 296.97, 294.52, 289.61, 269.98, 203.74, 142.39, 135.85, 129.31, 403.3, 116.22, 115.4, 99.864, 97.41, 95.774, 95.774, 90.049, 89.231, 82.688, 81.052, 77.781, 74.509, 69.602, 65.513, 62.241, 62.241, 60.605, 60.605, 132.82, 561.84, 199.18, 147.83, 731.37, 528.54, 267.08, 194.19, 260.75, 60.589, 949.93, 659.7, 977.97, 127.88, 126.23, 413.99, 1813.3, 1541.8, 320.69, 182.47, 142.39, 211.1, 166.11, 309.8, 77.509, 71.978, 206.87, 153.03, 176.27, 850.22, 743.26, 235.39, 81.031, 402.45, 160.47, 241.85, 317, 54.866, 116.34, 4261.9, 661.39, 98.051, 97.261, 919.15, 147.45, 180.79, 114.69, 144.85, 95.681, 1068.9, 206.87, 1677.1, 421.18, 1076.9, 1216, 630.58, 5035.9, 819.32, 209.4, 2738.6, 821.78, 1486.3, 4042.2, 139.9, 543.67, 423.96, 310.66, 1371.3, 212.73, 1491, 278.98, 688.59, 1356.6, 2268.3, 404.01, 377.03, 117.01, 384.31, 521.89, 1494.8, 173.43, 1743, 412.51, 293.62, 4135.1, 444.19, 527.48, 754.62, 1141.8, 935.49, 420.48, 282.93, 721.87, 716.59, 410.93, 326.39, 468.33, 126, 460.99, 302.62, 3642.8, 2375.5, 415.57, 1378.8, 2925, 1183, 1461.1, 789.13, 320.82, 310.88, 1909.5, 126, 953.74, 1108, 4081.1, 493.95, 292.88, 331.26, 1349.2, 1638.7, 447.47, 3003.7, 2373, 2269.1, 1258.3, 377.21, 5521.8, 355.86, 380.4, 485.2, 533.4, 766.07, 732.09, 361.15, 1369.6, 5878.1, 261.81, 2040.9, 917.78, 253.63, 1438.1, 1650.1, 634.59, 1057, 988.49, 454.71, 1022.4, 998.45, 441.62, 592.09, 2849.6, 828.03, 761.53, 702.46, 423.89, 3700.2, 598.97, 661.65, 2724.3, 1718.5, 1154.6, 1089.3, 655.03, 3413.3, 1512, 581.63, 1252.7, 564.06, 1495.2, 1107.4, 1085.4, 719.63, 2858.7, 644.58, 890.52, 842.28, 855.94, 1476.8, 474.67, 939.58, 1510.7, 1940.4, 1286.4, 656.84, 666.4, 911.06, 681.96, 685.42, 470.37, 1142.9, 774.38, 606.79, 614.15, 852.32, 721.54, 992.04, 690.21, 779.53, 573.27, 858.92, 637.05, 870.03, 463.01, 573.95, 778.91, 561, 453.19, 626.42, 546.74, 781.49, 495.72, 455.64, 678.29, 824.94, 596.21, 602.7, 427.02, 681.93, 632.95, 621.51, 614.91, 412.3, 409.84 ], | |
"Total": [ 6553, 6512, 5259, 2411, 7153, 3678, 5730, 1824, 4311, 1550, 5193, 3540, 12420, 5546, 21372, 2126, 1958, 2351, 3334, 6886, 1989, 3181, 2545, 2355, 2014, 1254, 956, 1001, 1927, 850, 704.38, 338.57, 312.49, 227.16, 574.83, 136.3, 129.19, 121.29, 102.33, 77.834, 77.834, 74.674, 65.982, 65.192, 62.822, 62.032, 61.242, 61.242, 59.662, 59.662, 51.761, 284.11, 160.8, 43.86, 43.86, 43.86, 42.28, 41.489, 40.699, 39.119, 655.64, 545.51, 354.56, 326.83, 264.24, 200.86, 177.88, 176.3, 169.16, 162.03, 159.66, 155.7, 145.4, 144.6, 136.68, 128.76, 727.73, 119.25, 117.66, 116.87, 104.2, 612.88, 98.65, 98.65, 97.857, 94.688, 89.934, 86.765, 82.011, 79.634, 200.73, 314.36, 78.9, 54.37, 52.735, 42.923, 39.652, 37.199, 36.382, 35.564, 35.564, 34.746, 34.746, 34.746, 33.929, 31.476, 31.476, 29.023, 28.205, 127.09, 65.007, 131.94, 35.539, 35.564, 34.753, 120.55, 30.665, 68.19, 203.05, 66.636, 862.86, 851.31, 716.09, 380.51, 293.11, 273.32, 254.36, 247.76, 234.57, 197.47, 185.92, 185.1, 174.38, 2411.3, 128.21, 124.08, 120.78, 119.14, 383.78, 86.155, 81.208, 657.48, 72.962, 64.717, 222.99, 63.893, 62.244, 58.121, 57.296, 53.998, 850.19, 652.26, 345.55, 297.3, 294.84, 289.94, 270.31, 204.06, 142.72, 136.17, 129.63, 404.41, 116.54, 115.73, 100.19, 97.733, 96.097, 96.097, 90.372, 89.554, 83.011, 81.375, 78.103, 74.832, 69.925, 65.835, 62.564, 62.564, 60.928, 60.928, 134.78, 579.34, 203.5, 150.59, 734.86, 532.88, 268.23, 195.31, 263.44, 63.338, 956.58, 667.19, 1001, 129, 127.35, 423.31, 1824.7, 1550.3, 323.39, 183.62, 143.51, 213.82, 168.07, 319.12, 78.652, 73.121, 210.36, 154.98, 184.02, 902.83, 786.25, 240.49, 85.417, 423.06, 167.39, 257.72, 330.78, 57.563, 118.25, 5259.6, 740.7, 100.83, 100.06, 1010.3, 149.35, 202.28, 116.59, 149.91, 98.448, 1201.7, 213.74, 2126.6, 494.62, 1254.6, 1505, 745.38, 6513, 934.91, 242.44, 3678.4, 1009.1, 1927.4, 5730.4, 159.85, 660.1, 468.53, 333.9, 1958.7, 232.05, 2014.2, 318.71, 801.11, 1989.2, 3540.5, 522.69, 491.12, 134.78, 445.64, 626.06, 2355.6, 209.45, 2545.8, 497.06, 388.16, 6553.2, 544.27, 761.51, 1007.6, 1635.7, 1516.9, 532.87, 324.88, 930.78, 961.35, 504.47, 386.41, 569.81, 150.38, 592.04, 428.42, 7153.2, 4311.8, 558.95, 2206.8, 5546, 1775.6, 2351.9, 1473.5, 397.19, 404.59, 3334.4, 154.81, 1651.1, 2359.6, 12420, 871.55, 379.56, 390.05, 3181.8, 4199.1, 661.14, 6886, 5193.6, 6553.2, 2372.9, 462.11, 21372, 491.38, 538.87, 669.54, 762.33, 1280.2, 1315.5, 452.24, 2859.2, 21372, 331.85, 5193.6, 1681.1, 320.02, 3181.8, 5546, 1396.7, 2140.1, 1999, 871.39, 2607.4, 2897.4, 853.4, 978.44, 12420, 1573.2, 1770.6, 1775.3, 592.79, 21372, 1020, 1188.8, 12420, 6886, 4311.8, 2897.4, 1680.3, 21372, 7153.2, 1051, 5404.3, 990.71, 7153.2, 3334.4, 4199.1, 2101.1, 21372, 1714.1, 2351.9, 2858.7, 2253.2, 6513, 740.54, 3678.4, 6886, 12420, 5404.3, 1999, 1532.9, 2858.7, 1573.2, 1681.1, 1028.3, 5404.3, 2137.6, 1638.2, 1714.1, 5404.3, 2101.1, 5730.4, 1964.3, 5193.6, 1505.4, 3540.5, 2137.6, 5404.3, 1431.9, 1434, 4199.1, 1434, 1638.2, 2372.9, 1315.5, 4311.8, 2897.4, 2014.2, 2858.7, 12420, 2607.4, 2607.4, 2858.7, 4199.1, 2015.7, 5259.6, 5546, 2140.1, 2355.6 ], | |
"Category": [ "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Default", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic1", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic1", "Topic1", "Topic1", "Topic1", "Topic2", "Topic2", "Topic2", "Topic2", "Topic2", "Topic3", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic4", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic5", "Topic1", "Topic1", "Topic1", "Topic2", "Topic5", "Topic1", "Topic2", "Topic2", "Topic2", "Topic3", "Topic4", "Topic1", "Topic1", "Topic2", "Topic3", "Topic4", "Topic1", "Topic1", "Topic1", "Topic1", "Topic2", "Topic2", "Topic3", "Topic4", "Topic5", "Topic1", "Topic2", "Topic2", "Topic3", "Topic3", "Topic4", "Topic1", "Topic1", "Topic2", "Topic2", "Topic3", "Topic1", "Topic1", "Topic1", "Topic1", "Topic3", "Topic1", "Topic2", "Topic2", "Topic3", "Topic5", "Topic1", "Topic1", "Topic2", "Topic3", "Topic3", "Topic3", "Topic3", "Topic3", "Topic4", "Topic5", "Topic3", "Topic3", "Topic1", "Topic1", "Topic3", "Topic4", "Topic5", "Topic3", "Topic1", "Topic1", "Topic3", "Topic5", "Topic1", "Topic2", "Topic4", "Topic1", "Topic1", "Topic2", "Topic3", "Topic4", "Topic3", "Topic4", "Topic4", "Topic5", "Topic1", "Topic1", "Topic2", "Topic2", "Topic3", "Topic4", "Topic5", "Topic2", "Topic3", "Topic5", "Topic3", "Topic3", "Topic3", "Topic5", "Topic2", "Topic3", "Topic3", "Topic5", "Topic2", "Topic2", "Topic3", "Topic4", "Topic2", "Topic3", "Topic5", "Topic5", "Topic1", "Topic1", "Topic4", "Topic5", "Topic1", "Topic4", "Topic4", "Topic5", "Topic1", "Topic4", "Topic5", "Topic1", "Topic3", "Topic3", "Topic2", "Topic1", "Topic3", "Topic5", "Topic3", "Topic3", "Topic4", "Topic5", "Topic2", "Topic5", "Topic3", "Topic4", "Topic5", "Topic1", "Topic2", "Topic4", "Topic5", "Topic3", "Topic4", "Topic3", "Topic1", "Topic3", "Topic2", "Topic3", "Topic4", "Topic5", "Topic4", "Topic5", "Topic3", "Topic2", "Topic5", "Topic1", "Topic3", "Topic4", "Topic1", "Topic2", "Topic3", "Topic1", "Topic2", "Topic1", "Topic5", "Topic2", "Topic1", "Topic4", "Topic2", "Topic5", "Topic4", "Topic1", "Topic3", "Topic3", "Topic5", "Topic4", "Topic2", "Topic4", "Topic5", "Topic3", "Topic1", "Topic3", "Topic2", "Topic5", "Topic4", "Topic2", "Topic3", "Topic5", "Topic3", "Topic4", "Topic1", "Topic5", "Topic5", "Topic2", "Topic1", "Topic4", "Topic3", "Topic5", "Topic1", "Topic1", "Topic3", "Topic2", "Topic5", "Topic5" ] | |
}, | |
"token.table": { | |
"Term": [ "abdomen", "abdominal", "abdominal", "abdominal", "absolute", "absolute", "accept", "account", "addict", "admitted", "admitted", "admitted", "afford", "agency", "amazing", "amazing", "amazing", "amount", "amount", "amount", "animal", "antibiotics", "anxiety", "appointment", "appointment", "appreciated", "approached", "aren't", "aren't", "aren't", "arrogant", "arrogant", "arrogant", "asked", "asked", "asked", "asks", "attack", "attack", "attack", "attentive", "awesome", "awesome", "bad", "bad", "bad", "bad", "bad", "balance", "bathroom", "bathroom", "bed", "bed", "bed", "bed", "best", "best", "best", "better", "better", "better", "better", "better", "bigger", "bill", "bill", "billed", "billing", "bills", "blanket", "blanket", "blanket", "blanket", "blood", "blood", "boyfriend", "bp", "broken", "broken", "broken", "call", "call", "call", "call", "called", "called", "called", "called", "calls", "calls", "calls", "cancer", "cancer", "card", "card", "care", "care", "care", "care", "career", "career", "caring", "caring", "caring", "cat", "caused", "caused", "chair", "charge", "charge", "charge", "charged", "charges", "charges", "check", "check", "check", "check", "check", "chest", "chest", "claim", "clean", "clean", "clean", "clinic", "clinic", "clinic", "clot", "collection", "collections", "comfortable", "comfortable", "comfortable", "comfortable", "company", "company", "compassionate", "copay", "corner", "cost", "courteous", "covered", "credit", "credit", "crying", "ct", "cup", "cyst", "daughters", "day", "day", "day", "day", "day", "days", "days", "days", "delivered", "delivered", "department", "department", "department", "desk", "diagnosed", "diagnosed", "diagnosed", "diagnosed", "didn", "disease", "disgrace", "disrespect", "doctor", "doctor", "doctor", "doctor", "doctor", "doctors", "doctors", "doctors", "doctors", "dollars", "dollars", "dont", "dont", "dont", "door", "door", "door", "dose", "dr", "dr", "dr", "dr", "efficient", "ekg", "ekg", "ekg", "emergency", "emergency", "emergency", "emergency", "ER", "ER", "ER", "ER", "ER", "escorted", "excellent", "exceptional", "exceptional", "experience", "experience", "experience", "experience", "experience", "family", "family", "family", "family", "family", "fantastic", "fianc", "finally", "finally", "finally", "financial", "floor", "floor", "floor", "fluid", "forbid", "fracture", "frankly", "friendly", "front", "front", "front", "gall", "gallbladder", "gi", "girl", "girl", "gloves", "going", "going", "going", "going", "good", "good", "good", "good", "good", "gown", "gown", "grandma", "grateful", "great", "great", "guard", "guy", "guy", "guy", "half", "half", "half", "half", "hall", "hall", "hallway", "hallway", "handed", "hate", "heads", "health", "health", "health", "health", "heart", "heart", "help", "help", "help", "help", "helpful", "helpful", "helpful", "horrible", "horrible", "horrible", "horrible", "hospital", "hospital", "hospital", "hospital", "hospital", "hospitals", "hospitals", "hospitals", "hospitals", "hour", "hour", "hour", "hours", "hours", "hours", "hours", "housekeeping", "husband", "husband", "husband", "i'm", "i'm", "i'm", "i'm", "i'm", "icu", "icu", "ignorant", "ignorant", "ignorant", "ignore", "ignore", "ignore", "impressed", "incident", "infection", "infection", "informative", "insurance", "insurance", "it's", "it's", "it's", "it's", "iv", "iv", "iv", "jail", "joke", "joke", "joke", "kidney", "kind", "kind", "kind", "kindness", "knowledgeable", "knowledgeable", "kudos", "lady", "lady", "lazy", "lazy", "left", "left", "left", "letter", "life", "life", "life", "life", "long", "long", "long", "long", "love", "love", "lunch", "lunch", "lungs", "mail", "male", "male", "male", "maternity", "medical", "medical", "medical", "medical", "medicare", "medication", "medication", "medications", "medicine", "medicine", "medicine", "medicine", "medicine", "meds", "meds", "meds", "mental", "mental", "mental", "midnight", "midnight", "migraine", "migraine", "mins", "mins", "mins", "minutes", "minutes", "minutes", "minutes", "money", "money", "morning", "morning", "morning", "morphine", "mri", "nausea", "nausea", "needle", "needle", "network", "network", "neurologist", "nice", "nice", "nice", "nice", "nice", "notch", "notch", "nurse", "nurse", "nurse", "nurse", "nurses", "nurses", "nurses", "nursing", "nursing", "nursing", "office", "office", "office", "outrageous", "outstanding", "oxygen", "pack", "paid", "paid", "pain", "pain", "pains", "pains", "pants", "patient", "patient", "patient", "patient", "patients", "patients", "patients", "patients", "pay", "paying", "paying", "paying", "payment", "payments", "people", "people", "people", "people", "people", "people's", "physician", "physician", "physician", "pills", "pissed", "place", "place", "place", "place", "pleasant", "pleased", "pm", "pm", "pm", "pm", "pointed", "prescribed", "prescribed", "professional", "professional", "professional", "prompt", "provider", "racist", "racist", "rating", "rating", "rating", "rating", "reality", "received", "received", "received", "recommend", "recommend", "recommend", "recommend", "relief", "reputation", "respectful", "responsive", "restroom", "rights", "rights", "rip", "rolled", "room", "room", "room", "rude", "rude", "rude", "rudeness", "rudeness", "ruptured", "sad", "sad", "sad", "sad", "sat", "sat", "scam", "scan", "scan", "scans", "seat", "security", "security", "service", "service", "service", "service", "services", "services", "services", "services", "severe", "severe", "shame", "shame", "shame", "sick", "sick", "sick", "sick", "sit", "sit", "sit", "sitting", "sitting", "sitting", "slow", "slow", "slowest", "slowest", "special", "special", "staff", "staff", "staff", "staff", "star", "star", "star", "star", "stays", "stitches", "stomach", "stomach", "stone", "stone", "stones", "stroke", "stroke", "stroke", "students", "suck", "sucks", "sucks", "sucks", "surgery", "surgery", "surgery", "survive", "symptoms", "symptoms", "symptoms", "team", "team", "technicians", "terrible", "terrible", "terrible", "terrible", "test", "test", "test", "tests", "tests", "tests", "thankful", "they're", "they're", "thorough", "time", "time", "time", "time", "time", "times", "times", "times", "times", "times", "told", "told", "told", "tone", "tone", "towel", "train", "treat", "treat", "treat", "treated", "treated", "treated", "treated", "treated", "treatment", "treatment", "treatment", "treatment", "triage", "triage", "triage", "uncaring", "uncaring", "uncaring", "uncaring", "understaffed", "understaffed", "unfriendly", "unfriendly", "unfriendly", "unprofessional", "unprofessional", "urge", "urgent", "urgent", "uti", "visit", "visit", "visit", "visit", "visit", "vitals", "vitals", "vitals", "vitals", "vomit", "wait", "wait", "wait", "wait", "waited", "waited", "waited", "waiting", "waiting", "walked", "walked", "walked", "walked", "walked", "wearing", "well", "well", "well", "well", "well", "wheel", "wheel", "wheelchair", "will", "will", "will", "will", "will", "witnessed", "witnessed", "woman", "woman", "woman", "wonderful", "worst", "worst", "worst", "worst", "wrong", "wrong", "wrong", "wrong", "yell", "yelling", "yelling", "yelling", "you're", "you're", "you're", "you're" ], | |
"Topic": [ 2, 1, 2, 3, 3, 5, 5, 5, 2, 2, 3, 4, 5, 5, 1, 4, 5, 1, 3, 5, 3, 2, 2, 2, 5, 4, 1, 1, 3, 4, 2, 3, 5, 1, 2, 5, 1, 1, 2, 3, 4, 2, 4, 1, 2, 3, 4, 5, 5, 1, 3, 1, 2, 3, 5, 1, 3, 4, 1, 2, 3, 4, 5, 3, 3, 5, 5, 5, 5, 1, 2, 4, 5, 1, 2, 1, 2, 1, 2, 5, 1, 2, 3, 5, 1, 2, 4, 5, 1, 2, 5, 2, 3, 1, 5, 2, 3, 4, 5, 3, 4, 1, 2, 4, 2, 1, 2, 1, 1, 3, 5, 5, 1, 5, 1, 2, 3, 4, 5, 1, 2, 5, 1, 3, 4, 1, 2, 5, 2, 5, 5, 1, 2, 3, 4, 1, 5, 4, 5, 1, 5, 4, 5, 3, 5, 1, 2, 1, 2, 1, 1, 2, 3, 4, 5, 2, 4, 5, 1, 4, 3, 4, 5, 1, 1, 2, 4, 5, 1, 2, 3, 3, 1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 5, 1, 3, 5, 1, 3, 5, 2, 1, 2, 4, 5, 4, 1, 2, 3, 1, 3, 4, 5, 1, 2, 3, 4, 5, 1, 4, 1, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 4, 1, 1, 2, 5, 5, 1, 3, 4, 2, 3, 5, 3, 4, 1, 3, 5, 2, 2, 2, 1, 4, 1, 1, 2, 3, 5, 1, 2, 3, 4, 5, 1, 4, 3, 4, 4, 5, 1, 1, 2, 3, 1, 2, 3, 5, 1, 2, 1, 3, 1, 3, 3, 2, 3, 4, 5, 2, 3, 1, 2, 3, 5, 2, 3, 4, 1, 2, 3, 5, 1, 2, 3, 4, 5, 1, 3, 4, 5, 1, 3, 5, 1, 2, 3, 5, 4, 1, 2, 4, 1, 2, 3, 4, 5, 2, 4, 1, 2, 3, 1, 2, 3, 4, 5, 1, 2, 4, 2, 5, 1, 2, 3, 5, 1, 2, 5, 3, 1, 3, 5, 2, 2, 3, 4, 4, 2, 4, 4, 1, 5, 1, 3, 1, 2, 5, 5, 2, 3, 4, 5, 1, 3, 4, 5, 3, 4, 1, 3, 2, 5, 1, 2, 3, 4, 2, 3, 4, 5, 5, 1, 2, 2, 1, 2, 3, 4, 5, 1, 2, 3, 1, 3, 5, 1, 5, 1, 2, 1, 4, 5, 1, 2, 4, 5, 3, 5, 1, 2, 4, 2, 2, 1, 2, 1, 3, 4, 5, 2, 1, 2, 3, 4, 5, 2, 4, 1, 2, 3, 4, 1, 3, 4, 2, 3, 4, 1, 2, 5, 5, 4, 2, 1, 2, 5, 1, 2, 1, 2, 1, 1, 3, 4, 5, 1, 2, 3, 5, 5, 1, 3, 5, 5, 5, 1, 2, 3, 4, 5, 3, 2, 4, 5, 2, 1, 1, 3, 4, 5, 4, 4, 1, 2, 3, 4, 1, 2, 3, 1, 3, 4, 4, 5, 3, 4, 2, 3, 4, 5, 3, 2, 4, 5, 2, 3, 4, 5, 2, 3, 4, 4, 1, 3, 5, 5, 1, 1, 3, 4, 1, 3, 5, 3, 5, 2, 1, 2, 3, 4, 1, 3, 5, 1, 2, 2, 1, 1, 3, 1, 3, 4, 5, 2, 3, 4, 5, 1, 2, 2, 3, 5, 1, 2, 3, 5, 1, 3, 5, 1, 3, 5, 2, 3, 2, 3, 2, 4, 1, 3, 4, 5, 1, 2, 3, 5, 4, 5, 1, 2, 1, 2, 2, 2, 3, 4, 3, 3, 1, 3, 5, 2, 4, 5, 3, 1, 2, 3, 3, 4, 4, 1, 2, 3, 5, 1, 2, 5, 2, 4, 5, 4, 3, 5, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 5, 1, 5, 1, 3, 2, 3, 5, 1, 2, 3, 4, 5, 2, 3, 4, 5, 1, 3, 4, 1, 2, 3, 4, 2, 3, 1, 3, 5, 1, 3, 3, 3, 5, 2, 1, 2, 3, 4, 5, 1, 2, 4, 5, 1, 1, 3, 4, 5, 1, 3, 5, 1, 3, 1, 2, 3, 4, 5, 1, 1, 2, 3, 4, 5, 1, 4, 1, 1, 2, 3, 4, 5, 3, 4, 1, 3, 5, 4, 1, 2, 3, 5, 1, 2, 3, 5, 1, 1, 2, 4, 1, 3, 4, 5 ], | |
"Freq": [ 0.99118, 0.039301, 0.95833, 0.0030231, 0.8758, 0.12511, 0.99899, 0.99987, 0.99812, 0.40747, 0.046398, 0.54606, 1.0025, 0.99814, 0.0089929, 0.98922, 0.0029976, 0.15936, 0.046872, 0.79369, 0.98951, 1.0005, 0.99553, 0.21094, 0.78951, 0.99609, 0.99696, 0.11871, 0.86807, 0.014839, 0.011707, 0.94829, 0.035122, 0.68465, 0.21722, 0.098199, 0.98891, 0.0037532, 0.99273, 0.0037532, 0.99866, 0.0026057, 0.99798, 0.17067, 0.24221, 0.39542, 0.13406, 0.057454, 1.0012, 0.99259, 0.0070397, 0.74933, 0.15384, 0.096271, 0.00099249, 0.00079704, 0.14108, 0.85841, 0.086296, 0.14879, 0.38982, 0.25353, 0.122, 0.99464, 0.0051603, 0.99465, 1.0005, 0.9996, 0.9984, 0.98282, 0.0066407, 0.0066407, 0.0066407, 0.37885, 0.62121, 0.99779, 0.99502, 0.2097, 0.083509, 0.70518, 0.30667, 0.21857, 0.044617, 0.43036, 0.49424, 0.17558, 0.0015007, 0.32866, 0.034476, 0.047404, 0.91791, 0.96848, 0.032751, 0.0069683, 0.9895, 0.070318, 0.21137, 0.50928, 0.209, 0.97832, 0.032611, 0.005227, 0.0020908, 0.99312, 1.0007, 0.0051201, 0.9933, 0.99842, 0.22182, 0.052912, 0.72448, 0.99887, 0.033353, 0.96724, 0.58726, 0.19608, 0.04902, 0.025491, 0.14216, 0.13981, 0.86006, 0.99382, 0.23111, 0.053982, 0.71527, 0.0052692, 0.22394, 0.77194, 1.0011, 0.99373, 0.99873, 0.0047275, 0.0070912, 0.03782, 0.95023, 0.0061846, 0.99262, 0.99962, 0.99539, 0.99705, 1.0002, 0.99947, 0.99498, 0.012905, 0.9872, 0.99833, 0.99903, 1.0021, 0.99986, 0.99339, 0.08224, 0.49391, 0.021495, 0.20981, 0.19252, 0.66624, 0.24217, 0.091798, 0.017154, 0.98634, 0.085875, 0.16996, 0.74425, 0.99946, 0.004328, 0.81582, 0.11036, 0.067084, 1.0032, 0.99728, 1.0018, 0.98355, 0.21943, 0.43625, 0.086988, 0.007842, 0.24949, 0.10837, 0.34445, 0.37586, 0.17119, 0.0119, 0.98768, 0.22928, 0.75741, 0.015457, 0.83089, 0.14284, 0.026154, 0.99341, 0.035688, 0.57281, 0.33199, 0.059381, 0.99882, 0.016633, 0.97719, 0.0041582, 0.18557, 0.37054, 0.16726, 0.27653, 0.15969, 0.13377, 0.25837, 0.27503, 0.17312, 0.98891, 0.99963, 0.0078526, 0.98943, 0.14689, 0.060506, 0.2074, 0.47915, 0.10632, 0.011855, 0.12273, 0.39121, 0.40028, 0.073919, 0.99764, 0.99948, 0.69817, 0.25555, 0.046463, 0.99899, 0.27455, 0.15645, 0.56929, 0.99791, 0.97852, 0.9925, 0.97852, 1.0002, 0.84655, 0.12745, 0.026832, 0.99273, 0.99589, 1.0007, 0.95643, 0.043474, 0.99605, 0.31867, 0.23717, 0.29454, 0.14937, 0.0037928, 0.096506, 0.26381, 0.53015, 0.10536, 0.96942, 0.029982, 0.99319, 1.0004, 0.99781, 0.0020736, 0.99761, 0.87108, 0.006156, 0.12004, 0.72438, 0.11351, 0.052275, 0.10903, 0.99505, 0.006219, 0.97143, 0.028203, 1.0021, 0.99635, 0.98414, 0.072936, 0.29077, 0.17894, 0.45706, 0.88959, 0.11068, 0.3621, 0.19555, 0.298, 0.14409, 0.0030419, 0.001521, 0.99623, 0.2545, 0.1303, 0.53547, 0.080083, 0.066423, 0.1562, 0.32857, 0.21932, 0.22946, 0.0022952, 0.52215, 0.36952, 0.10558, 0.77099, 0.06226, 0.16655, 0.52741, 0.11089, 0.29751, 0.06419, 0.99792, 0.35228, 0.43448, 0.21332, 0.31404, 0.27633, 0.26839, 0.019844, 0.12155, 0.13688, 0.86168, 0.017372, 0.034745, 0.95548, 0.02933, 0.014665, 0.95322, 0.99693, 0.99589, 0.0027483, 0.99762, 0.9982, 0.0060282, 0.99356, 0.13119, 0.083064, 0.61639, 0.16877, 0.431, 0.55374, 0.015223, 0.99922, 0.24976, 0.70726, 0.044349, 0.99907, 0.10818, 0.14667, 0.74583, 0.99933, 0.0044844, 0.99555, 1, 0.97007, 0.029344, 0.022738, 0.97015, 0.62488, 0.24107, 0.13413, 0.99533, 0.26347, 0.45463, 0.21765, 0.064436, 0.33147, 0.38062, 0.18666, 0.10097, 0.19135, 0.80818, 0.98467, 0.013676, 0.99435, 0.99868, 0.97791, 0.014742, 0.0049141, 0.99744, 0.14804, 0.23127, 0.22858, 0.39197, 1.0022, 0.05469, 0.94499, 0.99909, 0.056159, 0.82133, 0.02106, 0.0070199, 0.094769, 0.053166, 0.94149, 0.0044305, 0.016591, 0.96228, 0.024887, 0.97193, 0.029753, 0.013391, 0.98425, 0.939, 0.0038802, 0.058202, 0.74025, 0.0039719, 0.029292, 0.2264, 0.16612, 0.83379, 0.27953, 0.64142, 0.079672, 0.99979, 0.99841, 0.014262, 0.98405, 0.98682, 0.014839, 0.0054461, 0.99119, 1.0015, 0.16951, 0.028121, 0.17341, 0.59835, 0.030464, 0.0077521, 0.99227, 0.70536, 0.17311, 0.051305, 0.070152, 0.18113, 0.26787, 0.55104, 0.048983, 0.17228, 0.77866, 0.091451, 0.13841, 0.76868, 0.99099, 0.99783, 0.99833, 0.99605, 0.0024727, 0.9965, 0.22678, 0.77323, 0.15126, 0.8486, 0.98282, 0.17588, 0.46957, 0.20215, 0.15257, 0.10345, 0.0047024, 0.78859, 0.10298, 0.99978, 0.0093538, 0.0046769, 0.98683, 0.99972, 1.0011, 0.24262, 0.00028244, 0.64058, 0.06016, 0.056489, 0.98489, 0.16033, 0.16184, 0.6761, 0.99903, 0.9853, 0.16387, 0.63467, 0.027594, 0.17406, 0.99859, 0.9984, 0.81462, 0.11198, 0.064416, 0.0079281, 0.98691, 0.99542, 0.0037282, 0.0039958, 0.01898, 0.97698, 0.9935, 0.99514, 0.97833, 0.028774, 0.014831, 0.89481, 0.0049437, 0.084043, 0.97852, 0.028126, 0.41581, 0.55644, 0.05008, 0.26266, 0.60505, 0.081763, 0.99583, 0.98606, 1.0005, 0.98892, 0.99853, 0.96044, 0.045021, 0.99099, 1.0003, 0.81033, 0.11826, 0.071488, 0.29918, 0.69995, 0.00051054, 0.95602, 0.028118, 0.99203, 0.14323, 0.0095489, 0.82598, 0.014323, 0.99855, 0.0017396, 1.0012, 0.0040824, 0.99475, 0.99341, 0.9968, 0.79825, 0.20122, 0.00058341, 0.35821, 0.26487, 0.3763, 0.0018766, 0.0056299, 0.20267, 0.78818, 0.090069, 0.9096, 0.09975, 0.8379, 0.05985, 0.27881, 0.1526, 0.56681, 0.0011474, 0.81472, 0.18237, 0.0019823, 0.82411, 0.16967, 0.0060597, 0.003181, 0.99566, 0.028138, 0.95671, 0.016914, 0.981, 0.0001526, 0.34624, 0.63098, 0.022584, 0.14157, 0.0057395, 0.77292, 0.080353, 0.99483, 0.999, 0.093911, 0.90496, 0.0075918, 0.99073, 1.0007, 0.93141, 0.062893, 0.0089847, 0.98414, 1.0013, 0.0197, 0.96036, 0.0197, 0.52631, 0.43351, 0.040045, 0.98489, 0.0016316, 0.99694, 0.0016316, 0.021261, 0.97801, 1.0017, 0.13476, 0.17811, 0.51793, 0.16991, 0.051342, 0.87602, 0.071665, 0.7757, 0.11281, 0.11173, 0.99886, 0.86206, 0.13611, 0.99757, 0.23796, 0.16098, 0.23185, 0.2115, 0.15765, 0.097742, 0.14356, 0.24843, 0.35126, 0.15883, 0.39298, 0.45691, 0.15018, 0.99171, 0.012714, 1.0032, 1.0021, 0.24163, 0.69205, 0.065659, 0.0019038, 0.24464, 0.34268, 0.34364, 0.067585, 0.31078, 0.16622, 0.19974, 0.32336, 0.69917, 0.22431, 0.076082, 0.17441, 0.0064597, 0.81393, 0.0064597, 0.015737, 0.98354, 0.015788, 0.96309, 0.031577, 0.23212, 0.76763, 0.99273, 0.18373, 0.81577, 0.99412, 0.053297, 0.13445, 0.001817, 0.23318, 0.57779, 0.8754, 0.075303, 0.037652, 0.012551, 0.99098, 0.45195, 0.42398, 0.096801, 0.027029, 0.80796, 0.1289, 0.063122, 0.74462, 0.25555, 0.8924, 0.0027002, 0.013501, 0.086405, 0.0040502, 0.9882, 0.16288, 0.21436, 0.14113, 0.3799, 0.10119, 0.95585, 0.041818, 0.99928, 0.16242, 0.18552, 0.39033, 0.0033341, 0.25839, 0.98451, 0.015383, 0.84366, 0.10352, 0.051758, 0.99987, 0.27851, 0.0015082, 0.68219, 0.037704, 0.1329, 0.55685, 0.11945, 0.19094, 1.0032, 0.97514, 0.010158, 0.020315, 0.028305, 0.85116, 0.0020218, 0.11726 ] | |
}, | |
"R": 30, | |
"lambda.step": 0.01, | |
"plot.opts": { | |
"xlab": "PC1", | |
"ylab": "PC2" | |
}, | |
"topic.order": [ 4, 3, 5, 2, 1 ] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
LDAvis = function(to_select, json_file) { | |
// This section sets up the logic for event handling | |
var current_clicked = { | |
what: "nothing", | |
element: undefined | |
}, | |
current_hover = { | |
what: "nothing", | |
element: undefined | |
}, | |
old_winning_state = { | |
what: "nothing", | |
element: undefined | |
}, | |
vis_state = { | |
lambda: 1, | |
topic: 0, | |
term: "" | |
}; | |
// Set up a few 'global' variables to hold the data: | |
var K, // number of topics | |
R, // number of terms to display in bar chart | |
mdsData, // (x,y) locations and topic proportions | |
mdsData3, // topic proportions for all terms in the viz | |
lamData, // all terms that are among the top-R most relevant for all topics, lambda values | |
lambda = { | |
old: 1, | |
current: 1 | |
}, | |
color1 = "#1f77b4", // baseline color for default topic circles and overall term frequencies | |
color2 = "#d62728"; // 'highlight' color for selected topics and term-topic frequencies | |
// Set the duration of each half of the transition: | |
var duration = 750; | |
// Set global margins used for everything | |
var margin = { | |
top: 30, | |
right: 30, | |
bottom: 70, | |
left: 30 | |
}, | |
mdswidth = 530, | |
mdsheight = 530, | |
barwidth = 530, | |
barheight = 530, | |
termwidth = 90, // width to add between two panels to display terms | |
mdsarea = mdsheight * mdswidth; | |
// controls how big the maximum circle can be | |
// doesn't depend on data, only on mds width and height: | |
var rMax = 60; | |
// proportion of area of MDS plot to which the sum of default topic circle areas is set | |
var circle_prop = 0.25; | |
var word_prop = 0.25; | |
// opacity of topic circles: | |
var base_opacity = 0.2, | |
highlight_opacity = 0.6; | |
// topic/lambda selection names are specific to *this* vis | |
var topic_select = to_select + "-topic"; | |
var lambda_select = to_select + "-lambda"; | |
// get rid of the # in the to_select (useful) for setting ID values | |
var parts = to_select.split("#"); | |
var visID = parts[parts.length - 1]; | |
var topicID = visID + "-topic"; | |
var lambdaID = visID + "-lambda"; | |
var termID = visID + "-term"; | |
var topicDown = topicID + "-down"; | |
var topicUp = topicID + "-up"; | |
var topicClear = topicID + "-clear"; | |
////////////////////////////////////////////////////////////////////////////// | |
// sort array according to a specified object key name | |
// Note that default is decreasing sort, set decreasing = -1 for increasing | |
// adpated from http://stackoverflow.com/questions/16648076/sort-array-on-key-value | |
function fancysort(key_name, decreasing) { | |
decreasing = (typeof decreasing === "undefined") ? 1 : decreasing; | |
return function(a, b) { | |
if (a[key_name] < b[key_name]) | |
return 1 * decreasing; | |
if (a[key_name] > b[key_name]) | |
return -1 * decreasing; | |
return 0; | |
}; | |
} | |
// The actual read-in of the data and main code: | |
d3.json(json_file, function(error, data) { | |
// set the number of topics to global variable K: | |
K = data['mdsDat'].x.length; | |
// R is the number of top relevant (or salient) words whose bars we display | |
R = data['R']; | |
// a (K x 5) matrix with columns x, y, topics, Freq, cluster (where x and y are locations for left panel) | |
mdsData = []; | |
for (var i = 0; i < K; i++) { | |
var obj = {}; | |
for (var key in data['mdsDat']) { | |
obj[key] = data['mdsDat'][key][i]; | |
} | |
mdsData.push(obj); | |
} | |
// a huge matrix with 3 columns: Term, Topic, Freq, where Freq is all non-zero probabilities of topics given terms | |
// for the terms that appear in the barcharts for this data | |
mdsData3 = []; | |
for (var i = 0; i < data['token.table'].Term.length; i++) { | |
var obj = {}; | |
for (var key in data['token.table']) { | |
obj[key] = data['token.table'][key][i]; | |
} | |
mdsData3.push(obj); | |
} | |
// large data for the widths of bars in bar-charts. 6 columns: Term, logprob, loglift, Freq, Total, Category | |
// Contains all possible terms for topics in (1, 2, ..., k) and lambda in the user-supplied grid of lambda values | |
// which defaults to (0, 0.01, 0.02, ..., 0.99, 1). | |
lamData = []; | |
for (var i = 0; i < data['tinfo'].Term.length; i++) { | |
var obj = {}; | |
for (var key in data['tinfo']) { | |
obj[key] = data['tinfo'][key][i]; | |
} | |
lamData.push(obj); | |
} | |
// Create the topic input & lambda slider forms. Inspired from: | |
// http://bl.ocks.org/d3noob/10632804 | |
// http://bl.ocks.org/d3noob/10633704 | |
init_forms(topicID, lambdaID, visID); | |
// When the value of lambda changes, update the visualization | |
d3.select(lambda_select) | |
.on("mouseup", function() { | |
// store the previous lambda value | |
lambda.old = lambda.current; | |
lambda.current = document.getElementById(lambdaID).value; | |
vis_state.lambda = +this.value; | |
// adjust the text on the range slider | |
d3.select(lambda_select).property("value", vis_state.lambda); | |
d3.select(lambda_select + "-value").text(vis_state.lambda); | |
// transition the order of the bars | |
var increased = lambda.old < vis_state.lambda; | |
if (vis_state.topic > 0) reorder_bars(increased); | |
// store the current lambda value | |
state_save(true); | |
document.getElementById(lambdaID).value = vis_state.lambda; | |
}); | |
d3.select("#" + topicUp) | |
.on("click", function() { | |
// remove term selection if it exists (from a saved URL) | |
var termElem = document.getElementById(termID + vis_state.term); | |
if (termElem !== undefined) term_off(termElem); | |
vis_state.term = ""; | |
var value_old = document.getElementById(topicID).value; | |
var value_new = Math.min(K, +value_old + 1).toFixed(0); | |
// increment the value in the input box | |
document.getElementById(topicID).value = value_new; | |
topic_off(document.getElementById(topicID + value_old)); | |
topic_on(document.getElementById(topicID + value_new)); | |
vis_state.topic = value_new; | |
state_save(true); | |
}) | |
d3.select("#" + topicDown) | |
.on("click", function() { | |
// remove term selection if it exists (from a saved URL) | |
var termElem = document.getElementById(termID + vis_state.term); | |
if (termElem !== undefined) term_off(termElem); | |
vis_state.term = ""; | |
var value_old = document.getElementById(topicID).value; | |
var value_new = Math.max(0, +value_old - 1).toFixed(0); | |
// increment the value in the input box | |
document.getElementById(topicID).value = value_new; | |
topic_off(document.getElementById(topicID + value_old)); | |
topic_on(document.getElementById(topicID + value_new)); | |
vis_state.topic = value_new; | |
state_save(true); | |
}) | |
d3.select("#" + topicID) | |
.on("keyup", function() { | |
// remove term selection if it exists (from a saved URL) | |
var termElem = document.getElementById(termID + vis_state.term); | |
if (termElem !== undefined) term_off(termElem); | |
vis_state.term = ""; | |
topic_off(document.getElementById(topicID + vis_state.topic)) | |
var value_new = document.getElementById(topicID).value; | |
if (!isNaN(value_new) && value_new > 0) { | |
value_new = Math.min(K, Math.max(1, value_new)) | |
topic_on(document.getElementById(topicID + value_new)); | |
vis_state.topic = value_new; | |
state_save(true); | |
document.getElementById(topicID).value = vis_state.topic; | |
} | |
}) | |
d3.select("#" + topicClear) | |
.on("click", function() { | |
state_reset(); | |
state_save(true); | |
}) | |
// create linear scaling to pixels (and add some padding on outer region of scatterplot) | |
var xrange = d3.extent(mdsData, function(d) { | |
return d.x; | |
}); //d3.extent returns min and max of an array | |
var xdiff = xrange[1] - xrange[0], | |
xpad = 0.05; | |
var yrange = d3.extent(mdsData, function(d) { | |
return d.y; | |
}); | |
var ydiff = yrange[1] - yrange[0], | |
ypad = 0.05; | |
if (xdiff > ydiff) { | |
var xScale = d3.scale.linear() | |
.range([0, mdswidth]) | |
.domain([xrange[0] - xpad * xdiff, xrange[1] + xpad * xdiff]); | |
var yScale = d3.scale.linear() | |
.range([mdsheight, 0]) | |
.domain([yrange[0] - 0.5*(xdiff - ydiff) - ypad*xdiff, yrange[1] + 0.5*(xdiff - ydiff) + ypad*xdiff]); | |
} else { | |
var xScale = d3.scale.linear() | |
.range([0, mdswidth]) | |
.domain([xrange[0] - 0.5*(ydiff - xdiff) - xpad*ydiff, xrange[1] + 0.5*(ydiff - xdiff) + xpad*ydiff]); | |
var yScale = d3.scale.linear() | |
.range([mdsheight, 0]) | |
.domain([yrange[0] - ypad * ydiff, yrange[1] + ypad * ydiff]); | |
} | |
// Create new svg element (that will contain everything): | |
var svg = d3.select(to_select).append("svg") | |
.attr("width", mdswidth + barwidth + margin.left + termwidth + margin.right) | |
.attr("height", mdsheight + 2 * margin.top + margin.bottom + 2 * rMax); | |
// Create a group for the mds plot | |
var mdsplot = svg.append("g") | |
.attr("id", "leftpanel") | |
.attr("class", "points") | |
.attr("transform", "translate(" + margin.left + "," + 2 * margin.top + ")"); | |
// Clicking on the mdsplot should clear the selection | |
mdsplot | |
.append("rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("height", mdsheight) | |
.attr("width", mdswidth) | |
.style("fill", color1) | |
.attr("opacity", 0) | |
.on("click", function() { | |
state_reset(); | |
state_save(true); | |
}); | |
mdsplot.append("line") // draw x-axis | |
.attr("x1", 0) | |
.attr("x2", mdswidth) | |
.attr("y1", mdsheight / 2) | |
.attr("y2", mdsheight / 2) | |
.attr("stroke", "gray") | |
.attr("opacity", 0.3); | |
mdsplot.append("text") // label x-axis | |
.attr("x", 0) | |
.attr("y", mdsheight/2 - 5) | |
.text(data['plot.opts'].xlab) | |
.attr("fill", "gray"); | |
mdsplot.append("line") // draw y-axis | |
.attr("x1", mdswidth / 2) | |
.attr("x2", mdswidth / 2) | |
.attr("y1", 0) | |
.attr("y2", mdsheight) | |
.attr("stroke", "gray") | |
.attr("opacity", 0.3); | |
mdsplot.append("text") // label y-axis | |
.attr("x", mdswidth/2 + 5) | |
.attr("y", 7) | |
.text(data['plot.opts'].ylab) | |
.attr("fill", "gray"); | |
// new definitions based on fixing the sum of the areas of the default topic circles: | |
var newSmall = Math.sqrt(0.02*mdsarea*circle_prop/Math.PI); | |
var newMedium = Math.sqrt(0.05*mdsarea*circle_prop/Math.PI); | |
var newLarge = Math.sqrt(0.10*mdsarea*circle_prop/Math.PI); | |
var cx = 10 + newLarge, | |
cx2 = cx + 1.5 * newLarge; | |
// circle guide inspired from | |
// http://www.nytimes.com/interactive/2012/02/13/us/politics/2013-budget-proposal-graphic.html?_r=0 | |
circleGuide = function(rSize, size) { | |
d3.select("#leftpanel").append("circle") | |
.attr('class', "circleGuide" + size) | |
.attr('r', rSize) | |
.attr('cx', cx) | |
.attr('cy', mdsheight + rSize) | |
.style('fill', 'none') | |
.style('stroke-dasharray', '2 2') | |
.style('stroke', '#999'); | |
d3.select("#leftpanel").append("line") | |
.attr('class', "lineGuide" + size) | |
.attr("x1", cx) | |
.attr("x2", cx2) | |
.attr("y1", mdsheight + 2 * rSize) | |
.attr("y2", mdsheight + 2 * rSize) | |
.style("stroke", "gray") | |
.style("opacity", 0.3); | |
} | |
circleGuide(newSmall, "Small"); | |
circleGuide(newMedium, "Medium"); | |
circleGuide(newLarge, "Large"); | |
var defaultLabelSmall = "2%"; | |
var defaultLabelMedium = "5%"; | |
var defaultLabelLarge = "10%"; | |
d3.select("#leftpanel").append("text") | |
.attr("x", 10) | |
.attr("y", mdsheight - 10) | |
.attr('class', "circleGuideTitle") | |
.style("text-anchor", "left") | |
.style("fontWeight", "bold") | |
.text("Marginal topic distribution"); | |
d3.select("#leftpanel").append("text") | |
.attr("x", cx2 + 10) | |
.attr("y", mdsheight + 2 * newSmall) | |
.attr('class', "circleGuideLabelSmall") | |
.style("text-anchor", "start") | |
.text(defaultLabelSmall); | |
d3.select("#leftpanel").append("text") | |
.attr("x", cx2 + 10) | |
.attr("y", mdsheight + 2 * newMedium) | |
.attr('class', "circleGuideLabelMedium") | |
.style("text-anchor", "start") | |
.text(defaultLabelMedium); | |
d3.select("#leftpanel").append("text") | |
.attr("x", cx2 + 10) | |
.attr("y", mdsheight + 2 * newLarge) | |
.attr('class', "circleGuideLabelLarge") | |
.style("text-anchor", "start") | |
.text(defaultLabelLarge); | |
// bind mdsData to the points in the left panel: | |
var points = mdsplot.selectAll("points") | |
.data(mdsData) | |
.enter(); | |
// text to indicate topic | |
points.append("text") | |
.attr("class", "txt") | |
.attr("x", function(d) { | |
return (xScale(+d.x)); | |
}) | |
.attr("y", function(d) { | |
return (yScale(+d.y) + 4); | |
}) | |
.attr("stroke", "black") | |
.attr("opacity", 1) | |
.style("text-anchor", "middle") | |
.style("font-size", "11px") | |
.style("fontWeight", 100) | |
.text(function(d) { | |
return d.topics; | |
}); | |
// draw circles | |
points.append("circle") | |
.attr("class", "dot") | |
.style("opacity", 0.2) | |
.style("fill", color1) | |
.attr("r", function(d) { | |
//return (rScaleMargin(+d.Freq)); | |
return (Math.sqrt((d.Freq/100)*mdswidth*mdsheight*circle_prop/Math.PI)); | |
}) | |
.attr("cx", function(d) { | |
return (xScale(+d.x)); | |
}) | |
.attr("cy", function(d) { | |
return (yScale(+d.y)); | |
}) | |
.attr("stroke", "black") | |
.attr("id", function(d) { | |
return (topicID + d.topics) | |
}) | |
.on("mouseover", function(d) { | |
var old_topic = topicID + vis_state.topic; | |
if (vis_state.topic > 0 && old_topic != this.id) { | |
topic_off(document.getElementById(old_topic)); | |
} | |
topic_on(this); | |
}) | |
.on("click", function(d) { | |
// prevent click event defined on the div container from firing | |
// http://bl.ocks.org/jasondavies/3186840 | |
d3.event.stopPropagation(); | |
var old_topic = topicID + vis_state.topic; | |
if (vis_state.topic > 0 && old_topic != this.id) { | |
topic_off(document.getElementById(old_topic)); | |
} | |
// make sure topic input box value and fragment reflects clicked selection | |
document.getElementById(topicID).value = vis_state.topic = d.topics; | |
state_save(true); | |
topic_on(this); | |
}) | |
.on("mouseout", function(d) { | |
if (vis_state.topic != d.topics) topic_off(this); | |
if (vis_state.topic > 0) topic_on(document.getElementById(topicID + vis_state.topic)); | |
}); | |
svg.append("text") | |
.text("Intertopic Distance Map (via multidimensional scaling)") | |
.attr("x", mdswidth/2 + margin.left) | |
.attr("y", 30) | |
.style("font-size", "16px") | |
.style("text-anchor", "middle"); | |
// establish layout and vars for bar chart | |
var barDefault2 = lamData.filter(function(d) { | |
return d.Category == "Default" | |
}); | |
var y = d3.scale.ordinal() | |
.domain(barDefault2.map(function(d) { | |
return d.Term; | |
})) | |
.rangeRoundBands([0, barheight], 0.15); | |
var x = d3.scale.linear() | |
.domain([0, d3.max(barDefault2, function(d) { | |
return d.Total; | |
})]) | |
.range([0, barwidth]) | |
.nice(); | |
var yAxis = d3.svg.axis() | |
.scale(y); | |
// Add a group for the bar chart | |
var chart = svg.append("g") | |
.attr("transform", "translate(" + +(mdswidth + margin.left + termwidth) + "," + 2 * margin.top + ")") | |
.attr("id", "bar-freqs"); | |
// bar chart legend/guide: | |
var barguide = {"width": 100, "height": 15}; | |
d3.select("#bar-freqs").append("rect") | |
.attr("x", 0) | |
.attr("y", mdsheight + 10) | |
.attr("height", barguide.height) | |
.attr("width", barguide.width) | |
.style("fill", color1) | |
.attr("opacity", 0.4); | |
d3.select("#bar-freqs").append("text") | |
.attr("x", barguide.width + 5) | |
.attr("y", mdsheight + 10 + barguide.height/2) | |
.style("dominant-baseline", "middle") | |
.text("Overall term frequency"); | |
d3.select("#bar-freqs").append("rect") | |
.attr("x", 0) | |
.attr("y", mdsheight + 10 + barguide.height + 5) | |
.attr("height", barguide.height) | |
.attr("width", barguide.width/2) | |
.style("fill", color2) | |
.attr("opacity", 0.8); | |
d3.select("#bar-freqs").append("text") | |
.attr("x", barguide.width/2 + 5) | |
.attr("y", mdsheight + 10 + (3/2)*barguide.height + 5) | |
.style("dominant-baseline", "middle") | |
.text("Estimated term frequency within the selected topic"); | |
// footnotes: | |
d3.select("#bar-freqs") | |
.append("a") | |
.attr("xlink:href", "http://vis.stanford.edu/files/2012-Termite-AVI.pdf") | |
.attr("target", "_blank") | |
.append("text") | |
.attr("x", 0) | |
.attr("y", mdsheight + 10 + (6/2)*barguide.height + 5) | |
.style("dominant-baseline", "middle") | |
.text("1. saliency(term w) = frequency(w) * [sum_t p(t | w) * log(p(t | w)/p(t))] for topics t; see Chuang et. al (2012)"); | |
d3.select("#bar-freqs") | |
.append("a") | |
.attr("xlink:href", "http://nlp.stanford.edu/events/illvi2014/papers/sievert-illvi2014.pdf") | |
.attr("target", "_blank") | |
.append("text") | |
.attr("x", 0) | |
.attr("y", mdsheight + 10 + (8/2)*barguide.height + 5) | |
.style("dominant-baseline", "middle") | |
.text("2. relevance(term w | topic t) = \u03BB * p(w | t) + (1 - \u03BB) * p(w | t)/p(w); see Sievert & Shirley (2014)"); | |
// Bind 'default' data to 'default' bar chart | |
var basebars = chart.selectAll(".bar-totals") | |
.data(barDefault2) | |
.enter(); | |
// Draw the gray background bars defining the overall frequency of each word | |
basebars | |
.append("rect") | |
.attr("class", "bar-totals") | |
.attr("x", 0) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.attr("height", y.rangeBand()) | |
.attr("width", function(d) { | |
return x(d.Total); | |
}) | |
.style("fill", color1) | |
.attr("opacity", 0.4); | |
// Add word labels to the side of each bar | |
basebars | |
.append("text") | |
.attr("x", -5) | |
.attr("class", "terms") | |
.attr("y", function(d) { | |
return y(d.Term) + 12; | |
}) | |
.attr("cursor", "pointer") | |
.attr("id", function(d) { | |
return (termID + d.Term) | |
}) | |
.style("text-anchor", "end") // right align text - use 'middle' for center alignment | |
.text(function(d) { | |
return d.Term; | |
}) | |
.on("mouseover", function() { | |
term_hover(this); | |
}) | |
// .on("click", function(d) { | |
// var old_term = termID + vis_state.term; | |
// if (vis_state.term != "" && old_term != this.id) { | |
// term_off(document.getElementById(old_term)); | |
// } | |
// vis_state.term = d.Term; | |
// state_save(true); | |
// term_on(this); | |
// debugger; | |
// }) | |
.on("mouseout", function() { | |
vis_state.term = ""; | |
term_off(this); | |
state_save(true); | |
}); | |
var title = chart.append("text") | |
.attr("x", barwidth/2) | |
.attr("y", -30) | |
.attr("class", "bubble-tool") // set class so we can remove it when highlight_off is called | |
.style("text-anchor", "middle") | |
.style("font-size", "16px") | |
.text("Top-" + R + " Most Salient Terms"); | |
title.append("tspan") | |
.attr("baseline-shift", "super") | |
.attr("font-size", "12px") | |
.text("(1)"); | |
// barchart axis adapted from http://bl.ocks.org/mbostock/1166403 | |
var xAxis = d3.svg.axis().scale(x) | |
.orient("top") | |
.tickSize(-barheight) | |
.tickSubdivide(true) | |
.ticks(6); | |
chart.attr("class", "xaxis") | |
.call(xAxis); | |
// dynamically create the topic and lambda input forms at the top of the page: | |
function init_forms(topicID, lambdaID, visID) { | |
// create container div for topic and lambda input: | |
var inputDiv = document.createElement("div"); | |
inputDiv.setAttribute("id", "top"); | |
inputDiv.setAttribute("style", "width: 1210px"); // to match the width of the main svg element | |
document.getElementById(visID).appendChild(inputDiv); | |
// topic input container: | |
var topicDiv = document.createElement("div"); | |
topicDiv.setAttribute("style", "padding: 5px; background-color: #e8e8e8; display: inline-block; width: " + mdswidth + "px; height: 50px; float: left"); | |
inputDiv.appendChild(topicDiv); | |
var topicLabel = document.createElement("label"); | |
topicLabel.setAttribute("for", topicID); | |
topicLabel.setAttribute("style", "font-family: sans-serif; font-size: 14px"); | |
topicLabel.innerHTML = "Selected Topic: <span id='" + topicID + "-value'></span>"; | |
topicDiv.appendChild(topicLabel); | |
var topicInput = document.createElement("input"); | |
topicInput.setAttribute("style", "width: 50px"); | |
topicInput.type = "text"; | |
topicInput.min = "0"; | |
topicInput.max = K; // assumes the data has already been read in | |
topicInput.step = "1"; | |
topicInput.value = "0"; // a value of 0 indicates no topic is selected | |
topicInput.id = topicID; | |
topicDiv.appendChild(topicInput); | |
var previous = document.createElement("button"); | |
previous.setAttribute("id", topicDown); | |
previous.setAttribute("style", "margin-left: 5px"); | |
previous.innerHTML = "Previous Topic"; | |
topicDiv.appendChild(previous); | |
var next = document.createElement("button"); | |
next.setAttribute("id", topicUp); | |
next.setAttribute("style", "margin-left: 5px"); | |
next.innerHTML = "Next Topic"; | |
topicDiv.appendChild(next); | |
var clear = document.createElement("button"); | |
clear.setAttribute("id", topicClear); | |
clear.setAttribute("style", "margin-left: 5px"); | |
clear.innerHTML = "Clear Topic"; | |
topicDiv.appendChild(clear); | |
// lambda inputs | |
//var lambdaDivLeft = 8 + mdswidth + margin.left + termwidth; | |
var lambdaDivWidth = barwidth; | |
var lambdaDiv = document.createElement("div"); | |
lambdaDiv.setAttribute("id", "lambdaInput"); | |
lambdaDiv.setAttribute("style", "padding: 5px; background-color: #e8e8e8; display: inline-block; height: 50px; width: " + lambdaDivWidth + "px; float: right; margin-right: 30px"); | |
inputDiv.appendChild(lambdaDiv); | |
var lambdaZero = document.createElement("div"); | |
lambdaZero.setAttribute("style", "padding: 5px; height: 20px; width: 220px; font-family: sans-serif; float: left"); | |
lambdaZero.setAttribute("id", "lambdaZero"); | |
lambdaDiv.appendChild(lambdaZero); | |
var xx = d3.select("#lambdaZero") | |
.append("text") | |
.attr("x", 0) | |
.attr("y", 0) | |
.style("font-size", "14px") | |
.text("Slide to adjust relevance metric:"); | |
var yy = d3.select("#lambdaZero") | |
.append("text") | |
.attr("x", 125) | |
.attr("y", -5) | |
.style("font-size", "10px") | |
.style("position", "absolute") | |
.text("(2)"); | |
var sliderDiv = document.createElement("div"); | |
sliderDiv.setAttribute("id", "sliderdiv"); | |
sliderDiv.setAttribute("style", "padding: 5px; height: 40px; width: 250px; float: right; margin-top: -5px; margin-right: 10px"); | |
lambdaDiv.appendChild(sliderDiv); | |
var lambdaInput = document.createElement("input"); | |
lambdaInput.setAttribute("style", "width: 250px; margin-left: 0px; margin-right: 0px"); | |
lambdaInput.type = "range"; | |
lambdaInput.min = 0; | |
lambdaInput.max = 1; | |
lambdaInput.step = data['lambda.step']; | |
lambdaInput.value = vis_state.lambda; | |
lambdaInput.id = lambdaID; | |
lambdaInput.setAttribute("list", "ticks"); // to enable automatic ticks (with no labels, see below) | |
sliderDiv.appendChild(lambdaInput); | |
var lambdaLabel = document.createElement("label"); | |
lambdaLabel.setAttribute("id", "lamlabel"); | |
lambdaLabel.setAttribute("for", lambdaID); | |
lambdaLabel.setAttribute("style", "height: 20px; width: 60px; font-family: sans-serif; font-size: 14px; margin-left: 80px"); | |
lambdaLabel.innerHTML = "λ = <span id='" + lambdaID + "-value'>" + vis_state.lambda + "</span>"; | |
lambdaDiv.appendChild(lambdaLabel); | |
// Create the svg to contain the slider scale: | |
var scaleContainer = d3.select("#sliderdiv").append("svg") | |
.attr("width", 250) | |
.attr("height", 25); | |
var sliderScale = d3.scale.linear() | |
.domain([0, 1]) | |
.range([7.5, 242.5]) // trimmed by 7.5px on each side to match the input type=range slider: | |
.nice(); | |
// adapted from http://bl.ocks.org/mbostock/1166403 | |
var sliderAxis = d3.svg.axis() | |
.scale(sliderScale) | |
.orient("bottom") | |
.tickSize(10) | |
.tickSubdivide(true) | |
.ticks(6); | |
// group to contain the elements of the slider axis: | |
var sliderAxisGroup = scaleContainer.append("g") | |
.attr("class", "slideraxis") | |
.attr("margin-top", "-10px") | |
.call(sliderAxis); | |
// Another strategy for tick marks on the slider; simpler, but not labels | |
// var sliderTicks = document.createElement("datalist"); | |
// sliderTicks.setAttribute("id", "ticks"); | |
// for (var tick = 0; tick <= 10; tick++) { | |
// var tickOption = document.createElement("option"); | |
// //tickOption.value = tick/10; | |
// tickOption.innerHTML = tick/10; | |
// sliderTicks.appendChild(tickOption); | |
// } | |
// append the forms to the containers | |
//lambdaDiv.appendChild(sliderTicks); | |
} | |
// function to re-order the bars (gray and red), and terms: | |
function reorder_bars(increase) { | |
// grab the bar-chart data for this topic only: | |
var dat2 = lamData.filter(function(d) { | |
//return d.Category == "Topic" + Math.min(K, Math.max(0, vis_state.topic)) // fails for negative topic numbers... | |
return d.Category == "Topic" + vis_state.topic; | |
}); | |
// define relevance: | |
for (var i = 0; i < dat2.length; i++) { | |
dat2[i].relevance = vis_state.lambda * dat2[i].logprob + | |
(1 - vis_state.lambda) * dat2[i].loglift; | |
} | |
// sort by relevance: | |
dat2.sort(fancysort("relevance")); | |
// truncate to the top R tokens: | |
var dat3 = dat2.slice(0, R); | |
var y = d3.scale.ordinal() | |
.domain(dat3.map(function(d) { | |
return d.Term; | |
})) | |
.rangeRoundBands([0, barheight], 0.15); | |
var x = d3.scale.linear() | |
.domain([0, d3.max(dat3, function(d) { | |
return d.Total; | |
})]) | |
.range([0, barwidth]) | |
.nice(); | |
// Change Total Frequency bars | |
var graybars = d3.select("#bar-freqs") | |
.selectAll(".bar-totals") | |
.data(dat3, function(d) { | |
return d.Term; | |
}); | |
// Change word labels | |
var labels = d3.select("#bar-freqs") | |
.selectAll(".terms") | |
.data(dat3, function(d) { | |
return d.Term; | |
}); | |
// Create red bars (drawn over the gray ones) to signify the frequency under the selected topic | |
var redbars = d3.select("#bar-freqs") | |
.selectAll(".overlay") | |
.data(dat3, function(d) { | |
return d.Term; | |
}); | |
// adapted from http://bl.ocks.org/mbostock/1166403 | |
var xAxis = d3.svg.axis().scale(x) | |
.orient("top") | |
.tickSize(-barheight) | |
.tickSubdivide(true) | |
.ticks(6); | |
// New axis definition: | |
var newaxis = d3.selectAll(".xaxis"); | |
// define the new elements to enter: | |
var graybarsEnter = graybars.enter().append("rect") | |
.attr("class", "bar-totals") | |
.attr("x", 0) | |
.attr("y", function(d) { | |
return y(d.Term) + barheight + margin.bottom + 2 * rMax; | |
}) | |
.attr("height", y.rangeBand()) | |
.style("fill", color1) | |
.attr("opacity", 0.4); | |
var labelsEnter = labels.enter() | |
.append("text") | |
.attr("x", -5) | |
.attr("class", "terms") | |
.attr("y", function(d) { | |
return y(d.Term) + 12 + barheight + margin.bottom + 2 * rMax; | |
}) | |
.attr("cursor", "pointer") | |
.style("text-anchor", "end") | |
.attr("id", function(d) { | |
return (termID + d.Term) | |
}) | |
.text(function(d) { | |
return d.Term; | |
}) | |
.on("mouseover", function() { | |
term_hover(this); | |
}) | |
// .on("click", function(d) { | |
// var old_term = termID + vis_state.term; | |
// if (vis_state.term != "" && old_term != this.id) { | |
// term_off(document.getElementById(old_term)); | |
// } | |
// vis_state.term = d.Term; | |
// state_save(true); | |
// term_on(this); | |
// }) | |
.on("mouseout", function() { | |
vis_state.term = ""; | |
term_off(this); | |
state_save(true); | |
}); | |
var redbarsEnter = redbars.enter().append("rect") | |
.attr("class", "overlay") | |
.attr("x", 0) | |
.attr("y", function(d) { | |
return y(d.Term) + barheight + margin.bottom + 2 * rMax; | |
}) | |
.attr("height", y.rangeBand()) | |
.style("fill", color2) | |
.attr("opacity", 0.8); | |
if (increase) { | |
graybarsEnter | |
.attr("width", function(d) { | |
return x(d.Total); | |
}) | |
.transition().duration(duration) | |
.delay(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}); | |
labelsEnter | |
.transition().duration(duration) | |
.delay(duration) | |
.attr("y", function(d) { | |
return y(d.Term) + 12; | |
}); | |
redbarsEnter | |
.attr("width", function(d) { | |
return x(d.Freq); | |
}) | |
.transition().duration(duration) | |
.delay(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}); | |
graybars.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Total); | |
}) | |
.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}); | |
labels.transition().duration(duration) | |
.delay(duration) | |
.attr("y", function(d) { | |
return y(d.Term) + 12; | |
}); | |
redbars.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Freq); | |
}) | |
.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}); | |
// Transition exiting rectangles to the bottom of the barchart: | |
graybars.exit() | |
.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Total); | |
}) | |
.transition().duration(duration) | |
.attr("y", function(d, i) { | |
return barheight + margin.bottom + 6 + i * 18; | |
}) | |
.remove(); | |
labels.exit() | |
.transition().duration(duration) | |
.delay(duration) | |
.attr("y", function(d, i) { | |
return barheight + margin.bottom + 18 + i * 18; | |
}) | |
.remove(); | |
redbars.exit() | |
.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Freq); | |
}) | |
.transition().duration(duration) | |
.attr("y", function(d, i) { | |
return barheight + margin.bottom + 6 + i * 18; | |
}) | |
.remove(); | |
// https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_ease | |
newaxis.transition().duration(duration) | |
.call(xAxis) | |
.transition().duration(duration); | |
} else { | |
graybarsEnter | |
.attr("width", 100) // FIXME by looking up old width of these bars | |
.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Total); | |
}); | |
labelsEnter | |
.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term) + 12; | |
}); | |
redbarsEnter | |
.attr("width", 50) // FIXME by looking up old width of these bars | |
.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Freq); | |
}); | |
graybars.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Total); | |
}); | |
labels.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term) + 12; | |
}); | |
redbars.transition().duration(duration) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.transition().duration(duration) | |
.attr("width", function(d) { | |
return x(d.Freq); | |
}); | |
// Transition exiting rectangles to the bottom of the barchart: | |
graybars.exit() | |
.transition().duration(duration) | |
.attr("y", function(d, i) { | |
return barheight + margin.bottom + 6 + i * 18 + 2 * rMax; | |
}) | |
.remove(); | |
labels.exit() | |
.transition().duration(duration) | |
.attr("y", function(d, i) { | |
return barheight + margin.bottom + 18 + i * 18 + 2 * rMax; | |
}) | |
.remove(); | |
redbars.exit() | |
.transition().duration(duration) | |
.attr("y", function(d, i) { | |
return barheight + margin.bottom + 6 + i * 18 + 2 * rMax; | |
}) | |
.remove(); | |
// https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_ease | |
newaxis.transition().duration(duration) | |
.transition().duration(duration) | |
.call(xAxis); | |
} | |
} | |
////////////////////////////////////////////////////////////////////////////// | |
// function to update bar chart when a topic is selected | |
// the circle argument should be the appropriate circle element | |
function topic_on(circle) { | |
if (circle == null) return null; | |
// grab data bound to this element | |
var d = circle.__data__ | |
var Freq = Math.round(d.Freq * 10) / 10, | |
topics = d.topics; | |
// change opacity and fill of the selected circle | |
circle.style.opacity = highlight_opacity; | |
circle.style.fill = color2; | |
// Remove 'old' bar chart title | |
var text = d3.select(".bubble-tool"); | |
text.remove(); | |
// append text with info relevant to topic of interest | |
d3.select("#bar-freqs") | |
.append("text") | |
.attr("x", barwidth/2) | |
.attr("y", -30) | |
.attr("class", "bubble-tool") // set class so we can remove it when highlight_off is called | |
.style("text-anchor", "middle") | |
.style("font-size", "16px") | |
.text("Top-" + R + " Most Relevant Terms for Topic " + topics + " (" + Freq + "% of tokens)"); | |
// grab the bar-chart data for this topic only: | |
var dat2 = lamData.filter(function(d) { | |
return d.Category == "Topic" + topics | |
}); | |
// define relevance: | |
for (var i = 0; i < dat2.length; i++) { | |
dat2[i].relevance = lambda.current * dat2[i].logprob + | |
(1 - lambda.current) * dat2[i].loglift; | |
} | |
// sort by relevance: | |
dat2.sort(fancysort("relevance")); | |
// truncate to the top R tokens: | |
var dat3 = dat2.slice(0, R); | |
// scale the bars to the top R terms: | |
var y = d3.scale.ordinal() | |
.domain(dat3.map(function(d) { | |
return d.Term; | |
})) | |
.rangeRoundBands([0, barheight], 0.15); | |
var x = d3.scale.linear() | |
.domain([0, d3.max(dat3, function(d) { | |
return d.Total; | |
})]) | |
.range([0, barwidth]) | |
.nice(); | |
// remove the red bars if there are any: | |
d3.selectAll(".overlay").remove(); | |
// Change Total Frequency bars | |
d3.selectAll(".bar-totals") | |
.data(dat3) | |
.attr("x", 0) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.attr("height", y.rangeBand()) | |
.attr("width", function(d) { | |
return x(d.Total); | |
}) | |
.style("fill", color1) | |
.attr("opacity", 0.4); | |
// Change word labels | |
d3.selectAll(".terms") | |
.data(dat3) | |
.attr("x", -5) | |
.attr("y", function(d) { | |
return y(d.Term) + 12; | |
}) | |
.attr("id", function(d) { | |
return (termID + d.Term) | |
}) | |
.style("text-anchor", "end") // right align text - use 'middle' for center alignment | |
.text(function(d) { | |
return d.Term; | |
}); | |
// Create red bars (drawn over the gray ones) to signify the frequency under the selected topic | |
d3.select("#bar-freqs").selectAll(".overlay") | |
.data(dat3) | |
.enter() | |
.append("rect") | |
.attr("class", "overlay") | |
.attr("x", 0) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.attr("height", y.rangeBand()) | |
.attr("width", function(d) { | |
return x(d.Freq); | |
}) | |
.style("fill", color2) | |
.attr("opacity", 0.8); | |
// adapted from http://bl.ocks.org/mbostock/1166403 | |
var xAxis = d3.svg.axis().scale(x) | |
.orient("top") | |
.tickSize(-barheight) | |
.tickSubdivide(true) | |
.ticks(6); | |
// redraw x-axis | |
d3.selectAll(".xaxis") | |
//.attr("class", "xaxis") | |
.call(xAxis); | |
} | |
function topic_off(circle) { | |
if (circle == null) return circle; | |
// go back to original opacity/fill | |
circle.style.opacity = base_opacity; | |
circle.style.fill = color1; | |
var title = d3.selectAll(".bubble-tool") | |
.text("Top-" + R + " Most Salient Terms"); | |
title.append("tspan") | |
.attr("baseline-shift", "super") | |
.attr("font-size", 12) | |
.text(1); | |
// remove the red bars | |
d3.selectAll(".overlay").remove(); | |
// go back to 'default' bar chart | |
var dat2 = lamData.filter(function(d) { | |
return d.Category == "Default" | |
}); | |
var y = d3.scale.ordinal() | |
.domain(dat2.map(function(d) { | |
return d.Term; | |
})) | |
.rangeRoundBands([0, barheight], 0.15); | |
var x = d3.scale.linear() | |
.domain([0, d3.max(dat2, function(d) { | |
return d.Total; | |
})]) | |
.range([0, barwidth]) | |
.nice(); | |
// Change Total Frequency bars | |
d3.selectAll(".bar-totals") | |
.data(dat2) | |
.attr("x", 0) | |
.attr("y", function(d) { | |
return y(d.Term); | |
}) | |
.attr("height", y.rangeBand()) | |
.attr("width", function(d) { | |
return x(d.Total); | |
}) | |
.style("fill", color1) | |
.attr("opacity", 0.4); | |
//Change word labels | |
d3.selectAll(".terms") | |
.data(dat2) | |
.attr("x", -5) | |
.attr("y", function(d) { | |
return y(d.Term) + 12; | |
}) | |
.style("text-anchor", "end") // right align text - use 'middle' for center alignment | |
.text(function(d) { | |
return d.Term; | |
}); | |
// adapted from http://bl.ocks.org/mbostock/1166403 | |
var xAxis = d3.svg.axis().scale(x) | |
.orient("top") | |
.tickSize(-barheight) | |
.tickSubdivide(true) | |
.ticks(6); | |
// redraw x-axis | |
d3.selectAll(".xaxis") | |
.attr("class", "xaxis") | |
.call(xAxis); | |
} | |
// event definition for mousing over a term | |
function term_hover(term) { | |
var old_term = termID + vis_state.term; | |
if (vis_state.term != "" && old_term != term.id) { | |
term_off(document.getElementById(old_term)); | |
} | |
vis_state.term = term.innerHTML; | |
term_on(term); | |
state_save(true); | |
} | |
// updates vis when a term is selected via click or hover | |
function term_on(term) { | |
if (term == null) return null; | |
term.style["fontWeight"] = "bold"; | |
var d = term.__data__ | |
var Term = d.Term; | |
var dat2 = mdsData3.filter(function(d2) { | |
return d2.Term == Term | |
}); | |
var k = dat2.length; // number of topics for this token with non-zero frequency | |
var radius = []; | |
for (var i = 0; i < K; ++i) { | |
radius[i] = 0; | |
} | |
for (i = 0; i < k; i++) { | |
radius[dat2[i].Topic - 1] = dat2[i].Freq; | |
} | |
var size = []; | |
for (var i = 0; i < K; ++i) { | |
size[i] = 0; | |
} | |
for (i = 0; i < k; i++) { | |
// If we want to also re-size the topic number labels, do it here | |
// 11 is the default, so leaving this as 11 won't change anything. | |
size[dat2[i].Topic - 1] = 11; | |
} | |
var rScaleCond = d3.scale.sqrt() | |
.domain([0, 1]).range([0, rMax]); | |
// Change size of bubbles according to the word's distribution over topics | |
d3.selectAll(".dot") | |
.data(radius) | |
.transition() | |
.attr("r", function(d) { | |
//return (rScaleCond(d)); | |
return (Math.sqrt(d*mdswidth*mdsheight*word_prop/Math.PI)); | |
}); | |
// re-bind mdsData so we can handle multiple selection | |
d3.selectAll(".dot") | |
.data(mdsData) | |
// Change sizes of topic numbers: | |
d3.selectAll(".txt") | |
.data(size) | |
.transition() | |
.style("font-size", function(d) { | |
return +d; | |
}); | |
// Alter the guide | |
d3.select(".circleGuideTitle") | |
.text("Conditional topic distribution given term = '" + term.innerHTML + "'"); | |
} | |
function term_off(term) { | |
if (term == null) return null; | |
term.style["fontWeight"] = "normal"; | |
d3.selectAll(".dot") | |
.data(mdsData) | |
.transition() | |
.attr("r", function(d) { | |
//return (rScaleMargin(+d.Freq)); | |
return (Math.sqrt((d.Freq/100)*mdswidth*mdsheight*circle_prop/Math.PI)); | |
}); | |
// Change sizes of topic numbers: | |
d3.selectAll(".txt") | |
.transition() | |
.style("font-size", "11px"); | |
// Go back to the default guide | |
d3.select(".circleGuideTitle") | |
.text("Marginal topic distribution"); | |
d3.select(".circleGuideLabelLarge") | |
.text(defaultLabelLarge); | |
d3.select(".circleGuideLabelSmall") | |
.attr("y", mdsheight + 2 * newSmall) | |
.text(defaultLabelSmall); | |
d3.select(".circleGuideSmall") | |
.attr("r", newSmall) | |
.attr("cy", mdsheight + newSmall); | |
d3.select(".lineGuideSmall") | |
.attr("y1", mdsheight + 2 * newSmall) | |
.attr("y2", mdsheight + 2 * newSmall); | |
} | |
// serialize the visualization state using fragment identifiers -- http://en.wikipedia.org/wiki/Fragment_identifier | |
// location.hash holds the address information | |
var params = location.hash.split("&"); | |
if (params.length > 1) { | |
vis_state.topic = params[0].split("=")[1]; | |
vis_state.lambda = params[1].split("=")[1]; | |
vis_state.term = params[2].split("=")[1]; | |
// Idea: write a function to parse the URL string | |
// only accept values in [0,1] for lambda, {0, 1, ..., K} for topics (any string is OK for term) | |
// Allow for subsets of the three to be entered: | |
// (1) topic only (lambda = 1 term = "") | |
// (2) lambda only (topic = 0 term = "") visually the same but upon hovering a topic, the effect of lambda will be seen | |
// (3) term only (topic = 0 lambda = 1) only fires when the term is among the R most salient | |
// (4) topic + lambda (term = "") | |
// (5) topic + term (lambda = 1) | |
// (6) lambda + term (topic = 0) visually lambda doesn't make a difference unless a topic is hovered | |
// (7) topic + lambda + term | |
// Short-term: assume format of "#topic=k&lambda=l&term=s" where k, l, and s are strings (b/c they're from a URL) | |
// Force k (topic identifier) to be an integer between 0 and K: | |
vis_state.topic = Math.round(Math.min(K, Math.max(0, vis_state.topic))); | |
// Force l (lambda identifier) to be in [0, 1]: | |
vis_state.lambda = Math.min(1, Math.max(0, vis_state.lambda)); | |
// impose the value of lambda: | |
document.getElementById(lambdaID).value = vis_state.lambda; | |
document.getElementById(lambdaID + "-value").innerHTML = vis_state.lambda; | |
// select the topic and transition the order of the bars (if approporiate) | |
if (!isNaN(vis_state.topic)) { | |
document.getElementById(topicID).value = vis_state.topic; | |
if (vis_state.topic > 0) { | |
topic_on(document.getElementById(topicID + vis_state.topic)); | |
} | |
if (vis_state.lambda < 1 && vis_state.topic > 0) { | |
reorder_bars(false); | |
} | |
} | |
lambda.current = vis_state.lambda; | |
var termElem = document.getElementById(termID + vis_state.term); | |
if (termElem !== undefined) term_on(termElem); | |
} | |
function state_url() { | |
return location.origin + location.pathname + "#topic=" + vis_state.topic + | |
"&lambda=" + vis_state.lambda + "&term=" + vis_state.term; | |
} | |
function state_save(replace) { | |
if (replace) | |
history.replaceState(vis_state, "Query", state_url()); | |
else | |
history.pushState(vis_state, "Query", state_url()); | |
} | |
function state_reset() { | |
if (vis_state.topic > 0) { | |
topic_off(document.getElementById(topicID + vis_state.topic)); | |
} | |
if (vis_state.term != "") { | |
term_off(document.getElementById(termID + vis_state.term)); | |
} | |
vis_state.term = ""; | |
document.getElementById(topicID).value = vis_state.topic = 0; | |
state_save(true); | |
} | |
}); | |
// var current_clicked = { | |
// what: "nothing", | |
// element: undefined | |
// }, | |
//debugger; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment