0

I'm trying to draw a timeline chart with data that I get from a database by using anychart v8 and Angular CLI v10.0.4 I saw this topic, which is very similar to my problem here. I followed the steps but I can't see the data. And I get this error : Error: attribute d: Expected number, "M NaN 56.5 L NaN 5…". I tried to hardcode the data, and then it worked just fine, so I don't know what went wrong.

Here's how I get the data with Sequelize :

exports.getAllStoryArcs = (req, res, next) => {
    StoryArc.findAll({
        include: [StoryArc.startChapter, StoryArc.endChapter],
        order: [['startChapter', 'number', 'ASC']]
    })
            .then((storyArcs) => {
                res.status(200).json(storyArcs);
            })
            .catch((err) => {
                console.log(err);
                res.status(400).json({
                    error: err
                })
            });
};

EDIT : Here's a sample of the data get from MySQL DB with Sequelize :

[
  Story Arc {
    dataValues: {
      id: 6,
      name: "Introduction",
      synopsis: "synopsis text",
      delailedSummary: "detailedSummary text",
      createdAt: 2020-08-22T16:41:21.000Z,
      updatedAt: 2020-08-22T16:41:21.000Z,
      startChapterId: 1,
      endChapterId: 8,
      startChapter: {
        id: 1,
        number: 1,
        title: "title text",
        synopsis: "synopsis text"
      },
      endChapter: {
        id: 8,
        number: 8,
        title: "title text",
        synopsis: "synopsys text"
      }
    }
  }
]

Here's my data transformation function (data.service.ts) :

import { Injectable } from '@angular/core';
import { StoryArcService } from './story-arc.service';
import { StoryArcDTO } from '../models/story-arc-dto.model';
const BASE_YEAR: number = 2000;
const START_MONTH: number = 0;
const END_MONTH: number = 11;
const START_DAY: number = 1;
const END_DAY: number = 31;

@Injectable({
  providedIn: 'root'
})
/**
* Service class to manage the timeline chart's data.
*/
export class DataService {
  
  // Array of arcs
  private _arcs: Array<StoryArcDTO>;
  // The arcs mapped to be use in the timeline chart
  private _arcsMap: Array<Object> = [];
  // The set to use in the chart
  private _arcsSet: anychart.data.Set;
  
  constructor(private arcService: StoryArcService) {
    this.setArcData();
  }
  
  private setArcData() {
    // Fill the array of story arcs
    this.arcService.getAllArcs().subscribe(
      gottenArcs => {
        if (gottenArcs) {
          this._arcs = gottenArcs;
          // Fill the anychart data set
          this._arcs.forEach((arc) => {
            // Map the arc data set
            this._arcsMap.push({
              name: arc.name,
              start: Date.UTC(BASE_YEAR + arc.startChapter.number, START_MONTH, START_DAY),
              end: Date.UTC(BASE_YEAR + arc.endChapter.number, END_MONTH, END_DAY),
              startNb: arc.startChapter.number,
              endNb: arc.endChapter.number
            });
          });
        }
      }
    );
  }
  
  public get arcsMap() : Object[] {
    return this._arcsMap;
  }
}

EDIT 2 : I do have done the mapping but it doesn't work. After the mapping, it looks like this :

[
   {name: "Introduction", start: Date.UTC(2001, 0, 1), end: Date.UTC(2008, 11, 31), startNb: 1, endNb: 8},
   {name: "Révolution chez les princesses", start: Date.UTC(2009, 0, 1), end: Date.UTC(2014, 11, 31), startNb: 9, endNb: 14},
   {name: "La formule magique de l'ange", start: Date.UTC(2015, 0, 1), end: Date.UTC(2019, 11, 31), startNb: 15, endNb: 19}
]

And then my component (timelines.component.js):


import { Component, OnInit, AfterViewInit } from '@angular/core';
import 'anychart';
import { DataService } from 'src/app/services/data.service';

@Component({
  selector: 'app-timelines',
  templateUrl: './timelines.component.html',
  styleUrls: ['./timelines.component.css']
})
export class TimelinesComponent implements OnInit {
  
  public initTimeline: anychart.charts.Timeline;
  public globalTimeline: anychart.charts.Timeline;
  public globalRange: anychart.core.timeline.series.Range;
  
  constructor(private dataService: DataService) { }
  
  ngOnInit(): void {
    this.initChart();
  }
  
