How implement Chart.js in Angular 2? - javascript

I am using the latest version of Angular 2, V4.0.0 and I want to use graphs from the Chart.js library in my project without many complications.
How can I implement Chart.js in my angular project that does not give me problems in the final production?

You can implement Chart.js in a simple way with the following instructions:
1. Create a new project with angular-cli, skip if you already have one created
ng new example-chartjs
2. Install Chart.js in your project
npm install chart.js --save
3. Import Chart into its component
import Chart from 'chart.js';
4. Use Chart in your view and component
In your view:
<canvas id="myChart" width="400" height="400"></canvas>
In your component:
ngOnInit() {
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {...});
}
The component should look similar to the following
import { Component, OnInit } from '#angular/core';
import Chart from 'chart.js';
#Component({
selector: 'app-chart',
templateUrl: './chart.component.html'
})
export class DashboardComponent implements OnInit {
constructor() { }
ngOnInit() {
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {....});
}
}
Another alternative to use is to include the library from the file ".angular-cli.json"
1. Include in the scripts the library
"styles": [
"styles.css"
],
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
"../node_modules/chart.js/dist/Chart.min.js"
]
2. Declare a variable of type "any" in the controller
declare var Chart:any;
3. Use Chart in your view and component
In your view:
<canvas id="myChart" width="400" height="400"></canvas>
In your component:
ngOnInit() {
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {...});
}
The component should look similar to the following
import { Component, OnInit } from '#angular/core';
declare var Chart:any;
#Component({
selector: 'app-chart',
templateUrl: './chart.component.html'
})
export class DashboardComponent implements OnInit {
constructor() { }
ngOnInit() {
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {....});
}
}

First
npm install chart.js --save
Second
npm install #types/chart.js --save
Third - import Chart into component this way
import * as Chart from 'chart.js';

I've implemented the Chart.js on Angular at this way(first you'll need to install it using npm install chart.js --save):
The folder structure of my project
src/
assets/
app/
charjs/
services/
First I've created a service called report.service.ts :
src/app/services/report.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class ReportService {
constructor(public http: Http) {
}
getReports() {
return this.http.get('assets/report.json')
.map(res => res.json());
}
}
This service it's created based on Angular tutorial showing how to get an external file(or link) and retrieve Json data.
This is important to collect the data from external source(if you must)
The difference between a service and a component, It's you need to to insert this service as a provider on the app.module.ts :
src/app/app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { HttpModule, JsonpModule } from '#angular/http';
import { ReportService } from './services/report.service';
import { ChartjsComponent } from './chartjs/chartjs.component';
#NgModule({
declarations: [
AppComponent,
ChartjsComponent
],
imports: [
BrowserModule,
HttpModule,
JsonpModule
],
providers: [ReportService],
bootstrap: [AppComponent]
})
export class AppModule { }
After that I've created the component chartjs.component.js , and used AfterViewInit instead of OnInit. I've used this approach because our service retrieves the data in asynchronous and, because of that, the data can be returned before the view has been initiated.
src/app/chartjs/chartjs.component.ts
import { Component, AfterViewInit,ViewChild, ElementRef } from '#angular/core';
import Chart from 'chart.js';
import { Respon2se } from '#angular/http';
import 'rxjs/add/operator/map';
import { ReportService } from '../services/report.service';
#Component({
selector: 'app-chartjs',
templateUrl: './chartjs.component.html',
styleUrls: ['./chartjs.component.css']
})
export class ChartjsComponent implements AfterViewInit {
#ViewChild('graphcanvas') mycanvas:ElementRef;
createData;
chartOptions;
constructor(public reportService: ReportService) {
}
ngAfterViewInit() {
this.reportService.getReports().subscribe(reportsData => {
this.createData = {
labels: 'Scatter Dataset',
datasets: [{
label: "reportRetrieve",
data: reportsData,
}]
};
this.chartOptions = {
legend: {
display: false,
position: 'top',
labels: {
boxWidth: 80,
fontColor: 'black'
}
},
scales: {
xAxes: [{
gridLines: {
display: false,
color: "black"
},
scaleLabel: {
display: true,
labelString: "Report Size",
fontColor: "red"
}
}],
yAxes: [{
gridLines: {
color: "black",
display: false
},
scaleLabel: {
display: true,
labelString: "Chart Report",
fontColor: "green"
}
}]
},
layout: {
padding: {
left: 0,
right: 50,
top: 50,
bottom: 0
}
},
maintainAspectRatio: false
};
let ctx = this.mycanvas.nativeElement.getContext('2d');
new Chart(ctx, {
type: 'bubble',
data: this.createData,
options: this.chartOptions,
responsive: false
});
});
}
}
A few comments about this file;
. After imported the service, I've used subscribe,to allow charjs library to get the data and push it on new Chart
. ChartOptions its just a variable to change the chart view the way you want, I've used to create a bubble chart.
. You can define if it's responsive or not.
After you've done that, you'll need to set your html:
src/app/chartjs/chartjs.component.html
<div style="height: 600px;width: 600px">
<canvas #graphcanvas></canvas>
</div>
I hope that helps someone who couldn't implement on the other ways.

