【问题标题】:Chart.js and Angular 8 - Dynamically updating Chart.js labels and data from *ngforChart.js and Angular 8 - 从 *ngfor 动态更新 Chart.js 标签和数据
【发布时间】:2019-07-15 14:35:33
【问题描述】:

我对 Angular 比较陌生,但我的任务是构建一个证明相当复杂的单页应用程序(无论如何对我来说)。

在此应用程序的一部分中,有一个图表 - 通过使用 Chart.js 创建 - 可以通过选择字段和输入字段动态更新。

以下是平面设计的示例:

因此,用户将通过“添加存款来源”链接添加存款来源,这反过来会显示选项字段和输入字段(我已经编码)以及当用户从选择字段并在输入中输入一个值,图表应该更新。然后他们可以根据需要多次重复此过程。此外,单击时,垃圾桶图标也应该能够从图表的数组中删除这些值以及从页面中删除字段。

我已经能够让这些值分别更新,所以我可以在用户选择一个选项时向数组添加标签,并且我可以在用户关注字段后从输入字段添加值,但我不能让它们一起发生。

这是我的 HTML 中的代码:

            <div class="chart-container">
              <canvas #lineChart id="depositBreakdown" width="300" height="300">{{chart}}</canvas>
            </div>
            <div class="source-container">
                <div *ngFor="let depositSource of depositSources; let depositParent = index" id="{{'source' + depositParent}}" class="deposit-source">
                  <mat-form-field class="dropdown">
                    <mat-select placeholder="Deposit source" (selectionChange)="getLabel($event, chart, label, data)">
                      <mat-option *ngFor="let deposit of deposits; let depositSourceOption = index" [value]="deposit.value" id="{{'option' + depositSourceOption}}">
                        {{ deposit.viewValue }}
                      </mat-option>
                    </mat-select>
                  </mat-form-field>
                  <mat-form-field class="textfield">
                    <input
                      matInput
                      currencyMask
                      [options]="{ align: 'right', prefix: '£ ', thousands: ',', precision: 0 }"
                      placeholder="£ 0"
                      [(ngModel)]="depositSourceAmount"
                      [ngModelOptions]="{ standalone: true }"
                      (focusout)="getData(index, chart, label, data)"
                    />
                  </mat-form-field>
                  <mat-icon (click)="removeDeposit(depositSource)">delete</mat-icon>
                </div>
                <a id="addDepositSource" (click)="appendDeposit()">+ Add Deposit Source</a>
              </div>
        </div>

我的 TS 文件中与此相关的代码:

  deposits: Deposit[] = [
    { value: 'buildersGift', viewValue: 'Builders Gift' },
    { value: 'gift', viewValue: 'Gift' },
    { value: 'loan', viewValue: 'Loan' },
    { value: 'savings', viewValue: 'Savings' },
    { value: 'saleOfProperty', viewValue: 'Sale of Property' },
    { value: 'inheritance', viewValue: 'Inheritance' },
    { value: 'vendorGifted', viewValue: 'Vendor Gifted' },
    { value: 'equity', viewValue: 'Equity' },
    { value: 'forcesHelp', viewValue: 'Forces Help to Buy Loan' },
    { value: 'helpToBuyISA', viewValue: 'Help to Buy ISA' },
    { value: 'porting', viewValue: 'Porting' },
    { value: 'other', viewValue: 'Other' }
  ];

 ngAfterViewInit() {
    this.chart = new Chart(this.chartRef.nativeElement, {
      type: 'doughnut',
      data: {
          labels: [],
          datasets: [{
              label: 'Deposit Sources',
              data: [],
              backgroundColor: [
                  'rgba(254, 11, 48, 1)',
                  'rgba(252, 92, 101, 1)',
                  'rgba(86, 223, 144, 1)',
                  'rgba(186, 223, 86, 1)',
                  'rgba(191, 86, 223, 1)',
                  'rgba(235, 5, 5, 1)',
                  'rgba(43, 203, 186, 1)',
                  'rgba(5, 235, 235, 1)',
                  'rgba(169, 86, 223, 1)',
                  'rgba(86, 160, 223, 1)',
                  'rgba(102, 86, 223, 1)',
                  'rgba(223, 86, 218, 1)',
              ]
          }]
      },
      options: {
        legend: {
          display: false
        },
        scales: {
          xAxes: [{
            display: false
          }],
          yAxes: [{
            display: false
          }],
        }
      }
    });
  }

  getLabel(event, chart, data) {
    let target = event.source.selected._element.nativeElement;
    chart.data.labels.push(target.innerText.trim());
    chart.data.datasets.forEach((dataset) => {
      dataset.data.push(data);
    });
    chart.update();
  }

  getData(event, chart, label, data) {
    data = this.depositSourceAmount;
    chart.data.datasets.forEach((dataset) => {
      dataset.data.push(data);
    });
    chart.update();
  }

    depositSources: depositCreate[] = [];

  appendDeposit() {
    this.depositSources.push(new depositCreate());
  }

  removeDeposit = function(depositSource) {
    this.depositSources.splice(this.depositSources.indexOf(depositSource), 1);
  }

