Full Code of novus/nvd3 for AI

master 447cce8c180a cached
190 files
2.9 MB
773.6k tokens
207 symbols
1 requests
Download .txt
Showing preview only (3,092K chars total). Download the full file or copy to clipboard to get everything.
Repository: novus/nvd3
Branch: master
Commit: 447cce8c180a
Files: 190
Total size: 2.9 MB

Directory structure:
gitextract_tmwn_v_x/

├── .eslintrc.json
├── .gitignore
├── .jshintrc
├── .travis.yml
├── GruntFile.js
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── bower.json
├── build/
│   ├── nv.d3.css
│   └── nv.d3.js
├── composer.json
├── examples/
│   ├── TimeSeries.html
│   ├── actual.json
│   ├── boxPlot.html
│   ├── boxPlotCustomModel.html
│   ├── bullet.html
│   ├── bulletChart.html
│   ├── candlestick.html
│   ├── candlestickChart.html
│   ├── cumulativeLineChart.html
│   ├── differenceChart.html
│   ├── discreteBarChart.html
│   ├── distroPlotChart.html
│   ├── documentation.html
│   ├── donutChart.html
│   ├── forceDirected.html
│   ├── furiousLegend.html
│   ├── heatMap.html
│   ├── historicalBar.html
│   ├── historicalBarChart.html
│   ├── index.html
│   ├── legend.html
│   ├── lib/
│   │   ├── colorbrewer.js
│   │   └── stream_layers.js
│   ├── line.html
│   ├── lineChart.html
│   ├── lineChartLogScale.html
│   ├── lineChartSVGResize.html
│   ├── linePlusBarChart.html
│   ├── lineWithFocusChart.html
│   ├── lineWithFocusChart_x2AxisLabel.html
│   ├── monitoringChart.html
│   ├── multiBarChart.html
│   ├── multiBarChart2.html
│   ├── multiBarHorizontalChart.html
│   ├── multiChart.html
│   ├── ohlc.html
│   ├── ohlcChart.html
│   ├── parallelCoordinates.html
│   ├── parallelCoordinatesChart.html
│   ├── pie.html
│   ├── pieChart.html
│   ├── predicted.json
│   ├── sankeyChart.html
│   ├── scatter.html
│   ├── scatterChart.html
│   ├── scatterPlusLineChart.html
│   ├── site.html
│   ├── sparkline.html
│   ├── sparklinePlus.html
│   ├── stackedArea.html
│   ├── stackedAreaChart.html
│   ├── stackedAreaWithFocusChart.html
│   ├── stylesheets/
│   │   ├── pygment_trac.css
│   │   └── styles.css
│   ├── sunburst.html
│   └── tooltip.html
├── index.html
├── meteor/
│   └── export.js
├── package.js
├── package.json
├── src/
│   ├── core.js
│   ├── css/
│   │   ├── axis.css
│   │   ├── bars.css
│   │   ├── boxplot.css
│   │   ├── bullet.css
│   │   ├── candlestick.css
│   │   ├── forceDirectedGraph.css
│   │   ├── furiousLegend.css
│   │   ├── lineplusbar.css
│   │   ├── lines.css
│   │   ├── main.css
│   │   ├── ohlc.css
│   │   ├── parallelcoordinates.css
│   │   ├── pie.css
│   │   ├── scatter.css
│   │   ├── sparkline.css
│   │   ├── stackedarea.css
│   │   └── tooltip.css
│   ├── dom.js
│   ├── interactiveLayer.js
│   ├── models/
│   │   ├── axis.js
│   │   ├── boxPlot.js
│   │   ├── boxPlotChart.js
│   │   ├── bullet.js
│   │   ├── bulletChart.js
│   │   ├── candlestickBar.js
│   │   ├── cumulativeLineChart.js
│   │   ├── differenceChart.js
│   │   ├── discreteBar.js
│   │   ├── discreteBarChart.js
│   │   ├── distribution.js
│   │   ├── distroPlot.js
│   │   ├── distroPlotChart.js
│   │   ├── focus.js
│   │   ├── forceDirectedGraph.js
│   │   ├── furiousLegend.js
│   │   ├── heatMap.js
│   │   ├── heatMapChart.js
│   │   ├── historicalBar.js
│   │   ├── historicalBarChart.js
│   │   ├── legend.js
│   │   ├── line.js
│   │   ├── lineChart.js
│   │   ├── linePlusBarChart.js
│   │   ├── multiBar.js
│   │   ├── multiBarChart.js
│   │   ├── multiBarHorizontal.js
│   │   ├── multiBarHorizontalChart.js
│   │   ├── multiChart.js
│   │   ├── ohlcBar.js
│   │   ├── parallelCoordinates.js
│   │   ├── parallelCoordinatesChart.js
│   │   ├── pie.js
│   │   ├── pieChart.js
│   │   ├── sankey.js
│   │   ├── sankeyChart.js
│   │   ├── scatter.js
│   │   ├── scatterChart.js
│   │   ├── sparkline.js
│   │   ├── sparklinePlus.js
│   │   ├── stackedArea.js
│   │   ├── stackedAreaChart.js
│   │   ├── sunburst.js
│   │   └── sunburstChart.js
│   ├── tooltip.js
│   └── utils.js
└── test/
    ├── ScatterChartTest.html
    ├── bootstrapModalTest.html
    ├── boxPlotTest.html
    ├── cumulativeLineChart.html
    ├── lineChartTest.html
    ├── linePlusBarChart.html
    ├── linePlusBarWithFocusChart.html
    ├── lineWithFisheyeChart.html
    ├── lineWithFocusChart.html
    ├── lineWithFocusChartMissingData.html
    ├── mocha/
    │   ├── axis.coffee
    │   ├── boxplot.coffee
    │   ├── bullet.coffee
    │   ├── core.coffee
    │   ├── cumulative-line.coffee
    │   ├── differenceChart.js
    │   ├── discretebar.coffee
    │   ├── distrochart.coffee
    │   ├── heatmap.coffee
    │   ├── historical-bar.coffee
    │   ├── legend.coffee
    │   ├── line.coffee
    │   ├── multibar-horizontal.coffee
    │   ├── multibar.coffee
    │   ├── pie.coffee
    │   ├── sankey.coffee
    │   ├── scatter.coffee
    │   ├── sparkline.coffee
    │   ├── stacked.coffee
    │   ├── sunburst.coffee
    │   ├── test-utils.coffee
    │   └── utils.coffee
    ├── multiBarChartTest.html
    ├── multiBarHorizontalChart.html
    ├── node/
    │   ├── GruntFile.js
    │   ├── README.md
    │   ├── nodeTest.html
    │   ├── nodeTest.js
    │   └── package.json
    ├── pieChartTest.html
    ├── polylinearTest.html
    ├── realTimeChartTest.html
    ├── scatterPlusLineChart.html
    ├── scrollTest.html
    ├── scrollTest2.html
    ├── stackedAreaChartMissingData.html
    ├── stackedAreaChartTest.html
    ├── stream_layers.js
    ├── testScript.js
    ├── teststyle.css
    ├── tinytest/
    │   └── nv-is-defined-test.js
    └── translateTest.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.json
================================================
{
  "env": {
    "browser": true,
    "node": true,
    "es6": true,
    "mocha": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
      "sourceType": "module"
  },
  "globals": {
    "nv": true,
    "d3": true
  },
  "rules": {
    "indent": [
      "error",
      2
    ],
    "linebreak-style": [
      "error",
      "unix"
    ],
    "quotes": [
      "error",
      "single"
    ],
    "object-curly-spacing": [
      "error",
      "always"
    ],
    "prefer-arrow-callback": [
      "never",
      {
        "allowNamedFunctions": true
      }
    ],
    "arrow-parens": [
      "error",
      "always"
    ],
    "space-before-function-paren": ["error", {
      "anonymous": "never",
      "named": "never",
      "asyncArrow": "never"
    }],
    "semi": [
      "error",
      "always"
    ],
    "comma-dangle": ["error", {
      "arrays": "never",
      "objects": "never",
      "imports": "never",
      "exports": "never",
      "functions": "ignore"
    }]
  }
}


================================================
FILE: .gitignore
================================================

.idea
*.swp
*~
*.log
.DS_Store*
ehthumbs.db
Icon?
Thumbs.db
node_modules
bower_components
coverage
test-results.xml
*.orig


================================================
FILE: .jshintrc
================================================
{
    "asi": true
}


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
    - "0.12"
before_install:
    - "npm install -g bower"
    - "npm install -g grunt-cli"
    - "export DISPLAY=:99.0"
    - "sh -e /etc/init.d/xvfb start"
#   Meteor Tinytest support
    - "curl https://install.meteor.com | /bin/sh"
    - export PATH="$HOME/.meteor:$PATH"
    - "npm install -g spacejam"
install:
    - "npm install"
    - "bower install"

script:
    - "npm test"
    - "spacejam test-packages ./"


