Skip to content

Instantly share code, notes, and snippets.

@guypursey guypursey/.block
Last active Jul 29, 2017

Embed
What would you like to do?
UK General Election 2017 FT-style slopegraph (D3 v4)
license: mit
node_modules/

This is a simple slopegraph of the UK general election results for 2015 and 2017.

The idea was based on the slopegraphs seen in the Financial Times' webpage on full constituency results for the 2017 election. You can read about part of how I created this chart on my blogpost about how I scraped the data to build this chart from that same Financial Times webpage.

The term "slopegraph" was coined in Tufte's original post on these types of visualisations. However, I like Charlie Park's definition of a slopegraph as being a line chart that shows "a progression of univariate data among multiple actors over time".

To achieve the swatches and legend, I used Susie Lu's extremely helpful d3-svg-legend package.

Unless you are already on Blocks looking at this, you can see this code in action on the Blocks page for this visualisation.

Local usage

If downloading as a local repo, viewing the HTML file directly can be problematic unless you enable CORS (cross-origin resource sharing). This is because the data is pulled in from raw.csv or equivalent and if you view the HTML file directly without CORS enabled the browser is prevented from getting the data file even though it's in the same folder.

To get around this, I've specified http-server as a devDependency.

You can use either npm start or http-server to start up a simple local server and then go its address (e.g., localhost:8080) in your browser directly to see the file.

Local development

If developing this visualisation for yourself, you should know that the Node packages are included as dependencies in package.json.

You can use npm install as usual to get these.

Amend index.html and main.js to make changes.

Because the visualisation was developed with the browser and specifically Blocks, in mind, each time you update main.js you will need to run

browserify main.js > bundle.js

