Search code examples
javascriptasp.netasp.net-corechartsgoogle-visualization

Google Charts API How to display bar chart value as Hours:Minutes:Seconds when value is passed in as number of seconds


I have a combo chart with a bar showing the average number of seconds per week for a reaction time. I want to display the value as HH:MM:SS or MM:SS instead of just the number of seconds above the bar. In the example, the last value of 849 seconds should display as 00:14:09. Ideally, if the time was less than 1 hour, then just display 14:09

enter image description here

JavaScript

 google.charts.load('current', { packages: ['corechart'] });
 google.charts.setOnLoadCallback(drawChart);
  
 function drawChart() {
     var data = new google.visualization.DataTable();

     var jsonList = @(Json.Serialize(Model.listWeeklyWebLeadReactionTime))

     var title = 'Weekly Web Lead Reaction Time';

     data.addColumn('string', 'Week Of');
     data.addColumn('number', 'Avg Reaction Time');
     data.addColumn('number', 'Reaction Goal');
     data.addColumn('number', '% Change');

     data.addRows(jsonList.map((p) => {
         return [p.weekOf, p.avgReactionTime, p.reactionTimeGoal, p.reactionPercentChange];
     }));

     var toHHMMSS = (secs) => {
         var sec_num = parseInt(secs, 10)
         var hours = Math.floor(sec_num / 3600)
         var minutes = Math.floor(sec_num / 60) % 60
         var seconds = sec_num % 60

         return [hours, minutes, seconds]
             .map(v => v < 10 ? "0" + v : v)
             .filter((v, i) => v !== "00" || i > 0)
             .join(":")
     }

     var formatPercent = new google.visualization.NumberFormat({ pattern: '#.#%' });
     formatPercent.format(data, 3);

     var view = new google.visualization.DataView(data);
     view.setColumns([0, 1,
         {
             calc: "stringify",
             sourceColumn: 1,
             type: "string",
             role: "annotation"
         },
         2,
         {
             calc: "stringify",
             sourceColumn: 2,
             type: "string",
             role: "annotationText"
         },
         3,
         {
             calc: "stringify",
             sourceColumn: 3,
             type: "string",
             role: "annotation"
         }

     ]);
     var options = {
         interpolateNulls: true,
         title: title,
         titlePosition: 'out',
         isStacked: false,
         seriesType: "bars",
         vAxes: {
             0: {
                 textPosition: 'out',
                 viewWindowMode: 'pretty',
                 title: "",
                 viewWindow: { min: -5000, max: 5000 },
                 gridlines: { color: 'lightgray' }
             },
             1: {
                 textPosition: 'out',
                 viewWindow: { min: -1, max: 1 },
                 format: 'percent',
                 gridlines: { color: 'transparent' }
             },
         },
         series: {
             0: {
                 targetAxisIndex: 0,
                 color: 'lightgray',
                 annotations: {
                     alwaysOutside: true,
                     stem: {
                         color: 'gray',
                         length: 8
                     },
                     textStyle: {
                         color: 'gray',
                         fontSize: 11,
                         bold: false
                     },
                 }
             },
             1: {
                 targetAxisIndex: 0,
                 color: 'purple',
                 type: 'line',
                 lineWidth: 1,
                 lineDashStyle: [4, 4],
                 pointSize: 0,
                 highContrast: true,
                 annotations: {
                     stem: {
                         color: 'transparent',
                         length: -30
                     },
                 textStyle: {
                     color: 'purple',
                     fontSize: 11,
                     bold: false,
                     format: '#,###'
                 },
                 }
             },
             2: {
                 targetAxisIndex: 1,
                 color: 'red',
                 type: 'line',
                 lineWidth: 1,
                 lineDashStyle: [4, 4],
                 pointSize: 5,
                 highContrast: true,
                 annotations: {
                     stem: {
                         color: 'red',
                         length: 10
                     },
                     textStyle: {
                         color: 'red',
                         fontSize: 11,
                         bold: false,
                         format: '#%'
                     },
                 }
             }
         },
         width: '100%',
         height: '450',

         legend: { position: 'top' },
         chartArea: {
             height: '100%',
             width: '100%',
             top: 48,
             left: 60,
             right: 60,
             bottom: 75
         },
     }

     var chart = new google.visualization.ComboChart(document.getElementById('WeeklyWebLeadReactionTime'));
     chart.draw(view, options);

I tried converting the seconds to a format of HH:MM:SS using this code that I found on the site, but I can't figure out how to implement it correctly.

var toHHMMSS = (secs) => {
    var sec_num = parseInt(secs, 10)
    var hours = Math.floor(sec_num / 3600)
    var minutes = Math.floor(sec_num / 60) % 60
    var seconds = sec_num % 60

    return [hours, minutes, seconds]
        .map(v => v < 10 ? "0" + v : v)
        .filter((v, i) => v !== "00" || i > 0)
        .join(":")
}

Solution

  • From the documentation, it guides to display the formatted value

    1. Define a formatted function. To get the value, you need the getValue(rowIndex, columnIndex) function.
    var getFormattedReactionTime = (column, dataTable, row) => {
      return toHHMMSS(dataTable.getValue(row, column));
    };
    
    1. Pass the formatted function into the calc property with the column index of avgReactionTime value.
    view.setColumns([
        0,
        1,
        {
          calc: getFormattedReactionTime.bind(undefined, 1),
          sourceColumn: 1,
          type: 'string',
          role: 'annotation',
        },
        ...
    ]);
    

    JS Demo @ StackBlitz