it-swarm.com.de

ng2-charts aktualisieren Labels und Daten

Ich versuche, mit ng2-chart dynamisch ein Diagramm zu erstellen Ich bekomme Informationen von einem eckigen 2-Service. Wenn ich nur die Beschriftungen des Diagramms ändere, funktioniert es und wenn ich nur die Daten ändere, funktioniert es nur, aber wenn ich beide nur ändere Daten werden im Diagramm aktualisiert. habe jemand eine Erklärung für dieses seltsame Verhalten.

meine Vorlage:

<canvas baseChart height="130" width="180"

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

meine Klasse : 

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);

    })
  }
}
14
mustafa918

Wenn Sie die ursprüngliche Referenz am Etiketten-Array nicht ändern, scheint dies zumindest für mich zu funktionieren. Ich meine, wenn Sie einen völlig anderen Satz von Etiketten wünschen, sollten Sie Folgendes tun:

In der Vorlage:

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

In der Komponente ts:

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

Oder verwenden Sie die neue ECMAScript-Syntax:

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

Der Schlüssel ist möglicherweise die this.lineChartLabels.length = 0;-Anweisung, die Ihr Array praktisch "leert", indem Sie die Länge auf 0 setzen, ohne die Referenz zu ändern.

35
Sleeper9

Vor kurzem musste ich ng2-charts verwenden und hatte große Probleme mit der Aktualisierung meiner Daten, bis ich diese Lösung gefunden hatte:

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

und hier, was ich in meiner Komponente habe:

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;
    }    
}

ich bin sicher, dass dies der richtige Weg ist, und hoffe, dass dies hilfreich wäre

Wie Deyd bereits angedeutet hat, wird dies durch eine Kombination von Angular 2 + 's Änderungserkennung und einem Fehler in ng2-Diagrammen verursacht.

Nach meinen eigenen Beobachtungen (korrigieren Sie mich, wenn ich falsch liege), führt Angular mehrere Änderungen in einem sehr kurzen Zeitraum in einer einzigen Sammlung (changes: SimpleChanges) zusammen, wenn ngOnChanges aufgerufen wird.

Leider überprüft ng2-charts nur, ob das dataset mit dieser Sammlung geändert wurde, und aktualisiert es. Ansonsten wird das gesamte Diagramm vollständig neu erstellt. Aufgrund der Funktionsweise der Änderungserkennung wurden jedoch möglicherweise mehr als eine Eigenschaft geändert. Dann wird nur das Dataset aktualisiert, auch wenn die Beschriftungen und möglicherweise andere Eigenschaften ebenfalls aktualisiert wurden. Siehe ngOnChanges in ng2-charts: valor-software/ng2-charts/src/charts/charts.ts

Wenn Sie in Ihrer App keine separate Kopie von ng2-Diagrammen haben und das Problem selbst beheben möchten, können Sie das Dataset mithilfe der in JavaScript integrierten Funktion setTimeout(callback: () => void, delay: number) mit einer kurzen Verzögerung einstellen.

Vor:

@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;
  }
}

Nach dem:

@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);
  }
}

Mit BaseChartDirective habe ich ein Chart-Update durchgeführt und es diente dazu. Probe unten:

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

innerhalb der Klasse wie folgt hinzufügen

@ViewChild(BaseChartDirective) chart: BaseChartDirective;

Während Sie die zu ändernden Werte haben, fügen Sie sie wie folgt hinzu

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

Der Trick besteht darin, das Label und das Datenarray zu löschen. Der folgende Code hat für mich nicht funktioniert: ( `` `

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)

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

`` `

3
PraveenIglesias

Dies ist ein Problem in der Bibliothek ng2-charts. Um dies zu beheben, habe ich den github von ng2-charts in meinem App-Verzeichnis geklont und folgende Schritte ausgeführt: 

  • npm install
  • in appmodule import ng-2charts.ts aus dem src-verzeichnis.
  • fügen Sie diese updateChartLabels-Funktion der Datei chart.ts hinzu
  • rufen Sie es in der Funktion onChanges auf. 

public ngOnChanges (Änderungen: 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;
}
2
mustafa918

Dies ist ein Problem mit der aktuellen ng2-charts-Bibliothek.

Versuchen Sie es mit der neuen ng4-charts-Bibliothek, die dieses Problem behoben hat.

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

2
Krishna Modi

Für diejenigen, die nach einem Rundgang suchen, können Sie Ihre Beschriftungen und Daten zunächst in ein Objekt einfügen, dieses Objekt in ein Array einfügen und das Array in Ihrer HTML-Datei durchlaufen. Dadurch wird das Element bei jeder Änderung des Arrays neu gezeichnet.

in Ihrem Typ-Skript wird jedes Mal eine Änderung vorgenommen.

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

in deiner HTML

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

Es gibt einen anderen Weg, dies zu tun: 

In Ihrem HTML haben Sie

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

und in der Komponente habe ich eine Funktion, die das Diagramm mit neuen Daten aktualisiert, und dann kloniere ich die Datensätze und ordne sie neu zu

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.
}

