2

I have a chart displayed in a canvas that I want to destroy and redraw from a Vue 3 watcher. The watcher works and the function that fires on the change works up to the redraw step. When it reaches the redraw step, I get:

TypeError: Argument 1 ('element') to Window.getComputedStyle must be an instance of Element

The chart object is loaded as a component and is rendered from a method when initially mounted. I am using vanilla chart.js (not vue-chartjs).

Mount:

  mounted() {
    this.renderChart()
  },

Watch:

  watch: {
    '$store.state.weather': {
      handler(newValue, oldValue) {
        this.forecastChart.destroy()
        this.animation = 0
        this.renderChart()  // works fine until this line
      },
      deep: true
    }
  }

Method:

  methods: {
    renderChart() {
      let ctx = document.getElementById(this.id).getContext('2d');
      this.forecastChart = new Chart(ctx, {
        // source: https://stackoverflow.com/a/69047139/2827397
        type: 'doughnut',
        plugins: [{
          beforeDraw: (chart) => {
            const {ctx} = chart;

// etc.

Similar questions seem to have solutions that are outdated and have not worked for me.

Ideally, I'd like to make the chart reactive to the change in the Vuex store state value, but destroying and redrawing the chart would be an acceptable outcome and that is what my question here is regarding.

chart.js 3.9.1, vue 3.0.0, vuex 4.0.2

Edit 1:

Trying to .update() rather than .destroy() the chart object didn't yield results, either.

    updateChart() {
      this.forecastChart.data.datasets[0].needleValue = this.weather.airQuality - 0.5
      this.forecastChart.update()
    },

Results in:

Unhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'item.fullSize = options.fullSize')

DaveL17
  • 1,673
  • 7
  • 24
  • 38

1 Answers1

0

I'm not smart enough to be able to explain why, but the following revision solves the issue I was facing. Above, I was referencing the chart object with the following destroy() command:

this.forecastChart.destroy()

While this command didn't cause any error to be displayed in the console, it was clearly not working properly in this context (again--very important to note here that this is being done in Vue 3).

I replaced the above line with:

let chartStatus = Chart.getChart(this.forecastChart)
chartStatus.destroy()

And now the original chart is properly destroyed and the new chart is drawn in its place. Here is the relevant code all together:

  watch: {
    '$store.state.weather.airQuality': {
      handler() {
        this.updateChart()
      },
      deep: true
    }
  },
  methods: {
    updateChart() {
      let chartStatus = Chart.getChart(this.forecastChart)  // key change
      chartStatus.destroy()                                 // key change
      this.animation = 0
      this.renderChart()
    },
    renderChart() {
      let ctx = document.getElementById(this.id).getContext('2d');
      this.forecastChart = new Chart(ctx, {
        type: 'doughnut',
        plugins: [{
          beforeDraw: (chart) => {
            const {ctx} = chart;

// etc.
DaveL17
  • 1,673
  • 7
  • 24
  • 38