Create a responsive Angular D3 charts

Create a responsive Angular D3 charts
While the landscape of frameworks available for structuring and building web applications is changing by the minute, D3 is still the recognized way to create visualizations using Javascript. In this tutorial, we will add a D3 chart to an Angular application and make the size of the graph dynamic.

Note: You can find the finished source code here.

Creating the Angular project

The first step is to create a new Angular project using the CLI, and to add the d3 library to it:

ng new angular-d3
npm install d3 --save
npm install @types/d3 --save-dev

Next, we will create the component that we will work with:

ng generate component bar-chart

Finally, we will replace the content of ‘src/app/app.component.html’ with the following:

<h1>Bar Chart</h1>

Loading and passing data

In this tutorial, we will use this bar chart from Mike Bostock as the D3 visualization. You can find the data in JSON format here, and we will put it in a new asset file at ‘src/assets/data.json’.

We can also create an interface for the data points, in a new file ‘src/app/data/data.model.ts’:

export interface DataModel {
  letter: string;
  frequency: number;

To load this data, we can modify the ‘src/app/app.component.ts’ file like this:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { DataModel } from 'src/data/data.model';

  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
export class AppComponent {
  data: Observable<DataModel>;

  constructor(private http: HttpClient) { = this.http.get<DataModel>('data/data.json');

For HttpClient to work, we need to add HttpClientModule to our App NgModule imports in ‘src/app/app.module.ts’.

Finally, we can pass the data to our chart component by modifying ‘src/app/app.component.html’:

<h1>Bar Chart</h1>
<app-bar-chart [data]=”data | async”></app-bar-chart>

Integrating the D3 chart

Let’s replace the content of ‘src/app/bar-char/bar-chart.component.html’ with:

<div #chart id="chart"></div>

As you can see, our component will be code-driven, with nothing in the template except a div, which will serve as our container. The chart size will be inferred from the size of this element, which will be helpful in making the SVG react like a normal html node. Here is the main part of the code, the ‘src/app/bar-chart/bar-chart.component.ts’ file:


import { Component, ElementRef, Input, OnChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import * as d3 from 'd3';
import { DataModel } from 'src/app/data/data.model';

  selector: 'app-bar-chart',
  encapsulation: ViewEncapsulation.None,
  templateUrl: './bar-chart.component.html',
  styleUrls: ['./bar-chart.component.scss']
export class BarChartComponent implements OnChanges {
  private chartContainer: ElementRef;

  data: DataModel[];

  margin = {top: 20, right: 20, bottom: 30, left: 40};

  constructor() { }

  ngOnChanges(): void {
    if (! { return; }


  private createChart(): void {'svg').remove();

    const element = this.chartContainer.nativeElement;
    const data =;

    const svg ='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.bottom;

    const x = d3
      .rangeRound([0, contentWidth])
      .domain( => d.letter));

    const y = d3
      .rangeRound([contentHeight, 0])
      .domain([0, d3.max(data, d => d.frequency)]);

    const g = svg.append('g')
      .attr('transform', 'translate(' + this.margin.left + ',' + + ')');

      .attr('class', 'axis axis--x')
      .attr('transform', 'translate(0,' + contentHeight + ')')

      .attr('class', 'axis axis--y')
      .call(d3.axisLeft(y).ticks(10, '%'))
        .attr('transform', 'rotate(-90)')
        .attr('y', 6)
        .attr('dy', '0.71em')
        .attr('text-anchor', 'end')

        .attr('class', 'bar')
        .attr('x', d => x(d.letter))
        .attr('y', d => y(d.frequency))
        .attr('width', x.bandwidth())
        .attr('height', d => contentHeight - y(d.frequency));

This file is mostly a slightly modified version of Mike Bostock’s snippet, but instead of having a static height and width, we use the div element’s height and width. We use the data that is passed through an input property instead of getting it from the file, which separates responsibility. In the component declaration, we changed the ViewEncapsulation, since the dynamic modifications to the DOM by D3 don’t play well with the default Angular styling. Without this modification, the styles aren’t applied.

We can add some styling by adding the following to the renamed ‘src/app/bar-chart/bar-chart.component.scss’ file:


app-bar-chart {
    .bar {
        fill: steelblue;
    .bar:hover {
        fill: brown;
    .axis--x path {
        display: none;

Now, when you run ‘ng serve’, you should see the bar chart. You can also notice that it is taking up the whole page. If you resize the page and refresh, you will notice that the chart changes its size accordingly.

Using the component’s width and height

A nice tweak would be to use the width and size of the component, so we can style the component from its parent. We can accomplish this by modifying the ‘src/app/bar-chart/bar-chart.component.scss‘ file like this:


app-bar-chart {
    #chart {
        height: inherit;
        width: inherit;

        .bar {
            fill: steelblue;
        .bar:hover {
            fill: brown;
        .axis--x path {
            display: none;

An example use case would be to make the chart take 50% of its parent width. This is easily done by going to app.component.css and adding the following:

app-bar-chart {
  width: 50%;

This is especially useful when using grid systems, where the specific width of a chart in a column varies for almost every screen.

Resizing dynamically

The last tweak that we are going to make is to recreate the chart when the window is resized. This can cause a hit to performance if your chart has a lot of data, but we can manage this by throttling (which won’t be explained in this post series). This should be a relatively unfrequent event anyway.

To resize dynamically, we can modify the file ‘src/app/bar-chart/bar-chart.component.html’ like such:

<div #chart id=”chart” (window:resize)=”onResize($event)”></div>

And we can add the following method to the file ‘src/app/bar-chart/bar-chart.component.ts’ :

onResize() {


Integrating D3 with Angular can be extremely powerful, as D3 allows us to create amazing visualizations and Angular provides the framework to create everything else related to a web application in a scalable way. This is an example of the power of both libraries combined, as we find ourselves with a chart that can be reused easily, with the responsibility of displaying data completely isolated while still allowing us to style it and position it from its parent container. We do need to be careful when integrating the librairies since they are both modifying the DOM and can possibly alter the expected behavior. The ViewEncapsulation that is not working properly is a great example of this.

30s ad

Build Enterprise Applications with Angular 2

AngularJS for the Real World - Learn by creating a WebApp

Unit Testing AngularJS: Build Bugfree Apps That Always Work!


Angular Tutorial - Learn Angular from Scratch

Web Development Tutorial - JavaScript, HTML, CSS

Test Driven Development with Angular

E-Commerce JavaScript Tutorial - Shopping Cart from Scratch

Javascript Project Tutorial: Budget App

React + TypeScript : Why and How