54👍
You can install the package, along with the types for full functionality in a typescript environment such as Angular:
npm install --save chart.js && npm install --save-dev @types/chart.js
Then in your component you can now import * as Chart from 'chart.js'
and use it in your typescript environment. Check out this example for implementation methods using typescript.
Because you need to get the canvas from the DOM you need to make sure it’s rendered before attempting to access it. This can be accomplished with AfterViewInit
.
import { Component, AfterViewInit } from '@angular/core';
import * as Chart from 'chart.js'
export class MyChartComponent implements AfterViewInit {
canvas: any;
ctx: any;
ngAfterViewInit() {
this.canvas = document.getElementById('myChart');
this.ctx = this.canvas.getContext('2d');
let myChart = new Chart(this.ctx, {
type: 'pie',
data: {
labels: ["New", "In Progress", "On Hold"],
datasets: [{
label: '# of Votes',
data: [1,2,3],
backgroundColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {}
});
}
}
2👍
In my Angular 6.1 site, I am using chart.js by itself in mgechev/angular-seed.
As of writing this response, Chart.js developers have some work to do to make exporting its members compliant with newer standards so rollups may be problematic.
To get Chart.js 2.7.x to work after installing package chart.js
and types @types/chart.js
in this angular-seed, all I needed to do is:
-
Update
project.config.ts
to include ROLLUP_NAMED_EXPORTS to get rollup to work properly (if you’re using a rollup).this.ROLLUP_NAMED_EXPORTS = [ ...this.ROLLUP_NAMED_EXPORTS, { 'node_modules/chart.js/src/chart.js': ['Chart'] } ];
-
Update
project.config.ts
to include additional packages. This seed uses SystemJS config. This might vary if you’re using something else.// Add packages const additionalPackages: ExtendPackages[] = [ { name: 'chart.js', path: 'node_modules/chart.js/dist/Chart.bundle.min.js' }, ... ];
-
In your component
import { Chart } from 'chart.js'; ... export class MyComponent implements OnInit { @ViewChild('myChart') myChartRef: ElementRef; chartObj: Chart; ... }
Then load chart configuration in ngOnInit() per Chart.js documentation
-
HTML will look something like this:
<div class="chart-container"> <canvas #myChart></canvas> </div>
2👍
So, after a lot of thought, I decided to jump in on this thread, b/c there is an Angular way of doing this that follows best practices and doesn’t use any document scope querying… (yuck). For brevity’s sake, I’ve used a template
in the Component decorator, not a templateUrl
, but they behave the same as if it were in a template. The DOM still has to e loaded first, and that’s the big gotcha with Chart.js. This example is for Angular 8+ and is working with my current version which is 9.1.7
import { Component, ViewChild, AfterViewInit, Input } from '@angular/core'
import { Chart } from 'chart.js'
@Component({
selector: 'app-chart',
template: `<canvas #myChart></canvas>,
})
export class SkillsChartComponent implements AfterViewInit {
@ViewChild('myChart', {
static: true
}) myChart: {
nativeElement: HTMLCanvasElement
}
constructor() {}
ngAfterViewInit() {
this.createChart()
}
private createChart(): void {
const elem = this.myChart.nativeElement
try {
new Chart(elem, {
type: 'pie',
data: {
labels: ["New", "In Progress", "On Hold"],
datasets: [{
label: '# of Votes',
data: [1,2,3],
backgroundColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: false,
display:true
}
})
} catch (err) {
throw new Error(err) // You can either throw an error or do whatever here...
} finally {
// Any cleanup of logging...
}
}
}
What’s going on here is that you’re getting a reference to the Canvas itself, and using Angular’s lifecycle hooks to say once the HTML content is initialized, then draw onto the canvas using Chart. The fact that the first argument of Chart is the element itself, this leads to a lot of anti-patterns, but you definitely don’t need vanilla JS querying the document scope to get a handle on a specific canvas, and this is the best practice way of doing it according to Angular style guides. If you have concerns, leave them in the comments.