title: How can I calculate a value and place it inside the last bar in a Chart.JS bar chart?
body: <p>Since it seems impossible or highly difficult (no working answers <a href="https://stackoverflow.com/questions/39735005/how-can-i-add-a-label-above-just-the-last-bar-in-a-chart-js-bar-chart">here</a>) to place a label above the last bar on a bar chart, I would like to now know how to place a label inside the last bar.</p>
  
  <p>I am adding labels to all the bars of a horizontal bar chart with this code:</p>
  
  <pre><code>Chart.pluginService.register({
      afterDraw: function (chartInstance) {
          if (chartInstance.id !== 1) return; // affect this one only
          var ctx = chartInstance.chart.ctx;
          // render the value of the chart above the bar
          ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
          ctx.textAlign = 'center';
          ctx.textBaseline = 'bottom';
  
          chartInstance.data.datasets.forEach(function (dataset) {
              for (var i = 0; i &lt; dataset.data.length; i++) {
                  var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
                  ctx.fillText(dataset.data[i] + (Number.isInteger(dataset.data[i]) ? ".0" : "") + "%", ((model.x + model.base) / 2), model.y + (model.height / 3));
              }
          });
      }
  });
  </code></pre>
  
  <p>That working chart looks like this:</p>
  
  <p><a href="https://i.stack.imgur.com/9perk.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/9perk.png" alt="enter image description here"></a></p>
  
  <p>...but this is a "regular" (vertical) bar chart, and my attempt to add a label to just the last bar like so:</p>
  
  <pre><code>Chart.pluginService.register({
      afterDraw: function (chartInstance) {
          if (chartInstance.id !== 2) return; // affect this one only
          var ctx = chartInstance.chart.ctx;
          // render the value of the chart above the bar
          ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
          ctx.textAlign = 'center';
          ctx.textBaseline = 'center';
  
          var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
          ctx.fillText(dataset.data[dataset.data.length - 1]);
      }
  });
  </code></pre>
  
  <p>...fails (nothing displays and, in fact, it causes problems not only with its own appearance, but that of other charts on the page, even though I use code to only apply this event to this particular chart:</p>
  
  <p><a href="https://i.stack.imgur.com/h0xc0.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/h0xc0.png" alt="enter image description here"></a></p>
  
  <p>So how can I calculate a value (based on last and penultimate bar values) and then place that calculated "label" inside the last bar in a Chart.JS bar chart?</p>
  
  <p>With the code I attempted above, I just wanted to get the raw value for the bar inside the bar for now; the calculation portion of the logic can be left until later.</p>
  
  <p>One possibility would be to make it a stacked bar chart, with nothing added to any of the bars but the last one, and then make its background color white to blend in with the chart background...</p>
  
  <h2>UPDATE</h2>
  
  <p>I tried my last idea; thinking maybe I could accomplish what I wanted by morphing my chart into a stacked bar chart (from a simple bar chart), adding a second set of mostly "zero" data as the second piece of the stack, like so:</p>
  
  <p>Old code excerpt:</p>
  
  <pre><code>var forecastChartData = {
      labels: [
          "Total Sales"
      ],
      datasets: [
      {
          label: "8/28/2016 - 9/3/2016",
          backgroundColor: "rgba(255,0,0,0.75)",
          hoverBackgroundColor: "rgba(255,0,0,1)",
          data: [240]
      },
      {
          label: "9/4/2016 - 9/10/2016",
          backgroundColor: "rgba(255,153,0,0.75)",
          hoverBackgroundColor: "rgba(255,153,0,1)",
          data: [272]
      },
      {
          label: "9/11/2016 - 9/17/2016",
          backgroundColor: "rgba(255,255,0,0.75)",
          hoverBackgroundColor: "rgba(255,255,0,1)",
          data: [250]
      },
      {
          label: "9/18/2016 - 9/24/2016",
          backgroundColor: "rgba(0,255,0,0.75)",
          hoverBackgroundColor: "rgba(0,255,0,1)",
          data: [232]
      },
      {
          label: "9/25/2016 - 10/1/2016",
          backgroundColor: "rgba(0,0,255,0.75)",
          hoverBackgroundColor: "rgba(0,0,255,1)",
          data: [244]
      }],
  };
  
  var forecastOptions = {
      tooltips: {
          enabled: true
      }
  };
  </code></pre>
  
  <p>New code:</p>
  
  <pre><code>var forecastChartData = {
      labels: [
          "Total Sales"
      ],
      datasets: [
      {
          label: "8/28/2016 - 9/3/2016",
          backgroundColor: "rgba(255,0,0,0.75)",
          hoverBackgroundColor: "rgba(255,0,0,1)",
          data: [240]
      },
      {
          label: "9/4/2016 - 9/10/2016",
          backgroundColor: "rgba(255,153,0,0.75)",
          hoverBackgroundColor: "rgba(255,153,0,1)",
          data: [272]
      },
      {
          label: "9/11/2016 - 9/17/2016",
          backgroundColor: "rgba(255,255,0,0.75)",
          hoverBackgroundColor: "rgba(255,255,0,1)",
          data: [250]
      },
      {
          label: "9/18/2016 - 9/24/2016",
          backgroundColor: "rgba(0,255,0,0.75)",
          hoverBackgroundColor: "rgba(0,255,0,1)",
          data: [232]
      },
      {
          label: "9/25/2016 - 10/1/2016",
          backgroundColor: "rgba(0,0,255,0.75)",
          hoverBackgroundColor: "rgba(0,0,255,1)",
          data: [244]
      }],
      [{
          backgroundColor: "rgba(255, 255, 255, 0.5)",
          hoverBackgroundColor: "rgba(200, 200, 200, 1)",
          data: [0, 0, 0, 0, 5.2]
      }]
  };
  
  var forecastOptions = {
      scales: {
          xAxes: [
          {
              stacked: true
          }
          ],
          yAxes: [
          {
              stacked: true
          }
          ]
      },
      tooltips: {
          enabled: true
      }
  };
  </code></pre>
  
  <p>But it didn't help at all; what am I doing wrong; if everything, how can I proceed after pursuing the nuclear option with my new code?</p>
  
  <h2>UPDATE 2</h2>
  
  <p>The code from Hung Tran <a href="https://stackoverflow.com/questions/31631354/how-to-display-data-values-on-chart-js">here</a> gets me close. My options is now:</p>
  
  <pre><code>var forecastOptions = {
      tooltips: {
          enabled: true
      },
      animation: {
          duration: 500,
          easing: "easeOutQuart",
          onComplete: function () {
              var ctx = this.chart.ctx;
              ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
              ctx.textAlign = 'center';
              ctx.textBaseline = 'bottom';
  
              this.data.datasets.forEach(function (dataset) {
                  for (var i = 0; i &lt; dataset.data.length; i++) {
                      var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                          scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
                      ctx.fillStyle = '#444';
                      var y_pos = model.y - 5;
                      // Make sure data value does not get overflown and hidden
                      // when the bar's value is too close to max value of scale
                      // Note: The y value is reverse, it counts from top down
                      if ((scale_max - model.y) / scale_max &gt;= 0.93)
                          y_pos = model.y + 20;
                      ctx.fillText(dataset.data[i], model.x, y_pos);
                  }
              });
          }
      }
  };
  </code></pre>
  
  <p>...and it places the data value above each bar.</p>
  
  <p>As stated, this is close to what I want; what I really want, though, is the difference between the last value and the current value. For example, with this chart:</p>
  
  <p><a href="https://i.stack.imgur.com/PbQMg.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/PbQMg.png" alt="enter image description here"></a></p>
  
  <p>...what I want to see is:</p>
  
  <p><strong>240, 272 (30), 250 (-22), 232 (-18), 244 (12)</strong></p>
  
  <p>Or perhaps just a value above the last bar, either "<strong>244 (12)</strong>" or just "<strong>12</strong>".</p>
  
  <p>That's what they say they want (the latter), but I wouldn't be surprised if they change their mind and want all the vals/diffs.</p>
  
  <h2>UPDATE 3</h2>
  
  <p>The solution adds no values atop the bars, and eats one of my slices of pie:</p>
  
  <p><a href="https://i.stack.imgur.com/Hgmxr.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Hgmxr.png" alt="enter image description here"></a></p>
  
  <h2>UPDATE 4</h2>
  
  <p>Here is pretty much <em>all</em> the code in Index.cshtml:</p>
  
  <pre><code>    &lt;style&gt;
  
          .pieLegend li span {
              display: inline-block;
              width: 12px;
              height: 12px;
              margin-right: 5px;
          }
  
          #piechartlegendleft {
              height: 360px;
              width: 100%;
          }
  
          #top10Legend {
              display: inline-block;
          }
  
              #top10Legend &gt; ul {
                  list-style: none;
              }
  
          #container {
              display: inline-block;
              height: 50%;
              width: 50%;
          }
      &lt;/style&gt;
      &lt;script&gt;
          $(document).ready(function () {
              $("body").on("click", "#btnGetData",
          . . .
                      });
  
              Chart.defaults.global.defaultFontFamily = "Candara";
              Chart.defaults.global.defaultFontSize = 16;
  
              // Top 10 Pie Chart
              var formatter = new Intl.NumberFormat("en-US");
  
              Chart.pluginService.register({
                  afterDatasetsDraw: function (chartInstance) {
                      var ctx = chartInstance.chart.ctx;
  
                      ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
                      ctx.textAlign = 'center';
                      ctx.textBaseline = 'bottom';
                      ctx.fillStyle = '#666';
  
                      chartInstance.config.data.datasets.forEach(function (dataset) {
  
                          for (var i = 0; i &lt; dataset.data.length; i++) {
                              var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                                  total = dataset._meta[Object.keys(dataset._meta)[0]].total,
                                  mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius) / 2,
                                  start_angle = model.startAngle,
                                  end_angle = model.endAngle,
                                  mid_angle = start_angle + (end_angle - start_angle) / 2;
  
                              var x = mid_radius * 1.5 * Math.cos(mid_angle);
                              var y = mid_radius * 1.5 * Math.sin(mid_angle);
  
                              ctx.fillStyle = '#fff';
                              if (i === 0 || i === 3 || i === 7 || i === 9) { // Darker text color for lighter background
                                  ctx.fillStyle = '#000';
                              }
                              var percent = String(Math.round(dataset.data[i] / total * 100)) + "%";
                              // this prints the data number
                              // this prints the percentage
                              ctx.fillText(percent, model.x + x, model.y + y);
                          }
                      });
                  }
              });
  
              var data = {
                  labels: [
                      "Bananas (18%)",
                      "Lettuce, Romaine (14%)",
                      "Melons, Watermelon (10%)",
                      "Pineapple (10%)",
                      "Berries (10%)",
                      "Lettuce, Spring Mix (9%)",
                      "Broccoli (8%)",
                      "Melons, Honeydew (7%)",
                      "Grapes (7%)",
                      "Melons, Cantaloupe (7%)"
                  ],
                  datasets: [
                  {
                      data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076, 1056, 1048],
                      backgroundColor: [
                          "#FFE135",
                          "#3B5323",
                          "#fc6c85",
                          "#ffec89",
                          "#021c3d",
                          "#3B5323",
                          "#046b00",
                          "#cef45a",
                          "#421C52",
                          "#FEA620"
                      ]
                  }]
              };
  
              var optionsPie = {
                  responsive: true,
                  scaleBeginAtZero: true,
                  legend: {
                      display: false
                  },
                  tooltips: {
                      callbacks: {
                          label: function (tooltipItem, data) {
                              return data.labels[tooltipItem.index] + ": " +
                                  formatter.format(data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]);
                          }
                      }
                  },
              };
  
              var ctx = $("#top10ItemsChart").get(0).getContext("2d");
              var top10PieChart = new Chart(ctx,
              {
                  type: 'pie',
                  data: data,
                  options: optionsPie
              });
  
              $("#top10Legend").html(top10PieChart.generateLegend());
              // &lt;/ Top 10 Pie Chart
  
              // Price Compliance Bar Chart
              Chart.pluginService.register({
                  afterDraw: function (chartInstance) {
                      if (chartInstance.id !== 1) return; // affect this one only
                      var ctx = chartInstance.chart.ctx;
                      // render the value of the chart above the bar
                      ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
                      ctx.textAlign = 'center';
                      ctx.textBaseline = 'bottom';
  
                      ctx.fillStyle = "#000";
  
                      chartInstance.data.datasets.forEach(function (dataset) {
                          for (var i = 0; i &lt; dataset.data.length; i++) {
                              var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
                              ctx.fillText(dataset.data[i] + (Number.isInteger(dataset.data[i]) ? ".0" : "") + "%", ((model.x + model.base) / 2), model.y + (model.height / 3));
                          }
                      });
                  }
              });
  
              var ctxBarChart = $("#priceComplianceBarChart").get(0).getContext("2d");
              var priceComplianceData = {
                  labels: [
                      "Bix Produce", "Capitol City", "Charlies Portland", "Costa Fruit and Produce",
                      "Get Fresh Sales", "Loffredo East", "Loffredo West", "Paragon", "Piazza Produce"
                  ],
                  datasets: [
                  {
                      label: "Price Compliant",
                      backgroundColor: "rgba(34,139,34,0.5)",
                      hoverBackgroundColor: "rgba(34,139,34,1)",
                      data: [99.0, 99.2, 99.4, 98.9, 99.1, 99.5, 99.6, 99.2, 99.7]
                  },
                  {
                      label: "Non-Compliant",
                      backgroundColor: "rgba(255, 0, 0, 0.5)",
                      hoverBackgroundColor: "rgba(255, 0, 0, 1)",
                      data: [1.0, 0.8, 0.6, 1.1, 0.9, 0.5, 0.4, 0.8, 0.3]
                  }
                  ]
              }
  
              var priceComplianceOptions = {
                  scales: {
                      xAxes: [
                      {
                          stacked: true
                      }],
                      yAxes: [
                      {
                          stacked: true
                      }]
                  },
                  tooltips: {
                      enabled: false
                  }
              };
  
              var priceBarChart = new Chart(ctxBarChart,
              {
                  type: 'horizontalBar',
                  data: priceComplianceData,
                  options: priceComplianceOptions
              });
              // &lt;/Price Compliance Bar Chart
  
              // Forecast/Impact Analysis chart
              var ctxForecastChart = $("#forecastLineChart"); //.get(0).getContext("2d");
              // See if the "olde style" makes any diff (used by the Chart.JS Whisperer)
              //var ctxForecastChart = document.getElementById("forecastLineChart"); // no diff
  
              var forecastChartData = {
                  labels: ["Total Sales"],
                  datasets: [
                  {
                      label: "8/28/2016 - 9/3/2016",
                      backgroundColor: "rgba(255,0,0,0.75)",
                      hoverBackgroundColor: "rgba(255,0,0,1)",
                      data: [240]
                  },
                  {
                      label: "9/4/2016 - 9/10/2016",
                      backgroundColor: "rgba(255,153,0,0.75)",
                      hoverBackgroundColor: "rgba(255,153,0,1)",
                      data: [272]
                  },
                  {
                      label: "9/11/2016 - 9/17/2016",
                      backgroundColor: "rgba(255,255,0,0.75)",
                      hoverBackgroundColor: "rgba(255,255,0,1)",
                      data: [250]
                  },
                  {
                      label: "9/18/2016 - 9/24/2016",
                      backgroundColor: "rgba(0,255,0,0.75)",
                      hoverBackgroundColor: "rgba(0,255,0,1)",
                      data: [232]
                  },
                  {
                      label: "9/25/2016 - 10/1/2016",
                      backgroundColor: "rgba(0,0,255,0.75)",
                      hoverBackgroundColor: "rgba(0,0,255,1)",
                      data: [244]
                  }]
          };
  
          var forecastOptions = {
              tooltips: {
                  enabled: true
              },
              animation: {
                      duration: 500,
                      easing: "easeOutQuart",
                      onComplete: function () {
                          var ctx = this.chart.ctx;
                          ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
                          ctx.textAlign = 'center';
                          ctx.textBaseline = 'bottom';
  
                          this.data.datasets.forEach(function (dataset) {
                              for (var i = 0; i &lt; dataset.data.length; i++) {
                                  var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                                      scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
                                  ctx.fillStyle = '#444';
                                  var y_pos = model.y - 5;
                                  // Make sure data value does not get overflown and hidden
                                  // when the bar's value is too close to max value of scale
                                  // Note: The y value is reverse, it counts from top down
                                  if ((scale_max - model.y) / scale_max &gt;= 0.93)
                                      y_pos = model.y + 20;
                                  ctx.fillText(dataset.data[i], model.x, y_pos);
                              }
                          });
                      }
                  }
              };
  
          var forecastBarChart = new Chart(ctxForecastChart, {
              type: 'bar',
              //type: 'line',
              data: forecastChartData,
              options: forecastOptions
          });
          // &lt;/ Forecast/Impact Analysis chart
  
          $('#delperfTable').DataTable({
              "paging": false,
              "info": false,
              "searching": false
          });
          });
  
  
      &lt;/script&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
      &lt;div class="container body-content"&gt;
          &lt;div class="jumbotronjr"&gt;
              &lt;div class="col-md-3" style="margin-top: 0.6cm"&gt;
                  &lt;img src="http://www.proactusa.com/wp-content/themes/proact/images/pa_logo_notag.png" height="86" width="133" alt="PRO*ACT usa logo"&gt;
              &lt;/div&gt;
              &lt;div class="col-md-9"&gt;
                  &lt;label class="titletext" style="margin-top: 0.2cm;"&gt;Customer Dashboard&lt;/label&gt;
                  &lt;br /&gt;
                  &lt;label class="titletextjr" style="margin-top: -2.2cm;" id="unitName"&gt;SODEXO&lt;/label&gt;
                  &lt;label class="cccsfont"&gt; for the week of September 25          &lt;/label&gt;
                  &lt;input class="smalldatepicker" type="date" id="datepickerFrom" value="2016-09-25"&gt;
                  &lt;/input&gt;
                  &lt;label class="cccsfont"&gt; to &lt;/label&gt;
                  &lt;input type="date" class="smalldatepicker" id="datepickerTo" value="2016-10-01"&gt;
                  &lt;/input&gt;
                  &lt;span id="newhourglass" class="fa fa-4x fa-refresh fa-spin boxRefresh hide" runat="server"&gt;&lt;/span&gt;
                  &lt;button class="btn btn-success btn-sm green" id="btnGetData"&gt;&lt;span class="glyphicon glyphicon-refresh"&gt;&lt;/span&gt;&lt;/button&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="row"&gt;
              &lt;div class="col-md-12"&gt;
                  &lt;hr /&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="row"&gt;
              &lt;div class="col-md-12"&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="row" id="top10Items"&gt;
              &lt;div class="col-md-6"&gt;
                  &lt;div class="topleft"&gt;
                      &lt;h2 class="sectiontext"&gt;Top 10 Items&lt;/h2&gt;
                      &lt;br /&gt;
                      &lt;div id="piechartlegendleft"&gt;
                          &lt;div id="container"&gt;
                              &lt;canvas id="top10ItemsChart" width="800" height="800"&gt;&lt;/canvas&gt;
                          &lt;/div&gt;
                          &lt;div id="top10Legend" class="pieLegend"&gt;&lt;/div&gt;
                      &lt;/div&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
  
              &lt;div class="col-md-6"&gt;
                  &lt;div class="topright"&gt;
                      &lt;h2 class="sectiontext"&gt;Price Compliance&lt;/h2&gt;
                      &lt;div class="graph_container"&gt;
                          &lt;canvas id="priceComplianceBarChart"&gt;&lt;/canvas&gt;
                      &lt;/div&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="row"&gt;
              &lt;div class="col-md-6"&gt;
                  &lt;div class="bottomleft"&gt;
                      &lt;h2 class="sectiontext"&gt;Forecast/Impact Analysis&lt;/h2&gt;
                      &lt;div class="graph_container"&gt;
                          &lt;canvas id="forecastLineChart"&gt;&lt;/canvas&gt;
                      &lt;/div&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
  
              &lt;div class="col-md-6"&gt;
                  &lt;div class="bottomright"&gt;
                      &lt;h2 class="sectiontext"&gt;Delivery Performance&lt;/h2&gt;
                      &lt;table id="delperfTable"&gt;
              . . .
                      &lt;/table&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  
      &lt;/div&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>