  initChart() {
    console.log(this.dataService.arcsMap);
    let arcsSet = anychart.data.set(this.dataService.arcsMap);
    
    this.globalTimeline = anychart.timeline();
    this.globalTimeline.axis().height(20);
    this.globalTimeline.axis().fill("#7030A0");
    this.globalTimeline.axis().stroke("#381850");
    this.globalTimeline.axis().ticks().stroke("#AB74D5");
    this.globalTimeline.axis().labels().fontFamily("Ubuntu");
    this.globalTimeline.axis().labels().fontWeight("bold");
    this.globalTimeline.axis().labels().fontColor("#E3D1F1");
    this.globalTimeline.axis().labels().format(function() {
      let realNumber = this.value;
      if (realNumber >= BASE_YEAR) {
        realNumber = this.value - BASE_YEAR;
      }
      return realNumber;
    })
    
    this.globalRange = this.globalTimeline.range(arcsSet);
    
    this.globalRangeSettings();
    
    this.globalTimeline.container("global-timeline");
    this.globalTimeline.draw();      
  }
  
  globalRangeSettings() {
    this.globalRange.height(30);
    this.globalRange.labels().format("{%name}");
    this.globalRange.labels().fontFamily("Ubuntu");
    this.globalRange.tooltip().titleFormat("{%name}");
    this.globalRange.tooltip().fontFamily("Ubuntu");
    this.globalRange.tooltip().format(function() {
      return `Début : Chapitre ${this.getData("startNb")}
              Fin : Chapitre ${this.getData("endNb")}`;
    })
    this.globalRange.color("#8E44BD");
  }
}

I verified, and I get the data as I want them in the initChart function, but the draw function seems not to understand them or something.

Could someone help me please ?

2
  • The error you get tells that chart can render correctly the applied data. It means that data is not valid or includes misconfiguration. Can you provide the this.dataService.arcsMap content to review and reproduce the issue? Commented Aug 31, 2020 at 4:55
  • Hi ! I added it to the post. Commented Aug 31, 2020 at 10:45

2 Answers 2

0

Your data content doesn't meet the required data format of the chart. You can preprocess it or apply a specified mapping to let the chart parse your data correctly. You can find the required data format in the article. The sample describes how to apply mapping to the Timeline chart.

Sign up to request clarification or add additional context in comments.

5 Comments

I did the mapping, that what I do when I fill the arcsMap. I've edit my post to show the result of the mapping, but it doesn't work and I get the error.
The data you provided in the last edit works well - playground.anychart.com/0d50n22z Can you provide the full chart configuration code?
Yeah, and that is my problem =/ When I hardcode them, there's no problem but when I get them from the database, it doesn't work. I edit the post with all my to classes (data.service.ts and timelines.component.ts) and I added the sequelize method that get all the arcs
The chart configuration code is absolutely correct. It requires debugging the moment when the data is applied to the data set in a real application. Probably data is not fetched yet or smth else goes wrong.
Well, I'll try to debug that. Thank you for you're help though !
0

OK, so I followed what @AnyChart Support said about the timing of fetching data.

I got rid of my data service class, I transformed the data in the timelines component, and I added the async keyword to my iniChart method, and so it works !

I don't really understand why though XD

the result looks like this :

ngOnInit(): void {
    this.initChart();
}
    
async initChart() {
    let arcsSet = anychart.data.set(await this.setArcData());
        
    this.globalTimeline = anychart.timeline();
    this.globalTimeline.axis().height(20);
    this.globalTimeline.axis().fill("#7030A0");
    this.globalTimeline.axis().stroke("#381850");
    this.globalTimeline.axis().ticks().stroke("#AB74D5");
    this.globalTimeline.axis().labels().fontFamily("Ubuntu");
    this.globalTimeline.axis().labels().fontWeight("bold");
    this.globalTimeline.axis().labels().fontColor("#E3D1F1");
    this.globalTimeline.axis().labels().format(function() {
        let realNumber = this.value;
        if (realNumber >= BASE_YEAR) {
            realNumber = this.value - BASE_YEAR;
        }
        return realNumber;
    });
        
    this.globalRange = this.globalTimeline.range(arcsSet);
        
    this.globalRangeSettings();
        
    this.globalTimeline.container("global-timeline");
    this.globalTimeline.draw();      
}
      
globalRangeSettings() {
    this.globalRange.height(30);
    this.globalRange.labels().format("{%name}");
    this.globalRange.labels().fontFamily("Ubuntu");
    this.globalRange.tooltip().titleFormat("{%name}");
    this.globalRange.tooltip().fontFamily("Ubuntu");
    this.globalRange.tooltip().format(function() {
        return `Début : Chapitre ${this.getData("startNb")}
                Fin : Chapitre ${this.getData("endNb")}`;
        })
    this.globalRange.color("#8E44BD");
}
      
async setArcData(): Promise<Object[]> {
    this.arcs = await this.arcService.getAllArcs().toPromise();
    let result: Object[] = [];
    this.arcs.forEach(arc => {
        result.push({
            name: arc.name,
            start: Date.UTC(BASE_YEAR + arc.startChapter.number, START_MONTH, START_DAY),
            end: Date.UTC(BASE_YEAR + arc.endChapter.number, END_MONTH, END_DAY),
            startNb: arc.startChapter.number,
            endNb: arc.endChapter.number
        });
    });
    return result;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.