0

健康)状况

我在没有包装器的情况下在 Vue 3 中使用 Chartjs,并且能够成功呈现我的图表。图表数据存储在 Vuex 存储中,我每 5 秒更新一次 Vuex 存储状态(轮询 Restful API)。我发现,根据新数据更新图表的唯一安全方法是每次都destroy()重新调整图表。renderChart()这似乎有点矫枉过正,因为 Chartjs 具有update()可用的功能。

如果我尝试用命令替换destroy()andrenderChart()命令update(0),我的 CPU 很快就会溢出(达到 150% +)。因为我不希望图表每 5 秒重新设置一次动画,所以我的解决方案是在变量中设置动画时间,this.animation初始渲染设置为 2000,然后为所有后续渲染设置为 0。

这会在第一次加载页面时为图表提供动画,随后的重绘对查看器“隐藏”(无动画)。

期望的结果

更新 Vuex 存储状态时更新图表(而不是销毁和重新渲染)。

图表组件

这个文件中的重要部分(我认为)是mounted()watch.data

<template>
  <canvas width="100%" height="100%" :id="id"/>
</template>

<script>
import Chart from "chart.js/auto";
import annotationPlugin from 'chartjs-plugin-annotation';
import ChartDataLabels from 'chartjs-plugin-datalabels';

Chart.register(annotationPlugin);
Chart.register(ChartDataLabels);

export default {
  name: "ChartPressure8day.vue",
  props: ['id', 'data'],
  data() {
    return {
      pressureChart: null,
      animation: 2000,
      pressureLabels: [
        this.data['d01_day_short'], this.data['d02_day_short'], this.data['d03_day_short'], this.data['d04_day_short'],
        this.data['d05_day_short'], this.data['d06_day_short'], this.data['d07_day_short'], this.data['d08_day_short'],
      ],
      pressureData: [
        this.data['d01_pressure'], this.data['d02_pressure'], this.data['d03_pressure'], this.data['d04_pressure'],
        this.data['d05_pressure'], this.data['d06_pressure'], this.data['d07_pressure'], this.data['d08_pressure'],
      ],
      chartMaxY: Math.max(...[
        this.data['d01_pressure'], this.data['d02_pressure'], this.data['d03_pressure'], this.data['d04_pressure'],
        this.data['d05_pressure'], this.data['d06_pressure'], this.data['d07_pressure'], this.data['d08_pressure'],
      ]),
    }
  },
  mounted() {
    this.renderChart()
  },
  watch: {
    // the intention here is to rerender the chart when the data changes.
    data: function (){
      // this.pressureChart.update(0)
      this.pressureChart.destroy()
      this.animation = 0
      this.renderChart()
    }
  },
  methods: {
    renderChart() {
      let ctx = document.getElementById(this.id).getContext('2d');
      this.pressureChart = new Chart(ctx, {
        options: {
          layout: {
            padding: {
              right: 20,
            }
          },
          plugins: {
            datalabels: {
              backgroundColor: function (context) {
                return context.dataset.backgroundColor;
              },
              borderRadius: 4,
              color: '#888888',
              font: {
                weight: 'bold'
              },
            },
            annotation: {
              annotations: {
                line1: {
                  type: 'line',
                  label: {
                    color: '#888888',
                    enabled: true,
                    content: 'normal',
                    font: {
                      style: 'normal',
                      size: 9,
                      position: 'start',
                    },
                  },
                  yMin: 1015,
                  yMax: 1015,
                  borderColor: 'rgb(255, 255, 0, 0.4)',
                  borderWidth: 1,
                  borderDash: [5, 5],
                  adjustScaleRange: false,
                },
              }
            },
            tooltip: {
              position: 'nearest',
            },
            legend: {
              display: false,
            },
          },
          responsive: true,
          scales: {
            x: {
              categoryPercentage: 0.5,
              stacked: false,
              fontSize: 5,
              grid: {
                color: "#333333",
                display: true,
                borderDash: [1, 2],
              },
            },
            y: {
              grid:{
                color: "#333333",
                display: true,
                borderDash: [1, 2],
              },
              ticks: {
                stepSize: 10,
              },
              barPercentage: 0,
              categoryPercentage: 0,
              fontSize: 5,
              // min: 970,
              max: Math.ceil((this.chartMaxY + 10) / 10) * 10,
              stacked: false,
              position: 'left',
            },
          },
          maintainAspectRatio: false,
          animation: {
            duration: this.animation,
            easing:'easeInOutQuart'
          }
        },
        data: {
          labels: this.pressureLabels,
          datasets: [
            {type: 'line',
             backgroundColor: "rgba(200, 200, 0, 0.2)",
             borderColor: "rgba(200, 200, 0, 1)",
             borderRadius: 3,
             data: this.pressureData,
             hoverBackgroundColor: "rgba(200, 200, 0, 0.5)",
             label: "",
             yAxisID: 'y',
             datalabels: {
               align: 'end',
             }
            },
          ]
        },
      },
      Chart.defaults.elements.point.radius = 0,
      Chart.defaults.elements.point.hoverRadius = 0,
      Chart.defaults.elements.point.pointStyle = 'triangle',
      Chart.defaults.elements.bar.borderWidth = 1,
      Chart.defaults.elements.line.borderWidth = 1,
      );
    }
  },
}
</script>

编辑 1:我刚刚发现这种方法的一个副作用(销毁和重新渲染)是,如果光标悬停在图表上 - 就像显示工具提示时一样 - 它最终会导致错误canvas.getContext,大概是因为图表对象在光标下被破坏。我认为这可以通过update().

编辑 2:为清晰和布局对图表代码进行了细微改进(无功能更改)。

4

0 回答 0