我尝试设置一个准系统 StackBlitz,尽管它似乎比我的原始代码更有问题:https://stackblitz.com/edit/angular-zpu7jh

我一直在尝试将我的 getLabel() 和 getData() 函数组合成一个函数,但我已经陷入了僵局,我已经达到了我的知识极限。我已经尝试在此处和网络的其他部分进行搜索,但无法完全找到帮助我确定它的信息。我能得到的最好的是将标签和值添加到图表但彼此分开的位置。我的主要问题是试图理解嵌套的 ngFor 循环。

我希望我已经充分解释了这一点 - 我周五和今天一整天都在努力,我已经走到了尽头。任何帮助将不胜感激。

【问题讨论】:

  • 问题是,Chartjs 在“Angular 世界”之外。如果可能的话,让它们一起工作变得非常困难。幸运的是,大多数插件也以 Angular 风格存在。在你的情况下是ng2-charts
  • I've been trying to combine my getLabel() and getLabel() functions into one function 没有任何意义,是错字吗?您可能需要对此进行编辑或澄清
  • @Riv - 是的,你说得非常对,对不起,应该读 getLabel() 和 getData()。我已经对其进行了编辑以反映这一点。
  • @JeremyThille - 啊,我明白了。谢谢,我去看看希望它比 Chart.js 更容易实现,尽管我觉得我会遇到类似的问题。

标签: javascript angular charts chart.js ngfor


【解决方案1】:

Jeremy Thille 给我的回复帮助我朝着正确的方向前进。通过安装 ng2-charts,我能够添加一个图表,让我可以更轻松地将标签和数据推送到图表:

HTML:

<div class="deposit-container">
            <div class="chart-container">
              <canvas baseChart
              width="290" 
              height="290"
              [data]="doughnutChartData"
              [labels]="doughnutChartLabels"
              [options]="doughnutChartOptions"
              [colors]="doughnutChartColors"
              [chartType]="doughnutChartType"></canvas>
            </div>
            <div class="source-container">
                <div *ngFor="let depositSource of depositSources; let depositParent = index" id="{{'source' + depositParent}}" class="deposit-source">
                  <mat-form-field class="dropdown">
                    <mat-select placeholder="Deposit source" (selectionChange)="getLabel($event)">
                      <mat-option *ngFor="let deposit of deposits; let depositSourceOption = index" [value]="deposit.value" id="{{'option' + depositSourceOption}}">
                        {{ deposit.viewValue }}
                      </mat-option>
                    </mat-select>
                  </mat-form-field>
                  <mat-form-field class="textfield">
                    <input
                      matInput
                      currencyMask
                      [options]="{ align: 'right', prefix: '£ ', thousands: ',', precision: 0 }"
                      placeholder="£ 0"
                      [(ngModel)]="depositSourceAmount[depositParent]"
                      [ngModelOptions]="{ standalone: true }"
                      (focusout)="getData(depositParent)"
                    />
                  </mat-form-field>
                  <mat-icon (click)="removeDeposit(depositSource)">delete</mat-icon>
                </div>
                <a id="addDepositSource" (click)="appendDeposit()">+ Add Deposit Source</a>
              </div>
        </div>

TS:

  public doughnutChartLabels = [];
  public doughnutChartData = [];
  public doughnutChartType = 'doughnut';

  public doughnutChartOptions = {
    legend: {
      display: false
    }
  };

  public doughnutChartColors: Array<any> = [
    { 
      backgroundColor: [
        'rgba(254, 11, 48, 1)',
        'rgba(86, 223, 144, 1)',
        'rgba(186, 223, 86, 1)',
        'rgba(191, 86, 223, 1)',
        'rgba(235, 5, 5, 1)',
        'rgba(43, 203, 186, 1)',
        'rgba(5, 235, 235, 1)',
        'rgba(169, 86, 223, 1)',
        'rgba(252, 92, 101, 1)',
        'rgba(86, 160, 223, 1)',
        'rgba(102, 86, 223, 1)',
        'rgba(223, 86, 218, 1)'
      ]
    }
]

  getLabel(event) {
    let target = event.source.selected._element.nativeElement;
    console.log(target.innerText.trim());
    this.doughnutChartLabels.push(target.innerText.trim());
    this.chart.chart.update();
  }

  getData(depositParent) {
    let data = this.depositSourceAmount[depositParent];
    this.doughnutChartData.push(data);
    this.chart.chart.update();
  }

  depositSources: depositCreate[] = [];

  appendDeposit() {
    this.depositSources.push(new depositCreate());
  }

  removeDeposit = function(depositSource) {
    this.depositSources.splice(this.depositSources.indexOf(depositSource), 1);
  }

我仍然需要弄清楚从正确的位置编辑和删除数组中的数据,但这完全是一个单独的问题,所以我将其标记为已解决。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多