2016-10-24 41 views
1

我正在尝试为使用angular 2和chart.js(通过ngcharts)的图表构建一个仪表板。我想有一个图表阵列,每个图表通过自定义时间间隔内的http请求进行更新。如何使用interval更新observables数组?

现在我有三个单独的图表调用,将数据推送到一个数组。我在遇到下一次迭代时遇到了麻烦 - 如果再次推入阵列,我最终会得到3个图表。我希望阵列中的订阅者在间隔发出时使用新数据进行更新。

对于如何正确构造我的用例的组件/服务/ http关系,我有点困惑。我觉得我很接近,但我肯定错过了一些东西。如何获取间隔/订户关系以映射到视图并在一个时间间隔内更新现有图表? 任何帮助将是伟大的!

现在:

服务:

我在这里实施的时间间隔:

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只是采取响应和操纵它与图表JS工作。它返回一个Graph对象,该对象具有易于使用的属性。我无法控制API,因此我无法重新配置响应以包含多个图。

组件:

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

的观点:

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

而不是推新图表在你的数组中,你不能只用新的数据替换现有的图表吗?我对chart.js一无所知,所以也许不可能替换他的数据,只是等待角度来渲染新图表 –

+0

@ NoémiSalaün我认为这是我问的问题。每张图表都在不同的时间间隔,所以我希望我可以让每件物品n阵列订阅更改和更新自己而不必吹散阵列。我尝试将每个对象作为数组的订阅者,但它没有奏效。我希望有一种方法可以做到这一点,而无需在阵列中搜索ID并自己更新数据。 – Skerrvy

回答

1

由于每个图都有自己id(我假设它是唯一的),所以我只希望改变getSingleChart()方法在特定键上更新graphs对象。请注意,我改变了graphs属性从一个数组对象:

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

然后在你需要遍历键阵列模板(可以迭代graphs对象:

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

感谢您的回答。这两个答案都奏效了,但这更接近我一直在尝试的方式,并对我现有的方法造成了最少的变化。 – Skerrvy

1

你有图表的数量有限?如果你总是有三个,你可以利用combineLatest运算符(如果你有更多的话,你将不得不使用某种形式的递归,我猜)。

在你的组件,你可以做到以下几点:

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

这将每一个图表中获取更新时间返回一个新的数组。如果图2得到一个新值,函数(combineLatest的第三个参数)将被调用,旧值为1,新值为2,旧值为3。

在模板你可以只使用此:

<div *ngFor="let graph of graphs | async" ...> 

CombineLatest:https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/combinelatest.md

+0

实际上这不会像这样工作,因为'combineLatest()'返回一个Observable,而不是从回调中返回的值。这也意味着你必须一次刷新所有的图表。 – martin

+0

它确实会返回一个可观察的。但是,这就是关键,在这种情况下,可以在异步管道中使用observable。 combineLatest将不会强制每个图表进行重新编译。在封面之下,这将保持所有三个电话的最新价值。例如,A1,B1和C1。如果B1更新到B2,则下一个值将是A1,B2,C1。看到A和C引用没有改变。所以,它和你的答案一样。但更优雅的AFAIAC,因为你不需要清理订阅后。 – KwintenP

+0

你对'异步'我是没有注意到的。但是,它必须一次更新所有图表,而不是像你所描述的那样更新图表,因为每次更改'图表| async'接收到一个新的数组,然后它会再次破坏并重新创建所有三个元素的''元素。但是你的解决方案肯定比我的更容易。 – martin