I’m trying to build a dashboard for charts using angular 2 and chart.js (via ngcharts). I’d like to have an array of charts that each update via an http request on a custom interval.
我正在尝试使用angular 2和chart.js(通过ngcharts)为图表构建仪表板。我想要一个图表数组,每个图表都通过自定义间隔的http请求进行更新。
Right now I have three separate chart calls that push data to an array. I’m having trouble when it comes to the next iteration - if I push to the array again, I’ll end up with 3 more charts. I’d like the subscribers in the array to update with new data when the interval emits it.
现在我有三个单独的图表调用,将数据推送到数组。我在下一次迭代时遇到了麻烦 - 如果我再次推送到阵列,我最终会再增加3个图表。我希望数组中的订阅者在间隔发出时使用新数据进行更新。
I’m a little confused as to how to correctly structure the component/service/http relationship for my use case. I feel that I’m close but I’m definitely missing something. How can I get the interval/subscriber relationship to map to the view and update the existing charts on an interval? Any help would be great!
关于如何为我的用例正确构建组件/服务/ http关系,我有点困惑。我觉得我很亲密,但我肯定错过了一些东西。如何让间隔/订户关系映射到视图并在一定时间间隔内更新现有图表?任何帮助都会很棒!
Right now:
Service:
I’m implementing the interval here:
我在这里实施间隔:
getSingleChartObsinterval(id: number, interval: number) : Observable<Graph> {
return Observable.interval(interval).flatMap(() => this.getSingleChartobs(id));
}
getSingleChartobs(id: number) : Observable<Graph> {
return this.jsonp.get(“api location”)
.map(response => this.extractJsonData(response, id) as Graph)
}
extractJsonData is just taking the response and manipulating it to work with the chart JS. It returns a Graph object that has properties that are easy to work with. I don’t have control of the API so I can’t reconfigure the response to include more than one graph.
extractJsonData只是接受响应并操纵它来使用图表JS。它返回一个Graph对象,该对象具有易于使用的属性。我无法控制API,因此我无法重新配置响应以包含多个图表。
The component:
import { Component } from '@angular/core';
import { ChartsModule } from 'ng2-charts/ng2-charts';
import { ChartService } from './chart.service';
import { Graph } from './graph';
import { OnInit } from '@angular/core';
import { Observable } from 'rxjs/Rx';
@Component({
selector: 'ab-chart',
styles: [`
.chart {
display: block;
}
`],
templateUrl: 'app/chart.component.html'
})
export class ChartComponent implements OnInit {
ngOnInit(): void {
console.log("Chart component init");
this.getSingleChart(3, 5000);
this.getSingleChart(5, 4000);
this.getSingleChart(6, 5000);
}
graph: Graph;
graphs: Graph[] = [];
constructor(
private chartService: ChartService
) {}
getSingleChart(id: number, interval: number): void {
this.chartService.getSingleChartObsinterval(id, interval)
.subscribe(x =>
this.graphs.push(x)
);
}
}
The view:
<div *ngFor="let graph of graphs" class="chart-container">
<base-chart
class="chart"
[datasets]="graph.datasets"
[labels]="graph.labels"
[options]="graph.options"
[chartType]="graph.type">
</base-chart>
</div>
2 个解决方案
#1
1
Since each graph has its own id
(I assume its unique) so I'd just change getSingleChart()
method to update graphs
object at specific key. Note I changed the graphs
property from an array to an object:
由于每个图都有自己的id(我假设它是唯一的)所以我只需更改getSingleChart()方法来更新特定键的图形对象。注意我将graph属性从数组更改为对象:
graphs: {[key: number]: Graph} = {};
getSingleChart(id: number, interval: number): void {
this.chartService.getSingleChartObsinterval(id, interval)
.subscribe(x => this.graphs[id] = x);
}
get graphIds() {
return Object.keys(this.graphs);
}
Then in the template you need to iterate the array of keys (you can iterate the graphs
object:
然后在模板中,您需要迭代键数组(您可以迭代图形对象:
<div *ngFor="let id of graphIds" class="chart-container">
<base-chart
class="chart"
[datasets]="graphs[id].datasets"
[labels]="graphs[id].labels"
[options]="graphs[id].options"
[chartType]="graphs[id].type">
</base-chart>
</div>
#2
1
Do you have a limited amount of charts? If you always have three you could leverage the combineLatest
operator (if you have more you would have to use some form of recursion I guess).
你的图表数量有限吗?如果你总是有三个你可以利用combineLatest运算符(如果你有更多,你必须使用某种形式的递归我猜)。
In your component you could do the following:
在您的组件中,您可以执行以下操作:
this.graphs = this.getSingleChart(3, 5000).combineLatest(
this.getSingleChart(5, 4000),
this.getSingleChart(6, 5000),
(val1, val2, val3) => return [val1, val2, val3])
//.subscribe((arrayOfVal) => console.log(arrayOfVal);
This will return a new array every time one of the charts gets updated. If chart 2 gets a new value, the function (third argument of the combineLatest) will be called with the old value of 1, the new value for 2 and the old value of three.
每次更新其中一个图表时,这将返回一个新数组。如果图表2获得一个新值,则将使用旧值1,新值2和旧值3调用函数(combineLatest的第三个参数)。
In your template you could just be using this:
在您的模板中,您可以使用此:
<div *ngFor="let graph of graphs | async" ...>
CombineLatest: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/combinelatest.md
#1
1
Since each graph has its own id
(I assume its unique) so I'd just change getSingleChart()
method to update graphs
object at specific key. Note I changed the graphs
property from an array to an object:
由于每个图都有自己的id(我假设它是唯一的)所以我只需更改getSingleChart()方法来更新特定键的图形对象。注意我将graph属性从数组更改为对象:
graphs: {[key: number]: Graph} = {};
getSingleChart(id: number, interval: number): void {
this.chartService.getSingleChartObsinterval(id, interval)
.subscribe(x => this.graphs[id] = x);
}
get graphIds() {
return Object.keys(this.graphs);
}
Then in the template you need to iterate the array of keys (you can iterate the graphs
object:
然后在模板中,您需要迭代键数组(您可以迭代图形对象:
<div *ngFor="let id of graphIds" class="chart-container">
<base-chart
class="chart"
[datasets]="graphs[id].datasets"
[labels]="graphs[id].labels"
[options]="graphs[id].options"
[chartType]="graphs[id].type">
</base-chart>
</div>
#2
1
Do you have a limited amount of charts? If you always have three you could leverage the combineLatest
operator (if you have more you would have to use some form of recursion I guess).
你的图表数量有限吗?如果你总是有三个你可以利用combineLatest运算符(如果你有更多,你必须使用某种形式的递归我猜)。
In your component you could do the following:
在您的组件中,您可以执行以下操作:
this.graphs = this.getSingleChart(3, 5000).combineLatest(
this.getSingleChart(5, 4000),
this.getSingleChart(6, 5000),
(val1, val2, val3) => return [val1, val2, val3])
//.subscribe((arrayOfVal) => console.log(arrayOfVal);
This will return a new array every time one of the charts gets updated. If chart 2 gets a new value, the function (third argument of the combineLatest) will be called with the old value of 1, the new value for 2 and the old value of three.
每次更新其中一个图表时,这将返回一个新数组。如果图表2获得一个新值,则将使用旧值1,新值2和旧值3调用函数(combineLatest的第三个参数)。
In your template you could just be using this:
在您的模板中,您可以使用此:
<div *ngFor="let graph of graphs | async" ...>
CombineLatest: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/combinelatest.md