diff --git a/nvd3/nvd-test-bullet.ts b/nvd3/nvd-test-bullet.ts
new file mode 100644
index 000000000..7ec2363e0
--- /dev/null
+++ b/nvd3/nvd-test-bullet.ts
@@ -0,0 +1,46 @@
+///
+///
+
+var width = 960,
+ height = 55,
+ margin = {top: 5, right: 40, bottom: 20, left: 120};
+
+ var chart = nv.models.bullet()
+ .width(width - margin.right - margin.left)
+ .height(height - margin.top - margin.bottom);
+
+ var data = [
+ {"title":"Revenue","subtitle":"US$, in thousands","ranges":[-150,-225,-300],"measures":[-220],"markers":[-250]}
+ ];
+
+ //TODO: to be consistent with other models, should be appending a g to an already made svg, not creating the svg element
+ var vis = d3.select("#chart").selectAll("svg")
+ .data(data)
+ .enter().append("svg")
+ .attr("class", "bullet nvd3")
+ .attr("width", width)
+ .attr("height", height);
+
+ vis.transition().duration(1000).call(chart);
+
+ var transition = function() {
+ vis.datum(randomize);
+ vis.transition().duration(1000).call(chart);
+ };
+
+ function randomize(d) {
+ if (!d.randomizer) d.randomizer = randomizer(d);
+ d.ranges = d.ranges.map(d.randomizer);
+ d.markers = d.markers.map(d.randomizer);
+ d.measures = d.measures.map(d.randomizer);
+ return d;
+ }
+
+ function randomizer(d) {
+ var k = d3.max(d.ranges) * .2;
+ return function(d) {
+ return Math.max(0, d + k * (Math.random() - .5));
+ };
+ }
+
+ d3.select('body').on('click', transition);
\ No newline at end of file
diff --git a/nvd3/nvd-test-bulletChart.ts b/nvd3/nvd-test-bulletChart.ts
new file mode 100644
index 000000000..eb727589e
--- /dev/null
+++ b/nvd3/nvd-test-bulletChart.ts
@@ -0,0 +1,72 @@
+///
+///
+
+var width = 960,
+ height = 80,
+ margin = {top: 5, right: 40, bottom: 20, left: 120};
+
+var chart = nv.models.bulletChart()
+ .width(width - margin.right - margin.left)
+ .height(height - margin.top - margin.bottom);
+
+var chart2 = nv.models.bulletChart()
+ .width(width - margin.right - margin.left)
+ .height(height - margin.top - margin.bottom);
+
+var data = [
+ {"title":"Revenue","subtitle":"US$, in thousands","ranges":[150,225,300],"measures":[220],"markers":[250]},
+ {"title":"Order Size","subtitle":"US$, average","ranges":[350,500,600],"measures":[100],"markers":[550]},
+ {"title":"Satisfaction","subtitle":"out of 5","ranges":[3.5,4.25,5],"measures":[3.2,4.7],"markers":[4.4]}
+];
+
+var dataWithLabels = [{
+ "title":"Revenue",
+ "subtitle":"US$, in thousands",
+ "ranges":[150,225,300],
+ "measures":[220],
+ "markers":[250, 100],
+ "markerLabels":['Target Inventory', 'Low Inventory'],
+ "rangeLabels":['Maximum Inventory','Average Inventory','Minimum Inventory'],
+ "measureLabels":['Current Inventory']
+}];
+
+//TODO: to be consistent with other models, should be appending a g to an already made svg, not creating the svg element
+var vis = d3.select("#chart").selectAll("svg")
+ .data(data)
+ .enter().append("svg")
+ .attr("class", "bullet nvd3")
+ .attr("width", width)
+ .attr("height", height);
+
+vis.transition().duration(1000).call(chart);
+
+var vis2 = d3.select("#chart2").selectAll("svg")
+ .data(dataWithLabels)
+ .enter().append('svg')
+ .attr('class',"bullet nvd3")
+ .attr("width",width)
+ .attr("height",height);
+
+vis2.transition().duration(1000).call(chart2);
+
+var transition = function() {
+ vis.datum(randomize).transition().duration(1000).call(chart);
+ vis2.datum(randomize).transition().duration(1000).call(chart2);
+};
+
+function randomize(d) {
+ if (!d.randomizer) d.randomizer = randomizer(d);
+ d.ranges = d.ranges.map(d.randomizer);
+ d.markers = d.markers.map(d.randomizer);
+ d.measures = d.measures.map(d.randomizer);
+ return d;
+}
+
+function randomizer(d) {
+ var k = d3.max(d.ranges) * .2;
+ return function(d) {
+ return Math.max(0, d + k * (Math.random() - .5));
+ };
+ }
+
+ d3.select('body').on('click', transition);
\ No newline at end of file
diff --git a/nvd3/nvd3-test-boxplot.ts b/nvd3/nvd3-test-boxplot.ts
new file mode 100644
index 000000000..3b7809531
--- /dev/null
+++ b/nvd3/nvd3-test-boxplot.ts
@@ -0,0 +1,57 @@
+///
+///
+nv.addGraph(function() {
+ var chart = nv.models.boxPlotChart()
+ .x(function(d) { return d.label })
+ .y(function(d) { return d.values.Q3 })
+ .staggerLabels(true)
+ .maxBoxWidth(75) // prevent boxes from being incredibly wide
+ .yDomain([0, 500])
+ ;
+
+ d3.select('#chart1 svg')
+ .datum(exampleData())
+ .call(chart);
+
+ nv.utils.windowResize(chart.update);
+
+ return chart;
+ });
+
+ function exampleData() {
+ return [
+ {
+ label: "Sample A",
+ values: {
+ Q1: 120,
+ Q2: 150,
+ Q3: 200,
+ whisker_low: 115,
+ whisker_high: 210,
+ outliers: [50, 100, 225]
+ },
+ },
+ {
+ label: "Sample B",
+ values: {
+ Q1: 300,
+ Q2: 350,
+ Q3: 400,
+ whisker_low: 225,
+ whisker_high: 425,
+ outliers: [175]
+ },
+ },
+ {
+ label: "Sample C",
+ values: {
+ Q1: 50,
+ Q2: 100,
+ Q3: 125,
+ whisker_low: 25,
+ whisker_high: 175,
+ outliers: [0]
+ },
+ }
+ ];
+ }
\ No newline at end of file
diff --git a/nvd3/nvd3-test-historicalBar.ts b/nvd3/nvd3-test-historicalBar.ts
new file mode 100644
index 000000000..dc765cdcd
--- /dev/null
+++ b/nvd3/nvd3-test-historicalBar.ts
@@ -0,0 +1,59 @@
+///
+///
+nv.addGraph({
+ generate: function() {
+ var chart = nv.models.historicalBar();
+
+ d3.select("#test1")
+ .datum(sinData())
+ .datum(sinData())
+ .transition()
+ .call(chart);
+
+ return chart;
+ },
+ callback: function(graph) {
+ graph.dispatch.on('elementMouseover', function(e) {
+ var offsetElement = document.getElementById("chart"),
+ left = e.pos[0],
+ top = e.pos[1];
+ var content = '
' + e.point.y + '
';
+
+ nv.tooltip.show([left, top], content, e.value < 0 ? 'n' : 's');
+ });
+
+ graph.dispatch.on('elementMouseout', function(e) {
+ nv.tooltip.cleanup();
+ });
+ }
+});
+
+//Simple test data generators
+function sinAndCos() {
+ var sin = [],
+ cos = [];
+
+ for (var i = 0; i < 100; i++) {
+ sin.push({x: i, y: Math.sin(i/10)});
+ cos.push({x: i, y: .5 * Math.cos(i/10)});
+ }
+
+ return [
+ {values: sin, key: "Sine Wave", color: "#ff7f0e"},
+ {values: cos, key: "Cosine Wave", color: "#2ca02c"}
+ ];
+}
+
+function sinData() {
+ var sin = [];
+
+ for (var i = 0; i < 100; i++) {
+ sin.push({x: i, y: Math.sin(i/10)});
+ }
+
+ return [{
+ values: sin,
+ key: "Sine Wave",
+ color: "#ff7f0e"
+ }];
+}
\ No newline at end of file
diff --git a/nvd3/nvd3-test-historicalBarChart.ts b/nvd3/nvd3-test-historicalBarChart.ts
new file mode 100644
index 000000000..dfd8a30ae
--- /dev/null
+++ b/nvd3/nvd3-test-historicalBarChart.ts
@@ -0,0 +1,165 @@
+///
+///
+var data = [{
+ values : []
+ }];
+
+ var i, x;
+ var gap = false;
+ var prevVal = 3000;
+ var tickCount = 100;
+ var probEnterGap = 0.1;
+ var probExitGap = 0.2;
+ var barTimespan = 30 * 60; // thirty minutes in seconds
+ var startOfTime = 1425096000;
+ for (i = 0; i < tickCount; i++) {
+ x = startOfTime + i * barTimespan;
+ if (!gap) {
+ if (Math.random() > probEnterGap) {
+ prevVal += (Math.random() - 0.5) * 500;
+ if (prevVal <= 0) {
+ prevVal = Math.random() * 100;
+ }
+ data[0].values.push({x: x * 1000, y: prevVal});
+ }
+ else {
+ gap = true;
+ }
+ }
+ else {
+ if (Math.random() < probExitGap) {
+ gap = false;
+ }
+ }
+ }
+
+ var chart : nv.HistoricalBarChart;
+
+ var halfBarXMin = data[0].values[0].x - barTimespan / 2 * 1000;
+ var halfBarXMax = data[0].values[data[0].values.length-1].x + barTimespan / 2 * 1000;
+
+ function renderChart(location, meaning) {
+ nv.addGraph(function() {
+ chart = nv.models.historicalBarChart();
+ chart
+ .xScale(d3.time.scale()) // use a time scale instead of plain numbers in order to get nice round default values in the axis
+ .color(['#68c'])
+ .forceX([halfBarXMin, halfBarXMax]) // fix half-bar problem on the first and last bars
+ .useInteractiveGuideline(true) // check out the css that turns the guideline into this nice thing
+ .margin({"left": 80, "right": 50, "top": 20, "bottom": 30})
+ .duration(0)
+ ;
+
+ var tickMultiFormat = d3.time.format.multi([
+ ["%-I:%M%p", function(d) { return d.getMinutes(); }], // not the beginning of the hour
+ ["%-I%p", function(d) { return d.getHours(); }], // not midnight
+ ["%b %-d", function(d) { return d.getDate() != 1; }], // not the first of the month
+ ["%b %-d", function(d) { return d.getMonth(); }], // not Jan 1st
+ ["%Y", function() { return true; }]
+ ]);
+ chart.xAxis
+ .showMaxMin(false)
+ .tickPadding(10)
+ .tickFormat(function (d) { return tickMultiFormat(new Date(d)); })
+ ;
+
+ chart.yAxis
+ .showMaxMin(false)
+ .tickFormat(d3.format(",.0f"))
+ ;
+
+ var svgElem = d3.select(location);
+ svgElem
+ .datum(data)
+ .transition()
+ .call(chart);
+
+ // make our own x-axis tick marks because NVD3 doesn't provide any
+ var tickY2 = chart.yAxis.scale().range()[1];
+ var lineElems = svgElem
+ .select('.nv-x.nv-axis.nvd3-svg')
+ .select('.nvd3.nv-wrap.nv-axis')
+ .select('g')
+ .selectAll('.tick')
+ .data(chart.xScale().ticks())
+ .append('line')
+ .attr('class', 'x-axis-tick-mark')
+ .attr('x2', 0)
+ .attr('y1', tickY2 + 4)
+ .attr('y2', tickY2)
+ .attr('stroke-width', 1)
+ ;
+
+ // set up the tooltip to display full dates
+ var tsFormat = d3.time.format('%b %-d, %Y %I:%M%p');
+ var contentGenerator = chart.interactiveLayer.tooltip.contentGenerator();
+ var tooltip = chart.interactiveLayer.tooltip;
+ tooltip.contentGenerator(function (d) { d.value = d.series[0].data.x; return contentGenerator(d); });
+ tooltip.headerFormatter(function (d) { return tsFormat(new Date(d)); });
+
+ // common stuff for the sections below
+ var xScale = chart.xScale();
+ var xPixelFirstBar = xScale(data[0].values[0].x);
+ var xPixelSecondBar = xScale(data[0].values[0].x + barTimespan * 1000);
+ var barWidth = xPixelSecondBar - xPixelFirstBar; // number of pixels representing time delta per bar
+
+ // fix the bar widths so they don't overlap when there are gaps
+ function fixBarWidths(barSpacingFraction) {
+ svgElem
+ .selectAll('.nv-bars')
+ .selectAll('rect')
+ .attr('width', (1 - barSpacingFraction) * barWidth)
+ .attr('transform', function(d, i) {
+ var deltaX = xScale(data[0].values[i].x) - xPixelFirstBar;
+ deltaX += barSpacingFraction / 2 * barWidth;
+ return 'translate(' + deltaX + ', 0)';
+ })
+ ;
+ }
+
+ /*
+ If you're representing sample measurements spaced a certain time apart, the tick marks should
+ be in the middle of the bars and some spacing between bars is recommended to aid with interpretation.
+ On the other hand, if you want to represent a quantity measured over a span of time (one bar), you're
+ better off placing the ticks on the edge of the bar and leaving no gap in between bars.
+ */
+ function shiftXAxis() {
+ var xAxisElem = svgElem.select('.nv-axis.nv-x');
+ var transform = xAxisElem.attr('transform');
+ var xShift = -barWidth/2;
+ transform = transform.replace('0,', xShift + ',');
+ xAxisElem.attr('transform', transform);
+ }
+
+ if (meaning === 'instant') {
+ fixBarWidths(0.2);
+ }
+ else if (meaning === 'timespan') {
+ fixBarWidths(0.0);
+ shiftXAxis();
+ }
+
+ return chart;
+ });
+ }
+
+ renderChart('#test1', 'instant');
+ renderChart('#test2', 'timespan');
+
+ window.setTimeout(function() {
+ window.setTimeout(function() {
+ document.getElementById('sc-one').style.display = 'block';
+ document.getElementById('sc-two').style.display = 'none';
+ }, 0);
+ }, 0);
+
+ function switchChartStyle(style) {
+ if (style === 'instant') {
+ document.getElementById('sc-one').style.display = 'block';
+ document.getElementById('sc-two').style.display = 'none';
+ }
+ else if (style === 'timespan') {
+ document.getElementById('sc-one').style.display = 'none';
+ document.getElementById('sc-two').style.display = 'block';
+ }
+ }
diff --git a/nvd3/nvd3-test-legend.ts b/nvd3/nvd3-test-legend.ts
new file mode 100644
index 000000000..81f39d2da
--- /dev/null
+++ b/nvd3/nvd3-test-legend.ts
@@ -0,0 +1,67 @@
+///
+///
+var width = 500,
+ height = 20;
+
+ var legend = nv.models.legend();
+
+ d3.select('#test1')
+ .attr('width', width)
+ .attr('height', height)
+ .datum(sinAndCos());
+
+ var legend2 = nv.models.legend()
+ .align(false);
+
+ d3.select('#test2')
+ .attr('width', width)
+ .attr('height', height)
+ .datum(sinAndCos()).call(legend2);
+
+ var legend3 = nv.models.legend()
+ .width(900)
+ .padding(70);
+
+ d3.select('#test3')
+ .attr('width', 900)
+ .attr('height', 200)
+ .datum(sinAndCos()).call(legend3);
+
+ var update = function() {
+ d3.select('#test1').call(legend);
+ }
+
+ update();
+ legend.dispatch.on('stateChange', function(d) {
+ console.log(d);
+ update();
+ });
+
+ d3.select('#changeData').on('click', function() {
+ d3.select('#test1')
+ .datum(differentData())
+ .call(legend);
+ });
+
+ function sinAndCos() {
+ return [
+ {key: "Sine Wave"},
+ {key: "A Very Long Label With Over Twenty Characters"},
+ {key: "A Very Long Series Label With Over Twenty Characters"},
+ {key: "A Very Long Series Label With Over Twenty Characters"},
+ {key: "Cosine Wave"},
+ {key: "Another test label"}
+ ];
+ }
+
+ function differentData() {
+ return [
+ {key: "Fixed Income"},
+ {key: "Derivatives"},
+ {key: "Credit Default Swaps"},
+ {key: "Equities"},
+ {key: "Bonds"},
+ {key: "Stocks"},
+ {key: "Apple"}
+ ];
+ }
diff --git a/nvd3/nvd3-test-ohlcChart.ts b/nvd3/nvd3-test-ohlcChart.ts
new file mode 100644
index 000000000..b62027f63
--- /dev/null
+++ b/nvd3/nvd3-test-ohlcChart.ts
@@ -0,0 +1,36 @@
+///
+///
+var data = [{values: [
+ {"date": 15707, "open": 145.11, "high": 146.15, "low": 144.73, "close": 146.06, "volume": 192059000, "adjusted": 144.65},
+ {"date": 15953, "open": 165.85, "high": 166.4, "low": 165.73, "close": 165.96, "volume": 62930500, "adjusted": 165.96}
+ ]}];
+
+nv.addGraph(function() {
+ var chart = nv.models.ohlcBarChart()
+ .x(function(d) { return d['date'] })
+ .y(function(d) { return d['close'] })
+ .duration(250)
+ .margin({left: 75, bottom: 50});
+
+ // chart sub-models (ie. xAxis, yAxis, etc) when accessed directly, return themselves, not the parent chart, so need to chain separately
+ chart.xAxis
+ .axisLabel("Dates")
+ .tickFormat(function(d) {
+ // I didn't feel like changing all the above date values
+ // so I hack it to make each value fall on a different date
+ return d3.time.format('%x')(new Date(new Date().valueOf() - (20000 * 86400000) + (d * 86400000)));
+ });
+
+ chart.yAxis
+ .axisLabel('Stock Price')
+ .tickFormat(function(d,i){ return '$' + d3.format(',.1f')(d); });
+
+
+
+ d3.select("#chart1 svg")
+ .datum(data)
+ .transition().duration(500)
+ .call(chart);
+ nv.utils.windowResize(chart.update);
+ return chart;
+});
\ No newline at end of file
diff --git a/nvd3/nvd3-test-tooltip.ts b/nvd3/nvd3-test-tooltip.ts
new file mode 100644
index 000000000..ee45f9ea7
--- /dev/null
+++ b/nvd3/nvd3-test-tooltip.ts
@@ -0,0 +1,55 @@
+///
+///
+var width = 500,
+ height = 20;
+
+ var tooltip = nv.models.tooltip();
+ tooltip.duration(0);
+
+ d3.select('.tooltip_me')
+ .on('mouseover', function(d,i) {
+ console.log("mouseover", d, i);
+ var data = {series: {
+ key: "title",
+ value: "the value",
+ color: "#229922"
+ }};
+ tooltip.data(data).hidden(false);
+ })
+ .on('mouseout', function(d,i) {
+ console.log("mouseout", d, i);
+ tooltip.hidden(true);
+ })
+ .on('mousemove', function(d,i) {
+ console.log("mousemove", d, i);
+ tooltip.position({top: d3.event.pageY, left: d3.event.pageX})();
+ });
+
+
+ // we must also test the scatter/line way of getting position
+ // Wrapping in nv.addGraph allows for '0 timeout render', stores rendered charts in nv.graphs, and may do more in the future... it's NOT required
+ var chart;
+ nv.addGraph(function() {
+ chart = nv.models.lineChart()
+ .showXAxis(false)
+ .showLegend(false)
+ .clipVoronoi(false)
+ .showVoronoi(true)
+ .showYAxis(false);
+ d3.select('#test2')
+ .datum(sinAndCos())
+ .call(chart);
+ return chart;
+ });
+
+ function sinAndCos() {
+ var cos = [];
+ for (var i = 0; i < 5; i++) {
+ cos.push({x: i, y: Math.round(.5 * Math.cos(i/10) * 100) / 100});
+ }
+ return [{
+ values: cos,
+ key: "Cosine Wave",
+ color: "#2ca02c"
+ }];
+ }
diff --git a/nvd3/nvd3.d.ts b/nvd3/nvd3.d.ts
new file mode 100644
index 000000000..0fb9db4ed
--- /dev/null
+++ b/nvd3/nvd3.d.ts
@@ -0,0 +1,252 @@
+// Type definitions for nvd3 1.8.1
+// Project: https://github.com/novus/nvd3
+// Definitions by: Maxime LUCE
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+declare module nv {
+
+// interface Datum{
+// values: any[],
+// key: string,
+// color: string
+// }
+
+ interface Margin {
+ left?: number,
+ right?: number,
+ top?: number,
+ bottom?: number
+ }
+
+ interface Legend extends Chart