Ng2-chartを使用して動的にチャートを作成しようとしています。angular 2サービスから情報を取得します。チャートのラベルのみを変更すると機能し、データのみを変更すると機能します。しかし、両方を変更すると、グラフ内のデータだけが更新されます。
私のテンプレート:
<canvas baseChart height="130" width="180"
[data]="doughnutChartData"
[labels]="doughnutChartLabels"
[chartType]="doughnutChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)">
</canvas>
私のクラス :
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);
})
}
}
どうやら、元の参照を変更しないでくださいラベル配列に、それは少なくとも私にとってはうまくいくようです。つまり、まったく異なるラベルのセットが必要な場合は、次のようにする必要があります。
テンプレートで:
<canvas baseChart
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="lineChartOptions"
[chartType]="'line'"></canvas>
Tsコンポーネント:
this.lineChartLabels.length = 0;
for (let i = tempLabels.length - 1; i >= 0; i--) {
this.lineChartLabels.Push(tempLabels[i]);
}
または、新しいECMAScript構文を使用します。
this.lineChartLabels.length = 0;
this.lineChartLabels.Push(...tempLabels);
キーはおそらくthis.lineChartLabels.length = 0;
ステートメント。参照を変更せずに、長さを0に設定することにより、実際に配列を「空にします」。お役に立てれば!
最近、私はng2-chartsを使用しなければなりませんでしたが、この解決策が見つかるまでデータの更新に非常に大きな問題がありました:
<div class="chart">
<canvas baseChart [datasets]="datasets_lines" [labels]="labels_line" [colors]="chartColors" [options]="options" [chartType]="lineChartType">
</canvas>
</div>
そしてここに私のコンポーネントにあるもの:
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;
}
}
これが正しい方法であると確信しており、これが役立つことを願っています
前に指摘したように、これはAngular 2+の変更検出とng2-chartsのバグの組み合わせによって引き起こされます。
私自身の観察によれば(間違っている場合は私を修正してください)、Angular=は非常に短い時間枠内のいくつかの変更を単一のコレクションにマージします(_changes: SimpleChanges
_)ngOnChanges
と呼ばれます。
残念ながら、ng2-chartsはdatasetがこのコレクションで変更されたかどうかのみをチェックし、更新します。それ以外の場合は、チャート全体が完全に再構築されます。ただし、変更検出の動作方法により、複数のプロパティが変更された可能性があります。次に、ラベルやその他のプロパティも更新されていても、データセットのみが更新されます。 ng2-chartsのngOnChanges
を参照してください: valor-software/ng2-charts/src/charts/charts.ts
また、アプリにng2-chartsのコピーを個別に作成して問題を自分で解決したくない場合、この問題の回避策として、JavaScriptの組み込み関数setTimeout(callback: () => void, delay: number)
。
前:
_@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;
}
}
_
後:
_@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);
}
}
_
BaseChartDirectiveを使用して、チャートを更新し、目的を果たしました。以下のサンプル:
import { BaseChartDirective } from 'ng2-charts/ng2-charts';
クラス内に次のように追加します
@ViewChild(BaseChartDirective) chart: BaseChartDirective;
変更する値がありますが、次のように追加します
setTimeout(() => {
if (this.chart && this.chart.chart && this.chart.chart.config) {
this.chart.chart.config.data.labels = this.labels_pie;
this.chart.chart.update();
}
});
秘Theはラベルとデータ配列をクリアすることで、以下のコードは私にとってはうまくいきませんでした:( `` `
_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';
}
_
`` `
これはライブラリng2-chartsの問題です。それを解決するために、ng2-chartsのgithubをアプリディレクトリに複製し、次の手順を実行しました。
npm install
updateChartLabels
関数をchart.tsファイルに追加しますonChanges
関数で呼び出します。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;
}
これは、現在のng2-chartsライブラリの問題です。
この問題を修正した新しいng4-chartsライブラリを試してください。
散歩を探している人のために、今のところ、あなたはラベルとデータをオブジェクトに入れ、そのオブジェクトを配列に入れて、あなたのhtmlの配列をただループすることができます。これにより、配列が変更されるたびに要素が再描画されます。
タイプスクリプトに変更があるたびに。
data = [...]; labels = [...]; chartArray = [{data , labels }]
あなたのHTMLで
<canvas *ngFor="let chartData of chartArray " [datasets]="chartData.data" [labels]="chartData.labels" > </canvas>
別の方法があります:
あなたのHTMLには
<canvas baseChart
[datasets]="ChartData"
//...other stuff >
</canvas>
コンポーネントには、新しいデータでチャートを更新する機能があり、データセットを複製して再割り当てします
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.
}
これは私のために働く、あなたのためにも働くことを願って
BaseChartDirectiveを使用して、チャートを更新し、目的を果たしました。以下のサンプル:
import { BaseChartDirective } from 'ng2-charts/ng2-charts';
クラス内に次のように追加します
@ViewChild(BaseChartDirective) chart: BaseChartDirective;
変更する値がありますが、次のように追加します
this.cart.ngOnChanges({});
上記の解決策のいずれかを適切に機能させることができなかったため、誰かがこの投稿を偶然見つけ、現在のアプローチに固執した場合に備えて、解決策を提供したいと思います。
@ 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>
そして、TypeScriptのチャートデータの初期化には、次のものがあります。
public lineChartData: Array<any> = [
{ data: this.heights, label: 'Heights History', type: 'line', fill: false},
{ data: this.widths, label: 'Widths History', type: 'line', fill: false }];
そして、私にとっては、データとラベルを同時に設定するだけで機能し、chart.update()を使用しません-チャートはBaseChartDirectiveへの参照です。
this.heights、this.widthおよびthis.lineChartLabelsが対応するデータになるように、それぞれのデータとラベルを事前にロードしました。
例えば。 :heights [i]、widths [i]、およびlineChartLabels [i]のエントリは、インデックスi => element = {"height":30、 "width"のmy elementArrayの要素と一致します。 20、「ラベル」:「ボックス」}
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;
}
私はこれが誰かを助けることを願っています:)幸運を!
今日、私は同様の問題に苦しんでいますが、ng2-chartsライブラリバージョン1.6.0のupdateChartData関数内に大きなバグがあるようです。
元の関数は次のとおりです。
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;
}
}
ご覧のとおり、これによりデータとラベルのみが更新されますが、他のすべてのプロパティは残されています。私の場合、pointBorderColorも更新したいので、これをオーバーライドすることにしました。
まず、ng2-chartsライブラリへの参照を取得します。
import { BaseChartDirective } from 'ng2-charts';
@ViewChild(BaseChartDirective) chart: any;
タイプが「any」であることが非常に重要です。そうしないと、TypeScriptではプライベート関数をオーバーライドできません。
次に、関数のバグを修正し、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);
}
}