Javascript ng2-charts 更新标签和数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42629819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:18:08  来源:igfitidea点击:

ng2-charts update labels and data

javascriptangularchart.jsng2-charts

提问by mustafa918

I'm trying to create dynamically a chart using ng2-chart, I get information from an angular 2 service, when I change only labels of chart it works and when I change data only it works, but When I change both just data are updated in the chart. have any one an explication for this strange behavior.

我正在尝试使用 ng2-chart 动态创建图表,我从 angular 2 服务获取信息,当我只更改图表标签时,它可以工作,而当我更改数据时,它只工作,但是当我更改两者时,只更新数据在图表中。有没有人解释一下这种奇怪的行为。

my template :

我的模板:

<canvas baseChart height="130" width="180"  
    [data]="doughnutChartData"
    [labels]="doughnutChartLabels"
    [chartType]="doughnutChartType"
    (chartHover)="chartHovered($event)"
    (chartClick)="chartClicked($event)">
</canvas>

my class :

我的课 :

export class PlDoughnutComponent implements OnInit {

  constructor(private homeService: TileServiceService) { }

  ngOnInit() {
    this.updatePLdoughnut();

  }

  public util : UtilService = new UtilService();
  public doughnutChartLabels:string[] = ['Download Sales'];
  public doughnutChartData:number[] = [0,0,100];
  public doughnutChartType:string = 'doughnut';

  public updatePLdoughnut(){

    this.homeService.getTile().
    then(res => {

      this.doughnutChartLabels =  res.PLtypes;
      this.doughnutChartData = this.util.objectToIntArray(res.PLByTypes);

    })
  }
}

回答by Sleeper9

Apparently, if you do not modify the original referenceto the labels array, it seems to work, at least for me. I mean, if you want a completely different set of labels, you should do something like this:

显然,如果您不修改对标签数组的原始引用,它似乎有效,至少对我而言。我的意思是,如果你想要一组完全不同的标签,你应该这样做:

In the template:

在模板中:

<canvas baseChart
  [datasets]="lineChartData"
  [labels]="lineChartLabels"
  [options]="lineChartOptions"
  [chartType]="'line'"></canvas>

In the ts component:

在 ts 组件中:

this.lineChartLabels.length = 0;
for (let i = tempLabels.length - 1; i >= 0; i--) {
  this.lineChartLabels.push(tempLabels[i]);
}

Or, using new ECMAScript syntax:

或者,使用新的 ECMAScript 语法:

this.lineChartLabels.length = 0;
this.lineChartLabels.push(...tempLabels);

The key is maybe the this.lineChartLabels.length = 0;statement, which practically 'empties' your array by setting its length to 0, without modifying the reference. Hope this helps!

关键可能是this.lineChartLabels.length = 0;语句,它实际上通过将数组的长度设置为 0 来“清空”数组,而不修改引用。希望这可以帮助!

回答by Abdelhalim FELLAGUE CHEBRA

Recently i had to use ng2-charts and i was having a very big issues with updating my data untill i found this sollution:

最近我不得不使用 ng2-charts 并且我在更新我的数据时遇到了一个非常大的问题,直到我找到了这个解决方案:

<div class="chart">
    <canvas baseChart [datasets]="datasets_lines" [labels]="labels_line" [colors]="chartColors" [options]="options" [chartType]="lineChartType">
    </canvas>
</div>

and here what i have in my component :

在这里,我的组件中有什么:

import { Component, OnInit, Pipe, ViewChild, ElementRef } from '@angular/core';
import { BaseChartDirective } from 'ng2-charts/ng2-charts';

@Component({
    moduleId: module.id,
    selector: 'product-detail',
    templateUrl: 'product-detail.component.html'
})

export class ProductDetailComponent {
    @ViewChild(BaseChartDirective) chart: BaseChartDirective;

