diff gtc/nv.d3.js @ 89:18f8c214169f

add gtc
author paulo
date Sun, 19 Feb 2017 19:45:31 -0800
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gtc/nv.d3.js	Sun Feb 19 19:45:31 2017 -0800
     1.3 @@ -0,0 +1,13298 @@
     1.4 +/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-06-15 */
     1.5 +(function(){
     1.6 +
     1.7 +// set up main nv object
     1.8 +var nv = {};
     1.9 +
    1.10 +// the major global objects under the nv namespace
    1.11 +nv.dev = false; //set false when in production
    1.12 +nv.tooltip = nv.tooltip || {}; // For the tooltip system
    1.13 +nv.utils = nv.utils || {}; // Utility subsystem
    1.14 +nv.models = nv.models || {}; //stores all the possible models/components
    1.15 +nv.charts = {}; //stores all the ready to use charts
    1.16 +nv.logs = {}; //stores some statistics and potential error messages
    1.17 +nv.dom = {}; //DOM manipulation functions
    1.18 +
    1.19 +nv.dispatch = d3.dispatch('render_start', 'render_end');
    1.20 +
    1.21 +// Function bind polyfill
    1.22 +// Needed ONLY for phantomJS as it's missing until version 2.0 which is unreleased as of this comment
    1.23 +// https://github.com/ariya/phantomjs/issues/10522
    1.24 +// http://kangax.github.io/compat-table/es5/#Function.prototype.bind
    1.25 +// phantomJS is used for running the test suite
    1.26 +if (!Function.prototype.bind) {
    1.27 +    Function.prototype.bind = function (oThis) {
    1.28 +        if (typeof this !== "function") {
    1.29 +            // closest thing possible to the ECMAScript 5 internal IsCallable function
    1.30 +            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    1.31 +        }
    1.32 +
    1.33 +        var aArgs = Array.prototype.slice.call(arguments, 1),
    1.34 +            fToBind = this,
    1.35 +            fNOP = function () {},
    1.36 +            fBound = function () {
    1.37 +                return fToBind.apply(this instanceof fNOP && oThis
    1.38 +                        ? this
    1.39 +                        : oThis,
    1.40 +                    aArgs.concat(Array.prototype.slice.call(arguments)));
    1.41 +            };
    1.42 +
    1.43 +        fNOP.prototype = this.prototype;
    1.44 +        fBound.prototype = new fNOP();
    1.45 +        return fBound;
    1.46 +    };
    1.47 +}
    1.48 +
    1.49 +//  Development render timers - disabled if dev = false
    1.50 +if (nv.dev) {
    1.51 +    nv.dispatch.on('render_start', function(e) {
    1.52 +        nv.logs.startTime = +new Date();
    1.53 +    });
    1.54 +
    1.55 +    nv.dispatch.on('render_end', function(e) {
    1.56 +        nv.logs.endTime = +new Date();
    1.57 +        nv.logs.totalTime = nv.logs.endTime - nv.logs.startTime;
    1.58 +        nv.log('total', nv.logs.totalTime); // used for development, to keep track of graph generation times
    1.59 +    });
    1.60 +}
    1.61 +
    1.62 +// Logs all arguments, and returns the last so you can test things in place
    1.63 +// Note: in IE8 console.log is an object not a function, and if modernizr is used
    1.64 +// then calling Function.prototype.bind with with anything other than a function
    1.65 +// causes a TypeError to be thrown.
    1.66 +nv.log = function() {
    1.67 +    if (nv.dev && window.console && console.log && console.log.apply)
    1.68 +        console.log.apply(console, arguments);
    1.69 +    else if (nv.dev && window.console && typeof console.log == "function" && Function.prototype.bind) {
    1.70 +        var log = Function.prototype.bind.call(console.log, console);
    1.71 +        log.apply(console, arguments);
    1.72 +    }
    1.73 +    return arguments[arguments.length - 1];
    1.74 +};
    1.75 +
    1.76 +// print console warning, should be used by deprecated functions
    1.77 +nv.deprecated = function(name, info) {
    1.78 +    if (console && console.warn) {
    1.79 +        console.warn('nvd3 warning: `' + name + '` has been deprecated. ', info || '');
    1.80 +    }
    1.81 +};
    1.82 +
    1.83 +// The nv.render function is used to queue up chart rendering
    1.84 +// in non-blocking async functions.
    1.85 +// When all queued charts are done rendering, nv.dispatch.render_end is invoked.
    1.86 +nv.render = function render(step) {
    1.87 +    // number of graphs to generate in each timeout loop
    1.88 +    step = step || 1;
    1.89 +
    1.90 +    nv.render.active = true;
    1.91 +    nv.dispatch.render_start();
    1.92 +
    1.93 +    var renderLoop = function() {
    1.94 +        var chart, graph;
    1.95 +
    1.96 +        for (var i = 0; i < step && (graph = nv.render.queue[i]); i++) {
    1.97 +            chart = graph.generate();
    1.98 +            if (typeof graph.callback == typeof(Function)) graph.callback(chart);
    1.99 +        }
   1.100 +
   1.101 +        nv.render.queue.splice(0, i);
   1.102 +
   1.103 +        if (nv.render.queue.length) {
   1.104 +            setTimeout(renderLoop);
   1.105 +        }
   1.106 +        else {
   1.107 +            nv.dispatch.render_end();
   1.108 +            nv.render.active = false;
   1.109 +        }
   1.110 +    };
   1.111 +
   1.112 +    setTimeout(renderLoop);
   1.113 +};
   1.114 +
   1.115 +nv.render.active = false;
   1.116 +nv.render.queue = [];
   1.117 +
   1.118 +/*
   1.119 +Adds a chart to the async rendering queue. This method can take arguments in two forms:
   1.120 +nv.addGraph({
   1.121 +    generate: <Function>
   1.122 +    callback: <Function>
   1.123 +})
   1.124 +
   1.125 +or
   1.126 +
   1.127 +nv.addGraph(<generate Function>, <callback Function>)
   1.128 +
   1.129 +The generate function should contain code that creates the NVD3 model, sets options
   1.130 +on it, adds data to an SVG element, and invokes the chart model. The generate function
   1.131 +should return the chart model.  See examples/lineChart.html for a usage example.
   1.132 +
   1.133 +The callback function is optional, and it is called when the generate function completes.
   1.134 +*/
   1.135 +nv.addGraph = function(obj) {
   1.136 +    if (typeof arguments[0] === typeof(Function)) {
   1.137 +        obj = {generate: arguments[0], callback: arguments[1]};
   1.138 +    }
   1.139 +
   1.140 +    nv.render.queue.push(obj);
   1.141 +
   1.142 +    if (!nv.render.active) {
   1.143 +        nv.render();
   1.144 +    }
   1.145 +};
   1.146 +
   1.147 +// Node/CommonJS exports
   1.148 +if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') {
   1.149 +  module.exports = nv;
   1.150 +}
   1.151 +
   1.152 +if (typeof(window) !== 'undefined') {
   1.153 +  window.nv = nv;
   1.154 +}
   1.155 +/* Facade for queueing DOM write operations
   1.156 + * with Fastdom (https://github.com/wilsonpage/fastdom)
   1.157 + * if available.
   1.158 + * This could easily be extended to support alternate
   1.159 + * implementations in the future.
   1.160 + */
   1.161 +nv.dom.write = function(callback) {
   1.162 +	if (window.fastdom !== undefined) {
   1.163 +		return fastdom.write(callback);
   1.164 +	}
   1.165 +	return callback();
   1.166 +};
   1.167 +
   1.168 +/* Facade for queueing DOM read operations
   1.169 + * with Fastdom (https://github.com/wilsonpage/fastdom)
   1.170 + * if available.
   1.171 + * This could easily be extended to support alternate
   1.172 + * implementations in the future.
   1.173 + */
   1.174 +nv.dom.read = function(callback) {
   1.175 +	if (window.fastdom !== undefined) {
   1.176 +		return fastdom.read(callback);
   1.177 +	}
   1.178 +	return callback();
   1.179 +};/* Utility class to handle creation of an interactive layer.
   1.180 + This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch
   1.181 + containing the X-coordinate. It can also render a vertical line where the mouse is located.
   1.182 +
   1.183 + dispatch.elementMousemove is the important event to latch onto.  It is fired whenever the mouse moves over
   1.184 + the rectangle. The dispatch is given one object which contains the mouseX/Y location.
   1.185 + It also has 'pointXValue', which is the conversion of mouseX to the x-axis scale.
   1.186 + */
   1.187 +nv.interactiveGuideline = function() {
   1.188 +    "use strict";
   1.189 +
   1.190 +    var tooltip = nv.models.tooltip();
   1.191 +    tooltip.duration(0).hideDelay(0)._isInteractiveLayer(true).hidden(false);
   1.192 +
   1.193 +    //Public settings
   1.194 +    var width = null;
   1.195 +    var height = null;
   1.196 +
   1.197 +    //Please pass in the bounding chart's top and left margins
   1.198 +    //This is important for calculating the correct mouseX/Y positions.
   1.199 +    var margin = {left: 0, top: 0}
   1.200 +        , xScale = d3.scale.linear()
   1.201 +        , dispatch = d3.dispatch('elementMousemove', 'elementMouseout', 'elementClick', 'elementDblclick')
   1.202 +        , showGuideLine = true;
   1.203 +    //Must pass in the bounding chart's <svg> container.
   1.204 +    //The mousemove event is attached to this container.
   1.205 +    var svgContainer = null;
   1.206 +
   1.207 +    // check if IE by looking for activeX
   1.208 +    var isMSIE = "ActiveXObject" in window;
   1.209 +
   1.210 +
   1.211 +    function layer(selection) {
   1.212 +        selection.each(function(data) {
   1.213 +            var container = d3.select(this);
   1.214 +            var availableWidth = (width || 960), availableHeight = (height || 400);
   1.215 +            var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer")
   1.216 +                .data([data]);
   1.217 +            var wrapEnter = wrap.enter()
   1.218 +                .append("g").attr("class", " nv-wrap nv-interactiveLineLayer");
   1.219 +            wrapEnter.append("g").attr("class","nv-interactiveGuideLine");
   1.220 +
   1.221 +            if (!svgContainer) {
   1.222 +                return;
   1.223 +            }
   1.224 +
   1.225 +            function mouseHandler() {
   1.226 +                var d3mouse = d3.mouse(this);
   1.227 +                var mouseX = d3mouse[0];
   1.228 +                var mouseY = d3mouse[1];
   1.229 +                var subtractMargin = true;
   1.230 +                var mouseOutAnyReason = false;
   1.231 +                if (isMSIE) {
   1.232 +                    /*
   1.233 +                     D3.js (or maybe SVG.getScreenCTM) has a nasty bug in Internet Explorer 10.
   1.234 +                     d3.mouse() returns incorrect X,Y mouse coordinates when mouse moving
   1.235 +                     over a rect in IE 10.
   1.236 +                     However, d3.event.offsetX/Y also returns the mouse coordinates
   1.237 +                     relative to the triggering <rect>. So we use offsetX/Y on IE.
   1.238 +                     */
   1.239 +                    mouseX = d3.event.offsetX;
   1.240 +                    mouseY = d3.event.offsetY;
   1.241 +
   1.242 +                    /*
   1.243 +                     On IE, if you attach a mouse event listener to the <svg> container,
   1.244 +                     it will actually trigger it for all the child elements (like <path>, <circle>, etc).
   1.245 +                     When this happens on IE, the offsetX/Y is set to where ever the child element
   1.246 +                     is located.
   1.247 +                     As a result, we do NOT need to subtract margins to figure out the mouse X/Y
   1.248 +                     position under this scenario. Removing the line below *will* cause
   1.249 +                     the interactive layer to not work right on IE.
   1.250 +                     */
   1.251 +                    if(d3.event.target.tagName !== "svg") {
   1.252 +                        subtractMargin = false;
   1.253 +                    }
   1.254 +
   1.255 +                    if (d3.event.target.className.baseVal.match("nv-legend")) {
   1.256 +                        mouseOutAnyReason = true;
   1.257 +                    }
   1.258 +
   1.259 +                }
   1.260 +
   1.261 +                if(subtractMargin) {
   1.262 +                    mouseX -= margin.left;
   1.263 +                    mouseY -= margin.top;
   1.264 +                }
   1.265 +
   1.266 +                /* If mouseX/Y is outside of the chart's bounds,
   1.267 +                 trigger a mouseOut event.
   1.268 +                 */
   1.269 +                if (mouseX < 0 || mouseY < 0
   1.270 +                    || mouseX > availableWidth || mouseY > availableHeight
   1.271 +                    || (d3.event.relatedTarget && d3.event.relatedTarget.ownerSVGElement === undefined)
   1.272 +                    || mouseOutAnyReason
   1.273 +                    ) {
   1.274 +
   1.275 +                    if (isMSIE) {
   1.276 +                        if (d3.event.relatedTarget
   1.277 +                            && d3.event.relatedTarget.ownerSVGElement === undefined
   1.278 +                            && (d3.event.relatedTarget.className === undefined
   1.279 +                                || d3.event.relatedTarget.className.match(tooltip.nvPointerEventsClass))) {
   1.280 +
   1.281 +                            return;
   1.282 +                        }
   1.283 +                    }
   1.284 +                    dispatch.elementMouseout({
   1.285 +                        mouseX: mouseX,
   1.286 +                        mouseY: mouseY
   1.287 +                    });
   1.288 +                    layer.renderGuideLine(null); //hide the guideline
   1.289 +                    tooltip.hidden(true);
   1.290 +                    return;
   1.291 +                } else {
   1.292 +                    tooltip.hidden(false);
   1.293 +                }
   1.294 +
   1.295 +                var pointXValue = xScale.invert(mouseX);
   1.296 +                dispatch.elementMousemove({
   1.297 +                    mouseX: mouseX,
   1.298 +                    mouseY: mouseY,
   1.299 +                    pointXValue: pointXValue
   1.300 +                });
   1.301 +
   1.302 +                //If user double clicks the layer, fire a elementDblclick
   1.303 +                if (d3.event.type === "dblclick") {
   1.304 +                    dispatch.elementDblclick({
   1.305 +                        mouseX: mouseX,
   1.306 +                        mouseY: mouseY,
   1.307 +                        pointXValue: pointXValue
   1.308 +                    });
   1.309 +                }
   1.310 +
   1.311 +                // if user single clicks the layer, fire elementClick
   1.312 +                if (d3.event.type === 'click') {
   1.313 +                    dispatch.elementClick({
   1.314 +                        mouseX: mouseX,
   1.315 +                        mouseY: mouseY,
   1.316 +                        pointXValue: pointXValue
   1.317 +                    });
   1.318 +                }
   1.319 +            }
   1.320 +
   1.321 +            svgContainer
   1.322 +                .on("touchmove",mouseHandler)
   1.323 +                .on("mousemove",mouseHandler, true)
   1.324 +                .on("mouseout" ,mouseHandler,true)
   1.325 +                .on("dblclick" ,mouseHandler)
   1.326 +                .on("click", mouseHandler)
   1.327 +            ;
   1.328 +
   1.329 +            layer.guideLine = null;
   1.330 +            //Draws a vertical guideline at the given X postion.
   1.331 +            layer.renderGuideLine = function(x) {
   1.332 +                if (!showGuideLine) return;
   1.333 +                if (layer.guideLine && layer.guideLine.attr("x1") === x) return;
   1.334 +                nv.dom.write(function() {
   1.335 +                    var line = wrap.select(".nv-interactiveGuideLine")
   1.336 +                        .selectAll("line")
   1.337 +                        .data((x != null) ? [nv.utils.NaNtoZero(x)] : [], String);
   1.338 +                    line.enter()
   1.339 +                        .append("line")
   1.340 +                        .attr("class", "nv-guideline")
   1.341 +                        .attr("x1", function(d) { return d;})
   1.342 +                        .attr("x2", function(d) { return d;})
   1.343 +                        .attr("y1", availableHeight)
   1.344 +                        .attr("y2",0);
   1.345 +                    line.exit().remove();
   1.346 +                });
   1.347 +            }
   1.348 +        });
   1.349 +    }
   1.350 +
   1.351 +    layer.dispatch = dispatch;
   1.352 +    layer.tooltip = tooltip;
   1.353 +
   1.354 +    layer.margin = function(_) {
   1.355 +        if (!arguments.length) return margin;
   1.356 +        margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
   1.357 +        margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
   1.358 +        return layer;
   1.359 +    };
   1.360 +
   1.361 +    layer.width = function(_) {
   1.362 +        if (!arguments.length) return width;
   1.363 +        width = _;
   1.364 +        return layer;
   1.365 +    };
   1.366 +
   1.367 +    layer.height = function(_) {
   1.368 +        if (!arguments.length) return height;
   1.369 +        height = _;
   1.370 +        return layer;
   1.371 +    };
   1.372 +
   1.373 +    layer.xScale = function(_) {
   1.374 +        if (!arguments.length) return xScale;
   1.375 +        xScale = _;
   1.376 +        return layer;
   1.377 +    };
   1.378 +
   1.379 +    layer.showGuideLine = function(_) {
   1.380 +        if (!arguments.length) return showGuideLine;
   1.381 +        showGuideLine = _;
   1.382 +        return layer;
   1.383 +    };
   1.384 +
   1.385 +    layer.svgContainer = function(_) {
   1.386 +        if (!arguments.length) return svgContainer;
   1.387 +        svgContainer = _;
   1.388 +        return layer;
   1.389 +    };
   1.390 +
   1.391 +    return layer;
   1.392 +};
   1.393 +
   1.394 +/* Utility class that uses d3.bisect to find the index in a given array, where a search value can be inserted.
   1.395 + This is different from normal bisectLeft; this function finds the nearest index to insert the search value.
   1.396 +
   1.397 + For instance, lets say your array is [1,2,3,5,10,30], and you search for 28.
   1.398 + Normal d3.bisectLeft will return 4, because 28 is inserted after the number 10.  But interactiveBisect will return 5
   1.399 + because 28 is closer to 30 than 10.
   1.400 +
   1.401 + Unit tests can be found in: interactiveBisectTest.html
   1.402 +
   1.403 + Has the following known issues:
   1.404 + * Will not work if the data points move backwards (ie, 10,9,8,7, etc) or if the data points are in random order.
   1.405 + * Won't work if there are duplicate x coordinate values.
   1.406 + */
   1.407 +nv.interactiveBisect = function (values, searchVal, xAccessor) {
   1.408 +    "use strict";
   1.409 +    if (! (values instanceof Array)) {
   1.410 +        return null;
   1.411 +    }
   1.412 +    var _xAccessor;
   1.413 +    if (typeof xAccessor !== 'function') {
   1.414 +        _xAccessor = function(d) {
   1.415 +            return d.x;
   1.416 +        }
   1.417 +    } else {
   1.418 +        _xAccessor = xAccessor;
   1.419 +    }
   1.420 +    var _cmp = function(d, v) {
   1.421 +        // Accessors are no longer passed the index of the element along with
   1.422 +        // the element itself when invoked by d3.bisector.
   1.423 +        //
   1.424 +        // Starting at D3 v3.4.4, d3.bisector() started inspecting the
   1.425 +        // function passed to determine if it should consider it an accessor
   1.426 +        // or a comparator. This meant that accessors that take two arguments
   1.427 +        // (expecting an index as the second parameter) are treated as
   1.428 +        // comparators where the second argument is the search value against
   1.429 +        // which the first argument is compared.
   1.430 +        return _xAccessor(d) - v;
   1.431 +    };
   1.432 +
   1.433 +    var bisect = d3.bisector(_cmp).left;
   1.434 +    var index = d3.max([0, bisect(values,searchVal) - 1]);
   1.435 +    var currentValue = _xAccessor(values[index]);
   1.436 +
   1.437 +    if (typeof currentValue === 'undefined') {
   1.438 +        currentValue = index;
   1.439 +    }
   1.440 +
   1.441 +    if (currentValue === searchVal) {
   1.442 +        return index; //found exact match
   1.443 +    }
   1.444 +
   1.445 +    var nextIndex = d3.min([index+1, values.length - 1]);
   1.446 +    var nextValue = _xAccessor(values[nextIndex]);
   1.447 +
   1.448 +    if (typeof nextValue === 'undefined') {
   1.449 +        nextValue = nextIndex;
   1.450 +    }
   1.451 +
   1.452 +    if (Math.abs(nextValue - searchVal) >= Math.abs(currentValue - searchVal)) {
   1.453 +        return index;
   1.454 +    } else {
   1.455 +        return nextIndex
   1.456 +    }
   1.457 +};
   1.458 +
   1.459 +/*
   1.460 + Returns the index in the array "values" that is closest to searchVal.
   1.461 + Only returns an index if searchVal is within some "threshold".
   1.462 + Otherwise, returns null.
   1.463 + */
   1.464 +nv.nearestValueIndex = function (values, searchVal, threshold) {
   1.465 +    "use strict";
   1.466 +    var yDistMax = Infinity, indexToHighlight = null;
   1.467 +    values.forEach(function(d,i) {
   1.468 +        var delta = Math.abs(searchVal - d);
   1.469 +        if ( d != null && delta <= yDistMax && delta < threshold) {
   1.470 +            yDistMax = delta;
   1.471 +            indexToHighlight = i;
   1.472 +        }
   1.473 +    });
   1.474 +    return indexToHighlight;
   1.475 +};
   1.476 +/* Tooltip rendering model for nvd3 charts.
   1.477 + window.nv.models.tooltip is the updated,new way to render tooltips.
   1.478 +
   1.479 + window.nv.tooltip.show is the old tooltip code.
   1.480 + window.nv.tooltip.* also has various helper methods.
   1.481 + */
   1.482 +(function() {
   1.483 +    "use strict";
   1.484 +
   1.485 +    /* Model which can be instantiated to handle tooltip rendering.
   1.486 +     Example usage:
   1.487 +     var tip = nv.models.tooltip().gravity('w').distance(23)
   1.488 +     .data(myDataObject);
   1.489 +
   1.490 +     tip();    //just invoke the returned function to render tooltip.
   1.491 +     */
   1.492 +    nv.models.tooltip = function() {
   1.493 +
   1.494 +        /*
   1.495 +        Tooltip data. If data is given in the proper format, a consistent tooltip is generated.
   1.496 +        Example Format of data:
   1.497 +        {
   1.498 +            key: "Date",
   1.499 +            value: "August 2009",
   1.500 +            series: [
   1.501 +                {key: "Series 1", value: "Value 1", color: "#000"},
   1.502 +                {key: "Series 2", value: "Value 2", color: "#00f"}
   1.503 +            ]
   1.504 +        }
   1.505 +        */
   1.506 +        var data = null;
   1.507 +        var gravity = 'w'   //Can be 'n','s','e','w'. Determines how tooltip is positioned.
   1.508 +            ,   distance = 25   //Distance to offset tooltip from the mouse location.
   1.509 +            ,   snapDistance = 0   //Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect)
   1.510 +            ,   fixedTop = null //If not null, this fixes the top position of the tooltip.
   1.511 +            ,   classes = null  //Attaches additional CSS classes to the tooltip DIV that is created.
   1.512 +            ,   chartContainer = null   //Parent dom element of the SVG that holds the chart.
   1.513 +            ,   hidden = true  // start off hidden, toggle with hide/show functions below
   1.514 +            ,   hideDelay = 400  // delay before the tooltip hides after calling hide()
   1.515 +            ,   tooltip = null // d3 select of tooltipElem below
   1.516 +            ,   tooltipElem = null  //actual DOM element representing the tooltip.
   1.517 +            ,   position = {left: null, top: null}   //Relative position of the tooltip inside chartContainer.
   1.518 +            ,   offset = {left: 0, top: 0}   //Offset of tooltip against the pointer
   1.519 +            ,   enabled = true  //True -> tooltips are rendered. False -> don't render tooltips.
   1.520 +            ,   duration = 100 // duration for tooltip movement
   1.521 +            ,   headerEnabled = true
   1.522 +        ;
   1.523 +
   1.524 +        // set to true by interactive layer to adjust tooltip positions
   1.525 +        // eventually we should probably fix interactive layer to get the position better.
   1.526 +        // for now this is needed if you want to set chartContainer for normal tooltips, else it "fixes" it to broken
   1.527 +        var isInteractiveLayer = false;
   1.528 +
   1.529 +        //Generates a unique id when you create a new tooltip() object
   1.530 +        var id = "nvtooltip-" + Math.floor(Math.random() * 100000);
   1.531 +
   1.532 +        //CSS class to specify whether element should not have mouse events.
   1.533 +        var  nvPointerEventsClass = "nv-pointer-events-none";
   1.534 +
   1.535 +        //Format function for the tooltip values column
   1.536 +        var valueFormatter = function(d,i) {
   1.537 +            return d;
   1.538 +        };
   1.539 +
   1.540 +        //Format function for the tooltip header value.
   1.541 +        var headerFormatter = function(d) {
   1.542 +            return d;
   1.543 +        };
   1.544 +
   1.545 +        var keyFormatter = function(d, i) {
   1.546 +            return d;
   1.547 +        };
   1.548 +
   1.549 +        //By default, the tooltip model renders a beautiful table inside a DIV.
   1.550 +        //You can override this function if a custom tooltip is desired.
   1.551 +        var contentGenerator = function(d) {
   1.552 +            if (d === null) {
   1.553 +                return '';
   1.554 +            }
   1.555 +
   1.556 +            var table = d3.select(document.createElement("table"));
   1.557 +            if (headerEnabled) {
   1.558 +                var theadEnter = table.selectAll("thead")
   1.559 +                    .data([d])
   1.560 +                    .enter().append("thead");
   1.561 +
   1.562 +                theadEnter.append("tr")
   1.563 +                    .append("td")
   1.564 +                    .attr("colspan", 3)
   1.565 +                    .append("strong")
   1.566 +                    .classed("x-value", true)
   1.567 +                    .html(headerFormatter(d.value));
   1.568 +            }
   1.569 +
   1.570 +            var tbodyEnter = table.selectAll("tbody")
   1.571 +                .data([d])
   1.572 +                .enter().append("tbody");
   1.573 +
   1.574 +            var trowEnter = tbodyEnter.selectAll("tr")
   1.575 +                    .data(function(p) { return p.series})
   1.576 +                    .enter()
   1.577 +                    .append("tr")
   1.578 +                    .classed("highlight", function(p) { return p.highlight});
   1.579 +
   1.580 +            trowEnter.append("td")
   1.581 +                .classed("legend-color-guide",true)
   1.582 +                .append("div")
   1.583 +                .style("background-color", function(p) { return p.color});
   1.584 +
   1.585 +            trowEnter.append("td")
   1.586 +                .classed("key",true)
   1.587 +                .html(function(p, i) {return keyFormatter(p.key, i)});
   1.588 +
   1.589 +            trowEnter.append("td")
   1.590 +                .classed("value",true)
   1.591 +                .html(function(p, i) { return valueFormatter(p.value, i) });
   1.592 +
   1.593 +
   1.594 +            trowEnter.selectAll("td").each(function(p) {
   1.595 +                if (p.highlight) {
   1.596 +                    var opacityScale = d3.scale.linear().domain([0,1]).range(["#fff",p.color]);
   1.597 +                    var opacity = 0.6;
   1.598 +                    d3.select(this)
   1.599 +                        .style("border-bottom-color", opacityScale(opacity))
   1.600 +                        .style("border-top-color", opacityScale(opacity))
   1.601 +                    ;
   1.602 +                }
   1.603 +            });
   1.604 +
   1.605 +            var html = table.node().outerHTML;
   1.606 +            if (d.footer !== undefined)
   1.607 +                html += "<div class='footer'>" + d.footer + "</div>";
   1.608 +            return html;
   1.609 +
   1.610 +        };
   1.611 +
   1.612 +        var dataSeriesExists = function(d) {
   1.613 +            if (d && d.series) {
   1.614 +                if (d.series instanceof Array) {
   1.615 +                    return !!d.series.length;
   1.616 +                }
   1.617 +                // if object, it's okay just convert to array of the object
   1.618 +                if (d.series instanceof Object) {
   1.619 +                    d.series = [d.series];
   1.620 +                    return true;
   1.621 +                }
   1.622 +            }
   1.623 +            return false;
   1.624 +        };
   1.625 +
   1.626 +        var calcTooltipPosition = function(pos) {
   1.627 +            if (!tooltipElem) return;
   1.628 +
   1.629 +            nv.dom.read(function() {
   1.630 +                var height = parseInt(tooltipElem.offsetHeight, 10),
   1.631 +                    width = parseInt(tooltipElem.offsetWidth, 10),
   1.632 +                    windowWidth = nv.utils.windowSize().width,
   1.633 +                    windowHeight = nv.utils.windowSize().height,
   1.634 +                    scrollTop = window.pageYOffset,
   1.635 +                    scrollLeft = window.pageXOffset,
   1.636 +                    left, top;
   1.637 +
   1.638 +                windowHeight = window.innerWidth >= document.body.scrollWidth ? windowHeight : windowHeight - 16;
   1.639 +                windowWidth = window.innerHeight >= document.body.scrollHeight ? windowWidth : windowWidth - 16;
   1.640 +
   1.641 +
   1.642 +                //Helper functions to find the total offsets of a given DOM element.
   1.643 +                //Looks up the entire ancestry of an element, up to the first relatively positioned element.
   1.644 +                var tooltipTop = function ( Elem ) {
   1.645 +                    var offsetTop = top;
   1.646 +                    do {
   1.647 +                        if( !isNaN( Elem.offsetTop ) ) {
   1.648 +                            offsetTop += (Elem.offsetTop);
   1.649 +                        }
   1.650 +                        Elem = Elem.offsetParent;
   1.651 +                    } while( Elem );
   1.652 +                    return offsetTop;
   1.653 +                };
   1.654 +                var tooltipLeft = function ( Elem ) {
   1.655 +                    var offsetLeft = left;
   1.656 +                    do {
   1.657 +                        if( !isNaN( Elem.offsetLeft ) ) {
   1.658 +                            offsetLeft += (Elem.offsetLeft);
   1.659 +                        }
   1.660 +                        Elem = Elem.offsetParent;
   1.661 +                    } while( Elem );
   1.662 +                    return offsetLeft;
   1.663 +                };
   1.664 +
   1.665 +                // calculate position based on gravity
   1.666 +                var tLeft, tTop;
   1.667 +                switch (gravity) {
   1.668 +                    case 'e':
   1.669 +                        left = pos[0] - width - distance;
   1.670 +                        top = pos[1] - (height / 2);
   1.671 +                        tLeft = tooltipLeft(tooltipElem);
   1.672 +                        tTop = tooltipTop(tooltipElem);
   1.673 +                        if (tLeft < scrollLeft) left = pos[0] + distance > scrollLeft ? pos[0] + distance : scrollLeft - tLeft + left;
   1.674 +                        if (tTop < scrollTop) top = scrollTop - tTop + top;
   1.675 +                        if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
   1.676 +                        break;
   1.677 +                    case 'w':
   1.678 +                        left = pos[0] + distance;
   1.679 +                        top = pos[1] - (height / 2);
   1.680 +                        tLeft = tooltipLeft(tooltipElem);
   1.681 +                        tTop = tooltipTop(tooltipElem);
   1.682 +                        if (tLeft + width > windowWidth) left = pos[0] - width - distance;
   1.683 +                        if (tTop < scrollTop) top = scrollTop + 5;
   1.684 +                        if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
   1.685 +                        break;
   1.686 +                    case 'n':
   1.687 +                        left = pos[0] - (width / 2) - 5;
   1.688 +                        top = pos[1] + distance;
   1.689 +                        tLeft = tooltipLeft(tooltipElem);
   1.690 +                        tTop = tooltipTop(tooltipElem);
   1.691 +                        if (tLeft < scrollLeft) left = scrollLeft + 5;
   1.692 +                        if (tLeft + width > windowWidth) left = left - width/2 + 5;
   1.693 +                        if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height;
   1.694 +                        break;
   1.695 +                    case 's':
   1.696 +                        left = pos[0] - (width / 2);
   1.697 +                        top = pos[1] - height - distance;
   1.698 +                        tLeft = tooltipLeft(tooltipElem);
   1.699 +                        tTop = tooltipTop(tooltipElem);
   1.700 +                        if (tLeft < scrollLeft) left = scrollLeft + 5;
   1.701 +                        if (tLeft + width > windowWidth) left = left - width/2 + 5;
   1.702 +                        if (scrollTop > tTop) top = scrollTop;
   1.703 +                        break;
   1.704 +                    case 'none':
   1.705 +                        left = pos[0];
   1.706 +                        top = pos[1] - distance;
   1.707 +                        tLeft = tooltipLeft(tooltipElem);
   1.708 +                        tTop = tooltipTop(tooltipElem);
   1.709 +                        break;
   1.710 +                }
   1.711 +                
   1.712 +                // adjust tooltip offsets
   1.713 +                left -= offset.left;
   1.714 +                top -= offset.top;
   1.715 +
   1.716 +                // using tooltip.style('transform') returns values un-usable for tween
   1.717 +                var box = tooltipElem.getBoundingClientRect();
   1.718 +                var scrollTop  = window.pageYOffset || document.documentElement.scrollTop;
   1.719 +                var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
   1.720 +                var old_translate = 'translate(' + (box.left + scrollLeft) + 'px, ' + (box.top + scrollTop) + 'px)';
   1.721 +                var new_translate = 'translate(' + left + 'px, ' + top + 'px)';
   1.722 +                var translateInterpolator = d3.interpolateString(old_translate, new_translate);
   1.723 +
   1.724 +                var is_hidden = tooltip.style('opacity') < 0.1;
   1.725 +
   1.726 +                // delay hiding a bit to avoid flickering
   1.727 +                if (hidden) {
   1.728 +                    tooltip
   1.729 +                        .transition()
   1.730 +                        .delay(hideDelay)
   1.731 +                        .duration(0)
   1.732 +                        .style('opacity', 0);
   1.733 +                } else {
   1.734 +                    tooltip
   1.735 +                        .interrupt() // cancel running transitions
   1.736 +                        .transition()
   1.737 +                        .duration(is_hidden ? 0 : duration)
   1.738 +                        // using tween since some versions of d3 can't auto-tween a translate on a div
   1.739 +                        .styleTween('transform', function (d) {
   1.740 +                            return translateInterpolator;
   1.741 +                        }, 'important')
   1.742 +                        // Safari has its own `-webkit-transform` and does not support `transform` 
   1.743 +                        // transform tooltip without transition only in Safari
   1.744 +                        .style('-webkit-transform', new_translate)
   1.745 +                        .style('opacity', 1);
   1.746 +                }
   1.747 +
   1.748 +
   1.749 +
   1.750 +            });
   1.751 +        };
   1.752 +
   1.753 +        //In situations where the chart is in a 'viewBox', re-position the tooltip based on how far chart is zoomed.
   1.754 +        function convertViewBoxRatio() {
   1.755 +            if (chartContainer) {
   1.756 +                var svg = d3.select(chartContainer);
   1.757 +                if (svg.node().tagName !== "svg") {
   1.758 +                    svg = svg.select("svg");
   1.759 +                }
   1.760 +                var viewBox = (svg.node()) ? svg.attr('viewBox') : null;
   1.761 +                if (viewBox) {
   1.762 +                    viewBox = viewBox.split(' ');
   1.763 +                    var ratio = parseInt(svg.style('width'), 10) / viewBox[2];
   1.764 +
   1.765 +                    position.left = position.left * ratio;
   1.766 +                    position.top  = position.top * ratio;
   1.767 +                }
   1.768 +            }
   1.769 +        }
   1.770 +
   1.771 +        //Creates new tooltip container, or uses existing one on DOM.
   1.772 +        function initTooltip() {
   1.773 +            if (!tooltip) {
   1.774 +                var body;
   1.775 +                if (chartContainer) {
   1.776 +                    body = chartContainer;
   1.777 +                } else {
   1.778 +                    body = document.body;
   1.779 +                }
   1.780 +                //Create new tooltip div if it doesn't exist on DOM.
   1.781 +                tooltip = d3.select(body).append("div")
   1.782 +                    .attr("class", "nvtooltip " + (classes ? classes : "xy-tooltip"))
   1.783 +                    .attr("id", id);
   1.784 +                tooltip.style("top", 0).style("left", 0);
   1.785 +                tooltip.style('opacity', 0);
   1.786 +                tooltip.selectAll("div, table, td, tr").classed(nvPointerEventsClass, true);
   1.787 +                tooltip.classed(nvPointerEventsClass, true);
   1.788 +                tooltipElem = tooltip.node();
   1.789 +            }
   1.790 +        }
   1.791 +
   1.792 +        //Draw the tooltip onto the DOM.
   1.793 +        function nvtooltip() {
   1.794 +            if (!enabled) return;
   1.795 +            if (!dataSeriesExists(data)) return;
   1.796 +
   1.797 +            convertViewBoxRatio();
   1.798 +
   1.799 +            var left = position.left;
   1.800 +            var top = (fixedTop !== null) ? fixedTop : position.top;
   1.801 +
   1.802 +            nv.dom.write(function () {
   1.803 +                initTooltip();
   1.804 +                // generate data and set it into tooltip
   1.805 +                // Bonus - If you override contentGenerator and return falsey you can use something like
   1.806 +                //         React or Knockout to bind the data for your tooltip
   1.807 +                var newContent = contentGenerator(data);
   1.808 +                if (newContent) {
   1.809 +                    tooltipElem.innerHTML = newContent;
   1.810 +                }
   1.811 +
   1.812 +                if (chartContainer && isInteractiveLayer) {
   1.813 +                    nv.dom.read(function() {
   1.814 +                        var svgComp = chartContainer.getElementsByTagName("svg")[0];
   1.815 +                        var svgOffset = {left:0,top:0};
   1.816 +                        if (svgComp) {
   1.817 +                            var svgBound = svgComp.getBoundingClientRect();
   1.818 +                            var chartBound = chartContainer.getBoundingClientRect();
   1.819 +                            var svgBoundTop = svgBound.top;
   1.820 +
   1.821 +                            //Defensive code. Sometimes, svgBoundTop can be a really negative
   1.822 +                            //  number, like -134254. That's a bug.
   1.823 +                            //  If such a number is found, use zero instead. FireFox bug only
   1.824 +                            if (svgBoundTop < 0) {
   1.825 +                                var containerBound = chartContainer.getBoundingClientRect();
   1.826 +                                svgBoundTop = (Math.abs(svgBoundTop) > containerBound.height) ? 0 : svgBoundTop;
   1.827 +                            }
   1.828 +                            svgOffset.top = Math.abs(svgBoundTop - chartBound.top);
   1.829 +                            svgOffset.left = Math.abs(svgBound.left - chartBound.left);
   1.830 +                        }
   1.831 +                        //If the parent container is an overflow <div> with scrollbars, subtract the scroll offsets.
   1.832 +                        //You need to also add any offset between the <svg> element and its containing <div>
   1.833 +                        //Finally, add any offset of the containing <div> on the whole page.
   1.834 +                        left += chartContainer.offsetLeft + svgOffset.left - 2*chartContainer.scrollLeft;
   1.835 +                        top += chartContainer.offsetTop + svgOffset.top - 2*chartContainer.scrollTop;
   1.836 +
   1.837 +                        if (snapDistance && snapDistance > 0) {
   1.838 +                            top = Math.floor(top/snapDistance) * snapDistance;
   1.839 +                        }
   1.840 +                        calcTooltipPosition([left,top]);
   1.841 +                    });
   1.842 +                } else {
   1.843 +                    calcTooltipPosition([left,top]);
   1.844 +                }
   1.845 +            });
   1.846 +
   1.847 +            return nvtooltip;
   1.848 +        }
   1.849 +
   1.850 +        nvtooltip.nvPointerEventsClass = nvPointerEventsClass;
   1.851 +        nvtooltip.options = nv.utils.optionsFunc.bind(nvtooltip);
   1.852 +
   1.853 +        nvtooltip._options = Object.create({}, {
   1.854 +            // simple read/write options
   1.855 +            duration: {get: function(){return duration;}, set: function(_){duration=_;}},
   1.856 +            gravity: {get: function(){return gravity;}, set: function(_){gravity=_;}},
   1.857 +            distance: {get: function(){return distance;}, set: function(_){distance=_;}},
   1.858 +            snapDistance: {get: function(){return snapDistance;}, set: function(_){snapDistance=_;}},
   1.859 +            classes: {get: function(){return classes;}, set: function(_){classes=_;}},
   1.860 +            chartContainer: {get: function(){return chartContainer;}, set: function(_){chartContainer=_;}},
   1.861 +            fixedTop: {get: function(){return fixedTop;}, set: function(_){fixedTop=_;}},
   1.862 +            enabled: {get: function(){return enabled;}, set: function(_){enabled=_;}},
   1.863 +            hideDelay: {get: function(){return hideDelay;}, set: function(_){hideDelay=_;}},
   1.864 +            contentGenerator: {get: function(){return contentGenerator;}, set: function(_){contentGenerator=_;}},
   1.865 +            valueFormatter: {get: function(){return valueFormatter;}, set: function(_){valueFormatter=_;}},
   1.866 +            headerFormatter: {get: function(){return headerFormatter;}, set: function(_){headerFormatter=_;}},
   1.867 +            keyFormatter: {get: function(){return keyFormatter;}, set: function(_){keyFormatter=_;}},
   1.868 +            headerEnabled:   {get: function(){return headerEnabled;}, set: function(_){headerEnabled=_;}},
   1.869 +
   1.870 +            // internal use only, set by interactive layer to adjust position.
   1.871 +            _isInteractiveLayer: {get: function(){return isInteractiveLayer;}, set: function(_){isInteractiveLayer=!!_;}},
   1.872 +
   1.873 +            // options with extra logic
   1.874 +            position: {get: function(){return position;}, set: function(_){
   1.875 +                position.left = _.left !== undefined ? _.left : position.left;
   1.876 +                position.top  = _.top  !== undefined ? _.top  : position.top;
   1.877 +            }},
   1.878 +            offset: {get: function(){return offset;}, set: function(_){
   1.879 +                offset.left = _.left !== undefined ? _.left : offset.left;
   1.880 +                offset.top  = _.top  !== undefined ? _.top  : offset.top;
   1.881 +            }},
   1.882 +            hidden: {get: function(){return hidden;}, set: function(_){
   1.883 +                if (hidden != _) {
   1.884 +                    hidden = !!_;
   1.885 +                    nvtooltip();
   1.886 +                }
   1.887 +            }},
   1.888 +            data: {get: function(){return data;}, set: function(_){
   1.889 +                // if showing a single data point, adjust data format with that
   1.890 +                if (_.point) {
   1.891 +                    _.value = _.point.x;
   1.892 +                    _.series = _.series || {};
   1.893 +                    _.series.value = _.point.y;
   1.894 +                    _.series.color = _.point.color || _.series.color;
   1.895 +                }
   1.896 +                data = _;
   1.897 +            }},
   1.898 +
   1.899 +            // read only properties
   1.900 +            tooltipElem: {get: function(){return tooltipElem;}, set: function(_){}},
   1.901 +            id: {get: function(){return id;}, set: function(_){}}
   1.902 +        });
   1.903 +
   1.904 +        nv.utils.initOptions(nvtooltip);
   1.905 +        return nvtooltip;
   1.906 +    };
   1.907 +
   1.908 +})();
   1.909 +
   1.910 +
   1.911 +/*
   1.912 +Gets the browser window size
   1.913 +
   1.914 +Returns object with height and width properties
   1.915 + */
   1.916 +nv.utils.windowSize = function() {
   1.917 +    // Sane defaults
   1.918 +    var size = {width: 640, height: 480};
   1.919 +
   1.920 +    // Most recent browsers use
   1.921 +    if (window.innerWidth && window.innerHeight) {
   1.922 +        size.width = window.innerWidth;
   1.923 +        size.height = window.innerHeight;
   1.924 +        return (size);
   1.925 +    }
   1.926 +
   1.927 +    // IE can use depending on mode it is in
   1.928 +    if (document.compatMode=='CSS1Compat' &&
   1.929 +        document.documentElement &&
   1.930 +        document.documentElement.offsetWidth ) {
   1.931 +
   1.932 +        size.width = document.documentElement.offsetWidth;
   1.933 +        size.height = document.documentElement.offsetHeight;
   1.934 +        return (size);
   1.935 +    }
   1.936 +
   1.937 +    // Earlier IE uses Doc.body
   1.938 +    if (document.body && document.body.offsetWidth) {
   1.939 +        size.width = document.body.offsetWidth;
   1.940 +        size.height = document.body.offsetHeight;
   1.941 +        return (size);
   1.942 +    }
   1.943 +
   1.944 +    return (size);
   1.945 +};
   1.946 +
   1.947 +/*
   1.948 +Binds callback function to run when window is resized
   1.949 + */
   1.950 +nv.utils.windowResize = function(handler) {
   1.951 +    if (window.addEventListener) {
   1.952 +        window.addEventListener('resize', handler);
   1.953 +    } else {
   1.954 +        nv.log("ERROR: Failed to bind to window.resize with: ", handler);
   1.955 +    }
   1.956 +    // return object with clear function to remove the single added callback.
   1.957 +    return {
   1.958 +        callback: handler,
   1.959 +        clear: function() {
   1.960 +            window.removeEventListener('resize', handler);
   1.961 +        }
   1.962 +    }
   1.963 +};
   1.964 +
   1.965 +
   1.966 +/*
   1.967 +Backwards compatible way to implement more d3-like coloring of graphs.
   1.968 +Can take in nothing, an array, or a function/scale
   1.969 +To use a normal scale, get the range and pass that because we must be able
   1.970 +to take two arguments and use the index to keep backward compatibility
   1.971 +*/
   1.972 +nv.utils.getColor = function(color) {
   1.973 +    //if you pass in nothing, get default colors back
   1.974 +    if (color === undefined) {
   1.975 +        return nv.utils.defaultColor();
   1.976 +
   1.977 +    //if passed an array, turn it into a color scale
   1.978 +    // use isArray, instanceof fails if d3 range is created in an iframe
   1.979 +    } else if(Array.isArray(color)) {
   1.980 +        var color_scale = d3.scale.ordinal().range(color);
   1.981 +        return function(d, i) {
   1.982 +            var key = i === undefined ? d : i;
   1.983 +            return d.color || color_scale(key);
   1.984 +        };
   1.985 +
   1.986 +    //if passed a function or scale, return it, or whatever it may be
   1.987 +    //external libs, such as angularjs-nvd3-directives use this
   1.988 +    } else {
   1.989 +        //can't really help it if someone passes rubbish as color
   1.990 +        return color;
   1.991 +    }
   1.992 +};
   1.993 +
   1.994 +
   1.995 +/*
   1.996 +Default color chooser uses a color scale of 20 colors from D3
   1.997 + https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors
   1.998 + */
   1.999 +nv.utils.defaultColor = function() {
  1.1000 +    // get range of the scale so we'll turn it into our own function.
  1.1001 +    return nv.utils.getColor(d3.scale.category20().range());
  1.1002 +};
  1.1003 +
  1.1004 +
  1.1005 +/*
  1.1006 +Returns a color function that takes the result of 'getKey' for each series and
  1.1007 +looks for a corresponding color from the dictionary
  1.1008 +*/
  1.1009 +nv.utils.customTheme = function(dictionary, getKey, defaultColors) {
  1.1010 +    // use default series.key if getKey is undefined
  1.1011 +    getKey = getKey || function(series) { return series.key };
  1.1012 +    defaultColors = defaultColors || d3.scale.category20().range();
  1.1013 +
  1.1014 +    // start at end of default color list and walk back to index 0
  1.1015 +    var defIndex = defaultColors.length;
  1.1016 +
  1.1017 +    return function(series, index) {
  1.1018 +        var key = getKey(series);
  1.1019 +        if (typeof dictionary[key] === 'function') {
  1.1020 +            return dictionary[key]();
  1.1021 +        } else if (dictionary[key] !== undefined) {
  1.1022 +            return dictionary[key];
  1.1023 +        } else {
  1.1024 +            // no match in dictionary, use a default color
  1.1025 +            if (!defIndex) {
  1.1026 +                // used all the default colors, start over
  1.1027 +                defIndex = defaultColors.length;
  1.1028 +            }
  1.1029 +            defIndex = defIndex - 1;
  1.1030 +            return defaultColors[defIndex];
  1.1031 +        }
  1.1032 +    };
  1.1033 +};
  1.1034 +
  1.1035 +
  1.1036 +/*
  1.1037 +From the PJAX example on d3js.org, while this is not really directly needed
  1.1038 +it's a very cool method for doing pjax, I may expand upon it a little bit,
  1.1039 +open to suggestions on anything that may be useful
  1.1040 +*/
  1.1041 +nv.utils.pjax = function(links, content) {
  1.1042 +
  1.1043 +    var load = function(href) {
  1.1044 +        d3.html(href, function(fragment) {
  1.1045 +            var target = d3.select(content).node();
  1.1046 +            target.parentNode.replaceChild(
  1.1047 +                d3.select(fragment).select(content).node(),
  1.1048 +                target);
  1.1049 +            nv.utils.pjax(links, content);
  1.1050 +        });
  1.1051 +    };
  1.1052 +
  1.1053 +    d3.selectAll(links).on("click", function() {
  1.1054 +        history.pushState(this.href, this.textContent, this.href);
  1.1055 +        load(this.href);
  1.1056 +        d3.event.preventDefault();
  1.1057 +    });
  1.1058 +
  1.1059 +    d3.select(window).on("popstate", function() {
  1.1060 +        if (d3.event.state) {
  1.1061 +            load(d3.event.state);
  1.1062 +        }
  1.1063 +    });
  1.1064 +};
  1.1065 +
  1.1066 +
  1.1067 +/*
  1.1068 +For when we want to approximate the width in pixels for an SVG:text element.
  1.1069 +Most common instance is when the element is in a display:none; container.
  1.1070 +Forumla is : text.length * font-size * constant_factor
  1.1071 +*/
  1.1072 +nv.utils.calcApproxTextWidth = function (svgTextElem) {
  1.1073 +    if (typeof svgTextElem.style === 'function'
  1.1074 +        && typeof svgTextElem.text === 'function') {
  1.1075 +
  1.1076 +        var fontSize = parseInt(svgTextElem.style("font-size").replace("px",""), 10);
  1.1077 +        var textLength = svgTextElem.text().length;
  1.1078 +        return textLength * fontSize * 0.5;
  1.1079 +    }
  1.1080 +    return 0;
  1.1081 +};
  1.1082 +
  1.1083 +
  1.1084 +/*
  1.1085 +Numbers that are undefined, null or NaN, convert them to zeros.
  1.1086 +*/
  1.1087 +nv.utils.NaNtoZero = function(n) {
  1.1088 +    if (typeof n !== 'number'
  1.1089 +        || isNaN(n)
  1.1090 +        || n === null
  1.1091 +        || n === Infinity
  1.1092 +        || n === -Infinity) {
  1.1093 +
  1.1094 +        return 0;
  1.1095 +    }
  1.1096 +    return n;
  1.1097 +};
  1.1098 +
  1.1099 +/*
  1.1100 +Add a way to watch for d3 transition ends to d3
  1.1101 +*/
  1.1102 +d3.selection.prototype.watchTransition = function(renderWatch){
  1.1103 +    var args = [this].concat([].slice.call(arguments, 1));
  1.1104 +    return renderWatch.transition.apply(renderWatch, args);
  1.1105 +};
  1.1106 +
  1.1107 +
  1.1108 +/*
  1.1109 +Helper object to watch when d3 has rendered something
  1.1110 +*/
  1.1111 +nv.utils.renderWatch = function(dispatch, duration) {
  1.1112 +    if (!(this instanceof nv.utils.renderWatch)) {
  1.1113 +        return new nv.utils.renderWatch(dispatch, duration);
  1.1114 +    }
  1.1115 +
  1.1116 +    var _duration = duration !== undefined ? duration : 250;
  1.1117 +    var renderStack = [];
  1.1118 +    var self = this;
  1.1119 +
  1.1120 +    this.models = function(models) {
  1.1121 +        models = [].slice.call(arguments, 0);
  1.1122 +        models.forEach(function(model){
  1.1123 +            model.__rendered = false;
  1.1124 +            (function(m){
  1.1125 +                m.dispatch.on('renderEnd', function(arg){
  1.1126 +                    m.__rendered = true;
  1.1127 +                    self.renderEnd('model');
  1.1128 +                });
  1.1129 +            })(model);
  1.1130 +
  1.1131 +            if (renderStack.indexOf(model) < 0) {
  1.1132 +                renderStack.push(model);
  1.1133 +            }
  1.1134 +        });
  1.1135 +    return this;
  1.1136 +    };
  1.1137 +
  1.1138 +    this.reset = function(duration) {
  1.1139 +        if (duration !== undefined) {
  1.1140 +            _duration = duration;
  1.1141 +        }
  1.1142 +        renderStack = [];
  1.1143 +    };
  1.1144 +
  1.1145 +    this.transition = function(selection, args, duration) {
  1.1146 +        args = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
  1.1147 +
  1.1148 +        if (args.length > 1) {
  1.1149 +            duration = args.pop();
  1.1150 +        } else {
  1.1151 +            duration = _duration !== undefined ? _duration : 250;
  1.1152 +        }
  1.1153 +        selection.__rendered = false;
  1.1154 +
  1.1155 +        if (renderStack.indexOf(selection) < 0) {
  1.1156 +            renderStack.push(selection);
  1.1157 +        }
  1.1158 +
  1.1159 +        if (duration === 0) {
  1.1160 +            selection.__rendered = true;
  1.1161 +            selection.delay = function() { return this; };
  1.1162 +            selection.duration = function() { return this; };
  1.1163 +            return selection;
  1.1164 +        } else {
  1.1165 +            if (selection.length === 0) {
  1.1166 +                selection.__rendered = true;
  1.1167 +            } else if (selection.every( function(d){ return !d.length; } )) {
  1.1168 +                selection.__rendered = true;
  1.1169 +            } else {
  1.1170 +                selection.__rendered = false;
  1.1171 +            }
  1.1172 +
  1.1173 +            var n = 0;
  1.1174 +            return selection
  1.1175 +                .transition()
  1.1176 +                .duration(duration)
  1.1177 +                .each(function(){ ++n; })
  1.1178 +                .each('end', function(d, i) {
  1.1179 +                    if (--n === 0) {
  1.1180 +                        selection.__rendered = true;
  1.1181 +                        self.renderEnd.apply(this, args);
  1.1182 +                    }
  1.1183 +                });
  1.1184 +        }
  1.1185 +    };
  1.1186 +
  1.1187 +    this.renderEnd = function() {
  1.1188 +        if (renderStack.every( function(d){ return d.__rendered; } )) {
  1.1189 +            renderStack.forEach( function(d){ d.__rendered = false; });
  1.1190 +            dispatch.renderEnd.apply(this, arguments);
  1.1191 +        }
  1.1192 +    }
  1.1193 +
  1.1194 +};
  1.1195 +
  1.1196 +
  1.1197 +/*
  1.1198 +Takes multiple objects and combines them into the first one (dst)
  1.1199 +example:  nv.utils.deepExtend({a: 1}, {a: 2, b: 3}, {c: 4});
  1.1200 +gives:  {a: 2, b: 3, c: 4}
  1.1201 +*/
  1.1202 +nv.utils.deepExtend = function(dst){
  1.1203 +    var sources = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
  1.1204 +    sources.forEach(function(source) {
  1.1205 +        for (var key in source) {
  1.1206 +            var isArray = dst[key] instanceof Array;
  1.1207 +            var isObject = typeof dst[key] === 'object';
  1.1208 +            var srcObj = typeof source[key] === 'object';
  1.1209 +
  1.1210 +            if (isObject && !isArray && srcObj) {
  1.1211 +                nv.utils.deepExtend(dst[key], source[key]);
  1.1212 +            } else {
  1.1213 +                dst[key] = source[key];
  1.1214 +            }
  1.1215 +        }
  1.1216 +    });
  1.1217 +};
  1.1218 +
  1.1219 +
  1.1220 +/*
  1.1221 +state utility object, used to track d3 states in the models
  1.1222 +*/
  1.1223 +nv.utils.state = function(){
  1.1224 +    if (!(this instanceof nv.utils.state)) {
  1.1225 +        return new nv.utils.state();
  1.1226 +    }
  1.1227 +    var state = {};
  1.1228 +    var _self = this;
  1.1229 +    var _setState = function(){};
  1.1230 +    var _getState = function(){ return {}; };
  1.1231 +    var init = null;
  1.1232 +    var changed = null;
  1.1233 +
  1.1234 +    this.dispatch = d3.dispatch('change', 'set');
  1.1235 +
  1.1236 +    this.dispatch.on('set', function(state){
  1.1237 +        _setState(state, true);
  1.1238 +    });
  1.1239 +
  1.1240 +    this.getter = function(fn){
  1.1241 +        _getState = fn;
  1.1242 +        return this;
  1.1243 +    };
  1.1244 +
  1.1245 +    this.setter = function(fn, callback) {
  1.1246 +        if (!callback) {
  1.1247 +            callback = function(){};
  1.1248 +        }
  1.1249 +        _setState = function(state, update){
  1.1250 +            fn(state);
  1.1251 +            if (update) {
  1.1252 +                callback();
  1.1253 +            }
  1.1254 +        };
  1.1255 +        return this;
  1.1256 +    };
  1.1257 +
  1.1258 +    this.init = function(state){
  1.1259 +        init = init || {};
  1.1260 +        nv.utils.deepExtend(init, state);
  1.1261 +    };
  1.1262 +
  1.1263 +    var _set = function(){
  1.1264 +        var settings = _getState();
  1.1265 +
  1.1266 +        if (JSON.stringify(settings) === JSON.stringify(state)) {
  1.1267 +            return false;
  1.1268 +        }
  1.1269 +
  1.1270 +        for (var key in settings) {
  1.1271 +            if (state[key] === undefined) {
  1.1272 +                state[key] = {};
  1.1273 +            }
  1.1274 +            state[key] = settings[key];
  1.1275 +            changed = true;
  1.1276 +        }
  1.1277 +        return true;
  1.1278 +    };
  1.1279 +
  1.1280 +    this.update = function(){
  1.1281 +        if (init) {
  1.1282 +            _setState(init, false);
  1.1283 +            init = null;
  1.1284 +        }
  1.1285 +        if (_set.call(this)) {
  1.1286 +            this.dispatch.change(state);
  1.1287 +        }
  1.1288 +    };
  1.1289 +
  1.1290 +};
  1.1291 +
  1.1292 +
  1.1293 +/*
  1.1294 +Snippet of code you can insert into each nv.models.* to give you the ability to
  1.1295 +do things like:
  1.1296 +chart.options({
  1.1297 +  showXAxis: true,
  1.1298 +  tooltips: true
  1.1299 +});
  1.1300 +
  1.1301 +To enable in the chart:
  1.1302 +chart.options = nv.utils.optionsFunc.bind(chart);
  1.1303 +*/
  1.1304 +nv.utils.optionsFunc = function(args) {
  1.1305 +    if (args) {
  1.1306 +        d3.map(args).forEach((function(key,value) {
  1.1307 +            if (typeof this[key] === "function") {
  1.1308 +                this[key](value);
  1.1309 +            }
  1.1310 +        }).bind(this));
  1.1311 +    }
  1.1312 +    return this;
  1.1313 +};
  1.1314 +
  1.1315 +
  1.1316 +/*
  1.1317 +numTicks:  requested number of ticks
  1.1318 +data:  the chart data
  1.1319 +
  1.1320 +returns the number of ticks to actually use on X axis, based on chart data
  1.1321 +to avoid duplicate ticks with the same value
  1.1322 +*/
  1.1323 +nv.utils.calcTicksX = function(numTicks, data) {
  1.1324 +    // find max number of values from all data streams
  1.1325 +    var numValues = 1;
  1.1326 +    var i = 0;
  1.1327 +    for (i; i < data.length; i += 1) {
  1.1328 +        var stream_len = data[i] && data[i].values ? data[i].values.length : 0;
  1.1329 +        numValues = stream_len > numValues ? stream_len : numValues;
  1.1330 +    }
  1.1331 +    nv.log("Requested number of ticks: ", numTicks);
  1.1332 +    nv.log("Calculated max values to be: ", numValues);
  1.1333 +    // make sure we don't have more ticks than values to avoid duplicates
  1.1334 +    numTicks = numTicks > numValues ? numTicks = numValues - 1 : numTicks;
  1.1335 +    // make sure we have at least one tick
  1.1336 +    numTicks = numTicks < 1 ? 1 : numTicks;
  1.1337 +    // make sure it's an integer
  1.1338 +    numTicks = Math.floor(numTicks);
  1.1339 +    nv.log("Calculating tick count as: ", numTicks);
  1.1340 +    return numTicks;
  1.1341 +};
  1.1342 +
  1.1343 +
  1.1344 +/*
  1.1345 +returns number of ticks to actually use on Y axis, based on chart data
  1.1346 +*/
  1.1347 +nv.utils.calcTicksY = function(numTicks, data) {
  1.1348 +    // currently uses the same logic but we can adjust here if needed later
  1.1349 +    return nv.utils.calcTicksX(numTicks, data);
  1.1350 +};
  1.1351 +
  1.1352 +
  1.1353 +/*
  1.1354 +Add a particular option from an options object onto chart
  1.1355 +Options exposed on a chart are a getter/setter function that returns chart
  1.1356 +on set to mimic typical d3 option chaining, e.g. svg.option1('a').option2('b');
  1.1357 +
  1.1358 +option objects should be generated via Object.create() to provide
  1.1359 +the option of manipulating data via get/set functions.
  1.1360 +*/
  1.1361 +nv.utils.initOption = function(chart, name) {
  1.1362 +    // if it's a call option, just call it directly, otherwise do get/set
  1.1363 +    if (chart._calls && chart._calls[name]) {
  1.1364 +        chart[name] = chart._calls[name];
  1.1365 +    } else {
  1.1366 +        chart[name] = function (_) {
  1.1367 +            if (!arguments.length) return chart._options[name];
  1.1368 +            chart._overrides[name] = true;
  1.1369 +            chart._options[name] = _;
  1.1370 +            return chart;
  1.1371 +        };
  1.1372 +        // calling the option as _option will ignore if set by option already
  1.1373 +        // so nvd3 can set options internally but the stop if set manually
  1.1374 +        chart['_' + name] = function(_) {
  1.1375 +            if (!arguments.length) return chart._options[name];
  1.1376 +            if (!chart._overrides[name]) {
  1.1377 +                chart._options[name] = _;
  1.1378 +            }
  1.1379 +            return chart;
  1.1380 +        }
  1.1381 +    }
  1.1382 +};
  1.1383 +
  1.1384 +
  1.1385 +/*
  1.1386 +Add all options in an options object to the chart
  1.1387 +*/
  1.1388 +nv.utils.initOptions = function(chart) {
  1.1389 +    chart._overrides = chart._overrides || {};
  1.1390 +    var ops = Object.getOwnPropertyNames(chart._options || {});
  1.1391 +    var calls = Object.getOwnPropertyNames(chart._calls || {});
  1.1392 +    ops = ops.concat(calls);
  1.1393 +    for (var i in ops) {
  1.1394 +        nv.utils.initOption(chart, ops[i]);
  1.1395 +    }
  1.1396 +};
  1.1397 +
  1.1398 +
  1.1399 +/*
  1.1400 +Inherit options from a D3 object
  1.1401 +d3.rebind makes calling the function on target actually call it on source
  1.1402 +Also use _d3options so we can track what we inherit for documentation and chained inheritance
  1.1403 +*/
  1.1404 +nv.utils.inheritOptionsD3 = function(target, d3_source, oplist) {
  1.1405 +    target._d3options = oplist.concat(target._d3options || []);
  1.1406 +    oplist.unshift(d3_source);
  1.1407 +    oplist.unshift(target);
  1.1408 +    d3.rebind.apply(this, oplist);
  1.1409 +};
  1.1410 +
  1.1411 +
  1.1412 +/*
  1.1413 +Remove duplicates from an array
  1.1414 +*/
  1.1415 +nv.utils.arrayUnique = function(a) {
  1.1416 +    return a.sort().filter(function(item, pos) {
  1.1417 +        return !pos || item != a[pos - 1];
  1.1418 +    });
  1.1419 +};
  1.1420 +
  1.1421 +
  1.1422 +/*
  1.1423 +Keeps a list of custom symbols to draw from in addition to d3.svg.symbol
  1.1424 +Necessary since d3 doesn't let you extend its list -_-
  1.1425 +Add new symbols by doing nv.utils.symbols.set('name', function(size){...});
  1.1426 +*/
  1.1427 +nv.utils.symbolMap = d3.map();
  1.1428 +
  1.1429 +
  1.1430 +/*
  1.1431 +Replaces d3.svg.symbol so that we can look both there and our own map
  1.1432 + */
  1.1433 +nv.utils.symbol = function() {
  1.1434 +    var type,
  1.1435 +        size = 64;
  1.1436 +    function symbol(d,i) {
  1.1437 +        var t = type.call(this,d,i);
  1.1438 +        var s = size.call(this,d,i);
  1.1439 +        if (d3.svg.symbolTypes.indexOf(t) !== -1) {
  1.1440 +            return d3.svg.symbol().type(t).size(s)();
  1.1441 +        } else {
  1.1442 +            return nv.utils.symbolMap.get(t)(s);
  1.1443 +        }
  1.1444 +    }
  1.1445 +    symbol.type = function(_) {
  1.1446 +        if (!arguments.length) return type;
  1.1447 +        type = d3.functor(_);
  1.1448 +        return symbol;
  1.1449 +    };
  1.1450 +    symbol.size = function(_) {
  1.1451 +        if (!arguments.length) return size;
  1.1452 +        size = d3.functor(_);
  1.1453 +        return symbol;
  1.1454 +    };
  1.1455 +    return symbol;
  1.1456 +};
  1.1457 +
  1.1458 +
  1.1459 +/*
  1.1460 +Inherit option getter/setter functions from source to target
  1.1461 +d3.rebind makes calling the function on target actually call it on source
  1.1462 +Also track via _inherited and _d3options so we can track what we inherit
  1.1463 +for documentation generation purposes and chained inheritance
  1.1464 +*/
  1.1465 +nv.utils.inheritOptions = function(target, source) {
  1.1466 +    // inherit all the things
  1.1467 +    var ops = Object.getOwnPropertyNames(source._options || {});
  1.1468 +    var calls = Object.getOwnPropertyNames(source._calls || {});
  1.1469 +    var inherited = source._inherited || [];
  1.1470 +    var d3ops = source._d3options || [];
  1.1471 +    var args = ops.concat(calls).concat(inherited).concat(d3ops);
  1.1472 +    args.unshift(source);
  1.1473 +    args.unshift(target);
  1.1474 +    d3.rebind.apply(this, args);
  1.1475 +    // pass along the lists to keep track of them, don't allow duplicates
  1.1476 +    target._inherited = nv.utils.arrayUnique(ops.concat(calls).concat(inherited).concat(ops).concat(target._inherited || []));
  1.1477 +    target._d3options = nv.utils.arrayUnique(d3ops.concat(target._d3options || []));
  1.1478 +};
  1.1479 +
  1.1480 +
  1.1481 +/*
  1.1482 +Runs common initialize code on the svg before the chart builds
  1.1483 +*/
  1.1484 +nv.utils.initSVG = function(svg) {
  1.1485 +    svg.classed({'nvd3-svg':true});
  1.1486 +};
  1.1487 +
  1.1488 +
  1.1489 +/*
  1.1490 +Sanitize and provide default for the container height.
  1.1491 +*/
  1.1492 +nv.utils.sanitizeHeight = function(height, container) {
  1.1493 +    return (height || parseInt(container.style('height'), 10) || 400);
  1.1494 +};
  1.1495 +
  1.1496 +
  1.1497 +/*
  1.1498 +Sanitize and provide default for the container width.
  1.1499 +*/
  1.1500 +nv.utils.sanitizeWidth = function(width, container) {
  1.1501 +    return (width || parseInt(container.style('width'), 10) || 960);
  1.1502 +};
  1.1503 +
  1.1504 +
  1.1505 +/*
  1.1506 +Calculate the available height for a chart.
  1.1507 +*/
  1.1508 +nv.utils.availableHeight = function(height, container, margin) {
  1.1509 +    return nv.utils.sanitizeHeight(height, container) - margin.top - margin.bottom;
  1.1510 +};
  1.1511 +
  1.1512 +/*
  1.1513 +Calculate the available width for a chart.
  1.1514 +*/
  1.1515 +nv.utils.availableWidth = function(width, container, margin) {
  1.1516 +    return nv.utils.sanitizeWidth(width, container) - margin.left - margin.right;
  1.1517 +};
  1.1518 +
  1.1519 +/*
  1.1520 +Clear any rendered chart components and display a chart's 'noData' message
  1.1521 +*/
  1.1522 +nv.utils.noData = function(chart, container) {
  1.1523 +    var opt = chart.options(),
  1.1524 +        margin = opt.margin(),
  1.1525 +        noData = opt.noData(),
  1.1526 +        data = (noData == null) ? ["No Data Available."] : [noData],
  1.1527 +        height = nv.utils.availableHeight(opt.height(), container, margin),
  1.1528 +        width = nv.utils.availableWidth(opt.width(), container, margin),
  1.1529 +        x = margin.left + width/2,
  1.1530 +        y = margin.top + height/2;
  1.1531 +
  1.1532 +    //Remove any previously created chart components
  1.1533 +    container.selectAll('g').remove();
  1.1534 +
  1.1535 +    var noDataText = container.selectAll('.nv-noData').data(data);
  1.1536 +
  1.1537 +    noDataText.enter().append('text')
  1.1538 +        .attr('class', 'nvd3 nv-noData')
  1.1539 +        .attr('dy', '-.7em')
  1.1540 +        .style('text-anchor', 'middle');
  1.1541 +
  1.1542 +    noDataText
  1.1543 +        .attr('x', x)
  1.1544 +        .attr('y', y)
  1.1545 +        .text(function(t){ return t; });
  1.1546 +};
  1.1547 +
  1.1548 +nv.models.axis = function() {
  1.1549 +    "use strict";
  1.1550 +
  1.1551 +    //============================================================
  1.1552 +    // Public Variables with Default Settings
  1.1553 +    //------------------------------------------------------------
  1.1554 +
  1.1555 +    var axis = d3.svg.axis();
  1.1556 +    var scale = d3.scale.linear();
  1.1557 +
  1.1558 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.1559 +        , width = 75 //only used for tickLabel currently
  1.1560 +        , height = 60 //only used for tickLabel currently
  1.1561 +        , axisLabelText = null
  1.1562 +        , showMaxMin = true //TODO: showMaxMin should be disabled on all ordinal scaled axes
  1.1563 +        , rotateLabels = 0
  1.1564 +        , rotateYLabel = true
  1.1565 +        , staggerLabels = false
  1.1566 +        , isOrdinal = false
  1.1567 +        , ticks = null
  1.1568 +        , axisLabelDistance = 0
  1.1569 +        , duration = 250
  1.1570 +        , dispatch = d3.dispatch('renderEnd')
  1.1571 +        ;
  1.1572 +    axis
  1.1573 +        .scale(scale)
  1.1574 +        .orient('bottom')
  1.1575 +        .tickFormat(function(d) { return d })
  1.1576 +    ;
  1.1577 +
  1.1578 +    //============================================================
  1.1579 +    // Private Variables
  1.1580 +    //------------------------------------------------------------
  1.1581 +
  1.1582 +    var scale0;
  1.1583 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.1584 +
  1.1585 +    function chart(selection) {
  1.1586 +        renderWatch.reset();
  1.1587 +        selection.each(function(data) {
  1.1588 +            var container = d3.select(this);
  1.1589 +            nv.utils.initSVG(container);
  1.1590 +
  1.1591 +            // Setup containers and skeleton of chart
  1.1592 +            var wrap = container.selectAll('g.nv-wrap.nv-axis').data([data]);
  1.1593 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-axis');
  1.1594 +            var gEnter = wrapEnter.append('g');
  1.1595 +            var g = wrap.select('g');
  1.1596 +
  1.1597 +            if (ticks !== null)
  1.1598 +                axis.ticks(ticks);
  1.1599 +            else if (axis.orient() == 'top' || axis.orient() == 'bottom')
  1.1600 +                axis.ticks(Math.abs(scale.range()[1] - scale.range()[0]) / 100);
  1.1601 +
  1.1602 +            //TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component
  1.1603 +            g.watchTransition(renderWatch, 'axis').call(axis);
  1.1604 +
  1.1605 +            scale0 = scale0 || axis.scale();
  1.1606 +
  1.1607 +            var fmt = axis.tickFormat();
  1.1608 +            if (fmt == null) {
  1.1609 +                fmt = scale0.tickFormat();
  1.1610 +            }
  1.1611 +
  1.1612 +            var axisLabel = g.selectAll('text.nv-axislabel')
  1.1613 +                .data([axisLabelText || null]);
  1.1614 +            axisLabel.exit().remove();
  1.1615 +
  1.1616 +            var xLabelMargin;
  1.1617 +            var axisMaxMin;
  1.1618 +            var w;
  1.1619 +            switch (axis.orient()) {
  1.1620 +                case 'top':
  1.1621 +                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
  1.1622 +                    if (scale.range().length < 2) {
  1.1623 +                        w = 0;
  1.1624 +                    } else if (scale.range().length === 2) {
  1.1625 +                        w = scale.range()[1];
  1.1626 +                    } else {
  1.1627 +                        w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]);
  1.1628 +                    }
  1.1629 +                    axisLabel
  1.1630 +                        .attr('text-anchor', 'middle')
  1.1631 +                        .attr('y', 0)
  1.1632 +                        .attr('x', w/2);
  1.1633 +                    if (showMaxMin) {
  1.1634 +                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
  1.1635 +                            .data(scale.domain());
  1.1636 +                        axisMaxMin.enter().append('g').attr('class',function(d,i){
  1.1637 +                                return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ')
  1.1638 +                        }).append('text');
  1.1639 +                        axisMaxMin.exit().remove();
  1.1640 +                        axisMaxMin
  1.1641 +                            .attr('transform', function(d,i) {
  1.1642 +                                return 'translate(' + nv.utils.NaNtoZero(scale(d)) + ',0)'
  1.1643 +                            })
  1.1644 +                            .select('text')
  1.1645 +                            .attr('dy', '-0.5em')
  1.1646 +                            .attr('y', -axis.tickPadding())
  1.1647 +                            .attr('text-anchor', 'middle')
  1.1648 +                            .text(function(d,i) {
  1.1649 +                                var v = fmt(d);
  1.1650 +                                return ('' + v).match('NaN') ? '' : v;
  1.1651 +                            });
  1.1652 +                        axisMaxMin.watchTransition(renderWatch, 'min-max top')
  1.1653 +                            .attr('transform', function(d,i) {
  1.1654 +                                return 'translate(' + nv.utils.NaNtoZero(scale.range()[i]) + ',0)'
  1.1655 +                            });
  1.1656 +                    }
  1.1657 +                    break;
  1.1658 +                case 'bottom':
  1.1659 +                    xLabelMargin = axisLabelDistance + 36;
  1.1660 +                    var maxTextWidth = 30;
  1.1661 +                    var textHeight = 0;
  1.1662 +                    var xTicks = g.selectAll('g').select("text");
  1.1663 +                    var rotateLabelsRule = '';
  1.1664 +                    if (rotateLabels%360) {
  1.1665 +                        //Calculate the longest xTick width
  1.1666 +                        xTicks.each(function(d,i){
  1.1667 +                            var box = this.getBoundingClientRect();
  1.1668 +                            var width = box.width;
  1.1669 +                            textHeight = box.height;
  1.1670 +                            if(width > maxTextWidth) maxTextWidth = width;
  1.1671 +                        });
  1.1672 +                        rotateLabelsRule = 'rotate(' + rotateLabels + ' 0,' + (textHeight/2 + axis.tickPadding()) + ')';
  1.1673 +                        //Convert to radians before calculating sin. Add 30 to margin for healthy padding.
  1.1674 +                        var sin = Math.abs(Math.sin(rotateLabels*Math.PI/180));
  1.1675 +                        xLabelMargin = (sin ? sin*maxTextWidth : maxTextWidth)+30;
  1.1676 +                        //Rotate all xTicks
  1.1677 +                        xTicks
  1.1678 +                            .attr('transform', rotateLabelsRule)
  1.1679 +                            .style('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end');
  1.1680 +                    }
  1.1681 +                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
  1.1682 +                    if (scale.range().length < 2) {
  1.1683 +                        w = 0;
  1.1684 +                    } else if (scale.range().length === 2) {
  1.1685 +                        w = scale.range()[1];
  1.1686 +                    } else {
  1.1687 +                        w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]);
  1.1688 +                    }
  1.1689 +                    axisLabel
  1.1690 +                        .attr('text-anchor', 'middle')
  1.1691 +                        .attr('y', xLabelMargin)
  1.1692 +                        .attr('x', w/2);
  1.1693 +                    if (showMaxMin) {
  1.1694 +                        //if (showMaxMin && !isOrdinal) {
  1.1695 +                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
  1.1696 +                            //.data(scale.domain())
  1.1697 +                            .data([scale.domain()[0], scale.domain()[scale.domain().length - 1]]);
  1.1698 +                        axisMaxMin.enter().append('g').attr('class',function(d,i){
  1.1699 +                                return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ')
  1.1700 +                        }).append('text');
  1.1701 +                        axisMaxMin.exit().remove();
  1.1702 +                        axisMaxMin
  1.1703 +                            .attr('transform', function(d,i) {
  1.1704 +                                return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)'
  1.1705 +                            })
  1.1706 +                            .select('text')
  1.1707 +                            .attr('dy', '.71em')
  1.1708 +                            .attr('y', axis.tickPadding())
  1.1709 +                            .attr('transform', rotateLabelsRule)
  1.1710 +                            .style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle')
  1.1711 +                            .text(function(d,i) {
  1.1712 +                                var v = fmt(d);
  1.1713 +                                return ('' + v).match('NaN') ? '' : v;
  1.1714 +                            });
  1.1715 +                        axisMaxMin.watchTransition(renderWatch, 'min-max bottom')
  1.1716 +                            .attr('transform', function(d,i) {
  1.1717 +                                return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)'
  1.1718 +                            });
  1.1719 +                    }
  1.1720 +                    if (staggerLabels)
  1.1721 +                        xTicks
  1.1722 +                            .attr('transform', function(d,i) {
  1.1723 +                                return 'translate(0,' + (i % 2 == 0 ? '0' : '12') + ')'
  1.1724 +                            });
  1.1725 +
  1.1726 +                    break;
  1.1727 +                case 'right':
  1.1728 +                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
  1.1729 +                    axisLabel
  1.1730 +                        .style('text-anchor', rotateYLabel ? 'middle' : 'begin')
  1.1731 +                        .attr('transform', rotateYLabel ? 'rotate(90)' : '')
  1.1732 +                        .attr('y', rotateYLabel ? (-Math.max(margin.right, width) + 12) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
  1.1733 +                        .attr('x', rotateYLabel ? (d3.max(scale.range()) / 2) : axis.tickPadding());
  1.1734 +                    if (showMaxMin) {
  1.1735 +                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
  1.1736 +                            .data(scale.domain());
  1.1737 +                       	axisMaxMin.enter().append('g').attr('class',function(d,i){
  1.1738 +                                return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ')
  1.1739 +                        }).append('text')
  1.1740 +                            .style('opacity', 0);
  1.1741 +                        axisMaxMin.exit().remove();
  1.1742 +                        axisMaxMin
  1.1743 +                            .attr('transform', function(d,i) {
  1.1744 +                                return 'translate(0,' + nv.utils.NaNtoZero(scale(d)) + ')'
  1.1745 +                            })
  1.1746 +                            .select('text')
  1.1747 +                            .attr('dy', '.32em')
  1.1748 +                            .attr('y', 0)
  1.1749 +                            .attr('x', axis.tickPadding())
  1.1750 +                            .style('text-anchor', 'start')
  1.1751 +                            .text(function(d, i) {
  1.1752 +                                var v = fmt(d);
  1.1753 +                                return ('' + v).match('NaN') ? '' : v;
  1.1754 +                            });
  1.1755 +                        axisMaxMin.watchTransition(renderWatch, 'min-max right')
  1.1756 +                            .attr('transform', function(d,i) {
  1.1757 +                                return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')'
  1.1758 +                            })
  1.1759 +                            .select('text')
  1.1760 +                            .style('opacity', 1);
  1.1761 +                    }
  1.1762 +                    break;
  1.1763 +                case 'left':
  1.1764 +                    /*
  1.1765 +                     //For dynamically placing the label. Can be used with dynamically-sized chart axis margins
  1.1766 +                     var yTicks = g.selectAll('g').select("text");
  1.1767 +                     yTicks.each(function(d,i){
  1.1768 +                     var labelPadding = this.getBoundingClientRect().width + axis.tickPadding() + 16;
  1.1769 +                     if(labelPadding > width) width = labelPadding;
  1.1770 +                     });
  1.1771 +                     */
  1.1772 +                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
  1.1773 +                    axisLabel
  1.1774 +                        .style('text-anchor', rotateYLabel ? 'middle' : 'end')
  1.1775 +                        .attr('transform', rotateYLabel ? 'rotate(-90)' : '')
  1.1776 +                        .attr('y', rotateYLabel ? (-Math.max(margin.left, width) + 25 - (axisLabelDistance || 0)) : -10)
  1.1777 +                        .attr('x', rotateYLabel ? (-d3.max(scale.range()) / 2) : -axis.tickPadding());
  1.1778 +                    if (showMaxMin) {
  1.1779 +                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
  1.1780 +                            .data(scale.domain());
  1.1781 +                        axisMaxMin.enter().append('g').attr('class',function(d,i){
  1.1782 +                                return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ')
  1.1783 +                        }).append('text')
  1.1784 +                            .style('opacity', 0);
  1.1785 +                        axisMaxMin.exit().remove();
  1.1786 +                        axisMaxMin
  1.1787 +                            .attr('transform', function(d,i) {
  1.1788 +                                return 'translate(0,' + nv.utils.NaNtoZero(scale0(d)) + ')'
  1.1789 +                            })
  1.1790 +                            .select('text')
  1.1791 +                            .attr('dy', '.32em')
  1.1792 +                            .attr('y', 0)
  1.1793 +                            .attr('x', -axis.tickPadding())
  1.1794 +                            .attr('text-anchor', 'end')
  1.1795 +                            .text(function(d,i) {
  1.1796 +                                var v = fmt(d);
  1.1797 +                                return ('' + v).match('NaN') ? '' : v;
  1.1798 +                            });
  1.1799 +                        axisMaxMin.watchTransition(renderWatch, 'min-max right')
  1.1800 +                            .attr('transform', function(d,i) {
  1.1801 +                                return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')'
  1.1802 +                            })
  1.1803 +                            .select('text')
  1.1804 +                            .style('opacity', 1);
  1.1805 +                    }
  1.1806 +                    break;
  1.1807 +            }
  1.1808 +            axisLabel.text(function(d) { return d });
  1.1809 +
  1.1810 +            if (showMaxMin && (axis.orient() === 'left' || axis.orient() === 'right')) {
  1.1811 +                //check if max and min overlap other values, if so, hide the values that overlap
  1.1812 +                g.selectAll('g') // the g's wrapping each tick
  1.1813 +                    .each(function(d,i) {
  1.1814 +                        d3.select(this).select('text').attr('opacity', 1);
  1.1815 +                        if (scale(d) < scale.range()[1] + 10 || scale(d) > scale.range()[0] - 10) { // 10 is assuming text height is 16... if d is 0, leave it!
  1.1816 +                            if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
  1.1817 +                                d3.select(this).attr('opacity', 0);
  1.1818 +
  1.1819 +                            d3.select(this).select('text').attr('opacity', 0); // Don't remove the ZERO line!!
  1.1820 +                        }
  1.1821 +                    });
  1.1822 +
  1.1823 +                //if Max and Min = 0 only show min, Issue #281
  1.1824 +                if (scale.domain()[0] == scale.domain()[1] && scale.domain()[0] == 0) {
  1.1825 +                    wrap.selectAll('g.nv-axisMaxMin').style('opacity', function (d, i) {
  1.1826 +                        return !i ? 1 : 0
  1.1827 +                    });
  1.1828 +                }
  1.1829 +            }
  1.1830 +
  1.1831 +            if (showMaxMin && (axis.orient() === 'top' || axis.orient() === 'bottom')) {
  1.1832 +                var maxMinRange = [];
  1.1833 +                wrap.selectAll('g.nv-axisMaxMin')
  1.1834 +                    .each(function(d,i) {
  1.1835 +                        try {
  1.1836 +                            if (i) // i== 1, max position
  1.1837 +                                maxMinRange.push(scale(d) - this.getBoundingClientRect().width - 4);  //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
  1.1838 +                            else // i==0, min position
  1.1839 +                                maxMinRange.push(scale(d) + this.getBoundingClientRect().width + 4)
  1.1840 +                        }catch (err) {
  1.1841 +                            if (i) // i== 1, max position
  1.1842 +                                maxMinRange.push(scale(d) - 4);  //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
  1.1843 +                            else // i==0, min position
  1.1844 +                                maxMinRange.push(scale(d) + 4);
  1.1845 +                        }
  1.1846 +                    });
  1.1847 +                // the g's wrapping each tick
  1.1848 +                g.selectAll('g').each(function(d, i) {
  1.1849 +                    if (scale(d) < maxMinRange[0] || scale(d) > maxMinRange[1]) {
  1.1850 +                        if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
  1.1851 +                            d3.select(this).remove();
  1.1852 +                        else
  1.1853 +                            d3.select(this).select('text').remove(); // Don't remove the ZERO line!!
  1.1854 +                    }
  1.1855 +                });
  1.1856 +            }
  1.1857 +
  1.1858 +            //Highlight zero tick line
  1.1859 +            g.selectAll('.tick')
  1.1860 +                .filter(function (d) {
  1.1861 +                    /*
  1.1862 +                    The filter needs to return only ticks at or near zero.
  1.1863 +                    Numbers like 0.00001 need to count as zero as well,
  1.1864 +                    and the arithmetic trick below solves that.
  1.1865 +                    */
  1.1866 +                    return !parseFloat(Math.round(d * 100000) / 1000000) && (d !== undefined)
  1.1867 +                }) 
  1.1868 +                .classed('zero', true);
  1.1869 +            
  1.1870 +            //store old scales for use in transitions on update
  1.1871 +            scale0 = scale.copy();
  1.1872 +
  1.1873 +        });
  1.1874 +
  1.1875 +        renderWatch.renderEnd('axis immediate');
  1.1876 +        return chart;
  1.1877 +    }
  1.1878 +
  1.1879 +    //============================================================
  1.1880 +    // Expose Public Variables
  1.1881 +    //------------------------------------------------------------
  1.1882 +
  1.1883 +    // expose chart's sub-components
  1.1884 +    chart.axis = axis;
  1.1885 +    chart.dispatch = dispatch;
  1.1886 +
  1.1887 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.1888 +    chart._options = Object.create({}, {
  1.1889 +        // simple options, just get/set the necessary values
  1.1890 +        axisLabelDistance: {get: function(){return axisLabelDistance;}, set: function(_){axisLabelDistance=_;}},
  1.1891 +        staggerLabels:     {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
  1.1892 +        rotateLabels:      {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}},
  1.1893 +        rotateYLabel:      {get: function(){return rotateYLabel;}, set: function(_){rotateYLabel=_;}},
  1.1894 +        showMaxMin:        {get: function(){return showMaxMin;}, set: function(_){showMaxMin=_;}},
  1.1895 +        axisLabel:         {get: function(){return axisLabelText;}, set: function(_){axisLabelText=_;}},
  1.1896 +        height:            {get: function(){return height;}, set: function(_){height=_;}},
  1.1897 +        ticks:             {get: function(){return ticks;}, set: function(_){ticks=_;}},
  1.1898 +        width:             {get: function(){return width;}, set: function(_){width=_;}},
  1.1899 +
  1.1900 +        // options that require extra logic in the setter
  1.1901 +        margin: {get: function(){return margin;}, set: function(_){
  1.1902 +            margin.top    = _.top !== undefined    ? _.top    : margin.top;
  1.1903 +            margin.right  = _.right !== undefined  ? _.right  : margin.right;
  1.1904 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.1905 +            margin.left   = _.left !== undefined   ? _.left   : margin.left;
  1.1906 +        }},
  1.1907 +        duration: {get: function(){return duration;}, set: function(_){
  1.1908 +            duration=_;
  1.1909 +            renderWatch.reset(duration);
  1.1910 +        }},
  1.1911 +        scale: {get: function(){return scale;}, set: function(_){
  1.1912 +            scale = _;
  1.1913 +            axis.scale(scale);
  1.1914 +            isOrdinal = typeof scale.rangeBands === 'function';
  1.1915 +            nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']);
  1.1916 +        }}
  1.1917 +    });
  1.1918 +
  1.1919 +    nv.utils.initOptions(chart);
  1.1920 +    nv.utils.inheritOptionsD3(chart, axis, ['orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat']);
  1.1921 +    nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']);
  1.1922 +
  1.1923 +    return chart;
  1.1924 +};
  1.1925 +nv.models.boxPlot = function() {
  1.1926 +    "use strict";
  1.1927 +
  1.1928 +    //============================================================
  1.1929 +    // Public Variables with Default Settings
  1.1930 +    //------------------------------------------------------------
  1.1931 +
  1.1932 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.1933 +        , width = 960
  1.1934 +        , height = 500
  1.1935 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
  1.1936 +        , x = d3.scale.ordinal()
  1.1937 +        , y = d3.scale.linear()
  1.1938 +        , getX = function(d) { return d.x }
  1.1939 +        , getY = function(d) { return d.y }
  1.1940 +        , color = nv.utils.defaultColor()
  1.1941 +        , container = null
  1.1942 +        , xDomain
  1.1943 +        , yDomain
  1.1944 +        , xRange
  1.1945 +        , yRange
  1.1946 +        , dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd')
  1.1947 +        , duration = 250
  1.1948 +        , maxBoxWidth = null
  1.1949 +        ;
  1.1950 +
  1.1951 +    //============================================================
  1.1952 +    // Private Variables
  1.1953 +    //------------------------------------------------------------
  1.1954 +
  1.1955 +    var x0, y0;
  1.1956 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.1957 +
  1.1958 +    function chart(selection) {
  1.1959 +        renderWatch.reset();
  1.1960 +        selection.each(function(data) {
  1.1961 +            var availableWidth = width - margin.left - margin.right,
  1.1962 +                availableHeight = height - margin.top - margin.bottom;
  1.1963 +
  1.1964 +            container = d3.select(this);
  1.1965 +            nv.utils.initSVG(container);
  1.1966 +
  1.1967 +            // Setup Scales
  1.1968 +            x   .domain(xDomain || data.map(function(d,i) { return getX(d,i); }))
  1.1969 +                .rangeBands(xRange || [0, availableWidth], .1);
  1.1970 +
  1.1971 +            // if we know yDomain, no need to calculate
  1.1972 +            var yData = []
  1.1973 +            if (!yDomain) {
  1.1974 +                // (y-range is based on quartiles, whiskers and outliers)
  1.1975 +
  1.1976 +                // lower values
  1.1977 +                var yMin = d3.min(data.map(function(d) {
  1.1978 +                    var min_arr = [];
  1.1979 +
  1.1980 +                    min_arr.push(d.values.Q1);
  1.1981 +                    if (d.values.hasOwnProperty('whisker_low') && d.values.whisker_low !== null) { min_arr.push(d.values.whisker_low); }
  1.1982 +                    if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { min_arr = min_arr.concat(d.values.outliers); }
  1.1983 +
  1.1984 +                    return d3.min(min_arr);
  1.1985 +                }));
  1.1986 +
  1.1987 +                // upper values
  1.1988 +                var yMax = d3.max(data.map(function(d) {
  1.1989 +                    var max_arr = [];
  1.1990 +
  1.1991 +                    max_arr.push(d.values.Q3);
  1.1992 +                    if (d.values.hasOwnProperty('whisker_high') && d.values.whisker_high !== null) { max_arr.push(d.values.whisker_high); }
  1.1993 +                    if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { max_arr = max_arr.concat(d.values.outliers); }
  1.1994 +
  1.1995 +                    return d3.max(max_arr);
  1.1996 +                }));
  1.1997 +
  1.1998 +                yData = [ yMin, yMax ] ;
  1.1999 +            }
  1.2000 +
  1.2001 +            y.domain(yDomain || yData);
  1.2002 +            y.range(yRange || [availableHeight, 0]);
  1.2003 +
  1.2004 +            //store old scales if they exist
  1.2005 +            x0 = x0 || x;
  1.2006 +            y0 = y0 || y.copy().range([y(0),y(0)]);
  1.2007 +
  1.2008 +            // Setup containers and skeleton of chart
  1.2009 +            var wrap = container.selectAll('g.nv-wrap').data([data]);
  1.2010 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap');
  1.2011 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.2012 +
  1.2013 +            var boxplots = wrap.selectAll('.nv-boxplot').data(function(d) { return d });
  1.2014 +            var boxEnter = boxplots.enter().append('g').style('stroke-opacity', 1e-6).style('fill-opacity', 1e-6);
  1.2015 +            boxplots
  1.2016 +                .attr('class', 'nv-boxplot')
  1.2017 +                .attr('transform', function(d,i,j) { return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05) + ', 0)'; })
  1.2018 +                .classed('hover', function(d) { return d.hover });
  1.2019 +            boxplots
  1.2020 +                .watchTransition(renderWatch, 'nv-boxplot: boxplots')
  1.2021 +                .style('stroke-opacity', 1)
  1.2022 +                .style('fill-opacity', .75)
  1.2023 +                .delay(function(d,i) { return i * duration / data.length })
  1.2024 +                .attr('transform', function(d,i) {
  1.2025 +                    return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05) + ', 0)';
  1.2026 +                });
  1.2027 +            boxplots.exit().remove();
  1.2028 +
  1.2029 +            // ----- add the SVG elements for each boxPlot -----
  1.2030 +
  1.2031 +            // conditionally append whisker lines
  1.2032 +            boxEnter.each(function(d,i) {
  1.2033 +              var box = d3.select(this);
  1.2034 +
  1.2035 +              ['low', 'high'].forEach(function(key) {
  1.2036 +                if (d.values.hasOwnProperty('whisker_' + key) && d.values['whisker_' + key] !== null) {
  1.2037 +                  box.append('line')
  1.2038 +                    .style('stroke', (d.color) ? d.color : color(d,i))
  1.2039 +                    .attr('class', 'nv-boxplot-whisker nv-boxplot-' + key);
  1.2040 +
  1.2041 +                  box.append('line')
  1.2042 +                    .style('stroke', (d.color) ? d.color : color(d,i))
  1.2043 +                    .attr('class', 'nv-boxplot-tick nv-boxplot-' + key);
  1.2044 +                }
  1.2045 +              });
  1.2046 +            });
  1.2047 +
  1.2048 +            // outliers
  1.2049 +            // TODO: support custom colors here
  1.2050 +            var outliers = boxplots.selectAll('.nv-boxplot-outlier').data(function(d) {
  1.2051 +                if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { return d.values.outliers; }
  1.2052 +                else { return []; }
  1.2053 +            });
  1.2054 +            outliers.enter().append('circle')
  1.2055 +                .style('fill', function(d,i,j) { return color(d,j) }).style('stroke', function(d,i,j) { return color(d,j) })
  1.2056 +                .on('mouseover', function(d,i,j) {
  1.2057 +                    d3.select(this).classed('hover', true);
  1.2058 +                    dispatch.elementMouseover({
  1.2059 +                        series: { key: d, color: color(d,j) },
  1.2060 +                        e: d3.event
  1.2061 +                    });
  1.2062 +                })
  1.2063 +                .on('mouseout', function(d,i,j) {
  1.2064 +                    d3.select(this).classed('hover', false);
  1.2065 +                    dispatch.elementMouseout({
  1.2066 +                        series: { key: d, color: color(d,j) },
  1.2067 +                        e: d3.event
  1.2068 +                    });
  1.2069 +                })
  1.2070 +                .on('mousemove', function(d,i) {
  1.2071 +                    dispatch.elementMousemove({e: d3.event});
  1.2072 +                });
  1.2073 +
  1.2074 +            outliers.attr('class', 'nv-boxplot-outlier');
  1.2075 +            outliers
  1.2076 +              .watchTransition(renderWatch, 'nv-boxplot: nv-boxplot-outlier')
  1.2077 +                .attr('cx', x.rangeBand() * .45)
  1.2078 +                .attr('cy', function(d,i,j) { return y(d); })
  1.2079 +                .attr('r', '3');
  1.2080 +            outliers.exit().remove();
  1.2081 +
  1.2082 +            var box_width = function() { return (maxBoxWidth === null ? x.rangeBand() * .9 : Math.min(75, x.rangeBand() * .9)); };
  1.2083 +            var box_left  = function() { return x.rangeBand() * .45 - box_width()/2; };
  1.2084 +            var box_right = function() { return x.rangeBand() * .45 + box_width()/2; };
  1.2085 +
  1.2086 +            // update whisker lines and ticks
  1.2087 +            ['low', 'high'].forEach(function(key) {
  1.2088 +              var endpoint = (key === 'low') ? 'Q1' : 'Q3';
  1.2089 +
  1.2090 +              boxplots.select('line.nv-boxplot-whisker.nv-boxplot-' + key)
  1.2091 +                .watchTransition(renderWatch, 'nv-boxplot: boxplots')
  1.2092 +                  .attr('x1', x.rangeBand() * .45 )
  1.2093 +                  .attr('y1', function(d,i) { return y(d.values['whisker_' + key]); })
  1.2094 +                  .attr('x2', x.rangeBand() * .45 )
  1.2095 +                  .attr('y2', function(d,i) { return y(d.values[endpoint]); });
  1.2096 +
  1.2097 +              boxplots.select('line.nv-boxplot-tick.nv-boxplot-' + key)
  1.2098 +                .watchTransition(renderWatch, 'nv-boxplot: boxplots')
  1.2099 +                  .attr('x1', box_left )
  1.2100 +                  .attr('y1', function(d,i) { return y(d.values['whisker_' + key]); })
  1.2101 +                  .attr('x2', box_right )
  1.2102 +                  .attr('y2', function(d,i) { return y(d.values['whisker_' + key]); });
  1.2103 +            });
  1.2104 +
  1.2105 +            ['low', 'high'].forEach(function(key) {
  1.2106 +              boxEnter.selectAll('.nv-boxplot-' + key)
  1.2107 +                .on('mouseover', function(d,i,j) {
  1.2108 +                    d3.select(this).classed('hover', true);
  1.2109 +                    dispatch.elementMouseover({
  1.2110 +                        series: { key: d.values['whisker_' + key], color: color(d,j) },
  1.2111 +                        e: d3.event
  1.2112 +                    });
  1.2113 +                })
  1.2114 +                .on('mouseout', function(d,i,j) {
  1.2115 +                    d3.select(this).classed('hover', false);
  1.2116 +                    dispatch.elementMouseout({
  1.2117 +                        series: { key: d.values['whisker_' + key], color: color(d,j) },
  1.2118 +                        e: d3.event
  1.2119 +                    });
  1.2120 +                })
  1.2121 +                .on('mousemove', function(d,i) {
  1.2122 +                    dispatch.elementMousemove({e: d3.event});
  1.2123 +                });
  1.2124 +            });
  1.2125 +
  1.2126 +            // boxes
  1.2127 +            boxEnter.append('rect')
  1.2128 +                .attr('class', 'nv-boxplot-box')
  1.2129 +                // tooltip events
  1.2130 +                .on('mouseover', function(d,i) {
  1.2131 +                    d3.select(this).classed('hover', true);
  1.2132 +                    dispatch.elementMouseover({
  1.2133 +                        key: d.label,
  1.2134 +                        value: d.label,
  1.2135 +                        series: [
  1.2136 +                            { key: 'Q3', value: d.values.Q3, color: d.color || color(d,i) },
  1.2137 +                            { key: 'Q2', value: d.values.Q2, color: d.color || color(d,i) },
  1.2138 +                            { key: 'Q1', value: d.values.Q1, color: d.color || color(d,i) }
  1.2139 +                        ],
  1.2140 +                        data: d,
  1.2141 +                        index: i,
  1.2142 +                        e: d3.event
  1.2143 +                    });
  1.2144 +                })
  1.2145 +                .on('mouseout', function(d,i) {
  1.2146 +                    d3.select(this).classed('hover', false);
  1.2147 +                    dispatch.elementMouseout({
  1.2148 +                        key: d.label,
  1.2149 +                        value: d.label,
  1.2150 +                        series: [
  1.2151 +                            { key: 'Q3', value: d.values.Q3, color: d.color || color(d,i) },
  1.2152 +                            { key: 'Q2', value: d.values.Q2, color: d.color || color(d,i) },
  1.2153 +                            { key: 'Q1', value: d.values.Q1, color: d.color || color(d,i) }
  1.2154 +                        ],
  1.2155 +                        data: d,
  1.2156 +                        index: i,
  1.2157 +                        e: d3.event
  1.2158 +                    });
  1.2159 +                })
  1.2160 +                .on('mousemove', function(d,i) {
  1.2161 +                    dispatch.elementMousemove({e: d3.event});
  1.2162 +                });
  1.2163 +
  1.2164 +            // box transitions
  1.2165 +            boxplots.select('rect.nv-boxplot-box')
  1.2166 +              .watchTransition(renderWatch, 'nv-boxplot: boxes')
  1.2167 +                .attr('y', function(d,i) { return y(d.values.Q3); })
  1.2168 +                .attr('width', box_width)
  1.2169 +                .attr('x', box_left )
  1.2170 +
  1.2171 +                .attr('height', function(d,i) { return Math.abs(y(d.values.Q3) - y(d.values.Q1)) || 1 })
  1.2172 +                .style('fill', function(d,i) { return d.color || color(d,i) })
  1.2173 +                .style('stroke', function(d,i) { return d.color || color(d,i) });
  1.2174 +
  1.2175 +            // median line
  1.2176 +            boxEnter.append('line').attr('class', 'nv-boxplot-median');
  1.2177 +
  1.2178 +            boxplots.select('line.nv-boxplot-median')
  1.2179 +              .watchTransition(renderWatch, 'nv-boxplot: boxplots line')
  1.2180 +                .attr('x1', box_left)
  1.2181 +                .attr('y1', function(d,i) { return y(d.values.Q2); })
  1.2182 +                .attr('x2', box_right)
  1.2183 +                .attr('y2', function(d,i) { return y(d.values.Q2); });
  1.2184 +
  1.2185 +            //store old scales for use in transitions on update
  1.2186 +            x0 = x.copy();
  1.2187 +            y0 = y.copy();
  1.2188 +        });
  1.2189 +
  1.2190 +        renderWatch.renderEnd('nv-boxplot immediate');
  1.2191 +        return chart;
  1.2192 +    }
  1.2193 +
  1.2194 +    //============================================================
  1.2195 +    // Expose Public Variables
  1.2196 +    //------------------------------------------------------------
  1.2197 +
  1.2198 +    chart.dispatch = dispatch;
  1.2199 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.2200 +
  1.2201 +    chart._options = Object.create({}, {
  1.2202 +        // simple options, just get/set the necessary values
  1.2203 +        width:   {get: function(){return width;}, set: function(_){width=_;}},
  1.2204 +        height:  {get: function(){return height;}, set: function(_){height=_;}},
  1.2205 +        maxBoxWidth: {get: function(){return maxBoxWidth;}, set: function(_){maxBoxWidth=_;}},
  1.2206 +        x:       {get: function(){return getX;}, set: function(_){getX=_;}},
  1.2207 +        y:       {get: function(){return getY;}, set: function(_){getY=_;}},
  1.2208 +        xScale:  {get: function(){return x;}, set: function(_){x=_;}},
  1.2209 +        yScale:  {get: function(){return y;}, set: function(_){y=_;}},
  1.2210 +        xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
  1.2211 +        yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
  1.2212 +        xRange:  {get: function(){return xRange;}, set: function(_){xRange=_;}},
  1.2213 +        yRange:  {get: function(){return yRange;}, set: function(_){yRange=_;}},
  1.2214 +        id:          {get: function(){return id;}, set: function(_){id=_;}},
  1.2215 +        // rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}},
  1.2216 +
  1.2217 +        // options that require extra logic in the setter
  1.2218 +        margin: {get: function(){return margin;}, set: function(_){
  1.2219 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.2220 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.2221 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.2222 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.2223 +        }},
  1.2224 +        color:  {get: function(){return color;}, set: function(_){
  1.2225 +            color = nv.utils.getColor(_);
  1.2226 +        }},
  1.2227 +        duration: {get: function(){return duration;}, set: function(_){
  1.2228 +            duration = _;
  1.2229 +            renderWatch.reset(duration);
  1.2230 +        }}
  1.2231 +    });
  1.2232 +
  1.2233 +    nv.utils.initOptions(chart);
  1.2234 +
  1.2235 +    return chart;
  1.2236 +};
  1.2237 +nv.models.boxPlotChart = function() {
  1.2238 +    "use strict";
  1.2239 +
  1.2240 +    //============================================================
  1.2241 +    // Public Variables with Default Settings
  1.2242 +    //------------------------------------------------------------
  1.2243 +
  1.2244 +    var boxplot = nv.models.boxPlot()
  1.2245 +        , xAxis = nv.models.axis()
  1.2246 +        , yAxis = nv.models.axis()
  1.2247 +        ;
  1.2248 +
  1.2249 +    var margin = {top: 15, right: 10, bottom: 50, left: 60}
  1.2250 +        , width = null
  1.2251 +        , height = null
  1.2252 +        , color = nv.utils.getColor()
  1.2253 +        , showXAxis = true
  1.2254 +        , showYAxis = true
  1.2255 +        , rightAlignYAxis = false
  1.2256 +        , staggerLabels = false
  1.2257 +        , tooltip = nv.models.tooltip()
  1.2258 +        , x
  1.2259 +        , y
  1.2260 +        , noData = "No Data Available."
  1.2261 +        , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'beforeUpdate', 'renderEnd')
  1.2262 +        , duration = 250
  1.2263 +        ;
  1.2264 +
  1.2265 +    xAxis
  1.2266 +        .orient('bottom')
  1.2267 +        .showMaxMin(false)
  1.2268 +        .tickFormat(function(d) { return d })
  1.2269 +    ;
  1.2270 +    yAxis
  1.2271 +        .orient((rightAlignYAxis) ? 'right' : 'left')
  1.2272 +        .tickFormat(d3.format(',.1f'))
  1.2273 +    ;
  1.2274 +    
  1.2275 +    tooltip.duration(0);
  1.2276 +
  1.2277 +    //============================================================
  1.2278 +    // Private Variables
  1.2279 +    //------------------------------------------------------------
  1.2280 +
  1.2281 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.2282 +
  1.2283 +    function chart(selection) {
  1.2284 +        renderWatch.reset();
  1.2285 +        renderWatch.models(boxplot);
  1.2286 +        if (showXAxis) renderWatch.models(xAxis);
  1.2287 +        if (showYAxis) renderWatch.models(yAxis);
  1.2288 +
  1.2289 +        selection.each(function(data) {
  1.2290 +            var container = d3.select(this),
  1.2291 +                that = this;
  1.2292 +            nv.utils.initSVG(container);
  1.2293 +            var availableWidth = (width  || parseInt(container.style('width')) || 960)
  1.2294 +                    - margin.left - margin.right,
  1.2295 +                availableHeight = (height || parseInt(container.style('height')) || 400)
  1.2296 +                    - margin.top - margin.bottom;
  1.2297 +
  1.2298 +            chart.update = function() {
  1.2299 +                dispatch.beforeUpdate();
  1.2300 +                container.transition().duration(duration).call(chart);
  1.2301 +            };
  1.2302 +            chart.container = this;
  1.2303 +
  1.2304 +            // Display No Data message if there's nothing to show. (quartiles required at minimum)
  1.2305 +            if (!data || !data.length || 
  1.2306 +                    !data.filter(function(d) { return d.values.hasOwnProperty("Q1") && d.values.hasOwnProperty("Q2") && d.values.hasOwnProperty("Q3"); }).length) {
  1.2307 +                var noDataText = container.selectAll('.nv-noData').data([noData]);
  1.2308 +
  1.2309 +                noDataText.enter().append('text')
  1.2310 +                    .attr('class', 'nvd3 nv-noData')
  1.2311 +                    .attr('dy', '-.7em')
  1.2312 +                    .style('text-anchor', 'middle');
  1.2313 +
  1.2314 +                noDataText
  1.2315 +                    .attr('x', margin.left + availableWidth / 2)
  1.2316 +                    .attr('y', margin.top + availableHeight / 2)
  1.2317 +                    .text(function(d) { return d });
  1.2318 +
  1.2319 +                return chart;
  1.2320 +            } else {
  1.2321 +                container.selectAll('.nv-noData').remove();
  1.2322 +            }
  1.2323 +
  1.2324 +            // Setup Scales
  1.2325 +            x = boxplot.xScale();
  1.2326 +            y = boxplot.yScale().clamp(true);
  1.2327 +
  1.2328 +            // Setup containers and skeleton of chart
  1.2329 +            var wrap = container.selectAll('g.nv-wrap.nv-boxPlotWithAxes').data([data]);
  1.2330 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-boxPlotWithAxes').append('g');
  1.2331 +            var defsEnter = gEnter.append('defs');
  1.2332 +            var g = wrap.select('g');
  1.2333 +
  1.2334 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
  1.2335 +            gEnter.append('g').attr('class', 'nv-y nv-axis')
  1.2336 +                .append('g').attr('class', 'nv-zeroLine')
  1.2337 +                .append('line');
  1.2338 +
  1.2339 +            gEnter.append('g').attr('class', 'nv-barsWrap');
  1.2340 +
  1.2341 +            g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.2342 +
  1.2343 +            if (rightAlignYAxis) {
  1.2344 +                g.select(".nv-y.nv-axis")
  1.2345 +                    .attr("transform", "translate(" + availableWidth + ",0)");
  1.2346 +            }
  1.2347 +
  1.2348 +            // Main Chart Component(s)
  1.2349 +            boxplot
  1.2350 +                .width(availableWidth)
  1.2351 +                .height(availableHeight);
  1.2352 +
  1.2353 +            var barsWrap = g.select('.nv-barsWrap')
  1.2354 +                .datum(data.filter(function(d) { return !d.disabled }))
  1.2355 +
  1.2356 +            barsWrap.transition().call(boxplot);
  1.2357 +
  1.2358 +
  1.2359 +            defsEnter.append('clipPath')
  1.2360 +                .attr('id', 'nv-x-label-clip-' + boxplot.id())
  1.2361 +                .append('rect');
  1.2362 +
  1.2363 +            g.select('#nv-x-label-clip-' + boxplot.id() + ' rect')
  1.2364 +                .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1))
  1.2365 +                .attr('height', 16)
  1.2366 +                .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 ));
  1.2367 +
  1.2368 +            // Setup Axes
  1.2369 +            if (showXAxis) {
  1.2370 +                xAxis
  1.2371 +                    .scale(x)
  1.2372 +                    .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.2373 +                    .tickSize(-availableHeight, 0);
  1.2374 +
  1.2375 +                g.select('.nv-x.nv-axis').attr('transform', 'translate(0,' + y.range()[0] + ')');
  1.2376 +                g.select('.nv-x.nv-axis').call(xAxis);
  1.2377 +
  1.2378 +                var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
  1.2379 +                if (staggerLabels) {
  1.2380 +                    xTicks
  1.2381 +                        .selectAll('text')
  1.2382 +                        .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')' })
  1.2383 +                }
  1.2384 +            }
  1.2385 +
  1.2386 +            if (showYAxis) {
  1.2387 +                yAxis
  1.2388 +                    .scale(y)
  1.2389 +                    .ticks( Math.floor(availableHeight/36) ) // can't use nv.utils.calcTicksY with Object data
  1.2390 +                    .tickSize( -availableWidth, 0);
  1.2391 +
  1.2392 +                g.select('.nv-y.nv-axis').call(yAxis);
  1.2393 +            }
  1.2394 +
  1.2395 +            // Zero line
  1.2396 +            g.select(".nv-zeroLine line")
  1.2397 +                .attr("x1",0)
  1.2398 +                .attr("x2",availableWidth)
  1.2399 +                .attr("y1", y(0))
  1.2400 +                .attr("y2", y(0))
  1.2401 +            ;
  1.2402 +
  1.2403 +            //============================================================
  1.2404 +            // Event Handling/Dispatching (in chart's scope)
  1.2405 +            //------------------------------------------------------------
  1.2406 +        });
  1.2407 +
  1.2408 +        renderWatch.renderEnd('nv-boxplot chart immediate');
  1.2409 +        return chart;
  1.2410 +    }
  1.2411 +
  1.2412 +    //============================================================
  1.2413 +    // Event Handling/Dispatching (out of chart's scope)
  1.2414 +    //------------------------------------------------------------
  1.2415 +
  1.2416 +    boxplot.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.2417 +        tooltip.data(evt).hidden(false);
  1.2418 +    });
  1.2419 +
  1.2420 +    boxplot.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.2421 +        tooltip.data(evt).hidden(true);
  1.2422 +    });
  1.2423 +
  1.2424 +    boxplot.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.2425 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.2426 +    });
  1.2427 +
  1.2428 +    //============================================================
  1.2429 +    // Expose Public Variables
  1.2430 +    //------------------------------------------------------------
  1.2431 +
  1.2432 +    chart.dispatch = dispatch;
  1.2433 +    chart.boxplot = boxplot;
  1.2434 +    chart.xAxis = xAxis;
  1.2435 +    chart.yAxis = yAxis;
  1.2436 +    chart.tooltip = tooltip;
  1.2437 +
  1.2438 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.2439 +
  1.2440 +    chart._options = Object.create({}, {
  1.2441 +        // simple options, just get/set the necessary values
  1.2442 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.2443 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.2444 +        staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
  1.2445 +        showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
  1.2446 +        showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
  1.2447 +        tooltips:    {get: function(){return tooltips;}, set: function(_){tooltips=_;}},
  1.2448 +        tooltipContent:    {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
  1.2449 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.2450 +
  1.2451 +        // options that require extra logic in the setter
  1.2452 +        margin: {get: function(){return margin;}, set: function(_){
  1.2453 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.2454 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.2455 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.2456 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.2457 +        }},
  1.2458 +        duration: {get: function(){return duration;}, set: function(_){
  1.2459 +            duration = _;
  1.2460 +            renderWatch.reset(duration);
  1.2461 +            boxplot.duration(duration);
  1.2462 +            xAxis.duration(duration);
  1.2463 +            yAxis.duration(duration);
  1.2464 +        }},
  1.2465 +        color:  {get: function(){return color;}, set: function(_){
  1.2466 +            color = nv.utils.getColor(_);
  1.2467 +            boxplot.color(color);
  1.2468 +        }},
  1.2469 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
  1.2470 +            rightAlignYAxis = _;
  1.2471 +            yAxis.orient( (_) ? 'right' : 'left');
  1.2472 +        }}
  1.2473 +    });
  1.2474 +
  1.2475 +    nv.utils.inheritOptions(chart, boxplot);
  1.2476 +    nv.utils.initOptions(chart);
  1.2477 +
  1.2478 +    return chart;
  1.2479 +}
  1.2480 +// Chart design based on the recommendations of Stephen Few. Implementation
  1.2481 +// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
  1.2482 +// http://projects.instantcognition.com/protovis/bulletchart/
  1.2483 +
  1.2484 +nv.models.bullet = function() {
  1.2485 +    "use strict";
  1.2486 +
  1.2487 +    //============================================================
  1.2488 +    // Public Variables with Default Settings
  1.2489 +    //------------------------------------------------------------
  1.2490 +
  1.2491 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.2492 +        , orient = 'left' // TODO top & bottom
  1.2493 +        , reverse = false
  1.2494 +        , ranges = function(d) { return d.ranges }
  1.2495 +        , markers = function(d) { return d.markers ? d.markers : [0] }
  1.2496 +        , measures = function(d) { return d.measures }
  1.2497 +        , rangeLabels = function(d) { return d.rangeLabels ? d.rangeLabels : [] }
  1.2498 +        , markerLabels = function(d) { return d.markerLabels ? d.markerLabels : []  }
  1.2499 +        , measureLabels = function(d) { return d.measureLabels ? d.measureLabels : []  }
  1.2500 +        , forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
  1.2501 +        , width = 380
  1.2502 +        , height = 30
  1.2503 +        , container = null
  1.2504 +        , tickFormat = null
  1.2505 +        , color = nv.utils.getColor(['#1f77b4'])
  1.2506 +        , dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove')
  1.2507 +        ;
  1.2508 +
  1.2509 +    function chart(selection) {
  1.2510 +        selection.each(function(d, i) {
  1.2511 +            var availableWidth = width - margin.left - margin.right,
  1.2512 +                availableHeight = height - margin.top - margin.bottom;
  1.2513 +
  1.2514 +            container = d3.select(this);
  1.2515 +            nv.utils.initSVG(container);
  1.2516 +
  1.2517 +            var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
  1.2518 +                markerz = markers.call(this, d, i).slice().sort(d3.descending),
  1.2519 +                measurez = measures.call(this, d, i).slice().sort(d3.descending),
  1.2520 +                rangeLabelz = rangeLabels.call(this, d, i).slice(),
  1.2521 +                markerLabelz = markerLabels.call(this, d, i).slice(),
  1.2522 +                measureLabelz = measureLabels.call(this, d, i).slice();
  1.2523 +
  1.2524 +            // Setup Scales
  1.2525 +            // Compute the new x-scale.
  1.2526 +            var x1 = d3.scale.linear()
  1.2527 +                .domain( d3.extent(d3.merge([forceX, rangez])) )
  1.2528 +                .range(reverse ? [availableWidth, 0] : [0, availableWidth]);
  1.2529 +
  1.2530 +            // Retrieve the old x-scale, if this is an update.
  1.2531 +            var x0 = this.__chart__ || d3.scale.linear()
  1.2532 +                .domain([0, Infinity])
  1.2533 +                .range(x1.range());
  1.2534 +
  1.2535 +            // Stash the new scale.
  1.2536 +            this.__chart__ = x1;
  1.2537 +
  1.2538 +            var rangeMin = d3.min(rangez), //rangez[2]
  1.2539 +                rangeMax = d3.max(rangez), //rangez[0]
  1.2540 +                rangeAvg = rangez[1];
  1.2541 +
  1.2542 +            // Setup containers and skeleton of chart
  1.2543 +            var wrap = container.selectAll('g.nv-wrap.nv-bullet').data([d]);
  1.2544 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bullet');
  1.2545 +            var gEnter = wrapEnter.append('g');
  1.2546 +            var g = wrap.select('g');
  1.2547 +
  1.2548 +            gEnter.append('rect').attr('class', 'nv-range nv-rangeMax');
  1.2549 +            gEnter.append('rect').attr('class', 'nv-range nv-rangeAvg');
  1.2550 +            gEnter.append('rect').attr('class', 'nv-range nv-rangeMin');
  1.2551 +            gEnter.append('rect').attr('class', 'nv-measure');
  1.2552 +
  1.2553 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.2554 +
  1.2555 +            var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
  1.2556 +                w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
  1.2557 +            var xp0 = function(d) { return d < 0 ? x0(d) : x0(0) },
  1.2558 +                xp1 = function(d) { return d < 0 ? x1(d) : x1(0) };
  1.2559 +
  1.2560 +            g.select('rect.nv-rangeMax')
  1.2561 +                .attr('height', availableHeight)
  1.2562 +                .attr('width', w1(rangeMax > 0 ? rangeMax : rangeMin))
  1.2563 +                .attr('x', xp1(rangeMax > 0 ? rangeMax : rangeMin))
  1.2564 +                .datum(rangeMax > 0 ? rangeMax : rangeMin)
  1.2565 +
  1.2566 +            g.select('rect.nv-rangeAvg')
  1.2567 +                .attr('height', availableHeight)
  1.2568 +                .attr('width', w1(rangeAvg))
  1.2569 +                .attr('x', xp1(rangeAvg))
  1.2570 +                .datum(rangeAvg)
  1.2571 +
  1.2572 +            g.select('rect.nv-rangeMin')
  1.2573 +                .attr('height', availableHeight)
  1.2574 +                .attr('width', w1(rangeMax))
  1.2575 +                .attr('x', xp1(rangeMax))
  1.2576 +                .attr('width', w1(rangeMax > 0 ? rangeMin : rangeMax))
  1.2577 +                .attr('x', xp1(rangeMax > 0 ? rangeMin : rangeMax))
  1.2578 +                .datum(rangeMax > 0 ? rangeMin : rangeMax)
  1.2579 +
  1.2580 +            g.select('rect.nv-measure')
  1.2581 +                .style('fill', color)
  1.2582 +                .attr('height', availableHeight / 3)
  1.2583 +                .attr('y', availableHeight / 3)
  1.2584 +                .attr('width', measurez < 0 ?
  1.2585 +                    x1(0) - x1(measurez[0])
  1.2586 +                    : x1(measurez[0]) - x1(0))
  1.2587 +                .attr('x', xp1(measurez))
  1.2588 +                .on('mouseover', function() {
  1.2589 +                    dispatch.elementMouseover({
  1.2590 +                        value: measurez[0],
  1.2591 +                        label: measureLabelz[0] || 'Current',
  1.2592 +                        color: d3.select(this).style("fill")
  1.2593 +                    })
  1.2594 +                })
  1.2595 +                .on('mousemove', function() {
  1.2596 +                    dispatch.elementMousemove({
  1.2597 +                        value: measurez[0],
  1.2598 +                        label: measureLabelz[0] || 'Current',
  1.2599 +                        color: d3.select(this).style("fill")
  1.2600 +                    })
  1.2601 +                })
  1.2602 +                .on('mouseout', function() {
  1.2603 +                    dispatch.elementMouseout({
  1.2604 +                        value: measurez[0],
  1.2605 +                        label: measureLabelz[0] || 'Current',
  1.2606 +                        color: d3.select(this).style("fill")
  1.2607 +                    })
  1.2608 +                });
  1.2609 +
  1.2610 +            var h3 =  availableHeight / 6;
  1.2611 +
  1.2612 +            var markerData = markerz.map( function(marker, index) {
  1.2613 +                return {value: marker, label: markerLabelz[index]}
  1.2614 +            });
  1.2615 +            gEnter
  1.2616 +              .selectAll("path.nv-markerTriangle")
  1.2617 +              .data(markerData)
  1.2618 +              .enter()
  1.2619 +              .append('path')
  1.2620 +              .attr('class', 'nv-markerTriangle')
  1.2621 +              .attr('transform', function(d) { return 'translate(' + x1(d.value) + ',' + (availableHeight / 2) + ')' })
  1.2622 +              .attr('d', 'M0,' + h3 + 'L' + h3 + ',' + (-h3) + ' ' + (-h3) + ',' + (-h3) + 'Z')
  1.2623 +              .on('mouseover', function(d) {
  1.2624 +                dispatch.elementMouseover({
  1.2625 +                  value: d.value,
  1.2626 +                  label: d.label || 'Previous',
  1.2627 +                  color: d3.select(this).style("fill"),
  1.2628 +                  pos: [x1(d.value), availableHeight/2]
  1.2629 +                })
  1.2630 +
  1.2631 +              })
  1.2632 +              .on('mousemove', function(d) {
  1.2633 +                  dispatch.elementMousemove({
  1.2634 +                      value: d.value,
  1.2635 +                      label: d.label || 'Previous',
  1.2636 +                      color: d3.select(this).style("fill")
  1.2637 +                  })
  1.2638 +              })
  1.2639 +              .on('mouseout', function(d, i) {
  1.2640 +                  dispatch.elementMouseout({
  1.2641 +                      value: d.value,
  1.2642 +                      label: d.label || 'Previous',
  1.2643 +                      color: d3.select(this).style("fill")
  1.2644 +                  })
  1.2645 +              });
  1.2646 +
  1.2647 +            wrap.selectAll('.nv-range')
  1.2648 +                .on('mouseover', function(d,i) {
  1.2649 +                    var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum");
  1.2650 +                    dispatch.elementMouseover({
  1.2651 +                        value: d,
  1.2652 +                        label: label,
  1.2653 +                        color: d3.select(this).style("fill")
  1.2654 +                    })
  1.2655 +                })
  1.2656 +                .on('mousemove', function() {
  1.2657 +                    dispatch.elementMousemove({
  1.2658 +                        value: measurez[0],
  1.2659 +                        label: measureLabelz[0] || 'Previous',
  1.2660 +                        color: d3.select(this).style("fill")
  1.2661 +                    })
  1.2662 +                })
  1.2663 +                .on('mouseout', function(d,i) {
  1.2664 +                    var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum");
  1.2665 +                    dispatch.elementMouseout({
  1.2666 +                        value: d,
  1.2667 +                        label: label,
  1.2668 +                        color: d3.select(this).style("fill")
  1.2669 +                    })
  1.2670 +                });
  1.2671 +        });
  1.2672 +
  1.2673 +        return chart;
  1.2674 +    }
  1.2675 +
  1.2676 +    //============================================================
  1.2677 +    // Expose Public Variables
  1.2678 +    //------------------------------------------------------------
  1.2679 +
  1.2680 +    chart.dispatch = dispatch;
  1.2681 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.2682 +
  1.2683 +    chart._options = Object.create({}, {
  1.2684 +        // simple options, just get/set the necessary values
  1.2685 +        ranges:      {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good)
  1.2686 +        markers:     {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal)
  1.2687 +        measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast)
  1.2688 +        forceX:      {get: function(){return forceX;}, set: function(_){forceX=_;}},
  1.2689 +        width:    {get: function(){return width;}, set: function(_){width=_;}},
  1.2690 +        height:    {get: function(){return height;}, set: function(_){height=_;}},
  1.2691 +        tickFormat:    {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}},
  1.2692 +
  1.2693 +        // options that require extra logic in the setter
  1.2694 +        margin: {get: function(){return margin;}, set: function(_){
  1.2695 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.2696 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.2697 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.2698 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.2699 +        }},
  1.2700 +        orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom
  1.2701 +            orient = _;
  1.2702 +            reverse = orient == 'right' || orient == 'bottom';
  1.2703 +        }},
  1.2704 +        color:  {get: function(){return color;}, set: function(_){
  1.2705 +            color = nv.utils.getColor(_);
  1.2706 +        }}
  1.2707 +    });
  1.2708 +
  1.2709 +    nv.utils.initOptions(chart);
  1.2710 +    return chart;
  1.2711 +};
  1.2712 +
  1.2713 +
  1.2714 +
  1.2715 +// Chart design based on the recommendations of Stephen Few. Implementation
  1.2716 +// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
  1.2717 +// http://projects.instantcognition.com/protovis/bulletchart/
  1.2718 +nv.models.bulletChart = function() {
  1.2719 +    "use strict";
  1.2720 +
  1.2721 +    //============================================================
  1.2722 +    // Public Variables with Default Settings
  1.2723 +    //------------------------------------------------------------
  1.2724 +
  1.2725 +    var bullet = nv.models.bullet();
  1.2726 +    var tooltip = nv.models.tooltip();
  1.2727 +
  1.2728 +    var orient = 'left' // TODO top & bottom
  1.2729 +        , reverse = false
  1.2730 +        , margin = {top: 5, right: 40, bottom: 20, left: 120}
  1.2731 +        , ranges = function(d) { return d.ranges }
  1.2732 +        , markers = function(d) { return d.markers ? d.markers : [0] }
  1.2733 +        , measures = function(d) { return d.measures }
  1.2734 +        , width = null
  1.2735 +        , height = 55
  1.2736 +        , tickFormat = null
  1.2737 +	, ticks = null
  1.2738 +        , noData = null
  1.2739 +        , dispatch = d3.dispatch('tooltipShow', 'tooltipHide')
  1.2740 +        ;
  1.2741 +
  1.2742 +    tooltip.duration(0).headerEnabled(false);
  1.2743 +
  1.2744 +    function chart(selection) {
  1.2745 +        selection.each(function(d, i) {
  1.2746 +            var container = d3.select(this);
  1.2747 +            nv.utils.initSVG(container);
  1.2748 +
  1.2749 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.2750 +                availableHeight = height - margin.top - margin.bottom,
  1.2751 +                that = this;
  1.2752 +
  1.2753 +            chart.update = function() { chart(selection) };
  1.2754 +            chart.container = this;
  1.2755 +
  1.2756 +            // Display No Data message if there's nothing to show.
  1.2757 +            if (!d || !ranges.call(this, d, i)) {
  1.2758 +                nv.utils.noData(chart, container)
  1.2759 +                return chart;
  1.2760 +            } else {
  1.2761 +                container.selectAll('.nv-noData').remove();
  1.2762 +            }
  1.2763 +
  1.2764 +            var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
  1.2765 +                markerz = markers.call(this, d, i).slice().sort(d3.descending),
  1.2766 +                measurez = measures.call(this, d, i).slice().sort(d3.descending);
  1.2767 +
  1.2768 +            // Setup containers and skeleton of chart
  1.2769 +            var wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]);
  1.2770 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart');
  1.2771 +            var gEnter = wrapEnter.append('g');
  1.2772 +            var g = wrap.select('g');
  1.2773 +
  1.2774 +            gEnter.append('g').attr('class', 'nv-bulletWrap');
  1.2775 +            gEnter.append('g').attr('class', 'nv-titles');
  1.2776 +
  1.2777 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.2778 +
  1.2779 +            // Compute the new x-scale.
  1.2780 +            var x1 = d3.scale.linear()
  1.2781 +                .domain([0, Math.max(rangez[0], markerz[0], measurez[0])])  // TODO: need to allow forceX and forceY, and xDomain, yDomain
  1.2782 +                .range(reverse ? [availableWidth, 0] : [0, availableWidth]);
  1.2783 +
  1.2784 +            // Retrieve the old x-scale, if this is an update.
  1.2785 +            var x0 = this.__chart__ || d3.scale.linear()
  1.2786 +                .domain([0, Infinity])
  1.2787 +                .range(x1.range());
  1.2788 +
  1.2789 +            // Stash the new scale.
  1.2790 +            this.__chart__ = x1;
  1.2791 +
  1.2792 +            var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
  1.2793 +                w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
  1.2794 +
  1.2795 +            var title = gEnter.select('.nv-titles').append('g')
  1.2796 +                .attr('text-anchor', 'end')
  1.2797 +                .attr('transform', 'translate(-6,' + (height - margin.top - margin.bottom) / 2 + ')');
  1.2798 +            title.append('text')
  1.2799 +                .attr('class', 'nv-title')
  1.2800 +                .text(function(d) { return d.title; });
  1.2801 +
  1.2802 +            title.append('text')
  1.2803 +                .attr('class', 'nv-subtitle')
  1.2804 +                .attr('dy', '1em')
  1.2805 +                .text(function(d) { return d.subtitle; });
  1.2806 +
  1.2807 +            bullet
  1.2808 +                .width(availableWidth)
  1.2809 +                .height(availableHeight)
  1.2810 +
  1.2811 +            var bulletWrap = g.select('.nv-bulletWrap');
  1.2812 +            d3.transition(bulletWrap).call(bullet);
  1.2813 +
  1.2814 +            // Compute the tick format.
  1.2815 +            var format = tickFormat || x1.tickFormat( availableWidth / 100 );
  1.2816 +
  1.2817 +            // Update the tick groups.
  1.2818 +            var tick = g.selectAll('g.nv-tick')
  1.2819 +                .data(x1.ticks( ticks ? ticks : (availableWidth / 50) ), function(d) {
  1.2820 +                    return this.textContent || format(d);
  1.2821 +                });
  1.2822 +
  1.2823 +            // Initialize the ticks with the old scale, x0.
  1.2824 +            var tickEnter = tick.enter().append('g')
  1.2825 +                .attr('class', 'nv-tick')
  1.2826 +                .attr('transform', function(d) { return 'translate(' + x0(d) + ',0)' })
  1.2827 +                .style('opacity', 1e-6);
  1.2828 +
  1.2829 +            tickEnter.append('line')
  1.2830 +                .attr('y1', availableHeight)
  1.2831 +                .attr('y2', availableHeight * 7 / 6);
  1.2832 +
  1.2833 +            tickEnter.append('text')
  1.2834 +                .attr('text-anchor', 'middle')
  1.2835 +                .attr('dy', '1em')
  1.2836 +                .attr('y', availableHeight * 7 / 6)
  1.2837 +                .text(format);
  1.2838 +
  1.2839 +            // Transition the updating ticks to the new scale, x1.
  1.2840 +            var tickUpdate = d3.transition(tick)
  1.2841 +                .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
  1.2842 +                .style('opacity', 1);
  1.2843 +
  1.2844 +            tickUpdate.select('line')
  1.2845 +                .attr('y1', availableHeight)
  1.2846 +                .attr('y2', availableHeight * 7 / 6);
  1.2847 +
  1.2848 +            tickUpdate.select('text')
  1.2849 +                .attr('y', availableHeight * 7 / 6);
  1.2850 +
  1.2851 +            // Transition the exiting ticks to the new scale, x1.
  1.2852 +            d3.transition(tick.exit())
  1.2853 +                .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
  1.2854 +                .style('opacity', 1e-6)
  1.2855 +                .remove();
  1.2856 +        });
  1.2857 +
  1.2858 +        d3.timer.flush();
  1.2859 +        return chart;
  1.2860 +    }
  1.2861 +
  1.2862 +    //============================================================
  1.2863 +    // Event Handling/Dispatching (out of chart's scope)
  1.2864 +    //------------------------------------------------------------
  1.2865 +
  1.2866 +    bullet.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.2867 +        evt['series'] = {
  1.2868 +            key: evt.label,
  1.2869 +            value: evt.value,
  1.2870 +            color: evt.color
  1.2871 +        };
  1.2872 +        tooltip.data(evt).hidden(false);
  1.2873 +    });
  1.2874 +
  1.2875 +    bullet.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.2876 +        tooltip.hidden(true);
  1.2877 +    });
  1.2878 +
  1.2879 +    bullet.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.2880 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.2881 +    });
  1.2882 +
  1.2883 +    //============================================================
  1.2884 +    // Expose Public Variables
  1.2885 +    //------------------------------------------------------------
  1.2886 +
  1.2887 +    chart.bullet = bullet;
  1.2888 +    chart.dispatch = dispatch;
  1.2889 +    chart.tooltip = tooltip;
  1.2890 +
  1.2891 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.2892 +
  1.2893 +    chart._options = Object.create({}, {
  1.2894 +        // simple options, just get/set the necessary values
  1.2895 +        ranges:      {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good)
  1.2896 +        markers:     {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal)
  1.2897 +        measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast)
  1.2898 +        width:    {get: function(){return width;}, set: function(_){width=_;}},
  1.2899 +        height:    {get: function(){return height;}, set: function(_){height=_;}},
  1.2900 +        tickFormat:    {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}},
  1.2901 +        ticks:    {get: function(){return ticks;}, set: function(_){ticks=_;}},
  1.2902 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.2903 +
  1.2904 +        // deprecated options
  1.2905 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.2906 +            // deprecated after 1.7.1
  1.2907 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.2908 +            tooltip.enabled(!!_);
  1.2909 +        }},
  1.2910 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.2911 +            // deprecated after 1.7.1
  1.2912 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.2913 +            tooltip.contentGenerator(_);
  1.2914 +        }},
  1.2915 +
  1.2916 +        // options that require extra logic in the setter
  1.2917 +        margin: {get: function(){return margin;}, set: function(_){
  1.2918 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.2919 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.2920 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.2921 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.2922 +        }},
  1.2923 +        orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom
  1.2924 +            orient = _;
  1.2925 +            reverse = orient == 'right' || orient == 'bottom';
  1.2926 +        }}
  1.2927 +    });
  1.2928 +
  1.2929 +    nv.utils.inheritOptions(chart, bullet);
  1.2930 +    nv.utils.initOptions(chart);
  1.2931 +
  1.2932 +    return chart;
  1.2933 +};
  1.2934 +
  1.2935 +
  1.2936 +
  1.2937 +nv.models.candlestickBar = function() {
  1.2938 +    "use strict";
  1.2939 +
  1.2940 +    //============================================================
  1.2941 +    // Public Variables with Default Settings
  1.2942 +    //------------------------------------------------------------
  1.2943 +
  1.2944 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.2945 +        , width = null
  1.2946 +        , height = null
  1.2947 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
  1.2948 +        , container
  1.2949 +        , x = d3.scale.linear()
  1.2950 +        , y = d3.scale.linear()
  1.2951 +        , getX = function(d) { return d.x }
  1.2952 +        , getY = function(d) { return d.y }
  1.2953 +        , getOpen = function(d) { return d.open }
  1.2954 +        , getClose = function(d) { return d.close }
  1.2955 +        , getHigh = function(d) { return d.high }
  1.2956 +        , getLow = function(d) { return d.low }
  1.2957 +        , forceX = []
  1.2958 +        , forceY = []
  1.2959 +        , padData     = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
  1.2960 +        , clipEdge = true
  1.2961 +        , color = nv.utils.defaultColor()
  1.2962 +        , interactive = false
  1.2963 +        , xDomain
  1.2964 +        , yDomain
  1.2965 +        , xRange
  1.2966 +        , yRange
  1.2967 +        , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove')
  1.2968 +        ;
  1.2969 +
  1.2970 +    //============================================================
  1.2971 +    // Private Variables
  1.2972 +    //------------------------------------------------------------
  1.2973 +
  1.2974 +    function chart(selection) {
  1.2975 +        selection.each(function(data) {
  1.2976 +            container = d3.select(this);
  1.2977 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.2978 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.2979 +
  1.2980 +            nv.utils.initSVG(container);
  1.2981 +
  1.2982 +            // Width of the candlestick bars.
  1.2983 +            var barWidth = (availableWidth / data[0].values.length) * .45;
  1.2984 +
  1.2985 +            // Setup Scales
  1.2986 +            x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ));
  1.2987 +
  1.2988 +            if (padData)
  1.2989 +                x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5)  / data[0].values.length ]);
  1.2990 +            else
  1.2991 +                x.range(xRange || [5 + barWidth / 2, availableWidth - barWidth / 2 - 5]);
  1.2992 +
  1.2993 +            y.domain(yDomain || [
  1.2994 +                    d3.min(data[0].values.map(getLow).concat(forceY)),
  1.2995 +                    d3.max(data[0].values.map(getHigh).concat(forceY))
  1.2996 +                ]
  1.2997 +            ).range(yRange || [availableHeight, 0]);
  1.2998 +
  1.2999 +            // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
  1.3000 +            if (x.domain()[0] === x.domain()[1])
  1.3001 +                x.domain()[0] ?
  1.3002 +                    x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
  1.3003 +                    : x.domain([-1,1]);
  1.3004 +
  1.3005 +            if (y.domain()[0] === y.domain()[1])
  1.3006 +                y.domain()[0] ?
  1.3007 +                    y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
  1.3008 +                    : y.domain([-1,1]);
  1.3009 +
  1.3010 +            // Setup containers and skeleton of chart
  1.3011 +            var wrap = d3.select(this).selectAll('g.nv-wrap.nv-candlestickBar').data([data[0].values]);
  1.3012 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-candlestickBar');
  1.3013 +            var defsEnter = wrapEnter.append('defs');
  1.3014 +            var gEnter = wrapEnter.append('g');
  1.3015 +            var g = wrap.select('g');
  1.3016 +
  1.3017 +            gEnter.append('g').attr('class', 'nv-ticks');
  1.3018 +
  1.3019 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.3020 +
  1.3021 +            container
  1.3022 +                .on('click', function(d,i) {
  1.3023 +                    dispatch.chartClick({
  1.3024 +                        data: d,
  1.3025 +                        index: i,
  1.3026 +                        pos: d3.event,
  1.3027 +                        id: id
  1.3028 +                    });
  1.3029 +                });
  1.3030 +
  1.3031 +            defsEnter.append('clipPath')
  1.3032 +                .attr('id', 'nv-chart-clip-path-' + id)
  1.3033 +                .append('rect');
  1.3034 +
  1.3035 +            wrap.select('#nv-chart-clip-path-' + id + ' rect')
  1.3036 +                .attr('width', availableWidth)
  1.3037 +                .attr('height', availableHeight);
  1.3038 +
  1.3039 +            g   .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
  1.3040 +
  1.3041 +            var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick')
  1.3042 +                .data(function(d) { return d });
  1.3043 +            ticks.exit().remove();
  1.3044 +
  1.3045 +            // The colors are currently controlled by CSS.
  1.3046 +            var tickGroups = ticks.enter().append('g')
  1.3047 +                .attr('class', function(d, i, j) { return (getOpen(d, i) > getClose(d, i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i});
  1.3048 +
  1.3049 +            var lines = tickGroups.append('line')
  1.3050 +                .attr('class', 'nv-candlestick-lines')
  1.3051 +                .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; })
  1.3052 +                .attr('x1', 0)
  1.3053 +                .attr('y1', function(d, i) { return y(getHigh(d, i)); })
  1.3054 +                .attr('x2', 0)
  1.3055 +                .attr('y2', function(d, i) { return y(getLow(d, i)); });
  1.3056 +
  1.3057 +            var rects = tickGroups.append('rect')
  1.3058 +                .attr('class', 'nv-candlestick-rects nv-bars')
  1.3059 +                .attr('transform', function(d, i) {
  1.3060 +                    return 'translate(' + (x(getX(d, i)) - barWidth/2) + ','
  1.3061 +                    + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0))
  1.3062 +                    + ')';
  1.3063 +                })
  1.3064 +                .attr('x', 0)
  1.3065 +                .attr('y', 0)
  1.3066 +                .attr('width', barWidth)
  1.3067 +                .attr('height', function(d, i) {
  1.3068 +                    var open = getOpen(d, i);
  1.3069 +                    var close = getClose(d, i);
  1.3070 +                    return open > close ? y(close) - y(open) : y(open) - y(close);
  1.3071 +                });
  1.3072 +
  1.3073 +            container.selectAll('.nv-candlestick-lines').transition()
  1.3074 +                .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; })
  1.3075 +                .attr('x1', 0)
  1.3076 +                .attr('y1', function(d, i) { return y(getHigh(d, i)); })
  1.3077 +                .attr('x2', 0)
  1.3078 +                .attr('y2', function(d, i) { return y(getLow(d, i)); });
  1.3079 +
  1.3080 +            container.selectAll('.nv-candlestick-rects').transition()
  1.3081 +                .attr('transform', function(d, i) {
  1.3082 +                    return 'translate(' + (x(getX(d, i)) - barWidth/2) + ','
  1.3083 +                    + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0))
  1.3084 +                    + ')';
  1.3085 +                })
  1.3086 +                .attr('x', 0)
  1.3087 +                .attr('y', 0)
  1.3088 +                .attr('width', barWidth)
  1.3089 +                .attr('height', function(d, i) {
  1.3090 +                    var open = getOpen(d, i);
  1.3091 +                    var close = getClose(d, i);
  1.3092 +                    return open > close ? y(close) - y(open) : y(open) - y(close);
  1.3093 +                });
  1.3094 +        });
  1.3095 +
  1.3096 +        return chart;
  1.3097 +    }
  1.3098 +
  1.3099 +
  1.3100 +    //Create methods to allow outside functions to highlight a specific bar.
  1.3101 +    chart.highlightPoint = function(pointIndex, isHoverOver) {
  1.3102 +        chart.clearHighlights();
  1.3103 +        container.select(".nv-candlestickBar .nv-tick-0-" + pointIndex)
  1.3104 +            .classed("hover", isHoverOver)
  1.3105 +        ;
  1.3106 +    };
  1.3107 +
  1.3108 +    chart.clearHighlights = function() {
  1.3109 +        container.select(".nv-candlestickBar .nv-tick.hover")
  1.3110 +            .classed("hover", false)
  1.3111 +        ;
  1.3112 +    };
  1.3113 +
  1.3114 +    //============================================================
  1.3115 +    // Expose Public Variables
  1.3116 +    //------------------------------------------------------------
  1.3117 +
  1.3118 +    chart.dispatch = dispatch;
  1.3119 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.3120 +
  1.3121 +    chart._options = Object.create({}, {
  1.3122 +        // simple options, just get/set the necessary values
  1.3123 +        width:    {get: function(){return width;}, set: function(_){width=_;}},
  1.3124 +        height:   {get: function(){return height;}, set: function(_){height=_;}},
  1.3125 +        xScale:   {get: function(){return x;}, set: function(_){x=_;}},
  1.3126 +        yScale:   {get: function(){return y;}, set: function(_){y=_;}},
  1.3127 +        xDomain:  {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
  1.3128 +        yDomain:  {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
  1.3129 +        xRange:   {get: function(){return xRange;}, set: function(_){xRange=_;}},
  1.3130 +        yRange:   {get: function(){return yRange;}, set: function(_){yRange=_;}},
  1.3131 +        forceX:   {get: function(){return forceX;}, set: function(_){forceX=_;}},
  1.3132 +        forceY:   {get: function(){return forceY;}, set: function(_){forceY=_;}},
  1.3133 +        padData:  {get: function(){return padData;}, set: function(_){padData=_;}},
  1.3134 +        clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
  1.3135 +        id:       {get: function(){return id;}, set: function(_){id=_;}},
  1.3136 +        interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},
  1.3137 +
  1.3138 +        x:     {get: function(){return getX;}, set: function(_){getX=_;}},
  1.3139 +        y:     {get: function(){return getY;}, set: function(_){getY=_;}},
  1.3140 +        open:  {get: function(){return getOpen();}, set: function(_){getOpen=_;}},
  1.3141 +        close: {get: function(){return getClose();}, set: function(_){getClose=_;}},
  1.3142 +        high:  {get: function(){return getHigh;}, set: function(_){getHigh=_;}},
  1.3143 +        low:   {get: function(){return getLow;}, set: function(_){getLow=_;}},
  1.3144 +
  1.3145 +        // options that require extra logic in the setter
  1.3146 +        margin: {get: function(){return margin;}, set: function(_){
  1.3147 +            margin.top    = _.top    != undefined ? _.top    : margin.top;
  1.3148 +            margin.right  = _.right  != undefined ? _.right  : margin.right;
  1.3149 +            margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom;
  1.3150 +            margin.left   = _.left   != undefined ? _.left   : margin.left;
  1.3151 +        }},
  1.3152 +        color:  {get: function(){return color;}, set: function(_){
  1.3153 +            color = nv.utils.getColor(_);
  1.3154 +        }}
  1.3155 +    });
  1.3156 +
  1.3157 +    nv.utils.initOptions(chart);
  1.3158 +    return chart;
  1.3159 +};
  1.3160 +
  1.3161 +nv.models.cumulativeLineChart = function() {
  1.3162 +    "use strict";
  1.3163 +
  1.3164 +    //============================================================
  1.3165 +    // Public Variables with Default Settings
  1.3166 +    //------------------------------------------------------------
  1.3167 +
  1.3168 +    var lines = nv.models.line()
  1.3169 +        , xAxis = nv.models.axis()
  1.3170 +        , yAxis = nv.models.axis()
  1.3171 +        , legend = nv.models.legend()
  1.3172 +        , controls = nv.models.legend()
  1.3173 +        , interactiveLayer = nv.interactiveGuideline()
  1.3174 +        , tooltip = nv.models.tooltip()
  1.3175 +        ;
  1.3176 +
  1.3177 +    var margin = {top: 30, right: 30, bottom: 50, left: 60}
  1.3178 +        , color = nv.utils.defaultColor()
  1.3179 +        , width = null
  1.3180 +        , height = null
  1.3181 +        , showLegend = true
  1.3182 +        , showXAxis = true
  1.3183 +        , showYAxis = true
  1.3184 +        , rightAlignYAxis = false
  1.3185 +        , showControls = true
  1.3186 +        , useInteractiveGuideline = false
  1.3187 +        , rescaleY = true
  1.3188 +        , x //can be accessed via chart.xScale()
  1.3189 +        , y //can be accessed via chart.yScale()
  1.3190 +        , id = lines.id()
  1.3191 +        , state = nv.utils.state()
  1.3192 +        , defaultState = null
  1.3193 +        , noData = null
  1.3194 +        , average = function(d) { return d.average }
  1.3195 +        , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd')
  1.3196 +        , transitionDuration = 250
  1.3197 +        , duration = 250
  1.3198 +        , noErrorCheck = false  //if set to TRUE, will bypass an error check in the indexify function.
  1.3199 +        ;
  1.3200 +
  1.3201 +    state.index = 0;
  1.3202 +    state.rescaleY = rescaleY;
  1.3203 +
  1.3204 +    xAxis.orient('bottom').tickPadding(7);
  1.3205 +    yAxis.orient((rightAlignYAxis) ? 'right' : 'left');
  1.3206 +
  1.3207 +    tooltip.valueFormatter(function(d, i) {
  1.3208 +        return yAxis.tickFormat()(d, i);
  1.3209 +    }).headerFormatter(function(d, i) {
  1.3210 +        return xAxis.tickFormat()(d, i);
  1.3211 +    });
  1.3212 +
  1.3213 +    controls.updateState(false);
  1.3214 +
  1.3215 +    //============================================================
  1.3216 +    // Private Variables
  1.3217 +    //------------------------------------------------------------
  1.3218 +
  1.3219 +    var dx = d3.scale.linear()
  1.3220 +        , index = {i: 0, x: 0}
  1.3221 +        , renderWatch = nv.utils.renderWatch(dispatch, duration)
  1.3222 +        ;
  1.3223 +
  1.3224 +    var stateGetter = function(data) {
  1.3225 +        return function(){
  1.3226 +            return {
  1.3227 +                active: data.map(function(d) { return !d.disabled }),
  1.3228 +                index: index.i,
  1.3229 +                rescaleY: rescaleY
  1.3230 +            };
  1.3231 +        }
  1.3232 +    };
  1.3233 +
  1.3234 +    var stateSetter = function(data) {
  1.3235 +        return function(state) {
  1.3236 +            if (state.index !== undefined)
  1.3237 +                index.i = state.index;
  1.3238 +            if (state.rescaleY !== undefined)
  1.3239 +                rescaleY = state.rescaleY;
  1.3240 +            if (state.active !== undefined)
  1.3241 +                data.forEach(function(series,i) {
  1.3242 +                    series.disabled = !state.active[i];
  1.3243 +                });
  1.3244 +        }
  1.3245 +    };
  1.3246 +
  1.3247 +    function chart(selection) {
  1.3248 +        renderWatch.reset();
  1.3249 +        renderWatch.models(lines);
  1.3250 +        if (showXAxis) renderWatch.models(xAxis);
  1.3251 +        if (showYAxis) renderWatch.models(yAxis);
  1.3252 +        selection.each(function(data) {
  1.3253 +            var container = d3.select(this);
  1.3254 +            nv.utils.initSVG(container);
  1.3255 +            container.classed('nv-chart-' + id, true);
  1.3256 +            var that = this;
  1.3257 +
  1.3258 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.3259 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.3260 +
  1.3261 +            chart.update = function() {
  1.3262 +                if (duration === 0)
  1.3263 +                    container.call(chart);
  1.3264 +                else
  1.3265 +                    container.transition().duration(duration).call(chart)
  1.3266 +            };
  1.3267 +            chart.container = this;
  1.3268 +
  1.3269 +            state
  1.3270 +                .setter(stateSetter(data), chart.update)
  1.3271 +                .getter(stateGetter(data))
  1.3272 +                .update();
  1.3273 +
  1.3274 +            // DEPRECATED set state.disableddisabled
  1.3275 +            state.disabled = data.map(function(d) { return !!d.disabled });
  1.3276 +
  1.3277 +            if (!defaultState) {
  1.3278 +                var key;
  1.3279 +                defaultState = {};
  1.3280 +                for (key in state) {
  1.3281 +                    if (state[key] instanceof Array)
  1.3282 +                        defaultState[key] = state[key].slice(0);
  1.3283 +                    else
  1.3284 +                        defaultState[key] = state[key];
  1.3285 +                }
  1.3286 +            }
  1.3287 +
  1.3288 +            var indexDrag = d3.behavior.drag()
  1.3289 +                .on('dragstart', dragStart)
  1.3290 +                .on('drag', dragMove)
  1.3291 +                .on('dragend', dragEnd);
  1.3292 +
  1.3293 +
  1.3294 +            function dragStart(d,i) {
  1.3295 +                d3.select(chart.container)
  1.3296 +                    .style('cursor', 'ew-resize');
  1.3297 +            }
  1.3298 +
  1.3299 +            function dragMove(d,i) {
  1.3300 +                index.x = d3.event.x;
  1.3301 +                index.i = Math.round(dx.invert(index.x));
  1.3302 +                updateZero();
  1.3303 +            }
  1.3304 +
  1.3305 +            function dragEnd(d,i) {
  1.3306 +                d3.select(chart.container)
  1.3307 +                    .style('cursor', 'auto');
  1.3308 +
  1.3309 +                // update state and send stateChange with new index
  1.3310 +                state.index = index.i;
  1.3311 +                dispatch.stateChange(state);
  1.3312 +            }
  1.3313 +
  1.3314 +            // Display No Data message if there's nothing to show.
  1.3315 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.3316 +                nv.utils.noData(chart, container)
  1.3317 +                return chart;
  1.3318 +            } else {
  1.3319 +                container.selectAll('.nv-noData').remove();
  1.3320 +            }
  1.3321 +
  1.3322 +            // Setup Scales
  1.3323 +            x = lines.xScale();
  1.3324 +            y = lines.yScale();
  1.3325 +
  1.3326 +            if (!rescaleY) {
  1.3327 +                var seriesDomains = data
  1.3328 +                    .filter(function(series) { return !series.disabled })
  1.3329 +                    .map(function(series,i) {
  1.3330 +                        var initialDomain = d3.extent(series.values, lines.y());
  1.3331 +
  1.3332 +                        //account for series being disabled when losing 95% or more
  1.3333 +                        if (initialDomain[0] < -.95) initialDomain[0] = -.95;
  1.3334 +
  1.3335 +                        return [
  1.3336 +                                (initialDomain[0] - initialDomain[1]) / (1 + initialDomain[1]),
  1.3337 +                                (initialDomain[1] - initialDomain[0]) / (1 + initialDomain[0])
  1.3338 +                        ];
  1.3339 +                    });
  1.3340 +
  1.3341 +                var completeDomain = [
  1.3342 +                    d3.min(seriesDomains, function(d) { return d[0] }),
  1.3343 +                    d3.max(seriesDomains, function(d) { return d[1] })
  1.3344 +                ];
  1.3345 +
  1.3346 +                lines.yDomain(completeDomain);
  1.3347 +            } else {
  1.3348 +                lines.yDomain(null);
  1.3349 +            }
  1.3350 +
  1.3351 +            dx.domain([0, data[0].values.length - 1]) //Assumes all series have same length
  1.3352 +                .range([0, availableWidth])
  1.3353 +                .clamp(true);
  1.3354 +
  1.3355 +            var data = indexify(index.i, data);
  1.3356 +
  1.3357 +            // Setup containers and skeleton of chart
  1.3358 +            var interactivePointerEvents = (useInteractiveGuideline) ? "none" : "all";
  1.3359 +            var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]);
  1.3360 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-cumulativeLine').append('g');
  1.3361 +            var g = wrap.select('g');
  1.3362 +
  1.3363 +            gEnter.append('g').attr('class', 'nv-interactive');
  1.3364 +            gEnter.append('g').attr('class', 'nv-x nv-axis').style("pointer-events","none");
  1.3365 +            gEnter.append('g').attr('class', 'nv-y nv-axis');
  1.3366 +            gEnter.append('g').attr('class', 'nv-background');
  1.3367 +            gEnter.append('g').attr('class', 'nv-linesWrap').style("pointer-events",interactivePointerEvents);
  1.3368 +            gEnter.append('g').attr('class', 'nv-avgLinesWrap').style("pointer-events","none");
  1.3369 +            gEnter.append('g').attr('class', 'nv-legendWrap');
  1.3370 +            gEnter.append('g').attr('class', 'nv-controlsWrap');
  1.3371 +
  1.3372 +            // Legend
  1.3373 +            if (showLegend) {
  1.3374 +                legend.width(availableWidth);
  1.3375 +
  1.3376 +                g.select('.nv-legendWrap')
  1.3377 +                    .datum(data)
  1.3378 +                    .call(legend);
  1.3379 +
  1.3380 +                if ( margin.top != legend.height()) {
  1.3381 +                    margin.top = legend.height();
  1.3382 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
  1.3383 +                }
  1.3384 +
  1.3385 +                g.select('.nv-legendWrap')
  1.3386 +                    .attr('transform', 'translate(0,' + (-margin.top) +')')
  1.3387 +            }
  1.3388 +
  1.3389 +            // Controls
  1.3390 +            if (showControls) {
  1.3391 +                var controlsData = [
  1.3392 +                    { key: 'Re-scale y-axis', disabled: !rescaleY }
  1.3393 +                ];
  1.3394 +
  1.3395 +                controls
  1.3396 +                    .width(140)
  1.3397 +                    .color(['#444', '#444', '#444'])
  1.3398 +                    .rightAlign(false)
  1.3399 +                    .margin({top: 5, right: 0, bottom: 5, left: 20})
  1.3400 +                ;
  1.3401 +
  1.3402 +                g.select('.nv-controlsWrap')
  1.3403 +                    .datum(controlsData)
  1.3404 +                    .attr('transform', 'translate(0,' + (-margin.top) +')')
  1.3405 +                    .call(controls);
  1.3406 +            }
  1.3407 +
  1.3408 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.3409 +
  1.3410 +            if (rightAlignYAxis) {
  1.3411 +                g.select(".nv-y.nv-axis")
  1.3412 +                    .attr("transform", "translate(" + availableWidth + ",0)");
  1.3413 +            }
  1.3414 +
  1.3415 +            // Show error if series goes below 100%
  1.3416 +            var tempDisabled = data.filter(function(d) { return d.tempDisabled });
  1.3417 +
  1.3418 +            wrap.select('.tempDisabled').remove(); //clean-up and prevent duplicates
  1.3419 +            if (tempDisabled.length) {
  1.3420 +                wrap.append('text').attr('class', 'tempDisabled')
  1.3421 +                    .attr('x', availableWidth / 2)
  1.3422 +                    .attr('y', '-.71em')
  1.3423 +                    .style('text-anchor', 'end')
  1.3424 +                    .text(tempDisabled.map(function(d) { return d.key }).join(', ') + ' values cannot be calculated for this time period.');
  1.3425 +            }
  1.3426 +
  1.3427 +            //Set up interactive layer
  1.3428 +            if (useInteractiveGuideline) {
  1.3429 +                interactiveLayer
  1.3430 +                    .width(availableWidth)
  1.3431 +                    .height(availableHeight)
  1.3432 +                    .margin({left:margin.left,top:margin.top})
  1.3433 +                    .svgContainer(container)
  1.3434 +                    .xScale(x);
  1.3435 +                wrap.select(".nv-interactive").call(interactiveLayer);
  1.3436 +            }
  1.3437 +
  1.3438 +            gEnter.select('.nv-background')
  1.3439 +                .append('rect');
  1.3440 +
  1.3441 +            g.select('.nv-background rect')
  1.3442 +                .attr('width', availableWidth)
  1.3443 +                .attr('height', availableHeight);
  1.3444 +
  1.3445 +            lines
  1.3446 +                //.x(function(d) { return d.x })
  1.3447 +                .y(function(d) { return d.display.y })
  1.3448 +                .width(availableWidth)
  1.3449 +                .height(availableHeight)
  1.3450 +                .color(data.map(function(d,i) {
  1.3451 +                    return d.color || color(d, i);
  1.3452 +                }).filter(function(d,i) { return !data[i].disabled && !data[i].tempDisabled; }));
  1.3453 +
  1.3454 +            var linesWrap = g.select('.nv-linesWrap')
  1.3455 +                .datum(data.filter(function(d) { return  !d.disabled && !d.tempDisabled }));
  1.3456 +
  1.3457 +            linesWrap.call(lines);
  1.3458 +
  1.3459 +            //Store a series index number in the data array.
  1.3460 +            data.forEach(function(d,i) {
  1.3461 +                d.seriesIndex = i;
  1.3462 +            });
  1.3463 +
  1.3464 +            var avgLineData = data.filter(function(d) {
  1.3465 +                return !d.disabled && !!average(d);
  1.3466 +            });
  1.3467 +
  1.3468 +            var avgLines = g.select(".nv-avgLinesWrap").selectAll("line")
  1.3469 +                .data(avgLineData, function(d) { return d.key; });
  1.3470 +
  1.3471 +            var getAvgLineY = function(d) {
  1.3472 +                //If average lines go off the svg element, clamp them to the svg bounds.
  1.3473 +                var yVal = y(average(d));
  1.3474 +                if (yVal < 0) return 0;
  1.3475 +                if (yVal > availableHeight) return availableHeight;
  1.3476 +                return yVal;
  1.3477 +            };
  1.3478 +
  1.3479 +            avgLines.enter()
  1.3480 +                .append('line')
  1.3481 +                .style('stroke-width',2)
  1.3482 +                .style('stroke-dasharray','10,10')
  1.3483 +                .style('stroke',function (d,i) {
  1.3484 +                    return lines.color()(d,d.seriesIndex);
  1.3485 +                })
  1.3486 +                .attr('x1',0)
  1.3487 +                .attr('x2',availableWidth)
  1.3488 +                .attr('y1', getAvgLineY)
  1.3489 +                .attr('y2', getAvgLineY);
  1.3490 +
  1.3491 +            avgLines
  1.3492 +                .style('stroke-opacity',function(d){
  1.3493 +                    //If average lines go offscreen, make them transparent
  1.3494 +                    var yVal = y(average(d));
  1.3495 +                    if (yVal < 0 || yVal > availableHeight) return 0;
  1.3496 +                    return 1;
  1.3497 +                })
  1.3498 +                .attr('x1',0)
  1.3499 +                .attr('x2',availableWidth)
  1.3500 +                .attr('y1', getAvgLineY)
  1.3501 +                .attr('y2', getAvgLineY);
  1.3502 +
  1.3503 +            avgLines.exit().remove();
  1.3504 +
  1.3505 +            //Create index line
  1.3506 +            var indexLine = linesWrap.selectAll('.nv-indexLine')
  1.3507 +                .data([index]);
  1.3508 +            indexLine.enter().append('rect').attr('class', 'nv-indexLine')
  1.3509 +                .attr('width', 3)
  1.3510 +                .attr('x', -2)
  1.3511 +                .attr('fill', 'red')
  1.3512 +                .attr('fill-opacity', .5)
  1.3513 +                .style("pointer-events","all")
  1.3514 +                .call(indexDrag);
  1.3515 +
  1.3516 +            indexLine
  1.3517 +                .attr('transform', function(d) { return 'translate(' + dx(d.i) + ',0)' })
  1.3518 +                .attr('height', availableHeight);
  1.3519 +
  1.3520 +            // Setup Axes
  1.3521 +            if (showXAxis) {
  1.3522 +                xAxis
  1.3523 +                    .scale(x)
  1.3524 +                    ._ticks( nv.utils.calcTicksX(availableWidth/70, data) )
  1.3525 +                    .tickSize(-availableHeight, 0);
  1.3526 +
  1.3527 +                g.select('.nv-x.nv-axis')
  1.3528 +                    .attr('transform', 'translate(0,' + y.range()[0] + ')');
  1.3529 +                g.select('.nv-x.nv-axis')
  1.3530 +                    .call(xAxis);
  1.3531 +            }
  1.3532 +
  1.3533 +            if (showYAxis) {
  1.3534 +                yAxis
  1.3535 +                    .scale(y)
  1.3536 +                    ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
  1.3537 +                    .tickSize( -availableWidth, 0);
  1.3538 +
  1.3539 +                g.select('.nv-y.nv-axis')
  1.3540 +                    .call(yAxis);
  1.3541 +            }
  1.3542 +
  1.3543 +            //============================================================
  1.3544 +            // Event Handling/Dispatching (in chart's scope)
  1.3545 +            //------------------------------------------------------------
  1.3546 +
  1.3547 +            function updateZero() {
  1.3548 +                indexLine
  1.3549 +                    .data([index]);
  1.3550 +
  1.3551 +                //When dragging the index line, turn off line transitions.
  1.3552 +                // Then turn them back on when done dragging.
  1.3553 +                var oldDuration = chart.duration();
  1.3554 +                chart.duration(0);
  1.3555 +                chart.update();
  1.3556 +                chart.duration(oldDuration);
  1.3557 +            }
  1.3558 +
  1.3559 +            g.select('.nv-background rect')
  1.3560 +                .on('click', function() {
  1.3561 +                    index.x = d3.mouse(this)[0];
  1.3562 +                    index.i = Math.round(dx.invert(index.x));
  1.3563 +
  1.3564 +                    // update state and send stateChange with new index
  1.3565 +                    state.index = index.i;
  1.3566 +                    dispatch.stateChange(state);
  1.3567 +
  1.3568 +                    updateZero();
  1.3569 +                });
  1.3570 +
  1.3571 +            lines.dispatch.on('elementClick', function(e) {
  1.3572 +                index.i = e.pointIndex;
  1.3573 +                index.x = dx(index.i);
  1.3574 +
  1.3575 +                // update state and send stateChange with new index
  1.3576 +                state.index = index.i;
  1.3577 +                dispatch.stateChange(state);
  1.3578 +
  1.3579 +                updateZero();
  1.3580 +            });
  1.3581 +
  1.3582 +            controls.dispatch.on('legendClick', function(d,i) {
  1.3583 +                d.disabled = !d.disabled;
  1.3584 +                rescaleY = !d.disabled;
  1.3585 +
  1.3586 +                state.rescaleY = rescaleY;
  1.3587 +                dispatch.stateChange(state);
  1.3588 +                chart.update();
  1.3589 +            });
  1.3590 +
  1.3591 +            legend.dispatch.on('stateChange', function(newState) {
  1.3592 +                for (var key in newState)
  1.3593 +                    state[key] = newState[key];
  1.3594 +                dispatch.stateChange(state);
  1.3595 +                chart.update();
  1.3596 +            });
  1.3597 +
  1.3598 +            interactiveLayer.dispatch.on('elementMousemove', function(e) {
  1.3599 +                lines.clearHighlights();
  1.3600 +                var singlePoint, pointIndex, pointXLocation, allData = [];
  1.3601 +
  1.3602 +                data
  1.3603 +                    .filter(function(series, i) {
  1.3604 +                        series.seriesIndex = i;
  1.3605 +                        return !series.disabled;
  1.3606 +                    })
  1.3607 +                    .forEach(function(series,i) {
  1.3608 +                        pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
  1.3609 +                        lines.highlightPoint(i, pointIndex, true);
  1.3610 +                        var point = series.values[pointIndex];
  1.3611 +                        if (typeof point === 'undefined') return;
  1.3612 +                        if (typeof singlePoint === 'undefined') singlePoint = point;
  1.3613 +                        if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
  1.3614 +                        allData.push({
  1.3615 +                            key: series.key,
  1.3616 +                            value: chart.y()(point, pointIndex),
  1.3617 +                            color: color(series,series.seriesIndex)
  1.3618 +                        });
  1.3619 +                    });
  1.3620 +
  1.3621 +                //Highlight the tooltip entry based on which point the mouse is closest to.
  1.3622 +                if (allData.length > 2) {
  1.3623 +                    var yValue = chart.yScale().invert(e.mouseY);
  1.3624 +                    var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
  1.3625 +                    var threshold = 0.03 * domainExtent;
  1.3626 +                    var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold);
  1.3627 +                    if (indexToHighlight !== null)
  1.3628 +                        allData[indexToHighlight].highlight = true;
  1.3629 +                }
  1.3630 +
  1.3631 +                var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex), pointIndex);
  1.3632 +                interactiveLayer.tooltip
  1.3633 +                    .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
  1.3634 +                    .chartContainer(that.parentNode)
  1.3635 +                    .valueFormatter(function(d,i) {
  1.3636 +                        return yAxis.tickFormat()(d);
  1.3637 +                    })
  1.3638 +                    .data(
  1.3639 +                    {
  1.3640 +                        value: xValue,
  1.3641 +                        series: allData
  1.3642 +                    }
  1.3643 +                )();
  1.3644 +
  1.3645 +                interactiveLayer.renderGuideLine(pointXLocation);
  1.3646 +            });
  1.3647 +
  1.3648 +            interactiveLayer.dispatch.on("elementMouseout",function(e) {
  1.3649 +                lines.clearHighlights();
  1.3650 +            });
  1.3651 +
  1.3652 +            // Update chart from a state object passed to event handler
  1.3653 +            dispatch.on('changeState', function(e) {
  1.3654 +                if (typeof e.disabled !== 'undefined') {
  1.3655 +                    data.forEach(function(series,i) {
  1.3656 +                        series.disabled = e.disabled[i];
  1.3657 +                    });
  1.3658 +
  1.3659 +                    state.disabled = e.disabled;
  1.3660 +                }
  1.3661 +
  1.3662 +                if (typeof e.index !== 'undefined') {
  1.3663 +                    index.i = e.index;
  1.3664 +                    index.x = dx(index.i);
  1.3665 +
  1.3666 +                    state.index = e.index;
  1.3667 +
  1.3668 +                    indexLine
  1.3669 +                        .data([index]);
  1.3670 +                }
  1.3671 +
  1.3672 +                if (typeof e.rescaleY !== 'undefined') {
  1.3673 +                    rescaleY = e.rescaleY;
  1.3674 +                }
  1.3675 +
  1.3676 +                chart.update();
  1.3677 +            });
  1.3678 +
  1.3679 +        });
  1.3680 +
  1.3681 +        renderWatch.renderEnd('cumulativeLineChart immediate');
  1.3682 +
  1.3683 +        return chart;
  1.3684 +    }
  1.3685 +
  1.3686 +    //============================================================
  1.3687 +    // Event Handling/Dispatching (out of chart's scope)
  1.3688 +    //------------------------------------------------------------
  1.3689 +
  1.3690 +    lines.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.3691 +        var point = {
  1.3692 +            x: chart.x()(evt.point),
  1.3693 +            y: chart.y()(evt.point),
  1.3694 +            color: evt.point.color
  1.3695 +        };
  1.3696 +        evt.point = point;
  1.3697 +        tooltip.data(evt).position(evt.pos).hidden(false);
  1.3698 +    });
  1.3699 +
  1.3700 +    lines.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.3701 +        tooltip.hidden(true)
  1.3702 +    });
  1.3703 +
  1.3704 +    //============================================================
  1.3705 +    // Functions
  1.3706 +    //------------------------------------------------------------
  1.3707 +
  1.3708 +    var indexifyYGetter = null;
  1.3709 +    /* Normalize the data according to an index point. */
  1.3710 +    function indexify(idx, data) {
  1.3711 +        if (!indexifyYGetter) indexifyYGetter = lines.y();
  1.3712 +        return data.map(function(line, i) {
  1.3713 +            if (!line.values) {
  1.3714 +                return line;
  1.3715 +            }
  1.3716 +            var indexValue = line.values[idx];
  1.3717 +            if (indexValue == null) {
  1.3718 +                return line;
  1.3719 +            }
  1.3720 +            var v = indexifyYGetter(indexValue, idx);
  1.3721 +
  1.3722 +            //TODO: implement check below, and disable series if series loses 100% or more cause divide by 0 issue
  1.3723 +            if (v < -.95 && !noErrorCheck) {
  1.3724 +                //if a series loses more than 100%, calculations fail.. anything close can cause major distortion (but is mathematically correct till it hits 100)
  1.3725 +
  1.3726 +                line.tempDisabled = true;
  1.3727 +                return line;
  1.3728 +            }
  1.3729 +
  1.3730 +            line.tempDisabled = false;
  1.3731 +
  1.3732 +            line.values = line.values.map(function(point, pointIndex) {
  1.3733 +                point.display = {'y': (indexifyYGetter(point, pointIndex) - v) / (1 + v) };
  1.3734 +                return point;
  1.3735 +            });
  1.3736 +
  1.3737 +            return line;
  1.3738 +        })
  1.3739 +    }
  1.3740 +
  1.3741 +    //============================================================
  1.3742 +    // Expose Public Variables
  1.3743 +    //------------------------------------------------------------
  1.3744 +
  1.3745 +    // expose chart's sub-components
  1.3746 +    chart.dispatch = dispatch;
  1.3747 +    chart.lines = lines;
  1.3748 +    chart.legend = legend;
  1.3749 +    chart.controls = controls;
  1.3750 +    chart.xAxis = xAxis;
  1.3751 +    chart.yAxis = yAxis;
  1.3752 +    chart.interactiveLayer = interactiveLayer;
  1.3753 +    chart.state = state;
  1.3754 +    chart.tooltip = tooltip;
  1.3755 +
  1.3756 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.3757 +
  1.3758 +    chart._options = Object.create({}, {
  1.3759 +        // simple options, just get/set the necessary values
  1.3760 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.3761 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.3762 +        rescaleY:     {get: function(){return rescaleY;}, set: function(_){rescaleY=_;}},
  1.3763 +        showControls:     {get: function(){return showControls;}, set: function(_){showControls=_;}},
  1.3764 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.3765 +        average: {get: function(){return average;}, set: function(_){average=_;}},
  1.3766 +        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
  1.3767 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.3768 +        showXAxis:    {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
  1.3769 +        showYAxis:    {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
  1.3770 +        noErrorCheck:    {get: function(){return noErrorCheck;}, set: function(_){noErrorCheck=_;}},
  1.3771 +
  1.3772 +        // deprecated options
  1.3773 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.3774 +            // deprecated after 1.7.1
  1.3775 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.3776 +            tooltip.enabled(!!_);
  1.3777 +        }},
  1.3778 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.3779 +            // deprecated after 1.7.1
  1.3780 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.3781 +            tooltip.contentGenerator(_);
  1.3782 +        }},
  1.3783 +
  1.3784 +        // options that require extra logic in the setter
  1.3785 +        margin: {get: function(){return margin;}, set: function(_){
  1.3786 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.3787 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.3788 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.3789 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.3790 +        }},
  1.3791 +        color:  {get: function(){return color;}, set: function(_){
  1.3792 +            color = nv.utils.getColor(_);
  1.3793 +            legend.color(color);
  1.3794 +        }},
  1.3795 +        useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
  1.3796 +            useInteractiveGuideline = _;
  1.3797 +            if (_ === true) {
  1.3798 +                chart.interactive(false);
  1.3799 +                chart.useVoronoi(false);
  1.3800 +            }
  1.3801 +        }},
  1.3802 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
  1.3803 +            rightAlignYAxis = _;
  1.3804 +            yAxis.orient( (_) ? 'right' : 'left');
  1.3805 +        }},
  1.3806 +        duration:    {get: function(){return duration;}, set: function(_){
  1.3807 +            duration = _;
  1.3808 +            lines.duration(duration);
  1.3809 +            xAxis.duration(duration);
  1.3810 +            yAxis.duration(duration);
  1.3811 +            renderWatch.reset(duration);
  1.3812 +        }}
  1.3813 +    });
  1.3814 +
  1.3815 +    nv.utils.inheritOptions(chart, lines);
  1.3816 +    nv.utils.initOptions(chart);
  1.3817 +
  1.3818 +    return chart;
  1.3819 +};
  1.3820 +//TODO: consider deprecating by adding necessary features to multiBar model
  1.3821 +nv.models.discreteBar = function() {
  1.3822 +    "use strict";
  1.3823 +
  1.3824 +    //============================================================
  1.3825 +    // Public Variables with Default Settings
  1.3826 +    //------------------------------------------------------------
  1.3827 +
  1.3828 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.3829 +        , width = 960
  1.3830 +        , height = 500
  1.3831 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
  1.3832 +        , container
  1.3833 +        , x = d3.scale.ordinal()
  1.3834 +        , y = d3.scale.linear()
  1.3835 +        , getX = function(d) { return d.x }
  1.3836 +        , getY = function(d) { return d.y }
  1.3837 +        , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
  1.3838 +        , color = nv.utils.defaultColor()
  1.3839 +        , showValues = false
  1.3840 +        , valueFormat = d3.format(',.2f')
  1.3841 +        , xDomain
  1.3842 +        , yDomain
  1.3843 +        , xRange
  1.3844 +        , yRange
  1.3845 +        , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd')
  1.3846 +        , rectClass = 'discreteBar'
  1.3847 +        , duration = 250
  1.3848 +        ;
  1.3849 +
  1.3850 +    //============================================================
  1.3851 +    // Private Variables
  1.3852 +    //------------------------------------------------------------
  1.3853 +
  1.3854 +    var x0, y0;
  1.3855 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.3856 +
  1.3857 +    function chart(selection) {
  1.3858 +        renderWatch.reset();
  1.3859 +        selection.each(function(data) {
  1.3860 +            var availableWidth = width - margin.left - margin.right,
  1.3861 +                availableHeight = height - margin.top - margin.bottom;
  1.3862 +
  1.3863 +            container = d3.select(this);
  1.3864 +            nv.utils.initSVG(container);
  1.3865 +
  1.3866 +            //add series index to each data point for reference
  1.3867 +            data.forEach(function(series, i) {
  1.3868 +                series.values.forEach(function(point) {
  1.3869 +                    point.series = i;
  1.3870 +                });
  1.3871 +            });
  1.3872 +
  1.3873 +            // Setup Scales
  1.3874 +            // remap and flatten the data for use in calculating the scales' domains
  1.3875 +            var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
  1.3876 +                data.map(function(d) {
  1.3877 +                    return d.values.map(function(d,i) {
  1.3878 +                        return { x: getX(d,i), y: getY(d,i), y0: d.y0 }
  1.3879 +                    })
  1.3880 +                });
  1.3881 +
  1.3882 +            x   .domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
  1.3883 +                .rangeBands(xRange || [0, availableWidth], .1);
  1.3884 +            y   .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY)));
  1.3885 +
  1.3886 +            // If showValues, pad the Y axis range to account for label height
  1.3887 +            if (showValues) y.range(yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]);
  1.3888 +            else y.range(yRange || [availableHeight, 0]);
  1.3889 +
  1.3890 +            //store old scales if they exist
  1.3891 +            x0 = x0 || x;
  1.3892 +            y0 = y0 || y.copy().range([y(0),y(0)]);
  1.3893 +
  1.3894 +            // Setup containers and skeleton of chart
  1.3895 +            var wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([data]);
  1.3896 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discretebar');
  1.3897 +            var gEnter = wrapEnter.append('g');
  1.3898 +            var g = wrap.select('g');
  1.3899 +
  1.3900 +            gEnter.append('g').attr('class', 'nv-groups');
  1.3901 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.3902 +
  1.3903 +            //TODO: by definition, the discrete bar should not have multiple groups, will modify/remove later
  1.3904 +            var groups = wrap.select('.nv-groups').selectAll('.nv-group')
  1.3905 +                .data(function(d) { return d }, function(d) { return d.key });
  1.3906 +            groups.enter().append('g')
  1.3907 +                .style('stroke-opacity', 1e-6)
  1.3908 +                .style('fill-opacity', 1e-6);
  1.3909 +            groups.exit()
  1.3910 +                .watchTransition(renderWatch, 'discreteBar: exit groups')
  1.3911 +                .style('stroke-opacity', 1e-6)
  1.3912 +                .style('fill-opacity', 1e-6)
  1.3913 +                .remove();
  1.3914 +            groups
  1.3915 +                .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
  1.3916 +                .classed('hover', function(d) { return d.hover });
  1.3917 +            groups
  1.3918 +                .watchTransition(renderWatch, 'discreteBar: groups')
  1.3919 +                .style('stroke-opacity', 1)
  1.3920 +                .style('fill-opacity', .75);
  1.3921 +
  1.3922 +            var bars = groups.selectAll('g.nv-bar')
  1.3923 +                .data(function(d) { return d.values });
  1.3924 +            bars.exit().remove();
  1.3925 +
  1.3926 +            var barsEnter = bars.enter().append('g')
  1.3927 +                .attr('transform', function(d,i,j) {
  1.3928 +                    return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')'
  1.3929 +                })
  1.3930 +                .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
  1.3931 +                    d3.select(this).classed('hover', true);
  1.3932 +                    dispatch.elementMouseover({
  1.3933 +                        data: d,
  1.3934 +                        index: i,
  1.3935 +                        color: d3.select(this).style("fill")
  1.3936 +                    });
  1.3937 +                })
  1.3938 +                .on('mouseout', function(d,i) {
  1.3939 +                    d3.select(this).classed('hover', false);
  1.3940 +                    dispatch.elementMouseout({
  1.3941 +                        data: d,
  1.3942 +                        index: i,
  1.3943 +                        color: d3.select(this).style("fill")
  1.3944 +                    });
  1.3945 +                })
  1.3946 +                .on('mousemove', function(d,i) {
  1.3947 +                    dispatch.elementMousemove({
  1.3948 +                        data: d,
  1.3949 +                        index: i,
  1.3950 +                        color: d3.select(this).style("fill")
  1.3951 +                    });
  1.3952 +                })
  1.3953 +                .on('click', function(d,i) {
  1.3954 +                    dispatch.elementClick({
  1.3955 +                        data: d,
  1.3956 +                        index: i,
  1.3957 +                        color: d3.select(this).style("fill")
  1.3958 +                    });
  1.3959 +                    d3.event.stopPropagation();
  1.3960 +                })
  1.3961 +                .on('dblclick', function(d,i) {
  1.3962 +                    dispatch.elementDblClick({
  1.3963 +                        data: d,
  1.3964 +                        index: i,
  1.3965 +                        color: d3.select(this).style("fill")
  1.3966 +                    });
  1.3967 +                    d3.event.stopPropagation();
  1.3968 +                });
  1.3969 +
  1.3970 +            barsEnter.append('rect')
  1.3971 +                .attr('height', 0)
  1.3972 +                .attr('width', x.rangeBand() * .9 / data.length )
  1.3973 +
  1.3974 +            if (showValues) {
  1.3975 +                barsEnter.append('text')
  1.3976 +                    .attr('text-anchor', 'middle')
  1.3977 +                ;
  1.3978 +
  1.3979 +                bars.select('text')
  1.3980 +                    .text(function(d,i) { return valueFormat(getY(d,i)) })
  1.3981 +                    .watchTransition(renderWatch, 'discreteBar: bars text')
  1.3982 +                    .attr('x', x.rangeBand() * .9 / 2)
  1.3983 +                    .attr('y', function(d,i) { return getY(d,i) < 0 ? y(getY(d,i)) - y(0) + 12 : -4 })
  1.3984 +
  1.3985 +                ;
  1.3986 +            } else {
  1.3987 +                bars.selectAll('text').remove();
  1.3988 +            }
  1.3989 +
  1.3990 +            bars
  1.3991 +                .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive' })
  1.3992 +                .style('fill', function(d,i) { return d.color || color(d,i) })
  1.3993 +                .style('stroke', function(d,i) { return d.color || color(d,i) })
  1.3994 +                .select('rect')
  1.3995 +                .attr('class', rectClass)
  1.3996 +                .watchTransition(renderWatch, 'discreteBar: bars rect')
  1.3997 +                .attr('width', x.rangeBand() * .9 / data.length);
  1.3998 +            bars.watchTransition(renderWatch, 'discreteBar: bars')
  1.3999 +                //.delay(function(d,i) { return i * 1200 / data[0].values.length })
  1.4000 +                .attr('transform', function(d,i) {
  1.4001 +                    var left = x(getX(d,i)) + x.rangeBand() * .05,
  1.4002 +                        top = getY(d,i) < 0 ?
  1.4003 +                            y(0) :
  1.4004 +                                y(0) - y(getY(d,i)) < 1 ?
  1.4005 +                            y(0) - 1 : //make 1 px positive bars show up above y=0
  1.4006 +                            y(getY(d,i));
  1.4007 +
  1.4008 +                    return 'translate(' + left + ', ' + top + ')'
  1.4009 +                })
  1.4010 +                .select('rect')
  1.4011 +                .attr('height', function(d,i) {
  1.4012 +                    return  Math.max(Math.abs(y(getY(d,i)) - y((yDomain && yDomain[0]) || 0)) || 1)
  1.4013 +                });
  1.4014 +
  1.4015 +
  1.4016 +            //store old scales for use in transitions on update
  1.4017 +            x0 = x.copy();
  1.4018 +            y0 = y.copy();
  1.4019 +
  1.4020 +        });
  1.4021 +
  1.4022 +        renderWatch.renderEnd('discreteBar immediate');
  1.4023 +        return chart;
  1.4024 +    }
  1.4025 +
  1.4026 +    //============================================================
  1.4027 +    // Expose Public Variables
  1.4028 +    //------------------------------------------------------------
  1.4029 +
  1.4030 +    chart.dispatch = dispatch;
  1.4031 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.4032 +
  1.4033 +    chart._options = Object.create({}, {
  1.4034 +        // simple options, just get/set the necessary values
  1.4035 +        width:   {get: function(){return width;}, set: function(_){width=_;}},
  1.4036 +        height:  {get: function(){return height;}, set: function(_){height=_;}},
  1.4037 +        forceY:  {get: function(){return forceY;}, set: function(_){forceY=_;}},
  1.4038 +        showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}},
  1.4039 +        x:       {get: function(){return getX;}, set: function(_){getX=_;}},
  1.4040 +        y:       {get: function(){return getY;}, set: function(_){getY=_;}},
  1.4041 +        xScale:  {get: function(){return x;}, set: function(_){x=_;}},
  1.4042 +        yScale:  {get: function(){return y;}, set: function(_){y=_;}},
  1.4043 +        xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
  1.4044 +        yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
  1.4045 +        xRange:  {get: function(){return xRange;}, set: function(_){xRange=_;}},
  1.4046 +        yRange:  {get: function(){return yRange;}, set: function(_){yRange=_;}},
  1.4047 +        valueFormat:    {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}},
  1.4048 +        id:          {get: function(){return id;}, set: function(_){id=_;}},
  1.4049 +        rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}},
  1.4050 +
  1.4051 +        // options that require extra logic in the setter
  1.4052 +        margin: {get: function(){return margin;}, set: function(_){
  1.4053 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.4054 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.4055 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.4056 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.4057 +        }},
  1.4058 +        color:  {get: function(){return color;}, set: function(_){
  1.4059 +            color = nv.utils.getColor(_);
  1.4060 +        }},
  1.4061 +        duration: {get: function(){return duration;}, set: function(_){
  1.4062 +            duration = _;
  1.4063 +            renderWatch.reset(duration);
  1.4064 +        }}
  1.4065 +    });
  1.4066 +
  1.4067 +    nv.utils.initOptions(chart);
  1.4068 +
  1.4069 +    return chart;
  1.4070 +};
  1.4071 +
  1.4072 +nv.models.discreteBarChart = function() {
  1.4073 +    "use strict";
  1.4074 +
  1.4075 +    //============================================================
  1.4076 +    // Public Variables with Default Settings
  1.4077 +    //------------------------------------------------------------
  1.4078 +
  1.4079 +    var discretebar = nv.models.discreteBar()
  1.4080 +        , xAxis = nv.models.axis()
  1.4081 +        , yAxis = nv.models.axis()
  1.4082 +        , tooltip = nv.models.tooltip()
  1.4083 +        ;
  1.4084 +
  1.4085 +    var margin = {top: 15, right: 10, bottom: 50, left: 60}
  1.4086 +        , width = null
  1.4087 +        , height = null
  1.4088 +        , color = nv.utils.getColor()
  1.4089 +        , showXAxis = true
  1.4090 +        , showYAxis = true
  1.4091 +        , rightAlignYAxis = false
  1.4092 +        , staggerLabels = false
  1.4093 +        , x
  1.4094 +        , y
  1.4095 +        , noData = null
  1.4096 +        , dispatch = d3.dispatch('beforeUpdate','renderEnd')
  1.4097 +        , duration = 250
  1.4098 +        ;
  1.4099 +
  1.4100 +    xAxis
  1.4101 +        .orient('bottom')
  1.4102 +        .showMaxMin(false)
  1.4103 +        .tickFormat(function(d) { return d })
  1.4104 +    ;
  1.4105 +    yAxis
  1.4106 +        .orient((rightAlignYAxis) ? 'right' : 'left')
  1.4107 +        .tickFormat(d3.format(',.1f'))
  1.4108 +    ;
  1.4109 +
  1.4110 +    tooltip
  1.4111 +        .duration(0)
  1.4112 +        .headerEnabled(false)
  1.4113 +        .valueFormatter(function(d, i) {
  1.4114 +            return yAxis.tickFormat()(d, i);
  1.4115 +        })
  1.4116 +        .keyFormatter(function(d, i) {
  1.4117 +            return xAxis.tickFormat()(d, i);
  1.4118 +        });
  1.4119 +
  1.4120 +    //============================================================
  1.4121 +    // Private Variables
  1.4122 +    //------------------------------------------------------------
  1.4123 +
  1.4124 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.4125 +
  1.4126 +    function chart(selection) {
  1.4127 +        renderWatch.reset();
  1.4128 +        renderWatch.models(discretebar);
  1.4129 +        if (showXAxis) renderWatch.models(xAxis);
  1.4130 +        if (showYAxis) renderWatch.models(yAxis);
  1.4131 +
  1.4132 +        selection.each(function(data) {
  1.4133 +            var container = d3.select(this),
  1.4134 +                that = this;
  1.4135 +            nv.utils.initSVG(container);
  1.4136 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.4137 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.4138 +
  1.4139 +            chart.update = function() {
  1.4140 +                dispatch.beforeUpdate();
  1.4141 +                container.transition().duration(duration).call(chart);
  1.4142 +            };
  1.4143 +            chart.container = this;
  1.4144 +
  1.4145 +            // Display No Data message if there's nothing to show.
  1.4146 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.4147 +                nv.utils.noData(chart, container);
  1.4148 +                return chart;
  1.4149 +            } else {
  1.4150 +                container.selectAll('.nv-noData').remove();
  1.4151 +            }
  1.4152 +
  1.4153 +            // Setup Scales
  1.4154 +            x = discretebar.xScale();
  1.4155 +            y = discretebar.yScale().clamp(true);
  1.4156 +
  1.4157 +            // Setup containers and skeleton of chart
  1.4158 +            var wrap = container.selectAll('g.nv-wrap.nv-discreteBarWithAxes').data([data]);
  1.4159 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discreteBarWithAxes').append('g');
  1.4160 +            var defsEnter = gEnter.append('defs');
  1.4161 +            var g = wrap.select('g');
  1.4162 +
  1.4163 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
  1.4164 +            gEnter.append('g').attr('class', 'nv-y nv-axis')
  1.4165 +                .append('g').attr('class', 'nv-zeroLine')
  1.4166 +                .append('line');
  1.4167 +
  1.4168 +            gEnter.append('g').attr('class', 'nv-barsWrap');
  1.4169 +
  1.4170 +            g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.4171 +
  1.4172 +            if (rightAlignYAxis) {
  1.4173 +                g.select(".nv-y.nv-axis")
  1.4174 +                    .attr("transform", "translate(" + availableWidth + ",0)");
  1.4175 +            }
  1.4176 +
  1.4177 +            // Main Chart Component(s)
  1.4178 +            discretebar
  1.4179 +                .width(availableWidth)
  1.4180 +                .height(availableHeight);
  1.4181 +
  1.4182 +            var barsWrap = g.select('.nv-barsWrap')
  1.4183 +                .datum(data.filter(function(d) { return !d.disabled }));
  1.4184 +
  1.4185 +            barsWrap.transition().call(discretebar);
  1.4186 +
  1.4187 +
  1.4188 +            defsEnter.append('clipPath')
  1.4189 +                .attr('id', 'nv-x-label-clip-' + discretebar.id())
  1.4190 +                .append('rect');
  1.4191 +
  1.4192 +            g.select('#nv-x-label-clip-' + discretebar.id() + ' rect')
  1.4193 +                .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1))
  1.4194 +                .attr('height', 16)
  1.4195 +                .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 ));
  1.4196 +
  1.4197 +            // Setup Axes
  1.4198 +            if (showXAxis) {
  1.4199 +                xAxis
  1.4200 +                    .scale(x)
  1.4201 +                    ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.4202 +                    .tickSize(-availableHeight, 0);
  1.4203 +
  1.4204 +                g.select('.nv-x.nv-axis')
  1.4205 +                    .attr('transform', 'translate(0,' + (y.range()[0] + ((discretebar.showValues() && y.domain()[0] < 0) ? 16 : 0)) + ')');
  1.4206 +                g.select('.nv-x.nv-axis').call(xAxis);
  1.4207 +
  1.4208 +                var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
  1.4209 +                if (staggerLabels) {
  1.4210 +                    xTicks
  1.4211 +                        .selectAll('text')
  1.4212 +                        .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')' })
  1.4213 +                }
  1.4214 +            }
  1.4215 +
  1.4216 +            if (showYAxis) {
  1.4217 +                yAxis
  1.4218 +                    .scale(y)
  1.4219 +                    ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
  1.4220 +                    .tickSize( -availableWidth, 0);
  1.4221 +
  1.4222 +                g.select('.nv-y.nv-axis').call(yAxis);
  1.4223 +            }
  1.4224 +
  1.4225 +            // Zero line
  1.4226 +            g.select(".nv-zeroLine line")
  1.4227 +                .attr("x1",0)
  1.4228 +                .attr("x2",availableWidth)
  1.4229 +                .attr("y1", y(0))
  1.4230 +                .attr("y2", y(0))
  1.4231 +            ;
  1.4232 +        });
  1.4233 +
  1.4234 +        renderWatch.renderEnd('discreteBar chart immediate');
  1.4235 +        return chart;
  1.4236 +    }
  1.4237 +
  1.4238 +    //============================================================
  1.4239 +    // Event Handling/Dispatching (out of chart's scope)
  1.4240 +    //------------------------------------------------------------
  1.4241 +
  1.4242 +    discretebar.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.4243 +        evt['series'] = {
  1.4244 +            key: chart.x()(evt.data),
  1.4245 +            value: chart.y()(evt.data),
  1.4246 +            color: evt.color
  1.4247 +        };
  1.4248 +        tooltip.data(evt).hidden(false);
  1.4249 +    });
  1.4250 +
  1.4251 +    discretebar.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.4252 +        tooltip.hidden(true);
  1.4253 +    });
  1.4254 +
  1.4255 +    discretebar.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.4256 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.4257 +    });
  1.4258 +
  1.4259 +    //============================================================
  1.4260 +    // Expose Public Variables
  1.4261 +    //------------------------------------------------------------
  1.4262 +
  1.4263 +    chart.dispatch = dispatch;
  1.4264 +    chart.discretebar = discretebar;
  1.4265 +    chart.xAxis = xAxis;
  1.4266 +    chart.yAxis = yAxis;
  1.4267 +    chart.tooltip = tooltip;
  1.4268 +
  1.4269 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.4270 +
  1.4271 +    chart._options = Object.create({}, {
  1.4272 +        // simple options, just get/set the necessary values
  1.4273 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.4274 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.4275 +        staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
  1.4276 +        showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
  1.4277 +        showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
  1.4278 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.4279 +
  1.4280 +        // deprecated options
  1.4281 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.4282 +            // deprecated after 1.7.1
  1.4283 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.4284 +            tooltip.enabled(!!_);
  1.4285 +        }},
  1.4286 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.4287 +            // deprecated after 1.7.1
  1.4288 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.4289 +            tooltip.contentGenerator(_);
  1.4290 +        }},
  1.4291 +
  1.4292 +        // options that require extra logic in the setter
  1.4293 +        margin: {get: function(){return margin;}, set: function(_){
  1.4294 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.4295 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.4296 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.4297 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.4298 +        }},
  1.4299 +        duration: {get: function(){return duration;}, set: function(_){
  1.4300 +            duration = _;
  1.4301 +            renderWatch.reset(duration);
  1.4302 +            discretebar.duration(duration);
  1.4303 +            xAxis.duration(duration);
  1.4304 +            yAxis.duration(duration);
  1.4305 +        }},
  1.4306 +        color:  {get: function(){return color;}, set: function(_){
  1.4307 +            color = nv.utils.getColor(_);
  1.4308 +            discretebar.color(color);
  1.4309 +        }},
  1.4310 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
  1.4311 +            rightAlignYAxis = _;
  1.4312 +            yAxis.orient( (_) ? 'right' : 'left');
  1.4313 +        }}
  1.4314 +    });
  1.4315 +
  1.4316 +    nv.utils.inheritOptions(chart, discretebar);
  1.4317 +    nv.utils.initOptions(chart);
  1.4318 +
  1.4319 +    return chart;
  1.4320 +}
  1.4321 +
  1.4322 +nv.models.distribution = function() {
  1.4323 +    "use strict";
  1.4324 +    //============================================================
  1.4325 +    // Public Variables with Default Settings
  1.4326 +    //------------------------------------------------------------
  1.4327 +
  1.4328 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.4329 +        , width = 400 //technically width or height depending on x or y....
  1.4330 +        , size = 8
  1.4331 +        , axis = 'x' // 'x' or 'y'... horizontal or vertical
  1.4332 +        , getData = function(d) { return d[axis] }  // defaults d.x or d.y
  1.4333 +        , color = nv.utils.defaultColor()
  1.4334 +        , scale = d3.scale.linear()
  1.4335 +        , domain
  1.4336 +        , duration = 250
  1.4337 +        , dispatch = d3.dispatch('renderEnd')
  1.4338 +        ;
  1.4339 +
  1.4340 +    //============================================================
  1.4341 +
  1.4342 +
  1.4343 +    //============================================================
  1.4344 +    // Private Variables
  1.4345 +    //------------------------------------------------------------
  1.4346 +
  1.4347 +    var scale0;
  1.4348 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.4349 +
  1.4350 +    //============================================================
  1.4351 +
  1.4352 +
  1.4353 +    function chart(selection) {
  1.4354 +        renderWatch.reset();
  1.4355 +        selection.each(function(data) {
  1.4356 +            var availableLength = width - (axis === 'x' ? margin.left + margin.right : margin.top + margin.bottom),
  1.4357 +                naxis = axis == 'x' ? 'y' : 'x',
  1.4358 +                container = d3.select(this);
  1.4359 +            nv.utils.initSVG(container);
  1.4360 +
  1.4361 +            //------------------------------------------------------------
  1.4362 +            // Setup Scales
  1.4363 +
  1.4364 +            scale0 = scale0 || scale;
  1.4365 +
  1.4366 +            //------------------------------------------------------------
  1.4367 +
  1.4368 +
  1.4369 +            //------------------------------------------------------------
  1.4370 +            // Setup containers and skeleton of chart
  1.4371 +
  1.4372 +            var wrap = container.selectAll('g.nv-distribution').data([data]);
  1.4373 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-distribution');
  1.4374 +            var gEnter = wrapEnter.append('g');
  1.4375 +            var g = wrap.select('g');
  1.4376 +
  1.4377 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
  1.4378 +
  1.4379 +            //------------------------------------------------------------
  1.4380 +
  1.4381 +
  1.4382 +            var distWrap = g.selectAll('g.nv-dist')
  1.4383 +                .data(function(d) { return d }, function(d) { return d.key });
  1.4384 +
  1.4385 +            distWrap.enter().append('g');
  1.4386 +            distWrap
  1.4387 +                .attr('class', function(d,i) { return 'nv-dist nv-series-' + i })
  1.4388 +                .style('stroke', function(d,i) { return color(d, i) });
  1.4389 +
  1.4390 +            var dist = distWrap.selectAll('line.nv-dist' + axis)
  1.4391 +                .data(function(d) { return d.values })
  1.4392 +            dist.enter().append('line')
  1.4393 +                .attr(axis + '1', function(d,i) { return scale0(getData(d,i)) })
  1.4394 +                .attr(axis + '2', function(d,i) { return scale0(getData(d,i)) })
  1.4395 +            renderWatch.transition(distWrap.exit().selectAll('line.nv-dist' + axis), 'dist exit')
  1.4396 +                // .transition()
  1.4397 +                .attr(axis + '1', function(d,i) { return scale(getData(d,i)) })
  1.4398 +                .attr(axis + '2', function(d,i) { return scale(getData(d,i)) })
  1.4399 +                .style('stroke-opacity', 0)
  1.4400 +                .remove();
  1.4401 +            dist
  1.4402 +                .attr('class', function(d,i) { return 'nv-dist' + axis + ' nv-dist' + axis + '-' + i })
  1.4403 +                .attr(naxis + '1', 0)
  1.4404 +                .attr(naxis + '2', size);
  1.4405 +            renderWatch.transition(dist, 'dist')
  1.4406 +                // .transition()
  1.4407 +                .attr(axis + '1', function(d,i) { return scale(getData(d,i)) })
  1.4408 +                .attr(axis + '2', function(d,i) { return scale(getData(d,i)) })
  1.4409 +
  1.4410 +
  1.4411 +            scale0 = scale.copy();
  1.4412 +
  1.4413 +        });
  1.4414 +        renderWatch.renderEnd('distribution immediate');
  1.4415 +        return chart;
  1.4416 +    }
  1.4417 +
  1.4418 +
  1.4419 +    //============================================================
  1.4420 +    // Expose Public Variables
  1.4421 +    //------------------------------------------------------------
  1.4422 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.4423 +    chart.dispatch = dispatch;
  1.4424 +
  1.4425 +    chart.margin = function(_) {
  1.4426 +        if (!arguments.length) return margin;
  1.4427 +        margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
  1.4428 +        margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
  1.4429 +        margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
  1.4430 +        margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
  1.4431 +        return chart;
  1.4432 +    };
  1.4433 +
  1.4434 +    chart.width = function(_) {
  1.4435 +        if (!arguments.length) return width;
  1.4436 +        width = _;
  1.4437 +        return chart;
  1.4438 +    };
  1.4439 +
  1.4440 +    chart.axis = function(_) {
  1.4441 +        if (!arguments.length) return axis;
  1.4442 +        axis = _;
  1.4443 +        return chart;
  1.4444 +    };
  1.4445 +
  1.4446 +    chart.size = function(_) {
  1.4447 +        if (!arguments.length) return size;
  1.4448 +        size = _;
  1.4449 +        return chart;
  1.4450 +    };
  1.4451 +
  1.4452 +    chart.getData = function(_) {
  1.4453 +        if (!arguments.length) return getData;
  1.4454 +        getData = d3.functor(_);
  1.4455 +        return chart;
  1.4456 +    };
  1.4457 +
  1.4458 +    chart.scale = function(_) {
  1.4459 +        if (!arguments.length) return scale;
  1.4460 +        scale = _;
  1.4461 +        return chart;
  1.4462 +    };
  1.4463 +
  1.4464 +    chart.color = function(_) {
  1.4465 +        if (!arguments.length) return color;
  1.4466 +        color = nv.utils.getColor(_);
  1.4467 +        return chart;
  1.4468 +    };
  1.4469 +
  1.4470 +    chart.duration = function(_) {
  1.4471 +        if (!arguments.length) return duration;
  1.4472 +        duration = _;
  1.4473 +        renderWatch.reset(duration);
  1.4474 +        return chart;
  1.4475 +    };
  1.4476 +    //============================================================
  1.4477 +
  1.4478 +
  1.4479 +    return chart;
  1.4480 +}
  1.4481 +nv.models.furiousLegend = function() {
  1.4482 +    "use strict";
  1.4483 +
  1.4484 +    //============================================================
  1.4485 +    // Public Variables with Default Settings
  1.4486 +    //------------------------------------------------------------
  1.4487 +
  1.4488 +    var margin = {top: 5, right: 0, bottom: 5, left: 0}
  1.4489 +        , width = 400
  1.4490 +        , height = 20
  1.4491 +        , getKey = function(d) { return d.key }
  1.4492 +        , color = nv.utils.getColor()
  1.4493 +        , align = true
  1.4494 +        , padding = 28 //define how much space between legend items. - recommend 32 for furious version
  1.4495 +        , rightAlign = true
  1.4496 +        , updateState = true   //If true, legend will update data.disabled and trigger a 'stateChange' dispatch.
  1.4497 +        , radioButtonMode = false   //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time)
  1.4498 +        , expanded = false
  1.4499 +        , dispatch = d3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange')
  1.4500 +        , vers = 'classic' //Options are "classic" and "furious"
  1.4501 +        ;
  1.4502 +
  1.4503 +    function chart(selection) {
  1.4504 +        selection.each(function(data) {
  1.4505 +            var availableWidth = width - margin.left - margin.right,
  1.4506 +                container = d3.select(this);
  1.4507 +            nv.utils.initSVG(container);
  1.4508 +
  1.4509 +            // Setup containers and skeleton of chart
  1.4510 +            var wrap = container.selectAll('g.nv-legend').data([data]);
  1.4511 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g');
  1.4512 +            var g = wrap.select('g');
  1.4513 +
  1.4514 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.4515 +
  1.4516 +            var series = g.selectAll('.nv-series')
  1.4517 +                .data(function(d) {
  1.4518 +                    if(vers != 'furious') return d;
  1.4519 +
  1.4520 +                    return d.filter(function(n) {
  1.4521 +                        return expanded ? true : !n.disengaged;
  1.4522 +                    });
  1.4523 +                });
  1.4524 +            var seriesEnter = series.enter().append('g').attr('class', 'nv-series')
  1.4525 +
  1.4526 +            var seriesShape;
  1.4527 +
  1.4528 +            if(vers == 'classic') {
  1.4529 +                seriesEnter.append('circle')
  1.4530 +                    .style('stroke-width', 2)
  1.4531 +                    .attr('class','nv-legend-symbol')
  1.4532 +                    .attr('r', 5);
  1.4533 +
  1.4534 +                seriesShape = series.select('circle');
  1.4535 +            } else if (vers == 'furious') {
  1.4536 +                seriesEnter.append('rect')
  1.4537 +                    .style('stroke-width', 2)
  1.4538 +                    .attr('class','nv-legend-symbol')
  1.4539 +                    .attr('rx', 3)
  1.4540 +                    .attr('ry', 3);
  1.4541 +
  1.4542 +                seriesShape = series.select('rect');
  1.4543 +
  1.4544 +                seriesEnter.append('g')
  1.4545 +                    .attr('class', 'nv-check-box')
  1.4546 +                    .property('innerHTML','<path d="M0.5,5 L22.5,5 L22.5,26.5 L0.5,26.5 L0.5,5 Z" class="nv-box"></path><path d="M5.5,12.8618467 L11.9185089,19.2803556 L31,0.198864511" class="nv-check"></path>')
  1.4547 +                    .attr('transform', 'translate(-10,-8)scale(0.5)');
  1.4548 +
  1.4549 +                var seriesCheckbox = series.select('.nv-check-box');
  1.4550 +
  1.4551 +                seriesCheckbox.each(function(d,i) {
  1.4552 +                    d3.select(this).selectAll('path')
  1.4553 +                        .attr('stroke', setTextColor(d,i));
  1.4554 +                });
  1.4555 +            }
  1.4556 +
  1.4557 +            seriesEnter.append('text')
  1.4558 +                .attr('text-anchor', 'start')
  1.4559 +                .attr('class','nv-legend-text')
  1.4560 +                .attr('dy', '.32em')
  1.4561 +                .attr('dx', '8');
  1.4562 +
  1.4563 +            var seriesText = series.select('text.nv-legend-text');
  1.4564 +
  1.4565 +            series
  1.4566 +                .on('mouseover', function(d,i) {
  1.4567 +                    dispatch.legendMouseover(d,i);  //TODO: Make consistent with other event objects
  1.4568 +                })
  1.4569 +                .on('mouseout', function(d,i) {
  1.4570 +                    dispatch.legendMouseout(d,i);
  1.4571 +                })
  1.4572 +                .on('click', function(d,i) {
  1.4573 +                    dispatch.legendClick(d,i);
  1.4574 +                    // make sure we re-get data in case it was modified
  1.4575 +                    var data = series.data();
  1.4576 +                    if (updateState) {
  1.4577 +                        if(vers =='classic') {
  1.4578 +                            if (radioButtonMode) {
  1.4579 +                                //Radio button mode: set every series to disabled,
  1.4580 +                                //  and enable the clicked series.
  1.4581 +                                data.forEach(function(series) { series.disabled = true});
  1.4582 +                                d.disabled = false;
  1.4583 +                            }
  1.4584 +                            else {
  1.4585 +                                d.disabled = !d.disabled;
  1.4586 +                                if (data.every(function(series) { return series.disabled})) {
  1.4587 +                                    //the default behavior of NVD3 legends is, if every single series
  1.4588 +                                    // is disabled, turn all series' back on.
  1.4589 +                                    data.forEach(function(series) { series.disabled = false});
  1.4590 +                                }
  1.4591 +                            }
  1.4592 +                        } else if(vers == 'furious') {
  1.4593 +                            if(expanded) {
  1.4594 +                                d.disengaged = !d.disengaged;
  1.4595 +                                d.userDisabled = d.userDisabled == undefined ? !!d.disabled : d.userDisabled;
  1.4596 +                                d.disabled = d.disengaged || d.userDisabled;
  1.4597 +                            } else if (!expanded) {
  1.4598 +                                d.disabled = !d.disabled;
  1.4599 +                                d.userDisabled = d.disabled;
  1.4600 +                                var engaged = data.filter(function(d) { return !d.disengaged; });
  1.4601 +                                if (engaged.every(function(series) { return series.userDisabled })) {
  1.4602 +                                    //the default behavior of NVD3 legends is, if every single series
  1.4603 +                                    // is disabled, turn all series' back on.
  1.4604 +                                    data.forEach(function(series) {
  1.4605 +                                        series.disabled = series.userDisabled = false;
  1.4606 +                                    });
  1.4607 +                                }
  1.4608 +                            }
  1.4609 +                        }
  1.4610 +                        dispatch.stateChange({
  1.4611 +                            disabled: data.map(function(d) { return !!d.disabled }),
  1.4612 +                            disengaged: data.map(function(d) { return !!d.disengaged })
  1.4613 +                        });
  1.4614 +
  1.4615 +                    }
  1.4616 +                })
  1.4617 +                .on('dblclick', function(d,i) {
  1.4618 +                    if(vers == 'furious' && expanded) return;
  1.4619 +                    dispatch.legendDblclick(d,i);
  1.4620 +                    if (updateState) {
  1.4621 +                        // make sure we re-get data in case it was modified
  1.4622 +                        var data = series.data();
  1.4623 +                        //the default behavior of NVD3 legends, when double clicking one,
  1.4624 +                        // is to set all other series' to false, and make the double clicked series enabled.
  1.4625 +                        data.forEach(function(series) {
  1.4626 +                            series.disabled = true;
  1.4627 +                            if(vers == 'furious') series.userDisabled = series.disabled;
  1.4628 +                        });
  1.4629 +                        d.disabled = false;
  1.4630 +                        if(vers == 'furious') d.userDisabled = d.disabled;
  1.4631 +                        dispatch.stateChange({
  1.4632 +                            disabled: data.map(function(d) { return !!d.disabled })
  1.4633 +                        });
  1.4634 +                    }
  1.4635 +                });
  1.4636 +
  1.4637 +            series.classed('nv-disabled', function(d) { return d.userDisabled });
  1.4638 +            series.exit().remove();
  1.4639 +
  1.4640 +            seriesText
  1.4641 +                .attr('fill', setTextColor)
  1.4642 +                .text(getKey);
  1.4643 +
  1.4644 +            //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option)
  1.4645 +            // NEW ALIGNING CODE, TODO: clean up
  1.4646 +
  1.4647 +            var versPadding;
  1.4648 +            switch(vers) {
  1.4649 +                case 'furious' :
  1.4650 +                    versPadding = 23;
  1.4651 +                    break;
  1.4652 +                case 'classic' :
  1.4653 +                    versPadding = 20;
  1.4654 +            }
  1.4655 +
  1.4656 +            if (align) {
  1.4657 +
  1.4658 +                var seriesWidths = [];
  1.4659 +                series.each(function(d,i) {
  1.4660 +                    var legendText = d3.select(this).select('text');
  1.4661 +                    var nodeTextLength;
  1.4662 +                    try {
  1.4663 +                        nodeTextLength = legendText.node().getComputedTextLength();
  1.4664 +                        // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead
  1.4665 +                        if(nodeTextLength <= 0) throw Error();
  1.4666 +                    }
  1.4667 +                    catch(e) {
  1.4668 +                        nodeTextLength = nv.utils.calcApproxTextWidth(legendText);
  1.4669 +                    }
  1.4670 +
  1.4671 +                    seriesWidths.push(nodeTextLength + padding);
  1.4672 +                });
  1.4673 +
  1.4674 +                var seriesPerRow = 0;
  1.4675 +                var legendWidth = 0;
  1.4676 +                var columnWidths = [];
  1.4677 +
  1.4678 +                while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) {
  1.4679 +                    columnWidths[seriesPerRow] = seriesWidths[seriesPerRow];
  1.4680 +                    legendWidth += seriesWidths[seriesPerRow++];
  1.4681 +                }
  1.4682 +                if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row
  1.4683 +
  1.4684 +                while ( legendWidth > availableWidth && seriesPerRow > 1 ) {
  1.4685 +                    columnWidths = [];
  1.4686 +                    seriesPerRow--;
  1.4687 +
  1.4688 +                    for (var k = 0; k < seriesWidths.length; k++) {
  1.4689 +                        if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) )
  1.4690 +                            columnWidths[k % seriesPerRow] = seriesWidths[k];
  1.4691 +                    }
  1.4692 +
  1.4693 +                    legendWidth = columnWidths.reduce(function(prev, cur, index, array) {
  1.4694 +                        return prev + cur;
  1.4695 +                    });
  1.4696 +                }
  1.4697 +
  1.4698 +                var xPositions = [];
  1.4699 +                for (var i = 0, curX = 0; i < seriesPerRow; i++) {
  1.4700 +                    xPositions[i] = curX;
  1.4701 +                    curX += columnWidths[i];
  1.4702 +                }
  1.4703 +
  1.4704 +                series
  1.4705 +                    .attr('transform', function(d, i) {
  1.4706 +                        return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * versPadding) + ')';
  1.4707 +                    });
  1.4708 +
  1.4709 +                //position legend as far right as possible within the total width
  1.4710 +                if (rightAlign) {
  1.4711 +                    g.attr('transform', 'translate(' + (width - margin.right - legendWidth) + ',' + margin.top + ')');
  1.4712 +                }
  1.4713 +                else {
  1.4714 +                    g.attr('transform', 'translate(0' + ',' + margin.top + ')');
  1.4715 +                }
  1.4716 +
  1.4717 +                height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * versPadding);
  1.4718 +
  1.4719 +            } else {
  1.4720 +
  1.4721 +                var ypos = 5,
  1.4722 +                    newxpos = 5,
  1.4723 +                    maxwidth = 0,
  1.4724 +                    xpos;
  1.4725 +                series
  1.4726 +                    .attr('transform', function(d, i) {
  1.4727 +                        var length = d3.select(this).select('text').node().getComputedTextLength() + padding;
  1.4728 +                        xpos = newxpos;
  1.4729 +
  1.4730 +                        if (width < margin.left + margin.right + xpos + length) {
  1.4731 +                            newxpos = xpos = 5;
  1.4732 +                            ypos += versPadding;
  1.4733 +                        }
  1.4734 +
  1.4735 +                        newxpos += length;
  1.4736 +                        if (newxpos > maxwidth) maxwidth = newxpos;
  1.4737 +
  1.4738 +                        return 'translate(' + xpos + ',' + ypos + ')';
  1.4739 +                    });
  1.4740 +
  1.4741 +                //position legend as far right as possible within the total width
  1.4742 +                g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')');
  1.4743 +
  1.4744 +                height = margin.top + margin.bottom + ypos + 15;
  1.4745 +            }
  1.4746 +
  1.4747 +            if(vers == 'furious') {
  1.4748 +                // Size rectangles after text is placed
  1.4749 +                seriesShape
  1.4750 +                    .attr('width', function(d,i) {
  1.4751 +                        return seriesText[0][i].getComputedTextLength() + 27;
  1.4752 +                    })
  1.4753 +                    .attr('height', 18)
  1.4754 +                    .attr('y', -9)
  1.4755 +                    .attr('x', -15)
  1.4756 +            }
  1.4757 +
  1.4758 +            seriesShape
  1.4759 +                .style('fill', setBGColor)
  1.4760 +                .style('stroke', function(d,i) { return d.color || color(d, i) });
  1.4761 +        });
  1.4762 +
  1.4763 +        function setTextColor(d,i) {
  1.4764 +            if(vers != 'furious') return '#000';
  1.4765 +            if(expanded) {
  1.4766 +                return d.disengaged ? color(d,i) : '#fff';
  1.4767 +            } else if (!expanded) {
  1.4768 +                return !!d.disabled ? color(d,i) : '#fff';
  1.4769 +            }
  1.4770 +        }
  1.4771 +
  1.4772 +        function setBGColor(d,i) {
  1.4773 +            if(expanded && vers == 'furious') {
  1.4774 +                return d.disengaged ? '#fff' : color(d,i);
  1.4775 +            } else {
  1.4776 +                return !!d.disabled ? '#fff' : color(d,i);
  1.4777 +            }
  1.4778 +        }
  1.4779 +
  1.4780 +        return chart;
  1.4781 +    }
  1.4782 +
  1.4783 +    //============================================================
  1.4784 +    // Expose Public Variables
  1.4785 +    //------------------------------------------------------------
  1.4786 +
  1.4787 +    chart.dispatch = dispatch;
  1.4788 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.4789 +
  1.4790 +    chart._options = Object.create({}, {
  1.4791 +        // simple options, just get/set the necessary values
  1.4792 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.4793 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.4794 +        key:        {get: function(){return getKey;}, set: function(_){getKey=_;}},
  1.4795 +        align:      {get: function(){return align;}, set: function(_){align=_;}},
  1.4796 +        rightAlign:    {get: function(){return rightAlign;}, set: function(_){rightAlign=_;}},
  1.4797 +        padding:       {get: function(){return padding;}, set: function(_){padding=_;}},
  1.4798 +        updateState:   {get: function(){return updateState;}, set: function(_){updateState=_;}},
  1.4799 +        radioButtonMode:    {get: function(){return radioButtonMode;}, set: function(_){radioButtonMode=_;}},
  1.4800 +        expanded:   {get: function(){return expanded;}, set: function(_){expanded=_;}},
  1.4801 +        vers:   {get: function(){return vers;}, set: function(_){vers=_;}},
  1.4802 +
  1.4803 +        // options that require extra logic in the setter
  1.4804 +        margin: {get: function(){return margin;}, set: function(_){
  1.4805 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.4806 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.4807 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.4808 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.4809 +        }},
  1.4810 +        color:  {get: function(){return color;}, set: function(_){
  1.4811 +            color = nv.utils.getColor(_);
  1.4812 +        }}
  1.4813 +    });
  1.4814 +
  1.4815 +    nv.utils.initOptions(chart);
  1.4816 +
  1.4817 +    return chart;
  1.4818 +};
  1.4819 +//TODO: consider deprecating and using multibar with single series for this
  1.4820 +nv.models.historicalBar = function() {
  1.4821 +    "use strict";
  1.4822 +
  1.4823 +    //============================================================
  1.4824 +    // Public Variables with Default Settings
  1.4825 +    //------------------------------------------------------------
  1.4826 +
  1.4827 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.4828 +        , width = null
  1.4829 +        , height = null
  1.4830 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
  1.4831 +        , container = null
  1.4832 +        , x = d3.scale.linear()
  1.4833 +        , y = d3.scale.linear()
  1.4834 +        , getX = function(d) { return d.x }
  1.4835 +        , getY = function(d) { return d.y }
  1.4836 +        , forceX = []
  1.4837 +        , forceY = [0]
  1.4838 +        , padData = false
  1.4839 +        , clipEdge = true
  1.4840 +        , color = nv.utils.defaultColor()
  1.4841 +        , xDomain
  1.4842 +        , yDomain
  1.4843 +        , xRange
  1.4844 +        , yRange
  1.4845 +        , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd')
  1.4846 +        , interactive = true
  1.4847 +        ;
  1.4848 +
  1.4849 +    var renderWatch = nv.utils.renderWatch(dispatch, 0);
  1.4850 +
  1.4851 +    function chart(selection) {
  1.4852 +        selection.each(function(data) {
  1.4853 +            renderWatch.reset();
  1.4854 +
  1.4855 +            container = d3.select(this);
  1.4856 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.4857 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.4858 +
  1.4859 +            nv.utils.initSVG(container);
  1.4860 +
  1.4861 +            // Setup Scales
  1.4862 +            x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ));
  1.4863 +
  1.4864 +            if (padData)
  1.4865 +                x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5)  / data[0].values.length ]);
  1.4866 +            else
  1.4867 +                x.range(xRange || [0, availableWidth]);
  1.4868 +
  1.4869 +            y.domain(yDomain || d3.extent(data[0].values.map(getY).concat(forceY) ))
  1.4870 +                .range(yRange || [availableHeight, 0]);
  1.4871 +
  1.4872 +            // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
  1.4873 +            if (x.domain()[0] === x.domain()[1])
  1.4874 +                x.domain()[0] ?
  1.4875 +                    x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
  1.4876 +                    : x.domain([-1,1]);
  1.4877 +
  1.4878 +            if (y.domain()[0] === y.domain()[1])
  1.4879 +                y.domain()[0] ?
  1.4880 +                    y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
  1.4881 +                    : y.domain([-1,1]);
  1.4882 +
  1.4883 +            // Setup containers and skeleton of chart
  1.4884 +            var wrap = container.selectAll('g.nv-wrap.nv-historicalBar-' + id).data([data[0].values]);
  1.4885 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBar-' + id);
  1.4886 +            var defsEnter = wrapEnter.append('defs');
  1.4887 +            var gEnter = wrapEnter.append('g');
  1.4888 +            var g = wrap.select('g');
  1.4889 +
  1.4890 +            gEnter.append('g').attr('class', 'nv-bars');
  1.4891 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.4892 +
  1.4893 +            container
  1.4894 +                .on('click', function(d,i) {
  1.4895 +                    dispatch.chartClick({
  1.4896 +                        data: d,
  1.4897 +                        index: i,
  1.4898 +                        pos: d3.event,
  1.4899 +                        id: id
  1.4900 +                    });
  1.4901 +                });
  1.4902 +
  1.4903 +            defsEnter.append('clipPath')
  1.4904 +                .attr('id', 'nv-chart-clip-path-' + id)
  1.4905 +                .append('rect');
  1.4906 +
  1.4907 +            wrap.select('#nv-chart-clip-path-' + id + ' rect')
  1.4908 +                .attr('width', availableWidth)
  1.4909 +                .attr('height', availableHeight);
  1.4910 +
  1.4911 +            g.attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
  1.4912 +
  1.4913 +            var bars = wrap.select('.nv-bars').selectAll('.nv-bar')
  1.4914 +                .data(function(d) { return d }, function(d,i) {return getX(d,i)});
  1.4915 +            bars.exit().remove();
  1.4916 +
  1.4917 +            bars.enter().append('rect')
  1.4918 +                .attr('x', 0 )
  1.4919 +                .attr('y', function(d,i) {  return nv.utils.NaNtoZero(y(Math.max(0, getY(d,i)))) })
  1.4920 +                .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.abs(y(getY(d,i)) - y(0))) })
  1.4921 +                .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; })
  1.4922 +                .on('mouseover', function(d,i) {
  1.4923 +                    if (!interactive) return;
  1.4924 +                    d3.select(this).classed('hover', true);
  1.4925 +                    dispatch.elementMouseover({
  1.4926 +                        data: d,
  1.4927 +                        index: i,
  1.4928 +                        color: d3.select(this).style("fill")
  1.4929 +                    });
  1.4930 +
  1.4931 +                })
  1.4932 +                .on('mouseout', function(d,i) {
  1.4933 +                    if (!interactive) return;
  1.4934 +                    d3.select(this).classed('hover', false);
  1.4935 +                    dispatch.elementMouseout({
  1.4936 +                        data: d,
  1.4937 +                        index: i,
  1.4938 +                        color: d3.select(this).style("fill")
  1.4939 +                    });
  1.4940 +                })
  1.4941 +                .on('mousemove', function(d,i) {
  1.4942 +                    if (!interactive) return;
  1.4943 +                    dispatch.elementMousemove({
  1.4944 +                        data: d,
  1.4945 +                        index: i,
  1.4946 +                        color: d3.select(this).style("fill")
  1.4947 +                    });
  1.4948 +                })
  1.4949 +                .on('click', function(d,i) {
  1.4950 +                    if (!interactive) return;
  1.4951 +                    dispatch.elementClick({
  1.4952 +                        data: d,
  1.4953 +                        index: i,
  1.4954 +                        color: d3.select(this).style("fill")
  1.4955 +                    });
  1.4956 +                    d3.event.stopPropagation();
  1.4957 +                })
  1.4958 +                .on('dblclick', function(d,i) {
  1.4959 +                    if (!interactive) return;
  1.4960 +                    dispatch.elementDblClick({
  1.4961 +                        data: d,
  1.4962 +                        index: i,
  1.4963 +                        color: d3.select(this).style("fill")
  1.4964 +                    });
  1.4965 +                    d3.event.stopPropagation();
  1.4966 +                });
  1.4967 +
  1.4968 +            bars
  1.4969 +                .attr('fill', function(d,i) { return color(d, i); })
  1.4970 +                .attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i })
  1.4971 +                .watchTransition(renderWatch, 'bars')
  1.4972 +                .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; })
  1.4973 +                //TODO: better width calculations that don't assume always uniform data spacing;w
  1.4974 +                .attr('width', (availableWidth / data[0].values.length) * .9 );
  1.4975 +
  1.4976 +            bars.watchTransition(renderWatch, 'bars')
  1.4977 +                .attr('y', function(d,i) {
  1.4978 +                    var rval = getY(d,i) < 0 ?
  1.4979 +                        y(0) :
  1.4980 +                            y(0) - y(getY(d,i)) < 1 ?
  1.4981 +                        y(0) - 1 :
  1.4982 +                        y(getY(d,i));
  1.4983 +                    return nv.utils.NaNtoZero(rval);
  1.4984 +                })
  1.4985 +                .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.max(Math.abs(y(getY(d,i)) - y(0)),1)) });
  1.4986 +
  1.4987 +        });
  1.4988 +
  1.4989 +        renderWatch.renderEnd('historicalBar immediate');
  1.4990 +        return chart;
  1.4991 +    }
  1.4992 +
  1.4993 +    //Create methods to allow outside functions to highlight a specific bar.
  1.4994 +    chart.highlightPoint = function(pointIndex, isHoverOver) {
  1.4995 +        container
  1.4996 +            .select(".nv-bars .nv-bar-0-" + pointIndex)
  1.4997 +            .classed("hover", isHoverOver)
  1.4998 +        ;
  1.4999 +    };
  1.5000 +
  1.5001 +    chart.clearHighlights = function() {
  1.5002 +        container
  1.5003 +            .select(".nv-bars .nv-bar.hover")
  1.5004 +            .classed("hover", false)
  1.5005 +        ;
  1.5006 +    };
  1.5007 +
  1.5008 +    //============================================================
  1.5009 +    // Expose Public Variables
  1.5010 +    //------------------------------------------------------------
  1.5011 +
  1.5012 +    chart.dispatch = dispatch;
  1.5013 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.5014 +
  1.5015 +    chart._options = Object.create({}, {
  1.5016 +        // simple options, just get/set the necessary values
  1.5017 +        width:   {get: function(){return width;}, set: function(_){width=_;}},
  1.5018 +        height:  {get: function(){return height;}, set: function(_){height=_;}},
  1.5019 +        forceX:  {get: function(){return forceX;}, set: function(_){forceX=_;}},
  1.5020 +        forceY:  {get: function(){return forceY;}, set: function(_){forceY=_;}},
  1.5021 +        padData: {get: function(){return padData;}, set: function(_){padData=_;}},
  1.5022 +        x:       {get: function(){return getX;}, set: function(_){getX=_;}},
  1.5023 +        y:       {get: function(){return getY;}, set: function(_){getY=_;}},
  1.5024 +        xScale:  {get: function(){return x;}, set: function(_){x=_;}},
  1.5025 +        yScale:  {get: function(){return y;}, set: function(_){y=_;}},
  1.5026 +        xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
  1.5027 +        yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
  1.5028 +        xRange:  {get: function(){return xRange;}, set: function(_){xRange=_;}},
  1.5029 +        yRange:  {get: function(){return yRange;}, set: function(_){yRange=_;}},
  1.5030 +        clipEdge:    {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
  1.5031 +        id:          {get: function(){return id;}, set: function(_){id=_;}},
  1.5032 +        interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},
  1.5033 +
  1.5034 +        // options that require extra logic in the setter
  1.5035 +        margin: {get: function(){return margin;}, set: function(_){
  1.5036 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.5037 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.5038 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.5039 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.5040 +        }},
  1.5041 +        color:  {get: function(){return color;}, set: function(_){
  1.5042 +            color = nv.utils.getColor(_);
  1.5043 +        }}
  1.5044 +    });
  1.5045 +
  1.5046 +    nv.utils.initOptions(chart);
  1.5047 +
  1.5048 +    return chart;
  1.5049 +};
  1.5050 +
  1.5051 +nv.models.historicalBarChart = function(bar_model) {
  1.5052 +    "use strict";
  1.5053 +
  1.5054 +    //============================================================
  1.5055 +    // Public Variables with Default Settings
  1.5056 +    //------------------------------------------------------------
  1.5057 +
  1.5058 +    var bars = bar_model || nv.models.historicalBar()
  1.5059 +        , xAxis = nv.models.axis()
  1.5060 +        , yAxis = nv.models.axis()
  1.5061 +        , legend = nv.models.legend()
  1.5062 +        , interactiveLayer = nv.interactiveGuideline()
  1.5063 +        , tooltip = nv.models.tooltip()
  1.5064 +        ;
  1.5065 +
  1.5066 +
  1.5067 +    var margin = {top: 30, right: 90, bottom: 50, left: 90}
  1.5068 +        , color = nv.utils.defaultColor()
  1.5069 +        , width = null
  1.5070 +        , height = null
  1.5071 +        , showLegend = false
  1.5072 +        , showXAxis = true
  1.5073 +        , showYAxis = true
  1.5074 +        , rightAlignYAxis = false
  1.5075 +        , useInteractiveGuideline = false
  1.5076 +        , x
  1.5077 +        , y
  1.5078 +        , state = {}
  1.5079 +        , defaultState = null
  1.5080 +        , noData = null
  1.5081 +        , dispatch = d3.dispatch('tooltipHide', 'stateChange', 'changeState', 'renderEnd')
  1.5082 +        , transitionDuration = 250
  1.5083 +        ;
  1.5084 +
  1.5085 +    xAxis.orient('bottom').tickPadding(7);
  1.5086 +    yAxis.orient( (rightAlignYAxis) ? 'right' : 'left');
  1.5087 +    tooltip
  1.5088 +        .duration(0)
  1.5089 +        .headerEnabled(false)
  1.5090 +        .valueFormatter(function(d, i) {
  1.5091 +            return yAxis.tickFormat()(d, i);
  1.5092 +        })
  1.5093 +        .headerFormatter(function(d, i) {
  1.5094 +            return xAxis.tickFormat()(d, i);
  1.5095 +        });
  1.5096 +
  1.5097 +
  1.5098 +    //============================================================
  1.5099 +    // Private Variables
  1.5100 +    //------------------------------------------------------------
  1.5101 +
  1.5102 +    var renderWatch = nv.utils.renderWatch(dispatch, 0);
  1.5103 +
  1.5104 +    function chart(selection) {
  1.5105 +        selection.each(function(data) {
  1.5106 +            renderWatch.reset();
  1.5107 +            renderWatch.models(bars);
  1.5108 +            if (showXAxis) renderWatch.models(xAxis);
  1.5109 +            if (showYAxis) renderWatch.models(yAxis);
  1.5110 +
  1.5111 +            var container = d3.select(this),
  1.5112 +                that = this;
  1.5113 +            nv.utils.initSVG(container);
  1.5114 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.5115 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.5116 +
  1.5117 +            chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
  1.5118 +            chart.container = this;
  1.5119 +
  1.5120 +            //set state.disabled
  1.5121 +            state.disabled = data.map(function(d) { return !!d.disabled });
  1.5122 +
  1.5123 +            if (!defaultState) {
  1.5124 +                var key;
  1.5125 +                defaultState = {};
  1.5126 +                for (key in state) {
  1.5127 +                    if (state[key] instanceof Array)
  1.5128 +                        defaultState[key] = state[key].slice(0);
  1.5129 +                    else
  1.5130 +                        defaultState[key] = state[key];
  1.5131 +                }
  1.5132 +            }
  1.5133 +
  1.5134 +            // Display noData message if there's nothing to show.
  1.5135 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.5136 +                nv.utils.noData(chart, container)
  1.5137 +                return chart;
  1.5138 +            } else {
  1.5139 +                container.selectAll('.nv-noData').remove();
  1.5140 +            }
  1.5141 +
  1.5142 +            // Setup Scales
  1.5143 +            x = bars.xScale();
  1.5144 +            y = bars.yScale();
  1.5145 +
  1.5146 +            // Setup containers and skeleton of chart
  1.5147 +            var wrap = container.selectAll('g.nv-wrap.nv-historicalBarChart').data([data]);
  1.5148 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBarChart').append('g');
  1.5149 +            var g = wrap.select('g');
  1.5150 +
  1.5151 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
  1.5152 +            gEnter.append('g').attr('class', 'nv-y nv-axis');
  1.5153 +            gEnter.append('g').attr('class', 'nv-barsWrap');
  1.5154 +            gEnter.append('g').attr('class', 'nv-legendWrap');
  1.5155 +            gEnter.append('g').attr('class', 'nv-interactive');
  1.5156 +
  1.5157 +            // Legend
  1.5158 +            if (showLegend) {
  1.5159 +                legend.width(availableWidth);
  1.5160 +
  1.5161 +                g.select('.nv-legendWrap')
  1.5162 +                    .datum(data)
  1.5163 +                    .call(legend);
  1.5164 +
  1.5165 +                if ( margin.top != legend.height()) {
  1.5166 +                    margin.top = legend.height();
  1.5167 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
  1.5168 +                }
  1.5169 +
  1.5170 +                wrap.select('.nv-legendWrap')
  1.5171 +                    .attr('transform', 'translate(0,' + (-margin.top) +')')
  1.5172 +            }
  1.5173 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.5174 +
  1.5175 +            if (rightAlignYAxis) {
  1.5176 +                g.select(".nv-y.nv-axis")
  1.5177 +                    .attr("transform", "translate(" + availableWidth + ",0)");
  1.5178 +            }
  1.5179 +
  1.5180 +            //Set up interactive layer
  1.5181 +            if (useInteractiveGuideline) {
  1.5182 +                interactiveLayer
  1.5183 +                    .width(availableWidth)
  1.5184 +                    .height(availableHeight)
  1.5185 +                    .margin({left:margin.left, top:margin.top})
  1.5186 +                    .svgContainer(container)
  1.5187 +                    .xScale(x);
  1.5188 +                wrap.select(".nv-interactive").call(interactiveLayer);
  1.5189 +            }
  1.5190 +            bars
  1.5191 +                .width(availableWidth)
  1.5192 +                .height(availableHeight)
  1.5193 +                .color(data.map(function(d,i) {
  1.5194 +                    return d.color || color(d, i);
  1.5195 +                }).filter(function(d,i) { return !data[i].disabled }));
  1.5196 +
  1.5197 +            var barsWrap = g.select('.nv-barsWrap')
  1.5198 +                .datum(data.filter(function(d) { return !d.disabled }));
  1.5199 +            barsWrap.transition().call(bars);
  1.5200 +
  1.5201 +            // Setup Axes
  1.5202 +            if (showXAxis) {
  1.5203 +                xAxis
  1.5204 +                    .scale(x)
  1.5205 +                    ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.5206 +                    .tickSize(-availableHeight, 0);
  1.5207 +
  1.5208 +                g.select('.nv-x.nv-axis')
  1.5209 +                    .attr('transform', 'translate(0,' + y.range()[0] + ')');
  1.5210 +                g.select('.nv-x.nv-axis')
  1.5211 +                    .transition()
  1.5212 +                    .call(xAxis);
  1.5213 +            }
  1.5214 +
  1.5215 +            if (showYAxis) {
  1.5216 +                yAxis
  1.5217 +                    .scale(y)
  1.5218 +                    ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
  1.5219 +                    .tickSize( -availableWidth, 0);
  1.5220 +
  1.5221 +                g.select('.nv-y.nv-axis')
  1.5222 +                    .transition()
  1.5223 +                    .call(yAxis);
  1.5224 +            }
  1.5225 +
  1.5226 +            //============================================================
  1.5227 +            // Event Handling/Dispatching (in chart's scope)
  1.5228 +            //------------------------------------------------------------
  1.5229 +
  1.5230 +            interactiveLayer.dispatch.on('elementMousemove', function(e) {
  1.5231 +                bars.clearHighlights();
  1.5232 +
  1.5233 +                var singlePoint, pointIndex, pointXLocation, allData = [];
  1.5234 +                data
  1.5235 +                    .filter(function(series, i) {
  1.5236 +                        series.seriesIndex = i;
  1.5237 +                        return !series.disabled;
  1.5238 +                    })
  1.5239 +                    .forEach(function(series,i) {
  1.5240 +                        pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
  1.5241 +                        bars.highlightPoint(pointIndex,true);
  1.5242 +                        var point = series.values[pointIndex];
  1.5243 +                        if (point === undefined) return;
  1.5244 +                        if (singlePoint === undefined) singlePoint = point;
  1.5245 +                        if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
  1.5246 +                        allData.push({
  1.5247 +                            key: series.key,
  1.5248 +                            value: chart.y()(point, pointIndex),
  1.5249 +                            color: color(series,series.seriesIndex),
  1.5250 +                            data: series.values[pointIndex]
  1.5251 +                        });
  1.5252 +                    });
  1.5253 +
  1.5254 +                var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
  1.5255 +                interactiveLayer.tooltip
  1.5256 +                    .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
  1.5257 +                    .chartContainer(that.parentNode)
  1.5258 +                    .valueFormatter(function(d,i) {
  1.5259 +                        return yAxis.tickFormat()(d);
  1.5260 +                    })
  1.5261 +                    .data({
  1.5262 +                        value: xValue,
  1.5263 +                        index: pointIndex,
  1.5264 +                        series: allData
  1.5265 +                    })();
  1.5266 +
  1.5267 +                interactiveLayer.renderGuideLine(pointXLocation);
  1.5268 +
  1.5269 +            });
  1.5270 +
  1.5271 +            interactiveLayer.dispatch.on("elementMouseout",function(e) {
  1.5272 +                dispatch.tooltipHide();
  1.5273 +                bars.clearHighlights();
  1.5274 +            });
  1.5275 +
  1.5276 +            legend.dispatch.on('legendClick', function(d,i) {
  1.5277 +                d.disabled = !d.disabled;
  1.5278 +
  1.5279 +                if (!data.filter(function(d) { return !d.disabled }).length) {
  1.5280 +                    data.map(function(d) {
  1.5281 +                        d.disabled = false;
  1.5282 +                        wrap.selectAll('.nv-series').classed('disabled', false);
  1.5283 +                        return d;
  1.5284 +                    });
  1.5285 +                }
  1.5286 +
  1.5287 +                state.disabled = data.map(function(d) { return !!d.disabled });
  1.5288 +                dispatch.stateChange(state);
  1.5289 +
  1.5290 +                selection.transition().call(chart);
  1.5291 +            });
  1.5292 +
  1.5293 +            legend.dispatch.on('legendDblclick', function(d) {
  1.5294 +                //Double clicking should always enable current series, and disabled all others.
  1.5295 +                data.forEach(function(d) {
  1.5296 +                    d.disabled = true;
  1.5297 +                });
  1.5298 +                d.disabled = false;
  1.5299 +
  1.5300 +                state.disabled = data.map(function(d) { return !!d.disabled });
  1.5301 +                dispatch.stateChange(state);
  1.5302 +                chart.update();
  1.5303 +            });
  1.5304 +
  1.5305 +            dispatch.on('changeState', function(e) {
  1.5306 +                if (typeof e.disabled !== 'undefined') {
  1.5307 +                    data.forEach(function(series,i) {
  1.5308 +                        series.disabled = e.disabled[i];
  1.5309 +                    });
  1.5310 +
  1.5311 +                    state.disabled = e.disabled;
  1.5312 +                }
  1.5313 +
  1.5314 +                chart.update();
  1.5315 +            });
  1.5316 +        });
  1.5317 +
  1.5318 +        renderWatch.renderEnd('historicalBarChart immediate');
  1.5319 +        return chart;
  1.5320 +    }
  1.5321 +
  1.5322 +    //============================================================
  1.5323 +    // Event Handling/Dispatching (out of chart's scope)
  1.5324 +    //------------------------------------------------------------
  1.5325 +
  1.5326 +    bars.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.5327 +        evt['series'] = {
  1.5328 +            key: chart.x()(evt.data),
  1.5329 +            value: chart.y()(evt.data),
  1.5330 +            color: evt.color
  1.5331 +        };
  1.5332 +        tooltip.data(evt).hidden(false);
  1.5333 +    });
  1.5334 +
  1.5335 +    bars.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.5336 +        tooltip.hidden(true);
  1.5337 +    });
  1.5338 +
  1.5339 +    bars.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.5340 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.5341 +    });
  1.5342 +
  1.5343 +    //============================================================
  1.5344 +    // Expose Public Variables
  1.5345 +    //------------------------------------------------------------
  1.5346 +
  1.5347 +    // expose chart's sub-components
  1.5348 +    chart.dispatch = dispatch;
  1.5349 +    chart.bars = bars;
  1.5350 +    chart.legend = legend;
  1.5351 +    chart.xAxis = xAxis;
  1.5352 +    chart.yAxis = yAxis;
  1.5353 +    chart.interactiveLayer = interactiveLayer;
  1.5354 +    chart.tooltip = tooltip;
  1.5355 +
  1.5356 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.5357 +
  1.5358 +    chart._options = Object.create({}, {
  1.5359 +        // simple options, just get/set the necessary values
  1.5360 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.5361 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.5362 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.5363 +        showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
  1.5364 +        showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
  1.5365 +        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
  1.5366 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.5367 +
  1.5368 +        // deprecated options
  1.5369 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.5370 +            // deprecated after 1.7.1
  1.5371 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.5372 +            tooltip.enabled(!!_);
  1.5373 +        }},
  1.5374 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.5375 +            // deprecated after 1.7.1
  1.5376 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.5377 +            tooltip.contentGenerator(_);
  1.5378 +        }},
  1.5379 +
  1.5380 +        // options that require extra logic in the setter
  1.5381 +        margin: {get: function(){return margin;}, set: function(_){
  1.5382 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.5383 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.5384 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.5385 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.5386 +        }},
  1.5387 +        color:  {get: function(){return color;}, set: function(_){
  1.5388 +            color = nv.utils.getColor(_);
  1.5389 +            legend.color(color);
  1.5390 +            bars.color(color);
  1.5391 +        }},
  1.5392 +        duration:    {get: function(){return transitionDuration;}, set: function(_){
  1.5393 +            transitionDuration=_;
  1.5394 +            renderWatch.reset(transitionDuration);
  1.5395 +            yAxis.duration(transitionDuration);
  1.5396 +            xAxis.duration(transitionDuration);
  1.5397 +        }},
  1.5398 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
  1.5399 +            rightAlignYAxis = _;
  1.5400 +            yAxis.orient( (_) ? 'right' : 'left');
  1.5401 +        }},
  1.5402 +        useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
  1.5403 +            useInteractiveGuideline = _;
  1.5404 +            if (_ === true) {
  1.5405 +                chart.interactive(false);
  1.5406 +            }
  1.5407 +        }}
  1.5408 +    });
  1.5409 +
  1.5410 +    nv.utils.inheritOptions(chart, bars);
  1.5411 +    nv.utils.initOptions(chart);
  1.5412 +
  1.5413 +    return chart;
  1.5414 +};
  1.5415 +
  1.5416 +
  1.5417 +// ohlcChart is just a historical chart with ohlc bars and some tweaks
  1.5418 +nv.models.ohlcBarChart = function() {
  1.5419 +    var chart = nv.models.historicalBarChart(nv.models.ohlcBar());
  1.5420 +
  1.5421 +    // special default tooltip since we show multiple values per x
  1.5422 +    chart.useInteractiveGuideline(true);
  1.5423 +    chart.interactiveLayer.tooltip.contentGenerator(function(data) {
  1.5424 +        // we assume only one series exists for this chart
  1.5425 +        var d = data.series[0].data;
  1.5426 +        // match line colors as defined in nv.d3.css
  1.5427 +        var color = d.open < d.close ? "2ca02c" : "d62728";
  1.5428 +        return '' +
  1.5429 +            '<h3 style="color: #' + color + '">' + data.value + '</h3>' +
  1.5430 +            '<table>' +
  1.5431 +            '<tr><td>open:</td><td>' + chart.yAxis.tickFormat()(d.open) + '</td></tr>' +
  1.5432 +            '<tr><td>close:</td><td>' + chart.yAxis.tickFormat()(d.close) + '</td></tr>' +
  1.5433 +            '<tr><td>high</td><td>' + chart.yAxis.tickFormat()(d.high) + '</td></tr>' +
  1.5434 +            '<tr><td>low:</td><td>' + chart.yAxis.tickFormat()(d.low) + '</td></tr>' +
  1.5435 +            '</table>';
  1.5436 +    });
  1.5437 +    return chart;
  1.5438 +};
  1.5439 +
  1.5440 +// candlestickChart is just a historical chart with candlestick bars and some tweaks
  1.5441 +nv.models.candlestickBarChart = function() {
  1.5442 +    var chart = nv.models.historicalBarChart(nv.models.candlestickBar());
  1.5443 +
  1.5444 +    // special default tooltip since we show multiple values per x
  1.5445 +    chart.useInteractiveGuideline(true);
  1.5446 +    chart.interactiveLayer.tooltip.contentGenerator(function(data) {
  1.5447 +        // we assume only one series exists for this chart
  1.5448 +        var d = data.series[0].data;
  1.5449 +        // match line colors as defined in nv.d3.css
  1.5450 +        var color = d.open < d.close ? "2ca02c" : "d62728";
  1.5451 +        return '' +
  1.5452 +            '<h3 style="color: #' + color + '">' + data.value + '</h3>' +
  1.5453 +            '<table>' +
  1.5454 +            '<tr><td>open:</td><td>' + chart.yAxis.tickFormat()(d.open) + '</td></tr>' +
  1.5455 +            '<tr><td>close:</td><td>' + chart.yAxis.tickFormat()(d.close) + '</td></tr>' +
  1.5456 +            '<tr><td>high</td><td>' + chart.yAxis.tickFormat()(d.high) + '</td></tr>' +
  1.5457 +            '<tr><td>low:</td><td>' + chart.yAxis.tickFormat()(d.low) + '</td></tr>' +
  1.5458 +            '</table>';
  1.5459 +    });
  1.5460 +    return chart;
  1.5461 +};
  1.5462 +nv.models.legend = function() {
  1.5463 +    "use strict";
  1.5464 +
  1.5465 +    //============================================================
  1.5466 +    // Public Variables with Default Settings
  1.5467 +    //------------------------------------------------------------
  1.5468 +
  1.5469 +    var margin = {top: 5, right: 0, bottom: 5, left: 0}
  1.5470 +        , width = 400
  1.5471 +        , height = 20
  1.5472 +        , getKey = function(d) { return d.key }
  1.5473 +        , color = nv.utils.getColor()
  1.5474 +        , align = true
  1.5475 +        , padding = 32 //define how much space between legend items. - recommend 32 for furious version
  1.5476 +        , rightAlign = true
  1.5477 +        , updateState = true   //If true, legend will update data.disabled and trigger a 'stateChange' dispatch.
  1.5478 +        , radioButtonMode = false   //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time)
  1.5479 +        , expanded = false
  1.5480 +        , dispatch = d3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange')
  1.5481 +        , vers = 'classic' //Options are "classic" and "furious"
  1.5482 +        ;
  1.5483 +
  1.5484 +    function chart(selection) {
  1.5485 +        selection.each(function(data) {
  1.5486 +            var availableWidth = width - margin.left - margin.right,
  1.5487 +                container = d3.select(this);
  1.5488 +            nv.utils.initSVG(container);
  1.5489 +
  1.5490 +            // Setup containers and skeleton of chart
  1.5491 +            var wrap = container.selectAll('g.nv-legend').data([data]);
  1.5492 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g');
  1.5493 +            var g = wrap.select('g');
  1.5494 +
  1.5495 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.5496 +
  1.5497 +            var series = g.selectAll('.nv-series')
  1.5498 +                .data(function(d) {
  1.5499 +                    if(vers != 'furious') return d;
  1.5500 +
  1.5501 +                    return d.filter(function(n) {
  1.5502 +                        return expanded ? true : !n.disengaged;
  1.5503 +                    });
  1.5504 +                });
  1.5505 +
  1.5506 +            var seriesEnter = series.enter().append('g').attr('class', 'nv-series');
  1.5507 +            var seriesShape;
  1.5508 +
  1.5509 +            var versPadding;
  1.5510 +            switch(vers) {
  1.5511 +                case 'furious' :
  1.5512 +                    versPadding = 23;
  1.5513 +                    break;
  1.5514 +                case 'classic' :
  1.5515 +                    versPadding = 20;
  1.5516 +            }
  1.5517 +
  1.5518 +            if(vers == 'classic') {
  1.5519 +                seriesEnter.append('circle')
  1.5520 +                    .style('stroke-width', 2)
  1.5521 +                    .attr('class','nv-legend-symbol')
  1.5522 +                    .attr('r', 5);
  1.5523 +
  1.5524 +                seriesShape = series.select('circle');
  1.5525 +            } else if (vers == 'furious') {
  1.5526 +                seriesEnter.append('rect')
  1.5527 +                    .style('stroke-width', 2)
  1.5528 +                    .attr('class','nv-legend-symbol')
  1.5529 +                    .attr('rx', 3)
  1.5530 +                    .attr('ry', 3);
  1.5531 +
  1.5532 +                seriesShape = series.select('.nv-legend-symbol');
  1.5533 +
  1.5534 +                seriesEnter.append('g')
  1.5535 +                    .attr('class', 'nv-check-box')
  1.5536 +                    .property('innerHTML','<path d="M0.5,5 L22.5,5 L22.5,26.5 L0.5,26.5 L0.5,5 Z" class="nv-box"></path><path d="M5.5,12.8618467 L11.9185089,19.2803556 L31,0.198864511" class="nv-check"></path>')
  1.5537 +                    .attr('transform', 'translate(-10,-8)scale(0.5)');
  1.5538 +
  1.5539 +                var seriesCheckbox = series.select('.nv-check-box');
  1.5540 +
  1.5541 +                seriesCheckbox.each(function(d,i) {
  1.5542 +                    d3.select(this).selectAll('path')
  1.5543 +                        .attr('stroke', setTextColor(d,i));
  1.5544 +                });
  1.5545 +            }
  1.5546 +
  1.5547 +            seriesEnter.append('text')
  1.5548 +                .attr('text-anchor', 'start')
  1.5549 +                .attr('class','nv-legend-text')
  1.5550 +                .attr('dy', '.32em')
  1.5551 +                .attr('dx', '8');
  1.5552 +
  1.5553 +            var seriesText = series.select('text.nv-legend-text');
  1.5554 +
  1.5555 +            series
  1.5556 +                .on('mouseover', function(d,i) {
  1.5557 +                    dispatch.legendMouseover(d,i);  //TODO: Make consistent with other event objects
  1.5558 +                })
  1.5559 +                .on('mouseout', function(d,i) {
  1.5560 +                    dispatch.legendMouseout(d,i);
  1.5561 +                })
  1.5562 +                .on('click', function(d,i) {
  1.5563 +                    dispatch.legendClick(d,i);
  1.5564 +                    // make sure we re-get data in case it was modified
  1.5565 +                    var data = series.data();
  1.5566 +                    if (updateState) {
  1.5567 +                        if(vers =='classic') {
  1.5568 +                            if (radioButtonMode) {
  1.5569 +                                //Radio button mode: set every series to disabled,
  1.5570 +                                //  and enable the clicked series.
  1.5571 +                                data.forEach(function(series) { series.disabled = true});
  1.5572 +                                d.disabled = false;
  1.5573 +                            }
  1.5574 +                            else {
  1.5575 +                                d.disabled = !d.disabled;
  1.5576 +                                if (data.every(function(series) { return series.disabled})) {
  1.5577 +                                    //the default behavior of NVD3 legends is, if every single series
  1.5578 +                                    // is disabled, turn all series' back on.
  1.5579 +                                    data.forEach(function(series) { series.disabled = false});
  1.5580 +                                }
  1.5581 +                            }
  1.5582 +                        } else if(vers == 'furious') {
  1.5583 +                            if(expanded) {
  1.5584 +                                d.disengaged = !d.disengaged;
  1.5585 +                                d.userDisabled = d.userDisabled == undefined ? !!d.disabled : d.userDisabled;
  1.5586 +                                d.disabled = d.disengaged || d.userDisabled;
  1.5587 +                            } else if (!expanded) {
  1.5588 +                                d.disabled = !d.disabled;
  1.5589 +                                d.userDisabled = d.disabled;
  1.5590 +                                var engaged = data.filter(function(d) { return !d.disengaged; });
  1.5591 +                                if (engaged.every(function(series) { return series.userDisabled })) {
  1.5592 +                                    //the default behavior of NVD3 legends is, if every single series
  1.5593 +                                    // is disabled, turn all series' back on.
  1.5594 +                                    data.forEach(function(series) {
  1.5595 +                                        series.disabled = series.userDisabled = false;
  1.5596 +                                    });
  1.5597 +                                }
  1.5598 +                            }
  1.5599 +                        }
  1.5600 +                        dispatch.stateChange({
  1.5601 +                            disabled: data.map(function(d) { return !!d.disabled }),
  1.5602 +                            disengaged: data.map(function(d) { return !!d.disengaged })
  1.5603 +                        });
  1.5604 +
  1.5605 +                    }
  1.5606 +                })
  1.5607 +                .on('dblclick', function(d,i) {
  1.5608 +                    if(vers == 'furious' && expanded) return;
  1.5609 +                    dispatch.legendDblclick(d,i);
  1.5610 +                    if (updateState) {
  1.5611 +                        // make sure we re-get data in case it was modified
  1.5612 +                        var data = series.data();
  1.5613 +                        //the default behavior of NVD3 legends, when double clicking one,
  1.5614 +                        // is to set all other series' to false, and make the double clicked series enabled.
  1.5615 +                        data.forEach(function(series) {
  1.5616 +                            series.disabled = true;
  1.5617 +                            if(vers == 'furious') series.userDisabled = series.disabled;
  1.5618 +                        });
  1.5619 +                        d.disabled = false;
  1.5620 +                        if(vers == 'furious') d.userDisabled = d.disabled;
  1.5621 +                        dispatch.stateChange({
  1.5622 +                            disabled: data.map(function(d) { return !!d.disabled })
  1.5623 +                        });
  1.5624 +                    }
  1.5625 +                });
  1.5626 +
  1.5627 +            series.classed('nv-disabled', function(d) { return d.userDisabled });
  1.5628 +            series.exit().remove();
  1.5629 +
  1.5630 +            seriesText
  1.5631 +                .attr('fill', setTextColor)
  1.5632 +                .text(getKey);
  1.5633 +
  1.5634 +            //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option)
  1.5635 +            // NEW ALIGNING CODE, TODO: clean up
  1.5636 +            var legendWidth = 0;
  1.5637 +            if (align) {
  1.5638 +
  1.5639 +                var seriesWidths = [];
  1.5640 +                series.each(function(d,i) {
  1.5641 +                    var legendText = d3.select(this).select('text');
  1.5642 +                    var nodeTextLength;
  1.5643 +                    try {
  1.5644 +                        nodeTextLength = legendText.node().getComputedTextLength();
  1.5645 +                        // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead
  1.5646 +                        if(nodeTextLength <= 0) throw Error();
  1.5647 +                    }
  1.5648 +                    catch(e) {
  1.5649 +                        nodeTextLength = nv.utils.calcApproxTextWidth(legendText);
  1.5650 +                    }
  1.5651 +
  1.5652 +                    seriesWidths.push(nodeTextLength + padding);
  1.5653 +                });
  1.5654 +
  1.5655 +                var seriesPerRow = 0;
  1.5656 +                var columnWidths = [];
  1.5657 +                legendWidth = 0;
  1.5658 +
  1.5659 +                while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) {
  1.5660 +                    columnWidths[seriesPerRow] = seriesWidths[seriesPerRow];
  1.5661 +                    legendWidth += seriesWidths[seriesPerRow++];
  1.5662 +                }
  1.5663 +                if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row
  1.5664 +
  1.5665 +                while ( legendWidth > availableWidth && seriesPerRow > 1 ) {
  1.5666 +                    columnWidths = [];
  1.5667 +                    seriesPerRow--;
  1.5668 +
  1.5669 +                    for (var k = 0; k < seriesWidths.length; k++) {
  1.5670 +                        if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) )
  1.5671 +                            columnWidths[k % seriesPerRow] = seriesWidths[k];
  1.5672 +                    }
  1.5673 +
  1.5674 +                    legendWidth = columnWidths.reduce(function(prev, cur, index, array) {
  1.5675 +                        return prev + cur;
  1.5676 +                    });
  1.5677 +                }
  1.5678 +
  1.5679 +                var xPositions = [];
  1.5680 +                for (var i = 0, curX = 0; i < seriesPerRow; i++) {
  1.5681 +                    xPositions[i] = curX;
  1.5682 +                    curX += columnWidths[i];
  1.5683 +                }
  1.5684 +
  1.5685 +                series
  1.5686 +                    .attr('transform', function(d, i) {
  1.5687 +                        return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * versPadding) + ')';
  1.5688 +                    });
  1.5689 +
  1.5690 +                //position legend as far right as possible within the total width
  1.5691 +                if (rightAlign) {
  1.5692 +                    g.attr('transform', 'translate(' + (width - margin.right - legendWidth) + ',' + margin.top + ')');
  1.5693 +                }
  1.5694 +                else {
  1.5695 +                    g.attr('transform', 'translate(0' + ',' + margin.top + ')');
  1.5696 +                }
  1.5697 +
  1.5698 +                height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * versPadding);
  1.5699 +
  1.5700 +            } else {
  1.5701 +
  1.5702 +                var ypos = 5,
  1.5703 +                    newxpos = 5,
  1.5704 +                    maxwidth = 0,
  1.5705 +                    xpos;
  1.5706 +                series
  1.5707 +                    .attr('transform', function(d, i) {
  1.5708 +                        var length = d3.select(this).select('text').node().getComputedTextLength() + padding;
  1.5709 +                        xpos = newxpos;
  1.5710 +
  1.5711 +                        if (width < margin.left + margin.right + xpos + length) {
  1.5712 +                            newxpos = xpos = 5;
  1.5713 +                            ypos += versPadding;
  1.5714 +                        }
  1.5715 +
  1.5716 +                        newxpos += length;
  1.5717 +                        if (newxpos > maxwidth) maxwidth = newxpos;
  1.5718 +
  1.5719 +                        if(legendWidth < xpos + maxwidth) {
  1.5720 +                            legendWidth = xpos + maxwidth;
  1.5721 +                        }
  1.5722 +                        return 'translate(' + xpos + ',' + ypos + ')';
  1.5723 +                    });
  1.5724 +
  1.5725 +                //position legend as far right as possible within the total width
  1.5726 +                g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')');
  1.5727 +
  1.5728 +                height = margin.top + margin.bottom + ypos + 15;
  1.5729 +            }
  1.5730 +
  1.5731 +            if(vers == 'furious') {
  1.5732 +                // Size rectangles after text is placed
  1.5733 +                seriesShape
  1.5734 +                    .attr('width', function(d,i) {
  1.5735 +                        return seriesText[0][i].getComputedTextLength() + 27;
  1.5736 +                    })
  1.5737 +                    .attr('height', 18)
  1.5738 +                    .attr('y', -9)
  1.5739 +                    .attr('x', -15);
  1.5740 +
  1.5741 +                // The background for the expanded legend (UI)
  1.5742 +                gEnter.insert('rect',':first-child')
  1.5743 +                    .attr('class', 'nv-legend-bg')
  1.5744 +                    .attr('fill', '#eee')
  1.5745 +                    // .attr('stroke', '#444')
  1.5746 +                    .attr('opacity',0);
  1.5747 +
  1.5748 +                var seriesBG = g.select('.nv-legend-bg');
  1.5749 +
  1.5750 +                seriesBG
  1.5751 +                .transition().duration(300)
  1.5752 +                    .attr('x', -versPadding )
  1.5753 +                    .attr('width', legendWidth + versPadding - 12)
  1.5754 +                    .attr('height', height + 10)
  1.5755 +                    .attr('y', -margin.top - 10)
  1.5756 +                    .attr('opacity', expanded ? 1 : 0);
  1.5757 +
  1.5758 +
  1.5759 +            }
  1.5760 +
  1.5761 +            seriesShape
  1.5762 +                .style('fill', setBGColor)
  1.5763 +                .style('fill-opacity', setBGOpacity)
  1.5764 +                .style('stroke', setBGColor);
  1.5765 +        });
  1.5766 +
  1.5767 +        function setTextColor(d,i) {
  1.5768 +            if(vers != 'furious') return '#000';
  1.5769 +            if(expanded) {
  1.5770 +                return d.disengaged ? '#000' : '#fff';
  1.5771 +            } else if (!expanded) {
  1.5772 +                if(!d.color) d.color = color(d,i);
  1.5773 +                return !!d.disabled ? d.color : '#fff';
  1.5774 +            }
  1.5775 +        }
  1.5776 +
  1.5777 +        function setBGColor(d,i) {
  1.5778 +            if(expanded && vers == 'furious') {
  1.5779 +                return d.disengaged ? '#eee' : d.color || color(d,i);
  1.5780 +            } else {
  1.5781 +                return d.color || color(d,i);
  1.5782 +            }
  1.5783 +        }
  1.5784 +
  1.5785 +
  1.5786 +        function setBGOpacity(d,i) {
  1.5787 +            if(expanded && vers == 'furious') {
  1.5788 +                return 1;
  1.5789 +            } else {
  1.5790 +                return !!d.disabled ? 0 : 1;
  1.5791 +            }
  1.5792 +        }
  1.5793 +
  1.5794 +        return chart;
  1.5795 +    }
  1.5796 +
  1.5797 +    //============================================================
  1.5798 +    // Expose Public Variables
  1.5799 +    //------------------------------------------------------------
  1.5800 +
  1.5801 +    chart.dispatch = dispatch;
  1.5802 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.5803 +
  1.5804 +    chart._options = Object.create({}, {
  1.5805 +        // simple options, just get/set the necessary values
  1.5806 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.5807 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.5808 +        key:        {get: function(){return getKey;}, set: function(_){getKey=_;}},
  1.5809 +        align:      {get: function(){return align;}, set: function(_){align=_;}},
  1.5810 +        rightAlign:    {get: function(){return rightAlign;}, set: function(_){rightAlign=_;}},
  1.5811 +        padding:       {get: function(){return padding;}, set: function(_){padding=_;}},
  1.5812 +        updateState:   {get: function(){return updateState;}, set: function(_){updateState=_;}},
  1.5813 +        radioButtonMode:    {get: function(){return radioButtonMode;}, set: function(_){radioButtonMode=_;}},
  1.5814 +        expanded:   {get: function(){return expanded;}, set: function(_){expanded=_;}},
  1.5815 +        vers:   {get: function(){return vers;}, set: function(_){vers=_;}},
  1.5816 +
  1.5817 +        // options that require extra logic in the setter
  1.5818 +        margin: {get: function(){return margin;}, set: function(_){
  1.5819 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.5820 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.5821 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.5822 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.5823 +        }},
  1.5824 +        color:  {get: function(){return color;}, set: function(_){
  1.5825 +            color = nv.utils.getColor(_);
  1.5826 +        }}
  1.5827 +    });
  1.5828 +
  1.5829 +    nv.utils.initOptions(chart);
  1.5830 +
  1.5831 +    return chart;
  1.5832 +};
  1.5833 +
  1.5834 +nv.models.line = function() {
  1.5835 +    "use strict";
  1.5836 +    //============================================================
  1.5837 +    // Public Variables with Default Settings
  1.5838 +    //------------------------------------------------------------
  1.5839 +
  1.5840 +    var  scatter = nv.models.scatter()
  1.5841 +        ;
  1.5842 +
  1.5843 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.5844 +        , width = 960
  1.5845 +        , height = 500
  1.5846 +        , container = null
  1.5847 +        , strokeWidth = 1.5
  1.5848 +        , color = nv.utils.defaultColor() // a function that returns a color
  1.5849 +        , getX = function(d) { return d.x } // accessor to get the x value from a data point
  1.5850 +        , getY = function(d) { return d.y } // accessor to get the y value from a data point
  1.5851 +        , defined = function(d,i) { return !isNaN(getY(d,i)) && getY(d,i) !== null } // allows a line to be not continuous when it is not defined
  1.5852 +        , isArea = function(d) { return d.area } // decides if a line is an area or just a line
  1.5853 +        , clipEdge = false // if true, masks lines within x and y scale
  1.5854 +        , x //can be accessed via chart.xScale()
  1.5855 +        , y //can be accessed via chart.yScale()
  1.5856 +        , interpolate = "linear" // controls the line interpolation
  1.5857 +        , duration = 250
  1.5858 +        , dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout', 'renderEnd')
  1.5859 +        ;
  1.5860 +
  1.5861 +    scatter
  1.5862 +        .pointSize(16) // default size
  1.5863 +        .pointDomain([16,256]) //set to speed up calculation, needs to be unset if there is a custom size accessor
  1.5864 +    ;
  1.5865 +
  1.5866 +    //============================================================
  1.5867 +
  1.5868 +
  1.5869 +    //============================================================
  1.5870 +    // Private Variables
  1.5871 +    //------------------------------------------------------------
  1.5872 +
  1.5873 +    var x0, y0 //used to store previous scales
  1.5874 +        , renderWatch = nv.utils.renderWatch(dispatch, duration)
  1.5875 +        ;
  1.5876 +
  1.5877 +    //============================================================
  1.5878 +
  1.5879 +
  1.5880 +    function chart(selection) {
  1.5881 +        renderWatch.reset();
  1.5882 +        renderWatch.models(scatter);
  1.5883 +        selection.each(function(data) {
  1.5884 +            container = d3.select(this);
  1.5885 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.5886 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.5887 +            nv.utils.initSVG(container);
  1.5888 +
  1.5889 +            // Setup Scales
  1.5890 +            x = scatter.xScale();
  1.5891 +            y = scatter.yScale();
  1.5892 +
  1.5893 +            x0 = x0 || x;
  1.5894 +            y0 = y0 || y;
  1.5895 +
  1.5896 +            // Setup containers and skeleton of chart
  1.5897 +            var wrap = container.selectAll('g.nv-wrap.nv-line').data([data]);
  1.5898 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-line');
  1.5899 +            var defsEnter = wrapEnter.append('defs');
  1.5900 +            var gEnter = wrapEnter.append('g');
  1.5901 +            var g = wrap.select('g');
  1.5902 +
  1.5903 +            gEnter.append('g').attr('class', 'nv-groups');
  1.5904 +            gEnter.append('g').attr('class', 'nv-scatterWrap');
  1.5905 +
  1.5906 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.5907 +
  1.5908 +            scatter
  1.5909 +                .width(availableWidth)
  1.5910 +                .height(availableHeight);
  1.5911 +
  1.5912 +            var scatterWrap = wrap.select('.nv-scatterWrap');
  1.5913 +            scatterWrap.call(scatter);
  1.5914 +
  1.5915 +            defsEnter.append('clipPath')
  1.5916 +                .attr('id', 'nv-edge-clip-' + scatter.id())
  1.5917 +                .append('rect');
  1.5918 +
  1.5919 +            wrap.select('#nv-edge-clip-' + scatter.id() + ' rect')
  1.5920 +                .attr('width', availableWidth)
  1.5921 +                .attr('height', (availableHeight > 0) ? availableHeight : 0);
  1.5922 +
  1.5923 +            g   .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
  1.5924 +            scatterWrap
  1.5925 +                .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
  1.5926 +
  1.5927 +            var groups = wrap.select('.nv-groups').selectAll('.nv-group')
  1.5928 +                .data(function(d) { return d }, function(d) { return d.key });
  1.5929 +            groups.enter().append('g')
  1.5930 +                .style('stroke-opacity', 1e-6)
  1.5931 +                .style('stroke-width', function(d) { return d.strokeWidth || strokeWidth })
  1.5932 +                .style('fill-opacity', 1e-6);
  1.5933 +
  1.5934 +            groups.exit().remove();
  1.5935 +
  1.5936 +            groups
  1.5937 +                .attr('class', function(d,i) {
  1.5938 +                    return (d.classed || '') + ' nv-group nv-series-' + i;
  1.5939 +                })
  1.5940 +                .classed('hover', function(d) { return d.hover })
  1.5941 +                .style('fill', function(d,i){ return color(d, i) })
  1.5942 +                .style('stroke', function(d,i){ return color(d, i)});
  1.5943 +            groups.watchTransition(renderWatch, 'line: groups')
  1.5944 +                .style('stroke-opacity', 1)
  1.5945 +                .style('fill-opacity', function(d) { return d.fillOpacity || .5});
  1.5946 +
  1.5947 +            var areaPaths = groups.selectAll('path.nv-area')
  1.5948 +                .data(function(d) { return isArea(d) ? [d] : [] }); // this is done differently than lines because I need to check if series is an area
  1.5949 +            areaPaths.enter().append('path')
  1.5950 +                .attr('class', 'nv-area')
  1.5951 +                .attr('d', function(d) {
  1.5952 +                    return d3.svg.area()
  1.5953 +                        .interpolate(interpolate)
  1.5954 +                        .defined(defined)
  1.5955 +                        .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
  1.5956 +                        .y0(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
  1.5957 +                        .y1(function(d,i) { return y0( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) })
  1.5958 +                        //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this
  1.5959 +                        .apply(this, [d.values])
  1.5960 +                });
  1.5961 +            groups.exit().selectAll('path.nv-area')
  1.5962 +                .remove();
  1.5963 +
  1.5964 +            areaPaths.watchTransition(renderWatch, 'line: areaPaths')
  1.5965 +                .attr('d', function(d) {
  1.5966 +                    return d3.svg.area()
  1.5967 +                        .interpolate(interpolate)
  1.5968 +                        .defined(defined)
  1.5969 +                        .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
  1.5970 +                        .y0(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
  1.5971 +                        .y1(function(d,i) { return y( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) })
  1.5972 +                        //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this
  1.5973 +                        .apply(this, [d.values])
  1.5974 +                });
  1.5975 +
  1.5976 +            var linePaths = groups.selectAll('path.nv-line')
  1.5977 +                .data(function(d) { return [d.values] });
  1.5978 +
  1.5979 +            linePaths.enter().append('path')
  1.5980 +                .attr('class', 'nv-line')
  1.5981 +                .attr('d',
  1.5982 +                    d3.svg.line()
  1.5983 +                    .interpolate(interpolate)
  1.5984 +                    .defined(defined)
  1.5985 +                    .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
  1.5986 +                    .y(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
  1.5987 +            );
  1.5988 +
  1.5989 +            linePaths.watchTransition(renderWatch, 'line: linePaths')
  1.5990 +                .attr('d',
  1.5991 +                    d3.svg.line()
  1.5992 +                    .interpolate(interpolate)
  1.5993 +                    .defined(defined)
  1.5994 +                    .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
  1.5995 +                    .y(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
  1.5996 +            );
  1.5997 +
  1.5998 +            //store old scales for use in transitions on update
  1.5999 +            x0 = x.copy();
  1.6000 +            y0 = y.copy();
  1.6001 +        });
  1.6002 +        renderWatch.renderEnd('line immediate');
  1.6003 +        return chart;
  1.6004 +    }
  1.6005 +
  1.6006 +
  1.6007 +    //============================================================
  1.6008 +    // Expose Public Variables
  1.6009 +    //------------------------------------------------------------
  1.6010 +
  1.6011 +    chart.dispatch = dispatch;
  1.6012 +    chart.scatter = scatter;
  1.6013 +    // Pass through events
  1.6014 +    scatter.dispatch.on('elementClick', function(){ dispatch.elementClick.apply(this, arguments); });
  1.6015 +    scatter.dispatch.on('elementMouseover', function(){ dispatch.elementMouseover.apply(this, arguments); });
  1.6016 +    scatter.dispatch.on('elementMouseout', function(){ dispatch.elementMouseout.apply(this, arguments); });
  1.6017 +
  1.6018 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.6019 +
  1.6020 +    chart._options = Object.create({}, {
  1.6021 +        // simple options, just get/set the necessary values
  1.6022 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.6023 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.6024 +        defined: {get: function(){return defined;}, set: function(_){defined=_;}},
  1.6025 +        interpolate:      {get: function(){return interpolate;}, set: function(_){interpolate=_;}},
  1.6026 +        clipEdge:    {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
  1.6027 +
  1.6028 +        // options that require extra logic in the setter
  1.6029 +        margin: {get: function(){return margin;}, set: function(_){
  1.6030 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.6031 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.6032 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.6033 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.6034 +        }},
  1.6035 +        duration: {get: function(){return duration;}, set: function(_){
  1.6036 +            duration = _;
  1.6037 +            renderWatch.reset(duration);
  1.6038 +            scatter.duration(duration);
  1.6039 +        }},
  1.6040 +        isArea: {get: function(){return isArea;}, set: function(_){
  1.6041 +            isArea = d3.functor(_);
  1.6042 +        }},
  1.6043 +        x: {get: function(){return getX;}, set: function(_){
  1.6044 +            getX = _;
  1.6045 +            scatter.x(_);
  1.6046 +        }},
  1.6047 +        y: {get: function(){return getY;}, set: function(_){
  1.6048 +            getY = _;
  1.6049 +            scatter.y(_);
  1.6050 +        }},
  1.6051 +        color:  {get: function(){return color;}, set: function(_){
  1.6052 +            color = nv.utils.getColor(_);
  1.6053 +            scatter.color(color);
  1.6054 +        }}
  1.6055 +    });
  1.6056 +
  1.6057 +    nv.utils.inheritOptions(chart, scatter);
  1.6058 +    nv.utils.initOptions(chart);
  1.6059 +
  1.6060 +    return chart;
  1.6061 +};
  1.6062 +nv.models.lineChart = function() {
  1.6063 +    "use strict";
  1.6064 +
  1.6065 +    //============================================================
  1.6066 +    // Public Variables with Default Settings
  1.6067 +    //------------------------------------------------------------
  1.6068 +
  1.6069 +    var lines = nv.models.line()
  1.6070 +        , xAxis = nv.models.axis()
  1.6071 +        , yAxis = nv.models.axis()
  1.6072 +        , legend = nv.models.legend()
  1.6073 +        , interactiveLayer = nv.interactiveGuideline()
  1.6074 +        , tooltip = nv.models.tooltip()
  1.6075 +        ;
  1.6076 +
  1.6077 +    var margin = {top: 30, right: 20, bottom: 50, left: 60}
  1.6078 +        , color = nv.utils.defaultColor()
  1.6079 +        , width = null
  1.6080 +        , height = null
  1.6081 +        , showLegend = true
  1.6082 +        , showXAxis = true
  1.6083 +        , showYAxis = true
  1.6084 +        , rightAlignYAxis = false
  1.6085 +        , useInteractiveGuideline = false
  1.6086 +        , x
  1.6087 +        , y
  1.6088 +        , state = nv.utils.state()
  1.6089 +        , defaultState = null
  1.6090 +        , noData = null
  1.6091 +        , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd')
  1.6092 +        , duration = 250
  1.6093 +        ;
  1.6094 +
  1.6095 +    // set options on sub-objects for this chart
  1.6096 +    xAxis.orient('bottom').tickPadding(7);
  1.6097 +    yAxis.orient(rightAlignYAxis ? 'right' : 'left');
  1.6098 +    tooltip.valueFormatter(function(d, i) {
  1.6099 +        return yAxis.tickFormat()(d, i);
  1.6100 +    }).headerFormatter(function(d, i) {
  1.6101 +        return xAxis.tickFormat()(d, i);
  1.6102 +    });
  1.6103 +
  1.6104 +
  1.6105 +    //============================================================
  1.6106 +    // Private Variables
  1.6107 +    //------------------------------------------------------------
  1.6108 +
  1.6109 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.6110 +
  1.6111 +    var stateGetter = function(data) {
  1.6112 +        return function(){
  1.6113 +            return {
  1.6114 +                active: data.map(function(d) { return !d.disabled })
  1.6115 +            };
  1.6116 +        }
  1.6117 +    };
  1.6118 +
  1.6119 +    var stateSetter = function(data) {
  1.6120 +        return function(state) {
  1.6121 +            if (state.active !== undefined)
  1.6122 +                data.forEach(function(series,i) {
  1.6123 +                    series.disabled = !state.active[i];
  1.6124 +                });
  1.6125 +        }
  1.6126 +    };
  1.6127 +
  1.6128 +    function chart(selection) {
  1.6129 +        renderWatch.reset();
  1.6130 +        renderWatch.models(lines);
  1.6131 +        if (showXAxis) renderWatch.models(xAxis);
  1.6132 +        if (showYAxis) renderWatch.models(yAxis);
  1.6133 +
  1.6134 +        selection.each(function(data) {
  1.6135 +            var container = d3.select(this),
  1.6136 +                that = this;
  1.6137 +            nv.utils.initSVG(container);
  1.6138 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.6139 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.6140 +
  1.6141 +            chart.update = function() {
  1.6142 +                if (duration === 0)
  1.6143 +                    container.call(chart);
  1.6144 +                else
  1.6145 +                    container.transition().duration(duration).call(chart)
  1.6146 +            };
  1.6147 +            chart.container = this;
  1.6148 +
  1.6149 +            state
  1.6150 +                .setter(stateSetter(data), chart.update)
  1.6151 +                .getter(stateGetter(data))
  1.6152 +                .update();
  1.6153 +
  1.6154 +            // DEPRECATED set state.disableddisabled
  1.6155 +            state.disabled = data.map(function(d) { return !!d.disabled });
  1.6156 +
  1.6157 +            if (!defaultState) {
  1.6158 +                var key;
  1.6159 +                defaultState = {};
  1.6160 +                for (key in state) {
  1.6161 +                    if (state[key] instanceof Array)
  1.6162 +                        defaultState[key] = state[key].slice(0);
  1.6163 +                    else
  1.6164 +                        defaultState[key] = state[key];
  1.6165 +                }
  1.6166 +            }
  1.6167 +
  1.6168 +            // Display noData message if there's nothing to show.
  1.6169 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.6170 +                nv.utils.noData(chart, container)
  1.6171 +                return chart;
  1.6172 +            } else {
  1.6173 +                container.selectAll('.nv-noData').remove();
  1.6174 +            }
  1.6175 +
  1.6176 +
  1.6177 +            // Setup Scales
  1.6178 +            x = lines.xScale();
  1.6179 +            y = lines.yScale();
  1.6180 +
  1.6181 +            // Setup containers and skeleton of chart
  1.6182 +            var wrap = container.selectAll('g.nv-wrap.nv-lineChart').data([data]);
  1.6183 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineChart').append('g');
  1.6184 +            var g = wrap.select('g');
  1.6185 +
  1.6186 +            gEnter.append("rect").style("opacity",0);
  1.6187 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
  1.6188 +            gEnter.append('g').attr('class', 'nv-y nv-axis');
  1.6189 +            gEnter.append('g').attr('class', 'nv-linesWrap');
  1.6190 +            gEnter.append('g').attr('class', 'nv-legendWrap');
  1.6191 +            gEnter.append('g').attr('class', 'nv-interactive');
  1.6192 +
  1.6193 +            g.select("rect")
  1.6194 +                .attr("width",availableWidth)
  1.6195 +                .attr("height",(availableHeight > 0) ? availableHeight : 0);
  1.6196 +
  1.6197 +            // Legend
  1.6198 +            if (showLegend) {
  1.6199 +                legend.width(availableWidth);
  1.6200 +
  1.6201 +                g.select('.nv-legendWrap')
  1.6202 +                    .datum(data)
  1.6203 +                    .call(legend);
  1.6204 +
  1.6205 +                if ( margin.top != legend.height()) {
  1.6206 +                    margin.top = legend.height();
  1.6207 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
  1.6208 +                }
  1.6209 +
  1.6210 +                wrap.select('.nv-legendWrap')
  1.6211 +                    .attr('transform', 'translate(0,' + (-margin.top) +')')
  1.6212 +            }
  1.6213 +
  1.6214 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.6215 +
  1.6216 +            if (rightAlignYAxis) {
  1.6217 +                g.select(".nv-y.nv-axis")
  1.6218 +                    .attr("transform", "translate(" + availableWidth + ",0)");
  1.6219 +            }
  1.6220 +
  1.6221 +            //Set up interactive layer
  1.6222 +            if (useInteractiveGuideline) {
  1.6223 +                interactiveLayer
  1.6224 +                    .width(availableWidth)
  1.6225 +                    .height(availableHeight)
  1.6226 +                    .margin({left:margin.left, top:margin.top})
  1.6227 +                    .svgContainer(container)
  1.6228 +                    .xScale(x);
  1.6229 +                wrap.select(".nv-interactive").call(interactiveLayer);
  1.6230 +            }
  1.6231 +
  1.6232 +            lines
  1.6233 +                .width(availableWidth)
  1.6234 +                .height(availableHeight)
  1.6235 +                .color(data.map(function(d,i) {
  1.6236 +                    return d.color || color(d, i);
  1.6237 +                }).filter(function(d,i) { return !data[i].disabled }));
  1.6238 +
  1.6239 +
  1.6240 +            var linesWrap = g.select('.nv-linesWrap')
  1.6241 +                .datum(data.filter(function(d) { return !d.disabled }));
  1.6242 +
  1.6243 +            linesWrap.call(lines);
  1.6244 +
  1.6245 +            // Setup Axes
  1.6246 +            if (showXAxis) {
  1.6247 +                xAxis
  1.6248 +                    .scale(x)
  1.6249 +                    ._ticks(nv.utils.calcTicksX(availableWidth/100, data) )
  1.6250 +                    .tickSize(-availableHeight, 0);
  1.6251 +
  1.6252 +                g.select('.nv-x.nv-axis')
  1.6253 +                    .attr('transform', 'translate(0,' + y.range()[0] + ')');
  1.6254 +                g.select('.nv-x.nv-axis')
  1.6255 +                    .call(xAxis);
  1.6256 +            }
  1.6257 +
  1.6258 +            if (showYAxis) {
  1.6259 +                yAxis
  1.6260 +                    .scale(y)
  1.6261 +                    ._ticks(nv.utils.calcTicksY(availableHeight/36, data) )
  1.6262 +                    .tickSize( -availableWidth, 0);
  1.6263 +
  1.6264 +                g.select('.nv-y.nv-axis')
  1.6265 +                    .call(yAxis);
  1.6266 +            }
  1.6267 +
  1.6268 +            //============================================================
  1.6269 +            // Event Handling/Dispatching (in chart's scope)
  1.6270 +            //------------------------------------------------------------
  1.6271 +
  1.6272 +            legend.dispatch.on('stateChange', function(newState) {
  1.6273 +                for (var key in newState)
  1.6274 +                    state[key] = newState[key];
  1.6275 +                dispatch.stateChange(state);
  1.6276 +                chart.update();
  1.6277 +            });
  1.6278 +
  1.6279 +            interactiveLayer.dispatch.on('elementMousemove', function(e) {
  1.6280 +                lines.clearHighlights();
  1.6281 +                var singlePoint, pointIndex, pointXLocation, allData = [];
  1.6282 +                data
  1.6283 +                    .filter(function(series, i) {
  1.6284 +                        series.seriesIndex = i;
  1.6285 +                        return !series.disabled;
  1.6286 +                    })
  1.6287 +                    .forEach(function(series,i) {
  1.6288 +                        pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
  1.6289 +                        var point = series.values[pointIndex];
  1.6290 +                        var pointYValue = chart.y()(point, pointIndex);
  1.6291 +                        if (pointYValue != null) {
  1.6292 +                            lines.highlightPoint(i, pointIndex, true);
  1.6293 +                        }
  1.6294 +                        if (point === undefined) return;
  1.6295 +                        if (singlePoint === undefined) singlePoint = point;
  1.6296 +                        if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
  1.6297 +                        allData.push({
  1.6298 +                            key: series.key,
  1.6299 +                            value: pointYValue,
  1.6300 +                            color: color(series,series.seriesIndex)
  1.6301 +                        });
  1.6302 +                    });
  1.6303 +                //Highlight the tooltip entry based on which point the mouse is closest to.
  1.6304 +                if (allData.length > 2) {
  1.6305 +                    var yValue = chart.yScale().invert(e.mouseY);
  1.6306 +                    var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
  1.6307 +                    var threshold = 0.03 * domainExtent;
  1.6308 +                    var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold);
  1.6309 +                    if (indexToHighlight !== null)
  1.6310 +                        allData[indexToHighlight].highlight = true;
  1.6311 +                }
  1.6312 +
  1.6313 +                var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
  1.6314 +                interactiveLayer.tooltip
  1.6315 +                    .position({left: e.mouseX + margin.left, top: e.mouseY + margin.top})
  1.6316 +                    .chartContainer(that.parentNode)
  1.6317 +                    .valueFormatter(function(d,i) {
  1.6318 +                        return d == null ? "N/A" : yAxis.tickFormat()(d);
  1.6319 +                    })
  1.6320 +                    .data({
  1.6321 +                        value: xValue,
  1.6322 +                        index: pointIndex,
  1.6323 +                        series: allData
  1.6324 +                    })();
  1.6325 +
  1.6326 +                interactiveLayer.renderGuideLine(pointXLocation);
  1.6327 +
  1.6328 +            });
  1.6329 +
  1.6330 +            interactiveLayer.dispatch.on('elementClick', function(e) {
  1.6331 +                var pointXLocation, allData = [];
  1.6332 +
  1.6333 +                data.filter(function(series, i) {
  1.6334 +                    series.seriesIndex = i;
  1.6335 +                    return !series.disabled;
  1.6336 +                }).forEach(function(series) {
  1.6337 +                    var pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
  1.6338 +                    var point = series.values[pointIndex];
  1.6339 +                    if (typeof point === 'undefined') return;
  1.6340 +                    if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
  1.6341 +                    var yPos = chart.yScale()(chart.y()(point,pointIndex));
  1.6342 +                    allData.push({
  1.6343 +                        point: point,
  1.6344 +                        pointIndex: pointIndex,
  1.6345 +                        pos: [pointXLocation, yPos],
  1.6346 +                        seriesIndex: series.seriesIndex,
  1.6347 +                        series: series
  1.6348 +                    });
  1.6349 +                });
  1.6350 +
  1.6351 +                lines.dispatch.elementClick(allData);
  1.6352 +            });
  1.6353 +
  1.6354 +            interactiveLayer.dispatch.on("elementMouseout",function(e) {
  1.6355 +                lines.clearHighlights();
  1.6356 +            });
  1.6357 +
  1.6358 +            dispatch.on('changeState', function(e) {
  1.6359 +                if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) {
  1.6360 +                    data.forEach(function(series,i) {
  1.6361 +                        series.disabled = e.disabled[i];
  1.6362 +                    });
  1.6363 +
  1.6364 +                    state.disabled = e.disabled;
  1.6365 +                }
  1.6366 +
  1.6367 +                chart.update();
  1.6368 +            });
  1.6369 +
  1.6370 +        });
  1.6371 +
  1.6372 +        renderWatch.renderEnd('lineChart immediate');
  1.6373 +        return chart;
  1.6374 +    }
  1.6375 +
  1.6376 +    //============================================================
  1.6377 +    // Event Handling/Dispatching (out of chart's scope)
  1.6378 +    //------------------------------------------------------------
  1.6379 +
  1.6380 +    lines.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.6381 +        tooltip.data(evt).position(evt.pos).hidden(false);
  1.6382 +    });
  1.6383 +
  1.6384 +    lines.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.6385 +        tooltip.hidden(true)
  1.6386 +    });
  1.6387 +
  1.6388 +    //============================================================
  1.6389 +    // Expose Public Variables
  1.6390 +    //------------------------------------------------------------
  1.6391 +
  1.6392 +    // expose chart's sub-components
  1.6393 +    chart.dispatch = dispatch;
  1.6394 +    chart.lines = lines;
  1.6395 +    chart.legend = legend;
  1.6396 +    chart.xAxis = xAxis;
  1.6397 +    chart.yAxis = yAxis;
  1.6398 +    chart.interactiveLayer = interactiveLayer;
  1.6399 +    chart.tooltip = tooltip;
  1.6400 +
  1.6401 +    chart.dispatch = dispatch;
  1.6402 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.6403 +
  1.6404 +    chart._options = Object.create({}, {
  1.6405 +        // simple options, just get/set the necessary values
  1.6406 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.6407 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.6408 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.6409 +        showXAxis:      {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
  1.6410 +        showYAxis:    {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
  1.6411 +        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
  1.6412 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.6413 +
  1.6414 +        // deprecated options
  1.6415 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.6416 +            // deprecated after 1.7.1
  1.6417 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.6418 +            tooltip.enabled(!!_);
  1.6419 +        }},
  1.6420 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.6421 +            // deprecated after 1.7.1
  1.6422 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.6423 +            tooltip.contentGenerator(_);
  1.6424 +        }},
  1.6425 +
  1.6426 +        // options that require extra logic in the setter
  1.6427 +        margin: {get: function(){return margin;}, set: function(_){
  1.6428 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.6429 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.6430 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.6431 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.6432 +        }},
  1.6433 +        duration: {get: function(){return duration;}, set: function(_){
  1.6434 +            duration = _;
  1.6435 +            renderWatch.reset(duration);
  1.6436 +            lines.duration(duration);
  1.6437 +            xAxis.duration(duration);
  1.6438 +            yAxis.duration(duration);
  1.6439 +        }},
  1.6440 +        color:  {get: function(){return color;}, set: function(_){
  1.6441 +            color = nv.utils.getColor(_);
  1.6442 +            legend.color(color);
  1.6443 +            lines.color(color);
  1.6444 +        }},
  1.6445 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
  1.6446 +            rightAlignYAxis = _;
  1.6447 +            yAxis.orient( rightAlignYAxis ? 'right' : 'left');
  1.6448 +        }},
  1.6449 +        useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
  1.6450 +            useInteractiveGuideline = _;
  1.6451 +            if (useInteractiveGuideline) {
  1.6452 +                lines.interactive(false);
  1.6453 +                lines.useVoronoi(false);
  1.6454 +            }
  1.6455 +        }}
  1.6456 +    });
  1.6457 +
  1.6458 +    nv.utils.inheritOptions(chart, lines);
  1.6459 +    nv.utils.initOptions(chart);
  1.6460 +
  1.6461 +    return chart;
  1.6462 +};
  1.6463 +nv.models.linePlusBarChart = function() {
  1.6464 +    "use strict";
  1.6465 +
  1.6466 +    //============================================================
  1.6467 +    // Public Variables with Default Settings
  1.6468 +    //------------------------------------------------------------
  1.6469 +
  1.6470 +    var lines = nv.models.line()
  1.6471 +        , lines2 = nv.models.line()
  1.6472 +        , bars = nv.models.historicalBar()
  1.6473 +        , bars2 = nv.models.historicalBar()
  1.6474 +        , xAxis = nv.models.axis()
  1.6475 +        , x2Axis = nv.models.axis()
  1.6476 +        , y1Axis = nv.models.axis()
  1.6477 +        , y2Axis = nv.models.axis()
  1.6478 +        , y3Axis = nv.models.axis()
  1.6479 +        , y4Axis = nv.models.axis()
  1.6480 +        , legend = nv.models.legend()
  1.6481 +        , brush = d3.svg.brush()
  1.6482 +        , tooltip = nv.models.tooltip()
  1.6483 +        ;
  1.6484 +
  1.6485 +    var margin = {top: 30, right: 30, bottom: 30, left: 60}
  1.6486 +        , margin2 = {top: 0, right: 30, bottom: 20, left: 60}
  1.6487 +        , width = null
  1.6488 +        , height = null
  1.6489 +        , getX = function(d) { return d.x }
  1.6490 +        , getY = function(d) { return d.y }
  1.6491 +        , color = nv.utils.defaultColor()
  1.6492 +        , showLegend = true
  1.6493 +        , focusEnable = true
  1.6494 +        , focusShowAxisY = false
  1.6495 +        , focusShowAxisX = true
  1.6496 +        , focusHeight = 50
  1.6497 +        , extent
  1.6498 +        , brushExtent = null
  1.6499 +        , x
  1.6500 +        , x2
  1.6501 +        , y1
  1.6502 +        , y2
  1.6503 +        , y3
  1.6504 +        , y4
  1.6505 +        , noData = null
  1.6506 +        , dispatch = d3.dispatch('brush', 'stateChange', 'changeState')
  1.6507 +        , transitionDuration = 0
  1.6508 +        , state = nv.utils.state()
  1.6509 +        , defaultState = null
  1.6510 +        , legendLeftAxisHint = ' (left axis)'
  1.6511 +        , legendRightAxisHint = ' (right axis)'
  1.6512 +        ;
  1.6513 +
  1.6514 +    lines.clipEdge(true);
  1.6515 +    lines2.interactive(false);
  1.6516 +    xAxis.orient('bottom').tickPadding(5);
  1.6517 +    y1Axis.orient('left');
  1.6518 +    y2Axis.orient('right');
  1.6519 +    x2Axis.orient('bottom').tickPadding(5);
  1.6520 +    y3Axis.orient('left');
  1.6521 +    y4Axis.orient('right');
  1.6522 +
  1.6523 +    tooltip.headerEnabled(true).headerFormatter(function(d, i) {
  1.6524 +        return xAxis.tickFormat()(d, i);
  1.6525 +    });
  1.6526 +
  1.6527 +    //============================================================
  1.6528 +    // Private Variables
  1.6529 +    //------------------------------------------------------------
  1.6530 +
  1.6531 +    var stateGetter = function(data) {
  1.6532 +        return function(){
  1.6533 +            return {
  1.6534 +                active: data.map(function(d) { return !d.disabled })
  1.6535 +            };
  1.6536 +        }
  1.6537 +    };
  1.6538 +
  1.6539 +    var stateSetter = function(data) {
  1.6540 +        return function(state) {
  1.6541 +            if (state.active !== undefined)
  1.6542 +                data.forEach(function(series,i) {
  1.6543 +                    series.disabled = !state.active[i];
  1.6544 +                });
  1.6545 +        }
  1.6546 +    };
  1.6547 +
  1.6548 +    function chart(selection) {
  1.6549 +        selection.each(function(data) {
  1.6550 +            var container = d3.select(this),
  1.6551 +                that = this;
  1.6552 +            nv.utils.initSVG(container);
  1.6553 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.6554 +                availableHeight1 = nv.utils.availableHeight(height, container, margin)
  1.6555 +                    - (focusEnable ? focusHeight : 0),
  1.6556 +                availableHeight2 = focusHeight - margin2.top - margin2.bottom;
  1.6557 +
  1.6558 +            chart.update = function() { container.transition().duration(transitionDuration).call(chart); };
  1.6559 +            chart.container = this;
  1.6560 +
  1.6561 +            state
  1.6562 +                .setter(stateSetter(data), chart.update)
  1.6563 +                .getter(stateGetter(data))
  1.6564 +                .update();
  1.6565 +
  1.6566 +            // DEPRECATED set state.disableddisabled
  1.6567 +            state.disabled = data.map(function(d) { return !!d.disabled });
  1.6568 +
  1.6569 +            if (!defaultState) {
  1.6570 +                var key;
  1.6571 +                defaultState = {};
  1.6572 +                for (key in state) {
  1.6573 +                    if (state[key] instanceof Array)
  1.6574 +                        defaultState[key] = state[key].slice(0);
  1.6575 +                    else
  1.6576 +                        defaultState[key] = state[key];
  1.6577 +                }
  1.6578 +            }
  1.6579 +
  1.6580 +            // Display No Data message if there's nothing to show.
  1.6581 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.6582 +                nv.utils.noData(chart, container)
  1.6583 +                return chart;
  1.6584 +            } else {
  1.6585 +                container.selectAll('.nv-noData').remove();
  1.6586 +            }
  1.6587 +
  1.6588 +            // Setup Scales
  1.6589 +            var dataBars = data.filter(function(d) { return !d.disabled && d.bar });
  1.6590 +            var dataLines = data.filter(function(d) { return !d.bar }); // removed the !d.disabled clause here to fix Issue #240
  1.6591 +
  1.6592 +            x = bars.xScale();
  1.6593 +            x2 = x2Axis.scale();
  1.6594 +            y1 = bars.yScale();
  1.6595 +            y2 = lines.yScale();
  1.6596 +            y3 = bars2.yScale();
  1.6597 +            y4 = lines2.yScale();
  1.6598 +
  1.6599 +            var series1 = data
  1.6600 +                .filter(function(d) { return !d.disabled && d.bar })
  1.6601 +                .map(function(d) {
  1.6602 +                    return d.values.map(function(d,i) {
  1.6603 +                        return { x: getX(d,i), y: getY(d,i) }
  1.6604 +                    })
  1.6605 +                });
  1.6606 +
  1.6607 +            var series2 = data
  1.6608 +                .filter(function(d) { return !d.disabled && !d.bar })
  1.6609 +                .map(function(d) {
  1.6610 +                    return d.values.map(function(d,i) {
  1.6611 +                        return { x: getX(d,i), y: getY(d,i) }
  1.6612 +                    })
  1.6613 +                });
  1.6614 +
  1.6615 +            x.range([0, availableWidth]);
  1.6616 +
  1.6617 +            x2  .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } ))
  1.6618 +                .range([0, availableWidth]);
  1.6619 +
  1.6620 +            // Setup containers and skeleton of chart
  1.6621 +            var wrap = container.selectAll('g.nv-wrap.nv-linePlusBar').data([data]);
  1.6622 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-linePlusBar').append('g');
  1.6623 +            var g = wrap.select('g');
  1.6624 +
  1.6625 +            gEnter.append('g').attr('class', 'nv-legendWrap');
  1.6626 +
  1.6627 +            // this is the main chart
  1.6628 +            var focusEnter = gEnter.append('g').attr('class', 'nv-focus');
  1.6629 +            focusEnter.append('g').attr('class', 'nv-x nv-axis');
  1.6630 +            focusEnter.append('g').attr('class', 'nv-y1 nv-axis');
  1.6631 +            focusEnter.append('g').attr('class', 'nv-y2 nv-axis');
  1.6632 +            focusEnter.append('g').attr('class', 'nv-barsWrap');
  1.6633 +            focusEnter.append('g').attr('class', 'nv-linesWrap');
  1.6634 +
  1.6635 +            // context chart is where you can focus in
  1.6636 +            var contextEnter = gEnter.append('g').attr('class', 'nv-context');
  1.6637 +            contextEnter.append('g').attr('class', 'nv-x nv-axis');
  1.6638 +            contextEnter.append('g').attr('class', 'nv-y1 nv-axis');
  1.6639 +            contextEnter.append('g').attr('class', 'nv-y2 nv-axis');
  1.6640 +            contextEnter.append('g').attr('class', 'nv-barsWrap');
  1.6641 +            contextEnter.append('g').attr('class', 'nv-linesWrap');
  1.6642 +            contextEnter.append('g').attr('class', 'nv-brushBackground');
  1.6643 +            contextEnter.append('g').attr('class', 'nv-x nv-brush');
  1.6644 +
  1.6645 +            //============================================================
  1.6646 +            // Legend
  1.6647 +            //------------------------------------------------------------
  1.6648 +
  1.6649 +            if (showLegend) {
  1.6650 +                var legendWidth = legend.align() ? availableWidth / 2 : availableWidth;
  1.6651 +                var legendXPosition = legend.align() ? legendWidth : 0;
  1.6652 +
  1.6653 +                legend.width(legendWidth);
  1.6654 +
  1.6655 +                g.select('.nv-legendWrap')
  1.6656 +                    .datum(data.map(function(series) {
  1.6657 +                        series.originalKey = series.originalKey === undefined ? series.key : series.originalKey;
  1.6658 +                        series.key = series.originalKey + (series.bar ? legendLeftAxisHint : legendRightAxisHint);
  1.6659 +                        return series;
  1.6660 +                    }))
  1.6661 +                    .call(legend);
  1.6662 +
  1.6663 +                if ( margin.top != legend.height()) {
  1.6664 +                    margin.top = legend.height();
  1.6665 +                    // FIXME: shouldn't this be "- (focusEnabled ? focusHeight : 0)"?
  1.6666 +                    availableHeight1 = nv.utils.availableHeight(height, container, margin) - focusHeight;
  1.6667 +                }
  1.6668 +
  1.6669 +                g.select('.nv-legendWrap')
  1.6670 +                    .attr('transform', 'translate(' + legendXPosition + ',' + (-margin.top) +')');
  1.6671 +            }
  1.6672 +
  1.6673 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.6674 +
  1.6675 +            //============================================================
  1.6676 +            // Context chart (focus chart) components
  1.6677 +            //------------------------------------------------------------
  1.6678 +
  1.6679 +            // hide or show the focus context chart
  1.6680 +            g.select('.nv-context').style('display', focusEnable ? 'initial' : 'none');
  1.6681 +
  1.6682 +            bars2
  1.6683 +                .width(availableWidth)
  1.6684 +                .height(availableHeight2)
  1.6685 +                .color(data.map(function (d, i) {
  1.6686 +                    return d.color || color(d, i);
  1.6687 +                }).filter(function (d, i) {
  1.6688 +                    return !data[i].disabled && data[i].bar
  1.6689 +                }));
  1.6690 +            lines2
  1.6691 +                .width(availableWidth)
  1.6692 +                .height(availableHeight2)
  1.6693 +                .color(data.map(function (d, i) {
  1.6694 +                    return d.color || color(d, i);
  1.6695 +                }).filter(function (d, i) {
  1.6696 +                    return !data[i].disabled && !data[i].bar
  1.6697 +                }));
  1.6698 +
  1.6699 +            var bars2Wrap = g.select('.nv-context .nv-barsWrap')
  1.6700 +                .datum(dataBars.length ? dataBars : [
  1.6701 +                    {values: []}
  1.6702 +                ]);
  1.6703 +            var lines2Wrap = g.select('.nv-context .nv-linesWrap')
  1.6704 +                .datum(!dataLines[0].disabled ? dataLines : [
  1.6705 +                    {values: []}
  1.6706 +                ]);
  1.6707 +
  1.6708 +            g.select('.nv-context')
  1.6709 +                .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')');
  1.6710 +
  1.6711 +            bars2Wrap.transition().call(bars2);
  1.6712 +            lines2Wrap.transition().call(lines2);
  1.6713 +
  1.6714 +            // context (focus chart) axis controls
  1.6715 +            if (focusShowAxisX) {
  1.6716 +                x2Axis
  1.6717 +                    ._ticks( nv.utils.calcTicksX(availableWidth / 100, data))
  1.6718 +                    .tickSize(-availableHeight2, 0);
  1.6719 +                g.select('.nv-context .nv-x.nv-axis')
  1.6720 +                    .attr('transform', 'translate(0,' + y3.range()[0] + ')');
  1.6721 +                g.select('.nv-context .nv-x.nv-axis').transition()
  1.6722 +                    .call(x2Axis);
  1.6723 +            }
  1.6724 +
  1.6725 +            if (focusShowAxisY) {
  1.6726 +                y3Axis
  1.6727 +                    .scale(y3)
  1.6728 +                    ._ticks( availableHeight2 / 36 )
  1.6729 +                    .tickSize( -availableWidth, 0);
  1.6730 +                y4Axis
  1.6731 +                    .scale(y4)
  1.6732 +                    ._ticks( availableHeight2 / 36 )
  1.6733 +                    .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none
  1.6734 +
  1.6735 +                g.select('.nv-context .nv-y3.nv-axis')
  1.6736 +                    .style('opacity', dataBars.length ? 1 : 0)
  1.6737 +                    .attr('transform', 'translate(0,' + x2.range()[0] + ')');
  1.6738 +                g.select('.nv-context .nv-y2.nv-axis')
  1.6739 +                    .style('opacity', dataLines.length ? 1 : 0)
  1.6740 +                    .attr('transform', 'translate(' + x2.range()[1] + ',0)');
  1.6741 +
  1.6742 +                g.select('.nv-context .nv-y1.nv-axis').transition()
  1.6743 +                    .call(y3Axis);
  1.6744 +                g.select('.nv-context .nv-y2.nv-axis').transition()
  1.6745 +                    .call(y4Axis);
  1.6746 +            }
  1.6747 +
  1.6748 +            // Setup Brush
  1.6749 +            brush.x(x2).on('brush', onBrush);
  1.6750 +
  1.6751 +            if (brushExtent) brush.extent(brushExtent);
  1.6752 +
  1.6753 +            var brushBG = g.select('.nv-brushBackground').selectAll('g')
  1.6754 +                .data([brushExtent || brush.extent()]);
  1.6755 +
  1.6756 +            var brushBGenter = brushBG.enter()
  1.6757 +                .append('g');
  1.6758 +
  1.6759 +            brushBGenter.append('rect')
  1.6760 +                .attr('class', 'left')
  1.6761 +                .attr('x', 0)
  1.6762 +                .attr('y', 0)
  1.6763 +                .attr('height', availableHeight2);
  1.6764 +
  1.6765 +            brushBGenter.append('rect')
  1.6766 +                .attr('class', 'right')
  1.6767 +                .attr('x', 0)
  1.6768 +                .attr('y', 0)
  1.6769 +                .attr('height', availableHeight2);
  1.6770 +
  1.6771 +            var gBrush = g.select('.nv-x.nv-brush')
  1.6772 +                .call(brush);
  1.6773 +            gBrush.selectAll('rect')
  1.6774 +                //.attr('y', -5)
  1.6775 +                .attr('height', availableHeight2);
  1.6776 +            gBrush.selectAll('.resize').append('path').attr('d', resizePath);
  1.6777 +
  1.6778 +            //============================================================
  1.6779 +            // Event Handling/Dispatching (in chart's scope)
  1.6780 +            //------------------------------------------------------------
  1.6781 +
  1.6782 +            legend.dispatch.on('stateChange', function(newState) {
  1.6783 +                for (var key in newState)
  1.6784 +                    state[key] = newState[key];
  1.6785 +                dispatch.stateChange(state);
  1.6786 +                chart.update();
  1.6787 +            });
  1.6788 +
  1.6789 +            // Update chart from a state object passed to event handler
  1.6790 +            dispatch.on('changeState', function(e) {
  1.6791 +                if (typeof e.disabled !== 'undefined') {
  1.6792 +                    data.forEach(function(series,i) {
  1.6793 +                        series.disabled = e.disabled[i];
  1.6794 +                    });
  1.6795 +                    state.disabled = e.disabled;
  1.6796 +                }
  1.6797 +                chart.update();
  1.6798 +            });
  1.6799 +
  1.6800 +            //============================================================
  1.6801 +            // Functions
  1.6802 +            //------------------------------------------------------------
  1.6803 +
  1.6804 +            // Taken from crossfilter (http://square.github.com/crossfilter/)
  1.6805 +            function resizePath(d) {
  1.6806 +                var e = +(d == 'e'),
  1.6807 +                    x = e ? 1 : -1,
  1.6808 +                    y = availableHeight2 / 3;
  1.6809 +                return 'M' + (.5 * x) + ',' + y
  1.6810 +                    + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
  1.6811 +                    + 'V' + (2 * y - 6)
  1.6812 +                    + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y)
  1.6813 +                    + 'Z'
  1.6814 +                    + 'M' + (2.5 * x) + ',' + (y + 8)
  1.6815 +                    + 'V' + (2 * y - 8)
  1.6816 +                    + 'M' + (4.5 * x) + ',' + (y + 8)
  1.6817 +                    + 'V' + (2 * y - 8);
  1.6818 +            }
  1.6819 +
  1.6820 +
  1.6821 +            function updateBrushBG() {
  1.6822 +                if (!brush.empty()) brush.extent(brushExtent);
  1.6823 +                brushBG
  1.6824 +                    .data([brush.empty() ? x2.domain() : brushExtent])
  1.6825 +                    .each(function(d,i) {
  1.6826 +                        var leftWidth = x2(d[0]) - x2.range()[0],
  1.6827 +                            rightWidth = x2.range()[1] - x2(d[1]);
  1.6828 +                        d3.select(this).select('.left')
  1.6829 +                            .attr('width',  leftWidth < 0 ? 0 : leftWidth);
  1.6830 +
  1.6831 +                        d3.select(this).select('.right')
  1.6832 +                            .attr('x', x2(d[1]))
  1.6833 +                            .attr('width', rightWidth < 0 ? 0 : rightWidth);
  1.6834 +                    });
  1.6835 +            }
  1.6836 +
  1.6837 +            function onBrush() {
  1.6838 +                brushExtent = brush.empty() ? null : brush.extent();
  1.6839 +                extent = brush.empty() ? x2.domain() : brush.extent();
  1.6840 +                dispatch.brush({extent: extent, brush: brush});
  1.6841 +                updateBrushBG();
  1.6842 +
  1.6843 +                // Prepare Main (Focus) Bars and Lines
  1.6844 +                bars
  1.6845 +                    .width(availableWidth)
  1.6846 +                    .height(availableHeight1)
  1.6847 +                    .color(data.map(function(d,i) {
  1.6848 +                        return d.color || color(d, i);
  1.6849 +                    }).filter(function(d,i) { return !data[i].disabled && data[i].bar }));
  1.6850 +
  1.6851 +                lines
  1.6852 +                    .width(availableWidth)
  1.6853 +                    .height(availableHeight1)
  1.6854 +                    .color(data.map(function(d,i) {
  1.6855 +                        return d.color || color(d, i);
  1.6856 +                    }).filter(function(d,i) { return !data[i].disabled && !data[i].bar }));
  1.6857 +
  1.6858 +                var focusBarsWrap = g.select('.nv-focus .nv-barsWrap')
  1.6859 +                    .datum(!dataBars.length ? [{values:[]}] :
  1.6860 +                        dataBars
  1.6861 +                            .map(function(d,i) {
  1.6862 +                                return {
  1.6863 +                                    key: d.key,
  1.6864 +                                    values: d.values.filter(function(d,i) {
  1.6865 +                                        return bars.x()(d,i) >= extent[0] && bars.x()(d,i) <= extent[1];
  1.6866 +                                    })
  1.6867 +                                }
  1.6868 +                            })
  1.6869 +                );
  1.6870 +
  1.6871 +                var focusLinesWrap = g.select('.nv-focus .nv-linesWrap')
  1.6872 +                    .datum(dataLines[0].disabled ? [{values:[]}] :
  1.6873 +                        dataLines
  1.6874 +                            .map(function(d,i) {
  1.6875 +                                return {
  1.6876 +                                    area: d.area,
  1.6877 +                                    fillOpacity: d.fillOpacity,
  1.6878 +                                    key: d.key,
  1.6879 +                                    values: d.values.filter(function(d,i) {
  1.6880 +                                        return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1];
  1.6881 +                                    })
  1.6882 +                                }
  1.6883 +                            })
  1.6884 +                );
  1.6885 +
  1.6886 +                // Update Main (Focus) X Axis
  1.6887 +                if (dataBars.length) {
  1.6888 +                    x = bars.xScale();
  1.6889 +                } else {
  1.6890 +                    x = lines.xScale();
  1.6891 +                }
  1.6892 +
  1.6893 +                xAxis
  1.6894 +                    .scale(x)
  1.6895 +                    ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.6896 +                    .tickSize(-availableHeight1, 0);
  1.6897 +
  1.6898 +                xAxis.domain([Math.ceil(extent[0]), Math.floor(extent[1])]);
  1.6899 +
  1.6900 +                g.select('.nv-x.nv-axis').transition().duration(transitionDuration)
  1.6901 +                    .call(xAxis);
  1.6902 +
  1.6903 +                // Update Main (Focus) Bars and Lines
  1.6904 +                focusBarsWrap.transition().duration(transitionDuration).call(bars);
  1.6905 +                focusLinesWrap.transition().duration(transitionDuration).call(lines);
  1.6906 +
  1.6907 +                // Setup and Update Main (Focus) Y Axes
  1.6908 +                g.select('.nv-focus .nv-x.nv-axis')
  1.6909 +                    .attr('transform', 'translate(0,' + y1.range()[0] + ')');
  1.6910 +
  1.6911 +                y1Axis
  1.6912 +                    .scale(y1)
  1.6913 +                    ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) )
  1.6914 +                    .tickSize(-availableWidth, 0);
  1.6915 +                y2Axis
  1.6916 +                    .scale(y2)
  1.6917 +                    ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) )
  1.6918 +                    .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none
  1.6919 +
  1.6920 +                g.select('.nv-focus .nv-y1.nv-axis')
  1.6921 +                    .style('opacity', dataBars.length ? 1 : 0);
  1.6922 +                g.select('.nv-focus .nv-y2.nv-axis')
  1.6923 +                    .style('opacity', dataLines.length && !dataLines[0].disabled ? 1 : 0)
  1.6924 +                    .attr('transform', 'translate(' + x.range()[1] + ',0)');
  1.6925 +
  1.6926 +                g.select('.nv-focus .nv-y1.nv-axis').transition().duration(transitionDuration)
  1.6927 +                    .call(y1Axis);
  1.6928 +                g.select('.nv-focus .nv-y2.nv-axis').transition().duration(transitionDuration)
  1.6929 +                    .call(y2Axis);
  1.6930 +            }
  1.6931 +
  1.6932 +            onBrush();
  1.6933 +
  1.6934 +        });
  1.6935 +
  1.6936 +        return chart;
  1.6937 +    }
  1.6938 +
  1.6939 +    //============================================================
  1.6940 +    // Event Handling/Dispatching (out of chart's scope)
  1.6941 +    //------------------------------------------------------------
  1.6942 +
  1.6943 +    lines.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.6944 +        tooltip
  1.6945 +            .duration(100)
  1.6946 +            .valueFormatter(function(d, i) {
  1.6947 +                return y2Axis.tickFormat()(d, i);
  1.6948 +            })
  1.6949 +            .data(evt)
  1.6950 +            .position(evt.pos)
  1.6951 +            .hidden(false);
  1.6952 +    });
  1.6953 +
  1.6954 +    lines.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.6955 +        tooltip.hidden(true)
  1.6956 +    });
  1.6957 +
  1.6958 +    bars.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.6959 +        evt.value = chart.x()(evt.data);
  1.6960 +        evt['series'] = {
  1.6961 +            value: chart.y()(evt.data),
  1.6962 +            color: evt.color
  1.6963 +        };
  1.6964 +        tooltip
  1.6965 +            .duration(0)
  1.6966 +            .valueFormatter(function(d, i) {
  1.6967 +                return y1Axis.tickFormat()(d, i);
  1.6968 +            })
  1.6969 +            .data(evt)
  1.6970 +            .hidden(false);
  1.6971 +    });
  1.6972 +
  1.6973 +    bars.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.6974 +        tooltip.hidden(true);
  1.6975 +    });
  1.6976 +
  1.6977 +    bars.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.6978 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.6979 +    });
  1.6980 +
  1.6981 +    //============================================================
  1.6982 +
  1.6983 +
  1.6984 +    //============================================================
  1.6985 +    // Expose Public Variables
  1.6986 +    //------------------------------------------------------------
  1.6987 +
  1.6988 +    // expose chart's sub-components
  1.6989 +    chart.dispatch = dispatch;
  1.6990 +    chart.legend = legend;
  1.6991 +    chart.lines = lines;
  1.6992 +    chart.lines2 = lines2;
  1.6993 +    chart.bars = bars;
  1.6994 +    chart.bars2 = bars2;
  1.6995 +    chart.xAxis = xAxis;
  1.6996 +    chart.x2Axis = x2Axis;
  1.6997 +    chart.y1Axis = y1Axis;
  1.6998 +    chart.y2Axis = y2Axis;
  1.6999 +    chart.y3Axis = y3Axis;
  1.7000 +    chart.y4Axis = y4Axis;
  1.7001 +    chart.tooltip = tooltip;
  1.7002 +
  1.7003 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.7004 +
  1.7005 +    chart._options = Object.create({}, {
  1.7006 +        // simple options, just get/set the necessary values
  1.7007 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.7008 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.7009 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.7010 +        brushExtent:    {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}},
  1.7011 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.7012 +        focusEnable:    {get: function(){return focusEnable;}, set: function(_){focusEnable=_;}},
  1.7013 +        focusHeight:    {get: function(){return focusHeight;}, set: function(_){focusHeight=_;}},
  1.7014 +        focusShowAxisX:    {get: function(){return focusShowAxisX;}, set: function(_){focusShowAxisX=_;}},
  1.7015 +        focusShowAxisY:    {get: function(){return focusShowAxisY;}, set: function(_){focusShowAxisY=_;}},
  1.7016 +        legendLeftAxisHint:    {get: function(){return legendLeftAxisHint;}, set: function(_){legendLeftAxisHint=_;}},
  1.7017 +        legendRightAxisHint:    {get: function(){return legendRightAxisHint;}, set: function(_){legendRightAxisHint=_;}},
  1.7018 +
  1.7019 +        // deprecated options
  1.7020 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.7021 +            // deprecated after 1.7.1
  1.7022 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.7023 +            tooltip.enabled(!!_);
  1.7024 +        }},
  1.7025 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.7026 +            // deprecated after 1.7.1
  1.7027 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.7028 +            tooltip.contentGenerator(_);
  1.7029 +        }},
  1.7030 +
  1.7031 +        // options that require extra logic in the setter
  1.7032 +        margin: {get: function(){return margin;}, set: function(_){
  1.7033 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.7034 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.7035 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.7036 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.7037 +        }},
  1.7038 +        duration: {get: function(){return transitionDuration;}, set: function(_){
  1.7039 +            transitionDuration = _;
  1.7040 +        }},
  1.7041 +        color:  {get: function(){return color;}, set: function(_){
  1.7042 +            color = nv.utils.getColor(_);
  1.7043 +            legend.color(color);
  1.7044 +        }},
  1.7045 +        x: {get: function(){return getX;}, set: function(_){
  1.7046 +            getX = _;
  1.7047 +            lines.x(_);
  1.7048 +            lines2.x(_);
  1.7049 +            bars.x(_);
  1.7050 +            bars2.x(_);
  1.7051 +        }},
  1.7052 +        y: {get: function(){return getY;}, set: function(_){
  1.7053 +            getY = _;
  1.7054 +            lines.y(_);
  1.7055 +            lines2.y(_);
  1.7056 +            bars.y(_);
  1.7057 +            bars2.y(_);
  1.7058 +        }}
  1.7059 +    });
  1.7060 +
  1.7061 +    nv.utils.inheritOptions(chart, lines);
  1.7062 +    nv.utils.initOptions(chart);
  1.7063 +
  1.7064 +    return chart;
  1.7065 +};
  1.7066 +nv.models.lineWithFocusChart = function() {
  1.7067 +    "use strict";
  1.7068 +
  1.7069 +    //============================================================
  1.7070 +    // Public Variables with Default Settings
  1.7071 +    //------------------------------------------------------------
  1.7072 +
  1.7073 +    var lines = nv.models.line()
  1.7074 +        , lines2 = nv.models.line()
  1.7075 +        , xAxis = nv.models.axis()
  1.7076 +        , yAxis = nv.models.axis()
  1.7077 +        , x2Axis = nv.models.axis()
  1.7078 +        , y2Axis = nv.models.axis()
  1.7079 +        , legend = nv.models.legend()
  1.7080 +        , brush = d3.svg.brush()
  1.7081 +        , tooltip = nv.models.tooltip()
  1.7082 +        , interactiveLayer = nv.interactiveGuideline()
  1.7083 +        ;
  1.7084 +
  1.7085 +    var margin = {top: 30, right: 30, bottom: 30, left: 60}
  1.7086 +        , margin2 = {top: 0, right: 30, bottom: 20, left: 60}
  1.7087 +        , color = nv.utils.defaultColor()
  1.7088 +        , width = null
  1.7089 +        , height = null
  1.7090 +        , height2 = 50
  1.7091 +        , useInteractiveGuideline = false
  1.7092 +        , x
  1.7093 +        , y
  1.7094 +        , x2
  1.7095 +        , y2
  1.7096 +        , showLegend = true
  1.7097 +        , brushExtent = null
  1.7098 +        , noData = null
  1.7099 +        , dispatch = d3.dispatch('brush', 'stateChange', 'changeState')
  1.7100 +        , transitionDuration = 250
  1.7101 +        , state = nv.utils.state()
  1.7102 +        , defaultState = null
  1.7103 +        ;
  1.7104 +
  1.7105 +    lines.clipEdge(true).duration(0);
  1.7106 +    lines2.interactive(false);
  1.7107 +    xAxis.orient('bottom').tickPadding(5);
  1.7108 +    yAxis.orient('left');
  1.7109 +    x2Axis.orient('bottom').tickPadding(5);
  1.7110 +    y2Axis.orient('left');
  1.7111 +
  1.7112 +    tooltip.valueFormatter(function(d, i) {
  1.7113 +        return yAxis.tickFormat()(d, i);
  1.7114 +    }).headerFormatter(function(d, i) {
  1.7115 +        return xAxis.tickFormat()(d, i);
  1.7116 +    });
  1.7117 +
  1.7118 +    //============================================================
  1.7119 +    // Private Variables
  1.7120 +    //------------------------------------------------------------
  1.7121 +
  1.7122 +    var stateGetter = function(data) {
  1.7123 +        return function(){
  1.7124 +            return {
  1.7125 +                active: data.map(function(d) { return !d.disabled })
  1.7126 +            };
  1.7127 +        }
  1.7128 +    };
  1.7129 +
  1.7130 +    var stateSetter = function(data) {
  1.7131 +        return function(state) {
  1.7132 +            if (state.active !== undefined)
  1.7133 +                data.forEach(function(series,i) {
  1.7134 +                    series.disabled = !state.active[i];
  1.7135 +                });
  1.7136 +        }
  1.7137 +    };
  1.7138 +
  1.7139 +    function chart(selection) {
  1.7140 +        selection.each(function(data) {
  1.7141 +            var container = d3.select(this),
  1.7142 +                that = this;
  1.7143 +            nv.utils.initSVG(container);
  1.7144 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.7145 +                availableHeight1 = nv.utils.availableHeight(height, container, margin) - height2,
  1.7146 +                availableHeight2 = height2 - margin2.top - margin2.bottom;
  1.7147 +
  1.7148 +            chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
  1.7149 +            chart.container = this;
  1.7150 +
  1.7151 +            state
  1.7152 +                .setter(stateSetter(data), chart.update)
  1.7153 +                .getter(stateGetter(data))
  1.7154 +                .update();
  1.7155 +
  1.7156 +            // DEPRECATED set state.disableddisabled
  1.7157 +            state.disabled = data.map(function(d) { return !!d.disabled });
  1.7158 +
  1.7159 +            if (!defaultState) {
  1.7160 +                var key;
  1.7161 +                defaultState = {};
  1.7162 +                for (key in state) {
  1.7163 +                    if (state[key] instanceof Array)
  1.7164 +                        defaultState[key] = state[key].slice(0);
  1.7165 +                    else
  1.7166 +                        defaultState[key] = state[key];
  1.7167 +                }
  1.7168 +            }
  1.7169 +
  1.7170 +            // Display No Data message if there's nothing to show.
  1.7171 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.7172 +                nv.utils.noData(chart, container)
  1.7173 +                return chart;
  1.7174 +            } else {
  1.7175 +                container.selectAll('.nv-noData').remove();
  1.7176 +            }
  1.7177 +
  1.7178 +            // Setup Scales
  1.7179 +            x = lines.xScale();
  1.7180 +            y = lines.yScale();
  1.7181 +            x2 = lines2.xScale();
  1.7182 +            y2 = lines2.yScale();
  1.7183 +
  1.7184 +            // Setup containers and skeleton of chart
  1.7185 +            var wrap = container.selectAll('g.nv-wrap.nv-lineWithFocusChart').data([data]);
  1.7186 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineWithFocusChart').append('g');
  1.7187 +            var g = wrap.select('g');
  1.7188 +
  1.7189 +            gEnter.append('g').attr('class', 'nv-legendWrap');
  1.7190 +
  1.7191 +            var focusEnter = gEnter.append('g').attr('class', 'nv-focus');
  1.7192 +            focusEnter.append('g').attr('class', 'nv-x nv-axis');
  1.7193 +            focusEnter.append('g').attr('class', 'nv-y nv-axis');
  1.7194 +            focusEnter.append('g').attr('class', 'nv-linesWrap');
  1.7195 +            focusEnter.append('g').attr('class', 'nv-interactive');
  1.7196 +
  1.7197 +            var contextEnter = gEnter.append('g').attr('class', 'nv-context');
  1.7198 +            contextEnter.append('g').attr('class', 'nv-x nv-axis');
  1.7199 +            contextEnter.append('g').attr('class', 'nv-y nv-axis');
  1.7200 +            contextEnter.append('g').attr('class', 'nv-linesWrap');
  1.7201 +            contextEnter.append('g').attr('class', 'nv-brushBackground');
  1.7202 +            contextEnter.append('g').attr('class', 'nv-x nv-brush');
  1.7203 +
  1.7204 +            // Legend
  1.7205 +            if (showLegend) {
  1.7206 +                legend.width(availableWidth);
  1.7207 +
  1.7208 +                g.select('.nv-legendWrap')
  1.7209 +                    .datum(data)
  1.7210 +                    .call(legend);
  1.7211 +
  1.7212 +                if ( margin.top != legend.height()) {
  1.7213 +                    margin.top = legend.height();
  1.7214 +                    availableHeight1 = nv.utils.availableHeight(height, container, margin) - height2;
  1.7215 +                }
  1.7216 +
  1.7217 +                g.select('.nv-legendWrap')
  1.7218 +                    .attr('transform', 'translate(0,' + (-margin.top) +')')
  1.7219 +            }
  1.7220 +
  1.7221 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.7222 +
  1.7223 +            
  1.7224 +            //Set up interactive layer
  1.7225 +            if (useInteractiveGuideline) {
  1.7226 +                interactiveLayer
  1.7227 +                    .width(availableWidth)
  1.7228 +                    .height(availableHeight1)
  1.7229 +                    .margin({left:margin.left, top:margin.top})
  1.7230 +                    .svgContainer(container)
  1.7231 +                    .xScale(x);
  1.7232 +                wrap.select(".nv-interactive").call(interactiveLayer);
  1.7233 +            }
  1.7234 +
  1.7235 +            // Main Chart Component(s)
  1.7236 +            lines
  1.7237 +                .width(availableWidth)
  1.7238 +                .height(availableHeight1)
  1.7239 +                .color(
  1.7240 +                data
  1.7241 +                    .map(function(d,i) {
  1.7242 +                        return d.color || color(d, i);
  1.7243 +                    })
  1.7244 +                    .filter(function(d,i) {
  1.7245 +                        return !data[i].disabled;
  1.7246 +                    })
  1.7247 +            );
  1.7248 +
  1.7249 +            lines2
  1.7250 +                .defined(lines.defined())
  1.7251 +                .width(availableWidth)
  1.7252 +                .height(availableHeight2)
  1.7253 +                .color(
  1.7254 +                data
  1.7255 +                    .map(function(d,i) {
  1.7256 +                        return d.color || color(d, i);
  1.7257 +                    })
  1.7258 +                    .filter(function(d,i) {
  1.7259 +                        return !data[i].disabled;
  1.7260 +                    })
  1.7261 +            );
  1.7262 +
  1.7263 +            g.select('.nv-context')
  1.7264 +                .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')')
  1.7265 +
  1.7266 +            var contextLinesWrap = g.select('.nv-context .nv-linesWrap')
  1.7267 +                .datum(data.filter(function(d) { return !d.disabled }))
  1.7268 +
  1.7269 +            d3.transition(contextLinesWrap).call(lines2);
  1.7270 +
  1.7271 +            // Setup Main (Focus) Axes
  1.7272 +            xAxis
  1.7273 +                .scale(x)
  1.7274 +                ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.7275 +                .tickSize(-availableHeight1, 0);
  1.7276 +
  1.7277 +            yAxis
  1.7278 +                .scale(y)
  1.7279 +                ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) )
  1.7280 +                .tickSize( -availableWidth, 0);
  1.7281 +
  1.7282 +            g.select('.nv-focus .nv-x.nv-axis')
  1.7283 +                .attr('transform', 'translate(0,' + availableHeight1 + ')');
  1.7284 +
  1.7285 +            // Setup Brush
  1.7286 +            brush
  1.7287 +                .x(x2)
  1.7288 +                .on('brush', function() {
  1.7289 +                    onBrush();
  1.7290 +                });
  1.7291 +
  1.7292 +            if (brushExtent) brush.extent(brushExtent);
  1.7293 +
  1.7294 +            var brushBG = g.select('.nv-brushBackground').selectAll('g')
  1.7295 +                .data([brushExtent || brush.extent()])
  1.7296 +
  1.7297 +            var brushBGenter = brushBG.enter()
  1.7298 +                .append('g');
  1.7299 +
  1.7300 +            brushBGenter.append('rect')
  1.7301 +                .attr('class', 'left')
  1.7302 +                .attr('x', 0)
  1.7303 +                .attr('y', 0)
  1.7304 +                .attr('height', availableHeight2);
  1.7305 +
  1.7306 +            brushBGenter.append('rect')
  1.7307 +                .attr('class', 'right')
  1.7308 +                .attr('x', 0)
  1.7309 +                .attr('y', 0)
  1.7310 +                .attr('height', availableHeight2);
  1.7311 +
  1.7312 +            var gBrush = g.select('.nv-x.nv-brush')
  1.7313 +                .call(brush);
  1.7314 +            gBrush.selectAll('rect')
  1.7315 +                .attr('height', availableHeight2);
  1.7316 +            gBrush.selectAll('.resize').append('path').attr('d', resizePath);
  1.7317 +
  1.7318 +            onBrush();
  1.7319 +
  1.7320 +            // Setup Secondary (Context) Axes
  1.7321 +            x2Axis
  1.7322 +                .scale(x2)
  1.7323 +                ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.7324 +                .tickSize(-availableHeight2, 0);
  1.7325 +
  1.7326 +            g.select('.nv-context .nv-x.nv-axis')
  1.7327 +                .attr('transform', 'translate(0,' + y2.range()[0] + ')');
  1.7328 +            d3.transition(g.select('.nv-context .nv-x.nv-axis'))
  1.7329 +                .call(x2Axis);
  1.7330 +
  1.7331 +            y2Axis
  1.7332 +                .scale(y2)
  1.7333 +                ._ticks( nv.utils.calcTicksY(availableHeight2/36, data) )
  1.7334 +                .tickSize( -availableWidth, 0);
  1.7335 +
  1.7336 +            d3.transition(g.select('.nv-context .nv-y.nv-axis'))
  1.7337 +                .call(y2Axis);
  1.7338 +
  1.7339 +            g.select('.nv-context .nv-x.nv-axis')
  1.7340 +                .attr('transform', 'translate(0,' + y2.range()[0] + ')');
  1.7341 +
  1.7342 +            //============================================================
  1.7343 +            // Event Handling/Dispatching (in chart's scope)
  1.7344 +            //------------------------------------------------------------
  1.7345 +
  1.7346 +            legend.dispatch.on('stateChange', function(newState) {
  1.7347 +                for (var key in newState)
  1.7348 +                    state[key] = newState[key];
  1.7349 +                dispatch.stateChange(state);
  1.7350 +                chart.update();
  1.7351 +            });
  1.7352 +
  1.7353 +            interactiveLayer.dispatch.on('elementMousemove', function(e) {
  1.7354 +                lines.clearHighlights();
  1.7355 +                var singlePoint, pointIndex, pointXLocation, allData = [];
  1.7356 +                data
  1.7357 +                    .filter(function(series, i) {
  1.7358 +                        series.seriesIndex = i;
  1.7359 +                        return !series.disabled;
  1.7360 +                    })
  1.7361 +                    .forEach(function(series,i) {
  1.7362 +                            var extent = brush.empty() ? x2.domain() : brush.extent();
  1.7363 +                            var currentValues = series.values.filter(function(d,i) {
  1.7364 +                            return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1];
  1.7365 +                        });
  1.7366 + 
  1.7367 +                        pointIndex = nv.interactiveBisect(currentValues, e.pointXValue, lines.x());
  1.7368 +                        var point = currentValues[pointIndex];
  1.7369 +                        var pointYValue = chart.y()(point, pointIndex);
  1.7370 +                        if (pointYValue != null) {
  1.7371 +                            lines.highlightPoint(i, pointIndex, true);
  1.7372 +                        }
  1.7373 +                        if (point === undefined) return;
  1.7374 +                        if (singlePoint === undefined) singlePoint = point;
  1.7375 +                        if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
  1.7376 +                        allData.push({
  1.7377 +                            key: series.key,
  1.7378 +                            value: chart.y()(point, pointIndex),
  1.7379 +                            color: color(series,series.seriesIndex)
  1.7380 +                        });
  1.7381 +                    });
  1.7382 +                //Highlight the tooltip entry based on which point the mouse is closest to.
  1.7383 +                if (allData.length > 2) {
  1.7384 +                    var yValue = chart.yScale().invert(e.mouseY);
  1.7385 +                    var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
  1.7386 +                    var threshold = 0.03 * domainExtent;
  1.7387 +                    var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold);
  1.7388 +                    if (indexToHighlight !== null)
  1.7389 +                        allData[indexToHighlight].highlight = true;
  1.7390 +                }
  1.7391 +
  1.7392 +                var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
  1.7393 +                interactiveLayer.tooltip
  1.7394 +                    .position({left: e.mouseX + margin.left, top: e.mouseY + margin.top})
  1.7395 +                    .chartContainer(that.parentNode)
  1.7396 +                    .valueFormatter(function(d,i) {
  1.7397 +                        return d == null ? "N/A" : yAxis.tickFormat()(d);
  1.7398 +                    })
  1.7399 +                    .data({
  1.7400 +                        value: xValue,
  1.7401 +                        index: pointIndex,
  1.7402 +                        series: allData
  1.7403 +                    })();
  1.7404 +
  1.7405 +                interactiveLayer.renderGuideLine(pointXLocation);
  1.7406 +
  1.7407 +            });
  1.7408 +
  1.7409 +            interactiveLayer.dispatch.on("elementMouseout",function(e) {
  1.7410 +                lines.clearHighlights();
  1.7411 +            });
  1.7412 +
  1.7413 +            dispatch.on('changeState', function(e) {
  1.7414 +                if (typeof e.disabled !== 'undefined') {
  1.7415 +                    data.forEach(function(series,i) {
  1.7416 +                        series.disabled = e.disabled[i];
  1.7417 +                    });
  1.7418 +                }
  1.7419 +                chart.update();
  1.7420 +            });
  1.7421 +
  1.7422 +            //============================================================
  1.7423 +            // Functions
  1.7424 +            //------------------------------------------------------------
  1.7425 +
  1.7426 +            // Taken from crossfilter (http://square.github.com/crossfilter/)
  1.7427 +            function resizePath(d) {
  1.7428 +                var e = +(d == 'e'),
  1.7429 +                    x = e ? 1 : -1,
  1.7430 +                    y = availableHeight2 / 3;
  1.7431 +                return 'M' + (.5 * x) + ',' + y
  1.7432 +                    + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
  1.7433 +                    + 'V' + (2 * y - 6)
  1.7434 +                    + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y)
  1.7435 +                    + 'Z'
  1.7436 +                    + 'M' + (2.5 * x) + ',' + (y + 8)
  1.7437 +                    + 'V' + (2 * y - 8)
  1.7438 +                    + 'M' + (4.5 * x) + ',' + (y + 8)
  1.7439 +                    + 'V' + (2 * y - 8);
  1.7440 +            }
  1.7441 +
  1.7442 +
  1.7443 +            function updateBrushBG() {
  1.7444 +                if (!brush.empty()) brush.extent(brushExtent);
  1.7445 +                brushBG
  1.7446 +                    .data([brush.empty() ? x2.domain() : brushExtent])
  1.7447 +                    .each(function(d,i) {
  1.7448 +                        var leftWidth = x2(d[0]) - x.range()[0],
  1.7449 +                            rightWidth = availableWidth - x2(d[1]);
  1.7450 +                        d3.select(this).select('.left')
  1.7451 +                            .attr('width',  leftWidth < 0 ? 0 : leftWidth);
  1.7452 +
  1.7453 +                        d3.select(this).select('.right')
  1.7454 +                            .attr('x', x2(d[1]))
  1.7455 +                            .attr('width', rightWidth < 0 ? 0 : rightWidth);
  1.7456 +                    });
  1.7457 +            }
  1.7458 +
  1.7459 +
  1.7460 +            function onBrush() {
  1.7461 +                brushExtent = brush.empty() ? null : brush.extent();
  1.7462 +                var extent = brush.empty() ? x2.domain() : brush.extent();
  1.7463 +
  1.7464 +                //The brush extent cannot be less than one.  If it is, don't update the line chart.
  1.7465 +                if (Math.abs(extent[0] - extent[1]) <= 1) {
  1.7466 +                    return;
  1.7467 +                }
  1.7468 +
  1.7469 +                dispatch.brush({extent: extent, brush: brush});
  1.7470 +
  1.7471 +
  1.7472 +                updateBrushBG();
  1.7473 +
  1.7474 +                // Update Main (Focus)
  1.7475 +                var focusLinesWrap = g.select('.nv-focus .nv-linesWrap')
  1.7476 +                    .datum(
  1.7477 +                    data
  1.7478 +                        .filter(function(d) { return !d.disabled })
  1.7479 +                        .map(function(d,i) {
  1.7480 +                            return {
  1.7481 +                                key: d.key,
  1.7482 +                                area: d.area,
  1.7483 +                                values: d.values.filter(function(d,i) {
  1.7484 +                                    return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1];
  1.7485 +                                })
  1.7486 +                            }
  1.7487 +                        })
  1.7488 +                );
  1.7489 +                focusLinesWrap.transition().duration(transitionDuration).call(lines);
  1.7490 +
  1.7491 +
  1.7492 +                // Update Main (Focus) Axes
  1.7493 +                g.select('.nv-focus .nv-x.nv-axis').transition().duration(transitionDuration)
  1.7494 +                    .call(xAxis);
  1.7495 +                g.select('.nv-focus .nv-y.nv-axis').transition().duration(transitionDuration)
  1.7496 +                    .call(yAxis);
  1.7497 +            }
  1.7498 +        });
  1.7499 +
  1.7500 +        return chart;
  1.7501 +    }
  1.7502 +
  1.7503 +    //============================================================
  1.7504 +    // Event Handling/Dispatching (out of chart's scope)
  1.7505 +    //------------------------------------------------------------
  1.7506 +
  1.7507 +    lines.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.7508 +        tooltip.data(evt).position(evt.pos).hidden(false);
  1.7509 +    });
  1.7510 +
  1.7511 +    lines.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.7512 +        tooltip.hidden(true)
  1.7513 +    });
  1.7514 +
  1.7515 +    //============================================================
  1.7516 +    // Expose Public Variables
  1.7517 +    //------------------------------------------------------------
  1.7518 +
  1.7519 +    // expose chart's sub-components
  1.7520 +    chart.dispatch = dispatch;
  1.7521 +    chart.legend = legend;
  1.7522 +    chart.lines = lines;
  1.7523 +    chart.lines2 = lines2;
  1.7524 +    chart.xAxis = xAxis;
  1.7525 +    chart.yAxis = yAxis;
  1.7526 +    chart.x2Axis = x2Axis;
  1.7527 +    chart.y2Axis = y2Axis;
  1.7528 +    chart.interactiveLayer = interactiveLayer;
  1.7529 +    chart.tooltip = tooltip;
  1.7530 +
  1.7531 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.7532 +
  1.7533 +    chart._options = Object.create({}, {
  1.7534 +        // simple options, just get/set the necessary values
  1.7535 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.7536 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.7537 +        focusHeight:     {get: function(){return height2;}, set: function(_){height2=_;}},
  1.7538 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.7539 +        brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}},
  1.7540 +        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
  1.7541 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.7542 +
  1.7543 +        // deprecated options
  1.7544 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.7545 +            // deprecated after 1.7.1
  1.7546 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.7547 +            tooltip.enabled(!!_);
  1.7548 +        }},
  1.7549 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.7550 +            // deprecated after 1.7.1
  1.7551 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.7552 +            tooltip.contentGenerator(_);
  1.7553 +        }},
  1.7554 +
  1.7555 +        // options that require extra logic in the setter
  1.7556 +        margin: {get: function(){return margin;}, set: function(_){
  1.7557 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.7558 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.7559 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.7560 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.7561 +        }},
  1.7562 +        color:  {get: function(){return color;}, set: function(_){
  1.7563 +            color = nv.utils.getColor(_);
  1.7564 +            legend.color(color);
  1.7565 +            // line color is handled above?
  1.7566 +        }},
  1.7567 +        interpolate: {get: function(){return lines.interpolate();}, set: function(_){
  1.7568 +            lines.interpolate(_);
  1.7569 +            lines2.interpolate(_);
  1.7570 +        }},
  1.7571 +        xTickFormat: {get: function(){return xAxis.tickFormat();}, set: function(_){
  1.7572 +            xAxis.tickFormat(_);
  1.7573 +            x2Axis.tickFormat(_);
  1.7574 +        }},
  1.7575 +        yTickFormat: {get: function(){return yAxis.tickFormat();}, set: function(_){
  1.7576 +            yAxis.tickFormat(_);
  1.7577 +            y2Axis.tickFormat(_);
  1.7578 +        }},
  1.7579 +        duration:    {get: function(){return transitionDuration;}, set: function(_){
  1.7580 +            transitionDuration=_;
  1.7581 +            yAxis.duration(transitionDuration);
  1.7582 +            y2Axis.duration(transitionDuration);
  1.7583 +            xAxis.duration(transitionDuration);
  1.7584 +            x2Axis.duration(transitionDuration);
  1.7585 +        }},
  1.7586 +        x: {get: function(){return lines.x();}, set: function(_){
  1.7587 +            lines.x(_);
  1.7588 +            lines2.x(_);
  1.7589 +        }},
  1.7590 +        y: {get: function(){return lines.y();}, set: function(_){
  1.7591 +            lines.y(_);
  1.7592 +            lines2.y(_);
  1.7593 +        }},
  1.7594 +        useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
  1.7595 +            useInteractiveGuideline = _;
  1.7596 +            if (useInteractiveGuideline) {
  1.7597 +                lines.interactive(false);
  1.7598 +                lines.useVoronoi(false);
  1.7599 +            }
  1.7600 +        }}
  1.7601 +    });
  1.7602 +
  1.7603 +    nv.utils.inheritOptions(chart, lines);
  1.7604 +    nv.utils.initOptions(chart);
  1.7605 +
  1.7606 +    return chart;
  1.7607 +};
  1.7608 +
  1.7609 +nv.models.multiBar = function() {
  1.7610 +    "use strict";
  1.7611 +
  1.7612 +    //============================================================
  1.7613 +    // Public Variables with Default Settings
  1.7614 +    //------------------------------------------------------------
  1.7615 +
  1.7616 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.7617 +        , width = 960
  1.7618 +        , height = 500
  1.7619 +        , x = d3.scale.ordinal()
  1.7620 +        , y = d3.scale.linear()
  1.7621 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
  1.7622 +        , container = null
  1.7623 +        , getX = function(d) { return d.x }
  1.7624 +        , getY = function(d) { return d.y }
  1.7625 +        , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
  1.7626 +        , clipEdge = true
  1.7627 +        , stacked = false
  1.7628 +        , stackOffset = 'zero' // options include 'silhouette', 'wiggle', 'expand', 'zero', or a custom function
  1.7629 +        , color = nv.utils.defaultColor()
  1.7630 +        , hideable = false
  1.7631 +        , barColor = null // adding the ability to set the color for each rather than the whole group
  1.7632 +        , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled
  1.7633 +        , duration = 500
  1.7634 +        , xDomain
  1.7635 +        , yDomain
  1.7636 +        , xRange
  1.7637 +        , yRange
  1.7638 +        , groupSpacing = 0.1
  1.7639 +        , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd')
  1.7640 +        ;
  1.7641 +
  1.7642 +    //============================================================
  1.7643 +    // Private Variables
  1.7644 +    //------------------------------------------------------------
  1.7645 +
  1.7646 +    var x0, y0 //used to store previous scales
  1.7647 +        , renderWatch = nv.utils.renderWatch(dispatch, duration)
  1.7648 +        ;
  1.7649 +
  1.7650 +    var last_datalength = 0;
  1.7651 +
  1.7652 +    function chart(selection) {
  1.7653 +        renderWatch.reset();
  1.7654 +        selection.each(function(data) {
  1.7655 +            var availableWidth = width - margin.left - margin.right,
  1.7656 +                availableHeight = height - margin.top - margin.bottom;
  1.7657 +
  1.7658 +            container = d3.select(this);
  1.7659 +            nv.utils.initSVG(container);
  1.7660 +            var nonStackableCount = 0;
  1.7661 +            // This function defines the requirements for render complete
  1.7662 +            var endFn = function(d, i) {
  1.7663 +                if (d.series === data.length - 1 && i === data[0].values.length - 1)
  1.7664 +                    return true;
  1.7665 +                return false;
  1.7666 +            };
  1.7667 +
  1.7668 +            if(hideable && data.length) hideable = [{
  1.7669 +                values: data[0].values.map(function(d) {
  1.7670 +                        return {
  1.7671 +                            x: d.x,
  1.7672 +                            y: 0,
  1.7673 +                            series: d.series,
  1.7674 +                            size: 0.01
  1.7675 +                        };}
  1.7676 +                )}];
  1.7677 +
  1.7678 +            if (stacked) {
  1.7679 +                var parsed = d3.layout.stack()
  1.7680 +                    .offset(stackOffset)
  1.7681 +                    .values(function(d){ return d.values })
  1.7682 +                    .y(getY)
  1.7683 +                (!data.length && hideable ? hideable : data);
  1.7684 +
  1.7685 +                parsed.forEach(function(series, i){
  1.7686 +                    // if series is non-stackable, use un-parsed data
  1.7687 +                    if (series.nonStackable) {
  1.7688 +                        data[i].nonStackableSeries = nonStackableCount++; 
  1.7689 +                        parsed[i] = data[i];
  1.7690 +                    } else {
  1.7691 +                        // don't stack this seires on top of the nonStackable seriees 
  1.7692 +                        if (i > 0 && parsed[i - 1].nonStackable){
  1.7693 +                            parsed[i].values.map(function(d,j){
  1.7694 +                                d.y0 -= parsed[i - 1].values[j].y;
  1.7695 +                                d.y1 = d.y0 + d.y;
  1.7696 +                            });
  1.7697 +                        }
  1.7698 +                    }
  1.7699 +                });
  1.7700 +                data = parsed;
  1.7701 +            }
  1.7702 +            //add series index and key to each data point for reference
  1.7703 +            data.forEach(function(series, i) {
  1.7704 +                series.values.forEach(function(point) {
  1.7705 +                    point.series = i;
  1.7706 +                    point.key = series.key;
  1.7707 +                });
  1.7708 +            });
  1.7709 +
  1.7710 +            // HACK for negative value stacking
  1.7711 +            if (stacked) {
  1.7712 +                data[0].values.map(function(d,i) {
  1.7713 +                    var posBase = 0, negBase = 0;
  1.7714 +                    data.map(function(d, idx) {
  1.7715 +                        if (!data[idx].nonStackable) {
  1.7716 +                            var f = d.values[i]
  1.7717 +                            f.size = Math.abs(f.y);
  1.7718 +                            if (f.y<0)  {
  1.7719 +                                f.y1 = negBase;
  1.7720 +                                negBase = negBase - f.size;
  1.7721 +                            } else
  1.7722 +                            {
  1.7723 +                                f.y1 = f.size + posBase;
  1.7724 +                                posBase = posBase + f.size;
  1.7725 +                            }
  1.7726 +                        }
  1.7727 +                        
  1.7728 +                    });
  1.7729 +                });
  1.7730 +            }
  1.7731 +            // Setup Scales
  1.7732 +            // remap and flatten the data for use in calculating the scales' domains
  1.7733 +            var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
  1.7734 +                data.map(function(d, idx) {
  1.7735 +                    return d.values.map(function(d,i) {
  1.7736 +                        return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1, idx:idx }
  1.7737 +                    })
  1.7738 +                });
  1.7739 +
  1.7740 +            x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
  1.7741 +                .rangeBands(xRange || [0, availableWidth], groupSpacing);
  1.7742 +
  1.7743 +            y.domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) {
  1.7744 +                var domain = d.y;
  1.7745 +                // increase the domain range if this series is stackable
  1.7746 +                if (stacked && !data[d.idx].nonStackable) {
  1.7747 +                    if (d.y > 0){
  1.7748 +                        domain = d.y1
  1.7749 +                    } else {
  1.7750 +                        domain = d.y1 + d.y
  1.7751 +                    }
  1.7752 +                }
  1.7753 +                return domain;
  1.7754 +            }).concat(forceY)))
  1.7755 +            .range(yRange || [availableHeight, 0]);
  1.7756 +
  1.7757 +            // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
  1.7758 +            if (x.domain()[0] === x.domain()[1])
  1.7759 +                x.domain()[0] ?
  1.7760 +                    x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
  1.7761 +                    : x.domain([-1,1]);
  1.7762 +
  1.7763 +            if (y.domain()[0] === y.domain()[1])
  1.7764 +                y.domain()[0] ?
  1.7765 +                    y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
  1.7766 +                    : y.domain([-1,1]);
  1.7767 +
  1.7768 +            x0 = x0 || x;
  1.7769 +            y0 = y0 || y;
  1.7770 +
  1.7771 +            // Setup containers and skeleton of chart
  1.7772 +            var wrap = container.selectAll('g.nv-wrap.nv-multibar').data([data]);
  1.7773 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibar');
  1.7774 +            var defsEnter = wrapEnter.append('defs');
  1.7775 +            var gEnter = wrapEnter.append('g');
  1.7776 +            var g = wrap.select('g');
  1.7777 +
  1.7778 +            gEnter.append('g').attr('class', 'nv-groups');
  1.7779 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.7780 +
  1.7781 +            defsEnter.append('clipPath')
  1.7782 +                .attr('id', 'nv-edge-clip-' + id)
  1.7783 +                .append('rect');
  1.7784 +            wrap.select('#nv-edge-clip-' + id + ' rect')
  1.7785 +                .attr('width', availableWidth)
  1.7786 +                .attr('height', availableHeight);
  1.7787 +
  1.7788 +            g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
  1.7789 +
  1.7790 +            var groups = wrap.select('.nv-groups').selectAll('.nv-group')
  1.7791 +                .data(function(d) { return d }, function(d,i) { return i });
  1.7792 +            groups.enter().append('g')
  1.7793 +                .style('stroke-opacity', 1e-6)
  1.7794 +                .style('fill-opacity', 1e-6);
  1.7795 +
  1.7796 +            var exitTransition = renderWatch
  1.7797 +                .transition(groups.exit().selectAll('rect.nv-bar'), 'multibarExit', Math.min(100, duration))
  1.7798 +                .attr('y', function(d, i, j) {
  1.7799 +                    var yVal = y0(0) || 0;
  1.7800 +                    if (stacked) {
  1.7801 +                        if (data[d.series] && !data[d.series].nonStackable) {
  1.7802 +                            yVal = y0(d.y0);
  1.7803 +                        }
  1.7804 +                    }
  1.7805 +                    return yVal;
  1.7806 +                })
  1.7807 +                .attr('height', 0)
  1.7808 +                .remove();
  1.7809 +            if (exitTransition.delay)
  1.7810 +                exitTransition.delay(function(d,i) {
  1.7811 +                    var delay = i * (duration / (last_datalength + 1)) - i;
  1.7812 +                    return delay;
  1.7813 +                });
  1.7814 +            groups
  1.7815 +                .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
  1.7816 +                .classed('hover', function(d) { return d.hover })
  1.7817 +                .style('fill', function(d,i){ return color(d, i) })
  1.7818 +                .style('stroke', function(d,i){ return color(d, i) });
  1.7819 +            groups
  1.7820 +                .style('stroke-opacity', 1)
  1.7821 +                .style('fill-opacity', 0.75);
  1.7822 +
  1.7823 +            var bars = groups.selectAll('rect.nv-bar')
  1.7824 +                .data(function(d) { return (hideable && !data.length) ? hideable.values : d.values });
  1.7825 +            bars.exit().remove();
  1.7826 +
  1.7827 +            var barsEnter = bars.enter().append('rect')
  1.7828 +                    .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
  1.7829 +                    .attr('x', function(d,i,j) {
  1.7830 +                        return stacked && !data[j].nonStackable ? 0 : (j * x.rangeBand() / data.length )
  1.7831 +                    })
  1.7832 +                    .attr('y', function(d,i,j) { return y0(stacked && !data[j].nonStackable ? d.y0 : 0) || 0 })
  1.7833 +                    .attr('height', 0)
  1.7834 +                    .attr('width', function(d,i,j) { return x.rangeBand() / (stacked && !data[j].nonStackable ? 1 : data.length) })
  1.7835 +                    .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; })
  1.7836 +                ;
  1.7837 +            bars
  1.7838 +                .style('fill', function(d,i,j){ return color(d, j, i);  })
  1.7839 +                .style('stroke', function(d,i,j){ return color(d, j, i); })
  1.7840 +                .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
  1.7841 +                    d3.select(this).classed('hover', true);
  1.7842 +                    dispatch.elementMouseover({
  1.7843 +                        data: d,
  1.7844 +                        index: i,
  1.7845 +                        color: d3.select(this).style("fill")
  1.7846 +                    });
  1.7847 +                })
  1.7848 +                .on('mouseout', function(d,i) {
  1.7849 +                    d3.select(this).classed('hover', false);
  1.7850 +                    dispatch.elementMouseout({
  1.7851 +                        data: d,
  1.7852 +                        index: i,
  1.7853 +                        color: d3.select(this).style("fill")
  1.7854 +                    });
  1.7855 +                })
  1.7856 +                .on('mousemove', function(d,i) {
  1.7857 +                    dispatch.elementMousemove({
  1.7858 +                        data: d,
  1.7859 +                        index: i,
  1.7860 +                        color: d3.select(this).style("fill")
  1.7861 +                    });
  1.7862 +                })
  1.7863 +                .on('click', function(d,i) {
  1.7864 +                    dispatch.elementClick({
  1.7865 +                        data: d,
  1.7866 +                        index: i,
  1.7867 +                        color: d3.select(this).style("fill")
  1.7868 +                    });
  1.7869 +                    d3.event.stopPropagation();
  1.7870 +                })
  1.7871 +                .on('dblclick', function(d,i) {
  1.7872 +                    dispatch.elementDblClick({
  1.7873 +                        data: d,
  1.7874 +                        index: i,
  1.7875 +                        color: d3.select(this).style("fill")
  1.7876 +                    });
  1.7877 +                    d3.event.stopPropagation();
  1.7878 +                });
  1.7879 +            bars
  1.7880 +                .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
  1.7881 +                .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',0)'; })
  1.7882 +
  1.7883 +            if (barColor) {
  1.7884 +                if (!disabled) disabled = data.map(function() { return true });
  1.7885 +                bars
  1.7886 +                    .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker(  disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i]  })[j]   ).toString(); })
  1.7887 +                    .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker(  disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i]  })[j]   ).toString(); });
  1.7888 +            }
  1.7889 +
  1.7890 +            var barSelection =
  1.7891 +                bars.watchTransition(renderWatch, 'multibar', Math.min(250, duration))
  1.7892 +                    .delay(function(d,i) {
  1.7893 +                        return i * duration / data[0].values.length;
  1.7894 +                    });
  1.7895 +            if (stacked){
  1.7896 +                barSelection
  1.7897 +                    .attr('y', function(d,i,j) {
  1.7898 +                        var yVal = 0;
  1.7899 +                        // if stackable, stack it on top of the previous series
  1.7900 +                        if (!data[j].nonStackable) {
  1.7901 +                            yVal = y(d.y1);
  1.7902 +                        } else {
  1.7903 +                            if (getY(d,i) < 0){
  1.7904 +                                yVal = y(0);
  1.7905 +                            } else {
  1.7906 +                                if (y(0) - y(getY(d,i)) < -1){
  1.7907 +                                    yVal = y(0) - 1;
  1.7908 +                                } else {
  1.7909 +                                    yVal = y(getY(d, i)) || 0;
  1.7910 +                                }
  1.7911 +                            }
  1.7912 +                        }
  1.7913 +                        return yVal;
  1.7914 +                    })
  1.7915 +                    .attr('height', function(d,i,j) {
  1.7916 +                        if (!data[j].nonStackable) {
  1.7917 +                            return Math.max(Math.abs(y(d.y+d.y0) - y(d.y0)), 1);
  1.7918 +                        } else {
  1.7919 +                            return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0;
  1.7920 +                        }
  1.7921 +                    })
  1.7922 +                    .attr('x', function(d,i,j) {
  1.7923 +                        var width = 0;
  1.7924 +                        if (data[j].nonStackable) {
  1.7925 +                            width = d.series * x.rangeBand() / data.length;
  1.7926 +                            if (data.length !== nonStackableCount){
  1.7927 +                                width = data[j].nonStackableSeries * x.rangeBand()/(nonStackableCount*2); 
  1.7928 +                            }
  1.7929 +                        }
  1.7930 +                        return width;
  1.7931 +                    })
  1.7932 +                    .attr('width', function(d,i,j){
  1.7933 +                        if (!data[j].nonStackable) {
  1.7934 +                            return x.rangeBand();
  1.7935 +                        } else {
  1.7936 +                            // if all series are nonStacable, take the full width
  1.7937 +                            var width = (x.rangeBand() / nonStackableCount);
  1.7938 +                            // otherwise, nonStackable graph will be only taking the half-width 
  1.7939 +                            // of the x rangeBand
  1.7940 +                            if (data.length !== nonStackableCount) {
  1.7941 +                                width = x.rangeBand()/(nonStackableCount*2);
  1.7942 +                            }
  1.7943 +                            return width;
  1.7944 +                        }
  1.7945 +                    });
  1.7946 +            }
  1.7947 +            else {
  1.7948 +                barSelection
  1.7949 +                    .attr('x', function(d,i) {
  1.7950 +                        return d.series * x.rangeBand() / data.length;
  1.7951 +                    })
  1.7952 +                    .attr('width', x.rangeBand() / data.length)
  1.7953 +                    .attr('y', function(d,i) {
  1.7954 +                        return getY(d,i) < 0 ?
  1.7955 +                            y(0) :
  1.7956 +                                y(0) - y(getY(d,i)) < 1 ?
  1.7957 +                            y(0) - 1 :
  1.7958 +                            y(getY(d,i)) || 0;
  1.7959 +                    })
  1.7960 +                    .attr('height', function(d,i) {
  1.7961 +                        return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0;
  1.7962 +                    });
  1.7963 +            }
  1.7964 +
  1.7965 +            //store old scales for use in transitions on update
  1.7966 +            x0 = x.copy();
  1.7967 +            y0 = y.copy();
  1.7968 +
  1.7969 +            // keep track of the last data value length for transition calculations
  1.7970 +            if (data[0] && data[0].values) {
  1.7971 +                last_datalength = data[0].values.length;
  1.7972 +            }
  1.7973 +
  1.7974 +        });
  1.7975 +
  1.7976 +        renderWatch.renderEnd('multibar immediate');
  1.7977 +
  1.7978 +        return chart;
  1.7979 +    }
  1.7980 +
  1.7981 +    //============================================================
  1.7982 +    // Expose Public Variables
  1.7983 +    //------------------------------------------------------------
  1.7984 +
  1.7985 +    chart.dispatch = dispatch;
  1.7986 +
  1.7987 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.7988 +
  1.7989 +    chart._options = Object.create({}, {
  1.7990 +        // simple options, just get/set the necessary values
  1.7991 +        width:   {get: function(){return width;}, set: function(_){width=_;}},
  1.7992 +        height:  {get: function(){return height;}, set: function(_){height=_;}},
  1.7993 +        x:       {get: function(){return getX;}, set: function(_){getX=_;}},
  1.7994 +        y:       {get: function(){return getY;}, set: function(_){getY=_;}},
  1.7995 +        xScale:  {get: function(){return x;}, set: function(_){x=_;}},
  1.7996 +        yScale:  {get: function(){return y;}, set: function(_){y=_;}},
  1.7997 +        xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
  1.7998 +        yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
  1.7999 +        xRange:  {get: function(){return xRange;}, set: function(_){xRange=_;}},
  1.8000 +        yRange:  {get: function(){return yRange;}, set: function(_){yRange=_;}},
  1.8001 +        forceY:  {get: function(){return forceY;}, set: function(_){forceY=_;}},
  1.8002 +        stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}},
  1.8003 +        stackOffset: {get: function(){return stackOffset;}, set: function(_){stackOffset=_;}},
  1.8004 +        clipEdge:    {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
  1.8005 +        disabled:    {get: function(){return disabled;}, set: function(_){disabled=_;}},
  1.8006 +        id:          {get: function(){return id;}, set: function(_){id=_;}},
  1.8007 +        hideable:    {get: function(){return hideable;}, set: function(_){hideable=_;}},
  1.8008 +        groupSpacing:{get: function(){return groupSpacing;}, set: function(_){groupSpacing=_;}},
  1.8009 +
  1.8010 +        // options that require extra logic in the setter
  1.8011 +        margin: {get: function(){return margin;}, set: function(_){
  1.8012 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.8013 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.8014 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.8015 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.8016 +        }},
  1.8017 +        duration: {get: function(){return duration;}, set: function(_){
  1.8018 +            duration = _;
  1.8019 +            renderWatch.reset(duration);
  1.8020 +        }},
  1.8021 +        color:  {get: function(){return color;}, set: function(_){
  1.8022 +            color = nv.utils.getColor(_);
  1.8023 +        }},
  1.8024 +        barColor:  {get: function(){return barColor;}, set: function(_){
  1.8025 +            barColor = _ ? nv.utils.getColor(_) : null;
  1.8026 +        }}
  1.8027 +    });
  1.8028 +
  1.8029 +    nv.utils.initOptions(chart);
  1.8030 +
  1.8031 +    return chart;
  1.8032 +};
  1.8033 +nv.models.multiBarChart = function() {
  1.8034 +    "use strict";
  1.8035 +
  1.8036 +    //============================================================
  1.8037 +    // Public Variables with Default Settings
  1.8038 +    //------------------------------------------------------------
  1.8039 +
  1.8040 +    var multibar = nv.models.multiBar()
  1.8041 +        , xAxis = nv.models.axis()
  1.8042 +        , yAxis = nv.models.axis()
  1.8043 +        , legend = nv.models.legend()
  1.8044 +        , controls = nv.models.legend()
  1.8045 +        , tooltip = nv.models.tooltip()
  1.8046 +        ;
  1.8047 +
  1.8048 +    var margin = {top: 30, right: 20, bottom: 50, left: 60}
  1.8049 +        , width = null
  1.8050 +        , height = null
  1.8051 +        , color = nv.utils.defaultColor()
  1.8052 +        , showControls = true
  1.8053 +        , controlLabels = {}
  1.8054 +        , showLegend = true
  1.8055 +        , showXAxis = true
  1.8056 +        , showYAxis = true
  1.8057 +        , rightAlignYAxis = false
  1.8058 +        , reduceXTicks = true // if false a tick will show for every data point
  1.8059 +        , staggerLabels = false
  1.8060 +        , rotateLabels = 0
  1.8061 +        , x //can be accessed via chart.xScale()
  1.8062 +        , y //can be accessed via chart.yScale()
  1.8063 +        , state = nv.utils.state()
  1.8064 +        , defaultState = null
  1.8065 +        , noData = null
  1.8066 +        , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd')
  1.8067 +        , controlWidth = function() { return showControls ? 180 : 0 }
  1.8068 +        , duration = 250
  1.8069 +        ;
  1.8070 +
  1.8071 +    state.stacked = false // DEPRECATED Maintained for backward compatibility
  1.8072 +
  1.8073 +    multibar.stacked(false);
  1.8074 +    xAxis
  1.8075 +        .orient('bottom')
  1.8076 +        .tickPadding(7)
  1.8077 +        .showMaxMin(false)
  1.8078 +        .tickFormat(function(d) { return d })
  1.8079 +    ;
  1.8080 +    yAxis
  1.8081 +        .orient((rightAlignYAxis) ? 'right' : 'left')
  1.8082 +        .tickFormat(d3.format(',.1f'))
  1.8083 +    ;
  1.8084 +
  1.8085 +    tooltip
  1.8086 +        .duration(0)
  1.8087 +        .valueFormatter(function(d, i) {
  1.8088 +            return yAxis.tickFormat()(d, i);
  1.8089 +        })
  1.8090 +        .headerFormatter(function(d, i) {
  1.8091 +            return xAxis.tickFormat()(d, i);
  1.8092 +        });
  1.8093 +
  1.8094 +    controls.updateState(false);
  1.8095 +
  1.8096 +    //============================================================
  1.8097 +    // Private Variables
  1.8098 +    //------------------------------------------------------------
  1.8099 +
  1.8100 +    var renderWatch = nv.utils.renderWatch(dispatch);
  1.8101 +    var stacked = false;
  1.8102 +
  1.8103 +    var stateGetter = function(data) {
  1.8104 +        return function(){
  1.8105 +            return {
  1.8106 +                active: data.map(function(d) { return !d.disabled }),
  1.8107 +                stacked: stacked
  1.8108 +            };
  1.8109 +        }
  1.8110 +    };
  1.8111 +
  1.8112 +    var stateSetter = function(data) {
  1.8113 +        return function(state) {
  1.8114 +            if (state.stacked !== undefined)
  1.8115 +                stacked = state.stacked;
  1.8116 +            if (state.active !== undefined)
  1.8117 +                data.forEach(function(series,i) {
  1.8118 +                    series.disabled = !state.active[i];
  1.8119 +                });
  1.8120 +        }
  1.8121 +    };
  1.8122 +
  1.8123 +    function chart(selection) {
  1.8124 +        renderWatch.reset();
  1.8125 +        renderWatch.models(multibar);
  1.8126 +        if (showXAxis) renderWatch.models(xAxis);
  1.8127 +        if (showYAxis) renderWatch.models(yAxis);
  1.8128 +
  1.8129 +        selection.each(function(data) {
  1.8130 +            var container = d3.select(this),
  1.8131 +                that = this;
  1.8132 +            nv.utils.initSVG(container);
  1.8133 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.8134 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.8135 +
  1.8136 +            chart.update = function() {
  1.8137 +                if (duration === 0)
  1.8138 +                    container.call(chart);
  1.8139 +                else
  1.8140 +                    container.transition()
  1.8141 +                        .duration(duration)
  1.8142 +                        .call(chart);
  1.8143 +            };
  1.8144 +            chart.container = this;
  1.8145 +
  1.8146 +            state
  1.8147 +                .setter(stateSetter(data), chart.update)
  1.8148 +                .getter(stateGetter(data))
  1.8149 +                .update();
  1.8150 +
  1.8151 +            // DEPRECATED set state.disableddisabled
  1.8152 +            state.disabled = data.map(function(d) { return !!d.disabled });
  1.8153 +
  1.8154 +            if (!defaultState) {
  1.8155 +                var key;
  1.8156 +                defaultState = {};
  1.8157 +                for (key in state) {
  1.8158 +                    if (state[key] instanceof Array)
  1.8159 +                        defaultState[key] = state[key].slice(0);
  1.8160 +                    else
  1.8161 +                        defaultState[key] = state[key];
  1.8162 +                }
  1.8163 +            }
  1.8164 +
  1.8165 +            // Display noData message if there's nothing to show.
  1.8166 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.8167 +                nv.utils.noData(chart, container)
  1.8168 +                return chart;
  1.8169 +            } else {
  1.8170 +                container.selectAll('.nv-noData').remove();
  1.8171 +            }
  1.8172 +
  1.8173 +            // Setup Scales
  1.8174 +            x = multibar.xScale();
  1.8175 +            y = multibar.yScale();
  1.8176 +
  1.8177 +            // Setup containers and skeleton of chart
  1.8178 +            var wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]);
  1.8179 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend').append('g');
  1.8180 +            var g = wrap.select('g');
  1.8181 +
  1.8182 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
  1.8183 +            gEnter.append('g').attr('class', 'nv-y nv-axis');
  1.8184 +            gEnter.append('g').attr('class', 'nv-barsWrap');
  1.8185 +            gEnter.append('g').attr('class', 'nv-legendWrap');
  1.8186 +            gEnter.append('g').attr('class', 'nv-controlsWrap');
  1.8187 +
  1.8188 +            // Legend
  1.8189 +            if (showLegend) {
  1.8190 +                legend.width(availableWidth - controlWidth());
  1.8191 +
  1.8192 +                g.select('.nv-legendWrap')
  1.8193 +                    .datum(data)
  1.8194 +                    .call(legend);
  1.8195 +
  1.8196 +                if ( margin.top != legend.height()) {
  1.8197 +                    margin.top = legend.height();
  1.8198 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
  1.8199 +                }
  1.8200 +
  1.8201 +                g.select('.nv-legendWrap')
  1.8202 +                    .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')');
  1.8203 +            }
  1.8204 +
  1.8205 +            // Controls
  1.8206 +            if (showControls) {
  1.8207 +                var controlsData = [
  1.8208 +                    { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() },
  1.8209 +                    { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() }
  1.8210 +                ];
  1.8211 +
  1.8212 +                controls.width(controlWidth()).color(['#444', '#444', '#444']);
  1.8213 +                g.select('.nv-controlsWrap')
  1.8214 +                    .datum(controlsData)
  1.8215 +                    .attr('transform', 'translate(0,' + (-margin.top) +')')
  1.8216 +                    .call(controls);
  1.8217 +            }
  1.8218 +
  1.8219 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.8220 +            if (rightAlignYAxis) {
  1.8221 +                g.select(".nv-y.nv-axis")
  1.8222 +                    .attr("transform", "translate(" + availableWidth + ",0)");
  1.8223 +            }
  1.8224 +
  1.8225 +            // Main Chart Component(s)
  1.8226 +            multibar
  1.8227 +                .disabled(data.map(function(series) { return series.disabled }))
  1.8228 +                .width(availableWidth)
  1.8229 +                .height(availableHeight)
  1.8230 +                .color(data.map(function(d,i) {
  1.8231 +                    return d.color || color(d, i);
  1.8232 +                }).filter(function(d,i) { return !data[i].disabled }));
  1.8233 +
  1.8234 +
  1.8235 +            var barsWrap = g.select('.nv-barsWrap')
  1.8236 +                .datum(data.filter(function(d) { return !d.disabled }));
  1.8237 +
  1.8238 +            barsWrap.call(multibar);
  1.8239 +
  1.8240 +            // Setup Axes
  1.8241 +            if (showXAxis) {
  1.8242 +                xAxis
  1.8243 +                    .scale(x)
  1.8244 +                    ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.8245 +                    .tickSize(-availableHeight, 0);
  1.8246 +
  1.8247 +                g.select('.nv-x.nv-axis')
  1.8248 +                    .attr('transform', 'translate(0,' + y.range()[0] + ')');
  1.8249 +                g.select('.nv-x.nv-axis')
  1.8250 +                    .call(xAxis);
  1.8251 +
  1.8252 +                var xTicks = g.select('.nv-x.nv-axis > g').selectAll('g');
  1.8253 +
  1.8254 +                xTicks
  1.8255 +                    .selectAll('line, text')
  1.8256 +                    .style('opacity', 1)
  1.8257 +
  1.8258 +                if (staggerLabels) {
  1.8259 +                    var getTranslate = function(x,y) {
  1.8260 +                        return "translate(" + x + "," + y + ")";
  1.8261 +                    };
  1.8262 +
  1.8263 +                    var staggerUp = 5, staggerDown = 17;  //pixels to stagger by
  1.8264 +                    // Issue #140
  1.8265 +                    xTicks
  1.8266 +                        .selectAll("text")
  1.8267 +                        .attr('transform', function(d,i,j) {
  1.8268 +                            return  getTranslate(0, (j % 2 == 0 ? staggerUp : staggerDown));
  1.8269 +                        });
  1.8270 +
  1.8271 +                    var totalInBetweenTicks = d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;
  1.8272 +                    g.selectAll(".nv-x.nv-axis .nv-axisMaxMin text")
  1.8273 +                        .attr("transform", function(d,i) {
  1.8274 +                            return getTranslate(0, (i === 0 || totalInBetweenTicks % 2 !== 0) ? staggerDown : staggerUp);
  1.8275 +                        });
  1.8276 +                }
  1.8277 +
  1.8278 +                if (reduceXTicks)
  1.8279 +                    xTicks
  1.8280 +                        .filter(function(d,i) {
  1.8281 +                            return i % Math.ceil(data[0].values.length / (availableWidth / 100)) !== 0;
  1.8282 +                        })
  1.8283 +                        .selectAll('text, line')
  1.8284 +                        .style('opacity', 0);
  1.8285 +
  1.8286 +                if(rotateLabels)
  1.8287 +                    xTicks
  1.8288 +                        .selectAll('.tick text')
  1.8289 +                        .attr('transform', 'rotate(' + rotateLabels + ' 0,0)')
  1.8290 +                        .style('text-anchor', rotateLabels > 0 ? 'start' : 'end');
  1.8291 +
  1.8292 +                g.select('.nv-x.nv-axis').selectAll('g.nv-axisMaxMin text')
  1.8293 +                    .style('opacity', 1);
  1.8294 +            }
  1.8295 +
  1.8296 +            if (showYAxis) {
  1.8297 +                yAxis
  1.8298 +                    .scale(y)
  1.8299 +                    ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
  1.8300 +                    .tickSize( -availableWidth, 0);
  1.8301 +
  1.8302 +                g.select('.nv-y.nv-axis')
  1.8303 +                    .call(yAxis);
  1.8304 +            }
  1.8305 +
  1.8306 +            //============================================================
  1.8307 +            // Event Handling/Dispatching (in chart's scope)
  1.8308 +            //------------------------------------------------------------
  1.8309 +
  1.8310 +            legend.dispatch.on('stateChange', function(newState) {
  1.8311 +                for (var key in newState)
  1.8312 +                    state[key] = newState[key];
  1.8313 +                dispatch.stateChange(state);
  1.8314 +                chart.update();
  1.8315 +            });
  1.8316 +
  1.8317 +            controls.dispatch.on('legendClick', function(d,i) {
  1.8318 +                if (!d.disabled) return;
  1.8319 +                controlsData = controlsData.map(function(s) {
  1.8320 +                    s.disabled = true;
  1.8321 +                    return s;
  1.8322 +                });
  1.8323 +                d.disabled = false;
  1.8324 +
  1.8325 +                switch (d.key) {
  1.8326 +                    case 'Grouped':
  1.8327 +                    case controlLabels.grouped:
  1.8328 +                        multibar.stacked(false);
  1.8329 +                        break;
  1.8330 +                    case 'Stacked':
  1.8331 +                    case controlLabels.stacked:
  1.8332 +                        multibar.stacked(true);
  1.8333 +                        break;
  1.8334 +                }
  1.8335 +
  1.8336 +                state.stacked = multibar.stacked();
  1.8337 +                dispatch.stateChange(state);
  1.8338 +                chart.update();
  1.8339 +            });
  1.8340 +
  1.8341 +            // Update chart from a state object passed to event handler
  1.8342 +            dispatch.on('changeState', function(e) {
  1.8343 +                if (typeof e.disabled !== 'undefined') {
  1.8344 +                    data.forEach(function(series,i) {
  1.8345 +                        series.disabled = e.disabled[i];
  1.8346 +                    });
  1.8347 +                    state.disabled = e.disabled;
  1.8348 +                }
  1.8349 +                if (typeof e.stacked !== 'undefined') {
  1.8350 +                    multibar.stacked(e.stacked);
  1.8351 +                    state.stacked = e.stacked;
  1.8352 +                    stacked = e.stacked;
  1.8353 +                }
  1.8354 +                chart.update();
  1.8355 +            });
  1.8356 +        });
  1.8357 +
  1.8358 +        renderWatch.renderEnd('multibarchart immediate');
  1.8359 +        return chart;
  1.8360 +    }
  1.8361 +
  1.8362 +    //============================================================
  1.8363 +    // Event Handling/Dispatching (out of chart's scope)
  1.8364 +    //------------------------------------------------------------
  1.8365 +
  1.8366 +    multibar.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.8367 +        evt.value = chart.x()(evt.data);
  1.8368 +        evt['series'] = {
  1.8369 +            key: evt.data.key,
  1.8370 +            value: chart.y()(evt.data),
  1.8371 +            color: evt.color
  1.8372 +        };
  1.8373 +        tooltip.data(evt).hidden(false);
  1.8374 +    });
  1.8375 +
  1.8376 +    multibar.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.8377 +        tooltip.hidden(true);
  1.8378 +    });
  1.8379 +
  1.8380 +    multibar.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.8381 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.8382 +    });
  1.8383 +
  1.8384 +    //============================================================
  1.8385 +    // Expose Public Variables
  1.8386 +    //------------------------------------------------------------
  1.8387 +
  1.8388 +    // expose chart's sub-components
  1.8389 +    chart.dispatch = dispatch;
  1.8390 +    chart.multibar = multibar;
  1.8391 +    chart.legend = legend;
  1.8392 +    chart.controls = controls;
  1.8393 +    chart.xAxis = xAxis;
  1.8394 +    chart.yAxis = yAxis;
  1.8395 +    chart.state = state;
  1.8396 +    chart.tooltip = tooltip;
  1.8397 +
  1.8398 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.8399 +
  1.8400 +    chart._options = Object.create({}, {
  1.8401 +        // simple options, just get/set the necessary values
  1.8402 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.8403 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.8404 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.8405 +        showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}},
  1.8406 +        controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}},
  1.8407 +        showXAxis:      {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
  1.8408 +        showYAxis:    {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
  1.8409 +        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
  1.8410 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.8411 +        reduceXTicks:    {get: function(){return reduceXTicks;}, set: function(_){reduceXTicks=_;}},
  1.8412 +        rotateLabels:    {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}},
  1.8413 +        staggerLabels:    {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
  1.8414 +
  1.8415 +        // deprecated options
  1.8416 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.8417 +            // deprecated after 1.7.1
  1.8418 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.8419 +            tooltip.enabled(!!_);
  1.8420 +        }},
  1.8421 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.8422 +            // deprecated after 1.7.1
  1.8423 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.8424 +            tooltip.contentGenerator(_);
  1.8425 +        }},
  1.8426 +
  1.8427 +        // options that require extra logic in the setter
  1.8428 +        margin: {get: function(){return margin;}, set: function(_){
  1.8429 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.8430 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.8431 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.8432 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.8433 +        }},
  1.8434 +        duration: {get: function(){return duration;}, set: function(_){
  1.8435 +            duration = _;
  1.8436 +            multibar.duration(duration);
  1.8437 +            xAxis.duration(duration);
  1.8438 +            yAxis.duration(duration);
  1.8439 +            renderWatch.reset(duration);
  1.8440 +        }},
  1.8441 +        color:  {get: function(){return color;}, set: function(_){
  1.8442 +            color = nv.utils.getColor(_);
  1.8443 +            legend.color(color);
  1.8444 +        }},
  1.8445 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
  1.8446 +            rightAlignYAxis = _;
  1.8447 +            yAxis.orient( rightAlignYAxis ? 'right' : 'left');
  1.8448 +        }},
  1.8449 +        barColor:  {get: function(){return multibar.barColor;}, set: function(_){
  1.8450 +            multibar.barColor(_);
  1.8451 +            legend.color(function(d,i) {return d3.rgb('#ccc').darker(i * 1.5).toString();})
  1.8452 +        }}
  1.8453 +    });
  1.8454 +
  1.8455 +    nv.utils.inheritOptions(chart, multibar);
  1.8456 +    nv.utils.initOptions(chart);
  1.8457 +
  1.8458 +    return chart;
  1.8459 +};
  1.8460 +
  1.8461 +nv.models.multiBarHorizontal = function() {
  1.8462 +    "use strict";
  1.8463 +
  1.8464 +    //============================================================
  1.8465 +    // Public Variables with Default Settings
  1.8466 +    //------------------------------------------------------------
  1.8467 +
  1.8468 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.8469 +        , width = 960
  1.8470 +        , height = 500
  1.8471 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
  1.8472 +        , container = null
  1.8473 +        , x = d3.scale.ordinal()
  1.8474 +        , y = d3.scale.linear()
  1.8475 +        , getX = function(d) { return d.x }
  1.8476 +        , getY = function(d) { return d.y }
  1.8477 +        , getYerr = function(d) { return d.yErr }
  1.8478 +        , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
  1.8479 +        , color = nv.utils.defaultColor()
  1.8480 +        , barColor = null // adding the ability to set the color for each rather than the whole group
  1.8481 +        , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled
  1.8482 +        , stacked = false
  1.8483 +        , showValues = false
  1.8484 +        , showBarLabels = false
  1.8485 +        , valuePadding = 60
  1.8486 +        , groupSpacing = 0.1
  1.8487 +        , valueFormat = d3.format(',.2f')
  1.8488 +        , delay = 1200
  1.8489 +        , xDomain
  1.8490 +        , yDomain
  1.8491 +        , xRange
  1.8492 +        , yRange
  1.8493 +        , duration = 250
  1.8494 +        , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd')
  1.8495 +        ;
  1.8496 +
  1.8497 +    //============================================================
  1.8498 +    // Private Variables
  1.8499 +    //------------------------------------------------------------
  1.8500 +
  1.8501 +    var x0, y0; //used to store previous scales
  1.8502 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.8503 +
  1.8504 +    function chart(selection) {
  1.8505 +        renderWatch.reset();
  1.8506 +        selection.each(function(data) {
  1.8507 +            var availableWidth = width - margin.left - margin.right,
  1.8508 +                availableHeight = height - margin.top - margin.bottom;
  1.8509 +
  1.8510 +            container = d3.select(this);
  1.8511 +            nv.utils.initSVG(container);
  1.8512 +
  1.8513 +            if (stacked)
  1.8514 +                data = d3.layout.stack()
  1.8515 +                    .offset('zero')
  1.8516 +                    .values(function(d){ return d.values })
  1.8517 +                    .y(getY)
  1.8518 +                (data);
  1.8519 +
  1.8520 +            //add series index and key to each data point for reference
  1.8521 +            data.forEach(function(series, i) {
  1.8522 +                series.values.forEach(function(point) {
  1.8523 +                    point.series = i;
  1.8524 +                    point.key = series.key;
  1.8525 +                });
  1.8526 +            });
  1.8527 +
  1.8528 +            // HACK for negative value stacking
  1.8529 +            if (stacked)
  1.8530 +                data[0].values.map(function(d,i) {
  1.8531 +                    var posBase = 0, negBase = 0;
  1.8532 +                    data.map(function(d) {
  1.8533 +                        var f = d.values[i]
  1.8534 +                        f.size = Math.abs(f.y);
  1.8535 +                        if (f.y<0)  {
  1.8536 +                            f.y1 = negBase - f.size;
  1.8537 +                            negBase = negBase - f.size;
  1.8538 +                        } else
  1.8539 +                        {
  1.8540 +                            f.y1 = posBase;
  1.8541 +                            posBase = posBase + f.size;
  1.8542 +                        }
  1.8543 +                    });
  1.8544 +                });
  1.8545 +
  1.8546 +            // Setup Scales
  1.8547 +            // remap and flatten the data for use in calculating the scales' domains
  1.8548 +            var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
  1.8549 +                data.map(function(d) {
  1.8550 +                    return d.values.map(function(d,i) {
  1.8551 +                        return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1 }
  1.8552 +                    })
  1.8553 +                });
  1.8554 +
  1.8555 +            x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
  1.8556 +                .rangeBands(xRange || [0, availableHeight], groupSpacing);
  1.8557 +
  1.8558 +            y.domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return stacked ? (d.y > 0 ? d.y1 + d.y : d.y1 ) : d.y }).concat(forceY)))
  1.8559 +
  1.8560 +            if (showValues && !stacked)
  1.8561 +                y.range(yRange || [(y.domain()[0] < 0 ? valuePadding : 0), availableWidth - (y.domain()[1] > 0 ? valuePadding : 0) ]);
  1.8562 +            else
  1.8563 +                y.range(yRange || [0, availableWidth]);
  1.8564 +
  1.8565 +            x0 = x0 || x;
  1.8566 +            y0 = y0 || d3.scale.linear().domain(y.domain()).range([y(0),y(0)]);
  1.8567 +
  1.8568 +            // Setup containers and skeleton of chart
  1.8569 +            var wrap = d3.select(this).selectAll('g.nv-wrap.nv-multibarHorizontal').data([data]);
  1.8570 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibarHorizontal');
  1.8571 +            var defsEnter = wrapEnter.append('defs');
  1.8572 +            var gEnter = wrapEnter.append('g');
  1.8573 +            var g = wrap.select('g');
  1.8574 +
  1.8575 +            gEnter.append('g').attr('class', 'nv-groups');
  1.8576 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.8577 +
  1.8578 +            var groups = wrap.select('.nv-groups').selectAll('.nv-group')
  1.8579 +                .data(function(d) { return d }, function(d,i) { return i });
  1.8580 +            groups.enter().append('g')
  1.8581 +                .style('stroke-opacity', 1e-6)
  1.8582 +                .style('fill-opacity', 1e-6);
  1.8583 +            groups.exit().watchTransition(renderWatch, 'multibarhorizontal: exit groups')
  1.8584 +                .style('stroke-opacity', 1e-6)
  1.8585 +                .style('fill-opacity', 1e-6)
  1.8586 +                .remove();
  1.8587 +            groups
  1.8588 +                .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
  1.8589 +                .classed('hover', function(d) { return d.hover })
  1.8590 +                .style('fill', function(d,i){ return color(d, i) })
  1.8591 +                .style('stroke', function(d,i){ return color(d, i) });
  1.8592 +            groups.watchTransition(renderWatch, 'multibarhorizontal: groups')
  1.8593 +                .style('stroke-opacity', 1)
  1.8594 +                .style('fill-opacity', .75);
  1.8595 +
  1.8596 +            var bars = groups.selectAll('g.nv-bar')
  1.8597 +                .data(function(d) { return d.values });
  1.8598 +            bars.exit().remove();
  1.8599 +
  1.8600 +            var barsEnter = bars.enter().append('g')
  1.8601 +                .attr('transform', function(d,i,j) {
  1.8602 +                    return 'translate(' + y0(stacked ? d.y0 : 0) + ',' + (stacked ? 0 : (j * x.rangeBand() / data.length ) + x(getX(d,i))) + ')'
  1.8603 +                });
  1.8604 +
  1.8605 +            barsEnter.append('rect')
  1.8606 +                .attr('width', 0)
  1.8607 +                .attr('height', x.rangeBand() / (stacked ? 1 : data.length) )
  1.8608 +
  1.8609 +            bars
  1.8610 +                .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
  1.8611 +                    d3.select(this).classed('hover', true);
  1.8612 +                    dispatch.elementMouseover({
  1.8613 +                        data: d,
  1.8614 +                        index: i,
  1.8615 +                        color: d3.select(this).style("fill")
  1.8616 +                    });
  1.8617 +                })
  1.8618 +                .on('mouseout', function(d,i) {
  1.8619 +                    d3.select(this).classed('hover', false);
  1.8620 +                    dispatch.elementMouseout({
  1.8621 +                        data: d,
  1.8622 +                        index: i,
  1.8623 +                        color: d3.select(this).style("fill")
  1.8624 +                    });
  1.8625 +                })
  1.8626 +                .on('mouseout', function(d,i) {
  1.8627 +                    dispatch.elementMouseout({
  1.8628 +                        data: d,
  1.8629 +                        index: i,
  1.8630 +                        color: d3.select(this).style("fill")
  1.8631 +                    });
  1.8632 +                })
  1.8633 +                .on('mousemove', function(d,i) {
  1.8634 +                    dispatch.elementMousemove({
  1.8635 +                        data: d,
  1.8636 +                        index: i,
  1.8637 +                        color: d3.select(this).style("fill")
  1.8638 +                    });
  1.8639 +                })
  1.8640 +                .on('click', function(d,i) {
  1.8641 +                    dispatch.elementClick({
  1.8642 +                        data: d,
  1.8643 +                        index: i,
  1.8644 +                        color: d3.select(this).style("fill")
  1.8645 +                    });
  1.8646 +                    d3.event.stopPropagation();
  1.8647 +                })
  1.8648 +                .on('dblclick', function(d,i) {
  1.8649 +                    dispatch.elementDblClick({
  1.8650 +                        data: d,
  1.8651 +                        index: i,
  1.8652 +                        color: d3.select(this).style("fill")
  1.8653 +                    });
  1.8654 +                    d3.event.stopPropagation();
  1.8655 +                });
  1.8656 +
  1.8657 +            if (getYerr(data[0],0)) {
  1.8658 +                barsEnter.append('polyline');
  1.8659 +
  1.8660 +                bars.select('polyline')
  1.8661 +                    .attr('fill', 'none')
  1.8662 +                    .attr('points', function(d,i) {
  1.8663 +                        var xerr = getYerr(d,i)
  1.8664 +                            , mid = 0.8 * x.rangeBand() / ((stacked ? 1 : data.length) * 2);
  1.8665 +                        xerr = xerr.length ? xerr : [-Math.abs(xerr), Math.abs(xerr)];
  1.8666 +                        xerr = xerr.map(function(e) { return y(e) - y(0); });
  1.8667 +                        var a = [[xerr[0],-mid], [xerr[0],mid], [xerr[0],0], [xerr[1],0], [xerr[1],-mid], [xerr[1],mid]];
  1.8668 +                        return a.map(function (path) { return path.join(',') }).join(' ');
  1.8669 +                    })
  1.8670 +                    .attr('transform', function(d,i) {
  1.8671 +                        var mid = x.rangeBand() / ((stacked ? 1 : data.length) * 2);
  1.8672 +                        return 'translate(' + (getY(d,i) < 0 ? 0 : y(getY(d,i)) - y(0)) + ', ' + mid + ')'
  1.8673 +                    });
  1.8674 +            }
  1.8675 +
  1.8676 +            barsEnter.append('text');
  1.8677 +
  1.8678 +            if (showValues && !stacked) {
  1.8679 +                bars.select('text')
  1.8680 +                    .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'end' : 'start' })
  1.8681 +                    .attr('y', x.rangeBand() / (data.length * 2))
  1.8682 +                    .attr('dy', '.32em')
  1.8683 +                    .text(function(d,i) {
  1.8684 +                        var t = valueFormat(getY(d,i))
  1.8685 +                            , yerr = getYerr(d,i);
  1.8686 +                        if (yerr === undefined)
  1.8687 +                            return t;
  1.8688 +                        if (!yerr.length)
  1.8689 +                            return t + '±' + valueFormat(Math.abs(yerr));
  1.8690 +                        return t + '+' + valueFormat(Math.abs(yerr[1])) + '-' + valueFormat(Math.abs(yerr[0]));
  1.8691 +                    });
  1.8692 +                bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
  1.8693 +                    .select('text')
  1.8694 +                    .attr('x', function(d,i) { return getY(d,i) < 0 ? -4 : y(getY(d,i)) - y(0) + 4 })
  1.8695 +            } else {
  1.8696 +                bars.selectAll('text').text('');
  1.8697 +            }
  1.8698 +
  1.8699 +            if (showBarLabels && !stacked) {
  1.8700 +                barsEnter.append('text').classed('nv-bar-label',true);
  1.8701 +                bars.select('text.nv-bar-label')
  1.8702 +                    .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'start' : 'end' })
  1.8703 +                    .attr('y', x.rangeBand() / (data.length * 2))
  1.8704 +                    .attr('dy', '.32em')
  1.8705 +                    .text(function(d,i) { return getX(d,i) });
  1.8706 +                bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
  1.8707 +                    .select('text.nv-bar-label')
  1.8708 +                    .attr('x', function(d,i) { return getY(d,i) < 0 ? y(0) - y(getY(d,i)) + 4 : -4 });
  1.8709 +            }
  1.8710 +            else {
  1.8711 +                bars.selectAll('text.nv-bar-label').text('');
  1.8712 +            }
  1.8713 +
  1.8714 +            bars
  1.8715 +                .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'})
  1.8716 +
  1.8717 +            if (barColor) {
  1.8718 +                if (!disabled) disabled = data.map(function() { return true });
  1.8719 +                bars
  1.8720 +                    .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker(  disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i]  })[j]   ).toString(); })
  1.8721 +                    .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker(  disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i]  })[j]   ).toString(); });
  1.8722 +            }
  1.8723 +
  1.8724 +            if (stacked)
  1.8725 +                bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
  1.8726 +                    .attr('transform', function(d,i) {
  1.8727 +                        return 'translate(' + y(d.y1) + ',' + x(getX(d,i)) + ')'
  1.8728 +                    })
  1.8729 +                    .select('rect')
  1.8730 +                    .attr('width', function(d,i) {
  1.8731 +                        return Math.abs(y(getY(d,i) + d.y0) - y(d.y0))
  1.8732 +                    })
  1.8733 +                    .attr('height', x.rangeBand() );
  1.8734 +            else
  1.8735 +                bars.watchTransition(renderWatch, 'multibarhorizontal: bars')
  1.8736 +                    .attr('transform', function(d,i) {
  1.8737 +                        //TODO: stacked must be all positive or all negative, not both?
  1.8738 +                        return 'translate(' +
  1.8739 +                            (getY(d,i) < 0 ? y(getY(d,i)) : y(0))
  1.8740 +                            + ',' +
  1.8741 +                            (d.series * x.rangeBand() / data.length
  1.8742 +                                +
  1.8743 +                                x(getX(d,i)) )
  1.8744 +                            + ')'
  1.8745 +                    })
  1.8746 +                    .select('rect')
  1.8747 +                    .attr('height', x.rangeBand() / data.length )
  1.8748 +                    .attr('width', function(d,i) {
  1.8749 +                        return Math.max(Math.abs(y(getY(d,i)) - y(0)),1)
  1.8750 +                    });
  1.8751 +
  1.8752 +            //store old scales for use in transitions on update
  1.8753 +            x0 = x.copy();
  1.8754 +            y0 = y.copy();
  1.8755 +
  1.8756 +        });
  1.8757 +
  1.8758 +        renderWatch.renderEnd('multibarHorizontal immediate');
  1.8759 +        return chart;
  1.8760 +    }
  1.8761 +
  1.8762 +    //============================================================
  1.8763 +    // Expose Public Variables
  1.8764 +    //------------------------------------------------------------
  1.8765 +
  1.8766 +    chart.dispatch = dispatch;
  1.8767 +
  1.8768 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.8769 +
  1.8770 +    chart._options = Object.create({}, {
  1.8771 +        // simple options, just get/set the necessary values
  1.8772 +        width:   {get: function(){return width;}, set: function(_){width=_;}},
  1.8773 +        height:  {get: function(){return height;}, set: function(_){height=_;}},
  1.8774 +        x:       {get: function(){return getX;}, set: function(_){getX=_;}},
  1.8775 +        y:       {get: function(){return getY;}, set: function(_){getY=_;}},
  1.8776 +        yErr:       {get: function(){return getYerr;}, set: function(_){getYerr=_;}},
  1.8777 +        xScale:  {get: function(){return x;}, set: function(_){x=_;}},
  1.8778 +        yScale:  {get: function(){return y;}, set: function(_){y=_;}},
  1.8779 +        xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
  1.8780 +        yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
  1.8781 +        xRange:  {get: function(){return xRange;}, set: function(_){xRange=_;}},
  1.8782 +        yRange:  {get: function(){return yRange;}, set: function(_){yRange=_;}},
  1.8783 +        forceY:  {get: function(){return forceY;}, set: function(_){forceY=_;}},
  1.8784 +        stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}},
  1.8785 +        showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}},
  1.8786 +        // this shows the group name, seems pointless?
  1.8787 +        //showBarLabels:    {get: function(){return showBarLabels;}, set: function(_){showBarLabels=_;}},
  1.8788 +        disabled:     {get: function(){return disabled;}, set: function(_){disabled=_;}},
  1.8789 +        id:           {get: function(){return id;}, set: function(_){id=_;}},
  1.8790 +        valueFormat:  {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}},
  1.8791 +        valuePadding: {get: function(){return valuePadding;}, set: function(_){valuePadding=_;}},
  1.8792 +        groupSpacing:{get: function(){return groupSpacing;}, set: function(_){groupSpacing=_;}},
  1.8793 +
  1.8794 +        // options that require extra logic in the setter
  1.8795 +        margin: {get: function(){return margin;}, set: function(_){
  1.8796 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.8797 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.8798 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.8799 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.8800 +        }},
  1.8801 +        duration: {get: function(){return duration;}, set: function(_){
  1.8802 +            duration = _;
  1.8803 +            renderWatch.reset(duration);
  1.8804 +        }},
  1.8805 +        color:  {get: function(){return color;}, set: function(_){
  1.8806 +            color = nv.utils.getColor(_);
  1.8807 +        }},
  1.8808 +        barColor:  {get: function(){return barColor;}, set: function(_){
  1.8809 +            barColor = _ ? nv.utils.getColor(_) : null;
  1.8810 +        }}
  1.8811 +    });
  1.8812 +
  1.8813 +    nv.utils.initOptions(chart);
  1.8814 +
  1.8815 +    return chart;
  1.8816 +};
  1.8817 +
  1.8818 +nv.models.multiBarHorizontalChart = function() {
  1.8819 +    "use strict";
  1.8820 +
  1.8821 +    //============================================================
  1.8822 +    // Public Variables with Default Settings
  1.8823 +    //------------------------------------------------------------
  1.8824 +
  1.8825 +    var multibar = nv.models.multiBarHorizontal()
  1.8826 +        , xAxis = nv.models.axis()
  1.8827 +        , yAxis = nv.models.axis()
  1.8828 +        , legend = nv.models.legend().height(30)
  1.8829 +        , controls = nv.models.legend().height(30)
  1.8830 +        , tooltip = nv.models.tooltip()
  1.8831 +        ;
  1.8832 +
  1.8833 +    var margin = {top: 30, right: 20, bottom: 50, left: 60}
  1.8834 +        , width = null
  1.8835 +        , height = null
  1.8836 +        , color = nv.utils.defaultColor()
  1.8837 +        , showControls = true
  1.8838 +        , controlLabels = {}
  1.8839 +        , showLegend = true
  1.8840 +        , showXAxis = true
  1.8841 +        , showYAxis = true
  1.8842 +        , stacked = false
  1.8843 +        , x //can be accessed via chart.xScale()
  1.8844 +        , y //can be accessed via chart.yScale()
  1.8845 +        , state = nv.utils.state()
  1.8846 +        , defaultState = null
  1.8847 +        , noData = null
  1.8848 +        , dispatch = d3.dispatch('stateChange', 'changeState','renderEnd')
  1.8849 +        , controlWidth = function() { return showControls ? 180 : 0 }
  1.8850 +        , duration = 250
  1.8851 +        ;
  1.8852 +
  1.8853 +    state.stacked = false; // DEPRECATED Maintained for backward compatibility
  1.8854 +
  1.8855 +    multibar.stacked(stacked);
  1.8856 +
  1.8857 +    xAxis
  1.8858 +        .orient('left')
  1.8859 +        .tickPadding(5)
  1.8860 +        .showMaxMin(false)
  1.8861 +        .tickFormat(function(d) { return d })
  1.8862 +    ;
  1.8863 +    yAxis
  1.8864 +        .orient('bottom')
  1.8865 +        .tickFormat(d3.format(',.1f'))
  1.8866 +    ;
  1.8867 +
  1.8868 +    tooltip
  1.8869 +        .duration(0)
  1.8870 +        .valueFormatter(function(d, i) {
  1.8871 +            return yAxis.tickFormat()(d, i);
  1.8872 +        })
  1.8873 +        .headerFormatter(function(d, i) {
  1.8874 +            return xAxis.tickFormat()(d, i);
  1.8875 +        });
  1.8876 +
  1.8877 +    controls.updateState(false);
  1.8878 +
  1.8879 +    //============================================================
  1.8880 +    // Private Variables
  1.8881 +    //------------------------------------------------------------
  1.8882 +
  1.8883 +    var stateGetter = function(data) {
  1.8884 +        return function(){
  1.8885 +            return {
  1.8886 +                active: data.map(function(d) { return !d.disabled }),
  1.8887 +                stacked: stacked
  1.8888 +            };
  1.8889 +        }
  1.8890 +    };
  1.8891 +
  1.8892 +    var stateSetter = function(data) {
  1.8893 +        return function(state) {
  1.8894 +            if (state.stacked !== undefined)
  1.8895 +                stacked = state.stacked;
  1.8896 +            if (state.active !== undefined)
  1.8897 +                data.forEach(function(series,i) {
  1.8898 +                    series.disabled = !state.active[i];
  1.8899 +                });
  1.8900 +        }
  1.8901 +    };
  1.8902 +
  1.8903 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
  1.8904 +
  1.8905 +    function chart(selection) {
  1.8906 +        renderWatch.reset();
  1.8907 +        renderWatch.models(multibar);
  1.8908 +        if (showXAxis) renderWatch.models(xAxis);
  1.8909 +        if (showYAxis) renderWatch.models(yAxis);
  1.8910 +
  1.8911 +        selection.each(function(data) {
  1.8912 +            var container = d3.select(this),
  1.8913 +                that = this;
  1.8914 +            nv.utils.initSVG(container);
  1.8915 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.8916 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.8917 +
  1.8918 +            chart.update = function() { container.transition().duration(duration).call(chart) };
  1.8919 +            chart.container = this;
  1.8920 +
  1.8921 +            stacked = multibar.stacked();
  1.8922 +
  1.8923 +            state
  1.8924 +                .setter(stateSetter(data), chart.update)
  1.8925 +                .getter(stateGetter(data))
  1.8926 +                .update();
  1.8927 +
  1.8928 +            // DEPRECATED set state.disableddisabled
  1.8929 +            state.disabled = data.map(function(d) { return !!d.disabled });
  1.8930 +
  1.8931 +            if (!defaultState) {
  1.8932 +                var key;
  1.8933 +                defaultState = {};
  1.8934 +                for (key in state) {
  1.8935 +                    if (state[key] instanceof Array)
  1.8936 +                        defaultState[key] = state[key].slice(0);
  1.8937 +                    else
  1.8938 +                        defaultState[key] = state[key];
  1.8939 +                }
  1.8940 +            }
  1.8941 +
  1.8942 +            // Display No Data message if there's nothing to show.
  1.8943 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.8944 +                nv.utils.noData(chart, container)
  1.8945 +                return chart;
  1.8946 +            } else {
  1.8947 +                container.selectAll('.nv-noData').remove();
  1.8948 +            }
  1.8949 +
  1.8950 +            // Setup Scales
  1.8951 +            x = multibar.xScale();
  1.8952 +            y = multibar.yScale();
  1.8953 +
  1.8954 +            // Setup containers and skeleton of chart
  1.8955 +            var wrap = container.selectAll('g.nv-wrap.nv-multiBarHorizontalChart').data([data]);
  1.8956 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarHorizontalChart').append('g');
  1.8957 +            var g = wrap.select('g');
  1.8958 +
  1.8959 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
  1.8960 +            gEnter.append('g').attr('class', 'nv-y nv-axis')
  1.8961 +                .append('g').attr('class', 'nv-zeroLine')
  1.8962 +                .append('line');
  1.8963 +            gEnter.append('g').attr('class', 'nv-barsWrap');
  1.8964 +            gEnter.append('g').attr('class', 'nv-legendWrap');
  1.8965 +            gEnter.append('g').attr('class', 'nv-controlsWrap');
  1.8966 +
  1.8967 +            // Legend
  1.8968 +            if (showLegend) {
  1.8969 +                legend.width(availableWidth - controlWidth());
  1.8970 +
  1.8971 +                g.select('.nv-legendWrap')
  1.8972 +                    .datum(data)
  1.8973 +                    .call(legend);
  1.8974 +
  1.8975 +                if ( margin.top != legend.height()) {
  1.8976 +                    margin.top = legend.height();
  1.8977 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
  1.8978 +                }
  1.8979 +
  1.8980 +                g.select('.nv-legendWrap')
  1.8981 +                    .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')');
  1.8982 +            }
  1.8983 +
  1.8984 +            // Controls
  1.8985 +            if (showControls) {
  1.8986 +                var controlsData = [
  1.8987 +                    { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() },
  1.8988 +                    { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() }
  1.8989 +                ];
  1.8990 +
  1.8991 +                controls.width(controlWidth()).color(['#444', '#444', '#444']);
  1.8992 +                g.select('.nv-controlsWrap')
  1.8993 +                    .datum(controlsData)
  1.8994 +                    .attr('transform', 'translate(0,' + (-margin.top) +')')
  1.8995 +                    .call(controls);
  1.8996 +            }
  1.8997 +
  1.8998 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.8999 +
  1.9000 +            // Main Chart Component(s)
  1.9001 +            multibar
  1.9002 +                .disabled(data.map(function(series) { return series.disabled }))
  1.9003 +                .width(availableWidth)
  1.9004 +                .height(availableHeight)
  1.9005 +                .color(data.map(function(d,i) {
  1.9006 +                    return d.color || color(d, i);
  1.9007 +                }).filter(function(d,i) { return !data[i].disabled }));
  1.9008 +
  1.9009 +            var barsWrap = g.select('.nv-barsWrap')
  1.9010 +                .datum(data.filter(function(d) { return !d.disabled }));
  1.9011 +
  1.9012 +            barsWrap.transition().call(multibar);
  1.9013 +
  1.9014 +            // Setup Axes
  1.9015 +            if (showXAxis) {
  1.9016 +                xAxis
  1.9017 +                    .scale(x)
  1.9018 +                    ._ticks( nv.utils.calcTicksY(availableHeight/24, data) )
  1.9019 +                    .tickSize(-availableWidth, 0);
  1.9020 +
  1.9021 +                g.select('.nv-x.nv-axis').call(xAxis);
  1.9022 +
  1.9023 +                var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
  1.9024 +
  1.9025 +                xTicks
  1.9026 +                    .selectAll('line, text');
  1.9027 +            }
  1.9028 +
  1.9029 +            if (showYAxis) {
  1.9030 +                yAxis
  1.9031 +                    .scale(y)
  1.9032 +                    ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.9033 +                    .tickSize( -availableHeight, 0);
  1.9034 +
  1.9035 +                g.select('.nv-y.nv-axis')
  1.9036 +                    .attr('transform', 'translate(0,' + availableHeight + ')');
  1.9037 +                g.select('.nv-y.nv-axis').call(yAxis);
  1.9038 +            }
  1.9039 +
  1.9040 +            // Zero line
  1.9041 +            g.select(".nv-zeroLine line")
  1.9042 +                .attr("x1", y(0))
  1.9043 +                .attr("x2", y(0))
  1.9044 +                .attr("y1", 0)
  1.9045 +                .attr("y2", -availableHeight)
  1.9046 +            ;
  1.9047 +
  1.9048 +            //============================================================
  1.9049 +            // Event Handling/Dispatching (in chart's scope)
  1.9050 +            //------------------------------------------------------------
  1.9051 +
  1.9052 +            legend.dispatch.on('stateChange', function(newState) {
  1.9053 +                for (var key in newState)
  1.9054 +                    state[key] = newState[key];
  1.9055 +                dispatch.stateChange(state);
  1.9056 +                chart.update();
  1.9057 +            });
  1.9058 +
  1.9059 +            controls.dispatch.on('legendClick', function(d,i) {
  1.9060 +                if (!d.disabled) return;
  1.9061 +                controlsData = controlsData.map(function(s) {
  1.9062 +                    s.disabled = true;
  1.9063 +                    return s;
  1.9064 +                });
  1.9065 +                d.disabled = false;
  1.9066 +
  1.9067 +                switch (d.key) {
  1.9068 +                    case 'Grouped':
  1.9069 +                        multibar.stacked(false);
  1.9070 +                        break;
  1.9071 +                    case 'Stacked':
  1.9072 +                        multibar.stacked(true);
  1.9073 +                        break;
  1.9074 +                }
  1.9075 +
  1.9076 +                state.stacked = multibar.stacked();
  1.9077 +                dispatch.stateChange(state);
  1.9078 +                stacked = multibar.stacked();
  1.9079 +
  1.9080 +                chart.update();
  1.9081 +            });
  1.9082 +
  1.9083 +            // Update chart from a state object passed to event handler
  1.9084 +            dispatch.on('changeState', function(e) {
  1.9085 +
  1.9086 +                if (typeof e.disabled !== 'undefined') {
  1.9087 +                    data.forEach(function(series,i) {
  1.9088 +                        series.disabled = e.disabled[i];
  1.9089 +                    });
  1.9090 +
  1.9091 +                    state.disabled = e.disabled;
  1.9092 +                }
  1.9093 +
  1.9094 +                if (typeof e.stacked !== 'undefined') {
  1.9095 +                    multibar.stacked(e.stacked);
  1.9096 +                    state.stacked = e.stacked;
  1.9097 +                    stacked = e.stacked;
  1.9098 +                }
  1.9099 +
  1.9100 +                chart.update();
  1.9101 +            });
  1.9102 +        });
  1.9103 +        renderWatch.renderEnd('multibar horizontal chart immediate');
  1.9104 +        return chart;
  1.9105 +    }
  1.9106 +
  1.9107 +    //============================================================
  1.9108 +    // Event Handling/Dispatching (out of chart's scope)
  1.9109 +    //------------------------------------------------------------
  1.9110 +
  1.9111 +    multibar.dispatch.on('elementMouseover.tooltip', function(evt) {
  1.9112 +        evt.value = chart.x()(evt.data);
  1.9113 +        evt['series'] = {
  1.9114 +            key: evt.data.key,
  1.9115 +            value: chart.y()(evt.data),
  1.9116 +            color: evt.color
  1.9117 +        };
  1.9118 +        tooltip.data(evt).hidden(false);
  1.9119 +    });
  1.9120 +
  1.9121 +    multibar.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.9122 +        tooltip.hidden(true);
  1.9123 +    });
  1.9124 +
  1.9125 +    multibar.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.9126 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.9127 +    });
  1.9128 +
  1.9129 +    //============================================================
  1.9130 +    // Expose Public Variables
  1.9131 +    //------------------------------------------------------------
  1.9132 +
  1.9133 +    // expose chart's sub-components
  1.9134 +    chart.dispatch = dispatch;
  1.9135 +    chart.multibar = multibar;
  1.9136 +    chart.legend = legend;
  1.9137 +    chart.controls = controls;
  1.9138 +    chart.xAxis = xAxis;
  1.9139 +    chart.yAxis = yAxis;
  1.9140 +    chart.state = state;
  1.9141 +    chart.tooltip = tooltip;
  1.9142 +
  1.9143 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.9144 +
  1.9145 +    chart._options = Object.create({}, {
  1.9146 +        // simple options, just get/set the necessary values
  1.9147 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.9148 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.9149 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.9150 +        showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}},
  1.9151 +        controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}},
  1.9152 +        showXAxis:      {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
  1.9153 +        showYAxis:    {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
  1.9154 +        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
  1.9155 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.9156 +
  1.9157 +        // deprecated options
  1.9158 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.9159 +            // deprecated after 1.7.1
  1.9160 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.9161 +            tooltip.enabled(!!_);
  1.9162 +        }},
  1.9163 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.9164 +            // deprecated after 1.7.1
  1.9165 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.9166 +            tooltip.contentGenerator(_);
  1.9167 +        }},
  1.9168 +
  1.9169 +        // options that require extra logic in the setter
  1.9170 +        margin: {get: function(){return margin;}, set: function(_){
  1.9171 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.9172 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.9173 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.9174 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.9175 +        }},
  1.9176 +        duration: {get: function(){return duration;}, set: function(_){
  1.9177 +            duration = _;
  1.9178 +            renderWatch.reset(duration);
  1.9179 +            multibar.duration(duration);
  1.9180 +            xAxis.duration(duration);
  1.9181 +            yAxis.duration(duration);
  1.9182 +        }},
  1.9183 +        color:  {get: function(){return color;}, set: function(_){
  1.9184 +            color = nv.utils.getColor(_);
  1.9185 +            legend.color(color);
  1.9186 +        }},
  1.9187 +        barColor:  {get: function(){return multibar.barColor;}, set: function(_){
  1.9188 +            multibar.barColor(_);
  1.9189 +            legend.color(function(d,i) {return d3.rgb('#ccc').darker(i * 1.5).toString();})
  1.9190 +        }}
  1.9191 +    });
  1.9192 +
  1.9193 +    nv.utils.inheritOptions(chart, multibar);
  1.9194 +    nv.utils.initOptions(chart);
  1.9195 +
  1.9196 +    return chart;
  1.9197 +};
  1.9198 +nv.models.multiChart = function() {
  1.9199 +    "use strict";
  1.9200 +
  1.9201 +    //============================================================
  1.9202 +    // Public Variables with Default Settings
  1.9203 +    //------------------------------------------------------------
  1.9204 +
  1.9205 +    var margin = {top: 30, right: 20, bottom: 50, left: 60},
  1.9206 +        color = nv.utils.defaultColor(),
  1.9207 +        width = null,
  1.9208 +        height = null,
  1.9209 +        showLegend = true,
  1.9210 +        noData = null,
  1.9211 +        yDomain1,
  1.9212 +        yDomain2,
  1.9213 +        getX = function(d) { return d.x },
  1.9214 +        getY = function(d) { return d.y},
  1.9215 +        interpolate = 'monotone',
  1.9216 +        useVoronoi = true
  1.9217 +        ;
  1.9218 +
  1.9219 +    //============================================================
  1.9220 +    // Private Variables
  1.9221 +    //------------------------------------------------------------
  1.9222 +
  1.9223 +    var x = d3.scale.linear(),
  1.9224 +        yScale1 = d3.scale.linear(),
  1.9225 +        yScale2 = d3.scale.linear(),
  1.9226 +
  1.9227 +        lines1 = nv.models.line().yScale(yScale1),
  1.9228 +        lines2 = nv.models.line().yScale(yScale2),
  1.9229 +
  1.9230 +        bars1 = nv.models.multiBar().stacked(false).yScale(yScale1),
  1.9231 +        bars2 = nv.models.multiBar().stacked(false).yScale(yScale2),
  1.9232 +
  1.9233 +        stack1 = nv.models.stackedArea().yScale(yScale1),
  1.9234 +        stack2 = nv.models.stackedArea().yScale(yScale2),
  1.9235 +
  1.9236 +        xAxis = nv.models.axis().scale(x).orient('bottom').tickPadding(5),
  1.9237 +        yAxis1 = nv.models.axis().scale(yScale1).orient('left'),
  1.9238 +        yAxis2 = nv.models.axis().scale(yScale2).orient('right'),
  1.9239 +
  1.9240 +        legend = nv.models.legend().height(30),
  1.9241 +        tooltip = nv.models.tooltip(),
  1.9242 +        dispatch = d3.dispatch();
  1.9243 +
  1.9244 +    function chart(selection) {
  1.9245 +        selection.each(function(data) {
  1.9246 +            var container = d3.select(this),
  1.9247 +                that = this;
  1.9248 +            nv.utils.initSVG(container);
  1.9249 +
  1.9250 +            chart.update = function() { container.transition().call(chart); };
  1.9251 +            chart.container = this;
  1.9252 +
  1.9253 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.9254 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.9255 +
  1.9256 +            var dataLines1 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 1});
  1.9257 +            var dataLines2 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 2});
  1.9258 +            var dataBars1 =  data.filter(function(d) {return d.type == 'bar'  && d.yAxis == 1});
  1.9259 +            var dataBars2 =  data.filter(function(d) {return d.type == 'bar'  && d.yAxis == 2});
  1.9260 +            var dataStack1 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 1});
  1.9261 +            var dataStack2 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 2});
  1.9262 +
  1.9263 +            // Display noData message if there's nothing to show.
  1.9264 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
  1.9265 +                nv.utils.noData(chart, container);
  1.9266 +                return chart;
  1.9267 +            } else {
  1.9268 +                container.selectAll('.nv-noData').remove();
  1.9269 +            }
  1.9270 +
  1.9271 +            var series1 = data.filter(function(d) {return !d.disabled && d.yAxis == 1})
  1.9272 +                .map(function(d) {
  1.9273 +                    return d.values.map(function(d,i) {
  1.9274 +                        return { x: d.x, y: d.y }
  1.9275 +                    })
  1.9276 +                });
  1.9277 +
  1.9278 +            var series2 = data.filter(function(d) {return !d.disabled && d.yAxis == 2})
  1.9279 +                .map(function(d) {
  1.9280 +                    return d.values.map(function(d,i) {
  1.9281 +                        return { x: d.x, y: d.y }
  1.9282 +                    })
  1.9283 +                });
  1.9284 +
  1.9285 +            x   .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } ))
  1.9286 +                .range([0, availableWidth]);
  1.9287 +
  1.9288 +            var wrap = container.selectAll('g.wrap.multiChart').data([data]);
  1.9289 +            var gEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 multiChart').append('g');
  1.9290 +
  1.9291 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
  1.9292 +            gEnter.append('g').attr('class', 'nv-y1 nv-axis');
  1.9293 +            gEnter.append('g').attr('class', 'nv-y2 nv-axis');
  1.9294 +            gEnter.append('g').attr('class', 'lines1Wrap');
  1.9295 +            gEnter.append('g').attr('class', 'lines2Wrap');
  1.9296 +            gEnter.append('g').attr('class', 'bars1Wrap');
  1.9297 +            gEnter.append('g').attr('class', 'bars2Wrap');
  1.9298 +            gEnter.append('g').attr('class', 'stack1Wrap');
  1.9299 +            gEnter.append('g').attr('class', 'stack2Wrap');
  1.9300 +            gEnter.append('g').attr('class', 'legendWrap');
  1.9301 +
  1.9302 +            var g = wrap.select('g');
  1.9303 +
  1.9304 +            var color_array = data.map(function(d,i) {
  1.9305 +                return data[i].color || color(d, i);
  1.9306 +            });
  1.9307 +
  1.9308 +            if (showLegend) {
  1.9309 +                var legendWidth = legend.align() ? availableWidth / 2 : availableWidth;
  1.9310 +                var legendXPosition = legend.align() ? legendWidth : 0;
  1.9311 +
  1.9312 +                legend.width(legendWidth);
  1.9313 +                legend.color(color_array);
  1.9314 +
  1.9315 +                g.select('.legendWrap')
  1.9316 +                    .datum(data.map(function(series) {
  1.9317 +                        series.originalKey = series.originalKey === undefined ? series.key : series.originalKey;
  1.9318 +                        series.key = series.originalKey + (series.yAxis == 1 ? '' : ' (right axis)');
  1.9319 +                        return series;
  1.9320 +                    }))
  1.9321 +                    .call(legend);
  1.9322 +
  1.9323 +                if ( margin.top != legend.height()) {
  1.9324 +                    margin.top = legend.height();
  1.9325 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
  1.9326 +                }
  1.9327 +
  1.9328 +                g.select('.legendWrap')
  1.9329 +                    .attr('transform', 'translate(' + legendXPosition + ',' + (-margin.top) +')');
  1.9330 +            }
  1.9331 +
  1.9332 +            lines1
  1.9333 +                .width(availableWidth)
  1.9334 +                .height(availableHeight)
  1.9335 +                .interpolate(interpolate)
  1.9336 +                .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'line'}));
  1.9337 +            lines2
  1.9338 +                .width(availableWidth)
  1.9339 +                .height(availableHeight)
  1.9340 +                .interpolate(interpolate)
  1.9341 +                .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'line'}));
  1.9342 +            bars1
  1.9343 +                .width(availableWidth)
  1.9344 +                .height(availableHeight)
  1.9345 +                .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'bar'}));
  1.9346 +            bars2
  1.9347 +                .width(availableWidth)
  1.9348 +                .height(availableHeight)
  1.9349 +                .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'bar'}));
  1.9350 +            stack1
  1.9351 +                .width(availableWidth)
  1.9352 +                .height(availableHeight)
  1.9353 +                .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'area'}));
  1.9354 +            stack2
  1.9355 +                .width(availableWidth)
  1.9356 +                .height(availableHeight)
  1.9357 +                .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'area'}));
  1.9358 +
  1.9359 +            g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.9360 +
  1.9361 +            var lines1Wrap = g.select('.lines1Wrap')
  1.9362 +                .datum(dataLines1.filter(function(d){return !d.disabled}));
  1.9363 +            var bars1Wrap = g.select('.bars1Wrap')
  1.9364 +                .datum(dataBars1.filter(function(d){return !d.disabled}));
  1.9365 +            var stack1Wrap = g.select('.stack1Wrap')
  1.9366 +                .datum(dataStack1.filter(function(d){return !d.disabled}));
  1.9367 +            var lines2Wrap = g.select('.lines2Wrap')
  1.9368 +                .datum(dataLines2.filter(function(d){return !d.disabled}));
  1.9369 +            var bars2Wrap = g.select('.bars2Wrap')
  1.9370 +                .datum(dataBars2.filter(function(d){return !d.disabled}));
  1.9371 +            var stack2Wrap = g.select('.stack2Wrap')
  1.9372 +                .datum(dataStack2.filter(function(d){return !d.disabled}));
  1.9373 +
  1.9374 +            var extraValue1 = dataStack1.length ? dataStack1.map(function(a){return a.values}).reduce(function(a,b){
  1.9375 +                return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}})
  1.9376 +            }).concat([{x:0, y:0}]) : [];
  1.9377 +            var extraValue2 = dataStack2.length ? dataStack2.map(function(a){return a.values}).reduce(function(a,b){
  1.9378 +                return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}})
  1.9379 +            }).concat([{x:0, y:0}]) : [];
  1.9380 +
  1.9381 +            yScale1 .domain(yDomain1 || d3.extent(d3.merge(series1).concat(extraValue1), function(d) { return d.y } ))
  1.9382 +                .range([0, availableHeight]);
  1.9383 +
  1.9384 +            yScale2 .domain(yDomain2 || d3.extent(d3.merge(series2).concat(extraValue2), function(d) { return d.y } ))
  1.9385 +                .range([0, availableHeight]);
  1.9386 +
  1.9387 +            lines1.yDomain(yScale1.domain());
  1.9388 +            bars1.yDomain(yScale1.domain());
  1.9389 +            stack1.yDomain(yScale1.domain());
  1.9390 +
  1.9391 +            lines2.yDomain(yScale2.domain());
  1.9392 +            bars2.yDomain(yScale2.domain());
  1.9393 +            stack2.yDomain(yScale2.domain());
  1.9394 +
  1.9395 +            if(dataStack1.length){d3.transition(stack1Wrap).call(stack1);}
  1.9396 +            if(dataStack2.length){d3.transition(stack2Wrap).call(stack2);}
  1.9397 +
  1.9398 +            if(dataBars1.length){d3.transition(bars1Wrap).call(bars1);}
  1.9399 +            if(dataBars2.length){d3.transition(bars2Wrap).call(bars2);}
  1.9400 +
  1.9401 +            if(dataLines1.length){d3.transition(lines1Wrap).call(lines1);}
  1.9402 +            if(dataLines2.length){d3.transition(lines2Wrap).call(lines2);}
  1.9403 +
  1.9404 +            xAxis
  1.9405 +                ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
  1.9406 +                .tickSize(-availableHeight, 0);
  1.9407 +
  1.9408 +            g.select('.nv-x.nv-axis')
  1.9409 +                .attr('transform', 'translate(0,' + availableHeight + ')');
  1.9410 +            d3.transition(g.select('.nv-x.nv-axis'))
  1.9411 +                .call(xAxis);
  1.9412 +
  1.9413 +            yAxis1
  1.9414 +                ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
  1.9415 +                .tickSize( -availableWidth, 0);
  1.9416 +
  1.9417 +
  1.9418 +            d3.transition(g.select('.nv-y1.nv-axis'))
  1.9419 +                .call(yAxis1);
  1.9420 +
  1.9421 +            yAxis2
  1.9422 +                ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
  1.9423 +                .tickSize( -availableWidth, 0);
  1.9424 +
  1.9425 +            d3.transition(g.select('.nv-y2.nv-axis'))
  1.9426 +                .call(yAxis2);
  1.9427 +
  1.9428 +            g.select('.nv-y1.nv-axis')
  1.9429 +                .classed('nv-disabled', series1.length ? false : true)
  1.9430 +                .attr('transform', 'translate(' + x.range()[0] + ',0)');
  1.9431 +
  1.9432 +            g.select('.nv-y2.nv-axis')
  1.9433 +                .classed('nv-disabled', series2.length ? false : true)
  1.9434 +                .attr('transform', 'translate(' + x.range()[1] + ',0)');
  1.9435 +
  1.9436 +            legend.dispatch.on('stateChange', function(newState) {
  1.9437 +                chart.update();
  1.9438 +            });
  1.9439 +
  1.9440 +            //============================================================
  1.9441 +            // Event Handling/Dispatching
  1.9442 +            //------------------------------------------------------------
  1.9443 +
  1.9444 +            function mouseover_line(evt) {
  1.9445 +                var yaxis = data[evt.seriesIndex].yAxis === 2 ? yAxis2 : yAxis1;
  1.9446 +                evt.value = evt.point.x;
  1.9447 +                evt.series = {
  1.9448 +                    value: evt.point.y,
  1.9449 +                    color: evt.point.color
  1.9450 +                };
  1.9451 +                tooltip
  1.9452 +                    .duration(100)
  1.9453 +                    .valueFormatter(function(d, i) {
  1.9454 +                        return yaxis.tickFormat()(d, i);
  1.9455 +                    })
  1.9456 +                    .data(evt)
  1.9457 +                    .position(evt.pos)
  1.9458 +                    .hidden(false);
  1.9459 +            }
  1.9460 +
  1.9461 +            function mouseover_stack(evt) {
  1.9462 +                var yaxis = data[evt.seriesIndex].yAxis === 2 ? yAxis2 : yAxis1;
  1.9463 +                evt.point['x'] = stack1.x()(evt.point);
  1.9464 +                evt.point['y'] = stack1.y()(evt.point);
  1.9465 +                tooltip
  1.9466 +                    .duration(100)
  1.9467 +                    .valueFormatter(function(d, i) {
  1.9468 +                        return yaxis.tickFormat()(d, i);
  1.9469 +                    })
  1.9470 +                    .data(evt)
  1.9471 +                    .position(evt.pos)
  1.9472 +                    .hidden(false);
  1.9473 +            }
  1.9474 +
  1.9475 +            function mouseover_bar(evt) {
  1.9476 +                var yaxis = data[evt.data.series].yAxis === 2 ? yAxis2 : yAxis1;
  1.9477 +
  1.9478 +                evt.value = bars1.x()(evt.data);
  1.9479 +                evt['series'] = {
  1.9480 +                    value: bars1.y()(evt.data),
  1.9481 +                    color: evt.color
  1.9482 +                };
  1.9483 +                tooltip
  1.9484 +                    .duration(0)
  1.9485 +                    .valueFormatter(function(d, i) {
  1.9486 +                        return yaxis.tickFormat()(d, i);
  1.9487 +                    })
  1.9488 +                    .data(evt)
  1.9489 +                    .hidden(false);
  1.9490 +            }
  1.9491 +
  1.9492 +            lines1.dispatch.on('elementMouseover.tooltip', mouseover_line);
  1.9493 +            lines2.dispatch.on('elementMouseover.tooltip', mouseover_line);
  1.9494 +            lines1.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.9495 +                tooltip.hidden(true)
  1.9496 +            });
  1.9497 +            lines2.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.9498 +                tooltip.hidden(true)
  1.9499 +            });
  1.9500 +
  1.9501 +            stack1.dispatch.on('elementMouseover.tooltip', mouseover_stack);
  1.9502 +            stack2.dispatch.on('elementMouseover.tooltip', mouseover_stack);
  1.9503 +            stack1.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.9504 +                tooltip.hidden(true)
  1.9505 +            });
  1.9506 +            stack2.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.9507 +                tooltip.hidden(true)
  1.9508 +            });
  1.9509 +
  1.9510 +            bars1.dispatch.on('elementMouseover.tooltip', mouseover_bar);
  1.9511 +            bars2.dispatch.on('elementMouseover.tooltip', mouseover_bar);
  1.9512 +
  1.9513 +            bars1.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.9514 +                tooltip.hidden(true);
  1.9515 +            });
  1.9516 +            bars2.dispatch.on('elementMouseout.tooltip', function(evt) {
  1.9517 +                tooltip.hidden(true);
  1.9518 +            });
  1.9519 +            bars1.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.9520 +                tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.9521 +            });
  1.9522 +            bars2.dispatch.on('elementMousemove.tooltip', function(evt) {
  1.9523 +                tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
  1.9524 +            });
  1.9525 +
  1.9526 +        });
  1.9527 +
  1.9528 +        return chart;
  1.9529 +    }
  1.9530 +
  1.9531 +    //============================================================
  1.9532 +    // Global getters and setters
  1.9533 +    //------------------------------------------------------------
  1.9534 +
  1.9535 +    chart.dispatch = dispatch;
  1.9536 +    chart.lines1 = lines1;
  1.9537 +    chart.lines2 = lines2;
  1.9538 +    chart.bars1 = bars1;
  1.9539 +    chart.bars2 = bars2;
  1.9540 +    chart.stack1 = stack1;
  1.9541 +    chart.stack2 = stack2;
  1.9542 +    chart.xAxis = xAxis;
  1.9543 +    chart.yAxis1 = yAxis1;
  1.9544 +    chart.yAxis2 = yAxis2;
  1.9545 +    chart.tooltip = tooltip;
  1.9546 +
  1.9547 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.9548 +
  1.9549 +    chart._options = Object.create({}, {
  1.9550 +        // simple options, just get/set the necessary values
  1.9551 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
  1.9552 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
  1.9553 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
  1.9554 +        yDomain1:      {get: function(){return yDomain1;}, set: function(_){yDomain1=_;}},
  1.9555 +        yDomain2:    {get: function(){return yDomain2;}, set: function(_){yDomain2=_;}},
  1.9556 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
  1.9557 +        interpolate:    {get: function(){return interpolate;}, set: function(_){interpolate=_;}},
  1.9558 +
  1.9559 +        // deprecated options
  1.9560 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
  1.9561 +            // deprecated after 1.7.1
  1.9562 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
  1.9563 +            tooltip.enabled(!!_);
  1.9564 +        }},
  1.9565 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
  1.9566 +            // deprecated after 1.7.1
  1.9567 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
  1.9568 +            tooltip.contentGenerator(_);
  1.9569 +        }},
  1.9570 +
  1.9571 +        // options that require extra logic in the setter
  1.9572 +        margin: {get: function(){return margin;}, set: function(_){
  1.9573 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
  1.9574 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
  1.9575 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
  1.9576 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
  1.9577 +        }},
  1.9578 +        color:  {get: function(){return color;}, set: function(_){
  1.9579 +            color = nv.utils.getColor(_);
  1.9580 +        }},
  1.9581 +        x: {get: function(){return getX;}, set: function(_){
  1.9582 +            getX = _;
  1.9583 +            lines1.x(_);
  1.9584 +            lines2.x(_);
  1.9585 +            bars1.x(_);
  1.9586 +            bars2.x(_);
  1.9587 +            stack1.x(_);
  1.9588 +            stack2.x(_);
  1.9589 +        }},
  1.9590 +        y: {get: function(){return getY;}, set: function(_){
  1.9591 +            getY = _;
  1.9592 +            lines1.y(_);
  1.9593 +            lines2.y(_);
  1.9594 +            stack1.y(_);
  1.9595 +            stack2.y(_);
  1.9596 +            bars1.y(_);
  1.9597 +            bars2.y(_);
  1.9598 +        }},
  1.9599 +        useVoronoi: {get: function(){return useVoronoi;}, set: function(_){
  1.9600 +            useVoronoi=_;
  1.9601 +            lines1.useVoronoi(_);
  1.9602 +            lines2.useVoronoi(_);
  1.9603 +            stack1.useVoronoi(_);
  1.9604 +            stack2.useVoronoi(_);
  1.9605 +        }}
  1.9606 +    });
  1.9607 +
  1.9608 +    nv.utils.initOptions(chart);
  1.9609 +
  1.9610 +    return chart;
  1.9611 +};
  1.9612 +
  1.9613 +
  1.9614 +nv.models.ohlcBar = function() {
  1.9615 +    "use strict";
  1.9616 +
  1.9617 +    //============================================================
  1.9618 +    // Public Variables with Default Settings
  1.9619 +    //------------------------------------------------------------
  1.9620 +
  1.9621 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
  1.9622 +        , width = null
  1.9623 +        , height = null
  1.9624 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
  1.9625 +        , container = null
  1.9626 +        , x = d3.scale.linear()
  1.9627 +        , y = d3.scale.linear()
  1.9628 +        , getX = function(d) { return d.x }
  1.9629 +        , getY = function(d) { return d.y }
  1.9630 +        , getOpen = function(d) { return d.open }
  1.9631 +        , getClose = function(d) { return d.close }
  1.9632 +        , getHigh = function(d) { return d.high }
  1.9633 +        , getLow = function(d) { return d.low }
  1.9634 +        , forceX = []
  1.9635 +        , forceY = []
  1.9636 +        , padData     = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
  1.9637 +        , clipEdge = true
  1.9638 +        , color = nv.utils.defaultColor()
  1.9639 +        , interactive = false
  1.9640 +        , xDomain
  1.9641 +        , yDomain
  1.9642 +        , xRange
  1.9643 +        , yRange
  1.9644 +        , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove')
  1.9645 +        ;
  1.9646 +
  1.9647 +    //============================================================
  1.9648 +    // Private Variables
  1.9649 +    //------------------------------------------------------------
  1.9650 +
  1.9651 +    function chart(selection) {
  1.9652 +        selection.each(function(data) {
  1.9653 +            container = d3.select(this);
  1.9654 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.9655 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.9656 +
  1.9657 +            nv.utils.initSVG(container);
  1.9658 +
  1.9659 +            // ohlc bar width.
  1.9660 +            var w = (availableWidth / data[0].values.length) * .9;
  1.9661 +
  1.9662 +            // Setup Scales
  1.9663 +            x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ));
  1.9664 +
  1.9665 +            if (padData)
  1.9666 +                x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5)  / data[0].values.length ]);
  1.9667 +            else
  1.9668 +                x.range(xRange || [5 + w/2, availableWidth - w/2 - 5]);
  1.9669 +
  1.9670 +            y.domain(yDomain || [
  1.9671 +                    d3.min(data[0].values.map(getLow).concat(forceY)),
  1.9672 +                    d3.max(data[0].values.map(getHigh).concat(forceY))
  1.9673 +                ]
  1.9674 +            ).range(yRange || [availableHeight, 0]);
  1.9675 +
  1.9676 +            // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
  1.9677 +            if (x.domain()[0] === x.domain()[1])
  1.9678 +                x.domain()[0] ?
  1.9679 +                    x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
  1.9680 +                    : x.domain([-1,1]);
  1.9681 +
  1.9682 +            if (y.domain()[0] === y.domain()[1])
  1.9683 +                y.domain()[0] ?
  1.9684 +                    y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
  1.9685 +                    : y.domain([-1,1]);
  1.9686 +
  1.9687 +            // Setup containers and skeleton of chart
  1.9688 +            var wrap = d3.select(this).selectAll('g.nv-wrap.nv-ohlcBar').data([data[0].values]);
  1.9689 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-ohlcBar');
  1.9690 +            var defsEnter = wrapEnter.append('defs');
  1.9691 +            var gEnter = wrapEnter.append('g');
  1.9692 +            var g = wrap.select('g');
  1.9693 +
  1.9694 +            gEnter.append('g').attr('class', 'nv-ticks');
  1.9695 +
  1.9696 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.9697 +
  1.9698 +            container
  1.9699 +                .on('click', function(d,i) {
  1.9700 +                    dispatch.chartClick({
  1.9701 +                        data: d,
  1.9702 +                        index: i,
  1.9703 +                        pos: d3.event,
  1.9704 +                        id: id
  1.9705 +                    });
  1.9706 +                });
  1.9707 +
  1.9708 +            defsEnter.append('clipPath')
  1.9709 +                .attr('id', 'nv-chart-clip-path-' + id)
  1.9710 +                .append('rect');
  1.9711 +
  1.9712 +            wrap.select('#nv-chart-clip-path-' + id + ' rect')
  1.9713 +                .attr('width', availableWidth)
  1.9714 +                .attr('height', availableHeight);
  1.9715 +
  1.9716 +            g   .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
  1.9717 +
  1.9718 +            var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick')
  1.9719 +                .data(function(d) { return d });
  1.9720 +            ticks.exit().remove();
  1.9721 +
  1.9722 +            ticks.enter().append('path')
  1.9723 +                .attr('class', function(d,i,j) { return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i })
  1.9724 +                .attr('d', function(d,i) {
  1.9725 +                    return 'm0,0l0,'
  1.9726 +                        + (y(getOpen(d,i))
  1.9727 +                            - y(getHigh(d,i)))
  1.9728 +                        + 'l'
  1.9729 +                        + (-w/2)
  1.9730 +                        + ',0l'
  1.9731 +                        + (w/2)
  1.9732 +                        + ',0l0,'
  1.9733 +                        + (y(getLow(d,i)) - y(getOpen(d,i)))
  1.9734 +                        + 'l0,'
  1.9735 +                        + (y(getClose(d,i))
  1.9736 +                            - y(getLow(d,i)))
  1.9737 +                        + 'l'
  1.9738 +                        + (w/2)
  1.9739 +                        + ',0l'
  1.9740 +                        + (-w/2)
  1.9741 +                        + ',0z';
  1.9742 +                })
  1.9743 +                .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; })
  1.9744 +                .attr('fill', function(d,i) { return color[0]; })
  1.9745 +                .attr('stroke', function(d,i) { return color[0]; })
  1.9746 +                .attr('x', 0 )
  1.9747 +                .attr('y', function(d,i) {  return y(Math.max(0, getY(d,i))) })
  1.9748 +                .attr('height', function(d,i) { return Math.abs(y(getY(d,i)) - y(0)) });
  1.9749 +
  1.9750 +            // the bar colors are controlled by CSS currently
  1.9751 +            ticks.attr('class', function(d,i,j) {
  1.9752 +                return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i;
  1.9753 +            });
  1.9754 +
  1.9755 +            d3.transition(ticks)
  1.9756 +                .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; })
  1.9757 +                .attr('d', function(d,i) {
  1.9758 +                    var w = (availableWidth / data[0].values.length) * .9;
  1.9759 +                    return 'm0,0l0,'
  1.9760 +                        + (y(getOpen(d,i))
  1.9761 +                            - y(getHigh(d,i)))
  1.9762 +                        + 'l'
  1.9763 +                        + (-w/2)
  1.9764 +                        + ',0l'
  1.9765 +                        + (w/2)
  1.9766 +                        + ',0l0,'
  1.9767 +                        + (y(getLow(d,i))
  1.9768 +                            - y(getOpen(d,i)))
  1.9769 +                        + 'l0,'
  1.9770 +                        + (y(getClose(d,i))
  1.9771 +                            - y(getLow(d,i)))
  1.9772 +                        + 'l'
  1.9773 +                        + (w/2)
  1.9774 +                        + ',0l'
  1.9775 +                        + (-w/2)
  1.9776 +                        + ',0z';
  1.9777 +                });
  1.9778 +        });
  1.9779 +
  1.9780 +        return chart;
  1.9781 +    }
  1.9782 +
  1.9783 +
  1.9784 +    //Create methods to allow outside functions to highlight a specific bar.
  1.9785 +    chart.highlightPoint = function(pointIndex, isHoverOver) {
  1.9786 +        chart.clearHighlights();
  1.9787 +        container.select(".nv-ohlcBar .nv-tick-0-" + pointIndex)
  1.9788 +            .classed("hover", isHoverOver)
  1.9789 +        ;
  1.9790 +    };
  1.9791 +
  1.9792 +    chart.clearHighlights = function() {
  1.9793 +        container.select(".nv-ohlcBar .nv-tick.hover")
  1.9794 +            .classed("hover", false)
  1.9795 +        ;
  1.9796 +    };
  1.9797 +
  1.9798 +    //============================================================
  1.9799 +    // Expose Public Variables
  1.9800 +    //------------------------------------------------------------
  1.9801 +
  1.9802 +    chart.dispatch = dispatch;
  1.9803 +    chart.options = nv.utils.optionsFunc.bind(chart);
  1.9804 +
  1.9805 +    chart._options = Object.create({}, {
  1.9806 +        // simple options, just get/set the necessary values
  1.9807 +        width:    {get: function(){return width;}, set: function(_){width=_;}},
  1.9808 +        height:   {get: function(){return height;}, set: function(_){height=_;}},
  1.9809 +        xScale:   {get: function(){return x;}, set: function(_){x=_;}},
  1.9810 +        yScale:   {get: function(){return y;}, set: function(_){y=_;}},
  1.9811 +        xDomain:  {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
  1.9812 +        yDomain:  {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
  1.9813 +        xRange:   {get: function(){return xRange;}, set: function(_){xRange=_;}},
  1.9814 +        yRange:   {get: function(){return yRange;}, set: function(_){yRange=_;}},
  1.9815 +        forceX:   {get: function(){return forceX;}, set: function(_){forceX=_;}},
  1.9816 +        forceY:   {get: function(){return forceY;}, set: function(_){forceY=_;}},
  1.9817 +        padData:  {get: function(){return padData;}, set: function(_){padData=_;}},
  1.9818 +        clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
  1.9819 +        id:       {get: function(){return id;}, set: function(_){id=_;}},
  1.9820 +        interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},
  1.9821 +
  1.9822 +        x:     {get: function(){return getX;}, set: function(_){getX=_;}},
  1.9823 +        y:     {get: function(){return getY;}, set: function(_){getY=_;}},
  1.9824 +        open:  {get: function(){return getOpen();}, set: function(_){getOpen=_;}},
  1.9825 +        close: {get: function(){return getClose();}, set: function(_){getClose=_;}},
  1.9826 +        high:  {get: function(){return getHigh;}, set: function(_){getHigh=_;}},
  1.9827 +        low:   {get: function(){return getLow;}, set: function(_){getLow=_;}},
  1.9828 +
  1.9829 +        // options that require extra logic in the setter
  1.9830 +        margin: {get: function(){return margin;}, set: function(_){
  1.9831 +            margin.top    = _.top    != undefined ? _.top    : margin.top;
  1.9832 +            margin.right  = _.right  != undefined ? _.right  : margin.right;
  1.9833 +            margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom;
  1.9834 +            margin.left   = _.left   != undefined ? _.left   : margin.left;
  1.9835 +        }},
  1.9836 +        color:  {get: function(){return color;}, set: function(_){
  1.9837 +            color = nv.utils.getColor(_);
  1.9838 +        }}
  1.9839 +    });
  1.9840 +
  1.9841 +    nv.utils.initOptions(chart);
  1.9842 +    return chart;
  1.9843 +};
  1.9844 +// Code adapted from Jason Davies' "Parallel Coordinates"
  1.9845 +// http://bl.ocks.org/jasondavies/1341281
  1.9846 +nv.models.parallelCoordinates = function() {
  1.9847 +    "use strict";
  1.9848 +
  1.9849 +    //============================================================
  1.9850 +    // Public Variables with Default Settings
  1.9851 +    //------------------------------------------------------------
  1.9852 +
  1.9853 +    var margin = {top: 30, right: 0, bottom: 10, left: 0}
  1.9854 +        , width = null
  1.9855 +        , height = null
  1.9856 +        , x = d3.scale.ordinal()
  1.9857 +        , y = {}
  1.9858 +        , dimensionNames = []
  1.9859 +        , dimensionFormats = []
  1.9860 +        , color = nv.utils.defaultColor()
  1.9861 +        , filters = []
  1.9862 +        , active = []
  1.9863 +        , dragging = []
  1.9864 +        , lineTension = 1
  1.9865 +        , dispatch = d3.dispatch('brush', 'elementMouseover', 'elementMouseout')
  1.9866 +        ;
  1.9867 +
  1.9868 +    //============================================================
  1.9869 +    // Private Variables
  1.9870 +    //------------------------------------------------------------
  1.9871 +
  1.9872 +    function chart(selection) {
  1.9873 +        selection.each(function(data) {
  1.9874 +            var container = d3.select(this);
  1.9875 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
  1.9876 +                availableHeight = nv.utils.availableHeight(height, container, margin);
  1.9877 +
  1.9878 +            nv.utils.initSVG(container);
  1.9879 +
  1.9880 +            active = data; //set all active before first brush call
  1.9881 +
  1.9882 +            // Setup Scales
  1.9883 +            x.rangePoints([0, availableWidth], 1).domain(dimensionNames);
  1.9884 +
  1.9885 +            //Set as true if all values on an axis are missing.
  1.9886 +            var onlyNanValues = {};
  1.9887 +            // Extract the list of dimensions and create a scale for each.
  1.9888 +            dimensionNames.forEach(function(d) {
  1.9889 +                var extent = d3.extent(data, function(p) { return +p[d]; });
  1.9890 +                onlyNanValues[d] = false;
  1.9891 +                //If there is no values to display on an axis, set the extent to 0
  1.9892 +                if (extent[0] === undefined) {
  1.9893 +                    onlyNanValues[d] = true;
  1.9894 +                    extent[0] = 0;
  1.9895 +                    extent[1] = 0;
  1.9896 +                }
  1.9897 +                //Scale axis if there is only one value
  1.9898 +                if (extent[0] === extent[1]) {
  1.9899 +                    extent[0] = extent[0] - 1;
  1.9900 +                    extent[1] = extent[1] + 1;
  1.9901 +                }
  1.9902 +                //Use 90% of (availableHeight - 12) for the axis range, 12 reprensenting the space necessary to display "undefined values" text.
  1.9903 +                //The remaining 10% are used to display the missingValue line.
  1.9904 +                y[d] = d3.scale.linear()
  1.9905 +                    .domain(extent)
  1.9906 +                    .range([(availableHeight - 12) * 0.9, 0]);
  1.9907 +
  1.9908 +                y[d].brush = d3.svg.brush().y(y[d]).on('brush', brush);
  1.9909 +
  1.9910 +                return d != 'name';
  1.9911 +            });
  1.9912 +
  1.9913 +            // Setup containers and skeleton of chart
  1.9914 +            var wrap = container.selectAll('g.nv-wrap.nv-parallelCoordinates').data([data]);
  1.9915 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-parallelCoordinates');
  1.9916 +            var gEnter = wrapEnter.append('g');
  1.9917 +            var g = wrap.select('g');
  1.9918 +
  1.9919 +            gEnter.append('g').attr('class', 'nv-parallelCoordinates background');
  1.9920 +            gEnter.append('g').attr('class', 'nv-parallelCoordinates foreground');
  1.9921 +            gEnter.append('g').attr('class', 'nv-parallelCoordinates missingValuesline');
  1.9922 +
  1.9923 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1.9924 +
  1.9925 +            var line = d3.svg.line().interpolate('cardinal').tension(lineTension),
  1.9926 +                axis = d3.svg.axis().orient('left'),
  1.9927 +                axisDrag = d3.behavior.drag()
  1.9928 +                        .on('dragstart', dragStart)
  1.9929 +                        .on('drag', dragMove)
  1.9930 +                        .on('dragend', dragEnd);
  1.9931 +
  1.9932 +            //Add missing value line at the bottom of the chart
  1.9933 +            var missingValuesline, missingValueslineText;
  1.9934 +            var step = x.range()[1] - x.range()[0];
  1.9935 +            var axisWithMissingValues = [];
  1.9936 +            var lineData = [0 + step / 2, availableHeight - 12, availableWidth - step / 2, availableHeight - 12];
  1.9937 +            missingValuesline = wrap.select('.missingValuesline').selectAll('line').data([lineData]);
  1.9938 +            missingValuesline.enter().append('line');
  1.9939 +            missingValuesline.exit().remove();
  1.9940 +            missingValuesline.attr("x1", function(d) { return d[0]; })
  1.9941 +                    .attr("y1", function(d) { return d[1]; })
  1.9942 +                    .attr("x2", function(d) { return d[2]; })
  1.9943 +                    .attr("y2", function(d) { return d[3]; });
  1.9944 +
  1.9945 +            //Add the text "undefined values" under the missing value line
  1.9946 +            missingValueslineText = wrap.select('.missingValuesline').selectAll('text').data(["undefined values"]);
  1.9947 +            missingValueslineText.append('text').data(["undefined values"]);
  1.9948 +            missingValueslineText.enter().append('text');
  1.9949 +            missingValueslineText.exit().remove();
  1.9950 +            missingValueslineText.attr("y", availableHeight)
  1.9951 +                    //To have the text right align with the missingValues line, substract 92 representing the text size.
  1.9952 +                    .attr("x", availableWidth - 92 - step / 2)
  1.9953 +                    .text(function(d) { return d; });
  1.9954 +
  1.9955 +            // Add grey background lines for context.
  1.9956 +            var background = wrap.select('.background').selectAll('path').data(data);
  1.9957 +            background.enter().append('path');
  1.9958 +            background.exit().remove();
  1.9959 +            background.attr('d', path);
  1.9960 +
  1.9961 +            // Add blue foreground lines for focus.
  1.9962 +            var foreground = wrap.select('.foreground').selectAll('path').data(data);
  1.9963 +            foreground.enter().append('path')
  1.9964 +            foreground.exit().remove();
  1.9965 +            foreground.attr('d', path).attr('stroke', color);
  1.9966 +            foreground.on("mouseover", function (d, i) {
  1.9967 +                d3.select(this).classed('hover', true);
  1.9968 +                dispatch.elementMouseover({
  1.9969 +                    label: d.name,
  1.9970 +                    data: d.data,
  1.9971 +                    index: i,
  1.9972 +                    pos: [d3.mouse(this.parentNode)[0], d3.mouse(this.parentNode)[1]]
  1.9973 +                });
  1.9974 +
  1.9975 +            });
  1.9976 +            foreground.on("mouseout", function (d, i) {
  1.9977 +                d3.select(this).classed('hover', false);
  1.9978 +                dispatch.elementMouseout({
  1.9979 +                    label: d.name,
  1.9980 +                    data: d.data,
  1.9981 +                    index: i
  1.9982 +                });
  1.9983 +            });
  1.9984 +
  1.9985 +            // Add a group element for each dimension.
  1.9986 +            var dimensions = g.selectAll('.dimension').data(dimensionNames);
  1.9987 +            var dimensionsEnter = dimensions.enter().append('g').attr('class', 'nv-parallelCoordinates dimension');
  1.9988 +            dimensionsEnter.append('g').attr('class', 'nv-parallelCoordinates nv-axis');
  1.9989 +            dimensionsEnter.append('g').attr('class', 'nv-parallelCoordinates-brush');
  1.9990 +            dimensionsEnter.append('text').attr('class', 'nv-parallelCoordinates nv-label');
  1.9991 +
  1.9992 +            dimensions.attr('transform', function(d) { return 'translate(' + x(d) + ',0)'; });
  1.9993 +            dimensions.exit().remove();
  1.9994 +
  1.9995 +            // Add an axis and title.
  1.9996 +            dimensions.select('.nv-label')
  1.9997 +                .style("cursor", "move")
  1.9998 +                .attr('dy', '-1em')
  1.9999 +                .attr('text-anchor', 'middle')
 1.10000 +                .text(String)
 1.10001 +                .on("mouseover", function(d, i) {
 1.10002 +                    dispatch.elementMouseover({
 1.10003 +                        dim: d,
 1.10004 +                        pos: [d3.mouse(this.parentNode.parentNode)[0], d3.mouse(this.parentNode.parentNode)[1]]
 1.10005 +                    });
 1.10006 +                })
 1.10007 +                .on("mouseout", function(d, i) {
 1.10008 +                    dispatch.elementMouseout({
 1.10009 +                        dim: d
 1.10010 +                    });
 1.10011 +                })
 1.10012 +                .call(axisDrag);
 1.10013 +
 1.10014 +            dimensions.select('.nv-axis')
 1.10015 +                .each(function (d, i) {
 1.10016 +                    d3.select(this).call(axis.scale(y[d]).tickFormat(d3.format(dimensionFormats[i])));
 1.10017 +                });
 1.10018 +
 1.10019 +                dimensions.select('.nv-parallelCoordinates-brush')
 1.10020 +                .each(function (d) {
 1.10021 +                    d3.select(this).call(y[d].brush);
 1.10022 +                })
 1.10023 +                .selectAll('rect')
 1.10024 +                .attr('x', -8)
 1.10025 +                .attr('width', 16);
 1.10026 +
 1.10027 +            // Returns the path for a given data point.
 1.10028 +            function path(d) {
 1.10029 +                return line(dimensionNames.map(function (p) {
 1.10030 +                    //If value if missing, put the value on the missing value line
 1.10031 +                    if(isNaN(d[p]) || isNaN(parseFloat(d[p]))) {
 1.10032 +                        var domain = y[p].domain();
 1.10033 +                        var range = y[p].range();
 1.10034 +                        var min = domain[0] - (domain[1] - domain[0]) / 9;
 1.10035 +
 1.10036 +                        //If it's not already the case, allow brush to select undefined values
 1.10037 +                        if(axisWithMissingValues.indexOf(p) < 0) {
 1.10038 +
 1.10039 +                            var newscale = d3.scale.linear().domain([min, domain[1]]).range([availableHeight - 12, range[1]]);
 1.10040 +                            y[p].brush.y(newscale);
 1.10041 +                            axisWithMissingValues.push(p);
 1.10042 +                        }
 1.10043 +
 1.10044 +                        return [x(p), y[p](min)];
 1.10045 +                    }
 1.10046 +
 1.10047 +                    //If parallelCoordinate contain missing values show the missing values line otherwise, hide it.
 1.10048 +                    if(axisWithMissingValues.length > 0) {
 1.10049 +                        missingValuesline.style("display", "inline");
 1.10050 +                        missingValueslineText.style("display", "inline");
 1.10051 +                    } else {
 1.10052 +                        missingValuesline.style("display", "none");
 1.10053 +                        missingValueslineText.style("display", "none");
 1.10054 +                    }
 1.10055 +
 1.10056 +                     return [x(p), y[p](d[p])];
 1.10057 +                }));
 1.10058 +            }
 1.10059 +
 1.10060 +            // Handles a brush event, toggling the display of foreground lines.
 1.10061 +            function brush() {
 1.10062 +                var actives = dimensionNames.filter(function(p) { return !y[p].brush.empty(); }),
 1.10063 +                    extents = actives.map(function(p) { return y[p].brush.extent(); });
 1.10064 +
 1.10065 +                filters = []; //erase current filters
 1.10066 +                actives.forEach(function(d,i) {
 1.10067 +                    filters[i] = {
 1.10068 +                        dimension: d,
 1.10069 +                        extent: extents[i]
 1.10070 +                    }
 1.10071 +                });
 1.10072 +
 1.10073 +                active = []; //erase current active list
 1.10074 +                foreground.style('display', function(d) {
 1.10075 +                    var isActive = actives.every(function(p, i) {
 1.10076 +                        if(isNaN(d[p]) && extents[i][0] == y[p].brush.y().domain()[0]) return true;
 1.10077 +                        return extents[i][0] <= d[p] && d[p] <= extents[i][1];
 1.10078 +                    });
 1.10079 +                    if (isActive) active.push(d);
 1.10080 +                    return isActive ? null : 'none';
 1.10081 +                });
 1.10082 +
 1.10083 +                dispatch.brush({
 1.10084 +                    filters: filters,
 1.10085 +                    active: active
 1.10086 +                });
 1.10087 +            }
 1.10088 +
 1.10089 +            function dragStart(d, i) {
 1.10090 +                dragging[d] = this.parentNode.__origin__ = x(d);
 1.10091 +                background.attr("visibility", "hidden");
 1.10092 +
 1.10093 +            }
 1.10094 +
 1.10095 +            function dragMove(d, i) {
 1.10096 +                dragging[d] = Math.min(availableWidth, Math.max(0, this.parentNode.__origin__ += d3.event.x));
 1.10097 +                foreground.attr("d", path);
 1.10098 +                dimensionNames.sort(function (a, b) { return position(a) - position(b); });
 1.10099 +                x.domain(dimensionNames);
 1.10100 +                dimensions.attr("transform", function(d) { return "translate(" + position(d) + ")"; });
 1.10101 +            }
 1.10102 +
 1.10103 +            function dragEnd(d, i) {
 1.10104 +                delete this.parentNode.__origin__;
 1.10105 +                delete dragging[d];
 1.10106 +                d3.select(this.parentNode).attr("transform", "translate(" + x(d) + ")");
 1.10107 +                foreground
 1.10108 +                  .attr("d", path);
 1.10109 +                background
 1.10110 +                  .attr("d", path)
 1.10111 +                  .attr("visibility", null);
 1.10112 +
 1.10113 +            }
 1.10114 +
 1.10115 +            function position(d) {
 1.10116 +                var v = dragging[d];
 1.10117 +                return v == null ? x(d) : v;
 1.10118 +            }
 1.10119 +        });
 1.10120 +
 1.10121 +        return chart;
 1.10122 +    }
 1.10123 +
 1.10124 +    //============================================================
 1.10125 +    // Expose Public Variables
 1.10126 +    //------------------------------------------------------------
 1.10127 +
 1.10128 +    chart.dispatch = dispatch;
 1.10129 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.10130 +
 1.10131 +    chart._options = Object.create({}, {
 1.10132 +        // simple options, just get/set the necessary values
 1.10133 +        width:         {get: function(){return width;},           set: function(_){width= _;}},
 1.10134 +        height:        {get: function(){return height;},          set: function(_){height= _;}},
 1.10135 +        dimensionNames: {get: function() { return dimensionNames;}, set: function(_){dimensionNames= _;}},
 1.10136 +        dimensionFormats : {get: function(){return dimensionFormats;}, set: function (_){dimensionFormats=_;}},
 1.10137 +        lineTension:   {get: function(){return lineTension;},     set: function(_){lineTension = _;}},
 1.10138 +
 1.10139 +        // deprecated options
 1.10140 +        dimensions: {get: function (){return dimensionNames;}, set: function(_){
 1.10141 +            // deprecated after 1.8.1
 1.10142 +            nv.deprecated('dimensions', 'use dimensionNames instead');
 1.10143 +            dimensionNames = _;
 1.10144 +        }},
 1.10145 +
 1.10146 +        // options that require extra logic in the setter
 1.10147 +        margin: {get: function(){return margin;}, set: function(_){
 1.10148 +            margin.top    =  _.top    !== undefined ? _.top    : margin.top;
 1.10149 +            margin.right  =  _.right  !== undefined ? _.right  : margin.right;
 1.10150 +            margin.bottom =  _.bottom !== undefined ? _.bottom : margin.bottom;
 1.10151 +            margin.left   =  _.left   !== undefined ? _.left   : margin.left;
 1.10152 +        }},
 1.10153 +        color:  {get: function(){return color;}, set: function(_){
 1.10154 +            color = nv.utils.getColor(_);
 1.10155 +        }}
 1.10156 +    });
 1.10157 +
 1.10158 +    nv.utils.initOptions(chart);
 1.10159 +    return chart;
 1.10160 +};
 1.10161 +nv.models.pie = function() {
 1.10162 +    "use strict";
 1.10163 +
 1.10164 +    //============================================================
 1.10165 +    // Public Variables with Default Settings
 1.10166 +    //------------------------------------------------------------
 1.10167 +
 1.10168 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
 1.10169 +        , width = 500
 1.10170 +        , height = 500
 1.10171 +        , getX = function(d) { return d.x }
 1.10172 +        , getY = function(d) { return d.y }
 1.10173 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
 1.10174 +        , container = null
 1.10175 +        , color = nv.utils.defaultColor()
 1.10176 +        , valueFormat = d3.format(',.2f')
 1.10177 +        , showLabels = true
 1.10178 +        , labelsOutside = false
 1.10179 +        , labelType = "key"
 1.10180 +        , labelThreshold = .02 //if slice percentage is under this, don't show label
 1.10181 +        , donut = false
 1.10182 +        , title = false
 1.10183 +        , growOnHover = true
 1.10184 +        , titleOffset = 0
 1.10185 +        , labelSunbeamLayout = false
 1.10186 +        , startAngle = false
 1.10187 +        , padAngle = false
 1.10188 +        , endAngle = false
 1.10189 +        , cornerRadius = 0
 1.10190 +        , donutRatio = 0.5
 1.10191 +        , arcsRadius = []
 1.10192 +        , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd')
 1.10193 +        ;
 1.10194 +
 1.10195 +    var arcs = [];
 1.10196 +    var arcsOver = [];
 1.10197 +
 1.10198 +    //============================================================
 1.10199 +    // chart function
 1.10200 +    //------------------------------------------------------------
 1.10201 +
 1.10202 +    var renderWatch = nv.utils.renderWatch(dispatch);
 1.10203 +
 1.10204 +    function chart(selection) {
 1.10205 +        renderWatch.reset();
 1.10206 +        selection.each(function(data) {
 1.10207 +            var availableWidth = width - margin.left - margin.right
 1.10208 +                , availableHeight = height - margin.top - margin.bottom
 1.10209 +                , radius = Math.min(availableWidth, availableHeight) / 2
 1.10210 +                , arcsRadiusOuter = []
 1.10211 +                , arcsRadiusInner = []
 1.10212 +                ;
 1.10213 +
 1.10214 +            container = d3.select(this)
 1.10215 +            if (arcsRadius.length === 0) {
 1.10216 +                var outer = radius - radius / 5;
 1.10217 +                var inner = donutRatio * radius;
 1.10218 +                for (var i = 0; i < data[0].length; i++) {
 1.10219 +                    arcsRadiusOuter.push(outer);
 1.10220 +                    arcsRadiusInner.push(inner);
 1.10221 +                }
 1.10222 +            } else {
 1.10223 +                arcsRadiusOuter = arcsRadius.map(function (d) { return (d.outer - d.outer / 5) * radius; });
 1.10224 +                arcsRadiusInner = arcsRadius.map(function (d) { return (d.inner - d.inner / 5) * radius; });
 1.10225 +                donutRatio = d3.min(arcsRadius.map(function (d) { return (d.inner - d.inner / 5); }));
 1.10226 +            }
 1.10227 +            nv.utils.initSVG(container);
 1.10228 +
 1.10229 +            // Setup containers and skeleton of chart
 1.10230 +            var wrap = container.selectAll('.nv-wrap.nv-pie').data(data);
 1.10231 +            var wrapEnter = wrap.enter().append('g').attr('class','nvd3 nv-wrap nv-pie nv-chart-' + id);
 1.10232 +            var gEnter = wrapEnter.append('g');
 1.10233 +            var g = wrap.select('g');
 1.10234 +            var g_pie = gEnter.append('g').attr('class', 'nv-pie');
 1.10235 +            gEnter.append('g').attr('class', 'nv-pieLabels');
 1.10236 +
 1.10237 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.10238 +            g.select('.nv-pie').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')');
 1.10239 +            g.select('.nv-pieLabels').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')');
 1.10240 +
 1.10241 +            //
 1.10242 +            container.on('click', function(d,i) {
 1.10243 +                dispatch.chartClick({
 1.10244 +                    data: d,
 1.10245 +                    index: i,
 1.10246 +                    pos: d3.event,
 1.10247 +                    id: id
 1.10248 +                });
 1.10249 +            });
 1.10250 +
 1.10251 +            arcs = [];
 1.10252 +            arcsOver = [];
 1.10253 +            for (var i = 0; i < data[0].length; i++) {
 1.10254 +
 1.10255 +                var arc = d3.svg.arc().outerRadius(arcsRadiusOuter[i]);
 1.10256 +                var arcOver = d3.svg.arc().outerRadius(arcsRadiusOuter[i] + 5);
 1.10257 +
 1.10258 +                if (startAngle !== false) {
 1.10259 +                    arc.startAngle(startAngle);
 1.10260 +                    arcOver.startAngle(startAngle);
 1.10261 +                }
 1.10262 +                if (endAngle !== false) {
 1.10263 +                    arc.endAngle(endAngle);
 1.10264 +                    arcOver.endAngle(endAngle);
 1.10265 +                }
 1.10266 +                if (donut) {
 1.10267 +                    arc.innerRadius(arcsRadiusInner[i]);
 1.10268 +                    arcOver.innerRadius(arcsRadiusInner[i]);
 1.10269 +                }
 1.10270 +
 1.10271 +                if (arc.cornerRadius && cornerRadius) {
 1.10272 +                    arc.cornerRadius(cornerRadius);
 1.10273 +                    arcOver.cornerRadius(cornerRadius);
 1.10274 +                }
 1.10275 +
 1.10276 +                arcs.push(arc);
 1.10277 +                arcsOver.push(arcOver);
 1.10278 +            }
 1.10279 +
 1.10280 +            // Setup the Pie chart and choose the data element
 1.10281 +            var pie = d3.layout.pie()
 1.10282 +                .sort(null)
 1.10283 +                .value(function(d) { return d.disabled ? 0 : getY(d) });
 1.10284 +
 1.10285 +            // padAngle added in d3 3.5
 1.10286 +            if (pie.padAngle && padAngle) {
 1.10287 +                pie.padAngle(padAngle);
 1.10288 +            }
 1.10289 +
 1.10290 +            // if title is specified and donut, put it in the middle
 1.10291 +            if (donut && title) {
 1.10292 +                g_pie.append("text").attr('class', 'nv-pie-title');
 1.10293 +
 1.10294 +                wrap.select('.nv-pie-title')
 1.10295 +                    .style("text-anchor", "middle")
 1.10296 +                    .text(function (d) {
 1.10297 +                        return title;
 1.10298 +                    })
 1.10299 +                    .style("font-size", (Math.min(availableWidth, availableHeight)) * donutRatio * 2 / (title.length + 2) + "px")
 1.10300 +                    .attr("dy", "0.35em") // trick to vertically center text
 1.10301 +                    .attr('transform', function(d, i) {
 1.10302 +                        return 'translate(0, '+ titleOffset + ')';
 1.10303 +                    });
 1.10304 +            }
 1.10305 +
 1.10306 +            var slices = wrap.select('.nv-pie').selectAll('.nv-slice').data(pie);
 1.10307 +            var pieLabels = wrap.select('.nv-pieLabels').selectAll('.nv-label').data(pie);
 1.10308 +
 1.10309 +            slices.exit().remove();
 1.10310 +            pieLabels.exit().remove();
 1.10311 +
 1.10312 +            var ae = slices.enter().append('g');
 1.10313 +            ae.attr('class', 'nv-slice');
 1.10314 +            ae.on('mouseover', function(d, i) {
 1.10315 +                d3.select(this).classed('hover', true);
 1.10316 +                if (growOnHover) {
 1.10317 +                    d3.select(this).select("path").transition()
 1.10318 +                        .duration(70)
 1.10319 +                        .attr("d", arcsOver[i]);
 1.10320 +                }
 1.10321 +                dispatch.elementMouseover({
 1.10322 +                    data: d.data,
 1.10323 +                    index: i,
 1.10324 +                    color: d3.select(this).style("fill")
 1.10325 +                });
 1.10326 +            });
 1.10327 +            ae.on('mouseout', function(d, i) {
 1.10328 +                d3.select(this).classed('hover', false);
 1.10329 +                if (growOnHover) {
 1.10330 +                    d3.select(this).select("path").transition()
 1.10331 +                        .duration(50)
 1.10332 +                        .attr("d", arcs[i]);
 1.10333 +                }
 1.10334 +                dispatch.elementMouseout({data: d.data, index: i});
 1.10335 +            });
 1.10336 +            ae.on('mousemove', function(d, i) {
 1.10337 +                dispatch.elementMousemove({data: d.data, index: i});
 1.10338 +            });
 1.10339 +            ae.on('click', function(d, i) {
 1.10340 +                dispatch.elementClick({
 1.10341 +                    data: d.data,
 1.10342 +                    index: i,
 1.10343 +                    color: d3.select(this).style("fill")
 1.10344 +                });
 1.10345 +            });
 1.10346 +            ae.on('dblclick', function(d, i) {
 1.10347 +                dispatch.elementDblClick({
 1.10348 +                    data: d.data,
 1.10349 +                    index: i,
 1.10350 +                    color: d3.select(this).style("fill")
 1.10351 +                });
 1.10352 +            });
 1.10353 +
 1.10354 +            slices.attr('fill', function(d,i) { return color(d.data, i); });
 1.10355 +            slices.attr('stroke', function(d,i) { return color(d.data, i); });
 1.10356 +
 1.10357 +            var paths = ae.append('path').each(function(d) {
 1.10358 +                this._current = d;
 1.10359 +            });
 1.10360 +
 1.10361 +            slices.select('path')
 1.10362 +                .transition()
 1.10363 +                .attr('d', function (d, i) { return arcs[i](d); })
 1.10364 +                .attrTween('d', arcTween);
 1.10365 +
 1.10366 +            if (showLabels) {
 1.10367 +                // This does the normal label
 1.10368 +                var labelsArc = [];
 1.10369 +                for (var i = 0; i < data[0].length; i++) {
 1.10370 +                    labelsArc.push(arcs[i]);
 1.10371 +
 1.10372 +                    if (labelsOutside) {
 1.10373 +                        if (donut) {
 1.10374 +                            labelsArc[i] = d3.svg.arc().outerRadius(arcs[i].outerRadius());
 1.10375 +                            if (startAngle !== false) labelsArc[i].startAngle(startAngle);
 1.10376 +                            if (endAngle !== false) labelsArc[i].endAngle(endAngle);
 1.10377 +                        }
 1.10378 +                    } else if (!donut) {
 1.10379 +                            labelsArc[i].innerRadius(0);
 1.10380 +                    }
 1.10381 +                }
 1.10382 +
 1.10383 +                pieLabels.enter().append("g").classed("nv-label",true).each(function(d,i) {
 1.10384 +                    var group = d3.select(this);
 1.10385 +
 1.10386 +                    group.attr('transform', function (d, i) {
 1.10387 +                        if (labelSunbeamLayout) {
 1.10388 +                            d.outerRadius = arcsRadiusOuter[i] + 10; // Set Outer Coordinate
 1.10389 +                            d.innerRadius = arcsRadiusOuter[i] + 15; // Set Inner Coordinate
 1.10390 +                            var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI);
 1.10391 +                            if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
 1.10392 +                                rotateAngle -= 90;
 1.10393 +                            } else {
 1.10394 +                                rotateAngle += 90;
 1.10395 +                            }
 1.10396 +                            return 'translate(' + labelsArc[i].centroid(d) + ') rotate(' + rotateAngle + ')';
 1.10397 +                        } else {
 1.10398 +                            d.outerRadius = radius + 10; // Set Outer Coordinate
 1.10399 +                            d.innerRadius = radius + 15; // Set Inner Coordinate
 1.10400 +                            return 'translate(' + labelsArc[i].centroid(d) + ')'
 1.10401 +                        }
 1.10402 +                    });
 1.10403 +
 1.10404 +                    group.append('rect')
 1.10405 +                        .style('stroke', '#fff')
 1.10406 +                        .style('fill', '#fff')
 1.10407 +                        .attr("rx", 3)
 1.10408 +                        .attr("ry", 3);
 1.10409 +
 1.10410 +                    group.append('text')
 1.10411 +                        .style('text-anchor', labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle') //center the text on it's origin or begin/end if orthogonal aligned
 1.10412 +                        .style('fill', '#000')
 1.10413 +                });
 1.10414 +
 1.10415 +                var labelLocationHash = {};
 1.10416 +                var avgHeight = 14;
 1.10417 +                var avgWidth = 140;
 1.10418 +                var createHashKey = function(coordinates) {
 1.10419 +                    return Math.floor(coordinates[0]/avgWidth) * avgWidth + ',' + Math.floor(coordinates[1]/avgHeight) * avgHeight;
 1.10420 +                };
 1.10421 +
 1.10422 +                pieLabels.watchTransition(renderWatch, 'pie labels').attr('transform', function (d, i) {
 1.10423 +                    if (labelSunbeamLayout) {
 1.10424 +                        d.outerRadius = arcsRadiusOuter[i] + 10; // Set Outer Coordinate
 1.10425 +                        d.innerRadius = arcsRadiusOuter[i] + 15; // Set Inner Coordinate
 1.10426 +                        var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI);
 1.10427 +                        if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
 1.10428 +                            rotateAngle -= 90;
 1.10429 +                        } else {
 1.10430 +                            rotateAngle += 90;
 1.10431 +                        }
 1.10432 +                        return 'translate(' + labelsArc[i].centroid(d) + ') rotate(' + rotateAngle + ')';
 1.10433 +                    } else {
 1.10434 +                        d.outerRadius = radius + 10; // Set Outer Coordinate
 1.10435 +                        d.innerRadius = radius + 15; // Set Inner Coordinate
 1.10436 +
 1.10437 +                        /*
 1.10438 +                        Overlapping pie labels are not good. What this attempts to do is, prevent overlapping.
 1.10439 +                        Each label location is hashed, and if a hash collision occurs, we assume an overlap.
 1.10440 +                        Adjust the label's y-position to remove the overlap.
 1.10441 +                        */
 1.10442 +                        var center = labelsArc[i].centroid(d);
 1.10443 +                        if (d.value) {
 1.10444 +                            var hashKey = createHashKey(center);
 1.10445 +                            if (labelLocationHash[hashKey]) {
 1.10446 +                                center[1] -= avgHeight;
 1.10447 +                            }
 1.10448 +                            labelLocationHash[createHashKey(center)] = true;
 1.10449 +                        }
 1.10450 +                        return 'translate(' + center + ')'
 1.10451 +                    }
 1.10452 +                });
 1.10453 +
 1.10454 +                pieLabels.select(".nv-label text")
 1.10455 +                    .style('text-anchor', function(d,i) {
 1.10456 +                        //center the text on it's origin or begin/end if orthogonal aligned
 1.10457 +                        return labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle';
 1.10458 +                    })
 1.10459 +                    .text(function(d, i) {
 1.10460 +                        var percent = (d.endAngle - d.startAngle) / (2 * Math.PI);
 1.10461 +                        var label = '';
 1.10462 +                        if (!d.value || percent < labelThreshold) return '';
 1.10463 +
 1.10464 +                        if(typeof labelType === 'function') {
 1.10465 +                            label = labelType(d, i, {
 1.10466 +                                'key': getX(d.data),
 1.10467 +                                'value': getY(d.data),
 1.10468 +                                'percent': valueFormat(percent)
 1.10469 +                            });
 1.10470 +                        } else {
 1.10471 +                            switch (labelType) {
 1.10472 +                                case 'key':
 1.10473 +                                    label = getX(d.data);
 1.10474 +                                    break;
 1.10475 +                                case 'value':
 1.10476 +                                    label = valueFormat(getY(d.data));
 1.10477 +                                    break;
 1.10478 +                                case 'percent':
 1.10479 +                                    label = d3.format('%')(percent);
 1.10480 +                                    break;
 1.10481 +                            }
 1.10482 +                        }
 1.10483 +                        return label;
 1.10484 +                    })
 1.10485 +                ;
 1.10486 +            }
 1.10487 +
 1.10488 +
 1.10489 +            // Computes the angle of an arc, converting from radians to degrees.
 1.10490 +            function angle(d) {
 1.10491 +                var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
 1.10492 +                return a > 90 ? a - 180 : a;
 1.10493 +            }
 1.10494 +
 1.10495 +            function arcTween(a, idx) {
 1.10496 +                a.endAngle = isNaN(a.endAngle) ? 0 : a.endAngle;
 1.10497 +                a.startAngle = isNaN(a.startAngle) ? 0 : a.startAngle;
 1.10498 +                if (!donut) a.innerRadius = 0;
 1.10499 +                var i = d3.interpolate(this._current, a);
 1.10500 +                this._current = i(0);
 1.10501 +                return function (t) {
 1.10502 +                    return arcs[idx](i(t));
 1.10503 +                };
 1.10504 +            }
 1.10505 +        });
 1.10506 +
 1.10507 +        renderWatch.renderEnd('pie immediate');
 1.10508 +        return chart;
 1.10509 +    }
 1.10510 +
 1.10511 +    //============================================================
 1.10512 +    // Expose Public Variables
 1.10513 +    //------------------------------------------------------------
 1.10514 +
 1.10515 +    chart.dispatch = dispatch;
 1.10516 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.10517 +
 1.10518 +    chart._options = Object.create({}, {
 1.10519 +        // simple options, just get/set the necessary values
 1.10520 +        arcsRadius: { get: function () { return arcsRadius; }, set: function (_) { arcsRadius = _; } },
 1.10521 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
 1.10522 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
 1.10523 +        showLabels: {get: function(){return showLabels;}, set: function(_){showLabels=_;}},
 1.10524 +        title:      {get: function(){return title;}, set: function(_){title=_;}},
 1.10525 +        titleOffset:    {get: function(){return titleOffset;}, set: function(_){titleOffset=_;}},
 1.10526 +        labelThreshold: {get: function(){return labelThreshold;}, set: function(_){labelThreshold=_;}},
 1.10527 +        valueFormat:    {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}},
 1.10528 +        x:          {get: function(){return getX;}, set: function(_){getX=_;}},
 1.10529 +        id:         {get: function(){return id;}, set: function(_){id=_;}},
 1.10530 +        endAngle:   {get: function(){return endAngle;}, set: function(_){endAngle=_;}},
 1.10531 +        startAngle: {get: function(){return startAngle;}, set: function(_){startAngle=_;}},
 1.10532 +        padAngle:   {get: function(){return padAngle;}, set: function(_){padAngle=_;}},
 1.10533 +        cornerRadius: {get: function(){return cornerRadius;}, set: function(_){cornerRadius=_;}},
 1.10534 +        donutRatio:   {get: function(){return donutRatio;}, set: function(_){donutRatio=_;}},
 1.10535 +        labelsOutside: {get: function(){return labelsOutside;}, set: function(_){labelsOutside=_;}},
 1.10536 +        labelSunbeamLayout: {get: function(){return labelSunbeamLayout;}, set: function(_){labelSunbeamLayout=_;}},
 1.10537 +        donut:              {get: function(){return donut;}, set: function(_){donut=_;}},
 1.10538 +        growOnHover:        {get: function(){return growOnHover;}, set: function(_){growOnHover=_;}},
 1.10539 +
 1.10540 +        // depreciated after 1.7.1
 1.10541 +        pieLabelsOutside: {get: function(){return labelsOutside;}, set: function(_){
 1.10542 +            labelsOutside=_;
 1.10543 +            nv.deprecated('pieLabelsOutside', 'use labelsOutside instead');
 1.10544 +        }},
 1.10545 +        // depreciated after 1.7.1
 1.10546 +        donutLabelsOutside: {get: function(){return labelsOutside;}, set: function(_){
 1.10547 +            labelsOutside=_;
 1.10548 +            nv.deprecated('donutLabelsOutside', 'use labelsOutside instead');
 1.10549 +        }},
 1.10550 +        // deprecated after 1.7.1
 1.10551 +        labelFormat: {get: function(){ return valueFormat;}, set: function(_) {
 1.10552 +            valueFormat=_;
 1.10553 +            nv.deprecated('labelFormat','use valueFormat instead');
 1.10554 +        }},
 1.10555 +
 1.10556 +        // options that require extra logic in the setter
 1.10557 +        margin: {get: function(){return margin;}, set: function(_){
 1.10558 +            margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
 1.10559 +            margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
 1.10560 +            margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
 1.10561 +            margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
 1.10562 +        }},
 1.10563 +        y: {get: function(){return getY;}, set: function(_){
 1.10564 +            getY=d3.functor(_);
 1.10565 +        }},
 1.10566 +        color: {get: function(){return color;}, set: function(_){
 1.10567 +            color=nv.utils.getColor(_);
 1.10568 +        }},
 1.10569 +        labelType:          {get: function(){return labelType;}, set: function(_){
 1.10570 +            labelType= _ || 'key';
 1.10571 +        }}
 1.10572 +    });
 1.10573 +
 1.10574 +    nv.utils.initOptions(chart);
 1.10575 +    return chart;
 1.10576 +};
 1.10577 +nv.models.pieChart = function() {
 1.10578 +    "use strict";
 1.10579 +
 1.10580 +    //============================================================
 1.10581 +    // Public Variables with Default Settings
 1.10582 +    //------------------------------------------------------------
 1.10583 +
 1.10584 +    var pie = nv.models.pie();
 1.10585 +    var legend = nv.models.legend();
 1.10586 +    var tooltip = nv.models.tooltip();
 1.10587 +
 1.10588 +    var margin = {top: 30, right: 20, bottom: 20, left: 20}
 1.10589 +        , width = null
 1.10590 +        , height = null
 1.10591 +        , showLegend = true
 1.10592 +        , legendPosition = "top"
 1.10593 +        , color = nv.utils.defaultColor()
 1.10594 +        , state = nv.utils.state()
 1.10595 +        , defaultState = null
 1.10596 +        , noData = null
 1.10597 +        , duration = 250
 1.10598 +        , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd')
 1.10599 +        ;
 1.10600 +
 1.10601 +    tooltip
 1.10602 +        .headerEnabled(false)
 1.10603 +        .duration(0)
 1.10604 +        .valueFormatter(function(d, i) {
 1.10605 +            return pie.valueFormat()(d, i);
 1.10606 +        });
 1.10607 +
 1.10608 +    //============================================================
 1.10609 +    // Private Variables
 1.10610 +    //------------------------------------------------------------
 1.10611 +
 1.10612 +    var renderWatch = nv.utils.renderWatch(dispatch);
 1.10613 +
 1.10614 +    var stateGetter = function(data) {
 1.10615 +        return function(){
 1.10616 +            return {
 1.10617 +                active: data.map(function(d) { return !d.disabled })
 1.10618 +            };
 1.10619 +        }
 1.10620 +    };
 1.10621 +
 1.10622 +    var stateSetter = function(data) {
 1.10623 +        return function(state) {
 1.10624 +            if (state.active !== undefined) {
 1.10625 +                data.forEach(function (series, i) {
 1.10626 +                    series.disabled = !state.active[i];
 1.10627 +                });
 1.10628 +            }
 1.10629 +        }
 1.10630 +    };
 1.10631 +
 1.10632 +    //============================================================
 1.10633 +    // Chart function
 1.10634 +    //------------------------------------------------------------
 1.10635 +
 1.10636 +    function chart(selection) {
 1.10637 +        renderWatch.reset();
 1.10638 +        renderWatch.models(pie);
 1.10639 +
 1.10640 +        selection.each(function(data) {
 1.10641 +            var container = d3.select(this);
 1.10642 +            nv.utils.initSVG(container);
 1.10643 +
 1.10644 +            var that = this;
 1.10645 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
 1.10646 +                availableHeight = nv.utils.availableHeight(height, container, margin);
 1.10647 +
 1.10648 +            chart.update = function() { container.transition().call(chart); };
 1.10649 +            chart.container = this;
 1.10650 +
 1.10651 +            state.setter(stateSetter(data), chart.update)
 1.10652 +                .getter(stateGetter(data))
 1.10653 +                .update();
 1.10654 +
 1.10655 +            //set state.disabled
 1.10656 +            state.disabled = data.map(function(d) { return !!d.disabled });
 1.10657 +
 1.10658 +            if (!defaultState) {
 1.10659 +                var key;
 1.10660 +                defaultState = {};
 1.10661 +                for (key in state) {
 1.10662 +                    if (state[key] instanceof Array)
 1.10663 +                        defaultState[key] = state[key].slice(0);
 1.10664 +                    else
 1.10665 +                        defaultState[key] = state[key];
 1.10666 +                }
 1.10667 +            }
 1.10668 +
 1.10669 +            // Display No Data message if there's nothing to show.
 1.10670 +            if (!data || !data.length) {
 1.10671 +                nv.utils.noData(chart, container);
 1.10672 +                return chart;
 1.10673 +            } else {
 1.10674 +                container.selectAll('.nv-noData').remove();
 1.10675 +            }
 1.10676 +
 1.10677 +            // Setup containers and skeleton of chart
 1.10678 +            var wrap = container.selectAll('g.nv-wrap.nv-pieChart').data([data]);
 1.10679 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-pieChart').append('g');
 1.10680 +            var g = wrap.select('g');
 1.10681 +
 1.10682 +            gEnter.append('g').attr('class', 'nv-pieWrap');
 1.10683 +            gEnter.append('g').attr('class', 'nv-legendWrap');
 1.10684 +
 1.10685 +            // Legend
 1.10686 +            if (showLegend) {
 1.10687 +                if (legendPosition === "top") {
 1.10688 +                    legend.width( availableWidth ).key(pie.x());
 1.10689 +
 1.10690 +                    wrap.select('.nv-legendWrap')
 1.10691 +                        .datum(data)
 1.10692 +                        .call(legend);
 1.10693 +
 1.10694 +                    if ( margin.top != legend.height()) {
 1.10695 +                        margin.top = legend.height();
 1.10696 +                        availableHeight = nv.utils.availableHeight(height, container, margin);
 1.10697 +                    }
 1.10698 +
 1.10699 +                    wrap.select('.nv-legendWrap')
 1.10700 +                        .attr('transform', 'translate(0,' + (-margin.top) +')');
 1.10701 +                } else if (legendPosition === "right") {
 1.10702 +                    var legendWidth = nv.models.legend().width();
 1.10703 +                    if (availableWidth / 2 < legendWidth) {
 1.10704 +                        legendWidth = (availableWidth / 2)
 1.10705 +                    }
 1.10706 +                    legend.height(availableHeight).key(pie.x());
 1.10707 +                    legend.width(legendWidth);
 1.10708 +                    availableWidth -= legend.width();
 1.10709 +
 1.10710 +                    wrap.select('.nv-legendWrap')
 1.10711 +                        .datum(data)
 1.10712 +                        .call(legend)
 1.10713 +                        .attr('transform', 'translate(' + (availableWidth) +',0)');
 1.10714 +                }
 1.10715 +            }
 1.10716 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.10717 +
 1.10718 +            // Main Chart Component(s)
 1.10719 +            pie.width(availableWidth).height(availableHeight);
 1.10720 +            var pieWrap = g.select('.nv-pieWrap').datum([data]);
 1.10721 +            d3.transition(pieWrap).call(pie);
 1.10722 +
 1.10723 +            //============================================================
 1.10724 +            // Event Handling/Dispatching (in chart's scope)
 1.10725 +            //------------------------------------------------------------
 1.10726 +
 1.10727 +            legend.dispatch.on('stateChange', function(newState) {
 1.10728 +                for (var key in newState) {
 1.10729 +                    state[key] = newState[key];
 1.10730 +                }
 1.10731 +                dispatch.stateChange(state);
 1.10732 +                chart.update();
 1.10733 +            });
 1.10734 +
 1.10735 +            // Update chart from a state object passed to event handler
 1.10736 +            dispatch.on('changeState', function(e) {
 1.10737 +                if (typeof e.disabled !== 'undefined') {
 1.10738 +                    data.forEach(function(series,i) {
 1.10739 +                        series.disabled = e.disabled[i];
 1.10740 +                    });
 1.10741 +                    state.disabled = e.disabled;
 1.10742 +                }
 1.10743 +                chart.update();
 1.10744 +            });
 1.10745 +        });
 1.10746 +
 1.10747 +        renderWatch.renderEnd('pieChart immediate');
 1.10748 +        return chart;
 1.10749 +    }
 1.10750 +
 1.10751 +    //============================================================
 1.10752 +    // Event Handling/Dispatching (out of chart's scope)
 1.10753 +    //------------------------------------------------------------
 1.10754 +
 1.10755 +    pie.dispatch.on('elementMouseover.tooltip', function(evt) {
 1.10756 +        evt['series'] = {
 1.10757 +            key: chart.x()(evt.data),
 1.10758 +            value: chart.y()(evt.data),
 1.10759 +            color: evt.color
 1.10760 +        };
 1.10761 +        tooltip.data(evt).hidden(false);
 1.10762 +    });
 1.10763 +
 1.10764 +    pie.dispatch.on('elementMouseout.tooltip', function(evt) {
 1.10765 +        tooltip.hidden(true);
 1.10766 +    });
 1.10767 +
 1.10768 +    pie.dispatch.on('elementMousemove.tooltip', function(evt) {
 1.10769 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
 1.10770 +    });
 1.10771 +
 1.10772 +    //============================================================
 1.10773 +    // Expose Public Variables
 1.10774 +    //------------------------------------------------------------
 1.10775 +
 1.10776 +    // expose chart's sub-components
 1.10777 +    chart.legend = legend;
 1.10778 +    chart.dispatch = dispatch;
 1.10779 +    chart.pie = pie;
 1.10780 +    chart.tooltip = tooltip;
 1.10781 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.10782 +
 1.10783 +    // use Object get/set functionality to map between vars and chart functions
 1.10784 +    chart._options = Object.create({}, {
 1.10785 +        // simple options, just get/set the necessary values
 1.10786 +        noData:         {get: function(){return noData;},         set: function(_){noData=_;}},
 1.10787 +        showLegend:     {get: function(){return showLegend;},     set: function(_){showLegend=_;}},
 1.10788 +        legendPosition: {get: function(){return legendPosition;}, set: function(_){legendPosition=_;}},
 1.10789 +        defaultState:   {get: function(){return defaultState;},   set: function(_){defaultState=_;}},
 1.10790 +
 1.10791 +        // deprecated options
 1.10792 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
 1.10793 +            // deprecated after 1.7.1
 1.10794 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
 1.10795 +            tooltip.enabled(!!_);
 1.10796 +        }},
 1.10797 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
 1.10798 +            // deprecated after 1.7.1
 1.10799 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
 1.10800 +            tooltip.contentGenerator(_);
 1.10801 +        }},
 1.10802 +
 1.10803 +        // options that require extra logic in the setter
 1.10804 +        color: {get: function(){return color;}, set: function(_){
 1.10805 +            color = _;
 1.10806 +            legend.color(color);
 1.10807 +            pie.color(color);
 1.10808 +        }},
 1.10809 +        duration: {get: function(){return duration;}, set: function(_){
 1.10810 +            duration = _;
 1.10811 +            renderWatch.reset(duration);
 1.10812 +        }},
 1.10813 +        margin: {get: function(){return margin;}, set: function(_){
 1.10814 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.10815 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.10816 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.10817 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.10818 +        }}
 1.10819 +    });
 1.10820 +    nv.utils.inheritOptions(chart, pie);
 1.10821 +    nv.utils.initOptions(chart);
 1.10822 +    return chart;
 1.10823 +};
 1.10824 +
 1.10825 +nv.models.scatter = function() {
 1.10826 +    "use strict";
 1.10827 +
 1.10828 +    //============================================================
 1.10829 +    // Public Variables with Default Settings
 1.10830 +    //------------------------------------------------------------
 1.10831 +
 1.10832 +    var margin       = {top: 0, right: 0, bottom: 0, left: 0}
 1.10833 +        , width        = null
 1.10834 +        , height       = null
 1.10835 +        , color        = nv.utils.defaultColor() // chooses color
 1.10836 +        , id           = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't select one
 1.10837 +        , container    = null
 1.10838 +        , x            = d3.scale.linear()
 1.10839 +        , y            = d3.scale.linear()
 1.10840 +        , z            = d3.scale.linear() //linear because d3.svg.shape.size is treated as area
 1.10841 +        , getX         = function(d) { return d.x } // accessor to get the x value
 1.10842 +        , getY         = function(d) { return d.y } // accessor to get the y value
 1.10843 +        , getSize      = function(d) { return d.size || 1} // accessor to get the point size
 1.10844 +        , getShape     = function(d) { return d.shape || 'circle' } // accessor to get point shape
 1.10845 +        , forceX       = [] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
 1.10846 +        , forceY       = [] // List of numbers to Force into the Y scale
 1.10847 +        , forceSize    = [] // List of numbers to Force into the Size scale
 1.10848 +        , interactive  = true // If true, plots a voronoi overlay for advanced point intersection
 1.10849 +        , pointActive  = function(d) { return !d.notActive } // any points that return false will be filtered out
 1.10850 +        , padData      = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
 1.10851 +        , padDataOuter = .1 //outerPadding to imitate ordinal scale outer padding
 1.10852 +        , clipEdge     = false // if true, masks points within x and y scale
 1.10853 +        , clipVoronoi  = true // if true, masks each point with a circle... can turn off to slightly increase performance
 1.10854 +        , showVoronoi  = false // display the voronoi areas
 1.10855 +        , clipRadius   = function() { return 25 } // function to get the radius for voronoi point clips
 1.10856 +        , xDomain      = null // Override x domain (skips the calculation from data)
 1.10857 +        , yDomain      = null // Override y domain
 1.10858 +        , xRange       = null // Override x range
 1.10859 +        , yRange       = null // Override y range
 1.10860 +        , sizeDomain   = null // Override point size domain
 1.10861 +        , sizeRange    = null
 1.10862 +        , singlePoint  = false
 1.10863 +        , dispatch     = d3.dispatch('elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'renderEnd')
 1.10864 +        , useVoronoi   = true
 1.10865 +        , duration     = 250
 1.10866 +        ;
 1.10867 +
 1.10868 +
 1.10869 +    //============================================================
 1.10870 +    // Private Variables
 1.10871 +    //------------------------------------------------------------
 1.10872 +
 1.10873 +    var x0, y0, z0 // used to store previous scales
 1.10874 +        , timeoutID
 1.10875 +        , needsUpdate = false // Flag for when the points are visually updating, but the interactive layer is behind, to disable tooltips
 1.10876 +        , renderWatch = nv.utils.renderWatch(dispatch, duration)
 1.10877 +        , _sizeRange_def = [16, 256]
 1.10878 +        ;
 1.10879 +
 1.10880 +    function chart(selection) {
 1.10881 +        renderWatch.reset();
 1.10882 +        selection.each(function(data) {
 1.10883 +            container = d3.select(this);
 1.10884 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
 1.10885 +                availableHeight = nv.utils.availableHeight(height, container, margin);
 1.10886 +
 1.10887 +            nv.utils.initSVG(container);
 1.10888 +
 1.10889 +            //add series index to each data point for reference
 1.10890 +            data.forEach(function(series, i) {
 1.10891 +                series.values.forEach(function(point) {
 1.10892 +                    point.series = i;
 1.10893 +                });
 1.10894 +            });
 1.10895 +
 1.10896 +            // Setup Scales
 1.10897 +            // remap and flatten the data for use in calculating the scales' domains
 1.10898 +            var seriesData = (xDomain && yDomain && sizeDomain) ? [] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance
 1.10899 +                d3.merge(
 1.10900 +                    data.map(function(d) {
 1.10901 +                        return d.values.map(function(d,i) {
 1.10902 +                            return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) }
 1.10903 +                        })
 1.10904 +                    })
 1.10905 +                );
 1.10906 +
 1.10907 +            x   .domain(xDomain || d3.extent(seriesData.map(function(d) { return d.x; }).concat(forceX)))
 1.10908 +
 1.10909 +            if (padData && data[0])
 1.10910 +                x.range(xRange || [(availableWidth * padDataOuter +  availableWidth) / (2 *data[0].values.length), availableWidth - availableWidth * (1 + padDataOuter) / (2 * data[0].values.length)  ]);
 1.10911 +            //x.range([availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5)  / data[0].values.length ]);
 1.10912 +            else
 1.10913 +                x.range(xRange || [0, availableWidth]);
 1.10914 +
 1.10915 +            y   .domain(yDomain || d3.extent(seriesData.map(function(d) { return d.y }).concat(forceY)))
 1.10916 +                .range(yRange || [availableHeight, 0]);
 1.10917 +
 1.10918 +            z   .domain(sizeDomain || d3.extent(seriesData.map(function(d) { return d.size }).concat(forceSize)))
 1.10919 +                .range(sizeRange || _sizeRange_def);
 1.10920 +
 1.10921 +            // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
 1.10922 +            singlePoint = x.domain()[0] === x.domain()[1] || y.domain()[0] === y.domain()[1];
 1.10923 +
 1.10924 +            if (x.domain()[0] === x.domain()[1])
 1.10925 +                x.domain()[0] ?
 1.10926 +                    x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
 1.10927 +                    : x.domain([-1,1]);
 1.10928 +
 1.10929 +            if (y.domain()[0] === y.domain()[1])
 1.10930 +                y.domain()[0] ?
 1.10931 +                    y.domain([y.domain()[0] - y.domain()[0] * 0.01, y.domain()[1] + y.domain()[1] * 0.01])
 1.10932 +                    : y.domain([-1,1]);
 1.10933 +
 1.10934 +            if ( isNaN(x.domain()[0])) {
 1.10935 +                x.domain([-1,1]);
 1.10936 +            }
 1.10937 +
 1.10938 +            if ( isNaN(y.domain()[0])) {
 1.10939 +                y.domain([-1,1]);
 1.10940 +            }
 1.10941 +
 1.10942 +            x0 = x0 || x;
 1.10943 +            y0 = y0 || y;
 1.10944 +            z0 = z0 || z;
 1.10945 +
 1.10946 +            // Setup containers and skeleton of chart
 1.10947 +            var wrap = container.selectAll('g.nv-wrap.nv-scatter').data([data]);
 1.10948 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatter nv-chart-' + id);
 1.10949 +            var defsEnter = wrapEnter.append('defs');
 1.10950 +            var gEnter = wrapEnter.append('g');
 1.10951 +            var g = wrap.select('g');
 1.10952 +
 1.10953 +            wrap.classed('nv-single-point', singlePoint);
 1.10954 +            gEnter.append('g').attr('class', 'nv-groups');
 1.10955 +            gEnter.append('g').attr('class', 'nv-point-paths');
 1.10956 +            wrapEnter.append('g').attr('class', 'nv-point-clips');
 1.10957 +
 1.10958 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.10959 +
 1.10960 +            defsEnter.append('clipPath')
 1.10961 +                .attr('id', 'nv-edge-clip-' + id)
 1.10962 +                .append('rect');
 1.10963 +
 1.10964 +            wrap.select('#nv-edge-clip-' + id + ' rect')
 1.10965 +                .attr('width', availableWidth)
 1.10966 +                .attr('height', (availableHeight > 0) ? availableHeight : 0);
 1.10967 +
 1.10968 +            g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
 1.10969 +
 1.10970 +            function updateInteractiveLayer() {
 1.10971 +                // Always clear needs-update flag regardless of whether or not
 1.10972 +                // we will actually do anything (avoids needless invocations).
 1.10973 +                needsUpdate = false;
 1.10974 +
 1.10975 +                if (!interactive) return false;
 1.10976 +
 1.10977 +                // inject series and point index for reference into voronoi
 1.10978 +                if (useVoronoi === true) {
 1.10979 +                    var vertices = d3.merge(data.map(function(group, groupIndex) {
 1.10980 +                            return group.values
 1.10981 +                                .map(function(point, pointIndex) {
 1.10982 +                                    // *Adding noise to make duplicates very unlikely
 1.10983 +                                    // *Injecting series and point index for reference
 1.10984 +                                    /* *Adding a 'jitter' to the points, because there's an issue in d3.geom.voronoi.
 1.10985 +                                     */
 1.10986 +                                    var pX = getX(point,pointIndex);
 1.10987 +                                    var pY = getY(point,pointIndex);
 1.10988 +
 1.10989 +                                    return [x(pX)+ Math.random() * 1e-4,
 1.10990 +                                            y(pY)+ Math.random() * 1e-4,
 1.10991 +                                        groupIndex,
 1.10992 +                                        pointIndex, point]; //temp hack to add noise until I think of a better way so there are no duplicates
 1.10993 +                                })
 1.10994 +                                .filter(function(pointArray, pointIndex) {
 1.10995 +                                    return pointActive(pointArray[4], pointIndex); // Issue #237.. move filter to after map, so pointIndex is correct!
 1.10996 +                                })
 1.10997 +                        })
 1.10998 +                    );
 1.10999 +
 1.11000 +                    if (vertices.length == 0) return false;  // No active points, we're done
 1.11001 +                    if (vertices.length < 3) {
 1.11002 +                        // Issue #283 - Adding 2 dummy points to the voronoi b/c voronoi requires min 3 points to work
 1.11003 +                        vertices.push([x.range()[0] - 20, y.range()[0] - 20, null, null]);
 1.11004 +                        vertices.push([x.range()[1] + 20, y.range()[1] + 20, null, null]);
 1.11005 +                        vertices.push([x.range()[0] - 20, y.range()[0] + 20, null, null]);
 1.11006 +                        vertices.push([x.range()[1] + 20, y.range()[1] - 20, null, null]);
 1.11007 +                    }
 1.11008 +
 1.11009 +                    // keep voronoi sections from going more than 10 outside of graph
 1.11010 +                    // to avoid overlap with other things like legend etc
 1.11011 +                    var bounds = d3.geom.polygon([
 1.11012 +                        [-10,-10],
 1.11013 +                        [-10,height + 10],
 1.11014 +                        [width + 10,height + 10],
 1.11015 +                        [width + 10,-10]
 1.11016 +                    ]);
 1.11017 +
 1.11018 +                    var voronoi = d3.geom.voronoi(vertices).map(function(d, i) {
 1.11019 +                        return {
 1.11020 +                            'data': bounds.clip(d),
 1.11021 +                            'series': vertices[i][2],
 1.11022 +                            'point': vertices[i][3]
 1.11023 +                        }
 1.11024 +                    });
 1.11025 +
 1.11026 +                    // nuke all voronoi paths on reload and recreate them
 1.11027 +                    wrap.select('.nv-point-paths').selectAll('path').remove();
 1.11028 +                    var pointPaths = wrap.select('.nv-point-paths').selectAll('path').data(voronoi);
 1.11029 +                    var vPointPaths = pointPaths
 1.11030 +                        .enter().append("svg:path")
 1.11031 +                        .attr("d", function(d) {
 1.11032 +                            if (!d || !d.data || d.data.length === 0)
 1.11033 +                                return 'M 0 0';
 1.11034 +                            else
 1.11035 +                                return "M" + d.data.join(",") + "Z";
 1.11036 +                        })
 1.11037 +                        .attr("id", function(d,i) {
 1.11038 +                            return "nv-path-"+i; })
 1.11039 +                        .attr("clip-path", function(d,i) { return "url(#nv-clip-"+i+")"; })
 1.11040 +                        ;
 1.11041 +
 1.11042 +                    // good for debugging point hover issues
 1.11043 +                    if (showVoronoi) {
 1.11044 +                        vPointPaths.style("fill", d3.rgb(230, 230, 230))
 1.11045 +                            .style('fill-opacity', 0.4)
 1.11046 +                            .style('stroke-opacity', 1)
 1.11047 +                            .style("stroke", d3.rgb(200,200,200));
 1.11048 +                    }
 1.11049 +
 1.11050 +                    if (clipVoronoi) {
 1.11051 +                        // voronoi sections are already set to clip,
 1.11052 +                        // just create the circles with the IDs they expect
 1.11053 +                        wrap.select('.nv-point-clips').selectAll('clipPath').remove();
 1.11054 +                        wrap.select('.nv-point-clips').selectAll("clipPath")
 1.11055 +                            .data(vertices)
 1.11056 +                            .enter().append("svg:clipPath")
 1.11057 +                            .attr("id", function(d, i) { return "nv-clip-"+i;})
 1.11058 +                            .append("svg:circle")
 1.11059 +                            .attr('cx', function(d) { return d[0]; })
 1.11060 +                            .attr('cy', function(d) { return d[1]; })
 1.11061 +                            .attr('r', clipRadius);
 1.11062 +                    }
 1.11063 +
 1.11064 +                    var mouseEventCallback = function(d, mDispatch) {
 1.11065 +                        if (needsUpdate) return 0;
 1.11066 +                        var series = data[d.series];
 1.11067 +                        if (series === undefined) return;
 1.11068 +                        var point  = series.values[d.point];
 1.11069 +                        point['color'] = color(series, d.series);
 1.11070 +
 1.11071 +                        // standardize attributes for tooltip.
 1.11072 +                        point['x'] = getX(point);
 1.11073 +                        point['y'] = getY(point);
 1.11074 +
 1.11075 +                        // can't just get box of event node since it's actually a voronoi polygon
 1.11076 +                        var box = container.node().getBoundingClientRect();
 1.11077 +                        var scrollTop  = window.pageYOffset || document.documentElement.scrollTop;
 1.11078 +                        var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
 1.11079 +
 1.11080 +                        var pos = {
 1.11081 +                            left: x(getX(point, d.point)) + box.left + scrollLeft + margin.left + 10,
 1.11082 +                            top: y(getY(point, d.point)) + box.top + scrollTop + margin.top + 10
 1.11083 +                        };
 1.11084 +
 1.11085 +                        mDispatch({
 1.11086 +                            point: point,
 1.11087 +                            series: series,
 1.11088 +                            pos: pos,
 1.11089 +                            seriesIndex: d.series,
 1.11090 +                            pointIndex: d.point
 1.11091 +                        });
 1.11092 +                    };
 1.11093 +
 1.11094 +                    pointPaths
 1.11095 +                        .on('click', function(d) {
 1.11096 +                            mouseEventCallback(d, dispatch.elementClick);
 1.11097 +                        })
 1.11098 +                        .on('dblclick', function(d) {
 1.11099 +                            mouseEventCallback(d, dispatch.elementDblClick);
 1.11100 +                        })
 1.11101 +                        .on('mouseover', function(d) {
 1.11102 +                            mouseEventCallback(d, dispatch.elementMouseover);
 1.11103 +                        })
 1.11104 +                        .on('mouseout', function(d, i) {
 1.11105 +                            mouseEventCallback(d, dispatch.elementMouseout);
 1.11106 +                        });
 1.11107 +
 1.11108 +                } else {
 1.11109 +                    // add event handlers to points instead voronoi paths
 1.11110 +                    wrap.select('.nv-groups').selectAll('.nv-group')
 1.11111 +                        .selectAll('.nv-point')
 1.11112 +                        //.data(dataWithPoints)
 1.11113 +                        //.style('pointer-events', 'auto') // recativate events, disabled by css
 1.11114 +                        .on('click', function(d,i) {
 1.11115 +                            //nv.log('test', d, i);
 1.11116 +                            if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
 1.11117 +                            var series = data[d.series],
 1.11118 +                                point  = series.values[i];
 1.11119 +
 1.11120 +                            dispatch.elementClick({
 1.11121 +                                point: point,
 1.11122 +                                series: series,
 1.11123 +                                pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top],
 1.11124 +                                seriesIndex: d.series,
 1.11125 +                                pointIndex: i
 1.11126 +                            });
 1.11127 +                        })
 1.11128 +                        .on('dblclick', function(d,i) {
 1.11129 +                            if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
 1.11130 +                            var series = data[d.series],
 1.11131 +                                point  = series.values[i];
 1.11132 +
 1.11133 +                            dispatch.elementDblClick({
 1.11134 +                                point: point,
 1.11135 +                                series: series,
 1.11136 +                                pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top],
 1.11137 +                                seriesIndex: d.series,
 1.11138 +                                pointIndex: i
 1.11139 +                            });
 1.11140 +                        })
 1.11141 +                        .on('mouseover', function(d,i) {
 1.11142 +                            if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
 1.11143 +                            var series = data[d.series],
 1.11144 +                                point  = series.values[i];
 1.11145 +
 1.11146 +                            dispatch.elementMouseover({
 1.11147 +                                point: point,
 1.11148 +                                series: series,
 1.11149 +                                pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top],
 1.11150 +                                seriesIndex: d.series,
 1.11151 +                                pointIndex: i,
 1.11152 +                                color: color(d, i)
 1.11153 +                            });
 1.11154 +                        })
 1.11155 +                        .on('mouseout', function(d,i) {
 1.11156 +                            if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point
 1.11157 +                            var series = data[d.series],
 1.11158 +                                point  = series.values[i];
 1.11159 +
 1.11160 +                            dispatch.elementMouseout({
 1.11161 +                                point: point,
 1.11162 +                                series: series,
 1.11163 +                                seriesIndex: d.series,
 1.11164 +                                pointIndex: i,
 1.11165 +                                color: color(d, i)
 1.11166 +                            });
 1.11167 +                        });
 1.11168 +                }
 1.11169 +            }
 1.11170 +
 1.11171 +            needsUpdate = true;
 1.11172 +            var groups = wrap.select('.nv-groups').selectAll('.nv-group')
 1.11173 +                .data(function(d) { return d }, function(d) { return d.key });
 1.11174 +            groups.enter().append('g')
 1.11175 +                .style('stroke-opacity', 1e-6)
 1.11176 +                .style('fill-opacity', 1e-6);
 1.11177 +            groups.exit()
 1.11178 +                .remove();
 1.11179 +            groups
 1.11180 +                .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
 1.11181 +                .classed('hover', function(d) { return d.hover });
 1.11182 +            groups.watchTransition(renderWatch, 'scatter: groups')
 1.11183 +                .style('fill', function(d,i) { return color(d, i) })
 1.11184 +                .style('stroke', function(d,i) { return color(d, i) })
 1.11185 +                .style('stroke-opacity', 1)
 1.11186 +                .style('fill-opacity', .5);
 1.11187 +
 1.11188 +            // create the points, maintaining their IDs from the original data set
 1.11189 +            var points = groups.selectAll('path.nv-point')
 1.11190 +                .data(function(d) {
 1.11191 +                    return d.values.map(
 1.11192 +                        function (point, pointIndex) {
 1.11193 +                            return [point, pointIndex]
 1.11194 +                        }).filter(
 1.11195 +                            function(pointArray, pointIndex) {
 1.11196 +                                return pointActive(pointArray[0], pointIndex)
 1.11197 +                            })
 1.11198 +                    });
 1.11199 +            points.enter().append('path')
 1.11200 +                .style('fill', function (d) { return d.color })
 1.11201 +                .style('stroke', function (d) { return d.color })
 1.11202 +                .attr('transform', function(d) {
 1.11203 +                    return 'translate(' + x0(getX(d[0],d[1])) + ',' + y0(getY(d[0],d[1])) + ')'
 1.11204 +                })
 1.11205 +                .attr('d',
 1.11206 +                    nv.utils.symbol()
 1.11207 +                    .type(function(d) { return getShape(d[0]); })
 1.11208 +                    .size(function(d) { return z(getSize(d[0],d[1])) })
 1.11209 +            );
 1.11210 +            points.exit().remove();
 1.11211 +            groups.exit().selectAll('path.nv-point')
 1.11212 +                .watchTransition(renderWatch, 'scatter exit')
 1.11213 +                .attr('transform', function(d) {
 1.11214 +                    return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')'
 1.11215 +                })
 1.11216 +                .remove();
 1.11217 +            points.each(function(d) {
 1.11218 +                d3.select(this)
 1.11219 +                    .classed('nv-point', true)
 1.11220 +                    .classed('nv-point-' + d[1], true)
 1.11221 +                    .classed('nv-noninteractive', !interactive)
 1.11222 +                    .classed('hover',false)
 1.11223 +                ;
 1.11224 +            });
 1.11225 +            points
 1.11226 +                .watchTransition(renderWatch, 'scatter points')
 1.11227 +                .attr('transform', function(d) {
 1.11228 +                    //nv.log(d, getX(d[0],d[1]), x(getX(d[0],d[1])));
 1.11229 +                    return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')'
 1.11230 +                })
 1.11231 +                .attr('d',
 1.11232 +                    nv.utils.symbol()
 1.11233 +                    .type(function(d) { return getShape(d[0]); })
 1.11234 +                    .size(function(d) { return z(getSize(d[0],d[1])) })
 1.11235 +            );
 1.11236 +
 1.11237 +            // Delay updating the invisible interactive layer for smoother animation
 1.11238 +            clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer
 1.11239 +            timeoutID = setTimeout(updateInteractiveLayer, 300);
 1.11240 +            //updateInteractiveLayer();
 1.11241 +
 1.11242 +            //store old scales for use in transitions on update
 1.11243 +            x0 = x.copy();
 1.11244 +            y0 = y.copy();
 1.11245 +            z0 = z.copy();
 1.11246 +
 1.11247 +        });
 1.11248 +        renderWatch.renderEnd('scatter immediate');
 1.11249 +        return chart;
 1.11250 +    }
 1.11251 +
 1.11252 +    //============================================================
 1.11253 +    // Expose Public Variables
 1.11254 +    //------------------------------------------------------------
 1.11255 +
 1.11256 +    chart.dispatch = dispatch;
 1.11257 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.11258 +
 1.11259 +    // utility function calls provided by this chart
 1.11260 +    chart._calls = new function() {
 1.11261 +        this.clearHighlights = function () {
 1.11262 +            nv.dom.write(function() {
 1.11263 +                container.selectAll(".nv-point.hover").classed("hover", false);
 1.11264 +            });
 1.11265 +            return null;
 1.11266 +        };
 1.11267 +        this.highlightPoint = function (seriesIndex, pointIndex, isHoverOver) {
 1.11268 +            nv.dom.write(function() {
 1.11269 +                container.select(" .nv-series-" + seriesIndex + " .nv-point-" + pointIndex)
 1.11270 +                    .classed("hover", isHoverOver);
 1.11271 +            });
 1.11272 +        };
 1.11273 +    };
 1.11274 +
 1.11275 +    // trigger calls from events too
 1.11276 +    dispatch.on('elementMouseover.point', function(d) {
 1.11277 +        if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,true);
 1.11278 +    });
 1.11279 +
 1.11280 +    dispatch.on('elementMouseout.point', function(d) {
 1.11281 +        if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,false);
 1.11282 +    });
 1.11283 +
 1.11284 +    chart._options = Object.create({}, {
 1.11285 +        // simple options, just get/set the necessary values
 1.11286 +        width:        {get: function(){return width;}, set: function(_){width=_;}},
 1.11287 +        height:       {get: function(){return height;}, set: function(_){height=_;}},
 1.11288 +        xScale:       {get: function(){return x;}, set: function(_){x=_;}},
 1.11289 +        yScale:       {get: function(){return y;}, set: function(_){y=_;}},
 1.11290 +        pointScale:   {get: function(){return z;}, set: function(_){z=_;}},
 1.11291 +        xDomain:      {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
 1.11292 +        yDomain:      {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
 1.11293 +        pointDomain:  {get: function(){return sizeDomain;}, set: function(_){sizeDomain=_;}},
 1.11294 +        xRange:       {get: function(){return xRange;}, set: function(_){xRange=_;}},
 1.11295 +        yRange:       {get: function(){return yRange;}, set: function(_){yRange=_;}},
 1.11296 +        pointRange:   {get: function(){return sizeRange;}, set: function(_){sizeRange=_;}},
 1.11297 +        forceX:       {get: function(){return forceX;}, set: function(_){forceX=_;}},
 1.11298 +        forceY:       {get: function(){return forceY;}, set: function(_){forceY=_;}},
 1.11299 +        forcePoint:   {get: function(){return forceSize;}, set: function(_){forceSize=_;}},
 1.11300 +        interactive:  {get: function(){return interactive;}, set: function(_){interactive=_;}},
 1.11301 +        pointActive:  {get: function(){return pointActive;}, set: function(_){pointActive=_;}},
 1.11302 +        padDataOuter: {get: function(){return padDataOuter;}, set: function(_){padDataOuter=_;}},
 1.11303 +        padData:      {get: function(){return padData;}, set: function(_){padData=_;}},
 1.11304 +        clipEdge:     {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
 1.11305 +        clipVoronoi:  {get: function(){return clipVoronoi;}, set: function(_){clipVoronoi=_;}},
 1.11306 +        clipRadius:   {get: function(){return clipRadius;}, set: function(_){clipRadius=_;}},
 1.11307 +        showVoronoi:   {get: function(){return showVoronoi;}, set: function(_){showVoronoi=_;}},
 1.11308 +        id:           {get: function(){return id;}, set: function(_){id=_;}},
 1.11309 +
 1.11310 +
 1.11311 +        // simple functor options
 1.11312 +        x:     {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}},
 1.11313 +        y:     {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}},
 1.11314 +        pointSize: {get: function(){return getSize;}, set: function(_){getSize = d3.functor(_);}},
 1.11315 +        pointShape: {get: function(){return getShape;}, set: function(_){getShape = d3.functor(_);}},
 1.11316 +
 1.11317 +        // options that require extra logic in the setter
 1.11318 +        margin: {get: function(){return margin;}, set: function(_){
 1.11319 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.11320 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.11321 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.11322 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.11323 +        }},
 1.11324 +        duration: {get: function(){return duration;}, set: function(_){
 1.11325 +            duration = _;
 1.11326 +            renderWatch.reset(duration);
 1.11327 +        }},
 1.11328 +        color: {get: function(){return color;}, set: function(_){
 1.11329 +            color = nv.utils.getColor(_);
 1.11330 +        }},
 1.11331 +        useVoronoi: {get: function(){return useVoronoi;}, set: function(_){
 1.11332 +            useVoronoi = _;
 1.11333 +            if (useVoronoi === false) {
 1.11334 +                clipVoronoi = false;
 1.11335 +            }
 1.11336 +        }}
 1.11337 +    });
 1.11338 +
 1.11339 +    nv.utils.initOptions(chart);
 1.11340 +    return chart;
 1.11341 +};
 1.11342 +
 1.11343 +nv.models.scatterChart = function() {
 1.11344 +    "use strict";
 1.11345 +
 1.11346 +    //============================================================
 1.11347 +    // Public Variables with Default Settings
 1.11348 +    //------------------------------------------------------------
 1.11349 +
 1.11350 +    var scatter      = nv.models.scatter()
 1.11351 +        , xAxis        = nv.models.axis()
 1.11352 +        , yAxis        = nv.models.axis()
 1.11353 +        , legend       = nv.models.legend()
 1.11354 +        , distX        = nv.models.distribution()
 1.11355 +        , distY        = nv.models.distribution()
 1.11356 +        , tooltip      = nv.models.tooltip()
 1.11357 +        ;
 1.11358 +
 1.11359 +    var margin       = {top: 30, right: 20, bottom: 50, left: 75}
 1.11360 +        , width        = null
 1.11361 +        , height       = null
 1.11362 +        , container    = null
 1.11363 +        , color        = nv.utils.defaultColor()
 1.11364 +        , x            = scatter.xScale()
 1.11365 +        , y            = scatter.yScale()
 1.11366 +        , showDistX    = false
 1.11367 +        , showDistY    = false
 1.11368 +        , showLegend   = true
 1.11369 +        , showXAxis    = true
 1.11370 +        , showYAxis    = true
 1.11371 +        , rightAlignYAxis = false
 1.11372 +        , state = nv.utils.state()
 1.11373 +        , defaultState = null
 1.11374 +        , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd')
 1.11375 +        , noData       = null
 1.11376 +        , duration = 250
 1.11377 +        ;
 1.11378 +
 1.11379 +    scatter.xScale(x).yScale(y);
 1.11380 +    xAxis.orient('bottom').tickPadding(10);
 1.11381 +    yAxis
 1.11382 +        .orient((rightAlignYAxis) ? 'right' : 'left')
 1.11383 +        .tickPadding(10)
 1.11384 +    ;
 1.11385 +    distX.axis('x');
 1.11386 +    distY.axis('y');
 1.11387 +    tooltip
 1.11388 +        .headerFormatter(function(d, i) {
 1.11389 +            return xAxis.tickFormat()(d, i);
 1.11390 +        })
 1.11391 +        .valueFormatter(function(d, i) {
 1.11392 +            return yAxis.tickFormat()(d, i);
 1.11393 +        });
 1.11394 +
 1.11395 +    //============================================================
 1.11396 +    // Private Variables
 1.11397 +    //------------------------------------------------------------
 1.11398 +
 1.11399 +    var x0, y0
 1.11400 +        , renderWatch = nv.utils.renderWatch(dispatch, duration);
 1.11401 +
 1.11402 +    var stateGetter = function(data) {
 1.11403 +        return function(){
 1.11404 +            return {
 1.11405 +                active: data.map(function(d) { return !d.disabled })
 1.11406 +            };
 1.11407 +        }
 1.11408 +    };
 1.11409 +
 1.11410 +    var stateSetter = function(data) {
 1.11411 +        return function(state) {
 1.11412 +            if (state.active !== undefined)
 1.11413 +                data.forEach(function(series,i) {
 1.11414 +                    series.disabled = !state.active[i];
 1.11415 +                });
 1.11416 +        }
 1.11417 +    };
 1.11418 +
 1.11419 +    function chart(selection) {
 1.11420 +        renderWatch.reset();
 1.11421 +        renderWatch.models(scatter);
 1.11422 +        if (showXAxis) renderWatch.models(xAxis);
 1.11423 +        if (showYAxis) renderWatch.models(yAxis);
 1.11424 +        if (showDistX) renderWatch.models(distX);
 1.11425 +        if (showDistY) renderWatch.models(distY);
 1.11426 +
 1.11427 +        selection.each(function(data) {
 1.11428 +            var that = this;
 1.11429 +
 1.11430 +            container = d3.select(this);
 1.11431 +            nv.utils.initSVG(container);
 1.11432 +
 1.11433 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
 1.11434 +                availableHeight = nv.utils.availableHeight(height, container, margin);
 1.11435 +
 1.11436 +            chart.update = function() {
 1.11437 +                if (duration === 0)
 1.11438 +                    container.call(chart);
 1.11439 +                else
 1.11440 +                    container.transition().duration(duration).call(chart);
 1.11441 +            };
 1.11442 +            chart.container = this;
 1.11443 +
 1.11444 +            state
 1.11445 +                .setter(stateSetter(data), chart.update)
 1.11446 +                .getter(stateGetter(data))
 1.11447 +                .update();
 1.11448 +
 1.11449 +            // DEPRECATED set state.disableddisabled
 1.11450 +            state.disabled = data.map(function(d) { return !!d.disabled });
 1.11451 +
 1.11452 +            if (!defaultState) {
 1.11453 +                var key;
 1.11454 +                defaultState = {};
 1.11455 +                for (key in state) {
 1.11456 +                    if (state[key] instanceof Array)
 1.11457 +                        defaultState[key] = state[key].slice(0);
 1.11458 +                    else
 1.11459 +                        defaultState[key] = state[key];
 1.11460 +                }
 1.11461 +            }
 1.11462 +
 1.11463 +            // Display noData message if there's nothing to show.
 1.11464 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
 1.11465 +                nv.utils.noData(chart, container);
 1.11466 +                renderWatch.renderEnd('scatter immediate');
 1.11467 +                return chart;
 1.11468 +            } else {
 1.11469 +                container.selectAll('.nv-noData').remove();
 1.11470 +            }
 1.11471 +
 1.11472 +            // Setup Scales
 1.11473 +            x = scatter.xScale();
 1.11474 +            y = scatter.yScale();
 1.11475 +
 1.11476 +            // Setup containers and skeleton of chart
 1.11477 +            var wrap = container.selectAll('g.nv-wrap.nv-scatterChart').data([data]);
 1.11478 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatterChart nv-chart-' + scatter.id());
 1.11479 +            var gEnter = wrapEnter.append('g');
 1.11480 +            var g = wrap.select('g');
 1.11481 +
 1.11482 +            // background for pointer events
 1.11483 +            gEnter.append('rect').attr('class', 'nvd3 nv-background').style("pointer-events","none");
 1.11484 +
 1.11485 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
 1.11486 +            gEnter.append('g').attr('class', 'nv-y nv-axis');
 1.11487 +            gEnter.append('g').attr('class', 'nv-scatterWrap');
 1.11488 +            gEnter.append('g').attr('class', 'nv-regressionLinesWrap');
 1.11489 +            gEnter.append('g').attr('class', 'nv-distWrap');
 1.11490 +            gEnter.append('g').attr('class', 'nv-legendWrap');
 1.11491 +
 1.11492 +            if (rightAlignYAxis) {
 1.11493 +                g.select(".nv-y.nv-axis")
 1.11494 +                    .attr("transform", "translate(" + availableWidth + ",0)");
 1.11495 +            }
 1.11496 +
 1.11497 +            // Legend
 1.11498 +            if (showLegend) {
 1.11499 +                var legendWidth = availableWidth;
 1.11500 +                legend.width(legendWidth);
 1.11501 +
 1.11502 +                wrap.select('.nv-legendWrap')
 1.11503 +                    .datum(data)
 1.11504 +                    .call(legend);
 1.11505 +
 1.11506 +                if ( margin.top != legend.height()) {
 1.11507 +                    margin.top = legend.height();
 1.11508 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
 1.11509 +                }
 1.11510 +
 1.11511 +                wrap.select('.nv-legendWrap')
 1.11512 +                    .attr('transform', 'translate(0' + ',' + (-margin.top) +')');
 1.11513 +            }
 1.11514 +
 1.11515 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.11516 +
 1.11517 +            // Main Chart Component(s)
 1.11518 +            scatter
 1.11519 +                .width(availableWidth)
 1.11520 +                .height(availableHeight)
 1.11521 +                .color(data.map(function(d,i) {
 1.11522 +                    d.color = d.color || color(d, i);
 1.11523 +                    return d.color;
 1.11524 +                }).filter(function(d,i) { return !data[i].disabled }));
 1.11525 +
 1.11526 +            wrap.select('.nv-scatterWrap')
 1.11527 +                .datum(data.filter(function(d) { return !d.disabled }))
 1.11528 +                .call(scatter);
 1.11529 +
 1.11530 +
 1.11531 +            wrap.select('.nv-regressionLinesWrap')
 1.11532 +                .attr('clip-path', 'url(#nv-edge-clip-' + scatter.id() + ')');
 1.11533 +
 1.11534 +            var regWrap = wrap.select('.nv-regressionLinesWrap').selectAll('.nv-regLines')
 1.11535 +                .data(function (d) {
 1.11536 +                    return d;
 1.11537 +                });
 1.11538 +
 1.11539 +            regWrap.enter().append('g').attr('class', 'nv-regLines');
 1.11540 +
 1.11541 +            var regLine = regWrap.selectAll('.nv-regLine')
 1.11542 +                .data(function (d) {
 1.11543 +                    return [d]
 1.11544 +                });
 1.11545 +
 1.11546 +            regLine.enter()
 1.11547 +                .append('line').attr('class', 'nv-regLine')
 1.11548 +                .style('stroke-opacity', 0);
 1.11549 +
 1.11550 +            // don't add lines unless we have slope and intercept to use
 1.11551 +            regLine.filter(function(d) {
 1.11552 +                return d.intercept && d.slope;
 1.11553 +            })
 1.11554 +                .watchTransition(renderWatch, 'scatterPlusLineChart: regline')
 1.11555 +                .attr('x1', x.range()[0])
 1.11556 +                .attr('x2', x.range()[1])
 1.11557 +                .attr('y1', function (d, i) {
 1.11558 +                    return y(x.domain()[0] * d.slope + d.intercept)
 1.11559 +                })
 1.11560 +                .attr('y2', function (d, i) {
 1.11561 +                    return y(x.domain()[1] * d.slope + d.intercept)
 1.11562 +                })
 1.11563 +                .style('stroke', function (d, i, j) {
 1.11564 +                    return color(d, j)
 1.11565 +                })
 1.11566 +                .style('stroke-opacity', function (d, i) {
 1.11567 +                    return (d.disabled || typeof d.slope === 'undefined' || typeof d.intercept === 'undefined') ? 0 : 1
 1.11568 +                });
 1.11569 +
 1.11570 +            // Setup Axes
 1.11571 +            if (showXAxis) {
 1.11572 +                xAxis
 1.11573 +                    .scale(x)
 1.11574 +                    ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
 1.11575 +                    .tickSize( -availableHeight , 0);
 1.11576 +
 1.11577 +                g.select('.nv-x.nv-axis')
 1.11578 +                    .attr('transform', 'translate(0,' + y.range()[0] + ')')
 1.11579 +                    .call(xAxis);
 1.11580 +            }
 1.11581 +
 1.11582 +            if (showYAxis) {
 1.11583 +                yAxis
 1.11584 +                    .scale(y)
 1.11585 +                    ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
 1.11586 +                    .tickSize( -availableWidth, 0);
 1.11587 +
 1.11588 +                g.select('.nv-y.nv-axis')
 1.11589 +                    .call(yAxis);
 1.11590 +            }
 1.11591 +
 1.11592 +
 1.11593 +            if (showDistX) {
 1.11594 +                distX
 1.11595 +                    .getData(scatter.x())
 1.11596 +                    .scale(x)
 1.11597 +                    .width(availableWidth)
 1.11598 +                    .color(data.map(function(d,i) {
 1.11599 +                        return d.color || color(d, i);
 1.11600 +                    }).filter(function(d,i) { return !data[i].disabled }));
 1.11601 +                gEnter.select('.nv-distWrap').append('g')
 1.11602 +                    .attr('class', 'nv-distributionX');
 1.11603 +                g.select('.nv-distributionX')
 1.11604 +                    .attr('transform', 'translate(0,' + y.range()[0] + ')')
 1.11605 +                    .datum(data.filter(function(d) { return !d.disabled }))
 1.11606 +                    .call(distX);
 1.11607 +            }
 1.11608 +
 1.11609 +            if (showDistY) {
 1.11610 +                distY
 1.11611 +                    .getData(scatter.y())
 1.11612 +                    .scale(y)
 1.11613 +                    .width(availableHeight)
 1.11614 +                    .color(data.map(function(d,i) {
 1.11615 +                        return d.color || color(d, i);
 1.11616 +                    }).filter(function(d,i) { return !data[i].disabled }));
 1.11617 +                gEnter.select('.nv-distWrap').append('g')
 1.11618 +                    .attr('class', 'nv-distributionY');
 1.11619 +                g.select('.nv-distributionY')
 1.11620 +                    .attr('transform', 'translate(' + (rightAlignYAxis ? availableWidth : -distY.size() ) + ',0)')
 1.11621 +                    .datum(data.filter(function(d) { return !d.disabled }))
 1.11622 +                    .call(distY);
 1.11623 +            }
 1.11624 +
 1.11625 +            //============================================================
 1.11626 +            // Event Handling/Dispatching (in chart's scope)
 1.11627 +            //------------------------------------------------------------
 1.11628 +
 1.11629 +            legend.dispatch.on('stateChange', function(newState) {
 1.11630 +                for (var key in newState)
 1.11631 +                    state[key] = newState[key];
 1.11632 +                dispatch.stateChange(state);
 1.11633 +                chart.update();
 1.11634 +            });
 1.11635 +
 1.11636 +            // Update chart from a state object passed to event handler
 1.11637 +            dispatch.on('changeState', function(e) {
 1.11638 +                if (typeof e.disabled !== 'undefined') {
 1.11639 +                    data.forEach(function(series,i) {
 1.11640 +                        series.disabled = e.disabled[i];
 1.11641 +                    });
 1.11642 +                    state.disabled = e.disabled;
 1.11643 +                }
 1.11644 +                chart.update();
 1.11645 +            });
 1.11646 +
 1.11647 +            // mouseover needs availableHeight so we just keep scatter mouse events inside the chart block
 1.11648 +            scatter.dispatch.on('elementMouseout.tooltip', function(evt) {
 1.11649 +                tooltip.hidden(true);
 1.11650 +                container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex)
 1.11651 +                    .attr('y1', 0);
 1.11652 +                container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex)
 1.11653 +                    .attr('x2', distY.size());
 1.11654 +            });
 1.11655 +
 1.11656 +            scatter.dispatch.on('elementMouseover.tooltip', function(evt) {
 1.11657 +                container.select('.nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex)
 1.11658 +                    .attr('y1', evt.pos.top - availableHeight - margin.top);
 1.11659 +                container.select('.nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex)
 1.11660 +                    .attr('x2', evt.pos.left + distX.size() - margin.left);
 1.11661 +                tooltip.position(evt.pos).data(evt).hidden(false);
 1.11662 +            });
 1.11663 +
 1.11664 +            //store old scales for use in transitions on update
 1.11665 +            x0 = x.copy();
 1.11666 +            y0 = y.copy();
 1.11667 +
 1.11668 +        });
 1.11669 +
 1.11670 +        renderWatch.renderEnd('scatter with line immediate');
 1.11671 +        return chart;
 1.11672 +    }
 1.11673 +
 1.11674 +    //============================================================
 1.11675 +    // Expose Public Variables
 1.11676 +    //------------------------------------------------------------
 1.11677 +
 1.11678 +    // expose chart's sub-components
 1.11679 +    chart.dispatch = dispatch;
 1.11680 +    chart.scatter = scatter;
 1.11681 +    chart.legend = legend;
 1.11682 +    chart.xAxis = xAxis;
 1.11683 +    chart.yAxis = yAxis;
 1.11684 +    chart.distX = distX;
 1.11685 +    chart.distY = distY;
 1.11686 +    chart.tooltip = tooltip;
 1.11687 +
 1.11688 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.11689 +    chart._options = Object.create({}, {
 1.11690 +        // simple options, just get/set the necessary values
 1.11691 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
 1.11692 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
 1.11693 +        container:  {get: function(){return container;}, set: function(_){container=_;}},
 1.11694 +        showDistX:  {get: function(){return showDistX;}, set: function(_){showDistX=_;}},
 1.11695 +        showDistY:  {get: function(){return showDistY;}, set: function(_){showDistY=_;}},
 1.11696 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
 1.11697 +        showXAxis:  {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
 1.11698 +        showYAxis:  {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
 1.11699 +        defaultState:     {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
 1.11700 +        noData:     {get: function(){return noData;}, set: function(_){noData=_;}},
 1.11701 +        duration:   {get: function(){return duration;}, set: function(_){duration=_;}},
 1.11702 +
 1.11703 +        // deprecated options
 1.11704 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
 1.11705 +            // deprecated after 1.7.1
 1.11706 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
 1.11707 +            tooltip.enabled(!!_);
 1.11708 +        }},
 1.11709 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
 1.11710 +            // deprecated after 1.7.1
 1.11711 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
 1.11712 +            tooltip.contentGenerator(_);
 1.11713 +        }},
 1.11714 +        tooltipXContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
 1.11715 +            // deprecated after 1.7.1
 1.11716 +            nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.');
 1.11717 +        }},
 1.11718 +        tooltipYContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
 1.11719 +            // deprecated after 1.7.1
 1.11720 +            nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.');
 1.11721 +        }},
 1.11722 +
 1.11723 +        // options that require extra logic in the setter
 1.11724 +        margin: {get: function(){return margin;}, set: function(_){
 1.11725 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.11726 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.11727 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.11728 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.11729 +        }},
 1.11730 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
 1.11731 +            rightAlignYAxis = _;
 1.11732 +            yAxis.orient( (_) ? 'right' : 'left');
 1.11733 +        }},
 1.11734 +        color: {get: function(){return color;}, set: function(_){
 1.11735 +            color = nv.utils.getColor(_);
 1.11736 +            legend.color(color);
 1.11737 +            distX.color(color);
 1.11738 +            distY.color(color);
 1.11739 +        }}
 1.11740 +    });
 1.11741 +
 1.11742 +    nv.utils.inheritOptions(chart, scatter);
 1.11743 +    nv.utils.initOptions(chart);
 1.11744 +    return chart;
 1.11745 +};
 1.11746 +
 1.11747 +nv.models.sparkline = function() {
 1.11748 +    "use strict";
 1.11749 +
 1.11750 +    //============================================================
 1.11751 +    // Public Variables with Default Settings
 1.11752 +    //------------------------------------------------------------
 1.11753 +
 1.11754 +    var margin = {top: 2, right: 0, bottom: 2, left: 0}
 1.11755 +        , width = 400
 1.11756 +        , height = 32
 1.11757 +        , container = null
 1.11758 +        , animate = true
 1.11759 +        , x = d3.scale.linear()
 1.11760 +        , y = d3.scale.linear()
 1.11761 +        , getX = function(d) { return d.x }
 1.11762 +        , getY = function(d) { return d.y }
 1.11763 +        , color = nv.utils.getColor(['#000'])
 1.11764 +        , xDomain
 1.11765 +        , yDomain
 1.11766 +        , xRange
 1.11767 +        , yRange
 1.11768 +        ;
 1.11769 +
 1.11770 +    function chart(selection) {
 1.11771 +        selection.each(function(data) {
 1.11772 +            var availableWidth = width - margin.left - margin.right,
 1.11773 +                availableHeight = height - margin.top - margin.bottom;
 1.11774 +
 1.11775 +            container = d3.select(this);
 1.11776 +            nv.utils.initSVG(container);
 1.11777 +
 1.11778 +            // Setup Scales
 1.11779 +            x   .domain(xDomain || d3.extent(data, getX ))
 1.11780 +                .range(xRange || [0, availableWidth]);
 1.11781 +
 1.11782 +            y   .domain(yDomain || d3.extent(data, getY ))
 1.11783 +                .range(yRange || [availableHeight, 0]);
 1.11784 +
 1.11785 +            // Setup containers and skeleton of chart
 1.11786 +            var wrap = container.selectAll('g.nv-wrap.nv-sparkline').data([data]);
 1.11787 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparkline');
 1.11788 +            var gEnter = wrapEnter.append('g');
 1.11789 +            var g = wrap.select('g');
 1.11790 +
 1.11791 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
 1.11792 +
 1.11793 +            var paths = wrap.selectAll('path')
 1.11794 +                .data(function(d) { return [d] });
 1.11795 +            paths.enter().append('path');
 1.11796 +            paths.exit().remove();
 1.11797 +            paths
 1.11798 +                .style('stroke', function(d,i) { return d.color || color(d, i) })
 1.11799 +                .attr('d', d3.svg.line()
 1.11800 +                    .x(function(d,i) { return x(getX(d,i)) })
 1.11801 +                    .y(function(d,i) { return y(getY(d,i)) })
 1.11802 +            );
 1.11803 +
 1.11804 +            // TODO: Add CURRENT data point (Need Min, Mac, Current / Most recent)
 1.11805 +            var points = wrap.selectAll('circle.nv-point')
 1.11806 +                .data(function(data) {
 1.11807 +                    var yValues = data.map(function(d, i) { return getY(d,i); });
 1.11808 +                    function pointIndex(index) {
 1.11809 +                        if (index != -1) {
 1.11810 +                            var result = data[index];
 1.11811 +                            result.pointIndex = index;
 1.11812 +                            return result;
 1.11813 +                        } else {
 1.11814 +                            return null;
 1.11815 +                        }
 1.11816 +                    }
 1.11817 +                    var maxPoint = pointIndex(yValues.lastIndexOf(y.domain()[1])),
 1.11818 +                        minPoint = pointIndex(yValues.indexOf(y.domain()[0])),
 1.11819 +                        currentPoint = pointIndex(yValues.length - 1);
 1.11820 +                    return [minPoint, maxPoint, currentPoint].filter(function (d) {return d != null;});
 1.11821 +                });
 1.11822 +            points.enter().append('circle');
 1.11823 +            points.exit().remove();
 1.11824 +            points
 1.11825 +                .attr('cx', function(d,i) { return x(getX(d,d.pointIndex)) })
 1.11826 +                .attr('cy', function(d,i) { return y(getY(d,d.pointIndex)) })
 1.11827 +                .attr('r', 2)
 1.11828 +                .attr('class', function(d,i) {
 1.11829 +                    return getX(d, d.pointIndex) == x.domain()[1] ? 'nv-point nv-currentValue' :
 1.11830 +                            getY(d, d.pointIndex) == y.domain()[0] ? 'nv-point nv-minValue' : 'nv-point nv-maxValue'
 1.11831 +                });
 1.11832 +        });
 1.11833 +
 1.11834 +        return chart;
 1.11835 +    }
 1.11836 +
 1.11837 +    //============================================================
 1.11838 +    // Expose Public Variables
 1.11839 +    //------------------------------------------------------------
 1.11840 +
 1.11841 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.11842 +
 1.11843 +    chart._options = Object.create({}, {
 1.11844 +        // simple options, just get/set the necessary values
 1.11845 +        width:     {get: function(){return width;}, set: function(_){width=_;}},
 1.11846 +        height:    {get: function(){return height;}, set: function(_){height=_;}},
 1.11847 +        xDomain:   {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
 1.11848 +        yDomain:   {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
 1.11849 +        xRange:    {get: function(){return xRange;}, set: function(_){xRange=_;}},
 1.11850 +        yRange:    {get: function(){return yRange;}, set: function(_){yRange=_;}},
 1.11851 +        xScale:    {get: function(){return x;}, set: function(_){x=_;}},
 1.11852 +        yScale:    {get: function(){return y;}, set: function(_){y=_;}},
 1.11853 +        animate:   {get: function(){return animate;}, set: function(_){animate=_;}},
 1.11854 +
 1.11855 +        //functor options
 1.11856 +        x: {get: function(){return getX;}, set: function(_){getX=d3.functor(_);}},
 1.11857 +        y: {get: function(){return getY;}, set: function(_){getY=d3.functor(_);}},
 1.11858 +
 1.11859 +        // options that require extra logic in the setter
 1.11860 +        margin: {get: function(){return margin;}, set: function(_){
 1.11861 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.11862 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.11863 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.11864 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.11865 +        }},
 1.11866 +        color:  {get: function(){return color;}, set: function(_){
 1.11867 +            color = nv.utils.getColor(_);
 1.11868 +        }}
 1.11869 +    });
 1.11870 +
 1.11871 +    nv.utils.initOptions(chart);
 1.11872 +    return chart;
 1.11873 +};
 1.11874 +
 1.11875 +nv.models.sparklinePlus = function() {
 1.11876 +    "use strict";
 1.11877 +
 1.11878 +    //============================================================
 1.11879 +    // Public Variables with Default Settings
 1.11880 +    //------------------------------------------------------------
 1.11881 +
 1.11882 +    var sparkline = nv.models.sparkline();
 1.11883 +
 1.11884 +    var margin = {top: 15, right: 100, bottom: 10, left: 50}
 1.11885 +        , width = null
 1.11886 +        , height = null
 1.11887 +        , x
 1.11888 +        , y
 1.11889 +        , index = []
 1.11890 +        , paused = false
 1.11891 +        , xTickFormat = d3.format(',r')
 1.11892 +        , yTickFormat = d3.format(',.2f')
 1.11893 +        , showLastValue = true
 1.11894 +        , alignValue = true
 1.11895 +        , rightAlignValue = false
 1.11896 +        , noData = null
 1.11897 +        ;
 1.11898 +
 1.11899 +    function chart(selection) {
 1.11900 +        selection.each(function(data) {
 1.11901 +            var container = d3.select(this);
 1.11902 +            nv.utils.initSVG(container);
 1.11903 +
 1.11904 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
 1.11905 +                availableHeight = nv.utils.availableHeight(height, container, margin);
 1.11906 +
 1.11907 +            chart.update = function() { container.call(chart); };
 1.11908 +            chart.container = this;
 1.11909 +
 1.11910 +            // Display No Data message if there's nothing to show.
 1.11911 +            if (!data || !data.length) {
 1.11912 +                nv.utils.noData(chart, container)
 1.11913 +                return chart;
 1.11914 +            } else {
 1.11915 +                container.selectAll('.nv-noData').remove();
 1.11916 +            }
 1.11917 +
 1.11918 +            var currentValue = sparkline.y()(data[data.length-1], data.length-1);
 1.11919 +
 1.11920 +            // Setup Scales
 1.11921 +            x = sparkline.xScale();
 1.11922 +            y = sparkline.yScale();
 1.11923 +
 1.11924 +            // Setup containers and skeleton of chart
 1.11925 +            var wrap = container.selectAll('g.nv-wrap.nv-sparklineplus').data([data]);
 1.11926 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparklineplus');
 1.11927 +            var gEnter = wrapEnter.append('g');
 1.11928 +            var g = wrap.select('g');
 1.11929 +
 1.11930 +            gEnter.append('g').attr('class', 'nv-sparklineWrap');
 1.11931 +            gEnter.append('g').attr('class', 'nv-valueWrap');
 1.11932 +            gEnter.append('g').attr('class', 'nv-hoverArea');
 1.11933 +
 1.11934 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.11935 +
 1.11936 +            // Main Chart Component(s)
 1.11937 +            var sparklineWrap = g.select('.nv-sparklineWrap');
 1.11938 +
 1.11939 +            sparkline.width(availableWidth).height(availableHeight);
 1.11940 +            sparklineWrap.call(sparkline);
 1.11941 +
 1.11942 +            if (showLastValue) {
 1.11943 +                var valueWrap = g.select('.nv-valueWrap');
 1.11944 +                var value = valueWrap.selectAll('.nv-currentValue')
 1.11945 +                    .data([currentValue]);
 1.11946 +
 1.11947 +                value.enter().append('text').attr('class', 'nv-currentValue')
 1.11948 +                    .attr('dx', rightAlignValue ? -8 : 8)
 1.11949 +                    .attr('dy', '.9em')
 1.11950 +                    .style('text-anchor', rightAlignValue ? 'end' : 'start');
 1.11951 +
 1.11952 +                value
 1.11953 +                    .attr('x', availableWidth + (rightAlignValue ? margin.right : 0))
 1.11954 +                    .attr('y', alignValue ? function (d) {
 1.11955 +                        return y(d)
 1.11956 +                    } : 0)
 1.11957 +                    .style('fill', sparkline.color()(data[data.length - 1], data.length - 1))
 1.11958 +                    .text(yTickFormat(currentValue));
 1.11959 +            }
 1.11960 +
 1.11961 +            gEnter.select('.nv-hoverArea').append('rect')
 1.11962 +                .on('mousemove', sparklineHover)
 1.11963 +                .on('click', function() { paused = !paused })
 1.11964 +                .on('mouseout', function() { index = []; updateValueLine(); });
 1.11965 +
 1.11966 +            g.select('.nv-hoverArea rect')
 1.11967 +                .attr('transform', function(d) { return 'translate(' + -margin.left + ',' + -margin.top + ')' })
 1.11968 +                .attr('width', availableWidth + margin.left + margin.right)
 1.11969 +                .attr('height', availableHeight + margin.top);
 1.11970 +
 1.11971 +            //index is currently global (within the chart), may or may not keep it that way
 1.11972 +            function updateValueLine() {
 1.11973 +                if (paused) return;
 1.11974 +
 1.11975 +                var hoverValue = g.selectAll('.nv-hoverValue').data(index);
 1.11976 +
 1.11977 +                var hoverEnter = hoverValue.enter()
 1.11978 +                    .append('g').attr('class', 'nv-hoverValue')
 1.11979 +                    .style('stroke-opacity', 0)
 1.11980 +                    .style('fill-opacity', 0);
 1.11981 +
 1.11982 +                hoverValue.exit()
 1.11983 +                    .transition().duration(250)
 1.11984 +                    .style('stroke-opacity', 0)
 1.11985 +                    .style('fill-opacity', 0)
 1.11986 +                    .remove();
 1.11987 +
 1.11988 +                hoverValue
 1.11989 +                    .attr('transform', function(d) { return 'translate(' + x(sparkline.x()(data[d],d)) + ',0)' })
 1.11990 +                    .transition().duration(250)
 1.11991 +                    .style('stroke-opacity', 1)
 1.11992 +                    .style('fill-opacity', 1);
 1.11993 +
 1.11994 +                if (!index.length) return;
 1.11995 +
 1.11996 +                hoverEnter.append('line')
 1.11997 +                    .attr('x1', 0)
 1.11998 +                    .attr('y1', -margin.top)
 1.11999 +                    .attr('x2', 0)
 1.12000 +                    .attr('y2', availableHeight);
 1.12001 +
 1.12002 +                hoverEnter.append('text').attr('class', 'nv-xValue')
 1.12003 +                    .attr('x', -6)
 1.12004 +                    .attr('y', -margin.top)
 1.12005 +                    .attr('text-anchor', 'end')
 1.12006 +                    .attr('dy', '.9em');
 1.12007 +
 1.12008 +                g.select('.nv-hoverValue .nv-xValue')
 1.12009 +                    .text(xTickFormat(sparkline.x()(data[index[0]], index[0])));
 1.12010 +
 1.12011 +                hoverEnter.append('text').attr('class', 'nv-yValue')
 1.12012 +                    .attr('x', 6)
 1.12013 +                    .attr('y', -margin.top)
 1.12014 +                    .attr('text-anchor', 'start')
 1.12015 +                    .attr('dy', '.9em');
 1.12016 +
 1.12017 +                g.select('.nv-hoverValue .nv-yValue')
 1.12018 +                    .text(yTickFormat(sparkline.y()(data[index[0]], index[0])));
 1.12019 +            }
 1.12020 +
 1.12021 +            function sparklineHover() {
 1.12022 +                if (paused) return;
 1.12023 +
 1.12024 +                var pos = d3.mouse(this)[0] - margin.left;
 1.12025 +
 1.12026 +                function getClosestIndex(data, x) {
 1.12027 +                    var distance = Math.abs(sparkline.x()(data[0], 0) - x);
 1.12028 +                    var closestIndex = 0;
 1.12029 +                    for (var i = 0; i < data.length; i++){
 1.12030 +                        if (Math.abs(sparkline.x()(data[i], i) - x) < distance) {
 1.12031 +                            distance = Math.abs(sparkline.x()(data[i], i) - x);
 1.12032 +                            closestIndex = i;
 1.12033 +                        }
 1.12034 +                    }
 1.12035 +                    return closestIndex;
 1.12036 +                }
 1.12037 +
 1.12038 +                index = [getClosestIndex(data, Math.round(x.invert(pos)))];
 1.12039 +                updateValueLine();
 1.12040 +            }
 1.12041 +
 1.12042 +        });
 1.12043 +
 1.12044 +        return chart;
 1.12045 +    }
 1.12046 +
 1.12047 +    //============================================================
 1.12048 +    // Expose Public Variables
 1.12049 +    //------------------------------------------------------------
 1.12050 +
 1.12051 +    // expose chart's sub-components
 1.12052 +    chart.sparkline = sparkline;
 1.12053 +
 1.12054 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.12055 +
 1.12056 +    chart._options = Object.create({}, {
 1.12057 +        // simple options, just get/set the necessary values
 1.12058 +        width:           {get: function(){return width;}, set: function(_){width=_;}},
 1.12059 +        height:          {get: function(){return height;}, set: function(_){height=_;}},
 1.12060 +        xTickFormat:     {get: function(){return xTickFormat;}, set: function(_){xTickFormat=_;}},
 1.12061 +        yTickFormat:     {get: function(){return yTickFormat;}, set: function(_){yTickFormat=_;}},
 1.12062 +        showLastValue:   {get: function(){return showLastValue;}, set: function(_){showLastValue=_;}},
 1.12063 +        alignValue:      {get: function(){return alignValue;}, set: function(_){alignValue=_;}},
 1.12064 +        rightAlignValue: {get: function(){return rightAlignValue;}, set: function(_){rightAlignValue=_;}},
 1.12065 +        noData:          {get: function(){return noData;}, set: function(_){noData=_;}},
 1.12066 +
 1.12067 +        // options that require extra logic in the setter
 1.12068 +        margin: {get: function(){return margin;}, set: function(_){
 1.12069 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.12070 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.12071 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.12072 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.12073 +        }}
 1.12074 +    });
 1.12075 +
 1.12076 +    nv.utils.inheritOptions(chart, sparkline);
 1.12077 +    nv.utils.initOptions(chart);
 1.12078 +
 1.12079 +    return chart;
 1.12080 +};
 1.12081 +
 1.12082 +nv.models.stackedArea = function() {
 1.12083 +    "use strict";
 1.12084 +
 1.12085 +    //============================================================
 1.12086 +    // Public Variables with Default Settings
 1.12087 +    //------------------------------------------------------------
 1.12088 +
 1.12089 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
 1.12090 +        , width = 960
 1.12091 +        , height = 500
 1.12092 +        , color = nv.utils.defaultColor() // a function that computes the color
 1.12093 +        , id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't selet one
 1.12094 +        , container = null
 1.12095 +        , getX = function(d) { return d.x } // accessor to get the x value from a data point
 1.12096 +        , getY = function(d) { return d.y } // accessor to get the y value from a data point
 1.12097 +        , style = 'stack'
 1.12098 +        , offset = 'zero'
 1.12099 +        , order = 'default'
 1.12100 +        , interpolate = 'linear'  // controls the line interpolation
 1.12101 +        , clipEdge = false // if true, masks lines within x and y scale
 1.12102 +        , x //can be accessed via chart.xScale()
 1.12103 +        , y //can be accessed via chart.yScale()
 1.12104 +        , scatter = nv.models.scatter()
 1.12105 +        , duration = 250
 1.12106 +        , dispatch =  d3.dispatch('areaClick', 'areaMouseover', 'areaMouseout','renderEnd', 'elementClick', 'elementMouseover', 'elementMouseout')
 1.12107 +        ;
 1.12108 +
 1.12109 +    scatter
 1.12110 +        .pointSize(2.2) // default size
 1.12111 +        .pointDomain([2.2, 2.2]) // all the same size by default
 1.12112 +    ;
 1.12113 +
 1.12114 +    /************************************
 1.12115 +     * offset:
 1.12116 +     *   'wiggle' (stream)
 1.12117 +     *   'zero' (stacked)
 1.12118 +     *   'expand' (normalize to 100%)
 1.12119 +     *   'silhouette' (simple centered)
 1.12120 +     *
 1.12121 +     * order:
 1.12122 +     *   'inside-out' (stream)
 1.12123 +     *   'default' (input order)
 1.12124 +     ************************************/
 1.12125 +
 1.12126 +    var renderWatch = nv.utils.renderWatch(dispatch, duration);
 1.12127 +
 1.12128 +    function chart(selection) {
 1.12129 +        renderWatch.reset();
 1.12130 +        renderWatch.models(scatter);
 1.12131 +        selection.each(function(data) {
 1.12132 +            var availableWidth = width - margin.left - margin.right,
 1.12133 +                availableHeight = height - margin.top - margin.bottom;
 1.12134 +
 1.12135 +            container = d3.select(this);
 1.12136 +            nv.utils.initSVG(container);
 1.12137 +
 1.12138 +            // Setup Scales
 1.12139 +            x = scatter.xScale();
 1.12140 +            y = scatter.yScale();
 1.12141 +
 1.12142 +            var dataRaw = data;
 1.12143 +            // Injecting point index into each point because d3.layout.stack().out does not give index
 1.12144 +            data.forEach(function(aseries, i) {
 1.12145 +                aseries.seriesIndex = i;
 1.12146 +                aseries.values = aseries.values.map(function(d, j) {
 1.12147 +                    d.index = j;
 1.12148 +                    d.seriesIndex = i;
 1.12149 +                    return d;
 1.12150 +                });
 1.12151 +            });
 1.12152 +
 1.12153 +            var dataFiltered = data.filter(function(series) {
 1.12154 +                return !series.disabled;
 1.12155 +            });
 1.12156 +
 1.12157 +            data = d3.layout.stack()
 1.12158 +                .order(order)
 1.12159 +                .offset(offset)
 1.12160 +                .values(function(d) { return d.values })  //TODO: make values customizeable in EVERY model in this fashion
 1.12161 +                .x(getX)
 1.12162 +                .y(getY)
 1.12163 +                .out(function(d, y0, y) {
 1.12164 +                    d.display = {
 1.12165 +                        y: y,
 1.12166 +                        y0: y0
 1.12167 +                    };
 1.12168 +                })
 1.12169 +            (dataFiltered);
 1.12170 +
 1.12171 +            // Setup containers and skeleton of chart
 1.12172 +            var wrap = container.selectAll('g.nv-wrap.nv-stackedarea').data([data]);
 1.12173 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedarea');
 1.12174 +            var defsEnter = wrapEnter.append('defs');
 1.12175 +            var gEnter = wrapEnter.append('g');
 1.12176 +            var g = wrap.select('g');
 1.12177 +
 1.12178 +            gEnter.append('g').attr('class', 'nv-areaWrap');
 1.12179 +            gEnter.append('g').attr('class', 'nv-scatterWrap');
 1.12180 +
 1.12181 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.12182 +            
 1.12183 +            // If the user has not specified forceY, make sure 0 is included in the domain
 1.12184 +            // Otherwise, use user-specified values for forceY
 1.12185 +            if (scatter.forceY().length == 0) {
 1.12186 +                scatter.forceY().push(0);
 1.12187 +            }
 1.12188 +            
 1.12189 +            scatter
 1.12190 +                .width(availableWidth)
 1.12191 +                .height(availableHeight)
 1.12192 +                .x(getX)
 1.12193 +                .y(function(d) { return d.display.y + d.display.y0 })
 1.12194 +                .forceY([0])
 1.12195 +                .color(data.map(function(d,i) {
 1.12196 +                    return d.color || color(d, d.seriesIndex);
 1.12197 +                }));
 1.12198 +
 1.12199 +            var scatterWrap = g.select('.nv-scatterWrap')
 1.12200 +                .datum(data);
 1.12201 +
 1.12202 +            scatterWrap.call(scatter);
 1.12203 +
 1.12204 +            defsEnter.append('clipPath')
 1.12205 +                .attr('id', 'nv-edge-clip-' + id)
 1.12206 +                .append('rect');
 1.12207 +
 1.12208 +            wrap.select('#nv-edge-clip-' + id + ' rect')
 1.12209 +                .attr('width', availableWidth)
 1.12210 +                .attr('height', availableHeight);
 1.12211 +
 1.12212 +            g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '');
 1.12213 +
 1.12214 +            var area = d3.svg.area()
 1.12215 +                .x(function(d,i)  { return x(getX(d,i)) })
 1.12216 +                .y0(function(d) {
 1.12217 +                    return y(d.display.y0)
 1.12218 +                })
 1.12219 +                .y1(function(d) {
 1.12220 +                    return y(d.display.y + d.display.y0)
 1.12221 +                })
 1.12222 +                .interpolate(interpolate);
 1.12223 +
 1.12224 +            var zeroArea = d3.svg.area()
 1.12225 +                .x(function(d,i)  { return x(getX(d,i)) })
 1.12226 +                .y0(function(d) { return y(d.display.y0) })
 1.12227 +                .y1(function(d) { return y(d.display.y0) });
 1.12228 +
 1.12229 +            var path = g.select('.nv-areaWrap').selectAll('path.nv-area')
 1.12230 +                .data(function(d) { return d });
 1.12231 +
 1.12232 +            path.enter().append('path').attr('class', function(d,i) { return 'nv-area nv-area-' + i })
 1.12233 +                .attr('d', function(d,i){
 1.12234 +                    return zeroArea(d.values, d.seriesIndex);
 1.12235 +                })
 1.12236 +                .on('mouseover', function(d,i) {
 1.12237 +                    d3.select(this).classed('hover', true);
 1.12238 +                    dispatch.areaMouseover({
 1.12239 +                        point: d,
 1.12240 +                        series: d.key,
 1.12241 +                        pos: [d3.event.pageX, d3.event.pageY],
 1.12242 +                        seriesIndex: d.seriesIndex
 1.12243 +                    });
 1.12244 +                })
 1.12245 +                .on('mouseout', function(d,i) {
 1.12246 +                    d3.select(this).classed('hover', false);
 1.12247 +                    dispatch.areaMouseout({
 1.12248 +                        point: d,
 1.12249 +                        series: d.key,
 1.12250 +                        pos: [d3.event.pageX, d3.event.pageY],
 1.12251 +                        seriesIndex: d.seriesIndex
 1.12252 +                    });
 1.12253 +                })
 1.12254 +                .on('click', function(d,i) {
 1.12255 +                    d3.select(this).classed('hover', false);
 1.12256 +                    dispatch.areaClick({
 1.12257 +                        point: d,
 1.12258 +                        series: d.key,
 1.12259 +                        pos: [d3.event.pageX, d3.event.pageY],
 1.12260 +                        seriesIndex: d.seriesIndex
 1.12261 +                    });
 1.12262 +                });
 1.12263 +
 1.12264 +            path.exit().remove();
 1.12265 +            path.style('fill', function(d,i){
 1.12266 +                    return d.color || color(d, d.seriesIndex)
 1.12267 +                })
 1.12268 +                .style('stroke', function(d,i){ return d.color || color(d, d.seriesIndex) });
 1.12269 +            path.watchTransition(renderWatch,'stackedArea path')
 1.12270 +                .attr('d', function(d,i) {
 1.12271 +                    return area(d.values,i)
 1.12272 +                });
 1.12273 +
 1.12274 +            //============================================================
 1.12275 +            // Event Handling/Dispatching (in chart's scope)
 1.12276 +            //------------------------------------------------------------
 1.12277 +
 1.12278 +            scatter.dispatch.on('elementMouseover.area', function(e) {
 1.12279 +                g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', true);
 1.12280 +            });
 1.12281 +            scatter.dispatch.on('elementMouseout.area', function(e) {
 1.12282 +                g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', false);
 1.12283 +            });
 1.12284 +
 1.12285 +            //Special offset functions
 1.12286 +            chart.d3_stackedOffset_stackPercent = function(stackData) {
 1.12287 +                var n = stackData.length,    //How many series
 1.12288 +                    m = stackData[0].length,     //how many points per series
 1.12289 +                    i,
 1.12290 +                    j,
 1.12291 +                    o,
 1.12292 +                    y0 = [];
 1.12293 +
 1.12294 +                for (j = 0; j < m; ++j) { //Looping through all points
 1.12295 +                    for (i = 0, o = 0; i < dataRaw.length; i++) { //looping through all series
 1.12296 +                        o += getY(dataRaw[i].values[j]); //total y value of all series at a certian point in time.
 1.12297 +                    }
 1.12298 +
 1.12299 +                    if (o) for (i = 0; i < n; i++) { //(total y value of all series at point in time i) != 0
 1.12300 +                        stackData[i][j][1] /= o;
 1.12301 +                    } else { //(total y value of all series at point in time i) == 0
 1.12302 +                        for (i = 0; i < n; i++) {
 1.12303 +                            stackData[i][j][1] = 0;
 1.12304 +                        }
 1.12305 +                    }
 1.12306 +                }
 1.12307 +                for (j = 0; j < m; ++j) y0[j] = 0;
 1.12308 +                return y0;
 1.12309 +            };
 1.12310 +
 1.12311 +        });
 1.12312 +
 1.12313 +        renderWatch.renderEnd('stackedArea immediate');
 1.12314 +        return chart;
 1.12315 +    }
 1.12316 +
 1.12317 +    //============================================================
 1.12318 +    // Global getters and setters
 1.12319 +    //------------------------------------------------------------
 1.12320 +
 1.12321 +    chart.dispatch = dispatch;
 1.12322 +    chart.scatter = scatter;
 1.12323 +
 1.12324 +    scatter.dispatch.on('elementClick', function(){ dispatch.elementClick.apply(this, arguments); });
 1.12325 +    scatter.dispatch.on('elementMouseover', function(){ dispatch.elementMouseover.apply(this, arguments); });
 1.12326 +    scatter.dispatch.on('elementMouseout', function(){ dispatch.elementMouseout.apply(this, arguments); });
 1.12327 +
 1.12328 +    chart.interpolate = function(_) {
 1.12329 +        if (!arguments.length) return interpolate;
 1.12330 +        interpolate = _;
 1.12331 +        return chart;
 1.12332 +    };
 1.12333 +
 1.12334 +    chart.duration = function(_) {
 1.12335 +        if (!arguments.length) return duration;
 1.12336 +        duration = _;
 1.12337 +        renderWatch.reset(duration);
 1.12338 +        scatter.duration(duration);
 1.12339 +        return chart;
 1.12340 +    };
 1.12341 +
 1.12342 +    chart.dispatch = dispatch;
 1.12343 +    chart.scatter = scatter;
 1.12344 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.12345 +
 1.12346 +    chart._options = Object.create({}, {
 1.12347 +        // simple options, just get/set the necessary values
 1.12348 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
 1.12349 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
 1.12350 +        clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
 1.12351 +        offset:      {get: function(){return offset;}, set: function(_){offset=_;}},
 1.12352 +        order:    {get: function(){return order;}, set: function(_){order=_;}},
 1.12353 +        interpolate:    {get: function(){return interpolate;}, set: function(_){interpolate=_;}},
 1.12354 +
 1.12355 +        // simple functor options
 1.12356 +        x:     {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}},
 1.12357 +        y:     {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}},
 1.12358 +
 1.12359 +        // options that require extra logic in the setter
 1.12360 +        margin: {get: function(){return margin;}, set: function(_){
 1.12361 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.12362 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.12363 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.12364 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.12365 +        }},
 1.12366 +        color:  {get: function(){return color;}, set: function(_){
 1.12367 +            color = nv.utils.getColor(_);
 1.12368 +        }},
 1.12369 +        style: {get: function(){return style;}, set: function(_){
 1.12370 +            style = _;
 1.12371 +            switch (style) {
 1.12372 +                case 'stack':
 1.12373 +                    chart.offset('zero');
 1.12374 +                    chart.order('default');
 1.12375 +                    break;
 1.12376 +                case 'stream':
 1.12377 +                    chart.offset('wiggle');
 1.12378 +                    chart.order('inside-out');
 1.12379 +                    break;
 1.12380 +                case 'stream-center':
 1.12381 +                    chart.offset('silhouette');
 1.12382 +                    chart.order('inside-out');
 1.12383 +                    break;
 1.12384 +                case 'expand':
 1.12385 +                    chart.offset('expand');
 1.12386 +                    chart.order('default');
 1.12387 +                    break;
 1.12388 +                case 'stack_percent':
 1.12389 +                    chart.offset(chart.d3_stackedOffset_stackPercent);
 1.12390 +                    chart.order('default');
 1.12391 +                    break;
 1.12392 +            }
 1.12393 +        }},
 1.12394 +        duration: {get: function(){return duration;}, set: function(_){
 1.12395 +            duration = _;
 1.12396 +            renderWatch.reset(duration);
 1.12397 +            scatter.duration(duration);
 1.12398 +        }}
 1.12399 +    });
 1.12400 +
 1.12401 +    nv.utils.inheritOptions(chart, scatter);
 1.12402 +    nv.utils.initOptions(chart);
 1.12403 +
 1.12404 +    return chart;
 1.12405 +};
 1.12406 +
 1.12407 +nv.models.stackedAreaChart = function() {
 1.12408 +    "use strict";
 1.12409 +
 1.12410 +    //============================================================
 1.12411 +    // Public Variables with Default Settings
 1.12412 +    //------------------------------------------------------------
 1.12413 +
 1.12414 +    var stacked = nv.models.stackedArea()
 1.12415 +        , xAxis = nv.models.axis()
 1.12416 +        , yAxis = nv.models.axis()
 1.12417 +        , legend = nv.models.legend()
 1.12418 +        , controls = nv.models.legend()
 1.12419 +        , interactiveLayer = nv.interactiveGuideline()
 1.12420 +        , tooltip = nv.models.tooltip()
 1.12421 +        ;
 1.12422 +
 1.12423 +    var margin = {top: 30, right: 25, bottom: 50, left: 60}
 1.12424 +        , width = null
 1.12425 +        , height = null
 1.12426 +        , color = nv.utils.defaultColor()
 1.12427 +        , showControls = true
 1.12428 +        , showLegend = true
 1.12429 +        , showXAxis = true
 1.12430 +        , showYAxis = true
 1.12431 +        , rightAlignYAxis = false
 1.12432 +        , useInteractiveGuideline = false
 1.12433 +        , x //can be accessed via chart.xScale()
 1.12434 +        , y //can be accessed via chart.yScale()
 1.12435 +        , state = nv.utils.state()
 1.12436 +        , defaultState = null
 1.12437 +        , noData = null
 1.12438 +        , dispatch = d3.dispatch('stateChange', 'changeState','renderEnd')
 1.12439 +        , controlWidth = 250
 1.12440 +        , controlOptions = ['Stacked','Stream','Expanded']
 1.12441 +        , controlLabels = {}
 1.12442 +        , duration = 250
 1.12443 +        ;
 1.12444 +
 1.12445 +    state.style = stacked.style();
 1.12446 +    xAxis.orient('bottom').tickPadding(7);
 1.12447 +    yAxis.orient((rightAlignYAxis) ? 'right' : 'left');
 1.12448 +
 1.12449 +    tooltip
 1.12450 +        .headerFormatter(function(d, i) {
 1.12451 +            return xAxis.tickFormat()(d, i);
 1.12452 +        })
 1.12453 +        .valueFormatter(function(d, i) {
 1.12454 +            return yAxis.tickFormat()(d, i);
 1.12455 +        });
 1.12456 +
 1.12457 +    interactiveLayer.tooltip
 1.12458 +        .headerFormatter(function(d, i) {
 1.12459 +            return xAxis.tickFormat()(d, i);
 1.12460 +        })
 1.12461 +        .valueFormatter(function(d, i) {
 1.12462 +            return yAxis.tickFormat()(d, i);
 1.12463 +        });
 1.12464 +
 1.12465 +    var oldYTickFormat = null,
 1.12466 +        oldValueFormatter = null;
 1.12467 +
 1.12468 +    controls.updateState(false);
 1.12469 +
 1.12470 +    //============================================================
 1.12471 +    // Private Variables
 1.12472 +    //------------------------------------------------------------
 1.12473 +
 1.12474 +    var renderWatch = nv.utils.renderWatch(dispatch);
 1.12475 +    var style = stacked.style();
 1.12476 +
 1.12477 +    var stateGetter = function(data) {
 1.12478 +        return function(){
 1.12479 +            return {
 1.12480 +                active: data.map(function(d) { return !d.disabled }),
 1.12481 +                style: stacked.style()
 1.12482 +            };
 1.12483 +        }
 1.12484 +    };
 1.12485 +
 1.12486 +    var stateSetter = function(data) {
 1.12487 +        return function(state) {
 1.12488 +            if (state.style !== undefined)
 1.12489 +                style = state.style;
 1.12490 +            if (state.active !== undefined)
 1.12491 +                data.forEach(function(series,i) {
 1.12492 +                    series.disabled = !state.active[i];
 1.12493 +                });
 1.12494 +        }
 1.12495 +    };
 1.12496 +
 1.12497 +    var percentFormatter = d3.format('%');
 1.12498 +
 1.12499 +    function chart(selection) {
 1.12500 +        renderWatch.reset();
 1.12501 +        renderWatch.models(stacked);
 1.12502 +        if (showXAxis) renderWatch.models(xAxis);
 1.12503 +        if (showYAxis) renderWatch.models(yAxis);
 1.12504 +
 1.12505 +        selection.each(function(data) {
 1.12506 +            var container = d3.select(this),
 1.12507 +                that = this;
 1.12508 +            nv.utils.initSVG(container);
 1.12509 +
 1.12510 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
 1.12511 +                availableHeight = nv.utils.availableHeight(height, container, margin);
 1.12512 +
 1.12513 +            chart.update = function() { container.transition().duration(duration).call(chart); };
 1.12514 +            chart.container = this;
 1.12515 +
 1.12516 +            state
 1.12517 +                .setter(stateSetter(data), chart.update)
 1.12518 +                .getter(stateGetter(data))
 1.12519 +                .update();
 1.12520 +
 1.12521 +            // DEPRECATED set state.disabled
 1.12522 +            state.disabled = data.map(function(d) { return !!d.disabled });
 1.12523 +
 1.12524 +            if (!defaultState) {
 1.12525 +                var key;
 1.12526 +                defaultState = {};
 1.12527 +                for (key in state) {
 1.12528 +                    if (state[key] instanceof Array)
 1.12529 +                        defaultState[key] = state[key].slice(0);
 1.12530 +                    else
 1.12531 +                        defaultState[key] = state[key];
 1.12532 +                }
 1.12533 +            }
 1.12534 +
 1.12535 +            // Display No Data message if there's nothing to show.
 1.12536 +            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
 1.12537 +                nv.utils.noData(chart, container)
 1.12538 +                return chart;
 1.12539 +            } else {
 1.12540 +                container.selectAll('.nv-noData').remove();
 1.12541 +            }
 1.12542 +
 1.12543 +            // Setup Scales
 1.12544 +            x = stacked.xScale();
 1.12545 +            y = stacked.yScale();
 1.12546 +
 1.12547 +            // Setup containers and skeleton of chart
 1.12548 +            var wrap = container.selectAll('g.nv-wrap.nv-stackedAreaChart').data([data]);
 1.12549 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedAreaChart').append('g');
 1.12550 +            var g = wrap.select('g');
 1.12551 +
 1.12552 +            gEnter.append("rect").style("opacity",0);
 1.12553 +            gEnter.append('g').attr('class', 'nv-x nv-axis');
 1.12554 +            gEnter.append('g').attr('class', 'nv-y nv-axis');
 1.12555 +            gEnter.append('g').attr('class', 'nv-stackedWrap');
 1.12556 +            gEnter.append('g').attr('class', 'nv-legendWrap');
 1.12557 +            gEnter.append('g').attr('class', 'nv-controlsWrap');
 1.12558 +            gEnter.append('g').attr('class', 'nv-interactive');
 1.12559 +
 1.12560 +            g.select("rect").attr("width",availableWidth).attr("height",availableHeight);
 1.12561 +
 1.12562 +            // Legend
 1.12563 +            if (showLegend) {
 1.12564 +                var legendWidth = (showControls) ? availableWidth - controlWidth : availableWidth;
 1.12565 +
 1.12566 +                legend.width(legendWidth);
 1.12567 +                g.select('.nv-legendWrap').datum(data).call(legend);
 1.12568 +
 1.12569 +                if ( margin.top != legend.height()) {
 1.12570 +                    margin.top = legend.height();
 1.12571 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
 1.12572 +                }
 1.12573 +
 1.12574 +                g.select('.nv-legendWrap')
 1.12575 +                    .attr('transform', 'translate(' + (availableWidth-legendWidth) + ',' + (-margin.top) +')');
 1.12576 +            }
 1.12577 +
 1.12578 +            // Controls
 1.12579 +            if (showControls) {
 1.12580 +                var controlsData = [
 1.12581 +                    {
 1.12582 +                        key: controlLabels.stacked || 'Stacked',
 1.12583 +                        metaKey: 'Stacked',
 1.12584 +                        disabled: stacked.style() != 'stack',
 1.12585 +                        style: 'stack'
 1.12586 +                    },
 1.12587 +                    {
 1.12588 +                        key: controlLabels.stream || 'Stream',
 1.12589 +                        metaKey: 'Stream',
 1.12590 +                        disabled: stacked.style() != 'stream',
 1.12591 +                        style: 'stream'
 1.12592 +                    },
 1.12593 +                    {
 1.12594 +                        key: controlLabels.expanded || 'Expanded',
 1.12595 +                        metaKey: 'Expanded',
 1.12596 +                        disabled: stacked.style() != 'expand',
 1.12597 +                        style: 'expand'
 1.12598 +                    },
 1.12599 +                    {
 1.12600 +                        key: controlLabels.stack_percent || 'Stack %',
 1.12601 +                        metaKey: 'Stack_Percent',
 1.12602 +                        disabled: stacked.style() != 'stack_percent',
 1.12603 +                        style: 'stack_percent'
 1.12604 +                    }
 1.12605 +                ];
 1.12606 +
 1.12607 +                controlWidth = (controlOptions.length/3) * 260;
 1.12608 +                controlsData = controlsData.filter(function(d) {
 1.12609 +                    return controlOptions.indexOf(d.metaKey) !== -1;
 1.12610 +                });
 1.12611 +
 1.12612 +                controls
 1.12613 +                    .width( controlWidth )
 1.12614 +                    .color(['#444', '#444', '#444']);
 1.12615 +
 1.12616 +                g.select('.nv-controlsWrap')
 1.12617 +                    .datum(controlsData)
 1.12618 +                    .call(controls);
 1.12619 +
 1.12620 +                if ( margin.top != Math.max(controls.height(), legend.height()) ) {
 1.12621 +                    margin.top = Math.max(controls.height(), legend.height());
 1.12622 +                    availableHeight = nv.utils.availableHeight(height, container, margin);
 1.12623 +                }
 1.12624 +
 1.12625 +                g.select('.nv-controlsWrap')
 1.12626 +                    .attr('transform', 'translate(0,' + (-margin.top) +')');
 1.12627 +            }
 1.12628 +
 1.12629 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.12630 +
 1.12631 +            if (rightAlignYAxis) {
 1.12632 +                g.select(".nv-y.nv-axis")
 1.12633 +                    .attr("transform", "translate(" + availableWidth + ",0)");
 1.12634 +            }
 1.12635 +
 1.12636 +            //Set up interactive layer
 1.12637 +            if (useInteractiveGuideline) {
 1.12638 +                interactiveLayer
 1.12639 +                    .width(availableWidth)
 1.12640 +                    .height(availableHeight)
 1.12641 +                    .margin({left: margin.left, top: margin.top})
 1.12642 +                    .svgContainer(container)
 1.12643 +                    .xScale(x);
 1.12644 +                wrap.select(".nv-interactive").call(interactiveLayer);
 1.12645 +            }
 1.12646 +
 1.12647 +            stacked
 1.12648 +                .width(availableWidth)
 1.12649 +                .height(availableHeight);
 1.12650 +
 1.12651 +            var stackedWrap = g.select('.nv-stackedWrap')
 1.12652 +                .datum(data);
 1.12653 +
 1.12654 +            stackedWrap.transition().call(stacked);
 1.12655 +
 1.12656 +            // Setup Axes
 1.12657 +            if (showXAxis) {
 1.12658 +                xAxis.scale(x)
 1.12659 +                    ._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
 1.12660 +                    .tickSize( -availableHeight, 0);
 1.12661 +
 1.12662 +                g.select('.nv-x.nv-axis')
 1.12663 +                    .attr('transform', 'translate(0,' + availableHeight + ')');
 1.12664 +
 1.12665 +                g.select('.nv-x.nv-axis')
 1.12666 +                    .transition().duration(0)
 1.12667 +                    .call(xAxis);
 1.12668 +            }
 1.12669 +
 1.12670 +            if (showYAxis) {
 1.12671 +                var ticks;
 1.12672 +                if (stacked.offset() === 'wiggle') {
 1.12673 +                    ticks = 0;
 1.12674 +                }
 1.12675 +                else {
 1.12676 +                    ticks = nv.utils.calcTicksY(availableHeight/36, data);
 1.12677 +                }
 1.12678 +                yAxis.scale(y)
 1.12679 +                    ._ticks(ticks)
 1.12680 +                    .tickSize(-availableWidth, 0);
 1.12681 +
 1.12682 +                    if (stacked.style() === 'expand' || stacked.style() === 'stack_percent') {
 1.12683 +                        var currentFormat = yAxis.tickFormat();
 1.12684 +
 1.12685 +                        if ( !oldYTickFormat || currentFormat !== percentFormatter )
 1.12686 +                            oldYTickFormat = currentFormat;
 1.12687 +
 1.12688 +                        //Forces the yAxis to use percentage in 'expand' mode.
 1.12689 +                        yAxis.tickFormat(percentFormatter);
 1.12690 +                    }
 1.12691 +                    else {
 1.12692 +                        if (oldYTickFormat) {
 1.12693 +                            yAxis.tickFormat(oldYTickFormat);
 1.12694 +                            oldYTickFormat = null;
 1.12695 +                        }
 1.12696 +                    }
 1.12697 +
 1.12698 +                g.select('.nv-y.nv-axis')
 1.12699 +                    .transition().duration(0)
 1.12700 +                    .call(yAxis);
 1.12701 +            }
 1.12702 +
 1.12703 +            //============================================================
 1.12704 +            // Event Handling/Dispatching (in chart's scope)
 1.12705 +            //------------------------------------------------------------
 1.12706 +
 1.12707 +            stacked.dispatch.on('areaClick.toggle', function(e) {
 1.12708 +                if (data.filter(function(d) { return !d.disabled }).length === 1)
 1.12709 +                    data.forEach(function(d) {
 1.12710 +                        d.disabled = false;
 1.12711 +                    });
 1.12712 +                else
 1.12713 +                    data.forEach(function(d,i) {
 1.12714 +                        d.disabled = (i != e.seriesIndex);
 1.12715 +                    });
 1.12716 +
 1.12717 +                state.disabled = data.map(function(d) { return !!d.disabled });
 1.12718 +                dispatch.stateChange(state);
 1.12719 +
 1.12720 +                chart.update();
 1.12721 +            });
 1.12722 +
 1.12723 +            legend.dispatch.on('stateChange', function(newState) {
 1.12724 +                for (var key in newState)
 1.12725 +                    state[key] = newState[key];
 1.12726 +                dispatch.stateChange(state);
 1.12727 +                chart.update();
 1.12728 +            });
 1.12729 +
 1.12730 +            controls.dispatch.on('legendClick', function(d,i) {
 1.12731 +                if (!d.disabled) return;
 1.12732 +
 1.12733 +                controlsData = controlsData.map(function(s) {
 1.12734 +                    s.disabled = true;
 1.12735 +                    return s;
 1.12736 +                });
 1.12737 +                d.disabled = false;
 1.12738 +
 1.12739 +                stacked.style(d.style);
 1.12740 +
 1.12741 +
 1.12742 +                state.style = stacked.style();
 1.12743 +                dispatch.stateChange(state);
 1.12744 +
 1.12745 +                chart.update();
 1.12746 +            });
 1.12747 +
 1.12748 +            interactiveLayer.dispatch.on('elementMousemove', function(e) {
 1.12749 +                stacked.clearHighlights();
 1.12750 +                var singlePoint, pointIndex, pointXLocation, allData = [];
 1.12751 +                data
 1.12752 +                    .filter(function(series, i) {
 1.12753 +                        series.seriesIndex = i;
 1.12754 +                        return !series.disabled;
 1.12755 +                    })
 1.12756 +                    .forEach(function(series,i) {
 1.12757 +                        pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
 1.12758 +                        var point = series.values[pointIndex];
 1.12759 +                        var pointYValue = chart.y()(point, pointIndex);
 1.12760 +                        if (pointYValue != null) {
 1.12761 +                            stacked.highlightPoint(i, pointIndex, true);
 1.12762 +                        }
 1.12763 +                        if (typeof point === 'undefined') return;
 1.12764 +                        if (typeof singlePoint === 'undefined') singlePoint = point;
 1.12765 +                        if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
 1.12766 +
 1.12767 +                        //If we are in 'expand' mode, use the stacked percent value instead of raw value.
 1.12768 +                        var tooltipValue = (stacked.style() == 'expand') ? point.display.y : chart.y()(point,pointIndex);
 1.12769 +                        allData.push({
 1.12770 +                            key: series.key,
 1.12771 +                            value: tooltipValue,
 1.12772 +                            color: color(series,series.seriesIndex),
 1.12773 +                            stackedValue: point.display
 1.12774 +                        });
 1.12775 +                    });
 1.12776 +
 1.12777 +                allData.reverse();
 1.12778 +
 1.12779 +                //Highlight the tooltip entry based on which stack the mouse is closest to.
 1.12780 +                if (allData.length > 2) {
 1.12781 +                    var yValue = chart.yScale().invert(e.mouseY);
 1.12782 +                    var yDistMax = Infinity, indexToHighlight = null;
 1.12783 +                    allData.forEach(function(series,i) {
 1.12784 +
 1.12785 +                        //To handle situation where the stacked area chart is negative, we need to use absolute values
 1.12786 +                        //when checking if the mouse Y value is within the stack area.
 1.12787 +                        yValue = Math.abs(yValue);
 1.12788 +                        var stackedY0 = Math.abs(series.stackedValue.y0);
 1.12789 +                        var stackedY = Math.abs(series.stackedValue.y);
 1.12790 +                        if ( yValue >= stackedY0 && yValue <= (stackedY + stackedY0))
 1.12791 +                        {
 1.12792 +                            indexToHighlight = i;
 1.12793 +                            return;
 1.12794 +                        }
 1.12795 +                    });
 1.12796 +                    if (indexToHighlight != null)
 1.12797 +                        allData[indexToHighlight].highlight = true;
 1.12798 +                }
 1.12799 +
 1.12800 +                var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex));
 1.12801 +
 1.12802 +                var valueFormatter = interactiveLayer.tooltip.valueFormatter();
 1.12803 +                // Keeps track of the tooltip valueFormatter if the chart changes to expanded view
 1.12804 +                if (stacked.style() === 'expand' || stacked.style() === 'stack_percent') {
 1.12805 +                    if ( !oldValueFormatter ) {
 1.12806 +                        oldValueFormatter = valueFormatter;
 1.12807 +                    }
 1.12808 +                    //Forces the tooltip to use percentage in 'expand' mode.
 1.12809 +                    valueFormatter = d3.format(".1%");
 1.12810 +                }
 1.12811 +                else {
 1.12812 +                    if (oldValueFormatter) {
 1.12813 +                        valueFormatter = oldValueFormatter;
 1.12814 +                        oldValueFormatter = null;
 1.12815 +                    }
 1.12816 +                }
 1.12817 +
 1.12818 +                interactiveLayer.tooltip
 1.12819 +                    .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top})
 1.12820 +                    .chartContainer(that.parentNode)
 1.12821 +                    .valueFormatter(valueFormatter)
 1.12822 +                    .data(
 1.12823 +                    {
 1.12824 +                        value: xValue,
 1.12825 +                        series: allData
 1.12826 +                    }
 1.12827 +                )();
 1.12828 +
 1.12829 +                interactiveLayer.renderGuideLine(pointXLocation);
 1.12830 +
 1.12831 +            });
 1.12832 +
 1.12833 +            interactiveLayer.dispatch.on("elementMouseout",function(e) {
 1.12834 +                stacked.clearHighlights();
 1.12835 +            });
 1.12836 +
 1.12837 +            // Update chart from a state object passed to event handler
 1.12838 +            dispatch.on('changeState', function(e) {
 1.12839 +
 1.12840 +                if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) {
 1.12841 +                    data.forEach(function(series,i) {
 1.12842 +                        series.disabled = e.disabled[i];
 1.12843 +                    });
 1.12844 +
 1.12845 +                    state.disabled = e.disabled;
 1.12846 +                }
 1.12847 +
 1.12848 +                if (typeof e.style !== 'undefined') {
 1.12849 +                    stacked.style(e.style);
 1.12850 +                    style = e.style;
 1.12851 +                }
 1.12852 +
 1.12853 +                chart.update();
 1.12854 +            });
 1.12855 +
 1.12856 +        });
 1.12857 +
 1.12858 +        renderWatch.renderEnd('stacked Area chart immediate');
 1.12859 +        return chart;
 1.12860 +    }
 1.12861 +
 1.12862 +    //============================================================
 1.12863 +    // Event Handling/Dispatching (out of chart's scope)
 1.12864 +    //------------------------------------------------------------
 1.12865 +
 1.12866 +    stacked.dispatch.on('elementMouseover.tooltip', function(evt) {
 1.12867 +        evt.point['x'] = stacked.x()(evt.point);
 1.12868 +        evt.point['y'] = stacked.y()(evt.point);
 1.12869 +        tooltip.data(evt).position(evt.pos).hidden(false);
 1.12870 +    });
 1.12871 +
 1.12872 +    stacked.dispatch.on('elementMouseout.tooltip', function(evt) {
 1.12873 +        tooltip.hidden(true)
 1.12874 +    });
 1.12875 +
 1.12876 +    //============================================================
 1.12877 +    // Expose Public Variables
 1.12878 +    //------------------------------------------------------------
 1.12879 +
 1.12880 +    // expose chart's sub-components
 1.12881 +    chart.dispatch = dispatch;
 1.12882 +    chart.stacked = stacked;
 1.12883 +    chart.legend = legend;
 1.12884 +    chart.controls = controls;
 1.12885 +    chart.xAxis = xAxis;
 1.12886 +    chart.yAxis = yAxis;
 1.12887 +    chart.interactiveLayer = interactiveLayer;
 1.12888 +    chart.tooltip = tooltip;
 1.12889 +
 1.12890 +    chart.dispatch = dispatch;
 1.12891 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.12892 +
 1.12893 +    chart._options = Object.create({}, {
 1.12894 +        // simple options, just get/set the necessary values
 1.12895 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
 1.12896 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
 1.12897 +        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
 1.12898 +        showXAxis:      {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
 1.12899 +        showYAxis:    {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
 1.12900 +        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
 1.12901 +        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
 1.12902 +        showControls:    {get: function(){return showControls;}, set: function(_){showControls=_;}},
 1.12903 +        controlLabels:    {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}},
 1.12904 +        controlOptions:    {get: function(){return controlOptions;}, set: function(_){controlOptions=_;}},
 1.12905 +
 1.12906 +        // deprecated options
 1.12907 +        tooltips:    {get: function(){return tooltip.enabled();}, set: function(_){
 1.12908 +            // deprecated after 1.7.1
 1.12909 +            nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
 1.12910 +            tooltip.enabled(!!_);
 1.12911 +        }},
 1.12912 +        tooltipContent:    {get: function(){return tooltip.contentGenerator();}, set: function(_){
 1.12913 +            // deprecated after 1.7.1
 1.12914 +            nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
 1.12915 +            tooltip.contentGenerator(_);
 1.12916 +        }},
 1.12917 +
 1.12918 +        // options that require extra logic in the setter
 1.12919 +        margin: {get: function(){return margin;}, set: function(_){
 1.12920 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.12921 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.12922 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.12923 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.12924 +        }},
 1.12925 +        duration: {get: function(){return duration;}, set: function(_){
 1.12926 +            duration = _;
 1.12927 +            renderWatch.reset(duration);
 1.12928 +            stacked.duration(duration);
 1.12929 +            xAxis.duration(duration);
 1.12930 +            yAxis.duration(duration);
 1.12931 +        }},
 1.12932 +        color:  {get: function(){return color;}, set: function(_){
 1.12933 +            color = nv.utils.getColor(_);
 1.12934 +            legend.color(color);
 1.12935 +            stacked.color(color);
 1.12936 +        }},
 1.12937 +        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
 1.12938 +            rightAlignYAxis = _;
 1.12939 +            yAxis.orient( rightAlignYAxis ? 'right' : 'left');
 1.12940 +        }},
 1.12941 +        useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
 1.12942 +            useInteractiveGuideline = !!_;
 1.12943 +            chart.interactive(!_);
 1.12944 +            chart.useVoronoi(!_);
 1.12945 +            stacked.scatter.interactive(!_);
 1.12946 +        }}
 1.12947 +    });
 1.12948 +
 1.12949 +    nv.utils.inheritOptions(chart, stacked);
 1.12950 +    nv.utils.initOptions(chart);
 1.12951 +
 1.12952 +    return chart;
 1.12953 +};
 1.12954 +// based on http://bl.ocks.org/kerryrodden/477c1bfb081b783f80ad
 1.12955 +nv.models.sunburst = function() {
 1.12956 +    "use strict";
 1.12957 +
 1.12958 +    //============================================================
 1.12959 +    // Public Variables with Default Settings
 1.12960 +    //------------------------------------------------------------
 1.12961 +
 1.12962 +    var margin = {top: 0, right: 0, bottom: 0, left: 0}
 1.12963 +        , width = null
 1.12964 +        , height = null
 1.12965 +        , mode = "count"
 1.12966 +        , modes = {count: function(d) { return 1; }, size: function(d) { return d.size }}
 1.12967 +        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
 1.12968 +        , container = null
 1.12969 +        , color = nv.utils.defaultColor()
 1.12970 +        , duration = 500
 1.12971 +        , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMousemove', 'elementMouseover', 'elementMouseout', 'renderEnd')
 1.12972 +        ;
 1.12973 +
 1.12974 +    var x = d3.scale.linear().range([0, 2 * Math.PI]);
 1.12975 +    var y = d3.scale.sqrt();
 1.12976 +
 1.12977 +    var partition = d3.layout.partition()
 1.12978 +        .sort(null)
 1.12979 +        .value(function(d) { return 1; });
 1.12980 +
 1.12981 +    var arc = d3.svg.arc()
 1.12982 +        .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
 1.12983 +        .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
 1.12984 +        .innerRadius(function(d) { return Math.max(0, y(d.y)); })
 1.12985 +        .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
 1.12986 +
 1.12987 +    // Keep track of the current and previous node being displayed as the root.
 1.12988 +    var node, prevNode;
 1.12989 +    // Keep track of the root node
 1.12990 +    var rootNode;
 1.12991 +
 1.12992 +    //============================================================
 1.12993 +    // chart function
 1.12994 +    //------------------------------------------------------------
 1.12995 +
 1.12996 +    var renderWatch = nv.utils.renderWatch(dispatch);
 1.12997 +
 1.12998 +    function chart(selection) {
 1.12999 +        renderWatch.reset();
 1.13000 +        selection.each(function(data) {
 1.13001 +            container = d3.select(this);
 1.13002 +            var availableWidth = nv.utils.availableWidth(width, container, margin);
 1.13003 +            var availableHeight = nv.utils.availableHeight(height, container, margin);
 1.13004 +            var radius = Math.min(availableWidth, availableHeight) / 2;
 1.13005 +            var path;
 1.13006 +
 1.13007 +            nv.utils.initSVG(container);
 1.13008 +
 1.13009 +            // Setup containers and skeleton of chart
 1.13010 +            var wrap = container.selectAll('.nv-wrap.nv-sunburst').data(data);
 1.13011 +            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sunburst nv-chart-' + id);
 1.13012 +
 1.13013 +            var g = wrapEnter.selectAll('nv-sunburst');
 1.13014 +
 1.13015 +            wrap.attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')');
 1.13016 +
 1.13017 +            container.on('click', function (d, i) {
 1.13018 +                dispatch.chartClick({
 1.13019 +                    data: d,
 1.13020 +                    index: i,
 1.13021 +                    pos: d3.event,
 1.13022 +                    id: id
 1.13023 +                });
 1.13024 +            });
 1.13025 +
 1.13026 +            y.range([0, radius]);
 1.13027 +
 1.13028 +            node = node || data;
 1.13029 +            rootNode = data[0];
 1.13030 +            partition.value(modes[mode] || modes["count"]);
 1.13031 +            path = g.data(partition.nodes).enter()
 1.13032 +                .append("path")
 1.13033 +                .attr("d", arc)
 1.13034 +                .style("fill", function (d) {
 1.13035 +                    return color((d.children ? d : d.parent).name);
 1.13036 +                })
 1.13037 +                .style("stroke", "#FFF")
 1.13038 +                .on("click", function(d) {
 1.13039 +                    if (prevNode !== node && node !== d) prevNode = node;
 1.13040 +                    node = d;
 1.13041 +                    path.transition()
 1.13042 +                        .duration(duration)
 1.13043 +                        .attrTween("d", arcTweenZoom(d));
 1.13044 +                })
 1.13045 +                .each(stash)
 1.13046 +                .on("dblclick", function(d) {
 1.13047 +                    if (prevNode.parent == d) {
 1.13048 +                        path.transition()
 1.13049 +                            .duration(duration)
 1.13050 +                            .attrTween("d", arcTweenZoom(rootNode));
 1.13051 +                    }
 1.13052 +                })
 1.13053 +                .each(stash)
 1.13054 +                .on('mouseover', function(d,i){
 1.13055 +                    d3.select(this).classed('hover', true).style('opacity', 0.8);
 1.13056 +                    dispatch.elementMouseover({
 1.13057 +                        data: d,
 1.13058 +                        color: d3.select(this).style("fill")
 1.13059 +                    });
 1.13060 +                })
 1.13061 +                .on('mouseout', function(d,i){
 1.13062 +                    d3.select(this).classed('hover', false).style('opacity', 1);
 1.13063 +                    dispatch.elementMouseout({
 1.13064 +                        data: d
 1.13065 +                    });
 1.13066 +                })
 1.13067 +                .on('mousemove', function(d,i){
 1.13068 +                    dispatch.elementMousemove({
 1.13069 +                        data: d
 1.13070 +                    });
 1.13071 +                });
 1.13072 +
 1.13073 +
 1.13074 +
 1.13075 +            // Setup for switching data: stash the old values for transition.
 1.13076 +            function stash(d) {
 1.13077 +                d.x0 = d.x;
 1.13078 +                d.dx0 = d.dx;
 1.13079 +            }
 1.13080 +
 1.13081 +            // When switching data: interpolate the arcs in data space.
 1.13082 +            function arcTweenData(a, i) {
 1.13083 +                var oi = d3.interpolate({x: a.x0, dx: a.dx0}, a);
 1.13084 +
 1.13085 +                function tween(t) {
 1.13086 +                    var b = oi(t);
 1.13087 +                    a.x0 = b.x;
 1.13088 +                    a.dx0 = b.dx;
 1.13089 +                    return arc(b);
 1.13090 +                }
 1.13091 +
 1.13092 +                if (i == 0) {
 1.13093 +                    // If we are on the first arc, adjust the x domain to match the root node
 1.13094 +                    // at the current zoom level. (We only need to do this once.)
 1.13095 +                    var xd = d3.interpolate(x.domain(), [node.x, node.x + node.dx]);
 1.13096 +                    return function (t) {
 1.13097 +                        x.domain(xd(t));
 1.13098 +                        return tween(t);
 1.13099 +                    };
 1.13100 +                } else {
 1.13101 +                    return tween;
 1.13102 +                }
 1.13103 +            }
 1.13104 +
 1.13105 +            // When zooming: interpolate the scales.
 1.13106 +            function arcTweenZoom(d) {
 1.13107 +                var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
 1.13108 +                    yd = d3.interpolate(y.domain(), [d.y, 1]),
 1.13109 +                    yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
 1.13110 +                return function (d, i) {
 1.13111 +                    return i
 1.13112 +                        ? function (t) {
 1.13113 +                        return arc(d);
 1.13114 +                    }
 1.13115 +                        : function (t) {
 1.13116 +                        x.domain(xd(t));
 1.13117 +                        y.domain(yd(t)).range(yr(t));
 1.13118 +                        return arc(d);
 1.13119 +                    };
 1.13120 +                };
 1.13121 +            }
 1.13122 +
 1.13123 +        });
 1.13124 +
 1.13125 +        renderWatch.renderEnd('sunburst immediate');
 1.13126 +        return chart;
 1.13127 +    }
 1.13128 +
 1.13129 +    //============================================================
 1.13130 +    // Expose Public Variables
 1.13131 +    //------------------------------------------------------------
 1.13132 +
 1.13133 +    chart.dispatch = dispatch;
 1.13134 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.13135 +
 1.13136 +    chart._options = Object.create({}, {
 1.13137 +        // simple options, just get/set the necessary values
 1.13138 +        width:      {get: function(){return width;}, set: function(_){width=_;}},
 1.13139 +        height:     {get: function(){return height;}, set: function(_){height=_;}},
 1.13140 +        mode:       {get: function(){return mode;}, set: function(_){mode=_;}},
 1.13141 +        id:         {get: function(){return id;}, set: function(_){id=_;}},
 1.13142 +        duration:   {get: function(){return duration;}, set: function(_){duration=_;}},
 1.13143 +
 1.13144 +        // options that require extra logic in the setter
 1.13145 +        margin: {get: function(){return margin;}, set: function(_){
 1.13146 +            margin.top    = _.top    != undefined ? _.top    : margin.top;
 1.13147 +            margin.right  = _.right  != undefined ? _.right  : margin.right;
 1.13148 +            margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom;
 1.13149 +            margin.left   = _.left   != undefined ? _.left   : margin.left;
 1.13150 +        }},
 1.13151 +        color: {get: function(){return color;}, set: function(_){
 1.13152 +            color=nv.utils.getColor(_);
 1.13153 +        }}
 1.13154 +    });
 1.13155 +
 1.13156 +    nv.utils.initOptions(chart);
 1.13157 +    return chart;
 1.13158 +};
 1.13159 +nv.models.sunburstChart = function() {
 1.13160 +    "use strict";
 1.13161 +
 1.13162 +    //============================================================
 1.13163 +    // Public Variables with Default Settings
 1.13164 +    //------------------------------------------------------------
 1.13165 +
 1.13166 +    var sunburst = nv.models.sunburst();
 1.13167 +    var tooltip = nv.models.tooltip();
 1.13168 +
 1.13169 +    var margin = {top: 30, right: 20, bottom: 20, left: 20}
 1.13170 +        , width = null
 1.13171 +        , height = null
 1.13172 +        , color = nv.utils.defaultColor()
 1.13173 +        , id = Math.round(Math.random() * 100000)
 1.13174 +        , defaultState = null
 1.13175 +        , noData = null
 1.13176 +        , duration = 250
 1.13177 +        , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd')
 1.13178 +        ;
 1.13179 +
 1.13180 +    //============================================================
 1.13181 +    // Private Variables
 1.13182 +    //------------------------------------------------------------
 1.13183 +
 1.13184 +    var renderWatch = nv.utils.renderWatch(dispatch);
 1.13185 +    tooltip.headerEnabled(false).duration(0).valueFormatter(function(d, i) {
 1.13186 +        return d;
 1.13187 +    });
 1.13188 +
 1.13189 +    //============================================================
 1.13190 +    // Chart function
 1.13191 +    //------------------------------------------------------------
 1.13192 +
 1.13193 +    function chart(selection) {
 1.13194 +        renderWatch.reset();
 1.13195 +        renderWatch.models(sunburst);
 1.13196 +
 1.13197 +        selection.each(function(data) {
 1.13198 +            var container = d3.select(this);
 1.13199 +            nv.utils.initSVG(container);
 1.13200 +
 1.13201 +            var that = this;
 1.13202 +            var availableWidth = nv.utils.availableWidth(width, container, margin),
 1.13203 +                availableHeight = nv.utils.availableHeight(height, container, margin);
 1.13204 +
 1.13205 +            chart.update = function() {
 1.13206 +                if (duration === 0)
 1.13207 +                    container.call(chart);
 1.13208 +                else
 1.13209 +                    container.transition().duration(duration).call(chart)
 1.13210 +            };
 1.13211 +            chart.container = this;
 1.13212 +
 1.13213 +            // Display No Data message if there's nothing to show.
 1.13214 +            if (!data || !data.length) {
 1.13215 +                nv.utils.noData(chart, container);
 1.13216 +                return chart;
 1.13217 +            } else {
 1.13218 +                container.selectAll('.nv-noData').remove();
 1.13219 +            }
 1.13220 +
 1.13221 +            // Setup containers and skeleton of chart
 1.13222 +            var wrap = container.selectAll('g.nv-wrap.nv-sunburstChart').data(data);
 1.13223 +            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sunburstChart').append('g');
 1.13224 +            var g = wrap.select('g');
 1.13225 +
 1.13226 +            gEnter.append('g').attr('class', 'nv-sunburstWrap');
 1.13227 +
 1.13228 +            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
 1.13229 +
 1.13230 +            // Main Chart Component(s)
 1.13231 +            sunburst.width(availableWidth).height(availableHeight);
 1.13232 +            var sunWrap = g.select('.nv-sunburstWrap').datum(data);
 1.13233 +            d3.transition(sunWrap).call(sunburst);
 1.13234 +
 1.13235 +        });
 1.13236 +
 1.13237 +        renderWatch.renderEnd('sunburstChart immediate');
 1.13238 +        return chart;
 1.13239 +    }
 1.13240 +
 1.13241 +    //============================================================
 1.13242 +    // Event Handling/Dispatching (out of chart's scope)
 1.13243 +    //------------------------------------------------------------
 1.13244 +
 1.13245 +    sunburst.dispatch.on('elementMouseover.tooltip', function(evt) {
 1.13246 +        evt['series'] = {
 1.13247 +            key: evt.data.name,
 1.13248 +            value: evt.data.size,
 1.13249 +            color: evt.color
 1.13250 +        };
 1.13251 +        tooltip.data(evt).hidden(false);
 1.13252 +    });
 1.13253 +
 1.13254 +    sunburst.dispatch.on('elementMouseout.tooltip', function(evt) {
 1.13255 +        tooltip.hidden(true);
 1.13256 +    });
 1.13257 +
 1.13258 +    sunburst.dispatch.on('elementMousemove.tooltip', function(evt) {
 1.13259 +        tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
 1.13260 +    });
 1.13261 +
 1.13262 +    //============================================================
 1.13263 +    // Expose Public Variables
 1.13264 +    //------------------------------------------------------------
 1.13265 +
 1.13266 +    // expose chart's sub-components
 1.13267 +    chart.dispatch = dispatch;
 1.13268 +    chart.sunburst = sunburst;
 1.13269 +    chart.tooltip = tooltip;
 1.13270 +    chart.options = nv.utils.optionsFunc.bind(chart);
 1.13271 +
 1.13272 +    // use Object get/set functionality to map between vars and chart functions
 1.13273 +    chart._options = Object.create({}, {
 1.13274 +        // simple options, just get/set the necessary values
 1.13275 +        noData:         {get: function(){return noData;},         set: function(_){noData=_;}},
 1.13276 +        defaultState:   {get: function(){return defaultState;},   set: function(_){defaultState=_;}},
 1.13277 +
 1.13278 +        // options that require extra logic in the setter
 1.13279 +        color: {get: function(){return color;}, set: function(_){
 1.13280 +            color = _;
 1.13281 +            sunburst.color(color);
 1.13282 +        }},
 1.13283 +        duration: {get: function(){return duration;}, set: function(_){
 1.13284 +            duration = _;
 1.13285 +            renderWatch.reset(duration);
 1.13286 +            sunburst.duration(duration);
 1.13287 +        }},
 1.13288 +        margin: {get: function(){return margin;}, set: function(_){
 1.13289 +            margin.top    = _.top    !== undefined ? _.top    : margin.top;
 1.13290 +            margin.right  = _.right  !== undefined ? _.right  : margin.right;
 1.13291 +            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
 1.13292 +            margin.left   = _.left   !== undefined ? _.left   : margin.left;
 1.13293 +        }}
 1.13294 +    });
 1.13295 +    nv.utils.inheritOptions(chart, sunburst);
 1.13296 +    nv.utils.initOptions(chart);
 1.13297 +    return chart;
 1.13298 +};
 1.13299 +
 1.13300 +nv.version = "1.8.1";
 1.13301 +})();
 1.13302 \ No newline at end of file