Display Dynamic Data in Angular6 with GoogleChart

2020-05-01 08:36发布

问题:

I use Angular Cli6, angularfire2 and firebase. I want to create a timeline with GoogleChart.

//GoogleChart.service

declare var google: any;

export class GoogleChartsBaseService 
{
  constructor() { google.charts.load('current', {'packages':["timeline"]}); }

   protected buildChart(data: any[], chartFunc: any, options: any) : void {
   var func = (chartFunc, options) => 
        {
        var datatable = google.visualization.arrayToDataTable(data);
        chartFunc().draw(datatable, options); 
        };   
   var callback = () => func(chartFunc, options);
   google.charts.setOnLoadCallback(callback);
   }
}

TimelineChart.service

import { GoogleChartsBaseService } from './google-charts-base.service';
import { Injectable } from '@angular/core';
import { GanttChartConfig } from './../models/GanttChartConfig.model';

declare var google: any;

@Injectable()
export class GoogleGanttChartService extends GoogleChartsBaseService {

  constructor() { super(); }

  public BuildPieChart(elementId: string, data: any[], config: GanttChartConfig) : void {  
    var chartFunc = () => { return new google.visualization.Timeline(document.getElementById(elementId)); };
    var options = {
            traitement: config.traitement,
                  datedebut: config.datedebut,
            datefin: config.datefin,

      };

    this.buildChart(data, chartFunc, options);
  }
}

Timeline.html

<div id="{{elementId}}" ></div>

Timeline.ts

import { Component, Input, OnInit } from '@angular/core';
import { GoogleGanttChartService } from './../../services/google-gantt-chart.service';
import { GanttChartConfig } from './../../models/GanttChartConfig.model';
declare var google: any;

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

    @Input() data: any[];
    @Input() config: GanttChartConfig;
    @Input() elementId: string;

 constructor(private _ganttChartService: GoogleGanttChartService) {}

    ngOnInit(): void {
        this._ganttChartService.BuildPieChart(this.elementId, this.data, this.config);
    }
}

And the component to display the graph :

Component.html

 <div class="full"><app-gantt [data]="data1" [config]="config1" [elementId]="elementId1"></app-gantt></div>

Component.ts

import { Component, OnInit, Inject } from '@angular/core';
import { Patient } from '../models/patient.model';
import { Diagnostic } from '../models/diagnostic.model';
import { ActivatedRoute, Router } from '@angular/router';
import { PatientsService } from '../services/patients.service';
import { DiagnosticsService } from '../services/diagnostics.service';
import { PPSsService } from '../services/ppss.service';
import { AngularFireDatabase, AngularFireList, AngularFireObject, AngularFireAction } from 'angularfire2/database';
import { Location } from '@angular/common';
import { Observable } from 'rxjs/Observable';
import { GanttChartConfig } from './../models/GanttChartConfig.model';
import { PPS } from '../models/pps.model';
import {MAT_MOMENT_DATE_FORMATS, MomentDateAdapter} from '@angular/material-moment-adapter';
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA,MatDatepickerModule, MatFormFieldModule,} from '@angular/material';
import { FormControl, FormControlName, FormBuilder, FormGroup, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
import { startWith } from 'rxjs/operators/startWith';
import { map, filter, catchError, mergeMap } from 'rxjs/operators';

  @Component({
  selector: 'app-pps',
  templateUrl: './pps.component.html',
  styleUrls: ['./pps.component.scss']
})
export class PpsComponent implements OnInit {
 patientid: string;
 patientToDisplay;
 ppssToDisplay;
 data1: any[];
 config1: GanttChartConfig;
 elementId1: string;

constructor( 
    private route: ActivatedRoute, 
    private location: Location,
    private patientsService: PatientsService,
    private diagnosticsService: DiagnosticsService,
    private ppssService: PPSsService,
    private router: Router, 
    public dialog: MatDialog, 
    ){ }
  ngOnInit() {

   this.route.params.forEach((urlParameters) => {
   this.patientid = urlParameters['id'];});
   this.patientToDisplay = 
   this.patientsService.getSinglePatient(this.patientid);
   this.ppssToDisplay = this.ppssService.getPPSByPatientid(this.patientid);


   this.data1 = [[ 'traitement','start', 'end'],
   [ 'Chirurgie',  new Date(2017, 3, 29), new Date(2017, 3, 30)],
   [ 'Chimiothérapie', new Date(2017, 2, 4),  new Date(2018, 2, 4)],
   [ 'Radiothérapie',   new Date(2017, 2, 4),  new Date(2018, 2, 4)]]; 

   this.config1 = new GanttChartConfig( '',new Date (),new Date ());
   this.elementId1 = 'myGanttChart';

Now i can display my graph easily with data write in my component

but my data are stocked in firebase like that :

I display the data with an observable from angularfire2

DATA.Service.TS

getPPSByPatientid(Patientid: string){
return this.database.list('/ppss', ref => ref.orderByChild("Patientid").equalTo(Patientid)).valueChanges();
}

I try this in my component .ts in order to have the good array for this.data1 but witout succes Console.log(this.data1) send an array of undefined

let interestingFields = [ 'treatement','dateA', 'dateB'];
    this.ppssToDisplay.subscribe(obj => {
      this.data1 = [
        interestingFields,
        interestingFields.map(field => obj[field]),
      ];
    console.log(this.data1);
    });


Error:

    core.js:1598 ERROR Error: Uncaught (in promise): Error: Not an array Error: Not an array

I wanted to put all of my code so you could have complete visualization of what I want to do.

My question is: Have I chosen the right solution or should I use a loop in my template to populate the chart?

And could someone show me the voice so I can sleep again (5 days lol)

回答1:

It seems you have gotten the right solution. There is just one problem when getting your data to data1.

For the retrieved data to match the pattern on your data written in hard, you have to loop through it from the perspective of the retrieved data:

this.ppssToDisplay.subscribe(ppsList => {
  this.data1 = [
    interestingFields,
    ...ppsList.map(pps => interestingFields.map(field => pps[field]))
    ];
});

And there you go. That should solve your problem.