ngx-charts render dynamic data

9.5k Views Asked by At

I'm new at ngx-charts I'm trying to render the dynamic bitcoin data by fetching the data from bitstamp service. The goal is to render visually the bitcoin data (price and timestamp) to the chart (value and date (convert to actual date from timestamp number)), and whenever bitcoin data updates, the data is pushed automatically to the chart. I tried to apply similar method from this plunker: https://plnkr.co/edit/JSTcS4FnJ5dshAldLWPL?p=preview.

However, I got tones of errors in the market-data component such as :

attribute d: Expected number, "M0,NaNZ". attribute cy: Expected length, "NaN".

I don't know at which step I did wrong. Here is the relevant scripts:

bitstamp.service.ts:

import Pusher from 'pusher-js';
import { Injectable, Output, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs/Observable'
import { BehaviorSubject } from "rxjs/Rx";
import { List } from 'immutable';

@Injectable()
export class BitstampService {
  private pusher: any;

  private _messages: BehaviorSubject<any> = new BehaviorSubject(null);
  public messages: Observable<any> = this._messages.asObservable();

  constructor() {
    this.pusher = new Pusher('de504dc5763aeef9ff52');
    this.pusher.logToConsole = true;

    let channel = this.pusher.subscribe('live_trades');
    channel.bind('trade', (data) => {
      this._messages.next(data);
    });
  }
}

market-data.component.ts:

import { Component, OnInit } from '@angular/core';
import { BitstampService } from '../../services/bitstamp.service';
import { Subject } from "rxjs/Subject";

@Component({
  selector: 'app-market-data',
  templateUrl: './market-data.component.html',
  styleUrls: ['./market-data.component.scss']
})
export class MarketDataComponent implements OnInit {

  private ngUnsubscribe: Subject<void> = new Subject<void>();

  bitcoinData: any = [
    {
      name: 'Bitcoin',
      series: [
        {
          "name": new Date,
          "value": Number
        }
      ]
    }
  ];

  view: any[] = [960, 500];

  // options
  showXAxis = true;
  showYAxis = true;
  gradient = false;
  showLegend = true;
  showXAxisLabel = true;
  xAxisLabel = 'Year';
  showYAxisLabel = true;
  yAxisLabel = 'USD';
  intervalId:any;

  colorScheme = {
    domain: ['#DC143C', '#A10A28', '#C7B42C', '#AAAAAA']
  };

  // line, area
  autoScale = true;

  constructor(private bitstamp: BitstampService) {
  }

  onSelect(event) {
    console.log(event);
  }

  ngOnInit() {
      this.bitstamp.messages.takeUntil(this.ngUnsubscribe).subscribe(data => {
        if (data != null) {
          this.bitcoinData[0].series.push({"name": new Date(parseInt(data.timestamp)*1000), "value": Math.floor(data.price)});
        }
        this.bitcoinData = [...this.bitcoinData];
      }, (err) => {
        console.log(err);
      });
  }

  ngOnDestroy() {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }
}

market-data.component.html:

<ngx-charts-line-chart
        [view]="view"
        [scheme]="colorScheme"
        [results]="bitcoinData"
        [gradient]="gradient"
        [xAxis]="showXAxis"
        [yAxis]="showYAxis"
        [legend]="showLegend"
        [showXAxisLabel]="showXAxisLabel"
        [showYAxisLabel]="showYAxisLabel"
        [xAxisLabel]="xAxisLabel"
        [yAxisLabel]="yAxisLabel"
        [autoScale]="autoScale"
        (select)="onSelect($event)">
      </ngx-charts-line-chart>

This is the chart image, it pushed data but blank chart and the date is probably just minutes and seconds, not including live date as I wanted

Thank you in advance.

2

There are 2 best solutions below

0
On

you trying to modify data is not recognized by change detection.

this.bitcoinData[0].series.push({"name": new Date(parseInt(data.timestamp)*1000), "value": Math.floor(data.price)});

instead try spreading data over, that will detect the changes. It worked for me.

this.bitcoinData[0].series = [...this.bitcoinData[0].series, ...[{"name": new Date(parseInt(data.timestamp)*1000), "value": Math.floor(data.price)}];
0
On

I think you running into problems by pushing the timestamp in the bitcoinData-array in your market-data-component.ts. With this line:

this.bitcoinData[0].series.push({"name": new Date(parseInt(data.timestamp)*1000), "value": Math.floor(data.price)});

This should work:

this.bitcoinData[0].series.push({"name": String( new Date()), "value": Math.floor(data.price)});