[英]ng2-charts update labels and data
我正在嘗試使用 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;
}
}
我確定這是正確的方法,希望這會有所幫助
就像 Deyd 之前指出的那樣,這是由 Angular 2+ 的變化檢測和 ng2-charts 中的錯誤組合引起的。
根據我自己的觀察(如果我錯了,請糾正我),當ngOnChanges
時,Angular 會在很短的時間內將多個更改合並到一個集合中( changes: SimpleChanges
)。
不幸的是,ng2-charts 只檢查數據集是否已隨此集合更改並更新它。 否則,它會完全重建整個圖表。 但是,由於更改檢測的工作方式,可能已更改多個屬性。 然后,即使標簽和可能的其他屬性也已更新,也只會更新數據集。 參見ngOnChanges
-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();
}
});
訣竅是清除標簽和數據數組,下面的代碼對我不起作用:(```
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;
}
對於那些想四處走走的人,現在您可以將標簽和數據放入一個對象中,然后將該對象放入一個數組中,然后在 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.
}
這對我有用,希望它也對你有用
由於我沒有設法使上述解決方案之一正常工作,我想貢獻我的解決方案,以防有人偶然發現這篇文章並且也被當前的方法卡住了。
我有類似於@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>
對於打字稿中圖表數據的初始化,我有:
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() - chart 是對 BaseChartDirective 的引用。
我預先加載了各自的數據和標簽,所以在this.heights、this.width和this.lineChartLabels中是對應的數據。
例如: 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;
}
我希望這對某人有所幫助:) 祝你好運!
使用 BaseChartDirective 我做了圖表更新,它達到了目的。 示例如下:
import { BaseChartDirective } from 'ng2-charts/ng2-charts';
在類中添加如下
@ViewChild(BaseChartDirective) chart: BaseChartDirective;
當您要更改值時,添加如下
this.chart.ngOnChanges({});
今天我遇到了類似的問題,似乎在 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;
類型是“任何”非常重要,否則打字稿將不允許我覆蓋私有函數。
然后我修復函數中的錯誤並在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);
}
}
我能夠通過將處理程序轉換為箭頭函數來解決此問題
export class HistogramChartComponent implements OnInit {
constructor(private dataService: MyFruitService ) { }
barChartOptions: ChartOptions = { responsive: true };
barChartLabels: Label[] = ['Apple', 'Banana', 'Kiwifruit', 'Blueberry', 'Orange', 'Grapes'];
barChartType: ChartType = 'bar';
barChartLegend = true;
barChartPlugins = [];
barChartData: ChartDataSets[] = [
{ data: [45, 37, 60, 70, 46, 33], label: 'Best Fruits' }
];
ngOnInit() {
this.dataService
.getDocument("Foobar")
.subscribe(this.handleResponse);
}
handleResponse = (doc: MyFruitDocument) => {
console.log('document: ', doc);
let labels = doc.dataPoints.map(p => p.fruitName);
let data = { data: doc.dataPoints.map(p => p.value), label: 'Best Fruits' };
this.barChartLabels = labels;
this.barChartData = [ data ];
}
}
代碼:
Declare : import { BaseChartDirective } from 'ng2-charts';
@ViewChild(BaseChartDirective) chart: BaseChartDirective;
public lineChartData: ChartDataSets[] = [
{ data: [0, 0, 0, 0, 0, 0, 0], label: 'Data 1' },
{ data: [0, 0, 0, 0, 0, 0, 0], label: 'Data 2' }
];
public lineChartLabels: Label[] = ['Label1', 'Label2', 'Label3', 'Label4',
'Label5', 'Label6';
TS Function:
refresh_chart(){
setTimeout(() => {
if (this.chart && this.chart.chart && this.chart.chart.config) {
this.chart.chart.config.data.datasets.forEach(x => {
x.data = [];
});
let index = 0;
this.chart.chart.config.data.datasets.forEach(x => {
x.data = this.lineChartData[index].data;
index++;
});
this.chart.chart.update();
}
}, 500);
}
HTML代碼:
<canvas baseChart [datasets]="lineChartData" class="canvas-wh" [labels]="lineChartLabels"
[options]="lineChartOptions" [colors]="lineChartColors" [legend]="lineChartLegend"
[chartType]="lineChartType" [plugins]="lineChartPlugins">
我在嘗試更新標簽時也遇到了這個問題(特別是在嘗試發送較短的數組時),這解決了它:
@ViewChild(BaseChartDirective) chart!: BaseChartDirective;
然后,在更新標簽時:
this.chart.chart!.config.data.labels = [...]
無需調用 update() 方法。
對我來說,它只有在使用 ViewChildren 而不是 ViewChild 后才有效。
TS:
@ViewChildren('baseLineChart1') chart !: QueryList<BaseChartDirective>;
this.chart.forEach((child) => { child.update() })
HTML:
<canvas class="card-line-chart" baseChart #baseLineChart1>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.