Creating a responsive bar chart in Angular using D3.js

Nikola Milicic
Sep 3, 2018 · 5 min read

D3.js is a great library for creating any kinds of charts and graphs using Javascript. In this tutorial I will show you how to create simple responsive bar chart using D3.js and Angular.

Getting started

In this tutorial we are going to use bar chart from Mike Bostock.

Create new angular project using Angular CLI

ng generate angular-d3-responsive-chart

Install D3.js

npm install d3 --save

(Optional) Install Typescript types for D3.js

npm install @types/d3 --save-dev

Create bar chart component

ng generate component bar-chart

Data

To show a chart we need data in this example we are gonna use data from a file. You can find data.json here and to be able to load it to the component we need to put it in assets folder of our Angular application. So now create data.json in src/assets/data.json.

Now we need to create a model for our data, first create folder models and create data.model.ts and inside create our data interface

export interface Data {
letter: string;
frequency: number;
}

Now let’s import that data into our application. Open app.component.ts and change it to match this:

We are using HttpClient to load data from our file, so we need to import HttpClientModule to our app.module.ts

Now when we have our data loaded we are ready to create our bar chart component.

Bar chart component

To create our component using:

ng generate component bar-chart

We are gonna display our component inside our app.component so let’s change our template to include our newly created bar chart component. To do so open app.component.html remove generated code and insert:

<h1>Responsive bar graph</h1>
<app-bar-chart></app-bar-chart>

If we run this we should see a title and bar-chart works! message beneath it.

Let’s now start with creating our bar chart. First, we need to create an element that is gonna hold our chart. Delete everything from bar-chart.component.html and insert:

<div #barChart id="bar-chart"></div>

We are going to use ElementRef to get a reference to our container of the graph so we can set width and height of our svg element that will hold our chart. That’s why we need to add #barChart to our div element.

Now let’s create edit bar-chart.component.ts copy this code to your component:

Now we only need to provide data to our component and we are should see our graph. To do that change app.component.html from:

<h1>Responsive bar chart</h1>
<app-bar-chart></app-bar-chart>

to:

<h1>Responsive bar chart</h1>
<app-bar-chart [data]="data | async"></app-bar-chart>

Now if we run our app we should see our bar graph

Ok now we have our chart but if you try to resize your window you will see that chart is not resizing until you refresh the site. Let’s first go back to our bar-chart.component.ts and see what we have done there.

So the first thing that we added is:

@ViewChild('barChart')
private chartContainer: ElementRef;

Here we bind our component to the div in our template and we are gonna use dimension of that div to set dimension of our chart

Next, we have

@Input()
data: Data[];

Nothing special here, just providing an input for our data

After that we have

ngOnChanges(): void {
if (!this.data) { return; }
this.createChart();
}

Here we are reacting to our data change, if the data changes we are going to re-create the whole chart.

Next is our createChart function here we can find whole definition of our graph it’s pretty much standard bar graph so I won’t go through all D3.js code. So important parts are:

d3.select('svg').remove();

First we remove old SVG element if that element exists, we need to do so because if data changes we also call this function so it could be called multiple times and we would end up with multiple charts. Very important note here is that d3.select() function is global so it will select first SVG element in the DOM.

const element = this.chartContainer.nativeElement;

Here we get our container element and his native element so we can it’s width and height.

const svg = d3.select(element).append('svg')
.attr('width', element.offsetWidth)
.attr('height', element.offsetHeight);
const contentWidth = element.offsetWidth - this.margin.left - this.margin.right;const contentHeight = element.offsetHeight - this.margin.top - this.margin.bottom;

Now when we have our element we select it and append to it new svg element with width and height that is equal to our container element. Also we calculate our content height and width.

Next thing we need to do is to adjust scaling of our X and Y axis based on our size

const x = d3.scaleBand()
.rangeRound([0, contentWidth])
.padding(0.1)
.domain(this.data.map(d => d.letter));
const y = d3.scaleLinear()
.rangeRound([contentHeight, 0])
.domain([0, d3.max(this.data, d => d.frequency)]);

So that’s it, now let’s make it responsive.

Making it responsive

To make a graph responsive we are going to listen to window.resize event and we are going to recreate the whole chart. Note that this is not an optimal solution because if the chart has a lot of data it will become laggy and it will take a while to recreate. To add event listener we need to add (window:resize)=”onResize($event) to our bar chart container so now our container looks like this:

<div #barChart id="bar-chart" (window:resize)="onResize($event)"></div>

Now we just have to add a function to our component go ahead and add this to bar-chart.component.ts

onResize() {
this.createChart();
}

Now we are done If we run our app and resize the window we can see that our chart adjusts to our window size.

Styling

Now we have our chart but is really ugly let’s add some style to it.

Since the Angular components by default use ViewEncapsulation.Emulated witch enable us to separate the styles by components. This mechanis doesn’t play well with D3 so we can either disable ViewEncapsulation or use /deep/ inside our style files. I will show you how to disable it and use it like that. We need to change our bar chart component definition to look like this:

@Component({
selector: 'app-bar-chart',
encapsulation: ViewEncapsulation.None,
templateUrl: './bar-chart.component.html',
styleUrls: ['./bar-chart.component.less'
]})

We have added encapsulation: ViewEncapsulation.None after selector.

Now we can style our chart. Open bar-chart.component.less and add this:

Now we have a nice blue graph and we are done with this tutorial. I hope it was helpful and you can find full source code here: https://github.com/NMilicic/angular-d3-responsive-chart

Conclusion

Using D3 in Angular is really simple and we can create reusable responsive chart very easily. This solution has its disadvantages but it provides a nice insight into how to combine Angular’s native element for adjusting D3 charts size.

Nikola Milicic

Written by

Software Engineer

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade