Assuming you have read our angular getting started to blog.
Today we will integrate the D3 js library with angular, one of the best data visualization libraries out there.
D3.js is a JavaScript library for manipulating documents based on data.
D3 helps you bring data to life using HTML, SVG, and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.
Let's Install D3 js in our angular project with its corresponding types
npm i --save d3
npm i --save-dev @types/d3
We suggest that instead of writing d3 code in your component directly we can create a separate component that encapsulates the logic of the d3 chart
Thus making it reusable
So Let's create a component to encapsulate the logic of d3 js
ng generate component d3-line-chart
Now Inside the component ts file add the following code
import { Component, ElementRef, Input, OnChanges, OnInit } from '@angular/core';
import * as d3 from 'd3'
@Component({
selector: 'app-line-chart',
templateUrl: './line-chart.component.html',
styleUrls: ['./line-chart.component.scss']
})
export class D3LineChartComponent implements OnChanges {
@Input() public data: { value: number, date: string }[];
private width = 700;
private height = 700;
private margin = 50;
public svg;
public svgInner;
public yScale;
public xScale;
public xAxis;
public yAxis;
public lineGroup;
constructor(public chartElem: ElementRef) {
}
public ngOnChanges(changes): void {
if (changes.hasOwnProperty('data') && this.data) {
console.log(this.data)
this.initializeChart();
this.drawChart();
window.addEventListener('resize', () => this.drawChart());
}
}
private initializeChart(): void {
this.svg = d3
.select(this.chartElem.nativeElement)
.select('.linechart')
.append('svg')
.attr('height', this.height);
this.svgInner = this.svg
.append('g')
.style('transform', 'translate(' + this.margin + 'px, ' + this.margin + 'px)');
this.yScale = d3
.scaleLinear()
.domain([d3.max(this.data, d => d.value) + 1, d3.min(this.data, d => d.value) - 1])
.range([0, this.height - 2 * this.margin]);
this.yAxis = this.svgInner
.append('g')
.attr('id', 'y-axis')
.style('transform', 'translate(' + this.margin + 'px, 0)');
this.xScale = d3.scaleTime().domain(d3.extent(this.data, d => new Date(d.date)));
this.xAxis = this.svgInner
.append('g')
.attr('id', 'x-axis')
.style('transform', 'translate(0, ' + (this.height - 2 * this.margin) + 'px)');
this.lineGroup = this.svgInner
.append('g')
.append('path')
.attr('id', 'line')
.style('fill', 'none')
.style('stroke', 'red')
.style('stroke-width', '2px')
}
private drawChart(): void {
this.width = this.chartElem.nativeElement.getBoundingClientRect().width;
this.svg.attr('width', this.width);
this.xScale.range([this.margin, this.width - 2 * this.margin]);
const xAxis = d3
.axisBottom(this.xScale)
.ticks(10)
.tickFormat(d3.timeFormat('%m / %Y'));
this.xAxis.call(xAxis);
const yAxis = d3
.axisLeft(this.yScale);
this.yAxis.call(yAxis);
const line = d3
.line()
.x(d => d[0])
.y(d => d[1])
.curve(d3.curveMonotoneX);
const points: [number, number][] = this.data.map(d => [
this.xScale(new Date(d.date)),
this.yScale(d.value),
]);
this.lineGroup.attr('d', line(points));
}
}
Inside the component HTML file
<div class="linechart"></div>
Now we can use this component throughout our project
Let's say you want to integrate this inside App Component
Inside the .ts file you can use the following structure to pass data to the above d3 shared component
data = [
{
"value": 74,
"date": "2012-10-05"
},
{
"value": 65,
"date": "2012-08-05"
},
]
Inside the .HTML file
<app-d3-line-chart [data]=”data”></app-d3-line-chart>
Vola! You can use the above component anywhere inside your project
Stay tuned for more such content on D3 and more chart integrations!