var app = angular.module('plunker', ['nvd3']);

app.controller('MainCtrl', function($scope, nvd3XRangeBarsPlugin, nvd3XMarkersPlugin, nvd3Plugins) {
    nvd3Plugins.addPlugin('x-range-bars', nvd3XRangeBarsPlugin);
    nvd3Plugins.addPlugin('x-markers', nvd3XMarkersPlugin);
    var dataBars = [{
        label: 'ver 1',
        from: -10,
        to: 15
    }, {
        label: 'ver 2.0',
        from: 25,
        to: 40
    }];
    var dataMarkers = [{
        label: 'beta',
        x: 30,
    }, {
        label: 'release',
        x: 42
    }];

    $scope.options = {
        plugins: [{
            type: 'x-range-bars'
        }, {
            type: 'x-markers'
        }, ],
        chart: {
            zoom: true,
            type: 'lineChart',
            height: 450,
            margin: {
                top: 20,
                right: 20,
                bottom: 40,
                left: 55
            },
            x: function(d) {
                return d.x;
            },
            y: function(d) {
                return d.y;
            },
            useInteractiveGuideline: true,
            dispatch: {
                stateChange: function(e) {
                    console.log("stateChange");
                },
                changeState: function(e) {
                    console.log("changeState");
                },
                tooltipShow: function(e) {
                    console.log("tooltipShow");
                },
                tooltipHide: function(e) {
                    console.log("tooltipHide");
                }
            },
            xAxis: {
                axisLabel: 'Time (ms)',
                tickFormat:function (d) {
                        return d3.time.format('%X')(new Date(d*3600))
                    }
            },
            yAxis: {
                axisLabel: 'Voltage (v)',
                tickFormat: function(d) {
                    return d3.format('.02f')(d);
                },
                axisLabelDistance: -10
            },
            callback: function(chart) {
                console.log("!!! lineChart callback !!!");
            }
        },
        title: {
            enable: true,
            text: 'Title for Line Chart'
        },
        subtitle: {
            enable: true,
            text: 'Subtitle for simple line chart. Lorem ipsum dolor sit amet, at eam blandit sadipscing, vim adhuc sanctus disputando ex, cu usu affert alienum urbanitas.',
            css: {
                'text-align': 'center',
                'margin': '10px 13px 0px 7px'
            }
        },
        caption: {
            enable: true,
            html: '<b>Figure 1.</b> Lorem ipsum dolor sit amet, at eam blandit sadipscing, <span style="text-decoration: underline;">vim adhuc sanctus disputando ex</span>, cu usu affert alienum urbanitas. <i>Cum in purto erat, mea ne nominavi persecuti reformidans.</i> Docendi blandit abhorreant ea has, minim tantas alterum pro eu. <span style="color: darkred;">Exerci graeci ad vix, elit tacimates ea duo</span>. Id mel eruditi fuisset. Stet vidit patrioque in pro, eum ex veri verterem abhorreant, id unum oportere intellegam nec<sup>[1, <a href="https://github.com/krispo/angular-nvd3" target="_blank">2</a>, 3]</sup>.',
            css: {
                'text-align': 'justify',
                'margin': '10px 13px 0px 7px'
            }
        }
    };

    $scope.data = sinAndCos();
    $scope.data.push({
        plugin: 'x-range-bars',
        values: dataBars
    });
    $scope.data.push({
        plugin: 'x-markers',
        values: dataMarkers
    });

    /*Random Data Generator */
    function sinAndCos() {
        var sin = [],
            sin2 = [],
            cos = [];

        //Data is represented as an array of {x,y} pairs.
        for (var i = 0; i < 100; i++) {
            sin.push({
                x: i,
                y: Math.sin(i / 10)
            });
            sin2.push({
                x: i,
                y: i % 10 == 5 ? null : Math.sin(i / 10) * 0.25 + 0.5
            });
            cos.push({
                x: i,
                y: .5 * Math.cos(i / 10 + 2) + Math.random() / 10
            });
        }

        //Line chart data should be sent as an array of series objects.
        return [{
            values: sin, //values - represents the array of {x,y} data points
            key: 'Sine Wave', //key  - the name of the series.
            color: '#ff7f0e', //color - optional: choose your own line color.
            strokeWidth: 2,
            classed: 'dashed'
        }, {
            values: cos,
            key: 'Cosine Wave',
            color: '#2ca02c'
        }, {
            values: sin2,
            key: 'Another sine wave',
            color: '#7777ff',
            area: true //area - set to true if you want this line to turn into a filled area chart.
        }];
    }
});
<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>Angular-nvD3 Line Chart</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.4/angular-material.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.4/angular-material.layouts.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.css" />
  <link rel="stylesheet" href="style.css" />

  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.4/angular-material.js" charset="utf-8"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js" charset="utf-8"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-nvd3/1.0.5/angular-nvd3.js"></script>

  <script src="angular-nvd3x.js"></script>
  <script src="app.js"></script>

</head>

