Search code examples
javascriptangularjsnvd3.jsangular-nvd3

Add reference line on NVD3 graph


I am currently using the Angular-NVD3 library to generate a graph that look like this:

Current Chart

I have been tasked with adding a reference line on to the graph that will act as a target date. I have looked for a way to add an asymptote onto the y-axis, a way to draw another line [targetDate, y] where y = [0:max], as well as a way to add a line graph onto the same axis. Unfortunately, nothing has come from my searching. My goal is to create a graph in code that look like this:

Goal

Does any one know how I can do this?


Solution

  • One approach might be to take your data set array and push data for a new line into it, with just two values/points, with x values just before and after the target date, and y values that are below the minimum value in your dataset and above the maximum value, respectively:

    var targetDate = Date.parse('May 2022');
    
    var targetLine = {
        key: 'Target Date',
        color: '#000',
        area: false,
        classed: 'target-date-line',  
        values: [
            [(targetDate - 1 msec), minValue],
            [(targetDate + 1 msec), maxValue]
        ]
    };
    

    var app = angular.module('snippet', ['nvd3']);
    
    app.controller('MainCtrl', function($scope) {
    
      $scope.options = {
        chart: {
          type: 'lineChart',
          height: 450,
          margin : {
            top: 20,
            right: 20,
            bottom: 80,
            left: 75
          },
          showLegend: false,
          x: function(d){ return d[0]; },
          y: function(d){ return d[1]; },
          isArea: function (d) {
            return d.area;
          },
          xAxis: {
            axisLabel: 'date',
            tickFormat: function(d){
              return d3.time.format('%b %Y')(new Date(d));
            },
            tickPadding: 10,
            axisLabelDistance: 10
          },
          yAxis: {
            axisLabel: 'value',
            axisLabelDistance: 10
          },
          tooltip: {
            enabled: true
          },
          callback: function(chart){
            console.log("!!! lineChart callback !!!");
          }
        },
        title: {
          enable: true,
          text: 'Line Chart with Target'
        }
      };
    
      $scope.data = [];
      
      
      var lineData = [
        {"key":"Some Val","area": true, "color":"#9bcd9b","values":[[1462075200000,0],[1525147200000,12],[1588305600000,26],[1651377600000,42],[1714536000000,60],[1777608000000,100]]},
        {"key":"Other Val","area": true, "color":"#e34343","values":[[1462075200000,0],[1525147200000,10],[1588305600000,21],[1651377600000,33],[1714536000000,46],[1777608000000,57]]}
      ];
      
      var targetDate = Date.parse('May 2022');
      
      var minVal = _.min(_.flatten(_.map(lineData, function(dataset) {
        return _.map(dataset.values, function(val) {
          return val[1];
        });
      })));
      
      var maxVal = _.max(_.flatten(_.map(lineData, function(dataset) {
        return _.map(dataset.values, function(val) {
          return val[1];
        });
      })));
    
      var targetLine = {
        key: 'Target Date',
        color: '#000',
        area: false,
        classed: 'target-date-line',
        /**
         * set first x value to target date - 1 msec
         * second x value to target + msec1
         * 
         * set first y value to minimum of data values (or less)
         * second y value to something higher than the max value in data
         */ 
        values: [[targetDate - 1, minVal],[targetDate + 1,1.5*maxVal]]
      }
    
      lineData.push(targetLine);
      $scope.data = lineData;
    
    });
    .target-date-line {
      stroke-dasharray: 5,5;
    }
    
    .target-date-line path.nv-line {
      stroke-width: 1px;
    }
    <!DOCTYPE html>
    <html ng-app="snippet">
    
      <head>
        <meta charset="utf-8" />
        <title>Angular-nvD3 Line Chart</title>
        <script>document.write('<base href="' + document.location + '" />');</script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="[email protected]" data-semver="4.6.1" src="https://cdn.jsdelivr.net/lodash/4.6.1/lodash.js"></script>
    
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.css"/>    
    
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-nvd3/1.0.5/angular-nvd3.min.js"></script>
        <script src="app.js"></script>
      </head>
    
      <body ng-controller="MainCtrl">
        
        <nvd3 options="options" data="data"></nvd3>
        
      </body>
    
    </html>