[英]Dynamically updating Chart.js data in angular
I"m attempting to update my chart data, specifically the labels for the x-axis, dynamically based on the data returned from an api call. I have a component called 'dashboard-card-component' defined like:我正在尝试根据从 api 调用返回的数据动态更新我的图表数据,特别是 x 轴的标签。我有一个名为“dashboard-card-component”的组件,其定义如下:
import { Component, OnInit, AfterViewInit, Input, ViewChild, Injectable } from '@angular/core';
import { BaseChartDirective, Label, Color } from 'ng2-charts';
import { ChartDataSets, ChartOptions } from 'chart.js';
import * as pluginAnnotations from 'chartjs-plugin-annotation';
import { DailyStats } from '../../general-stats/general-stats.component';
// mocked data is an any
/*{
title: 'BlockChain Reciepts by Day', type: 'line',
value: {
data: [65, 59, 80, 81, 56, 55, 40], label: 'Number Receipts'
}, cols: 1, rows: 1
}*/
@Component({
selector: 'app-dashboard-card',
templateUrl: './dashboard-card.component.html',
styleUrls: ['./dashboard-card.component.scss']
})
@Injectable({
providedIn: 'root'
})
export class DashboardCardComponent implements OnInit, AfterViewInit {
public lineChartData: ChartDataSets[] = [];
public lineChartLabels: Label[] = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
public lineChartOptions: (ChartOptions & { annotation: any }) = {
responsive: true,
scales: {
// We use this empty structure as a placeholder for dynamic theming.
xAxes: [{}],
yAxes: [
{
id: 'y-axis-0',
position: 'left',
}/*,
{
id: 'y-axis-1',
position: 'right',
gridLines: {
color: 'rgba(255,0,0,0.3)',
},
ticks: {
fontColor: 'red',
}
}*/
]
},
annotation: {
annotations: [/*
{
type: 'line',
mode: 'vertical',
scaleID: 'x-axis-0',
value: 'March',
borderColor: 'orange',
borderWidth: 2,
label: {
enabled: true,
fontColor: 'orange',
content: 'LineAnno'
}
},
*/],
},
};
public lineChartColors: Color[] = [
{ // dark grey
backgroundColor: 'rgba(77,83,96,0.2)',
borderColor: 'rgba(77,83,96,1)',
pointBackgroundColor: 'rgba(77,83,96,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(77,83,96,1)'
}
];
public lineChartLegend = false;
public lineChartType = 'line';
public lineChartPlugins = [pluginAnnotations];
@ViewChild(BaseChartDirective, { static: false }) chart: BaseChartDirective;
@Input() card: any;
constructor() { }
ngOnInit() {
if (this.card.type === 'line') {
this.lineChartData.push(this.card.value);
}
}
ngAfterViewInit() {
console.log(this.chart);
}
public refreshChart(data: any) {
console.log(`data is: ${data}`); // I set a breakpoint here in the debugger. this.chart isn't defined
setTimeout(() => {
if (this.chart && this.chart.chart && this.chart.chart.config) {
this.chart.chart.config.data.labels = data;
this.chart.chart.update(); // chart won't update because this.chart is undefined
}
});
}
// events
public chartClicked({ event, active }: { event: MouseEvent, active: {}[] }): void {
// console.log(event, active);
}
public chartHovered({ event, active }: { event: MouseEvent, active: {}[] }): void {
// console.log(event, active);
}
}
I have a general-stats-component that calls out to an api to retrieve the data to update the labels for the chart and re-rendering it:我有一个通用统计组件,它调用一个 api 来检索数据以更新图表的标签并重新呈现它:
import { Component, OnInit } from '@angular/core';
import { StatsService, PenStats } from '../services/stats.service';
import { DashboardCardComponent } from '../common/dashboard-card/dashboard-card.component';
export interface PenMetrics {
users: number;
logins: number;
newSignups: number;
}
export interface DailyStats {
createdAt: string;
date: string;
leakedPasswords: number;
logins: number;
signups: number;
updatedAt: string;
}
@Component({
selector: 'app-general-stats',
templateUrl: './general-stats.component.html',
styleUrls: ['./general-stats.component.scss']
})
export class GeneralStatsComponent implements OnInit {
stats: PenStats;
displayedColumns: string[] = ['users', 'logins', 'newSignups'];
dataSource: PenMetrics[];
users: object;
dailyStats: any = [];
tempStats: object;
userCount: number;
logins: number;
newSignups: number;
labelsArr: any = [];
cards = [
{
title: 'Unique Pen Logins Per Day', type: 'line',
value: {
data: [], label: 'Pen Logins'
}, cols: 1, rows: 1
},
{
title: 'Pen Signatures by Month', type: 'line',
value: {
data: [20, 39, 80, 16, 44, 18, 80], label: 'Pen Signatures'
}, cols: 1, rows: 1
},
{
title: 'BlockChain Reciepts Written by Month', type: 'line',
value: {
data: [65, 59, 80, 81, 56, 55, 40], label: 'Number Receipts'
}, cols: 1, rows: 1
}
,
{
title: 'BlockChain Validations by Month', type: 'line',
value: {
data: [165, 159, 80, 181, 156, 155, 240], label: 'Number Validations'
}, cols: 1, rows: 1
}
];
constructor(
private statsService: StatsService,
private dashboardComponent: DashboardCardComponent
) { }
ngOnInit() {
this.dataSource = this.statsService.getPenStats();
this.statsService.getPenUsers().subscribe(data => {
this.users = data;
this.userCount = Object.keys(this.users).length;
console.log(this.users);
});
this.dashboardComponent.lineChartLabels.length = 0;
// const currentStats: DailyStats[] = [];
this.statsService.getDailyStats().subscribe(stats => {
for (const d of (stats as any)) {
this.dailyStats.push({
date: d.date,
logins: d.logins
});
this.dashboardComponent.lineChartLabels.push(d.date);
console.log(`date is: ${d.date}`);
this.cards[0].value.data.push(d.logins);
}
this.labelsArr = this.dashboardComponent.lineChartLabels;
this.dashboardComponent.lineChartLabels.forEach(label => {
console.log(`label is: ${label}`);
});
this.dashboardComponent.refreshChart(this.labelsArr);
console.log(this.dailyStats);
});
}
}
The call out to:呼吁:
this.dataSource = this.statsService.getPenStats();
returns a valid json string in the form:以以下形式返回有效的 json 字符串:
[
{
"date": "2020-08-12T00:00:00.000Z",
"created_at": "2020-08-12T16:22:27.361Z",
"leaked_passwords": 0,
"logins": 1,
"signups": 0,
"updated_at": "2020-08-12T23:22:11.660Z"
},
{
"date": "2020-08-13T00:00:00.000Z",
"created_at": "2020-08-13T19:22:38.695Z",
"leaked_passwords": 0,
"logins": 1,
"signups": 1,
"updated_at": "2020-08-13T23:22:28.062Z"
},
{
"date": "2020-08-14T00:00:00.000Z",
"created_at": "2020-08-14T17:22:47.806Z",
"leaked_passwords": 0,
"logins": 2,
"signups": 0,
"updated_at": "2020-08-14T23:22:08.882Z"
},
{
"date": "2020-08-17T00:00:00.000Z",
"created_at": "2020-08-17T15:22:13.676Z",
"leaked_passwords": 0,
"logins": 10,
"signups": 4,
"updated_at": "2020-08-17T23:22:10.597Z"
},
{
"date": "2020-08-18T00:00:00.000Z",
"created_at": "2020-08-18T13:21:57.014Z",
"leaked_passwords": 0,
"logins": 8,
"signups": 3,
"updated_at": "2020-08-18T23:22:36.734Z"
},
{
"date": "2020-08-19T00:00:00.000Z",
"created_at": "2020-08-19T13:22:01.569Z",
"leaked_passwords": 0,
"logins": 3,
"signups": 1,
"updated_at": "2020-08-19T23:22:17.038Z"
},
{
"date": "2020-08-20T00:00:00.000Z",
"created_at": "2020-08-20T13:22:14.392Z",
"leaked_passwords": 0,
"logins": 27,
"signups": 15,
"updated_at": "2020-08-20T23:22:17.330Z"
},
{
"date": "2020-08-21T00:00:00.000Z",
"created_at": "2020-08-21T01:21:25.918Z",
"leaked_passwords": 0,
"logins": 7,
"signups": 5,
"updated_at": "2020-08-21T23:22:16.300Z"
},
{
"date": "2020-08-23T00:00:00.000Z",
"created_at": "2020-08-23T20:21:36.804Z",
"leaked_passwords": 0,
"logins": 3,
"signups": 3,
"updated_at": "2020-08-23T23:21:38.221Z"
},
]
How can I get access to my chart in order to update it once I've retrieved the data.我怎样才能访问我的图表以便在我检索到数据后更新它。 I check the value of
this.dashboardComponent.lineChartLabels
and it's correctly populated with the dates I'd like to use as labels on the x-axis, but I can't get it to update when calling this.dashboardComponent.refreshChart(this.labelsArr);
我检查了
this.dashboardComponent.lineChartLabels
的值,它正确填充了我想用作 x 轴标签的日期,但是在调用this.dashboardComponent.refreshChart(this.labelsArr);
DashboardCardComponent.ts DashboardCardComponent.ts
//@Input() card: any;
@Input() card$: Observable<any>;
tap the observable to fetch data and subsequent changes点击 observable 以获取数据和后续更改
ngOnInit() {
//if (this.card.type === 'line') {
// this.lineChartData.push(this.card.value);
//}
this.card$.pipe(
tap(data=>this.lineChartData.push(data.value))
.subscribe() // either unsubscribe in onDestroy or use async pipe in html
}
In your calling component GeneralStatsComponent在您的调用组件 GeneralStatsComponent
Subject card = new Subject() // from rsjx
card.next( ... data... ) // data fetched from api or your selection logic
GeneralStatsComponent.html通用统计组件.html
<app-dashboard-card [card$]='card' ...>
Above is just a pseudo code .. syntax needs to be reviewed.以上只是一个伪代码..语法需要审查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.