Creating Dynamic Donut Charts with Angular and D3.js ✨📊

Med Zied Cherif
4 min readAug 8, 2023

--

Introduction

Are you ready to add stunning data visualizations to your web applications? In this article, we’ll embark on a journey to create dynamic Donut Charts using the latest versions of Angular and D3.js. By combining the flexibility of D3.js with the power of Angular components, we’ll craft an interactive Donut Chart capable of displaying different datasets seamlessly.

Key Features

  • The heart of our solution lies in an Angular component, designed to seamlessly integrate and bring reusability to your projects.
  • Users can effortlessly switch between diverse datasets, as a mere click of a button triggers real-time updates to the chart.
  • Drawing on D3.js, a renowned JavaScript library for data visualization, we ensure that our chart not only captivates but enlightens as well.

Getting Started with D3.js

Before we dive into the code, let’s ensure we have D3.js set up in our project. You can install D3.js using npm with the following command:

npm install d3

Additionally, to enhance your development experience, you can install the types for D3.js:

npm install @types/d3 --save-dev

Don’t forget to include D3.js in your component by importing it:

import * as d3 from 'd3';

Understanding the Code

Let’s dive into the code that propels our project forward and create this dynamic Donut Chart step by step.

Importing Dependencies

First, we import necessary dependencies in our DonutChartComponent.ts:

import { Component, Input, OnChanges, SimpleChanges, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
import * as d3 from 'd3'; // Import the latest version of D3.js
import { DonutChartData } from '../models/donut-chart-data.model';

Component Setup

We define our Angular component and set up the necessary input and view child references:

@Component({
selector: 'app-donut-chart',
templateUrl: './donut-chart.component.html',
styleUrls: ['./donut-chart.component.css'],
})
export class DonutChartComponent implements AfterViewInit, OnChanges {
@Input() data: DonutChartData[] = [];
@ViewChild('donutChart', { static: false }) donutChartContainer!: ElementRef;

Handling Data Changes

We listen for changes in our input data and react accordingly to render the chart:

ngOnChanges(changes: SimpleChanges): void {
if (changes['data'] && this.data && !changes['data'].isFirstChange()) {
this.renderChart();
}
}

ngAfterViewInit(): void {
this.renderChart(); // Render the chart after the view is initialized
}

Rendering the Chart

Our renderChart() function creates the Donut Chart using D3.js:

renderChart(): void {
const container = this.donutChartContainer.nativeElement;
const width = container.clientWidth;
const height = container.clientHeight;
d3.select("svg").remove(); // Clear previous chart

const svg = d3.select(container).append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`);

const radius = Math.min(width, height) / 2;

// Create color scale based on data's color property
const color = d3.scaleOrdinal()
.domain(this.data.map(d => d.color))
.range(d3.quantize(t => d3.interpolateSpectral(t * 0.8 + 0.1), this.data.length).reverse());

const arc = d3.arc()
.innerRadius(radius * 0.6)
.outerRadius(radius);

const pie = d3.pie<DonutChartData>()
.value(d => d.value)
.sort(null);
const pieData = pie(this.data);

svg.selectAll('path')
.data(pieData)
.enter()
.append('path')
.attr('d', arc)
.attr("fill" , d => color(d.data.color));
}

Components Collaboration

Our project comprises several components working in harmony to create a seamless user experience. Let’s explore these components:

Chart Container Component

The ChartContainerComponent orchestrates the entire visualization process. It holds the data and enables dataset switching.

// ChartContainerComponent.ts
import { Component } from '@angular/core';
import { DonutChartData } from '../models/donut-chart-data.model';

@Component({
selector: 'app-chart-container',
templateUrl: './chart-container.component.html',
styleUrls: ['./chart-container.component.css']
})
export class ChartContainerComponent {
// Define your portfolio data here or fetch it from a service
portfolioData: DonutChartData[] = [
{ label: '1', value: 300, color: '#3366cc' }, // Blue
{ label: '2', value: 450, color: '#109618' }, // Green
{ label: '3', value: 250, color: '#ff9900' } // Orange
];
// Handle dataset selection
switchDataSet(dataSet: string): void {
// Update or fetch data based on the selected dataset (dataSet)
// ...
}
}

Data Controls Component

The DataControlsComponent is responsible for allowing users to switch between datasets:

<!-- data-controls.component.html -->
<div class="data-controls">
<button (click)="dataSetSelected.emit('1')">Dataset 1</button>
<button (click)="dataSetSelected.emit('2')">Dataset 2</button>
<button (click)="dataSetSelected.emit('3')">Dataset 3</button>
</div>typescriptCopy code
// DataControlsComponent.ts
import { Component, EventEmitter, Output } from '@angular/core';

@Component({
selector: 'app-data-controls',
templateUrl: './data-controls.component.html',
styleUrls: ['./data-controls.component.css']
})
export class DataControlsComponent {
@Output() dataSetSelected = new EventEmitter<string>();
}

HTML Structure

Here’s how the components collaborate within the HTML structure:

<div class="parent-container">
<app-donut-chart [data]="portfolioData"></app-donut-chart>
<app-data-controls (dataSetSelected)="switchDataSet($event)"></app-data-controls>
</div>

Exploration and Adaptation

Feel the freedom to explore, customize, and elevate the project to match your distinct data visualization requirements. Our project sets the stage for constructing captivating charts by marrying the latest Angular and D3.js technologies.

Conclusion: Illuminating Insights Through Dynamic Donut Charts ✨📊

In the realm of data-driven narratives, the ability to convey insights through captivating visuals is paramount. Our exploration into the world of dynamic Donut Charts using Angular and D3.js showcases the fusion of cutting-edge technologies to create a symphony of data and design.

Angular’s component-driven architecture marries seamlessly with D3.js’s prowess in data visualization, resulting in a harmonious interplay that transcends mere aesthetics. We’ve unveiled a solution where users can effortlessly navigate through datasets, gaining profound insights with every click. This dynamic interaction transforms charts from static visuals to enlightening narratives.

As we conclude our journey, remember that the power of data lies not just in its numbers, but in how we bring those numbers to life. By harnessing the capabilities of Angular and D3.js, you’re not just crafting charts; you’re unveiling stories waiting to be heard.

Elevate your web applications and empower your users with the capacity to explore, understand, and engage with data on a whole new level. This project serves as a testament to the possibilities that emerge when cutting-edge technologies converge, and as an invitation to illuminate insights through the magic of dynamic data visualization. 🚀💡

--

--

Med Zied Cherif

Chief Technology Officer | Tech Startup Founder | Edtech Enthusiast | Digital Inclusion Advocate | Youth Empowerment Fan | Disability Rights Advocate