如何将参数传递给 ng2-charts 中的全局注册插件(或者,如何在本地注册)?

问题描述 投票:0回答:1

我在 ng2-charts(版本 4.1.1,chart.js 版本为 4.4.0)中遇到以下问题:我制作了一个插件来根据某些阈值对折线图的不同部分进行着色。我从this Question获得了关于插件实现的帮助。阈值作为输入变量传递到包含图表的组件。我需要同时实例化多个图表(想象它们在仪表板上,采用某种网格布局),每个图表都有不同的阈值。

问题是,由于我制作的插件是在 Chart.js 中全局注册的,因此对于所有图表来说,它获得的阈值似乎都是首先通过的阈值,即使我使用

this
来引用类的实例变量(并且这些变量确实会更新)。例如,我有两个图表,第一个接收
minThreshold: 10
maxThreshold: 20
,第二个接收
minThreshold: 20
maxThreshold: 40
,但插件同时考虑 10 和 20。

稍微解释一下代码,

updateDataPointsColor
负责为折线图上的点着色。我还使用注释插件渲染一条水平虚线来表示阈值,顺便说一句,有趣的是,尽管后一个插件是全局注册的,但它能够动态获取阈值,如下所示我在选项对象中更新它们。我想对我的插件执行相同的操作,或者(如果有意义的话)在本地注册它(但我似乎无法使其工作)。 有人对如何解决这个问题有任何建议或想法吗?

这是我的代码:

import { ChangeDetectorRef, Component, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
import { Chart, ChartDataset, ChartOptions, ChartType } from 'chart.js';
import { BaseChartDirective } from 'ng2-charts';
import { Subject } from 'rxjs';
import annotationPlugin from 'chartjs-plugin-annotation';


@Component({
  selector: 'chart',
  templateUrl: './chart.component.html',
  styleUrls: ['./chart.component.css']
})
export class ChartComponent implements OnChanges {

  @Input()
  get data(): any[] { return this._data; }
  set data(data: any[]) {
    this._data = data;
    this.updateDataPointsColor();
    this.updateChart();
  }
  private _data!: any[];

  @Input()
  get yAxes(): any { return this._yAxes; }
  set yAxes(yAxes: any) {
    this._yAxes = yAxes;
    this.lineChartOptions.scales['y'] = this._yAxes;
    this.updateDataPointsColor();
    this.updateChart();
  }
  private _yAxes: any;

  @Input()
  maxThreshold: number = undefined;

  @Input()
  minThreshold: number = undefined;

  @Output() onCloseChartsDashlet: Subject<void> = new Subject<void>();
  display: boolean = true;
  destroyed: Subject<boolean> = new Subject();

  @ViewChild(BaseChartDirective) chart!: BaseChartDirective;

  // contains _data array
  public lineChartData: ChartDataset[];

  public lineChartLabels: any[];

  public lineChartOptions: ChartOptions = {
    animation: false,
    responsive: true,
    maintainAspectRatio: false,
    scales: {
      x: {
        display: false,
        title: {
          display: false,
          text: 'Time',
          font: {
            weight: 'bold',
            size: 14
          }
        },
        ticks: {
          display: true,
          padding: 10
        },
        grid: {
          color: "rgba(0, 0, 0, 0)"
        }
      }
    },
    datasets: {
      line: {
        backgroundColor: 'rgba(255, 0, 0, 0.3)',
        borderColor: 'rgba(31, 119, 180, 1)',
        pointBackgroundColor: 'rgba(31, 119, 180, 1)',
        pointBorderColor: '#fff',
        pointHoverBackgroundColor: '#fff',
        pointHoverBorderColor: 'rgba(31, 119, 180, 1)',
        tension: 0.1
      },
    },
    plugins: {
      annotation: {
        annotations: [
          {
            display: this.minThreshold ? true : false,
            type: 'line',
            id: 'minThreshold',
            scaleID: 'y',
            value: this.minThreshold,
            borderColor: 'red',
            borderDash: [5, 5],
            borderWidth: 0.5,
            drawTime: 'afterDatasetsDraw'
          },
          {
            display: this.maxThreshold ? true : false,
            type: 'line',
            id: 'maxThreshold',
            scaleID: 'y',
            value: this.maxThreshold,
            borderColor: 'red',
            borderDash: [5, 5],
            borderWidth: 0.5,
            drawTime: 'afterDatasetsDraw'
           },          
        ]
      }
    }
  };

  public lineChartLegend = false;
  public lineChartType: ChartType = 'line';

  public chartName = null;


  constructor(private cdRef: ChangeDetectorRef) {
    Chart.register(annotationPlugin);
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.minThreshold ||
        changes.maxThreshold) {

      if (changes.minThreshold) {
        this.lineChartOptions.plugins.annotation.annotations[0].value = this.minThreshold;
        this.lineChartOptions.plugins.annotation.annotations[0].display = this.minThreshold ? true : false;
      } else {
        this.lineChartOptions.plugins.annotation.annotations[1].value = this.maxThreshold;
        this.lineChartOptions.plugins.annotation.annotations[1].display = this.maxThreshold ? true : false;
      }

      if (this.minThreshold !== undefined ||
          this.maxThreshold !== undefined) {
        this.registerPlugins();
        this.updateDataPointsColor();
        this.updateChart();
      }
    }
  }

  ngOnDestroy(): void {
    //console.log("chart destroyed");
  }


  /**
   * Set data labels
   */
  private setLabels() {
    // do something
  }

  /**
   * Update chart with new data
   */
  updateChart() {

    this.lineChartData = [{
      data: this._data.map(el => {
        return {
          x: el.timestamp,
          y: el.value
        }
      }),
      fill: false
    }];
    this.setLabels();
    this.chart?.update();
  }

  /**
   * Change some data points color upon a condition
   */
  updateDataPointsColor() {

    let dataColors = this.lineChartOptions.datasets.line;
    let colorsArray: any = [];
    for (const dataPoint of this.data) {
      let color = 'rgba(31, 119, 180, 1)';
      if (dataPoint.value >= this.maxThreshold ||
          dataPoint.value <= this.minThreshold) {
        color = 'red';
      }
      colorsArray.push(color);
    }
    dataColors.pointBackgroundColor = colorsArray;
    dataColors.pointHoverBorderColor = colorsArray;
  }

  private registerPlugins() {
    Chart.register(
      {
        id: "color-by-min-max-thresholds",
        afterLayout: chart => {
          if (!this.maxThreshold || !this.minThreshold) {
            return;
          }
          let ctx = chart.ctx;
          ctx.save();
          let yAxis = chart.scales["y"];
          let yThresholdMax = this.maxThreshold ? yAxis.getPixelForValue(this.maxThreshold) : undefined;
          let yThresholdMin = this.minThreshold ? yAxis.getPixelForValue(this.minThreshold) : undefined;

          let offsetMax = yThresholdMax ? (yThresholdMax - yAxis.top) / (yAxis.bottom - yAxis.top) : 0;
          let offsetMin = yThresholdMin ? (yThresholdMin - yAxis.top) / (yAxis.bottom - yAxis.top) : 1;
      
          if (offsetMax < 0) {
            offsetMax = 0;
          } else if (offsetMax > 1) {
            offsetMax = 1;
          }

          if (offsetMin < 0) {
            offsetMin = 0;
          } else if (offsetMin > 1) {
            offsetMin = 1;
          }

          let gradient = ctx.createLinearGradient(0, yAxis.top, 0, yAxis.bottom);
          gradient.addColorStop(0, 'red');
          gradient.addColorStop(offsetMax, 'red');
          gradient.addColorStop(offsetMax, 'rgba(31, 119, 180, 1)');
          gradient.addColorStop(offsetMin, 'rgba(31, 119, 180, 1)');
          gradient.addColorStop(offsetMin, 'red');
          gradient.addColorStop(1, 'red');
          chart.data.datasets[0].borderColor = gradient;
          ctx.restore();
        }
      }
    );
  }

}