================================================
FILE: GruntFile.js
================================================
module.exports = function(grunt) {
    var _pkg = grunt.file.readJSON('package.json');

    // allows autoprefixer to work on older node_js versions
    require('es6-promise').polyfill();

    //Project configuration.
    grunt.initConfig({
        pkg: _pkg,
        concat: {
            css: {
                options: {
                    separator: '\n',
                    banner: '/* nvd3 version ' + _pkg.version + ' (' + _pkg.url + ') ' +
                        '<%= grunt.template.today("yyyy-mm-dd") %> */\n'
                },
                src: [
                    'src/css/*.css'
                ],
                dest: 'build/nv.d3.css'
            },
            js: {
                options: {
                    separator: '',
                    banner: '/* nvd3 version ' + _pkg.version + ' (' + _pkg.url + ') ' +
                        '<%= grunt.template.today("yyyy-mm-dd") %> */\n' + '(function(){\n',
                    footer: '\nnv.version = "' + _pkg.version + '";\n})();',
                    sourceMap: true,
                    sourceMapName: 'build/nv.d3.js.map',
                    sourceMapStyle: 'embed'
                },
                src: [
                    'src/core.js',
                    'src/dom.js',
                    'src/interactiveLayer.js',
                    'src/tooltip.js',
                    'src/utils.js',
                    //Include all files in src/models
                    'src/models/*.js',
                    // example to exclude files: '!src/models/excludeMe*'
                ],
                dest: 'build/nv.d3.js'
            }
        },
        uglify: {
            options: {
                sourceMap: true,
                sourceMapIncludeSources : true,
                sourceMapIn : 'build/nv.d3.js.map',
                banner: '/* nvd3 version ' + _pkg.version + ' (' + _pkg.url + ') ' +
                    '<%= grunt.template.today("yyyy-mm-dd") %> */\n'
            },
            js: {
                files: {
                    'build/nv.d3.min.js': ['build/nv.d3.js']
                }
            }
        },
        replace: {
            version: {
                src: [
                    'package.js'
                ],
                overwrite: true,
                replacements: [{
                    from: /(version?\s?=?\:?\s\')([\d\.]*)\'/gi,
                    to: '$1' + _pkg.version + "'"
                }]
            }
        },
        jshint: {
            foo: {
                src: "src/**/*.js"
            },
            options: {
                jshintrc: '.jshintrc'
            }
        },
        watch: {
            js: {
                files: ["src/**/*.js"],
                tasks: ['concat']
            }
        },
        copy: {
            css: {
                files: [
                    { src: 'src/nv.d3.css', dest: 'build/nv.d3.css' }
                ]
            }
        },
        postcss: {
            options: {
                processors: [
                    require('autoprefixer')({
                        browsers: [
                            'last 2 versions',
                            'last 3 iOS versions',
                            'last 2 safari versions',
                            'ie >= 9']
                    })
                ]
            },
            dist: {
                src: 'build/nv.d3.css'
            }
        },
        cssmin: {
            options: {
                sourceMap: true
            },
            dist: {
                files: {
                    'build/nv.d3.min.css' : ['build/nv.d3.css']
                }
            }
        },
        karma: {
            unit: {
                options: {
                    logLevel: 'DEBUG',
                    browsers: ['Firefox'],
                    browserNoActivityTimeout: 60000,
                    browserDisconnectTimeout: 60000,
                    captureTimeout: 60000,
                    frameworks: [ 'mocha', 'sinon-chai' ],
                    reporters: [ 'spec', 'junit', 'coverage'],
                    singleRun: true,
                    preprocessors: {
                        'src/*.js': ['coverage'],
                        'src/models/*.js': ['coverage'],
                        'test/mocha/*.coffee': ['coffee']
                    },
                    files: [
                        'bower_components/d3/d3.js',
                        'node_modules/moment/moment.js',
                        'src/*.js',
                        'src/models/*.js',
                        'test/mocha/*.coffee',
                        'https://cdn.rawgit.com/Kcnarf/d3-beeswarm/fbda9b54/build/d3-beeswarm.min.js',
                        'test/mocha/*.js'
                    ],
                    exclude: [
                        'src/intro.js',
                        'src/outro.js',
                        //Files we don't want to test.
                        'src/models/lineWith*',
                        'src/models/parallelCoordinates*',
                        'src/models/multiBarTime*',
                        'src/models/indented*',
                        'src/models/linePlus*',
                        'src/models/ohlcBar.js',
                        'src/models/candlestickBar.js'
                    ]
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-postcss');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-karma');
    grunt.loadNpmTasks('grunt-text-replace');

    grunt.registerTask('default', ['concat', 'copy', 'postcss', 'karma:unit']);
    grunt.registerTask('production', ['concat', 'uglify', 'copy', 'postcss', 'cssmin', 'replace']);
    grunt.registerTask('release', ['production']);
    grunt.registerTask('lint', ['jshint']);
};


================================================
FILE: ISSUE_TEMPLATE.md
================================================
PLEASE READ THIS BEFORE SUBMITTING A NEW ISSUE.

ARE YOU ASKING FOR HELP? Please use Stack Overflow tag nvd3.js and include a link to a live, minimal example on jsfiddle / plunker.

The live example should use the latest code for nvd3. Links are below:
https://raw.githubusercontent.com/novus/nvd3/master/build/nv.d3.js
https://raw.githubusercontent.com/novus/nvd3/master/build/nv.d3.css

Supported D3 js version. v3.5.17

https://github.com/cdnjs/cdnjs/blob/master/ajax/libs/d3/3.5.17/d3.min.js

ARE YOU REPORTING AN ISSUE? Please provide below information with the issue:

NVD3 version used:

Browser and OS used:

Live Example: Jsfiddle / Plunker

Expected Behaviour:

Present Behaviour:

Any more information regarding the issue:


================================================
FILE: LICENSE.md
================================================
##nvd3.js License

Copyright (c) 2011-2014 [Novus Partners, Inc.][novus]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

[novus]: https://www.novus.com/



##d3.js License

Copyright (c) 2012, Michael Bostock
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* The name Michael Bostock may not be used to endorse or promote products
  derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.md
================================================
## NVD3 - A reusable D3 charting library

Inspired by the work of Mike Bostock's [Towards Reusable Charts](http://bost.ocks.org/mike/chart/), and supported by a combined effort of [Novus](http://www.novus.com) and the NVD3 community.

[View Examples](http://nvd3-community.github.io/nvd3/) | [NEW Documentation!](http://nvd3-community.github.io/nvd3/examples/documentation.html) | Development build status: [![Build Status](https://travis-ci.org/novus/nvd3.svg?branch=master)](https://travis-ci.org/novus/nvd3)


## Usage
Simply add the `nv.d3` assets to your project and include them in your HTML.

```
<link href="nv.d3.min.css" rel="stylesheet">
<script src="nv.d3.min.js"></script>
```

*  `nv.d3.js` should appear after `d3.js` is included.
* Prefer minified assets (`.min`) for production.

### Dependencies

NVD3 is recommended to go with [d3.js](http://d3js.org/) version 3.5.3 and later, but NOT d3 4.x yet. [version 3.5.17](https://github.com/d3/d3/releases/tag/v3.5.17) is the most recent d3 v3 release. 

**Minimum D3 version required: 3.4.4**

For a D3v4 Version, see the work in progress at the [nvd3 organization](http://github.com/nvd3/nvd3)

Along with `pieChart` options `padAngle` and `cornerRadius`, the interactive guideline tooltip now requires these later versions of D3 (3.4.4+, specifically, to get interactive tooltips). The interactive guide lines rely on the more recent `d3.bisector()` method which treats accessors taking two parameters (the second being the element index) as comparators (see [d3.bisector()](https://github.com/mbostock/d3/wiki/Arrays#d3_bisector)).


## Supported Browsers
NVD3 runs best on WebKit based browsers.

* Google Chrome: latest version
* Opera 15+ (i.e. webkit version)
* Safari: latest version
* Firefox: latest version
* Internet Explorer: 10+

## Do we support D3 v4.x?

No, we do not...  we are very interested in taking this on but could use some help.  Please let us know if you'd like to help make this a reality!  :)

## Changelog

**1.8.6** Changes:

* Community bugfixes

**1.8.5** Changes:

* Community bugfixes
* New force-directed graph

**1.8.4** Changes:

* Community bugfixes including tooltip fixes.

**1.8.3** Changes:

* Lots of community bugfixes
* Added force-directed chart

**1.8.2** Changes:

* Lots of community bugfixes and a few extra minor features

**1.8.1** Changes:

* Tooltips were refactored - If you have customized your tooltips, note that you may need to adjust your custom functions as the data passed has changed format.  See the new [tooltip options](https://nvd3-community.github.io/nvd3/examples/documentation.html#tooltip) for more details.
* Added boxplot charts | [example](https://nvd3-community.github.io/nvd3/examples/boxPlot.html)
* Added candlestick charts | [example](https://nvd3-community.github.io/nvd3/examples/candlestickChart.html)
* Added extra donut chart abilities | [examples](https://nvd3-community.github.io/nvd3/examples/monitoringChart.html)
* Added sunburst Charts | [example](https://nvd3-community.github.io/nvd3/examples/sunburst.html)
* Time Series | [example](https://nvd3-community.github.io/nvd3/examples/TimeSeries.html)
* Another legend format available | [example](https://nvd3-community.github.io/nvd3/examples/stackedAreaChart.html)
* Lots of bug fixes (see closed issues)
* (for all examples, see [here](https://nvd3-community.github.io/nvd3/))

**1.7.1** Changes:

* Fixed axis.staggerLabels bug.
* Fixed Karma unit tests.
* Fixed chart test pages.
* Merged in nvd3-community changes and development branch.

**1.7.0** Changes:

* Fixes around 20 small bugs.
* Fixed the notorious slowness of line charts and scatter plots on chrome
* Combined the scatterChart and scatterChartWithLines models
* Combined the linePlusBarChart and linePlusBarChartWithFocus models.
* renamed some of the options (see the new documentation for what options are available for each chart)
* Completed the migration of the option functions to an object format which allows the generation of
the documentation in an automated way.  Not everything has a description yet, but check it out!
* Added extra options to the donut charts based on features that will be in d3 3.5.  The donut example page
loads the latest d3 from their 3.5 branch so keep that in mind.
* Added an example of the parallelCoordinates chart.
* Fixed up the half-done OHLC bar chart, and made an example for it as well.

**1.6.0** Changes:

* includes about a dozen bug fixes and pull requests I fixed and merged in
from the issues/pulls from the original project.
* It also standardized all indention

---

# Current development focus
- Review outstanding pull requests and issues.
- Try to find an easy way to actually document usage and all chart options.
- Improve the testing framework.
- Setup continuous integration.

---

# Bugs

Found a bug?  Check out the latest from the `master` branch and make sure it's not already fixed first! If you don't see a related fix, please [open an issue](https://github.com/novus/nvd3/issues).

---

# Optional dependencies

Including [Fastdom](https://github.com/wilsonpage/fastdom) in your project can greatly increase the performance of the line chart (particularly in Firefox and Internet Explorer) by batching DOM read and write operations to avoid [layout thrashing](http://wilsonpage.co.uk/preventing-layout-thrashing/). NVD3 will take advantage of Fastdom if present.

---

# Contributing

If one of [the existing models](https://github.com/novus/nvd3/tree/master/src/models)
doesn't meet your needs, fork the project, implement the model and an example using it,
send us a pull request, for consideration for inclusion in the project.

If you'd like to contribute consistently, show me what you've got with some good pull requests and you may get added to the nvd3-community org!

### A few rules for pull requests

1. Please commit to the `master` branch
2. Do NOT check in anything under the `build` directory, it clutters up the commit and just gets overwritten later.
3. All new features must come with unit test coverage
4. Bug fixes should come with unit tests that prove their fix

If you want to test your changes using the example pages,
you'll have to run `grunt production` to build the items into the `build` directory.
You must do this before your changes show up in the examples, as they link to the build directory
in order to properly show off the finished product.
Please remember to NOT include the build files in your commit though,
only include the source files you changed!

### Tips for Testing
* Unit tests were written in Karma and Mocha. Follow instructions in **Building Latest** to get npm packages setup. This may not work on Windows machines.
* Run `bower install` to get bower dependencies.
* Run `grunt` to start the unit tests.
* Also visually inspect the HTML pages in the **examples/ and test/ folders**.  Make sure there are no glaring errors.
* Novus now uses Travis CI for continuous integration. Visit [our travis build page](https://travis-ci.org/novus/nvd3/) to see the latest status.

#### Meteor Tinytests
* Any Meteor-specific features can be tested from the command line using `tinytest` and [Spacejam](https://www.npmjs.com/package/spacejam)
* `spacejam` can be installed by running `npm install -g spacejam`.
* Tinytests can then be executed by running `spacejam test-packages ./` from this project's root.

---

## Building latest

1. First clone the repository and checkout the `master` branch
2. make sure `nodejs` is installed via your system's package manager.
3. Install `grunt`, `grunt-cli`, and `bower`:  `npm install -g grunt grunt-cli bower`

> have node download nvd3's required modules with:  `npm install`

> build with:  `grunt production`

You should now have a `build` directory with the js and css files within.

---


================================================
FILE: bower.json
================================================
{
  "name": "nvd3",
  "homepage": "http://www.nvd3.org",
  "authors": [
    "Bob Monteverde",
    "Tyler Wolf",
    "Robin Hu",
    "Frank Shao",
    "liquidpele"
  ],
  "description": "Re-usable charts and chart components for d3.",
  "main": [
    "build/nv.d3.js",
    "build/nv.d3.css"
  ],
  "keywords": [
    "d3",
    "visualization",
    "svg",
    "charts"
  ],
  "license": "Apache-2.0",
  "dependencies": {
    "d3": "^3.4.4"
  },
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "src",
    "examples",
    "GruntFile.js",
    "*.html",
    "*.log",
    "*.xml",
    "*.json",
    "*.md"
  ]
}


================================================
FILE: build/nv.d3.css
================================================
/* nvd3 version 1.8.6-dev (https://github.com/novus/nvd3) 2018-02-24 */
.nvd3 .nv-axis {
    pointer-events:none;
    opacity: 1;
}

.nvd3 .nv-axis path {
    fill: none;
    stroke: #000;
    stroke-opacity: .75;
    shape-rendering: crispEdges;
}

.nvd3 .nv-axis path.domain {
    stroke-opacity: .75;
}

.nvd3 .nv-axis.nv-x path.domain {
    stroke-opacity: 0;
}

.nvd3 .nv-axis line {
    fill: none;
    stroke: #e5e5e5;
    shape-rendering: crispEdges;
}

.nvd3 .nv-axis .zero line,
    /*this selector may not be necessary*/ .nvd3 .nv-axis line.zero {
    stroke-opacity: .75;
}

.nvd3 .nv-axis .nv-axisMaxMin text {
    font-weight: bold;
}

.nvd3 .x  .nv-axis .nv-axisMaxMin text,
.nvd3 .x2 .nv-axis .nv-axisMaxMin text,
.nvd3 .x3 .nv-axis .nv-axisMaxMin text {
    text-anchor: middle;
}

.nvd3 .nv-axis.nv-disabled {
    opacity: 0;
}

.nvd3 .nv-bars rect {
    fill-opacity: .75;

    transition: fill-opacity 250ms linear;
}

.nvd3 .nv-bars rect.hover {
    fill-opacity: 1;
}

.nvd3 .nv-bars .hover rect {
    fill: lightblue;
}

.nvd3 .nv-bars text {
    fill: rgba(0,0,0,0);
}

.nvd3 .nv-bars .hover text {
    fill: rgba(0,0,0,1);
}

.nvd3 .nv-multibar .nv-groups rect,
.nvd3 .nv-multibarHorizontal .nv-groups rect,
.nvd3 .nv-discretebar .nv-groups rect {
    stroke-opacity: 0;

    transition: fill-opacity 250ms linear;
}

.nvd3 .nv-multibar .nv-groups rect:hover,
.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,
.nvd3 .nv-candlestickBar .nv-ticks rect:hover,
.nvd3 .nv-discretebar .nv-groups rect:hover {
    fill-opacity: 1;
}

.nvd3 .nv-discretebar .nv-groups text,
.nvd3 .nv-multibarHorizontal .nv-groups text {
    font-weight: bold;
    fill: rgba(0,0,0,1);
    stroke: rgba(0,0,0,0);
}

/* boxplot CSS */
.nvd3 .nv-boxplot circle {
  fill-opacity: 0.5;
}

.nvd3 .nv-boxplot circle:hover {
  fill-opacity: 1;
}

.nvd3 .nv-boxplot rect:hover {
  fill-opacity: 1;
}

.nvd3 line.nv-boxplot-median {
  stroke: black;
}

.nv-boxplot-tick:hover {
  stroke-width: 2.5px;
}
/* bullet */
.nvd3.nv-bullet { font: 10px sans-serif; }
.nvd3.nv-bullet .nv-measure { fill-opacity: .8; }
.nvd3.nv-bullet .nv-measure:hover { fill-opacity: 1; }
.nvd3.nv-bullet .nv-marker { stroke: #000; stroke-width: 2px; }
.nvd3.nv-bullet .nv-markerTriangle { stroke: #000; fill: #fff; stroke-width: 1.5px; }
.nvd3.nv-bullet .nv-markerLine { stroke: #000; stroke-width: 1.5px; }
.nvd3.nv-bullet .nv-tick line { stroke: #666; stroke-width: .5px; }
.nvd3.nv-bullet .nv-range.nv-s0 { fill: #eee; }
.nvd3.nv-bullet .nv-range.nv-s1 { fill: #ddd; }
.nvd3.nv-bullet .nv-range.nv-s2 { fill: #ccc; }
.nvd3.nv-bullet .nv-title { font-size: 14px; font-weight: bold; }
.nvd3.nv-bullet .nv-subtitle { fill: #999; }

.nvd3.nv-bullet .nv-range {
    fill: #bababa;
    fill-opacity: .4;
}

.nvd3.nv-bullet .nv-range:hover {
    fill-opacity: .7;
}

.nvd3.nv-candlestickBar .nv-ticks .nv-tick {
    stroke-width: 1px;
}

.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover {
    stroke-width: 2px;
}

.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect {
    stroke: #2ca02c;
    fill: #2ca02c;
}

.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect {
    stroke: #d62728;
    fill: #d62728;
}

.with-transitions .nv-candlestickBar .nv-ticks .nv-tick {
    transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
}

.nvd3.nv-candlestickBar .nv-ticks line {
    stroke: #333;
}

.nv-force-node {
    stroke: #fff;
    stroke-width: 1.5px;
}

.nv-force-link {
    stroke: #999;
    stroke-opacity: .6;
}

.nv-force-node text {
    stroke-width: 0px;
}

.nvd3 .nv-legend .nv-disabled rect {
    /*fill-opacity: 0;*/
}

.nvd3 .nv-check-box .nv-box {
    fill-opacity:0;
    stroke-width:2;
}

.nvd3 .nv-check-box .nv-check {
    fill-opacity:0;
    stroke-width:4;
}

.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check {
    fill-opacity:0;
    stroke-opacity:0;
}

.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check {
    opacity: 0;
}

/* line plus bar */
.nvd3.nv-linePlusBar .nv-bar rect {
    fill-opacity: .75;
}

.nvd3.nv-linePlusBar .nv-bar rect:hover {
    fill-opacity: 1;
}
.nvd3 .nv-groups path.nv-line {
    fill: none;
}

.nvd3 .nv-groups path.nv-area {
    stroke: none;
}

.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point {
    fill-opacity: 0;
    stroke-opacity: 0;
}

.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point {
    fill-opacity: .5 !important;
    stroke-opacity: .5 !important;
}


.with-transitions .nvd3 .nv-groups .nv-point {
    transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
}

.nvd3.nv-scatter .nv-groups .nv-point.hover,
.nvd3 .nv-groups .nv-point.hover {
    stroke-width: 7px;
    fill-opacity: .95 !important;
    stroke-opacity: .95 !important;
}


.nvd3 .nv-point-paths path {
    stroke: #aaa;
    stroke-opacity: 0;
    fill: #eee;
    fill-opacity: 0;
}


.nvd3 .nv-indexLine {
    cursor: ew-resize;
}

/********************
 * SVG CSS
 */

/********************
  Default CSS for an svg element nvd3 used
*/
svg.nvd3-svg {
    -webkit-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
            user-select: none;
    display: block;
    width:100%;
    height:100%;
}

/********************
  Box shadow and border radius styling
*/
.nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip {
    box-shadow: 0 5px 10px rgba(0,0,0,.2);
    border-radius: 5px;
}


.nvd3 text {
    font: normal 12px Arial, sans-serif;
}

.nvd3 .title {
    font: bold 14px Arial, sans-serif;
}

.nvd3 .nv-background {
    fill: white;
    fill-opacity: 0;
}

.nvd3.nv-noData {
    font-size: 18px;
    font-weight: bold;
}


/**********
*  Brush
*/

.nv-brush .extent {
    fill-opacity: .125;
    shape-rendering: crispEdges;
}

.nv-brush .resize path {
    fill: #eee;
    stroke: #666;
}


/**********
*  Legend
*/

.nvd3 .nv-legend .nv-series {
    cursor: pointer;
}

.nvd3 .nv-legend .nv-disabled circle {
    fill-opacity: 0;
}

/* focus */
.nvd3 .nv-brush .extent {
    fill-opacity: 0 !important;
}

.nvd3 .nv-brushBackground rect {
    stroke: #000;
    stroke-width: .4;
    fill: #fff;
    fill-opacity: .7;
}

/**********
*  Print
*/

@media print {
    .nvd3 text {
        stroke-width: 0;
        fill-opacity: 1;
    }
}

.nvd3.nv-ohlcBar .nv-ticks .nv-tick {
    stroke-width: 1px;
}

.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover {
    stroke-width: 2px;
}

.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive {
    stroke: #2ca02c;
}

.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative {
    stroke: #d62728;
}


.nvd3 .background path {
    fill: none;
    stroke: #EEE;
    stroke-opacity: .4;
    shape-rendering: crispEdges;
}

.nvd3 .foreground path {
    fill: none;
    stroke-opacity: .7;
}

.nvd3 .nv-parallelCoordinates-brush .extent {
    fill: #fff;
    fill-opacity: .6;
    stroke: gray;
    shape-rendering: crispEdges;
}

.nvd3 .nv-parallelCoordinates .hover  {
    fill-opacity: 1;
	stroke-width: 3px;
}


.nvd3 .missingValuesline line {
  fill: none;
  stroke: black;
  stroke-width: 1;
  stroke-opacity: 1;
  stroke-dasharray: 5, 5;
}

.nvd3.nv-pie path {
    stroke-opacity: 0;
    transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
}

.nvd3.nv-pie .nv-pie-title {
    font-size: 24px;
    fill: rgba(19, 196, 249, 0.59);
}

.nvd3.nv-pie .nv-slice text {
    stroke: #000;
    stroke-width: 0;
}

.nvd3.nv-pie path {
    stroke: #fff;
    stroke-width: 1px;
    stroke-opacity: 1;
}

.nvd3.nv-pie path {
    fill-opacity: .7;
}

.nvd3.nv-pie .hover path {
    fill-opacity: 1;
}

.nvd3.nv-pie .nv-label {
    pointer-events: none;
}

.nvd3.nv-pie .nv-label rect {
    fill-opacity: 0;
    stroke-opacity: 0;
}

/* scatter */
.nvd3 .nv-groups .nv-point.hover {
    stroke-width: 20px;
    stroke-opacity: .5;
}

.nvd3 .nv-scatter .nv-point.hover {
    fill-opacity: 1;
}

.nv-noninteractive {
    pointer-events: none;
}

.nv-distx, .nv-disty {
    pointer-events: none;
}

/* sparkline */
.nvd3.nv-sparkline path {
    fill: none;
}

.nvd3.nv-sparklineplus g.nv-hoverValue {
    pointer-events: none;
}

.nvd3.nv-sparklineplus .nv-hoverValue line {
    stroke: #333;
    stroke-width: 1.5px;
}

.nvd3.nv-sparklineplus,
.nvd3.nv-sparklineplus g {
    pointer-events: all;
}

.nvd3 .nv-hoverArea {
    fill-opacity: 0;
    stroke-opacity: 0;
}

.nvd3.nv-sparklineplus .nv-xValue,
.nvd3.nv-sparklineplus .nv-yValue {
    stroke-width: 0;
    font-size: .9em;
    font-weight: normal;
}

.nvd3.nv-sparklineplus .nv-yValue {
    stroke: #f66;
}

.nvd3.nv-sparklineplus .nv-maxValue {
    stroke: #2ca02c;
    fill: #2ca02c;
}

.nvd3.nv-sparklineplus .nv-minValue {
    stroke: #d62728;
    fill: #d62728;
}

.nvd3.nv-sparklineplus .nv-currentValue {
    font-weight: bold;
    font-size: 1.1em;
}
/* stacked area */
.nvd3.nv-stackedarea path.nv-area {
    fill-opacity: .7;
    stroke-opacity: 0;
    transition: fill-opacity 250ms linear, stroke-opacity 250ms linear;
}

.nvd3.nv-stackedarea path.nv-area.hover {
    fill-opacity: .9;
}


.nvd3.nv-stackedarea .nv-groups .nv-point {
    stroke-opacity: 0;
    fill-opacity: 0;
}

.nvtooltip {
    position: absolute;
    background-color: rgba(255,255,255,1.0);
    color: rgba(0,0,0,1.0);
    padding: 1px;
    border: 1px solid rgba(0,0,0,.2);
    z-index: 10000;
    display: block;

    font-family: Arial, sans-serif;
    font-size: 13px;
    text-align: left;
    pointer-events: none;

    white-space: nowrap;

    -webkit-user-select: none;

       -moz-user-select: none;

        -ms-user-select: none;

            user-select: none;
}

.nvtooltip {
    background: rgba(255,255,255, 0.8);
    border: 1px solid rgba(0,0,0,0.5);
    border-radius: 4px;
}

/*Give tooltips that old fade in transition by
    putting a "with-transitions" class on the container div.
*/
.nvtooltip.with-transitions, .with-transitions .nvtooltip {
    transition: opacity 50ms linear;

    transition-delay: 200ms;
}

.nvtooltip.x-nvtooltip,
.nvtooltip.y-nvtooltip {
    padding: 8px;
}

.nvtooltip h3 {
    margin: 0;
    padding: 4px 14px;
    line-height: 18px;
    font-weight: normal;
    background-color: rgba(247,247,247,0.75);
    color: rgba(0,0,0,1.0);
    text-align: center;

    border-bottom: 1px solid #ebebeb;

    border-radius: 5px 5px 0 0;
}

.nvtooltip p {
    margin: 0;
    padding: 5px 14px;
    text-align: center;
}

.nvtooltip span {
    display: inline-block;
    margin: 2px 0;
}

.nvtooltip table {
    margin: 6px;
    border-spacing:0;
}


.nvtooltip table td {
    padding: 2px 9px 2px 0;
    vertical-align: middle;
}

.nvtooltip table td.key {
    font-weight: normal;
}

.nvtooltip table td.key.total {
    font-weight: bold;
}

.nvtooltip table td.value {
    text-align: right;
    font-weight: bold;
}

.nvtooltip table td.percent {
    color: darkgray;
}

.nvtooltip table tr.highlight td {
    padding: 1px 9px 1px 0;
    border-bottom-style: solid;
    border-bottom-width: 1px;
    border-top-style: solid;
    border-top-width: 1px;
}

.nvtooltip table td.legend-color-guide div {
    width: 8px;
    height: 8px;
    vertical-align: middle;
}

.nvtooltip table td.legend-color-guide div {
    width: 12px;
    height: 12px;
    border: 1px solid #999;
}

.nvtooltip .footer {
    padding: 3px;
    text-align: center;
}

.nvtooltip-pending-removal {
    pointer-events: none;
    display: none;
}


/****
Interactive Layer
*/
.nvd3 .nv-interactiveGuideLine {
    pointer-events:none;
}

.nvd3 line.nv-guideline {
    stroke: #ccc;
}


================================================
FILE: build/nv.d3.js
================================================
/* nvd3 version 1.8.6-dev (https://github.com/novus/nvd3) 2018-02-24 */
(function(){

// set up main nv object
var nv = {};

// the major global objects under the nv namespace
nv.dev = false; //set false when in production
nv.tooltip = nv.tooltip || {}; // For the tooltip system
nv.utils = nv.utils || {}; // Utility subsystem
nv.models = nv.models || {}; //stores all the possible models/components
nv.charts = {}; //stores all the ready to use charts
nv.logs = {}; //stores some statistics and potential error messages
nv.dom = {}; //DOM manipulation functions

// Node/CommonJS - require D3
if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined' && typeof(d3) == 'undefined') {
    d3 = require('d3');
}

nv.dispatch = d3.dispatch('render_start', 'render_end');

// Function bind polyfill
// Needed ONLY for phantomJS as it's missing until version 2.0 which is unreleased as of this comment
// https://github.com/ariya/phantomjs/issues/10522
// http://kangax.github.io/compat-table/es5/#Function.prototype.bind
// phantomJS is used for running the test suite
if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5 internal IsCallable function
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }

        var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP = function () {},
            fBound = function () {
                return fToBind.apply(this instanceof fNOP && oThis
                        ? this
                        : oThis,
                    aArgs.concat(Array.prototype.slice.call(arguments)));
            };

        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
    };
}

//  Development render timers - disabled if dev = false
if (nv.dev) {
    nv.dispatch.on('render_start', function(e) {
        nv.logs.startTime = +new Date();
    });

    nv.dispatch.on('render_end', function(e) {
        nv.logs.endTime = +new Date();
        nv.logs.totalTime = nv.logs.endTime - nv.logs.startTime;
        nv.log('total', nv.logs.totalTime); // used for development, to keep track of graph generation times
    });
}

// Logs all arguments, and returns the last so you can test things in place
// Note: in IE8 console.log is an object not a function, and if modernizr is used
// then calling Function.prototype.bind with with anything other than a function
// causes a TypeError to be thrown.
nv.log = function() {
    if (nv.dev && window.console && console.log && console.log.apply)
        console.log.apply(console, arguments);
    else if (nv.dev && window.console && typeof console.log == "function" && Function.prototype.bind) {
        var log = Function.prototype.bind.call(console.log, console);
        log.apply(console, arguments);
    }
    return arguments[arguments.length - 1];
};

// print console warning, should be used by deprecated functions
nv.deprecated = function(name, info) {
    if (console && console.warn) {
        console.warn('nvd3 warning: `' + name + '` has been deprecated. ', info || '');
    }
};

// The nv.render function is used to queue up chart rendering
// in non-blocking async functions.
// When all queued charts are done rendering, nv.dispatch.render_end is invoked.
nv.render = function render(step) {
    // number of graphs to generate in each timeout loop
    step = step || 1;

    nv.render.active = true;
    nv.dispatch.render_start();

    var renderLoop = function() {
        var chart, graph;

        for (var i = 0; i < step && (graph = nv.render.queue[i]); i++) {
            chart = graph.generate();
            if (typeof graph.callback == typeof(Function)) graph.callback(chart);
        }

        nv.render.queue.splice(0, i);

        if (nv.render.queue.length) {
            setTimeout(renderLoop);
        }
        else {
            nv.dispatch.render_end();
            nv.render.active = false;
        }
    };

    setTimeout(renderLoop);
};

nv.render.active = false;
nv.render.queue = [];

/*
Adds a chart to the async rendering queue. This method can take arguments in two forms:
nv.addGraph({
    generate: <Function>
    callback: <Function>
})

or

nv.addGraph(<generate Function>, <callback Function>)

The generate function should contain code that creates the NVD3 model, sets options
on it, adds data to an SVG element, and invokes the chart model. The generate function
should return the chart model.  See examples/lineChart.html for a usage example.

The callback function is optional, and it is called when the generate function completes.
*/
nv.addGraph = function(obj) {
    if (typeof arguments[0] === typeof(Function)) {
        obj = {generate: arguments[0], callback: arguments[1]};
    }

    nv.render.queue.push(obj);

    if (!nv.render.active) {
        nv.render();
    }
};

// Node/CommonJS exports
if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') {
  module.exports = nv;
}

if (typeof(window) !== 'undefined') {
  window.nv = nv;
}
/* Facade for queueing DOM write operations
 * with Fastdom (https://github.com/wilsonpage/fastdom)
 * if available.
 * This could easily be extended to support alternate
 * implementations in the future.
 */
nv.dom.write = function(callback) {
	if (window.fastdom !== undefined) {
		return fastdom.mutate(callback);
	}
	return callback();
};

/* Facade for queueing DOM read operations
 * with Fastdom (https://github.com/wilsonpage/fastdom)
 * if available.
 * This could easily be extended to support alternate
 * implementations in the future.
 */
nv.dom.read = function(callback) {
	if (window.fastdom !== undefined) {
		return fastdom.measure(callback);
	}
	return callback();
};
/* Utility class to handle creation of an interactive layer.
 This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch
 containing the X-coordinate. It can also render a vertical line where the mouse is located.

 dispatch.elementMousemove is the important event to latch onto.  It is fired whenever the mouse moves over
 the rectangle. The dispatch is given one object which contains the mouseX/Y location.
 It also has 'pointXValue', which is the conversion of mouseX to the x-axis scale.
 */
nv.interactiveGuideline = function() {
    "use strict";

    var margin = { left: 0, top: 0 } //Pass the chart's top and left magins. Used to calculate the mouseX/Y.
        ,   width = null
        ,   height = null
        ,   xScale = d3.scale.linear()
        ,   dispatch = d3.dispatch('elementMousemove', 'elementMouseout', 'elementClick', 'elementDblclick', 'elementMouseDown', 'elementMouseUp')
        ,   showGuideLine = true
        ,   svgContainer = null // Must pass the chart's svg, we'll use its mousemove event.
        ,   tooltip = nv.models.tooltip()
        ,   isMSIE =  window.ActiveXObject// Checkt if IE by looking for activeX. (excludes IE11)
    ;

    tooltip
        .duration(0)
        .hideDelay(0)
        .hidden(false);

    function layer(selection) {
        selection.each(function(data) {
            var container = d3.select(this);
            var availableWidth = (width || 960), availableHeight = (height || 400);
            var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer")
                .data([data]);
            var wrapEnter = wrap.enter()
                .append("g").attr("class", " nv-wrap nv-interactiveLineLayer");
            wrapEnter.append("g").attr("class","nv-interactiveGuideLine");

            if (!svgContainer) {
                return;
            }

            function mouseHandler() {
                var mouseX = d3.event.clientX - this.getBoundingClientRect().left;
                var mouseY = d3.event.clientY - this.getBoundingClientRect().top;

                var subtractMargin = true;
                var mouseOutAnyReason = false;
                if (isMSIE) {
                    /*
                     D3.js (or maybe SVG.getScreenCTM) has a nasty bug in Internet Explorer 10.
                     d3.mouse() returns incorrect X,Y mouse coordinates when mouse moving
                     over a rect in IE 10.
                     However, d3.event.offsetX/Y also returns the mouse coordinates
                     relative to the triggering <rect>. So we use offsetX/Y on IE.
                     */
                    mouseX = d3.event.offsetX;
                    mouseY = d3.event.offsetY;

                    /*
                     On IE, if you attach a mouse event listener to the <svg> container,
                     it will actually trigger it for all the child elements (like <path>, <circle>, etc).
                     When this happens on IE, the offsetX/Y is set to where ever the child element
                     is located.
                     As a result, we do NOT need to subtract margins to figure out the mouse X/Y
                     position under this scenario. Removing the line below *will* cause
                     the interactive layer to not work right on IE.
                     */
                    if(d3.event.target.tagName !== "svg") {
                        subtractMargin = false;
                    }

                    if (d3.event.target.className.baseVal.match("nv-legend")) {
                        mouseOutAnyReason = true;
                    }

                }

                if(subtractMargin) {
                    mouseX -= margin.left;
                    mouseY -= margin.top;
                }

                /* If mouseX/Y is outside of the chart's bounds,
                 trigger a mouseOut event.
                 */
                if (d3.event.type === 'mouseout'
                    || mouseX < 0 || mouseY < 0
                    || mouseX > availableWidth || mouseY > availableHeight
                    || (d3.event.relatedTarget && d3.event.relatedTarget.ownerSVGElement === undefined)
                    || mouseOutAnyReason
                    ) {

                    if (isMSIE) {
                        if (d3.event.relatedTarget
                            && d3.event.relatedTarget.ownerSVGElement === undefined
                            && (d3.event.relatedTarget.className === undefined
                                || d3.event.relatedTarget.className.match(tooltip.nvPointerEventsClass))) {

                            return;
                        }
                    }
                    dispatch.elementMouseout({
                        mouseX: mouseX,
                        mouseY: mouseY
                    });
                    layer.renderGuideLine(null); //hide the guideline
                    tooltip.hidden(true);
                    return;
                } else {
                    tooltip.hidden(false);
                }


                var scaleIsOrdinal = typeof xScale.rangeBands === 'function';
                var pointXValue = undefined;

                // Ordinal scale has no invert method
                if (scaleIsOrdinal) {
                    var elementIndex = d3.bisect(xScale.range(), mouseX) - 1;
                    // Check if mouseX is in the range band
                    if (xScale.range()[elementIndex] + xScale.rangeBand() >= mouseX) {
                        pointXValue = xScale.domain()[d3.bisect(xScale.range(), mouseX) - 1];
                    }
                    else {
                        dispatch.elementMouseout({
                            mouseX: mouseX,
                            mouseY: mouseY
                        });
                        layer.renderGuideLine(null); //hide the guideline
                        tooltip.hidden(true);
                        return;
                    }
                }
                else {
                    pointXValue = xScale.invert(mouseX);
                }

                dispatch.elementMousemove({
                    mouseX: mouseX,
                    mouseY: mouseY,
                    pointXValue: pointXValue
                });

                //If user double clicks the layer, fire a elementDblclick
                if (d3.event.type === "dblclick") {
                    dispatch.elementDblclick({
                        mouseX: mouseX,
                        mouseY: mouseY,
                        pointXValue: pointXValue
                    });
                }

                // if user single clicks the layer, fire elementClick
                if (d3.event.type === 'click') {
                    dispatch.elementClick({
                        mouseX: mouseX,
                        mouseY: mouseY,
                        pointXValue: pointXValue
                    });
                }

                // if user presses mouse down the layer, fire elementMouseDown
                if (d3.event.type === 'mousedown') {
                	dispatch.elementMouseDown({
                		mouseX: mouseX,
                		mouseY: mouseY,
                		pointXValue: pointXValue
                	});
                }

                // if user presses mouse down the layer, fire elementMouseUp
                if (d3.event.type === 'mouseup') {
                	dispatch.elementMouseUp({
                		mouseX: mouseX,
                		mouseY: mouseY,
                		pointXValue: pointXValue
                	});
                }
            }

            svgContainer
                .on("touchmove",mouseHandler)
                .on("mousemove",mouseHandler, true)
                .on("mouseout" ,mouseHandler,true)
                .on("mousedown" ,mouseHandler,true)
                .on("mouseup" ,mouseHandler,true)
                .on("dblclick" ,mouseHandler)
                .on("click", mouseHandler)
            ;

            layer.guideLine = null;
            //Draws a vertical guideline at the given X postion.
            layer.renderGuideLine = function(x) {
                if (!showGuideLine) return;
                if (layer.guideLine && layer.guideLine.attr("x1") === x) return;
                nv.dom.write(function() {
                    var line = wrap.select(".nv-interactiveGuideLine")
                        .selectAll("line")
                        .data((x != null) ? [nv.utils.NaNtoZero(x)] : [], String);
                    line.enter()
                        .append("line")
                        .attr("class", "nv-guideline")
                        .attr("x1", function(d) { return d;})
                        .attr("x2", function(d) { return d;})
                        .attr("y1", availableHeight)
                        .attr("y2",0);
                    line.exit().remove();
                });
            }
        });
    }

    layer.dispatch = dispatch;
    layer.tooltip = tooltip;

    layer.margin = function(_) {
        if (!arguments.length) return margin;
        margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
        margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
        return layer;
    };

    layer.width = function(_) {
        if (!arguments.length) return width;
        width = _;
        return layer;
    };

    layer.height = function(_) {
        if (!arguments.length) return height;
        height = _;
        return layer;
    };

    layer.xScale = function(_) {
        if (!arguments.length) return xScale;
        xScale = _;
        return layer;
    };

    layer.showGuideLine = function(_) {
        if (!arguments.length) return showGuideLine;
        showGuideLine = _;
        return layer;
    };

    layer.svgContainer = function(_) {
        if (!arguments.length) return svgContainer;
        svgContainer = _;
        return layer;
    };

    return layer;
};

/* Utility class that uses d3.bisect to find the index in a given array, where a search value can be inserted.
 This is different from normal bisectLeft; this function finds the nearest index to insert the search value.

 For instance, lets say your array is [1,2,3,5,10,30], and you search for 28.
 Normal d3.bisectLeft will return 4, because 28 is inserted after the number 10.  But interactiveBisect will return 5
 because 28 is closer to 30 than 10.

 Unit tests can be found in: interactiveBisectTest.html

 Has the following known issues:
 * Will not work if the data points move backwards (ie, 10,9,8,7, etc) or if the data points are in random order.
 * Won't work if there are duplicate x coordinate values.
 */
nv.interactiveBisect = function (values, searchVal, xAccessor) {
    "use strict";
    if (! (values instanceof Array)) {
        return null;
    }
    var _xAccessor;
    if (typeof xAccessor !== 'function') {
        _xAccessor = function(d) {
            return d.x;
        }
    } else {
        _xAccessor = xAccessor;
    }
    var _cmp = function(d, v) {
        // Accessors are no longer passed the index of the element along with
        // the element itself when invoked by d3.bisector.
        //
        // Starting at D3 v3.4.4, d3.bisector() started inspecting the
        // function passed to determine if it should consider it an accessor
        // or a comparator. This meant that accessors that take two arguments
        // (expecting an index as the second parameter) are treated as
        // comparators where the second argument is the search value against
        // which the first argument is compared.
        return _xAccessor(d) - v;
    };

    var bisect = d3.bisector(_cmp).left;
    var index = d3.max([0, bisect(values,searchVal) - 1]);
    var currentValue = _xAccessor(values[index]);

    if (typeof currentValue === 'undefined') {
        currentValue = index;
    }

    if (currentValue === searchVal) {
        return index; //found exact match
    }

    var nextIndex = d3.min([index+1, values.length - 1]);
    var nextValue = _xAccessor(values[nextIndex]);

    if (typeof nextValue === 'undefined') {
        nextValue = nextIndex;
    }

    if (Math.abs(nextValue - searchVal) >= Math.abs(currentValue - searchVal)) {
        return index;
    } else {
        return nextIndex
    }
};

/*
 Returns the index in the array "values" that is closest to searchVal.
 Only returns an index if searchVal is within some "threshold".
 Otherwise, returns null.
 */
nv.nearestValueIndex = function (values, searchVal, threshold) {
    "use strict";
    var yDistMax = Infinity, indexToHighlight = null;
    values.forEach(function(d,i) {
        var delta = Math.abs(searchVal - d);
        if ( d != null && delta <= yDistMax && delta < threshold) {
            yDistMax = delta;
            indexToHighlight = i;
        }
    });
    return indexToHighlight;
};

/* Model which can be instantiated to handle tooltip rendering.
 Example usage:
 var tip = nv.models.tooltip().gravity('w').distance(23)
 .data(myDataObject);

 tip();    //just invoke the returned function to render tooltip.
 */
nv.models.tooltip = function() {
    "use strict";

    /*
    Tooltip data. If data is given in the proper format, a consistent tooltip is generated.
    Example Format of data:
    {
        key: "Date",
        value: "August 2009",
        series: [
            {key: "Series 1", value: "Value 1", color: "#000"},
            {key: "Series 2", value: "Value 2", color: "#00f"}
        ]
    }
    */
    var id = "nvtooltip-" + Math.floor(Math.random() * 100000) // Generates a unique id when you create a new tooltip() object.
        ,   data = null
        ,   gravity = 'w'   // Can be 'n','s','e','w'. Determines how tooltip is positioned.
        ,   distance = 25 // Distance to offset tooltip from the mouse location.
        ,   snapDistance = 0   // Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect)
        ,   classes = null  // Attaches additional CSS classes to the tooltip DIV that is created.
        ,   hidden = true  // Start off hidden, toggle with hide/show functions below.
        ,   hideDelay = 200  // Delay (in ms) before the tooltip hides after calling hide().
        ,   tooltip = null // d3 select of the tooltip div.
        ,   lastPosition = { left: null, top: null } // Last position the tooltip was in.
        ,   enabled = true  // True -> tooltips are rendered. False -> don't render tooltips.
        ,   duration = 100 // Tooltip movement duration, in ms.
        ,   headerEnabled = true // If is to show the tooltip header.
        ,   nvPointerEventsClass = "nv-pointer-events-none" // CSS class to specify whether element should not have mouse events.
    ;

    // Format function for the tooltip values column.
    // d is value,
    // i is series index
    // p is point containing the value
    var valueFormatter = function(d, i, p) {
        return d;
    };

    // Format function for the tooltip header value.
    var headerFormatter = function(d) {
        return d;
    };

    var keyFormatter = function(d, i) {
        return d;
    };

    // By default, the tooltip model renders a beautiful table inside a DIV, returned as HTML
    // You can override this function if a custom tooltip is desired. For instance, you could directly manipulate
    // the DOM by accessing elem and returning false.
    var contentGenerator = function(d, elem) {
        if (d === null) {
            return '';
        }

        var table = d3.select(document.createElement("table"));
        if (headerEnabled) {
            var theadEnter = table.selectAll("thead")
                .data([d])
                .enter().append("thead");

            theadEnter.append("tr")
                .append("td")
                .attr("colspan", 3)
                .append("strong")
                .classed("x-value", true)
                .html(headerFormatter(d.value));
        }

        var tbodyEnter = table.selectAll("tbody")
            .data([d])
            .enter().append("tbody");

        var trowEnter = tbodyEnter.selectAll("tr")
                .data(function(p) { return p.series})
                .enter()
                .append("tr")
                .classed("highlight", function(p) { return p.highlight});

        trowEnter.append("td")
            .classed("legend-color-guide",true)
            .append("div")
            .style("background-color", function(p) { return p.color});

        trowEnter.append("td")
            .classed("key",true)
            .classed("total",function(p) { return !!p.total})
            .html(function(p, i) { return keyFormatter(p.key, i)});

        trowEnter.append("td")
            .classed("value",true)
            .html(function(p, i) { return valueFormatter(p.value, i, p) });

        trowEnter.filter(function (p,i) { return p.percent !== undefined }).append("td")
            .classed("percent", true)
            .html(function(p, i) { return "(" + d3.format('%')(p.percent) + ")" });

        trowEnter.selectAll("td").each(function(p) {
            if (p.highlight) {
                var opacityScale = d3.scale.linear().domain([0,1]).range(["#fff",p.color]);
                var opacity = 0.6;
                d3.select(this)
                    .style("border-bottom-color", opacityScale(opacity))
                    .style("border-top-color", opacityScale(opacity))
                ;
            }
        });

        var html = table.node().outerHTML;
        if (d.footer !== undefined)
            html += "<div class='footer'>" + d.footer + "</div>";
        return html;

    };

    /*
     Function that returns the position (relative to the viewport/document.body)
     the tooltip should be placed in.
     Should return: {
        left: <leftPos>,
        top: <topPos>
     }
     */
    var position = function() {
        var pos = {
            left: d3.event !== null ? d3.event.clientX : 0,
            top: d3.event !== null ? d3.event.clientY : 0
        };

        if(getComputedStyle(document.body).transform != 'none') {
            // Take the offset into account, as now the tooltip is relative
            // to document.body.
            var client = document.body.getBoundingClientRect();
            pos.left -= client.left;
            pos.top -= client.top;
        }

        return pos;
    };

    var dataSeriesExists = function(d) {
        if (d && d.series) {
            if (nv.utils.isArray(d.series)) {
                return true;
            }
            // if object, it's okay just convert to array of the object
            if (nv.utils.isObject(d.series)) {
                d.series = [d.series];
                return true;
            }
        }
        return false;
    };

    // Calculates the gravity offset of the tooltip. Parameter is position of tooltip
    // relative to the viewport.
    var calcGravityOffset = function(pos) {
        var height = tooltip.node().offsetHeight,
            width = tooltip.node().offsetWidth,
            clientWidth = document.documentElement.clientWidth, // Don't want scrollbars.
            clientHeight = document.documentElement.clientHeight, // Don't want scrollbars.
            left, top, tmp;

        // calculate position based on gravity
        switch (gravity) {
            case 'e':
                left = - width - distance;
                top = - (height / 2);
                if(pos.left + left < 0) left = distance;
                if((tmp = pos.top + top) < 0) top -= tmp;
                if((tmp = pos.top + top + height) > clientHeight) top -= tmp - clientHeight;
                break;
            case 'w':
                left = distance;
                top = - (height / 2);
                if (pos.left + left + width > clientWidth) left = - width - distance;
                if ((tmp = pos.top + top) < 0) top -= tmp;
                if ((tmp = pos.top + top + height) > clientHeight) top -= tmp - clientHeight;
                break;
            case 'n':
                left = - (width / 2) - 5; // - 5 is an approximation of the mouse's height.
                top = distance;
                if (pos.top + top + height > clientHeight) top = - height - distance;
                if ((tmp = pos.left + left) < 0) left -= tmp;
                if ((tmp = pos.left + left + width) > clientWidth) left -= tmp - clientWidth;
                break;
            case 's':
                left = - (width / 2);
                top = - height - distance;
                if (pos.top + top < 0) top = distance;
                if ((tmp = pos.left + left) < 0) left -= tmp;
                if ((tmp = pos.left + left + width) > clientWidth) left -= tmp - clientWidth;
                break;
            case 'center':
                left = - (width / 2);
                top = - (height / 2);
                break;
            default:
                left = 0;
                top = 0;
                break;
        }

        return { 'left': left, 'top': top };
    };

    /*
     Positions the tooltip in the correct place, as given by the position() function.
     */
    var positionTooltip = function() {
        nv.dom.read(function() {
            var pos = position(),
                gravityOffset = calcGravityOffset(pos),
                left = pos.left + gravityOffset.left,
                top = pos.top + gravityOffset.top;

            // delay hiding a bit to avoid flickering
            if (hidden) {
                tooltip
                    .interrupt()
                    .transition()
                    .delay(hideDelay)
                    .duration(0)
                    .style('opacity', 0);
            } else {
                // using tooltip.style('transform') returns values un-usable for tween
                var old_translate = 'translate(' + lastPosition.left + 'px, ' + lastPosition.top + 'px)';
                var new_translate = 'translate(' + Math.round(left) + 'px, ' + Math.round(top) + 'px)';
                var translateInterpolator = d3.interpolateString(old_translate, new_translate);
                var is_hidden = tooltip.style('opacity') < 0.1;

                tooltip
                    .interrupt() // cancel running transitions
                    .transition()
                    .duration(is_hidden ? 0 : duration)
                    // using tween since some versions of d3 can't auto-tween a translate on a div
                    .styleTween('transform', function (d) {
                        return translateInterpolator;
                    }, 'important')
                    // Safari has its own `-webkit-transform` and does not support `transform`
                    .styleTween('-webkit-transform', function (d) {
                        return translateInterpolator;
                    })
                    .style('-ms-transform', new_translate)
                    .style('opacity', 1);
            }

            lastPosition.left = left;
            lastPosition.top = top;
        });
    };

    // Creates new tooltip container, or uses existing one on DOM.
    function initTooltip() {
        if (!tooltip || !tooltip.node()) {
            // Create new tooltip div if it doesn't exist on DOM.

            var data = [1];
            tooltip = d3.select(document.body).selectAll('#'+id).data(data);

            tooltip.enter().append('div')
                   .attr("class", "nvtooltip " + (classes ? classes : "xy-tooltip"))
                   .attr("id", id)
                   .style("top", 0).style("left", 0)
                   .style('opacity', 0)
                   .style('position', 'absolute')
                   .selectAll("div, table, td, tr").classed(nvPointerEventsClass, true)
                   .classed(nvPointerEventsClass, true);

            tooltip.exit().remove()
        }
    }

    // Draw the tooltip onto the DOM.
    function nvtooltip() {
        if (!enabled) return;
        if (!dataSeriesExists(data)) return;

        nv.dom.write(function () {
            initTooltip();
            // Generate data and set it into tooltip.
            // Bonus - If you override contentGenerator and return false, you can use something like
            //         Angular, React or Knockout to bind the data for your tooltip directly to the DOM.
            var newContent = contentGenerator(data, tooltip.node());
            if (newContent) {
                tooltip.node().innerHTML = newContent;
            }

            positionTooltip();
        });

        return nvtooltip;
    }

    nvtooltip.nvPointerEventsClass = nvPointerEventsClass;
    nvtooltip.options = nv.utils.optionsFunc.bind(nvtooltip);

    nvtooltip._options = Object.create({}, {
        // simple read/write options
        duration: {get: function(){return duration;}, set: function(_){duration=_;}},
        gravity: {get: function(){return gravity;}, set: function(_){gravity=_;}},
        distance: {get: function(){return distance;}, set: function(_){distance=_;}},
        snapDistance: {get: function(){return snapDistance;}, set: function(_){snapDistance=_;}},
        classes: {get: function(){return classes;}, set: function(_){classes=_;}},
        enabled: {get: function(){return enabled;}, set: function(_){enabled=_;}},
        hideDelay: {get: function(){return hideDelay;}, set: function(_){hideDelay=_;}},
        contentGenerator: {get: function(){return contentGenerator;}, set: function(_){contentGenerator=_;}},
        valueFormatter: {get: function(){return valueFormatter;}, set: function(_){valueFormatter=_;}},
        headerFormatter: {get: function(){return headerFormatter;}, set: function(_){headerFormatter=_;}},
        keyFormatter: {get: function(){return keyFormatter;}, set: function(_){keyFormatter=_;}},
        headerEnabled: {get: function(){return headerEnabled;}, set: function(_){headerEnabled=_;}},
        position: {get: function(){return position;}, set: function(_){position=_;}},

        // Deprecated options
        chartContainer: {get: function(){return document.body;}, set: function(_){
            // deprecated after 1.8.3
            nv.deprecated('chartContainer', 'feature removed after 1.8.3');
        }},
        fixedTop: {get: function(){return null;}, set: function(_){
            // deprecated after 1.8.1
            nv.deprecated('fixedTop', 'feature removed after 1.8.1');
        }},
        offset: {get: function(){return {left: 0, top: 0};}, set: function(_){
            // deprecated after 1.8.1
            nv.deprecated('offset', 'use chart.tooltip.distance() instead');
        }},

        // options with extra logic
        hidden: {get: function(){return hidden;}, set: function(_){
            if (hidden != _) {
                hidden = !!_;
                nvtooltip();
            }
        }},
        data: {get: function(){return data;}, set: function(_){
            // if showing a single data point, adjust data format with that
            if (_.point) {
                _.value = _.point.x;
                _.series = _.series || {};
                _.series.value = _.point.y;
                _.series.color = _.point.color || _.series.color;
            }
            data = _;
        }},

        // read only properties
        node: {get: function(){return tooltip.node();}, set: function(_){}},
        id: {get: function(){return id;}, set: function(_){}}
    });

    nv.utils.initOptions(nvtooltip);
    return nvtooltip;
};


/*
Gets the browser window size

Returns object with height and width properties
 */
nv.utils.windowSize = function() {
    // Sane defaults
    var size = {width: 640, height: 480};

    // Most recent browsers use
    if (window.innerWidth && window.innerHeight) {
        size.width = window.innerWidth;
        size.height = window.innerHeight;
        return (size);
    }

    // IE can use depending on mode it is in
    if (document.compatMode=='CSS1Compat' &&
        document.documentElement &&
        document.documentElement.offsetWidth ) {

        size.width = document.documentElement.offsetWidth;
        size.height = document.documentElement.offsetHeight;
        return (size);
    }

    // Earlier IE uses Doc.body
    if (document.body && document.body.offsetWidth) {
        size.width = document.body.offsetWidth;
        size.height = document.body.offsetHeight;
        return (size);
    }

    return (size);
};


/* handle dumb browser quirks...  isinstance breaks if you use frames
typeof returns 'object' for null, NaN is a number, etc.
 */
nv.utils.isArray = Array.isArray;
nv.utils.isObject = function(a) {
    return a !== null && typeof a === 'object';
};
nv.utils.isFunction = function(a) {
    return typeof a === 'function';
};
nv.utils.isDate = function(a) {
    return toString.call(a) === '[object Date]';
};
nv.utils.isNumber = function(a) {
    return !isNaN(a) && typeof a === 'number';
};


/*
Binds callback function to run when window is resized
 */
nv.utils.windowResize = function(handler) {
    if (window.addEventListener) {
        window.addEventListener('resize', handler);
    } else {
        nv.log("ERROR: Failed to bind to window.resize with: ", handler);
    }
    // return object with clear function to remove the single added callback.
    return {
        callback: handler,
        clear: function() {
            window.removeEventListener('resize', handler);
        }
    }
};


/*
Backwards compatible way to implement more d3-like coloring of graphs.
Can take in nothing, an array, or a function/scale
To use a normal scale, get the range and pass that because we must be able
to take two arguments and use the index to keep backward compatibility
*/
nv.utils.getColor = function(color) {
    //if you pass in nothing, get default colors back
    if (color === undefined) {
        return nv.utils.defaultColor();

    //if passed an array, turn it into a color scale
    } else if(nv.utils.isArray(color)) {
        var color_scale = d3.scale.ordinal().range(color);
        return function(d, i) {
            var key = i === undefined ? d : i;
            return d.color || color_scale(key);
        };

    //if passed a function or scale, return it, or whatever it may be
    //external libs, such as angularjs-nvd3-directives use this
    } else {
        //can't really help it if someone passes rubbish as color
        return color;
    }
};


/*
Default color chooser uses a color scale of 20 colors from D3
 https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors
 */
nv.utils.defaultColor = function() {
    // get range of the scale so we'll turn it into our own function.
    return nv.utils.getColor(d3.scale.category20().range());
};


/*
Returns a color function that takes the result of 'getKey' for each series and
looks for a corresponding color from the dictionary
*/
nv.utils.customTheme = function(dictionary, getKey, defaultColors) {
    // use default series.key if getKey is undefined
    getKey = getKey || function(series) { return series.key };
    defaultColors = defaultColors || d3.scale.category20().range();

    // start at end of default color list and walk back to index 0
    var defIndex = defaultColors.length;

    return function(series, index) {
        var key = getKey(series);
        if (nv.utils.isFunction(dictionary[key])) {
            return dictionary[key]();
        } else if (dictionary[key] !== undefined) {
            return dictionary[key];
        } else {
            // no match in dictionary, use a default color
            if (!defIndex) {
                // used all the default colors, start over
                defIndex = defaultColors.length;
            }
            defIndex = defIndex - 1;
            return defaultColors[defIndex];
        }
    };
};


/*
From the PJAX example on d3js.org, while this is not really directly needed
it's a very cool method for doing pjax, I may expand upon it a little bit,
open to suggestions on anything that may be useful
*/
nv.utils.pjax = function(links, content) {

    var load = function(href) {
        d3.html(href, function(fragment) {
            var target = d3.select(content).node();
            target.parentNode.replaceChild(
                d3.select(fragment).select(content).node(),
                target);
            nv.utils.pjax(links, content);
        });
    };

    d3.selectAll(links).on("click", function() {
        history.pushState(this.href, this.textContent, this.href);
        load(this.href);
        d3.event.preventDefault();
    });

    d3.select(window).on("popstate", function() {
        if (d3.event.state) {
            load(d3.event.state);
        }
    });
};


/*
For when we want to approximate the width in pixels for an SVG:text element.
Most common instance is when the element is in a display:none; container.
Forumla is : text.length * font-size * constant_factor
*/
nv.utils.calcApproxTextWidth = function (svgTextElem) {
    if (nv.utils.isFunction(svgTextElem.style) && nv.utils.isFunction(svgTextElem.text)) {
        var fontSize = parseInt(svgTextElem.style("font-size").replace("px",""), 10);
        var textLength = svgTextElem.text().length;
        return nv.utils.NaNtoZero(textLength * fontSize * 0.5);
    }
    return 0;
};


/*
Numbers that are undefined, null or NaN, convert them to zeros.
*/
nv.utils.NaNtoZero = function(n) {
    if (!nv.utils.isNumber(n)
        || isNaN(n)
        || n === null
        || n === Infinity
        || n === -Infinity) {

        return 0;
    }
    return n;
};

/*
Add a way to watch for d3 transition ends to d3
*/
d3.selection.prototype.watchTransition = function(renderWatch){
    var args = [this].concat([].slice.call(arguments, 1));
    return renderWatch.transition.apply(renderWatch, args);
};


/*
Helper object to watch when d3 has rendered something
*/
nv.utils.renderWatch = function(dispatch, duration) {
    if (!(this instanceof nv.utils.renderWatch)) {
        return new nv.utils.renderWatch(dispatch, duration);
    }

    var _duration = duration !== undefined ? duration : 250;
    var renderStack = [];
    var self = this;

    this.models = function(models) {
        models = [].slice.call(arguments, 0);
        models.forEach(function(model){
            model.__rendered = false;
            (function(m){
                m.dispatch.on('renderEnd', function(arg){
                    m.__rendered = true;
                    self.renderEnd('model');
                });
            })(model);

            if (renderStack.indexOf(model) < 0) {
                renderStack.push(model);
            }
        });
    return this;
    };

    this.reset = function(duration) {
        if (duration !== undefined) {
            _duration = duration;
        }
        renderStack = [];
    };

    this.transition = function(selection, args, duration) {
        args = arguments.length > 1 ? [].slice.call(arguments, 1) : [];

        if (args.length > 1) {
            duration = args.pop();
        } else {
            duration = _duration !== undefined ? _duration : 250;
        }
        selection.__rendered = false;

        if (renderStack.indexOf(selection) < 0) {
            renderStack.push(selection);
        }

        if (duration === 0) {
            selection.__rendered = true;
            selection.delay = function() { return this; };
            selection.duration = function() { return this; };
            return selection;
        } else {
            if (selection.length === 0) {
                selection.__rendered = true;
            } else if (selection.every( function(d){ return !d.length; } )) {
                selection.__rendered = true;
            } else {
                selection.__rendered = false;
            }

            var n = 0;
            return selection
                .transition()
                .duration(duration)
                .each(function(){ ++n; })
                .each('end', function(d, i) {
                    if (--n === 0) {
                        selection.__rendered = true;
                        self.renderEnd.apply(this, args);
                    }
                });
        }
    };

    this.renderEnd = function() {
        if (renderStack.every( function(d){ return d.__rendered; } )) {
            renderStack.forEach( function(d){ d.__rendered = false; });
            dispatch.renderEnd.apply(this, arguments);
        }
    }

};


/*
Takes multiple objects and combines them into the first one (dst)
example:  nv.utils.deepExtend({a: 1}, {a: 2, b: 3}, {c: 4});
gives:  {a: 2, b: 3, c: 4}
*/
nv.utils.deepExtend = function(dst){
    var sources = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
    sources.forEach(function(source) {
        for (var key in source) {
            var isArray = nv.utils.isArray(dst[key]);
            var isObject = nv.utils.isObject(dst[key]);
            var srcObj = nv.utils.isObject(source[key]);

            if (isObject && !isArray && srcObj) {
                nv.utils.deepExtend(dst[key], source[key]);
            } else {
                dst[key] = source[key];
            }
        }
    });
};


/*
state utility object, used to track d3 states in the models
*/
nv.utils.state = function(){
    if (!(this instanceof nv.utils.state)) {
        return new nv.utils.state();
    }
    var state = {};
    var _self = this;
    var _setState = function(){};
    var _getState = function(){ return {}; };
    var init = null;
    var changed = null;

    this.dispatch = d3.dispatch('change', 'set');

    this.dispatch.on('set', function(state){
        _setState(state, true);
    });

    this.getter = function(fn){
        _getState = fn;
        return this;
    };

    this.setter = function(fn, callback) {
        if (!callback) {
            callback = function(){};
        }
        _setState = function(state, update){
            fn(state);
            if (update) {
                callback();
            }
        };
        return this;
    };

    this.init = function(state){
        init = init || {};
        nv.utils.deepExtend(init, state);
    };

    var _set = function(){
        var settings = _getState();

        if (JSON.stringify(settings) === JSON.stringify(state)) {
            return false;
        }

        for (var key in settings) {
            if (state[key] === undefined) {
                state[key] = {};
            }
            state[key] = settings[key];
            changed = true;
        }
        return true;
    };

    this.update = function(){
        if (init) {
            _setState(init, false);
            init = null;
        }
        if (_set.call(this)) {
            this.dispatch.change(state);
        }
    };

};


/*
Snippet of code you can insert into each nv.models.* to give you the ability to
do things like:
chart.options({
  showXAxis: true,
  tooltips: true
});

To enable in the chart:
chart.options = nv.utils.optionsFunc.bind(chart);
*/
nv.utils.optionsFunc = function(args) {
    if (args) {
        d3.map(args).forEach((function(key,value) {
            if (nv.utils.isFunction(this[key])) {
                this[key](value);
            }
        }).bind(this));
    }
    return this;
};


/*
numTicks:  requested number of ticks
data:  the chart data

returns the number of ticks to actually use on X axis, based on chart data
to avoid duplicate ticks with the same value
*/
nv.utils.calcTicksX = function(numTicks, data) {
    // find max number of values from all data streams
    var numValues = 1;
    var i = 0;
    for (i; i < data.length; i += 1) {
        var stream_len = data[i] && data[i].values ? data[i].values.length : 0;
        numValues = stream_len > numValues ? stream_len : numValues;
    }
    nv.log("Requested number of ticks: ", numTicks);
    nv.log("Calculated max values to be: ", numValues);
    // make sure we don't have more ticks than values to avoid duplicates
    numTicks = numTicks > numValues ? numTicks = numValues - 1 : numTicks;
    // make sure we have at least one tick
    numTicks = numTicks < 1 ? 1 : numTicks;
    // make sure it's an integer
    numTicks = Math.floor(numTicks);
    nv.log("Calculating tick count as: ", numTicks);
    return numTicks;
};


/*
returns number of ticks to actually use on Y axis, based on chart data
*/
nv.utils.calcTicksY = function(numTicks, data) {
    // currently uses the same logic but we can adjust here if needed later
    return nv.utils.calcTicksX(numTicks, data);
};


/*
Add a particular option from an options object onto chart
Options exposed on a chart are a getter/setter function that returns chart
on set to mimic typical d3 option chaining, e.g. svg.option1('a').option2('b');

option objects should be generated via Object.create() to provide
the option of manipulating data via get/set functions.
*/
nv.utils.initOption = function(chart, name) {
    // if it's a call option, just call it directly, otherwise do get/set
    if (chart._calls && chart._calls[name]) {
        chart[name] = chart._calls[name];
    } else {
        chart[name] = function (_) {
            if (!arguments.length) return chart._options[name];
            chart._overrides[name] = true;
            chart._options[name] = _;
            return chart;
        };
        // calling the option as _option will ignore if set by option already
        // so nvd3 can set options internally but the stop if set manually
        chart['_' + name] = function(_) {
            if (!arguments.length) return chart._options[name];
            if (!chart._overrides[name]) {
                chart._options[name] = _;
            }
            return chart;
        }
    }
};


/*
Add all options in an options object to the chart
*/
nv.utils.initOptions = function(chart) {
    chart._overrides = chart._overrides || {};
    var ops = Object.getOwnPropertyNames(chart._options || {});
    var calls = Object.getOwnPropertyNames(chart._calls || {});
    ops = ops.concat(calls);
    for (var i in ops) {
        nv.utils.initOption(chart, ops[i]);
    }
};


/*
Inherit options from a D3 object
d3.rebind makes calling the function on target actually call it on source
Also use _d3options so we can track what we inherit for documentation and chained inheritance
*/
nv.utils.inheritOptionsD3 = function(target, d3_source, oplist) {
    target._d3options = oplist.concat(target._d3options || []);
    // Find unique d3 options (string) and update d3options
    target._d3options = (target._d3options || []).filter(function(item, i, ar){ return ar.indexOf(item) === i; });
    oplist.unshift(d3_source);
    oplist.unshift(target);
    d3.rebind.apply(this, oplist);
};


/*
Remove duplicates from an array
*/
nv.utils.arrayUnique = function(a) {
    return a.sort().filter(function(item, pos) {
        return !pos || item != a[pos - 1];
    });
};


/*
Keeps a list of custom symbols to draw from in addition to d3.svg.symbol
Necessary since d3 doesn't let you extend its list -_-
Add new symbols by doing nv.utils.symbols.set('name', function(size){...});
*/
nv.utils.symbolMap = d3.map();


/*
Replaces d3.svg.symbol so that we can look both there and our own map
 */
nv.utils.symbol = function() {
    var type,
        size = 64;
    function symbol(d,i) {
        var t = type.call(this,d,i);
        var s = size.call(this,d,i);
        if (d3.svg.symbolTypes.indexOf(t) !== -1) {
            return d3.svg.symbol().type(t).size(s)();
        } else {
            return nv.utils.symbolMap.get(t)(s);
        }
    }
    symbol.type = function(_) {
        if (!arguments.length) return type;
        type = d3.functor(_);
        return symbol;
    };
    symbol.size = function(_) {
        if (!arguments.length) return size;
        size = d3.functor(_);
        return symbol;
    };
    return symbol;
};


/*
Inherit option getter/setter functions from source to target
d3.rebind makes calling the function on target actually call it on source
Also track via _inherited and _d3options so we can track what we inherit
for documentation generation purposes and chained inheritance
*/
nv.utils.inheritOptions = function(target, source) {
    // inherit all the things
    var ops = Object.getOwnPropertyNames(source._options || {});
    var calls = Object.getOwnPropertyNames(source._calls || {});
    var inherited = source._inherited || [];
    var d3ops = source._d3options || [];
    var args = ops.concat(calls).concat(inherited).concat(d3ops);
    args.unshift(source);
    args.unshift(target);
    d3.rebind.apply(this, args);
    // pass along the lists to keep track of them, don't allow duplicates
    target._inherited = nv.utils.arrayUnique(ops.concat(calls).concat(inherited).concat(ops).concat(target._inherited || []));
    target._d3options = nv.utils.arrayUnique(d3ops.concat(target._d3options || []));
};


/*
Runs common initialize code on the svg before the chart builds
*/
nv.utils.initSVG = function(svg) {
    svg.classed({'nvd3-svg':true});
};


/*
Sanitize and provide default for the container height.
*/
nv.utils.sanitizeHeight = function(height, container) {
    return (height || parseInt(container.style('height'), 10) || 400);
};


/*
Sanitize and provide default for the container width.
*/
nv.utils.sanitizeWidth = function(width, container) {
    return (width || parseInt(container.style('width'), 10) || 960);
};


/*
Calculate the available height for a chart.
*/
nv.utils.availableHeight = function(height, container, margin) {
    return Math.max(0,nv.utils.sanitizeHeight(height, container) - margin.top - margin.bottom);
};

/*
Calculate the available width for a chart.
*/
nv.utils.availableWidth = function(width, container, margin) {
    return Math.max(0,nv.utils.sanitizeWidth(width, container) - margin.left - margin.right);
};

/*
Clear any rendered chart components and display a chart's 'noData' message
*/
nv.utils.noData = function(chart, container) {
    var opt = chart.options(),
        margin = opt.margin(),
        noData = opt.noData(),
        data = (noData == null) ? ["No Data Available."] : [noData],
        height = nv.utils.availableHeight(null, container, margin),
        width = nv.utils.availableWidth(null, container, margin),
        x = margin.left + width/2,
        y = margin.top + height/2;

    //Remove any previously created chart components
    container.selectAll('g').remove();

    var noDataText = container.selectAll('.nv-noData').data(data);

    noDataText.enter().append('text')
        .attr('class', 'nvd3 nv-noData')
        .attr('dy', '-.7em')
        .style('text-anchor', 'middle');

    noDataText
        .attr('x', x)
        .attr('y', y)
        .text(function(t){ return t; });
};

/*
 Wrap long labels.
 */
nv.utils.wrapTicks = function (text, width) {
    text.each(function() {
        var text = d3.select(this),
            words = text.text().split(/\s+/).reverse(),
            word,
            line = [],
            lineNumber = 0,
            lineHeight = 1.1,
            y = text.attr("y"),
            dy = parseFloat(text.attr("dy")),
            tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
        while (word = words.pop()) {
            line.push(word);
            tspan.text(line.join(" "));
            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(" "));
                line = [word];
                tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
            }
        }
    });
};

/*
Check equality of 2 array
*/
nv.utils.arrayEquals = function (array1, array2) {
    if (array1 === array2)
        return true;

    if (!array1 || !array2)
        return false;

    // compare lengths - can save a lot of time
    if (array1.length != array2.length)
        return false;

    for (var i = 0,
        l = array1.length; i < l; i++) {
        // Check if we have nested arrays
        if (array1[i] instanceof Array && array2[i] instanceof Array) {
            // recurse into the nested arrays
            if (!nv.arrayEquals(array1[i], array2[i]))
                return false;
        } else if (array1[i] != array2[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
};

/*
 Check if a point within an arc
 */
nv.utils.pointIsInArc = function(pt, ptData, d3Arc) {
    // Center of the arc is assumed to be 0,0
    // (pt.x, pt.y) are assumed to be relative to the center
    var r1 = d3Arc.innerRadius()(ptData), // Note: Using the innerRadius
      r2 = d3Arc.outerRadius()(ptData),
      theta1 = d3Arc.startAngle()(ptData),
      theta2 = d3Arc.endAngle()(ptData);

    var dist = pt.x * pt.x + pt.y * pt.y,
      angle = Math.atan2(pt.x, -pt.y); // Note: different coordinate system.

    angle = (angle < 0) ? (angle + Math.PI * 2) : angle;

    return (r1 * r1 <= dist) && (dist <= r2 * r2) &&
      (theta1 <= angle) && (angle <= theta2);
};

nv.models.axis = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var axis = d3.svg.axis();
    var scale = d3.scale.linear();

    var margin = {top: 0, right: 0, bottom: 0, left: 0}
        , width = 75 //only used for tickLabel currently
        , height = 60 //only used for tickLabel currently
        , axisLabelText = null
        , showMaxMin = true //TODO: showMaxMin should be disabled on all ordinal scaled axes
        , rotateLabels = 0
        , rotateYLabel = true
        , staggerLabels = false
        , isOrdinal = false
        , ticks = null
        , axisLabelDistance = 0
        , fontSize = undefined
        , duration = 250
        , dispatch = d3.dispatch('renderEnd')
        , tickFormatMaxMin
        ;
    axis
        .scale(scale)
        .orient('bottom')
        .tickFormat(function(d) { return d })
    ;

    //============================================================
    // Private Variables
    //------------------------------------------------------------

    var scale0;
    var renderWatch = nv.utils.renderWatch(dispatch, duration);

    function chart(selection) {
        renderWatch.reset();
        selection.each(function(data) {
            var container = d3.select(this);
            nv.utils.initSVG(container);

            // Setup containers and skeleton of chart
            var wrap = container.selectAll('g.nv-wrap.nv-axis').data([data]);
            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-axis');
            var gEnter = wrapEnter.append('g');
            var g = wrap.select('g');

            if (ticks !== null)
                axis.ticks(ticks);
            else if (axis.orient() == 'top' || axis.orient() == 'bottom')
                axis.ticks(Math.abs(scale.range()[1] - scale.range()[0]) / 100);

            //TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component
            g.watchTransition(renderWatch, 'axis').call(axis);

            scale0 = scale0 || axis.scale();

            var fmt = axis.tickFormat();
            if (fmt == null) {
                fmt = scale0.tickFormat();
            }

            var axisLabel = g.selectAll('text.nv-axislabel')
                .data([axisLabelText || null]);
            axisLabel.exit().remove();

            //only skip when fontSize is undefined so it can be cleared with a null or blank string
            if (fontSize !== undefined) {
                g.selectAll('g').select("text").style('font-size', fontSize);
            }

            var xLabelMargin;
            var axisMaxMin;
            var w;
            switch (axis.orient()) {
                case 'top':
                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
                  w = 0;
                  if (scale.range().length === 1) {
                    w = isOrdinal ? scale.range()[0] * 2 + scale.rangeBand() : 0;
                  } else if (scale.range().length === 2) {
                    w = isOrdinal ? scale.range()[0] + scale.range()[1] + scale.rangeBand() : scale.range()[1];
                  } else if ( scale.range().length > 2){
                    w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]);
                  };
                    axisLabel
                        .attr('text-anchor', 'middle')
                        .attr('y', 0)
                        .attr('x', w/2);
                    if (showMaxMin) {
                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
                            .data(scale.domain());
                        axisMaxMin.enter().append('g').attr('class',function(d,i){
                                return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ')
                        }).append('text');
                        axisMaxMin.exit().remove();
                        axisMaxMin
                            .attr('transform', function(d,i) {
                                return 'translate(' + nv.utils.NaNtoZero(scale(d)) + ',0)'
                            })
                            .select('text')
                            .attr('dy', '-0.5em')
                            .attr('y', -axis.tickPadding())
                            .attr('text-anchor', 'middle')
                            .text(function(d,i) {
                                var formatter = tickFormatMaxMin || fmt;
                                var v = formatter(d);
                                return ('' + v).match('NaN') ? '' : v;
                            });
                        axisMaxMin.watchTransition(renderWatch, 'min-max top')
                            .attr('transform', function(d,i) {
                                return 'translate(' + nv.utils.NaNtoZero(scale.range()[i]) + ',0)'
                            });
                    }
                    break;
                case 'bottom':
                    xLabelMargin = axisLabelDistance + 36;
                    var maxTextWidth = 30;
                    var textHeight = 0;
                    var xTicks = g.selectAll('g').select("text");
                    var rotateLabelsRule = '';
                    if (rotateLabels%360) {
                        //Reset transform on ticks so textHeight can be calculated correctly
                        xTicks.attr('transform', '');
                        //Calculate the longest xTick width
                        xTicks.each(function(d,i){
                            var box = this.getBoundingClientRect();
                            var width = box.width;
                            textHeight = box.height;
                            if(width > maxTextWidth) maxTextWidth = width;
                        });
                        rotateLabelsRule = 'rotate(' + rotateLabels + ' 0,' + (textHeight/2 + axis.tickPadding()) + ')';
                        //Convert to radians before calculating sin. Add 30 to margin for healthy padding.
                        var sin = Math.abs(Math.sin(rotateLabels*Math.PI/180));
                        xLabelMargin = (sin ? sin*maxTextWidth : maxTextWidth)+30;
                        //Rotate all xTicks
                        xTicks
                            .attr('transform', rotateLabelsRule)
                            .style('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end');
                    } else {
                        if (staggerLabels) {
                            xTicks
                                .attr('transform', function(d,i) {
                                    return 'translate(0,' + (i % 2 == 0 ? '0' : '12') + ')'
                                });
                        } else {
                            xTicks.attr('transform', "translate(0,0)");
                        }
                    }
                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
                    w = 0;
                    if (scale.range().length === 1) {
                        w = isOrdinal ? scale.range()[0] * 2 + scale.rangeBand() : 0;
                    } else if (scale.range().length === 2) {
                        w = isOrdinal ? scale.range()[0] + scale.range()[1] + scale.rangeBand() : scale.range()[1];
                    } else if ( scale.range().length > 2){
                        w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]);
                    };
                    axisLabel
                        .attr('text-anchor', 'middle')
                        .attr('y', xLabelMargin)
                        .attr('x', w/2);
                    if (showMaxMin) {
                        //if (showMaxMin && !isOrdinal) {
                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
                            //.data(scale.domain())
                            .data([scale.domain()[0], scale.domain()[scale.domain().length - 1]]);
                        axisMaxMin.enter().append('g').attr('class',function(d,i){
                                return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ')
                        }).append('text');
                        axisMaxMin.exit().remove();
                        axisMaxMin
                            .attr('transform', function(d,i) {
                                return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)'
                            })
                            .select('text')
                            .attr('dy', '.71em')
                            .attr('y', axis.tickPadding())
                            .attr('transform', rotateLabelsRule)
                            .style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle')
                            .text(function(d,i) {
                                var formatter = tickFormatMaxMin || fmt;
                                var v = formatter(d);
                                return ('' + v).match('NaN') ? '' : v;
                            });
                        axisMaxMin.watchTransition(renderWatch, 'min-max bottom')
                            .attr('transform', function(d,i) {
                                return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)'
                            });
                    }

                    break;
                case 'right':
                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
                    axisLabel
                        .style('text-anchor', rotateYLabel ? 'middle' : 'begin')
                        .attr('transform', rotateYLabel ? 'rotate(90)' : '')
                        .attr('y', rotateYLabel ? (-Math.max(margin.right, width) + 12 - (axisLabelDistance || 0)) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
                        .attr('x', rotateYLabel ? (d3.max(scale.range()) / 2) : axis.tickPadding());
                    if (showMaxMin) {
                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
                            .data(scale.domain());
                       	axisMaxMin.enter().append('g').attr('class',function(d,i){
                                return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ')
                        }).append('text')
                            .style('opacity', 0);
                        axisMaxMin.exit().remove();
                        axisMaxMin
                            .attr('transform', function(d,i) {
                                return 'translate(0,' + nv.utils.NaNtoZero(scale(d)) + ')'
                            })
                            .select('text')
                            .attr('dy', '.32em')
                            .attr('y', 0)
                            .attr('x', axis.tickPadding())
                            .style('text-anchor', 'start')
                            .text(function(d, i) {
                                var formatter = tickFormatMaxMin || fmt;
                                var v = formatter(d);
                                return ('' + v).match('NaN') ? '' : v;
                            });
                        axisMaxMin.watchTransition(renderWatch, 'min-max right')
                            .attr('transform', function(d,i) {
                                return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')'
                            })
                            .select('text')
                            .style('opacity', 1);
                    }
                    break;
                case 'left':
                    /*
                     //For dynamically placing the label. Can be used with dynamically-sized chart axis margins
                     var yTicks = g.selectAll('g').select("text");
                     yTicks.each(function(d,i){
                     var labelPadding = this.getBoundingClientRect().width + axis.tickPadding() + 16;
                     if(labelPadding > width) width = labelPadding;
                     });
                     */
                    axisLabel.enter().append('text').attr('class', 'nv-axislabel');
                    axisLabel
                        .style('text-anchor', rotateYLabel ? 'middle' : 'end')
                        .attr('transform', rotateYLabel ? 'rotate(-90)' : '')
                        .attr('y', rotateYLabel ? (-Math.max(margin.left, width) + 25 - (axisLabelDistance || 0)) : -10)
                        .attr('x', rotateYLabel ? (-d3.max(scale.range()) / 2) : -axis.tickPadding());
                    if (showMaxMin) {
                        axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
                            .data(scale.domain());
                        axisMaxMin.enter().append('g').attr('class',function(d,i){
                                return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ')
                        }).append('text')
                            .style('opacity', 0);
                        axisMaxMin.exit().remove();
                        axisMaxMin
                            .attr('transform', function(d,i) {
                                return 'translate(0,' + nv.utils.NaNtoZero(scale0(d)) + ')'
                            })
                            .select('text')
                            .attr('dy', '.32em')
                            .attr('y', 0)
                            .attr('x', -axis.tickPadding())
                            .attr('text-anchor', 'end')
                            .text(function(d,i) {
                                var formatter = tickFormatMaxMin || fmt;
                                var v = formatter(d);
                                return ('' + v).match('NaN') ? '' : v;
                            });
                        axisMaxMin.watchTransition(renderWatch, 'min-max right')
                            .attr('transform', function(d,i) {
                                return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')'
                            })
                            .select('text')
                            .style('opacity', 1);
                    }
                    break;
            }
            axisLabel.text(function(d) { return d });

            if (showMaxMin && (axis.orient() === 'left' || axis.orient() === 'right')) {
                //check if max and min overlap other values, if so, hide the values that overlap
                g.selectAll('g') // the g's wrapping each tick
                    .each(function(d,i) {
                        d3.select(this).select('text').attr('opacity', 1);
                        if (scale(d) < scale.range()[1] + 10 || scale(d) > scale.range()[0] - 10) { // 10 is assuming text height is 16... if d is 0, leave it!
                            if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
                                d3.select(this).attr('opacity', 0);

                            d3.select(this).select('text').attr('opacity', 0); // Don't remove the ZERO line!!
                        }
                    });

                //if Max and Min = 0 only show min, Issue #281
                if (scale.domain()[0] == scale.domain()[1] && scale.domain()[0] == 0) {
                    wrap.selectAll('g.nv-axisMaxMin').style('opacity', function (d, i) {
                        return !i ? 1 : 0
                    });
                }
            }

            if (showMaxMin && (axis.orient() === 'top' || axis.orient() === 'bottom')) {
                var maxMinRange = [];
                wrap.selectAll('g.nv-axisMaxMin')
                    .each(function(d,i) {
                        try {
                            if (i) // i== 1, max position
                                maxMinRange.push(scale(d) - this.getBoundingClientRect().width - 4);  //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
                            else // i==0, min position
                                maxMinRange.push(scale(d) + this.getBoundingClientRect().width + 4)
                        }catch (err) {
                            if (i) // i== 1, max position
                                maxMinRange.push(scale(d) - 4);  //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
                            else // i==0, min position
                                maxMinRange.push(scale(d) + 4);
                        }
                    });
                // the g's wrapping each tick
                g.selectAll('g').each(function(d, i) {
                    if (scale(d) < maxMinRange[0] || scale(d) > maxMinRange[1]) {
                        if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
                            d3.select(this).remove();
                        else
                            d3.select(this).select('text').remove(); // Don't remove the ZERO line!!
                    }
                });
            }

            //Highlight zero tick line
            g.selectAll('.tick')
                .filter(function (d) {
                    /*
                    The filter needs to return only ticks at or near zero.
                    Numbers like 0.00001 need to count as zero as well,
                    and the arithmetic trick below solves that.
                    */
                    return !parseFloat(Math.round(d * 100000) / 1000000) && (d !== undefined)
                })
                .classed('zero', true);

            //store old scales for use in transitions on update
            scale0 = scale.copy();

        });

        renderWatch.renderEnd('axis immediate');
        return chart;
    }

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    // expose chart's sub-components
    chart.axis = axis;
    chart.dispatch = dispatch;

    chart.options = nv.utils.optionsFunc.bind(chart);
    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        axisLabelDistance: {get: function(){return axisLabelDistance;}, set: function(_){axisLabelDistance=_;}},
        staggerLabels:     {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
        rotateLabels:      {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}},
        rotateYLabel:      {get: function(){return rotateYLabel;}, set: function(_){rotateYLabel=_;}},
        showMaxMin:        {get: function(){return showMaxMin;}, set: function(_){showMaxMin=_;}},
        axisLabel:         {get: function(){return axisLabelText;}, set: function(_){axisLabelText=_;}},
        height:            {get: function(){return height;}, set: function(_){height=_;}},
        ticks:             {get: function(){return ticks;}, set: function(_){ticks=_;}},
        width:             {get: function(){return width;}, set: function(_){width=_;}},
        fontSize:          {get: function(){return fontSize;}, set: function(_){fontSize=_;}},
        tickFormatMaxMin:  {get: function(){return tickFormatMaxMin;}, set: function(_){tickFormatMaxMin=_;}},

        // options that require extra logic in the setter
        margin: {get: function(){return margin;}, set: function(_){
            margin.top    = _.top !== undefined    ? _.top    : margin.top;
            margin.right  = _.right !== undefined  ? _.right  : margin.right;
            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
            margin.left   = _.left !== undefined   ? _.left   : margin.left;
        }},
        duration: {get: function(){return duration;}, set: function(_){
            duration=_;
            renderWatch.reset(duration);
        }},
        scale: {get: function(){return scale;}, set: function(_){
            scale = _;
            axis.scale(scale);
            isOrdinal = typeof scale.rangeBands === 'function';
            nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']);
        }}
    });

    nv.utils.initOptions(chart);
    nv.utils.inheritOptionsD3(chart, axis, ['orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat']);
    nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']);

    return chart;
};
nv.models.boxPlot = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var margin = {top: 0, right: 0, bottom: 0, left: 0},
        width = 960,
        height = 500,
        id = Math.floor(Math.random() * 10000), // Create semi-unique ID in case user doesn't select one
        xScale = d3.scale.ordinal(),
        yScale = d3.scale.linear(),
        getX  = function(d) { return d.label }, // Default data model selectors.
        getQ1 = function(d) { return d.values.Q1 },
        getQ2 = function(d) { return d.values.Q2 },
        getQ3 = function(d) { return d.values.Q3 },
        getWl = function(d) { return d.values.whisker_low },
        getWh = function(d) { return d.values.whisker_high },
        getColor = function(d) { return d.color },
        getOlItems  = function(d) { return d.values.outliers },
        getOlValue = function(d, i, j) { return d },
        getOlLabel = function(d, i, j) { return d },
        getOlColor = function(d, i, j) { return undefined },
        color = nv.utils.defaultColor(),
        container = null,
        xDomain, xRange,
        yDomain, yRange,
        dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd'),
        duration = 250,
        maxBoxWidth = null;

    //============================================================
    // Private Variables
    //------------------------------------------------------------

    var xScale0, yScale0;
    var renderWatch = nv.utils.renderWatch(dispatch, duration);

    function chart(selection) {
        renderWatch.reset();
        selection.each(function(data) {
            var availableWidth = width - margin.left - margin.right,
                availableHeight = height - margin.top - margin.bottom;

            container = d3.select(this);
            nv.utils.initSVG(container);

            // Setup Scales
            xScale.domain(xDomain || data.map(function(d,i) { return getX(d,i); }))
                .rangeBands(xRange || [0, availableWidth], 0.1);

            // if we know yDomain, no need to calculate
            var yData = []
            if (!yDomain) {
                // (y-range is based on quartiles, whiskers and outliers)
                var values = [], yMin, yMax;
                data.forEach(function (d, i) {
                    var q1 = getQ1(d), q3 = getQ3(d), wl = getWl(d), wh = getWh(d);
                    var olItems = getOlItems(d);
                    if (olItems) {
                        olItems.forEach(function (e, i) {
                            values.push(getOlValue(e, i, undefined));
                        });
                    }
                    if (wl) { values.push(wl) }
                    if (q1) { values.push(q1) }
                    if (q3) { values.push(q3) }
                    if (wh) { values.push(wh) }
                });
                yMin = d3.min(values);
                yMax = d3.max(values);
                yData = [ yMin, yMax ] ;
            }

            yScale.domain(yDomain || yData);
            yScale.range(yRange || [availableHeight, 0]);

            //store old scales if they exist
            xScale0 = xScale0 || xScale;
            yScale0 = yScale0 || yScale.copy().range([yScale(0),yScale(0)]);

            // Setup containers and skeleton of chart
            var wrap = container.selectAll('g.nv-wrap').data([data]);
            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap');
            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            var boxplots = wrap.selectAll('.nv-boxplot').data(function(d) { return d });
            var boxEnter = boxplots.enter().append('g').style('stroke-opacity', 1e-6).style('fill-opacity', 1e-6);
            boxplots
                .attr('class', 'nv-boxplot')
                .attr('transform', function(d,i,j) { return 'translate(' + (xScale(getX(d,i)) + xScale.rangeBand() * 0.05) + ', 0)'; })
                .classed('hover', function(d) { return d.hover });
            boxplots
                .watchTransition(renderWatch, 'nv-boxplot: boxplots')
                .style('stroke-opacity', 1)
                .style('fill-opacity', 0.75)
                .delay(function(d,i) { return i * duration / data.length })
                .attr('transform', function(d,i) {
                    return 'translate(' + (xScale(getX(d,i)) + xScale.rangeBand() * 0.05) + ', 0)';
                });
            boxplots.exit().remove();

            // ----- add the SVG elements for each boxPlot -----

            // conditionally append whisker lines
            boxEnter.each(function(d,i) {
                var box = d3.select(this);
                [getWl, getWh].forEach(function (f) {
                    if (f(d) !== undefined && f(d) !== null) {
                        var key = (f === getWl) ? 'low' : 'high';
                        box.append('line')
                          .style('stroke', getColor(d) || color(d,i))
                          .attr('class', 'nv-boxplot-whisker nv-boxplot-' + key);
                        box.append('line')
                          .style('stroke', getColor(d) || color(d,i))
                          .attr('class', 'nv-boxplot-tick nv-boxplot-' + key);
                    }
                });
            });

            var box_width = function() { return (maxBoxWidth === null ? xScale.rangeBand() * 0.9 : Math.min(75, xScale.rangeBand() * 0.9)); };
            var box_left  = function() { return xScale.rangeBand() * 0.45 - box_width()/2; };
            var box_right = function() { return xScale.rangeBand() * 0.45 + box_width()/2; };

            // update whisker lines and ticks
            [getWl, getWh].forEach(function (f) {
                var key = (f === getWl) ? 'low' : 'high';
                var endpoint = (f === getWl) ? getQ1 : getQ3;
                boxplots.select('line.nv-boxplot-whisker.nv-boxplot-' + key)
                  .watchTransition(renderWatch, 'nv-boxplot: boxplots')
                    .attr('x1', xScale.rangeBand() * 0.45 )
                    .attr('y1', function(d,i) { return yScale(f(d)); })
                    .attr('x2', xScale.rangeBand() * 0.45 )
                    .attr('y2', function(d,i) { return yScale(endpoint(d)); });
                boxplots.select('line.nv-boxplot-tick.nv-boxplot-' + key)
                  .watchTransition(renderWatch, 'nv-boxplot: boxplots')
                    .attr('x1', box_left )
                    .attr('y1', function(d,i) { return yScale(f(d)); })
                    .attr('x2', box_right )
                    .attr('y2', function(d,i) { return yScale(f(d)); });
            });

            [getWl, getWh].forEach(function (f) {
                var key = (f === getWl) ? 'low' : 'high';
                boxEnter.selectAll('.nv-boxplot-' + key)
                  .on('mouseover', function(d,i,j) {
                      d3.select(this).classed('hover', true);
                      dispatch.elementMouseover({
                          series: { key: f(d), color: getColor(d) || color(d,j) },
                          e: d3.event
                      });
                  })
                  .on('mouseout', function(d,i,j) {
                      d3.select(this).classed('hover', false);
                      dispatch.elementMouseout({
                          series: { key: f(d), color: getColor(d) || color(d,j) },
                          e: d3.event
                      });
                  })
                  .on('mousemove', function(d,i) {
                      dispatch.elementMousemove({e: d3.event});
                  });
            });

            // boxes
            boxEnter.append('rect')
                .attr('class', 'nv-boxplot-box')
                // tooltip events
                .on('mouseover', function(d,i) {
                    d3.select(this).classed('hover', true);
                    dispatch.elementMouseover({
                        key: getX(d),
                        value: getX(d),
                        series: [
                            { key: 'Q3', value: getQ3(d), color: getColor(d) || color(d,i) },
                            { key: 'Q2', value: getQ2(d), color: getColor(d) || color(d,i) },
                            { key: 'Q1', value: getQ1(d), color: getColor(d) || color(d,i) }
                        ],
                        data: d,
                        index: i,
                        e: d3.event
                    });
                })
                .on('mouseout', function(d,i) {
                    d3.select(this).classed('hover', false);
                    dispatch.elementMouseout({
                        key: getX(d),
                        value: getX(d),
                        series: [
                            { key: 'Q3', value: getQ3(d), color: getColor(d) || color(d,i) },
                            { key: 'Q2', value: getQ2(d), color: getColor(d) || color(d,i) },
                            { key: 'Q1', value: getQ1(d), color: getColor(d) || color(d,i) }
                        ],
                        data: d,
                        index: i,
                        e: d3.event
                    });
                })
                .on('mousemove', function(d,i) {
                    dispatch.elementMousemove({e: d3.event});
                });

            // box transitions
            boxplots.select('rect.nv-boxplot-box')
              .watchTransition(renderWatch, 'nv-boxplot: boxes')
                .attr('y', function(d,i) { return yScale(getQ3(d)); })
                .attr('width', box_width)
                .attr('x', box_left )
                .attr('height', function(d,i) { return Math.abs(yScale(getQ3(d)) - yScale(getQ1(d))) || 1 })
                .style('fill', function(d,i) { return getColor(d) || color(d,i) })
                .style('stroke', function(d,i) { return getColor(d) || color(d,i) });

            // median line
            boxEnter.append('line').attr('class', 'nv-boxplot-median');

            boxplots.select('line.nv-boxplot-median')
              .watchTransition(renderWatch, 'nv-boxplot: boxplots line')
                .attr('x1', box_left)
                .attr('y1', function(d,i) { return yScale(getQ2(d)); })
                .attr('x2', box_right)
                .attr('y2', function(d,i) { return yScale(getQ2(d)); });

            // outliers
            var outliers = boxplots.selectAll('.nv-boxplot-outlier').data(function(d) {
                return getOlItems(d) || [];
            });
            outliers.enter().append('circle')
                .style('fill', function(d,i,j) { return getOlColor(d,i,j) || color(d,j) })
                .style('stroke', function(d,i,j) { return getOlColor(d,i,j) || color(d,j) })
                .style('z-index', 9000)
                .on('mouseover', function(d,i,j) {
                    d3.select(this).classed('hover', true);
                    dispatch.elementMouseover({
                        series: { key: getOlLabel(d,i,j), color: getOlColor(d,i,j) || color(d,j) },
                        e: d3.event
                    });
                })
                .on('mouseout', function(d,i,j) {
                    d3.select(this).classed('hover', false);
                    dispatch.elementMouseout({
                        series: { key: getOlLabel(d,i,j), color: getOlColor(d,i,j) || color(d,j) },
                        e: d3.event
                    });
                })
                .on('mousemove', function(d,i) {
                    dispatch.elementMousemove({e: d3.event});
                });
            outliers.attr('class', 'nv-boxplot-outlier');
            outliers
              .watchTransition(renderWatch, 'nv-boxplot: nv-boxplot-outlier')
                .attr('cx', xScale.rangeBand() * 0.45)
                .attr('cy', function(d,i,j) { return yScale(getOlValue(d,i,j)); })
                .attr('r', '3');
            outliers.exit().remove();

            //store old scales for use in transitions on update
            xScale0 = xScale.copy();
            yScale0 = yScale.copy();
        });

        renderWatch.renderEnd('nv-boxplot immediate');
        return chart;
    }

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    chart.dispatch = dispatch;
    chart.options = nv.utils.optionsFunc.bind(chart);

    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        width:       {get: function(){return width;}, set: function(_){width=_;}},
        height:      {get: function(){return height;}, set: function(_){height=_;}},
        maxBoxWidth: {get: function(){return maxBoxWidth;}, set: function(_){maxBoxWidth=_;}},
        x:           {get: function(){return getX;}, set: function(_){getX=_;}},
        q1: {get: function(){return getQ1;}, set: function(_){getQ1=_;}},
        q2: {get: function(){return getQ2;}, set: function(_){getQ2=_;}},
        q3: {get: function(){return getQ3;}, set: function(_){getQ3=_;}},
        wl: {get: function(){return getWl;}, set: function(_){getWl=_;}},
        wh: {get: function(){return getWh;}, set: function(_){getWh=_;}},
        itemColor:    {get: function(){return getColor;}, set: function(_){getColor=_;}},
        outliers:     {get: function(){return getOlItems;}, set: function(_){getOlItems=_;}},
        outlierValue: {get: function(){return getOlValue;}, set: function(_){getOlValue=_;}},
        outlierLabel: {get: function(){return getOlLabel;}, set: function(_){getOlLabel=_;}},
        outlierColor: {get: function(){return getOlColor;}, set: function(_){getOlColor=_;}},
        xScale:  {get: function(){return xScale;}, set: function(_){xScale=_;}},
        yScale:  {get: function(){return yScale;}, set: function(_){yScale=_;}},
        xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
        yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
        xRange:  {get: function(){return xRange;}, set: function(_){xRange=_;}},
        yRange:  {get: function(){return yRange;}, set: function(_){yRange=_;}},
        id:          {get: function(){return id;}, set: function(_){id=_;}},
        // rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}},
        y: {
            get: function() {
                console.warn('BoxPlot \'y\' chart option is deprecated. Please use model overrides instead.');
                return {};
            },
            set: function(_) {
                console.warn('BoxPlot \'y\' chart option is deprecated. Please use model overrides instead.');
            }
        },
        // options that require extra logic in the setter
        margin: {get: function(){return margin;}, set: function(_){
            margin.top    = _.top    !== undefined ? _.top    : margin.top;
            margin.right  = _.right  !== undefined ? _.right  : margin.right;
            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
            margin.left   = _.left   !== undefined ? _.left   : margin.left;
        }},
        color:  {get: function(){return color;}, set: function(_){
            color = nv.utils.getColor(_);
        }},
        duration: {get: function(){return duration;}, set: function(_){
            duration = _;
            renderWatch.reset(duration);
        }}
    });

    nv.utils.initOptions(chart);

    return chart;
};
nv.models.boxPlotChart = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var boxplot = nv.models.boxPlot(),
        xAxis = nv.models.axis(),
        yAxis = nv.models.axis();

    var margin = {top: 15, right: 10, bottom: 50, left: 60},
        width = null,
        height = null,
        color = nv.utils.getColor(),
        showXAxis = true,
        showYAxis = true,
        rightAlignYAxis = false,
        staggerLabels = false,
        tooltip = nv.models.tooltip(),
        x, y,
        noData = 'No Data Available.',
        dispatch = d3.dispatch('beforeUpdate', 'renderEnd'),
        duration = 250;

    xAxis
        .orient('bottom')
        .showMaxMin(false)
        .tickFormat(function(d) { return d })
    ;
    yAxis
        .orient((rightAlignYAxis) ? 'right' : 'left')
        .tickFormat(d3.format(',.1f'))
    ;

    tooltip.duration(0);

    //============================================================
    // Private Variables
    //------------------------------------------------------------

    var renderWatch = nv.utils.renderWatch(dispatch, duration);

    function chart(selection) {
        renderWatch.reset();
        renderWatch.models(boxplot);
        if (showXAxis) renderWatch.models(xAxis);
        if (showYAxis) renderWatch.models(yAxis);

        selection.each(function(data) {
            var container = d3.select(this), that = this;
            nv.utils.initSVG(container);
            var availableWidth = (width  || parseInt(container.style('width')) || 960) - margin.left - margin.right;
            var availableHeight = (height || parseInt(container.style('height')) || 400) - margin.top - margin.bottom;

            chart.update = function() {
                dispatch.beforeUpdate();
                container.transition().duration(duration).call(chart);
            };
            chart.container = this;

            // TODO still need to find a way to validate quartile data presence using boxPlot callbacks.
            // Display No Data message if there's nothing to show. (quartiles required at minimum).
            if (!data || !data.length) {
                var noDataText = container.selectAll('.nv-noData').data([noData]);

                noDataText.enter().append('text')
                    .attr('class', 'nvd3 nv-noData')
                    .attr('dy', '-.7em')
                    .style('text-anchor', 'middle');

                noDataText
                    .attr('x', margin.left + availableWidth / 2)
                    .attr('y', margin.top + availableHeight / 2)
                    .text(function(d) { return d });

                return chart;
            } else {
                container.selectAll('.nv-noData').remove();
            }

            // Setup Scales
            x = boxplot.xScale();
            y = boxplot.yScale().clamp(true);

            // Setup containers and skeleton of chart
            var wrap = container.selectAll('g.nv-wrap.nv-boxPlotWithAxes').data([data]);
            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-boxPlotWithAxes').append('g');
            var defsEnter = gEnter.append('defs');
            var g = wrap.select('g');

            gEnter.append('g').attr('class', 'nv-x nv-axis');
            gEnter.append('g').attr('class', 'nv-y nv-axis')
                .append('g').attr('class', 'nv-zeroLine')
                .append('line');

            gEnter.append('g').attr('class', 'nv-barsWrap');
            g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            if (rightAlignYAxis) {
                g.select('.nv-y.nv-axis')
                    .attr('transform', 'translate(' + availableWidth + ',0)');
            }

            // Main Chart Component(s)
            boxplot.width(availableWidth).height(availableHeight);

            var barsWrap = g.select('.nv-barsWrap')
                .datum(data.filter(function(d) { return !d.disabled }))

            barsWrap.transition().call(boxplot);

            defsEnter.append('clipPath')
                .attr('id', 'nv-x-label-clip-' + boxplot.id())
                .append('rect');

            g.select('#nv-x-label-clip-' + boxplot.id() + ' rect')
                .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1))
                .attr('height', 16)
                .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 ));

            // Setup Axes
            if (showXAxis) {
                xAxis
                    .scale(x)
                    .ticks( nv.utils.calcTicksX(availableWidth/100, data) )
                    .tickSize(-availableHeight, 0);

                g.select('.nv-x.nv-axis').attr('transform', 'translate(0,' + y.range()[0] + ')');
                g.select('.nv-x.nv-axis').call(xAxis);

                var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
                if (staggerLabels) {
                    xTicks
                        .selectAll('text')
                        .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 === 0 ? '5' : '17') + ')' })
                }
            }

            if (showYAxis) {
                yAxis
                    .scale(y)
                    .ticks( Math.floor(availableHeight/36) ) // can't use nv.utils.calcTicksY with Object data
                    .tickSize( -availableWidth, 0);

                g.select('.nv-y.nv-axis').call(yAxis);
            }

            // Zero line
            g.select('.nv-zeroLine line')
                .attr('x1',0)
                .attr('x2',availableWidth)
                .attr('y1', y(0))
                .attr('y2', y(0))
            ;

            //============================================================
            // Event Handling/Dispatching (in chart's scope)
            //------------------------------------------------------------
        });

        renderWatch.renderEnd('nv-boxplot chart immediate');
        return chart;
    }

    //============================================================
    // Event Handling/Dispatching (out of chart's scope)
    //------------------------------------------------------------

    boxplot.dispatch.on('elementMouseover.tooltip', function(evt) {
        tooltip.data(evt).hidden(false);
    });

    boxplot.dispatch.on('elementMouseout.tooltip', function(evt) {
        tooltip.data(evt).hidden(true);
    });

    boxplot.dispatch.on('elementMousemove.tooltip', function(evt) {
        tooltip();
    });

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    chart.dispatch = dispatch;
    chart.boxplot = boxplot;
    chart.xAxis = xAxis;
    chart.yAxis = yAxis;
    chart.tooltip = tooltip;

    chart.options = nv.utils.optionsFunc.bind(chart);

    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        width:      {get: function(){return width;}, set: function(_){width=_;}},
        height:     {get: function(){return height;}, set: function(_){height=_;}},
        staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}},
        showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
        showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
        tooltipContent:    {get: function(){return tooltip;}, set: function(_){tooltip=_;}},
        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},

        // options that require extra logic in the setter
        margin: {get: function(){return margin;}, set: function(_){
            margin.top    = _.top    !== undefined ? _.top    : margin.top;
            margin.right  = _.right  !== undefined ? _.right  : margin.right;
            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
            margin.left   = _.left   !== undefined ? _.left   : margin.left;
        }},
        duration: {get: function(){return duration;}, set: function(_){
            duration = _;
            renderWatch.reset(duration);
            boxplot.duration(duration);
            xAxis.duration(duration);
            yAxis.duration(duration);
        }},
        color:  {get: function(){return color;}, set: function(_){
            color = nv.utils.getColor(_);
            boxplot.color(color);
        }},
        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
            rightAlignYAxis = _;
            yAxis.orient( (_) ? 'right' : 'left');
        }}
    });

    nv.utils.inheritOptions(chart, boxplot);
    nv.utils.initOptions(chart);

    return chart;
}

// Chart design based on the recommendations of Stephen Few. Implementation
// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
// http://projects.instantcognition.com/protovis/bulletchart/

nv.models.bullet = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var margin = {top: 0, right: 0, bottom: 0, left: 0}
        , orient = 'left' // TODO top & bottom
        , reverse = false
        , ranges = function(d) { return d.ranges }
        , markers = function(d) { return d.markers ? d.markers : [] }
        , markerLines = function(d) { return d.markerLines ? d.markerLines : [0] }
        , measures = function(d) { return d.measures }
        , rangeLabels = function(d) { return d.rangeLabels ? d.rangeLabels : [] }
        , markerLabels = function(d) { return d.markerLabels ? d.markerLabels : []  }
        , markerLineLabels = function(d) { return d.markerLineLabels ? d.markerLineLabels : []  }
        , measureLabels = function(d) { return d.measureLabels ? d.measureLabels : []  }
        , forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
        , width = 380
        , height = 30
        , container = null
        , tickFormat = null
        , color = nv.utils.getColor(['#1f77b4'])
        , dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove')
        , defaultRangeLabels = ["Maximum", "Mean", "Minimum"]
        , legacyRangeClassNames = ["Max", "Avg", "Min"]
        , duration = 1000
        ;

    function sortLabels(labels, values){
        var lz = labels.slice();
        labels.sort(function(a, b){
            var iA = lz.indexOf(a);
            var iB = lz.indexOf(b);
            return d3.descending(values[iA], values[iB]);
        });
    };

    function chart(selection) {
        selection.each(function(d, i) {
            var availableWidth = width - margin.left - margin.right,
                availableHeight = height - margin.top - margin.bottom;

            container = d3.select(this);
            nv.utils.initSVG(container);

            var rangez = ranges.call(this, d, i).slice(),
                markerz = markers.call(this, d, i).slice(),
                markerLinez = markerLines.call(this, d, i).slice(),
                measurez = measures.call(this, d, i).slice(),
                rangeLabelz = rangeLabels.call(this, d, i).slice(),
                markerLabelz = markerLabels.call(this, d, i).slice(),
                markerLineLabelz = markerLineLabels.call(this, d, i).slice(),
                measureLabelz = measureLabels.call(this, d, i).slice();

            // Sort labels according to their sorted values
            sortLabels(rangeLabelz, rangez);
            sortLabels(markerLabelz, markerz);
            sortLabels(markerLineLabelz, markerLinez);
            sortLabels(measureLabelz, measurez);

            // sort values descending
            rangez.sort(d3.descending);
            markerz.sort(d3.descending);
            markerLinez.sort(d3.descending);
            measurez.sort(d3.descending);

            // Setup Scales
            // Compute the new x-scale.
            var x1 = d3.scale.linear()
                .domain( d3.extent(d3.merge([forceX, rangez])) )
                .range(reverse ? [availableWidth, 0] : [0, availableWidth]);

            // Retrieve the old x-scale, if this is an update.
            var x0 = this.__chart__ || d3.scale.linear()
                .domain([0, Infinity])
                .range(x1.range());

            // Stash the new scale.
            this.__chart__ = x1;

            var rangeMin = d3.min(rangez), //rangez[2]
                rangeMax = d3.max(rangez), //rangez[0]
                rangeAvg = rangez[1];

            // Setup containers and skeleton of chart
            var wrap = container.selectAll('g.nv-wrap.nv-bullet').data([d]);
            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bullet');
            var gEnter = wrapEnter.append('g');
            var g = wrap.select('g');

            for(var i=0,il=rangez.length; i<il; i++){
                var rangeClassNames = 'nv-range nv-range'+i;
                if(i <= 2){
                    rangeClassNames = rangeClassNames + ' nv-range'+legacyRangeClassNames[i];
                }
                gEnter.append('rect').attr('class', rangeClassNames);
            }

            gEnter.append('rect').attr('class', 'nv-measure');

            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
                w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
            var xp0 = function(d) { return d < 0 ? x0(d) : x0(0) },
                xp1 = function(d) { return d < 0 ? x1(d) : x1(0) };

            for(var i=0,il=rangez.length; i<il; i++){
                var range = rangez[i];
                g.select('rect.nv-range'+i)
                    .datum(range)
                    .attr('height', availableHeight)
                    .transition()
                    .duration(duration)
                    .attr('width', w1(range))
                    .attr('x', xp1(range))
            }

            g.select('rect.nv-measure')
                .style('fill', color)
                .attr('height', availableHeight / 3)
                .attr('y', availableHeight / 3)
                .on('mouseover', function() {
                    dispatch.elementMouseover({
                        value: measurez[0],
                        label: measureLabelz[0] || 'Current',
                        color: d3.select(this).style("fill")
                    })
                })
                .on('mousemove', function() {
                    dispatch.elementMousemove({
                        value: measurez[0],
                        label: measureLabelz[0] || 'Current',
                        color: d3.select(this).style("fill")
                    })
                })
                .on('mouseout', function() {
                    dispatch.elementMouseout({
                        value: measurez[0],
                        label: measureLabelz[0] || 'Current',
                        color: d3.select(this).style("fill")
                    })
                })
                .transition()
                .duration(duration)
                .attr('width', measurez < 0 ?
                    x1(0) - x1(measurez[0])
                    : x1(measurez[0]) - x1(0))
                .attr('x', xp1(measurez));

            var h3 =  availableHeight / 6;

            var markerData = markerz.map( function(marker, index) {
                return {value: marker, label: markerLabelz[index]}
            });
            gEnter
              .selectAll("path.nv-markerTriangle")
              .data(markerData)
              .enter()
              .append('path')
              .attr('class', 'nv-markerTriangle')
              .attr('d', 'M0,' + h3 + 'L' + h3 + ',' + (-h3) + ' ' + (-h3) + ',' + (-h3) + 'Z')
              .on('mouseover', function(d) {
                dispatch.elementMouseover({
                  value: d.value,
                  label: d.label || 'Previous',
                  color: d3.select(this).style("fill"),
                  pos: [x1(d.value), availableHeight/2]
                })

              })
              .on('mousemove', function(d) {
                  dispatch.elementMousemove({
                      value: d.value,
                      label: d.label || 'Previous',
                      color: d3.select(this).style("fill")
                  })
              })
              .on('mouseout', function(d, i) {
                  dispatch.elementMouseout({
                      value: d.value,
                      label: d.label || 'Previous',
                      color: d3.select(this).style("fill")
                  })
              });

            g.selectAll("path.nv-markerTriangle")
              .data(markerData)
              .transition()
              .duration(duration)
              .attr('transform', function(d) { return 'translate(' + x1(d.value) + ',' + (availableHeight / 2) + ')' });

            var markerLinesData = markerLinez.map( function(marker, index) {
                return {value: marker, label: markerLineLabelz[index]}
            });
            gEnter
              .selectAll("line.nv-markerLine")
              .data(markerLinesData)
              .enter()
              .append('line')
              .attr('cursor', '')
              .attr('class', 'nv-markerLine')
              .attr('x1', function(d) { return x1(d.value) })
              .attr('y1', '2')
              .attr('x2', function(d) { return x1(d.value) })
              .attr('y2', availableHeight - 2)
              .on('mouseover', function(d) {
                dispatch.elementMouseover({
                  value: d.value,
                  label: d.label || 'Previous',
                  color: d3.select(this).style("fill"),
                  pos: [x1(d.value), availableHeight/2]
                })

              })
              .on('mousemove', function(d) {
                  dispatch.elementMousemove({
                      value: d.value,
                      label: d.label || 'Previous',
                      color: d3.select(this).style("fill")
                  })
              })
              .on('mouseout', function(d, i) {
                  dispatch.elementMouseout({
                      value: d.value,
                      label: d.label || 'Previous',
                      color: d3.select(this).style("fill")
                  })
              });

            g.selectAll("line.nv-markerLine")
              .data(markerLinesData)
              .transition()
              .duration(duration)
              .attr('x1', function(d) { return x1(d.value) })
              .attr('x2', function(d) { return x1(d.value) });

            wrap.selectAll('.nv-range')
                .on('mouseover', function(d,i) {
                    var label = rangeLabelz[i] || defaultRangeLabels[i];
                    dispatch.elementMouseover({
                        value: d,
                        label: label,
                        color: d3.select(this).style("fill")
                    })
                })
                .on('mousemove', function() {
                    dispatch.elementMousemove({
                        value: measurez[0],
                        label: measureLabelz[0] || 'Previous',
                        color: d3.select(this).style("fill")
                    })
                })
                .on('mouseout', function(d,i) {
                    var label = rangeLabelz[i] || defaultRangeLabels[i];
                    dispatch.elementMouseout({
                        value: d,
                        label: label,
                        color: d3.select(this).style("fill")
                    })
                });
        });

        return chart;
    }

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    chart.dispatch = dispatch;
    chart.options = nv.utils.optionsFunc.bind(chart);

    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        ranges:      {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good)
        markers:     {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal)
        measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast)
        forceX:      {get: function(){return forceX;}, set: function(_){forceX=_;}},
        width:    {get: function(){return width;}, set: function(_){width=_;}},
        height:    {get: function(){return height;}, set: function(_){height=_;}},
        tickFormat:    {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}},
        duration:    {get: function(){return duration;}, set: function(_){duration=_;}},

        // options that require extra logic in the setter
        margin: {get: function(){return margin;}, set: function(_){
            margin.top    = _.top    !== undefined ? _.top    : margin.top;
            margin.right  = _.right  !== undefined ? _.right  : margin.right;
            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
            margin.left   = _.left   !== undefined ? _.left   : margin.left;
        }},
        orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom
            orient = _;
            reverse = orient == 'right' || orient == 'bottom';
        }},
        color:  {get: function(){return color;}, set: function(_){
            color = nv.utils.getColor(_);
        }}
    });

    nv.utils.initOptions(chart);
    return chart;
};



