Как обновить диаграмму. js в vue - PullRequest
0 голосов
/ 06 мая 2020

Я создал диаграмму. js vue компонент, который отображает некоторые данные, которые передаются ему через props. Теперь я хочу иметь возможность вызывать метод update () на диаграмме при изменении данных. Моя проблема в том, что из-за того, как структурирован мой код, я не могу использовать обычный метод chart.update (), так как я не могу получить доступ к переменной диаграммы извне функции, в которой она была создана. Как я могу реструктурировать свой код, чтобы я мог вызвать метод обновления на диаграмме?

В момент изменения данных я просто вызываю начальную функцию рендеринга, которая заставляет диаграммы накладываться друг на друга. Это можно увидеть, изменив данные и наведя курсор на диаграмму.

Vue.component('chart', {
    template: '<canvas id="chart"></canvas>',
    props: {
        savings: Object,
    },
    watch: { 
        savings: {
            deep: true,
            handler() {
                console.log('Update Chart');
                this.createChart();
            }
        }
    },
    methods: {
        createChart() {
            new Chart(document.getElementById("chart"), {
                type: 'bar',
                data: {
                    datasets: [{
                        label: 'Bar Dataset',
                        data: [
                        	this.savings.annual[0], 
                            this.savings.annual[1], 
                            this.savings.annual[2], 
                            this.savings.annual[3],
                            this.savings.annual[4]
                        ]
                    }, {
                        label: 'Line Dataset',
                        data: [
                        	this.savings.cumulative[0], 
                            this.savings.cumulative[1], 
                            this.savings.cumulative[2], 
                            this.savings.cumulative[3],
                            this.savings.cumulative[4]
                        ],
                        type: 'line'
                    }],
                    labels: ['Year One', 'Year Two', 'Year Three', 'Year Four', 'Year Five']
                }
            });
        }
    },
    mounted() {
        this.createChart();
        console.log(this.totals);
    }
});

var app1 = new Vue({
    el: '#savings_calculator',
    data: {
        savings: {
        	annual: [123,345,234,234,523],
            cumulative: [234,523,234,423,100],
        }
    },
    methods: {
    	changeData() {
        	for(let i = 0; i < 5; i++) {
            	Vue.set(this.savings.annual, i, Math.floor((Math.random() * 1000) + 1));
                Vue.set(this.savings.cumulative, i, Math.floor((Math.random() * 1000) + 1));
            }
        	
        }
	}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="savings_calculator">
    <div class="input container">
        <button v-on:click="changeData">Change Data</button>
        <chart 
            v-bind:savings="savings"
        />
    </div>
</div>

Я работаю в WordPress и включил диаграмму. js библиотеку, скопировав код в один из моих js файлов, которые все уменьшаются и сжат в один файл с помощью gulp. Я упоминаю об этом только потому, что видел примеры, когда люди использовали импорт для включения библиотеки. Я загрузил библиотеку в свои node_modules, но мне не удалось заставить импорт работать в моих файлах js. Это дало мне следующую ошибку:

“Uncaught SyntaxError: Cannot use import statement outside a module” 

1 Ответ

1 голос
/ 06 мая 2020

Эта проблема в основном возникает из-за того, что вы рисуете несколько диаграмм на одном canvas при вызове метода createChart(). Вам просто нужно вызвать метод .destroy(), чтобы уничтожить все созданные экземпляры диаграммы. Это очистит все ссылки, хранящиеся в объекте диаграммы в Chart. js, вместе со всеми связанными прослушивателями событий, прикрепленными Chart. js. Это должно быть вызвано перед повторным использованием холста для новой диаграммы.

Итак, просто добавьте новый параметр данных для сохранения текущего экземпляра диаграммы, например:

data(){
  return{
    chart: null
  }
},

, а затем сохраните экземпляр диаграммы, например :

 createChart() {
    this.chart = new Chart(document.getElementById("chart"), {
    ...

и внутри watch перед звонком this.createChart(); используйте:

  this.chart.destroy();
  this.createChart();

Рабочая демонстрация:

Vue.component('chart', {
  template: '<canvas id="chart"></canvas>',
  props: {
    savings: Object,
  },
  data(){
    return{
      chart: null
    }
  },
  watch: {
    savings: {
      deep: true,
      handler() {
        console.clear();
        console.log('Update Chart');
        this.chart.destroy();
        this.createChart();
      }
    }
  },
  methods: {
    createChart() {
      this.chart = new Chart(document.getElementById("chart"), {
        type: 'bar',
        data: {
          datasets: [{
            label: 'Bar Dataset',
            data: [...this.savings.annual]
          }, {
            label: 'Line Dataset',
            data: [...this.savings.cumulative],
            type: 'line'
          }],
          labels: ['Year One', 'Year Two', 'Year Three', 'Year Four', 'Year Five']
        }
      });
    }
  },
  mounted() {
    this.createChart();
    //console.log(this.totals);
  }
});

var app1 = new Vue({
  el: '#savings_calculator',
  data: {
    savings: {
      annual: [123, 345, 234, 234, 523],
      cumulative: [234, 523, 234, 423, 100],
    }
  },
  methods: {
    changeData() {
      for (let i = 0; i < 5; i++) {
        Vue.set(this.savings.annual, i, Math.floor((Math.random() * 1000) + 1));
        Vue.set(this.savings.cumulative, i, Math.floor((Math.random() * 1000) + 1));
      }

    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="savings_calculator">
  <div class="input container">
    <button v-on:click="changeData">Change Data</button>
    <chart v-bind:savings="savings" />
  </div>
</div>
...