I believe, on Angular, chartjs will work like below, because context is available afterViewInit() not onInit()
import { Component, ViewChild, ElementRef, AfterViewInit} from '#angular/core';
import Chart from 'chart.js';
#Component({
selector: 'app-statistics',
templateUrl: './statistics.component.html',
styleUrls: ['./statistics.component.css']
})
export class StatisticsComponent implements AfterViewInit{
#ViewChild('myChart') Chart: ElementRef;
constructor() {
}
ngAfterViewInit() {
var ctx = this.Chart.nativeElement.getContext('2d')
var myChart = new Chart(ctx,{...})
}
}

Related

Type 'Chart' is missing the following properties

I want to add the data from the endpoint response to my chart but when I try to initialize the chart , it throws an error of "Type Chart is missing the following properties from type any . How do I fix this error ? thanks in advance ? this is my component.ts code
import { Component, OnInit } from '#angular/core';
import {ApiService} from '../api.service';
import { Chart} from 'chart.js';
import { from } from 'rxjs';
//import { map } from 'rxjs/operators';
//import { Data} from '../../app/Data';
#Component({
selector: 'app-transactions',
templateUrl: './transactions.component.html',
styleUrls: ['./transactions.component.scss']
})
export class TransactionsComponent implements OnInit {
price = [];
time = [] ;
data = [] ;
chart = [] ;
constructor(private apiService : ApiService) { }
ngOnInit() {
this.apiService.dailychart()
.subscribe((response : any []) => {
console.log(response);
this.data = response;
Array.from(response).forEach( x =>{
this.time.push(x.description);
this.price.push(x.values) ;
})
this
this.chart = new Chart('canvas', {
type: 'line',
data: {
labels: this.time,
datasets: [
{
data: this.price,
borderColor: '#3cb371',
backgroundColor: "#0000FF",
}
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}],
}
}
});
});
}
}
This is my service class code , the response logs to the console but won't show on chart after removing the [] in front of the chart instance member in component.ts
import { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private httpclient : HttpClient ) { }
public dailychart() {
return this.httpclient.get<any>('https://api.coindesk.com/v1/bpi/currentprice.json')
}
}
Inside TransactionsComponent, you initialize chart with an array of any but in your code, you try to assign an instance of Chart. Declared chart as type Chart and it should work.
export class TransactionsComponent implements OnInit {
...
chart: Chart;

Angular 6- importing variable from JS file

I am building a project with Angular 6 that requires me to import styles from an external js file in order to build a custom Google Map. However, it doesn't seem to be importing into my .ts file correctly. Any help would be great!
In my component
import {MapStyles} from './mapstyle.js'
#Component({
selector: 'map',
template: '<div #tref style="width:100%; height:100%;"></div>'
})
export class Map implements AfterViewInit {
...
ngAfterViewInit() {
console.log(MapStyles) //is 'undefined'
}
const mapProperties = {
styles: MapStyles
};
}
The file I'm trying to import (mapstyle.js):
export var MapStyles = [
{
"featureType": "water",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#d3d3d3"
}]
},
...
I've tried things such as
import * as MapStyles from './mapstyle.js'
and
var MapStyles = [...]
but no luck. thanks!
This is how you can import and use a variable from an imported file in Angular X projects.
map-config.ts
export const mapStyle = [
{
'elementType': 'labels.icon',
'stylers': [
{
'visibility': 'off'
}
]
},
{
'featureType': 'poi.medical',
'elementType': 'labels.icon',
'stylers': [
{
'visibility': 'off'
}
]
}
];
map.components.ts
import { Component, OnInit } from '#angular/core';
import { mapStyle } from './map-config';
#Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {
mapStyle = mapStyle;
constructor() {
//
}
}
I am considering MapStyles is a variable which is from external js file.
I had a similar requirement and this is how I have solved it,
I had loaded javascript file from root component and I am trying to use the variable inside sub component as shown below.