    private datasets_lines: { label: string, backgroundColor: string, borderColor: string, data: Array<any> }[] = [
        {
        label: "Quantities",
        data: Array<any>()
    }
];

private labels_line = Array<any>();

private options = {
    scales: {
        yAxes: [{
            ticks: {
                beginAtZero: true
            }
        }]
    }
};


constructor() { }
ngOnInit() {

    this.getStats();

}
getStats() {

    this._statsService.getStatistics(this.startDate, this.endDate, 'comparaison')
        .subscribe(
        res => {
            console.log('getStats success');
            this.stats = res;

            this.labels_line = this.getDates();
            this.datasets_lines = [];

            let arr: any[];
            arr = [];
            for (let stat of this.stats) {
                arr.push(stat.quantity);
            }

            this.datasets_lines.push({
                label: 'title',
                data: arr
            });

            this.refresh_chart();

        },
        err => {
            console.log("getStats failed from component");
        },
        () => {
            console.log('getStats finished');
        });
}

refresh_chart() {
    setTimeout(() => {
        console.log(this.datasets_lines_copy);
        console.log(this.datasets_lines);
        if (this.chart && this.chart.chart && this.chart.chart.config) {
            this.chart.chart.config.data.labels = this.labels_line;
            this.chart.chart.config.data.datasets = this.datasets_lines;
            this.chart.chart.update();
        }
    });
}

getDates() {
    let dateArray: string[] = [];
    let currentDate: Date = new Date();
    currentDate.setTime(this.startDate.getTime());
    let pushed: string;
    for (let i = 1; i < this.daysNum; i++) {
        pushed = currentDate == null ? '' : this._datePipe.transform(currentDate, 'dd/MM/yyyy');
        dateArray.push(pushed);
        currentDate.setTime(currentDate.getTime() + 24 * 60 * 60 * 1000);
    }
    re

turn dateArray;
    }    
}

i m sure this is the right way to do it, and hope this would be helpfull

我确定这是正确的方法,希望这会有所帮助

回答by Maximilian Wiedemann

Like Deyd pointed out before, this is caused by a combination of Angular 2+'s change detection and a bug in ng2-charts.

就像 Deyd 之前指出的那样,这是由 Angular 2+ 的更改检测和 ng2-charts 中的错误组合引起的。