// Chart design based on the recommendations of Stephen Few. Implementation
// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
// http://projects.instantcognition.com/protovis/bulletchart/
nv.models.bulletChart = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var bullet = nv.models.bullet();
    var tooltip = nv.models.tooltip();

    var orient = 'left' // TODO top & bottom
        , reverse = false
        , margin = {top: 5, right: 40, bottom: 20, left: 120}
        , ranges = function(d) { return d.ranges }
        , markers = function(d) { return d.markers ? d.markers : [] }
        , measures = function(d) { return d.measures }
        , width = null
        , height = 55
        , tickFormat = null
        , ticks = null
        , noData = null
        , dispatch = d3.dispatch()
        ;

    tooltip
        .duration(0)
        .headerEnabled(false);

    function chart(selection) {
        selection.each(function(d, i) {
            var container = d3.select(this);
            nv.utils.initSVG(container);

            var availableWidth = nv.utils.availableWidth(width, container, margin),
                availableHeight = height - margin.top - margin.bottom,
                that = this;

            chart.update = function() { chart(selection) };
            chart.container = this;

            // Display No Data message if there's nothing to show.
            if (!d || !ranges.call(this, d, i)) {
                nv.utils.noData(chart, container)
                return chart;
            } else {
                container.selectAll('.nv-noData').remove();
            }

            var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
                markerz = markers.call(this, d, i).slice().sort(d3.descending),
                measurez = measures.call(this, d, i).slice().sort(d3.descending);

            // Setup containers and skeleton of chart
            var wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]);
            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart');
            var gEnter = wrapEnter.append('g');
            var g = wrap.select('g');

            gEnter.append('g').attr('class', 'nv-bulletWrap');
            gEnter.append('g').attr('class', 'nv-titles');

            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            // Compute the new x-scale.
            var x1 = d3.scale.linear()
                .domain([0, Math.max(rangez[0], (markerz[0] || 0), measurez[0])])  // TODO: need to allow forceX and forceY, and xDomain, yDomain
                .range(reverse ? [availableWidth, 0] : [0, availableWidth]);

            // Retrieve the old x-scale, if this is an update.
            var x0 = this.__chart__ || d3.scale.linear()
                .domain([0, Infinity])
                .range(x1.range());

            // Stash the new scale.
            this.__chart__ = x1;

            var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
                w1 = function(d) { return Math.abs(x1(d) - x1(0)) };

            var title = gEnter.select('.nv-titles').append('g')
                .attr('text-anchor', 'end')
                .attr('transform', 'translate(-6,' + (height - margin.top - margin.bottom) / 2 + ')');
            title.append('text')
                .attr('class', 'nv-title')
                .text(function(d) { return d.title; });

            title.append('text')
                .attr('class', 'nv-subtitle')
                .attr('dy', '1em')
                .text(function(d) { return d.subtitle; });

            bullet
                .width(availableWidth)
                .height(availableHeight);

            var bulletWrap = g.select('.nv-bulletWrap');
            d3.transition(bulletWrap).call(bullet);

            // Compute the tick format.
            var format = tickFormat || x1.tickFormat( availableWidth / 100 );

            // Update the tick groups.
            var tick = g.selectAll('g.nv-tick')
                .data(x1.ticks( ticks ? ticks : (availableWidth / 50) ), function(d) {
                    return this.textContent || format(d);
                });

            // Initialize the ticks with the old scale, x0.
            var tickEnter = tick.enter().append('g')
                .attr('class', 'nv-tick')
                .attr('transform', function(d) { return 'translate(' + x0(d) + ',0)' })
                .style('opacity', 1e-6);

            tickEnter.append('line')
                .attr('y1', availableHeight)
                .attr('y2', availableHeight * 7 / 6);

            tickEnter.append('text')
                .attr('text-anchor', 'middle')
                .attr('dy', '1em')
                .attr('y', availableHeight * 7 / 6)
                .text(format);

            // Transition the updating ticks to the new scale, x1.
            var tickUpdate = d3.transition(tick)
                .transition()
                .duration(bullet.duration())
                .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
                .style('opacity', 1);

            tickUpdate.select('line')
                .attr('y1', availableHeight)
                .attr('y2', availableHeight * 7 / 6);

            tickUpdate.select('text')
                .attr('y', availableHeight * 7 / 6);

            // Transition the exiting ticks to the new scale, x1.
            d3.transition(tick.exit())
                .transition()
                .duration(bullet.duration())
                .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
                .style('opacity', 1e-6)
                .remove();
        });

        d3.timer.flush();
        return chart;
    }

    //============================================================
    // Event Handling/Dispatching (out of chart's scope)
    //------------------------------------------------------------

    bullet.dispatch.on('elementMouseover.tooltip', function(evt) {
        evt['series'] = {
            key: evt.label,
            value: evt.value,
            color: evt.color
        };
        tooltip.data(evt).hidden(false);
    });

    bullet.dispatch.on('elementMouseout.tooltip', function(evt) {
        tooltip.hidden(true);
    });

    bullet.dispatch.on('elementMousemove.tooltip', function(evt) {
        tooltip();
    });

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    chart.bullet = bullet;
    chart.dispatch = dispatch;
    chart.tooltip = tooltip;

    chart.options = nv.utils.optionsFunc.bind(chart);

    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        ranges:      {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good)
        markers:     {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal)
        measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast)
        width:    {get: function(){return width;}, set: function(_){width=_;}},
        height:    {get: function(){return height;}, set: function(_){height=_;}},
        tickFormat:    {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}},
        ticks:    {get: function(){return ticks;}, set: function(_){ticks=_;}},
        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},

        // options that require extra logic in the setter
        margin: {get: function(){return margin;}, set: function(_){
            margin.top    = _.top    !== undefined ? _.top    : margin.top;
            margin.right  = _.right  !== undefined ? _.right  : margin.right;
            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
            margin.left   = _.left   !== undefined ? _.left   : margin.left;
        }},
        orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom
            orient = _;
            reverse = orient == 'right' || orient == 'bottom';
        }}
    });

    nv.utils.inheritOptions(chart, bullet);
    nv.utils.initOptions(chart);

    return chart;
};