This updates the bundle.js file that pulls together the main code and any package dependencies for the browser.

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*
This file needs to be compiled with Browserify to `bundle.js` in order that the visualisation can be displayed in the browser.
*/
var d3 = require("d3")
d3.legend = require("d3-svg-legend")
var margin = {top: 20, right: 100, bottom: 10, left: 100}
var width = 960 - margin.left - margin.right
var height = 500 - margin.top - margin.bottom
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`)
var x = d3.scaleOrdinal()
.domain(["2015", "2017"])
.range([0, width / 2])
var y = d3.scaleLinear()
.rangeRound([height, 50])
var line = d3.line()
.x(d => x(d.year))
.y(d => y(d.seats))
d3.csv("raw.csv", function(error, data) {
if (error) throw error
var partyHashTable = data.reduce((p, c) => {
p[c["2015"]] = p[c["2015"]] || { "2015": 0, "2017": 0 }
p[c["2017"]] = p[c["2017"]] || { "2015": 0, "2017": 0 }
p[c["2015"]]["2015"] += 1
p[c["2017"]]["2017"] += 1
return p
}, {})
var partyPairs = Object.keys(partyHashTable)
.map(k => [{
"party": k,
"year": "2015",
"seats": partyHashTable[k]["2015"]
}, {
"party": k,
"year": "2017",
"seats": partyHashTable[k]["2017"]
}])
var partyData = partyPairs.reduce((p, c) => p.concat(c), [])
y.domain(d3.extent(partyData, d => d.seats))
svg.append("g")
.call(d3.axisLeft(y))
.classed("axis", true)
svg.append("g")
.attr("transform", `translate(${width / 2}, 0)`)
.call(d3.axisRight(y))
.classed("axis", true)
svg.selectAll(".axis-label")
.data(["2015", "2017"])
.enter().append("text")
.attr("x", (d, i, a) => ((width / 2) / (a.length - 1 || 0)) * i)
.attr("y", 0)
.attr("dy", "1em")
.attr("text-anchor", "end")
.attr("id", d => `label${d}`)
.classed("axis-label", true)
.text(d => d)
.attr("transform", d => `translate(${d3.select("#label" + d).node().getBBox().width / 2})`)
svg.append("path")
.classed("majorityline", true)
.attr("d", line([
{ "year": "2015", "seats": 325 },
{ "year": "2017", "seats": 325 }
]))
svg.selectAll(".dot")
.data(partyData)
.enter().append("circle")
.attr("class", d => d.party
.replace(/\s\(\d{4}\)$/, "")
.replace(/\s+/g, "-")
.toLowerCase())
.classed("dot", true)
.attr("cx", d => x(d.year))
.attr("cy", d => y(d.seats))
svg.selectAll(".partyline")
.data(partyPairs)
.enter().append("path")
.attr("class", d => `line ${d[0].party.replace(/\s\(\d{4}\)$/, "")
.replace(/\s+/g, "-")
.toLowerCase()}`)
.classed("partyline", true)
.attr("d", d => line(d))
var z = d3.scaleOrdinal()
.domain(Object.keys(partyHashTable)
.sort((a, b) => partyHashTable[b]["2017"] - partyHashTable[a]["2017"])
)
.range(Object.keys(partyHashTable)
.sort((a, b) => partyHashTable[b]["2017"] - partyHashTable[a]["2017"])
.map(p => p.replace(/\s/g, "-").toLowerCase())
)
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", `translate(${width / 2 + margin.left}, 20)`)
var legend = d3.legend.legendColor()
.labelFormat(d => d)
.useClass(true)
.title("Parties")
.titleWidth(100)
.scale(z)
svg.select(".legendOrdinal")
.call(legend)
})
},{"d3":13,"d3-svg-legend":5}],2:[function(require,module,exports){
// https://d3js.org/d3-collection/ Version 1.0.3. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, (function (exports) { 'use strict';
var prefix = "$";
function Map() {}
Map.prototype = map.prototype = {
constructor: Map,
has: function(key) {
return (prefix + key) in this;
},
get: function(key) {
return this[prefix + key];
},
set: function(key, value) {
this[prefix + key] = value;
return this;
},
remove: function(key) {
var property = prefix + key;
return property in this && delete this[property];
},
clear: function() {
for (var property in this) if (property[0] === prefix) delete this[property];
},
keys: function() {
var keys = [];
for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
return keys;
},
values: function() {
var values = [];
for (var property in this) if (property[0] === prefix) values.push(this[property]);
return values;
},
entries: function() {
var entries = [];
for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
return entries;
},
size: function() {
var size = 0;
for (var property in this) if (property[0] === prefix) ++size;
return size;
},
empty: function() {
for (var property in this) if (property[0] === prefix) return false;
return true;
},
each: function(f) {
for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
}
};
function map(object, f) {
var map = new Map;
// Copy constructor.
if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
// Index array by numeric index or specified key function.
else if (Array.isArray(object)) {
var i = -1,
n = object.length,
o;
if (f == null) while (++i < n) map.set(i, object[i]);
else while (++i < n) map.set(f(o = object[i], i, object), o);
}
// Convert object to map.
else if (object) for (var key in object) map.set(key, object[key]);
return map;
}
var nest = function() {
var keys = [],
sortKeys = [],
sortValues,
rollup,
nest;
function apply(array, depth, createResult, setResult) {
if (depth >= keys.length) return rollup != null
? rollup(array) : (sortValues != null
? array.sort(sortValues)
: array);
var i = -1,
n = array.length,
key = keys[depth++],
keyValue,
value,
valuesByKey = map(),
values,
result = createResult();
while (++i < n) {
if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
values.push(value);
} else {
valuesByKey.set(keyValue, [value]);
}
}
valuesByKey.each(function(values, key) {
setResult(result, key, apply(values, depth, createResult, setResult));
});
return result;
}
function entries(map$$1, depth) {
if (++depth > keys.length) return map$$1;
var array, sortKey = sortKeys[depth - 1];
if (rollup != null && depth >= keys.length) array = map$$1.entries();
else array = [], map$$1.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
}
return nest = {
object: function(array) { return apply(array, 0, createObject, setObject); },
map: function(array) { return apply(array, 0, createMap, setMap); },
entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
key: function(d) { keys.push(d); return nest; },
sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
sortValues: function(order) { sortValues = order; return nest; },
rollup: function(f) { rollup = f; return nest; }
};
};
function createObject() {
return {};
}
function setObject(object, key, value) {
object[key] = value;
}
function createMap() {
return map();
}
function setMap(map$$1, key, value) {
map$$1.set(key, value);
}
function Set() {}
var proto = map.prototype;
Set.prototype = set.prototype = {
constructor: Set,
has: proto.has,
add: function(value) {
value += "";
this[prefix + value] = value;
return this;
},
remove: proto.remove,
clear: proto.clear,
values: proto.keys,
size: proto.size,
empty: proto.empty,
each: proto.each
};
function set(object, f) {
var set = new Set;
// Copy constructor.
if (object instanceof Set) object.each(function(value) { set.add(value); });
// Otherwise, assume it’s an array.
else if (object) {
var i = -1, n = object.length;
if (f == null) while (++i < n) set.add(object[i]);
else while (++i < n) set.add(f(object[i], i, object));
}
return set;
}
var keys = function(map) {
var keys = [];
for (var key in map) keys.push(key);
return keys;
};
var values = function(map) {
var values = [];
for (var key in map) values.push(map[key]);
return values;
};
var entries = function(map) {
var entries = [];
for (var key in map) entries.push({key: key, value: map[key]});
return entries;
};
exports.nest = nest;
exports.set = set;
exports.map = map;
exports.keys = keys;
exports.values = values;
exports.entries = entries;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],3:[function(require,module,exports){
// https://d3js.org/d3-color/ Version 1.0.3. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, (function (exports) { 'use strict';
var define = function(constructor, factory, prototype) {
constructor.prototype = factory.prototype = prototype;
prototype.constructor = constructor;
};
function extend(parent, definition) {
var prototype = Object.create(parent.prototype);
for (var key in definition) prototype[key] = definition[key];
return prototype;
}
function Color() {}
var darker = 0.7;
var brighter = 1 / darker;
var reI = "\\s*([+-]?\\d+)\\s*";
var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
var reHex3 = /^#([0-9a-f]{3})$/;
var reHex6 = /^#([0-9a-f]{6})$/;
var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
var named = {
aliceblue: 0xf0f8ff,
antiquewhite: 0xfaebd7,
aqua: 0x00ffff,
aquamarine: 0x7fffd4,
azure: 0xf0ffff,
beige: 0xf5f5dc,
bisque: 0xffe4c4,
black: 0x000000,
blanchedalmond: 0xffebcd,
blue: 0x0000ff,
blueviolet: 0x8a2be2,
brown: 0xa52a2a,
burlywood: 0xdeb887,
cadetblue: 0x5f9ea0,
chartreuse: 0x7fff00,
chocolate: 0xd2691e,
coral: 0xff7f50,
cornflowerblue: 0x6495ed,
cornsilk: 0xfff8dc,
crimson: 0xdc143c,
cyan: 0x00ffff,
darkblue: 0x00008b,
darkcyan: 0x008b8b,
darkgoldenrod: 0xb8860b,
darkgray: 0xa9a9a9,
darkgreen: 0x006400,
darkgrey: 0xa9a9a9,
darkkhaki: 0xbdb76b,
darkmagenta: 0x8b008b,
darkolivegreen: 0x556b2f,
darkorange: 0xff8c00,
darkorchid: 0x9932cc,
darkred: 0x8b0000,
darksalmon: 0xe9967a,
darkseagreen: 0x8fbc8f,
darkslateblue: 0x483d8b,
darkslategray: 0x2f4f4f,
darkslategrey: 0x2f4f4f,
darkturquoise: 0x00ced1,
darkviolet: 0x9400d3,
deeppink: 0xff1493,
deepskyblue: 0x00bfff,
dimgray: 0x696969,
dimgrey: 0x696969,
dodgerblue: 0x1e90ff,
firebrick: 0xb22222,
floralwhite: 0xfffaf0,
forestgreen: 0x228b22,
fuchsia: 0xff00ff,
gainsboro: 0xdcdcdc,
ghostwhite: 0xf8f8ff,
gold: 0xffd700,
goldenrod: 0xdaa520,
gray: 0x808080,
green: 0x008000,
greenyellow: 0xadff2f,
grey: 0x808080,
honeydew: 0xf0fff0,
hotpink: 0xff69b4,
indianred: 0xcd5c5c,
indigo: 0x4b0082,
ivory: 0xfffff0,
khaki: 0xf0e68c,
lavender: 0xe6e6fa,
lavenderblush: 0xfff0f5,
lawngreen: 0x7cfc00,
lemonchiffon: 0xfffacd,
lightblue: 0xadd8e6,
lightcoral: 0xf08080,
lightcyan: 0xe0ffff,
lightgoldenrodyellow: 0xfafad2,
lightgray: 0xd3d3d3,
lightgreen: 0x90ee90,
lightgrey: 0xd3d3d3,
lightpink: 0xffb6c1,
lightsalmon: 0xffa07a,
lightseagreen: 0x20b2aa,
lightskyblue: 0x87cefa,
lightslategray: 0x778899,
lightslategrey: 0x778899,
lightsteelblue: 0xb0c4de,
lightyellow: 0xffffe0,
lime: 0x00ff00,
limegreen: 0x32cd32,
linen: 0xfaf0e6,
magenta: 0xff00ff,
maroon: 0x800000,
mediumaquamarine: 0x66cdaa,
mediumblue: 0x0000cd,
mediumorchid: 0xba55d3,
mediumpurple: 0x9370db,
mediumseagreen: 0x3cb371,
mediumslateblue: 0x7b68ee,
mediumspringgreen: 0x00fa9a,
mediumturquoise: 0x48d1cc,
mediumvioletred: 0xc71585,
midnightblue: 0x191970,
mintcream: 0xf5fffa,
mistyrose: 0xffe4e1,
moccasin: 0xffe4b5,
navajowhite: 0xffdead,
navy: 0x000080,
oldlace: 0xfdf5e6,
olive: 0x808000,
olivedrab: 0x6b8e23,
orange: 0xffa500,
orangered: 0xff4500,
orchid: 0xda70d6,
palegoldenrod: 0xeee8aa,
palegreen: 0x98fb98,
paleturquoise: 0xafeeee,
palevioletred: 0xdb7093,
papayawhip: 0xffefd5,
peachpuff: 0xffdab9,
peru: 0xcd853f,
pink: 0xffc0cb,
plum: 0xdda0dd,
powderblue: 0xb0e0e6,
purple: 0x800080,
rebeccapurple: 0x663399,
red: 0xff0000,
rosybrown: 0xbc8f8f,
royalblue: 0x4169e1,
saddlebrown: 0x8b4513,
salmon: 0xfa8072,
sandybrown: 0xf4a460,
seagreen: 0x2e8b57,
seashell: 0xfff5ee,
sienna: 0xa0522d,
silver: 0xc0c0c0,
skyblue: 0x87ceeb,
slateblue: 0x6a5acd,
slategray: 0x708090,
slategrey: 0x708090,
snow: 0xfffafa,
springgreen: 0x00ff7f,
steelblue: 0x4682b4,
tan: 0xd2b48c,
teal: 0x008080,
thistle: 0xd8bfd8,
tomato: 0xff6347,
turquoise: 0x40e0d0,
violet: 0xee82ee,
wheat: 0xf5deb3,
white: 0xffffff,
whitesmoke: 0xf5f5f5,
yellow: 0xffff00,
yellowgreen: 0x9acd32
};
define(Color, color, {
displayable: function() {
return this.rgb().displayable();
},
toString: function() {
return this.rgb() + "";
}
});
function color(format) {
var m;
format = (format + "").trim().toLowerCase();
return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
: (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
: (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
: (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
: (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
: (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
: (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
: (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
: named.hasOwnProperty(format) ? rgbn(named[format])
: format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
: null;
}
function rgbn(n) {
return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
}
function rgba(r, g, b, a) {
if (a <= 0) r = g = b = NaN;
return new Rgb(r, g, b, a);
}
function rgbConvert(o) {
if (!(o instanceof Color)) o = color(o);
if (!o) return new Rgb;
o = o.rgb();
return new Rgb(o.r, o.g, o.b, o.opacity);
}
function rgb(r, g, b, opacity) {
return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
}
function Rgb(r, g, b, opacity) {
this.r = +r;
this.g = +g;
this.b = +b;
this.opacity = +opacity;
}
define(Rgb, rgb, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
rgb: function() {
return this;
},
displayable: function() {
return (0 <= this.r && this.r <= 255)
&& (0 <= this.g && this.g <= 255)
&& (0 <= this.b && this.b <= 255)
&& (0 <= this.opacity && this.opacity <= 1);
},
toString: function() {
var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
return (a === 1 ? "rgb(" : "rgba(")
+ Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.b) || 0))
+ (a === 1 ? ")" : ", " + a + ")");
}
}));
function hsla(h, s, l, a) {
if (a <= 0) h = s = l = NaN;
else if (l <= 0 || l >= 1) h = s = NaN;
else if (s <= 0) h = NaN;
return new Hsl(h, s, l, a);
}
function hslConvert(o) {
if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Color)) o = color(o);
if (!o) return new Hsl;
if (o instanceof Hsl) return o;
o = o.rgb();
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
min = Math.min(r, g, b),
max = Math.max(r, g, b),
h = NaN,
s = max - min,
l = (max + min) / 2;
if (s) {
if (r === max) h = (g - b) / s + (g < b) * 6;
else if (g === max) h = (b - r) / s + 2;
else h = (r - g) / s + 4;
s /= l < 0.5 ? max + min : 2 - max - min;
h *= 60;
} else {
s = l > 0 && l < 1 ? 0 : h;
}
return new Hsl(h, s, l, o.opacity);
}
function hsl(h, s, l, opacity) {
return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
}
function Hsl(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Hsl, hsl, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = this.h % 360 + (this.h < 0) * 360,
s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
l = this.l,
m2 = l + (l < 0.5 ? l : 1 - l) * s,
m1 = 2 * l - m2;
return new Rgb(
hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
hsl2rgb(h, m1, m2),
hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
this.opacity
);
},
displayable: function() {
return (0 <= this.s && this.s <= 1 || isNaN(this.s))
&& (0 <= this.l && this.l <= 1)
&& (0 <= this.opacity && this.opacity <= 1);
}
}));
/* From FvD 13.37, CSS Color Module Level 3 */
function hsl2rgb(h, m1, m2) {
return (h < 60 ? m1 + (m2 - m1) * h / 60
: h < 180 ? m2
: h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
: m1) * 255;
}
var deg2rad = Math.PI / 180;
var rad2deg = 180 / Math.PI;
var Kn = 18;
var Xn = 0.950470;
var Yn = 1;
var Zn = 1.088830;
var t0 = 4 / 29;
var t1 = 6 / 29;
var t2 = 3 * t1 * t1;
var t3 = t1 * t1 * t1;
function labConvert(o) {
if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
if (o instanceof Hcl) {
var h = o.h * deg2rad;
return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
}
if (!(o instanceof Rgb)) o = rgbConvert(o);
var b = rgb2xyz(o.r),
a = rgb2xyz(o.g),
l = rgb2xyz(o.b),
x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
}
function lab(l, a, b, opacity) {
return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
}
function Lab(l, a, b, opacity) {
this.l = +l;
this.a = +a;
this.b = +b;
this.opacity = +opacity;
}
define(Lab, lab, extend(Color, {
brighter: function(k) {
return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
darker: function(k) {
return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
rgb: function() {
var y = (this.l + 16) / 116,
x = isNaN(this.a) ? y : y + this.a / 500,
z = isNaN(this.b) ? y : y - this.b / 200;
y = Yn * lab2xyz(y);
x = Xn * lab2xyz(x);
z = Zn * lab2xyz(z);
return new Rgb(
xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
this.opacity
);
}
}));
function xyz2lab(t) {
return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
}
function lab2xyz(t) {
return t > t1 ? t * t * t : t2 * (t - t0);
}
function xyz2rgb(x) {
return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
}
function rgb2xyz(x) {
return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
function hclConvert(o) {
if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
if (!(o instanceof Lab)) o = labConvert(o);
var h = Math.atan2(o.b, o.a) * rad2deg;
return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
}
function hcl(h, c, l, opacity) {
return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
}
function Hcl(h, c, l, opacity) {
this.h = +h;
this.c = +c;
this.l = +l;
this.opacity = +opacity;
}
define(Hcl, hcl, extend(Color, {
brighter: function(k) {
return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
},
darker: function(k) {
return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
},
rgb: function() {
return labConvert(this).rgb();
}
}));
var A = -0.14861;
var B = +1.78277;
var C = -0.29227;
var D = -0.90649;
var E = +1.97294;
var ED = E * D;
var EB = E * B;
var BC_DA = B * C - D * A;
function cubehelixConvert(o) {
if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Rgb)) o = rgbConvert(o);
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
bl = b - l,
k = (E * (g - l) - C * bl) / D,
s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
}
function cubehelix(h, s, l, opacity) {
return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
}
function Cubehelix(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Cubehelix, cubehelix, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
l = +this.l,
a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
cosh = Math.cos(h),
sinh = Math.sin(h);
return new Rgb(
255 * (l + a * (A * cosh + B * sinh)),
255 * (l + a * (C * cosh + D * sinh)),
255 * (l + a * (E * cosh)),
this.opacity
);
}
}));
exports.color = color;
exports.rgb = rgb;
exports.hsl = hsl;
exports.lab = lab;
exports.hcl = hcl;
exports.cubehelix = cubehelix;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],4:[function(require,module,exports){
// https://d3js.org/d3-interpolate/ Version 1.1.5. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-color')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3-color'], factory) :
(factory((global.d3 = global.d3 || {}),global.d3));
}(this, (function (exports,d3Color) { 'use strict';
function basis(t1, v0, v1, v2, v3) {
var t2 = t1 * t1, t3 = t2 * t1;
return ((1 - 3 * t1 + 3 * t2 - t3) * v0
+ (4 - 6 * t2 + 3 * t3) * v1
+ (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
+ t3 * v3) / 6;
}
var basis$1 = function(values) {
var n = values.length - 1;
return function(t) {
var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
v1 = values[i],
v2 = values[i + 1],
v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
return basis((t - i / n) * n, v0, v1, v2, v3);
};
};
var basisClosed = function(values) {
var n = values.length;
return function(t) {
var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
v0 = values[(i + n - 1) % n],
v1 = values[i % n],
v2 = values[(i + 1) % n],
v3 = values[(i + 2) % n];
return basis((t - i / n) * n, v0, v1, v2, v3);
};
};
var constant = function(x) {
return function() {
return x;
};
};
function linear(a, d) {
return function(t) {
return a + t * d;
};
}
function exponential(a, b, y) {
return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
return Math.pow(a + t * b, y);
};
}
function hue(a, b) {
var d = b - a;
return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant(isNaN(a) ? b : a);
}
function gamma(y) {
return (y = +y) === 1 ? nogamma : function(a, b) {
return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);
};
}
function nogamma(a, b) {
var d = b - a;
return d ? linear(a, d) : constant(isNaN(a) ? b : a);
}
var rgb$1 = ((function rgbGamma(y) {
var color$$1 = gamma(y);
function rgb$$1(start, end) {
var r = color$$1((start = d3Color.rgb(start)).r, (end = d3Color.rgb(end)).r),
g = color$$1(start.g, end.g),
b = color$$1(start.b, end.b),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.r = r(t);
start.g = g(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
rgb$$1.gamma = rgbGamma;
return rgb$$1;
}))(1);
function rgbSpline(spline) {
return function(colors) {
var n = colors.length,
r = new Array(n),
g = new Array(n),
b = new Array(n),
i, color$$1;
for (i = 0; i < n; ++i) {
color$$1 = d3Color.rgb(colors[i]);
r[i] = color$$1.r || 0;
g[i] = color$$1.g || 0;
b[i] = color$$1.b || 0;
}
r = spline(r);
g = spline(g);
b = spline(b);
color$$1.opacity = 1;
return function(t) {
color$$1.r = r(t);
color$$1.g = g(t);
color$$1.b = b(t);
return color$$1 + "";
};
};
}
var rgbBasis = rgbSpline(basis$1);
var rgbBasisClosed = rgbSpline(basisClosed);
var array = function(a, b) {
var nb = b ? b.length : 0,
na = a ? Math.min(nb, a.length) : 0,
x = new Array(nb),
c = new Array(nb),
i;
for (i = 0; i < na; ++i) x[i] = value(a[i], b[i]);
for (; i < nb; ++i) c[i] = b[i];
return function(t) {
for (i = 0; i < na; ++i) c[i] = x[i](t);
return c;
};
};
var date = function(a, b) {
var d = new Date;
return a = +a, b -= a, function(t) {
return d.setTime(a + b * t), d;
};
};
var number = function(a, b) {
return a = +a, b -= a, function(t) {
return a + b * t;
};
};
var object = function(a, b) {
var i = {},
c = {},
k;
if (a === null || typeof a !== "object") a = {};
if (b === null || typeof b !== "object") b = {};
for (k in b) {
if (k in a) {
i[k] = value(a[k], b[k]);
} else {
c[k] = b[k];
}
}
return function(t) {
for (k in i) c[k] = i[k](t);
return c;
};
};
var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
var reB = new RegExp(reA.source, "g");
function zero(b) {
return function() {
return b;
};
}
function one(b) {
return function(t) {
return b(t) + "";
};
}
var string = function(a, b) {
var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
am, // current match in a
bm, // current match in b
bs, // string preceding current number in b, if any
i = -1, // index in s
s = [], // string constants and placeholders
q = []; // number interpolators
// Coerce inputs to strings.
a = a + "", b = b + "";
// Interpolate pairs of numbers in a & b.
while ((am = reA.exec(a))
&& (bm = reB.exec(b))) {
if ((bs = bm.index) > bi) { // a string precedes the next number in b
bs = b.slice(bi, bs);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
if (s[i]) s[i] += bm; // coalesce with previous string
else s[++i] = bm;
} else { // interpolate non-matching numbers
s[++i] = null;
q.push({i: i, x: number(am, bm)});
}
bi = reB.lastIndex;
}
// Add remains of b.
if (bi < b.length) {
bs = b.slice(bi);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
// Special optimization for only a single match.
// Otherwise, interpolate each of the numbers and rejoin the string.
return s.length < 2 ? (q[0]
? one(q[0].x)
: zero(b))
: (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
};
var value = function(a, b) {
var t = typeof b, c;
return b == null || t === "boolean" ? constant(b)
: (t === "number" ? number
: t === "string" ? ((c = d3Color.color(b)) ? (b = c, rgb$1) : string)
: b instanceof d3Color.color ? rgb$1
: b instanceof Date ? date
: Array.isArray(b) ? array
: typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
: number)(a, b);
};
var round = function(a, b) {
return a = +a, b -= a, function(t) {
return Math.round(a + b * t);
};
};
var degrees = 180 / Math.PI;
var identity = {
translateX: 0,
translateY: 0,
rotate: 0,
skewX: 0,
scaleX: 1,
scaleY: 1
};
var decompose = function(a, b, c, d, e, f) {
var scaleX, scaleY, skewX;
if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
return {
translateX: e,
translateY: f,
rotate: Math.atan2(b, a) * degrees,
skewX: Math.atan(skewX) * degrees,
scaleX: scaleX,
scaleY: scaleY
};
};
var cssNode;
var cssRoot;
var cssView;
var svgNode;
function parseCss(value) {
if (value === "none") return identity;
if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
cssNode.style.transform = value;
value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
cssRoot.removeChild(cssNode);
value = value.slice(7, -1).split(",");
return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
}
function parseSvg(value) {
if (value == null) return identity;
if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
svgNode.setAttribute("transform", value);
if (!(value = svgNode.transform.baseVal.consolidate())) return identity;
value = value.matrix;
return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
}
function interpolateTransform(parse, pxComma, pxParen, degParen) {
function pop(s) {
return s.length ? s.pop() + " " : "";
}
function translate(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push("translate(", null, pxComma, null, pxParen);
q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
} else if (xb || yb) {
s.push("translate(" + xb + pxComma + yb + pxParen);
}
}
function rotate(a, b, s, q) {
if (a !== b) {
if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: number(a, b)});
} else if (b) {
s.push(pop(s) + "rotate(" + b + degParen);
}
}
function skewX(a, b, s, q) {
if (a !== b) {
q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: number(a, b)});
} else if (b) {
s.push(pop(s) + "skewX(" + b + degParen);
}
}
function scale(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push(pop(s) + "scale(", null, ",", null, ")");
q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
} else if (xb !== 1 || yb !== 1) {
s.push(pop(s) + "scale(" + xb + "," + yb + ")");
}
}
return function(a, b) {
var s = [], // string constants and placeholders
q = []; // number interpolators
a = parse(a), b = parse(b);
translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
rotate(a.rotate, b.rotate, s, q);
skewX(a.skewX, b.skewX, s, q);
scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
a = b = null; // gc
return function(t) {
var i = -1, n = q.length, o;
while (++i < n) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
};
}
var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
var rho = Math.SQRT2;
var rho2 = 2;
var rho4 = 4;
var epsilon2 = 1e-12;
function cosh(x) {
return ((x = Math.exp(x)) + 1 / x) / 2;
}
function sinh(x) {
return ((x = Math.exp(x)) - 1 / x) / 2;
}
function tanh(x) {
return ((x = Math.exp(2 * x)) - 1) / (x + 1);
}
// p0 = [ux0, uy0, w0]
// p1 = [ux1, uy1, w1]
var zoom = function(p0, p1) {
var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
dx = ux1 - ux0,
dy = uy1 - uy0,
d2 = dx * dx + dy * dy,
i,
S;
// Special case for u0 ≅ u1.
if (d2 < epsilon2) {
S = Math.log(w1 / w0) / rho;
i = function(t) {
return [
ux0 + t * dx,
uy0 + t * dy,
w0 * Math.exp(rho * t * S)
];
};
}
// General case.
else {
var d1 = Math.sqrt(d2),
b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
S = (r1 - r0) / rho;
i = function(t) {
var s = t * S,
coshr0 = cosh(r0),
u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
return [
ux0 + u * dx,
uy0 + u * dy,
w0 * coshr0 / cosh(rho * s + r0)
];
};
}
i.duration = S * 1000;
return i;
};
function hsl$1(hue$$1) {
return function(start, end) {
var h = hue$$1((start = d3Color.hsl(start)).h, (end = d3Color.hsl(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hsl$2 = hsl$1(hue);
var hslLong = hsl$1(nogamma);
function lab$1(start, end) {
var l = nogamma((start = d3Color.lab(start)).l, (end = d3Color.lab(end)).l),
a = nogamma(start.a, end.a),
b = nogamma(start.b, end.b),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.l = l(t);
start.a = a(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
function hcl$1(hue$$1) {
return function(start, end) {
var h = hue$$1((start = d3Color.hcl(start)).h, (end = d3Color.hcl(end)).h),
c = nogamma(start.c, end.c),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.c = c(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hcl$2 = hcl$1(hue);
var hclLong = hcl$1(nogamma);
function cubehelix$1(hue$$1) {
return (function cubehelixGamma(y) {
y = +y;
function cubehelix$$1(start, end) {
var h = hue$$1((start = d3Color.cubehelix(start)).h, (end = d3Color.cubehelix(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(Math.pow(t, y));
start.opacity = opacity(t);
return start + "";
};
}
cubehelix$$1.gamma = cubehelixGamma;
return cubehelix$$1;
})(1);
}
var cubehelix$2 = cubehelix$1(hue);
var cubehelixLong = cubehelix$1(nogamma);
var quantize = function(interpolator, n) {
var samples = new Array(n);
for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
return samples;
};
exports.interpolate = value;
exports.interpolateArray = array;
exports.interpolateBasis = basis$1;
exports.interpolateBasisClosed = basisClosed;
exports.interpolateDate = date;
exports.interpolateNumber = number;
exports.interpolateObject = object;
exports.interpolateRound = round;
exports.interpolateString = string;
exports.interpolateTransformCss = interpolateTransformCss;
exports.interpolateTransformSvg = interpolateTransformSvg;
exports.interpolateZoom = zoom;
exports.interpolateRgb = rgb$1;
exports.interpolateRgbBasis = rgbBasis;
exports.interpolateRgbBasisClosed = rgbBasisClosed;
exports.interpolateHsl = hsl$2;
exports.interpolateHslLong = hslLong;
exports.interpolateLab = lab$1;
exports.interpolateHcl = hcl$2;
exports.interpolateHclLong = hclLong;
exports.interpolateCubehelix = cubehelix$2;
exports.interpolateCubehelixLong = cubehelixLong;
exports.quantize = quantize;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{"d3-color":3}],5:[function(require,module,exports){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-selection'), require('d3-dispatch'), require('d3-scale'), require('d3-format'), require('d3-array')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3-selection', 'd3-dispatch', 'd3-scale', 'd3-format', 'd3-array'], factory) :
(factory((global.indexRollup = global.indexRollup || {}),global.d3Selection,global.d3Dispatch,global.d3Scale,global.d3Format,global.d3Array));
}(this, (function (exports,d3Selection,d3Dispatch,d3Scale,d3Format,d3Array) { 'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var d3_identity = function d3_identity(d) {
return d;
};
var d3_reverse = function d3_reverse(arr) {
var mirror = [];
for (var i = 0, l = arr.length; i < l; i++) {
mirror[i] = arr[l - i - 1];
}
return mirror;
};
//Text wrapping code adapted from Mike Bostock
var d3_textWrapping = function d3_textWrapping(text, width) {
text.each(function () {
var text = d3Selection.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.2,
//ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")) || 0,
tspan = text.text(null).append("tspan").attr("x", 0).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width && line.length > 1) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("dy", lineHeight + dy + "em").text(word);
}
}
});
};
var d3_mergeLabels = function d3_mergeLabels() {
var gen = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var labels = arguments[1];
var domain = arguments[2];
var range = arguments[3];
if ((typeof labels === "undefined" ? "undefined" : _typeof(labels)) === "object") {
if (labels.length === 0) return gen;
var i = labels.length;
for (; i < gen.length; i++) {
labels.push(gen[i]);
}
return labels;
} else if (typeof labels === "function") {
var customLabels = [];
var genLength = gen.length;
for (var _i = 0; _i < genLength; _i++) {
customLabels.push(labels({
i: _i,
genLength: genLength,
generatedLabels: gen,
domain: domain,
range: range }));
}
return customLabels;
}
return gen;
};
var d3_linearLegend = function d3_linearLegend(scale, cells, labelFormat) {
var data = [];
if (cells.length > 1) {
data = cells;
} else {
var domain = scale.domain(),
increment = (domain[domain.length - 1] - domain[0]) / (cells - 1);
var i = 0;
for (; i < cells; i++) {
data.push(domain[0] + i * increment);
}
}
var labels = data.map(labelFormat);
return { data: data,
labels: labels,
feature: function feature(d) {
return scale(d);
} };
};
var d3_quantLegend = function d3_quantLegend(scale, labelFormat, labelDelimiter) {
var labels = scale.range().map(function (d) {
var invert = scale.invertExtent(d);
return labelFormat(invert[0]) + " " + labelDelimiter + " " + labelFormat(invert[1]);
});
return { data: scale.range(),
labels: labels,
feature: d3_identity
};
};
var d3_ordinalLegend = function d3_ordinalLegend(scale) {
return { data: scale.domain(),
labels: scale.domain(),
feature: function feature(d) {
return scale(d);
} };
};
var d3_cellOver = function d3_cellOver(cellDispatcher, d, obj) {
cellDispatcher.call("cellover", obj, d);
};
var d3_cellOut = function d3_cellOut(cellDispatcher, d, obj) {
cellDispatcher.call("cellout", obj, d);
};
var d3_cellClick = function d3_cellClick(cellDispatcher, d, obj) {
cellDispatcher.call("cellclick", obj, d);
};
var helper = {
d3_drawShapes: function d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, path) {
if (shape === "rect") {
shapes.attr("height", shapeHeight).attr("width", shapeWidth);
} else if (shape === "circle") {
shapes.attr("r", shapeRadius);
} else if (shape === "line") {
shapes.attr("x1", 0).attr("x2", shapeWidth).attr("y1", 0).attr("y2", 0);
} else if (shape === "path") {
shapes.attr("d", path);
}
},
d3_addText: function d3_addText(svg, enter, labels, classPrefix, labelWidth) {
enter.append("text").attr("class", classPrefix + "label");
var text = svg.selectAll("g." + classPrefix + "cell text." + classPrefix + "label").data(labels).text(d3_identity);
if (labelWidth) {
svg.selectAll("g." + classPrefix + "cell text." + classPrefix + "label").call(d3_textWrapping, labelWidth);
}
return text;
},
d3_calcType: function d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter) {
var type = scale.invertExtent ? d3_quantLegend(scale, labelFormat, labelDelimiter) : scale.ticks ? d3_linearLegend(scale, cells, labelFormat) : d3_ordinalLegend(scale);
//for d3.scaleSequential that doesn't have a range function
var range = scale.range && scale.range() || scale.domain();
type.labels = d3_mergeLabels(type.labels, labels, scale.domain(), range);
if (ascending) {
type.labels = d3_reverse(type.labels);
type.data = d3_reverse(type.data);
}
return type;
},
d3_filterCells: function d3_filterCells(type, cellFilter) {
var filterCells = type.data.map(function (d, i) {
return { data: d, label: type.labels[i] };
}).filter(cellFilter);
var dataValues = filterCells.map(function (d) {
return d.data;
});
var labelValues = filterCells.map(function (d) {
return d.label;
});
type.data = type.data.filter(function (d) {
return dataValues.indexOf(d) !== -1;
});
type.labels = type.labels.filter(function (d) {
return labelValues.indexOf(d) !== -1;
});
return type;
},
d3_placement: function d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign) {
cell.attr("transform", cellTrans);
text.attr("transform", textTrans);
if (orient === "horizontal") {
text.style("text-anchor", labelAlign);
}
},
d3_addEvents: function d3_addEvents(cells, dispatcher) {
cells.on("mouseover.legend", function (d) {
d3_cellOver(dispatcher, d, this);
}).on("mouseout.legend", function (d) {
d3_cellOut(dispatcher, d, this);
}).on("click.legend", function (d) {
d3_cellClick(dispatcher, d, this);
});
},
d3_title: function d3_title(svg, title, classPrefix, titleWidth) {
if (title !== "") {
var titleText = svg.selectAll('text.' + classPrefix + 'legendTitle');
titleText.data([title]).enter().append('text').attr('class', classPrefix + 'legendTitle');
svg.selectAll('text.' + classPrefix + 'legendTitle').text(title);
if (titleWidth) {
svg.selectAll('text.' + classPrefix + 'legendTitle').call(d3_textWrapping, titleWidth);
}
var cellsSvg = svg.select('.' + classPrefix + 'legendCells');
var yOffset = svg.select('.' + classPrefix + 'legendTitle').nodes().map(function (d) {
return d.getBBox().height;
})[0],
xOffset = -cellsSvg.nodes().map(function (d) {
return d.getBBox().x;
})[0];
cellsSvg.attr('transform', 'translate(' + xOffset + ',' + yOffset + ')');
}
}
};
function color() {
var scale = d3Scale.scaleLinear(),
shape = "rect",
shapeWidth = 15,
shapeHeight = 15,
shapeRadius = 10,
shapePadding = 2,
cells = [5],
cellFilter = void 0,
labels = [],
classPrefix = "",
useClass = false,
title = "",
labelFormat = d3Format.format(".01f"),
labelOffset = 10,
labelAlign = "middle",
labelDelimiter = "to",
labelWrap = void 0,
orient = "vertical",
ascending = false,
path = void 0,
titleWidth = void 0,
legendDispatcher = d3Dispatch.dispatch("cellover", "cellout", "cellclick");
function legend(svg) {
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter),
legendG = svg.selectAll('g').data([scale]);
legendG.enter().append('g').attr('class', classPrefix + 'legendCells');
if (cellFilter) {
helper.d3_filterCells(type, cellFilter);
}
var cell = svg.select('.' + classPrefix + 'legendCells').selectAll("." + classPrefix + "cell").data(type.data);
var cellEnter = cell.enter().append("g").attr("class", classPrefix + "cell");
cellEnter.append(shape).attr("class", classPrefix + "swatch");
var shapes = svg.selectAll("g." + classPrefix + "cell " + shape);
//add event handlers
helper.d3_addEvents(cellEnter, legendDispatcher);
cell.exit().transition().style("opacity", 0).remove();
helper.d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, path);
helper.d3_addText(svg, cellEnter, type.labels, classPrefix, labelWrap);
// we need to merge the selection, otherwise changes in the legend (e.g. change of orientation) are applied only to the new cells and not the existing ones.
cell = cellEnter.merge(cell);
// sets placement
var text = cell.selectAll("text"),
textSize = text.nodes().map(function (d) {
return d.getBBox();
}),
shapeSize = shapes.nodes().map(function (d) {
return d.getBBox();
});
//sets scale
//everything is fill except for line which is stroke,
if (!useClass) {
if (shape == "line") {
shapes.style("stroke", type.feature);
} else {
shapes.style("fill", type.feature);
}
} else {
shapes.attr("class", function (d) {
return classPrefix + 'swatch ' + type.feature(d);
});
}
var cellTrans = void 0,
textTrans = void 0,
textAlign = labelAlign == "start" ? 0 : labelAlign == "middle" ? 0.5 : 1;
//positions cells and text
if (orient === "vertical") {
(function () {
var cellSize = textSize.map(function (d, i) {
return Math.max(d.height, shapeSize[i].height);
});
cellTrans = function cellTrans(d, i) {
var height = d3Array.sum(cellSize.slice(0, i));
return 'translate(0, ' + (height + i * shapePadding) + ')';
};
textTrans = function textTrans(d, i) {
return 'translate( ' + (shapeSize[i].width + shapeSize[i].x + labelOffset) + ', ' + (shapeSize[i].y + shapeSize[i].height / 2 + 5) + ')';
};
})();
} else if (orient === "horizontal") {
cellTrans = function cellTrans(d, i) {
return 'translate(' + i * (shapeSize[i].width + shapePadding) + ',0)';
};
textTrans = function textTrans(d, i) {
return 'translate(' + (shapeSize[i].width * textAlign + shapeSize[i].x) + ',\n ' + (shapeSize[i].height + shapeSize[i].y + labelOffset + 8) + ')';
};
}
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign);
helper.d3_title(svg, title, classPrefix, titleWidth);
cell.transition().style("opacity", 1);
}
legend.scale = function (_) {
if (!arguments.length) return scale;
scale = _;
return legend;
};
legend.cells = function (_) {
if (!arguments.length) return cells;
if (_.length > 1 || _ >= 2) {
cells = _;
}
return legend;
};
legend.cellFilter = function (_) {
if (!arguments.length) return cellFilter;
cellFilter = _;
return legend;
};
legend.shape = function (_, d) {
if (!arguments.length) return shape;
if (_ == "rect" || _ == "circle" || _ == "line" || _ == "path" && typeof d === 'string') {
shape = _;
path = d;
}
return legend;
};
legend.shapeWidth = function (_) {
if (!arguments.length) return shapeWidth;
shapeWidth = +_;
return legend;
};
legend.shapeHeight = function (_) {
if (!arguments.length) return shapeHeight;
shapeHeight = +_;
return legend;
};
legend.shapeRadius = function (_) {
if (!arguments.length) return shapeRadius;
shapeRadius = +_;
return legend;
};
legend.shapePadding = function (_) {
if (!arguments.length) return shapePadding;
shapePadding = +_;
return legend;
};
legend.labels = function (_) {
if (!arguments.length) return labels;
labels = _;
return legend;
};
legend.labelAlign = function (_) {
if (!arguments.length) return labelAlign;
if (_ == "start" || _ == "end" || _ == "middle") {
labelAlign = _;
}
return legend;
};
legend.labelFormat = function (_) {
if (!arguments.length) return labelFormat;
labelFormat = typeof _ === 'string' ? d3Format.format(_) : _;
return legend;
};
legend.labelOffset = function (_) {
if (!arguments.length) return labelOffset;
labelOffset = +_;
return legend;
};
legend.labelDelimiter = function (_) {
if (!arguments.length) return labelDelimiter;
labelDelimiter = _;
return legend;
};
legend.labelWrap = function (_) {
if (!arguments.length) return labelWrap;
labelWrap = _;
return legend;
};
legend.useClass = function (_) {
if (!arguments.length) return useClass;
if (_ === true || _ === false) {
useClass = _;
}
return legend;
};
legend.orient = function (_) {
if (!arguments.length) return orient;
_ = _.toLowerCase();
if (_ == "horizontal" || _ == "vertical") {
orient = _;
}
return legend;
};
legend.ascending = function (_) {
if (!arguments.length) return ascending;
ascending = !!_;
return legend;
};
legend.classPrefix = function (_) {
if (!arguments.length) return classPrefix;
classPrefix = _;
return legend;
};
legend.title = function (_) {
if (!arguments.length) return title;
title = _;
return legend;
};
legend.titleWidth = function (_) {
if (!arguments.length) return titleWidth;
titleWidth = _;
return legend;
};
legend.textWrap = function (_) {
if (!arguments.length) return textWrap;
textWrap = _;
return legend;
};
legend.on = function () {
var value = legendDispatcher.on.apply(legendDispatcher, arguments);
return value === legendDispatcher ? legend : value;
};
return legend;
}
function size() {
var scale = d3Scale.scaleLinear(),
shape = "rect",
shapeWidth = 15,
shapePadding = 2,
cells = [5],
cellFilter = void 0,
labels = [],
classPrefix = "",
title = "",
labelFormat = d3Format.format(".01f"),
labelOffset = 10,
labelAlign = "middle",
labelDelimiter = "to",
labelWrap = void 0,
orient = "vertical",
ascending = false,
path = void 0,
titleWidth = void 0,
legendDispatcher = d3Dispatch.dispatch("cellover", "cellout", "cellclick");
function legend(svg) {
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter),
legendG = svg.selectAll('g').data([scale]);
if (cellFilter) {
helper.d3_filterCells(type, cellFilter);
}
legendG.enter().append('g').attr('class', classPrefix + 'legendCells');
var cell = svg.select('.' + classPrefix + 'legendCells').selectAll("." + classPrefix + "cell").data(type.data);
var cellEnter = cell.enter().append("g").attr("class", classPrefix + "cell");
cellEnter.append(shape).attr("class", classPrefix + "swatch");
var shapes = svg.selectAll("g." + classPrefix + "cell " + shape);
//add event handlers
helper.d3_addEvents(cellEnter, legendDispatcher);
cell.exit().transition().style("opacity", 0).remove();
//creates shape
if (shape === "line") {
helper.d3_drawShapes(shape, shapes, 0, shapeWidth);
shapes.attr("stroke-width", type.feature);
} else {
helper.d3_drawShapes(shape, shapes, type.feature, type.feature, type.feature, path);
}
var text = helper.d3_addText(svg, cellEnter, type.labels, classPrefix, labelWrap);
// we need to merge the selection, otherwise changes in the legend (e.g. change of orientation) are applied only to the new cells and not the existing ones.
cell = cellEnter.merge(cell);
//sets placement
var textSize = text.nodes().map(function (d) {
return d.getBBox();
}),
shapeSize = shapes.nodes().map(function (d, i) {
var bbox = d.getBBox();
var stroke = scale(type.data[i]);
if (shape === "line" && orient === "horizontal") {
bbox.height = bbox.height + stroke;
} else if (shape === "line" && orient === "vertical") {
bbox.width = bbox.width;
}
return bbox;
});
//console.log('SHAPESIZE')
var maxH = d3Array.max(shapeSize, function (d) {
return d.height + d.y;
}),
maxW = d3Array.max(shapeSize, function (d) {
return d.width + d.x;
});
var cellTrans = void 0,
textTrans = void 0,
textAlign = labelAlign == "start" ? 0 : labelAlign == "middle" ? 0.5 : 1;
//positions cells and text
if (orient === "vertical") {
(function () {
var cellSize = textSize.map(function (d, i) {
return Math.max(d.height, shapeSize[i].height);
});
var y = shape == "circle" || shape == "line" ? shapeSize[0].height / 2 : 0;
cellTrans = function cellTrans(d, i) {
var height = d3Array.sum(cellSize.slice(0, i));
return 'translate(0, ' + (y + height + i * shapePadding) + ')';
};
textTrans = function textTrans(d, i) {
return 'translate( ' + (maxW + labelOffset) + ',\n ' + (shapeSize[i].y + shapeSize[i].height / 2 + 5) + ')';
};
})();
} else if (orient === "horizontal") {
cellTrans = function cellTrans(d, i) {
var width = d3Array.sum(shapeSize.slice(0, i), function (d) {
return d.width;
});
var y = shape == "circle" || shape == "line" ? maxH / 2 : 0;
return 'translate(' + (width + i * shapePadding) + ', ' + y + ')';
};
textTrans = function textTrans(d, i) {
return 'translate( ' + (shapeSize[i].width * textAlign + shapeSize[i].x) + ',\n ' + (maxH + labelOffset) + ')';
};
}
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign);
helper.d3_title(svg, title, classPrefix, titleWidth);
cell.transition().style("opacity", 1);
}
legend.scale = function (_) {
if (!arguments.length) return scale;
scale = _;
return legend;
};
legend.cells = function (_) {
if (!arguments.length) return cells;
if (_.length > 1 || _ >= 2) {
cells = _;
}
return legend;
};
legend.cellFilter = function (_) {
if (!arguments.length) return cellFilter;
cellFilter = _;
return legend;
};
legend.shape = function (_, d) {
if (!arguments.length) return shape;
if (_ == "rect" || _ == "circle" || _ == "line") {
shape = _;
path = d;
}
return legend;
};
legend.shapeWidth = function (_) {
if (!arguments.length) return shapeWidth;
shapeWidth = +_;
return legend;
};
legend.shapePadding = function (_) {
if (!arguments.length) return shapePadding;
shapePadding = +_;
return legend;
};
legend.labels = function (_) {
if (!arguments.length) return labels;
labels = _;
return legend;
};
legend.labelAlign = function (_) {
if (!arguments.length) return labelAlign;
if (_ == "start" || _ == "end" || _ == "middle") {
labelAlign = _;
}
return legend;
};
legend.labelFormat = function (_) {
if (!arguments.length) return labelFormat;
labelFormat = typeof _ === 'string' ? d3Format.format(_) : _;
return legend;
};
legend.labelOffset = function (_) {
if (!arguments.length) return labelOffset;
labelOffset = +_;
return legend;
};
legend.labelDelimiter = function (_) {
if (!arguments.length) return labelDelimiter;
labelDelimiter = _;
return legend;
};
legend.labelWrap = function (_) {
if (!arguments.length) return labelWrap;
labelWrap = _;
return legend;
};
legend.orient = function (_) {
if (!arguments.length) return orient;
_ = _.toLowerCase();
if (_ == "horizontal" || _ == "vertical") {
orient = _;
}
return legend;
};
legend.ascending = function (_) {
if (!arguments.length) return ascending;
ascending = !!_;
return legend;
};
legend.classPrefix = function (_) {
if (!arguments.length) return classPrefix;
classPrefix = _;
return legend;
};
legend.title = function (_) {
if (!arguments.length) return title;
title = _;
return legend;
};
legend.titleWidth = function (_) {
if (!arguments.length) return titleWidth;
titleWidth = _;
return legend;
};
legend.on = function () {
var value = legendDispatcher.on.apply(legendDispatcher, arguments);
return value === legendDispatcher ? legend : value;
};
return legend;
}
function symbol() {
var scale = d3Scale.scaleLinear(),
shape = "path",
shapeWidth = 15,
shapeHeight = 15,
shapeRadius = 10,
shapePadding = 5,
cells = [5],
cellFilter = void 0,
labels = [],
classPrefix = "",
title = "",
labelFormat = d3Format.format(".01f"),
labelAlign = "middle",
labelOffset = 10,
labelDelimiter = "to",
labelWrap = void 0,
orient = "vertical",
ascending = false,
titleWidth = void 0,
legendDispatcher = d3Dispatch.dispatch("cellover", "cellout", "cellclick");
function legend(svg) {
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter),
legendG = svg.selectAll('g').data([scale]);
if (cellFilter) {
helper.d3_filterCells(type, cellFilter);
}
legendG.enter().append('g').attr('class', classPrefix + 'legendCells');
var cell = svg.select('.' + classPrefix + 'legendCells').selectAll("." + classPrefix + "cell").data(type.data);
var cellEnter = cell.enter().append("g").attr("class", classPrefix + "cell");
cellEnter.append(shape).attr("class", classPrefix + "swatch");
var shapes = svg.selectAll("g." + classPrefix + "cell " + shape);
//add event handlers
helper.d3_addEvents(cellEnter, legendDispatcher);
//remove old shapes
cell.exit().transition().style("opacity", 0).remove();
helper.d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, type.feature);
helper.d3_addText(svg, cellEnter, type.labels, classPrefix, labelWrap);
// we need to merge the selection, otherwise changes in the legend (e.g. change of orientation) are applied only to the new cells and not the existing ones.
cell = cellEnter.merge(cell);
// sets placement
var text = cell.selectAll("text"),
textSize = text.nodes().map(function (d) {
return d.getBBox();
}),
shapeSize = shapes.nodes().map(function (d) {
return d.getBBox();
});
var maxH = d3Array.max(shapeSize, function (d) {
return d.height;
}),
maxW = d3Array.max(shapeSize, function (d) {
return d.width;
});
var cellTrans = void 0,
textTrans = void 0,
textAlign = labelAlign == "start" ? 0 : labelAlign == "middle" ? 0.5 : 1;
//positions cells and text
if (orient === "vertical") {
(function () {
var cellSize = textSize.map(function (d, i) {
return Math.max(maxH, d.height);
});
cellTrans = function cellTrans(d, i) {
var height = d3Array.sum(cellSize.slice(0, i));
return 'translate(0, ' + (height + i * shapePadding) + ' )';
};
textTrans = function textTrans(d, i) {
return 'translate( ' + (maxW + labelOffset) + ',\n ' + (shapeSize[i].y + shapeSize[i].height / 2 + 5) + ')';
};
})();
} else if (orient === "horizontal") {
cellTrans = function cellTrans(d, i) {
return 'translate( ' + i * (maxW + shapePadding) + ',0)';
};
textTrans = function textTrans(d, i) {
return 'translate( ' + (shapeSize[i].width * textAlign + shapeSize[i].x) + ',\n ' + (maxH + labelOffset) + ')';
};
}
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign);
helper.d3_title(svg, title, classPrefix, titleWidth);
cell.transition().style("opacity", 1);
}
legend.scale = function (_) {
if (!arguments.length) return scale;
scale = _;
return legend;
};
legend.cells = function (_) {
if (!arguments.length) return cells;
if (_.length > 1 || _ >= 2) {
cells = _;
}
return legend;
};
legend.cellFilter = function (_) {
if (!arguments.length) return cellFilter;
cellFilter = _;
return legend;
};
legend.shapePadding = function (_) {
if (!arguments.length) return shapePadding;
shapePadding = +_;
return legend;
};
legend.labels = function (_) {
if (!arguments.length) return labels;
labels = _;
return legend;
};
legend.labelAlign = function (_) {
if (!arguments.length) return labelAlign;
if (_ == "start" || _ == "end" || _ == "middle") {
labelAlign = _;
}
return legend;
};
legend.labelFormat = function (_) {
if (!arguments.length) return labelFormat;
labelFormat = typeof _ === 'string' ? d3Format.format(_) : _;
return legend;
};
legend.labelOffset = function (_) {
if (!arguments.length) return labelOffset;
labelOffset = +_;
return legend;
};
legend.labelDelimiter = function (_) {
if (!arguments.length) return labelDelimiter;
labelDelimiter = _;
return legend;
};
legend.labelWrap = function (_) {
if (!arguments.length) return labelWrap;
labelWrap = _;
return legend;
};
legend.orient = function (_) {
if (!arguments.length) return orient;
_ = _.toLowerCase();
if (_ == "horizontal" || _ == "vertical") {
orient = _;
}
return legend;
};
legend.ascending = function (_) {
if (!arguments.length) return ascending;
ascending = !!_;
return legend;
};
legend.classPrefix = function (_) {
if (!arguments.length) return classPrefix;
classPrefix = _;
return legend;
};
legend.title = function (_) {
if (!arguments.length) return title;
title = _;
return legend;
};
legend.titleWidth = function (_) {
if (!arguments.length) return titleWidth;
titleWidth = _;
return legend;
};
legend.on = function () {
var value = legendDispatcher.on.apply(legendDispatcher, arguments);
return value === legendDispatcher ? legend : value;
};
return legend;
}
var thresholdLabels = function thresholdLabels(_ref) {
var i = _ref.i,
genLength = _ref.genLength,
generatedLabels = _ref.generatedLabels;
if (i === 0) {
return generatedLabels[i].replace('NaN to', 'Less than');
} else if (i === genLength - 1) {
return 'More than ' + generatedLabels[genLength - 1].replace(' to NaN', '');
}
return generatedLabels[i];
};
var legendHelpers = {
thresholdLabels: thresholdLabels
};
var index = {
legendColor: color,
legendSize: size,
legendSymbol: symbol,
legendHelpers: legendHelpers
};
exports.legendColor = color;
exports.legendSize = size;
exports.legendSymbol = symbol;
exports.legendHelpers = legendHelpers;
exports['default'] = index;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{"d3-array":6,"d3-dispatch":7,"d3-format":8,"d3-scale":9,"d3-selection":10}],6:[function(require,module,exports){
// https://d3js.org/d3-array/ Version 1.0.1. Copyright 2016 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, function (exports) { 'use strict';
function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
function bisector(compare) {
if (compare.length === 1) compare = ascendingComparator(compare);
return {
left: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) < 0) lo = mid + 1;
else hi = mid;
}
return lo;
},
right: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) > 0) hi = mid;
else lo = mid + 1;
}
return lo;
}
};
}
function ascendingComparator(f) {
return function(d, x) {
return ascending(f(d), x);
};
}
var ascendingBisect = bisector(ascending);
var bisectRight = ascendingBisect.right;
var bisectLeft = ascendingBisect.left;
function descending(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
function number(x) {
return x === null ? NaN : +x;
}
function variance(array, f) {
var n = array.length,
m = 0,
a,
d,
s = 0,
i = -1,
j = 0;
if (f == null) {
while (++i < n) {
if (!isNaN(a = number(array[i]))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
}
else {
while (++i < n) {
if (!isNaN(a = number(f(array[i], i, array)))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
}
if (j > 1) return s / (j - 1);
}
function deviation(array, f) {
var v = variance(array, f);
return v ? Math.sqrt(v) : v;
}
function extent(array, f) {
var i = -1,
n = array.length,
a,
b,
c;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; }
while (++i < n) if ((b = array[i]) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = c = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
}
return [a, c];
}
var array = Array.prototype;
var slice = array.slice;
var map = array.map;
function constant(x) {
return function() {
return x;
};
}
function identity(x) {
return x;
}
function range(start, stop, step) {
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
var i = -1,
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
range = new Array(n);
while (++i < n) {
range[i] = start + i * step;
}
return range;
}
var e10 = Math.sqrt(50);
var e5 = Math.sqrt(10);
var e2 = Math.sqrt(2);
function ticks(start, stop, count) {
var step = tickStep(start, stop, count);
return range(
Math.ceil(start / step) * step,
Math.floor(stop / step) * step + step / 2, // inclusive
step
);
}
function tickStep(start, stop, count) {
var step0 = Math.abs(stop - start) / Math.max(0, count),
step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
error = step0 / step1;
if (error >= e10) step1 *= 10;
else if (error >= e5) step1 *= 5;
else if (error >= e2) step1 *= 2;
return stop < start ? -step1 : step1;
}
function sturges(values) {
return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
}
function histogram() {
var value = identity,
domain = extent,
threshold = sturges;
function histogram(data) {
var i,
n = data.length,
x,
values = new Array(n);
for (i = 0; i < n; ++i) {
values[i] = value(data[i], i, data);
}
var xz = domain(values),
x0 = xz[0],
x1 = xz[1],
tz = threshold(values, x0, x1);
// Convert number of thresholds into uniform thresholds.
if (!Array.isArray(tz)) tz = ticks(x0, x1, tz);
// Remove any thresholds outside the domain.
var m = tz.length;
while (tz[0] <= x0) tz.shift(), --m;
while (tz[m - 1] >= x1) tz.pop(), --m;
var bins = new Array(m + 1),
bin;
// Initialize bins.
for (i = 0; i <= m; ++i) {
bin = bins[i] = [];
bin.x0 = i > 0 ? tz[i - 1] : x0;
bin.x1 = i < m ? tz[i] : x1;
}
// Assign data to bins by value, ignoring any outside the domain.
for (i = 0; i < n; ++i) {
x = values[i];
if (x0 <= x && x <= x1) {
bins[bisectRight(tz, x, 0, m)].push(data[i]);
}
}
return bins;
}
histogram.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
};
histogram.domain = function(_) {
return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
};
histogram.thresholds = function(_) {
return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
};
return histogram;
}
function quantile(array, p, f) {
if (f == null) f = number;
if (!(n = array.length)) return;
if ((p = +p) <= 0 || n < 2) return +f(array[0], 0, array);
if (p >= 1) return +f(array[n - 1], n - 1, array);
var n,
h = (n - 1) * p,
i = Math.floor(h),
a = +f(array[i], i, array),
b = +f(array[i + 1], i + 1, array);
return a + (b - a) * (h - i);
}
function freedmanDiaconis(values, min, max) {
values = map.call(values, number).sort(ascending);
return Math.ceil((max - min) / (2 * (quantile(values, 0.75) - quantile(values, 0.25)) * Math.pow(values.length, -1 / 3)));
}
function scott(values, min, max) {
return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
}
function max(array, f) {
var i = -1,
n = array.length,
a,
b;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = array[i]) != null && b > a) a = b;
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null && b > a) a = b;
}
return a;
}
function mean(array, f) {
var s = 0,
n = array.length,
a,
i = -1,
j = n;
if (f == null) {
while (++i < n) if (!isNaN(a = number(array[i]))) s += a; else --j;
}
else {
while (++i < n) if (!isNaN(a = number(f(array[i], i, array)))) s += a; else --j;
}
if (j) return s / j;
}
function median(array, f) {
var numbers = [],
n = array.length,
a,
i = -1;
if (f == null) {
while (++i < n) if (!isNaN(a = number(array[i]))) numbers.push(a);
}
else {
while (++i < n) if (!isNaN(a = number(f(array[i], i, array)))) numbers.push(a);
}
return quantile(numbers.sort(ascending), 0.5);
}
function merge(arrays) {
var n = arrays.length,
m,
i = -1,
j = 0,
merged,
array;
while (++i < n) j += arrays[i].length;
merged = new Array(j);
while (--n >= 0) {
array = arrays[n];
m = array.length;
while (--m >= 0) {
merged[--j] = array[m];
}
}
return merged;
}
function min(array, f) {
var i = -1,
n = array.length,
a,
b;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = array[i]) != null && a > b) a = b;
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null && a > b) a = b;
}
return a;
}
function pairs(array) {
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
while (i < n) pairs[i] = [p, p = array[++i]];
return pairs;
}
function permute(array, indexes) {
var i = indexes.length, permutes = new Array(i);
while (i--) permutes[i] = array[indexes[i]];
return permutes;
}
function scan(array, compare) {
if (!(n = array.length)) return;
var i = 0,
n,
j = 0,
xi,
xj = array[j];
if (!compare) compare = ascending;
while (++i < n) if (compare(xi = array[i], xj) < 0 || compare(xj, xj) !== 0) xj = xi, j = i;
if (compare(xj, xj) === 0) return j;
}
function shuffle(array, i0, i1) {
var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
t,
i;
while (m) {
i = Math.random() * m-- | 0;
t = array[m + i0];
array[m + i0] = array[i + i0];
array[i + i0] = t;
}
return array;
}
function sum(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (f == null) {
while (++i < n) if (a = +array[i]) s += a; // Note: zero and null are equivalent.
}
else {
while (++i < n) if (a = +f(array[i], i, array)) s += a;
}
return s;
}
function transpose(matrix) {
if (!(n = matrix.length)) return [];
for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
row[j] = matrix[j][i];
}
}
return transpose;
}
function length(d) {
return d.length;
}
function zip() {
return transpose(arguments);
}
exports.bisect = bisectRight;
exports.bisectRight = bisectRight;
exports.bisectLeft = bisectLeft;
exports.ascending = ascending;
exports.bisector = bisector;
exports.descending = descending;
exports.deviation = deviation;
exports.extent = extent;
exports.histogram = histogram;
exports.thresholdFreedmanDiaconis = freedmanDiaconis;
exports.thresholdScott = scott;
exports.thresholdSturges = sturges;
exports.max = max;
exports.mean = mean;
exports.median = median;
exports.merge = merge;
exports.min = min;
exports.pairs = pairs;
exports.permute = permute;
exports.quantile = quantile;
exports.range = range;
exports.scan = scan;
exports.shuffle = shuffle;
exports.sum = sum;
exports.ticks = ticks;
exports.tickStep = tickStep;
exports.transpose = transpose;
exports.variance = variance;
exports.zip = zip;
Object.defineProperty(exports, '__esModule', { value: true });
}));
},{}],7:[function(require,module,exports){
// https://d3js.org/d3-dispatch/ Version 1.0.1. Copyright 2016 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, function (exports) { 'use strict';
var noop = {value: function() {}};
function dispatch() {
for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
_[t] = [];
}
return new Dispatch(_);
}
function Dispatch(_) {
this._ = _;
}
function parseTypenames(typenames, types) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
return {type: t, name: name};
});
}
Dispatch.prototype = dispatch.prototype = {
constructor: Dispatch,
on: function(typename, callback) {
var _ = this._,
T = parseTypenames(typename + "", _),
t,
i = -1,
n = T.length;
// If no callback was specified, return the callback of the given type and name.
if (arguments.length < 2) {
while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
return;
}
// If a type was specified, set the callback for the given type and name.
// Otherwise, if a null callback was specified, remove callbacks of the given name.
if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
while (++i < n) {
if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
}
return this;
},
copy: function() {
var copy = {}, _ = this._;
for (var t in _) copy[t] = _[t].slice();
return new Dispatch(copy);
},
call: function(type, that) {
if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
},
apply: function(type, that, args) {
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
}
};
function get(type, name) {
for (var i = 0, n = type.length, c; i < n; ++i) {
if ((c = type[i]).name === name) {
return c.value;
}
}
}
function set(type, name, callback) {
for (var i = 0, n = type.length; i < n; ++i) {
if (type[i].name === name) {
type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
break;
}
}
if (callback != null) type.push({name: name, value: callback});
return type;
}
exports.dispatch = dispatch;
Object.defineProperty(exports, '__esModule', { value: true });
}));
},{}],8:[function(require,module,exports){
// https://d3js.org/d3-format/ Version 1.0.2. Copyright 2016 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, function (exports) { 'use strict';
// Computes the decimal coefficient and exponent of the specified number x with
// significant digits p, where x is positive and p is in [1, 21] or undefined.
// For example, formatDecimal(1.23) returns ["123", 0].