1

I am following this tutorial, by Alligator, which explains how to create a basic line graph with vue js and chart js. The code works by defining a createChart vue method, importing chart configurations,planetChartData, and then calling the method once the vue instance is mounted to create a graph instance.

I, however, am interested in updating the line chart with new data points once an initial chart has been rendered to the html canvas element.

According to the chart js docs, a chart can be updated with the following function.

function addData(chart, label, data) {
    chart.data.labels.push(label);
    chart.data.datasets.forEach((dataset) => {
        dataset.data.push(data);
    });
    chart.update();
}

I took the function and decided to turn it into a vue method to update charts. Since coordinate data is stored in the data object I can directly modify the planetChartData like so, but my issue is that I'm unsure of what to pass as the chart parameter to rerender the chart once the arrays are updated, since the myChart instance is out of scope. I tried initializing myChart in other places but that always gave tons of errors.

addAtempt(chart, label, data){
  this.lineChartData.data.labels.push('label')
  this.lineChartData.data.datasets.forEach(dataset => {
    dataset.data.push(data);
  });
  //issue is here
  chart.update()
}

Below is my full vue component

 <template>
  <div>
      <h2>Fun Graph</h2>
      <canvas id="planet-chart"></canvas>
  </div>
</template>
<script>
import Chart from "chart.js";
import planetChartData from "./chart-data.js";

export default {
  name: "test",
  data() {
    return {
      text: "",
      planetChartData: planetChartData
    };
  },
  mounted() {
    this.createChart("planet-chart", this.planetChartData);
  },
  methods: {
    createChart(chartId, chartData) {
      const ctx = document.getElementById(chartId);
      const myChart = new Chart(ctx, {
        type: chartData.type,
        data: chartData.data,
        options: chartData.options
      });
    },
    addData(chart, label, data) {
      chart.data.labels.push(label);
      chart.data.datasets.forEach(dataset => {
        dataset.data.push(data);
      });
    }
  }
};
</script>
1
  • Brilliant idea creating the chart in the mounted function. I wasn't doing that, I was creating the chart by "watch"ing a prop so it wasn't working as it was throwing 'myChart is null'. Anyways, great solutions and great question! Commented Mar 23, 2020 at 10:02

1 Answer 1

3

You have to save a reference to the instance of your chart, namely in your createChart method.

Full working example on CodeSandbox.

 <template>
  <div>
      <h2>Fun Graph</h2>
      <canvas id="planet-chart"></canvas>
  </div>
</template>
<script>
import Chart from "chart.js";
import planetChartData from "./chart-data.js";

export default {
  name: "test",
  data() {
    return {
      text: "",
      planetChartData: planetChartData,
      myChart: null,
    };
  },
  mounted() {
    this.createChart("planet-chart", this.planetChartData);
  },
  methods: {
    createChart(chartId, chartData) {
      const ctx = document.getElementById(chartId);
      // Save reference
      this.myChart = new Chart(ctx, {
        type: chartData.type,
        data: chartData.data,
        options: chartData.options
      });
    },
    addData(label, data) {
    // Use reference
      this.myChart.data.labels.push(label);
      this.myChart.data.datasets.forEach(dataset => {
        dataset.data.push(data);
      });
    }
  }
};
</script>

Sign up to request clarification or add additional context in comments.

2 Comments

That worked!!! Would there be a way of making it dynamic. For example if I used the createChart() method again to create another chart, my original reference to graph 1 would be overridden, correct?
Yeah absolutely. I would create a key/value object to hold the reference to each new chart like myChart does now, with the key being the id and the value being the actual instance. Then maybe using an array to create new canvases. Here check this example on CodeSandbox.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.