nv.models.candlestickBar = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var margin = {top: 0, right: 0, bottom: 0, left: 0}
        , width = null
        , height = null
        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
        , container
        , x = d3.scale.linear()
        , y = d3.scale.linear()
        , getX = function(d) { return d.x }
        , getY = function(d) { return d.y }
        , getOpen = function(d) { return d.open }
        , getClose = function(d) { return d.close }
        , getHigh = function(d) { return d.high }
        , getLow = function(d) { return d.low }
        , forceX = []
        , forceY = []
        , padData     = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
        , clipEdge = true
        , color = nv.utils.defaultColor()
        , interactive = false
        , xDomain
        , yDomain
        , xRange
        , yRange
        , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove')
        ;

    //============================================================
    // Private Variables
    //------------------------------------------------------------

    function chart(selection) {
        selection.each(function(data) {
            container = d3.select(this);
            var availableWidth = nv.utils.availableWidth(width, container, margin),
                availableHeight = nv.utils.availableHeight(height, container, margin);

            nv.utils.initSVG(container);

            // Width of the candlestick bars.
            var barWidth = (availableWidth / data[0].values.length) * .45;

            // Setup Scales
            x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ));

            if (padData)
                x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5)  / data[0].values.length ]);
            else
                x.range(xRange || [5 + barWidth / 2, availableWidth - barWidth / 2 - 5]);

            y.domain(yDomain || [
                    d3.min(data[0].values.map(getLow).concat(forceY)),
                    d3.max(data[0].values.map(getHigh).concat(forceY))
                ]
            ).range(yRange || [availableHeight, 0]);

            // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
            if (x.domain()[0] === x.domain()[1])
                x.domain()[0] ?
                    x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
                    : x.domain([-1,1]);

            if (y.domain()[0] === y.domain()[1])
                y.domain()[0] ?
                    y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
                    : y.domain([-1,1]);

            // Setup containers and skeleton of chart
            var wrap = d3.select(this).selectAll('g.nv-wrap.nv-candlestickBar').data([data[0].values]);
            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-candlestickBar');
            var defsEnter = wrapEnter.append('defs');
            var gEnter = wrapEnter.append('g');
            var g = wrap.select('g');

            gEnter.append('g').attr('class', 'nv-ticks');

            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            container
                .on('click', function(d,i) {
                    dispatch.chartClick({
                        data: d,
                        index: i,
                        pos: d3.event,
                        id: id
                    });
                });

            defsEnter.append('clipPath')
                .attr('id', 'nv-chart-clip-path-' + id)
                .append('rect');

            wrap.select('#nv-chart-clip-path-' + id + ' rect')
                .attr('width', availableWidth)
                .attr('height', availableHeight);

            g   .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');

            var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick')
                .data(function(d) { return d });
            ticks.exit().remove();

            var tickGroups = ticks.enter().append('g');

            // The colors are currently controlled by CSS.
            ticks
                .attr('class', function(d, i, j) { return (getOpen(d, i) > getClose(d, i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i});

            var lines = tickGroups.append('line')
                .attr('class', 'nv-candlestick-lines')
                .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; })
                .attr('x1', 0)
                .attr('y1', function(d, i) { return y(getHigh(d, i)); })
                .attr('x2', 0)
                .attr('y2', function(d, i) { return y(getLow(d, i)); });

            var rects = tickGroups.append('rect')
                .attr('class', 'nv-candlestick-rects nv-bars')
                .attr('transform', function(d, i) {
                    return 'translate(' + (x(getX(d, i)) - barWidth/2) + ','
                    + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0))
                    + ')';
                })
                .attr('x', 0)
                .attr('y', 0)
                .attr('width', barWidth)
                .attr('height', function(d, i) {
                    var open = getOpen(d, i);
                    var close = getClose(d, i);
                    return open > close ? y(close) - y(open) : y(open) - y(close);
                });

            ticks.select('.nv-candlestick-lines').transition()
                .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; })
                .attr('x1', 0)
                .attr('y1', function(d, i) { return y(getHigh(d, i)); })
                .attr('x2', 0)
                .attr('y2', function(d, i) { return y(getLow(d, i)); });

            ticks.select('.nv-candlestick-rects').transition()
                .attr('transform', function(d, i) {
                    return 'translate(' + (x(getX(d, i)) - barWidth/2) + ','
                    + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0))
                    + ')';
                })
                .attr('x', 0)
                .attr('y', 0)
                .attr('width', barWidth)
                .attr('height', function(d, i) {
                    var open = getOpen(d, i);
                    var close = getClose(d, i);
                    return open > close ? y(close) - y(open) : y(open) - y(close);
                });
        });

        return chart;
    }


    //Create methods to allow outside functions to highlight a specific bar.
    chart.highlightPoint = function(pointIndex, isHoverOver) {
        chart.clearHighlights();
        container.select(".nv-candlestickBar .nv-tick-0-" + pointIndex)
            .classed("hover", isHoverOver)
        ;
    };

    chart.clearHighlights = function() {
        container.select(".nv-candlestickBar .nv-tick.hover")
            .classed("hover", false)
        ;
    };

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    chart.dispatch = dispatch;
    chart.options = nv.utils.optionsFunc.bind(chart);

    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        width:    {get: function(){return width;}, set: function(_){width=_;}},
        height:   {get: function(){return height;}, set: function(_){height=_;}},
        xScale:   {get: function(){return x;}, set: function(_){x=_;}},
        yScale:   {get: function(){return y;}, set: function(_){y=_;}},
        xDomain:  {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
        yDomain:  {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
        xRange:   {get: function(){return xRange;}, set: function(_){xRange=_;}},
        yRange:   {get: function(){return yRange;}, set: function(_){yRange=_;}},
        forceX:   {get: function(){return forceX;}, set: function(_){forceX=_;}},
        forceY:   {get: function(){return forceY;}, set: function(_){forceY=_;}},
        padData:  {get: function(){return padData;}, set: function(_){padData=_;}},
        clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
        id:       {get: function(){return id;}, set: function(_){id=_;}},
        interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},

        x:     {get: function(){return getX;}, set: function(_){getX=_;}},
        y:     {get: function(){return getY;}, set: function(_){getY=_;}},
        open:  {get: function(){return getOpen();}, set: function(_){getOpen=_;}},
        close: {get: function(){return getClose();}, set: function(_){getClose=_;}},
        high:  {get: function(){return getHigh;}, set: function(_){getHigh=_;}},
        low:   {get: function(){return getLow;}, set: function(_){getLow=_;}},

        // options that require extra logic in the setter
        margin: {get: function(){return margin;}, set: function(_){
            margin.top    = _.top    != undefined ? _.top    : margin.top;
            margin.right  = _.right  != undefined ? _.right  : margin.right;
            margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom;
            margin.left   = _.left   != undefined ? _.left   : margin.left;
        }},
        color:  {get: function(){return color;}, set: function(_){
            color = nv.utils.getColor(_);
        }}
    });

    nv.utils.initOptions(chart);
    return chart;
};

