--- /dev/null
+/* nvd3 version 1.7.1(https://github.com/novus/nvd3) 2015-02-08 */
+(function(){
+
+// set up main nv object on window
+var nv = window.nv || {};
+window.nv = nv;
+
+// the major global objects under the nv namespace
+nv.dev = false; //set false when in production
+nv.tooltip = nv.tooltip || {}; // For the tooltip system
+nv.utils = nv.utils || {}; // Utility subsystem
+nv.models = nv.models || {}; //stores all the possible models/components
+nv.charts = {}; //stores all the ready to use charts
+nv.graphs = []; //stores all the graphs currently on the page
+nv.logs = {}; //stores some statistics and potential error messages
+
+nv.dispatch = d3.dispatch('render_start', 'render_end');
+
+// Function bind polyfill
+// Needed ONLY for phantomJS as it's missing until version 2.0 which is unreleased as of this comment
+// https://github.com/ariya/phantomjs/issues/10522
+// http://kangax.github.io/compat-table/es5/#Function.prototype.bind
+// phantomJS is used for running the test suite
+if (!Function.prototype.bind) {
+ Function.prototype.bind = function (oThis) {
+ if (typeof this !== "function") {
+ // closest thing possible to the ECMAScript 5 internal IsCallable function
+ throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
+ }
+
+ var aArgs = Array.prototype.slice.call(arguments, 1),
+ fToBind = this,
+ fNOP = function () {},
+ fBound = function () {
+ return fToBind.apply(this instanceof fNOP && oThis
+ ? this
+ : oThis,
+ aArgs.concat(Array.prototype.slice.call(arguments)));
+ };
+
+ fNOP.prototype = this.prototype;
+ fBound.prototype = new fNOP();
+ return fBound;
+ };
+}
+
+// Development render timers - disabled if dev = false
+if (nv.dev) {
+ nv.dispatch.on('render_start', function(e) {
+ nv.logs.startTime = +new Date();
+ });
+
+ nv.dispatch.on('render_end', function(e) {
+ nv.logs.endTime = +new Date();
+ nv.logs.totalTime = nv.logs.endTime - nv.logs.startTime;
+ nv.log('total', nv.logs.totalTime); // used for development, to keep track of graph generation times
+ });
+}
+
+// Logs all arguments, and returns the last so you can test things in place
+// Note: in IE8 console.log is an object not a function, and if modernizr is used
+// then calling Function.prototype.bind with with anything other than a function
+// causes a TypeError to be thrown.
+nv.log = function() {
+ if (nv.dev && window.console && console.log && console.log.apply)
+ console.log.apply(console, arguments);
+ else if (nv.dev && window.console && typeof console.log == "function" && Function.prototype.bind) {
+ var log = Function.prototype.bind.call(console.log, console);
+ log.apply(console, arguments);
+ }
+ return arguments[arguments.length - 1];
+};
+
+// print console warning, should be used by deprecated functions
+nv.deprecated = function(name) {
+ if (nv.dev && console && console.warn) {
+ console.warn('`' + name + '` has been deprecated.');
+ }
+};
+
+// render function is used to queue up chart rendering
+// in non-blocking timeout functions
+nv.render = function render(step) {
+ // number of graphs to generate in each timeout loop
+ step = step || 1;
+
+ nv.render.active = true;
+ nv.dispatch.render_start();
+
+ setTimeout(function() {
+ var chart, graph;
+
+ for (var i = 0; i < step && (graph = nv.render.queue[i]); i++) {
+ chart = graph.generate();
+ if (typeof graph.callback == typeof(Function)) graph.callback(chart);
+ nv.graphs.push(chart);
+ }
+
+ nv.render.queue.splice(0, i);
+
+ if (nv.render.queue.length) setTimeout(arguments.callee, 0);
+ else {
+ nv.dispatch.render_end();
+ nv.render.active = false;
+ }
+ }, 0);
+};
+
+nv.render.active = false;
+nv.render.queue = [];
+
+// main function to use when adding a new graph, see examples
+nv.addGraph = function(obj) {
+ if (typeof arguments[0] === typeof(Function)) {
+ obj = {generate: arguments[0], callback: arguments[1]};
+ }
+
+ nv.render.queue.push(obj);
+
+ if (!nv.render.active) {
+ nv.render();
+ }
+};/* Utility class to handle creation of an interactive layer.
+ This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch
+ containing the X-coordinate. It can also render a vertical line where the mouse is located.
+
+ dispatch.elementMousemove is the important event to latch onto. It is fired whenever the mouse moves over
+ the rectangle. The dispatch is given one object which contains the mouseX/Y location.
+ It also has 'pointXValue', which is the conversion of mouseX to the x-axis scale.
+ */
+nv.interactiveGuideline = function() {
+ "use strict";
+
+ var tooltip = nv.models.tooltip();
+
+ //Public settings
+ var width = null;
+ var height = null;
+
+ //Please pass in the bounding chart's top and left margins
+ //This is important for calculating the correct mouseX/Y positions.
+ var margin = {left: 0, top: 0}
+ , xScale = d3.scale.linear()
+ , yScale = d3.scale.linear()
+ , dispatch = d3.dispatch('elementMousemove', 'elementMouseout', 'elementClick', 'elementDblclick')
+ , showGuideLine = true;
+ //Must pass in the bounding chart's <svg> container.
+ //The mousemove event is attached to this container.
+ var svgContainer = null;
+
+ // check if IE by looking for activeX
+ var isMSIE = "ActiveXObject" in window;
+
+
+ function layer(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this);
+ var availableWidth = (width || 960), availableHeight = (height || 400);
+ var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer")
+ .data([data]);
+ var wrapEnter = wrap.enter()
+ .append("g").attr("class", " nv-wrap nv-interactiveLineLayer");
+ wrapEnter.append("g").attr("class","nv-interactiveGuideLine");
+
+ if (!svgContainer) {
+ return;
+ }
+
+ function mouseHandler() {
+ var d3mouse = d3.mouse(this);
+ var mouseX = d3mouse[0];
+ var mouseY = d3mouse[1];
+ var subtractMargin = true;
+ var mouseOutAnyReason = false;
+ if (isMSIE) {
+ /*
+ D3.js (or maybe SVG.getScreenCTM) has a nasty bug in Internet Explorer 10.
+ d3.mouse() returns incorrect X,Y mouse coordinates when mouse moving
+ over a rect in IE 10.
+ However, d3.event.offsetX/Y also returns the mouse coordinates
+ relative to the triggering <rect>. So we use offsetX/Y on IE.
+ */
+ mouseX = d3.event.offsetX;
+ mouseY = d3.event.offsetY;
+
+ /*
+ On IE, if you attach a mouse event listener to the <svg> container,
+ it will actually trigger it for all the child elements (like <path>, <circle>, etc).
+ When this happens on IE, the offsetX/Y is set to where ever the child element
+ is located.
+ As a result, we do NOT need to subtract margins to figure out the mouse X/Y
+ position under this scenario. Removing the line below *will* cause
+ the interactive layer to not work right on IE.
+ */
+ if(d3.event.target.tagName !== "svg") {
+ subtractMargin = false;
+ }
+
+ if (d3.event.target.className.baseVal.match("nv-legend")) {
+ mouseOutAnyReason = true;
+ }
+
+ }
+
+ if(subtractMargin) {
+ mouseX -= margin.left;
+ mouseY -= margin.top;
+ }
+
+ /* If mouseX/Y is outside of the chart's bounds,
+ trigger a mouseOut event.
+ */
+ if (mouseX < 0 || mouseY < 0
+ || mouseX > availableWidth || mouseY > availableHeight
+ || (d3.event.relatedTarget && d3.event.relatedTarget.ownerSVGElement === undefined)
+ || mouseOutAnyReason
+ ) {
+
+ if (isMSIE) {
+ if (d3.event.relatedTarget
+ && d3.event.relatedTarget.ownerSVGElement === undefined
+ && d3.event.relatedTarget.className.match(tooltip.nvPointerEventsClass)) {
+
+ return;
+ }
+ }
+ dispatch.elementMouseout({
+ mouseX: mouseX,
+ mouseY: mouseY
+ });
+ layer.renderGuideLine(null); //hide the guideline
+ return;
+ }
+
+ var pointXValue = xScale.invert(mouseX);
+ dispatch.elementMousemove({
+ mouseX: mouseX,
+ mouseY: mouseY,
+ pointXValue: pointXValue
+ });
+
+ //If user double clicks the layer, fire a elementDblclick
+ if (d3.event.type === "dblclick") {
+ dispatch.elementDblclick({
+ mouseX: mouseX,
+ mouseY: mouseY,
+ pointXValue: pointXValue
+ });
+ }
+
+ // if user single clicks the layer, fire elementClick
+ if (d3.event.type === 'click') {
+ dispatch.elementClick({
+ mouseX: mouseX,
+ mouseY: mouseY,
+ pointXValue: pointXValue
+ });
+ }
+ }
+
+ svgContainer
+ .on("mousemove",mouseHandler, true)
+ .on("mouseout" ,mouseHandler,true)
+ .on("dblclick" ,mouseHandler)
+ .on("click", mouseHandler)
+ ;
+
+ //Draws a vertical guideline at the given X postion.
+ layer.renderGuideLine = function(x) {
+ if (!showGuideLine) return;
+ var line = wrap.select(".nv-interactiveGuideLine")
+ .selectAll("line")
+ .data((x != null) ? [nv.utils.NaNtoZero(x)] : [], String);
+
+ line.enter()
+ .append("line")
+ .attr("class", "nv-guideline")
+ .attr("x1", function(d) { return d;})
+ .attr("x2", function(d) { return d;})
+ .attr("y1", availableHeight)
+ .attr("y2",0)
+ ;
+ line.exit().remove();
+
+ }
+ });
+ }
+
+ layer.dispatch = dispatch;
+ layer.tooltip = tooltip;
+
+ layer.margin = function(_) {
+ if (!arguments.length) return margin;
+ margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+ margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+ return layer;
+ };
+
+ layer.width = function(_) {
+ if (!arguments.length) return width;
+ width = _;
+ return layer;
+ };
+
+ layer.height = function(_) {
+ if (!arguments.length) return height;
+ height = _;
+ return layer;
+ };
+
+ layer.xScale = function(_) {
+ if (!arguments.length) return xScale;
+ xScale = _;
+ return layer;
+ };
+
+ layer.showGuideLine = function(_) {
+ if (!arguments.length) return showGuideLine;
+ showGuideLine = _;
+ return layer;
+ };
+
+ layer.svgContainer = function(_) {
+ if (!arguments.length) return svgContainer;
+ svgContainer = _;
+ return layer;
+ };
+
+ return layer;
+};
+
+/* Utility class that uses d3.bisect to find the index in a given array, where a search value can be inserted.
+ This is different from normal bisectLeft; this function finds the nearest index to insert the search value.
+
+ For instance, lets say your array is [1,2,3,5,10,30], and you search for 28.
+ Normal d3.bisectLeft will return 4, because 28 is inserted after the number 10. But interactiveBisect will return 5
+ because 28 is closer to 30 than 10.
+
+ Unit tests can be found in: interactiveBisectTest.html
+
+ Has the following known issues:
+ * Will not work if the data points move backwards (ie, 10,9,8,7, etc) or if the data points are in random order.
+ * Won't work if there are duplicate x coordinate values.
+ */
+nv.interactiveBisect = function (values, searchVal, xAccessor) {
+ "use strict";
+ if (! (values instanceof Array)) {
+ return null;
+ }
+ if (typeof xAccessor !== 'function') {
+ xAccessor = function(d,i) {
+ return d.x;
+ }
+ }
+
+ var bisect = d3.bisector(xAccessor).left;
+ var index = d3.max([0, bisect(values,searchVal) - 1]);
+ var currentValue = xAccessor(values[index], index);
+
+ if (typeof currentValue === 'undefined') {
+ currentValue = index;
+ }
+
+ if (currentValue === searchVal) {
+ return index; //found exact match
+ }
+
+ var nextIndex = d3.min([index+1, values.length - 1]);
+ var nextValue = xAccessor(values[nextIndex], nextIndex);
+
+ if (typeof nextValue === 'undefined') {
+ nextValue = nextIndex;
+ }
+
+ if (Math.abs(nextValue - searchVal) >= Math.abs(currentValue - searchVal)) {
+ return index;
+ } else {
+ return nextIndex
+ }
+};
+
+/*
+ Returns the index in the array "values" that is closest to searchVal.
+ Only returns an index if searchVal is within some "threshold".
+ Otherwise, returns null.
+ */
+nv.nearestValueIndex = function (values, searchVal, threshold) {
+ "use strict";
+ var yDistMax = Infinity, indexToHighlight = null;
+ values.forEach(function(d,i) {
+ var delta = Math.abs(searchVal - d);
+ if ( delta <= yDistMax && delta < threshold) {
+ yDistMax = delta;
+ indexToHighlight = i;
+ }
+ });
+ return indexToHighlight;
+};
+/* Tooltip rendering model for nvd3 charts.
+ window.nv.models.tooltip is the updated,new way to render tooltips.
+
+ window.nv.tooltip.show is the old tooltip code.
+ window.nv.tooltip.* also has various helper methods.
+ */
+(function() {
+ "use strict";
+ window.nv.tooltip = {};
+
+ /* Model which can be instantiated to handle tooltip rendering.
+ Example usage:
+ var tip = nv.models.tooltip().gravity('w').distance(23)
+ .data(myDataObject);
+
+ tip(); //just invoke the returned function to render tooltip.
+ */
+ window.nv.models.tooltip = function() {
+ //HTML contents of the tooltip. If null, the content is generated via the data variable.
+ var content = null;
+
+ /*
+ Tooltip data. If data is given in the proper format, a consistent tooltip is generated.
+ Example Format of data:
+ {
+ key: "Date",
+ value: "August 2009",
+ series: [
+ {key: "Series 1", value: "Value 1", color: "#000"},
+ {key: "Series 2", value: "Value 2", color: "#00f"}
+ ]
+ }
+ */
+ var data = null;
+
+ var gravity = 'w' //Can be 'n','s','e','w'. Determines how tooltip is positioned.
+ ,distance = 50 //Distance to offset tooltip from the mouse location.
+ ,snapDistance = 25 //Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect)
+ , fixedTop = null //If not null, this fixes the top position of the tooltip.
+ , classes = null //Attaches additional CSS classes to the tooltip DIV that is created.
+ , chartContainer = null //Parent DIV, of the SVG Container that holds the chart.
+ , tooltipElem = null //actual DOM element representing the tooltip.
+ , position = {left: null, top: null} //Relative position of the tooltip inside chartContainer.
+ , enabled = true; //True -> tooltips are rendered. False -> don't render tooltips.
+
+ //Generates a unique id when you create a new tooltip() object
+ var id = "nvtooltip-" + Math.floor(Math.random() * 100000);
+
+ //CSS class to specify whether element should not have mouse events.
+ var nvPointerEventsClass = "nv-pointer-events-none";
+
+ //Format function for the tooltip values column
+ var valueFormatter = function(d,i) {
+ return d;
+ };
+
+ //Format function for the tooltip header value.
+ var headerFormatter = function(d) {
+ return d;
+ };
+
+ //By default, the tooltip model renders a beautiful table inside a DIV.
+ //You can override this function if a custom tooltip is desired.
+ var contentGenerator = function(d) {
+ if (content != null) {
+ return content;
+ }
+
+ if (d == null) {
+ return '';
+ }
+
+ var table = d3.select(document.createElement("table"));
+ var theadEnter = table.selectAll("thead")
+ .data([d])
+ .enter().append("thead");
+
+ theadEnter.append("tr")
+ .append("td")
+ .attr("colspan",3)
+ .append("strong")
+ .classed("x-value",true)
+ .html(headerFormatter(d.value));
+
+ var tbodyEnter = table.selectAll("tbody")
+ .data([d])
+ .enter().append("tbody");
+
+ var trowEnter = tbodyEnter.selectAll("tr")
+ .data(function(p) { return p.series})
+ .enter()
+ .append("tr")
+ .classed("highlight", function(p) { return p.highlight});
+
+ trowEnter.append("td")
+ .classed("legend-color-guide",true)
+ .append("div")
+ .style("background-color", function(p) { return p.color});
+
+ trowEnter.append("td")
+ .classed("key",true)
+ .html(function(p) {return p.key});
+
+ trowEnter.append("td")
+ .classed("value",true)
+ .html(function(p,i) { return valueFormatter(p.value,i) });
+
+
+ trowEnter.selectAll("td").each(function(p) {
+ if (p.highlight) {
+ var opacityScale = d3.scale.linear().domain([0,1]).range(["#fff",p.color]);
+ var opacity = 0.6;
+ d3.select(this)
+ .style("border-bottom-color", opacityScale(opacity))
+ .style("border-top-color", opacityScale(opacity))
+ ;
+ }
+ });
+
+ var html = table.node().outerHTML;
+ if (d.footer !== undefined)
+ html += "<div class='footer'>" + d.footer + "</div>";
+ return html;
+
+ };
+
+ var dataSeriesExists = function(d) {
+ if (d && d.series && d.series.length > 0) {
+ return true;
+ }
+ return false;
+ };
+
+ //In situations where the chart is in a 'viewBox', re-position the tooltip based on how far chart is zoomed.
+ function convertViewBoxRatio() {
+ if (chartContainer) {
+ var svg = d3.select(chartContainer);
+ if (svg.node().tagName !== "svg") {
+ svg = svg.select("svg");
+ }
+ var viewBox = (svg.node()) ? svg.attr('viewBox') : null;
+ if (viewBox) {
+ viewBox = viewBox.split(' ');
+ var ratio = parseInt(svg.style('width')) / viewBox[2];
+
+ position.left = position.left * ratio;
+ position.top = position.top * ratio;
+ }
+ }
+ }
+
+ //Creates new tooltip container, or uses existing one on DOM.
+ function getTooltipContainer(newContent) {
+ var body;
+ if (chartContainer) {
+ body = d3.select(chartContainer);
+ } else {
+ body = d3.select("body");
+ }
+
+ var container = body.select(".nvtooltip");
+ if (container.node() === null) {
+ //Create new tooltip div if it doesn't exist on DOM.
+ container = body.append("div")
+ .attr("class", "nvtooltip " + (classes? classes: "xy-tooltip"))
+ .attr("id",id)
+ ;
+ }
+
+ container.node().innerHTML = newContent;
+ container.style("top",0).style("left",0).style("opacity",0);
+ container.selectAll("div, table, td, tr").classed(nvPointerEventsClass,true)
+ container.classed(nvPointerEventsClass,true);
+ return container.node();
+ }
+
+ //Draw the tooltip onto the DOM.
+ function nvtooltip() {
+ if (!enabled) return;
+ if (!dataSeriesExists(data)) return;
+
+ convertViewBoxRatio();
+
+ var left = position.left;
+ var top = (fixedTop != null) ? fixedTop : position.top;
+ var container = getTooltipContainer(contentGenerator(data));
+ tooltipElem = container;
+ if (chartContainer) {
+ var svgComp = chartContainer.getElementsByTagName("svg")[0];
+ var boundRect = (svgComp) ? svgComp.getBoundingClientRect() : chartContainer.getBoundingClientRect();
+ var svgOffset = {left:0,top:0};
+ if (svgComp) {
+ var svgBound = svgComp.getBoundingClientRect();
+ var chartBound = chartContainer.getBoundingClientRect();
+ var svgBoundTop = svgBound.top;
+
+ //Defensive code. Sometimes, svgBoundTop can be a really negative
+ // number, like -134254. That's a bug.
+ // If such a number is found, use zero instead. FireFox bug only
+ if (svgBoundTop < 0) {
+ var containerBound = chartContainer.getBoundingClientRect();
+ svgBoundTop = (Math.abs(svgBoundTop) > containerBound.height) ? 0 : svgBoundTop;
+ }
+ svgOffset.top = Math.abs(svgBoundTop - chartBound.top);
+ svgOffset.left = Math.abs(svgBound.left - chartBound.left);
+ }
+ //If the parent container is an overflow <div> with scrollbars, subtract the scroll offsets.
+ //You need to also add any offset between the <svg> element and its containing <div>
+ //Finally, add any offset of the containing <div> on the whole page.
+ left += chartContainer.offsetLeft + svgOffset.left - 2*chartContainer.scrollLeft;
+ top += chartContainer.offsetTop + svgOffset.top - 2*chartContainer.scrollTop;
+ }
+
+ if (snapDistance && snapDistance > 0) {
+ top = Math.floor(top/snapDistance) * snapDistance;
+ }
+
+ nv.tooltip.calcTooltipPosition([left,top], gravity, distance, container);
+ return nvtooltip;
+ }
+
+ nvtooltip.nvPointerEventsClass = nvPointerEventsClass;
+
+ nvtooltip.content = function(_) {
+ if (!arguments.length) return content;
+ content = _;
+ return nvtooltip;
+ };
+
+ //Returns tooltipElem...not able to set it.
+ nvtooltip.tooltipElem = function() {
+ return tooltipElem;
+ };
+
+ nvtooltip.contentGenerator = function(_) {
+ if (!arguments.length) return contentGenerator;
+ if (typeof _ === 'function') {
+ contentGenerator = _;
+ }
+ return nvtooltip;
+ };
+
+ nvtooltip.data = function(_) {
+ if (!arguments.length) return data;
+ data = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.gravity = function(_) {
+ if (!arguments.length) return gravity;
+ gravity = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.distance = function(_) {
+ if (!arguments.length) return distance;
+ distance = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.snapDistance = function(_) {
+ if (!arguments.length) return snapDistance;
+ snapDistance = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.classes = function(_) {
+ if (!arguments.length) return classes;
+ classes = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.chartContainer = function(_) {
+ if (!arguments.length) return chartContainer;
+ chartContainer = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.position = function(_) {
+ if (!arguments.length) return position;
+ position.left = (typeof _.left !== 'undefined') ? _.left : position.left;
+ position.top = (typeof _.top !== 'undefined') ? _.top : position.top;
+ return nvtooltip;
+ };
+
+ nvtooltip.fixedTop = function(_) {
+ if (!arguments.length) return fixedTop;
+ fixedTop = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.enabled = function(_) {
+ if (!arguments.length) return enabled;
+ enabled = _;
+ return nvtooltip;
+ };
+
+ nvtooltip.valueFormatter = function(_) {
+ if (!arguments.length) return valueFormatter;
+ if (typeof _ === 'function') {
+ valueFormatter = _;
+ }
+ return nvtooltip;
+ };
+
+ nvtooltip.headerFormatter = function(_) {
+ if (!arguments.length) return headerFormatter;
+ if (typeof _ === 'function') {
+ headerFormatter = _;
+ }
+ return nvtooltip;
+ };
+
+ //id() is a read-only function. You can't use it to set the id.
+ nvtooltip.id = function() {
+ return id;
+ };
+
+ return nvtooltip;
+ };
+
+ //Original tooltip.show function. Kept for backward compatibility.
+ // pos = [left,top]
+ nv.tooltip.show = function(pos, content, gravity, dist, parentContainer, classes) {
+
+ //Create new tooltip div if it doesn't exist on DOM.
+ var container = document.createElement('div');
+ container.className = 'nvtooltip ' + (classes ? classes : 'xy-tooltip');
+
+ var body = parentContainer;
+ if ( !parentContainer || parentContainer.tagName.match(/g|svg/i)) {
+ //If the parent element is an SVG element, place tooltip in the <body> element.
+ body = document.getElementsByTagName('body')[0];
+ }
+
+ container.style.left = 0;
+ container.style.top = 0;
+ container.style.opacity = 0;
+ // Content can also be dom element
+ if (typeof content !== 'string')
+ container.appendChild(content);
+ else
+ container.innerHTML = content;
+ body.appendChild(container);
+
+ //If the parent container is an overflow <div> with scrollbars, subtract the scroll offsets.
+ if (parentContainer) {
+ pos[0] = pos[0] - parentContainer.scrollLeft;
+ pos[1] = pos[1] - parentContainer.scrollTop;
+ }
+ nv.tooltip.calcTooltipPosition(pos, gravity, dist, container);
+ };
+
+ //Looks up the ancestry of a DOM element, and returns the first NON-svg node.
+ nv.tooltip.findFirstNonSVGParent = function(Elem) {
+ while(Elem.tagName.match(/^g|svg$/i) !== null) {
+ Elem = Elem.parentNode;
+ }
+ return Elem;
+ };
+
+ //Finds the total offsetTop of a given DOM element.
+ //Looks up the entire ancestry of an element, up to the first relatively positioned element.
+ nv.tooltip.findTotalOffsetTop = function ( Elem, initialTop ) {
+ var offsetTop = initialTop;
+
+ do {
+ if( !isNaN( Elem.offsetTop ) ) {
+ offsetTop += (Elem.offsetTop);
+ }
+ } while( Elem = Elem.offsetParent );
+ return offsetTop;
+ };
+
+ //Finds the total offsetLeft of a given DOM element.
+ //Looks up the entire ancestry of an element, up to the first relatively positioned element.
+ nv.tooltip.findTotalOffsetLeft = function ( Elem, initialLeft) {
+ var offsetLeft = initialLeft;
+
+ do {
+ if( !isNaN( Elem.offsetLeft ) ) {
+ offsetLeft += (Elem.offsetLeft);
+ }
+ } while( Elem = Elem.offsetParent );
+ return offsetLeft;
+ };
+
+ //Global utility function to render a tooltip on the DOM.
+ //pos = [left,top] coordinates of where to place the tooltip, relative to the SVG chart container.
+ //gravity = how to orient the tooltip
+ //dist = how far away from the mouse to place tooltip
+ //container = tooltip DIV
+ nv.tooltip.calcTooltipPosition = function(pos, gravity, dist, container) {
+
+ var height = parseInt(container.offsetHeight),
+ width = parseInt(container.offsetWidth),
+ windowWidth = nv.utils.windowSize().width,
+ windowHeight = nv.utils.windowSize().height,
+ scrollTop = window.pageYOffset,
+ scrollLeft = window.pageXOffset,
+ left, top;
+
+ windowHeight = window.innerWidth >= document.body.scrollWidth ? windowHeight : windowHeight - 16;
+ windowWidth = window.innerHeight >= document.body.scrollHeight ? windowWidth : windowWidth - 16;
+
+ gravity = gravity || 's';
+ dist = dist || 20;
+
+ var tooltipTop = function ( Elem ) {
+ return nv.tooltip.findTotalOffsetTop(Elem, top);
+ };
+
+ var tooltipLeft = function ( Elem ) {
+ return nv.tooltip.findTotalOffsetLeft(Elem,left);
+ };
+
+ switch (gravity) {
+ case 'e':
+ left = pos[0] - width - dist;
+ top = pos[1] - (height / 2);
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft < scrollLeft) left = pos[0] + dist > scrollLeft ? pos[0] + dist : scrollLeft - tLeft + left;
+ if (tTop < scrollTop) top = scrollTop - tTop + top;
+ if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
+ break;
+ case 'w':
+ left = pos[0] + dist;
+ top = pos[1] - (height / 2);
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft + width > windowWidth) left = pos[0] - width - dist;
+ if (tTop < scrollTop) top = scrollTop + 5;
+ if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
+ break;
+ case 'n':
+ left = pos[0] - (width / 2) - 5;
+ top = pos[1] + dist;
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft < scrollLeft) left = scrollLeft + 5;
+ if (tLeft + width > windowWidth) left = left - width/2 + 5;
+ if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
+ break;
+ case 's':
+ left = pos[0] - (width / 2);
+ top = pos[1] - height - dist;
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ if (tLeft < scrollLeft) left = scrollLeft + 5;
+ if (tLeft + width > windowWidth) left = left - width/2 + 5;
+ if (scrollTop > tTop) top = scrollTop;
+ break;
+ case 'none':
+ left = pos[0];
+ top = pos[1] - dist;
+ var tLeft = tooltipLeft(container);
+ var tTop = tooltipTop(container);
+ break;
+ }
+
+ container.style.left = left+'px';
+ container.style.top = top+'px';
+ container.style.opacity = 1;
+ container.style.position = 'absolute';
+
+ return container;
+ };
+
+ //Global utility function to remove tooltips from the DOM.
+ nv.tooltip.cleanup = function() {
+
+ // Find the tooltips, mark them for removal by this class (so others cleanups won't find it)
+ var tooltips = document.getElementsByClassName('nvtooltip');
+ var purging = [];
+ while(tooltips.length) {
+ purging.push(tooltips[0]);
+ tooltips[0].style.transitionDelay = '0 !important';
+ tooltips[0].style.opacity = 0;
+ tooltips[0].className = 'nvtooltip-pending-removal';
+ }
+
+ setTimeout(function() {
+
+ while (purging.length) {
+ var removeMe = purging.pop();
+ removeMe.parentNode.removeChild(removeMe);
+ }
+ }, 500);
+ };
+
+})();
+
+
+/*
+Gets the browser window size
+
+Returns object with height and width properties
+ */
+nv.utils.windowSize = function() {
+ // Sane defaults
+ var size = {width: 640, height: 480};
+
+ // Earlier IE uses Doc.body
+ if (document.body && document.body.offsetWidth) {
+ size.width = document.body.offsetWidth;
+ size.height = document.body.offsetHeight;
+ }
+
+ // IE can use depending on mode it is in
+ if (document.compatMode=='CSS1Compat' &&
+ document.documentElement &&
+ document.documentElement.offsetWidth ) {
+
+ size.width = document.documentElement.offsetWidth;
+ size.height = document.documentElement.offsetHeight;
+ }
+
+ // Most recent browsers use
+ if (window.innerWidth && window.innerHeight) {
+ size.width = window.innerWidth;
+ size.height = window.innerHeight;
+ }
+ return (size);
+};
+
+
+/*
+Binds callback function to run when window is resized
+ */
+nv.utils.windowResize = function(handler) {
+ if (window.addEventListener) {
+ window.addEventListener('resize', handler);
+ } else {
+ nv.log("ERROR: Failed to bind to window.resize with: ", handler);
+ }
+ // return object with clear function to remove the single added callback.
+ return {
+ callback: handler,
+ clear: function() {
+ window.removeEventListener('resize', handler);
+ }
+ }
+};
+
+
+/*
+Backwards compatible way to implement more d3-like coloring of graphs.
+If passed an array, wrap it in a function which implements the old behavior
+Else return what was passed in
+*/
+nv.utils.getColor = function(color) {
+ //if you pass in nothing, get default colors back
+ if (!arguments.length) {
+ return nv.utils.defaultColor();
+
+ //if passed an array, wrap it in a function
+ } else if(color instanceof Array) {
+ return function(d, i) { return d.color || color[i % color.length]; };
+
+ //if passed a function, return the function, or whatever it may be
+ //external libs, such as angularjs-nvd3-directives use this
+ } else {
+ //can't really help it if someone passes rubbish as color
+ return color;
+ }
+};
+
+
+/*
+Default color chooser uses the index of an object as before.
+ */
+nv.utils.defaultColor = function() {
+ var colors = d3.scale.category20().range();
+ return function(d, i) {
+ return d.color || colors[i % colors.length]
+ };
+};
+
+
+/*
+Returns a color function that takes the result of 'getKey' for each series and
+looks for a corresponding color from the dictionary
+*/
+nv.utils.customTheme = function(dictionary, getKey, defaultColors) {
+ // use default series.key if getKey is undefined
+ getKey = getKey || function(series) { return series.key };
+ defaultColors = defaultColors || d3.scale.category20().range();
+
+ // start at end of default color list and walk back to index 0
+ var defIndex = defaultColors.length;
+
+ return function(series, index) {
+ var key = getKey(series);
+ if (typeof dictionary[key] === 'function') {
+ return dictionary[key]();
+ } else if (dictionary[key] !== undefined) {
+ return dictionary[key];
+ } else {
+ // no match in dictionary, use a default color
+ if (!defIndex) {
+ // used all the default colors, start over
+ defIndex = defaultColors.length;
+ }
+ defIndex = defIndex - 1;
+ return defaultColors[defIndex];
+ }
+ };
+};
+
+
+/*
+From the PJAX example on d3js.org, while this is not really directly needed
+it's a very cool method for doing pjax, I may expand upon it a little bit,
+open to suggestions on anything that may be useful
+*/
+nv.utils.pjax = function(links, content) {
+
+ var load = function(href) {
+ d3.html(href, function(fragment) {
+ var target = d3.select(content).node();
+ target.parentNode.replaceChild(
+ d3.select(fragment).select(content).node(),
+ target);
+ nv.utils.pjax(links, content);
+ });
+ };
+
+ d3.selectAll(links).on("click", function() {
+ history.pushState(this.href, this.textContent, this.href);
+ load(this.href);
+ d3.event.preventDefault();
+ });
+
+ d3.select(window).on("popstate", function() {
+ if (d3.event.state) {
+ load(d3.event.state);
+ }
+ });
+};
+
+
+/*
+For when we want to approximate the width in pixels for an SVG:text element.
+Most common instance is when the element is in a display:none; container.
+Forumla is : text.length * font-size * constant_factor
+*/
+nv.utils.calcApproxTextWidth = function (svgTextElem) {
+ if (typeof svgTextElem.style === 'function'
+ && typeof svgTextElem.text === 'function') {
+
+ var fontSize = parseInt(svgTextElem.style("font-size").replace("px",""));
+ var textLength = svgTextElem.text().length;
+ return textLength * fontSize * 0.5;
+ }
+ return 0;
+};
+
+
+/*
+Numbers that are undefined, null or NaN, convert them to zeros.
+*/
+nv.utils.NaNtoZero = function(n) {
+ if (typeof n !== 'number'
+ || isNaN(n)
+ || n === null
+ || n === Infinity
+ || n === -Infinity) {
+
+ return 0;
+ }
+ return n;
+};
+
+/*
+Add a way to watch for d3 transition ends to d3
+*/
+d3.selection.prototype.watchTransition = function(renderWatch){
+ var args = [this].concat([].slice.call(arguments, 1));
+ return renderWatch.transition.apply(renderWatch, args);
+};
+
+
+/*
+Helper object to watch when d3 has rendered something
+*/
+nv.utils.renderWatch = function(dispatch, duration) {
+ if (!(this instanceof nv.utils.renderWatch)) {
+ return new nv.utils.renderWatch(dispatch, duration);
+ }
+
+ var _duration = duration !== undefined ? duration : 250;
+ var renderStack = [];
+ var self = this;
+
+ this.models = function(models) {
+ models = [].slice.call(arguments, 0);
+ models.forEach(function(model){
+ model.__rendered = false;
+ (function(m){
+ m.dispatch.on('renderEnd', function(arg){
+ m.__rendered = true;
+ self.renderEnd('model');
+ });
+ })(model);
+
+ if (renderStack.indexOf(model) < 0) {
+ renderStack.push(model);
+ }
+ });
+ return this;
+ };
+
+ this.reset = function(duration) {
+ if (duration !== undefined) {
+ _duration = duration;
+ }
+ renderStack = [];
+ };
+
+ this.transition = function(selection, args, duration) {
+ args = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
+
+ if (args.length > 1) {
+ duration = args.pop();
+ } else {
+ duration = _duration !== undefined ? _duration : 250;
+ }
+ selection.__rendered = false;
+
+ if (renderStack.indexOf(selection) < 0) {
+ renderStack.push(selection);
+ }
+
+ if (duration === 0) {
+ selection.__rendered = true;
+ selection.delay = function() { return this; };
+ selection.duration = function() { return this; };
+ return selection;
+ } else {
+ if (selection.length === 0) {
+ selection.__rendered = true;
+ } else if (selection.every( function(d){ return !d.length; } )) {
+ selection.__rendered = true;
+ } else {
+ selection.__rendered = false;
+ }
+
+ var n = 0;
+ return selection
+ .transition()
+ .duration(duration)
+ .each(function(){ ++n; })
+ .each('end', function(d, i) {
+ if (--n === 0) {
+ selection.__rendered = true;
+ self.renderEnd.apply(this, args);
+ }
+ });
+ }
+ };
+
+ this.renderEnd = function() {
+ if (renderStack.every( function(d){ return d.__rendered; } )) {
+ renderStack.forEach( function(d){ d.__rendered = false; });
+ dispatch.renderEnd.apply(this, arguments);
+ }
+ }
+
+};
+
+
+/*
+Takes multiple objects and combines them into the first one (dst)
+example: nv.utils.deepExtend({a: 1}, {a: 2, b: 3}, {c: 4});
+gives: {a: 2, b: 3, c: 4}
+*/
+nv.utils.deepExtend = function(dst){
+ var sources = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
+ sources.forEach(function(source) {
+ for (key in source) {
+ var isArray = dst[key] instanceof Array;
+ var isObject = typeof dst[key] === 'object';
+ var srcObj = typeof source[key] === 'object';
+
+ if (isObject && !isArray && srcObj) {
+ nv.utils.deepExtend(dst[key], source[key]);
+ } else {
+ dst[key] = source[key];
+ }
+ }
+ });
+};
+
+
+/*
+state utility object, used to track d3 states in the models
+*/
+nv.utils.state = function(){
+ if (!(this instanceof nv.utils.state)) {
+ return new nv.utils.state();
+ }
+ var state = {};
+ var _self = this;
+ var _setState = function(){};
+ var _getState = function(){ return {}; };
+ var init = null;
+ var changed = null;
+
+ this.dispatch = d3.dispatch('change', 'set');
+
+ this.dispatch.on('set', function(state){
+ _setState(state, true);
+ });
+
+ this.getter = function(fn){
+ _getState = fn;
+ return this;
+ };
+
+ this.setter = function(fn, callback) {
+ if (!callback) {
+ callback = function(){};
+ }
+ _setState = function(state, update){
+ fn(state);
+ if (update) {
+ callback();
+ }
+ };
+ return this;
+ };
+
+ this.init = function(state){
+ init = init || {};
+ nv.utils.deepExtend(init, state);
+ };
+
+ var _set = function(){
+ var settings = _getState();
+
+ if (JSON.stringify(settings) === JSON.stringify(state)) {
+ return false;
+ }
+
+ for (var key in settings) {
+ if (state[key] === undefined) {
+ state[key] = {};
+ }
+ state[key] = settings[key];
+ changed = true;
+ }
+ return true;
+ };
+
+ this.update = function(){
+ if (init) {
+ _setState(init, false);
+ init = null;
+ }
+ if (_set.call(this)) {
+ this.dispatch.change(state);
+ }
+ };
+
+};
+
+
+/*
+Snippet of code you can insert into each nv.models.* to give you the ability to
+do things like:
+chart.options({
+ showXAxis: true,
+ tooltips: true
+});
+
+To enable in the chart:
+chart.options = nv.utils.optionsFunc.bind(chart);
+*/
+nv.utils.optionsFunc = function(args) {
+ nv.deprecated('nv.utils.optionsFunc');
+ if (args) {
+ d3.map(args).forEach((function(key,value) {
+ if (typeof this[key] === "function") {
+ this[key](value);
+ }
+ }).bind(this));
+ }
+ return this;
+};
+
+
+/*
+numTicks: requested number of ticks
+data: the chart data
+
+returns the number of ticks to actually use on X axis, based on chart data
+to avoid duplicate ticks with the same value
+*/
+nv.utils.calcTicksX = function(numTicks, data) {
+ // find max number of values from all data streams
+ var numValues = 1;
+ var i = 0;
+ for (i; i < data.length; i += 1) {
+ var stream_len = data[i] && data[i].values ? data[i].values.length : 0;
+ numValues = stream_len > numValues ? stream_len : numValues;
+ }
+ nv.log("Requested number of ticks: ", numTicks);
+ nv.log("Calculated max values to be: ", numValues);
+ // make sure we don't have more ticks than values to avoid duplicates
+ numTicks = numTicks > numValues ? numTicks = numValues - 1 : numTicks;
+ // make sure we have at least one tick
+ numTicks = numTicks < 1 ? 1 : numTicks;
+ // make sure it's an integer
+ numTicks = Math.floor(numTicks);
+ nv.log("Calculating tick count as: ", numTicks);
+ return numTicks;
+};
+
+
+/*
+returns number of ticks to actually use on Y axis, based on chart data
+*/
+nv.utils.calcTicksY = function(numTicks, data) {
+ // currently uses the same logic but we can adjust here if needed later
+ return nv.utils.calcTicksX(numTicks, data);
+};
+
+
+/*
+Add a particular option from an options object onto chart
+Options exposed on a chart are a getter/setter function that returns chart
+on set to mimic typical d3 option chaining, e.g. svg.option1('a').option2('b');
+
+option objects should be generated via Object.create() to provide
+the option of manipulating data via get/set functions.
+*/
+nv.utils.initOption = function(chart, name) {
+ // if it's a call option, just call it directly, otherwise do get/set
+ if (chart._calls && chart._calls[name]) {
+ chart[name] = chart._calls[name];
+ } else {
+ chart[name] = function (_) {
+ if (!arguments.length) return chart._options[name];
+ chart._options[name] = _;
+ return chart;
+ };
+ }
+};
+
+
+/*
+Add all options in an options object to the chart
+*/
+nv.utils.initOptions = function(chart) {
+ var ops = Object.getOwnPropertyNames(chart._options || {});
+ var calls = Object.getOwnPropertyNames(chart._calls || {});
+ ops = ops.concat(calls);
+ for (var i in ops) {
+ nv.utils.initOption(chart, ops[i]);
+ }
+};
+
+
+/*
+Inherit options from a D3 object
+d3.rebind makes calling the function on target actually call it on source
+Also use _d3options so we can track what we inherit for documentation and chained inheritance
+*/
+nv.utils.inheritOptionsD3 = function(target, d3_source, oplist) {
+ target._d3options = oplist.concat(target._d3options || []);
+ oplist.unshift(d3_source);
+ oplist.unshift(target);
+ d3.rebind.apply(this, oplist);
+};
+
+
+/*
+Remove duplicates from an array
+*/
+nv.utils.arrayUnique = function(a) {
+ return a.sort().filter(function(item, pos) {
+ return !pos || item != a[pos - 1];
+ });
+};
+
+
+/*
+Keeps a list of custom symbols to draw from in addition to d3.svg.symbol
+Necessary since d3 doesn't let you extend its list -_-
+Add new symbols by doing nv.utils.symbols.set('name', function(size){...});
+*/
+nv.utils.symbolMap = d3.map();
+
+
+/*
+Replaces d3.svg.symbol so that we can look both there and our own map
+ */
+nv.utils.symbol = function() {
+ var type,
+ size = 64;
+ function symbol(d,i) {
+ var t = type.call(this,d,i);
+ var s = size.call(this,d,i);
+ if (d3.svg.symbolTypes.indexOf(t) !== -1) {
+ return d3.svg.symbol().type(t).size(s)();
+ } else {
+ return nv.utils.symbolMap.get(t)(s);
+ }
+ }
+ symbol.type = function(_) {
+ if (!arguments.length) return type;
+ type = d3.functor(_);
+ return symbol;
+ };
+ symbol.size = function(_) {
+ if (!arguments.length) return size;
+ size = d3.functor(_);
+ return symbol;
+ };
+ return symbol;
+};
+
+
+/*
+Inherit option getter/setter functions from source to target
+d3.rebind makes calling the function on target actually call it on source
+Also track via _inherited and _d3options so we can track what we inherit
+for documentation generation purposes and chained inheritance
+*/
+nv.utils.inheritOptions = function(target, source) {
+ // inherit all the things
+ var ops = Object.getOwnPropertyNames(source._options || {});
+ var calls = Object.getOwnPropertyNames(source._calls || {});
+ var inherited = source._inherited || [];
+ var d3ops = source._d3options || [];
+ var args = ops.concat(calls).concat(inherited).concat(d3ops);
+ args.unshift(source);
+ args.unshift(target);
+ d3.rebind.apply(this, args);
+ // pass along the lists to keep track of them, don't allow duplicates
+ target._inherited = nv.utils.arrayUnique(ops.concat(calls).concat(inherited).concat(ops).concat(target._inherited || []));
+ target._d3options = nv.utils.arrayUnique(d3ops.concat(target._d3options || []));
+};
+
+
+/*
+Runs common initialize code on the svg before the chart builds
+*/
+nv.utils.initSVG = function(svg) {
+ svg.classed({'nvd3-svg':true});
+};nv.models.axis = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var axis = d3.svg.axis();
+ var scale = d3.scale.linear();
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 75 //only used for tickLabel currently
+ , height = 60 //only used for tickLabel currently
+ , axisLabelText = null
+ , showMaxMin = true //TODO: showMaxMin should be disabled on all ordinal scaled axes
+ , highlightZero = true
+ , rotateLabels = 0
+ , rotateYLabel = true
+ , staggerLabels = false
+ , isOrdinal = false
+ , ticks = null
+ , axisLabelDistance = 0
+ , duration = 250
+ , dispatch = d3.dispatch('renderEnd')
+ , axisRendered = false
+ , maxMinRendered = false
+ ;
+ axis
+ .scale(scale)
+ .orient('bottom')
+ .tickFormat(function(d) { return d })
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var scale0;
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ function chart(selection) {
+ renderWatch.reset();
+ selection.each(function(data) {
+ var container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-axis').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-axis');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g')
+
+ if (ticks !== null)
+ axis.ticks(ticks);
+ else if (axis.orient() == 'top' || axis.orient() == 'bottom')
+ axis.ticks(Math.abs(scale.range()[1] - scale.range()[0]) / 100);
+
+ //TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component
+ g.watchTransition(renderWatch, 'axis').call(axis);
+
+ scale0 = scale0 || axis.scale();
+
+ var fmt = axis.tickFormat();
+ if (fmt == null) {
+ fmt = scale0.tickFormat();
+ }
+
+ var axisLabel = g.selectAll('text.nv-axislabel')
+ .data([axisLabelText || null]);
+ axisLabel.exit().remove();
+
+ switch (axis.orient()) {
+ case 'top':
+ axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+ var w;
+ if (scale.range().length < 2) {
+ w = 0;
+ } else if (scale.range().length === 2) {
+ w = scale.range()[1];
+ } else {
+ w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]);
+ }
+ axisLabel
+ .attr('text-anchor', 'middle')
+ .attr('y', 0)
+ .attr('x', w/2);
+ if (showMaxMin) {
+ var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+ .data(scale.domain());
+ axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text');
+ axisMaxMin.exit().remove();
+ axisMaxMin
+ .attr('transform', function(d,i) {
+ return 'translate(' + nv.utils.NaNtoZero(scale(d)) + ',0)'
+ })
+ .select('text')
+ .attr('dy', '-0.5em')
+ .attr('y', -axis.tickPadding())
+ .attr('text-anchor', 'middle')
+ .text(function(d,i) {
+ var v = fmt(d);
+ return ('' + v).match('NaN') ? '' : v;
+ });
+ axisMaxMin.watchTransition(renderWatch, 'min-max top')
+ .attr('transform', function(d,i) {
+ return 'translate(' + nv.utils.NaNtoZero(scale.range()[i]) + ',0)'
+ });
+ }
+ break;
+ case 'bottom':
+ var xLabelMargin = axisLabelDistance + 36;
+ var maxTextWidth = 30;
+ var xTicks = g.selectAll('g').select("text");
+ if (rotateLabels%360) {
+ //Calculate the longest xTick width
+ xTicks.each(function(d,i){
+ var width = this.getBoundingClientRect().width;
+ if(width > maxTextWidth) maxTextWidth = width;
+ });
+ //Convert to radians before calculating sin. Add 30 to margin for healthy padding.
+ var sin = Math.abs(Math.sin(rotateLabels*Math.PI/180));
+ var xLabelMargin = (sin ? sin*maxTextWidth : maxTextWidth)+30;
+ //Rotate all xTicks
+ xTicks
+ .attr('transform', function(d,i,j) { return 'rotate(' + rotateLabels + ' 0,0)' })
+ .style('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end');
+ }
+ axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+ var w;
+ if (scale.range().length < 2) {
+ w = 0;
+ } else if (scale.range().length === 2) {
+ w = scale.range()[1];
+ } else {
+ w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]);
+ }
+ axisLabel
+ .attr('text-anchor', 'middle')
+ .attr('y', xLabelMargin)
+ .attr('x', w/2);
+ if (showMaxMin) {
+ //if (showMaxMin && !isOrdinal) {
+ var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+ //.data(scale.domain())
+ .data([scale.domain()[0], scale.domain()[scale.domain().length - 1]]);
+ axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text');
+ axisMaxMin.exit().remove();
+ axisMaxMin
+ .attr('transform', function(d,i) {
+ return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)'
+ })
+ .select('text')
+ .attr('dy', '.71em')
+ .attr('y', axis.tickPadding())
+ .attr('transform', function(d,i,j) { return 'rotate(' + rotateLabels + ' 0,0)' })
+ .style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle')
+ .text(function(d,i) {
+ var v = fmt(d);
+ return ('' + v).match('NaN') ? '' : v;
+ });
+ axisMaxMin.watchTransition(renderWatch, 'min-max bottom')
+ .attr('transform', function(d,i) {
+ return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)'
+ });
+ }
+ if (staggerLabels)
+ xTicks
+ .attr('transform', function(d,i) {
+ return 'translate(0,' + (i % 2 == 0 ? '0' : '12') + ')'
+ });
+
+ break;
+ case 'right':
+ axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+ axisLabel
+ .style('text-anchor', rotateYLabel ? 'middle' : 'begin')
+ .attr('transform', rotateYLabel ? 'rotate(90)' : '')
+ .attr('y', rotateYLabel ? (-Math.max(margin.right,width) + 12) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
+ .attr('x', rotateYLabel ? (scale.range()[0] / 2) : axis.tickPadding());
+ if (showMaxMin) {
+ var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+ .data(scale.domain());
+ axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text')
+ .style('opacity', 0);
+ axisMaxMin.exit().remove();
+ axisMaxMin
+ .attr('transform', function(d,i) {
+ return 'translate(0,' + nv.utils.NaNtoZero(scale(d)) + ')'
+ })
+ .select('text')
+ .attr('dy', '.32em')
+ .attr('y', 0)
+ .attr('x', axis.tickPadding())
+ .style('text-anchor', 'start')
+ .text(function(d,i) {
+ var v = fmt(d);
+ return ('' + v).match('NaN') ? '' : v;
+ });
+ axisMaxMin.watchTransition(renderWatch, 'min-max right')
+ .attr('transform', function(d,i) {
+ return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')'
+ })
+ .select('text')
+ .style('opacity', 1);
+ }
+ break;
+ case 'left':
+ /*
+ //For dynamically placing the label. Can be used with dynamically-sized chart axis margins
+ var yTicks = g.selectAll('g').select("text");
+ yTicks.each(function(d,i){
+ var labelPadding = this.getBoundingClientRect().width + axis.tickPadding() + 16;
+ if(labelPadding > width) width = labelPadding;
+ });
+ */
+ axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+ axisLabel
+ .style('text-anchor', rotateYLabel ? 'middle' : 'end')
+ .attr('transform', rotateYLabel ? 'rotate(-90)' : '')
+ .attr('y', rotateYLabel ? (-Math.max(margin.left,width) + 25 - (axisLabelDistance || 0)) : -10)
+ .attr('x', rotateYLabel ? (-scale.range()[0] / 2) : -axis.tickPadding());
+ if (showMaxMin) {
+ var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+ .data(scale.domain());
+ axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text')
+ .style('opacity', 0);
+ axisMaxMin.exit().remove();
+ axisMaxMin
+ .attr('transform', function(d,i) {
+ return 'translate(0,' + nv.utils.NaNtoZero(scale0(d)) + ')'
+ })
+ .select('text')
+ .attr('dy', '.32em')
+ .attr('y', 0)
+ .attr('x', -axis.tickPadding())
+ .attr('text-anchor', 'end')
+ .text(function(d,i) {
+ var v = fmt(d);
+ return ('' + v).match('NaN') ? '' : v;
+ });
+ axisMaxMin.watchTransition(renderWatch, 'min-max right')
+ .attr('transform', function(d,i) {
+ return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')'
+ })
+ .select('text')
+ .style('opacity', 1);
+ }
+ break;
+ }
+ axisLabel.text(function(d) { return d });
+
+ if (showMaxMin && (axis.orient() === 'left' || axis.orient() === 'right')) {
+ //check if max and min overlap other values, if so, hide the values that overlap
+ g.selectAll('g') // the g's wrapping each tick
+ .each(function(d,i) {
+ d3.select(this).select('text').attr('opacity', 1);
+ if (scale(d) < scale.range()[1] + 10 || scale(d) > scale.range()[0] - 10) { // 10 is assuming text height is 16... if d is 0, leave it!
+ if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
+ d3.select(this).attr('opacity', 0);
+
+ d3.select(this).select('text').attr('opacity', 0); // Don't remove the ZERO line!!
+ }
+ });
+
+ //if Max and Min = 0 only show min, Issue #281
+ if (scale.domain()[0] == scale.domain()[1] && scale.domain()[0] == 0) {
+ wrap.selectAll('g.nv-axisMaxMin').style('opacity', function (d, i) {
+ return !i ? 1 : 0
+ });
+ }
+ }
+
+ if (showMaxMin && (axis.orient() === 'top' || axis.orient() === 'bottom')) {
+ var maxMinRange = [];
+ wrap.selectAll('g.nv-axisMaxMin')
+ .each(function(d,i) {
+ try {
+ if (i) // i== 1, max position
+ maxMinRange.push(scale(d) - this.getBoundingClientRect().width - 4) //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
+ else // i==0, min position
+ maxMinRange.push(scale(d) + this.getBoundingClientRect().width + 4)
+ }catch (err) {
+ if (i) // i== 1, max position
+ maxMinRange.push(scale(d) - 4); //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
+ else // i==0, min position
+ maxMinRange.push(scale(d) + 4);
+ }
+ });
+ // the g's wrapping each tick
+ g.selectAll('g').each(function(d,i) {
+ if (scale(d) < maxMinRange[0] || scale(d) > maxMinRange[1]) {
+ if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
+ d3.select(this).remove();
+ else
+ d3.select(this).select('text').remove(); // Don't remove the ZERO line!!
+ }
+ });
+ }
+
+ //highlight zero line ... Maybe should not be an option and should just be in CSS?
+ if (highlightZero) {
+ g.selectAll('.tick')
+ .filter(function (d) {
+ return !parseFloat(Math.round(this.__data__ * 100000) / 1000000) && (this.__data__ !== undefined)
+ }) //this is because sometimes the 0 tick is a very small fraction, TODO: think of cleaner technique
+ .classed('zero', true);
+ }
+ //store old scales for use in transitions on update
+ scale0 = scale.copy();
+
+ });
+
+ renderWatch.renderEnd('axis immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.axis = axis;
+ chart.dispatch = dispatch;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ axisLabelDistance: {get: function(){return axisLabelDistance;}, set: function(_){axisLabelDistance=_;}},
+ staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
+ rotateLabels: {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}},
+ rotateYLabel: {get: function(){return rotateYLabel;}, set: function(_){rotateYLabel=_;}},
+ highlightZero: {get: function(){return highlightZero;}, set: function(_){highlightZero=_;}},
+ showMaxMin: {get: function(){return showMaxMin;}, set: function(_){showMaxMin=_;}},
+ axisLabel: {get: function(){return axisLabelText;}, set: function(_){axisLabelText=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ ticks: {get: function(){return ticks;}, set: function(_){ticks=_;}},
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration=_;
+ renderWatch.reset(duration);
+ }},
+ scale: {get: function(){return scale;}, set: function(_){
+ scale = _;
+ axis.scale(scale);
+ isOrdinal = typeof scale.rangeBands === 'function';
+ nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+ nv.utils.inheritOptionsD3(chart, axis, ['orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat']);
+ nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']);
+
+ return chart;
+};
+
+// Chart design based on the recommendations of Stephen Few. Implementation
+// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
+// http://projects.instantcognition.com/protovis/bulletchart/
+
+nv.models.bullet = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , orient = 'left' // TODO top & bottom
+ , reverse = false
+ , ranges = function(d) { return d.ranges }
+ , markers = function(d) { return d.markers ? d.markers : [0] }
+ , measures = function(d) { return d.measures }
+ , rangeLabels = function(d) { return d.rangeLabels ? d.rangeLabels : [] }
+ , markerLabels = function(d) { return d.markerLabels ? d.markerLabels : [] }
+ , measureLabels = function(d) { return d.measureLabels ? d.measureLabels : [] }
+ , forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
+ , width = 380
+ , height = 30
+ , tickFormat = null
+ , color = nv.utils.getColor(['#1f77b4'])
+ , dispatch = d3.dispatch('elementMouseover', 'elementMouseout')
+ ;
+
+ function chart(selection) {
+ selection.each(function(d, i) {
+ var availableWidth = width - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
+ markerz = markers.call(this, d, i).slice().sort(d3.descending),
+ measurez = measures.call(this, d, i).slice().sort(d3.descending),
+ rangeLabelz = rangeLabels.call(this, d, i).slice(),
+ markerLabelz = markerLabels.call(this, d, i).slice(),
+ measureLabelz = measureLabels.call(this, d, i).slice();
+
+ // Setup Scales
+ // Compute the new x-scale.
+ var x1 = d3.scale.linear()
+ .domain( d3.extent(d3.merge([forceX, rangez])) )
+ .range(reverse ? [availableWidth, 0] : [0, availableWidth]);
+
+ // Retrieve the old x-scale, if this is an update.
+ var x0 = this.__chart__ || d3.scale.linear()
+ .domain([0, Infinity])
+ .range(x1.range());
+
+ // Stash the new scale.
+ this.__chart__ = x1;
+
+ var rangeMin = d3.min(rangez), //rangez[2]
+ rangeMax = d3.max(rangez), //rangez[0]
+ rangeAvg = rangez[1];
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-bullet').data([d]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bullet');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('rect').attr('class', 'nv-range nv-rangeMax');
+ gEnter.append('rect').attr('class', 'nv-range nv-rangeAvg');
+ gEnter.append('rect').attr('class', 'nv-range nv-rangeMin');
+ gEnter.append('rect').attr('class', 'nv-measure');
+ gEnter.append('path').attr('class', 'nv-markerTriangle');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
+ w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
+ var xp0 = function(d) { return d < 0 ? x0(d) : x0(0) },
+ xp1 = function(d) { return d < 0 ? x1(d) : x1(0) };
+
+ g.select('rect.nv-rangeMax')
+ .attr('height', availableHeight)
+ .attr('width', w1(rangeMax > 0 ? rangeMax : rangeMin))
+ .attr('x', xp1(rangeMax > 0 ? rangeMax : rangeMin))
+ .datum(rangeMax > 0 ? rangeMax : rangeMin)
+
+ g.select('rect.nv-rangeAvg')
+ .attr('height', availableHeight)
+ .attr('width', w1(rangeAvg))
+ .attr('x', xp1(rangeAvg))
+ .datum(rangeAvg)
+
+ g.select('rect.nv-rangeMin')
+ .attr('height', availableHeight)
+ .attr('width', w1(rangeMax))
+ .attr('x', xp1(rangeMax))
+ .attr('width', w1(rangeMax > 0 ? rangeMin : rangeMax))
+ .attr('x', xp1(rangeMax > 0 ? rangeMin : rangeMax))
+ .datum(rangeMax > 0 ? rangeMin : rangeMax)
+
+ g.select('rect.nv-measure')
+ .style('fill', color)
+ .attr('height', availableHeight / 3)
+ .attr('y', availableHeight / 3)
+ .attr('width', measurez < 0 ?
+ x1(0) - x1(measurez[0])
+ : x1(measurez[0]) - x1(0))
+ .attr('x', xp1(measurez))
+ .on('mouseover', function() {
+ dispatch.elementMouseover({
+ value: measurez[0],
+ label: measureLabelz[0] || 'Current',
+ pos: [x1(measurez[0]), availableHeight/2]
+ })
+ })
+ .on('mouseout', function() {
+ dispatch.elementMouseout({
+ value: measurez[0],
+ label: measureLabelz[0] || 'Current'
+ })
+ });
+
+ var h3 = availableHeight / 6;
+ if (markerz[0]) {
+ g.selectAll('path.nv-markerTriangle')
+ .attr('transform', function(d) { return 'translate(' + x1(markerz[0]) + ',' + (availableHeight / 2) + ')' })
+ .attr('d', 'M0,' + h3 + 'L' + h3 + ',' + (-h3) + ' ' + (-h3) + ',' + (-h3) + 'Z')
+ .on('mouseover', function() {
+ dispatch.elementMouseover({
+ value: markerz[0],
+ label: markerLabelz[0] || 'Previous',
+ pos: [x1(markerz[0]), availableHeight/2]
+ })
+ })
+ .on('mouseout', function() {
+ dispatch.elementMouseout({
+ value: markerz[0],
+ label: markerLabelz[0] || 'Previous'
+ })
+ });
+ } else {
+ g.selectAll('path.nv-markerTriangle').remove();
+ }
+
+ wrap.selectAll('.nv-range')
+ .on('mouseover', function(d,i) {
+ var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum");
+
+ dispatch.elementMouseover({
+ value: d,
+ label: label,
+ pos: [x1(d), availableHeight/2]
+ })
+ })
+ .on('mouseout', function(d,i) {
+ var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum");
+
+ dispatch.elementMouseout({
+ value: d,
+ label: label
+ })
+ });
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ ranges: {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good)
+ markers: {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal)
+ measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast)
+ forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}},
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ tickFormat: {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom
+ orient = _;
+ reverse = orient == 'right' || orient == 'bottom';
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+ return chart;
+};
+
+
+
+// Chart design based on the recommendations of Stephen Few. Implementation
+// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
+// http://projects.instantcognition.com/protovis/bulletchart/
+nv.models.bulletChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var bullet = nv.models.bullet()
+ ;
+
+ var orient = 'left' // TODO top & bottom
+ , reverse = false
+ , margin = {top: 5, right: 40, bottom: 20, left: 120}
+ , ranges = function(d) { return d.ranges }
+ , markers = function(d) { return d.markers ? d.markers : [0] }
+ , measures = function(d) { return d.measures }
+ , width = null
+ , height = 55
+ , tickFormat = null
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + x + '</h3>' +
+ '<p>' + y + '</p>'
+ }
+ , noData = 'No Data Available.'
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ) + margin.left,
+ top = e.pos[1] + ( offsetElement.offsetTop || 0) + margin.top,
+ content = tooltip(e.key, e.label, e.value, e, chart);
+
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement);
+ };
+
+ function chart(selection) {
+ selection.each(function(d, i) {
+ var container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ that = this;
+
+ chart.update = function() { chart(selection) };
+ chart.container = this;
+
+ // Display No Data message if there's nothing to show.
+ if (!d || !ranges.call(this, d, i)) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', 18 + margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
+ markerz = markers.call(this, d, i).slice().sort(d3.descending),
+ measurez = measures.call(this, d, i).slice().sort(d3.descending);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-bulletWrap');
+ gEnter.append('g').attr('class', 'nv-titles');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ // Compute the new x-scale.
+ var x1 = d3.scale.linear()
+ .domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) // TODO: need to allow forceX and forceY, and xDomain, yDomain
+ .range(reverse ? [availableWidth, 0] : [0, availableWidth]);
+
+ // Retrieve the old x-scale, if this is an update.
+ var x0 = this.__chart__ || d3.scale.linear()
+ .domain([0, Infinity])
+ .range(x1.range());
+
+ // Stash the new scale.
+ this.__chart__ = x1;
+
+ var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
+ w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
+
+ var title = gEnter.select('.nv-titles').append('g')
+ .attr('text-anchor', 'end')
+ .attr('transform', 'translate(-6,' + (height - margin.top - margin.bottom) / 2 + ')');
+ title.append('text')
+ .attr('class', 'nv-title')
+ .text(function(d) { return d.title; });
+
+ title.append('text')
+ .attr('class', 'nv-subtitle')
+ .attr('dy', '1em')
+ .text(function(d) { return d.subtitle; });
+
+ bullet
+ .width(availableWidth)
+ .height(availableHeight)
+
+ var bulletWrap = g.select('.nv-bulletWrap');
+ d3.transition(bulletWrap).call(bullet);
+
+ // Compute the tick format.
+ var format = tickFormat || x1.tickFormat( availableWidth / 100 );
+
+ // Update the tick groups.
+ var tick = g.selectAll('g.nv-tick')
+ .data(x1.ticks( availableWidth / 50 ), function(d) {
+ return this.textContent || format(d);
+ });
+
+ // Initialize the ticks with the old scale, x0.
+ var tickEnter = tick.enter().append('g')
+ .attr('class', 'nv-tick')
+ .attr('transform', function(d) { return 'translate(' + x0(d) + ',0)' })
+ .style('opacity', 1e-6);
+
+ tickEnter.append('line')
+ .attr('y1', availableHeight)
+ .attr('y2', availableHeight * 7 / 6);
+
+ tickEnter.append('text')
+ .attr('text-anchor', 'middle')
+ .attr('dy', '1em')
+ .attr('y', availableHeight * 7 / 6)
+ .text(format);
+
+ // Transition the updating ticks to the new scale, x1.
+ var tickUpdate = d3.transition(tick)
+ .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
+ .style('opacity', 1);
+
+ tickUpdate.select('line')
+ .attr('y1', availableHeight)
+ .attr('y2', availableHeight * 7 / 6);
+
+ tickUpdate.select('text')
+ .attr('y', availableHeight * 7 / 6);
+
+ // Transition the exiting ticks to the new scale, x1.
+ d3.transition(tick.exit())
+ .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
+ .style('opacity', 1e-6)
+ .remove();
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ dispatch.on('tooltipShow', function(e) {
+ e.key = d.title;
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ });
+
+ d3.timer.flush();
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ bullet.dispatch.on('elementMouseover.tooltip', function(e) {
+ dispatch.tooltipShow(e);
+ });
+
+ bullet.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.bullet = bullet;
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ ranges: {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good)
+ markers: {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal)
+ measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast)
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ tickFormat: {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom
+ orient = _;
+ reverse = orient == 'right' || orient == 'bottom';
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, bullet);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+
+
+nv.models.cumulativeLineChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var lines = nv.models.line()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , legend = nv.models.legend()
+ , controls = nv.models.legend()
+ , interactiveLayer = nv.interactiveGuideline()
+ ;
+
+ var margin = {top: 30, right: 30, bottom: 50, left: 60}
+ , color = nv.utils.defaultColor()
+ , width = null
+ , height = null
+ , showLegend = true
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
+ , tooltips = true
+ , showControls = true
+ , useInteractiveGuideline = false
+ , rescaleY = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' at ' + x + '</p>'
+ }
+ , x //can be accessed via chart.xScale()
+ , y //can be accessed via chart.yScale()
+ , id = lines.id()
+ , state = nv.utils.state()
+ , defaultState = null
+ , noData = 'No Data Available.'
+ , average = function(d) { return d.average }
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd')
+ , transitionDuration = 250
+ , duration = 250
+ , noErrorCheck = false //if set to TRUE, will bypass an error check in the indexify function.
+ ;
+
+ state.index = 0;
+ state.rescaleY = rescaleY;
+
+ xAxis
+ .orient('bottom')
+ .tickPadding(7)
+ ;
+ yAxis
+ .orient((rightAlignYAxis) ? 'right' : 'left')
+ ;
+
+ controls.updateState(false);
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var dx = d3.scale.linear()
+ , index = {i: 0, x: 0}
+ , renderWatch = nv.utils.renderWatch(dispatch, duration)
+ ;
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, null, null, offsetElement);
+ };
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled }),
+ index: index.i,
+ rescaleY: rescaleY
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.index !== undefined)
+ index.i = state.index;
+ if (state.rescaleY !== undefined)
+ rescaleY = state.rescaleY;
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(lines);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+ selection.each(function(data) {
+ var container = d3.select(this);
+ nv.utils.initSVG(container);
+ container.classed('nv-chart-' + id, true);
+ var that = this;
+
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ chart.update = function() {
+ if (duration === 0)
+ container.call(chart);
+ else
+ container.transition().duration(duration).call(chart)
+ };
+ chart.container = this;
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disableddisabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ var indexDrag = d3.behavior.drag()
+ .on('dragstart', dragStart)
+ .on('drag', dragMove)
+ .on('dragend', dragEnd);
+
+
+ function dragStart(d,i) {
+ d3.select(chart.container)
+ .style('cursor', 'ew-resize');
+ }
+
+ function dragMove(d,i) {
+ index.x = d3.event.x;
+ index.i = Math.round(dx.invert(index.x));
+ updateZero();
+ }
+
+ function dragEnd(d,i) {
+ d3.select(chart.container)
+ .style('cursor', 'auto');
+
+ // update state and send stateChange with new index
+ state.index = index.i;
+ dispatch.stateChange(state);
+ }
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = lines.xScale();
+ y = lines.yScale();
+
+ if (!rescaleY) {
+ var seriesDomains = data
+ .filter(function(series) { return !series.disabled })
+ .map(function(series,i) {
+ var initialDomain = d3.extent(series.values, lines.y());
+
+ //account for series being disabled when losing 95% or more
+ if (initialDomain[0] < -.95) initialDomain[0] = -.95;
+
+ return [
+ (initialDomain[0] - initialDomain[1]) / (1 + initialDomain[1]),
+ (initialDomain[1] - initialDomain[0]) / (1 + initialDomain[0])
+ ];
+ });
+
+ var completeDomain = [
+ d3.min(seriesDomains, function(d) { return d[0] }),
+ d3.max(seriesDomains, function(d) { return d[1] })
+ ];
+
+ lines.yDomain(completeDomain);
+ } else {
+ lines.yDomain(null);
+ }
+
+ dx.domain([0, data[0].values.length - 1]) //Assumes all series have same length
+ .range([0, availableWidth])
+ .clamp(true);
+
+ var data = indexify(index.i, data);
+
+ // Setup containers and skeleton of chart
+ var interactivePointerEvents = (useInteractiveGuideline) ? "none" : "all";
+ var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-cumulativeLine').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-interactive');
+ gEnter.append('g').attr('class', 'nv-x nv-axis').style("pointer-events","none");
+ gEnter.append('g').attr('class', 'nv-y nv-axis');
+ gEnter.append('g').attr('class', 'nv-background');
+ gEnter.append('g').attr('class', 'nv-linesWrap').style("pointer-events",interactivePointerEvents);
+ gEnter.append('g').attr('class', 'nv-avgLinesWrap').style("pointer-events","none");
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+ gEnter.append('g').attr('class', 'nv-controlsWrap');
+
+ // Legend
+ if (showLegend) {
+ legend.width(availableWidth);
+
+ g.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ g.select('.nv-legendWrap')
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
+ }
+
+ // Controls
+ if (showControls) {
+ var controlsData = [
+ { key: 'Re-scale y-axis', disabled: !rescaleY }
+ ];
+
+ controls
+ .width(140)
+ .color(['#444', '#444', '#444'])
+ .rightAlign(false)
+ .margin({top: 5, right: 0, bottom: 5, left: 20})
+ ;
+
+ g.select('.nv-controlsWrap')
+ .datum(controlsData)
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
+ .call(controls);
+ }
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
+
+ // Show error if series goes below 100%
+ var tempDisabled = data.filter(function(d) { return d.tempDisabled });
+
+ wrap.select('.tempDisabled').remove(); //clean-up and prevent duplicates
+ if (tempDisabled.length) {
+ wrap.append('text').attr('class', 'tempDisabled')
+ .attr('x', availableWidth / 2)
+ .attr('y', '-.71em')
+ .style('text-anchor', 'end')
+ .text(tempDisabled.map(function(d) { return d.key }).join(', ') + ' values cannot be calculated for this time period.');
+ }
+
+ //Set up interactive layer
+ if (useInteractiveGuideline) {
+ interactiveLayer
+ .width(availableWidth)
+ .height(availableHeight)
+ .margin({left:margin.left,top:margin.top})
+ .svgContainer(container)
+ .xScale(x);
+ wrap.select(".nv-interactive").call(interactiveLayer);
+ }
+
+ gEnter.select('.nv-background')
+ .append('rect');
+
+ g.select('.nv-background rect')
+ .attr('width', availableWidth)
+ .attr('height', availableHeight);
+
+ lines
+ //.x(function(d) { return d.x })
+ .y(function(d) { return d.display.y })
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled && !data[i].tempDisabled; }));
+
+ var linesWrap = g.select('.nv-linesWrap')
+ .datum(data.filter(function(d) { return !d.disabled && !d.tempDisabled }));
+
+ linesWrap.call(lines);
+
+ //Store a series index number in the data array.
+ data.forEach(function(d,i) {
+ d.seriesIndex = i;
+ });
+
+ var avgLineData = data.filter(function(d) {
+ return !d.disabled && !!average(d);
+ });
+
+ var avgLines = g.select(".nv-avgLinesWrap").selectAll("line")
+ .data(avgLineData, function(d) { return d.key; });
+
+ var getAvgLineY = function(d) {
+ //If average lines go off the svg element, clamp them to the svg bounds.
+ var yVal = y(average(d));
+ if (yVal < 0) return 0;
+ if (yVal > availableHeight) return availableHeight;
+ return yVal;
+ };
+
+ avgLines.enter()
+ .append('line')
+ .style('stroke-width',2)
+ .style('stroke-dasharray','10,10')
+ .style('stroke',function (d,i) {
+ return lines.color()(d,d.seriesIndex);
+ })
+ .attr('x1',0)
+ .attr('x2',availableWidth)
+ .attr('y1', getAvgLineY)
+ .attr('y2', getAvgLineY);
+
+ avgLines
+ .style('stroke-opacity',function(d){
+ //If average lines go offscreen, make them transparent
+ var yVal = y(average(d));
+ if (yVal < 0 || yVal > availableHeight) return 0;
+ return 1;
+ })
+ .attr('x1',0)
+ .attr('x2',availableWidth)
+ .attr('y1', getAvgLineY)
+ .attr('y2', getAvgLineY);
+
+ avgLines.exit().remove();
+
+ //Create index line
+ var indexLine = linesWrap.selectAll('.nv-indexLine')
+ .data([index]);
+ indexLine.enter().append('rect').attr('class', 'nv-indexLine')
+ .attr('width', 3)
+ .attr('x', -2)
+ .attr('fill', 'red')
+ .attr('fill-opacity', .5)
+ .style("pointer-events","all")
+ .call(indexDrag);
+
+ indexLine
+ .attr('transform', function(d) { return 'translate(' + dx(d.i) + ',0)' })
+ .attr('height', availableHeight);
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ .ticks( nv.utils.calcTicksX(availableWidth/70, data) )
+ .tickSize(-availableHeight, 0);
+
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y.range()[0] + ')');
+ g.select('.nv-x.nv-axis')
+ .call(xAxis);
+ }
+
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ g.select('.nv-y.nv-axis')
+ .call(yAxis);
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ function updateZero() {
+ indexLine
+ .data([index]);
+
+ //When dragging the index line, turn off line transitions.
+ // Then turn them back on when done dragging.
+ var oldDuration = chart.duration();
+ chart.duration(0);
+ chart.update();
+ chart.duration(oldDuration);
+ }
+
+ g.select('.nv-background rect')
+ .on('click', function() {
+ index.x = d3.mouse(this)[0];
+ index.i = Math.round(dx.invert(index.x));
+
+ // update state and send stateChange with new index
+ state.index = index.i;
+ dispatch.stateChange(state);
+
+ updateZero();
+ });
+
+ lines.dispatch.on('elementClick', function(e) {
+ index.i = e.pointIndex;
+ index.x = dx(index.i);
+
+ // update state and send stateChange with new index
+ state.index = index.i;
+ dispatch.stateChange(state);
+
+ updateZero();
+ });
+
+ controls.dispatch.on('legendClick', function(d,i) {
+ d.disabled = !d.disabled;
+ rescaleY = !d.disabled;
+
+ state.rescaleY = rescaleY;
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ interactiveLayer.dispatch.on('elementMousemove', function(e) {
+ lines.clearHighlights();
+ var singlePoint, pointIndex, pointXLocation, allData = [];
+
+ data
+ .filter(function(series, i) {
+ series.seriesIndex = i;
+ return !series.disabled;
+ })
+ .forEach(function(series,i) {
+ pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
+ lines.highlightPoint(i, pointIndex, true);
+ var point = series.values[pointIndex];
+ if (typeof point === 'undefined') return;
+ if (typeof singlePoint === 'undefined') singlePoint = point;
+ if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
+ allData.push({
+ key: series.key,
+ value: chart.y()(point, pointIndex),
+ color: color(series,series.seriesIndex)
+ });
+ });
+
+ //Highlight the tooltip entry based on which point the mouse is closest to.
+ if (allData.length > 2) {
+ var yValue = chart.yScale().invert(e.mouseY);
+ var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
+ var threshold = 0.03 * domainExtent;
+ var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold);
+ if (indexToHighlight !== null)
+ allData[indexToHighlight].highlight = true;
+ }
+
+ var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex), pointIndex);
+ interactiveLayer.tooltip
+ .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
+ .chartContainer(that.parentNode)
+ .enabled(tooltips)
+ .valueFormatter(function(d,i) {
+ return yAxis.tickFormat()(d);
+ })
+ .data(
+ {
+ value: xValue,
+ series: allData
+ }
+ )();
+
+ interactiveLayer.renderGuideLine(pointXLocation);
+ });
+
+ interactiveLayer.dispatch.on("elementMouseout",function(e) {
+ dispatch.tooltipHide();
+ lines.clearHighlights();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ // Update chart from a state object passed to event handler
+ dispatch.on('changeState', function(e) {
+
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+
+ state.disabled = e.disabled;
+ }
+
+ if (typeof e.index !== 'undefined') {
+ index.i = e.index;
+ index.x = dx(index.i);
+
+ state.index = e.index;
+
+ indexLine
+ .data([index]);
+ }
+
+ if (typeof e.rescaleY !== 'undefined') {
+ rescaleY = e.rescaleY;
+ }
+
+ chart.update();
+ });
+
+ });
+
+ renderWatch.renderEnd('cumulativeLineChart immediate');
+
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ lines.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Functions
+ //------------------------------------------------------------
+
+ var indexifyYGetter = null;
+ /* Normalize the data according to an index point. */
+ function indexify(idx, data) {
+ if (!indexifyYGetter) indexifyYGetter = lines.y();
+ return data.map(function(line, i) {
+ if (!line.values) {
+ return line;
+ }
+ var indexValue = line.values[idx];
+ if (indexValue == null) {
+ return line;
+ }
+ var v = indexifyYGetter(indexValue, idx);
+
+ //TODO: implement check below, and disable series if series loses 100% or more cause divide by 0 issue
+ if (v < -.95 && !noErrorCheck) {
+ //if a series loses more than 100%, calculations fail.. anything close can cause major distortion (but is mathematically correct till it hits 100)
+
+ line.tempDisabled = true;
+ return line;
+ }
+
+ line.tempDisabled = false;
+
+ line.values = line.values.map(function(point, pointIndex) {
+ point.display = {'y': (indexifyYGetter(point, pointIndex) - v) / (1 + v) };
+ return point;
+ });
+
+ return line;
+ })
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.lines = lines;
+ chart.legend = legend;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.interactiveLayer = interactiveLayer;
+ chart.state = state;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ rescaleY: {get: function(){return rescaleY;}, set: function(_){rescaleY=_;}},
+ showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ average: {get: function(){return average;}, set: function(_){average=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ noErrorCheck: {get: function(){return noErrorCheck;}, set: function(_){noErrorCheck=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ }},
+ useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
+ useInteractiveGuideline = _;
+ if (_ === true) {
+ chart.interactive(false);
+ chart.useVoronoi(false);
+ }
+ }},
+ rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
+ rightAlignYAxis = _;
+ yAxis.orient( (_) ? 'right' : 'left');
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ lines.duration(duration);
+ xAxis.duration(duration);
+ yAxis.duration(duration);
+ renderWatch.reset(duration);
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, lines);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};//TODO: consider deprecating by adding necessary features to multiBar model
+nv.models.discreteBar = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 960
+ , height = 500
+ , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
+ , x = d3.scale.ordinal()
+ , y = d3.scale.linear()
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
+ , color = nv.utils.defaultColor()
+ , showValues = false
+ , valueFormat = d3.format(',.2f')
+ , xDomain
+ , yDomain
+ , xRange
+ , yRange
+ , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout','renderEnd')
+ , rectClass = 'discreteBar'
+ , duration = 250
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var x0, y0;
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ function chart(selection) {
+ renderWatch.reset();
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ //add series index to each data point for reference
+ data.forEach(function(series, i) {
+ series.values.forEach(function(point) {
+ point.series = i;
+ });
+ });
+
+ // Setup Scales
+ // remap and flatten the data for use in calculating the scales' domains
+ var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
+ data.map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: getX(d,i), y: getY(d,i), y0: d.y0 }
+ })
+ });
+
+ x .domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
+ .rangeBands(xRange || [0, availableWidth], .1);
+ y .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY)));
+
+ // If showValues, pad the Y axis range to account for label height
+ if (showValues) y.range(yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]);
+ else y.range(yRange || [availableHeight, 0]);
+
+ //store old scales if they exist
+ x0 = x0 || x;
+ y0 = y0 || y.copy().range([y(0),y(0)]);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discretebar');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-groups');
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ //TODO: by definition, the discrete bar should not have multiple groups, will modify/remove later
+ var groups = wrap.select('.nv-groups').selectAll('.nv-group')
+ .data(function(d) { return d }, function(d) { return d.key });
+ groups.enter().append('g')
+ .style('stroke-opacity', 1e-6)
+ .style('fill-opacity', 1e-6);
+ groups.exit()
+ .watchTransition(renderWatch, 'discreteBar: exit groups')
+ .style('stroke-opacity', 1e-6)
+ .style('fill-opacity', 1e-6)
+ .remove();
+ groups
+ .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
+ .classed('hover', function(d) { return d.hover });
+ groups
+ .watchTransition(renderWatch, 'discreteBar: groups')
+ .style('stroke-opacity', 1)
+ .style('fill-opacity', .75);
+
+ var bars = groups.selectAll('g.nv-bar')
+ .data(function(d) { return d.values });
+ bars.exit().remove();
+
+ var barsEnter = bars.enter().append('g')
+ .attr('transform', function(d,i,j) {
+ return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')'
+ })
+ .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
+ d3.select(this).classed('hover', true);
+ dispatch.elementMouseover({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (d.series + .5) / data.length), y(getY(d,i))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ })
+ .on('mouseout', function(d,i) {
+ d3.select(this).classed('hover', false);
+ dispatch.elementMouseout({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ })
+ .on('click', function(d,i) {
+ dispatch.elementClick({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (d.series + .5) / data.length), y(getY(d,i))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ d3.event.stopPropagation();
+ })
+ .on('dblclick', function(d,i) {
+ dispatch.elementDblClick({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (d.series + .5) / data.length), y(getY(d,i))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ d3.event.stopPropagation();
+ });
+
+ barsEnter.append('rect')
+ .attr('height', 0)
+ .attr('width', x.rangeBand() * .9 / data.length )
+
+ if (showValues) {
+ barsEnter.append('text')
+ .attr('text-anchor', 'middle')
+ ;
+
+ bars.select('text')
+ .text(function(d,i) { return valueFormat(getY(d,i)) })
+ .watchTransition(renderWatch, 'discreteBar: bars text')
+ .attr('x', x.rangeBand() * .9 / 2)
+ .attr('y', function(d,i) { return getY(d,i) < 0 ? y(getY(d,i)) - y(0) + 12 : -4 })
+
+ ;
+ } else {
+ bars.selectAll('text').remove();
+ }
+
+ bars
+ .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive' })
+ .style('fill', function(d,i) { return d.color || color(d,i) })
+ .style('stroke', function(d,i) { return d.color || color(d,i) })
+ .select('rect')
+ .attr('class', rectClass)
+ .watchTransition(renderWatch, 'discreteBar: bars rect')
+ .attr('width', x.rangeBand() * .9 / data.length);
+ bars.watchTransition(renderWatch, 'discreteBar: bars')
+ //.delay(function(d,i) { return i * 1200 / data[0].values.length })
+ .attr('transform', function(d,i) {
+ var left = x(getX(d,i)) + x.rangeBand() * .05,
+ top = getY(d,i) < 0 ?
+ y(0) :
+ y(0) - y(getY(d,i)) < 1 ?
+ y(0) - 1 : //make 1 px positive bars show up above y=0
+ y(getY(d,i));
+
+ return 'translate(' + left + ', ' + top + ')'
+ })
+ .select('rect')
+ .attr('height', function(d,i) {
+ return Math.max(Math.abs(y(getY(d,i)) - y((yDomain && yDomain[0]) || 0)) || 1)
+ });
+
+
+ //store old scales for use in transitions on update
+ x0 = x.copy();
+ y0 = y.copy();
+
+ });
+
+ renderWatch.renderEnd('discreteBar immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}},
+ showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}},
+ x: {get: function(){return getX;}, set: function(_){getX=_;}},
+ y: {get: function(){return getY;}, set: function(_){getY=_;}},
+ xScale: {get: function(){return x;}, set: function(_){x=_;}},
+ yScale: {get: function(){return y;}, set: function(_){y=_;}},
+ xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
+ yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
+ xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
+ yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
+ valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}},
+ id: {get: function(){return id;}, set: function(_){id=_;}},
+ rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.discreteBarChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var discretebar = nv.models.discreteBar()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ ;
+
+ var margin = {top: 15, right: 10, bottom: 50, left: 60}
+ , width = null
+ , height = null
+ , color = nv.utils.getColor()
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
+ , staggerLabels = false
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + x + '</h3>' +
+ '<p>' + y + '</p>'
+ }
+ , x
+ , y
+ , noData = "No Data Available."
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'beforeUpdate','renderEnd')
+ , duration = 250
+ ;
+
+ xAxis
+ .orient('bottom')
+ .highlightZero(false)
+ .showMaxMin(false)
+ .tickFormat(function(d) { return d })
+ ;
+ yAxis
+ .orient((rightAlignYAxis) ? 'right' : 'left')
+ .tickFormat(d3.format(',.1f'))
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(discretebar.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(discretebar.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+ };
+
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(discretebar);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ chart.update = function() {
+ dispatch.beforeUpdate();
+ container.transition().duration(duration).call(chart);
+ };
+ chart.container = this;
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = discretebar.xScale();
+ y = discretebar.yScale().clamp(true);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-discreteBarWithAxes').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discreteBarWithAxes').append('g');
+ var defsEnter = gEnter.append('defs');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-y nv-axis')
+ .append('g').attr('class', 'nv-zeroLine')
+ .append('line');
+
+ gEnter.append('g').attr('class', 'nv-barsWrap');
+
+ g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
+
+ // Main Chart Component(s)
+ discretebar
+ .width(availableWidth)
+ .height(availableHeight);
+
+ var barsWrap = g.select('.nv-barsWrap')
+ .datum(data.filter(function(d) { return !d.disabled }))
+
+ barsWrap.transition().call(discretebar);
+
+
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-x-label-clip-' + discretebar.id())
+ .append('rect');
+
+ g.select('#nv-x-label-clip-' + discretebar.id() + ' rect')
+ .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1))
+ .attr('height', 16)
+ .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 ));
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize(-availableHeight, 0);
+
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + (y.range()[0] + ((discretebar.showValues() && y.domain()[0] < 0) ? 16 : 0)) + ')');
+ g.select('.nv-x.nv-axis').call(xAxis);
+
+ var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
+ if (staggerLabels) {
+ xTicks
+ .selectAll('text')
+ .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')' })
+ }
+ }
+
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ g.select('.nv-y.nv-axis').call(yAxis);
+ }
+
+ // Zero line
+ g.select(".nv-zeroLine line")
+ .attr("x1",0)
+ .attr("x2",availableWidth)
+ .attr("y1", y(0))
+ .attr("y2", y(0))
+ ;
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ });
+
+ renderWatch.renderEnd('discreteBar chart immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ discretebar.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ discretebar.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.discretebar = discretebar;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ discretebar.duration(duration);
+ xAxis.duration(duration);
+ yAxis.duration(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ discretebar.color(color);
+ }},
+ rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
+ rightAlignYAxis = _;
+ yAxis.orient( (_) ? 'right' : 'left');
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, discretebar);
+ nv.utils.initOptions(chart);
+
+ return chart;
+}
+
+nv.models.distribution = function() {
+ "use strict";
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 400 //technically width or height depending on x or y....
+ , size = 8
+ , axis = 'x' // 'x' or 'y'... horizontal or vertical
+ , getData = function(d) { return d[axis] } // defaults d.x or d.y
+ , color = nv.utils.defaultColor()
+ , scale = d3.scale.linear()
+ , domain
+ , duration = 250
+ , dispatch = d3.dispatch('renderEnd')
+ ;
+
+ //============================================================
+
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var scale0;
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ //============================================================
+
+
+ function chart(selection) {
+ renderWatch.reset();
+ selection.each(function(data) {
+ var availableLength = width - (axis === 'x' ? margin.left + margin.right : margin.top + margin.bottom),
+ naxis = axis == 'x' ? 'y' : 'x',
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ //------------------------------------------------------------
+ // Setup Scales
+
+ scale0 = scale0 || scale;
+
+ //------------------------------------------------------------
+
+
+ //------------------------------------------------------------
+ // Setup containers and skeleton of chart
+
+ var wrap = container.selectAll('g.nv-distribution').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-distribution');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
+
+ //------------------------------------------------------------
+
+
+ var distWrap = g.selectAll('g.nv-dist')
+ .data(function(d) { return d }, function(d) { return d.key });
+
+ distWrap.enter().append('g');
+ distWrap
+ .attr('class', function(d,i) { return 'nv-dist nv-series-' + i })
+ .style('stroke', function(d,i) { return color(d, i) });
+
+ var dist = distWrap.selectAll('line.nv-dist' + axis)
+ .data(function(d) { return d.values })
+ dist.enter().append('line')
+ .attr(axis + '1', function(d,i) { return scale0(getData(d,i)) })
+ .attr(axis + '2', function(d,i) { return scale0(getData(d,i)) })
+ renderWatch.transition(distWrap.exit().selectAll('line.nv-dist' + axis), 'dist exit')
+ // .transition()
+ .attr(axis + '1', function(d,i) { return scale(getData(d,i)) })
+ .attr(axis + '2', function(d,i) { return scale(getData(d,i)) })
+ .style('stroke-opacity', 0)
+ .remove();
+ dist
+ .attr('class', function(d,i) { return 'nv-dist' + axis + ' nv-dist' + axis + '-' + i })
+ .attr(naxis + '1', 0)
+ .attr(naxis + '2', size);
+ renderWatch.transition(dist, 'dist')
+ // .transition()
+ .attr(axis + '1', function(d,i) { return scale(getData(d,i)) })
+ .attr(axis + '2', function(d,i) { return scale(getData(d,i)) })
+
+
+ scale0 = scale.copy();
+
+ });
+ renderWatch.renderEnd('distribution immediate');
+ return chart;
+ }
+
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+ chart.options = nv.utils.optionsFunc.bind(chart);
+ chart.dispatch = dispatch;
+
+ chart.margin = function(_) {
+ if (!arguments.length) return margin;
+ margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+ margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+ margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+ margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+ return chart;
+ };
+
+ chart.width = function(_) {
+ if (!arguments.length) return width;
+ width = _;
+ return chart;
+ };
+
+ chart.axis = function(_) {
+ if (!arguments.length) return axis;
+ axis = _;
+ return chart;
+ };
+
+ chart.size = function(_) {
+ if (!arguments.length) return size;
+ size = _;
+ return chart;
+ };
+
+ chart.getData = function(_) {
+ if (!arguments.length) return getData;
+ getData = d3.functor(_);
+ return chart;
+ };
+
+ chart.scale = function(_) {
+ if (!arguments.length) return scale;
+ scale = _;
+ return chart;
+ };
+
+ chart.color = function(_) {
+ if (!arguments.length) return color;
+ color = nv.utils.getColor(_);
+ return chart;
+ };
+
+ chart.duration = function(_) {
+ if (!arguments.length) return duration;
+ duration = _;
+ renderWatch.reset(duration);
+ return chart;
+ };
+ //============================================================
+
+
+ return chart;
+}
+//TODO: consider deprecating and using multibar with single series for this
+nv.models.historicalBar = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = null
+ , height = null
+ , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
+ , x = d3.scale.linear()
+ , y = d3.scale.linear()
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , forceX = []
+ , forceY = [0]
+ , padData = false
+ , clipEdge = true
+ , color = nv.utils.defaultColor()
+ , xDomain
+ , yDomain
+ , xRange
+ , yRange
+ , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'renderEnd')
+ , interactive = true
+ ;
+
+ var renderWatch = nv.utils.renderWatch(dispatch, 0);
+
+ function chart(selection) {
+ selection.each(function(data) {
+ renderWatch.reset();
+
+ var container = d3.select(this);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right;
+ var availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ nv.utils.initSVG(container);
+
+ // Setup Scales
+ x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ));
+
+ if (padData)
+ x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]);
+ else
+ x.range(xRange || [0, availableWidth]);
+
+ y.domain(yDomain || d3.extent(data[0].values.map(getY).concat(forceY) ))
+ .range(yRange || [availableHeight, 0]);
+
+ // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
+ if (x.domain()[0] === x.domain()[1])
+ x.domain()[0] ?
+ x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
+ : x.domain([-1,1]);
+
+ if (y.domain()[0] === y.domain()[1])
+ y.domain()[0] ?
+ y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
+ : y.domain([-1,1]);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-historicalBar-' + id).data([data[0].values]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBar-' + id);
+ var defsEnter = wrapEnter.append('defs');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-bars');
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ container
+ .on('click', function(d,i) {
+ dispatch.chartClick({
+ data: d,
+ index: i,
+ pos: d3.event,
+ id: id
+ });
+ });
+
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-chart-clip-path-' + id)
+ .append('rect');
+
+ wrap.select('#nv-chart-clip-path-' + id + ' rect')
+ .attr('width', availableWidth)
+ .attr('height', availableHeight);
+
+ g.attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
+
+ var bars = wrap.select('.nv-bars').selectAll('.nv-bar')
+ .data(function(d) { return d }, function(d,i) {return getX(d,i)});
+ bars.exit().remove();
+
+ var barsEnter = bars.enter().append('rect')
+ .attr('x', 0 )
+ .attr('y', function(d,i) { return nv.utils.NaNtoZero(y(Math.max(0, getY(d,i)))) })
+ .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.abs(y(getY(d,i)) - y(0))) })
+ .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; })
+ .on('mouseover', function(d,i) {
+ if (!interactive) return;
+ d3.select(this).classed('hover', true);
+ dispatch.elementMouseover({
+ point: d,
+ series: data[0],
+ pos: [x(getX(d,i)), y(getY(d,i))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: 0,
+ e: d3.event
+ });
+
+ })
+ .on('mouseout', function(d,i) {
+ if (!interactive) return;
+ d3.select(this).classed('hover', false);
+ dispatch.elementMouseout({
+ point: d,
+ series: data[0],
+ pointIndex: i,
+ seriesIndex: 0,
+ e: d3.event
+ });
+ })
+ .on('click', function(d,i) {
+ if (!interactive) return;
+ dispatch.elementClick({
+ //label: d[label],
+ value: getY(d,i),
+ data: d,
+ index: i,
+ pos: [x(getX(d,i)), y(getY(d,i))],
+ e: d3.event,
+ id: id
+ });
+ d3.event.stopPropagation();
+ })
+ .on('dblclick', function(d,i) {
+ if (!interactive) return;
+ dispatch.elementDblClick({
+ //label: d[label],
+ value: getY(d,i),
+ data: d,
+ index: i,
+ pos: [x(getX(d,i)), y(getY(d,i))],
+ e: d3.event,
+ id: id
+ });
+ d3.event.stopPropagation();
+ });
+
+ bars
+ .attr('fill', function(d,i) { return color(d, i); })
+ .attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i })
+ .watchTransition(renderWatch, 'bars')
+ .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; })
+ //TODO: better width calculations that don't assume always uniform data spacing;w
+ .attr('width', (availableWidth / data[0].values.length) * .9 );
+
+ bars.watchTransition(renderWatch, 'bars')
+ .attr('y', function(d,i) {
+ var rval = getY(d,i) < 0 ?
+ y(0) :
+ y(0) - y(getY(d,i)) < 1 ?
+ y(0) - 1 :
+ y(getY(d,i));
+ return nv.utils.NaNtoZero(rval);
+ })
+ .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.max(Math.abs(y(getY(d,i)) - y(0)),1)) });
+
+ });
+
+ renderWatch.renderEnd('historicalBar immediate');
+ return chart;
+ }
+
+ //Create methods to allow outside functions to highlight a specific bar.
+ chart.highlightPoint = function(pointIndex, isHoverOver) {
+ d3.select(".nv-historicalBar-" + id)
+ .select(".nv-bars .nv-bar-0-" + pointIndex)
+ .classed("hover", isHoverOver)
+ ;
+ };
+
+ chart.clearHighlights = function() {
+ d3.select(".nv-historicalBar-" + id)
+ .select(".nv-bars .nv-bar.hover")
+ .classed("hover", false)
+ ;
+ };
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}},
+ forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}},
+ padData: {get: function(){return padData;}, set: function(_){padData=_;}},
+ x: {get: function(){return getX;}, set: function(_){getX=_;}},
+ y: {get: function(){return getY;}, set: function(_){getY=_;}},
+ xScale: {get: function(){return x;}, set: function(_){x=_;}},
+ yScale: {get: function(){return y;}, set: function(_){y=_;}},
+ xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
+ yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
+ xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
+ yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
+ clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
+ id: {get: function(){return id;}, set: function(_){id=_;}},
+ interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.historicalBarChart = function(bar_model) {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var bars = bar_model || nv.models.historicalBar()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , legend = nv.models.legend()
+ , interactiveLayer = nv.interactiveGuideline()
+ ;
+
+
+ var margin = {top: 30, right: 90, bottom: 50, left: 90}
+ , color = nv.utils.defaultColor()
+ , width = null
+ , height = null
+ , showLegend = false
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
+ , useInteractiveGuideline = false
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' at ' + x + '</p>'
+ }
+ , x
+ , y
+ , state = {}
+ , defaultState = null
+ , noData = 'No Data Available.'
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd')
+ , transitionDuration = 250
+ ;
+
+ xAxis
+ .orient('bottom')
+ .tickPadding(7)
+ ;
+ yAxis
+ .orient( (rightAlignYAxis) ? 'right' : 'left')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+
+ // New addition to calculate position if SVG is scaled with viewBox, may move TODO: consider implementing everywhere else
+ if (offsetElement) {
+ var svg = d3.select(offsetElement).select('svg');
+ var viewBox = (svg.node()) ? svg.attr('viewBox') : null;
+ if (viewBox) {
+ viewBox = viewBox.split(' ');
+ var ratio = parseInt(svg.style('width')) / viewBox[2];
+ e.pos[0] = e.pos[0] * ratio;
+ e.pos[1] = e.pos[1] * ratio;
+ }
+ }
+
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(bars.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(bars.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, null, null, offsetElement);
+ };
+ var renderWatch = nv.utils.renderWatch(dispatch, 0);
+
+ function chart(selection) {
+ selection.each(function(data) {
+ renderWatch.reset();
+ renderWatch.models(bars);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+
+ chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
+ chart.container = this;
+
+ //set state.disabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display noData message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = bars.xScale();
+ y = bars.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-historicalBarChart').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBarChart').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-y nv-axis');
+ gEnter.append('g').attr('class', 'nv-barsWrap');
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+ gEnter.append('g').attr('class', 'nv-interactive');
+
+ // Legend
+ if (showLegend) {
+ legend.width(availableWidth);
+
+ g.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ wrap.select('.nv-legendWrap')
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
+ }
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
+
+ //Set up interactive layer
+ if (useInteractiveGuideline) {
+ interactiveLayer
+ .width(availableWidth)
+ .height(availableHeight)
+ .margin({left:margin.left, top:margin.top})
+ .svgContainer(container)
+ .xScale(x);
+ wrap.select(".nv-interactive").call(interactiveLayer);
+ }
+ bars
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled }));
+
+ var barsWrap = g.select('.nv-barsWrap')
+ .datum(data.filter(function(d) { return !d.disabled }));
+ barsWrap.transition().call(bars);
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ .tickSize(-availableHeight, 0);
+
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y.range()[0] + ')');
+ g.select('.nv-x.nv-axis')
+ .transition()
+ .call(xAxis);
+ }
+
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ g.select('.nv-y.nv-axis')
+ .transition()
+ .call(yAxis);
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ interactiveLayer.dispatch.on('elementMousemove', function(e) {
+ bars.clearHighlights();
+
+ var singlePoint, pointIndex, pointXLocation, allData = [];
+ data
+ .filter(function(series, i) {
+ series.seriesIndex = i;
+ return !series.disabled;
+ })
+ .forEach(function(series,i) {
+ pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
+ bars.highlightPoint(pointIndex,true);
+ var point = series.values[pointIndex];
+ if (typeof point === 'undefined') return;
+ if (typeof singlePoint === 'undefined') singlePoint = point;
+ if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
+ allData.push({
+ key: series.key,
+ value: chart.y()(point, pointIndex),
+ color: color(series,series.seriesIndex),
+ data: series.values[pointIndex]
+ });
+ });
+
+ var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
+ interactiveLayer.tooltip
+ .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
+ .chartContainer(that.parentNode)
+ .enabled(tooltips)
+ .valueFormatter(function(d,i) {
+ return yAxis.tickFormat()(d);
+ })
+ .data(
+ {
+ value: xValue,
+ series: allData
+ }
+ )();
+
+ interactiveLayer.renderGuideLine(pointXLocation);
+
+ });
+
+ interactiveLayer.dispatch.on("elementMouseout",function(e) {
+ dispatch.tooltipHide();
+ bars.clearHighlights();
+ });
+
+ legend.dispatch.on('legendClick', function(d,i) {
+ d.disabled = !d.disabled;
+
+ if (!data.filter(function(d) { return !d.disabled }).length) {
+ data.map(function(d) {
+ d.disabled = false;
+ wrap.selectAll('.nv-series').classed('disabled', false);
+ return d;
+ });
+ }
+
+ state.disabled = data.map(function(d) { return !!d.disabled });
+ dispatch.stateChange(state);
+
+ selection.transition().call(chart);
+ });
+
+ legend.dispatch.on('legendDblclick', function(d) {
+ //Double clicking should always enable current series, and disabled all others.
+ data.forEach(function(d) {
+ d.disabled = true;
+ });
+ d.disabled = false;
+
+ state.disabled = data.map(function(d) { return !!d.disabled });
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ dispatch.on('changeState', function(e) {
+
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+
+ state.disabled = e.disabled;
+ }
+
+ chart.update();
+ });
+ });
+
+ renderWatch.renderEnd('historicalBarChart immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ bars.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ bars.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.bars = bars;
+ chart.legend = legend;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.interactiveLayer = interactiveLayer;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ bars.color(color);
+ }},
+ duration: {get: function(){return transitionDuration;}, set: function(_){
+ transitionDuration=_;
+ renderWatch.reset(transitionDuration);
+ yAxis.duration(transitionDuration);
+ xAxis.duration(transitionDuration);
+ }},
+ rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
+ rightAlignYAxis = _;
+ yAxis.orient( (_) ? 'right' : 'left');
+ }},
+ useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
+ useInteractiveGuideline = _;
+ if (_ === true) {
+ chart.interactive(false);
+ }
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, bars);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+
+// ohlcChart is just a historical chart with oclc bars and some tweaks
+nv.models.ohlcBarChart = function() {
+ var chart = nv.models.historicalBarChart(nv.models.ohlcBar());
+
+ // special default tooltip since we show multiple values per x
+ chart.useInteractiveGuideline(true);
+ chart.interactiveLayer.tooltip.contentGenerator(function(data) {
+ // we assume only one series exists for this chart
+ var d = data.series[0].data;
+ // match line colors as defined in nv.d3.css
+ var color = d.open < d.close ? "2ca02c" : "d62728";
+ return '' +
+ '<h3 style="color: #' + color + '">' + data.value + '</h3>' +
+ '<table>' +
+ '<tr><td>open:</td><td>' + chart.yAxis.tickFormat()(d.open) + '</td></tr>' +
+ '<tr><td>close:</td><td>' + chart.yAxis.tickFormat()(d.close) + '</td></tr>' +
+ '<tr><td>high</td><td>' + chart.yAxis.tickFormat()(d.high) + '</td></tr>' +
+ '<tr><td>low:</td><td>' + chart.yAxis.tickFormat()(d.low) + '</td></tr>' +
+ '</table>';
+ });
+ return chart;
+};nv.models.legend = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 5, right: 0, bottom: 5, left: 0}
+ , width = 400
+ , height = 20
+ , getKey = function(d) { return d.key }
+ , color = nv.utils.defaultColor()
+ , align = true
+ , rightAlign = true
+ , updateState = true //If true, legend will update data.disabled and trigger a 'stateChange' dispatch.
+ , radioButtonMode = false //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time)
+ , dispatch = d3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange')
+ ;
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-legend').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g');
+ var g = wrap.select('g');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ var series = g.selectAll('.nv-series')
+ .data(function(d) { return d });
+ var seriesEnter = series.enter().append('g').attr('class', 'nv-series')
+ .on('mouseover', function(d,i) {
+ dispatch.legendMouseover(d,i); //TODO: Make consistent with other event objects
+ })
+ .on('mouseout', function(d,i) {
+ dispatch.legendMouseout(d,i);
+ })
+ .on('click', function(d,i) {
+ dispatch.legendClick(d,i);
+ if (updateState) {
+ if (radioButtonMode) {
+ //Radio button mode: set every series to disabled,
+ // and enable the clicked series.
+ data.forEach(function(series) { series.disabled = true});
+ d.disabled = false;
+ }
+ else {
+ d.disabled = !d.disabled;
+ if (data.every(function(series) { return series.disabled})) {
+ //the default behavior of NVD3 legends is, if every single series
+ // is disabled, turn all series' back on.
+ data.forEach(function(series) { series.disabled = false});
+ }
+ }
+ dispatch.stateChange({
+ disabled: data.map(function(d) { return !!d.disabled })
+ });
+ }
+ })
+ .on('dblclick', function(d,i) {
+ dispatch.legendDblclick(d,i);
+ if (updateState) {
+ //the default behavior of NVD3 legends, when double clicking one,
+ // is to set all other series' to false, and make the double clicked series enabled.
+ data.forEach(function(series) {
+ series.disabled = true;
+ });
+ d.disabled = false;
+ dispatch.stateChange({
+ disabled: data.map(function(d) { return !!d.disabled })
+ });
+ }
+ });
+ seriesEnter.append('circle')
+ .style('stroke-width', 2)
+ .attr('class','nv-legend-symbol')
+ .attr('r', 5);
+ seriesEnter.append('text')
+ .attr('text-anchor', 'start')
+ .attr('class','nv-legend-text')
+ .attr('dy', '.32em')
+ .attr('dx', '8');
+ series.classed('nv-disabled', function(d) { return d.disabled });
+ series.exit().remove();
+ series.select('circle')
+ .style('fill', function(d,i) { return d.color || color(d,i)})
+ .style('stroke', function(d,i) { return d.color || color(d, i) });
+ series.select('text').text(getKey);
+
+ //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option)
+ // NEW ALIGNING CODE, TODO: clean up
+ if (align) {
+
+ var seriesWidths = [];
+ series.each(function(d,i) {
+ var legendText = d3.select(this).select('text');
+ var nodeTextLength;
+ try {
+ nodeTextLength = legendText.node().getComputedTextLength();
+ // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead
+ if(nodeTextLength <= 0) throw Error();
+ }
+ catch(e) {
+ nodeTextLength = nv.utils.calcApproxTextWidth(legendText);
+ }
+
+ seriesWidths.push(nodeTextLength + 28); // 28 is ~ the width of the circle plus some padding
+ });
+
+ var seriesPerRow = 0;
+ var legendWidth = 0;
+ var columnWidths = [];
+
+ while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) {
+ columnWidths[seriesPerRow] = seriesWidths[seriesPerRow];
+ legendWidth += seriesWidths[seriesPerRow++];
+ }
+ if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row
+
+ while ( legendWidth > availableWidth && seriesPerRow > 1 ) {
+ columnWidths = [];
+ seriesPerRow--;
+
+ for (var k = 0; k < seriesWidths.length; k++) {
+ if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) )
+ columnWidths[k % seriesPerRow] = seriesWidths[k];
+ }
+
+ legendWidth = columnWidths.reduce(function(prev, cur, index, array) {
+ return prev + cur;
+ });
+ }
+
+ var xPositions = [];
+ for (var i = 0, curX = 0; i < seriesPerRow; i++) {
+ xPositions[i] = curX;
+ curX += columnWidths[i];
+ }
+
+ series
+ .attr('transform', function(d, i) {
+ return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * 20) + ')';
+ });
+
+ //position legend as far right as possible within the total width
+ if (rightAlign) {
+ g.attr('transform', 'translate(' + (width - margin.right - legendWidth) + ',' + margin.top + ')');
+ }
+ else {
+ g.attr('transform', 'translate(0' + ',' + margin.top + ')');
+ }
+
+ height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * 20);
+
+ } else {
+
+ var ypos = 5,
+ newxpos = 5,
+ maxwidth = 0,
+ xpos;
+ series
+ .attr('transform', function(d, i) {
+ var length = d3.select(this).select('text').node().getComputedTextLength() + 28;
+ xpos = newxpos;
+
+ if (width < margin.left + margin.right + xpos + length) {
+ newxpos = xpos = 5;
+ ypos += 20;
+ }
+
+ newxpos += length;
+ if (newxpos > maxwidth) maxwidth = newxpos;
+
+ return 'translate(' + xpos + ',' + ypos + ')';
+ });
+
+ //position legend as far right as possible within the total width
+ g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')');
+
+ height = margin.top + margin.bottom + ypos + 15;
+ }
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ key: {get: function(){return getKey;}, set: function(_){getKey=_;}},
+ align: {get: function(){return align;}, set: function(_){align=_;}},
+ rightAlign: {get: function(){return rightAlign;}, set: function(_){rightAlign=_;}},
+ updateState: {get: function(){return updateState;}, set: function(_){updateState=_;}},
+ radioButtonMode: {get: function(){return radioButtonMode;}, set: function(_){radioButtonMode=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.line = function() {
+ "use strict";
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var scatter = nv.models.scatter()
+ ;
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 960
+ , height = 500
+ , color = nv.utils.defaultColor() // a function that returns a color
+ , getX = function(d) { return d.x } // accessor to get the x value from a data point
+ , getY = function(d) { return d.y } // accessor to get the y value from a data point
+ , defined = function(d,i) { return !isNaN(getY(d,i)) && getY(d,i) !== null } // allows a line to be not continuous when it is not defined
+ , isArea = function(d) { return d.area } // decides if a line is an area or just a line
+ , clipEdge = false // if true, masks lines within x and y scale
+ , x //can be accessed via chart.xScale()
+ , y //can be accessed via chart.yScale()
+ , interpolate = "linear" // controls the line interpolation
+ , duration = 250
+ , dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout', 'renderEnd')
+ ;
+
+ scatter
+ .pointSize(16) // default size
+ .pointDomain([16,256]) //set to speed up calculation, needs to be unset if there is a custom size accessor
+ ;
+
+ //============================================================
+
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var x0, y0 //used to store previous scales
+ , renderWatch = nv.utils.renderWatch(dispatch, duration)
+ ;
+
+ //============================================================
+
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(scatter);
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ // Setup Scales
+ x = scatter.xScale();
+ y = scatter.yScale();
+
+ x0 = x0 || x;
+ y0 = y0 || y;
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-line').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-line');
+ var defsEnter = wrapEnter.append('defs');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-groups');
+ gEnter.append('g').attr('class', 'nv-scatterWrap');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ scatter
+ .width(availableWidth)
+ .height(availableHeight);
+
+ var scatterWrap = wrap.select('.nv-scatterWrap');
+ scatterWrap.call(scatter);
+
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-edge-clip-' + scatter.id())
+ .append('rect');
+
+ wrap.select('#nv-edge-clip-' + scatter.id() + ' rect')
+ .attr('width', availableWidth)
+ .attr('height', (availableHeight > 0) ? availableHeight : 0);
+
+ g .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
+ scatterWrap
+ .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
+
+ var groups = wrap.select('.nv-groups').selectAll('.nv-group')
+ .data(function(d) { return d }, function(d) { return d.key });
+ groups.enter().append('g')
+ .style('stroke-opacity', 1e-6)
+ .style('fill-opacity', 1e-6);
+
+ groups.exit().remove();
+
+ groups
+ .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
+ .classed('hover', function(d) { return d.hover })
+ .style('fill', function(d,i){ return color(d, i) })
+ .style('stroke', function(d,i){ return color(d, i)});
+ groups.watchTransition(renderWatch, 'line: groups')
+ .style('stroke-opacity', 1)
+ .style('fill-opacity', .5);
+
+ var areaPaths = groups.selectAll('path.nv-area')
+ .data(function(d) { return isArea(d) ? [d] : [] }); // this is done differently than lines because I need to check if series is an area
+ areaPaths.enter().append('path')
+ .attr('class', 'nv-area')
+ .attr('d', function(d) {
+ return d3.svg.area()
+ .interpolate(interpolate)
+ .defined(defined)
+ .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
+ .y0(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
+ .y1(function(d,i) { return y0( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) })
+ //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this
+ .apply(this, [d.values])
+ });
+ groups.exit().selectAll('path.nv-area')
+ .remove();
+
+ areaPaths.watchTransition(renderWatch, 'line: areaPaths')
+ .attr('d', function(d) {
+ return d3.svg.area()
+ .interpolate(interpolate)
+ .defined(defined)
+ .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
+ .y0(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
+ .y1(function(d,i) { return y( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) })
+ //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this
+ .apply(this, [d.values])
+ });
+
+ var linePaths = groups.selectAll('path.nv-line')
+ .data(function(d) { return [d.values] });
+ linePaths.enter().append('path')
+ .attr('class', 'nv-line')
+ .attr('d',
+ d3.svg.line()
+ .interpolate(interpolate)
+ .defined(defined)
+ .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
+ .y(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
+ );
+
+ linePaths.watchTransition(renderWatch, 'line: linePaths')
+ .attr('d',
+ d3.svg.line()
+ .interpolate(interpolate)
+ .defined(defined)
+ .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
+ .y(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
+ );
+
+ //store old scales for use in transitions on update
+ x0 = x.copy();
+ y0 = y.copy();
+ });
+ renderWatch.renderEnd('line immediate');
+ return chart;
+ }
+
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.scatter = scatter;
+ // Pass through events
+ scatter.dispatch.on('elementClick', function(){ dispatch.elementClick.apply(this, arguments); })
+ scatter.dispatch.on('elementMouseover', function(){ dispatch.elementMouseover.apply(this, arguments); })
+ scatter.dispatch.on('elementMouseout', function(){ dispatch.elementMouseout.apply(this, arguments); })
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ defined: {get: function(){return defined;}, set: function(_){defined=_;}},
+ interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}},
+ clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ scatter.duration(duration);
+ }},
+ isArea: {get: function(){return isArea;}, set: function(_){
+ isArea = d3.functor(_);
+ }},
+ x: {get: function(){return getX;}, set: function(_){
+ getX = _;
+ scatter.x(_);
+ }},
+ y: {get: function(){return getY;}, set: function(_){
+ getY = _;
+ scatter.y(_);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ scatter.color(color);
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, scatter);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+nv.models.lineChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var lines = nv.models.line()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , legend = nv.models.legend()
+ , interactiveLayer = nv.interactiveGuideline()
+ ;
+
+ var margin = {top: 30, right: 20, bottom: 50, left: 60}
+ , color = nv.utils.defaultColor()
+ , width = null
+ , height = null
+ , showLegend = true
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
+ , useInteractiveGuideline = false
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' at ' + x + '</p>'
+ }
+ , x
+ , y
+ , state = nv.utils.state()
+ , defaultState = null
+ , noData = 'No Data Available.'
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd')
+ , duration = 250
+ ;
+
+ xAxis
+ .orient('bottom')
+ .tickPadding(7)
+ ;
+ yAxis
+ .orient((rightAlignYAxis) ? 'right' : 'left')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, null, null, offsetElement);
+ };
+
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled })
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(lines);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+
+ chart.update = function() {
+ if (duration === 0)
+ container.call(chart);
+ else
+ container.transition().duration(duration).call(chart)
+ };
+ chart.container = this;
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disableddisabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display noData message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+
+ // Setup Scales
+ x = lines.xScale();
+ y = lines.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-lineChart').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineChart').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append("rect").style("opacity",0);
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-y nv-axis');
+ gEnter.append('g').attr('class', 'nv-linesWrap');
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+ gEnter.append('g').attr('class', 'nv-interactive');
+
+ g.select("rect")
+ .attr("width",availableWidth)
+ .attr("height",(availableHeight > 0) ? availableHeight : 0);
+
+ // Legend
+ if (showLegend) {
+ legend.width(availableWidth);
+
+ g.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ wrap.select('.nv-legendWrap')
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
+ }
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
+
+ //Set up interactive layer
+ if (useInteractiveGuideline) {
+ interactiveLayer
+ .width(availableWidth)
+ .height(availableHeight)
+ .margin({left:margin.left, top:margin.top})
+ .svgContainer(container)
+ .xScale(x);
+ wrap.select(".nv-interactive").call(interactiveLayer);
+ }
+
+ lines
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled }));
+
+
+ var linesWrap = g.select('.nv-linesWrap')
+ .datum(data.filter(function(d) { return !d.disabled }));
+
+ linesWrap.call(lines);
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize(-availableHeight, 0);
+
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y.range()[0] + ')');
+ g.select('.nv-x.nv-axis')
+ .call(xAxis);
+ }
+
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ g.select('.nv-y.nv-axis')
+ .call(yAxis);
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ interactiveLayer.dispatch.on('elementMousemove', function(e) {
+ lines.clearHighlights();
+ var singlePoint, pointIndex, pointXLocation, allData = [];
+ data
+ .filter(function(series, i) {
+ series.seriesIndex = i;
+ return !series.disabled;
+ })
+ .forEach(function(series,i) {
+ pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
+ lines.highlightPoint(i, pointIndex, true);
+ var point = series.values[pointIndex];
+ if (typeof point === 'undefined') return;
+ if (typeof singlePoint === 'undefined') singlePoint = point;
+ if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
+ allData.push({
+ key: series.key,
+ value: chart.y()(point, pointIndex),
+ color: color(series,series.seriesIndex)
+ });
+ });
+ //Highlight the tooltip entry based on which point the mouse is closest to.
+ if (allData.length > 2) {
+ var yValue = chart.yScale().invert(e.mouseY);
+ var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
+ var threshold = 0.03 * domainExtent;
+ var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold);
+ if (indexToHighlight !== null)
+ allData[indexToHighlight].highlight = true;
+ }
+
+ var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
+ interactiveLayer.tooltip
+ .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
+ .chartContainer(that.parentNode)
+ .enabled(tooltips)
+ .valueFormatter(function(d,i) {
+ return yAxis.tickFormat()(d);
+ })
+ .data(
+ {
+ value: xValue,
+ series: allData
+ }
+ )();
+
+ interactiveLayer.renderGuideLine(pointXLocation);
+
+ });
+
+ interactiveLayer.dispatch.on('elementClick', function(e) {
+ var pointXLocation, allData = [];
+
+ data.filter(function(series, i) {
+ series.seriesIndex = i;
+ return !series.disabled;
+ }).forEach(function(series) {
+ var pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
+ var point = series.values[pointIndex];
+ if (typeof point === 'undefined') return;
+ if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
+ var yPos = chart.yScale()(chart.y()(point,pointIndex));
+ allData.push({
+ point: point,
+ pointIndex: pointIndex,
+ pos: [pointXLocation, yPos],
+ seriesIndex: series.seriesIndex,
+ series: series
+ });
+ });
+
+ lines.dispatch.elementClick(allData);
+ });
+
+ interactiveLayer.dispatch.on("elementMouseout",function(e) {
+ dispatch.tooltipHide();
+ lines.clearHighlights();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ dispatch.on('changeState', function(e) {
+
+ if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+
+ state.disabled = e.disabled;
+ }
+
+ chart.update();
+ });
+
+ });
+
+ renderWatch.renderEnd('lineChart immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ lines.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.lines = lines;
+ chart.legend = legend;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.interactiveLayer = interactiveLayer;
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ lines.duration(duration);
+ xAxis.duration(duration);
+ yAxis.duration(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ lines.color(color);
+ }},
+ rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
+ rightAlignYAxis = _;
+ yAxis.orient( rightAlignYAxis ? 'right' : 'left');
+ }},
+ useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
+ useInteractiveGuideline = _;
+ if (useInteractiveGuideline) {
+ lines.interactive(false);
+ lines.useVoronoi(false);
+ }
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, lines);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+nv.models.linePlusBarChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var lines = nv.models.line()
+ , lines2 = nv.models.line()
+ , bars = nv.models.historicalBar()
+ , bars2 = nv.models.historicalBar()
+ , xAxis = nv.models.axis()
+ , x2Axis = nv.models.axis()
+ , y1Axis = nv.models.axis()
+ , y2Axis = nv.models.axis()
+ , y3Axis = nv.models.axis()
+ , y4Axis = nv.models.axis()
+ , legend = nv.models.legend()
+ , brush = d3.svg.brush()
+ ;
+
+ var margin = {top: 30, right: 30, bottom: 30, left: 60}
+ , margin2 = {top: 0, right: 30, bottom: 20, left: 60}
+ , width = null
+ , height = null
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , color = nv.utils.defaultColor()
+ , showLegend = true
+ , focusEnable = true
+ , focusShowAxisY = false
+ , focusShowAxisX = true
+ , focusHeight = 50
+ , extent
+ , brushExtent = null
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' at ' + x + '</p>';
+ }
+ , x
+ , x2
+ , y1
+ , y2
+ , y3
+ , y4
+ , noData = "No Data Available."
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'brush', 'stateChange', 'changeState')
+ , transitionDuration = 0
+ , state = nv.utils.state()
+ , defaultState = null
+ , legendLeftAxisHint = ' (left axis)'
+ , legendRightAxisHint = ' (right axis)'
+ ;
+
+ lines
+ .clipEdge(true)
+ ;
+ lines2
+ .interactive(false)
+ ;
+ xAxis
+ .orient('bottom')
+ .tickPadding(5)
+ ;
+ y1Axis
+ .orient('left')
+ ;
+ y2Axis
+ .orient('right')
+ ;
+ x2Axis
+ .orient('bottom')
+ .tickPadding(5)
+ ;
+ y3Axis
+ .orient('left')
+ ;
+ y4Axis
+ .orient('right')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+ if (extent) {
+ e.pointIndex += Math.ceil(extent[0]);
+ }
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
+ y = (e.series.bar ? y1Axis : y2Axis).tickFormat()(lines.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+ };
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled })
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight1 = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom - (focusEnable ? focusHeight : 0) ,
+ availableHeight2 = focusHeight - margin2.top - margin2.bottom;
+
+ chart.update = function() { container.transition().duration(transitionDuration).call(chart); };
+ chart.container = this;
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disableddisabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight1 / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ var dataBars = data.filter(function(d) { return !d.disabled && d.bar });
+ var dataLines = data.filter(function(d) { return !d.bar }); // removed the !d.disabled clause here to fix Issue #240
+
+ x = bars.xScale();
+ x2 = x2Axis.scale();
+ y1 = bars.yScale();
+ y2 = lines.yScale();
+ y3 = bars2.yScale();
+ y4 = lines2.yScale();
+
+ var series1 = data
+ .filter(function(d) { return !d.disabled && d.bar })
+ .map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: getX(d,i), y: getY(d,i) }
+ })
+ });
+
+ var series2 = data
+ .filter(function(d) { return !d.disabled && !d.bar })
+ .map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: getX(d,i), y: getY(d,i) }
+ })
+ });
+
+ x.range([0, availableWidth]);
+
+ x2 .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } ))
+ .range([0, availableWidth]);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-linePlusBar').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-linePlusBar').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+
+ // this is the main chart
+ var focusEnter = gEnter.append('g').attr('class', 'nv-focus');
+ focusEnter.append('g').attr('class', 'nv-x nv-axis');
+ focusEnter.append('g').attr('class', 'nv-y1 nv-axis');
+ focusEnter.append('g').attr('class', 'nv-y2 nv-axis');
+ focusEnter.append('g').attr('class', 'nv-barsWrap');
+ focusEnter.append('g').attr('class', 'nv-linesWrap');
+
+ // context chart is where you can focus in
+ var contextEnter = gEnter.append('g').attr('class', 'nv-context');
+ contextEnter.append('g').attr('class', 'nv-x nv-axis');
+ contextEnter.append('g').attr('class', 'nv-y1 nv-axis');
+ contextEnter.append('g').attr('class', 'nv-y2 nv-axis');
+ contextEnter.append('g').attr('class', 'nv-barsWrap');
+ contextEnter.append('g').attr('class', 'nv-linesWrap');
+ contextEnter.append('g').attr('class', 'nv-brushBackground');
+ contextEnter.append('g').attr('class', 'nv-x nv-brush');
+
+ //============================================================
+ // Legend
+ //------------------------------------------------------------
+
+ if (showLegend) {
+ legend.width( availableWidth / 2 );
+
+ g.select('.nv-legendWrap')
+ .datum(data.map(function(series) {
+ series.originalKey = series.originalKey === undefined ? series.key : series.originalKey;
+ series.key = series.originalKey + (series.bar ? legendLeftAxisHint : legendRightAxisHint);
+ return series;
+ }))
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight1 = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom - focusHeight;
+ }
+
+ g.select('.nv-legendWrap')
+ .attr('transform', 'translate(' + ( availableWidth / 2 ) + ',' + (-margin.top) +')');
+ }
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ //============================================================
+ // Context chart (focus chart) components
+ //------------------------------------------------------------
+
+ // hide or show the focus context chart
+ g.select('.nv-context').style('display', focusEnable ? 'initial' : 'none');
+
+ bars2
+ .width(availableWidth)
+ .height(availableHeight2)
+ .color(data.map(function (d, i) {
+ return d.color || color(d, i);
+ }).filter(function (d, i) {
+ return !data[i].disabled && data[i].bar
+ }));
+ lines2
+ .width(availableWidth)
+ .height(availableHeight2)
+ .color(data.map(function (d, i) {
+ return d.color || color(d, i);
+ }).filter(function (d, i) {
+ return !data[i].disabled && !data[i].bar
+ }));
+
+ var bars2Wrap = g.select('.nv-context .nv-barsWrap')
+ .datum(dataBars.length ? dataBars : [
+ {values: []}
+ ]);
+ var lines2Wrap = g.select('.nv-context .nv-linesWrap')
+ .datum(!dataLines[0].disabled ? dataLines : [
+ {values: []}
+ ]);
+
+ g.select('.nv-context')
+ .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')');
+
+ bars2Wrap.transition().call(bars2);
+ lines2Wrap.transition().call(lines2);
+
+ // context (focus chart) axis controls
+ if (focusShowAxisX) {
+ x2Axis
+ .ticks(nv.utils.calcTicksX(availableWidth / 100, data))
+ .tickSize(-availableHeight2, 0);
+ g.select('.nv-context .nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y3.range()[0] + ')');
+ g.select('.nv-context .nv-x.nv-axis').transition()
+ .call(x2Axis);
+ }
+
+ if (focusShowAxisY) {
+ y3Axis
+ .scale(y3)
+ .ticks( availableHeight2 / 36 )
+ .tickSize( -availableWidth, 0);
+ y4Axis
+ .scale(y4)
+ .ticks( availableHeight2 / 36 )
+ .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none
+
+ g.select('.nv-context .nv-y3.nv-axis')
+ .style('opacity', dataBars.length ? 1 : 0)
+ .attr('transform', 'translate(0,' + x2.range()[0] + ')');
+ g.select('.nv-context .nv-y2.nv-axis')
+ .style('opacity', dataLines.length ? 1 : 0)
+ .attr('transform', 'translate(' + x2.range()[1] + ',0)');
+
+ g.select('.nv-context .nv-y1.nv-axis').transition()
+ .call(y3Axis);
+ g.select('.nv-context .nv-y2.nv-axis').transition()
+ .call(y4Axis);
+ }
+
+ // Setup Brush
+ brush.x(x2).on('brush', onBrush);
+
+ if (brushExtent) brush.extent(brushExtent);
+
+ var brushBG = g.select('.nv-brushBackground').selectAll('g')
+ .data([brushExtent || brush.extent()]);
+
+ var brushBGenter = brushBG.enter()
+ .append('g');
+
+ brushBGenter.append('rect')
+ .attr('class', 'left')
+ .attr('x', 0)
+ .attr('y', 0)
+ .attr('height', availableHeight2);
+
+ brushBGenter.append('rect')
+ .attr('class', 'right')
+ .attr('x', 0)
+ .attr('y', 0)
+ .attr('height', availableHeight2);
+
+ var gBrush = g.select('.nv-x.nv-brush')
+ .call(brush);
+ gBrush.selectAll('rect')
+ //.attr('y', -5)
+ .attr('height', availableHeight2);
+ gBrush.selectAll('.resize').append('path').attr('d', resizePath);
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ // Update chart from a state object passed to event handler
+ dispatch.on('changeState', function(e) {
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+ state.disabled = e.disabled;
+ }
+ chart.update();
+ });
+
+ //============================================================
+ // Functions
+ //------------------------------------------------------------
+
+ // Taken from crossfilter (http://square.github.com/crossfilter/)
+ function resizePath(d) {
+ var e = +(d == 'e'),
+ x = e ? 1 : -1,
+ y = availableHeight2 / 3;
+ return 'M' + (.5 * x) + ',' + y
+ + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
+ + 'V' + (2 * y - 6)
+ + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y)
+ + 'Z'
+ + 'M' + (2.5 * x) + ',' + (y + 8)
+ + 'V' + (2 * y - 8)
+ + 'M' + (4.5 * x) + ',' + (y + 8)
+ + 'V' + (2 * y - 8);
+ }
+
+
+ function updateBrushBG() {
+ if (!brush.empty()) brush.extent(brushExtent);
+ brushBG
+ .data([brush.empty() ? x2.domain() : brushExtent])
+ .each(function(d,i) {
+ var leftWidth = x2(d[0]) - x2.range()[0],
+ rightWidth = x2.range()[1] - x2(d[1]);
+ d3.select(this).select('.left')
+ .attr('width', leftWidth < 0 ? 0 : leftWidth);
+
+ d3.select(this).select('.right')
+ .attr('x', x2(d[1]))
+ .attr('width', rightWidth < 0 ? 0 : rightWidth);
+ });
+ }
+
+ function onBrush() {
+ brushExtent = brush.empty() ? null : brush.extent();
+ extent = brush.empty() ? x2.domain() : brush.extent();
+ dispatch.brush({extent: extent, brush: brush});
+ updateBrushBG();
+
+ // Prepare Main (Focus) Bars and Lines
+ bars
+ .width(availableWidth)
+ .height(availableHeight1)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled && data[i].bar }));
+
+ lines
+ .width(availableWidth)
+ .height(availableHeight1)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled && !data[i].bar }));
+
+ var focusBarsWrap = g.select('.nv-focus .nv-barsWrap')
+ .datum(!dataBars.length ? [{values:[]}] :
+ dataBars
+ .map(function(d,i) {
+ return {
+ key: d.key,
+ values: d.values.filter(function(d,i) {
+ return bars.x()(d,i) >= extent[0] && bars.x()(d,i) <= extent[1];
+ })
+ }
+ })
+ );
+
+ var focusLinesWrap = g.select('.nv-focus .nv-linesWrap')
+ .datum(dataLines[0].disabled ? [{values:[]}] :
+ dataLines
+ .map(function(d,i) {
+ return {
+ key: d.key,
+ values: d.values.filter(function(d,i) {
+ return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1];
+ })
+ }
+ })
+ );
+
+ // Update Main (Focus) X Axis
+ if (dataBars.length) {
+ x = bars.xScale();
+ } else {
+ x = lines.xScale();
+ }
+
+ xAxis
+ .scale(x)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize(-availableHeight1, 0);
+
+ xAxis.domain([Math.ceil(extent[0]), Math.floor(extent[1])]);
+
+ g.select('.nv-x.nv-axis').transition().duration(transitionDuration)
+ .call(xAxis);
+
+ // Update Main (Focus) Bars and Lines
+ focusBarsWrap.transition().duration(transitionDuration).call(bars);
+ focusLinesWrap.transition().duration(transitionDuration).call(lines);
+
+ // Setup and Update Main (Focus) Y Axes
+ g.select('.nv-focus .nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y1.range()[0] + ')');
+
+ y1Axis
+ .scale(y1)
+ .ticks( nv.utils.calcTicksY(availableHeight1/36, data) )
+ .tickSize(-availableWidth, 0);
+ y2Axis
+ .scale(y2)
+ .ticks( nv.utils.calcTicksY(availableHeight1/36, data) )
+ .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none
+
+ g.select('.nv-focus .nv-y1.nv-axis')
+ .style('opacity', dataBars.length ? 1 : 0);
+ g.select('.nv-focus .nv-y2.nv-axis')
+ .style('opacity', dataLines.length && !dataLines[0].disabled ? 1 : 0)
+ .attr('transform', 'translate(' + x.range()[1] + ',0)');
+
+ g.select('.nv-focus .nv-y1.nv-axis').transition().duration(transitionDuration)
+ .call(y1Axis);
+ g.select('.nv-focus .nv-y2.nv-axis').transition().duration(transitionDuration)
+ .call(y2Axis);
+ }
+
+ onBrush();
+
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ lines.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ bars.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ bars.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.legend = legend;
+ chart.lines = lines;
+ chart.lines2 = lines2;
+ chart.bars = bars;
+ chart.bars2 = bars2;
+ chart.xAxis = xAxis;
+ chart.x2Axis = x2Axis;
+ chart.y1Axis = y1Axis;
+ chart.y2Axis = y2Axis;
+ chart.y3Axis = y3Axis;
+ chart.y4Axis = y4Axis;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+ focusEnable: {get: function(){return focusEnable;}, set: function(_){focusEnable=_;}},
+ focusHeight: {get: function(){return focusHeight;}, set: function(_){focusHeight=_;}},
+ focusShowAxisX: {get: function(){return focusShowAxisX;}, set: function(_){focusShowAxisX=_;}},
+ focusShowAxisY: {get: function(){return focusShowAxisY;}, set: function(_){focusShowAxisY=_;}},
+ legendLeftAxisHint: {get: function(){return legendLeftAxisHint;}, set: function(_){legendLeftAxisHint=_;}},
+ legendRightAxisHint: {get: function(){return legendRightAxisHint;}, set: function(_){legendRightAxisHint=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return transitionDuration;}, set: function(_){
+ transitionDuration = _;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ }},
+ x: {get: function(){return getX;}, set: function(_){
+ getX = _;
+ lines.x(_);
+ lines2.x(_);
+ bars.x(_);
+ bars2.x(_);
+ }},
+ y: {get: function(){return getY;}, set: function(_){
+ getY = _;
+ lines.y(_);
+ lines2.y(_);
+ bars.y(_);
+ bars2.y(_);
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, lines);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+nv.models.lineWithFocusChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var lines = nv.models.line()
+ , lines2 = nv.models.line()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , x2Axis = nv.models.axis()
+ , y2Axis = nv.models.axis()
+ , legend = nv.models.legend()
+ , brush = d3.svg.brush()
+ ;
+
+ var margin = {top: 30, right: 30, bottom: 30, left: 60}
+ , margin2 = {top: 0, right: 30, bottom: 20, left: 60}
+ , color = nv.utils.defaultColor()
+ , width = null
+ , height = null
+ , height2 = 100
+ , x
+ , y
+ , x2
+ , y2
+ , showLegend = true
+ , brushExtent = null
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' at ' + x + '</p>'
+ }
+ , noData = "No Data Available."
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'brush', 'stateChange', 'changeState')
+ , transitionDuration = 250
+ , state = nv.utils.state()
+ , defaultState = null
+ ;
+
+ lines
+ .clipEdge(true)
+ ;
+ lines2
+ .interactive(false)
+ ;
+ xAxis
+ .orient('bottom')
+ .tickPadding(5)
+ ;
+ yAxis
+ .orient('left')
+ ;
+ x2Axis
+ .orient('bottom')
+ .tickPadding(5)
+ ;
+ y2Axis
+ .orient('left')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, null, null, offsetElement);
+ };
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled })
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight1 = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom - height2,
+ availableHeight2 = height2 - margin2.top - margin2.bottom;
+
+ chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
+ chart.container = this;
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disableddisabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight1 / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = lines.xScale();
+ y = lines.yScale();
+ x2 = lines2.xScale();
+ y2 = lines2.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-lineWithFocusChart').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineWithFocusChart').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+
+ var focusEnter = gEnter.append('g').attr('class', 'nv-focus');
+ focusEnter.append('g').attr('class', 'nv-x nv-axis');
+ focusEnter.append('g').attr('class', 'nv-y nv-axis');
+ focusEnter.append('g').attr('class', 'nv-linesWrap');
+
+ var contextEnter = gEnter.append('g').attr('class', 'nv-context');
+ contextEnter.append('g').attr('class', 'nv-x nv-axis');
+ contextEnter.append('g').attr('class', 'nv-y nv-axis');
+ contextEnter.append('g').attr('class', 'nv-linesWrap');
+ contextEnter.append('g').attr('class', 'nv-brushBackground');
+ contextEnter.append('g').attr('class', 'nv-x nv-brush');
+
+ // Legend
+ if (showLegend) {
+ legend.width(availableWidth);
+
+ g.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight1 = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom - height2;
+ }
+
+ g.select('.nv-legendWrap')
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
+ }
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ // Main Chart Component(s)
+ lines
+ .width(availableWidth)
+ .height(availableHeight1)
+ .color(
+ data
+ .map(function(d,i) {
+ return d.color || color(d, i);
+ })
+ .filter(function(d,i) {
+ return !data[i].disabled;
+ })
+ );
+
+ lines2
+ .defined(lines.defined())
+ .width(availableWidth)
+ .height(availableHeight2)
+ .color(
+ data
+ .map(function(d,i) {
+ return d.color || color(d, i);
+ })
+ .filter(function(d,i) {
+ return !data[i].disabled;
+ })
+ );
+
+ g.select('.nv-context')
+ .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')')
+
+ var contextLinesWrap = g.select('.nv-context .nv-linesWrap')
+ .datum(data.filter(function(d) { return !d.disabled }))
+
+ d3.transition(contextLinesWrap).call(lines2);
+
+ // Setup Main (Focus) Axes
+ xAxis
+ .scale(x)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize(-availableHeight1, 0);
+
+ yAxis
+ .scale(y)
+ .ticks( nv.utils.calcTicksY(availableHeight1/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ g.select('.nv-focus .nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + availableHeight1 + ')');
+
+ // Setup Brush
+ brush
+ .x(x2)
+ .on('brush', function() {
+ //When brushing, turn off transitions because chart needs to change immediately.
+ var oldTransition = chart.duration();
+ chart.duration(0);
+ onBrush();
+ chart.duration(oldTransition);
+ });
+
+ if (brushExtent) brush.extent(brushExtent);
+
+ var brushBG = g.select('.nv-brushBackground').selectAll('g')
+ .data([brushExtent || brush.extent()])
+
+ var brushBGenter = brushBG.enter()
+ .append('g');
+
+ brushBGenter.append('rect')
+ .attr('class', 'left')
+ .attr('x', 0)
+ .attr('y', 0)
+ .attr('height', availableHeight2);
+
+ brushBGenter.append('rect')
+ .attr('class', 'right')
+ .attr('x', 0)
+ .attr('y', 0)
+ .attr('height', availableHeight2);
+
+ var gBrush = g.select('.nv-x.nv-brush')
+ .call(brush);
+ gBrush.selectAll('rect')
+ //.attr('y', -5)
+ .attr('height', availableHeight2);
+ gBrush.selectAll('.resize').append('path').attr('d', resizePath);
+
+ onBrush();
+
+ // Setup Secondary (Context) Axes
+ x2Axis
+ .scale(x2)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize(-availableHeight2, 0);
+
+ g.select('.nv-context .nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y2.range()[0] + ')');
+ d3.transition(g.select('.nv-context .nv-x.nv-axis'))
+ .call(x2Axis);
+
+ y2Axis
+ .scale(y2)
+ .ticks( nv.utils.calcTicksY(availableHeight2/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ d3.transition(g.select('.nv-context .nv-y.nv-axis'))
+ .call(y2Axis);
+
+ g.select('.nv-context .nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y2.range()[0] + ')');
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ dispatch.on('changeState', function(e) {
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+ }
+ chart.update();
+ });
+
+ //============================================================
+ // Functions
+ //------------------------------------------------------------
+
+ // Taken from crossfilter (http://square.github.com/crossfilter/)
+ function resizePath(d) {
+ var e = +(d == 'e'),
+ x = e ? 1 : -1,
+ y = availableHeight2 / 3;
+ return 'M' + (.5 * x) + ',' + y
+ + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
+ + 'V' + (2 * y - 6)
+ + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y)
+ + 'Z'
+ + 'M' + (2.5 * x) + ',' + (y + 8)
+ + 'V' + (2 * y - 8)
+ + 'M' + (4.5 * x) + ',' + (y + 8)
+ + 'V' + (2 * y - 8);
+ }
+
+
+ function updateBrushBG() {
+ if (!brush.empty()) brush.extent(brushExtent);
+ brushBG
+ .data([brush.empty() ? x2.domain() : brushExtent])
+ .each(function(d,i) {
+ var leftWidth = x2(d[0]) - x.range()[0],
+ rightWidth = x.range()[1] - x2(d[1]);
+ d3.select(this).select('.left')
+ .attr('width', leftWidth < 0 ? 0 : leftWidth);
+
+ d3.select(this).select('.right')
+ .attr('x', x2(d[1]))
+ .attr('width', rightWidth < 0 ? 0 : rightWidth);
+ });
+ }
+
+
+ function onBrush() {
+ brushExtent = brush.empty() ? null : brush.extent();
+ var extent = brush.empty() ? x2.domain() : brush.extent();
+
+ //The brush extent cannot be less than one. If it is, don't update the line chart.
+ if (Math.abs(extent[0] - extent[1]) <= 1) {
+ return;
+ }
+
+ dispatch.brush({extent: extent, brush: brush});
+
+
+ updateBrushBG();
+
+ // Update Main (Focus)
+ var focusLinesWrap = g.select('.nv-focus .nv-linesWrap')
+ .datum(
+ data
+ .filter(function(d) { return !d.disabled })
+ .map(function(d,i) {
+ return {
+ key: d.key,
+ area: d.area,
+ values: d.values.filter(function(d,i) {
+ return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1];
+ })
+ }
+ })
+ );
+ focusLinesWrap.transition().duration(transitionDuration).call(lines);
+
+
+ // Update Main (Focus) Axes
+ g.select('.nv-focus .nv-x.nv-axis').transition().duration(transitionDuration)
+ .call(xAxis);
+ g.select('.nv-focus .nv-y.nv-axis').transition().duration(transitionDuration)
+ .call(yAxis);
+ }
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ lines.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.legend = legend;
+ chart.lines = lines;
+ chart.lines2 = lines2;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.x2Axis = x2Axis;
+ chart.y2Axis = y2Axis;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ focusHeight: {get: function(){return height2;}, set: function(_){height2=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ // line color is handled above?
+ }},
+ interpolate: {get: function(){return lines.interpolate();}, set: function(_){
+ lines.interpolate(_);
+ lines2.interpolate(_);
+ }},
+ xTickFormat: {get: function(){return xAxis.xTickFormat();}, set: function(_){
+ xAxis.xTickFormat(_);
+ x2Axis.xTickFormat(_);
+ }},
+ yTickFormat: {get: function(){return yAxis.yTickFormat();}, set: function(_){
+ yAxis.yTickFormat(_);
+ y2Axis.yTickFormat(_);
+ }},
+ duration: {get: function(){return transitionDuration;}, set: function(_){
+ transitionDuration=_;
+ yAxis.duration(transitionDuration);
+ xAxis.duration(transitionDuration);
+ }},
+ x: {get: function(){return lines.x();}, set: function(_){
+ lines.x(_);
+ lines2.x(_);
+ }},
+ y: {get: function(){return lines.y();}, set: function(_){
+ lines.y(_);
+ lines2.y(_);
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, lines);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.multiBar = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 960
+ , height = 500
+ , x = d3.scale.ordinal()
+ , y = d3.scale.linear()
+ , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
+ , clipEdge = true
+ , stacked = false
+ , stackOffset = 'zero' // options include 'silhouette', 'wiggle', 'expand', 'zero', or a custom function
+ , color = nv.utils.defaultColor()
+ , hideable = false
+ , barColor = null // adding the ability to set the color for each rather than the whole group
+ , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled
+ , duration = 500
+ , xDomain
+ , yDomain
+ , xRange
+ , yRange
+ , groupSpacing = 0.1
+ , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'renderEnd')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var x0, y0 //used to store previous scales
+ , renderWatch = nv.utils.renderWatch(dispatch, duration)
+ ;
+
+ var last_datalength = 0;
+
+ function chart(selection) {
+ renderWatch.reset();
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ // This function defines the requirements for render complete
+ var endFn = function(d, i) {
+ if (d.series === data.length - 1 && i === data[0].values.length - 1)
+ return true;
+ return false;
+ };
+
+ if(hideable && data.length) hideable = [{
+ values: data[0].values.map(function(d) {
+ return {
+ x: d.x,
+ y: 0,
+ series: d.series,
+ size: 0.01
+ };}
+ )}];
+
+ if (stacked)
+ data = d3.layout.stack()
+ .offset(stackOffset)
+ .values(function(d){ return d.values })
+ .y(getY)
+ (!data.length && hideable ? hideable : data);
+
+
+ //add series index to each data point for reference
+ data.forEach(function(series, i) {
+ series.values.forEach(function(point) {
+ point.series = i;
+ });
+ });
+
+ // HACK for negative value stacking
+ if (stacked)
+ data[0].values.map(function(d,i) {
+ var posBase = 0, negBase = 0;
+ data.map(function(d) {
+ var f = d.values[i]
+ f.size = Math.abs(f.y);
+ if (f.y<0) {
+ f.y1 = negBase;
+ negBase = negBase - f.size;
+ } else
+ {
+ f.y1 = f.size + posBase;
+ posBase = posBase + f.size;
+ }
+ });
+ });
+
+ // Setup Scales
+ // remap and flatten the data for use in calculating the scales' domains
+ var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
+ data.map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1 }
+ })
+ });
+
+ x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
+ .rangeBands(xRange || [0, availableWidth], groupSpacing);
+
+ y.domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return stacked ? (d.y > 0 ? d.y1 : d.y1 + d.y ) : d.y }).concat(forceY)))
+ .range(yRange || [availableHeight, 0]);
+
+ // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
+ if (x.domain()[0] === x.domain()[1])
+ x.domain()[0] ?
+ x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
+ : x.domain([-1,1]);
+
+ if (y.domain()[0] === y.domain()[1])
+ y.domain()[0] ?
+ y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
+ : y.domain([-1,1]);
+
+ x0 = x0 || x;
+ y0 = y0 || y;
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-multibar').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibar');
+ var defsEnter = wrapEnter.append('defs');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g')
+
+ gEnter.append('g').attr('class', 'nv-groups');
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-edge-clip-' + id)
+ .append('rect');
+ wrap.select('#nv-edge-clip-' + id + ' rect')
+ .attr('width', availableWidth)
+ .attr('height', availableHeight);
+
+ g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
+
+ var groups = wrap.select('.nv-groups').selectAll('.nv-group')
+ .data(function(d) { return d }, function(d,i) { return i });
+ groups.enter().append('g')
+ .style('stroke-opacity', 1e-6)
+ .style('fill-opacity', 1e-6);
+
+ var exitTransition = renderWatch
+ .transition(groups.exit().selectAll('rect.nv-bar'), 'multibarExit', Math.min(100, duration))
+ .attr('y', function(d) { return (stacked ? y0(d.y0) : y0(0)) || 0 })
+ .attr('height', 0)
+ .remove();
+ if (exitTransition.delay)
+ exitTransition.delay(function(d,i) {
+ var delay = i * (duration / (last_datalength + 1)) - i;
+ return delay;
+ });
+ groups
+ .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
+ .classed('hover', function(d) { return d.hover })
+ .style('fill', function(d,i){ return color(d, i) })
+ .style('stroke', function(d,i){ return color(d, i) });
+ groups
+ .style('stroke-opacity', 1)
+ .style('fill-opacity', 0.75);
+
+ var bars = groups.selectAll('rect.nv-bar')
+ .data(function(d) { return (hideable && !data.length) ? hideable.values : d.values });
+ bars.exit().remove();
+
+ var barsEnter = bars.enter().append('rect')
+ .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
+ .attr('x', function(d,i,j) {
+ return stacked ? 0 : (j * x.rangeBand() / data.length )
+ })
+ .attr('y', function(d) { return y0(stacked ? d.y0 : 0) || 0 })
+ .attr('height', 0)
+ .attr('width', x.rangeBand() / (stacked ? 1 : data.length) )
+ .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; })
+ ;
+ bars
+ .style('fill', function(d,i,j){ return color(d, j, i); })
+ .style('stroke', function(d,i,j){ return color(d, j, i); })
+ .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
+ d3.select(this).classed('hover', true);
+ dispatch.elementMouseover({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ })
+ .on('mouseout', function(d,i) {
+ d3.select(this).classed('hover', false);
+ dispatch.elementMouseout({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ })
+ .on('click', function(d,i) {
+ dispatch.elementClick({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ d3.event.stopPropagation();
+ })
+ .on('dblclick', function(d,i) {
+ dispatch.elementDblClick({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ d3.event.stopPropagation();
+ });
+ bars
+ .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
+ .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; })
+
+ if (barColor) {
+ if (!disabled) disabled = data.map(function() { return true });
+ bars
+ .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); })
+ .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); });
+ }
+
+ var barSelection =
+ bars.watchTransition(renderWatch, 'multibar', Math.min(250, duration))
+ .delay(function(d,i) {
+ return i * duration / data[0].values.length;
+ });
+ if (stacked)
+ barSelection
+ .attr('y', function(d,i) {
+ return y((stacked ? d.y1 : 0));
+ })
+ .attr('height', function(d,i) {
+ return Math.max(Math.abs(y(d.y + (stacked ? d.y0 : 0)) - y((stacked ? d.y0 : 0))),1);
+ })
+ .attr('x', function(d,i) {
+ return stacked ? 0 : (d.series * x.rangeBand() / data.length )
+ })
+ .attr('width', x.rangeBand() / (stacked ? 1 : data.length) );
+ else
+ barSelection
+ .attr('x', function(d,i) {
+ return d.series * x.rangeBand() / data.length
+ })
+ .attr('width', x.rangeBand() / data.length)
+ .attr('y', function(d,i) {
+ return getY(d,i) < 0 ?
+ y(0) :
+ y(0) - y(getY(d,i)) < 1 ?
+ y(0) - 1 :
+ y(getY(d,i)) || 0;
+ })
+ .attr('height', function(d,i) {
+ return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0;
+ });
+
+ //store old scales for use in transitions on update
+ x0 = x.copy();
+ y0 = y.copy();
+
+ // keep track of the last data value length for transition calculations
+ if (data[0] && data[0].values) {
+ last_datalength = data[0].values.length;
+ }
+
+ });
+
+ renderWatch.renderEnd('multibar immediate');
+
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ x: {get: function(){return getX;}, set: function(_){getX=_;}},
+ y: {get: function(){return getY;}, set: function(_){getY=_;}},
+ xScale: {get: function(){return x;}, set: function(_){x=_;}},
+ yScale: {get: function(){return y;}, set: function(_){y=_;}},
+ xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
+ yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
+ xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
+ yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
+ forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}},
+ stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}},
+ stackOffset: {get: function(){return stackOffset;}, set: function(_){stackOffset=_;}},
+ clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
+ disabled: {get: function(){return disabled;}, set: function(_){disabled=_;}},
+ id: {get: function(){return id;}, set: function(_){id=_;}},
+ hideable: {get: function(){return hideable;}, set: function(_){hideable=_;}},
+ groupSpacing:{get: function(){return groupSpacing;}, set: function(_){groupSpacing=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }},
+ barColor: {get: function(){return barColor;}, set: function(_){
+ barColor = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.multiBarChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var multibar = nv.models.multiBar()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , legend = nv.models.legend()
+ , controls = nv.models.legend()
+ ;
+
+ var margin = {top: 30, right: 20, bottom: 50, left: 60}
+ , width = null
+ , height = null
+ , color = nv.utils.defaultColor()
+ , showControls = true
+ , controlLabels = {}
+ , showLegend = true
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
+ , reduceXTicks = true // if false a tick will show for every data point
+ , staggerLabels = false
+ , rotateLabels = 0
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' on ' + x + '</p>'
+ }
+ , x //can be accessed via chart.xScale()
+ , y //can be accessed via chart.yScale()
+ , state = nv.utils.state()
+ , defaultState = null
+ , noData = "No Data Available."
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd')
+ , controlWidth = function() { return showControls ? 180 : 0 }
+ , duration = 250
+ ;
+
+ state.stacked = false // DEPRECATED Maintained for backward compatibility
+
+ multibar
+ .stacked(false)
+ ;
+ xAxis
+ .orient('bottom')
+ .tickPadding(7)
+ .highlightZero(true)
+ .showMaxMin(false)
+ .tickFormat(function(d) { return d })
+ ;
+ yAxis
+ .orient((rightAlignYAxis) ? 'right' : 'left')
+ .tickFormat(d3.format(',.1f'))
+ ;
+
+ controls.updateState(false);
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var renderWatch = nv.utils.renderWatch(dispatch);
+ var stacked = false;
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+ };
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled }),
+ stacked: stacked
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.stacked !== undefined)
+ stacked = state.stacked;
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(multibar);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ chart.update = function() {
+ if (duration === 0)
+ container.call(chart);
+ else
+ container.transition()
+ .duration(duration)
+ .call(chart);
+ };
+ chart.container = this;
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disableddisabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display noData message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = multibar.xScale();
+ y = multibar.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-y nv-axis');
+ gEnter.append('g').attr('class', 'nv-barsWrap');
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+ gEnter.append('g').attr('class', 'nv-controlsWrap');
+
+ // Legend
+ if (showLegend) {
+ legend.width(availableWidth - controlWidth());
+
+ if (multibar.barColor())
+ data.forEach(function(series,i) {
+ series.color = d3.rgb('#ccc').darker(i * 1.5).toString();
+ });
+
+ g.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ g.select('.nv-legendWrap')
+ .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')');
+ }
+
+ // Controls
+ if (showControls) {
+ var controlsData = [
+ { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() },
+ { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() }
+ ];
+
+ controls.width(controlWidth()).color(['#444', '#444', '#444']);
+ g.select('.nv-controlsWrap')
+ .datum(controlsData)
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
+ .call(controls);
+ }
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
+
+ // Main Chart Component(s)
+ multibar
+ .disabled(data.map(function(series) { return series.disabled }))
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled }));
+
+
+ var barsWrap = g.select('.nv-barsWrap')
+ .datum(data.filter(function(d) { return !d.disabled }));
+
+ barsWrap.call(multibar);
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize(-availableHeight, 0);
+
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y.range()[0] + ')');
+ g.select('.nv-x.nv-axis')
+ .call(xAxis);
+
+ var xTicks = g.select('.nv-x.nv-axis > g').selectAll('g');
+
+ xTicks
+ .selectAll('line, text')
+ .style('opacity', 1)
+
+ if (staggerLabels) {
+ var getTranslate = function(x,y) {
+ return "translate(" + x + "," + y + ")";
+ };
+
+ var staggerUp = 5, staggerDown = 17; //pixels to stagger by
+ // Issue #140
+ xTicks
+ .selectAll("text")
+ .attr('transform', function(d,i,j) {
+ return getTranslate(0, (j % 2 == 0 ? staggerUp : staggerDown));
+ });
+
+ var totalInBetweenTicks = d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;
+ g.selectAll(".nv-x.nv-axis .nv-axisMaxMin text")
+ .attr("transform", function(d,i) {
+ return getTranslate(0, (i === 0 || totalInBetweenTicks % 2 !== 0) ? staggerDown : staggerUp);
+ });
+ }
+
+ if (reduceXTicks)
+ xTicks
+ .filter(function(d,i) {
+ return i % Math.ceil(data[0].values.length / (availableWidth / 100)) !== 0;
+ })
+ .selectAll('text, line')
+ .style('opacity', 0);
+
+ if(rotateLabels)
+ xTicks
+ .selectAll('.tick text')
+ .attr('transform', 'rotate(' + rotateLabels + ' 0,0)')
+ .style('text-anchor', rotateLabels > 0 ? 'start' : 'end');
+
+ g.select('.nv-x.nv-axis').selectAll('g.nv-axisMaxMin text')
+ .style('opacity', 1);
+ }
+
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ g.select('.nv-y.nv-axis')
+ .call(yAxis);
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ controls.dispatch.on('legendClick', function(d,i) {
+ if (!d.disabled) return;
+ controlsData = controlsData.map(function(s) {
+ s.disabled = true;
+ return s;
+ });
+ d.disabled = false;
+
+ switch (d.key) {
+ case 'Grouped':
+ multibar.stacked(false);
+ break;
+ case 'Stacked':
+ multibar.stacked(true);
+ break;
+ }
+
+ state.stacked = multibar.stacked();
+ dispatch.stateChange(state);
+
+ chart.update();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode)
+ });
+
+ // Update chart from a state object passed to event handler
+ dispatch.on('changeState', function(e) {
+
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+
+ state.disabled = e.disabled;
+ }
+
+ if (typeof e.stacked !== 'undefined') {
+ multibar.stacked(e.stacked);
+ state.stacked = e.stacked;
+ stacked = e.stacked;
+ }
+
+ chart.update();
+ });
+ });
+
+ renderWatch.renderEnd('multibarchart immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ multibar.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ multibar.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.multibar = multibar;
+ chart.legend = legend;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.state = state;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}},
+ controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+ reduceXTicks: {get: function(){return reduceXTicks;}, set: function(_){reduceXTicks=_;}},
+ rotateLabels: {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}},
+ staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ multibar.duration(duration);
+ xAxis.duration(duration);
+ yAxis.duration(duration);
+ renderWatch.reset(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ }},
+ rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
+ rightAlignYAxis = _;
+ yAxis.orient( rightAlignYAxis ? 'right' : 'left');
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, multibar);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.multiBarHorizontal = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 960
+ , height = 500
+ , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
+ , x = d3.scale.ordinal()
+ , y = d3.scale.linear()
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , getYerr = function(d) { return d.yErr }
+ , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
+ , color = nv.utils.defaultColor()
+ , barColor = null // adding the ability to set the color for each rather than the whole group
+ , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled
+ , stacked = false
+ , showValues = false
+ , showBarLabels = false
+ , valuePadding = 60
+ , valueFormat = d3.format(',.2f')
+ , delay = 1200
+ , xDomain
+ , yDomain
+ , xRange
+ , yRange
+ , duration = 250
+ , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout','renderEnd')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var x0, y0; //used to store previous scales
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ function chart(selection) {
+ renderWatch.reset();
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ if (stacked)
+ data = d3.layout.stack()
+ .offset('zero')
+ .values(function(d){ return d.values })
+ .y(getY)
+ (data);
+
+ //add series index to each data point for reference
+ data.forEach(function(series, i) {
+ series.values.forEach(function(point) {
+ point.series = i;
+ });
+ });
+
+ // HACK for negative value stacking
+ if (stacked)
+ data[0].values.map(function(d,i) {
+ var posBase = 0, negBase = 0;
+ data.map(function(d) {
+ var f = d.values[i]
+ f.size = Math.abs(f.y);
+ if (f.y<0) {
+ f.y1 = negBase - f.size;
+ negBase = negBase - f.size;
+ } else
+ {
+ f.y1 = posBase;
+ posBase = posBase + f.size;
+ }
+ });
+ });
+
+ // Setup Scales
+ // remap and flatten the data for use in calculating the scales' domains
+ var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
+ data.map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1 }
+ })
+ });
+
+ x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
+ .rangeBands(xRange || [0, availableHeight], .1);
+
+ y.domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return stacked ? (d.y > 0 ? d.y1 + d.y : d.y1 ) : d.y }).concat(forceY)))
+
+ if (showValues && !stacked)
+ y.range(yRange || [(y.domain()[0] < 0 ? valuePadding : 0), availableWidth - (y.domain()[1] > 0 ? valuePadding : 0) ]);
+ else
+ y.range(yRange || [0, availableWidth]);
+
+ x0 = x0 || x;
+ y0 = y0 || d3.scale.linear().domain(y.domain()).range([y(0),y(0)]);
+
+ // Setup containers and skeleton of chart
+ var wrap = d3.select(this).selectAll('g.nv-wrap.nv-multibarHorizontal').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibarHorizontal');
+ var defsEnter = wrapEnter.append('defs');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-groups');
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ var groups = wrap.select('.nv-groups').selectAll('.nv-group')
+ .data(function(d) { return d }, function(d,i) { return i });
+ groups.enter().append('g')
+ .style('stroke-opacity', 1e-6)
+ .style('fill-opacity', 1e-6);
+ groups.exit().watchTransition(renderWatch, 'multibarhorizontal: exit groups')
+ .style('stroke-opacity', 1e-6)
+ .style('fill-opacity', 1e-6)
+ .remove();
+ groups
+ .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
+ .classed('hover', function(d) { return d.hover })
+ .style('fill', function(d,i){ return color(d, i) })
+ .style('stroke', function(d,i){ return color(d, i) });
+ groups.watchTransition(renderWatch, 'multibarhorizontal: groups')
+ .style('stroke-opacity', 1)
+ .style('fill-opacity', .75);
+
+ var bars = groups.selectAll('g.nv-bar')
+ .data(function(d) { return d.values });
+ bars.exit().remove();
+
+ var barsEnter = bars.enter().append('g')
+ .attr('transform', function(d,i,j) {
+ return 'translate(' + y0(stacked ? d.y0 : 0) + ',' + (stacked ? 0 : (j * x.rangeBand() / data.length ) + x(getX(d,i))) + ')'
+ });
+
+ barsEnter.append('rect')
+ .attr('width', 0)
+ .attr('height', x.rangeBand() / (stacked ? 1 : data.length) )
+
+ bars
+ .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
+ d3.select(this).classed('hover', true);
+ dispatch.elementMouseover({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [ y(getY(d,i) + (stacked ? d.y0 : 0)), x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length) ],
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ })
+ .on('mouseout', function(d,i) {
+ d3.select(this).classed('hover', false);
+ dispatch.elementMouseout({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ })
+ .on('click', function(d,i) {
+ dispatch.elementClick({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ d3.event.stopPropagation();
+ })
+ .on('dblclick', function(d,i) {
+ dispatch.elementDblClick({
+ value: getY(d,i),
+ point: d,
+ series: data[d.series],
+ pos: [x(getX(d,i)) + (x.rangeBand() * (stacked ? data.length / 2 : d.series + .5) / data.length), y(getY(d,i) + (stacked ? d.y0 : 0))], // TODO: Figure out why the value appears to be shifted
+ pointIndex: i,
+ seriesIndex: d.series,
+ e: d3.event
+ });
+ d3.event.stopPropagation();
+ });
+
+ if (getYerr(data[0],0)) {
+ barsEnter.append('polyline');
+
+ bars.select('polyline')
+ .attr('fill', 'none')
+ .attr('points', function(d,i) {
+ var xerr = getYerr(d,i)
+ , mid = 0.8 * x.rangeBand() / ((stacked ? 1 : data.length) * 2);
+ xerr = xerr.length ? xerr : [-Math.abs(xerr), Math.abs(xerr)];
+ xerr = xerr.map(function(e) { return y(e) - y(0); });
+ var a = [[xerr[0],-mid], [xerr[0],mid], [xerr[0],0], [xerr[1],0], [xerr[1],-mid], [xerr[1],mid]];
+ return a.map(function (path) { return path.join(',') }).join(' ');
+ })
+ .attr('transform', function(d,i) {
+ var mid = x.rangeBand() / ((stacked ? 1 : data.length) * 2);
+ return 'translate(' + (getY(d,i) < 0 ? 0 : y(getY(d,i)) - y(0)) + ', ' + mid + ')'
+ });
+ }
+
+ barsEnter.append('text');
+
+ if (showValues && !stacked) {
+ bars.select('text')
+ .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'end' : 'start' })
+ .attr('y', x.rangeBand() / (data.length * 2))
+ .attr('dy', '.32em')
+ .html(function(d,i) {
+ var t = valueFormat(getY(d,i))
+ , yerr = getYerr(d,i);
+ if (yerr === undefined)
+ return t;
+ if (!yerr.length)
+ return t + '±' + valueFormat(Math.abs(yerr));
+ return t + '+' + valueFormat(Math.abs(yerr[1])) + '-' + valueFormat(Math.abs(yerr[0]));
+ });
+ bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
+ .select('text')
+ .attr('x', function(d,i) { return getY(d,i) < 0 ? -4 : y(getY(d,i)) - y(0) + 4 })
+ } else {
+ bars.selectAll('text').text('');
+ }
+
+ if (showBarLabels && !stacked) {
+ barsEnter.append('text').classed('nv-bar-label',true);
+ bars.select('text.nv-bar-label')
+ .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'start' : 'end' })
+ .attr('y', x.rangeBand() / (data.length * 2))
+ .attr('dy', '.32em')
+ .text(function(d,i) { return getX(d,i) });
+ bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
+ .select('text.nv-bar-label')
+ .attr('x', function(d,i) { return getY(d,i) < 0 ? y(0) - y(getY(d,i)) + 4 : -4 });
+ }
+ else {
+ bars.selectAll('text.nv-bar-label').text('');
+ }
+
+ bars
+ .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
+
+ if (barColor) {
+ if (!disabled) disabled = data.map(function() { return true });
+ bars
+ .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); })
+ .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); });
+ }
+
+ if (stacked)
+ bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
+ .attr('transform', function(d,i) {
+ return 'translate(' + y(d.y1) + ',' + x(getX(d,i)) + ')'
+ })
+ .select('rect')
+ .attr('width', function(d,i) {
+ return Math.abs(y(getY(d,i) + d.y0) - y(d.y0))
+ })
+ .attr('height', x.rangeBand() );
+ else
+ bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
+ .attr('transform', function(d,i) {
+ //TODO: stacked must be all positive or all negative, not both?
+ return 'translate(' +
+ (getY(d,i) < 0 ? y(getY(d,i)) : y(0))
+ + ',' +
+ (d.series * x.rangeBand() / data.length
+ +
+ x(getX(d,i)) )
+ + ')'
+ })
+ .select('rect')
+ .attr('height', x.rangeBand() / data.length )
+ .attr('width', function(d,i) {
+ return Math.max(Math.abs(y(getY(d,i)) - y(0)),1)
+ });
+
+ //store old scales for use in transitions on update
+ x0 = x.copy();
+ y0 = y.copy();
+
+ });
+
+ renderWatch.renderEnd('multibarHorizontal immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ x: {get: function(){return getX;}, set: function(_){getX=_;}},
+ y: {get: function(){return getY;}, set: function(_){getY=_;}},
+ yErr: {get: function(){return getYerr;}, set: function(_){getYerr=_;}},
+ xScale: {get: function(){return x;}, set: function(_){x=_;}},
+ yScale: {get: function(){return y;}, set: function(_){y=_;}},
+ xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
+ yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
+ xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
+ yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
+ forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}},
+ stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}},
+ showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}},
+ // this shows the group name, seems pointless?
+ //showBarLabels: {get: function(){return showBarLabels;}, set: function(_){showBarLabels=_;}},
+ disabled: {get: function(){return disabled;}, set: function(_){disabled=_;}},
+ id: {get: function(){return id;}, set: function(_){id=_;}},
+ valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}},
+ valuePadding: {get: function(){return valuePadding;}, set: function(_){valuePadding=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }},
+ barColor: {get: function(){return color;}, set: function(_){
+ barColor = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+nv.models.multiBarHorizontalChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var multibar = nv.models.multiBarHorizontal()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , legend = nv.models.legend().height(30)
+ , controls = nv.models.legend().height(30)
+ ;
+
+ var margin = {top: 30, right: 20, bottom: 50, left: 60}
+ , width = null
+ , height = null
+ , color = nv.utils.defaultColor()
+ , showControls = true
+ , controlLabels = {}
+ , showLegend = true
+ , showXAxis = true
+ , showYAxis = true
+ , stacked = false
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + ' - ' + x + '</h3>' +
+ '<p>' + y + '</p>'
+ }
+ , x //can be accessed via chart.xScale()
+ , y //can be accessed via chart.yScale()
+ , state = nv.utils.state()
+ , defaultState = null
+ , noData = 'No Data Available.'
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd')
+ , controlWidth = function() { return showControls ? 180 : 0 }
+ , duration = 250
+ ;
+
+ state.stacked = false; // DEPRECATED Maintained for backward compatibility
+
+ multibar
+ .stacked(stacked)
+ ;
+ xAxis
+ .orient('left')
+ .tickPadding(5)
+ .highlightZero(false)
+ .showMaxMin(false)
+ .tickFormat(function(d) { return d })
+ ;
+ yAxis
+ .orient('bottom')
+ .tickFormat(d3.format(',.1f'))
+ ;
+
+ controls.updateState(false);
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement);
+ };
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled }),
+ stacked: stacked
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.stacked !== undefined)
+ stacked = state.stacked;
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(multibar);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ chart.update = function() { container.transition().duration(duration).call(chart) };
+ chart.container = this;
+
+ stacked = multibar.stacked();
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disableddisabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = multibar.xScale();
+ y = multibar.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-multiBarHorizontalChart').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarHorizontalChart').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-y nv-axis')
+ .append('g').attr('class', 'nv-zeroLine')
+ .append('line');
+ gEnter.append('g').attr('class', 'nv-barsWrap');
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+ gEnter.append('g').attr('class', 'nv-controlsWrap');
+
+ // Legend
+ if (showLegend) {
+ legend.width(availableWidth - controlWidth());
+
+ if (multibar.barColor())
+ data.forEach(function(series,i) {
+ series.color = d3.rgb('#ccc').darker(i * 1.5).toString();
+ });
+
+ g.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ g.select('.nv-legendWrap')
+ .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')');
+ }
+
+ // Controls
+ if (showControls) {
+ var controlsData = [
+ { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() },
+ { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() }
+ ];
+
+ controls.width(controlWidth()).color(['#444', '#444', '#444']);
+ g.select('.nv-controlsWrap')
+ .datum(controlsData)
+ .attr('transform', 'translate(0,' + (-margin.top) +')')
+ .call(controls);
+ }
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ // Main Chart Component(s)
+ multibar
+ .disabled(data.map(function(series) { return series.disabled }))
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled }));
+
+ var barsWrap = g.select('.nv-barsWrap')
+ .datum(data.filter(function(d) { return !d.disabled }));
+
+ barsWrap.transition().call(multibar);
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ .ticks( nv.utils.calcTicksY(availableHeight/24, data) )
+ .tickSize(-availableWidth, 0);
+
+ g.select('.nv-x.nv-axis').call(xAxis);
+
+ var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
+
+ xTicks
+ .selectAll('line, text');
+ }
+
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize( -availableHeight, 0);
+
+ g.select('.nv-y.nv-axis')
+ .attr('transform', 'translate(0,' + availableHeight + ')');
+ g.select('.nv-y.nv-axis').call(yAxis);
+ }
+
+ // Zero line
+ g.select(".nv-zeroLine line")
+ .attr("x1", y(0))
+ .attr("x2", y(0))
+ .attr("y1", 0)
+ .attr("y2", -availableHeight)
+ ;
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ controls.dispatch.on('legendClick', function(d,i) {
+ if (!d.disabled) return;
+ controlsData = controlsData.map(function(s) {
+ s.disabled = true;
+ return s;
+ });
+ d.disabled = false;
+
+ switch (d.key) {
+ case 'Grouped':
+ multibar.stacked(false);
+ break;
+ case 'Stacked':
+ multibar.stacked(true);
+ break;
+ }
+
+ state.stacked = multibar.stacked();
+ dispatch.stateChange(state);
+ stacked = multibar.stacked();
+
+ chart.update();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ // Update chart from a state object passed to event handler
+ dispatch.on('changeState', function(e) {
+
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+
+ state.disabled = e.disabled;
+ }
+
+ if (typeof e.stacked !== 'undefined') {
+ multibar.stacked(e.stacked);
+ state.stacked = e.stacked;
+ stacked = e.stacked;
+ }
+
+ chart.update();
+ });
+ });
+ renderWatch.renderEnd('multibar horizontal chart immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ multibar.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ multibar.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.multibar = multibar;
+ chart.legend = legend;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.state = state;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}},
+ controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ multibar.duration(duration);
+ xAxis.duration(duration);
+ yAxis.duration(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, multibar);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+nv.models.multiChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 30, right: 20, bottom: 50, left: 60},
+ color = nv.utils.defaultColor(),
+ width = null,
+ height = null,
+ showLegend = true,
+ tooltips = true,
+ tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' at ' + x + '</p>'
+ },
+ x,
+ y,
+ noData = 'No Data Available.',
+ yDomain1,
+ yDomain2,
+ getX = function(d) { return d.x },
+ getY = function(d) { return d.y},
+ interpolate = 'monotone'
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var x = d3.scale.linear(),
+ yScale1 = d3.scale.linear(),
+ yScale2 = d3.scale.linear(),
+
+ lines1 = nv.models.line().yScale(yScale1),
+ lines2 = nv.models.line().yScale(yScale2),
+
+ bars1 = nv.models.multiBar().stacked(false).yScale(yScale1),
+ bars2 = nv.models.multiBar().stacked(false).yScale(yScale2),
+
+ stack1 = nv.models.stackedArea().yScale(yScale1),
+ stack2 = nv.models.stackedArea().yScale(yScale2),
+
+ xAxis = nv.models.axis().scale(x).orient('bottom').tickPadding(5),
+ yAxis1 = nv.models.axis().scale(yScale1).orient('left'),
+ yAxis2 = nv.models.axis().scale(yScale2).orient('right'),
+
+ legend = nv.models.legend().height(30),
+ dispatch = d3.dispatch('tooltipShow', 'tooltipHide');
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(lines1.x()(e.point, e.pointIndex)),
+ y = ((e.series.yAxis == 2) ? yAxis2 : yAxis1).tickFormat()(lines1.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, undefined, undefined, offsetElement.offsetParent);
+ };
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+
+ chart.update = function() { container.transition().call(chart); };
+ chart.container = this;
+
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ var dataLines1 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 1});
+ var dataLines2 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 2});
+ var dataBars1 = data.filter(function(d) {return d.type == 'bar' && d.yAxis == 1});
+ var dataBars2 = data.filter(function(d) {return d.type == 'bar' && d.yAxis == 2});
+ var dataStack1 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 1});
+ var dataStack2 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 2});
+
+ // Display noData message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ var series1 = data.filter(function(d) {return !d.disabled && d.yAxis == 1})
+ .map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: d.x, y: d.y }
+ })
+ });
+
+ var series2 = data.filter(function(d) {return !d.disabled && d.yAxis == 2})
+ .map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: d.x, y: d.y }
+ })
+ });
+
+ x .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } ))
+ .range([0, availableWidth]);
+
+ var wrap = container.selectAll('g.wrap.multiChart').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 multiChart').append('g');
+
+ gEnter.append('g').attr('class', 'x axis');
+ gEnter.append('g').attr('class', 'y1 axis');
+ gEnter.append('g').attr('class', 'y2 axis');
+ gEnter.append('g').attr('class', 'lines1Wrap');
+ gEnter.append('g').attr('class', 'lines2Wrap');
+ gEnter.append('g').attr('class', 'bars1Wrap');
+ gEnter.append('g').attr('class', 'bars2Wrap');
+ gEnter.append('g').attr('class', 'stack1Wrap');
+ gEnter.append('g').attr('class', 'stack2Wrap');
+ gEnter.append('g').attr('class', 'legendWrap');
+
+ var g = wrap.select('g');
+
+ var color_array = data.map(function(d,i) {
+ return data[i].color || color(d, i);
+ });
+
+ if (showLegend) {
+ legend.color(color_array);
+ legend.width( availableWidth / 2 );
+
+ g.select('.legendWrap')
+ .datum(data.map(function(series) {
+ series.originalKey = series.originalKey === undefined ? series.key : series.originalKey;
+ series.key = series.originalKey + (series.yAxis == 1 ? '' : ' (right axis)');
+ return series;
+ }))
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ g.select('.legendWrap')
+ .attr('transform', 'translate(' + ( availableWidth / 2 ) + ',' + (-margin.top) +')');
+ }
+
+ lines1
+ .width(availableWidth)
+ .height(availableHeight)
+ .interpolate(interpolate)
+ .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'line'}));
+ lines2
+ .width(availableWidth)
+ .height(availableHeight)
+ .interpolate(interpolate)
+ .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'line'}));
+ bars1
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'bar'}));
+ bars2
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'bar'}));
+ stack1
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'area'}));
+ stack2
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'area'}));
+
+ g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ var lines1Wrap = g.select('.lines1Wrap')
+ .datum(
+ dataLines1.filter(function(d){return !d.disabled})
+ );
+ var bars1Wrap = g.select('.bars1Wrap')
+ .datum(
+ dataBars1.filter(function(d){return !d.disabled})
+ );
+ var stack1Wrap = g.select('.stack1Wrap')
+ .datum(
+ dataStack1.filter(function(d){return !d.disabled})
+ );
+
+ var lines2Wrap = g.select('.lines2Wrap')
+ .datum(
+ dataLines2.filter(function(d){return !d.disabled})
+ );
+ var bars2Wrap = g.select('.bars2Wrap')
+ .datum(
+ dataBars2.filter(function(d){return !d.disabled})
+ );
+ var stack2Wrap = g.select('.stack2Wrap')
+ .datum(
+ dataStack2.filter(function(d){return !d.disabled})
+ );
+
+ var extraValue1 = dataStack1.length ? dataStack1.map(function(a){return a.values}).reduce(function(a,b){
+ return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}})
+ }).concat([{x:0, y:0}]) : []
+ var extraValue2 = dataStack2.length ? dataStack2.map(function(a){return a.values}).reduce(function(a,b){
+ return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}})
+ }).concat([{x:0, y:0}]) : []
+
+ yScale1 .domain(yDomain1 || d3.extent(d3.merge(series1).concat(extraValue1), function(d) { return d.y } ))
+ .range([0, availableHeight])
+
+ yScale2 .domain(yDomain2 || d3.extent(d3.merge(series2).concat(extraValue2), function(d) { return d.y } ))
+ .range([0, availableHeight])
+
+ lines1.yDomain(yScale1.domain())
+ bars1.yDomain(yScale1.domain())
+ stack1.yDomain(yScale1.domain())
+
+ lines2.yDomain(yScale2.domain())
+ bars2.yDomain(yScale2.domain())
+ stack2.yDomain(yScale2.domain())
+
+ if(dataStack1.length){d3.transition(stack1Wrap).call(stack1);}
+ if(dataStack2.length){d3.transition(stack2Wrap).call(stack2);}
+
+ if(dataBars1.length){d3.transition(bars1Wrap).call(bars1);}
+ if(dataBars2.length){d3.transition(bars2Wrap).call(bars2);}
+
+ if(dataLines1.length){d3.transition(lines1Wrap).call(lines1);}
+ if(dataLines2.length){d3.transition(lines2Wrap).call(lines2);}
+
+ xAxis
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize(-availableHeight, 0);
+
+ g.select('.x.axis')
+ .attr('transform', 'translate(0,' + availableHeight + ')');
+ d3.transition(g.select('.x.axis'))
+ .call(xAxis);
+
+ yAxis1
+ .ticks( nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+
+ d3.transition(g.select('.y1.axis'))
+ .call(yAxis1);
+
+ yAxis2
+ .ticks( nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ d3.transition(g.select('.y2.axis'))
+ .call(yAxis2);
+
+ g.select('.y1.axis')
+ .classed('nv-disabled', series1.length ? false : true)
+ .attr('transform', 'translate(' + x.range()[0] + ',0)');
+
+ g.select('.y2.axis')
+ .classed('nv-disabled', series2.length ? false : true)
+ .attr('transform', 'translate(' + x.range()[1] + ',0)');
+
+ legend.dispatch.on('stateChange', function(newState) {
+ chart.update();
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ lines1.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines1.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ lines2.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines2.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ bars1.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ bars1.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ bars2.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ bars2.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ stack1.dispatch.on('tooltipShow', function(e) {
+ //disable tooltips when value ~= 0
+ //// TODO: consider removing points from voronoi that have 0 value instead of this hack
+ if (!Math.round(stack1.y()(e.point) * 100)) { // 100 will not be good for very small numbers... will have to think about making this valu dynamic, based on data range
+ setTimeout(function() { d3.selectAll('.point.hover').classed('hover', false) }, 0);
+ return false;
+ }
+
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top],
+ dispatch.tooltipShow(e);
+ });
+
+ stack1.dispatch.on('tooltipHide', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ stack2.dispatch.on('tooltipShow', function(e) {
+ //disable tooltips when value ~= 0
+ //// TODO: consider removing points from voronoi that have 0 value instead of this hack
+ if (!Math.round(stack2.y()(e.point) * 100)) { // 100 will not be good for very small numbers... will have to think about making this valu dynamic, based on data range
+ setTimeout(function() { d3.selectAll('.point.hover').classed('hover', false) }, 0);
+ return false;
+ }
+
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top],
+ dispatch.tooltipShow(e);
+ });
+
+ stack2.dispatch.on('tooltipHide', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ lines1.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines1.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ lines2.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ lines2.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Global getters and setters
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.lines1 = lines1;
+ chart.lines2 = lines2;
+ chart.bars1 = bars1;
+ chart.bars2 = bars2;
+ chart.stack1 = stack1;
+ chart.stack2 = stack2;
+ chart.xAxis = xAxis;
+ chart.yAxis1 = yAxis1;
+ chart.yAxis2 = yAxis2;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ yDomain1: {get: function(){return yDomain1;}, set: function(_){yDomain1=_;}},
+ yDomain2: {get: function(){return yDomain2;}, set: function(_){yDomain2=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+ interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }},
+ x: {get: function(){return getX;}, set: function(_){
+ getX = _;
+ lines1.x(_);
+ bars1.x(_);
+ }},
+ y: {get: function(){return getY;}, set: function(_){
+ getY = _;
+ lines1.y(_);
+ bars1.y(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+
+nv.models.ohlcBar = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = null
+ , height = null
+ , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
+ , x = d3.scale.linear()
+ , y = d3.scale.linear()
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , getOpen = function(d) { return d.open }
+ , getClose = function(d) { return d.close }
+ , getHigh = function(d) { return d.high }
+ , getLow = function(d) { return d.low }
+ , forceX = []
+ , forceY = []
+ , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
+ , clipEdge = true
+ , color = nv.utils.defaultColor()
+ , interactive = false
+ , xDomain
+ , yDomain
+ , xRange
+ , yRange
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right;
+ var availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ nv.utils.initSVG(container);
+
+ // Setup Scales
+ x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ));
+
+ if (padData)
+ x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]);
+ else
+ x.range(xRange || [0, availableWidth]);
+
+ y.domain(yDomain || [
+ d3.min(data[0].values.map(getLow).concat(forceY)),
+ d3.max(data[0].values.map(getHigh).concat(forceY))
+ ]
+ ).range(yRange || [availableHeight, 0]);
+
+ // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
+ if (x.domain()[0] === x.domain()[1])
+ x.domain()[0] ?
+ x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
+ : x.domain([-1,1]);
+
+ if (y.domain()[0] === y.domain()[1])
+ y.domain()[0] ?
+ y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
+ : y.domain([-1,1]);
+
+ // Setup containers and skeleton of chart
+ var wrap = d3.select(this).selectAll('g.nv-wrap.nv-ohlcBar').data([data[0].values]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-ohlcBar');
+ var defsEnter = wrapEnter.append('defs');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-ticks');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ container
+ .on('click', function(d,i) {
+ dispatch.chartClick({
+ data: d,
+ index: i,
+ pos: d3.event,
+ id: id
+ });
+ });
+
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-chart-clip-path-' + id)
+ .append('rect');
+
+ wrap.select('#nv-chart-clip-path-' + id + ' rect')
+ .attr('width', availableWidth)
+ .attr('height', availableHeight);
+
+ g .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
+
+ var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick')
+ .data(function(d) { return d });
+ ticks.exit().remove();
+
+ var ticksEnter = ticks.enter().append('path')
+ .attr('class', function(d,i,j) { return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i })
+ .attr('d', function(d,i) {
+ var w = (availableWidth / data[0].values.length) * .9;
+ return 'm0,0l0,'
+ + (y(getOpen(d,i))
+ - y(getHigh(d,i)))
+ + 'l'
+ + (-w/2)
+ + ',0l'
+ + (w/2)
+ + ',0l0,'
+ + (y(getLow(d,i)) - y(getOpen(d,i)))
+ + 'l0,'
+ + (y(getClose(d,i))
+ - y(getLow(d,i)))
+ + 'l'
+ + (w/2)
+ + ',0l'
+ + (-w/2)
+ + ',0z';
+ })
+ .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; })
+ .attr('fill', function(d,i) { return color[0]; })
+ .attr('stroke', function(d,i) { return color[0]; })
+ .attr('x', 0 )
+ .attr('y', function(d,i) { return y(Math.max(0, getY(d,i))) })
+ .attr('height', function(d,i) { return Math.abs(y(getY(d,i)) - y(0)) });
+
+ // the bar colors are controlled by CSS currently
+ ticks.attr('class', function(d,i,j) {
+ return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i;
+ });
+
+ d3.transition(ticks)
+ .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; })
+ .attr('d', function(d,i) {
+ var w = (availableWidth / data[0].values.length) * .9;
+ return 'm0,0l0,'
+ + (y(getOpen(d,i))
+ - y(getHigh(d,i)))
+ + 'l'
+ + (-w/2)
+ + ',0l'
+ + (w/2)
+ + ',0l0,'
+ + (y(getLow(d,i))
+ - y(getOpen(d,i)))
+ + 'l0,'
+ + (y(getClose(d,i))
+ - y(getLow(d,i)))
+ + 'l'
+ + (w/2)
+ + ',0l'
+ + (-w/2)
+ + ',0z';
+ });
+ });
+
+ return chart;
+ }
+
+
+ //Create methods to allow outside functions to highlight a specific bar.
+ chart.highlightPoint = function(pointIndex, isHoverOver) {
+ chart.clearHighlights();
+ d3.select(".nv-ohlcBar .nv-tick-0-" + pointIndex)
+ .classed("hover", isHoverOver)
+ ;
+ };
+
+ chart.clearHighlights = function() {
+ d3.select(".nv-ohlcBar .nv-tick.hover")
+ .classed("hover", false)
+ ;
+ };
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ xScale: {get: function(){return x;}, set: function(_){x=_;}},
+ yScale: {get: function(){return y;}, set: function(_){y=_;}},
+ xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
+ yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
+ xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
+ yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
+ forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}},
+ forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}},
+ padData: {get: function(){return padData;}, set: function(_){padData=_;}},
+ clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
+ id: {get: function(){return id;}, set: function(_){id=_;}},
+ interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},
+
+ x: {get: function(){return getX;}, set: function(_){getX=_;}},
+ y: {get: function(){return getY;}, set: function(_){getY=_;}},
+ open: {get: function(){return getOpen();}, set: function(_){getOpen=_;}},
+ close: {get: function(){return getClose();}, set: function(_){getClose=_;}},
+ high: {get: function(){return getHigh;}, set: function(_){getHigh=_;}},
+ low: {get: function(){return getLow;}, set: function(_){getLow=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top != undefined ? _.top : margin.top;
+ margin.right = _.right != undefined ? _.right : margin.right;
+ margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom;
+ margin.left = _.left != undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+ return chart;
+};
+
+// Code adapted from Jason Davies' "Parallel Coordinates"
+// http://bl.ocks.org/jasondavies/1341281
+
+nv.models.parallelCoordinates = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 30, right: 10, bottom: 10, left: 10}
+ , width = null
+ , height = null
+ , x = d3.scale.ordinal()
+ , y = {}
+ , dimensions = []
+ , color = nv.utils.defaultColor()
+ , filters = []
+ , active = []
+ , dispatch = d3.dispatch('brush')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right;
+ var availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ nv.utils.initSVG(container);
+
+ active = data; //set all active before first brush call
+
+ //This is a placeholder until this chart is made resizeable
+ chart.update = function() { };
+
+ // Setup Scales
+ x.rangePoints([0, availableWidth], 1).domain(dimensions);
+
+ // Extract the list of dimensions and create a scale for each.
+ dimensions.forEach(function(d) {
+ y[d] = d3.scale.linear()
+ .domain(d3.extent(data, function(p) { return +p[d]; }))
+ .range([availableHeight, 0]);
+
+ y[d].brush = d3.svg.brush().y(y[d]).on('brush', brush);
+
+ return d != 'name';
+ });
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-parallelCoordinates').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-parallelCoordinates');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-parallelCoordinatesWrap');
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ var line = d3.svg.line(),
+ axis = d3.svg.axis().orient('left'),
+ background,
+ foreground;
+
+ // Add grey background lines for context.
+ background = gEnter.append('g')
+ .attr('class', 'background')
+ .selectAll('path')
+ .data(data)
+ .enter().append('path')
+ .attr('d', path)
+ ;
+
+ // Add blue foreground lines for focus.
+ foreground = gEnter.append('g')
+ .attr('class', 'foreground')
+ .selectAll('path')
+ .data(data)
+ .enter().append('path')
+ .attr('d', path)
+ .attr('stroke', color)
+ ;
+
+ // Add a group element for each dimension.
+ var dimension = g.selectAll('.dimension')
+ .data(dimensions)
+ .enter().append('g')
+ .attr('class', 'dimension')
+ .attr('transform', function(d) { return 'translate(' + x(d) + ',0)'; });
+
+ // Add an axis and title.
+ dimension.append('g')
+ .attr('class', 'axis')
+ .each(function(d) { d3.select(this).call(axis.scale(y[d])); })
+ .append('text')
+ .attr('text-anchor', 'middle')
+ .attr('y', -9)
+ .text(String);
+
+ // Add and store a brush for each axis.
+ dimension.append('g')
+ .attr('class', 'brush')
+ .each(function(d) { d3.select(this).call(y[d].brush); })
+ .selectAll('rect')
+ .attr('x', -8)
+ .attr('width', 16);
+
+ // Returns the path for a given data point.
+ function path(d) {
+ return line(dimensions.map(function(p) { return [x(p), y[p](d[p])]; }));
+ }
+
+ // Handles a brush event, toggling the display of foreground lines.
+ function brush() {
+ var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
+ extents = actives.map(function(p) { return y[p].brush.extent(); });
+
+ filters = []; //erase current filters
+ actives.forEach(function(d,i) {
+ filters[i] = {
+ dimension: d,
+ extent: extents[i]
+ }
+ });
+
+ active = []; //erase current active list
+ foreground.style('display', function(d) {
+ var isActive = actives.every(function(p, i) {
+ return extents[i][0] <= d[p] && d[p] <= extents[i][1];
+ });
+ if (isActive) active.push(d);
+ return isActive ? null : 'none';
+ });
+
+ dispatch.brush({
+ filters: filters,
+ active: active
+ });
+ }
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ dimensions: {get: function(){return dimensions;}, set: function(_){dimensions=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+ margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+ margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+ margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+ return chart;
+};
+nv.models.pie = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 500
+ , height = 500
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
+ , color = nv.utils.defaultColor()
+ , valueFormat = d3.format(',.2f')
+ , labelFormat = d3.format('%')
+ , showLabels = true
+ , pieLabelsOutside = true
+ , donutLabelsOutside = false
+ , labelType = "key"
+ , labelThreshold = .02 //if slice percentage is under this, don't show label
+ , donut = false
+ , title = false
+ , growOnHover = true
+ , titleOffset = 0
+ , labelSunbeamLayout = false
+ , startAngle = false
+ , padAngle = false
+ , endAngle = false
+ , cornerRadius = 0
+ , donutRatio = 0.5
+ , duration = 250
+ , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'renderEnd')
+ ;
+
+
+ //============================================================
+ // chart function
+ //------------------------------------------------------------
+
+ var renderWatch = nv.utils.renderWatch(dispatch);
+
+ function chart(selection) {
+ renderWatch.reset();
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right
+ ,availableHeight = height - margin.top - margin.bottom
+ ,radius = Math.min(availableWidth, availableHeight) / 2
+ ,arcRadius = radius-(radius / 5)
+ ,container = d3.select(this)
+ ;
+ nv.utils.initSVG(container);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('.nv-wrap.nv-pie').data(data);
+ var wrapEnter = wrap.enter().append('g').attr('class','nvd3 nv-wrap nv-pie nv-chart-' + id);
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+ var g_pie = gEnter.append('g').attr('class', 'nv-pie');
+ gEnter.append('g').attr('class', 'nv-pieLabels');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+ g.select('.nv-pie').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')');
+ g.select('.nv-pieLabels').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')');
+
+ //
+ container.on('click', function(d,i) {
+ dispatch.chartClick({
+ data: d,
+ index: i,
+ pos: d3.event,
+ id: id
+ });
+ });
+
+
+ var arc = d3.svg.arc().outerRadius(arcRadius);
+ var arcOver = d3.svg.arc().outerRadius(arcRadius + 5);
+
+ if (startAngle) {
+ arc.startAngle(startAngle);
+ arcOver.startAngle(startAngle);
+ }
+ if (endAngle) {
+ arc.endAngle(endAngle);
+ arcOver.endAngle(endAngle);
+ }
+ if (donut) {
+ arc.innerRadius(radius * donutRatio);
+ arcOver.innerRadius(radius * donutRatio);
+ }
+
+ // Setup the Pie chart and choose the data element
+ var pie = d3.layout.pie()
+ .sort(null)
+ .value(function(d) { return d.disabled ? 0 : getY(d) });
+
+ // padAngle added in d3 3.5
+ if (pie.padAngle && padAngle) {
+ pie.padAngle(padAngle);
+ }
+
+ if (arc.cornerRadius && cornerRadius) {
+ arc.cornerRadius(cornerRadius);
+ arcOver.cornerRadius(cornerRadius);
+ }
+
+ // if title is specified and donut, put it in the middle
+ if (donut && title) {
+ var title_g = g_pie.append('g').attr('class', 'nv-pie');
+
+ title_g.append("text")
+ .style("text-anchor", "middle")
+ .attr('class', 'nv-pie-title')
+ .text(function (d) {
+ return title;
+ })
+ .attr("dy", "0.35em") // trick to vertically center text
+ .attr('transform', function(d, i) {
+ return 'translate(0, '+ titleOffset + ')';
+ });
+ }
+
+ var slices = wrap.select('.nv-pie').selectAll('.nv-slice').data(pie);
+ var pieLabels = wrap.select('.nv-pieLabels').selectAll('.nv-label').data(pie);
+
+ slices.exit().remove();
+ pieLabels.exit().remove();
+
+ var ae = slices.enter().append('g')
+ ae.attr('class', 'nv-slice')
+ ae.on('mouseover', function(d,i){
+ d3.select(this).classed('hover', true);
+ if (growOnHover) {
+ d3.select(this).select("path").transition()
+ .duration(70)
+ .attr("d", arcOver);
+ }
+ dispatch.elementMouseover({
+ label: getX(d.data),
+ value: getY(d.data),
+ point: d.data,
+ pointIndex: i,
+ pos: [d3.event.pageX, d3.event.pageY],
+ id: id,
+ color: d3.select(this).style("fill")
+ });
+ });
+ ae.on('mouseout', function(d,i){
+ d3.select(this).classed('hover', false);
+ if (growOnHover) {
+ d3.select(this).select("path").transition()
+ .duration(50)
+ .attr("d", arc);
+ }
+ dispatch.elementMouseout({
+ label: getX(d.data),
+ value: getY(d.data),
+ point: d.data,
+ index: i,
+ id: id
+ });
+ });
+
+ slices.attr('fill', function(d,i) { return color(d, i); })
+ slices.attr('stroke', function(d,i) { return color(d, i); });
+
+ var paths = ae.append('path').each(function(d) {
+ this._current = d;
+ });
+
+ paths.on('click', function(d,i) {
+ dispatch.elementClick({
+ label: getX(d.data),
+ value: getY(d.data),
+ point: d.data,
+ index: i,
+ pos: d3.event,
+ id: id
+ });
+ d3.event.stopPropagation();
+ });
+ paths.on('dblclick', function(d,i) {
+ dispatch.elementDblClick({
+ label: getX(d.data),
+ value: getY(d.data),
+ point: d.data,
+ index: i,
+ pos: d3.event,
+ id: id
+ });
+ d3.event.stopPropagation();
+ });
+ slices.select('path')
+ .transition()
+ .attr('d', arc)
+ .attrTween('d', arcTween);
+
+ if (showLabels) {
+ // This does the normal label
+ var labelsArc = d3.svg.arc().innerRadius(0);
+
+ if (pieLabelsOutside){
+ var labelsArc = arc;
+ }
+
+ if (donutLabelsOutside) {
+ labelsArc = d3.svg.arc().outerRadius(arc.outerRadius());
+ }
+
+ pieLabels.enter().append("g").classed("nv-label",true).each(function(d,i) {
+ var group = d3.select(this);
+
+ group.attr('transform', function(d) {
+ if (labelSunbeamLayout) {
+ d.outerRadius = arcRadius + 10; // Set Outer Coordinate
+ d.innerRadius = arcRadius + 15; // Set Inner Coordinate
+ var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI);
+ if ((d.startAngle+d.endAngle)/2 < Math.PI) {
+ rotateAngle -= 90;
+ } else {
+ rotateAngle += 90;
+ }
+ return 'translate(' + labelsArc.centroid(d) + ') rotate(' + rotateAngle + ')';
+ } else {
+ d.outerRadius = radius + 10; // Set Outer Coordinate
+ d.innerRadius = radius + 15; // Set Inner Coordinate
+ return 'translate(' + labelsArc.centroid(d) + ')'
+ }
+ });
+
+ group.append('rect')
+ .style('stroke', '#fff')
+ .style('fill', '#fff')
+ .attr("rx", 3)
+ .attr("ry", 3);
+
+ group.append('text')
+ .style('text-anchor', labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle') //center the text on it's origin or begin/end if orthogonal aligned
+ .style('fill', '#000')
+
+ });
+
+ var labelLocationHash = {};
+ var avgHeight = 14;
+ var avgWidth = 140;
+ var createHashKey = function(coordinates) {
+ return Math.floor(coordinates[0]/avgWidth) * avgWidth + ',' + Math.floor(coordinates[1]/avgHeight) * avgHeight;
+ };
+
+ pieLabels.watchTransition(renderWatch,'pie labels').attr('transform', function(d) {
+ if (labelSunbeamLayout) {
+ d.outerRadius = arcRadius + 10; // Set Outer Coordinate
+ d.innerRadius = arcRadius + 15; // Set Inner Coordinate
+ var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI);
+ if ((d.startAngle+d.endAngle)/2 < Math.PI) {
+ rotateAngle -= 90;
+ } else {
+ rotateAngle += 90;
+ }
+ return 'translate(' + labelsArc.centroid(d) + ') rotate(' + rotateAngle + ')';
+ } else {
+ d.outerRadius = radius + 10; // Set Outer Coordinate
+ d.innerRadius = radius + 15; // Set Inner Coordinate
+
+ /*
+ Overlapping pie labels are not good. What this attempts to do is, prevent overlapping.
+ Each label location is hashed, and if a hash collision occurs, we assume an overlap.
+ Adjust the label's y-position to remove the overlap.
+ */
+ var center = labelsArc.centroid(d);
+ if(d.value){
+ var hashKey = createHashKey(center);
+ if (labelLocationHash[hashKey]) {
+ center[1] -= avgHeight;
+ }
+ labelLocationHash[createHashKey(center)] = true;
+ }
+ return 'translate(' + center + ')'
+ }
+ });
+
+ pieLabels.select(".nv-label text")
+ .style('text-anchor', labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle') //center the text on it's origin or begin/end if orthogonal aligned
+ .text(function(d, i) {
+ var percent = (d.endAngle - d.startAngle) / (2 * Math.PI);
+ var labelTypes = {
+ "key" : getX(d.data),
+ "value": getY(d.data),
+ "percent": labelFormat(percent)
+ };
+ return (d.value && percent > labelThreshold) ? labelTypes[labelType] : '';
+ })
+ ;
+ }
+
+
+ // Computes the angle of an arc, converting from radians to degrees.
+ function angle(d) {
+ var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
+ return a > 90 ? a - 180 : a;
+ }
+
+ function arcTween(a) {
+ a.endAngle = isNaN(a.endAngle) ? 0 : a.endAngle;
+ a.startAngle = isNaN(a.startAngle) ? 0 : a.startAngle;
+ if (!donut) a.innerRadius = 0;
+ var i = d3.interpolate(this._current, a);
+ this._current = i(0);
+ return function(t) {
+ return arc(i(t));
+ };
+ }
+ });
+
+ renderWatch.renderEnd('pie immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLabels: {get: function(){return showLabels;}, set: function(_){showLabels=_;}},
+ title: {get: function(){return title;}, set: function(_){title=_;}},
+ titleOffset: {get: function(){return titleOffset;}, set: function(_){titleOffset=_;}},
+ labelThreshold: {get: function(){return labelThreshold;}, set: function(_){labelThreshold=_;}},
+ labelFormat: {get: function(){return labelFormat;}, set: function(_){labelFormat=_;}},
+ valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}},
+ x: {get: function(){return getX;}, set: function(_){getX=_;}},
+ id: {get: function(){return id;}, set: function(_){id=_;}},
+ endAngle: {get: function(){return endAngle;}, set: function(_){endAngle=_;}},
+ startAngle: {get: function(){return startAngle;}, set: function(_){startAngle=_;}},
+ padAngle: {get: function(){return padAngle;}, set: function(_){padAngle=_;}},
+ cornerRadius: {get: function(){return cornerRadius;}, set: function(_){cornerRadius=_;}},
+ donutRatio: {get: function(){return donutRatio;}, set: function(_){donutRatio=_;}},
+ pieLabelsOutside: {get: function(){return pieLabelsOutside;}, set: function(_){pieLabelsOutside=_;}},
+ donutLabelsOutside: {get: function(){return donutLabelsOutside;}, set: function(_){donutLabelsOutside=_;}},
+ labelSunbeamLayout: {get: function(){return labelSunbeamLayout;}, set: function(_){labelSunbeamLayout=_;}},
+ donut: {get: function(){return donut;}, set: function(_){donut=_;}},
+ growOnHover: {get: function(){return growOnHover;}, set: function(_){growOnHover=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
+ margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
+ margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+ margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
+ }},
+ y: {get: function(){return getY;}, set: function(_){
+ getY=d3.functor(_);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color=nv.utils.getColor(_);
+ }},
+ labelType: {get: function(){return labelType;}, set: function(_){
+ labelType= _ || 'key';
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+ return chart;
+};
+nv.models.pieChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var pie = nv.models.pie();
+ var legend = nv.models.legend();
+
+ var margin = {top: 30, right: 20, bottom: 20, left: 20}
+ , width = null
+ , height = null
+ , showLegend = true
+ , color = nv.utils.defaultColor()
+ , tooltips = true
+ , tooltip = function(key, y, e, graph) {
+ return '<h3 style="background-color: '
+ + e.color + '">' + key + '</h3>'
+ + '<p>' + y + '</p>';
+ }
+ , state = nv.utils.state()
+ , defaultState = null
+ , noData = "No Data Available."
+ , duration = 250
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var showTooltip = function(e, offsetElement) {
+ var tooltipLabel = pie.x()(e.point);
+ var left = e.pos[0] + ( (offsetElement && offsetElement.offsetLeft) || 0 ),
+ top = e.pos[1] + ( (offsetElement && offsetElement.offsetTop) || 0),
+ y = pie.valueFormat()(pie.y()(e.point)),
+ content = tooltip(tooltipLabel, y, e, chart)
+ ;
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+ };
+
+ var renderWatch = nv.utils.renderWatch(dispatch);
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled })
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.active !== undefined) {
+ data.forEach(function (series, i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ }
+ };
+
+ //============================================================
+ // Chart function
+ //------------------------------------------------------------
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(pie);
+
+ selection.each(function(data) {
+ var container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ var that = this;
+ var availableWidth = (width || parseInt(container.style('width'), 10) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height'), 10) || 400)
+ - margin.top - margin.bottom
+ ;
+
+ chart.update = function() { container.transition().call(chart); };
+ chart.container = this;
+
+ state.setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ //set state.disabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-pieChart').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-pieChart').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-pieWrap');
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+
+ // Legend
+ if (showLegend) {
+ legend.width( availableWidth ).key(pie.x());
+
+ wrap.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ wrap.select('.nv-legendWrap')
+ .attr('transform', 'translate(0,' + (-margin.top) +')');
+ }
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ // Main Chart Component(s)
+ pie.width(availableWidth).height(availableHeight);
+ var pieWrap = g.select('.nv-pieWrap').datum([data]);
+ d3.transition(pieWrap).call(pie);
+
+ // Event Handling/Dispatching (in chart's scope)
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState) {
+ state[key] = newState[key];
+ }
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ pie.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ // Update chart from a state object passed to event handler
+ dispatch.on('changeState', function(e) {
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+ state.disabled = e.disabled;
+ }
+ chart.update();
+ });
+
+ });
+
+ renderWatch.renderEnd('pieChart immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ pie.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.legend = legend;
+ chart.dispatch = dispatch;
+ chart.pie = pie;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ // use Object get/set functionality to map between vars and chart functions
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ // options that require extra logic in the setter
+ color: {get: function(){return color;}, set: function(_){
+ color = _;
+ legend.color(color);
+ pie.color(color);
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ }}
+ });
+ nv.utils.inheritOptions(chart, pie);
+ nv.utils.initOptions(chart);
+ return chart;
+};
+
+nv.models.scatter = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = null
+ , height = null
+ , color = nv.utils.defaultColor() // chooses color
+ , id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't select one
+ , x = d3.scale.linear()
+ , y = d3.scale.linear()
+ , z = d3.scale.linear() //linear because d3.svg.shape.size is treated as area
+ , getX = function(d) { return d.x } // accessor to get the x value
+ , getY = function(d) { return d.y } // accessor to get the y value
+ , getSize = function(d) { return d.size || 1} // accessor to get the point size
+ , getShape = function(d) { return d.shape || 'circle' } // accessor to get point shape
+ , forceX = [] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
+ , forceY = [] // List of numbers to Force into the Y scale
+ , forceSize = [] // List of numbers to Force into the Size scale
+ , interactive = true // If true, plots a voronoi overlay for advanced point intersection
+ , pointActive = function(d) { return !d.notActive } // any points that return false will be filtered out
+ , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
+ , padDataOuter = .1 //outerPadding to imitate ordinal scale outer padding
+ , clipEdge = false // if true, masks points within x and y scale
+ , clipVoronoi = true // if true, masks each point with a circle... can turn off to slightly increase performance
+ , clipRadius = function() { return 25 } // function to get the radius for voronoi point clips
+ , xDomain = null // Override x domain (skips the calculation from data)
+ , yDomain = null // Override y domain
+ , xRange = null // Override x range
+ , yRange = null // Override y range
+ , sizeDomain = null // Override point size domain
+ , sizeRange = null
+ , singlePoint = false
+ , dispatch = d3.dispatch('elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'renderEnd')
+ , useVoronoi = true
+ , duration = 250
+ ;
+
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var x0, y0, z0 // used to store previous scales
+ , timeoutID
+ , needsUpdate = false // Flag for when the points are visually updating, but the interactive layer is behind, to disable tooltips
+ , renderWatch = nv.utils.renderWatch(dispatch, duration)
+ ;
+
+ function chart(selection) {
+ renderWatch.reset();
+ selection.each(function(data) {
+ var container = d3.select(this);
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right;
+ var availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ nv.utils.initSVG(container);
+
+ //add series index to each data point for reference
+ data.forEach(function(series, i) {
+ series.values.forEach(function(point) {
+ point.series = i;
+ });
+ });
+
+ // Setup Scales
+ // remap and flatten the data for use in calculating the scales' domains
+ var seriesData = (xDomain && yDomain && sizeDomain) ? [] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance
+ d3.merge(
+ data.map(function(d) {
+ return d.values.map(function(d,i) {
+ return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) }
+ })
+ })
+ );
+
+ x .domain(xDomain || d3.extent(seriesData.map(function(d) { return d.x; }).concat(forceX)))
+
+ if (padData && data[0])
+ x.range(xRange || [(availableWidth * padDataOuter + availableWidth) / (2 *data[0].values.length), availableWidth - availableWidth * (1 + padDataOuter) / (2 * data[0].values.length) ]);
+ //x.range([availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]);
+ else
+ x.range(xRange || [0, availableWidth]);
+
+ y .domain(yDomain || d3.extent(seriesData.map(function(d) { return d.y }).concat(forceY)))
+ .range(yRange || [availableHeight, 0]);
+
+ z .domain(sizeDomain || d3.extent(seriesData.map(function(d) { return d.size }).concat(forceSize)))
+ .range(sizeRange || [16, 256]);
+
+ // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
+ if (x.domain()[0] === x.domain()[1] || y.domain()[0] === y.domain()[1]) singlePoint = true;
+ if (x.domain()[0] === x.domain()[1])
+ x.domain()[0] ?
+ x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
+ : x.domain([-1,1]);
+
+ if (y.domain()[0] === y.domain()[1])
+ y.domain()[0] ?
+ y.domain([y.domain()[0] - y.domain()[0] * 0.01, y.domain()[1] + y.domain()[1] * 0.01])
+ : y.domain([-1,1]);
+
+ if ( isNaN(x.domain()[0])) {
+ x.domain([-1,1]);
+ }
+
+ if ( isNaN(y.domain()[0])) {
+ y.domain([-1,1]);
+ }
+
+ x0 = x0 || x;
+ y0 = y0 || y;
+ z0 = z0 || z;
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-scatter').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatter nv-chart-' + id + (singlePoint ? ' nv-single-point' : ''));
+ var defsEnter = wrapEnter.append('defs');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-groups');
+ gEnter.append('g').attr('class', 'nv-point-paths');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-edge-clip-' + id)
+ .append('rect');
+
+ wrap.select('#nv-edge-clip-' + id + ' rect')
+ .attr('width', availableWidth)
+ .attr('height', (availableHeight > 0) ? availableHeight : 0);
+
+ g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
+
+ function updateInteractiveLayer() {
+
+ if (!interactive) return false;
+
+ var eventElements;
+
+ var vertices = d3.merge(data.map(function(group, groupIndex) {
+ return group.values
+ .map(function(point, pointIndex) {
+ // *Adding noise to make duplicates very unlikely
+ // *Injecting series and point index for reference
+ /* *Adding a 'jitter' to the points, because there's an issue in d3.geom.voronoi.
+ */
+ var pX = getX(point,pointIndex);
+ var pY = getY(point,pointIndex);
+
+ return [x(pX)+ Math.random() * 1e-7,
+ y(pY)+ Math.random() * 1e-7,
+ groupIndex,
+ pointIndex, point]; //temp hack to add noise untill I think of a better way so there are no duplicates
+ })
+ .filter(function(pointArray, pointIndex) {
+ return pointActive(pointArray[4], pointIndex); // Issue #237.. move filter to after map, so pointIndex is correct!
+ })
+ })
+ );
+
+ //inject series and point index for reference into voronoi
+ if (useVoronoi === true) {
+
+ if(vertices.length < 3) {
+ // Issue #283 - Adding 2 dummy points to the voronoi b/c voronoi requires min 3 points to work
+ vertices.push([x.range()[0] - 20, y.range()[0] - 20, null, null]);
+ vertices.push([x.range()[1] + 20, y.range()[1] + 20, null, null]);
+ vertices.push([x.range()[0] - 20, y.range()[0] + 20, null, null]);
+ vertices.push([x.range()[1] + 20, y.range()[1] - 20, null, null]);
+ }
+
+ // keep voronoi sections from going more than 10 outside of graph
+ // to avoid overlap with other things like legend etc
+ var bounds = d3.geom.polygon([
+ [-10,-10],
+ [-10,height + 10],
+ [width + 10,height + 10],
+ [width + 10,-10]
+ ]);
+
+ var voronoi = d3.geom.voronoi(vertices).map(function(d, i) {
+ return {
+ 'data': bounds.clip(d),
+ 'series': vertices[i][2],
+ 'point': vertices[i][3]
+ }
+ });
+
+ // nuke all voronoi paths on reload and recreate them
+ wrap.select('.nv-point-paths').selectAll('path').remove();
+ var pointPaths = wrap.select('.nv-point-paths').selectAll('path').data(voronoi);
+ pointPaths
+ .enter().append("svg:path")
+ .attr("d", function(d) {
+ if (!d || !d.data || d.data.length === 0)
+ return 'M 0 0';
+ else
+ return "M" + d.data.join(",") + "Z";
+ })
+ .attr("id", function(d,i) {
+ return "nv-path-"+i; })
+ .attr("clip-path", function(d,i) { return "url(#nv-clip-"+i+")"; })
+ ;
+ // chain these to above to see the voronoi elements (good for debugging)
+ //.style("fill", d3.rgb(230, 230, 230))
+ //.style('fill-opacity', 0.4)
+ //.style('stroke-opacity', 1)
+ //.style("stroke", d3.rgb(200,200,200));
+
+ if (clipVoronoi) {
+ // voronoi sections are already set to clip,
+ // just create the circles with the IDs they expect
+ var clips = wrap.append("svg:g").attr("id", "nv-point-clips");
+ clips.selectAll("clipPath")
+ .data(vertices)
+ .enter().append("svg:clipPath")
+ .attr("id", function(d, i) { return "nv-clip-"+i;})
+ .append("svg:circle")
+ .attr('cx', function(d) { return d[0]; })
+ .attr('cy', function(d) { return d[1]; })
+ .attr('r', clipRadius);
+ }
+
+ var mouseEventCallback = function(d,mDispatch) {
+ if (needsUpdate) return 0;
+ var series = data[d.series];
+ if (typeof series === 'undefined') return;
+ var point = series.values[d.point];
+
+ mDispatch({
+ point: point,
+ series: series,
+ pos: [x(getX(point, d.point)) + margin.left, y(getY(point, d.point)) + margin.top],
+ seriesIndex: d.series,
+ pointIndex: d.point
+ });
+ };
+
+ pointPaths
+ .on('click', function(d) {
+ mouseEventCallback(d, dispatch.elementClick);
+ })
+ .on('dblclick', function(d) {
+ mouseEventCallback(d, dispatch.elementDblClick);
+ })
+ .on('mouseover', function(d) {
+ mouseEventCallback(d, dispatch.elementMouseover);
+ })
+ .on('mouseout', function(d, i) {
+ mouseEventCallback(d, dispatch.elementMouseout);
+ });
+
+ } else {
+ /*
+ // bring data in form needed for click handlers
+ var dataWithPoints = vertices.map(function(d, i) {
+ return {
+ 'data': d,
+ 'series': vertices[i][2],
+ 'point': vertices[i][3]
+ }
+ });
+ */
+
+ // add event handlers to points instead voronoi paths
+ wrap.select('.nv-groups').selectAll('.nv-group')
+ .selectAll('.nv-point')
+ //.data(dataWithPoints)
+ //.style('pointer-events', 'auto') // recativate events, disabled by css
+ .on('click', function(d,i) {
+ //nv.log('test', d, i);
+ if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
+ var series = data[d.series],
+ point = series.values[i];
+
+ dispatch.elementClick({
+ point: point,
+ series: series,
+ pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top],
+ seriesIndex: d.series,
+ pointIndex: i
+ });
+ })
+ .on('mouseover', function(d,i) {
+ if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
+ var series = data[d.series],
+ point = series.values[i];
+
+ dispatch.elementMouseover({
+ point: point,
+ series: series,
+ pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top],
+ seriesIndex: d.series,
+ pointIndex: i
+ });
+ })
+ .on('mouseout', function(d,i) {
+ if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
+ var series = data[d.series],
+ point = series.values[i];
+
+ dispatch.elementMouseout({
+ point: point,
+ series: series,
+ seriesIndex: d.series,
+ pointIndex: i
+ });
+ });
+ }
+
+ needsUpdate = false;
+ }
+
+ needsUpdate = true;
+ var groups = wrap.select('.nv-groups').selectAll('.nv-group')
+ .data(function(d) { return d }, function(d) { return d.key });
+ groups.enter().append('g')
+ .style('stroke-opacity', 1e-6)
+ .style('fill-opacity', 1e-6);
+ groups.exit()
+ .remove();
+ groups
+ .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
+ .classed('hover', function(d) { return d.hover });
+ groups.watchTransition(renderWatch, 'scatter: groups')
+ .style('fill', function(d,i) { return color(d, i) })
+ .style('stroke', function(d,i) { return color(d, i) })
+ .style('stroke-opacity', 1)
+ .style('fill-opacity', .5);
+
+ // create the points
+ var points = groups.selectAll('path.nv-point')
+ .data(function(d) { return d.values });
+ points.enter().append('path')
+ .style('fill', function (d,i) { return d.color })
+ .style('stroke', function (d,i) { return d.color })
+ .attr('transform', function(d,i) {
+ return 'translate(' + x0(getX(d,i)) + ',' + y0(getY(d,i)) + ')'
+ })
+ .attr('d',
+ nv.utils.symbol()
+ .type(getShape)
+ .size(function(d,i) { return z(getSize(d,i)) })
+ );
+ points.exit().remove();
+ groups.exit().selectAll('path.nv-point')
+ .watchTransition(renderWatch, 'scatter exit')
+ .attr('transform', function(d,i) {
+ return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
+ })
+ .remove();
+ points.each(function(d,i) {
+ d3.select(this)
+ .classed('nv-point', true)
+ .classed('nv-point-' + i, true)
+ .classed('hover',false)
+ ;
+ });
+ points
+ .watchTransition(renderWatch, 'scatter points')
+ .attr('transform', function(d,i) {
+ //nv.log(d,i,getX(d,i), x(getX(d,i)));
+ return 'translate(' + x(getX(d,i)) + ',' + y(getY(d,i)) + ')'
+ })
+ .attr('d',
+ nv.utils.symbol()
+ .type(getShape)
+ .size(function(d,i) { return z(getSize(d,i)) })
+ );
+
+ // Delay updating the invisible interactive layer for smoother animation
+ clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer
+ timeoutID = setTimeout(updateInteractiveLayer, 300);
+ //updateInteractiveLayer();
+
+ //store old scales for use in transitions on update
+ x0 = x.copy();
+ y0 = y.copy();
+ z0 = z.copy();
+
+ });
+ renderWatch.renderEnd('scatter immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ // utility function calls provided by this chart
+ chart._calls = new function() {
+ this.clearHighlights = function () {
+ d3.selectAll(".nv-chart-" + id + " .nv-point.hover").classed("hover", false);
+ return null;
+ };
+ this.highlightPoint = function (seriesIndex, pointIndex, isHoverOver) {
+ d3.select(".nv-chart-" + id + " .nv-series-" + seriesIndex + " .nv-point-" + pointIndex)
+ .classed("hover", isHoverOver);
+ };
+ };
+
+ // trigger calls from events too
+ dispatch.on('elementMouseover.point', function(d) {
+ if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,true);
+ });
+
+ dispatch.on('elementMouseout.point', function(d) {
+ if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,false);
+ });
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ xScale: {get: function(){return x;}, set: function(_){x=_;}},
+ yScale: {get: function(){return y;}, set: function(_){y=_;}},
+ pointScale: {get: function(){return z;}, set: function(_){z=_;}},
+ xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
+ yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
+ pointDomain: {get: function(){return sizeDomain;}, set: function(_){sizeDomain=_;}},
+ xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
+ yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
+ pointRange: {get: function(){return sizeRange;}, set: function(_){sizeRange=_;}},
+ forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}},
+ forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}},
+ forcePoint: {get: function(){return forceSize;}, set: function(_){forceSize=_;}},
+ interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},
+ pointActive: {get: function(){return pointActive;}, set: function(_){pointActive=_;}},
+ padDataOuter: {get: function(){return padDataOuter;}, set: function(_){padDataOuter=_;}},
+ padData: {get: function(){return padData;}, set: function(_){padData=_;}},
+ clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
+ clipVoronoi: {get: function(){return clipVoronoi;}, set: function(_){clipVoronoi=_;}},
+ clipRadius: {get: function(){return clipRadius;}, set: function(_){clipRadius=_;}},
+ id: {get: function(){return id;}, set: function(_){id=_;}},
+
+
+ // simple functor options
+ x: {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}},
+ y: {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}},
+ pointSize: {get: function(){return getSize;}, set: function(_){getSize = d3.functor(_);}},
+ pointShape: {get: function(){return getShape;}, set: function(_){getShape = d3.functor(_);}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }},
+ useVoronoi: {get: function(){return useVoronoi;}, set: function(_){
+ useVoronoi = _;
+ if (useVoronoi === false) {
+ clipVoronoi = false;
+ }
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+ return chart;
+};
+
+nv.models.scatterChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var scatter = nv.models.scatter()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , legend = nv.models.legend()
+ , distX = nv.models.distribution()
+ , distY = nv.models.distribution()
+ ;
+
+ var margin = {top: 30, right: 20, bottom: 50, left: 75}
+ , width = null
+ , height = null
+ , color = nv.utils.defaultColor()
+ , x = scatter.xScale()
+ , y = scatter.yScale()
+ , showDistX = false
+ , showDistY = false
+ , showLegend = true
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
+ , tooltips = true
+ , tooltipX = function(key, x, y) { return '<strong>' + x + '</strong>' }
+ , tooltipY = function(key, x, y) { return '<strong>' + y + '</strong>' }
+ , tooltip = function(key, x, y, date) { return '<h3>' + key + '</h3>'
+ + '<p>' + date + '</p>' }
+ , state = nv.utils.state()
+ , defaultState = null
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd')
+ , noData = "No Data Available."
+ , duration = 250
+ ;
+
+ scatter
+ .xScale(x)
+ .yScale(y)
+ ;
+ xAxis
+ .orient('bottom')
+ .tickPadding(10)
+ ;
+ yAxis
+ .orient((rightAlignYAxis) ? 'right' : 'left')
+ .tickPadding(10)
+ ;
+ distX
+ .axis('x')
+ ;
+ distY
+ .axis('y')
+ ;
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var x0, y0
+ , renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ var showTooltip = function(e, offsetElement) {
+ //TODO: make tooltip style an option between single or dual on axes (maybe on all charts with axes?
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ leftX = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ topX = y.range()[0] + margin.top + ( offsetElement.offsetTop || 0),
+ leftY = x.range()[0] + margin.left + ( offsetElement.offsetLeft || 0 ),
+ topY = e.pos[1] + ( offsetElement.offsetTop || 0),
+ xVal = xAxis.tickFormat()(scatter.x()(e.point, e.pointIndex)),
+ yVal = yAxis.tickFormat()(scatter.y()(e.point, e.pointIndex));
+
+ if( tooltipX != null )
+ nv.tooltip.show([leftX, topX], tooltipX(e.series.key, xVal, yVal, e, chart), 'n', 1, offsetElement, 'x-nvtooltip');
+ if( tooltipY != null )
+ nv.tooltip.show([leftY, topY], tooltipY(e.series.key, xVal, yVal, e, chart), 'e', 1, offsetElement, 'y-nvtooltip');
+ if( tooltip != null )
+ nv.tooltip.show([left, top], tooltip(e.series.key, xVal, yVal, e.point.tooltip, e, chart), e.value < 0 ? 'n' : 's', null, offsetElement);
+ };
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled })
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(scatter);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+ if (showDistX) renderWatch.models(distX);
+ if (showDistY) renderWatch.models(distY);
+
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ chart.update = function() {
+ if (duration === 0)
+ container.call(chart);
+ else
+ container.transition().duration(duration).call(chart);
+ };
+ chart.container = this;
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disableddisabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display noData message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ renderWatch.renderEnd('scatter immediate');
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = scatter.xScale();
+ y = scatter.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-scatterChart').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatterChart nv-chart-' + scatter.id());
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ // background for pointer events
+ gEnter.append('rect').attr('class', 'nvd3 nv-background').style("pointer-events","none");
+
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-y nv-axis');
+ gEnter.append('g').attr('class', 'nv-scatterWrap');
+ gEnter.append('g').attr('class', 'nv-regressionLinesWrap');
+ gEnter.append('g').attr('class', 'nv-distWrap');
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
+
+ // Legend
+ if (showLegend) {
+ legend.width( availableWidth / 2 );
+
+ wrap.select('.nv-legendWrap')
+ .datum(data)
+ .call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ wrap.select('.nv-legendWrap')
+ .attr('transform', 'translate(' + (availableWidth / 2) + ',' + (-margin.top) +')');
+ }
+
+ // Main Chart Component(s)
+ scatter
+ .width(availableWidth)
+ .height(availableHeight)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled }));
+
+ wrap.select('.nv-scatterWrap')
+ .datum(data.filter(function(d) { return !d.disabled }))
+ .call(scatter);
+
+
+ wrap.select('.nv-regressionLinesWrap')
+ .attr('clip-path', 'url(#nv-edge-clip-' + scatter.id() + ')');
+
+ var regWrap = wrap.select('.nv-regressionLinesWrap').selectAll('.nv-regLines')
+ .data(function (d) {
+ return d;
+ });
+
+ regWrap.enter().append('g').attr('class', 'nv-regLines');
+
+ var regLine = regWrap.selectAll('.nv-regLine')
+ .data(function (d) {
+ return [d]
+ });
+
+ regLine.enter()
+ .append('line').attr('class', 'nv-regLine')
+ .style('stroke-opacity', 0);
+
+ // don't add lines unless we have slope and intercept to use
+ regLine.filter(function(d) {
+ return d.intercept && d.slope;
+ })
+ .watchTransition(renderWatch, 'scatterPlusLineChart: regline')
+ .attr('x1', x.range()[0])
+ .attr('x2', x.range()[1])
+ .attr('y1', function (d, i) {
+ return y(x.domain()[0] * d.slope + d.intercept)
+ })
+ .attr('y2', function (d, i) {
+ return y(x.domain()[1] * d.slope + d.intercept)
+ })
+ .style('stroke', function (d, i, j) {
+ return color(d, j)
+ })
+ .style('stroke-opacity', function (d, i) {
+ return (d.disabled || typeof d.slope === 'undefined' || typeof d.intercept === 'undefined') ? 0 : 1
+ });
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis
+ .scale(x)
+ .ticks( xAxis.ticks() ? xAxis.ticks() : nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize( -availableHeight , 0);
+
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + y.range()[0] + ')')
+ .call(xAxis);
+ }
+
+ if (showYAxis) {
+ yAxis
+ .scale(y)
+ .ticks( yAxis.ticks() ? yAxis.ticks() : nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize( -availableWidth, 0);
+
+ g.select('.nv-y.nv-axis')
+ .call(yAxis);
+ }
+
+
+ if (showDistX) {
+ distX
+ .getData(scatter.x())
+ .scale(x)
+ .width(availableWidth)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled }));
+ gEnter.select('.nv-distWrap').append('g')
+ .attr('class', 'nv-distributionX');
+ g.select('.nv-distributionX')
+ .attr('transform', 'translate(0,' + y.range()[0] + ')')
+ .datum(data.filter(function(d) { return !d.disabled }))
+ .call(distX);
+ }
+
+ if (showDistY) {
+ distY
+ .getData(scatter.y())
+ .scale(y)
+ .width(availableHeight)
+ .color(data.map(function(d,i) {
+ return d.color || color(d, i);
+ }).filter(function(d,i) { return !data[i].disabled }));
+ gEnter.select('.nv-distWrap').append('g')
+ .attr('class', 'nv-distributionY');
+ g.select('.nv-distributionY')
+ .attr('transform', 'translate(' + (rightAlignYAxis ? availableWidth : -distY.size() ) + ',0)')
+ .datum(data.filter(function(d) { return !d.disabled }))
+ .call(distY);
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+
+ scatter.dispatch.on('elementMouseover.tooltip', function(e) {
+ d3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-distx-' + e.pointIndex)
+ .attr('y1', e.pos[1] - availableHeight);
+ d3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-disty-' + e.pointIndex)
+ .attr('x2', e.pos[0] + distX.size());
+
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ // Update chart from a state object passed to event handler
+ dispatch.on('changeState', function(e) {
+
+ if (typeof e.disabled !== 'undefined') {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+
+ state.disabled = e.disabled;
+ }
+
+ chart.update();
+ });
+
+ //store old scales for use in transitions on update
+ x0 = x.copy();
+ y0 = y.copy();
+
+ });
+
+ renderWatch.renderEnd('scatter with line immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ scatter.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+
+ d3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-distx-' + e.pointIndex)
+ .attr('y1', 0);
+ d3.select('.nv-chart-' + scatter.id() + ' .nv-series-' + e.seriesIndex + ' .nv-disty-' + e.pointIndex)
+ .attr('x2', distY.size());
+ });
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.scatter = scatter;
+ chart.legend = legend;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.distX = distX;
+ chart.distY = distY;
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showDistX: {get: function(){return showDistX;}, set: function(_){showDistX=_;}},
+ showDistY: {get: function(){return showDistY;}, set: function(_){showDistY=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ tooltipXContent: {get: function(){return tooltipX;}, set: function(_){tooltipX=_;}},
+ tooltipYContent: {get: function(){return tooltipY;}, set: function(_){tooltipY=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+ duration: {get: function(){return duration;}, set: function(_){duration=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
+ rightAlignYAxis = _;
+ yAxis.orient( (_) ? 'right' : 'left');
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ distX.color(color);
+ distY.color(color);
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, scatter);
+ nv.utils.initOptions(chart);
+ return chart;
+};
+
+nv.models.sparkline = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 2, right: 0, bottom: 2, left: 0}
+ , width = 400
+ , height = 32
+ , animate = true
+ , x = d3.scale.linear()
+ , y = d3.scale.linear()
+ , getX = function(d) { return d.x }
+ , getY = function(d) { return d.y }
+ , color = nv.utils.getColor(['#000'])
+ , xDomain
+ , yDomain
+ , xRange
+ , yRange
+ ;
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ // Setup Scales
+ x .domain(xDomain || d3.extent(data, getX ))
+ .range(xRange || [0, availableWidth]);
+
+ y .domain(yDomain || d3.extent(data, getY ))
+ .range(yRange || [availableHeight, 0]);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-sparkline').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparkline');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
+
+ var paths = wrap.selectAll('path')
+ .data(function(d) { return [d] });
+ paths.enter().append('path');
+ paths.exit().remove();
+ paths
+ .style('stroke', function(d,i) { return d.color || color(d, i) })
+ .attr('d', d3.svg.line()
+ .x(function(d,i) { return x(getX(d,i)) })
+ .y(function(d,i) { return y(getY(d,i)) })
+ );
+
+ // TODO: Add CURRENT data point (Need Min, Mac, Current / Most recent)
+ var points = wrap.selectAll('circle.nv-point')
+ .data(function(data) {
+ var yValues = data.map(function(d, i) { return getY(d,i); });
+ function pointIndex(index) {
+ if (index != -1) {
+ var result = data[index];
+ result.pointIndex = index;
+ return result;
+ } else {
+ return null;
+ }
+ }
+ var maxPoint = pointIndex(yValues.lastIndexOf(y.domain()[1])),
+ minPoint = pointIndex(yValues.indexOf(y.domain()[0])),
+ currentPoint = pointIndex(yValues.length - 1);
+ return [minPoint, maxPoint, currentPoint].filter(function (d) {return d != null;});
+ });
+ points.enter().append('circle');
+ points.exit().remove();
+ points
+ .attr('cx', function(d,i) { return x(getX(d,d.pointIndex)) })
+ .attr('cy', function(d,i) { return y(getY(d,d.pointIndex)) })
+ .attr('r', 2)
+ .attr('class', function(d,i) {
+ return getX(d, d.pointIndex) == x.domain()[1] ? 'nv-point nv-currentValue' :
+ getY(d, d.pointIndex) == y.domain()[0] ? 'nv-point nv-minValue' : 'nv-point nv-maxValue'
+ });
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
+ yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
+ xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
+ yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
+ xScale: {get: function(){return x;}, set: function(_){x=_;}},
+ yScale: {get: function(){return y;}, set: function(_){y=_;}},
+ animate: {get: function(){return animate;}, set: function(_){animate=_;}},
+
+ //functor options
+ x: {get: function(){return getX;}, set: function(_){getX=d3.functor(_);}},
+ y: {get: function(){return getY;}, set: function(_){getY=d3.functor(_);}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }}
+ });
+
+ nv.utils.initOptions(chart);
+ return chart;
+};
+
+nv.models.sparklinePlus = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var sparkline = nv.models.sparkline();
+
+ var margin = {top: 15, right: 100, bottom: 10, left: 50}
+ , width = null
+ , height = null
+ , x
+ , y
+ , index = []
+ , paused = false
+ , xTickFormat = d3.format(',r')
+ , yTickFormat = d3.format(',.2f')
+ , showValue = true
+ , alignValue = true
+ , rightAlignValue = false
+ , noData = "No Data Available."
+ ;
+
+ function chart(selection) {
+ selection.each(function(data) {
+ var container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ chart.update = function() { chart(selection) };
+ chart.container = this;
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ var currentValue = sparkline.y()(data[data.length-1], data.length-1);
+
+ // Setup Scales
+ x = sparkline.xScale();
+ y = sparkline.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-sparklineplus').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparklineplus');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-sparklineWrap');
+ gEnter.append('g').attr('class', 'nv-valueWrap');
+ gEnter.append('g').attr('class', 'nv-hoverArea');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ // Main Chart Component(s)
+ var sparklineWrap = g.select('.nv-sparklineWrap');
+
+ sparkline.width(availableWidth).height(availableHeight);
+ sparklineWrap.call(sparkline);
+
+ var valueWrap = g.select('.nv-valueWrap');
+ var value = valueWrap.selectAll('.nv-currentValue')
+ .data([currentValue]);
+
+ value.enter().append('text').attr('class', 'nv-currentValue')
+ .attr('dx', rightAlignValue ? -8 : 8)
+ .attr('dy', '.9em')
+ .style('text-anchor', rightAlignValue ? 'end' : 'start');
+
+ value
+ .attr('x', availableWidth + (rightAlignValue ? margin.right : 0))
+ .attr('y', alignValue ? function(d) { return y(d) } : 0)
+ .style('fill', sparkline.color()(data[data.length-1], data.length-1))
+ .text(yTickFormat(currentValue));
+
+ gEnter.select('.nv-hoverArea').append('rect')
+ .on('mousemove', sparklineHover)
+ .on('click', function() { paused = !paused })
+ .on('mouseout', function() { index = []; updateValueLine(); });
+
+ g.select('.nv-hoverArea rect')
+ .attr('transform', function(d) { return 'translate(' + -margin.left + ',' + -margin.top + ')' })
+ .attr('width', availableWidth + margin.left + margin.right)
+ .attr('height', availableHeight + margin.top);
+
+ //index is currently global (within the chart), may or may not keep it that way
+ function updateValueLine() {
+ if (paused) return;
+
+ var hoverValue = g.selectAll('.nv-hoverValue').data(index)
+
+ var hoverEnter = hoverValue.enter()
+ .append('g').attr('class', 'nv-hoverValue')
+ .style('stroke-opacity', 0)
+ .style('fill-opacity', 0);
+
+ hoverValue.exit()
+ .transition().duration(250)
+ .style('stroke-opacity', 0)
+ .style('fill-opacity', 0)
+ .remove();
+
+ hoverValue
+ .attr('transform', function(d) { return 'translate(' + x(sparkline.x()(data[d],d)) + ',0)' })
+ .transition().duration(250)
+ .style('stroke-opacity', 1)
+ .style('fill-opacity', 1);
+
+ if (!index.length) return;
+
+ hoverEnter.append('line')
+ .attr('x1', 0)
+ .attr('y1', -margin.top)
+ .attr('x2', 0)
+ .attr('y2', availableHeight);
+
+ hoverEnter.append('text').attr('class', 'nv-xValue')
+ .attr('x', -6)
+ .attr('y', -margin.top)
+ .attr('text-anchor', 'end')
+ .attr('dy', '.9em')
+
+ g.select('.nv-hoverValue .nv-xValue')
+ .text(xTickFormat(sparkline.x()(data[index[0]], index[0])));
+
+ hoverEnter.append('text').attr('class', 'nv-yValue')
+ .attr('x', 6)
+ .attr('y', -margin.top)
+ .attr('text-anchor', 'start')
+ .attr('dy', '.9em')
+
+ g.select('.nv-hoverValue .nv-yValue')
+ .text(yTickFormat(sparkline.y()(data[index[0]], index[0])));
+ }
+
+ function sparklineHover() {
+ if (paused) return;
+
+ var pos = d3.mouse(this)[0] - margin.left;
+
+ function getClosestIndex(data, x) {
+ var distance = Math.abs(sparkline.x()(data[0], 0) - x);
+ var closestIndex = 0;
+ for (var i = 0; i < data.length; i++){
+ if (Math.abs(sparkline.x()(data[i], i) - x) < distance) {
+ distance = Math.abs(sparkline.x()(data[i], i) - x);
+ closestIndex = i;
+ }
+ }
+ return closestIndex;
+ }
+
+ index = [getClosestIndex(data, Math.round(x.invert(pos)))];
+ updateValueLine();
+ }
+
+ });
+
+ return chart;
+ }
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.sparkline = sparkline;
+
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ xTickFormat: {get: function(){return xTickFormat;}, set: function(_){xTickFormat=_;}},
+ yTickFormat: {get: function(){return yTickFormat;}, set: function(_){yTickFormat=_;}},
+ showValue: {get: function(){return showValue;}, set: function(_){showValue=_;}},
+ alignValue: {get: function(){return alignValue;}, set: function(_){alignValue=_;}},
+ rightAlignValue: {get: function(){return rightAlignValue;}, set: function(_){rightAlignValue=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, sparkline);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.stackedArea = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var margin = {top: 0, right: 0, bottom: 0, left: 0}
+ , width = 960
+ , height = 500
+ , color = nv.utils.defaultColor() // a function that computes the color
+ , id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't selet one
+ , getX = function(d) { return d.x } // accessor to get the x value from a data point
+ , getY = function(d) { return d.y } // accessor to get the y value from a data point
+ , style = 'stack'
+ , offset = 'zero'
+ , order = 'default'
+ , interpolate = 'linear' // controls the line interpolation
+ , clipEdge = false // if true, masks lines within x and y scale
+ , x //can be accessed via chart.xScale()
+ , y //can be accessed via chart.yScale()
+ , scatter = nv.models.scatter()
+ , duration = 250
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'areaClick', 'areaMouseover', 'areaMouseout','renderEnd')
+ ;
+
+ // scatter is interactive by default, but this chart isn't so must disable
+ scatter.interactive(false);
+
+ scatter
+ .pointSize(2.2) // default size
+ .pointDomain([2.2, 2.2]) // all the same size by default
+ ;
+
+ /************************************
+ * offset:
+ * 'wiggle' (stream)
+ * 'zero' (stacked)
+ * 'expand' (normalize to 100%)
+ * 'silhouette' (simple centered)
+ *
+ * order:
+ * 'inside-out' (stream)
+ * 'default' (input order)
+ ************************************/
+
+ var renderWatch = nv.utils.renderWatch(dispatch, duration);
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(scatter);
+ selection.each(function(data) {
+ var availableWidth = width - margin.left - margin.right,
+ availableHeight = height - margin.top - margin.bottom,
+ container = d3.select(this);
+ nv.utils.initSVG(container);
+
+ // Setup Scales
+ x = scatter.xScale();
+ y = scatter.yScale();
+
+ var dataRaw = data;
+ // Injecting point index into each point because d3.layout.stack().out does not give index
+ data.forEach(function(aseries, i) {
+ aseries.seriesIndex = i;
+ aseries.values = aseries.values.map(function(d, j) {
+ d.index = j;
+ d.seriesIndex = i;
+ return d;
+ });
+ });
+
+ var dataFiltered = data.filter(function(series) {
+ return !series.disabled;
+ });
+
+ data = d3.layout.stack()
+ .order(order)
+ .offset(offset)
+ .values(function(d) { return d.values }) //TODO: make values customizeable in EVERY model in this fashion
+ .x(getX)
+ .y(getY)
+ .out(function(d, y0, y) {
+ var yHeight = (getY(d) === 0) ? 0 : y;
+ d.display = {
+ y: yHeight,
+ y0: y0
+ };
+ })
+ (dataFiltered);
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-stackedarea').data([data]);
+ var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedarea');
+ var defsEnter = wrapEnter.append('defs');
+ var gEnter = wrapEnter.append('g');
+ var g = wrap.select('g');
+
+ gEnter.append('g').attr('class', 'nv-areaWrap');
+ gEnter.append('g').attr('class', 'nv-scatterWrap');
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ scatter
+ .width(availableWidth)
+ .height(availableHeight)
+ .x(getX)
+ .y(function(d) { return d.display.y + d.display.y0 })
+ .forceY([0])
+ .color(data.map(function(d,i) {
+ return d.color || color(d, d.seriesIndex);
+ }));
+
+ var scatterWrap = g.select('.nv-scatterWrap')
+ .datum(data);
+
+ scatterWrap.call(scatter);
+
+ defsEnter.append('clipPath')
+ .attr('id', 'nv-edge-clip-' + id)
+ .append('rect');
+
+ wrap.select('#nv-edge-clip-' + id + ' rect')
+ .attr('width', availableWidth)
+ .attr('height', availableHeight);
+
+ g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
+
+ var area = d3.svg.area()
+ .x(function(d,i) { return x(getX(d,i)) })
+ .y0(function(d) {
+ return y(d.display.y0)
+ })
+ .y1(function(d) {
+ return y(d.display.y + d.display.y0)
+ })
+ .interpolate(interpolate);
+
+ var zeroArea = d3.svg.area()
+ .x(function(d,i) { return x(getX(d,i)) })
+ .y0(function(d) { return y(d.display.y0) })
+ .y1(function(d) { return y(d.display.y0) });
+
+ var path = g.select('.nv-areaWrap').selectAll('path.nv-area')
+ .data(function(d) { return d });
+
+ path.enter().append('path').attr('class', function(d,i) { return 'nv-area nv-area-' + i })
+ .attr('d', function(d,i){
+ return zeroArea(d.values, d.seriesIndex);
+ })
+ .on('mouseover', function(d,i) {
+ d3.select(this).classed('hover', true);
+ dispatch.areaMouseover({
+ point: d,
+ series: d.key,
+ pos: [d3.event.pageX, d3.event.pageY],
+ seriesIndex: d.seriesIndex
+ });
+ })
+ .on('mouseout', function(d,i) {
+ d3.select(this).classed('hover', false);
+ dispatch.areaMouseout({
+ point: d,
+ series: d.key,
+ pos: [d3.event.pageX, d3.event.pageY],
+ seriesIndex: d.seriesIndex
+ });
+ })
+ .on('click', function(d,i) {
+ d3.select(this).classed('hover', false);
+ dispatch.areaClick({
+ point: d,
+ series: d.key,
+ pos: [d3.event.pageX, d3.event.pageY],
+ seriesIndex: d.seriesIndex
+ });
+ });
+
+ path.exit().remove();
+ path.style('fill', function(d,i){
+ return d.color || color(d, d.seriesIndex)
+ })
+ .style('stroke', function(d,i){ return d.color || color(d, d.seriesIndex) });
+ path.watchTransition(renderWatch,'stackedArea path')
+ .attr('d', function(d,i) {
+ return area(d.values,i)
+ });
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ scatter.dispatch.on('elementMouseover.area', function(e) {
+ g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', true);
+ });
+ scatter.dispatch.on('elementMouseout.area', function(e) {
+ g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', false);
+ });
+
+ //Special offset functions
+ chart.d3_stackedOffset_stackPercent = function(stackData) {
+ var n = stackData.length, //How many series
+ m = stackData[0].length, //how many points per series
+ k = 1 / n,
+ i,
+ j,
+ o,
+ y0 = [];
+
+ for (j = 0; j < m; ++j) { //Looping through all points
+ for (i = 0, o = 0; i < dataRaw.length; i++) { //looping through series'
+ o += getY(dataRaw[i].values[j]); //total value of all points at a certian point in time.
+ }
+
+ if (o) for (i = 0; i < n; i++) {
+ stackData[i][j][1] /= o;
+ } else {
+ for (i = 0; i < n; i++) {
+ stackData[i][j][1] = k;
+ }
+ }
+ }
+ for (j = 0; j < m; ++j) y0[j] = 0;
+ return y0;
+ };
+
+ });
+
+ renderWatch.renderEnd('stackedArea immediate');
+ return chart;
+ }
+
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ scatter.dispatch.on('elementClick.area', function(e) {
+ dispatch.areaClick(e);
+ });
+ scatter.dispatch.on('elementMouseover.tooltip', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top],
+ dispatch.tooltipShow(e);
+ });
+ scatter.dispatch.on('elementMouseout.tooltip', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ //============================================================
+ // Global getters and setters
+ //------------------------------------------------------------
+
+ chart.dispatch = dispatch;
+ chart.scatter = scatter;
+
+ chart.interpolate = function(_) {
+ if (!arguments.length) return interpolate;
+ interpolate = _;
+ return chart;
+ };
+
+ chart.duration = function(_) {
+ if (!arguments.length) return duration;
+ duration = _;
+ renderWatch.reset(duration);
+ scatter.duration(duration);
+ return chart;
+ };
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
+ offset: {get: function(){return offset;}, set: function(_){offset=_;}},
+ order: {get: function(){return order;}, set: function(_){order=_;}},
+ interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}},
+
+ // simple functor options
+ x: {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}},
+ y: {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ }},
+ style: {get: function(){return style;}, set: function(_){
+ style = _;
+ switch (style) {
+ case 'stack':
+ chart.offset('zero');
+ chart.order('default');
+ break;
+ case 'stream':
+ chart.offset('wiggle');
+ chart.order('inside-out');
+ break;
+ case 'stream-center':
+ chart.offset('silhouette');
+ chart.order('inside-out');
+ break;
+ case 'expand':
+ chart.offset('expand');
+ chart.order('default');
+ break;
+ case 'stack_percent':
+ chart.offset(chart.d3_stackedOffset_stackPercent);
+ chart.order('default');
+ break;
+ }
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ scatter.duration(duration);
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, scatter);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.models.stackedAreaChart = function() {
+ "use strict";
+
+ //============================================================
+ // Public Variables with Default Settings
+ //------------------------------------------------------------
+
+ var stacked = nv.models.stackedArea()
+ , xAxis = nv.models.axis()
+ , yAxis = nv.models.axis()
+ , legend = nv.models.legend()
+ , controls = nv.models.legend()
+ , interactiveLayer = nv.interactiveGuideline()
+ ;
+
+ var margin = {top: 30, right: 25, bottom: 50, left: 60}
+ , width = null
+ , height = null
+ , color = nv.utils.defaultColor()
+ , showControls = true
+ , showLegend = true
+ , showXAxis = true
+ , showYAxis = true
+ , rightAlignYAxis = false
+ , useInteractiveGuideline = false
+ , tooltips = true
+ , tooltip = function(key, x, y, e, graph) {
+ return '<h3>' + key + '</h3>' +
+ '<p>' + y + ' on ' + x + '</p>'
+ }
+ , x //can be accessed via chart.xScale()
+ , y //can be accessed via chart.yScale()
+ , yAxisTickFormat = d3.format(',.2f')
+ , state = nv.utils.state()
+ , defaultState = null
+ , noData = 'No Data Available.'
+ , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd')
+ , controlWidth = 250
+ , cData = ['Stacked','Stream','Expanded']
+ , controlLabels = {}
+ , duration = 250
+ ;
+
+ state.style = stacked.style();
+ xAxis.orient('bottom').tickPadding(7);
+ yAxis.orient((rightAlignYAxis) ? 'right' : 'left');
+
+ controls.updateState(false);
+
+ //============================================================
+ // Private Variables
+ //------------------------------------------------------------
+
+ var renderWatch = nv.utils.renderWatch(dispatch);
+ var style = stacked.style();
+
+ var showTooltip = function(e, offsetElement) {
+ var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
+ top = e.pos[1] + ( offsetElement.offsetTop || 0),
+ x = xAxis.tickFormat()(stacked.x()(e.point, e.pointIndex)),
+ y = yAxis.tickFormat()(stacked.y()(e.point, e.pointIndex)),
+ content = tooltip(e.series.key, x, y, e, chart);
+
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's', null, offsetElement);
+ };
+
+ var stateGetter = function(data) {
+ return function(){
+ return {
+ active: data.map(function(d) { return !d.disabled }),
+ style: stacked.style()
+ };
+ }
+ };
+
+ var stateSetter = function(data) {
+ return function(state) {
+ if (state.style !== undefined)
+ style = state.style;
+ if (state.active !== undefined)
+ data.forEach(function(series,i) {
+ series.disabled = !state.active[i];
+ });
+ }
+ };
+
+ function chart(selection) {
+ renderWatch.reset();
+ renderWatch.models(stacked);
+ if (showXAxis) renderWatch.models(xAxis);
+ if (showYAxis) renderWatch.models(yAxis);
+
+ selection.each(function(data) {
+ var container = d3.select(this),
+ that = this;
+ nv.utils.initSVG(container);
+
+ var availableWidth = (width || parseInt(container.style('width')) || 960)
+ - margin.left - margin.right,
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+
+ chart.update = function() { container.transition().duration(duration).call(chart); };
+ chart.container = this;
+
+ state
+ .setter(stateSetter(data), chart.update)
+ .getter(stateGetter(data))
+ .update();
+
+ // DEPRECATED set state.disabled
+ state.disabled = data.map(function(d) { return !!d.disabled });
+
+ if (!defaultState) {
+ var key;
+ defaultState = {};
+ for (key in state) {
+ if (state[key] instanceof Array)
+ defaultState[key] = state[key].slice(0);
+ else
+ defaultState[key] = state[key];
+ }
+ }
+
+ // Display No Data message if there's nothing to show.
+ if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
+ var noDataText = container.selectAll('.nv-noData').data([noData]);
+
+ noDataText.enter().append('text')
+ .attr('class', 'nvd3 nv-noData')
+ .attr('dy', '-.7em')
+ .style('text-anchor', 'middle');
+
+ noDataText
+ .attr('x', margin.left + availableWidth / 2)
+ .attr('y', margin.top + availableHeight / 2)
+ .text(function(d) { return d });
+
+ return chart;
+ } else {
+ container.selectAll('.nv-noData').remove();
+ }
+
+ // Setup Scales
+ x = stacked.xScale();
+ y = stacked.yScale();
+
+ // Setup containers and skeleton of chart
+ var wrap = container.selectAll('g.nv-wrap.nv-stackedAreaChart').data([data]);
+ var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedAreaChart').append('g');
+ var g = wrap.select('g');
+
+ gEnter.append("rect").style("opacity",0);
+ gEnter.append('g').attr('class', 'nv-x nv-axis');
+ gEnter.append('g').attr('class', 'nv-y nv-axis');
+ gEnter.append('g').attr('class', 'nv-stackedWrap');
+ gEnter.append('g').attr('class', 'nv-legendWrap');
+ gEnter.append('g').attr('class', 'nv-controlsWrap');
+ gEnter.append('g').attr('class', 'nv-interactive');
+
+ g.select("rect").attr("width",availableWidth).attr("height",availableHeight);
+
+ // Legend
+ if (showLegend) {
+ var legendWidth = (showControls) ? availableWidth - controlWidth : availableWidth;
+
+ legend.width(legendWidth);
+ g.select('.nv-legendWrap').datum(data).call(legend);
+
+ if ( margin.top != legend.height()) {
+ margin.top = legend.height();
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ g.select('.nv-legendWrap')
+ .attr('transform', 'translate(' + (availableWidth-legendWidth) + ',' + (-margin.top) +')');
+ }
+
+ // Controls
+ if (showControls) {
+ var controlsData = [
+ {
+ key: controlLabels.stacked || 'Stacked',
+ metaKey: 'Stacked',
+ disabled: stacked.style() != 'stack',
+ style: 'stack'
+ },
+ {
+ key: controlLabels.stream || 'Stream',
+ metaKey: 'Stream',
+ disabled: stacked.style() != 'stream',
+ style: 'stream'
+ },
+ {
+ key: controlLabels.expanded || 'Expanded',
+ metaKey: 'Expanded',
+ disabled: stacked.style() != 'expand',
+ style: 'expand'
+ },
+ {
+ key: controlLabels.stack_percent || 'Stack %',
+ metaKey: 'Stack_Percent',
+ disabled: stacked.style() != 'stack_percent',
+ style: 'stack_percent'
+ }
+ ];
+
+ controlWidth = (cData.length/3) * 260;
+ controlsData = controlsData.filter(function(d) {
+ return cData.indexOf(d.metaKey) !== -1;
+ });
+
+ controls
+ .width( controlWidth )
+ .color(['#444', '#444', '#444']);
+
+ g.select('.nv-controlsWrap')
+ .datum(controlsData)
+ .call(controls);
+
+ if ( margin.top != Math.max(controls.height(), legend.height()) ) {
+ margin.top = Math.max(controls.height(), legend.height());
+ availableHeight = (height || parseInt(container.style('height')) || 400)
+ - margin.top - margin.bottom;
+ }
+
+ g.select('.nv-controlsWrap')
+ .attr('transform', 'translate(0,' + (-margin.top) +')');
+ }
+
+ wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
+
+ if (rightAlignYAxis) {
+ g.select(".nv-y.nv-axis")
+ .attr("transform", "translate(" + availableWidth + ",0)");
+ }
+
+ //Set up interactive layer
+ if (useInteractiveGuideline) {
+ interactiveLayer
+ .width(availableWidth)
+ .height(availableHeight)
+ .margin({left: margin.left, top: margin.top})
+ .svgContainer(container)
+ .xScale(x);
+ wrap.select(".nv-interactive").call(interactiveLayer);
+ }
+
+ stacked
+ .width(availableWidth)
+ .height(availableHeight);
+
+ var stackedWrap = g.select('.nv-stackedWrap')
+ .datum(data);
+
+ stackedWrap.transition().call(stacked);
+
+ // Setup Axes
+ if (showXAxis) {
+ xAxis.scale(x)
+ .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
+ .tickSize( -availableHeight, 0);
+
+ g.select('.nv-x.nv-axis')
+ .attr('transform', 'translate(0,' + availableHeight + ')');
+
+ g.select('.nv-x.nv-axis')
+ .transition().duration(0)
+ .call(xAxis);
+ }
+
+ if (showYAxis) {
+ yAxis.scale(y)
+ .ticks(stacked.offset() == 'wiggle' ? 0 : nv.utils.calcTicksY(availableHeight/36, data) )
+ .tickSize(-availableWidth, 0)
+ .setTickFormat( (stacked.style() == 'expand' || stacked.style() == 'stack_percent')
+ ? d3.format('%') : yAxisTickFormat);
+
+ g.select('.nv-y.nv-axis')
+ .transition().duration(0)
+ .call(yAxis);
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (in chart's scope)
+ //------------------------------------------------------------
+
+ stacked.dispatch.on('areaClick.toggle', function(e) {
+ if (data.filter(function(d) { return !d.disabled }).length === 1)
+ data.forEach(function(d) {
+ d.disabled = false;
+ });
+ else
+ data.forEach(function(d,i) {
+ d.disabled = (i != e.seriesIndex);
+ });
+
+ state.disabled = data.map(function(d) { return !!d.disabled });
+ dispatch.stateChange(state);
+
+ chart.update();
+ });
+
+ legend.dispatch.on('stateChange', function(newState) {
+ for (var key in newState)
+ state[key] = newState[key];
+ dispatch.stateChange(state);
+ chart.update();
+ });
+
+ controls.dispatch.on('legendClick', function(d,i) {
+ if (!d.disabled) return;
+
+ controlsData = controlsData.map(function(s) {
+ s.disabled = true;
+ return s;
+ });
+ d.disabled = false;
+
+ stacked.style(d.style);
+
+
+ state.style = stacked.style();
+ dispatch.stateChange(state);
+
+ chart.update();
+ });
+
+ interactiveLayer.dispatch.on('elementMousemove', function(e) {
+ stacked.clearHighlights();
+ var singlePoint, pointIndex, pointXLocation, allData = [];
+ data
+ .filter(function(series, i) {
+ series.seriesIndex = i;
+ return !series.disabled;
+ })
+ .forEach(function(series,i) {
+ pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
+ stacked.highlightPoint(i, pointIndex, true);
+ var point = series.values[pointIndex];
+ if (typeof point === 'undefined') return;
+ if (typeof singlePoint === 'undefined') singlePoint = point;
+ if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
+
+ //If we are in 'expand' mode, use the stacked percent value instead of raw value.
+ var tooltipValue = (stacked.style() == 'expand') ? point.display.y : chart.y()(point,pointIndex);
+ allData.push({
+ key: series.key,
+ value: tooltipValue,
+ color: color(series,series.seriesIndex),
+ stackedValue: point.display
+ });
+ });
+
+ allData.reverse();
+
+ //Highlight the tooltip entry based on which stack the mouse is closest to.
+ if (allData.length > 2) {
+ var yValue = chart.yScale().invert(e.mouseY);
+ var yDistMax = Infinity, indexToHighlight = null;
+ allData.forEach(function(series,i) {
+
+ //To handle situation where the stacked area chart is negative, we need to use absolute values
+ //when checking if the mouse Y value is within the stack area.
+ yValue = Math.abs(yValue);
+ var stackedY0 = Math.abs(series.stackedValue.y0);
+ var stackedY = Math.abs(series.stackedValue.y);
+ if ( yValue >= stackedY0 && yValue <= (stackedY + stackedY0))
+ {
+ indexToHighlight = i;
+ return;
+ }
+ });
+ if (indexToHighlight != null)
+ allData[indexToHighlight].highlight = true;
+ }
+
+ var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
+
+ //If we are in 'expand' mode, force the format to be a percentage.
+ var valueFormatter = (stacked.style() == 'expand') ?
+ function(d,i) {return d3.format(".1%")(d);} :
+ function(d,i) {return yAxis.tickFormat()(d); };
+ interactiveLayer.tooltip
+ .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
+ .chartContainer(that.parentNode)
+ .enabled(tooltips)
+ .valueFormatter(valueFormatter)
+ .data(
+ {
+ value: xValue,
+ series: allData
+ }
+ )();
+
+ interactiveLayer.renderGuideLine(pointXLocation);
+
+ });
+
+ interactiveLayer.dispatch.on("elementMouseout",function(e) {
+ dispatch.tooltipHide();
+ stacked.clearHighlights();
+ });
+
+
+ dispatch.on('tooltipShow', function(e) {
+ if (tooltips) showTooltip(e, that.parentNode);
+ });
+
+ // Update chart from a state object passed to event handler
+ dispatch.on('changeState', function(e) {
+
+ if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) {
+ data.forEach(function(series,i) {
+ series.disabled = e.disabled[i];
+ });
+
+ state.disabled = e.disabled;
+ }
+
+ if (typeof e.style !== 'undefined') {
+ stacked.style(e.style);
+ style = e.style;
+ }
+
+ chart.update();
+ });
+
+ });
+
+ renderWatch.renderEnd('stacked Area chart immediate');
+ return chart;
+ }
+
+ //============================================================
+ // Event Handling/Dispatching (out of chart's scope)
+ //------------------------------------------------------------
+
+ stacked.dispatch.on('tooltipShow', function(e) {
+ e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
+ dispatch.tooltipShow(e);
+ });
+
+ stacked.dispatch.on('tooltipHide', function(e) {
+ dispatch.tooltipHide(e);
+ });
+
+ dispatch.on('tooltipHide', function() {
+ if (tooltips) nv.tooltip.cleanup();
+ });
+
+ //============================================================
+ // Expose Public Variables
+ //------------------------------------------------------------
+
+ // expose chart's sub-components
+ chart.dispatch = dispatch;
+ chart.stacked = stacked;
+ chart.legend = legend;
+ chart.controls = controls;
+ chart.xAxis = xAxis;
+ chart.yAxis = yAxis;
+ chart.interactiveLayer = interactiveLayer;
+
+ yAxis.setTickFormat = yAxis.tickFormat;
+
+ chart.dispatch = dispatch;
+ chart.options = nv.utils.optionsFunc.bind(chart);
+
+ chart._options = Object.create({}, {
+ // simple options, just get/set the necessary values
+ width: {get: function(){return width;}, set: function(_){width=_;}},
+ height: {get: function(){return height;}, set: function(_){height=_;}},
+ showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
+ showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
+ showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
+ tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
+ tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
+ defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
+ noData: {get: function(){return noData;}, set: function(_){noData=_;}},
+ showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}},
+ controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}},
+ yAxisTickFormat: {get: function(){return yAxisTickFormat;}, set: function(_){yAxisTickFormat=_;}},
+
+ // options that require extra logic in the setter
+ margin: {get: function(){return margin;}, set: function(_){
+ margin.top = _.top !== undefined ? _.top : margin.top;
+ margin.right = _.right !== undefined ? _.right : margin.right;
+ margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
+ margin.left = _.left !== undefined ? _.left : margin.left;
+ }},
+ duration: {get: function(){return duration;}, set: function(_){
+ duration = _;
+ renderWatch.reset(duration);
+ stacked.duration(duration);
+ xAxis.duration(duration);
+ yAxis.duration(duration);
+ }},
+ color: {get: function(){return color;}, set: function(_){
+ color = nv.utils.getColor(_);
+ legend.color(color);
+ stacked.color(color);
+ }},
+ rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
+ rightAlignYAxis = _;
+ yAxis.orient( rightAlignYAxis ? 'right' : 'left');
+ }},
+ useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
+ useInteractiveGuideline = !!_;
+ if (_) {
+ chart.interactive(false);
+ chart.useVoronoi(false);
+ }
+ }}
+ });
+
+ nv.utils.inheritOptions(chart, stacked);
+ nv.utils.initOptions(chart);
+
+ return chart;
+};
+
+nv.version = "1.7.1";
+})();
\ No newline at end of file
--- /dev/null
+/* nvd3 version 1.7.1 (https://github.com/novus/nvd3) 2015-02-08 */
+!function(){var a=window.nv||{};window.nv=a,a.dev=!1,a.tooltip=a.tooltip||{},a.utils=a.utils||{},a.models=a.models||{},a.charts={},a.graphs=[],a.logs={},a.dispatch=d3.dispatch("render_start","render_end"),Function.prototype.bind||(Function.prototype.bind=function(a){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var b=Array.prototype.slice.call(arguments,1),c=this,d=function(){},e=function(){return c.apply(this instanceof d&&a?this:a,b.concat(Array.prototype.slice.call(arguments)))};return d.prototype=this.prototype,e.prototype=new d,e}),a.dev&&(a.dispatch.on("render_start",function(){a.logs.startTime=+new Date}),a.dispatch.on("render_end",function(){a.logs.endTime=+new Date,a.logs.totalTime=a.logs.endTime-a.logs.startTime,a.log("total",a.logs.totalTime)})),a.log=function(){if(a.dev&&window.console&&console.log&&console.log.apply)console.log.apply(console,arguments);else if(a.dev&&window.console&&"function"==typeof console.log&&Function.prototype.bind){var b=Function.prototype.bind.call(console.log,console);b.apply(console,arguments)}return arguments[arguments.length-1]},a.deprecated=function(b){a.dev&&console&&console.warn&&console.warn("`"+b+"` has been deprecated.")},a.render=function(b){b=b||1,a.render.active=!0,a.dispatch.render_start(),setTimeout(function(){for(var c,d,e=0;b>e&&(d=a.render.queue[e]);e++)c=d.generate(),typeof d.callback==typeof Function&&d.callback(c),a.graphs.push(c);a.render.queue.splice(0,e),a.render.queue.length?setTimeout(arguments.callee,0):(a.dispatch.render_end(),a.render.active=!1)},0)},a.render.active=!1,a.render.queue=[],a.addGraph=function(b){typeof arguments[0]==typeof Function&&(b={generate:arguments[0],callback:arguments[1]}),a.render.queue.push(b),a.render.active||a.render()},a.interactiveGuideline=function(){"use strict";function b(l){l.each(function(l){function m(){var a=d3.mouse(this),d=a[0],e=a[1],i=!0,j=!1;if(k&&(d=d3.event.offsetX,e=d3.event.offsetY,"svg"!==d3.event.target.tagName&&(i=!1),d3.event.target.className.baseVal.match("nv-legend")&&(j=!0)),i&&(d-=f.left,e-=f.top),0>d||0>e||d>o||e>p||d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement||j){if(k&&d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement&&d3.event.relatedTarget.className.match(c.nvPointerEventsClass))return;return h.elementMouseout({mouseX:d,mouseY:e}),void b.renderGuideLine(null)}var l=g.invert(d);h.elementMousemove({mouseX:d,mouseY:e,pointXValue:l}),"dblclick"===d3.event.type&&h.elementDblclick({mouseX:d,mouseY:e,pointXValue:l}),"click"===d3.event.type&&h.elementClick({mouseX:d,mouseY:e,pointXValue:l})}var n=d3.select(this),o=d||960,p=e||400,q=n.selectAll("g.nv-wrap.nv-interactiveLineLayer").data([l]),r=q.enter().append("g").attr("class"," nv-wrap nv-interactiveLineLayer");r.append("g").attr("class","nv-interactiveGuideLine"),j&&(j.on("mousemove",m,!0).on("mouseout",m,!0).on("dblclick",m).on("click",m),b.renderGuideLine=function(b){if(i){var c=q.select(".nv-interactiveGuideLine").selectAll("line").data(null!=b?[a.utils.NaNtoZero(b)]:[],String);c.enter().append("line").attr("class","nv-guideline").attr("x1",function(a){return a}).attr("x2",function(a){return a}).attr("y1",p).attr("y2",0),c.exit().remove()}})})}var c=a.models.tooltip(),d=null,e=null,f={left:0,top:0},g=d3.scale.linear(),h=(d3.scale.linear(),d3.dispatch("elementMousemove","elementMouseout","elementClick","elementDblclick")),i=!0,j=null,k="ActiveXObject"in window;return b.dispatch=h,b.tooltip=c,b.margin=function(a){return arguments.length?(f.top="undefined"!=typeof a.top?a.top:f.top,f.left="undefined"!=typeof a.left?a.left:f.left,b):f},b.width=function(a){return arguments.length?(d=a,b):d},b.height=function(a){return arguments.length?(e=a,b):e},b.xScale=function(a){return arguments.length?(g=a,b):g},b.showGuideLine=function(a){return arguments.length?(i=a,b):i},b.svgContainer=function(a){return arguments.length?(j=a,b):j},b},a.interactiveBisect=function(a,b,c){"use strict";if(!(a instanceof Array))return null;"function"!=typeof c&&(c=function(a){return a.x});var d=d3.bisector(c).left,e=d3.max([0,d(a,b)-1]),f=c(a[e],e);if("undefined"==typeof f&&(f=e),f===b)return e;var g=d3.min([e+1,a.length-1]),h=c(a[g],g);return"undefined"==typeof h&&(h=g),Math.abs(h-b)>=Math.abs(f-b)?e:g},a.nearestValueIndex=function(a,b,c){"use strict";var d=1/0,e=null;return a.forEach(function(a,f){var g=Math.abs(b-a);d>=g&&c>g&&(d=g,e=f)}),e},function(){"use strict";window.nv.tooltip={},window.nv.models.tooltip=function(){function b(){if(l){var a=d3.select(l);"svg"!==a.node().tagName&&(a=a.select("svg"));var b=a.node()?a.attr("viewBox"):null;if(b){b=b.split(" ");var c=parseInt(a.style("width"))/b[2];n.left=n.left*c,n.top=n.top*c}}}function c(a){var b;b=d3.select(l?l:"body");var c=b.select(".nvtooltip");return null===c.node()&&(c=b.append("div").attr("class","nvtooltip "+(k?k:"xy-tooltip")).attr("id",p)),c.node().innerHTML=a,c.style("top",0).style("left",0).style("opacity",0),c.selectAll("div, table, td, tr").classed(q,!0),c.classed(q,!0),c.node()}function d(){if(o&&u(f)){b();var e=n.left,k=null!=j?j:n.top,p=c(t(f));if(m=p,l){var q=l.getElementsByTagName("svg")[0],r=(q?q.getBoundingClientRect():l.getBoundingClientRect(),{left:0,top:0});if(q){var s=q.getBoundingClientRect(),v=l.getBoundingClientRect(),w=s.top;if(0>w){var x=l.getBoundingClientRect();w=Math.abs(w)>x.height?0:w}r.top=Math.abs(w-v.top),r.left=Math.abs(s.left-v.left)}e+=l.offsetLeft+r.left-2*l.scrollLeft,k+=l.offsetTop+r.top-2*l.scrollTop}return i&&i>0&&(k=Math.floor(k/i)*i),a.tooltip.calcTooltipPosition([e,k],g,h,p),d}}var e=null,f=null,g="w",h=50,i=25,j=null,k=null,l=null,m=null,n={left:null,top:null},o=!0,p="nvtooltip-"+Math.floor(1e5*Math.random()),q="nv-pointer-events-none",r=function(a){return a},s=function(a){return a},t=function(a){if(null!=e)return e;if(null==a)return"";var b=d3.select(document.createElement("table")),c=b.selectAll("thead").data([a]).enter().append("thead");c.append("tr").append("td").attr("colspan",3).append("strong").classed("x-value",!0).html(s(a.value));var d=b.selectAll("tbody").data([a]).enter().append("tbody"),f=d.selectAll("tr").data(function(a){return a.series}).enter().append("tr").classed("highlight",function(a){return a.highlight});f.append("td").classed("legend-color-guide",!0).append("div").style("background-color",function(a){return a.color}),f.append("td").classed("key",!0).html(function(a){return a.key}),f.append("td").classed("value",!0).html(function(a,b){return r(a.value,b)}),f.selectAll("td").each(function(a){if(a.highlight){var b=d3.scale.linear().domain([0,1]).range(["#fff",a.color]),c=.6;d3.select(this).style("border-bottom-color",b(c)).style("border-top-color",b(c))}});var g=b.node().outerHTML;return void 0!==a.footer&&(g+="<div class='footer'>"+a.footer+"</div>"),g},u=function(a){return a&&a.series&&a.series.length>0?!0:!1};return d.nvPointerEventsClass=q,d.content=function(a){return arguments.length?(e=a,d):e},d.tooltipElem=function(){return m},d.contentGenerator=function(a){return arguments.length?("function"==typeof a&&(t=a),d):t},d.data=function(a){return arguments.length?(f=a,d):f},d.gravity=function(a){return arguments.length?(g=a,d):g},d.distance=function(a){return arguments.length?(h=a,d):h},d.snapDistance=function(a){return arguments.length?(i=a,d):i},d.classes=function(a){return arguments.length?(k=a,d):k},d.chartContainer=function(a){return arguments.length?(l=a,d):l},d.position=function(a){return arguments.length?(n.left="undefined"!=typeof a.left?a.left:n.left,n.top="undefined"!=typeof a.top?a.top:n.top,d):n},d.fixedTop=function(a){return arguments.length?(j=a,d):j},d.enabled=function(a){return arguments.length?(o=a,d):o},d.valueFormatter=function(a){return arguments.length?("function"==typeof a&&(r=a),d):r},d.headerFormatter=function(a){return arguments.length?("function"==typeof a&&(s=a),d):s},d.id=function(){return p},d},a.tooltip.show=function(b,c,d,e,f,g){var h=document.createElement("div");h.className="nvtooltip "+(g?g:"xy-tooltip");var i=f;(!f||f.tagName.match(/g|svg/i))&&(i=document.getElementsByTagName("body")[0]),h.style.left=0,h.style.top=0,h.style.opacity=0,"string"!=typeof c?h.appendChild(c):h.innerHTML=c,i.appendChild(h),f&&(b[0]=b[0]-f.scrollLeft,b[1]=b[1]-f.scrollTop),a.tooltip.calcTooltipPosition(b,d,e,h)},a.tooltip.findFirstNonSVGParent=function(a){for(;null!==a.tagName.match(/^g|svg$/i);)a=a.parentNode;return a},a.tooltip.findTotalOffsetTop=function(a,b){var c=b;do isNaN(a.offsetTop)||(c+=a.offsetTop);while(a=a.offsetParent);return c},a.tooltip.findTotalOffsetLeft=function(a,b){var c=b;do isNaN(a.offsetLeft)||(c+=a.offsetLeft);while(a=a.offsetParent);return c},a.tooltip.calcTooltipPosition=function(b,c,d,e){var f,g,h=parseInt(e.offsetHeight),i=parseInt(e.offsetWidth),j=a.utils.windowSize().width,k=a.utils.windowSize().height,l=window.pageYOffset,m=window.pageXOffset;k=window.innerWidth>=document.body.scrollWidth?k:k-16,j=window.innerHeight>=document.body.scrollHeight?j:j-16,c=c||"s",d=d||20;var n=function(b){return a.tooltip.findTotalOffsetTop(b,g)},o=function(b){return a.tooltip.findTotalOffsetLeft(b,f)};switch(c){case"e":f=b[0]-i-d,g=b[1]-h/2;var p=o(e),q=n(e);m>p&&(f=b[0]+d>m?b[0]+d:m-p+f),l>q&&(g=l-q+g),q+h>l+k&&(g=l+k-q+g-h);break;case"w":f=b[0]+d,g=b[1]-h/2;var p=o(e),q=n(e);p+i>j&&(f=b[0]-i-d),l>q&&(g=l+5),q+h>l+k&&(g=l+k-q+g-h);break;case"n":f=b[0]-i/2-5,g=b[1]+d;var p=o(e),q=n(e);m>p&&(f=m+5),p+i>j&&(f=f-i/2+5),q+h>l+k&&(g=l+k-q+g-h);break;case"s":f=b[0]-i/2,g=b[1]-h-d;var p=o(e),q=n(e);m>p&&(f=m+5),p+i>j&&(f=f-i/2+5),l>q&&(g=l);break;case"none":f=b[0],g=b[1]-d;var p=o(e),q=n(e)}return e.style.left=f+"px",e.style.top=g+"px",e.style.opacity=1,e.style.position="absolute",e},a.tooltip.cleanup=function(){for(var a=document.getElementsByClassName("nvtooltip"),b=[];a.length;)b.push(a[0]),a[0].style.transitionDelay="0 !important",a[0].style.opacity=0,a[0].className="nvtooltip-pending-removal";setTimeout(function(){for(;b.length;){var a=b.pop();a.parentNode.removeChild(a)}},500)}}(),a.utils.windowSize=function(){var a={width:640,height:480};return document.body&&document.body.offsetWidth&&(a.width=document.body.offsetWidth,a.height=document.body.offsetHeight),"CSS1Compat"==document.compatMode&&document.documentElement&&document.documentElement.offsetWidth&&(a.width=document.documentElement.offsetWidth,a.height=document.documentElement.offsetHeight),window.innerWidth&&window.innerHeight&&(a.width=window.innerWidth,a.height=window.innerHeight),a},a.utils.windowResize=function(b){return window.addEventListener?window.addEventListener("resize",b):a.log("ERROR: Failed to bind to window.resize with: ",b),{callback:b,clear:function(){window.removeEventListener("resize",b)}}},a.utils.getColor=function(b){return arguments.length?b instanceof Array?function(a,c){return a.color||b[c%b.length]}:b:a.utils.defaultColor()},a.utils.defaultColor=function(){var a=d3.scale.category20().range();return function(b,c){return b.color||a[c%a.length]}},a.utils.customTheme=function(a,b,c){b=b||function(a){return a.key},c=c||d3.scale.category20().range();var d=c.length;return function(e){var f=b(e);return"function"==typeof a[f]?a[f]():void 0!==a[f]?a[f]:(d||(d=c.length),d-=1,c[d])}},a.utils.pjax=function(b,c){var d=function(d){d3.html(d,function(d){var e=d3.select(c).node();e.parentNode.replaceChild(d3.select(d).select(c).node(),e),a.utils.pjax(b,c)})};d3.selectAll(b).on("click",function(){history.pushState(this.href,this.textContent,this.href),d(this.href),d3.event.preventDefault()}),d3.select(window).on("popstate",function(){d3.event.state&&d(d3.event.state)})},a.utils.calcApproxTextWidth=function(a){if("function"==typeof a.style&&"function"==typeof a.text){var b=parseInt(a.style("font-size").replace("px","")),c=a.text().length;return c*b*.5}return 0},a.utils.NaNtoZero=function(a){return"number"!=typeof a||isNaN(a)||null===a||1/0===a||a===-1/0?0:a},d3.selection.prototype.watchTransition=function(a){var b=[this].concat([].slice.call(arguments,1));return a.transition.apply(a,b)},a.utils.renderWatch=function(b,c){if(!(this instanceof a.utils.renderWatch))return new a.utils.renderWatch(b,c);var d=void 0!==c?c:250,e=[],f=this;this.models=function(a){return a=[].slice.call(arguments,0),a.forEach(function(a){a.__rendered=!1,function(a){a.dispatch.on("renderEnd",function(){a.__rendered=!0,f.renderEnd("model")})}(a),e.indexOf(a)<0&&e.push(a)}),this},this.reset=function(a){void 0!==a&&(d=a),e=[]},this.transition=function(a,b,c){if(b=arguments.length>1?[].slice.call(arguments,1):[],c=b.length>1?b.pop():void 0!==d?d:250,a.__rendered=!1,e.indexOf(a)<0&&e.push(a),0===c)return a.__rendered=!0,a.delay=function(){return this},a.duration=function(){return this},a;a.__rendered=0===a.length?!0:a.every(function(a){return!a.length})?!0:!1;var g=0;return a.transition().duration(c).each(function(){++g}).each("end",function(){0===--g&&(a.__rendered=!0,f.renderEnd.apply(this,b))})},this.renderEnd=function(){e.every(function(a){return a.__rendered})&&(e.forEach(function(a){a.__rendered=!1}),b.renderEnd.apply(this,arguments))}},a.utils.deepExtend=function(b){var c=arguments.length>1?[].slice.call(arguments,1):[];c.forEach(function(c){for(key in c){var d=b[key]instanceof Array,e="object"==typeof b[key],f="object"==typeof c[key];e&&!d&&f?a.utils.deepExtend(b[key],c[key]):b[key]=c[key]}})},a.utils.state=function(){if(!(this instanceof a.utils.state))return new a.utils.state;var b={},c=function(){},d=function(){return{}},e=null,f=null;this.dispatch=d3.dispatch("change","set"),this.dispatch.on("set",function(a){c(a,!0)}),this.getter=function(a){return d=a,this},this.setter=function(a,b){return b||(b=function(){}),c=function(c,d){a(c),d&&b()},this},this.init=function(b){e=e||{},a.utils.deepExtend(e,b)};var g=function(){var a=d();if(JSON.stringify(a)===JSON.stringify(b))return!1;for(var c in a)void 0===b[c]&&(b[c]={}),b[c]=a[c],f=!0;return!0};this.update=function(){e&&(c(e,!1),e=null),g.call(this)&&this.dispatch.change(b)}},a.utils.optionsFunc=function(b){return a.deprecated("nv.utils.optionsFunc"),b&&d3.map(b).forEach(function(a,b){"function"==typeof this[a]&&this[a](b)}.bind(this)),this},a.utils.calcTicksX=function(b,c){var d=1,e=0;for(e;e<c.length;e+=1){var f=c[e]&&c[e].values?c[e].values.length:0;d=f>d?f:d}return a.log("Requested number of ticks: ",b),a.log("Calculated max values to be: ",d),b=b>d?b=d-1:b,b=1>b?1:b,b=Math.floor(b),a.log("Calculating tick count as: ",b),b},a.utils.calcTicksY=function(b,c){return a.utils.calcTicksX(b,c)},a.utils.initOption=function(a,b){a[b]=a._calls&&a._calls[b]?a._calls[b]:function(c){return arguments.length?(a._options[b]=c,a):a._options[b]}},a.utils.initOptions=function(b){var c=Object.getOwnPropertyNames(b._options||{}),d=Object.getOwnPropertyNames(b._calls||{});c=c.concat(d);for(var e in c)a.utils.initOption(b,c[e])},a.utils.inheritOptionsD3=function(a,b,c){a._d3options=c.concat(a._d3options||[]),c.unshift(b),c.unshift(a),d3.rebind.apply(this,c)},a.utils.arrayUnique=function(a){return a.sort().filter(function(b,c){return!c||b!=a[c-1]})},a.utils.symbolMap=d3.map(),a.utils.symbol=function(){function b(b,e){var f=c.call(this,b,e),g=d.call(this,b,e);return-1!==d3.svg.symbolTypes.indexOf(f)?d3.svg.symbol().type(f).size(g)():a.utils.symbolMap.get(f)(g)}var c,d=64;return b.type=function(a){return arguments.length?(c=d3.functor(a),b):c},b.size=function(a){return arguments.length?(d=d3.functor(a),b):d},b},a.utils.inheritOptions=function(b,c){var d=Object.getOwnPropertyNames(c._options||{}),e=Object.getOwnPropertyNames(c._calls||{}),f=c._inherited||[],g=c._d3options||[],h=d.concat(e).concat(f).concat(g);h.unshift(c),h.unshift(b),d3.rebind.apply(this,h),b._inherited=a.utils.arrayUnique(d.concat(e).concat(f).concat(d).concat(b._inherited||[])),b._d3options=a.utils.arrayUnique(g.concat(b._d3options||[]))},a.utils.initSVG=function(a){a.classed({"nvd3-svg":!0})},a.models.axis=function(){"use strict";function b(g){return t.reset(),g.each(function(b){var g=d3.select(this);a.utils.initSVG(g);var q=g.selectAll("g.nv-wrap.nv-axis").data([b]),r=q.enter().append("g").attr("class","nvd3 nv-wrap nv-axis"),u=(r.append("g"),q.select("g"));null!==o?c.ticks(o):("top"==c.orient()||"bottom"==c.orient())&&c.ticks(Math.abs(d.range()[1]-d.range()[0])/100),u.watchTransition(t,"axis").call(c),s=s||c.scale();var v=c.tickFormat();null==v&&(v=s.tickFormat());var w=u.selectAll("text.nv-axislabel").data([h||null]);switch(w.exit().remove(),c.orient()){case"top":w.enter().append("text").attr("class","nv-axislabel");var x;if(x=d.range().length<2?0:2===d.range().length?d.range()[1]:d.range()[d.range().length-1]+(d.range()[1]-d.range()[0]),w.attr("text-anchor","middle").attr("y",0).attr("x",x/2),i){var y=q.selectAll("g.nv-axisMaxMin").data(d.domain());y.enter().append("g").attr("class","nv-axisMaxMin").append("text"),y.exit().remove(),y.attr("transform",function(b){return"translate("+a.utils.NaNtoZero(d(b))+",0)"}).select("text").attr("dy","-0.5em").attr("y",-c.tickPadding()).attr("text-anchor","middle").text(function(a){var b=v(a);return(""+b).match("NaN")?"":b}),y.watchTransition(t,"min-max top").attr("transform",function(b,c){return"translate("+a.utils.NaNtoZero(d.range()[c])+",0)"})}break;case"bottom":var z=p+36,A=30,B=u.selectAll("g").select("text");if(k%360){B.each(function(){var a=this.getBoundingClientRect().width;a>A&&(A=a)});var C=Math.abs(Math.sin(k*Math.PI/180)),z=(C?C*A:A)+30;B.attr("transform",function(){return"rotate("+k+" 0,0)"}).style("text-anchor",k%360>0?"start":"end")}w.enter().append("text").attr("class","nv-axislabel");var x;if(x=d.range().length<2?0:2===d.range().length?d.range()[1]:d.range()[d.range().length-1]+(d.range()[1]-d.range()[0]),w.attr("text-anchor","middle").attr("y",z).attr("x",x/2),i){var y=q.selectAll("g.nv-axisMaxMin").data([d.domain()[0],d.domain()[d.domain().length-1]]);y.enter().append("g").attr("class","nv-axisMaxMin").append("text"),y.exit().remove(),y.attr("transform",function(b){return"translate("+a.utils.NaNtoZero(d(b)+(n?d.rangeBand()/2:0))+",0)"}).select("text").attr("dy",".71em").attr("y",c.tickPadding()).attr("transform",function(){return"rotate("+k+" 0,0)"}).style("text-anchor",k?k%360>0?"start":"end":"middle").text(function(a){var b=v(a);return(""+b).match("NaN")?"":b}),y.watchTransition(t,"min-max bottom").attr("transform",function(b){return"translate("+a.utils.NaNtoZero(d(b)+(n?d.rangeBand()/2:0))+",0)"})}m&&B.attr("transform",function(a,b){return"translate(0,"+(b%2==0?"0":"12")+")"});break;case"right":if(w.enter().append("text").attr("class","nv-axislabel"),w.style("text-anchor",l?"middle":"begin").attr("transform",l?"rotate(90)":"").attr("y",l?-Math.max(e.right,f)+12:-10).attr("x",l?d.range()[0]/2:c.tickPadding()),i){var y=q.selectAll("g.nv-axisMaxMin").data(d.domain());y.enter().append("g").attr("class","nv-axisMaxMin").append("text").style("opacity",0),y.exit().remove(),y.attr("transform",function(b){return"translate(0,"+a.utils.NaNtoZero(d(b))+")"}).select("text").attr("dy",".32em").attr("y",0).attr("x",c.tickPadding()).style("text-anchor","start").text(function(a){var b=v(a);return(""+b).match("NaN")?"":b}),y.watchTransition(t,"min-max right").attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(d.range()[c])+")"}).select("text").style("opacity",1)}break;case"left":if(w.enter().append("text").attr("class","nv-axislabel"),w.style("text-anchor",l?"middle":"end").attr("transform",l?"rotate(-90)":"").attr("y",l?-Math.max(e.left,f)+25-(p||0):-10).attr("x",l?-d.range()[0]/2:-c.tickPadding()),i){var y=q.selectAll("g.nv-axisMaxMin").data(d.domain());y.enter().append("g").attr("class","nv-axisMaxMin").append("text").style("opacity",0),y.exit().remove(),y.attr("transform",function(b){return"translate(0,"+a.utils.NaNtoZero(s(b))+")"}).select("text").attr("dy",".32em").attr("y",0).attr("x",-c.tickPadding()).attr("text-anchor","end").text(function(a){var b=v(a);return(""+b).match("NaN")?"":b}),y.watchTransition(t,"min-max right").attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(d.range()[c])+")"}).select("text").style("opacity",1)}}if(w.text(function(a){return a}),!i||"left"!==c.orient()&&"right"!==c.orient()||(u.selectAll("g").each(function(a){d3.select(this).select("text").attr("opacity",1),(d(a)<d.range()[1]+10||d(a)>d.range()[0]-10)&&((a>1e-10||-1e-10>a)&&d3.select(this).attr("opacity",0),d3.select(this).select("text").attr("opacity",0))}),d.domain()[0]==d.domain()[1]&&0==d.domain()[0]&&q.selectAll("g.nv-axisMaxMin").style("opacity",function(a,b){return b?0:1})),i&&("top"===c.orient()||"bottom"===c.orient())){var D=[];q.selectAll("g.nv-axisMaxMin").each(function(a,b){try{D.push(b?d(a)-this.getBoundingClientRect().width-4:d(a)+this.getBoundingClientRect().width+4)}catch(c){D.push(b?d(a)-4:d(a)+4)}}),u.selectAll("g").each(function(a){(d(a)<D[0]||d(a)>D[1])&&(a>1e-10||-1e-10>a?d3.select(this).remove():d3.select(this).select("text").remove())})}j&&u.selectAll(".tick").filter(function(){return!parseFloat(Math.round(1e5*this.__data__)/1e6)&&void 0!==this.__data__}).classed("zero",!0),s=d.copy()}),t.renderEnd("axis immediate"),b}var c=d3.svg.axis(),d=d3.scale.linear(),e={top:0,right:0,bottom:0,left:0},f=75,g=60,h=null,i=!0,j=!0,k=0,l=!0,m=!1,n=!1,o=null,p=0,q=250,r=d3.dispatch("renderEnd");c.scale(d).orient("bottom").tickFormat(function(a){return a});var s,t=a.utils.renderWatch(r,q);return b.axis=c,b.dispatch=r,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{axisLabelDistance:{get:function(){return p},set:function(a){p=a}},staggerLabels:{get:function(){return m},set:function(a){m=a}},rotateLabels:{get:function(){return k},set:function(a){k=a}},rotateYLabel:{get:function(){return l},set:function(a){l=a}},highlightZero:{get:function(){return j},set:function(a){j=a}},showMaxMin:{get:function(){return i},set:function(a){i=a}},axisLabel:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return g},set:function(a){g=a}},ticks:{get:function(){return o},set:function(a){o=a}},width:{get:function(){return f},set:function(a){f=a}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},duration:{get:function(){return q},set:function(a){q=a,t.reset(q)}},scale:{get:function(){return d},set:function(e){d=e,c.scale(d),n="function"==typeof d.rangeBands,a.utils.inheritOptionsD3(b,d,["domain","range","rangeBand","rangeBands"])}}}),a.utils.initOptions(b),a.utils.inheritOptionsD3(b,c,["orient","tickValues","tickSubdivide","tickSize","tickPadding","tickFormat"]),a.utils.inheritOptionsD3(b,d,["domain","range","rangeBand","rangeBands"]),b},a.models.bullet=function(){"use strict";function b(d){return d.each(function(b,d){var o=m-c.left-c.right,r=n-c.top-c.bottom,s=d3.select(this);a.utils.initSVG(s);{var t=f.call(this,b,d).slice().sort(d3.descending),u=g.call(this,b,d).slice().sort(d3.descending),v=h.call(this,b,d).slice().sort(d3.descending),w=i.call(this,b,d).slice(),x=j.call(this,b,d).slice(),y=k.call(this,b,d).slice(),z=d3.scale.linear().domain(d3.extent(d3.merge([l,t]))).range(e?[o,0]:[0,o]);this.__chart__||d3.scale.linear().domain([0,1/0]).range(z.range())}this.__chart__=z;var A=d3.min(t),B=d3.max(t),C=t[1],D=s.selectAll("g.nv-wrap.nv-bullet").data([b]),E=D.enter().append("g").attr("class","nvd3 nv-wrap nv-bullet"),F=E.append("g"),G=D.select("g");F.append("rect").attr("class","nv-range nv-rangeMax"),F.append("rect").attr("class","nv-range nv-rangeAvg"),F.append("rect").attr("class","nv-range nv-rangeMin"),F.append("rect").attr("class","nv-measure"),F.append("path").attr("class","nv-markerTriangle"),D.attr("transform","translate("+c.left+","+c.top+")");var H=function(a){return Math.abs(z(a)-z(0))},I=function(a){return z(0>a?a:0)};G.select("rect.nv-rangeMax").attr("height",r).attr("width",H(B>0?B:A)).attr("x",I(B>0?B:A)).datum(B>0?B:A),G.select("rect.nv-rangeAvg").attr("height",r).attr("width",H(C)).attr("x",I(C)).datum(C),G.select("rect.nv-rangeMin").attr("height",r).attr("width",H(B)).attr("x",I(B)).attr("width",H(B>0?A:B)).attr("x",I(B>0?A:B)).datum(B>0?A:B),G.select("rect.nv-measure").style("fill",p).attr("height",r/3).attr("y",r/3).attr("width",0>v?z(0)-z(v[0]):z(v[0])-z(0)).attr("x",I(v)).on("mouseover",function(){q.elementMouseover({value:v[0],label:y[0]||"Current",pos:[z(v[0]),r/2]})}).on("mouseout",function(){q.elementMouseout({value:v[0],label:y[0]||"Current"})});var J=r/6;u[0]?G.selectAll("path.nv-markerTriangle").attr("transform",function(){return"translate("+z(u[0])+","+r/2+")"}).attr("d","M0,"+J+"L"+J+","+-J+" "+-J+","+-J+"Z").on("mouseover",function(){q.elementMouseover({value:u[0],label:x[0]||"Previous",pos:[z(u[0]),r/2]})}).on("mouseout",function(){q.elementMouseout({value:u[0],label:x[0]||"Previous"})}):G.selectAll("path.nv-markerTriangle").remove(),D.selectAll(".nv-range").on("mouseover",function(a,b){var c=w[b]||(b?1==b?"Mean":"Minimum":"Maximum");q.elementMouseover({value:a,label:c,pos:[z(a),r/2]})}).on("mouseout",function(a,b){var c=w[b]||(b?1==b?"Mean":"Minimum":"Maximum");q.elementMouseout({value:a,label:c})})}),b}var c={top:0,right:0,bottom:0,left:0},d="left",e=!1,f=function(a){return a.ranges},g=function(a){return a.markers?a.markers:[0]},h=function(a){return a.measures},i=function(a){return a.rangeLabels?a.rangeLabels:[]},j=function(a){return a.markerLabels?a.markerLabels:[]},k=function(a){return a.measureLabels?a.measureLabels:[]},l=[0],m=380,n=30,o=null,p=a.utils.getColor(["#1f77b4"]),q=d3.dispatch("elementMouseover","elementMouseout");return b.dispatch=q,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{ranges:{get:function(){return f},set:function(a){f=a}},markers:{get:function(){return g},set:function(a){g=a}},measures:{get:function(){return h},set:function(a){h=a}},forceX:{get:function(){return l},set:function(a){l=a}},width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},tickFormat:{get:function(){return o},set:function(a){o=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},orient:{get:function(){return d},set:function(a){d=a,e="right"==d||"bottom"==d}},color:{get:function(){return p},set:function(b){p=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.bulletChart=function(){"use strict";function b(d){return d.each(function(n,r){var s=d3.select(this);a.utils.initSVG(s);var t=(j||parseInt(s.style("width"))||960)-f.left-f.right,u=k-f.top-f.bottom,v=this;if(b.update=function(){b(d)},b.container=this,!n||!g.call(this,n,r)){var w=s.selectAll(".nv-noData").data([o]);return w.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),w.attr("x",f.left+t/2).attr("y",18+f.top+u/2).text(function(a){return a}),b}s.selectAll(".nv-noData").remove();var x=g.call(this,n,r).slice().sort(d3.descending),y=h.call(this,n,r).slice().sort(d3.descending),z=i.call(this,n,r).slice().sort(d3.descending),A=s.selectAll("g.nv-wrap.nv-bulletChart").data([n]),B=A.enter().append("g").attr("class","nvd3 nv-wrap nv-bulletChart"),C=B.append("g"),D=A.select("g");C.append("g").attr("class","nv-bulletWrap"),C.append("g").attr("class","nv-titles"),A.attr("transform","translate("+f.left+","+f.top+")");var E=d3.scale.linear().domain([0,Math.max(x[0],y[0],z[0])]).range(e?[t,0]:[0,t]),F=this.__chart__||d3.scale.linear().domain([0,1/0]).range(E.range());this.__chart__=E;var G=C.select(".nv-titles").append("g").attr("text-anchor","end").attr("transform","translate(-6,"+(k-f.top-f.bottom)/2+")");G.append("text").attr("class","nv-title").text(function(a){return a.title}),G.append("text").attr("class","nv-subtitle").attr("dy","1em").text(function(a){return a.subtitle}),c.width(t).height(u);var H=D.select(".nv-bulletWrap");d3.transition(H).call(c);var I=l||E.tickFormat(t/100),J=D.selectAll("g.nv-tick").data(E.ticks(t/50),function(a){return this.textContent||I(a)}),K=J.enter().append("g").attr("class","nv-tick").attr("transform",function(a){return"translate("+F(a)+",0)"}).style("opacity",1e-6);K.append("line").attr("y1",u).attr("y2",7*u/6),K.append("text").attr("text-anchor","middle").attr("dy","1em").attr("y",7*u/6).text(I);var L=d3.transition(J).attr("transform",function(a){return"translate("+E(a)+",0)"}).style("opacity",1);L.select("line").attr("y1",u).attr("y2",7*u/6),L.select("text").attr("y",7*u/6),d3.transition(J.exit()).attr("transform",function(a){return"translate("+E(a)+",0)"}).style("opacity",1e-6).remove(),p.on("tooltipShow",function(a){a.key=n.title,m&&q(a,v.parentNode)})}),d3.timer.flush(),b}var c=a.models.bullet(),d="left",e=!1,f={top:5,right:40,bottom:20,left:120},g=function(a){return a.ranges},h=function(a){return a.markers?a.markers:[0]},i=function(a){return a.measures},j=null,k=55,l=null,m=!0,n=function(a,b,c){return"<h3>"+b+"</h3><p>"+c+"</p>"},o="No Data Available.",p=d3.dispatch("tooltipShow","tooltipHide"),q=function(c,d){var e=c.pos[0]+(d.offsetLeft||0)+f.left,g=c.pos[1]+(d.offsetTop||0)+f.top,h=n(c.key,c.label,c.value,c,b);a.tooltip.show([e,g],h,c.value<0?"e":"w",null,d)};return c.dispatch.on("elementMouseover.tooltip",function(a){p.tooltipShow(a)}),c.dispatch.on("elementMouseout.tooltip",function(a){p.tooltipHide(a)}),p.on("tooltipHide",function(){m&&a.tooltip.cleanup()}),b.bullet=c,b.dispatch=p,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{ranges:{get:function(){return g},set:function(a){g=a}},markers:{get:function(){return h},set:function(a){h=a}},measures:{get:function(){return i},set:function(a){i=a}},width:{get:function(){return j},set:function(a){j=a}},height:{get:function(){return k},set:function(a){k=a}},tickFormat:{get:function(){return l},set:function(a){l=a}},tooltips:{get:function(){return m},set:function(a){m=a}},tooltipContent:{get:function(){return n},set:function(a){n=a}},noData:{get:function(){return o},set:function(a){o=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}},orient:{get:function(){return d},set:function(a){d=a,e="right"==d||"bottom"==d}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.cumulativeLineChart=function(){"use strict";function b(x){return I.reset(),I.models(f),q&&I.models(g),r&&I.models(h),x.each(function(x){function F(){d3.select(b.container).style("cursor","ew-resize")}function I(){H.x=d3.event.x,H.i=Math.round(G.invert(H.x)),N()}function M(){d3.select(b.container).style("cursor","auto"),z.index=H.i,D.stateChange(z)}function N(){fb.data([H]);var a=b.duration();b.duration(0),b.update(),b.duration(a)}var O=d3.select(this);a.utils.initSVG(O),O.classed("nv-chart-"+y,!0);var P=this,Q=(n||parseInt(O.style("width"))||960)-l.left-l.right,R=(o||parseInt(O.style("height"))||400)-l.top-l.bottom;if(b.update=function(){0===E?O.call(b):O.transition().duration(E).call(b)},b.container=this,z.setter(L(x),b.update).getter(K(x)).update(),z.disabled=x.map(function(a){return!!a.disabled}),!A){var S;A={};for(S in z)A[S]=z[S]instanceof Array?z[S].slice(0):z[S]}var T=d3.behavior.drag().on("dragstart",F).on("drag",I).on("dragend",M);if(!(x&&x.length&&x.filter(function(a){return a.values.length}).length)){var U=O.selectAll(".nv-noData").data([B]);return U.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),U.attr("x",l.left+Q/2).attr("y",l.top+R/2).text(function(a){return a}),b}if(O.selectAll(".nv-noData").remove(),d=f.xScale(),e=f.yScale(),w)f.yDomain(null);else{var V=x.filter(function(a){return!a.disabled}).map(function(a){var b=d3.extent(a.values,f.y());return b[0]<-.95&&(b[0]=-.95),[(b[0]-b[1])/(1+b[1]),(b[1]-b[0])/(1+b[0])]}),W=[d3.min(V,function(a){return a[0]
+}),d3.max(V,function(a){return a[1]})];f.yDomain(W)}G.domain([0,x[0].values.length-1]).range([0,Q]).clamp(!0);var x=c(H.i,x),X=v?"none":"all",Y=O.selectAll("g.nv-wrap.nv-cumulativeLine").data([x]),Z=Y.enter().append("g").attr("class","nvd3 nv-wrap nv-cumulativeLine").append("g"),$=Y.select("g");if(Z.append("g").attr("class","nv-interactive"),Z.append("g").attr("class","nv-x nv-axis").style("pointer-events","none"),Z.append("g").attr("class","nv-y nv-axis"),Z.append("g").attr("class","nv-background"),Z.append("g").attr("class","nv-linesWrap").style("pointer-events",X),Z.append("g").attr("class","nv-avgLinesWrap").style("pointer-events","none"),Z.append("g").attr("class","nv-legendWrap"),Z.append("g").attr("class","nv-controlsWrap"),p&&(i.width(Q),$.select(".nv-legendWrap").datum(x).call(i),l.top!=i.height()&&(l.top=i.height(),R=(o||parseInt(O.style("height"))||400)-l.top-l.bottom),$.select(".nv-legendWrap").attr("transform","translate(0,"+-l.top+")")),u){var _=[{key:"Re-scale y-axis",disabled:!w}];j.width(140).color(["#444","#444","#444"]).rightAlign(!1).margin({top:5,right:0,bottom:5,left:20}),$.select(".nv-controlsWrap").datum(_).attr("transform","translate(0,"+-l.top+")").call(j)}Y.attr("transform","translate("+l.left+","+l.top+")"),s&&$.select(".nv-y.nv-axis").attr("transform","translate("+Q+",0)");var ab=x.filter(function(a){return a.tempDisabled});Y.select(".tempDisabled").remove(),ab.length&&Y.append("text").attr("class","tempDisabled").attr("x",Q/2).attr("y","-.71em").style("text-anchor","end").text(ab.map(function(a){return a.key}).join(", ")+" values cannot be calculated for this time period."),v&&(k.width(Q).height(R).margin({left:l.left,top:l.top}).svgContainer(O).xScale(d),Y.select(".nv-interactive").call(k)),Z.select(".nv-background").append("rect"),$.select(".nv-background rect").attr("width",Q).attr("height",R),f.y(function(a){return a.display.y}).width(Q).height(R).color(x.map(function(a,b){return a.color||m(a,b)}).filter(function(a,b){return!x[b].disabled&&!x[b].tempDisabled}));var bb=$.select(".nv-linesWrap").datum(x.filter(function(a){return!a.disabled&&!a.tempDisabled}));bb.call(f),x.forEach(function(a,b){a.seriesIndex=b});var cb=x.filter(function(a){return!a.disabled&&!!C(a)}),db=$.select(".nv-avgLinesWrap").selectAll("line").data(cb,function(a){return a.key}),eb=function(a){var b=e(C(a));return 0>b?0:b>R?R:b};db.enter().append("line").style("stroke-width",2).style("stroke-dasharray","10,10").style("stroke",function(a){return f.color()(a,a.seriesIndex)}).attr("x1",0).attr("x2",Q).attr("y1",eb).attr("y2",eb),db.style("stroke-opacity",function(a){var b=e(C(a));return 0>b||b>R?0:1}).attr("x1",0).attr("x2",Q).attr("y1",eb).attr("y2",eb),db.exit().remove();var fb=bb.selectAll(".nv-indexLine").data([H]);fb.enter().append("rect").attr("class","nv-indexLine").attr("width",3).attr("x",-2).attr("fill","red").attr("fill-opacity",.5).style("pointer-events","all").call(T),fb.attr("transform",function(a){return"translate("+G(a.i)+",0)"}).attr("height",R),q&&(g.scale(d).ticks(a.utils.calcTicksX(Q/70,x)).tickSize(-R,0),$.select(".nv-x.nv-axis").attr("transform","translate(0,"+e.range()[0]+")"),$.select(".nv-x.nv-axis").call(g)),r&&(h.scale(e).ticks(a.utils.calcTicksY(R/36,x)).tickSize(-Q,0),$.select(".nv-y.nv-axis").call(h)),$.select(".nv-background rect").on("click",function(){H.x=d3.mouse(this)[0],H.i=Math.round(G.invert(H.x)),z.index=H.i,D.stateChange(z),N()}),f.dispatch.on("elementClick",function(a){H.i=a.pointIndex,H.x=G(H.i),z.index=H.i,D.stateChange(z),N()}),j.dispatch.on("legendClick",function(a){a.disabled=!a.disabled,w=!a.disabled,z.rescaleY=w,D.stateChange(z),b.update()}),i.dispatch.on("stateChange",function(a){for(var c in a)z[c]=a[c];D.stateChange(z),b.update()}),k.dispatch.on("elementMousemove",function(c){f.clearHighlights();var d,e,i,j=[];if(x.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(g,h){e=a.interactiveBisect(g.values,c.pointXValue,b.x()),f.highlightPoint(h,e,!0);var k=g.values[e];"undefined"!=typeof k&&("undefined"==typeof d&&(d=k),"undefined"==typeof i&&(i=b.xScale()(b.x()(k,e))),j.push({key:g.key,value:b.y()(k,e),color:m(g,g.seriesIndex)}))}),j.length>2){var n=b.yScale().invert(c.mouseY),o=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),p=.03*o,q=a.nearestValueIndex(j.map(function(a){return a.value}),n,p);null!==q&&(j[q].highlight=!0)}var r=g.tickFormat()(b.x()(d,e),e);k.tooltip.position({left:i+l.left,top:c.mouseY+l.top}).chartContainer(P.parentNode).enabled(t).valueFormatter(function(a){return h.tickFormat()(a)}).data({value:r,series:j})(),k.renderGuideLine(i)}),k.dispatch.on("elementMouseout",function(){D.tooltipHide(),f.clearHighlights()}),D.on("tooltipShow",function(a){t&&J(a,P.parentNode)}),D.on("changeState",function(a){"undefined"!=typeof a.disabled&&(x.forEach(function(b,c){b.disabled=a.disabled[c]}),z.disabled=a.disabled),"undefined"!=typeof a.index&&(H.i=a.index,H.x=G(H.i),z.index=a.index,fb.data([H])),"undefined"!=typeof a.rescaleY&&(w=a.rescaleY),b.update()})}),I.renderEnd("cumulativeLineChart immediate"),b}function c(a,b){return M||(M=f.y()),b.map(function(b){if(!b.values)return b;var c=b.values[a];if(null==c)return b;var d=M(c,a);return-.95>d&&!F?(b.tempDisabled=!0,b):(b.tempDisabled=!1,b.values=b.values.map(function(a,b){return a.display={y:(M(a,b)-d)/(1+d)},a}),b)})}var d,e,f=a.models.line(),g=a.models.axis(),h=a.models.axis(),i=a.models.legend(),j=a.models.legend(),k=a.interactiveGuideline(),l={top:30,right:30,bottom:50,left:60},m=a.utils.defaultColor(),n=null,o=null,p=!0,q=!0,r=!0,s=!1,t=!0,u=!0,v=!1,w=!0,x=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" at "+b+"</p>"},y=f.id(),z=a.utils.state(),A=null,B="No Data Available.",C=function(a){return a.average},D=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),E=250,F=!1;z.index=0,z.rescaleY=w,g.orient("bottom").tickPadding(7),h.orient(s?"right":"left"),j.updateState(!1);var G=d3.scale.linear(),H={i:0,x:0},I=a.utils.renderWatch(D,E),J=function(c,d){var e=c.pos[0]+(d.offsetLeft||0),i=c.pos[1]+(d.offsetTop||0),j=g.tickFormat()(f.x()(c.point,c.pointIndex)),k=h.tickFormat()(f.y()(c.point,c.pointIndex)),l=x(c.series.key,j,k,c,b);a.tooltip.show([e,i],l,null,null,d)},K=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),index:H.i,rescaleY:w}}},L=function(a){return function(b){void 0!==b.index&&(H.i=b.index),void 0!==b.rescaleY&&(w=b.rescaleY),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};f.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+l.left,a.pos[1]+l.top],D.tooltipShow(a)}),f.dispatch.on("elementMouseout.tooltip",function(a){D.tooltipHide(a)}),D.on("tooltipHide",function(){t&&a.tooltip.cleanup()});var M=null;return b.dispatch=D,b.lines=f,b.legend=i,b.xAxis=g,b.yAxis=h,b.interactiveLayer=k,b.state=z,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return n},set:function(a){n=a}},height:{get:function(){return o},set:function(a){o=a}},rescaleY:{get:function(){return w},set:function(a){w=a}},showControls:{get:function(){return u},set:function(a){u=a}},showLegend:{get:function(){return p},set:function(a){p=a}},average:{get:function(){return C},set:function(a){C=a}},tooltips:{get:function(){return t},set:function(a){t=a}},tooltipContent:{get:function(){return x},set:function(a){x=a}},defaultState:{get:function(){return A},set:function(a){A=a}},noData:{get:function(){return B},set:function(a){B=a}},showXAxis:{get:function(){return q},set:function(a){q=a}},showYAxis:{get:function(){return r},set:function(a){r=a}},noErrorCheck:{get:function(){return F},set:function(a){F=a}},margin:{get:function(){return l},set:function(a){l.top=void 0!==a.top?a.top:l.top,l.right=void 0!==a.right?a.right:l.right,l.bottom=void 0!==a.bottom?a.bottom:l.bottom,l.left=void 0!==a.left?a.left:l.left}},color:{get:function(){return m},set:function(b){m=a.utils.getColor(b),i.color(m)}},useInteractiveGuideline:{get:function(){return v},set:function(a){v=a,a===!0&&(b.interactive(!1),b.useVoronoi(!1))}},rightAlignYAxis:{get:function(){return s},set:function(a){s=a,h.orient(a?"right":"left")}},duration:{get:function(){return E},set:function(a){E=a,f.duration(E),g.duration(E),h.duration(E),I.reset(E)}}}),a.utils.inheritOptions(b,f),a.utils.initOptions(b),b},a.models.discreteBar=function(){"use strict";function b(l){return x.reset(),l.each(function(b){var l=j-i.left-i.right,w=k-i.top-i.bottom,y=d3.select(this);a.utils.initSVG(y),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})});var z=c&&d?[]:b.map(function(a){return a.values.map(function(a,b){return{x:o(a,b),y:p(a,b),y0:a.y0}})});m.domain(c||d3.merge(z).map(function(a){return a.x})).rangeBands(e||[0,l],.1),n.domain(d||d3.extent(d3.merge(z).map(function(a){return a.y}).concat(q))),n.range(s?f||[w-(n.domain()[0]<0?12:0),n.domain()[1]>0?12:0]:f||[w,0]),g=g||m,h=h||n.copy().range([n(0),n(0)]);{var A=y.selectAll("g.nv-wrap.nv-discretebar").data([b]),B=A.enter().append("g").attr("class","nvd3 nv-wrap nv-discretebar"),C=B.append("g");A.select("g")}C.append("g").attr("class","nv-groups"),A.attr("transform","translate("+i.left+","+i.top+")");var D=A.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});D.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),D.exit().watchTransition(x,"discreteBar: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),D.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}),D.watchTransition(x,"discreteBar: groups").style("stroke-opacity",1).style("fill-opacity",.75);var E=D.selectAll("g.nv-bar").data(function(a){return a.values});E.exit().remove();var F=E.enter().append("g").attr("transform",function(a,b){return"translate("+(m(o(a,b))+.05*m.rangeBand())+", "+n(0)+")"}).on("mouseover",function(a,c){d3.select(this).classed("hover",!0),u.elementMouseover({value:p(a,c),point:a,series:b[a.series],pos:[m(o(a,c))+m.rangeBand()*(a.series+.5)/b.length,n(p(a,c))],pointIndex:c,seriesIndex:a.series,e:d3.event})}).on("mouseout",function(a,c){d3.select(this).classed("hover",!1),u.elementMouseout({value:p(a,c),point:a,series:b[a.series],pointIndex:c,seriesIndex:a.series,e:d3.event})}).on("click",function(a,c){u.elementClick({value:p(a,c),point:a,series:b[a.series],pos:[m(o(a,c))+m.rangeBand()*(a.series+.5)/b.length,n(p(a,c))],pointIndex:c,seriesIndex:a.series,e:d3.event}),d3.event.stopPropagation()}).on("dblclick",function(a,c){u.elementDblClick({value:p(a,c),point:a,series:b[a.series],pos:[m(o(a,c))+m.rangeBand()*(a.series+.5)/b.length,n(p(a,c))],pointIndex:c,seriesIndex:a.series,e:d3.event}),d3.event.stopPropagation()});F.append("rect").attr("height",0).attr("width",.9*m.rangeBand()/b.length),s?(F.append("text").attr("text-anchor","middle"),E.select("text").text(function(a,b){return t(p(a,b))}).watchTransition(x,"discreteBar: bars text").attr("x",.9*m.rangeBand()/2).attr("y",function(a,b){return p(a,b)<0?n(p(a,b))-n(0)+12:-4})):E.selectAll("text").remove(),E.attr("class",function(a,b){return p(a,b)<0?"nv-bar negative":"nv-bar positive"}).style("fill",function(a,b){return a.color||r(a,b)}).style("stroke",function(a,b){return a.color||r(a,b)}).select("rect").attr("class",v).watchTransition(x,"discreteBar: bars rect").attr("width",.9*m.rangeBand()/b.length),E.watchTransition(x,"discreteBar: bars").attr("transform",function(a,b){var c=m(o(a,b))+.05*m.rangeBand(),d=p(a,b)<0?n(0):n(0)-n(p(a,b))<1?n(0)-1:n(p(a,b));return"translate("+c+", "+d+")"}).select("rect").attr("height",function(a,b){return Math.max(Math.abs(n(p(a,b))-n(d&&d[0]||0))||1)}),g=m.copy(),h=n.copy()}),x.renderEnd("discreteBar immediate"),b}var c,d,e,f,g,h,i={top:0,right:0,bottom:0,left:0},j=960,k=500,l=Math.floor(1e4*Math.random()),m=d3.scale.ordinal(),n=d3.scale.linear(),o=function(a){return a.x},p=function(a){return a.y},q=[0],r=a.utils.defaultColor(),s=!1,t=d3.format(",.2f"),u=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),v="discreteBar",w=250,x=a.utils.renderWatch(u,w);return b.dispatch=u,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return j},set:function(a){j=a}},height:{get:function(){return k},set:function(a){k=a}},forceY:{get:function(){return q},set:function(a){q=a}},showValues:{get:function(){return s},set:function(a){s=a}},x:{get:function(){return o},set:function(a){o=a}},y:{get:function(){return p},set:function(a){p=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},valueFormat:{get:function(){return t},set:function(a){t=a}},id:{get:function(){return l},set:function(a){l=a}},rectClass:{get:function(){return v},set:function(a){v=a}},margin:{get:function(){return i},set:function(a){i.top=void 0!==a.top?a.top:i.top,i.right=void 0!==a.right?a.right:i.right,i.bottom=void 0!==a.bottom?a.bottom:i.bottom,i.left=void 0!==a.left?a.left:i.left}},color:{get:function(){return r},set:function(b){r=a.utils.getColor(b)}},duration:{get:function(){return w},set:function(a){w=a,x.reset(w)}}}),a.utils.initOptions(b),b},a.models.discreteBarChart=function(){"use strict";function b(k){return v.reset(),v.models(e),l&&v.models(f),m&&v.models(g),k.each(function(k){var q=d3.select(this),v=this;a.utils.initSVG(q);var w=(i||parseInt(q.style("width"))||960)-h.left-h.right,x=(j||parseInt(q.style("height"))||400)-h.top-h.bottom;if(b.update=function(){s.beforeUpdate(),q.transition().duration(t).call(b)},b.container=this,!(k&&k.length&&k.filter(function(a){return a.values.length}).length)){var y=q.selectAll(".nv-noData").data([r]);return y.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),y.attr("x",h.left+w/2).attr("y",h.top+x/2).text(function(a){return a}),b}q.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale().clamp(!0);var z=q.selectAll("g.nv-wrap.nv-discreteBarWithAxes").data([k]),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-discreteBarWithAxes").append("g"),B=A.append("defs"),C=z.select("g");A.append("g").attr("class","nv-x nv-axis"),A.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),A.append("g").attr("class","nv-barsWrap"),C.attr("transform","translate("+h.left+","+h.top+")"),n&&C.select(".nv-y.nv-axis").attr("transform","translate("+w+",0)"),e.width(w).height(x);var D=C.select(".nv-barsWrap").datum(k.filter(function(a){return!a.disabled}));if(D.transition().call(e),B.append("clipPath").attr("id","nv-x-label-clip-"+e.id()).append("rect"),C.select("#nv-x-label-clip-"+e.id()+" rect").attr("width",c.rangeBand()*(o?2:1)).attr("height",16).attr("x",-c.rangeBand()/(o?1:2)),l){f.scale(c).ticks(a.utils.calcTicksX(w/100,k)).tickSize(-x,0),C.select(".nv-x.nv-axis").attr("transform","translate(0,"+(d.range()[0]+(e.showValues()&&d.domain()[0]<0?16:0))+")"),C.select(".nv-x.nv-axis").call(f);var E=C.select(".nv-x.nv-axis").selectAll("g");o&&E.selectAll("text").attr("transform",function(a,b,c){return"translate(0,"+(c%2==0?"5":"17")+")"})}m&&(g.scale(d).ticks(a.utils.calcTicksY(x/36,k)).tickSize(-w,0),C.select(".nv-y.nv-axis").call(g)),C.select(".nv-zeroLine line").attr("x1",0).attr("x2",w).attr("y1",d(0)).attr("y2",d(0)),s.on("tooltipShow",function(a){p&&u(a,v.parentNode)})}),v.renderEnd("discreteBar chart immediate"),b}var c,d,e=a.models.discreteBar(),f=a.models.axis(),g=a.models.axis(),h={top:15,right:10,bottom:50,left:60},i=null,j=null,k=a.utils.getColor(),l=!0,m=!0,n=!1,o=!1,p=!0,q=function(a,b,c){return"<h3>"+b+"</h3><p>"+c+"</p>"},r="No Data Available.",s=d3.dispatch("tooltipShow","tooltipHide","beforeUpdate","renderEnd"),t=250;f.orient("bottom").highlightZero(!1).showMaxMin(!1).tickFormat(function(a){return a}),g.orient(n?"right":"left").tickFormat(d3.format(",.1f"));var u=function(c,d){var h=c.pos[0]+(d.offsetLeft||0),i=c.pos[1]+(d.offsetTop||0),j=f.tickFormat()(e.x()(c.point,c.pointIndex)),k=g.tickFormat()(e.y()(c.point,c.pointIndex)),l=q(c.series.key,j,k,c,b);a.tooltip.show([h,i],l,c.value<0?"n":"s",null,d)},v=a.utils.renderWatch(s,t);return e.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+h.left,a.pos[1]+h.top],s.tooltipShow(a)}),e.dispatch.on("elementMouseout.tooltip",function(a){s.tooltipHide(a)}),s.on("tooltipHide",function(){p&&a.tooltip.cleanup()}),b.dispatch=s,b.discretebar=e,b.xAxis=f,b.yAxis=g,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return i},set:function(a){i=a}},height:{get:function(){return j},set:function(a){j=a}},staggerLabels:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return l},set:function(a){l=a}},showYAxis:{get:function(){return m},set:function(a){m=a}},tooltips:{get:function(){return p},set:function(a){p=a}},tooltipContent:{get:function(){return q},set:function(a){q=a}},noData:{get:function(){return r},set:function(a){r=a}},margin:{get:function(){return h},set:function(a){h.top=void 0!==a.top?a.top:h.top,h.right=void 0!==a.right?a.right:h.right,h.bottom=void 0!==a.bottom?a.bottom:h.bottom,h.left=void 0!==a.left?a.left:h.left}},duration:{get:function(){return t},set:function(a){t=a,v.reset(t),e.duration(t),f.duration(t),g.duration(t)}},color:{get:function(){return k},set:function(b){k=a.utils.getColor(b),e.color(k)}},rightAlignYAxis:{get:function(){return n},set:function(a){n=a,g.orient(a?"right":"left")}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.distribution=function(){"use strict";function b(k){return m.reset(),k.each(function(b){var k=(e-("x"===g?d.left+d.right:d.top+d.bottom),"x"==g?"y":"x"),l=d3.select(this);a.utils.initSVG(l),c=c||j;var n=l.selectAll("g.nv-distribution").data([b]),o=n.enter().append("g").attr("class","nvd3 nv-distribution"),p=(o.append("g"),n.select("g"));n.attr("transform","translate("+d.left+","+d.top+")");var q=p.selectAll("g.nv-dist").data(function(a){return a},function(a){return a.key});q.enter().append("g"),q.attr("class",function(a,b){return"nv-dist nv-series-"+b}).style("stroke",function(a,b){return i(a,b)});var r=q.selectAll("line.nv-dist"+g).data(function(a){return a.values});r.enter().append("line").attr(g+"1",function(a,b){return c(h(a,b))}).attr(g+"2",function(a,b){return c(h(a,b))}),m.transition(q.exit().selectAll("line.nv-dist"+g),"dist exit").attr(g+"1",function(a,b){return j(h(a,b))}).attr(g+"2",function(a,b){return j(h(a,b))}).style("stroke-opacity",0).remove(),r.attr("class",function(a,b){return"nv-dist"+g+" nv-dist"+g+"-"+b}).attr(k+"1",0).attr(k+"2",f),m.transition(r,"dist").attr(g+"1",function(a,b){return j(h(a,b))}).attr(g+"2",function(a,b){return j(h(a,b))}),c=j.copy()}),m.renderEnd("distribution immediate"),b}var c,d={top:0,right:0,bottom:0,left:0},e=400,f=8,g="x",h=function(a){return a[g]},i=a.utils.defaultColor(),j=d3.scale.linear(),k=250,l=d3.dispatch("renderEnd"),m=a.utils.renderWatch(l,k);return b.options=a.utils.optionsFunc.bind(b),b.dispatch=l,b.margin=function(a){return arguments.length?(d.top="undefined"!=typeof a.top?a.top:d.top,d.right="undefined"!=typeof a.right?a.right:d.right,d.bottom="undefined"!=typeof a.bottom?a.bottom:d.bottom,d.left="undefined"!=typeof a.left?a.left:d.left,b):d},b.width=function(a){return arguments.length?(e=a,b):e},b.axis=function(a){return arguments.length?(g=a,b):g},b.size=function(a){return arguments.length?(f=a,b):f},b.getData=function(a){return arguments.length?(h=d3.functor(a),b):h},b.scale=function(a){return arguments.length?(j=a,b):j},b.color=function(c){return arguments.length?(i=a.utils.getColor(c),b):i},b.duration=function(a){return arguments.length?(k=a,m.reset(k),b):k},b},a.models.historicalBar=function(){"use strict";function b(w){return w.each(function(b){v.reset();var w=d3.select(this),x=(h||parseInt(w.style("width"))||960)-g.left-g.right,y=(i||parseInt(w.style("height"))||400)-g.top-g.bottom;a.utils.initSVG(w),k.domain(c||d3.extent(b[0].values.map(m).concat(o))),k.range(q?e||[.5*x/b[0].values.length,x*(b[0].values.length-.5)/b[0].values.length]:e||[0,x]),l.domain(d||d3.extent(b[0].values.map(n).concat(p))).range(f||[y,0]),k.domain()[0]===k.domain()[1]&&k.domain(k.domain()[0]?[k.domain()[0]-.01*k.domain()[0],k.domain()[1]+.01*k.domain()[1]]:[-1,1]),l.domain()[0]===l.domain()[1]&&l.domain(l.domain()[0]?[l.domain()[0]+.01*l.domain()[0],l.domain()[1]-.01*l.domain()[1]]:[-1,1]);var z=w.selectAll("g.nv-wrap.nv-historicalBar-"+j).data([b[0].values]),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-historicalBar-"+j),B=A.append("defs"),C=A.append("g"),D=z.select("g");C.append("g").attr("class","nv-bars"),z.attr("transform","translate("+g.left+","+g.top+")"),w.on("click",function(a,b){t.chartClick({data:a,index:b,pos:d3.event,id:j})}),B.append("clipPath").attr("id","nv-chart-clip-path-"+j).append("rect"),z.select("#nv-chart-clip-path-"+j+" rect").attr("width",x).attr("height",y),D.attr("clip-path",r?"url(#nv-chart-clip-path-"+j+")":"");var E=z.select(".nv-bars").selectAll(".nv-bar").data(function(a){return a},function(a,b){return m(a,b)});E.exit().remove();E.enter().append("rect").attr("x",0).attr("y",function(b,c){return a.utils.NaNtoZero(l(Math.max(0,n(b,c))))}).attr("height",function(b,c){return a.utils.NaNtoZero(Math.abs(l(n(b,c))-l(0)))}).attr("transform",function(a,c){return"translate("+(k(m(a,c))-x/b[0].values.length*.45)+",0)"}).on("mouseover",function(a,c){u&&(d3.select(this).classed("hover",!0),t.elementMouseover({point:a,series:b[0],pos:[k(m(a,c)),l(n(a,c))],pointIndex:c,seriesIndex:0,e:d3.event}))}).on("mouseout",function(a,c){u&&(d3.select(this).classed("hover",!1),t.elementMouseout({point:a,series:b[0],pointIndex:c,seriesIndex:0,e:d3.event}))}).on("click",function(a,b){u&&(t.elementClick({value:n(a,b),data:a,index:b,pos:[k(m(a,b)),l(n(a,b))],e:d3.event,id:j}),d3.event.stopPropagation())}).on("dblclick",function(a,b){u&&(t.elementDblClick({value:n(a,b),data:a,index:b,pos:[k(m(a,b)),l(n(a,b))],e:d3.event,id:j}),d3.event.stopPropagation())});E.attr("fill",function(a,b){return s(a,b)}).attr("class",function(a,b,c){return(n(a,b)<0?"nv-bar negative":"nv-bar positive")+" nv-bar-"+c+"-"+b}).watchTransition(v,"bars").attr("transform",function(a,c){return"translate("+(k(m(a,c))-x/b[0].values.length*.45)+",0)"}).attr("width",x/b[0].values.length*.9),E.watchTransition(v,"bars").attr("y",function(b,c){var d=n(b,c)<0?l(0):l(0)-l(n(b,c))<1?l(0)-1:l(n(b,c));return a.utils.NaNtoZero(d)}).attr("height",function(b,c){return a.utils.NaNtoZero(Math.max(Math.abs(l(n(b,c))-l(0)),1))})}),v.renderEnd("historicalBar immediate"),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=Math.floor(1e4*Math.random()),k=d3.scale.linear(),l=d3.scale.linear(),m=function(a){return a.x},n=function(a){return a.y},o=[],p=[0],q=!1,r=!0,s=a.utils.defaultColor(),t=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),u=!0,v=a.utils.renderWatch(t,0);return b.highlightPoint=function(a,b){d3.select(".nv-historicalBar-"+j).select(".nv-bars .nv-bar-0-"+a).classed("hover",b)},b.clearHighlights=function(){d3.select(".nv-historicalBar-"+j).select(".nv-bars .nv-bar.hover").classed("hover",!1)},b.dispatch=t,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},forceX:{get:function(){return o},set:function(a){o=a}},forceY:{get:function(){return p},set:function(a){p=a}},padData:{get:function(){return q},set:function(a){q=a}},x:{get:function(){return m},set:function(a){m=a}},y:{get:function(){return n},set:function(a){n=a}},xScale:{get:function(){return k},set:function(a){k=a}},yScale:{get:function(){return l},set:function(a){l=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},clipEdge:{get:function(){return r},set:function(a){r=a}},id:{get:function(){return j},set:function(a){j=a}},interactive:{get:function(){return u},set:function(a){u=a}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},color:{get:function(){return s},set:function(b){s=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.historicalBarChart=function(b){"use strict";function c(b){return b.each(function(u){B.reset(),B.models(f),p&&B.models(g),q&&B.models(h);var C=d3.select(this),D=this;a.utils.initSVG(C);var E=(m||parseInt(C.style("width"))||960)-k.left-k.right,F=(n||parseInt(C.style("height"))||400)-k.top-k.bottom;if(c.update=function(){C.transition().duration(z).call(c)},c.container=this,v.disabled=u.map(function(a){return!!a.disabled}),!w){var G;w={};for(G in v)w[G]=v[G]instanceof Array?v[G].slice(0):v[G]}if(!(u&&u.length&&u.filter(function(a){return a.values.length}).length)){var H=C.selectAll(".nv-noData").data([x]);return H.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),H.attr("x",k.left+E/2).attr("y",k.top+F/2).text(function(a){return a}),c}C.selectAll(".nv-noData").remove(),d=f.xScale(),e=f.yScale();var I=C.selectAll("g.nv-wrap.nv-historicalBarChart").data([u]),J=I.enter().append("g").attr("class","nvd3 nv-wrap nv-historicalBarChart").append("g"),K=I.select("g");J.append("g").attr("class","nv-x nv-axis"),J.append("g").attr("class","nv-y nv-axis"),J.append("g").attr("class","nv-barsWrap"),J.append("g").attr("class","nv-legendWrap"),J.append("g").attr("class","nv-interactive"),o&&(i.width(E),K.select(".nv-legendWrap").datum(u).call(i),k.top!=i.height()&&(k.top=i.height(),F=(n||parseInt(C.style("height"))||400)-k.top-k.bottom),I.select(".nv-legendWrap").attr("transform","translate(0,"+-k.top+")")),I.attr("transform","translate("+k.left+","+k.top+")"),r&&K.select(".nv-y.nv-axis").attr("transform","translate("+E+",0)"),s&&(j.width(E).height(F).margin({left:k.left,top:k.top}).svgContainer(C).xScale(d),I.select(".nv-interactive").call(j)),f.width(E).height(F).color(u.map(function(a,b){return a.color||l(a,b)}).filter(function(a,b){return!u[b].disabled}));var L=K.select(".nv-barsWrap").datum(u.filter(function(a){return!a.disabled}));L.transition().call(f),p&&(g.scale(d).tickSize(-F,0),K.select(".nv-x.nv-axis").attr("transform","translate(0,"+e.range()[0]+")"),K.select(".nv-x.nv-axis").transition().call(g)),q&&(h.scale(e).ticks(a.utils.calcTicksY(F/36,u)).tickSize(-E,0),K.select(".nv-y.nv-axis").transition().call(h)),j.dispatch.on("elementMousemove",function(b){f.clearHighlights();var d,e,i,m=[];u.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(g){e=a.interactiveBisect(g.values,b.pointXValue,c.x()),f.highlightPoint(e,!0);var h=g.values[e];"undefined"!=typeof h&&("undefined"==typeof d&&(d=h),"undefined"==typeof i&&(i=c.xScale()(c.x()(h,e))),m.push({key:g.key,value:c.y()(h,e),color:l(g,g.seriesIndex),data:g.values[e]}))});var n=g.tickFormat()(c.x()(d,e));j.tooltip.position({left:i+k.left,top:b.mouseY+k.top}).chartContainer(D.parentNode).enabled(t).valueFormatter(function(a){return h.tickFormat()(a)}).data({value:n,series:m})(),j.renderGuideLine(i)}),j.dispatch.on("elementMouseout",function(){y.tooltipHide(),f.clearHighlights()}),i.dispatch.on("legendClick",function(a){a.disabled=!a.disabled,u.filter(function(a){return!a.disabled}).length||u.map(function(a){return a.disabled=!1,I.selectAll(".nv-series").classed("disabled",!1),a}),v.disabled=u.map(function(a){return!!a.disabled}),y.stateChange(v),b.transition().call(c)}),i.dispatch.on("legendDblclick",function(a){u.forEach(function(a){a.disabled=!0}),a.disabled=!1,v.disabled=u.map(function(a){return!!a.disabled}),y.stateChange(v),c.update()}),y.on("tooltipShow",function(a){t&&A(a,D.parentNode)}),y.on("changeState",function(a){"undefined"!=typeof a.disabled&&(u.forEach(function(b,c){b.disabled=a.disabled[c]}),v.disabled=a.disabled),c.update()})}),B.renderEnd("historicalBarChart immediate"),c}var d,e,f=b||a.models.historicalBar(),g=a.models.axis(),h=a.models.axis(),i=a.models.legend(),j=a.interactiveGuideline(),k={top:30,right:90,bottom:50,left:90},l=a.utils.defaultColor(),m=null,n=null,o=!1,p=!0,q=!0,r=!1,s=!1,t=!0,u=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" at "+b+"</p>"},v={},w=null,x="No Data Available.",y=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),z=250;g.orient("bottom").tickPadding(7),h.orient(r?"right":"left");var A=function(b,d){if(d){var e=d3.select(d).select("svg"),i=e.node()?e.attr("viewBox"):null;if(i){i=i.split(" ");var j=parseInt(e.style("width"))/i[2];b.pos[0]=b.pos[0]*j,b.pos[1]=b.pos[1]*j}}var k=b.pos[0]+(d.offsetLeft||0),l=b.pos[1]+(d.offsetTop||0),m=g.tickFormat()(f.x()(b.point,b.pointIndex)),n=h.tickFormat()(f.y()(b.point,b.pointIndex)),o=u(b.series.key,m,n,b,c);a.tooltip.show([k,l],o,null,null,d)},B=a.utils.renderWatch(y,0);return f.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+k.left,a.pos[1]+k.top],y.tooltipShow(a)}),f.dispatch.on("elementMouseout.tooltip",function(a){y.tooltipHide(a)}),y.on("tooltipHide",function(){t&&a.tooltip.cleanup()}),c.dispatch=y,c.bars=f,c.legend=i,c.xAxis=g,c.yAxis=h,c.interactiveLayer=j,c.options=a.utils.optionsFunc.bind(c),c._options=Object.create({},{width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},showLegend:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return p},set:function(a){p=a}},showYAxis:{get:function(){return q},set:function(a){q=a}},tooltips:{get:function(){return t},set:function(a){t=a}},tooltipContent:{get:function(){return u},set:function(a){u=a}},defaultState:{get:function(){return w},set:function(a){w=a}},noData:{get:function(){return x},set:function(a){x=a}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},color:{get:function(){return l},set:function(b){l=a.utils.getColor(b),i.color(l),f.color(l)}},duration:{get:function(){return z},set:function(a){z=a,B.reset(z),h.duration(z),g.duration(z)}},rightAlignYAxis:{get:function(){return r},set:function(a){r=a,h.orient(a?"right":"left")}},useInteractiveGuideline:{get:function(){return s},set:function(a){s=a,a===!0&&c.interactive(!1)}}}),a.utils.inheritOptions(c,f),a.utils.initOptions(c),c},a.models.ohlcBarChart=function(){var b=a.models.historicalBarChart(a.models.ohlcBar());return b.useInteractiveGuideline(!0),b.interactiveLayer.tooltip.contentGenerator(function(a){var c=a.series[0].data,d=c.open<c.close?"2ca02c":"d62728";return'<h3 style="color: #'+d+'">'+a.value+"</h3><table><tr><td>open:</td><td>"+b.yAxis.tickFormat()(c.open)+"</td></tr><tr><td>close:</td><td>"+b.yAxis.tickFormat()(c.close)+"</td></tr><tr><td>high</td><td>"+b.yAxis.tickFormat()(c.high)+"</td></tr><tr><td>low:</td><td>"+b.yAxis.tickFormat()(c.low)+"</td></tr></table>"}),b},a.models.legend=function(){"use strict";function b(m){return m.each(function(b){var m=d-c.left-c.right,n=d3.select(this);a.utils.initSVG(n);var o=n.selectAll("g.nv-legend").data([b]),p=(o.enter().append("g").attr("class","nvd3 nv-legend").append("g"),o.select("g"));o.attr("transform","translate("+c.left+","+c.top+")");var q=p.selectAll(".nv-series").data(function(a){return a}),r=q.enter().append("g").attr("class","nv-series").on("mouseover",function(a,b){l.legendMouseover(a,b)}).on("mouseout",function(a,b){l.legendMouseout(a,b)}).on("click",function(a,c){l.legendClick(a,c),j&&(k?(b.forEach(function(a){a.disabled=!0
+}),a.disabled=!1):(a.disabled=!a.disabled,b.every(function(a){return a.disabled})&&b.forEach(function(a){a.disabled=!1})),l.stateChange({disabled:b.map(function(a){return!!a.disabled})}))}).on("dblclick",function(a,c){l.legendDblclick(a,c),j&&(b.forEach(function(a){a.disabled=!0}),a.disabled=!1,l.stateChange({disabled:b.map(function(a){return!!a.disabled})}))});if(r.append("circle").style("stroke-width",2).attr("class","nv-legend-symbol").attr("r",5),r.append("text").attr("text-anchor","start").attr("class","nv-legend-text").attr("dy",".32em").attr("dx","8"),q.classed("nv-disabled",function(a){return a.disabled}),q.exit().remove(),q.select("circle").style("fill",function(a,b){return a.color||g(a,b)}).style("stroke",function(a,b){return a.color||g(a,b)}),q.select("text").text(f),h){var s=[];q.each(function(){var b,c=d3.select(this).select("text");try{if(b=c.node().getComputedTextLength(),0>=b)throw Error()}catch(d){b=a.utils.calcApproxTextWidth(c)}s.push(b+28)});for(var t=0,u=0,v=[];m>u&&t<s.length;)v[t]=s[t],u+=s[t++];for(0===t&&(t=1);u>m&&t>1;){v=[],t--;for(var w=0;w<s.length;w++)s[w]>(v[w%t]||0)&&(v[w%t]=s[w]);u=v.reduce(function(a,b){return a+b})}for(var x=[],y=0,z=0;t>y;y++)x[y]=z,z+=v[y];q.attr("transform",function(a,b){return"translate("+x[b%t]+","+(5+20*Math.floor(b/t))+")"}),i?p.attr("transform","translate("+(d-c.right-u)+","+c.top+")"):p.attr("transform","translate(0,"+c.top+")"),e=c.top+c.bottom+20*Math.ceil(s.length/t)}else{var A,B=5,C=5,D=0;q.attr("transform",function(){var a=d3.select(this).select("text").node().getComputedTextLength()+28;return A=C,d<c.left+c.right+A+a&&(C=A=5,B+=20),C+=a,C>D&&(D=C),"translate("+A+","+B+")"}),p.attr("transform","translate("+(d-c.right-D)+","+c.top+")"),e=c.top+c.bottom+B+15}}),b}var c={top:5,right:0,bottom:5,left:0},d=400,e=20,f=function(a){return a.key},g=a.utils.defaultColor(),h=!0,i=!0,j=!0,k=!1,l=d3.dispatch("legendClick","legendDblclick","legendMouseover","legendMouseout","stateChange");return b.dispatch=l,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},key:{get:function(){return f},set:function(a){f=a}},align:{get:function(){return h},set:function(a){h=a}},rightAlign:{get:function(){return i},set:function(a){i=a}},updateState:{get:function(){return j},set:function(a){j=a}},radioButtonMode:{get:function(){return k},set:function(a){k=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},color:{get:function(){return g},set:function(b){g=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.line=function(){"use strict";function b(p){return t.reset(),t.models(e),p.each(function(b){var p=g-f.left-f.right,q=h-f.top-f.bottom,u=d3.select(this);a.utils.initSVG(u),c=e.xScale(),d=e.yScale(),r=r||c,s=s||d;var v=u.selectAll("g.nv-wrap.nv-line").data([b]),w=v.enter().append("g").attr("class","nvd3 nv-wrap nv-line"),x=w.append("defs"),y=w.append("g"),z=v.select("g");y.append("g").attr("class","nv-groups"),y.append("g").attr("class","nv-scatterWrap"),v.attr("transform","translate("+f.left+","+f.top+")"),e.width(p).height(q);var A=v.select(".nv-scatterWrap");A.call(e),x.append("clipPath").attr("id","nv-edge-clip-"+e.id()).append("rect"),v.select("#nv-edge-clip-"+e.id()+" rect").attr("width",p).attr("height",q>0?q:0),z.attr("clip-path",n?"url(#nv-edge-clip-"+e.id()+")":""),A.attr("clip-path",n?"url(#nv-edge-clip-"+e.id()+")":"");var B=v.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});B.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),B.exit().remove(),B.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return i(a,b)}).style("stroke",function(a,b){return i(a,b)}),B.watchTransition(t,"line: groups").style("stroke-opacity",1).style("fill-opacity",.5);var C=B.selectAll("path.nv-area").data(function(a){return m(a)?[a]:[]});C.enter().append("path").attr("class","nv-area").attr("d",function(b){return d3.svg.area().interpolate(o).defined(l).x(function(b,c){return a.utils.NaNtoZero(r(j(b,c)))}).y0(function(b,c){return a.utils.NaNtoZero(s(k(b,c)))}).y1(function(){return s(d.domain()[0]<=0?d.domain()[1]>=0?0:d.domain()[1]:d.domain()[0])}).apply(this,[b.values])}),B.exit().selectAll("path.nv-area").remove(),C.watchTransition(t,"line: areaPaths").attr("d",function(b){return d3.svg.area().interpolate(o).defined(l).x(function(b,d){return a.utils.NaNtoZero(c(j(b,d)))}).y0(function(b,c){return a.utils.NaNtoZero(d(k(b,c)))}).y1(function(){return d(d.domain()[0]<=0?d.domain()[1]>=0?0:d.domain()[1]:d.domain()[0])}).apply(this,[b.values])});var D=B.selectAll("path.nv-line").data(function(a){return[a.values]});D.enter().append("path").attr("class","nv-line").attr("d",d3.svg.line().interpolate(o).defined(l).x(function(b,c){return a.utils.NaNtoZero(r(j(b,c)))}).y(function(b,c){return a.utils.NaNtoZero(s(k(b,c)))})),D.watchTransition(t,"line: linePaths").attr("d",d3.svg.line().interpolate(o).defined(l).x(function(b,d){return a.utils.NaNtoZero(c(j(b,d)))}).y(function(b,c){return a.utils.NaNtoZero(d(k(b,c)))})),r=c.copy(),s=d.copy()}),t.renderEnd("line immediate"),b}var c,d,e=a.models.scatter(),f={top:0,right:0,bottom:0,left:0},g=960,h=500,i=a.utils.defaultColor(),j=function(a){return a.x},k=function(a){return a.y},l=function(a,b){return!isNaN(k(a,b))&&null!==k(a,b)},m=function(a){return a.area},n=!1,o="linear",p=250,q=d3.dispatch("elementClick","elementMouseover","elementMouseout","renderEnd");e.pointSize(16).pointDomain([16,256]);var r,s,t=a.utils.renderWatch(q,p);return b.dispatch=q,b.scatter=e,e.dispatch.on("elementClick",function(){q.elementClick.apply(this,arguments)}),e.dispatch.on("elementMouseover",function(){q.elementMouseover.apply(this,arguments)}),e.dispatch.on("elementMouseout",function(){q.elementMouseout.apply(this,arguments)}),b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},defined:{get:function(){return l},set:function(a){l=a}},interpolate:{get:function(){return o},set:function(a){o=a}},clipEdge:{get:function(){return n},set:function(a){n=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}},duration:{get:function(){return p},set:function(a){p=a,t.reset(p),e.duration(p)}},isArea:{get:function(){return m},set:function(a){m=d3.functor(a)}},x:{get:function(){return j},set:function(a){j=a,e.x(a)}},y:{get:function(){return k},set:function(a){k=a,e.y(a)}},color:{get:function(){return i},set:function(b){i=a.utils.getColor(b),e.color(i)}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.lineChart=function(){"use strict";function b(t){return A.reset(),A.models(e),o&&A.models(f),p&&A.models(g),t.each(function(t){var A=d3.select(this),D=this;a.utils.initSVG(A);var E=(l||parseInt(A.style("width"))||960)-j.left-j.right,F=(m||parseInt(A.style("height"))||400)-j.top-j.bottom;if(b.update=function(){0===y?A.call(b):A.transition().duration(y).call(b)},b.container=this,u.setter(C(t),b.update).getter(B(t)).update(),u.disabled=t.map(function(a){return!!a.disabled}),!v){var G;v={};for(G in u)v[G]=u[G]instanceof Array?u[G].slice(0):u[G]}if(!(t&&t.length&&t.filter(function(a){return a.values.length}).length)){var H=A.selectAll(".nv-noData").data([w]);return H.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),H.attr("x",j.left+E/2).attr("y",j.top+F/2).text(function(a){return a}),b}A.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var I=A.selectAll("g.nv-wrap.nv-lineChart").data([t]),J=I.enter().append("g").attr("class","nvd3 nv-wrap nv-lineChart").append("g"),K=I.select("g");J.append("rect").style("opacity",0),J.append("g").attr("class","nv-x nv-axis"),J.append("g").attr("class","nv-y nv-axis"),J.append("g").attr("class","nv-linesWrap"),J.append("g").attr("class","nv-legendWrap"),J.append("g").attr("class","nv-interactive"),K.select("rect").attr("width",E).attr("height",F>0?F:0),n&&(h.width(E),K.select(".nv-legendWrap").datum(t).call(h),j.top!=h.height()&&(j.top=h.height(),F=(m||parseInt(A.style("height"))||400)-j.top-j.bottom),I.select(".nv-legendWrap").attr("transform","translate(0,"+-j.top+")")),I.attr("transform","translate("+j.left+","+j.top+")"),q&&K.select(".nv-y.nv-axis").attr("transform","translate("+E+",0)"),r&&(i.width(E).height(F).margin({left:j.left,top:j.top}).svgContainer(A).xScale(c),I.select(".nv-interactive").call(i)),e.width(E).height(F).color(t.map(function(a,b){return a.color||k(a,b)}).filter(function(a,b){return!t[b].disabled}));var L=K.select(".nv-linesWrap").datum(t.filter(function(a){return!a.disabled}));L.call(e),o&&(f.scale(c).ticks(a.utils.calcTicksX(E/100,t)).tickSize(-F,0),K.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),K.select(".nv-x.nv-axis").call(f)),p&&(g.scale(d).ticks(a.utils.calcTicksY(F/36,t)).tickSize(-E,0),K.select(".nv-y.nv-axis").call(g)),h.dispatch.on("stateChange",function(a){for(var c in a)u[c]=a[c];x.stateChange(u),b.update()}),i.dispatch.on("elementMousemove",function(c){e.clearHighlights();var d,h,l,m=[];if(t.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(f,g){h=a.interactiveBisect(f.values,c.pointXValue,b.x()),e.highlightPoint(g,h,!0);var i=f.values[h];"undefined"!=typeof i&&("undefined"==typeof d&&(d=i),"undefined"==typeof l&&(l=b.xScale()(b.x()(i,h))),m.push({key:f.key,value:b.y()(i,h),color:k(f,f.seriesIndex)}))}),m.length>2){var n=b.yScale().invert(c.mouseY),o=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),p=.03*o,q=a.nearestValueIndex(m.map(function(a){return a.value}),n,p);null!==q&&(m[q].highlight=!0)}var r=f.tickFormat()(b.x()(d,h));i.tooltip.position({left:l+j.left,top:c.mouseY+j.top}).chartContainer(D.parentNode).enabled(s).valueFormatter(function(a){return g.tickFormat()(a)}).data({value:r,series:m})(),i.renderGuideLine(l)}),i.dispatch.on("elementClick",function(c){var d,f=[];t.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(e){var g=a.interactiveBisect(e.values,c.pointXValue,b.x()),h=e.values[g];if("undefined"!=typeof h){"undefined"==typeof d&&(d=b.xScale()(b.x()(h,g)));var i=b.yScale()(b.y()(h,g));f.push({point:h,pointIndex:g,pos:[d,i],seriesIndex:e.seriesIndex,series:e})}}),e.dispatch.elementClick(f)}),i.dispatch.on("elementMouseout",function(){x.tooltipHide(),e.clearHighlights()}),x.on("tooltipShow",function(a){s&&z(a,D.parentNode)}),x.on("changeState",function(a){"undefined"!=typeof a.disabled&&t.length===a.disabled.length&&(t.forEach(function(b,c){b.disabled=a.disabled[c]}),u.disabled=a.disabled),b.update()})}),A.renderEnd("lineChart immediate"),b}var c,d,e=a.models.line(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.interactiveGuideline(),j={top:30,right:20,bottom:50,left:60},k=a.utils.defaultColor(),l=null,m=null,n=!0,o=!0,p=!0,q=!1,r=!1,s=!0,t=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" at "+b+"</p>"},u=a.utils.state(),v=null,w="No Data Available.",x=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),y=250;f.orient("bottom").tickPadding(7),g.orient(q?"right":"left");var z=function(c,d){var h=c.pos[0]+(d.offsetLeft||0),i=c.pos[1]+(d.offsetTop||0),j=f.tickFormat()(e.x()(c.point,c.pointIndex)),k=g.tickFormat()(e.y()(c.point,c.pointIndex)),l=t(c.series.key,j,k,c,b);a.tooltip.show([h,i],l,null,null,d)},A=a.utils.renderWatch(x,y),B=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},C=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+j.left,a.pos[1]+j.top],x.tooltipShow(a)}),e.dispatch.on("elementMouseout.tooltip",function(a){x.tooltipHide(a)}),x.on("tooltipHide",function(){s&&a.tooltip.cleanup()}),b.dispatch=x,b.lines=e,b.legend=h,b.xAxis=f,b.yAxis=g,b.interactiveLayer=i,b.dispatch=x,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return l},set:function(a){l=a}},height:{get:function(){return m},set:function(a){m=a}},showLegend:{get:function(){return n},set:function(a){n=a}},showXAxis:{get:function(){return o},set:function(a){o=a}},showYAxis:{get:function(){return p},set:function(a){p=a}},tooltips:{get:function(){return s},set:function(a){s=a}},tooltipContent:{get:function(){return t},set:function(a){t=a}},defaultState:{get:function(){return v},set:function(a){v=a}},noData:{get:function(){return w},set:function(a){w=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return y},set:function(a){y=a,A.reset(y),e.duration(y),f.duration(y),g.duration(y)}},color:{get:function(){return k},set:function(b){k=a.utils.getColor(b),h.color(k),e.color(k)}},rightAlignYAxis:{get:function(){return q},set:function(a){q=a,g.orient(q?"right":"left")}},useInteractiveGuideline:{get:function(){return r},set:function(a){r=a,r&&(e.interactive(!1),e.useVoronoi(!1))}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.linePlusBarChart=function(){"use strict";function b(J){return J.each(function(J){function U(a){var b=+("e"==a),c=b?1:-1,d=_/3;return"M"+.5*c+","+d+"A6,6 0 0 "+b+" "+6.5*c+","+(d+6)+"V"+(2*d-6)+"A6,6 0 0 "+b+" "+.5*c+","+2*d+"ZM"+2.5*c+","+(d+8)+"V"+(2*d-8)+"M"+4.5*c+","+(d+8)+"V"+(2*d-8)}function V(){u.empty()||u.extent(H),nb.data([u.empty()?e.domain():H]).each(function(a){var b=e(a[0])-e.range()[0],c=e.range()[1]-e(a[1]);d3.select(this).select(".left").attr("width",0>b?0:b),d3.select(this).select(".right").attr("x",e(a[1])).attr("width",0>c?0:c)})}function W(){H=u.empty()?null:u.extent(),c=u.empty()?e.domain():u.extent(),L.brush({extent:c,brush:u}),V(),l.width(Z).height($).color(J.map(function(a,b){return a.color||B(a,b)}).filter(function(a,b){return!J[b].disabled&&J[b].bar})),j.width(Z).height($).color(J.map(function(a,b){return a.color||B(a,b)}).filter(function(a,b){return!J[b].disabled&&!J[b].bar}));var b=ib.select(".nv-focus .nv-barsWrap").datum(cb.length?cb.map(function(a){return{key:a.key,values:a.values.filter(function(a,b){return l.x()(a,b)>=c[0]&&l.x()(a,b)<=c[1]})}}):[{values:[]}]),h=ib.select(".nv-focus .nv-linesWrap").datum(db[0].disabled?[{values:[]}]:db.map(function(a){return{key:a.key,values:a.values.filter(function(a,b){return j.x()(a,b)>=c[0]&&j.x()(a,b)<=c[1]})}}));d=cb.length?l.xScale():j.xScale(),n.scale(d).ticks(a.utils.calcTicksX(Z/100,J)).tickSize(-$,0),n.domain([Math.ceil(c[0]),Math.floor(c[1])]),ib.select(".nv-x.nv-axis").transition().duration(M).call(n),b.transition().duration(M).call(l),h.transition().duration(M).call(j),ib.select(".nv-focus .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),p.scale(f).ticks(a.utils.calcTicksY($/36,J)).tickSize(-Z,0),q.scale(g).ticks(a.utils.calcTicksY($/36,J)).tickSize(cb.length?0:-Z,0),ib.select(".nv-focus .nv-y1.nv-axis").style("opacity",cb.length?1:0),ib.select(".nv-focus .nv-y2.nv-axis").style("opacity",db.length&&!db[0].disabled?1:0).attr("transform","translate("+d.range()[1]+",0)"),ib.select(".nv-focus .nv-y1.nv-axis").transition().duration(M).call(p),ib.select(".nv-focus .nv-y2.nv-axis").transition().duration(M).call(q)}var X=d3.select(this),Y=this;a.utils.initSVG(X);var Z=(x||parseInt(X.style("width"))||960)-v.left-v.right,$=(y||parseInt(X.style("height"))||400)-v.top-v.bottom-(D?G:0),_=G-w.top-w.bottom;if(b.update=function(){X.transition().duration(M).call(b)},b.container=this,N.setter(T(J),b.update).getter(S(J)).update(),N.disabled=J.map(function(a){return!!a.disabled}),!O){var ab;O={};for(ab in N)O[ab]=N[ab]instanceof Array?N[ab].slice(0):N[ab]}if(!(J&&J.length&&J.filter(function(a){return a.values.length}).length)){var bb=X.selectAll(".nv-noData").data([K]);return bb.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),bb.attr("x",v.left+Z/2).attr("y",v.top+$/2).text(function(a){return a}),b}X.selectAll(".nv-noData").remove();var cb=J.filter(function(a){return!a.disabled&&a.bar}),db=J.filter(function(a){return!a.bar});d=l.xScale(),e=o.scale(),f=l.yScale(),g=j.yScale(),h=m.yScale(),i=k.yScale();var eb=J.filter(function(a){return!a.disabled&&a.bar}).map(function(a){return a.values.map(function(a,b){return{x:z(a,b),y:A(a,b)}})}),fb=J.filter(function(a){return!a.disabled&&!a.bar}).map(function(a){return a.values.map(function(a,b){return{x:z(a,b),y:A(a,b)}})});d.range([0,Z]),e.domain(d3.extent(d3.merge(eb.concat(fb)),function(a){return a.x})).range([0,Z]);var gb=X.selectAll("g.nv-wrap.nv-linePlusBar").data([J]),hb=gb.enter().append("g").attr("class","nvd3 nv-wrap nv-linePlusBar").append("g"),ib=gb.select("g");hb.append("g").attr("class","nv-legendWrap");var jb=hb.append("g").attr("class","nv-focus");jb.append("g").attr("class","nv-x nv-axis"),jb.append("g").attr("class","nv-y1 nv-axis"),jb.append("g").attr("class","nv-y2 nv-axis"),jb.append("g").attr("class","nv-barsWrap"),jb.append("g").attr("class","nv-linesWrap");var kb=hb.append("g").attr("class","nv-context");kb.append("g").attr("class","nv-x nv-axis"),kb.append("g").attr("class","nv-y1 nv-axis"),kb.append("g").attr("class","nv-y2 nv-axis"),kb.append("g").attr("class","nv-barsWrap"),kb.append("g").attr("class","nv-linesWrap"),kb.append("g").attr("class","nv-brushBackground"),kb.append("g").attr("class","nv-x nv-brush"),C&&(t.width(Z/2),ib.select(".nv-legendWrap").datum(J.map(function(a){return a.originalKey=void 0===a.originalKey?a.key:a.originalKey,a.key=a.originalKey+(a.bar?P:Q),a})).call(t),v.top!=t.height()&&(v.top=t.height(),$=(y||parseInt(X.style("height"))||400)-v.top-v.bottom-G),ib.select(".nv-legendWrap").attr("transform","translate("+Z/2+","+-v.top+")")),gb.attr("transform","translate("+v.left+","+v.top+")"),ib.select(".nv-context").style("display",D?"initial":"none"),m.width(Z).height(_).color(J.map(function(a,b){return a.color||B(a,b)}).filter(function(a,b){return!J[b].disabled&&J[b].bar})),k.width(Z).height(_).color(J.map(function(a,b){return a.color||B(a,b)}).filter(function(a,b){return!J[b].disabled&&!J[b].bar}));var lb=ib.select(".nv-context .nv-barsWrap").datum(cb.length?cb:[{values:[]}]),mb=ib.select(".nv-context .nv-linesWrap").datum(db[0].disabled?[{values:[]}]:db);ib.select(".nv-context").attr("transform","translate(0,"+($+v.bottom+w.top)+")"),lb.transition().call(m),mb.transition().call(k),F&&(o.ticks(a.utils.calcTicksX(Z/100,J)).tickSize(-_,0),ib.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+h.range()[0]+")"),ib.select(".nv-context .nv-x.nv-axis").transition().call(o)),E&&(r.scale(h).ticks(_/36).tickSize(-Z,0),s.scale(i).ticks(_/36).tickSize(cb.length?0:-Z,0),ib.select(".nv-context .nv-y3.nv-axis").style("opacity",cb.length?1:0).attr("transform","translate(0,"+e.range()[0]+")"),ib.select(".nv-context .nv-y2.nv-axis").style("opacity",db.length?1:0).attr("transform","translate("+e.range()[1]+",0)"),ib.select(".nv-context .nv-y1.nv-axis").transition().call(r),ib.select(".nv-context .nv-y2.nv-axis").transition().call(s)),u.x(e).on("brush",W),H&&u.extent(H);var nb=ib.select(".nv-brushBackground").selectAll("g").data([H||u.extent()]),ob=nb.enter().append("g");ob.append("rect").attr("class","left").attr("x",0).attr("y",0).attr("height",_),ob.append("rect").attr("class","right").attr("x",0).attr("y",0).attr("height",_);var pb=ib.select(".nv-x.nv-brush").call(u);pb.selectAll("rect").attr("height",_),pb.selectAll(".resize").append("path").attr("d",U),t.dispatch.on("stateChange",function(a){for(var c in a)N[c]=a[c];L.stateChange(N),b.update()}),L.on("tooltipShow",function(a){I&&R(a,Y.parentNode)}),L.on("changeState",function(a){"undefined"!=typeof a.disabled&&(J.forEach(function(b,c){b.disabled=a.disabled[c]}),N.disabled=a.disabled),b.update()}),W()}),b}var c,d,e,f,g,h,i,j=a.models.line(),k=a.models.line(),l=a.models.historicalBar(),m=a.models.historicalBar(),n=a.models.axis(),o=a.models.axis(),p=a.models.axis(),q=a.models.axis(),r=a.models.axis(),s=a.models.axis(),t=a.models.legend(),u=d3.svg.brush(),v={top:30,right:30,bottom:30,left:60},w={top:0,right:30,bottom:20,left:60},x=null,y=null,z=function(a){return a.x},A=function(a){return a.y},B=a.utils.defaultColor(),C=!0,D=!0,E=!1,F=!0,G=50,H=null,I=!0,J=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" at "+b+"</p>"},K="No Data Available.",L=d3.dispatch("tooltipShow","tooltipHide","brush","stateChange","changeState"),M=0,N=a.utils.state(),O=null,P=" (left axis)",Q=" (right axis)";j.clipEdge(!0),k.interactive(!1),n.orient("bottom").tickPadding(5),p.orient("left"),q.orient("right"),o.orient("bottom").tickPadding(5),r.orient("left"),s.orient("right");var R=function(d,e){c&&(d.pointIndex+=Math.ceil(c[0]));var f=d.pos[0]+(e.offsetLeft||0),g=d.pos[1]+(e.offsetTop||0),h=n.tickFormat()(j.x()(d.point,d.pointIndex)),i=(d.series.bar?p:q).tickFormat()(j.y()(d.point,d.pointIndex)),k=J(d.series.key,h,i,d,b);a.tooltip.show([f,g],k,d.value<0?"n":"s",null,e)},S=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},T=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return j.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+v.left,a.pos[1]+v.top],L.tooltipShow(a)}),j.dispatch.on("elementMouseout.tooltip",function(a){L.tooltipHide(a)}),l.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+v.left,a.pos[1]+v.top],L.tooltipShow(a)}),l.dispatch.on("elementMouseout.tooltip",function(a){L.tooltipHide(a)}),L.on("tooltipHide",function(){I&&a.tooltip.cleanup()}),b.dispatch=L,b.legend=t,b.lines=j,b.lines2=k,b.bars=l,b.bars2=m,b.xAxis=n,b.x2Axis=o,b.y1Axis=p,b.y2Axis=q,b.y3Axis=r,b.y4Axis=s,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return x},set:function(a){x=a}},height:{get:function(){return y},set:function(a){y=a}},showLegend:{get:function(){return C},set:function(a){C=a}},tooltips:{get:function(){return I},set:function(a){I=a}},tooltipContent:{get:function(){return J},set:function(a){J=a}},brushExtent:{get:function(){return H},set:function(a){H=a}},noData:{get:function(){return K},set:function(a){K=a}},focusEnable:{get:function(){return D},set:function(a){D=a}},focusHeight:{get:function(){return G},set:function(a){G=a}},focusShowAxisX:{get:function(){return F},set:function(a){F=a}},focusShowAxisY:{get:function(){return E},set:function(a){E=a}},legendLeftAxisHint:{get:function(){return P},set:function(a){P=a}},legendRightAxisHint:{get:function(){return Q},set:function(a){Q=a}},margin:{get:function(){return v},set:function(a){v.top=void 0!==a.top?a.top:v.top,v.right=void 0!==a.right?a.right:v.right,v.bottom=void 0!==a.bottom?a.bottom:v.bottom,v.left=void 0!==a.left?a.left:v.left}},duration:{get:function(){return M},set:function(a){M=a}},color:{get:function(){return B},set:function(b){B=a.utils.getColor(b),t.color(B)}},x:{get:function(){return z},set:function(a){z=a,j.x(a),k.x(a),l.x(a),m.x(a)}},y:{get:function(){return A},set:function(a){A=a,j.y(a),k.y(a),l.y(a),m.y(a)}}}),a.utils.inheritOptions(b,j),a.utils.initOptions(b),b},a.models.lineWithFocusChart=function(){"use strict";function b(x){return x.each(function(x){function G(a){var b=+("e"==a),c=b?1:-1,d=N/3;return"M"+.5*c+","+d+"A6,6 0 0 "+b+" "+6.5*c+","+(d+6)+"V"+(2*d-6)+"A6,6 0 0 "+b+" "+.5*c+","+2*d+"ZM"+2.5*c+","+(d+8)+"V"+(2*d-8)+"M"+4.5*c+","+(d+8)+"V"+(2*d-8)}function H(){n.empty()||n.extent(v),W.data([n.empty()?e.domain():v]).each(function(a){var b=e(a[0])-c.range()[0],d=c.range()[1]-e(a[1]);d3.select(this).select(".left").attr("width",0>b?0:b),d3.select(this).select(".right").attr("x",e(a[1])).attr("width",0>d?0:d)})}function I(){v=n.empty()?null:n.extent();var a=n.empty()?e.domain():n.extent();if(!(Math.abs(a[0]-a[1])<=1)){z.brush({extent:a,brush:n}),H();var b=S.select(".nv-focus .nv-linesWrap").datum(x.filter(function(a){return!a.disabled}).map(function(b){return{key:b.key,area:b.area,values:b.values.filter(function(b,c){return g.x()(b,c)>=a[0]&&g.x()(b,c)<=a[1]})}}));b.transition().duration(A).call(g),S.select(".nv-focus .nv-x.nv-axis").transition().duration(A).call(i),S.select(".nv-focus .nv-y.nv-axis").transition().duration(A).call(j)}}var J=d3.select(this),K=this;a.utils.initSVG(J);var L=(r||parseInt(J.style("width"))||960)-o.left-o.right,M=(s||parseInt(J.style("height"))||400)-o.top-o.bottom-t,N=t-p.top-p.bottom;if(b.update=function(){J.transition().duration(A).call(b)},b.container=this,B.setter(F(x),b.update).getter(E(x)).update(),B.disabled=x.map(function(a){return!!a.disabled}),!C){var O;C={};for(O in B)C[O]=B[O]instanceof Array?B[O].slice(0):B[O]}if(!(x&&x.length&&x.filter(function(a){return a.values.length}).length)){var P=J.selectAll(".nv-noData").data([y]);return P.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),P.attr("x",o.left+L/2).attr("y",o.top+M/2).text(function(a){return a}),b}J.selectAll(".nv-noData").remove(),c=g.xScale(),d=g.yScale(),e=h.xScale(),f=h.yScale();var Q=J.selectAll("g.nv-wrap.nv-lineWithFocusChart").data([x]),R=Q.enter().append("g").attr("class","nvd3 nv-wrap nv-lineWithFocusChart").append("g"),S=Q.select("g");R.append("g").attr("class","nv-legendWrap");var T=R.append("g").attr("class","nv-focus");T.append("g").attr("class","nv-x nv-axis"),T.append("g").attr("class","nv-y nv-axis"),T.append("g").attr("class","nv-linesWrap");var U=R.append("g").attr("class","nv-context");U.append("g").attr("class","nv-x nv-axis"),U.append("g").attr("class","nv-y nv-axis"),U.append("g").attr("class","nv-linesWrap"),U.append("g").attr("class","nv-brushBackground"),U.append("g").attr("class","nv-x nv-brush"),u&&(m.width(L),S.select(".nv-legendWrap").datum(x).call(m),o.top!=m.height()&&(o.top=m.height(),M=(s||parseInt(J.style("height"))||400)-o.top-o.bottom-t),S.select(".nv-legendWrap").attr("transform","translate(0,"+-o.top+")")),Q.attr("transform","translate("+o.left+","+o.top+")"),g.width(L).height(M).color(x.map(function(a,b){return a.color||q(a,b)}).filter(function(a,b){return!x[b].disabled})),h.defined(g.defined()).width(L).height(N).color(x.map(function(a,b){return a.color||q(a,b)}).filter(function(a,b){return!x[b].disabled})),S.select(".nv-context").attr("transform","translate(0,"+(M+o.bottom+p.top)+")");var V=S.select(".nv-context .nv-linesWrap").datum(x.filter(function(a){return!a.disabled}));d3.transition(V).call(h),i.scale(c).ticks(a.utils.calcTicksX(L/100,x)).tickSize(-M,0),j.scale(d).ticks(a.utils.calcTicksY(M/36,x)).tickSize(-L,0),S.select(".nv-focus .nv-x.nv-axis").attr("transform","translate(0,"+M+")"),n.x(e).on("brush",function(){var a=b.duration();b.duration(0),I(),b.duration(a)}),v&&n.extent(v);var W=S.select(".nv-brushBackground").selectAll("g").data([v||n.extent()]),X=W.enter().append("g");X.append("rect").attr("class","left").attr("x",0).attr("y",0).attr("height",N),X.append("rect").attr("class","right").attr("x",0).attr("y",0).attr("height",N);var Y=S.select(".nv-x.nv-brush").call(n);Y.selectAll("rect").attr("height",N),Y.selectAll(".resize").append("path").attr("d",G),I(),k.scale(e).ticks(a.utils.calcTicksX(L/100,x)).tickSize(-N,0),S.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),d3.transition(S.select(".nv-context .nv-x.nv-axis")).call(k),l.scale(f).ticks(a.utils.calcTicksY(N/36,x)).tickSize(-L,0),d3.transition(S.select(".nv-context .nv-y.nv-axis")).call(l),S.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),m.dispatch.on("stateChange",function(a){for(var c in a)B[c]=a[c];z.stateChange(B),b.update()}),z.on("tooltipShow",function(a){w&&D(a,K.parentNode)}),z.on("changeState",function(a){"undefined"!=typeof a.disabled&&x.forEach(function(b,c){b.disabled=a.disabled[c]}),b.update()})}),b}var c,d,e,f,g=a.models.line(),h=a.models.line(),i=a.models.axis(),j=a.models.axis(),k=a.models.axis(),l=a.models.axis(),m=a.models.legend(),n=d3.svg.brush(),o={top:30,right:30,bottom:30,left:60},p={top:0,right:30,bottom:20,left:60},q=a.utils.defaultColor(),r=null,s=null,t=100,u=!0,v=null,w=!0,x=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" at "+b+"</p>"},y="No Data Available.",z=d3.dispatch("tooltipShow","tooltipHide","brush","stateChange","changeState"),A=250,B=a.utils.state(),C=null;g.clipEdge(!0),h.interactive(!1),i.orient("bottom").tickPadding(5),j.orient("left"),k.orient("bottom").tickPadding(5),l.orient("left");var D=function(c,d){var e=c.pos[0]+(d.offsetLeft||0),f=c.pos[1]+(d.offsetTop||0),h=i.tickFormat()(g.x()(c.point,c.pointIndex)),k=j.tickFormat()(g.y()(c.point,c.pointIndex)),l=x(c.series.key,h,k,c,b);a.tooltip.show([e,f],l,null,null,d)},E=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},F=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return g.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+o.left,a.pos[1]+o.top],z.tooltipShow(a)}),g.dispatch.on("elementMouseout.tooltip",function(a){z.tooltipHide(a)}),z.on("tooltipHide",function(){w&&a.tooltip.cleanup()}),b.dispatch=z,b.legend=m,b.lines=g,b.lines2=h,b.xAxis=i,b.yAxis=j,b.x2Axis=k,b.y2Axis=l,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return r},set:function(a){r=a}},height:{get:function(){return s},set:function(a){s=a}},focusHeight:{get:function(){return t},set:function(a){t=a}},showLegend:{get:function(){return u},set:function(a){u=a}},brushExtent:{get:function(){return v},set:function(a){v=a}},tooltips:{get:function(){return w},set:function(a){w=a}},tooltipContent:{get:function(){return x},set:function(a){x=a}},defaultState:{get:function(){return C},set:function(a){C=a}},noData:{get:function(){return y},set:function(a){y=a}},margin:{get:function(){return o},set:function(a){o.top=void 0!==a.top?a.top:o.top,o.right=void 0!==a.right?a.right:o.right,o.bottom=void 0!==a.bottom?a.bottom:o.bottom,o.left=void 0!==a.left?a.left:o.left}},color:{get:function(){return q},set:function(b){q=a.utils.getColor(b),m.color(q)}},interpolate:{get:function(){return g.interpolate()},set:function(a){g.interpolate(a),h.interpolate(a)}},xTickFormat:{get:function(){return i.xTickFormat()},set:function(a){i.xTickFormat(a),k.xTickFormat(a)}},yTickFormat:{get:function(){return j.yTickFormat()},set:function(a){j.yTickFormat(a),l.yTickFormat(a)}},duration:{get:function(){return A},set:function(a){A=a,j.duration(A),i.duration(A)}},x:{get:function(){return g.x()},set:function(a){g.x(a),h.x(a)}},y:{get:function(){return g.y()},set:function(a){g.y(a),h.y(a)}}}),a.utils.inheritOptions(b,g),a.utils.initOptions(b),b},a.models.multiBar=function(){"use strict";function b(D){return B.reset(),D.each(function(b){var D=k-j.left-j.right,E=l-j.top-j.bottom,F=d3.select(this);a.utils.initSVG(F);w&&b.length&&(w=[{values:b[0].values.map(function(a){return{x:a.x,y:0,series:a.series,size:.01}})}]),t&&(b=d3.layout.stack().offset(u).values(function(a){return a.values}).y(q)(!b.length&&w?w:b)),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})}),t&&b[0].values.map(function(a,c){var d=0,e=0;b.map(function(a){var b=a.values[c];b.size=Math.abs(b.y),b.y<0?(b.y1=e,e-=b.size):(b.y1=b.size+d,d+=b.size)})});var G=d&&e?[]:b.map(function(a){return a.values.map(function(a,b){return{x:p(a,b),y:q(a,b),y0:a.y0,y1:a.y1}})});m.domain(d||d3.merge(G).map(function(a){return a.x})).rangeBands(f||[0,D],z),n.domain(e||d3.extent(d3.merge(G).map(function(a){return t?a.y>0?a.y1:a.y1+a.y:a.y
+}).concat(r))).range(g||[E,0]),m.domain()[0]===m.domain()[1]&&m.domain(m.domain()[0]?[m.domain()[0]-.01*m.domain()[0],m.domain()[1]+.01*m.domain()[1]]:[-1,1]),n.domain()[0]===n.domain()[1]&&n.domain(n.domain()[0]?[n.domain()[0]+.01*n.domain()[0],n.domain()[1]-.01*n.domain()[1]]:[-1,1]),h=h||m,i=i||n;var H=F.selectAll("g.nv-wrap.nv-multibar").data([b]),I=H.enter().append("g").attr("class","nvd3 nv-wrap nv-multibar"),J=I.append("defs"),K=I.append("g"),L=H.select("g");K.append("g").attr("class","nv-groups"),H.attr("transform","translate("+j.left+","+j.top+")"),J.append("clipPath").attr("id","nv-edge-clip-"+o).append("rect"),H.select("#nv-edge-clip-"+o+" rect").attr("width",D).attr("height",E),L.attr("clip-path",s?"url(#nv-edge-clip-"+o+")":"");var M=H.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});M.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6);var N=B.transition(M.exit().selectAll("rect.nv-bar"),"multibarExit",Math.min(100,y)).attr("y",function(a){return i(t?a.y0:0)||0}).attr("height",0).remove();N.delay&&N.delay(function(a,b){var c=b*(y/(C+1))-b;return c}),M.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return v(a,b)}).style("stroke",function(a,b){return v(a,b)}),M.style("stroke-opacity",1).style("fill-opacity",.75);var O=M.selectAll("rect.nv-bar").data(function(a){return w&&!b.length?w.values:a.values});O.exit().remove();O.enter().append("rect").attr("class",function(a,b){return q(a,b)<0?"nv-bar negative":"nv-bar positive"}).attr("x",function(a,c,d){return t?0:d*m.rangeBand()/b.length}).attr("y",function(a){return i(t?a.y0:0)||0}).attr("height",0).attr("width",m.rangeBand()/(t?1:b.length)).attr("transform",function(a,b){return"translate("+m(p(a,b))+",0)"});O.style("fill",function(a,b,c){return v(a,c,b)}).style("stroke",function(a,b,c){return v(a,c,b)}).on("mouseover",function(a,c){d3.select(this).classed("hover",!0),A.elementMouseover({value:q(a,c),point:a,series:b[a.series],pos:[m(p(a,c))+m.rangeBand()*(t?b.length/2:a.series+.5)/b.length,n(q(a,c)+(t?a.y0:0))],pointIndex:c,seriesIndex:a.series,e:d3.event})}).on("mouseout",function(a,c){d3.select(this).classed("hover",!1),A.elementMouseout({value:q(a,c),point:a,series:b[a.series],pointIndex:c,seriesIndex:a.series,e:d3.event})}).on("click",function(a,c){A.elementClick({value:q(a,c),point:a,series:b[a.series],pos:[m(p(a,c))+m.rangeBand()*(t?b.length/2:a.series+.5)/b.length,n(q(a,c)+(t?a.y0:0))],pointIndex:c,seriesIndex:a.series,e:d3.event}),d3.event.stopPropagation()}).on("dblclick",function(a,c){A.elementDblClick({value:q(a,c),point:a,series:b[a.series],pos:[m(p(a,c))+m.rangeBand()*(t?b.length/2:a.series+.5)/b.length,n(q(a,c)+(t?a.y0:0))],pointIndex:c,seriesIndex:a.series,e:d3.event}),d3.event.stopPropagation()}),O.attr("class",function(a,b){return q(a,b)<0?"nv-bar negative":"nv-bar positive"}).attr("transform",function(a,b){return"translate("+m(p(a,b))+",0)"}),x&&(c||(c=b.map(function(){return!0})),O.style("fill",function(a,b,d){return d3.rgb(x(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}).style("stroke",function(a,b,d){return d3.rgb(x(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}));var P=O.watchTransition(B,"multibar",Math.min(250,y)).delay(function(a,c){return c*y/b[0].values.length});t?P.attr("y",function(a){return n(t?a.y1:0)}).attr("height",function(a){return Math.max(Math.abs(n(a.y+(t?a.y0:0))-n(t?a.y0:0)),1)}).attr("x",function(a){return t?0:a.series*m.rangeBand()/b.length}).attr("width",m.rangeBand()/(t?1:b.length)):P.attr("x",function(a){return a.series*m.rangeBand()/b.length}).attr("width",m.rangeBand()/b.length).attr("y",function(a,b){return q(a,b)<0?n(0):n(0)-n(q(a,b))<1?n(0)-1:n(q(a,b))||0}).attr("height",function(a,b){return Math.max(Math.abs(n(q(a,b))-n(0)),1)||0}),h=m.copy(),i=n.copy(),b[0]&&b[0].values&&(C=b[0].values.length)}),B.renderEnd("multibar immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=d3.scale.ordinal(),n=d3.scale.linear(),o=Math.floor(1e4*Math.random()),p=function(a){return a.x},q=function(a){return a.y},r=[0],s=!0,t=!1,u="zero",v=a.utils.defaultColor(),w=!1,x=null,y=500,z=.1,A=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),B=a.utils.renderWatch(A,y),C=0;return b.dispatch=A,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},x:{get:function(){return p},set:function(a){p=a}},y:{get:function(){return q},set:function(a){q=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceY:{get:function(){return r},set:function(a){r=a}},stacked:{get:function(){return t},set:function(a){t=a}},stackOffset:{get:function(){return u},set:function(a){u=a}},clipEdge:{get:function(){return s},set:function(a){s=a}},disabled:{get:function(){return c},set:function(a){c=a}},id:{get:function(){return o},set:function(a){o=a}},hideable:{get:function(){return w},set:function(a){w=a}},groupSpacing:{get:function(){return z},set:function(a){z=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return y},set:function(a){y=a,B.reset(y)}},color:{get:function(){return v},set:function(b){v=a.utils.getColor(b)}},barColor:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.multiBarChart=function(){"use strict";function b(x){return E.reset(),E.models(e),q&&E.models(f),r&&E.models(g),x.each(function(x){var E=d3.select(this),J=this;a.utils.initSVG(E);var K=(k||parseInt(E.style("width"))||960)-j.left-j.right,L=(l||parseInt(E.style("height"))||400)-j.top-j.bottom;if(b.update=function(){0===D?E.call(b):E.transition().duration(D).call(b)},b.container=this,y.setter(I(x),b.update).getter(H(x)).update(),y.disabled=x.map(function(a){return!!a.disabled}),!z){var M;z={};for(M in y)z[M]=y[M]instanceof Array?y[M].slice(0):y[M]}if(!(x&&x.length&&x.filter(function(a){return a.values.length}).length)){var N=E.selectAll(".nv-noData").data([A]);return N.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),N.attr("x",j.left+K/2).attr("y",j.top+L/2).text(function(a){return a}),b}E.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var O=E.selectAll("g.nv-wrap.nv-multiBarWithLegend").data([x]),P=O.enter().append("g").attr("class","nvd3 nv-wrap nv-multiBarWithLegend").append("g"),Q=O.select("g");if(P.append("g").attr("class","nv-x nv-axis"),P.append("g").attr("class","nv-y nv-axis"),P.append("g").attr("class","nv-barsWrap"),P.append("g").attr("class","nv-legendWrap"),P.append("g").attr("class","nv-controlsWrap"),p&&(h.width(K-C()),e.barColor()&&x.forEach(function(a,b){a.color=d3.rgb("#ccc").darker(1.5*b).toString()}),Q.select(".nv-legendWrap").datum(x).call(h),j.top!=h.height()&&(j.top=h.height(),L=(l||parseInt(E.style("height"))||400)-j.top-j.bottom),Q.select(".nv-legendWrap").attr("transform","translate("+C()+","+-j.top+")")),n){var R=[{key:o.grouped||"Grouped",disabled:e.stacked()},{key:o.stacked||"Stacked",disabled:!e.stacked()}];i.width(C()).color(["#444","#444","#444"]),Q.select(".nv-controlsWrap").datum(R).attr("transform","translate(0,"+-j.top+")").call(i)}O.attr("transform","translate("+j.left+","+j.top+")"),s&&Q.select(".nv-y.nv-axis").attr("transform","translate("+K+",0)"),e.disabled(x.map(function(a){return a.disabled})).width(K).height(L).color(x.map(function(a,b){return a.color||m(a,b)}).filter(function(a,b){return!x[b].disabled}));var S=Q.select(".nv-barsWrap").datum(x.filter(function(a){return!a.disabled}));if(S.call(e),q){f.scale(c).ticks(a.utils.calcTicksX(K/100,x)).tickSize(-L,0),Q.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),Q.select(".nv-x.nv-axis").call(f);var T=Q.select(".nv-x.nv-axis > g").selectAll("g");if(T.selectAll("line, text").style("opacity",1),u){var U=function(a,b){return"translate("+a+","+b+")"},V=5,W=17;T.selectAll("text").attr("transform",function(a,b,c){return U(0,c%2==0?V:W)});var X=d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;Q.selectAll(".nv-x.nv-axis .nv-axisMaxMin text").attr("transform",function(a,b){return U(0,0===b||X%2!==0?W:V)})}t&&T.filter(function(a,b){return b%Math.ceil(x[0].values.length/(K/100))!==0}).selectAll("text, line").style("opacity",0),v&&T.selectAll(".tick text").attr("transform","rotate("+v+" 0,0)").style("text-anchor",v>0?"start":"end"),Q.select(".nv-x.nv-axis").selectAll("g.nv-axisMaxMin text").style("opacity",1)}r&&(g.scale(d).ticks(a.utils.calcTicksY(L/36,x)).tickSize(-K,0),Q.select(".nv-y.nv-axis").call(g)),h.dispatch.on("stateChange",function(a){for(var c in a)y[c]=a[c];B.stateChange(y),b.update()}),i.dispatch.on("legendClick",function(a){if(a.disabled){switch(R=R.map(function(a){return a.disabled=!0,a}),a.disabled=!1,a.key){case"Grouped":e.stacked(!1);break;case"Stacked":e.stacked(!0)}y.stacked=e.stacked(),B.stateChange(y),b.update()}}),B.on("tooltipShow",function(a){w&&G(a,J.parentNode)}),B.on("changeState",function(a){"undefined"!=typeof a.disabled&&(x.forEach(function(b,c){b.disabled=a.disabled[c]}),y.disabled=a.disabled),"undefined"!=typeof a.stacked&&(e.stacked(a.stacked),y.stacked=a.stacked,F=a.stacked),b.update()})}),E.renderEnd("multibarchart immediate"),b}var c,d,e=a.models.multiBar(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.models.legend(),j={top:30,right:20,bottom:50,left:60},k=null,l=null,m=a.utils.defaultColor(),n=!0,o={},p=!0,q=!0,r=!0,s=!1,t=!0,u=!1,v=0,w=!0,x=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" on "+b+"</p>"},y=a.utils.state(),z=null,A="No Data Available.",B=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),C=function(){return n?180:0},D=250;y.stacked=!1,e.stacked(!1),f.orient("bottom").tickPadding(7).highlightZero(!0).showMaxMin(!1).tickFormat(function(a){return a}),g.orient(s?"right":"left").tickFormat(d3.format(",.1f")),i.updateState(!1);var E=a.utils.renderWatch(B),F=!1,G=function(c,d){var h=c.pos[0]+(d.offsetLeft||0),i=c.pos[1]+(d.offsetTop||0),j=f.tickFormat()(e.x()(c.point,c.pointIndex)),k=g.tickFormat()(e.y()(c.point,c.pointIndex)),l=x(c.series.key,j,k,c,b);a.tooltip.show([h,i],l,c.value<0?"n":"s",null,d)},H=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),stacked:F}}},I=function(a){return function(b){void 0!==b.stacked&&(F=b.stacked),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+j.left,a.pos[1]+j.top],B.tooltipShow(a)}),e.dispatch.on("elementMouseout.tooltip",function(a){B.tooltipHide(a)}),B.on("tooltipHide",function(){w&&a.tooltip.cleanup()}),b.dispatch=B,b.multibar=e,b.legend=h,b.xAxis=f,b.yAxis=g,b.state=y,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},showLegend:{get:function(){return p},set:function(a){p=a}},showControls:{get:function(){return n},set:function(a){n=a}},controlLabels:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return q},set:function(a){q=a}},showYAxis:{get:function(){return r},set:function(a){r=a}},tooltips:{get:function(){return w},set:function(a){w=a}},tooltipContent:{get:function(){return x},set:function(a){x=a}},defaultState:{get:function(){return z},set:function(a){z=a}},noData:{get:function(){return A},set:function(a){A=a}},reduceXTicks:{get:function(){return t},set:function(a){t=a}},rotateLabels:{get:function(){return v},set:function(a){v=a}},staggerLabels:{get:function(){return u},set:function(a){u=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return D},set:function(a){D=a,e.duration(D),f.duration(D),g.duration(D),E.reset(D)}},color:{get:function(){return m},set:function(b){m=a.utils.getColor(b),h.color(m)}},rightAlignYAxis:{get:function(){return s},set:function(a){s=a,g.orient(s?"right":"left")}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.multiBarHorizontal=function(){"use strict";function b(m){return C.reset(),m.each(function(b){var m=k-j.left-j.right,A=l-j.top-j.bottom,D=d3.select(this);a.utils.initSVG(D),v&&(b=d3.layout.stack().offset("zero").values(function(a){return a.values}).y(q)(b)),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})}),v&&b[0].values.map(function(a,c){var d=0,e=0;b.map(function(a){var b=a.values[c];b.size=Math.abs(b.y),b.y<0?(b.y1=e-b.size,e-=b.size):(b.y1=d,d+=b.size)})});var E=d&&e?[]:b.map(function(a){return a.values.map(function(a,b){return{x:p(a,b),y:q(a,b),y0:a.y0,y1:a.y1}})});n.domain(d||d3.merge(E).map(function(a){return a.x})).rangeBands(f||[0,A],.1),o.domain(e||d3.extent(d3.merge(E).map(function(a){return v?a.y>0?a.y1+a.y:a.y1:a.y}).concat(s))),o.range(w&&!v?g||[o.domain()[0]<0?y:0,m-(o.domain()[1]>0?y:0)]:g||[0,m]),h=h||n,i=i||d3.scale.linear().domain(o.domain()).range([o(0),o(0)]);{var F=d3.select(this).selectAll("g.nv-wrap.nv-multibarHorizontal").data([b]),G=F.enter().append("g").attr("class","nvd3 nv-wrap nv-multibarHorizontal"),H=(G.append("defs"),G.append("g"));F.select("g")}H.append("g").attr("class","nv-groups"),F.attr("transform","translate("+j.left+","+j.top+")");var I=F.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});I.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),I.exit().watchTransition(C,"multibarhorizontal: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),I.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return t(a,b)}).style("stroke",function(a,b){return t(a,b)}),I.watchTransition(C,"multibarhorizontal: groups").style("stroke-opacity",1).style("fill-opacity",.75);var J=I.selectAll("g.nv-bar").data(function(a){return a.values});J.exit().remove();var K=J.enter().append("g").attr("transform",function(a,c,d){return"translate("+i(v?a.y0:0)+","+(v?0:d*n.rangeBand()/b.length+n(p(a,c)))+")"});K.append("rect").attr("width",0).attr("height",n.rangeBand()/(v?1:b.length)),J.on("mouseover",function(a,c){d3.select(this).classed("hover",!0),B.elementMouseover({value:q(a,c),point:a,series:b[a.series],pos:[o(q(a,c)+(v?a.y0:0)),n(p(a,c))+n.rangeBand()*(v?b.length/2:a.series+.5)/b.length],pointIndex:c,seriesIndex:a.series,e:d3.event})}).on("mouseout",function(a,c){d3.select(this).classed("hover",!1),B.elementMouseout({value:q(a,c),point:a,series:b[a.series],pointIndex:c,seriesIndex:a.series,e:d3.event})}).on("click",function(a,c){B.elementClick({value:q(a,c),point:a,series:b[a.series],pos:[n(p(a,c))+n.rangeBand()*(v?b.length/2:a.series+.5)/b.length,o(q(a,c)+(v?a.y0:0))],pointIndex:c,seriesIndex:a.series,e:d3.event}),d3.event.stopPropagation()}).on("dblclick",function(a,c){B.elementDblClick({value:q(a,c),point:a,series:b[a.series],pos:[n(p(a,c))+n.rangeBand()*(v?b.length/2:a.series+.5)/b.length,o(q(a,c)+(v?a.y0:0))],pointIndex:c,seriesIndex:a.series,e:d3.event}),d3.event.stopPropagation()}),r(b[0],0)&&(K.append("polyline"),J.select("polyline").attr("fill","none").attr("points",function(a,c){var d=r(a,c),e=.8*n.rangeBand()/(2*(v?1:b.length));d=d.length?d:[-Math.abs(d),Math.abs(d)],d=d.map(function(a){return o(a)-o(0)});var f=[[d[0],-e],[d[0],e],[d[0],0],[d[1],0],[d[1],-e],[d[1],e]];return f.map(function(a){return a.join(",")}).join(" ")}).attr("transform",function(a,c){var d=n.rangeBand()/(2*(v?1:b.length));return"translate("+(q(a,c)<0?0:o(q(a,c))-o(0))+", "+d+")"})),K.append("text"),w&&!v?(J.select("text").attr("text-anchor",function(a,b){return q(a,b)<0?"end":"start"}).attr("y",n.rangeBand()/(2*b.length)).attr("dy",".32em").html(function(a,b){var c=z(q(a,b)),d=r(a,b);return void 0===d?c:d.length?c+"+"+z(Math.abs(d[1]))+"-"+z(Math.abs(d[0])):c+"±"+z(Math.abs(d))}),J.watchTransition(C,"multibarhorizontal: bars").select("text").attr("x",function(a,b){return q(a,b)<0?-4:o(q(a,b))-o(0)+4})):J.selectAll("text").text(""),x&&!v?(K.append("text").classed("nv-bar-label",!0),J.select("text.nv-bar-label").attr("text-anchor",function(a,b){return q(a,b)<0?"start":"end"}).attr("y",n.rangeBand()/(2*b.length)).attr("dy",".32em").text(function(a,b){return p(a,b)}),J.watchTransition(C,"multibarhorizontal: bars").select("text.nv-bar-label").attr("x",function(a,b){return q(a,b)<0?o(0)-o(q(a,b))+4:-4})):J.selectAll("text.nv-bar-label").text(""),J.attr("class",function(a,b){return q(a,b)<0?"nv-bar negative":"nv-bar positive"}),u&&(c||(c=b.map(function(){return!0})),J.style("fill",function(a,b,d){return d3.rgb(u(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}).style("stroke",function(a,b,d){return d3.rgb(u(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()})),v?J.watchTransition(C,"multibarhorizontal: bars").attr("transform",function(a,b){return"translate("+o(a.y1)+","+n(p(a,b))+")"}).select("rect").attr("width",function(a,b){return Math.abs(o(q(a,b)+a.y0)-o(a.y0))}).attr("height",n.rangeBand()):J.watchTransition(C,"multibarhorizontal: bars").attr("transform",function(a,c){return"translate("+o(q(a,c)<0?q(a,c):0)+","+(a.series*n.rangeBand()/b.length+n(p(a,c)))+")"}).select("rect").attr("height",n.rangeBand()/b.length).attr("width",function(a,b){return Math.max(Math.abs(o(q(a,b))-o(0)),1)}),h=n.copy(),i=o.copy()}),C.renderEnd("multibarHorizontal immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=Math.floor(1e4*Math.random()),n=d3.scale.ordinal(),o=d3.scale.linear(),p=function(a){return a.x},q=function(a){return a.y},r=function(a){return a.yErr},s=[0],t=a.utils.defaultColor(),u=null,v=!1,w=!1,x=!1,y=60,z=d3.format(",.2f"),A=250,B=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),C=a.utils.renderWatch(B,A);return b.dispatch=B,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},x:{get:function(){return p},set:function(a){p=a}},y:{get:function(){return q},set:function(a){q=a}},yErr:{get:function(){return r},set:function(a){r=a}},xScale:{get:function(){return n},set:function(a){n=a}},yScale:{get:function(){return o},set:function(a){o=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceY:{get:function(){return s},set:function(a){s=a}},stacked:{get:function(){return v},set:function(a){v=a}},showValues:{get:function(){return w},set:function(a){w=a}},disabled:{get:function(){return c},set:function(a){c=a}},id:{get:function(){return m},set:function(a){m=a}},valueFormat:{get:function(){return z},set:function(a){z=a}},valuePadding:{get:function(){return y},set:function(a){y=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return A},set:function(a){A=a,C.reset(A)}},color:{get:function(){return t},set:function(b){t=a.utils.getColor(b)}},barColor:{get:function(){return t},set:function(b){u=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.multiBarHorizontalChart=function(){"use strict";function b(u){return E.reset(),E.models(e),q&&E.models(f),r&&E.models(g),u.each(function(u){var E=d3.select(this),F=this;a.utils.initSVG(E);var G=(k||parseInt(E.style("width"))||960)-j.left-j.right,H=(l||parseInt(E.style("height"))||400)-j.top-j.bottom;if(b.update=function(){E.transition().duration(A).call(b)},b.container=this,s=e.stacked(),v.setter(D(u),b.update).getter(C(u)).update(),v.disabled=u.map(function(a){return!!a.disabled}),!w){var I;w={};for(I in v)w[I]=v[I]instanceof Array?v[I].slice(0):v[I]}if(!(u&&u.length&&u.filter(function(a){return a.values.length}).length)){var J=E.selectAll(".nv-noData").data([x]);return J.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),J.attr("x",j.left+G/2).attr("y",j.top+H/2).text(function(a){return a}),b}E.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var K=E.selectAll("g.nv-wrap.nv-multiBarHorizontalChart").data([u]),L=K.enter().append("g").attr("class","nvd3 nv-wrap nv-multiBarHorizontalChart").append("g"),M=K.select("g");if(L.append("g").attr("class","nv-x nv-axis"),L.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),L.append("g").attr("class","nv-barsWrap"),L.append("g").attr("class","nv-legendWrap"),L.append("g").attr("class","nv-controlsWrap"),p&&(h.width(G-z()),e.barColor()&&u.forEach(function(a,b){a.color=d3.rgb("#ccc").darker(1.5*b).toString()}),M.select(".nv-legendWrap").datum(u).call(h),j.top!=h.height()&&(j.top=h.height(),H=(l||parseInt(E.style("height"))||400)-j.top-j.bottom),M.select(".nv-legendWrap").attr("transform","translate("+z()+","+-j.top+")")),n){var N=[{key:o.grouped||"Grouped",disabled:e.stacked()},{key:o.stacked||"Stacked",disabled:!e.stacked()}];i.width(z()).color(["#444","#444","#444"]),M.select(".nv-controlsWrap").datum(N).attr("transform","translate(0,"+-j.top+")").call(i)}K.attr("transform","translate("+j.left+","+j.top+")"),e.disabled(u.map(function(a){return a.disabled})).width(G).height(H).color(u.map(function(a,b){return a.color||m(a,b)}).filter(function(a,b){return!u[b].disabled}));var O=M.select(".nv-barsWrap").datum(u.filter(function(a){return!a.disabled}));if(O.transition().call(e),q){f.scale(c).ticks(a.utils.calcTicksY(H/24,u)).tickSize(-G,0),M.select(".nv-x.nv-axis").call(f);var P=M.select(".nv-x.nv-axis").selectAll("g");P.selectAll("line, text")}r&&(g.scale(d).ticks(a.utils.calcTicksX(G/100,u)).tickSize(-H,0),M.select(".nv-y.nv-axis").attr("transform","translate(0,"+H+")"),M.select(".nv-y.nv-axis").call(g)),M.select(".nv-zeroLine line").attr("x1",d(0)).attr("x2",d(0)).attr("y1",0).attr("y2",-H),h.dispatch.on("stateChange",function(a){for(var c in a)v[c]=a[c];y.stateChange(v),b.update()}),i.dispatch.on("legendClick",function(a){if(a.disabled){switch(N=N.map(function(a){return a.disabled=!0,a}),a.disabled=!1,a.key){case"Grouped":e.stacked(!1);break;case"Stacked":e.stacked(!0)}v.stacked=e.stacked(),y.stateChange(v),s=e.stacked(),b.update()}}),y.on("tooltipShow",function(a){t&&B(a,F.parentNode)}),y.on("changeState",function(a){"undefined"!=typeof a.disabled&&(u.forEach(function(b,c){b.disabled=a.disabled[c]}),v.disabled=a.disabled),"undefined"!=typeof a.stacked&&(e.stacked(a.stacked),v.stacked=a.stacked,s=a.stacked),b.update()})}),E.renderEnd("multibar horizontal chart immediate"),b}var c,d,e=a.models.multiBarHorizontal(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend().height(30),i=a.models.legend().height(30),j={top:30,right:20,bottom:50,left:60},k=null,l=null,m=a.utils.defaultColor(),n=!0,o={},p=!0,q=!0,r=!0,s=!1,t=!0,u=function(a,b,c){return"<h3>"+a+" - "+b+"</h3><p>"+c+"</p>"},v=a.utils.state(),w=null,x="No Data Available.",y=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),z=function(){return n?180:0},A=250;v.stacked=!1,e.stacked(s),f.orient("left").tickPadding(5).highlightZero(!1).showMaxMin(!1).tickFormat(function(a){return a}),g.orient("bottom").tickFormat(d3.format(",.1f")),i.updateState(!1);var B=function(c,d){var h=c.pos[0]+(d.offsetLeft||0),i=c.pos[1]+(d.offsetTop||0),j=f.tickFormat()(e.x()(c.point,c.pointIndex)),k=g.tickFormat()(e.y()(c.point,c.pointIndex)),l=u(c.series.key,j,k,c,b);a.tooltip.show([h,i],l,c.value<0?"e":"w",null,d)},C=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),stacked:s}}},D=function(a){return function(b){void 0!==b.stacked&&(s=b.stacked),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}},E=a.utils.renderWatch(y,A);return e.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+j.left,a.pos[1]+j.top],y.tooltipShow(a)}),e.dispatch.on("elementMouseout.tooltip",function(a){y.tooltipHide(a)}),y.on("tooltipHide",function(){t&&a.tooltip.cleanup()}),b.dispatch=y,b.multibar=e,b.legend=h,b.xAxis=f,b.yAxis=g,b.state=v,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},showLegend:{get:function(){return p},set:function(a){p=a}},showControls:{get:function(){return n},set:function(a){n=a}},controlLabels:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return q},set:function(a){q=a}},showYAxis:{get:function(){return r},set:function(a){r=a}},tooltips:{get:function(){return t},set:function(a){t=a}},tooltipContent:{get:function(){return u},set:function(a){u=a}},defaultState:{get:function(){return w},set:function(a){w=a}},noData:{get:function(){return x},set:function(a){x=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return A},set:function(a){A=a,E.reset(A),e.duration(A),f.duration(A),g.duration(A)}},color:{get:function(){return m},set:function(b){m=a.utils.getColor(b),h.color(m)}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.multiChart=function(){"use strict";function b(l){return l.each(function(l){var n=d3.select(this),o=this;a.utils.initSVG(n),b.update=function(){n.transition().call(b)},b.container=this;var E=(h||parseInt(n.style("width"))||960)-f.left-f.right,F=(i||parseInt(n.style("height"))||400)-f.top-f.bottom,G=l.filter(function(a){return"line"==a.type&&1==a.yAxis}),H=l.filter(function(a){return"line"==a.type&&2==a.yAxis}),I=l.filter(function(a){return"bar"==a.type&&1==a.yAxis}),J=l.filter(function(a){return"bar"==a.type&&2==a.yAxis}),K=l.filter(function(a){return"area"==a.type&&1==a.yAxis}),L=l.filter(function(a){return"area"==a.type&&2==a.yAxis});if(!(l&&l.length&&l.filter(function(a){return a.values.length}).length)){var M=n.selectAll(".nv-noData").data([m]);return M.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),M.attr("x",f.left+E/2).attr("y",f.top+F/2).text(function(a){return a}),b}n.selectAll(".nv-noData").remove();var N=l.filter(function(a){return!a.disabled&&1==a.yAxis}).map(function(a){return a.values.map(function(a){return{x:a.x,y:a.y}})}),O=l.filter(function(a){return!a.disabled&&2==a.yAxis}).map(function(a){return a.values.map(function(a){return{x:a.x,y:a.y}})});c.domain(d3.extent(d3.merge(N.concat(O)),function(a){return a.x})).range([0,E]);var P=n.selectAll("g.wrap.multiChart").data([l]),Q=P.enter().append("g").attr("class","wrap nvd3 multiChart").append("g");Q.append("g").attr("class","x axis"),Q.append("g").attr("class","y1 axis"),Q.append("g").attr("class","y2 axis"),Q.append("g").attr("class","lines1Wrap"),Q.append("g").attr("class","lines2Wrap"),Q.append("g").attr("class","bars1Wrap"),Q.append("g").attr("class","bars2Wrap"),Q.append("g").attr("class","stack1Wrap"),Q.append("g").attr("class","stack2Wrap"),Q.append("g").attr("class","legendWrap");var R=P.select("g"),S=l.map(function(a,b){return l[b].color||g(a,b)});j&&(B.color(S),B.width(E/2),R.select(".legendWrap").datum(l.map(function(a){return a.originalKey=void 0===a.originalKey?a.key:a.originalKey,a.key=a.originalKey+(1==a.yAxis?"":" (right axis)"),a})).call(B),f.top!=B.height()&&(f.top=B.height(),F=(i||parseInt(n.style("height"))||400)-f.top-f.bottom),R.select(".legendWrap").attr("transform","translate("+E/2+","+-f.top+")")),s.width(E).height(F).interpolate(p).color(S.filter(function(a,b){return!l[b].disabled&&1==l[b].yAxis&&"line"==l[b].type})),t.width(E).height(F).interpolate(p).color(S.filter(function(a,b){return!l[b].disabled&&2==l[b].yAxis&&"line"==l[b].type})),u.width(E).height(F).color(S.filter(function(a,b){return!l[b].disabled&&1==l[b].yAxis&&"bar"==l[b].type})),v.width(E).height(F).color(S.filter(function(a,b){return!l[b].disabled&&2==l[b].yAxis&&"bar"==l[b].type})),w.width(E).height(F).color(S.filter(function(a,b){return!l[b].disabled&&1==l[b].yAxis&&"area"==l[b].type})),x.width(E).height(F).color(S.filter(function(a,b){return!l[b].disabled&&2==l[b].yAxis&&"area"==l[b].type})),R.attr("transform","translate("+f.left+","+f.top+")");var T=R.select(".lines1Wrap").datum(G.filter(function(a){return!a.disabled})),U=R.select(".bars1Wrap").datum(I.filter(function(a){return!a.disabled})),V=R.select(".stack1Wrap").datum(K.filter(function(a){return!a.disabled})),W=R.select(".lines2Wrap").datum(H.filter(function(a){return!a.disabled})),X=R.select(".bars2Wrap").datum(J.filter(function(a){return!a.disabled})),Y=R.select(".stack2Wrap").datum(L.filter(function(a){return!a.disabled})),Z=K.length?K.map(function(a){return a.values}).reduce(function(a,b){return a.map(function(a,c){return{x:a.x,y:a.y+b[c].y}})}).concat([{x:0,y:0}]):[],$=L.length?L.map(function(a){return a.values}).reduce(function(a,b){return a.map(function(a,c){return{x:a.x,y:a.y+b[c].y}})}).concat([{x:0,y:0}]):[];q.domain(d||d3.extent(d3.merge(N).concat(Z),function(a){return a.y})).range([0,F]),r.domain(e||d3.extent(d3.merge(O).concat($),function(a){return a.y})).range([0,F]),s.yDomain(q.domain()),u.yDomain(q.domain()),w.yDomain(q.domain()),t.yDomain(r.domain()),v.yDomain(r.domain()),x.yDomain(r.domain()),K.length&&d3.transition(V).call(w),L.length&&d3.transition(Y).call(x),I.length&&d3.transition(U).call(u),J.length&&d3.transition(X).call(v),G.length&&d3.transition(T).call(s),H.length&&d3.transition(W).call(t),y.ticks(a.utils.calcTicksX(E/100,l)).tickSize(-F,0),R.select(".x.axis").attr("transform","translate(0,"+F+")"),d3.transition(R.select(".x.axis")).call(y),z.ticks(a.utils.calcTicksY(F/36,l)).tickSize(-E,0),d3.transition(R.select(".y1.axis")).call(z),A.ticks(a.utils.calcTicksY(F/36,l)).tickSize(-E,0),d3.transition(R.select(".y2.axis")).call(A),R.select(".y1.axis").classed("nv-disabled",N.length?!1:!0).attr("transform","translate("+c.range()[0]+",0)"),R.select(".y2.axis").classed("nv-disabled",O.length?!1:!0).attr("transform","translate("+c.range()[1]+",0)"),B.dispatch.on("stateChange",function(){b.update()}),C.on("tooltipShow",function(a){k&&D(a,o.parentNode)})}),b}var c,d,e,f={top:30,right:20,bottom:50,left:60},g=a.utils.defaultColor(),h=null,i=null,j=!0,k=!0,l=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" at "+b+"</p>"},m="No Data Available.",n=function(a){return a.x},o=function(a){return a.y},p="monotone",c=d3.scale.linear(),q=d3.scale.linear(),r=d3.scale.linear(),s=a.models.line().yScale(q),t=a.models.line().yScale(r),u=a.models.multiBar().stacked(!1).yScale(q),v=a.models.multiBar().stacked(!1).yScale(r),w=a.models.stackedArea().yScale(q),x=a.models.stackedArea().yScale(r),y=a.models.axis().scale(c).orient("bottom").tickPadding(5),z=a.models.axis().scale(q).orient("left"),A=a.models.axis().scale(r).orient("right"),B=a.models.legend().height(30),C=d3.dispatch("tooltipShow","tooltipHide"),D=function(c,d){var e=c.pos[0]+(d.offsetLeft||0),f=c.pos[1]+(d.offsetTop||0),g=y.tickFormat()(s.x()(c.point,c.pointIndex)),h=(2==c.series.yAxis?A:z).tickFormat()(s.y()(c.point,c.pointIndex)),i=l(c.series.key,g,h,c,b);
+a.tooltip.show([e,f],i,void 0,void 0,d.offsetParent)};return s.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],C.tooltipShow(a)}),s.dispatch.on("elementMouseout.tooltip",function(a){C.tooltipHide(a)}),t.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],C.tooltipShow(a)}),t.dispatch.on("elementMouseout.tooltip",function(a){C.tooltipHide(a)}),u.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],C.tooltipShow(a)}),u.dispatch.on("elementMouseout.tooltip",function(a){C.tooltipHide(a)}),v.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],C.tooltipShow(a)}),v.dispatch.on("elementMouseout.tooltip",function(a){C.tooltipHide(a)}),w.dispatch.on("tooltipShow",function(a){return Math.round(100*w.y()(a.point))?(a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],void C.tooltipShow(a)):(setTimeout(function(){d3.selectAll(".point.hover").classed("hover",!1)},0),!1)}),w.dispatch.on("tooltipHide",function(a){C.tooltipHide(a)}),x.dispatch.on("tooltipShow",function(a){return Math.round(100*x.y()(a.point))?(a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],void C.tooltipShow(a)):(setTimeout(function(){d3.selectAll(".point.hover").classed("hover",!1)},0),!1)}),x.dispatch.on("tooltipHide",function(a){C.tooltipHide(a)}),s.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],C.tooltipShow(a)}),s.dispatch.on("elementMouseout.tooltip",function(a){C.tooltipHide(a)}),t.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+f.left,a.pos[1]+f.top],C.tooltipShow(a)}),t.dispatch.on("elementMouseout.tooltip",function(a){C.tooltipHide(a)}),C.on("tooltipHide",function(){k&&a.tooltip.cleanup()}),b.dispatch=C,b.lines1=s,b.lines2=t,b.bars1=u,b.bars2=v,b.stack1=w,b.stack2=x,b.xAxis=y,b.yAxis1=z,b.yAxis2=A,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},showLegend:{get:function(){return j},set:function(a){j=a}},yDomain1:{get:function(){return d},set:function(a){d=a}},yDomain2:{get:function(){return e},set:function(a){e=a}},tooltips:{get:function(){return k},set:function(a){k=a}},tooltipContent:{get:function(){return l},set:function(a){l=a}},noData:{get:function(){return m},set:function(a){m=a}},interpolate:{get:function(){return p},set:function(a){p=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}},color:{get:function(){return g},set:function(b){g=a.utils.getColor(b)}},x:{get:function(){return n},set:function(a){n=a,s.x(a),u.x(a)}},y:{get:function(){return o},set:function(a){o=a,s.y(a),u.y(a)}}}),a.utils.initOptions(b),b},a.models.ohlcBar=function(){"use strict";function b(x){return x.each(function(b){var x=d3.select(this),z=(h||parseInt(x.style("width"))||960)-g.left-g.right,A=(i||parseInt(x.style("height"))||400)-g.top-g.bottom;a.utils.initSVG(x),k.domain(c||d3.extent(b[0].values.map(m).concat(s))),k.range(u?e||[.5*z/b[0].values.length,z*(b[0].values.length-.5)/b[0].values.length]:e||[0,z]),l.domain(d||[d3.min(b[0].values.map(r).concat(t)),d3.max(b[0].values.map(q).concat(t))]).range(f||[A,0]),k.domain()[0]===k.domain()[1]&&k.domain(k.domain()[0]?[k.domain()[0]-.01*k.domain()[0],k.domain()[1]+.01*k.domain()[1]]:[-1,1]),l.domain()[0]===l.domain()[1]&&l.domain(l.domain()[0]?[l.domain()[0]+.01*l.domain()[0],l.domain()[1]-.01*l.domain()[1]]:[-1,1]);var B=d3.select(this).selectAll("g.nv-wrap.nv-ohlcBar").data([b[0].values]),C=B.enter().append("g").attr("class","nvd3 nv-wrap nv-ohlcBar"),D=C.append("defs"),E=C.append("g"),F=B.select("g");E.append("g").attr("class","nv-ticks"),B.attr("transform","translate("+g.left+","+g.top+")"),x.on("click",function(a,b){y.chartClick({data:a,index:b,pos:d3.event,id:j})}),D.append("clipPath").attr("id","nv-chart-clip-path-"+j).append("rect"),B.select("#nv-chart-clip-path-"+j+" rect").attr("width",z).attr("height",A),F.attr("clip-path",v?"url(#nv-chart-clip-path-"+j+")":"");var G=B.select(".nv-ticks").selectAll(".nv-tick").data(function(a){return a});G.exit().remove();G.enter().append("path").attr("class",function(a,b,c){return(o(a,b)>p(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b}).attr("d",function(a,c){var d=z/b[0].values.length*.9;return"m0,0l0,"+(l(o(a,c))-l(q(a,c)))+"l"+-d/2+",0l"+d/2+",0l0,"+(l(r(a,c))-l(o(a,c)))+"l0,"+(l(p(a,c))-l(r(a,c)))+"l"+d/2+",0l"+-d/2+",0z"}).attr("transform",function(a,b){return"translate("+k(m(a,b))+","+l(q(a,b))+")"}).attr("fill",function(){return w[0]}).attr("stroke",function(){return w[0]}).attr("x",0).attr("y",function(a,b){return l(Math.max(0,n(a,b)))}).attr("height",function(a,b){return Math.abs(l(n(a,b))-l(0))});G.attr("class",function(a,b,c){return(o(a,b)>p(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b}),d3.transition(G).attr("transform",function(a,b){return"translate("+k(m(a,b))+","+l(q(a,b))+")"}).attr("d",function(a,c){var d=z/b[0].values.length*.9;return"m0,0l0,"+(l(o(a,c))-l(q(a,c)))+"l"+-d/2+",0l"+d/2+",0l0,"+(l(r(a,c))-l(o(a,c)))+"l0,"+(l(p(a,c))-l(r(a,c)))+"l"+d/2+",0l"+-d/2+",0z"})}),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=Math.floor(1e4*Math.random()),k=d3.scale.linear(),l=d3.scale.linear(),m=function(a){return a.x},n=function(a){return a.y},o=function(a){return a.open},p=function(a){return a.close},q=function(a){return a.high},r=function(a){return a.low},s=[],t=[],u=!1,v=!0,w=a.utils.defaultColor(),x=!1,y=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd","chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout");return b.highlightPoint=function(a,c){b.clearHighlights(),d3.select(".nv-ohlcBar .nv-tick-0-"+a).classed("hover",c)},b.clearHighlights=function(){d3.select(".nv-ohlcBar .nv-tick.hover").classed("hover",!1)},b.dispatch=y,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xScale:{get:function(){return k},set:function(a){k=a}},yScale:{get:function(){return l},set:function(a){l=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},forceX:{get:function(){return s},set:function(a){s=a}},forceY:{get:function(){return t},set:function(a){t=a}},padData:{get:function(){return u},set:function(a){u=a}},clipEdge:{get:function(){return v},set:function(a){v=a}},id:{get:function(){return j},set:function(a){j=a}},interactive:{get:function(){return x},set:function(a){x=a}},x:{get:function(){return m},set:function(a){m=a}},y:{get:function(){return n},set:function(a){n=a}},open:{get:function(){return o()},set:function(a){o=a}},close:{get:function(){return p()},set:function(a){p=a}},high:{get:function(){return q},set:function(a){q=a}},low:{get:function(){return r},set:function(a){r=a}},margin:{get:function(){return g},set:function(a){g.top=void 0!=a.top?a.top:g.top,g.right=void 0!=a.right?a.right:g.right,g.bottom=void 0!=a.bottom?a.bottom:g.bottom,g.left=void 0!=a.left?a.left:g.left}},color:{get:function(){return w},set:function(b){w=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.parallelCoordinates=function(){"use strict";function b(m){return m.each(function(m){function n(a){return y(h.map(function(b){return[f(b),g[b](a[b])]}))}function o(){var a=h.filter(function(a){return!g[a].brush.empty()}),b=a.map(function(a){return g[a].brush.extent()});j=[],a.forEach(function(a,c){j[c]={dimension:a,extent:b[c]}}),k=[],x.style("display",function(c){var d=a.every(function(a,d){return b[d][0]<=c[a]&&c[a]<=b[d][1]});return d&&k.push(c),d?null:"none"}),l.brush({filters:j,active:k})}var p=d3.select(this),q=(d||parseInt(p.style("width"))||960)-c.left-c.right,r=(e||parseInt(p.style("height"))||400)-c.top-c.bottom;a.utils.initSVG(p),k=m,b.update=function(){},f.rangePoints([0,q],1).domain(h),h.forEach(function(a){return g[a]=d3.scale.linear().domain(d3.extent(m,function(b){return+b[a]})).range([r,0]),g[a].brush=d3.svg.brush().y(g[a]).on("brush",o),"name"!=a});var s=p.selectAll("g.nv-wrap.nv-parallelCoordinates").data([m]),t=s.enter().append("g").attr("class","nvd3 nv-wrap nv-parallelCoordinates"),u=t.append("g"),v=s.select("g");u.append("g").attr("class","nv-parallelCoordinatesWrap"),s.attr("transform","translate("+c.left+","+c.top+")");var w,x,y=d3.svg.line(),z=d3.svg.axis().orient("left");w=u.append("g").attr("class","background").selectAll("path").data(m).enter().append("path").attr("d",n),x=u.append("g").attr("class","foreground").selectAll("path").data(m).enter().append("path").attr("d",n).attr("stroke",i);var A=v.selectAll(".dimension").data(h).enter().append("g").attr("class","dimension").attr("transform",function(a){return"translate("+f(a)+",0)"});A.append("g").attr("class","axis").each(function(a){d3.select(this).call(z.scale(g[a]))}).append("text").attr("text-anchor","middle").attr("y",-9).text(String),A.append("g").attr("class","brush").each(function(a){d3.select(this).call(g[a].brush)}).selectAll("rect").attr("x",-8).attr("width",16)}),b}var c={top:30,right:10,bottom:10,left:10},d=null,e=null,f=d3.scale.ordinal(),g={},h=[],i=a.utils.defaultColor(),j=[],k=[],l=d3.dispatch("brush");return b.dispatch=l,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},dimensions:{get:function(){return h},set:function(a){h=a}},margin:{get:function(){return c},set:function(a){c.top="undefined"!=typeof a.top?a.top:c.top,c.right="undefined"!=typeof a.right?a.right:c.right,c.bottom="undefined"!=typeof a.bottom?a.bottom:c.bottom,c.left="undefined"!=typeof a.left?a.left:c.left}},color:{get:function(){return i},set:function(b){i=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.pie=function(){"use strict";function b(k){return C.reset(),k.each(function(b){function k(a){a.endAngle=isNaN(a.endAngle)?0:a.endAngle,a.startAngle=isNaN(a.startAngle)?0:a.startAngle,r||(a.innerRadius=0);var b=d3.interpolate(this._current,a);return this._current=b(0),function(a){return N(b(a))}}var D=e-c.left-c.right,E=f-c.top-c.bottom,F=Math.min(D,E)/2,G=F-F/5,H=d3.select(this);a.utils.initSVG(H);var I=H.selectAll(".nv-wrap.nv-pie").data(b),J=I.enter().append("g").attr("class","nvd3 nv-wrap nv-pie nv-chart-"+i),K=J.append("g"),L=I.select("g"),M=K.append("g").attr("class","nv-pie");K.append("g").attr("class","nv-pieLabels"),I.attr("transform","translate("+c.left+","+c.top+")"),L.select(".nv-pie").attr("transform","translate("+D/2+","+E/2+")"),L.select(".nv-pieLabels").attr("transform","translate("+D/2+","+E/2+")"),H.on("click",function(a,b){B.chartClick({data:a,index:b,pos:d3.event,id:i})});var N=d3.svg.arc().outerRadius(G),O=d3.svg.arc().outerRadius(G+5);w&&(N.startAngle(w),O.startAngle(w)),y&&(N.endAngle(y),O.endAngle(y)),r&&(N.innerRadius(F*A),O.innerRadius(F*A));var P=d3.layout.pie().sort(null).value(function(a){return a.disabled?0:h(a)});if(P.padAngle&&x&&P.padAngle(x),N.cornerRadius&&z&&(N.cornerRadius(z),O.cornerRadius(z)),r&&s){var Q=M.append("g").attr("class","nv-pie");Q.append("text").style("text-anchor","middle").attr("class","nv-pie-title").text(function(){return s}).attr("dy","0.35em").attr("transform",function(){return"translate(0, "+u+")"})}var R=I.select(".nv-pie").selectAll(".nv-slice").data(P),S=I.select(".nv-pieLabels").selectAll(".nv-label").data(P);R.exit().remove(),S.exit().remove();var T=R.enter().append("g");T.attr("class","nv-slice"),T.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),t&&d3.select(this).select("path").transition().duration(70).attr("d",O),B.elementMouseover({label:g(a.data),value:h(a.data),point:a.data,pointIndex:b,pos:[d3.event.pageX,d3.event.pageY],id:i,color:d3.select(this).style("fill")})}),T.on("mouseout",function(a,b){d3.select(this).classed("hover",!1),t&&d3.select(this).select("path").transition().duration(50).attr("d",N),B.elementMouseout({label:g(a.data),value:h(a.data),point:a.data,index:b,id:i})}),R.attr("fill",function(a,b){return j(a,b)}),R.attr("stroke",function(a,b){return j(a,b)});var U=T.append("path").each(function(a){this._current=a});if(U.on("click",function(a,b){B.elementClick({label:g(a.data),value:h(a.data),point:a.data,index:b,pos:d3.event,id:i}),d3.event.stopPropagation()}),U.on("dblclick",function(a,b){B.elementDblClick({label:g(a.data),value:h(a.data),point:a.data,index:b,pos:d3.event,id:i}),d3.event.stopPropagation()}),R.select("path").transition().attr("d",N).attrTween("d",k),m){var V=d3.svg.arc().innerRadius(0);if(n)var V=N;o&&(V=d3.svg.arc().outerRadius(N.outerRadius())),S.enter().append("g").classed("nv-label",!0).each(function(a){var b=d3.select(this);b.attr("transform",function(a){if(v){a.outerRadius=G+10,a.innerRadius=G+15;var b=(a.startAngle+a.endAngle)/2*(180/Math.PI);return(a.startAngle+a.endAngle)/2<Math.PI?b-=90:b+=90,"translate("+V.centroid(a)+") rotate("+b+")"}return a.outerRadius=F+10,a.innerRadius=F+15,"translate("+V.centroid(a)+")"}),b.append("rect").style("stroke","#fff").style("fill","#fff").attr("rx",3).attr("ry",3),b.append("text").style("text-anchor",v?(a.startAngle+a.endAngle)/2<Math.PI?"start":"end":"middle").style("fill","#000")});var W={},X=14,Y=140,Z=function(a){return Math.floor(a[0]/Y)*Y+","+Math.floor(a[1]/X)*X};S.watchTransition(C,"pie labels").attr("transform",function(a){if(v){a.outerRadius=G+10,a.innerRadius=G+15;var b=(a.startAngle+a.endAngle)/2*(180/Math.PI);return(a.startAngle+a.endAngle)/2<Math.PI?b-=90:b+=90,"translate("+V.centroid(a)+") rotate("+b+")"}a.outerRadius=F+10,a.innerRadius=F+15;var c=V.centroid(a);if(a.value){var d=Z(c);W[d]&&(c[1]-=X),W[Z(c)]=!0}return"translate("+c+")"}),S.select(".nv-label text").style("text-anchor",v?(d.startAngle+d.endAngle)/2<Math.PI?"start":"end":"middle").text(function(a){var b=(a.endAngle-a.startAngle)/(2*Math.PI),c={key:g(a.data),value:h(a.data),percent:l(b)};return a.value&&b>q?c[p]:""})}}),C.renderEnd("pie immediate"),b}var c={top:0,right:0,bottom:0,left:0},e=500,f=500,g=function(a){return a.x},h=function(a){return a.y},i=Math.floor(1e4*Math.random()),j=a.utils.defaultColor(),k=d3.format(",.2f"),l=d3.format("%"),m=!0,n=!0,o=!1,p="key",q=.02,r=!1,s=!1,t=!0,u=0,v=!1,w=!1,x=!1,y=!1,z=0,A=.5,B=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),C=a.utils.renderWatch(B);return b.dispatch=B,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return e},set:function(a){e=a}},height:{get:function(){return f},set:function(a){f=a}},showLabels:{get:function(){return m},set:function(a){m=a}},title:{get:function(){return s},set:function(a){s=a}},titleOffset:{get:function(){return u},set:function(a){u=a}},labelThreshold:{get:function(){return q},set:function(a){q=a}},labelFormat:{get:function(){return l},set:function(a){l=a}},valueFormat:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return g},set:function(a){g=a}},id:{get:function(){return i},set:function(a){i=a}},endAngle:{get:function(){return y},set:function(a){y=a}},startAngle:{get:function(){return w},set:function(a){w=a}},padAngle:{get:function(){return x},set:function(a){x=a}},cornerRadius:{get:function(){return z},set:function(a){z=a}},donutRatio:{get:function(){return A},set:function(a){A=a}},pieLabelsOutside:{get:function(){return n},set:function(a){n=a}},donutLabelsOutside:{get:function(){return o},set:function(a){o=a}},labelSunbeamLayout:{get:function(){return v},set:function(a){v=a}},donut:{get:function(){return r},set:function(a){r=a}},growOnHover:{get:function(){return t},set:function(a){t=a}},margin:{get:function(){return c},set:function(a){c.top="undefined"!=typeof a.top?a.top:c.top,c.right="undefined"!=typeof a.right?a.right:c.right,c.bottom="undefined"!=typeof a.bottom?a.bottom:c.bottom,c.left="undefined"!=typeof a.left?a.left:c.left}},y:{get:function(){return h},set:function(a){h=d3.functor(a)}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}},labelType:{get:function(){return p},set:function(a){p=a||"key"}}}),a.utils.initOptions(b),b},a.models.pieChart=function(){"use strict";function b(i){return r.reset(),r.models(c),i.each(function(i){var j=d3.select(this);a.utils.initSVG(j);var k=(f||parseInt(j.style("width"),10)||960)-e.left-e.right,o=(g||parseInt(j.style("height"),10)||400)-e.top-e.bottom;if(b.update=function(){j.transition().call(b)},b.container=this,l.setter(t(i),b.update).getter(s(i)).update(),l.disabled=i.map(function(a){return!!a.disabled}),!m){var q;m={};for(q in l)m[q]=l[q]instanceof Array?l[q].slice(0):l[q]}if(!i||!i.length){var r=j.selectAll(".nv-noData").data([n]);return r.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),r.attr("x",e.left+k/2).attr("y",e.top+o/2).text(function(a){return a}),b}j.selectAll(".nv-noData").remove();var u=j.selectAll("g.nv-wrap.nv-pieChart").data([i]),v=u.enter().append("g").attr("class","nvd3 nv-wrap nv-pieChart").append("g"),w=u.select("g");v.append("g").attr("class","nv-pieWrap"),v.append("g").attr("class","nv-legendWrap"),h&&(d.width(k).key(c.x()),u.select(".nv-legendWrap").datum(i).call(d),e.top!=d.height()&&(e.top=d.height(),o=(g||parseInt(j.style("height"))||400)-e.top-e.bottom),u.select(".nv-legendWrap").attr("transform","translate(0,"+-e.top+")")),u.attr("transform","translate("+e.left+","+e.top+")"),c.width(k).height(o);var x=w.select(".nv-pieWrap").datum([i]);d3.transition(x).call(c),d.dispatch.on("stateChange",function(a){for(var c in a)l[c]=a[c];p.stateChange(l),b.update()}),c.dispatch.on("elementMouseout.tooltip",function(a){p.tooltipHide(a)}),p.on("changeState",function(a){"undefined"!=typeof a.disabled&&(i.forEach(function(b,c){b.disabled=a.disabled[c]}),l.disabled=a.disabled),b.update()})}),r.renderEnd("pieChart immediate"),b}var c=a.models.pie(),d=a.models.legend(),e={top:30,right:20,bottom:20,left:20},f=null,g=null,h=!0,i=a.utils.defaultColor(),j=!0,k=function(a,b,c){return'<h3 style="background-color: '+c.color+'">'+a+"</h3><p>"+b+"</p>"},l=a.utils.state(),m=null,n="No Data Available.",o=250,p=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),q=function(d,e){var f=c.x()(d.point),g=d.pos[0]+(e&&e.offsetLeft||0),h=d.pos[1]+(e&&e.offsetTop||0),i=c.valueFormat()(c.y()(d.point)),j=k(f,i,d,b);a.tooltip.show([g,h],j,d.value<0?"n":"s",null,e)},r=a.utils.renderWatch(p),s=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},t=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return c.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+e.left,a.pos[1]+e.top],p.tooltipShow(a)}),p.on("tooltipShow",function(a){j&&q(a)}),p.on("tooltipHide",function(){j&&a.tooltip.cleanup()}),b.legend=d,b.dispatch=p,b.pie=c,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{noData:{get:function(){return n},set:function(a){n=a}},tooltipContent:{get:function(){return k},set:function(a){k=a}},tooltips:{get:function(){return j},set:function(a){j=a}},showLegend:{get:function(){return h},set:function(a){h=a}},defaultState:{get:function(){return m},set:function(a){m=a}},color:{get:function(){return i},set:function(a){i=a,d.color(i),c.color(i)}},duration:{get:function(){return o},set:function(a){o=a,r.reset(o)}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.scatter=function(){"use strict";function b(L){return N.reset(),L.each(function(b){function L(){if(!v)return!1;var a=d3.merge(b.map(function(a,b){return a.values.map(function(a,c){var d=o(a,c),e=p(a,c);return[l(d)+1e-7*Math.random(),m(e)+1e-7*Math.random(),b,c,a]}).filter(function(a,b){return w(a[4],b)})}));if(K===!0){a.length<3&&(a.push([l.range()[0]-20,m.range()[0]-20,null,null]),a.push([l.range()[1]+20,m.range()[1]+20,null,null]),a.push([l.range()[0]-20,m.range()[0]+20,null,null]),a.push([l.range()[1]+20,m.range()[1]-20,null,null]));var c=d3.geom.polygon([[-10,-10],[-10,i+10],[h+10,i+10],[h+10,-10]]),d=d3.geom.voronoi(a).map(function(b,d){return{data:c.clip(b),series:a[d][2],point:a[d][3]}});S.select(".nv-point-paths").selectAll("path").remove();var e=S.select(".nv-point-paths").selectAll("path").data(d);if(e.enter().append("svg:path").attr("d",function(a){return a&&a.data&&0!==a.data.length?"M"+a.data.join(",")+"Z":"M 0 0"}).attr("id",function(a,b){return"nv-path-"+b}).attr("clip-path",function(a,b){return"url(#nv-clip-"+b+")"}),A){var f=S.append("svg:g").attr("id","nv-point-clips");f.selectAll("clipPath").data(a).enter().append("svg:clipPath").attr("id",function(a,b){return"nv-clip-"+b}).append("svg:circle").attr("cx",function(a){return a[0]}).attr("cy",function(a){return a[1]}).attr("r",B)}var j=function(a,c){if(M)return 0;var d=b[a.series];if("undefined"!=typeof d){var e=d.values[a.point];c({point:e,series:d,pos:[l(o(e,a.point))+g.left,m(p(e,a.point))+g.top],seriesIndex:a.series,pointIndex:a.point})}};e.on("click",function(a){j(a,J.elementClick)}).on("dblclick",function(a){j(a,J.elementDblClick)}).on("mouseover",function(a){j(a,J.elementMouseover)}).on("mouseout",function(a){j(a,J.elementMouseout)})}else S.select(".nv-groups").selectAll(".nv-group").selectAll(".nv-point").on("click",function(a,c){if(M||!b[a.series])return 0;var d=b[a.series],e=d.values[c];J.elementClick({point:e,series:d,pos:[l(o(e,c))+g.left,m(p(e,c))+g.top],seriesIndex:a.series,pointIndex:c})}).on("mouseover",function(a,c){if(M||!b[a.series])return 0;var d=b[a.series],e=d.values[c];J.elementMouseover({point:e,series:d,pos:[l(o(e,c))+g.left,m(p(e,c))+g.top],seriesIndex:a.series,pointIndex:c})}).on("mouseout",function(a,c){if(M||!b[a.series])return 0;var d=b[a.series],e=d.values[c];J.elementMouseout({point:e,series:d,seriesIndex:a.series,pointIndex:c})});M=!1}var O=d3.select(this),P=(h||parseInt(O.style("width"))||960)-g.left-g.right,Q=(i||parseInt(O.style("height"))||400)-g.top-g.bottom;a.utils.initSVG(O),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})});var R=C&&D&&G?[]:d3.merge(b.map(function(a){return a.values.map(function(a,b){return{x:o(a,b),y:p(a,b),size:q(a,b)}})}));l.domain(C||d3.extent(R.map(function(a){return a.x}).concat(s))),l.range(x&&b[0]?E||[(P*y+P)/(2*b[0].values.length),P-P*(1+y)/(2*b[0].values.length)]:E||[0,P]),m.domain(D||d3.extent(R.map(function(a){return a.y}).concat(t))).range(F||[Q,0]),n.domain(G||d3.extent(R.map(function(a){return a.size}).concat(u))).range(H||[16,256]),(l.domain()[0]===l.domain()[1]||m.domain()[0]===m.domain()[1])&&(I=!0),l.domain()[0]===l.domain()[1]&&l.domain(l.domain()[0]?[l.domain()[0]-.01*l.domain()[0],l.domain()[1]+.01*l.domain()[1]]:[-1,1]),m.domain()[0]===m.domain()[1]&&m.domain(m.domain()[0]?[m.domain()[0]-.01*m.domain()[0],m.domain()[1]+.01*m.domain()[1]]:[-1,1]),isNaN(l.domain()[0])&&l.domain([-1,1]),isNaN(m.domain()[0])&&m.domain([-1,1]),c=c||l,d=d||m,e=e||n;var S=O.selectAll("g.nv-wrap.nv-scatter").data([b]),T=S.enter().append("g").attr("class","nvd3 nv-wrap nv-scatter nv-chart-"+k+(I?" nv-single-point":"")),U=T.append("defs"),V=T.append("g"),W=S.select("g");V.append("g").attr("class","nv-groups"),V.append("g").attr("class","nv-point-paths"),S.attr("transform","translate("+g.left+","+g.top+")"),U.append("clipPath").attr("id","nv-edge-clip-"+k).append("rect"),S.select("#nv-edge-clip-"+k+" rect").attr("width",P).attr("height",Q>0?Q:0),W.attr("clip-path",z?"url(#nv-edge-clip-"+k+")":""),M=!0;var X=S.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});X.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),X.exit().remove(),X.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}),X.watchTransition(N,"scatter: groups").style("fill",function(a,b){return j(a,b)}).style("stroke",function(a,b){return j(a,b)}).style("stroke-opacity",1).style("fill-opacity",.5);var Y=X.selectAll("path.nv-point").data(function(a){return a.values});Y.enter().append("path").style("fill",function(a){return a.color}).style("stroke",function(a){return a.color}).attr("transform",function(a,b){return"translate("+c(o(a,b))+","+d(p(a,b))+")"}).attr("d",a.utils.symbol().type(r).size(function(a,b){return n(q(a,b))})),Y.exit().remove(),X.exit().selectAll("path.nv-point").watchTransition(N,"scatter exit").attr("transform",function(a,b){return"translate("+l(o(a,b))+","+m(p(a,b))+")"}).remove(),Y.each(function(a,b){d3.select(this).classed("nv-point",!0).classed("nv-point-"+b,!0).classed("hover",!1)}),Y.watchTransition(N,"scatter points").attr("transform",function(a,b){return"translate("+l(o(a,b))+","+m(p(a,b))+")"}).attr("d",a.utils.symbol().type(r).size(function(a,b){return n(q(a,b))})),clearTimeout(f),f=setTimeout(L,300),c=l.copy(),d=m.copy(),e=n.copy()}),N.renderEnd("scatter immediate"),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=a.utils.defaultColor(),k=Math.floor(1e5*Math.random()),l=d3.scale.linear(),m=d3.scale.linear(),n=d3.scale.linear(),o=function(a){return a.x},p=function(a){return a.y},q=function(a){return a.size||1},r=function(a){return a.shape||"circle"},s=[],t=[],u=[],v=!0,w=function(a){return!a.notActive},x=!1,y=.1,z=!1,A=!0,B=function(){return 25},C=null,D=null,E=null,F=null,G=null,H=null,I=!1,J=d3.dispatch("elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),K=!0,L=250,M=!1,N=a.utils.renderWatch(J,L);return b.dispatch=J,b.options=a.utils.optionsFunc.bind(b),b._calls=new function(){this.clearHighlights=function(){return d3.selectAll(".nv-chart-"+k+" .nv-point.hover").classed("hover",!1),null},this.highlightPoint=function(a,b,c){d3.select(".nv-chart-"+k+" .nv-series-"+a+" .nv-point-"+b).classed("hover",c)}},J.on("elementMouseover.point",function(a){v&&b._calls.highlightPoint(a.seriesIndex,a.pointIndex,!0)}),J.on("elementMouseout.point",function(a){v&&b._calls.highlightPoint(a.seriesIndex,a.pointIndex,!1)}),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},pointScale:{get:function(){return n},set:function(a){n=a}},xDomain:{get:function(){return C},set:function(a){C=a}},yDomain:{get:function(){return D},set:function(a){D=a}},pointDomain:{get:function(){return G},set:function(a){G=a}},xRange:{get:function(){return E},set:function(a){E=a}},yRange:{get:function(){return F},set:function(a){F=a}},pointRange:{get:function(){return H},set:function(a){H=a}},forceX:{get:function(){return s},set:function(a){s=a}},forceY:{get:function(){return t},set:function(a){t=a}},forcePoint:{get:function(){return u},set:function(a){u=a}},interactive:{get:function(){return v},set:function(a){v=a}},pointActive:{get:function(){return w},set:function(a){w=a}},padDataOuter:{get:function(){return y},set:function(a){y=a}},padData:{get:function(){return x},set:function(a){x=a}},clipEdge:{get:function(){return z},set:function(a){z=a}},clipVoronoi:{get:function(){return A},set:function(a){A=a}},clipRadius:{get:function(){return B},set:function(a){B=a}},id:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return o},set:function(a){o=d3.functor(a)}},y:{get:function(){return p},set:function(a){p=d3.functor(a)}},pointSize:{get:function(){return q},set:function(a){q=d3.functor(a)}},pointShape:{get:function(){return r},set:function(a){r=d3.functor(a)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},duration:{get:function(){return L},set:function(a){L=a,N.reset(L)}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}},useVoronoi:{get:function(){return K},set:function(a){K=a,K===!1&&(A=!1)}}}),a.utils.initOptions(b),b},a.models.scatterChart=function(){"use strict";function b(v){return F.reset(),F.models(c),r&&F.models(d),s&&F.models(e),o&&F.models(g),p&&F.models(h),v.each(function(v){var w=d3.select(this),x=this;a.utils.initSVG(w);var J=(j||parseInt(w.style("width"))||960)-i.left-i.right,K=(k||parseInt(w.style("height"))||400)-i.top-i.bottom;if(b.update=function(){0===C?w.call(b):w.transition().duration(C).call(b)},b.container=this,y.setter(I(v),b.update).getter(H(v)).update(),y.disabled=v.map(function(a){return!!a.disabled}),!z){var L;z={};for(L in y)z[L]=y[L]instanceof Array?y[L].slice(0):y[L]}if(!(v&&v.length&&v.filter(function(a){return a.values.length}).length)){var M=w.selectAll(".nv-noData").data([B]);return M.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),M.attr("x",i.left+J/2).attr("y",i.top+K/2).text(function(a){return a}),F.renderEnd("scatter immediate"),b}w.selectAll(".nv-noData").remove(),m=c.xScale(),n=c.yScale();var N=w.selectAll("g.nv-wrap.nv-scatterChart").data([v]),O=N.enter().append("g").attr("class","nvd3 nv-wrap nv-scatterChart nv-chart-"+c.id()),P=O.append("g"),Q=N.select("g");P.append("rect").attr("class","nvd3 nv-background").style("pointer-events","none"),P.append("g").attr("class","nv-x nv-axis"),P.append("g").attr("class","nv-y nv-axis"),P.append("g").attr("class","nv-scatterWrap"),P.append("g").attr("class","nv-regressionLinesWrap"),P.append("g").attr("class","nv-distWrap"),P.append("g").attr("class","nv-legendWrap"),N.attr("transform","translate("+i.left+","+i.top+")"),t&&Q.select(".nv-y.nv-axis").attr("transform","translate("+J+",0)"),q&&(f.width(J/2),N.select(".nv-legendWrap").datum(v).call(f),i.top!=f.height()&&(i.top=f.height(),K=(k||parseInt(w.style("height"))||400)-i.top-i.bottom),N.select(".nv-legendWrap").attr("transform","translate("+J/2+","+-i.top+")")),c.width(J).height(K).color(v.map(function(a,b){return a.color||l(a,b)}).filter(function(a,b){return!v[b].disabled})),N.select(".nv-scatterWrap").datum(v.filter(function(a){return!a.disabled})).call(c),N.select(".nv-regressionLinesWrap").attr("clip-path","url(#nv-edge-clip-"+c.id()+")");var R=N.select(".nv-regressionLinesWrap").selectAll(".nv-regLines").data(function(a){return a});R.enter().append("g").attr("class","nv-regLines");var S=R.selectAll(".nv-regLine").data(function(a){return[a]});S.enter().append("line").attr("class","nv-regLine").style("stroke-opacity",0),S.filter(function(a){return a.intercept&&a.slope}).watchTransition(F,"scatterPlusLineChart: regline").attr("x1",m.range()[0]).attr("x2",m.range()[1]).attr("y1",function(a){return n(m.domain()[0]*a.slope+a.intercept)}).attr("y2",function(a){return n(m.domain()[1]*a.slope+a.intercept)}).style("stroke",function(a,b,c){return l(a,c)}).style("stroke-opacity",function(a){return a.disabled||"undefined"==typeof a.slope||"undefined"==typeof a.intercept?0:1}),r&&(d.scale(m).ticks(d.ticks()?d.ticks():a.utils.calcTicksX(J/100,v)).tickSize(-K,0),Q.select(".nv-x.nv-axis").attr("transform","translate(0,"+n.range()[0]+")").call(d)),s&&(e.scale(n).ticks(e.ticks()?e.ticks():a.utils.calcTicksY(K/36,v)).tickSize(-J,0),Q.select(".nv-y.nv-axis").call(e)),o&&(g.getData(c.x()).scale(m).width(J).color(v.map(function(a,b){return a.color||l(a,b)}).filter(function(a,b){return!v[b].disabled})),P.select(".nv-distWrap").append("g").attr("class","nv-distributionX"),Q.select(".nv-distributionX").attr("transform","translate(0,"+n.range()[0]+")").datum(v.filter(function(a){return!a.disabled})).call(g)),p&&(h.getData(c.y()).scale(n).width(K).color(v.map(function(a,b){return a.color||l(a,b)}).filter(function(a,b){return!v[b].disabled})),P.select(".nv-distWrap").append("g").attr("class","nv-distributionY"),Q.select(".nv-distributionY").attr("transform","translate("+(t?J:-h.size())+",0)").datum(v.filter(function(a){return!a.disabled
+})).call(h)),f.dispatch.on("stateChange",function(a){for(var c in a)y[c]=a[c];A.stateChange(y),b.update()}),c.dispatch.on("elementMouseover.tooltip",function(a){d3.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-distx-"+a.pointIndex).attr("y1",a.pos[1]-K),d3.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-disty-"+a.pointIndex).attr("x2",a.pos[0]+g.size()),a.pos=[a.pos[0]+i.left,a.pos[1]+i.top],A.tooltipShow(a)}),A.on("tooltipShow",function(a){u&&G(a,x.parentNode)}),A.on("changeState",function(a){"undefined"!=typeof a.disabled&&(v.forEach(function(b,c){b.disabled=a.disabled[c]}),y.disabled=a.disabled),b.update()}),D=m.copy(),E=n.copy()}),F.renderEnd("scatter with line immediate"),b}var c=a.models.scatter(),d=a.models.axis(),e=a.models.axis(),f=a.models.legend(),g=a.models.distribution(),h=a.models.distribution(),i={top:30,right:20,bottom:50,left:75},j=null,k=null,l=a.utils.defaultColor(),m=c.xScale(),n=c.yScale(),o=!1,p=!1,q=!0,r=!0,s=!0,t=!1,u=!0,v=function(a,b){return"<strong>"+b+"</strong>"},w=function(a,b,c){return"<strong>"+c+"</strong>"},x=function(a,b,c,d){return"<h3>"+a+"</h3><p>"+d+"</p>"},y=a.utils.state(),z=null,A=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),B="No Data Available.",C=250;c.xScale(m).yScale(n),d.orient("bottom").tickPadding(10),e.orient(t?"right":"left").tickPadding(10),g.axis("x"),h.axis("y");var D,E,F=a.utils.renderWatch(A,C),G=function(f,g){var h=f.pos[0]+(g.offsetLeft||0),j=f.pos[1]+(g.offsetTop||0),k=f.pos[0]+(g.offsetLeft||0),l=n.range()[0]+i.top+(g.offsetTop||0),o=m.range()[0]+i.left+(g.offsetLeft||0),p=f.pos[1]+(g.offsetTop||0),q=d.tickFormat()(c.x()(f.point,f.pointIndex)),r=e.tickFormat()(c.y()(f.point,f.pointIndex));null!=v&&a.tooltip.show([k,l],v(f.series.key,q,r,f,b),"n",1,g,"x-nvtooltip"),null!=w&&a.tooltip.show([o,p],w(f.series.key,q,r,f,b),"e",1,g,"y-nvtooltip"),null!=x&&a.tooltip.show([h,j],x(f.series.key,q,r,f.point.tooltip,f,b),f.value<0?"n":"s",null,g)},H=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},I=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return c.dispatch.on("elementMouseout.tooltip",function(a){A.tooltipHide(a),d3.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-distx-"+a.pointIndex).attr("y1",0),d3.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-disty-"+a.pointIndex).attr("x2",h.size())}),A.on("tooltipHide",function(){u&&a.tooltip.cleanup()}),b.dispatch=A,b.scatter=c,b.legend=f,b.xAxis=d,b.yAxis=e,b.distX=g,b.distY=h,b._options=Object.create({},{width:{get:function(){return j},set:function(a){j=a}},height:{get:function(){return k},set:function(a){k=a}},showDistX:{get:function(){return o},set:function(a){o=a}},showDistY:{get:function(){return p},set:function(a){p=a}},showLegend:{get:function(){return q},set:function(a){q=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},tooltips:{get:function(){return u},set:function(a){u=a}},tooltipContent:{get:function(){return x},set:function(a){x=a}},tooltipXContent:{get:function(){return v},set:function(a){v=a}},tooltipYContent:{get:function(){return w},set:function(a){w=a}},defaultState:{get:function(){return z},set:function(a){z=a}},noData:{get:function(){return B},set:function(a){B=a}},duration:{get:function(){return C},set:function(a){C=a}},margin:{get:function(){return i},set:function(a){i.top=void 0!==a.top?a.top:i.top,i.right=void 0!==a.right?a.right:i.right,i.bottom=void 0!==a.bottom?a.bottom:i.bottom,i.left=void 0!==a.left?a.left:i.left}},rightAlignYAxis:{get:function(){return t},set:function(a){t=a,e.orient(a?"right":"left")}},color:{get:function(){return l},set:function(b){l=a.utils.getColor(b),f.color(l),g.color(l),h.color(l)}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.sparkline=function(){"use strict";function b(j){return j.each(function(b){var j=h-g.left-g.right,p=i-g.top-g.bottom,q=d3.select(this);a.utils.initSVG(q),k.domain(c||d3.extent(b,m)).range(e||[0,j]),l.domain(d||d3.extent(b,n)).range(f||[p,0]);{var r=q.selectAll("g.nv-wrap.nv-sparkline").data([b]),s=r.enter().append("g").attr("class","nvd3 nv-wrap nv-sparkline");s.append("g"),r.select("g")}r.attr("transform","translate("+g.left+","+g.top+")");var t=r.selectAll("path").data(function(a){return[a]});t.enter().append("path"),t.exit().remove(),t.style("stroke",function(a,b){return a.color||o(a,b)}).attr("d",d3.svg.line().x(function(a,b){return k(m(a,b))}).y(function(a,b){return l(n(a,b))}));var u=r.selectAll("circle.nv-point").data(function(a){function b(b){if(-1!=b){var c=a[b];return c.pointIndex=b,c}return null}var c=a.map(function(a,b){return n(a,b)}),d=b(c.lastIndexOf(l.domain()[1])),e=b(c.indexOf(l.domain()[0])),f=b(c.length-1);return[e,d,f].filter(function(a){return null!=a})});u.enter().append("circle"),u.exit().remove(),u.attr("cx",function(a){return k(m(a,a.pointIndex))}).attr("cy",function(a){return l(n(a,a.pointIndex))}).attr("r",2).attr("class",function(a){return m(a,a.pointIndex)==k.domain()[1]?"nv-point nv-currentValue":n(a,a.pointIndex)==l.domain()[0]?"nv-point nv-minValue":"nv-point nv-maxValue"})}),b}var c,d,e,f,g={top:2,right:0,bottom:2,left:0},h=400,i=32,j=!0,k=d3.scale.linear(),l=d3.scale.linear(),m=function(a){return a.x},n=function(a){return a.y},o=a.utils.getColor(["#000"]);return b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},xScale:{get:function(){return k},set:function(a){k=a}},yScale:{get:function(){return l},set:function(a){l=a}},animate:{get:function(){return j},set:function(a){j=a}},x:{get:function(){return m},set:function(a){m=d3.functor(a)}},y:{get:function(){return n},set:function(a){n=d3.functor(a)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},color:{get:function(){return o},set:function(b){o=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.sparklinePlus=function(){"use strict";function b(m){return m.each(function(q){function r(){if(!j){var a=B.selectAll(".nv-hoverValue").data(i),b=a.enter().append("g").attr("class","nv-hoverValue").style("stroke-opacity",0).style("fill-opacity",0);a.exit().transition().duration(250).style("stroke-opacity",0).style("fill-opacity",0).remove(),a.attr("transform",function(a){return"translate("+c(e.x()(q[a],a))+",0)"}).transition().duration(250).style("stroke-opacity",1).style("fill-opacity",1),i.length&&(b.append("line").attr("x1",0).attr("y1",-f.top).attr("x2",0).attr("y2",v),b.append("text").attr("class","nv-xValue").attr("x",-6).attr("y",-f.top).attr("text-anchor","end").attr("dy",".9em"),B.select(".nv-hoverValue .nv-xValue").text(k(e.x()(q[i[0]],i[0]))),b.append("text").attr("class","nv-yValue").attr("x",6).attr("y",-f.top).attr("text-anchor","start").attr("dy",".9em"),B.select(".nv-hoverValue .nv-yValue").text(l(e.y()(q[i[0]],i[0]))))}}function s(){function a(a,b){for(var c=Math.abs(e.x()(a[0],0)-b),d=0,f=0;f<a.length;f++)Math.abs(e.x()(a[f],f)-b)<c&&(c=Math.abs(e.x()(a[f],f)-b),d=f);return d}if(!j){var b=d3.mouse(this)[0]-f.left;i=[a(q,Math.round(c.invert(b)))],r()}}var t=d3.select(this);a.utils.initSVG(t);var u=(g||parseInt(t.style("width"))||960)-f.left-f.right,v=(h||parseInt(t.style("height"))||400)-f.top-f.bottom;if(b.update=function(){b(m)},b.container=this,!q||!q.length){var w=t.selectAll(".nv-noData").data([p]);return w.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),w.attr("x",f.left+u/2).attr("y",f.top+v/2).text(function(a){return a}),b}t.selectAll(".nv-noData").remove();var x=e.y()(q[q.length-1],q.length-1);c=e.xScale(),d=e.yScale();var y=t.selectAll("g.nv-wrap.nv-sparklineplus").data([q]),z=y.enter().append("g").attr("class","nvd3 nv-wrap nv-sparklineplus"),A=z.append("g"),B=y.select("g");A.append("g").attr("class","nv-sparklineWrap"),A.append("g").attr("class","nv-valueWrap"),A.append("g").attr("class","nv-hoverArea"),y.attr("transform","translate("+f.left+","+f.top+")");var C=B.select(".nv-sparklineWrap");e.width(u).height(v),C.call(e);var D=B.select(".nv-valueWrap"),E=D.selectAll(".nv-currentValue").data([x]);E.enter().append("text").attr("class","nv-currentValue").attr("dx",o?-8:8).attr("dy",".9em").style("text-anchor",o?"end":"start"),E.attr("x",u+(o?f.right:0)).attr("y",n?function(a){return d(a)}:0).style("fill",e.color()(q[q.length-1],q.length-1)).text(l(x)),A.select(".nv-hoverArea").append("rect").on("mousemove",s).on("click",function(){j=!j}).on("mouseout",function(){i=[],r()}),B.select(".nv-hoverArea rect").attr("transform",function(){return"translate("+-f.left+","+-f.top+")"}).attr("width",u+f.left+f.right).attr("height",v+f.top)}),b}var c,d,e=a.models.sparkline(),f={top:15,right:100,bottom:10,left:50},g=null,h=null,i=[],j=!1,k=d3.format(",r"),l=d3.format(",.2f"),m=!0,n=!0,o=!1,p="No Data Available.";return b.sparkline=e,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},xTickFormat:{get:function(){return k},set:function(a){k=a}},yTickFormat:{get:function(){return l},set:function(a){l=a}},showValue:{get:function(){return m},set:function(a){m=a}},alignValue:{get:function(){return n},set:function(a){n=a}},rightAlignValue:{get:function(){return o},set:function(a){o=a}},noData:{get:function(){return p},set:function(a){p=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.stackedArea=function(){"use strict";function b(l){return t.reset(),t.models(q),l.each(function(l){var r=f-e.left-e.right,u=g-e.top-e.bottom,v=d3.select(this);a.utils.initSVG(v),c=q.xScale(),d=q.yScale();var w=l;l.forEach(function(a,b){a.seriesIndex=b,a.values=a.values.map(function(a,c){return a.index=c,a.seriesIndex=b,a})});var x=l.filter(function(a){return!a.disabled});l=d3.layout.stack().order(n).offset(m).values(function(a){return a.values}).x(j).y(k).out(function(a,b,c){var d=0===k(a)?0:c;a.display={y:d,y0:b}})(x);var y=v.selectAll("g.nv-wrap.nv-stackedarea").data([l]),z=y.enter().append("g").attr("class","nvd3 nv-wrap nv-stackedarea"),A=z.append("defs"),B=z.append("g"),C=y.select("g");B.append("g").attr("class","nv-areaWrap"),B.append("g").attr("class","nv-scatterWrap"),y.attr("transform","translate("+e.left+","+e.top+")"),q.width(r).height(u).x(j).y(function(a){return a.display.y+a.display.y0}).forceY([0]).color(l.map(function(a){return a.color||h(a,a.seriesIndex)}));var D=C.select(".nv-scatterWrap").datum(l);D.call(q),A.append("clipPath").attr("id","nv-edge-clip-"+i).append("rect"),y.select("#nv-edge-clip-"+i+" rect").attr("width",r).attr("height",u),C.attr("clip-path",p?"url(#nv-edge-clip-"+i+")":"");var E=d3.svg.area().x(function(a,b){return c(j(a,b))}).y0(function(a){return d(a.display.y0)}).y1(function(a){return d(a.display.y+a.display.y0)}).interpolate(o),F=d3.svg.area().x(function(a,b){return c(j(a,b))}).y0(function(a){return d(a.display.y0)}).y1(function(a){return d(a.display.y0)}),G=C.select(".nv-areaWrap").selectAll("path.nv-area").data(function(a){return a});G.enter().append("path").attr("class",function(a,b){return"nv-area nv-area-"+b}).attr("d",function(a){return F(a.values,a.seriesIndex)}).on("mouseover",function(a){d3.select(this).classed("hover",!0),s.areaMouseover({point:a,series:a.key,pos:[d3.event.pageX,d3.event.pageY],seriesIndex:a.seriesIndex})}).on("mouseout",function(a){d3.select(this).classed("hover",!1),s.areaMouseout({point:a,series:a.key,pos:[d3.event.pageX,d3.event.pageY],seriesIndex:a.seriesIndex})}).on("click",function(a){d3.select(this).classed("hover",!1),s.areaClick({point:a,series:a.key,pos:[d3.event.pageX,d3.event.pageY],seriesIndex:a.seriesIndex})}),G.exit().remove(),G.style("fill",function(a){return a.color||h(a,a.seriesIndex)}).style("stroke",function(a){return a.color||h(a,a.seriesIndex)}),G.watchTransition(t,"stackedArea path").attr("d",function(a,b){return E(a.values,b)}),q.dispatch.on("elementMouseover.area",function(a){C.select(".nv-chart-"+i+" .nv-area-"+a.seriesIndex).classed("hover",!0)}),q.dispatch.on("elementMouseout.area",function(a){C.select(".nv-chart-"+i+" .nv-area-"+a.seriesIndex).classed("hover",!1)}),b.d3_stackedOffset_stackPercent=function(a){var b,c,d,e=a.length,f=a[0].length,g=1/e,h=[];for(c=0;f>c;++c){for(b=0,d=0;b<w.length;b++)d+=k(w[b].values[c]);if(d)for(b=0;e>b;b++)a[b][c][1]/=d;else for(b=0;e>b;b++)a[b][c][1]=g}for(c=0;f>c;++c)h[c]=0;return h}}),t.renderEnd("stackedArea immediate"),b}var c,d,e={top:0,right:0,bottom:0,left:0},f=960,g=500,h=a.utils.defaultColor(),i=Math.floor(1e5*Math.random()),j=function(a){return a.x},k=function(a){return a.y},l="stack",m="zero",n="default",o="linear",p=!1,q=a.models.scatter(),r=250,s=d3.dispatch("tooltipShow","tooltipHide","areaClick","areaMouseover","areaMouseout","renderEnd");q.interactive(!1),q.pointSize(2.2).pointDomain([2.2,2.2]);var t=a.utils.renderWatch(s,r);return q.dispatch.on("elementClick.area",function(a){s.areaClick(a)}),q.dispatch.on("elementMouseover.tooltip",function(a){a.pos=[a.pos[0]+e.left,a.pos[1]+e.top],s.tooltipShow(a)}),q.dispatch.on("elementMouseout.tooltip",function(a){s.tooltipHide(a)}),b.dispatch=s,b.scatter=q,b.interpolate=function(a){return arguments.length?(o=a,b):o},b.duration=function(a){return arguments.length?(r=a,t.reset(r),q.duration(r),b):r},b.dispatch=s,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return f},set:function(a){f=a}},height:{get:function(){return g},set:function(a){g=a}},clipEdge:{get:function(){return p},set:function(a){p=a}},offset:{get:function(){return m},set:function(a){m=a}},order:{get:function(){return n},set:function(a){n=a}},interpolate:{get:function(){return o},set:function(a){o=a}},x:{get:function(){return j},set:function(a){j=d3.functor(a)}},y:{get:function(){return k},set:function(a){k=d3.functor(a)}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},color:{get:function(){return h},set:function(b){h=a.utils.getColor(b)}},style:{get:function(){return l},set:function(a){switch(l=a){case"stack":b.offset("zero"),b.order("default");break;case"stream":b.offset("wiggle"),b.order("inside-out");break;case"stream-center":b.offset("silhouette"),b.order("inside-out");break;case"expand":b.offset("expand"),b.order("default");break;case"stack_percent":b.offset(b.d3_stackedOffset_stackPercent),b.order("default")}}},duration:{get:function(){return r},set:function(a){r=a,t.reset(r),q.duration(r)}}}),a.utils.inheritOptions(b,q),a.utils.initOptions(b),b},a.models.stackedAreaChart=function(){"use strict";function b(v){return F.reset(),F.models(e),q&&F.models(f),r&&F.models(g),v.each(function(v){var F=d3.select(this),K=this;a.utils.initSVG(F);var L=(l||parseInt(F.style("width"))||960)-k.left-k.right,M=(m||parseInt(F.style("height"))||400)-k.top-k.bottom;if(b.update=function(){F.transition().duration(E).call(b)},b.container=this,x.setter(J(v),b.update).getter(I(v)).update(),x.disabled=v.map(function(a){return!!a.disabled}),!y){var N;y={};for(N in x)y[N]=x[N]instanceof Array?x[N].slice(0):x[N]}if(!(v&&v.length&&v.filter(function(a){return a.values.length}).length)){var O=F.selectAll(".nv-noData").data([z]);return O.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),O.attr("x",k.left+L/2).attr("y",k.top+M/2).text(function(a){return a}),b}F.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var P=F.selectAll("g.nv-wrap.nv-stackedAreaChart").data([v]),Q=P.enter().append("g").attr("class","nvd3 nv-wrap nv-stackedAreaChart").append("g"),R=P.select("g");if(Q.append("rect").style("opacity",0),Q.append("g").attr("class","nv-x nv-axis"),Q.append("g").attr("class","nv-y nv-axis"),Q.append("g").attr("class","nv-stackedWrap"),Q.append("g").attr("class","nv-legendWrap"),Q.append("g").attr("class","nv-controlsWrap"),Q.append("g").attr("class","nv-interactive"),R.select("rect").attr("width",L).attr("height",M),p){var S=o?L-B:L;h.width(S),R.select(".nv-legendWrap").datum(v).call(h),k.top!=h.height()&&(k.top=h.height(),M=(m||parseInt(F.style("height"))||400)-k.top-k.bottom),R.select(".nv-legendWrap").attr("transform","translate("+(L-S)+","+-k.top+")")}if(o){var T=[{key:D.stacked||"Stacked",metaKey:"Stacked",disabled:"stack"!=e.style(),style:"stack"},{key:D.stream||"Stream",metaKey:"Stream",disabled:"stream"!=e.style(),style:"stream"},{key:D.expanded||"Expanded",metaKey:"Expanded",disabled:"expand"!=e.style(),style:"expand"},{key:D.stack_percent||"Stack %",metaKey:"Stack_Percent",disabled:"stack_percent"!=e.style(),style:"stack_percent"}];B=C.length/3*260,T=T.filter(function(a){return-1!==C.indexOf(a.metaKey)}),i.width(B).color(["#444","#444","#444"]),R.select(".nv-controlsWrap").datum(T).call(i),k.top!=Math.max(i.height(),h.height())&&(k.top=Math.max(i.height(),h.height()),M=(m||parseInt(F.style("height"))||400)-k.top-k.bottom),R.select(".nv-controlsWrap").attr("transform","translate(0,"+-k.top+")")}P.attr("transform","translate("+k.left+","+k.top+")"),s&&R.select(".nv-y.nv-axis").attr("transform","translate("+L+",0)"),t&&(j.width(L).height(M).margin({left:k.left,top:k.top}).svgContainer(F).xScale(c),P.select(".nv-interactive").call(j)),e.width(L).height(M);var U=R.select(".nv-stackedWrap").datum(v);U.transition().call(e),q&&(f.scale(c).ticks(a.utils.calcTicksX(L/100,v)).tickSize(-M,0),R.select(".nv-x.nv-axis").attr("transform","translate(0,"+M+")"),R.select(".nv-x.nv-axis").transition().duration(0).call(f)),r&&(g.scale(d).ticks("wiggle"==e.offset()?0:a.utils.calcTicksY(M/36,v)).tickSize(-L,0).setTickFormat("expand"==e.style()||"stack_percent"==e.style()?d3.format("%"):w),R.select(".nv-y.nv-axis").transition().duration(0).call(g)),e.dispatch.on("areaClick.toggle",function(a){v.forEach(1===v.filter(function(a){return!a.disabled}).length?function(a){a.disabled=!1}:function(b,c){b.disabled=c!=a.seriesIndex}),x.disabled=v.map(function(a){return!!a.disabled}),A.stateChange(x),b.update()}),h.dispatch.on("stateChange",function(a){for(var c in a)x[c]=a[c];A.stateChange(x),b.update()}),i.dispatch.on("legendClick",function(a){a.disabled&&(T=T.map(function(a){return a.disabled=!0,a}),a.disabled=!1,e.style(a.style),x.style=e.style(),A.stateChange(x),b.update())}),j.dispatch.on("elementMousemove",function(c){e.clearHighlights();var d,h,i,l=[];if(v.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(f,g){h=a.interactiveBisect(f.values,c.pointXValue,b.x()),e.highlightPoint(g,h,!0);var j=f.values[h];if("undefined"!=typeof j){"undefined"==typeof d&&(d=j),"undefined"==typeof i&&(i=b.xScale()(b.x()(j,h)));var k="expand"==e.style()?j.display.y:b.y()(j,h);l.push({key:f.key,value:k,color:n(f,f.seriesIndex),stackedValue:j.display})}}),l.reverse(),l.length>2){var m=b.yScale().invert(c.mouseY),o=null;l.forEach(function(a,b){m=Math.abs(m);var c=Math.abs(a.stackedValue.y0),d=Math.abs(a.stackedValue.y);return m>=c&&d+c>=m?void(o=b):void 0}),null!=o&&(l[o].highlight=!0)}var p=f.tickFormat()(b.x()(d,h)),q="expand"==e.style()?function(a){return d3.format(".1%")(a)}:function(a){return g.tickFormat()(a)};j.tooltip.position({left:i+k.left,top:c.mouseY+k.top}).chartContainer(K.parentNode).enabled(u).valueFormatter(q).data({value:p,series:l})(),j.renderGuideLine(i)}),j.dispatch.on("elementMouseout",function(){A.tooltipHide(),e.clearHighlights()}),A.on("tooltipShow",function(a){u&&H(a,K.parentNode)}),A.on("changeState",function(a){"undefined"!=typeof a.disabled&&v.length===a.disabled.length&&(v.forEach(function(b,c){b.disabled=a.disabled[c]}),x.disabled=a.disabled),"undefined"!=typeof a.style&&(e.style(a.style),G=a.style),b.update()})}),F.renderEnd("stacked Area chart immediate"),b}var c,d,e=a.models.stackedArea(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.models.legend(),j=a.interactiveGuideline(),k={top:30,right:25,bottom:50,left:60},l=null,m=null,n=a.utils.defaultColor(),o=!0,p=!0,q=!0,r=!0,s=!1,t=!1,u=!0,v=function(a,b,c){return"<h3>"+a+"</h3><p>"+c+" on "+b+"</p>"},w=d3.format(",.2f"),x=a.utils.state(),y=null,z="No Data Available.",A=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),B=250,C=["Stacked","Stream","Expanded"],D={},E=250;x.style=e.style(),f.orient("bottom").tickPadding(7),g.orient(s?"right":"left"),i.updateState(!1);var F=a.utils.renderWatch(A),G=e.style(),H=function(c,d){var h=c.pos[0]+(d.offsetLeft||0),i=c.pos[1]+(d.offsetTop||0),j=f.tickFormat()(e.x()(c.point,c.pointIndex)),k=g.tickFormat()(e.y()(c.point,c.pointIndex)),l=v(c.series.key,j,k,c,b);a.tooltip.show([h,i],l,c.value<0?"n":"s",null,d)},I=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),style:e.style()}}},J=function(a){return function(b){void 0!==b.style&&(G=b.style),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on("tooltipShow",function(a){a.pos=[a.pos[0]+k.left,a.pos[1]+k.top],A.tooltipShow(a)}),e.dispatch.on("tooltipHide",function(a){A.tooltipHide(a)}),A.on("tooltipHide",function(){u&&a.tooltip.cleanup()}),b.dispatch=A,b.stacked=e,b.legend=h,b.controls=i,b.xAxis=f,b.yAxis=g,b.interactiveLayer=j,g.setTickFormat=g.tickFormat,b.dispatch=A,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return l},set:function(a){l=a}},height:{get:function(){return m},set:function(a){m=a}},showLegend:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return q},set:function(a){q=a}},showYAxis:{get:function(){return r},set:function(a){r=a}},tooltips:{get:function(){return u},set:function(a){u=a}},tooltipContent:{get:function(){return v},set:function(a){v=a}},defaultState:{get:function(){return y},set:function(a){y=a}},noData:{get:function(){return z},set:function(a){z=a}},showControls:{get:function(){return o},set:function(a){o=a}},controlLabels:{get:function(){return D},set:function(a){D=a}},yAxisTickFormat:{get:function(){return w},set:function(a){w=a}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},duration:{get:function(){return E},set:function(a){E=a,F.reset(E),e.duration(E),f.duration(E),g.duration(E)}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),h.color(n),e.color(n)}},rightAlignYAxis:{get:function(){return s},set:function(a){s=a,g.orient(s?"right":"left")}},useInteractiveGuideline:{get:function(){return t},set:function(a){t=!!a,a&&(b.interactive(!1),b.useVoronoi(!1))}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.version="1.7.1"}();
\ No newline at end of file