According to my own observations (correct me if I'm wrong), Angular merges several changes within a very short timeframe into a single collection (changes: SimpleChanges) when ngOnChangesis called.

根据我自己的观察(如果我错了,请纠正我),Angularchanges: SimpleChangesngOnChanges被调用时会在很短的时间内将多个更改合并到一个集合 ( ) 中。

Unfortunately, ng2-charts only checks if the datasethas been changed with this collection and updates it. Otherwise it completely rebuilds the entire chart. However, because of the way the change detection works, more than one property might have been changed. Then, only the dataset gets updated even if the labels and possibly other properties have been updated as well. See ngOnChangesin ng2-charts: valor-software/ng2-charts/src/charts/charts.ts

不幸的是,ng2-charts 只检查数据集是否已随此集合更改并更新它。否则,它会完全重建整个图表。但是,由于更改检测的工作方式,可能已更改多个属性。然后,即使标签和可能的其他属性也已更新,也只会更新数据集。参见ngOnChangesng2-charts:valor- software/ng2-charts/src/charts/charts.ts

And if you don't want to have a separate copy of ng2-charts in your app and fix the problem yourself, a possible workaround for this problem is to set the dataset with a short delay using JavaScript's built-in function setTimeout(callback: () => void, delay: number).

如果你不想在你的应用程序中有一个单独的 ng2-charts 副本并自己解决问题,这个问题的一个可能的解决方法是使用 JavaScript 的内置函数设置数据集的短暂延迟setTimeout(callback: () => void, delay: number)

Before:

前:

@Component({
  selector: 'app-root',
  template: `
  <select (change)="onChange($event.target.value)">
    <option value="" disabled selected>Select your option</option>
    <option value="0">Option 0</option>
    <option value="1">Option 1</option>
  </select>

  <canvas baseChart
          chartType="bar"
          [datasets]="barChartData"
          [labels]="barChartLabels"
          [colors]="barChartColors">
  </canvas>
  `
})
export class AppComponent implements OnInit {
  chartData: string[];
  chartLabels: string[];
  chartColors: string[];

  onChange(id: string) {
    getFromApiById(id)
      .then(result => this._setChart(result.data, result.labels, result.colors));
  }

  private _setChart(data: string[], labels: string[], colors: string[]) {
    this.chartData = data;
    this.chartLabels = labels;
    this.chartColors = colors;
  }
}

After:

后:

@Component({
  selector: 'app-root',
  template: `
  <select (change)="onChange($event.target.value)">
    <option value="" disabled selected>Select your option</option>
    <option value="0">Option 0</option>
    <option value="1">Option 1</option>
  </select>

  <canvas baseChart
          chartType="bar"
          [datasets]="barChartData"
          [labels]="barChartLabels"
          [colors]="barChartColors">
  </canvas>
  `
})
export class AppComponent implements OnInit {
  chartData: string[];
  chartLabels: string[];
  chartColors: string[];

  onChange(id: string) {
    getFromApiById(id)
      .then(result => this._setChart(result.data, result.labels, result.colors));
  }

  private _setChart(data: string[], labels: string[], colors: string[]) {
    this.chartLabels = labels;
    this.chartColors = colors;

    setTimeout(() => {
      this.chartData = data;
    }, 50);
  }
}

回答by Chandru

Using BaseChartDirective i did chart update and it served the purpose. Sample below:

使用 BaseChartDirective 我做了图表更新,它达到了目的。示例如下:

import { BaseChartDirective } from 'ng2-charts/ng2-charts';

inside the class add as below

在类中添加如下

@ViewChild(BaseChartDirective) chart: BaseChartDirective;

While you have the values to be changed, add as below

当您要更改值时,添加如下

setTimeout(() => {
if (this.chart && this.chart.chart && this.chart.chart.config) {
  this.chart.chart.config.data.labels = this.labels_pie;
  this.chart.chart.update();
}
});

回答by PraveenIglesias

The trick is in clearing the label and data array, the below code didnt work for me :( ```

诀窍是清除标签和数据数组,下面的代码对我不起作用:(```

clearCharts() {
    this.barChartLabels= [];
    this.barChartData= [
      {data: [], label: 'label1'},
      {data: [], label: 'label2'}
    ];
  }

However when I changed the way I cleared the data helped me (Using object reference)

However when I changed the way I cleared the data helped me (Using object reference)

clearCharts() {
    this.barChartLabels= [];
    this.emptyChartData(this.barChartData);
  }
   emptyChartData(obj) {
     obj[0].data = [];
     obj[1].data = [];
     obj[0].label = 'label1';
     obj[1].label = 'label2';
  }

```

``

回答by Krishna Modi

This is an issue with the current ng2-charts library.

这是当前 ng2-charts 库的一个问题。

Try the new ng4-charts library which has fixed this issue.

尝试解决此问题的新 ng4-charts 库。

https://www.npmjs.com/package/ng4-charts

https://www.npmjs.com/package/ng4-charts

回答by mustafa918

This is an issue in the library ng2-charts, to resolve it I have cloned the github of ng2-charts in my app directory and have done following steps :

这是库 ng2-charts 中的一个问题,为了解决它,我在我的应用程序目录中克隆了 ng2-charts 的 github 并完成了以下步骤:

  • npm install
  • in appmodule import ng-2charts.ts from src directory.
  • add this updateChartLabelsfunction to chart.ts file
  • call it in the onChangesfunction.
  • npm install
  • 在 appmodule 中从 src 目录导入 ng-2charts.ts。
  • 将此updateChartLabels函数添加到 chart.ts 文件
  • onChanges函数中调用它。

public ngOnChanges(changes: SimpleChanges): void { if (this.initFlag) {

public ngOnChanges(changes: SimpleChanges): void { if (this.initFlag) {

  if(changes.hasOwnProperty('labels')){
    console.log('labels changes ...');
    this.updateChartLabels(changes['labels'].currentValue);
  }
//..
//...
}

private updateChartLabels(newLabelsValues: string[] | any[]): void {
this.chart.data.labels = newLabelsValues;
}

回答by Hari Masimukkula

For those looking for a walk around, for now you can put your labels and data in an object and put that object in an array and just loop through the array in your html. This will redraw the element every time your array changes.

对于那些想四处走走的人,现在您可以将标签和数据放入一个对象中,然后将该对象放入一个数组中,然后在 html 中循环遍历该数组。每次数组更改时,这都会重绘元素。

in your type script every time there's a change.

每次发生变化时都在您的类型脚本中。

data = [...]; labels = [...]; chartArray = [{data , labels }]

in your html

在你的 html

<canvas *ngFor="let chartData of chartArray " [datasets]="chartData.data" [labels]="chartData.labels" > </canvas>

回答by Ricardo Del Rio

There is another way to do it:

还有另一种方法可以做到:

In your HTML you have

在您的 HTML 中,您有

<canvas baseChart 
            [datasets]="ChartData"
            //...other stuff >
</canvas>

and in the component I have a function which update the chart with new data, and then I clone the datasets and re-assign it

在组件中,我有一个用新数据更新图表的函数,然后我克隆数据集并重新分配它

drawChart(){
    this.ChartData=[{data: this.dataX, label: 'X'}]; // this.dataX has new values from some place in my code
    //nothing happened with my chart yet, until I add this lines:        
    let clone = JSON.parse(JSON.stringify(this.ChartData));
    this.ChartData=clone;
   //other stuff like labels etc.
}

this works for me, hope it works for you too

这对我有用,希望它也对你有用

回答by luminous_koyote

Since I didn't manage to get one of the above solutions to work properly, I want to contribute my solution, in case someone stumbles across this post and also got stuck with the present approaches.

由于我没有设法使上述解决方案之一正常工作,我想贡献我的解决方案,以防有人偶然发现这篇文章并且也被当前的方法卡住了。

I have the HTML similar to @mustafa918:

我有类似于@mustafa918 的 HTML:

 <div>
  <canvas #canvas id="canvas" 
    baseChart [datasets]="lineChartData" 
    [labels]="lineChartLabels" 
    [colors]="lineChartColors"
    [options]="lineChartOptions" 
    [chartType]="lineChartType" 
    [legend]="lineChartLegend" 
    (chartHover)="chartHovered($event)"
    (chartClick)="chartClicked($event)">
  </canvas>
</div>

And for the initialisation of the charts data in typescript i have:

对于打字稿中图表数据的初始化,我有:

public lineChartData: Array<any> = [
    { data: this.heights, label: 'Heights History', type: 'line', fill: false},
    { data: this.widths, label: 'Widths History', type: 'line', fill: false }];

And for me it worked only by setting the data and labels at the same time and don't use chart.update() - chart is the reference to the BaseChartDirective.

对我来说,它仅通过同时设置数据和标签起作用,并且不使用 chart.update() - chart 是对 BaseChartDirective 的引用。

I loaded the respective data and labels beforehand, so that in this.heights, this.widthand this.lineChartLabelsare corresponding data.

我预先加载了各自的数据和标签,所以在this.heights、this.widththis.lineChartLabels中是对应的数据。

E.g. : The entries on heights[i], widths[i] and lineChartLabels[i] match with the element in my elementArrayat index i => element ={ "height":30, "width":20, "label":"box"}

例如: heights[i]、widths[i] 和 lineChartLabels[i] 上的条目与我elementArray中索引 i => element ={ "height":30, "width":20, "label" 中的元素匹配: “盒子”}

setDatasets() {

//store data in chart references
var arrHeights = [];
for (var i in this.heights) {
  arrHeights.push({ x: this.lineChartLabels[i], y: this.heights[i] });
}

var arrWidths= [];
for (var i in this.widths) {
  arrWidths.push({ x: this.lineChartLabels[i], y: this.widths[i] });
}

this.lineChartData[0].data = arrHeights;
this.lineChartData[1].data = arrWidths;

}

}

I hope this helps someone :) Good Luck!

我希望这对某人有所帮助:) 祝你好运!