nv.models.cumulativeLineChart = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var lines = nv.models.line()
        , xAxis = nv.models.axis()
        , yAxis = nv.models.axis()
        , legend = nv.models.legend()
        , controls = nv.models.legend()
        , interactiveLayer = nv.interactiveGuideline()
        , tooltip = nv.models.tooltip()
        ;

    var margin = {top: 30, right: 30, bottom: 50, left: 60}
        , marginTop = null
        , color = nv.utils.defaultColor()
        , width = null
        , height = null
        , showLegend = true
        , showXAxis = true
        , showYAxis = true
        , rightAlignYAxis = false
        , showControls = true
        , useInteractiveGuideline = false
        , rescaleY = true
        , x //can be accessed via chart.xScale()
        , y //can be accessed via chart.yScale()
        , id = lines.id()
        , state = nv.utils.state()
        , defaultState = null
        , noData = null
        , average = function(d) { return d.average }
        , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd')
        , transitionDuration = 250
        , duration = 250
        , noErrorCheck = false  //if set to TRUE, will bypass an error check in the indexify function.
        ;

    state.index = 0;
    state.rescaleY = rescaleY;

    xAxis.orient('bottom').tickPadding(7);
    yAxis.orient((rightAlignYAxis) ? 'right' : 'left');

    tooltip.valueFormatter(function(d, i) {
        return yAxis.tickFormat()(d, i);
    }).headerFormatter(function(d, i) {
        return xAxis.tickFormat()(d, i);
    });

    controls.updateState(false);

    //============================================================
    // Private Variables
    //------------------------------------------------------------

    var dx = d3.scale.linear()
        , index = {i: 0, x: 0}
        , renderWatch = nv.utils.renderWatch(dispatch, duration)
        , currentYDomain
        ;

    var stateGetter = function(data) {
        return function(){
            return {
                active: data.map(function(d) { return !d.disabled }),
                index: index.i,
                rescaleY: rescaleY
            };
        }
    };

    var stateSetter = function(data) {
        return function(state) {
            if (state.index !== undefined)
                index.i = state.index;
            if (state.rescaleY !== undefined)
                rescaleY = state.rescaleY;
            if (state.active !== undefined)
                data.forEach(function(series,i) {
                    series.disabled = !state.active[i];
                });
        }
    };

    function chart(selection) {
        renderWatch.reset();
        renderWatch.models(lines);
        if (showXAxis) renderWatch.models(xAxis);
        if (showYAxis) renderWatch.models(yAxis);
        selection.each(function(data) {
            var container = d3.select(this);
            nv.utils.initSVG(container);
            container.classed('nv-chart-' + id, true);
            var that = this;

            var availableWidth = nv.utils.availableWidth(width, container, margin),
                availableHeight = nv.utils.availableHeight(height, container, margin);

            chart.update = function() {
                if (duration === 0)
                    container.call(chart);
                else
                    container.transition().duration(duration).call(chart)
            };
            chart.container = this;

            state
                .setter(stateSetter(data), chart.update)
                .getter(stateGetter(data))
                .update();

            // DEPRECATED set state.disableddisabled
            state.disabled = data.map(function(d) { return !!d.disabled });

            if (!defaultState) {
                var key;
                defaultState = {};
                for (key in state) {
                    if (state[key] instanceof Array)
                        defaultState[key] = state[key].slice(0);
                    else
                        defaultState[key] = state[key];
                }
            }

            var indexDrag = d3.behavior.drag()
                .on('dragstart', dragStart)
                .on('drag', dragMove)
                .on('dragend', dragEnd);


            function dragStart(d,i) {
                d3.select(chart.container)
                    .style('cursor', 'ew-resize');
            }

            function dragMove(d,i) {
                index.x = d3.event.x;
                index.i = Math.round(dx.invert(index.x));
                updateZero();
            }

            function dragEnd(d,i) {
                d3.select(chart.container)
                    .style('cursor', 'auto');

                // update state and send stateChange with new index
                state.index = index.i;
                dispatch.stateChange(state);
            }

            // Display No Data message if there's nothing to show.
            if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
                nv.utils.noData(chart, container)
                return chart;
            } else {
                container.selectAll('.nv-noData').remove();
            }

            // Setup Scales
            x = lines.xScale();
            y = lines.yScale();


            dx.domain([0, data[0].values.length - 1]) //Assumes all series have same length
                .range([0, availableWidth])
                .clamp(true);

            var data = indexify(index.i, data);

            // initialize the starting yDomain for the not-rescale case after indexify (to have calculated point.display)
            if (typeof(currentYDomain) === "undefined") {
                currentYDomain = getCurrentYDomain(data);
            }

            if (!rescaleY) {
                lines.yDomain(currentYDomain);
                lines.clipEdge(true);
            } else {
                lines.yDomain(null);
            }

            // Setup containers and skeleton of chart
            var interactivePointerEvents = (useInteractiveGuideline) ? "none" : "all";
            var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]);
            var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-cumulativeLine').append('g');
            var g = wrap.select('g');

            gEnter.append('g').attr('class', 'nv-interactive');
            gEnter.append('g').attr('class', 'nv-x nv-axis').style("pointer-events","none");
            gEnter.append('g').attr('class', 'nv-y nv-axis');
            gEnter.append('g').attr('class', 'nv-background');
            gEnter.append('g').attr('class', 'nv-linesWrap').style("pointer-events",interactivePointerEvents);
            gEnter.append('g').attr('class', 'nv-avgLinesWrap').style("pointer-events","none");
            gEnter.append('g').attr('class', 'nv-legendWrap');
            gEnter.append('g').attr('class', 'nv-controlsWrap');

            // Legend
            if (!showLegend) {
                g.select('.nv-legendWrap').selectAll('*').remove();
            } else {
                legend.width(availableWidth);

                g.select('.nv-legendWrap')
                    .datum(data)
                    .call(legend);

                if (!marginTop && legend.height() !== margin.top) {
                    margin.top = legend.height();
                    availableHeight = nv.utils.availableHeight(height, container, margin);
                }

                g.select('.nv-legendWrap')
                    .attr('transform', 'translate(0,' + (-margin.top) +')')
            }

            // Controls
            if (!showControls) {
                 g.select('.nv-controlsWrap').selectAll('*').remove();
            } else {
                var controlsData = [
                    { key: 'Re-scale y-axis', disabled: !rescaleY }
                ];

                controls
                    .width(140)
                    .color(['#444', '#444', '#444'])
                    .rightAlign(false)
                    .margin({top: 5, right: 0, bottom: 5, left: 20})
                ;

                g.select('.nv-controlsWrap')
                    .datum(controlsData)
                    .attr('transform', 'translate(0,' + (-margin.top) +')')
                    .call(controls);
            }

            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            if (rightAlignYAxis) {
                g.select(".nv-y.nv-axis")
                    .attr("transform", "translate(" + availableWidth + ",0)");
            }

            // Show error if index point value is 0 (division by zero avoided)
            var tempDisabled = data.filter(function(d) { return d.tempDisabled });

            wrap.select('.tempDisabled').remove(); //clean-up and prevent duplicates
            if (tempDisabled.length) {
                wrap.append('text').attr('class', 'tempDisabled')
                    .attr('x', availableWidth / 2)
                    .attr('y', '-.71em')
                    .style('text-anchor', 'end')
                    .text(tempDisabled.map(function(d) { return d.key }).join(', ') + ' values cannot be calculated for this time period.');
            }

            //Set up interactive layer
            if (useInteractiveGuideline) {
                interactiveLayer
                    .width(availableWidth)
                    .height(availableHeight)
                    .margin({left:margin.left,top:margin.top})
                    .svgContainer(container)
                    .xScale(x);
                wrap.select(".nv-interactive").call(interactiveLayer);
            }

            gEnter.select('.nv-background')
                .append('rect');

            g.select('.nv-background rect')
                .attr('width', availableWidth)
                .attr('height', availableHeight);

            lines
                //.x(function(d) { return d.x })
                .y(function(d) { return d.display.y })
                .width(availableWidth)
                .height(availableHeight)
                .color(data.map(function(d,i) {
                    return d.color || color(d, i);
                }).filter(function(d,i) { return !data[i].disabled && !data[i].tempDisabled; }));

            var linesWrap = g.select('.nv-linesWrap')
                .datum(data.filter(function(d) { return  !d.disabled && !d.tempDisabled }));

            linesWrap.call(lines);

            //Store a series index number in the data array.
            data.forEach(function(d,i) {
                d.seriesIndex = i;
            });

            var avgLineData = data.filter(function(d) {
                return !d.disabled && !!average(d);
            });

            var avgLines = g.select(".nv-avgLinesWrap").selectAll("line")
                .data(avgLineData, function(d) { return d.key; });

            var getAvgLineY = function(d) {
                //If average lines go off the svg element, clamp them to the svg bounds.
                var yVal = y(average(d));
                if (yVal < 0) return 0;
                if (yVal > availableHeight) return availableHeight;
                return yVal;
            };

            avgLines.enter()
                .append('line')
                .style('stroke-width',2)
                .style('stroke-dasharray','10,10')
                .style('stroke',function (d,i) {
                    return lines.color()(d,d.seriesIndex);
                })
                .attr('x1',0)
                .attr('x2',availableWidth)
                .attr('y1', getAvgLineY)
                .attr('y2', getAvgLineY);

            avgLines
                .style('stroke-opacity',function(d){
                    //If average lines go offscreen, make them transparent
                    var yVal = y(average(d));
                    if (yVal < 0 || yVal > availableHeight) return 0;
                    return 1;
                })
                .attr('x1',0)
                .attr('x2',availableWidth)
                .attr('y1', getAvgLineY)
                .attr('y2', getAvgLineY);

            avgLines.exit().remove();

            //Create index line
            var indexLine = linesWrap.selectAll('.nv-indexLine')
                .data([index]);
            indexLine.enter().append('rect').attr('class', 'nv-indexLine')
                .attr('width', 3)
                .attr('x', -2)
                .attr('fill', 'red')
                .attr('fill-opacity', .5)
                .style("pointer-events","all")
                .call(indexDrag);

            indexLine
                .attr('transform', function(d) { return 'translate(' + dx(d.i) + ',0)' })
                .attr('height', availableHeight);

            // Setup Axes
            if (showXAxis) {
                xAxis
                    .scale(x)
                    ._ticks( nv.utils.calcTicksX(availableWidth/70, data) )
                    .tickSize(-availableHeight, 0);

                g.select('.nv-x.nv-axis')
                    .attr('transform', 'translate(0,' + y.range()[0] + ')');
                g.select('.nv-x.nv-axis')
                    .call(xAxis);
            }

            if (showYAxis) {
                yAxis
                    .scale(y)
                    ._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
                    .tickSize( -availableWidth, 0);

                g.select('.nv-y.nv-axis')
                    .call(yAxis);
            }

            //============================================================
            // Event Handling/Dispatching (in chart's scope)
            //------------------------------------------------------------

            function updateZero() {
                indexLine
                    .data([index]);

                //When dragging the index line, turn off line transitions.
                // Then turn them back on when done dragging.
                var oldDuration = chart.duration();
                chart.duration(0);
                chart.update();
                chart.duration(oldDuration);
            }

            g.select('.nv-background rect')
                .on('click', function() {
                    index.x = d3.mouse(this)[0];
                    index.i = Math.round(dx.invert(index.x));

                    // update state and send stateChange with new index
                    state.index = index.i;
                    dispatch.stateChange(state);

                    updateZero();
                });

            lines.dispatch.on('elementClick', function(e) {
                index.i = e.pointIndex;
                index.x = dx(index.i);

                // update state and send stateChange with new index
                state.index = index.i;
                dispatch.stateChange(state);

                updateZero();
            });

            controls.dispatch.on('legendClick', function(d,i) {
                d.disabled = !d.disabled;
                rescaleY = !d.disabled;
                state.rescaleY = rescaleY;
                if (!rescaleY) {
                    currentYDomain = getCurrentYDomain(data); // rescale is turned off, so set the currentYDomain
                }
                dispatch.stateChange(state);
                chart.update();
            });

            legend.dispatch.on('stateChange', function(newState) {
                for (var key in newState)
                    state[key] = newState[key];
                dispatch.stateChange(state);
                chart.update();
            });

            interactiveLayer.dispatch.on('elementMousemove', function(e) {
                lines.clearHighlights();
                var singlePoint, pointIndex, pointXLocation, allData = [];

                data
                    .filter(function(series, i) {
                        series.seriesIndex = i;
                        return !(series.disabled || series.tempDisabled);
                    })
                    .forEach(function(series,i) {
                        pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x());
                        lines.highlightPoint(i, pointIndex, true);
                        var point = series.values[pointIndex];
                        if (typeof point === 'undefined') return;
                        if (typeof singlePoint === 'undefined') singlePoint = point;
                        if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex));
                        allData.push({
                            key: series.key,
                            value: chart.y()(point, pointIndex),
                            color: color(series,series.seriesIndex)
                        });
                    });

                //Highlight the tooltip entry based on which point the mouse is closest to.
                if (allData.length > 2) {
                    var yValue = chart.yScale().invert(e.mouseY);
                    var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]);
                    var threshold = 0.03 * domainExtent;
                    var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold);
                    if (indexToHighlight !== null)
                        allData[indexToHighlight].highlight = true;
                }

                var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex), pointIndex);
                interactiveLayer.tooltip
                    .valueFormatter(function(d,i) {
                        return yAxis.tickFormat()(d);
                    })
                    .data(
                    {
                        value: xValue,
                        series: allData
                    }
                )();

                interactiveLayer.renderGuideLine(pointXLocation);
            });

            interactiveLayer.dispatch.on("elementMouseout",function(e) {
                lines.clearHighlights();
            });

            // Update chart from a state object passed to event handler
            dispatch.on('changeState', function(e) {
                if (typeof e.disabled !== 'undefined') {
                    data.forEach(function(series,i) {
                        series.disabled = e.disabled[i];
                    });

                    state.disabled = e.disabled;
                }

                if (typeof e.index !== 'undefined') {
                    index.i = e.index;
                    index.x = dx(index.i);

                    state.index = e.index;

                    indexLine
                        .data([index]);
                }

                if (typeof e.rescaleY !== 'undefined') {
                    rescaleY = e.rescaleY;
                }

                chart.update();
            });

        });

        renderWatch.renderEnd('cumulativeLineChart immediate');

        return chart;
    }

    //============================================================
    // Event Handling/Dispatching (out of chart's scope)
    //------------------------------------------------------------

    lines.dispatch.on('elementMouseover.tooltip', function(evt) {
        var point = {
            x: chart.x()(evt.point),
            y: chart.y()(evt.point),
            color: evt.point.color
        };
        evt.point = point;
        tooltip.data(evt).hidden(false);
    });

    lines.dispatch.on('elementMouseout.tooltip', function(evt) {
        tooltip.hidden(true)
    });

    //============================================================
    // Functions
    //------------------------------------------------------------

    var indexifyYGetter = null;
    /* Normalize the data according to an index point. */
    function indexify(idx, data) {
        if (!indexifyYGetter) indexifyYGetter = lines.y();
        return data.map(function(line, i) {
            if (!line.values) {
                return line;
            }
            var indexValue = line.values[idx];
            if (indexValue == null) {
                return line;
            }
            var v = indexifyYGetter(indexValue, idx);

            // avoid divide by zero
            if (Math.abs(v) < 0.00001 && !noErrorCheck) {
                line.tempDisabled = true;
                return line;
            }

            line.tempDisabled = false;

            line.values = line.values.map(function(point, pointIndex) {
                point.display = {'y': (indexifyYGetter(point, pointIndex) - v) / v };
                return point;
            });

            return line;
        })
    }

    function getCurrentYDomain(data) {
        var seriesDomains = data
            .filter(function(series) { return !(series.disabled || series.tempDisabled)})
            .map(function(series,i) {
                return d3.extent(series.values, function (d) { return d.display.y });
            });

        return [
            d3.min(seriesDomains, function(d) { return d[0] }),
            d3.max(seriesDomains, function(d) { return d[1] })
        ];
    }

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    // expose chart's sub-components
    chart.dispatch = dispatch;
    chart.lines = lines;
    chart.legend = legend;
    chart.controls = controls;
    chart.xAxis = xAxis;
    chart.yAxis = yAxis;
    chart.interactiveLayer = interactiveLayer;
    chart.state = state;
    chart.tooltip = tooltip;

    chart.options = nv.utils.optionsFunc.bind(chart);

    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        width:      {get: function(){return width;}, set: function(_){width=_;}},
        height:     {get: function(){return height;}, set: function(_){height=_;}},
        showControls:     {get: function(){return showControls;}, set: function(_){showControls=_;}},
        showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
        average: {get: function(){return average;}, set: function(_){average=_;}},
        defaultState:    {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
        noData:    {get: function(){return noData;}, set: function(_){noData=_;}},
        showXAxis:    {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
        showYAxis:    {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
        noErrorCheck:    {get: function(){return noErrorCheck;}, set: function(_){noErrorCheck=_;}},

        // options that require extra logic in the setter
        rescaleY:     {get: function(){return rescaleY;}, set: function(_){
            rescaleY = _;
            chart.state.rescaleY = _; // also update state
        }},
        margin: {get: function(){return margin;}, set: function(_){
            if (_.top !== undefined) {
                margin.top = _.top;
                marginTop = _.top;
            }
            margin.right  = _.right  !== undefined ? _.right  : margin.right;
            margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
            margin.left   = _.left   !== undefined ? _.left   : margin.left;
        }},
        color:  {get: function(){return color;}, set: function(_){
            color = nv.utils.getColor(_);
            legend.color(color);
        }},
        useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){
            useInteractiveGuideline = _;
            if (_ === true) {
                chart.interactive(false);
                chart.useVoronoi(false);
            }
        }},
        rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
            rightAlignYAxis = _;
            yAxis.orient( (_) ? 'right' : 'left');
        }},
        duration:    {get: function(){return duration;}, set: function(_){
            duration = _;
            lines.duration(duration);
            xAxis.duration(duration);
            yAxis.duration(duration);
            renderWatch.reset(duration);
        }}
    });

    nv.utils.inheritOptions(chart, lines);
    nv.utils.initOptions(chart);

    return chart;
};
//TODO: consider deprecating by adding necessary features to multiBar model
nv.models.discreteBar = function() {
    "use strict";

    //============================================================
    // Public Variables with Default Settings
    //------------------------------------------------------------

    var margin = {top: 0, right: 0, bottom: 0, left: 0}
        , width = 960
        , height = 500
        , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
        , container
        , x = d3.scale.ordinal()
        , y = d3.scale.linear()
        , getX = function(d) { return d.x }
        , getY = function(d) { return d.y }
        , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove
        , color = nv.utils.defaultColor()
        , showValues = false
        , valueFormat = d3.format(',.2f')
        , xDomain
        , yDomain
        , xRange
        , yRange
        , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd')
        , rectClass = 'discreteBar'
        , duration = 250
        ;

    //============================================================
    // Private Variables
    //------------------------------------------------------------

    var x0, y0;
    var renderWatch = nv.utils.renderWatch(dispatch, duration);

    function chart(selection) {
        renderWatch.reset();
        selection.each(function(data) {
            var availableWidth = width - margin.left - margin.right,
                availableHeight = height - margin.top - margin.bottom;

            container = d3.select(this);
            nv.utils.initSVG(container);

            //add series index to each data point for reference
            data.forEach(function(series, i) {
                series.values.forEach(function(point) {
                    point.series = i;
                });
            });

            // Setup Scales
            // remap and flatten the data for use in calculating the scales' domains
            var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate
                data.map(function(d) {
                    return d.values.map(function(d,i) {
                        return { x: getX(d,i), y: getY(d,i), y0: d.y0 }
                    })
                });

            x   .domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x }))
                .rangeBands(xRange || [0, availableWidth], .1);
            y   .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY)));

            // If showValues, pad the Y axis range to account for label height
            if (showValues) y.range(yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]);
            else y.range(yRange || [availableHeight, 0]);

            //store old scales if they exist
            x0 = x0 || x;
            y0 = y0 || y.copy().range([y(0),y(0)]);

            // Setup containers and skeleton of chart
            var wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([data]);
            var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discretebar');
            var gEnter = wrapEnter.append('g');
            var g = wrap.select('g');

            gEnter.append('g').attr('class', 'nv-groups');
            wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            //TODO: by definition, the discrete bar should not have multiple groups, will modify/remove later
            var groups = wrap.select('.nv-groups').selectAll('.nv-group')
                .data(function(d) { return d }, function(d) { return d.key });
            groups.enter().append('g')
                .style('stroke-opacity', 1e-6)
                .style('fill-opacity', 1e-6);
            groups.exit()
                .watchTransition(renderWatch, 'discreteBar: exit groups')
                .style('stroke-opacity', 1e-6)
                .style('fill-opacity', 1e-6)
                .remove();
            groups
                .attr('class', function(d,i) { return 'nv-group nv-series-' + i })
                .classed('hover', function(d) { return d.hover });
            groups
                .watchTransition(renderWatch, 'discreteBar: groups')
                .style('stroke-opacity', 1)
                .style('fill-opacity', .75);

            var bars = groups.selectAll('g.nv-bar')
                .data(function(d) { return d.values });
            bars.exit().remove();

            var barsEnter = bars.enter().append('g')
                .attr('transform', function(d,i,j) {
                    return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')'
                })
                .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here
                    d3.select(this).classed('hover', true);
                    dispatch.elementMouseover({
                        data: d,
                        index: i,
                        color: d3.select(this).style("fill")
                    });
                })
                .on('mouseout', function(d,i) {
                    d3.select(this).classed('hover', false);
                    dispatch.elementMouseout({
                        data: d,
                        index: i,
                        color: d3.select(this).style("fill")
                    });
                })
                .on('mousemove', function(d,i) {
                    dispatch.elementMousemove({
                        data: d,
                        index: i,
                        color: d3.select(this).style("fill")
                    });
                })
                .on('click', function(d,i) {
                    var element = this;
                    dispatch.elementClick({
                        data: d,
                        index: i,
                        color: d3.select(this).style("fill"),
                        event: d3.event,
                        element: element
                    });
                    d3.event.stopPropagation();
                })
                .on('dblclick', function(d,i) {
                    dispatch.elementDblClick({
                        data: d,
                        index: i,
                        color: d3.select(this).style("fill")
                    });
                    d3.event.stopPropagation();
                });

            barsEnter.append('rect')
                .attr('height', 0)
                .attr('width', x.rangeBand() * .9 / data.length )

            if (showValues) {
                barsEnter.append('text')
                    .attr('text-anchor', 'middle')
                ;

                bars.select('text')
                    .text(function(d,i) { return valueFormat(getY(d,i)) })
                    .watchTransition(renderWatch, 'discreteBar: bars text')
                    .attr('x', x.rangeBand() * .9 / 2)
                    .attr('y', function(d,i) { return getY(d,i) < 0 ? y(getY(d,i)) - y(0) + 12 : -4 })

                ;
            } else {
                bars.selectAll('text').remove();
            }

            bars
                .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive' })
                .style('fill', function(d,i) { return d.color || color(d,i) })
                .style('stroke', function(d,i) { return d.color || color(d,i) })
                .select('rect')
                .attr('class', rectClass)
                .watchTransition(renderWatch, 'discreteBar: bars rect')
                .attr('width', x.rangeBand() * .9 / data.length);
            bars.watchTransition(renderWatch, 'discreteBar: bars')
                //.delay(function(d,i) { return i * 1200 / data[0].values.length })
                .attr('transform', function(d,i) {
                    var left = x(getX(d,i)) + x.rangeBand() * .05,
                        top = getY(d,i) < 0 ?
                            y(0) :
                                y(0) - y(getY(d,i)) < 1 ?
                            y(0) - 1 : //make 1 px positive bars show up above y=0
                            y(getY(d,i));

                    return 'translate(' + left + ', ' + top + ')'
                })
                .select('rect')
                .attr('height', function(d,i) {
                    return  Math.max(Math.abs(y(getY(d,i)) - y(0)), 1)
                });


            //store old scales for use in transitions on update
            x0 = x.copy();
            y0 = y.copy();

        });

        renderWatch.renderEnd('discreteBar immediate');
        return chart;
    }

    //============================================================
    // Expose Public Variables
    //------------------------------------------------------------

    chart.dispatch = dispatch;
    chart.options = nv.utils.optionsFunc.bind(chart);

    chart._options = Object.create({}, {
        // simple options, just get/set the necessary values
        width:   {get: function(){return width;}, set: function(_){width=_;}},
        height:  {get: function(){return height;}, set: function(_){height=_;}},
        forceY:  {get: function(){return forceY;}, set: function(_){forceY=_;}},
        showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}},
        x:       {get: function(){return getX;}, set: function(_){getX=_;}},
        y:       {get: function(){return getY;}, set: function(_){getY=_;}},
        xScale:  {get: function(){return x;}, set: function(_){x=_;}},
        yScale:  {get: function(){return y;}, set: function(_){y=_;}},
        xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
        yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
        xRange:  {get: function(){return xRange;}, set: function(_){xRange=_;}},
        yRange:  {get: function(){r
Download .txt
gitextract_tmwn_v_x/

├── .eslintrc.json
├── .gitignore
├── .jshintrc
├── .travis.yml
├── GruntFile.js
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── bower.json
├── build/
│   ├── nv.d3.css
│   └── nv.d3.js
├── composer.json
├── examples/
│   ├── TimeSeries.html
│   ├── actual.json
│   ├── boxPlot.html
│   ├── boxPlotCustomModel.html
│   ├── bullet.html
│   ├── bulletChart.html
│   ├── candlestick.html
│   ├── candlestickChart.html
│   ├── cumulativeLineChart.html
│   ├── differenceChart.html
│   ├── discreteBarChart.html
│   ├── distroPlotChart.html
│   ├── documentation.html
│   ├── donutChart.html
│   ├── forceDirected.html
│   ├── furiousLegend.html
│   ├── heatMap.html
│   ├── historicalBar.html
│   ├── historicalBarChart.html
│   ├── index.html
│   ├── legend.html
│   ├── lib/
│   │   ├── colorbrewer.js
│   │   └── stream_layers.js
│   ├── line.html
│   ├── lineChart.html
│   ├── lineChartLogScale.html
│   ├── lineChartSVGResize.html
│   ├── linePlusBarChart.html
│   ├── lineWithFocusChart.html
│   ├── lineWithFocusChart_x2AxisLabel.html
│   ├── monitoringChart.html
│   ├── multiBarChart.html
│   ├── multiBarChart2.html
│   ├── multiBarHorizontalChart.html
│   ├── multiChart.html
│   ├── ohlc.html
│   ├── ohlcChart.html
│   ├── parallelCoordinates.html
│   ├── parallelCoordinatesChart.html
│   ├── pie.html
│   ├── pieChart.html
│   ├── predicted.json
│   ├── sankeyChart.html
│   ├── scatter.html
│   ├── scatterChart.html
│   ├── scatterPlusLineChart.html
│   ├── site.html
│   ├── sparkline.html
│   ├── sparklinePlus.html
│   ├── stackedArea.html
│   ├── stackedAreaChart.html
│   ├── stackedAreaWithFocusChart.html
│   ├── stylesheets/
│   │   ├── pygment_trac.css
│   │   └── styles.css
│   ├── sunburst.html
│   └── tooltip.html
├── index.html
├── meteor/
│   └── export.js
├── package.js
├── package.json
├── src/
│   ├── core.js
│   ├── css/
│   │   ├── axis.css
│   │   ├── bars.css
│   │   ├── boxplot.css
│   │   ├── bullet.css
│   │   ├── candlestick.css
│   │   ├── forceDirectedGraph.css
│   │   ├── furiousLegend.css
│   │   ├── lineplusbar.css
│   │   ├── lines.css
│   │   ├── main.css
│   │   ├── ohlc.css
│   │   ├── parallelcoordinates.css
│   │   ├── pie.css
│   │   ├── scatter.css
│   │   ├── sparkline.css
│   │   ├── stackedarea.css
│   │   └── tooltip.css
│   ├── dom.js
│   ├── interactiveLayer.js
│   ├── models/
│   │   ├── axis.js
│   │   ├── boxPlot.js
│   │   ├── boxPlotChart.js
│   │   ├── bullet.js
│   │   ├── bulletChart.js
│   │   ├── candlestickBar.js
│   │   ├── cumulativeLineChart.js
│   │   ├── differenceChart.js
│   │   ├── discreteBar.js
│   │   ├── discreteBarChart.js
│   │   ├── distribution.js
│   │   ├── distroPlot.js
│   │   ├── distroPlotChart.js
│   │   ├── focus.js
│   │   ├── forceDirectedGraph.js
│   │   ├── furiousLegend.js
│   │   ├── heatMap.js
│   │   ├── heatMapChart.js
│   │   ├── historicalBar.js
│   │   ├── historicalBarChart.js
│   │   ├── legend.js
│   │   ├── line.js
│   │   ├── lineChart.js
│   │   ├── linePlusBarChart.js
│   │   ├── multiBar.js
│   │   ├── multiBarChart.js
│   │   ├── multiBarHorizontal.js
│   │   ├── multiBarHorizontalChart.js
│   │   ├── multiChart.js
│   │   ├── ohlcBar.js
│   │   ├── parallelCoordinates.js
│   │   ├── parallelCoordinatesChart.js
│   │   ├── pie.js
│   │   ├── pieChart.js
│   │   ├── sankey.js
│   │   ├── sankeyChart.js
│   │   ├── scatter.js
│   │   ├── scatterChart.js
│   │   ├── sparkline.js
│   │   ├── sparklinePlus.js
│   │   ├── stackedArea.js
│   │   ├── stackedAreaChart.js
│   │   ├── sunburst.js
│   │   └── sunburstChart.js
│   ├── tooltip.js
│   └── utils.js
└── test/
    ├── ScatterChartTest.html
    ├── bootstrapModalTest.html
    ├── boxPlotTest.html
    ├── cumulativeLineChart.html
    ├── lineChartTest.html
    ├── linePlusBarChart.html
    ├── linePlusBarWithFocusChart.html
    ├── lineWithFisheyeChart.html
    ├── lineWithFocusChart.html
    ├── lineWithFocusChartMissingData.html
    ├── mocha/
    │   ├── axis.coffee
    │   ├── boxplot.coffee
    │   ├── bullet.coffee
    │   ├── core.coffee
    │   ├── cumulative-line.coffee
    │   ├── differenceChart.js
    │   ├── discretebar.coffee
    │   ├── distrochart.coffee
    │   ├── heatmap.coffee
    │   ├── historical-bar.coffee
    │   ├── legend.coffee
    │   ├── line.coffee
    │   ├── multibar-horizontal.coffee
    │   ├── multibar.coffee
    │   ├── pie.coffee
    │   ├── sankey.coffee
    │   ├── scatter.coffee
    │   ├── sparkline.coffee
    │   ├── stacked.coffee
    │   ├── sunburst.coffee
    │   ├── test-utils.coffee
    │   └── utils.coffee
    ├── multiBarChartTest.html
    ├── multiBarHorizontalChart.html
    ├── node/
    │   ├── GruntFile.js
    │   ├── README.md
    │   ├── nodeTest.html
    │   ├── nodeTest.js
    │   └── package.json
    ├── pieChartTest.html
    ├── polylinearTest.html
    ├── realTimeChartTest.html
    ├── scatterPlusLineChart.html
    ├── scrollTest.html
    ├── scrollTest2.html
    ├── stackedAreaChartMissingData.html
    ├── stackedAreaChartTest.html
    ├── stream_layers.js
    ├── testScript.js
    ├── teststyle.css
    ├── tinytest/
    │   └── nv-is-defined-test.js
    └── translateTest.html
Download .txt
SYMBOL INDEX (207 symbols across 52 files)

FILE: build/nv.d3.js
  function layer (line 209) | function layer(selection) {
  function initTooltip (line 781) | function initTooltip() {
  function nvtooltip (line 802) | function nvtooltip() {
  function symbol (line 1426) | function symbol(d,i) {
  function chart (line 1653) | function chart(selection) {
  function chart (line 2051) | function chart(selection) {
  function chart (line 2380) | function chart(selection) {
  function sortLabels (line 2604) | function sortLabels(labels, values){
  function chart (line 2613) | function chart(selection) {
  function chart (line 2913) | function chart(selection) {
  function chart (line 3135) | function chart(selection) {
  function chart (line 3412) | function chart(selection) {
  function indexify (line 3867) | function indexify(idx, data) {
  function getCurrentYDomain (line 3896) | function getCurrentYDomain(data) {
  function chart (line 4019) | function chart(selection) {
  function chart (line 4296) | function chart(selection) {
  function chart (line 4551) | function chart(selection) {
  function select_sigma (line 4750) | function select_sigma(x) {
  function calcBandwidth (line 4783) | function calcBandwidth(x, type) {
  function prepData (line 4849) | function prepData(dat) {
  function kernelDensityEstimator (line 5008) | function kernelDensityEstimator(kernel, X) {
  function clampViolinKDE (line 5024) | function clampViolinKDE(kde, extent) {
  function eKernel (line 5045) | function eKernel(scale) {
  function makeNotchBox (line 5065) | function makeNotchBox(boxLeft, notchLeft, boxCenter, dat) {
  function getAvailableColorGroups (line 5098) | function getAvailableColorGroups(x) {
  function isOutlier (line 5105) | function isOutlier(d) {
  function chart (line 5121) | function chart(selection) {
  function dataHasChanged (line 5634) | function dataHasChanged(d) {
  function arraysEqual (line 5644) | function arraysEqual(arr1, arr2) {
  function objectEquals (line 5660) | function objectEquals(a, b) {
  function chart (line 5685) | function chart(selection) {
  function chart (line 5952) | function chart(selection) {
  function chart (line 6245) | function chart(selection) {
  function chart (line 6423) | function chart(selection) {
  function cellTextColor (line 6807) | function cellTextColor(bgColor) {
  function getHeatmapValues (line 6830) | function getHeatmapValues(data, axis) {
  function mad (line 6852) | function mad(dat) {
  function cellColor (line 6861) | function cellColor(d) {
  function getColorDomain (line 6871) | function getColorDomain() {
  function cellsAreNumeric (line 6882) | function cellsAreNumeric() {
  function normalizeData (line 6901) | function normalizeData(dat) {
  function prepData (line 6990) | function prepData(data) {
  function isArrayInArray (line 7089) | function isArrayInArray(arr, item){
  function removeAllHoverClasses (line 7098) | function removeAllHoverClasses() {
  function sortObjByVals (line 7115) | function sortObjByVals(obj) {
  function getKeyByValue (line 7120) | function getKeyByValue(object, value) {
  function chart (line 7143) | function chart(selection) {
  function quantizeLegendValues (line 7659) | function quantizeLegendValues() {
  function hasRowMeta (line 7683) | function hasRowMeta() {
  function hasColumnMeta (line 7687) | function hasColumnMeta() {
  function chart (line 7693) | function chart(selection) {
  function chart (line 7981) | function chart(selection) {
  function chart (line 8238) | function chart(selection) {
  function chart (line 8612) | function chart(selection) {
  function chart (line 9024) | function chart(selection) {
  function chart (line 9285) | function chart(selection) {
  function chart (line 9871) | function chart(selection) {
  function chart (line 10478) | function chart(selection) {
  function chart (line 10988) | function chart(selection) {
  function chart (line 11440) | function chart(selection) {
  function chart (line 11848) | function chart(selection) {
  function chart (line 12214) | function chart(selection) {
  function chart (line 12814) | function chart(selection) {
  function chart (line 13048) | function chart(selection) {
  function chart (line 13569) | function chart(selection) {
  function chart (line 13843) | function chart(selection) {
  function chart (line 14335) | function chart(selection) {
  function link (line 14569) | function link(d) {
  function computeNodeLinks (line 14605) | function computeNodeLinks() {
  function computeNodeValues (line 14623) | function computeNodeValues() {
  function computeNodeBreadths (line 14636) | function computeNodeBreadths() {
  function moveSourcesRight (line 14669) | function moveSourcesRight() {
  function moveSinksRight (line 14677) | function moveSinksRight(x) {
  function scaleNodeBreadths (line 14685) | function scaleNodeBreadths(kx) {
  function computeNodeDepths (line 14692) | function computeNodeDepths(iterations) {
  function computeLinkDepths (line 14803) | function computeLinkDepths() {
  function value (line 14830) | function value(x) {
  function chart (line 14914) | function chart(selection) {
  function getCache (line 15185) | function getCache(d) {
  function delCache (line 15192) | function delCache(d) {
  function getDiffs (line 15198) | function getDiffs(d) {
  function chart (line 15213) | function chart(selection) {
  function chart (line 15901) | function chart(selection) {
  function chart (line 16251) | function chart(selection) {
  function chart (line 16392) | function chart(selection) {
  function chart (line 16625) | function chart(selection) {
  function chart (line 17007) | function chart(selection) {
  function rotationToAvoidUpsideDown (line 17641) | function rotationToAvoidUpsideDown(d) {
  function computeCenterAngle (line 17651) | function computeCenterAngle(d) {
  function computeNodePercentage (line 17658) | function computeNodePercentage(d) {
  function labelThresholdMatched (line 17664) | function labelThresholdMatched(d) {
  function arcTweenZoom (line 17673) | function arcTweenZoom(e,i) {
  function arcTweenUpdate (line 17690) | function arcTweenUpdate(d) {
  function updatePrevPosition (line 17705) | function updatePrevPosition(node) {
  function storeRetrievePrevPositions (line 17715) | function storeRetrievePrevPositions(nodes) {
  function zoomClick (line 17736) | function zoomClick(d) {
  function chart (line 17797) | function chart(selection) {
  function chart (line 18020) | function chart(selection) {

FILE: examples/lib/stream_layers.js
  function stream_layers (line 3) | function stream_layers(n, m, o) {
  function stream_waves (line 23) | function stream_waves(n, m) {
  function stream_index (line 32) | function stream_index(d, i) {

FILE: src/interactiveLayer.js
  function layer (line 28) | function layer(selection) {

FILE: src/models/axis.js
  function chart (line 40) | function chart(selection) {

FILE: src/models/boxPlot.js
  function chart (line 40) | function chart(selection) {

FILE: src/models/boxPlotChart.js
  function chart (line 44) | function chart(selection) {

FILE: src/models/bullet.js
  function sortLabels (line 36) | function sortLabels(labels, values){
  function chart (line 45) | function chart(selection) {

FILE: src/models/bulletChart.js
  function chart (line 33) | function chart(selection) {

FILE: src/models/candlestickBar.js
  function chart (line 39) | function chart(selection) {

FILE: src/models/cumulativeLineChart.js
  function chart (line 90) | function chart(selection) {
  function indexify (line 545) | function indexify(idx, data) {
  function getCurrentYDomain (line 574) | function getCurrentYDomain(data) {

FILE: src/models/differenceChart.js
  function chart (line 57) | function chart(selection) {
  function processData (line 303) | function processData(data) {
  function isDefined (line 453) | function isDefined(thingToCheck) {

FILE: src/models/discreteBar.js
  function chart (line 39) | function chart(selection) {

FILE: src/models/discreteBarChart.js
  function chart (line 61) | function chart(selection) {

FILE: src/models/distribution.js
  function chart (line 33) | function chart(selection) {

FILE: src/models/distroPlot.js
  function select_sigma (line 72) | function select_sigma(x) {
  function calcBandwidth (line 105) | function calcBandwidth(x, type) {
  function prepData (line 171) | function prepData(dat) {
  function kernelDensityEstimator (line 330) | function kernelDensityEstimator(kernel, X) {
  function clampViolinKDE (line 346) | function clampViolinKDE(kde, extent) {
  function eKernel (line 367) | function eKernel(scale) {
  function makeNotchBox (line 387) | function makeNotchBox(boxLeft, notchLeft, boxCenter, dat) {
  function getAvailableColorGroups (line 420) | function getAvailableColorGroups(x) {
  function isOutlier (line 427) | function isOutlier(d) {
  function chart (line 443) | function chart(selection) {

FILE: src/models/distroPlotChart.js
  function dataHasChanged (line 56) | function dataHasChanged(d) {
  function arraysEqual (line 66) | function arraysEqual(arr1, arr2) {
  function objectEquals (line 82) | function objectEquals(a, b) {
  function chart (line 107) | function chart(selection) {

FILE: src/models/focus.js
  function chart (line 39) | function chart(selection) {

FILE: src/models/forceDirectedGraph.js
  function chart (line 38) | function chart(selection) {

FILE: src/models/furiousLegend.js
  function chart (line 25) | function chart(selection) {

FILE: src/models/heatMap.js
  function cellTextColor (line 60) | function cellTextColor(bgColor) {
  function getHeatmapValues (line 83) | function getHeatmapValues(data, axis) {
  function mad (line 105) | function mad(dat) {
  function cellColor (line 114) | function cellColor(d) {
  function getColorDomain (line 124) | function getColorDomain() {
  function cellsAreNumeric (line 135) | function cellsAreNumeric() {
  function normalizeData (line 154) | function normalizeData(dat) {
  function prepData (line 243) | function prepData(data) {
  function isArrayInArray (line 342) | function isArrayInArray(arr, item){
  function removeAllHoverClasses (line 351) | function removeAllHoverClasses() {
  function sortObjByVals (line 368) | function sortObjByVals(obj) {
  function getKeyByValue (line 373) | function getKeyByValue(object, value) {
  function chart (line 396) | function chart(selection) {

FILE: src/models/heatMapChart.js
  function quantizeLegendValues (line 86) | function quantizeLegendValues() {
  function hasRowMeta (line 110) | function hasRowMeta() {
  function hasColumnMeta (line 114) | function hasColumnMeta() {
  function chart (line 120) | function chart(selection) {

FILE: src/models/historicalBar.js
  function chart (line 33) | function chart(selection) {

FILE: src/models/historicalBarChart.js
  function chart (line 56) | function chart(selection) {

FILE: src/models/legend.js
  function chart (line 26) | function chart(selection) {

FILE: src/models/line.js
  function chart (line 48) | function chart(selection) {

FILE: src/models/lineChart.js
  function chart (line 80) | function chart(selection) {

FILE: src/models/linePlusBarChart.js
  function chart (line 108) | function chart(selection) {

FILE: src/models/multiBar.js
  function chart (line 46) | function chart(selection) {

FILE: src/models/multiBarChart.js
  function chart (line 121) | function chart(selection) {

FILE: src/models/multiBarHorizontal.js
  function chart (line 46) | function chart(selection) {

FILE: src/models/multiBarHorizontalChart.js
  function chart (line 92) | function chart(selection) {

FILE: src/models/multiChart.js
  function chart (line 57) | function chart(selection) {

FILE: src/models/ohlcBar.js
  function chart (line 39) | function chart(selection) {

FILE: src/models/parallelCoordinates.js
  function chart (line 42) | function chart(selection) {

FILE: src/models/parallelCoordinatesChart.js
  function chart (line 72) | function chart(selection) {

FILE: src/models/pie.js
  function chart (line 46) | function chart(selection) {

FILE: src/models/pieChart.js
  function chart (line 62) | function chart(selection) {

FILE: src/models/sankey.js
  function link (line 35) | function link(d) {
  function computeNodeLinks (line 71) | function computeNodeLinks() {
  function computeNodeValues (line 89) | function computeNodeValues() {
  function computeNodeBreadths (line 102) | function computeNodeBreadths() {
  function moveSourcesRight (line 135) | function moveSourcesRight() {
  function moveSinksRight (line 143) | function moveSinksRight(x) {
  function scaleNodeBreadths (line 151) | function scaleNodeBreadths(kx) {
  function computeNodeDepths (line 158) | function computeNodeDepths(iterations) {
  function computeLinkDepths (line 269) | function computeLinkDepths() {
  function value (line 296) | function value(x) {

FILE: src/models/sankeyChart.js
  function chart (line 53) | function chart(selection) {

FILE: src/models/scatter.js
  function getCache (line 89) | function getCache(d) {
  function delCache (line 96) | function delCache(d) {
  function getDiffs (line 102) | function getDiffs(d) {
  function chart (line 117) | function chart(selection) {

FILE: src/models/scatterChart.js
  function chart (line 80) | function chart(selection) {

FILE: src/models/sparkline.js
  function chart (line 34) | function chart(selection) {

FILE: src/models/sparklinePlus.js
  function chart (line 33) | function chart(selection) {

FILE: src/models/stackedArea.js
  function chart (line 51) | function chart(selection) {

FILE: src/models/stackedAreaChart.js
  function chart (line 100) | function chart(selection) {

FILE: src/models/sunburst.js
  function rotationToAvoidUpsideDown (line 50) | function rotationToAvoidUpsideDown(d) {
  function computeCenterAngle (line 60) | function computeCenterAngle(d) {
  function computeNodePercentage (line 67) | function computeNodePercentage(d) {
  function labelThresholdMatched (line 73) | function labelThresholdMatched(d) {
  function arcTweenZoom (line 82) | function arcTweenZoom(e,i) {
  function arcTweenUpdate (line 99) | function arcTweenUpdate(d) {
  function updatePrevPosition (line 114) | function updatePrevPosition(node) {
  function storeRetrievePrevPositions (line 124) | function storeRetrievePrevPositions(nodes) {
  function zoomClick (line 145) | function zoomClick(d) {
  function chart (line 206) | function chart(selection) {

FILE: src/models/sunburstChart.js
  function chart (line 38) | function chart(selection) {

FILE: src/tooltip.js
  function initTooltip (line 263) | function initTooltip() {
  function nvtooltip (line 284) | function nvtooltip() {

FILE: src/utils.js
  function symbol (line 567) | function symbol(d,i) {

FILE: test/mocha/differenceChart.js
  function setupBenv (line 66) | function setupBenv(done) {

FILE: test/node/nodeTest.js
  function exampleData (line 18) | function exampleData() {

FILE: test/stream_layers.js
  function stream_layers (line 3) | function stream_layers(n, m, o) {
  function stream_waves (line 23) | function stream_waves(n, m) {
  function stream_index (line 32) | function stream_index(d, i) {
Condensed preview — 190 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,218K chars).
[
  {
    "path": ".eslintrc.json",
    "chars": 998,
    "preview": "{\n  \"env\": {\n    \"browser\": true,\n    \"node\": true,\n    \"es6\": true,\n    \"mocha\": true\n  },\n  \"extends\": \"eslint:recomme"
  },
  {
    "path": ".gitignore",
    "chars": 124,
    "preview": "\n.idea\n*.swp\n*~\n*.log\n.DS_Store*\nehthumbs.db\nIcon?\nThumbs.db\nnode_modules\nbower_components\ncoverage\ntest-results.xml\n*.o"
  },
  {
    "path": ".jshintrc",
    "chars": 20,
    "preview": "{\n    \"asi\": true\n}\n"
  },
  {
    "path": ".travis.yml",
    "chars": 445,
    "preview": "language: node_js\nnode_js:\n    - \"0.12\"\nbefore_install:\n    - \"npm install -g bower\"\n    - \"npm install -g grunt-cli\"\n  "
  },
  {
    "path": "GruntFile.js",
    "chars": 6071,
    "preview": "module.exports = function(grunt) {\n    var _pkg = grunt.file.readJSON('package.json');\n\n    // allows autoprefixer to wo"
  },
  {
    "path": "ISSUE_TEMPLATE.md",
    "chars": 734,
    "preview": "PLEASE READ THIS BEFORE SUBMITTING A NEW ISSUE.\n\nARE YOU ASKING FOR HELP? Please use Stack Overflow tag nvd3.js and incl"
  },
  {
    "path": "LICENSE.md",
    "chars": 2075,
    "preview": "##nvd3.js License\n\nCopyright (c) 2011-2014 [Novus Partners, Inc.][novus]\n\nLicensed under the Apache License, Version 2.0"
  },
  {
    "path": "README.md",
    "chars": 7817,
    "preview": "## NVD3 - A reusable D3 charting library\n\nInspired by the work of Mike Bostock's [Towards Reusable Charts](http://bost.o"
  },
  {
    "path": "bower.json",
    "chars": 643,
    "preview": "{\n  \"name\": \"nvd3\",\n  \"homepage\": \"http://www.nvd3.org\",\n  \"authors\": [\n    \"Bob Monteverde\",\n    \"Tyler Wolf\",\n    \"Rob"
  },
  {
    "path": "build/nv.d3.css",
    "chars": 12015,
    "preview": "/* nvd3 version 1.8.6-dev (https://github.com/novus/nvd3) 2018-02-24 */\n.nvd3 .nv-axis {\r\n    pointer-events:none;\r\n    "
  },
  {
    "path": "build/nv.d3.js",
    "chars": 757167,
    "preview": "/* nvd3 version 1.8.6-dev (https://github.com/novus/nvd3) 2018-02-24 */\n(function(){\n\n// set up main nv object\nvar nv = "
  },
  {
    "path": "composer.json",
    "chars": 503,
    "preview": "{\n  \"name\": \"novus/nvd3\",\n  \"description\": \"A reusable charting library written in d3.js\",\n  \"keywords\": [\n    \"nvd3\",\n "
  },
  {
    "path": "examples/TimeSeries.html",
    "chars": 8666,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/actual.json",
    "chars": 216039,
    "preview": "[{\"key\":{\"measurement_point\":\"elec_energy_consumed\",\"units\":\"kWh\",\"interval_length\":30,\"timezone\":\"Asia/Tokyo\"},\"values\""
  },
  {
    "path": "examples/boxPlot.html",
    "chars": 1856,
    "preview": "<!DOCTYPE html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n"
  },
  {
    "path": "examples/boxPlotCustomModel.html",
    "chars": 2809,
    "preview": "<!DOCTYPE html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n"
  },
  {
    "path": "examples/bullet.html",
    "chars": 1746,
    "preview": "<!DOCTYPE html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n"
  },
  {
    "path": "examples/bulletChart.html",
    "chars": 3367,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/candlestick.html",
    "chars": 10106,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/candlestickChart.html",
    "chars": 10860,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/cumulativeLineChart.html",
    "chars": 18330,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/differenceChart.html",
    "chars": 5920,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <"
  },
  {
    "path": "examples/discreteBarChart.html",
    "chars": 2251,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/distroPlotChart.html",
    "chars": 133669,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<script src=\".."
  },
  {
    "path": "examples/documentation.html",
    "chars": 54060,
    "preview": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\">\n    "
  },
  {
    "path": "examples/donutChart.html",
    "chars": 3818,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/forceDirected.html",
    "chars": 15750,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/furiousLegend.html",
    "chars": 2614,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/heatMap.html",
    "chars": 17907,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<script src=\"ht"
  },
  {
    "path": "examples/historicalBar.html",
    "chars": 2152,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/historicalBarChart.html",
    "chars": 2284,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/index.html",
    "chars": 5873,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <title>NVD3 Examples List</title>\n</head>\n<body>\n    <script src=\"http://ajax.googleap"
  },
  {
    "path": "examples/legend.html",
    "chars": 2479,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/lib/colorbrewer.js",
    "chars": 18990,
    "preview": "// This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/).\nvar col"
  },
  {
    "path": "examples/lib/stream_layers.js",
    "chars": 922,
    "preview": "\n/* Inspired by Lee Byron's test data generator. */\nfunction stream_layers(n, m, o) {\n  if (arguments.length < 3) o = 0;"
  },
  {
    "path": "examples/line.html",
    "chars": 2587,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/lineChart.html",
    "chars": 4336,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/lineChartLogScale.html",
    "chars": 2357,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/lineChartSVGResize.html",
    "chars": 3876,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/linePlusBarChart.html",
    "chars": 6880,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/lineWithFocusChart.html",
    "chars": 1491,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/lineWithFocusChart_x2AxisLabel.html",
    "chars": 1632,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/monitoringChart.html",
    "chars": 4738,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"utf-8\">\n        <link href=\"../build/nv.d3.css\" rel=\"styleshee"
  },
  {
    "path": "examples/multiBarChart.html",
    "chars": 2547,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/multiBarChart2.html",
    "chars": 2137,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/multiBarHorizontalChart.html",
    "chars": 5546,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/multiChart.html",
    "chars": 1996,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/ohlc.html",
    "chars": 23140,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/ohlcChart.html",
    "chars": 23894,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/parallelCoordinates.html",
    "chars": 121018,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/parallelCoordinatesChart.html",
    "chars": 7794,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"utf-8\">\n        <link href=\"../build/nv.d3.css\" rel=\"stylesheet"
  },
  {
    "path": "examples/pie.html",
    "chars": 2790,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/pieChart.html",
    "chars": 4044,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/predicted.json",
    "chars": 201520,
    "preview": "[{\"actual\":54.36052778662519,\"falling_edge\":\"2017-06-30 15:00:00+00:00\",\"predicted\":54.36052778662519,\"rising_edge\":\"201"
  },
  {
    "path": "examples/sankeyChart.html",
    "chars": 4077,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/scatter.html",
    "chars": 1424,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/scatterChart.html",
    "chars": 2631,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/scatterPlusLineChart.html",
    "chars": 2140,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/site.html",
    "chars": 7062,
    "preview": "<!doctype html>\r\n<html>\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\">\r"
  },
  {
    "path": "examples/sparkline.html",
    "chars": 1144,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/sparklinePlus.html",
    "chars": 2385,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/stackedArea.html",
    "chars": 3672,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/stackedAreaChart.html",
    "chars": 29005,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/stackedAreaWithFocusChart.html",
    "chars": 29216,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/stylesheets/pygment_trac.css",
    "chars": 4354,
    "preview": ".highlight .hll { background-color: #404040 }\r\n.highlight  { color: #d0d0d0 }\r\n.highlight .c { color: #999999; font-styl"
  },
  {
    "path": "examples/stylesheets/styles.css",
    "chars": 23152,
    "preview": "/*\r\nLeap Day for GitHub Pages\r\nby Matt Graham\r\n*/\r\n\r\n\r\n/* normalize.css 2012-02-07T12:37 UTC - http://github.com/necolas"
  },
  {
    "path": "examples/sunburst.html",
    "chars": 21048,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "examples/tooltip.html",
    "chars": 3630,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "index.html",
    "chars": 612,
    "preview": "<html><body>\n<style>\nhtml, body, iframe {\n margin: 0px;\n padding: 0px;\n width: 100%;\n height: 100%;\n border: 0px;\n}\n</st"
  },
  {
    "path": "meteor/export.js",
    "chars": 158,
    "preview": "/*global nv:true*/  // Meteor creates a file-scope global for exporting. This comment prevents a potential JSHint warnin"
  },
  {
    "path": "package.js",
    "chars": 937,
    "preview": "// Package metadata for Meteor.js full stack web framework\n// This file is defined in Meteor documentation at http://doc"
  },
  {
    "path": "package.json",
    "chars": 1330,
    "preview": "{\n  \"name\": \"nvd3\",\n  \"version\": \"1.8.6-dev\",\n  \"description\": \"A reusable charting library written in d3.js\",\n  \"url\": "
  },
  {
    "path": "src/core.js",
    "chars": 5097,
    "preview": "\n// set up main nv object\nvar nv = {};\n\n// the major global objects under the nv namespace\nnv.dev = false; //set false w"
  },
  {
    "path": "src/css/axis.css",
    "chars": 818,
    "preview": ".nvd3 .nv-axis {\r\n    pointer-events:none;\r\n    opacity: 1;\r\n}\r\n\r\n.nvd3 .nv-axis path {\r\n    fill: none;\r\n    stroke: #0"
  },
  {
    "path": "src/css/bars.css",
    "chars": 911,
    "preview": ".nvd3 .nv-bars rect {\r\n    fill-opacity: .75;\r\n\r\n    transition: fill-opacity 250ms linear;\r\n}\n\r\n.nvd3 .nv-bars rect.hov"
  },
  {
    "path": "src/css/boxplot.css",
    "chars": 277,
    "preview": "/* boxplot CSS */\n.nvd3 .nv-boxplot circle {\n  fill-opacity: 0.5;\n}\n\n.nvd3 .nv-boxplot circle:hover {\n  fill-opacity: 1;"
  },
  {
    "path": "src/css/bullet.css",
    "chars": 854,
    "preview": "/* bullet */\r\n.nvd3.nv-bullet { font: 10px sans-serif; }\r\n.nvd3.nv-bullet .nv-measure { fill-opacity: .8; }\r\n.nvd3.nv-bu"
  },
  {
    "path": "src/css/candlestick.css",
    "chars": 570,
    "preview": ".nvd3.nv-candlestickBar .nv-ticks .nv-tick {\r\n    stroke-width: 1px;\r\n}\r\n\r\n.nvd3.nv-candlestickBar .nv-ticks .nv-tick.ho"
  },
  {
    "path": "src/css/forceDirectedGraph.css",
    "chars": 172,
    "preview": ".nv-force-node {\n    stroke: #fff;\n    stroke-width: 1.5px;\n}\n\n.nv-force-link {\n    stroke: #999;\n    stroke-opacity: .6"
  },
  {
    "path": "src/css/furiousLegend.css",
    "chars": 391,
    "preview": ".nvd3 .nv-legend .nv-disabled rect {\n    /*fill-opacity: 0;*/\n}\n\n.nvd3 .nv-check-box .nv-box {\n    fill-opacity:0;\n    s"
  },
  {
    "path": "src/css/lineplusbar.css",
    "chars": 153,
    "preview": "/* line plus bar */\r\n.nvd3.nv-linePlusBar .nv-bar rect {\r\n    fill-opacity: .75;\r\n}\r\n\r\n.nvd3.nv-linePlusBar .nv-bar rect"
  },
  {
    "path": "src/css/lines.css",
    "chars": 830,
    "preview": ".nvd3 .nv-groups path.nv-line {\r\n    fill: none;\r\n}\r\n\r\n.nvd3 .nv-groups path.nv-area {\r\n    stroke: none;\r\n}\r\n\r\n.nvd3.nv"
  },
  {
    "path": "src/css/main.css",
    "chars": 1332,
    "preview": "/********************\r\n * SVG CSS\r\n */\r\n\r\n/********************\r\n  Default CSS for an svg element nvd3 used\r\n*/\r\nsvg.nvd"
  },
  {
    "path": "src/css/ohlc.css",
    "chars": 292,
    "preview": ".nvd3.nv-ohlcBar .nv-ticks .nv-tick {\r\n    stroke-width: 1px;\r\n}\r\n\r\n.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover {\r\n    str"
  },
  {
    "path": "src/css/parallelcoordinates.css",
    "chars": 570,
    "preview": ".nvd3 .background path {\r\n    fill: none;\r\n    stroke: #EEE;\r\n    stroke-opacity: .4;\r\n    shape-rendering: crispEdges;\r"
  },
  {
    "path": "src/css/pie.css",
    "chars": 649,
    "preview": ".nvd3.nv-pie path {\r\n    stroke-opacity: 0;\r\n    transition: fill-opacity 250ms linear, stroke-width 250ms linear, strok"
  },
  {
    "path": "src/css/scatter.css",
    "chars": 276,
    "preview": "/* scatter */\r\n.nvd3 .nv-groups .nv-point.hover {\r\n    stroke-width: 20px;\r\n    stroke-opacity: .5;\r\n}\r\n\r\n.nvd3 .nv-scat"
  },
  {
    "path": "src/css/sparkline.css",
    "chars": 866,
    "preview": "/* sparkline */\r\n.nvd3.nv-sparkline path {\r\n    fill: none;\r\n}\r\n\r\n.nvd3.nv-sparklineplus g.nv-hoverValue {\r\n    pointer-"
  },
  {
    "path": "src/css/stackedarea.css",
    "chars": 347,
    "preview": "/* stacked area */\r\n.nvd3.nv-stackedarea path.nv-area {\r\n    fill-opacity: .7;\r\n    stroke-opacity: 0;\r\n    transition: "
  },
  {
    "path": "src/css/tooltip.css",
    "chars": 2405,
    "preview": ".nvtooltip {\n    position: absolute;\r\n    background-color: rgba(255,255,255,1.0);\r\n    color: rgba(0,0,0,1.0);\r\n    pad"
  },
  {
    "path": "src/dom.js",
    "chars": 711,
    "preview": "/* Facade for queueing DOM write operations\r\n * with Fastdom (https://github.com/wilsonpage/fastdom)\r\n * if available.\r\n"
  },
  {
    "path": "src/interactiveLayer.js",
    "chars": 12957,
    "preview": "/* Utility class to handle creation of an interactive layer.\n This places a rectangle on top of the chart. When you mous"
  },
  {
    "path": "src/models/axis.js",
    "chars": 21199,
    "preview": "nv.models.axis = function() {\n    \"use strict\";\n\n    //============================================================\n    "
  },
  {
    "path": "src/models/boxPlot.js",
    "chars": 15766,
    "preview": "nv.models.boxPlot = function() {\n    \"use strict\";\n\n    //============================================================\n "
  },
  {
    "path": "src/models/boxPlotChart.js",
    "chars": 8898,
    "preview": "nv.models.boxPlotChart = function() {\n    \"use strict\";\n\n    //========================================================="
  },
  {
    "path": "src/models/bullet.js",
    "chars": 13205,
    "preview": "\n// Chart design based on the recommendations of Stephen Few. Implementation\n// based on the work of Clint Ivy, Jamie Lo"
  },
  {
    "path": "src/models/bulletChart.js",
    "chars": 8582,
    "preview": "\n// Chart design based on the recommendations of Stephen Few. Implementation\n// based on the work of Clint Ivy, Jamie Lo"
  },
  {
    "path": "src/models/candlestickBar.js",
    "chars": 10237,
    "preview": "\nnv.models.candlestickBar = function() {\n    \"use strict\";\n\n    //======================================================"
  },
  {
    "path": "src/models/cumulativeLineChart.js",
    "chars": 24629,
    "preview": "\nnv.models.cumulativeLineChart = function() {\n    \"use strict\";\n\n    //================================================="
  },
  {
    "path": "src/models/differenceChart.js",
    "chars": 14652,
    "preview": "'use strict';\n\nnv.models.differenceChart = function () {\n  'use strict';\n\n  var container = void 0;\n  var multiChart = n"
  },
  {
    "path": "src/models/discreteBar.js",
    "chars": 11489,
    "preview": "//TODO: consider deprecating by adding necessary features to multiBar model\nnv.models.discreteBar = function() {\n    \"us"
  },
  {
    "path": "src/models/discreteBarChart.js",
    "chars": 10345,
    "preview": "\nnv.models.discreteBarChart = function() {\n    \"use strict\";\n\n    //===================================================="
  },
  {
    "path": "src/models/distribution.js",
    "chars": 5554,
    "preview": "\nnv.models.distribution = function() {\n    \"use strict\";\n    //========================================================="
  },
  {
    "path": "src/models/distroPlot.js",
    "chars": 44971,
    "preview": "nv.models.distroPlot = function() {\n    \"use strict\";\n\n    // IMPROVEMENTS:\n    // - cleanup tooltip to look like candle"
  },
  {
    "path": "src/models/distroPlotChart.js",
    "chars": 12469,
    "preview": "nv.models.distroPlotChart = function() {\n    \"use strict\";\n\n    //======================================================"
  },
  {
    "path": "src/models/focus.js",
    "chars": 11210,
    "preview": "nv.models.focus = function(content) {\n    \"use strict\";\n\n    //========================================================="
  },
  {
    "path": "src/models/forceDirectedGraph.js",
    "chars": 7358,
    "preview": "nv.models.forceDirectedGraph = function() {\n    \"use strict\";\n\n    //==================================================="
  },
  {
    "path": "src/models/furiousLegend.js",
    "chars": 15899,
    "preview": "nv.models.furiousLegend = function() {\n    \"use strict\";\n\n    //========================================================"
  },
  {
    "path": "src/models/heatMap.js",
    "chars": 37187,
    "preview": "/* \nImprovements:\n- consistenly apply no-hover classes to rect isntead of to containing g, see example CSS style for .no"
  },
  {
    "path": "src/models/heatMapChart.js",
    "chars": 13546,
    "preview": "/* Heatmap Chart Type\n\nA heatmap is a graphical representation of data where the individual values\ncontained in a matrix"
  },
  {
    "path": "src/models/historicalBar.js",
    "chars": 10270,
    "preview": "//TODO: consider deprecating and using multibar with single series for this\nnv.models.historicalBar = function() {\n    \""
  },
  {
    "path": "src/models/historicalBarChart.js",
    "chars": 15724,
    "preview": "\nnv.models.historicalBarChart = function(bar_model) {\n    \"use strict\";\n\n    //========================================="
  },
  {
    "path": "src/models/legend.js",
    "chars": 17604,
    "preview": "nv.models.legend = function() {\n    \"use strict\";\n\n    //============================================================\n  "
  },
  {
    "path": "src/models/line.js",
    "chars": 10111,
    "preview": "\nnv.models.line = function() {\n    \"use strict\";\n    //============================================================\n    "
  },
  {
    "path": "src/models/lineChart.js",
    "chars": 23129,
    "preview": "nv.models.lineChart = function() {\n    \"use strict\";\n\n    //============================================================"
  },
  {
    "path": "src/models/linePlusBarChart.js",
    "chars": 26768,
    "preview": "nv.models.linePlusBarChart = function() {\n    \"use strict\";\n\n    //====================================================="
  },
  {
    "path": "src/models/multiBar.js",
    "chars": 19741,
    "preview": "\nnv.models.multiBar = function() {\n    \"use strict\";\n\n    //============================================================"
  },
  {
    "path": "src/models/multiBarChart.js",
    "chars": 20456,
    "preview": "nv.models.multiBarChart = function() {\n    \"use strict\";\n\n    //========================================================"
  },
  {
    "path": "src/models/multiBarHorizontal.js",
    "chars": 16892,
    "preview": "\nnv.models.multiBarHorizontal = function() {\n    \"use strict\";\n\n    //=================================================="
  },
  {
    "path": "src/models/multiBarHorizontalChart.js",
    "chars": 15070,
    "preview": "\nnv.models.multiBarHorizontalChart = function() {\n    \"use strict\";\n\n    //============================================="
  },
  {
    "path": "src/models/multiChart.js",
    "chars": 29032,
    "preview": "nv.models.multiChart = function() {\n    \"use strict\";\n\n    //==========================================================="
  },
  {
    "path": "src/models/ohlcBar.js",
    "chars": 10179,
    "preview": "\nnv.models.ohlcBar = function() {\n    \"use strict\";\n\n    //============================================================\n"
  },
  {
    "path": "src/models/parallelCoordinates.js",
    "chars": 23636,
    "preview": "// Code adapted from Jason Davies' \"Parallel Coordinates\"\n// http://bl.ocks.org/jasondavies/1341281\nnv.models.parallelCo"
  },
  {
    "path": "src/models/parallelCoordinatesChart.js",
    "chars": 12770,
    "preview": "nv.models.parallelCoordinatesChart = function () {\n        \"use strict\";\n        //====================================="
  },
  {
    "path": "src/models/pie.js",
    "chars": 21565,
    "preview": "nv.models.pie = function() {\n    \"use strict\";\n\n    //============================================================\n    /"
  },
  {
    "path": "src/models/pieChart.js",
    "chars": 9979,
    "preview": "nv.models.pieChart = function() {\n    \"use strict\";\n\n    //============================================================\n"
  },
  {
    "path": "src/models/sankey.js",
    "chars": 11011,
    "preview": "nv.models.sankey = function() {\n    'use strict';\n\n    // Sources:\n    // - https://bost.ocks.org/mike/sankey/\n    // - "
  },
  {
    "path": "src/models/sankeyChart.js",
    "chars": 8961,
    "preview": "nv.models.sankeyChart = function() {\n    \"use strict\";\n\n    // Sources:\n    // - https://bost.ocks.org/mike/sankey/\n    "
  },
  {
    "path": "src/models/scatter.js",
    "chars": 36396,
    "preview": "\nnv.models.scatter = function() {\n    \"use strict\";\n\n    //============================================================\n"
  },
  {
    "path": "src/models/scatterChart.js",
    "chars": 15755,
    "preview": "\nnv.models.scatterChart = function() {\n    \"use strict\";\n\n    //========================================================"
  },
  {
    "path": "src/models/sparkline.js",
    "chars": 6384,
    "preview": "\nnv.models.sparkline = function() {\n    \"use strict\";\n\n    //==========================================================="
  },
  {
    "path": "src/models/sparklinePlus.js",
    "chars": 8763,
    "preview": "\nnv.models.sparklinePlus = function() {\n    \"use strict\";\n\n    //======================================================="
  },
  {
    "path": "src/models/stackedArea.js",
    "chars": 13475,
    "preview": "\nnv.models.stackedArea = function() {\n    \"use strict\";\n\n    //========================================================="
  },
  {
    "path": "src/models/stackedAreaChart.js",
    "chars": 28021,
    "preview": "\nnv.models.stackedAreaChart = function() {\n    \"use strict\";\n\n    //===================================================="
  },
  {
    "path": "src/models/sunburst.js",
    "chars": 15447,
    "preview": "// based on http://bl.ocks.org/kerryrodden/477c1bfb081b783f80ad\nnv.models.sunburst = function() {\n    \"use strict\";\n\n   "
  },
  {
    "path": "src/models/sunburstChart.js",
    "chars": 5003,
    "preview": "nv.models.sunburstChart = function() {\n    \"use strict\";\n\n    //========================================================"
  },
  {
    "path": "src/tooltip.js",
    "chars": 14647,
    "preview": "\n/* Model which can be instantiated to handle tooltip rendering.\n Example usage:\n var tip = nv.models.tooltip().gravity("
  },
  {
    "path": "src/utils.js",
    "chars": 22527,
    "preview": "\n\n/*\nGets the browser window size\n\nReturns object with height and width properties\n */\nnv.utils.windowSize = function() "
  },
  {
    "path": "test/ScatterChartTest.html",
    "chars": 6548,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<link href=\"te"
  },
  {
    "path": "test/bootstrapModalTest.html",
    "chars": 2143,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "test/boxPlotTest.html",
    "chars": 10366,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<link href=\"tes"
  },
  {
    "path": "test/cumulativeLineChart.html",
    "chars": 37902,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../src/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n\n<style>\n\nbody {"
  },
  {
    "path": "test/lineChartTest.html",
    "chars": 14089,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<"
  },
  {
    "path": "test/linePlusBarChart.html",
    "chars": 7097,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../src/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n\n<style>\n\nbody {"
  },
  {
    "path": "test/linePlusBarWithFocusChart.html",
    "chars": 7470,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../src/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n\n<style>\n\nbody {"
  },
  {
    "path": "test/lineWithFisheyeChart.html",
    "chars": 2393,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../src/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n\n<style>\n\nbody {"
  },
  {
    "path": "test/lineWithFocusChart.html",
    "chars": 1835,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../src/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n\n<style>\n\nbody {"
  },
  {
    "path": "test/lineWithFocusChartMissingData.html",
    "chars": 1903,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "test/mocha/axis.coffee",
    "chars": 4920,
    "preview": "describe 'NVD3', ->\n    describe 'Axis', ->\n        sampleData1 = [\n            key: 'Series 1'\n            values: [\n  "
  },
  {
    "path": "test/mocha/boxplot.coffee",
    "chars": 4176,
    "preview": "describe 'NVD3', ->\n    describe 'Box Plot', ->\n        sampleData1 = [\n            label: 'Sample A',\n            value"
  },
  {
    "path": "test/mocha/bullet.coffee",
    "chars": 6434,
    "preview": "describe 'NVD3', ->\n\n    describe 'Bullet Chart', ->\n        sampleData1 =\n            title: 'Revenue'\n            subt"
  },
  {
    "path": "test/mocha/core.coffee",
    "chars": 635,
    "preview": "describe 'NVD3', ->\n\n  describe 'Core', ->\n\n    objects = [\n      'window.nv'\n      'd3_time_range'\n      'nv.utils'\n   "
  },
  {
    "path": "test/mocha/cumulative-line.coffee",
    "chars": 8011,
    "preview": "describe 'NVD3', ->\n    describe 'Cumulative Line Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n       "
  },
  {
    "path": "test/mocha/differenceChart.js",
    "chars": 34782,
    "preview": "(function () {\n  'use strict';\n\n  var clean = void 0,\n      benv = void 0,\n      _sinon = void 0,\n      ChartFactory = v"
  },
  {
    "path": "test/mocha/discretebar.coffee",
    "chars": 2277,
    "preview": "describe 'NVD3', ->\n    describe 'Discrete Bar Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n          "
  },
  {
    "path": "test/mocha/distrochart.coffee",
    "chars": 22006,
    "preview": "describe 'NVD3', ->\n    describe 'Distrochart', ->\n        data = [\n            {subject: 3, weight: 19, isolator: 'C', "
  },
  {
    "path": "test/mocha/heatmap.coffee",
    "chars": 15696,
    "preview": "describe 'NVD3', ->\n    describe 'heatMapChart', ->\n        data = [\n            {day: 'Mo', hour: 1, value: 16, group: "
  },
  {
    "path": "test/mocha/historical-bar.coffee",
    "chars": 2152,
    "preview": "describe 'NVD3', ->\n    describe 'Historical Bar Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n        "
  },
  {
    "path": "test/mocha/legend.coffee",
    "chars": 3750,
    "preview": "describe 'NVD3', ->\n  describe 'Legend', ->\n    sampleData1 = [\n      {\"values\":[{\"x\":1,\"y\":2},{\"x\":3,\"y\":4},{\"x\":5,\"y\":"
  },
  {
    "path": "test/mocha/line.coffee",
    "chars": 4713,
    "preview": "describe 'NVD3', ->\n    describe 'Line Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n            values"
  },
  {
    "path": "test/mocha/multibar-horizontal.coffee",
    "chars": 3082,
    "preview": "describe 'NVD3', ->\n    describe 'MultiBar Horizontal Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n   "
  },
  {
    "path": "test/mocha/multibar.coffee",
    "chars": 3573,
    "preview": "describe 'NVD3', ->\n    describe 'MultiBar Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n            va"
  },
  {
    "path": "test/mocha/pie.coffee",
    "chars": 4691,
    "preview": "describe 'NVD3', ->\n    describe 'Pie Chart', ->\n        sampleData1 = [\n            {label: 'America', value: 100}\n    "
  },
  {
    "path": "test/mocha/sankey.coffee",
    "chars": 2450,
    "preview": "describe 'NVD3', ->\n  describe 'Sankey Chart', ->\n    sampleData1 =\n      nodes:\n        [\n          {'node': 1, 'name':"
  },
  {
    "path": "test/mocha/scatter.coffee",
    "chars": 6581,
    "preview": "describe 'NVD3', ->\n    describe 'Scatter Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n            slo"
  },
  {
    "path": "test/mocha/sparkline.coffee",
    "chars": 1877,
    "preview": "describe 'NVD3', ->\n    describe 'Sparkline Chart', ->\n        sampleData1 = [\n            {x: 1, y: 100}\n            {x"
  },
  {
    "path": "test/mocha/stacked.coffee",
    "chars": 4593,
    "preview": "describe 'NVD3', ->\n    describe 'Stacked Area Chart', ->\n        sampleData1 = [\n            key: 'Series 1'\n          "
  },
  {
    "path": "test/mocha/sunburst.coffee",
    "chars": 8872,
    "preview": "describe 'NVD3', ->\n    describe 'Sunburst', ->\n        sampleData1 = [{\n            \"name\": \"flare\",\n            \"child"
  },
  {
    "path": "test/mocha/test-utils.coffee",
    "chars": 1955,
    "preview": "###\nUtility to build an NVD3 chart.\n###\nclass ChartBuilder\n    # @model should be something like nv.models.scatterChart("
  },
  {
    "path": "test/mocha/utils.coffee",
    "chars": 6421,
    "preview": "describe 'NVD3', ->\n  describe 'Utils', ->\n    objects = [\n      'nv.utils.windowSize'\n      'nv.utils.windowResize'\n   "
  },
  {
    "path": "test/multiBarChartTest.html",
    "chars": 6714,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<link href=\"tes"
  },
  {
    "path": "test/multiBarHorizontalChart.html",
    "chars": 8504,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n\n<style>\n\nbody"
  },
  {
    "path": "test/node/GruntFile.js",
    "chars": 421,
    "preview": "module.exports = function(grunt) {\n  grunt.initConfig({\n    browserify: {\n      js: {\n        src: './nodeTest.js', dest"
  },
  {
    "path": "test/node/README.md",
    "chars": 292,
    "preview": "Build steps:\n\n- Build `nvd3`.\n- Build the example.\n- Start an HTTP server.\n\n    nvd3 $ grunt production\n    nvd3 $ cd te"
  },
  {
    "path": "test/node/nodeTest.html",
    "chars": 249,
    "preview": "<!doctype html>\n<html>\n<head>\n  <title>Node Test</title>\n  <meta charset=\"utf-8\">\n  <link rel=\"stylesheet\" href=\"./build"
  },
  {
    "path": "test/node/nodeTest.js",
    "chars": 680,
    "preview": "window.d3 = require('d3');\nvar nv = require('../../build/nv.d3');\nvar invariant = require('invariant');\n\nwindow.addEvent"
  },
  {
    "path": "test/node/package.json",
    "chars": 234,
    "preview": "{\n  \"name\": \"node-test\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"d3\": \"<=3.4.4\",\n    \"invarian"
  },
  {
    "path": "test/pieChartTest.html",
    "chars": 4448,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<link href=\"tes"
  },
  {
    "path": "test/polylinearTest.html",
    "chars": 4909,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<link href=\"te"
  },
  {
    "path": "test/realTimeChartTest.html",
    "chars": 2184,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<link href=\"te"
  },
  {
    "path": "test/scatterPlusLineChart.html",
    "chars": 2251,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../src/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n\n<style>\n\nbody {"
  },
  {
    "path": "test/scrollTest.html",
    "chars": 2215,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "test/scrollTest2.html",
    "chars": 3324,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "test/stackedAreaChartMissingData.html",
    "chars": 28969,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  },
  {
    "path": "test/stackedAreaChartTest.html",
    "chars": 67073,
    "preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\">\n\n<link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text/css\">\n<script src=\"."
  },
  {
    "path": "test/stream_layers.js",
    "chars": 922,
    "preview": "\n/* Inspired by Lee Byron's test data generator. */\nfunction stream_layers(n, m, o) {\n  if (arguments.length < 3) o = 0;"
  },
  {
    "path": "test/testScript.js",
    "chars": 690,
    "preview": "//A little snippet of D3 code that creates a button that lets you toggle whether a chart is the only one visible on a pa"
  },
  {
    "path": "test/teststyle.css",
    "chars": 414,
    "preview": "body {\n  overflow-y:scroll;\n  font-family: arial;\n}\n\ntext {\n  font: 12px sans-serif;\n}\n\n.chart {\n  float:left;\n  height:"
  },
  {
    "path": "test/tinytest/nv-is-defined-test.js",
    "chars": 158,
    "preview": "// nv-is-defined-test.js\n\nTinytest.add('nv object is defined', function(test) {\n  test.isNotUndefined(nv, 'nv is undefin"
  },
  {
    "path": "test/translateTest.html",
    "chars": 936,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link href=\"../build/nv.d3.css\" rel=\"stylesheet\" type=\"text"
  }
]

About this extraction

This page contains the full source code of the novus/nvd3 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 190 files (2.9 MB), approximately 773.6k tokens, and a symbol index with 207 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!