why is this chart.update( ) not working? chartjs

Viewed 24

I'm doing a project using vue3, TypeScript and chartJs. Already implemented the date-fns-adapter and made vars {}(just for testing purposes) ⇾ (day, week, month) that work when I change manually the time unit. Even from what I saw on vueDevTools and console.log chart the units are changing from ref.value but there's a big failure in chart.update() and I can't find the reason. If anyone can help me it would be really appreciated. Code:

<template>
  <div>
    <div class="relative">
      <canvas ref="ctx" width="360" height="256" />
      <span
        class="absolute right-4 bottom-8 text-3xl text-primary font-semibold"
      >
        {{ currentRating }}
      </span>
    </div>
    <footer class="ml-8 mr-2 flex justify-between gap-4">
      <button @click="periodChange('day')">Day</button>
      <button @click="periodChange('week')">Week</button>
      <button @click="periodChange('month')">Month</button>
      <button @click="periodChange('year')">">Year</button>
    </footer>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, reactive, computed, watch, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { useStore } from 'vuex'
import { useI18n } from 'vue-i18n'
import { formatISO, sub, intlFormat } from 'date-fns'
import { Rating, RatingHistory } from '@package/lib/types/Rating'
import 'chartjs-adapter-date-fns'
import { enUS } from 'date-fns/locale'
import {
  Chart,
  ChartItem,
  ChartArea,
  LineElement,
  PointElement,
  LineController,
  CategoryScale,
  LinearScale,
  Filler,
  Tooltip,
  TimeScale
} from 'chart.js'
//import { ClickFeedback } from 'aws-sdk/clients/kendra'

Chart.register(
  LineElement,
  PointElement,
  LineController,
  CategoryScale,
  LinearScale,
  Filler,
  Tooltip,
  TimeScale
)

export default defineComponent({
  name: 'RatingHistoryGraph',
  props: {
    verified: {
      type: Boolean,
      default: false
    }
  },
  setup(props) {
    const route = useRoute()
    const store = useStore()
    const { t, locale } = useI18n()

    const ctx = ref<HTMLCanvasElement | null>(null)
    let chart: any

    // GMT 0000,+ 12 hours => That's why the time is allways 12:00.
    const day = [
      { x: Date.parse('2019-06-14 00:00: GMT+1200'), y: 1 },
      { x: Date.parse('2019-09-06 00:00: GMT+1200'), y: 3 },
      { x: Date.parse('2020-03-11 00:00: GMT+1200'), y: 2.5 },
      { x: Date.parse('2021-07-11 00:00: GMT+1200'), y: 7 },
      { x: Date.parse('2022-03-06 00:00: GMT+1200'), y: 6 },
      { x: Date.parse('2022-06-18 00:00: GMT+1200'), y: 15 }
    ] // This is time in miliSeconds

    const week = [
      { x: Date.parse('2020-06-31 00:00: GMT+1200'), y: 1 },
      { x: Date.parse('2020-06-07 00:00: GMT+1200'), y: 1 },
      { x: Date.parse('2020-06-14 00:00: GMT+1200'), y: 4 },
      { x: Date.parse('2020-06-21 00:00: GMT+1200'), y: 10 }
    ]

    const month = [
      { x: Date.parse('2019-03-14 00:00: GMT+1200'), y: 1 },
      { x: Date.parse('2019-07-06 00:00: GMT+1200'), y: 3 },
      { x: Date.parse('2020-04-11 00:00: GMT+1200'), y: 2.5 },
      { x: Date.parse('2021-03-11 00:00: GMT+1200'), y: 7 },
      { x: Date.parse('2022-05-06 00:00: GMT+1200'), y: 6 },
      { x: Date.parse('2022-06-18 00:00: GMT+1200'), y: 15 }
    ]
type Period =
      | false
      | 'year'
      | 'day'
      | 'month'
      | 'week'
      | 'millisecond'
      | 'second'
      | 'minute'
      | 'hour'
      | 'quarter'
      | undefined

    const period = ref<Period>('year')

    const generateChart = () => {
      if (!ctx.value) return

      let width = 0
      let height = 0
      let gradient: CanvasGradient
      const getGradient = (
        ctx: CanvasRenderingContext2D,
        chartArea: ChartArea
      ): CanvasGradient => {
        const chartWidth = chartArea.right - chartArea.left
        const chartHeight = chartArea.bottom - chartArea.top
        if (!gradient || width !== chartWidth || height !== chartHeight) {
          width = chartWidth
          height = chartHeight
          gradient = ctx.createLinearGradient(
            0,
            chartArea.bottom,
            0,
            chartArea.top
          )
          gradient.addColorStop(0, 'rgba(222, 45, 119, 0.05)')
          gradient.addColorStop(1, 'rgba(222, 45, 119, 0.25)')
        }

        return gradient
      }

      Chart.defaults.font.weight = 'bold'

      chart = new Chart(ctx.value.getContext('2d') as ChartItem, {
        type: 'line',
        data: {
          datasets: [
            {
              label: 'Rating',
              //data: chartData.value.map(data => data.rating),
              data: day,
              fill: true,
              backgroundColor: context => {
                const chart = context.chart
                const { ctx, chartArea } = chart

                if (!chartArea) return

                return getGradient(ctx, chartArea)
              },
              borderColor: 'rgb(222, 45, 119)',
              tension: 0.4
            }
          ]
        },
        // Configuration options go here.
        options: {
          scales: {
            x: {
              type: 'time',
              time: {
                unit: period.value
              },
              min: '2019-01-01', // How to make it dinamic?
              max: Date.now(),
              adapters: {
                date: {
                  locale: enUS // DINAMIC need.
                }
              }
            },
            y: {
              suggestedMin: 0,
              suggestedMax: 21,
              grid: {
                color: 'rgb(242, 244, 246)',
                borderColor: 'rgb(242, 244, 246)'
              },
              ticks: {
                maxTicksLimit: 22
              }
            }
          },
          responsive: true,
          plugins: {
            legend: {
              display: false
            },
            tooltip: {
              boxWidth: 100       
            }
          }
        }
      })
    }

    const periodChange = (timeFrame: Period): void => {
      console.log(chart)
      period.value = timeFrame
      chart.update()
    }

    onMounted(() => {
      generateChart()
    })

    return {
      t,
      // currentRating,
      ctx,
      // chartData,
      actions,
      showHistoryFrom,
      fromOptions,
      id,
      to,
      from,
      changeFromOptions,
      timeFrame
    }
  }
})
</script>
0 Answers
Related