Error while loading components dynamically in angular 7. No component factory found

I need to load components dynamically to view on some button click.
I have created on directive and some components in my custom module.
But when I try to create new instance of component it says No component factory found.
Here is my code structure.
dashboard module
#NgModule({
declarations: [MainPageComponent, WidgetComponent, ChartsComponent, GraphsComponent, InfographicsComponent, InsertionDirective],
imports: [
CommonModule,
GridsterModule,
ButtonsModule,
ChartsModule,
DropDownsModule
],
entryComponents: [MainPageComponent, WidgetComponent, ChartsComponent, GraphsComponent, InfographicsComponent],
exports: [MainPageComponent, WidgetComponent, ChartsComponent, GraphsComponent, InfographicsComponent]
})
export class DashboardModule {
static customization(config: any): ModuleWithProviders {
return {
ngModule: DashboardModule,
providers: [
{ provide: Service, useClass: config.service }
]
}
}
}
dashboard/insert directive
import { Directive, ViewContainerRef } from '#angular/core';
#Directive({
selector: '[appInsertion]'
})
export class InsertionDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
1. dashboard/mainMainPageComponent.ts
import { Component, OnInit, ViewChild, ComponentFactoryResolver, ComponentRef, Type } from '#angular/core';
import { Service } from 'src/app/services/service';
import { Widget } from 'src/app/interface/widget';
import { GridsterConfig, GridsterItem } from 'angular-gridster2';
import { SETTINGS } from '../settings'
import { InsertionDirective } from '../insertion.directive';
import { ChartComponent } from '#progress/kendo-angular-charts';
#Component({
selector: 'dasbhoard-main-page',
templateUrl: './main-page.component.html',
styleUrls: ['./main-page.component.css']
})
export class MainPageComponent implements OnInit {
componentRef: ComponentRef<any>;
childComponentType: Type<any>;
#ViewChild(InsertionDirective)
insertionPoint: InsertionDirective;
public title: string;
public widgets: Array<{ widget: Widget, grid: GridsterItem, type: string }> = [];
public options: GridsterConfig;
constructor(private service: Service, private componentFactoryResolver: ComponentFactoryResolver) {
this.title = 'Dashboard';
}
ngOnInit() {
this.options = {
itemChangeCallback: MainPageComponent.itemChange,
itemResizeCallback: MainPageComponent.itemResize,
};
}
addNewWidget(type: string) {
let widgetType = SETTINGS.widgetSetting[type];
let totalWidgets = this.widgets ? this.widgets.length : 0;
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(widgetType.useClass);
//widgetType.useClass = ChartsComponent
// when I pass it statically its ok
//error here
let viewContainerRef = this.insertionPoint.viewContainerRef;
viewContainerRef.clear();
this.componentRef = viewContainerRef.createComponent(componentFactory);
this.widgets.push({ widget: { id: totalWidgets, header: `Widget ${totalWidgets} Header`, content: `<h1>Widget ${totalWidgets} Body</h4>` }, grid: { cols: 1, rows: 1, x: 0, y: 0 }, type: type });
}
}
dashboard/main-component/main-component.html
<ng-template appInsertion> </ng-template>
<button kendoButton(click) = "addNewWidget('charts')"[primary] = "true" class="pull-right" > Add Chart Widget </button>
I have each and every posts and all says you need to insert componets into entry points but I've already included all components to entry points. And all components are inside the same module but still it says no No component factory found for ChartsComponent. Did you add it to #NgModule.entryComponents?.
Any one please can you find out the where I'm doing wrong?
Thanks in advance.
I think it's just a typo:
In entryComponents you've written ChartsComponent and in the resolveComponentFactory method you've written ChartComponent
Could that be it?

Adding highchart3d in Angular 6 application

