Chart.js 在 Angular 8 中只有在缩放后才会渲染

4

我有一个 Angular 8 应用程序,使用的是 Primeng-lts 8.2.5 组件,我正在尝试在我的应用程序中使用 Chart.js 版本 2.9.3,但饼图不会显示出来,除非我放大它,同时也会出现标签问题。

在我的饼图中,我按状态显示计数,如下面的代码所示,我从 HTTP 调用中加载 status[],然后对于每个 status,我调用了一个返回计数的 HTTP 方法:

HTML:

<p-chart type="pie" [data]="numberByStatus" >
</p-chart>

抱歉,我只能用英语进行交流和翻译。
  numberByStatus : any;
  labelsByStatus: String[] = [];
  countsByStatus: number[] = [];


this.service.getStatus()
  .subscribe((res: status[]) => {


    res.forEach(element => {         
    this.service.getCountByStatus(element.id)
        .subscribe((count: number) => {
          this.countsByStatus.push(count);
          this.labelsByStatus.push(element.designation)
        }, (err) => {
          alert('Faild to load counts');
        });
    });


  }, (err) => {
    alert('Faild to load data');
  });


this.numberByStatus = {
  labels: this.labelsByStatus,
  datasets: [
    {
      data: this.countsByStatus,
      backgroundColor: [
        "#FF6384",
        "#36A2EB",
        "#FFCE56"
      ],
      hoverBackgroundColor: [
        "#FF6384",
        "#36A2EB",
        "#FFCE56"
      ]
    }]
};
2个回答

3

问题在于,当您尝试将项推入 labelsByStatuscountsByStatus 数组时,您的 numberByStatus 对象引用不会更改。

请尝试如下。

首先为两个解决方案导入所有这些项目。

import { forkJoin } from 'rxjs/internal/observable/forkJoin';
import { map } from 'rxjs/operators';

并且

numberByStatus : any;
labelsByStatus: String[] = [];
countsByStatus: number[] = [];


this.service.getStatus()
  .subscribe((res: status[]) => {

    const requestsList = [];   // define the request list property and store all of the requests here
    res.forEach(element => {  
    // push the request into the array
    requestsList.push(
       this.service.getCountByStatus(element.id).pipe(
          map(count => {   
              // push the count into countsByStatus
              this.countsByStatus.push(count);
              // push the element.designation into labelsByStatus
              this.labelsByStatus.push(element.designation);
              // return the count and the corresponding element
              // I think this can be helpfull. if you will need to know the count for the each element
              return { element: element, count: count }
          }))
       );

    });  
       // send all of the requests
       forkJoin(requestsList).subscribe(
             (response: {element: status, count: number}[]) => {
               // and now this line will work only once
                this.numberByStatus = { ...this.numberByStatus };
             },
             (err) => {
                alert('Faild to load data');
             }
        );

  }, (err) => {
    alert('Faild to load data');
  });

 this.numberByStatus = {
    labels: this.labelsByStatus,
    datasets: [
       {
           data: this.countsByStatus,
           backgroundColor: [
              "#FF6384",
              "#36A2EB",
              "#FFCE56"
           ],
           hoverBackgroundColor: [
              "#FF6384",
              "#36A2EB",
              "#FFCE56"
           ]
       }
    ]

 };

或者
numberByStatus : any;
labelsByStatus: String[] = [];
countsByStatus: number[] = [];


this.service.getStatus()
  .subscribe((res: status[]) => {

    const requestsList = [];   // define the request list property and store all of the requests here
    res.forEach(element => {  
    // push the request into the array
    requestsList.push(
       this.service.getCountByStatus(element.id).pipe(
          map(count => {   
               // push the count into countsByStatus
              this.countsByStatus.push(count);
              // push the element.designation into labelsByStatus
              this.labelsByStatus.push(element.designation);
              // return the count and the corresponding element
              // I think this can be helpfull. if you will need to know the count for the each element
              return { element: element, count: count }
          }))
       );
    });  
    
       forkJoin(requestsList).subscribe(
             (response: {element: status, count: number}[]) => {
              // and now this line will work only once
               this.numberByStatus = {
                   labels: this.labelsByStatus,
                   datasets: [
                      {
                         data: this.countsByStatus,
                         backgroundColor: [
                             "#FF6384",
                             "#36A2EB",
                             "#FFCE56"
                         ],
                         hoverBackgroundColor: [
                             "#FF6384",
                             "#36A2EB",
                             "#FFCE56"
                         ]
                     }
                 ]

             };
    
             },
             (err) => {
                alert('Faild to load data');
             }
          );

  }, (err) => {
    alert('Faild to load data');
  });

那正是问题所在,我尝试了第二个建议,而且成功了,谢谢你。 - Bilal Dekar
1
@BillyDEKAR,你也可以使用formJoin一次性完成所有请求,以提高性能。我看到你在每次迭代中都发送请求,并且更改检测将在每个this.numberByStatus = something上工作。 - Ashot Aleqsanyan
@BillyDEKAR 我已经更新了答案。请您再检查一遍。 - Ashot Aleqsanyan
如果在forkJoin中从未使用{ element: element, count: count }返回,那么返回它的意义是什么? - Bilal Dekar
1
@BillyDEKAR 如果将来需要它,您不需要进行任何更改。只是为了那个。 - Ashot Aleqsanyan

0

问题是由于 Angular 的异步特性引起的。图表是在其 labelsdatathis.numberByStatus 中定义之前创建的。

基本上有两种解决方法来解决这个问题。

  1. 确保图表只在 this.numberByStatus 完全配备后才创建。
  2. this.numberByStatus 完全定义后,通过编程方式更新图表。

不过,没有看到更多你的代码,很难提供最佳解决方案。我也不知道 primeng-lts。

  • 您可以尝试仅使用 *ngIf 在 HTML 模板中有条件地包含图表。它应该只在 this.numberByStatus 准备好使用 (解决方案1) 时评估为 true
  • 如果可以获取对 chart 对象的引用,则在重新定义 this.numberByStatus 后调用其 update() 方法(解决方案2)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接