<body ng-controller="MainCtrl">

  <nvd3x options="options" data="data"></nvd3x>

  <br><a href="http://krispo.github.io/angular-nvd3/" target="_blank" style="float: right;">See more</a>
</body>

</html>
/* Put your css in here */

.dashed {
  stroke-dasharray: 5, 5;
}

.u-bar:nth-child(odd) rect {
  fill: rgba(0, 170, 255, 0.08);
}

.u-bar:nth-child(even) rect {
  fill: rgba(0, 0, 0, 0.08);
}

.u-bar text {
  fill: rgba(0, 0, 0, 0.3);
}

.u-marker line {
  stroke: navy;
  stroke-dasharray: 5, 5;
}

.u-marker rect {
  stroke: black;
  /* stroke-dasharray: 5, 5; */
  fill: rgba(255, 255, 255, 0.5);
}

.u-marker text {
  /* font-size: 30px !important; */
}
Read more about Angular-nvD3:
http://krispo.github.io/angular-nvd3/
(function(window) {

    'use strict';
    var nv = window.nv;

    // Node.js or CommonJS
    if (typeof(exports) !== 'undefined') {
        /* jshint -W020 */
        nv = require('nvd3');
        /* jshint +W020 */
    }

    angular.module('nvd3')

    .directive('nvd3x', ['nvd3Utils', 'nvd3Plugins', function(nvd3Utils, nvd3Plugins) {
            return {
                restrict: 'AE',
                scope: {
                    data: '=', //chart data, [required]
                    options: '=', //chart options, according to nvd3 core api, [required]
                    api: '=?', //directive global api, [optional]
                    events: '=?', //global events that directive would subscribe to, [optional]
                    config: '=?', //global directive configuration, [optional]
                    onReady: '&?' //callback function that is called with internal scope when directive is created [optional]
                },
                template: '<nvd3 options="options" data="chartData" api="api" events="events" config="config" on-ready="onReadyHandler"></nvd3>',
                link: function($scope, element, attrs) {
                    $scope.chartData = extractChartData($scope.data);

                    function triggerReady(scope, el) {
                        var onReady = $scope.onReady({scope:scope, el:el});
                        if (angular.isFunction(onReady)) {
                            onReady(scope, el);
                        }
                    }

                    function findPluginOptions(type) {
                        for (var i = 0; i < $scope.options.plugins.length; i++) {
                            var options = $scope.options.plugins[i];
                            if (options.type === type) {
                                return options;
                            }
                        }
                    }

                    function findPluginData(type) {
                        if (!type) {
                            console.log('Type should be specified');
                            return;
                        }
                        for (var i = 0; i < $scope.data.length; i++) {
                            var data = $scope.data[i];
                            if (data.plugin === type) {
                                return data;
                            }
                        }
                    }

                    function renderPlugins(chart) {
                        var originalUpdate = chart.update;
                        chart.update = function() {
                            originalUpdate.apply(this, [].slice.call(arguments));
                            var container = d3.select(chart.container);
                            container.transition().call(function() {
                                renderPlugins(chart);
                            });
                        };

                        $scope.plugins.forEach(function(plugin) {
                            plugin.render(chart, plugin.options, findPluginData(plugin.options.type));
                        });
                    }

                    function extractChartData(data) {
                        return data.filter(function(entry) {
                            return !entry.plugin;
                        });
                    }

                    function updateApi() {
                        //override functions to treat data and restore connection to plugins update
                        var updateWithData = $scope.api.updateWithData;
                        $scope.api.updateWithData = function(data) {
                            if (data) {
                                updateWithData(extractChartData(data));
                                $scope.data = data;
                            } else {
                                updateWithData();
                            }
                            renderPlugins($scope.api.getScope().chart);
                        };

                        var update = $scope.api.update;
                        $scope.api.update = function() {
                            update();
                            renderPlugins($scope.api.getScope().chart);
                        };
                    }

                    $scope.onReadyHandler = function(scope, el) {
                        updateApi();
                        if ($scope.options.plugins) {
                            $scope.plugins = $scope.options.plugins.map(function(options) {
                                return {
                                    render: nvd3Plugins.getPluginInstance(options.type),
                                    options: options
                                };
                            });
                            if ($scope.plugins && $scope.plugins.length) {
                                renderPlugins(scope.chart);
                            }
                        }
                        triggerReady(scope, el);
                    };

                    $scope.$watchCollection('data', function(newData) {
                        $scope.chartData = extractChartData(newData);
                    });

                }
            };
        }])
        .service('nvd3Plugins', function() {
            var plugins = {};
            this.addPlugin = function(name, plugin) {
                if (plugins[name]) {
                    console.warn('NVD3x plugin "', name, '" already exists. Replacing with new one');
                }
                plugins[name] = plugin;
            };
            this.getPluginInstance = function(name) {
                if (!plugins[name]) {
                    console.warn('NVD3x plugin "', name, '" doesn\'t exist.');
                    return angular.noop;
                }
                return plugins[name]();
            };
        })
        .factory('nvd3XRangeBarsPlugin', function() {
            return function nvd3XRangeBarsPlugin() {
                var id = Math.floor(Math.random() * 10000);

                return function nvd3XRangeBarsRender(chart, options, data) {
                    var xAxis = chart.xAxis || chart.xAxis1 || chart.x1Axis;
                    var yAxis = chart.yAxis || chart.yAxis1 || chart.y1Axis;

                    var axis = d3.select(chart.container).selectAll('g.nv-axis');
                    var container = d3.select(axis[0][0].parentNode);

                    var clipEdge = true;

                    var xScale = xAxis.scale();
                    var yScale = yAxis.scale();

                    var yRange = yAxis.range();
                    var xRange = xAxis.range();

                    var availableWidth = xRange[1];
                    var availableHeight = yRange[0];

                    var wrap = container.selectAll('g.u-wrap.u-x-ranges').data([data]);
                    var wrapEnter = wrap.enter().insert('g', '.nv-axis + g:not(.nv-axis)').attr('class', 'nvd3 u-wrap u-x-ranges');
                    var defsEnter = wrapEnter.append('defs');
                    var gEnter = wrapEnter.append('g').attr('class', 'u-bars');
                    var g = wrap.select('g');

                    defsEnter.append('clipPath')
                        .attr('id', 'nv-edge-clip-' + id)
                        .append('rect');
                    wrap.select('#nv-edge-clip-' + id + ' rect')
                        .attr('width', availableWidth)
                        .attr('height', availableHeight);

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


                    var bars = wrap.select('.u-bars').selectAll('g.u-bar').data(function(d) {
                        return d.values;
                    });
                    var barsEnter = bars.enter().append('g').attr('class', 'u-bar');
                    bars.attr('transform', function(d, i, j) {
                        return 'translate(' + xScale(d.from) + ', 0)';
                    });
                    barsEnter.append('rect');

                    barsEnter.append('text').attr('text-anchor', 'start');
                    bars.select('text')
                        .text(function(d, i) {
                            return d.label;
                        })
                        .attr('y', availableHeight - 5)
                        .attr('x', 5);

                    bars.selectAll('.u-bar rect').attr('height', yRange[0])
                        .attr('width', function(d, i, j) {
                            return xScale(d.to) - xScale(d.from);
                        });
                    bars.exit().remove();

                };
            };
        })
        .factory('nvd3XMarkersPlugin', function() {
            return function nvd3XMarkersPlugin() {
                var id = Math.floor(Math.random() * 10000);

                return function nvd3XMarkersRender(chart, options, data) {
                    var xAxis = chart.xAxis || chart.xAxis1 || chart.x1Axis;
                    var yAxis = chart.yAxis || chart.yAxis1 || chart.y1Axis;

                    var axis = d3.select(chart.container).selectAll('g.nv-axis');
                    var container = d3.select(axis[0][0].parentNode);

                    var clipEdge = true;

                    var xScale = xAxis.scale();
                    var yScale = yAxis.scale();

                    var yRange = yAxis.range();
                    var xRange = xAxis.range();

                    var availableWidth = xRange[1];
                    var availableHeight = yRange[0];

                    var wrap = container.selectAll('g.u-wrap.u-x-markers').data([data]);
                    var wrapEnter = wrap.enter().insert('g', '.nv-interactive').attr('class', 'nvd3 u-wrap u-x-markers');
                    var defsEnter = wrapEnter.append('defs');
                    var gEnter = wrapEnter.append('g').attr('class', 'u-markers');
                    var g = wrap.select('g');

                    defsEnter.append('clipPath')
                        .attr('id', 'nv-edge-clip-' + id)
                        .append('rect');
                    wrap.select('#nv-edge-clip-' + id + ' rect')
                        .attr('width', availableWidth)
                        .attr('height', availableHeight);

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


                    var markers = wrap.select('.u-markers').selectAll('g.u-marker').data(function(d) {
                        return d.values;
                    });
                    var markersEnter = markers.enter().append('g').attr('class', 'u-marker');
                    markers.attr('transform', function(d, i, j) {
                        return 'translate(' + xScale(d.x) + ', 0)';
                    });
                    markersEnter.append('line');

                    markersEnter.append('text').attr('text-anchor', 'start');
                    markers.select('text')
                        .text(function(d, i) {
                            return d.label;
                        })
                        .attr('dy', '1.2em')
                        .attr('dx', '0.35em')
                        .call(getBB);

                    markersEnter.insert("rect", "text");
                    markers.select('rect')
                        .attr("width", function(d) {
                            return d.bbox.width + d.bbox.x * 2;
                        })
                        .attr("height", function(d) {
                            return d.bbox.height + d.bbox.y * 2;
                        });

                    function getBB(selection) {
                        selection.each(function(d) {
                            d.bbox = this.getBBox();
                        });
                    }

                    markers.selectAll('.u-marker line')
                        .attr('y1', yRange[0])
                        .attr('x1', 0)
                        .attr('y2', yRange[1])
                        .attr('x2', 0);
                    markers.exit().remove();

                };
            };
        });

})(window);