das funktioniert für mich, hoffe es funktioniert auch für dich

1
Ricardo Del Rio

Mit BaseChartDirective habe ich die Karte aktualisiert und es hat den Zweck erfüllt. Beispiel unten:

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

innerhalb der Klasse wie folgt hinzufügen

@ViewChild(BaseChartDirective) chart: BaseChartDirective;

Während Sie die zu ändernden Werte haben, fügen Sie Folgendes hinzu

 this.cart.ngOnChanges({});
0
yyy

Da ich es nicht geschafft habe, eine der oben genannten Lösungen richtig zum Laufen zu bringen, möchte ich meine Lösung einbringen, falls jemand über diesen Beitrag stolpert und auch bei den derzeitigen Ansätzen stecken blieb.

Ich habe den HTML-Code ähnlich @ mustafa918:

 <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>

Und für die Initialisierung der Diagrammdaten in TypeScript habe ich: 

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

Und für mich funktionierte es nur, indem die Daten und Beschriftungen gleichzeitig gesetzt wurden und chart.update () nicht verwendet wurde - chart ist die Referenz auf die BaseChartDirective.

Ich habe vorher die entsprechenden Daten und Labels geladen, so dass in this.heights, this.width und this.lineChartLabels entsprechende Daten sind.

Z.B. : Die Einträge für Höhen [i], Breiten [i] und LineChartLabels [i] stimmen mit dem Element in meinem elementArray at index überein. I => element = {"height": 30, "width": 20, " label ":" box "} 

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;

}

Ich hoffe das hilft jemandem :) Viel Glück!

0
luminous_koyote

Heute hatte ich mit ähnlichen Problemen zu kämpfen. Es scheint, dass es einen großen Fehler in der updateChartData-Funktion der ng2-charts library Version 1.6.0 gibt.

Hier ist die ursprüngliche Funktion:

        updateChartData = function (newDataValues) {
            if (Array.isArray(newDataValues[0].data)) {
                this.chart.data.datasets.forEach(function (dataset, i) {
                    dataset.data = newDataValues[i].data;
                    if (newDataValues[i].label) {
                        dataset.label = newDataValues[i].label;
                    }
                });
            }
            else {
                this.chart.data.datasets[0].data = newDataValues;
            }
        }

Wie Sie sehen, werden nur die Daten und die Beschriftung aktualisiert, alle anderen Eigenschaften bleiben jedoch erhalten. In meinem Fall wollte ich auch die pointBorderColor aktualisieren, also entschied ich mich, diese zu überschreiben.

Zuerst bekomme ich einen Verweis auf die ng2-charts Bibliothek:

import { BaseChartDirective } from 'ng2-charts';

@ViewChild(BaseChartDirective) chart: any;

Es ist sehr wichtig, dass der Typ "any" ist, da ich sonst mit TypeScript keine private Funktion überschreiben kann.

Dann behebe ich den Fehler in der Funktion und überschreibe ihn in afterVIew init:

ngAfterViewInit(){
    if (this.chart) {
        this.chart.updateChartData = function (newDataValues) {
            if (Array.isArray(newDataValues[0].data)) {
                this.chart.data.datasets.forEach(function (dataset, i) {
                    dataset.data = newDataValues[i].data;
                    if (newDataValues[i].pointBorderColor) {
                        dataset.pointBorderColor = newDataValues[i].pointBorderColor;
                    }
                    if (newDataValues[i].label) {
                        dataset.label = newDataValues[i].label;
                    }
                });
            }
            else {
                this.chart.data.datasets[0].data = newDataValues;
            }
        }.bind(this.chart);
    }
}
0
Arntor