我不明白的另一件事是,我“被迫”使用 OnChanges 钩子来调用

registerPlugins
,因为否则,阈值将是未定义的(我尝试在 ngOnInit 和 ngAfterViewInit 中注册插件,但是没有成功;在钩子中设置了值,但在插件函数中它们是未定义的)。

javascript angular typescript chart.js ng2-charts
1个回答
0
投票

// Modify the plugin to accept threshold values as parameters
const colorByMinMaxThresholds = {
  id: "color-by-min-max-thresholds",
  afterLayout: (chart: Chart) => {
    const options = chart.options;
    const minThreshold = options.plugins.minThreshold;
    const maxThreshold = options.plugins.maxThreshold;

    if (!maxThreshold || !minThreshold) {
      return;
    }

    // Plugin logic to handle threshold values...
  }
};

@Component({
  selector: 'chart',
  templateUrl: './chart.component.html',
  styleUrls: ['./chart.component.css']
})
export class ChartComponent implements OnChanges {

  @Input() maxThreshold: number = undefined;
  @Input() minThreshold: number = undefined;

  constructor(private cdRef: ChangeDetectorRef) {
    Chart.register(annotationPlugin);
    Chart.register(colorByMinMaxThresholds); // Register the modified plugin
  }

  ngOnChanges(changes: SimpleChanges): void {
    // Update the threshold values in chart options when they change
    if (this.chart && (changes.minThreshold || changes.maxThreshold)) {
      this.chart.options.plugins.minThreshold = this.minThreshold;
      this.chart.options.plugins.maxThreshold = this.maxThreshold;
      this.chart.update(); // Update the chart to reflect changes
    }
  }

  // Other component code...
}


© www.soinside.com 2019 - 2024. All rights reserved.