title: Annotations not showing on ChartJS - React
body: <p>The datasets plot fine on my line chart but I am trying to get vertical lines to display on the chart using <code>chartjs-plugin-annotation</code>. From looking at these questions &amp; answers:</p>
  
  <ul>
  <li><a href="https://stackoverflow.com/questions/60719104/solved-chartjs-annotation-not-displaying">SOLVED : ChartJS annotation not displaying</a></li>
  <li><a href="https://github.com/chartjs/chartjs-plugin-annotation/issues/209" rel="nofollow noreferrer">https://github.com/chartjs/chartjs-plugin-annotation/issues/209</a></li>
  <li><a href="https://stackoverflow.com/questions/55300288/react-chartjs-2-vertical-line-when-hovering-over-chart">react-chartjs-2 vertical line when hovering over chart</a></li>
  <li><a href="https://stackoverflow.com/questions/30256695/chart-js-drawing-an-arbitrary-vertical-line">Chart.js — drawing an arbitrary vertical line</a></li>
  </ul>
  
  <p>I thought I had the correct configuration but the lines are not appearing.</p>
  
  <p><strong>LineChart.js</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import 'chartjs-plugin-annotation'
  
  import React, { useContext } from 'react'
  import { Card, CardBody } from 'reactstrap'
  import { Line } from 'react-chartjs-2'
  import flatten from 'lodash/flatten'
  import { rgbaColor, exchangeChartColors, capitalize, exchanges } from '../../helpers/utils'
  import AppContext from '../../context/Context'
  import dayjs from 'dayjs'
  
  function getDepositsAndWithdrawals(activity) {
      return ['DEPOSIT', 'WITHDRAWAL'].reduce((acc, type) =&gt; {
          if (activity) {
              if (activity.betfair) {
                  acc[type].betfair = activity.betfair.filter(s =&gt; {
                      return s.legacyData.marketName === type
                  }).map(s =&gt; {
                      return {
                          exchange: 'BETFAIR',
                          type: type,
                          amount: s.amount,
                          date: getFormattedDate(s.itemDate)
                      }
                  })
              }
              if (activity.betdaq) {
                  acc[type].betdaq = activity.betdaq.filter(s =&gt; {
                      return s.PostingCategory === 3 &amp;&amp; s.Description.toUpperCase().includes(`${type}:`)
                  }).map(s =&gt; {
                      return {
                          exchange: 'BETDAQ',
                          type: type,
                          amount: s.Amount,
                          date: getFormattedDate(s.PostedAt)
                      }
                  })
              }
              if (activity.smarkets) {
                  const typeToGet = (type === 'DEPOSIT') ? 'deposit' : 'withdraw'
  
                  acc[type].smarkets = activity.smarkets.filter(s =&gt; {
                      return s.source === typeToGet
                  }).map(s =&gt; {
                      return {
                          exchange: 'SMARKETS',
                          type: type,
                          amount: parseFloat(s.money_change),
                          date: getFormattedDate(s.timestamp)
                      }
                  })
              }
          }
          return acc
      }, {
          DEPOSIT: {},
          WITHDRAWAL: {}
      })
  }
  
  function getFormattedDate(date) {
      const parsed = dayjs(date)
      const day = parsed
          .date()
          .toString()
          .padStart(2, '0')
      // Unsure why have to add 1 but don't care really
      const mnth = (parsed
          .month() + 1)
          .toString()
          .padStart(2, '0')
      const yr = parsed
          .year()
          .toString()
          .padStart(2, '0')
      const hr = parsed
          .hour()
          .toString()
          .padStart(2, '0')
      const min = parsed
          .minute()
          .toString()
          .padStart(2, '0')
  
      return `${day}/${mnth}/${yr} @ ${hr}:${min}`
  }
  
  function getXAxis(balances, annotations) {
      const balanceDates = balances.map(entry =&gt; {
          return getFormattedDate(entry.date)
      })
      const annotationDates = annotations.map(ann =&gt; {
          return ann.value
      })
  
      return [
          ...balanceDates,
          ...annotationDates
      ]
  }
  
  const ProfitsLineChart = props =&gt; {
      const { isDark } = useContext(AppContext)
      const depositsAndWithdrawals = getDepositsAndWithdrawals(props.activity)
      const annotations = Object.values(depositsAndWithdrawals).reduce((acc, exs) =&gt; {
          const newEntries = Object.values(exs).map(entries =&gt; {
              return entries.map(entry =&gt; {
                  return {
                      type: 'line',
                      mode: 'vertical',
                      drawTime: 'afterDatasetDraw',
                      scaleID: 'x-axis-0',
                      value: entry.date,
                      borderColor: isDark
                          ? exchangeChartColors.dark[entry.exchange.toLowerCase()]
                          : exchangeChartColors.light[entry.exchange.toLowerCase()],
                      borderWidth: 2,
                      label: {
                          content: `${entry.exchange} ~ ${entry.type} ~ ${entry.amount}`,
                          enabled: true,
                          position: 'top'
                      }
                  }
              })
          })
  
          return [
              ...acc,
              ...flatten(newEntries)
          ]
      }, [])
  
      const config = {
          data(canvas) {
              let datasets = exchanges.map(exchange =&gt; {
                  return {
                      exchange,
                      data: props.balances.reduce((acc, entry) =&gt; {
                          const entryForExchange = entry.balances.find(balance =&gt; {
                              return balance.exchange.toUpperCase() === exchange.toUpperCase()
                          })
  
                          if (entryForExchange) {
                              acc.push({
                                  date: entry.date,
                                  balance: entryForExchange.balance
                              })
                          }
                          return acc
                      }, [])
                  }
              })
              let labels = getXAxis(props.balances, annotations)
  
              // If not specified time period, only show most recent (30) entries
              if (!props.start &amp;&amp; !props.end) {
                  datasets = datasets.map(ds =&gt; {
                      return {
                          ...ds,
                          data: ds.data.slice(ds.data.length - 50, ds.data.length)
                      }
                  })
                  labels = labels.slice(labels.length - 50, labels.length)
              }
  
              return {
                  labels,
                  datasets: datasets.map(set =&gt; {
                      return {
                          label: capitalize(set.exchange),
                          borderWidth: 2,
                          fill: false,
                          data: set.data.map(s =&gt; s.balance.toFixed(2)),
                          borderColor: isDark ? exchangeChartColors.dark[set.exchange.toLowerCase()] : exchangeChartColors.light[set.exchange.toLowerCase()],
                          backgroundColor: isDark ? exchangeChartColors.dark[set.exchange.toLowerCase()] : exchangeChartColors.light[set.exchange.toLowerCase()]
                      }
                  })
              }
          },
          options: {
              annotation: {
                  annotations
              },
              responsive: true,
              title: {
                  display: true,
                  text: 'Balances',
                  fontSize: 20,
                  fontStyle: 'bold',
                  lineHeight: 2.5,
                  fontColor: rgbaColor('#cccccc', 0.7)
              },
              legend: {
                  labels: {
                      fontSize: 16,
                      fontStyle: 'italic',
                      fontColor: rgbaColor('#cccccc', 0.7)
                  },
                  display: true,
                  position: 'bottom'
              },
              tooltips: {
                  mode: 'index',
                  displayColors: true
              },
              hover: {
                  mode: 'label'
              },
              scales: {
                  xAxes: [
                      {
                          display: true,
                          id: 'x-axis-0',
                          scaleLabel: {
                              display: true,
                              labelString: 'Time',
                              fontSize: 12,
                              fontColor: rgbaColor('#cccccc', 0.7)
                          },
                          ticks: {
                              callback: () =&gt; '',
                              fontColor: rgbaColor('#cccccc', 0.7),
                              fontStyle: 600
                          }
                      }
                  ],
                  yAxes: [
                      {
                          display: true,
                          id: 'y-axis-0',
                          scaleLabel: {
                              display: true,
                              labelString: 'Balance (£)',
                              fontSize: 14,
                              fontColor: rgbaColor('#cccccc', 0.7)
                          },
                          ticks: {
                              min: 0,
                              fontColor: rgbaColor('#cccccc', 0.7),
                              fontStyle: 600
                          }
                      }
                  ]
              }
          }
      }
  
      return !props.balances.length ? (
          &lt;Card className="text-center mb-3"&gt;
              &lt;CardBody className="p-5"&gt;
                  &lt;div className="display-2 text-200"&gt;No Data&lt;/div&gt;
                  &lt;p className="lead mt-4 text-800 text-sans-serif font-weight-semi-bold"&gt;There are no balances to display.&lt;/p&gt;
                  &lt;hr /&gt;
                  &lt;p&gt;Please edit your time period search (or remove it altogether) to see data&lt;/p&gt;
              &lt;/CardBody&gt;
          &lt;/Card&gt;
      ) : (
          &lt;Card className="mb-3"&gt;
              &lt;CardBody className="rounded-soft bg-gradient"&gt;
                  &lt;Line data={config.data} options={config.options} /&gt;
              &lt;/CardBody&gt;
          &lt;/Card&gt;
      )
  }
  
  export default ProfitsLineChart
  </code></pre>
  
  <p>This is the config that is spit out that the chart is using:</p>
  
  <pre><code>{
      "options": {
          "annotation": {
              "annotations": [
                  {
                      "type": "line",
                      "mode": "vertical",
                      "drawTime": "afterDatasetDraw",
                      "scaleID": "x-axis-0",
                      "value": "08/03/2020 @ 14:47",
                      "borderColor": "rgba(239, 131, 0, 0.8)",
                      "borderWidth": 2,
                      "label": {
                          "content": "BETFAIR ~ DEPOSIT ~ 22",
                          "enabled": true,
                          "position": "top"
                      }
                  },
                  {
                      "type": "line",
                      "mode": "vertical",
                      "drawTime": "afterDatasetDraw",
                      "scaleID": "x-axis-0",
                      "value": "03/03/2020 @ 23:04",
                      "borderColor": "rgba(119, 0, 255, 0.8)",
                      "borderWidth": 2,
                      "label": {
                          "content": "BETDAQ ~ DEPOSIT ~ 26.57",
                          "enabled": true,
                          "position": "top"
                      }
                  },
                  {
                      "type": "line",
                      "mode": "vertical",
                      "drawTime": "afterDatasetDraw",
                      "scaleID": "x-axis-0",
                      "value": "19/03/2020 @ 17:57",
                      "borderColor": "rgba(68, 254, 59, 0.8)",
                      "borderWidth": 2,
                      "label": {
                          "content": "SMARKETS ~ DEPOSIT ~ 21",
                          "enabled": true,
                          "position": "top"
                      }
                  },
                  {
                      "type": "line",
                      "mode": "vertical",
                      "drawTime": "afterDatasetDraw",
                      "scaleID": "x-axis-0",
                      "value": "27/03/2020 @ 12:55",
                      "borderColor": "rgba(239, 131, 0, 0.8)",
                      "borderWidth": 2,
                      "label": {
                          "content": "BETFAIR ~ WITHDRAWAL ~ -10",
                          "enabled": true,
                          "position": "top"
                      }
                  },
                  {
                      "type": "line",
                      "mode": "vertical",
                      "drawTime": "afterDatasetDraw",
                      "scaleID": "x-axis-0",
                      "value": "27/03/2020 @ 13:02",
                      "borderColor": "rgba(119, 0, 255, 0.8)",
                      "borderWidth": 2,
                      "label": {
                          "content": "BETDAQ ~ WITHDRAWAL ~ -10",
                          "enabled": true,
                          "position": "top"
                      }
                  },
                  {
                      "type": "line",
                      "mode": "vertical",
                      "drawTime": "afterDatasetDraw",
                      "scaleID": "x-axis-0",
                      "value": "01/03/2020 @ 09:45",
                      "borderColor": "rgba(68, 254, 59, 0.8)",
                      "borderWidth": 2,
                      "label": {
                          "content": "SMARKETS ~ WITHDRAWAL ~ -26.57",
                          "enabled": true,
                          "position": "top"
                      }
                  }
              ]
          }
      },
      "responsive": true,
      "title": {
          "display": true,
          "text": "Balances",
          "fontSize": 20,
          "fontStyle": "bold",
          "lineHeight": 2.5,
          "fontColor": "rgba(204,204,204,0.7)"
      },
      "legend": {
          "labels": {
              "fontSize": 16,
              "fontStyle": "italic",
              "fontColor": "rgba(204,204,204,0.7)"
          },
          "display": true,
          "position": "bottom"
      },
      "tooltips": {
          "mode": "index",
          "displayColors": true
      },
      "hover": {
          "mode": "label"
      },
      "scales": {
          "xAxes": [
              {
                  "display": true,
                  "id": "x-axis-0",
                  "scaleLabel": {
                      "display": true,
                      "labelString": "Time",
                      "fontSize": 12,
                      "fontColor": "rgba(204,204,204,0.7)"
                  },
                  "ticks": {
                      "fontColor": "rgba(204,204,204,0.7)",
                      "fontStyle": 600
                  }
              }
          ],
          "yAxes": [
              {
                  "display": true,
                  "id": "y-axis-0",
                  "scaleLabel": {
                      "display": true,
                      "labelString": "Balance (£)",
                      "fontSize": 14,
                      "fontColor": "rgba(204,204,204,0.7)"
                  },
                  "ticks": {
                      "min": 0,
                      "fontColor": "rgba(204,204,204,0.7)",
                      "fontStyle": 600
                  }
              }
          ]
      }
  }
  </code></pre>
  
  <p>I can't think as to why this is not working as intended. <code>getXAxis</code> ensures that the string timestamps of the annotations are added to the X-Axis as well. I'm lost for ideas</p>