I am trying to add highcharts3d in Angular 6 application. How to use highchart3d in application to display chart in 3d format. It gives compilation error after import of highchart3d library as follows:
import Highcharts3d from 'highcharts/highcharts-3d';
Thanks,
Install angular2-highcharts from npm:
npm install angular2-highcharts --save
Setup in App Module:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { ChartModule } from 'angular2-highcharts';
import { App } from './App';
#NgModule({
imports: [
BrowserModule,
ChartModule.forRoot(require('highcharts')
],
declarations: [App],
bootstrap: [App]
})
export class AppModule {}
And use it in the component:
import { Component } from '#angular/core';
#Component({
selector: 'simple-chart-example',
template: `
<chart [options]="options"></chart>
`
})
export class App {
constructor() {
this.options = {
title : { text : 'simple chart' },
series: [{
data: [29.9, 71.5, 106.4, 129.2],
}]
};
}
options: Object;
}
Read more here:
https://www.npmjs.com/package/angular2-highcharts#add-highcharts-modules

C3.js in Angular2 getting error

I am trying to use c3.js in an angular 2 project and I keep getting the same error:
AppComponent.html:5 ERROR TypeError: Cannot read property 'id' of undefined
at Object.eval [as updateRenderer] (ng:///AppModule/AppComponent.ngfactory.js:39:29)
...
No compilation errors.
index.html:
<!-- CSS for C3 -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.12/c3.css" rel="stylesheet" type="text/css">
<!-- Load d3.js-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js" charset="utf-8"></script>
<!-- Load c3.js-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.12/c3.js"></script>
app.module.ts:
... (beginning of the file)
import { RcpChartComponent } from './chart.component';
#NgModule({
declarations: [
AppComponent,
RcpChartComponent
... (end of the file)
app.component.ts:
import { Component, OnInit } from '#angular/core';
import { RcpChart } from './chart.component';
import { RcpChartDataService } from './data.service';
#Component({
selector: 'app-root',
providers: [RcpChartDataService],
template: `
<h1>My Title</h1>
<div>Chart:</div>
<div>
<rcpchart style="text-align:center; height:700px; width:700px"[id]="chart.id"></rcpchart>
`
})
export class AppComponent implements OnInit{
title = 'My Title';
chart: RcpChart;
constructor(private rcpChartDataService: RcpChartDataService) { }
getCharts(): void {
this.rcpChartDataService.getChartData().then(charts => this.chart = charts);
}
ngOnInit(): void {
this.getCharts();
}
}
configuration.chart.ts:
import { RcpChart } from "./chart.component";
export const CHARTS: RcpChart[] = [
{
id: "line",
name: "A vs B",
type: "line"
}
];
data.service.ts:
import { Injectable } from '#angular/core';
import { CHARTS } from './configuration.chart';
import {RcpChart} from "./chart.component";
#Injectable()
export class RcpChartDataService {
getChartData(): Promise<any> {
return Promise.resolve(CHARTS);
}
}
and the famous chart component now,
chart.component.ts:
import {Component, Input, Output, EventEmitter, OnInit, AfterViewInit,
ChangeDetectorRef, Compiler} from '#angular/core';
import { CHARTS } from './configuration.chart';
import { RcpChartDataService } from './data.service';
declare var d3, c3: any;
export class RcpChart {
id?: string;
name?: string;
type?: string;
parameters?: any[];
}
#Component({
selector: 'rcpchart',
providers: [RcpChartDataService],
template:`
<table style="border:solid">
<tr>
<td>
<div style="height: 300px">
<h1 *ngIf="chart">{{chart.name}}</h1>
<svg [id]="chart.id"></svg>
</div>
</td>
<td>
<div *ngIf="!data">
Data Not Available
</div>
</td>
</tr>
</table>
`
})
export class RcpChartComponent implements AfterViewInit{
#Input() chart: RcpChart;
data: any;
constructor(private rcpChartDataService: RcpChartDataService){}
ngAfterViewInit() {
console.log("CHART starts drawing AFTER VIEW INIT :" + this.chart.id);
this.drawChart(this.chart);
}
drawChartLine(chartConfig: RcpChart) {
//line chart
let chart = c3.generate({
bindto: '#' + chartConfig.id,
type: 'line',
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
]
}
});
}
drawChart(chartConfig: RcpChart) {
if (chartConfig.type === 'line') this.drawChartLine(chartConfig);
}
getCharts(): void {
this.rcpChartDataService.getChartData().then(charts => this.chart = charts);
}
ngOnInit(): void {
this.getCharts();
}
I know it is a little long but I should have been missing something very easy, any help will be highly appreciated.
I think you are going the long route. Just follow the steps provided in the official google group of c3.js to configure it c3.js chart with the Angular2 project.

Categories