Make Pretty / User-Friendly Charts with Angular 14 & ng2-charts v3.1.0
Tags: angular, webdev, design, javascript
Published: 2022-07-01 03:45:47

In this post, we'll create a line chart (in Angular 14 with the latest release of `ng2-charts`) in a style that's all the rage in cryptocurrency dashboard design (RIP) and optimized for user interaction.

Here's how it will behave:
![End Result](https://ik.imagekit.io/fuc9k9ckt2b/Blog_Post_Images/Dev_to/result_g4F7hak32.gif?ik-sdk-version=javascript-1.4.3&updatedAt=1656646523341)

---

## Skip Ahead
- [**Create** App and Dependencies](#create-app-and-dependencies)
 - [Generate new **Angular app**](#generate-new-angular-app)
 - [Import **CommonModule**](#import-commonmodule)
 - [Install **SCSS Utility** and **Charts** Package](#install-scss-utility-and-charts-package)
 - [**Imports**](#imports)
- [Create Line Chart **Component**](#create-line-chart-component)
- [Add a Chart **Wrapper**](#add-a-chart-wrapper)
- [Feed and **Strip Default Chart Styles**](#feed-and-strip-default-chart-styles)
 - [Add the **Data**](#add-the-data)
 - [**Strip** the Chart](#strip-the-chart)
 - [Show Data with **Labels**](#show-data-with-labels)
- [Style the Chart for **Optimized User Interaction**](#style-the-chart-for-optimized-user-interaction)
- [Make it **Pretty**](#make-it-pretty)
 - [**Line and Point** Styling](#line-and-point-styling)
 - [**Tooltip** Styling](#tooltip-styling)
- [**Result**](#result)

*** [Full code here](https://github.com/riapacheco/chart-demo) ***

---

# Create App and Dependencies
### Generate new Angular App
```bash
# terminal
ng new chart-demo --skip-tests
```

When prompted:
```bash
# terminal
? Would you like to add Angular routing? n
? Which stylesheet format would you like to use?
  CSS
> SCSS
  Sass
  Less
```

### Import CommonModule
This module allows us to access and configure directives
```typescript
// app.module.ts
import { CommonModule } from '@angular/common';

imports: [
  ...
  CommonModule
]
```

### Install SCSS Utility and Charts Package

<small>Note: To keep this post as high-level as we can (especially with a robust, enterprise-level framework like Angular) we'll install my [@riapacheco/yutes SCSS package](https://www.npmjs.com/package/@riapacheco/yutes) for its utility configurations and classes. However, we'll visually style the component from scratch.</small>

```bash
# terminal 
npm install @riapacheco/yutes ng2-charts
```

#### @riapacheco/yutes
* Strips webkit styles
* Adds antialiasing / smoothing
* Can access *secret* stylesheet that has "seasonal" colors I like. View colors here (actual variables replace the `--` with `$`): [Click Me](https://xd.adobe.com/view/29870eb2-ae92-4c1f-89de-284afe9c22bc-7cd4/variables/?hints=off%2F)

#### ng2-charts
The package that gives us charts (from `chart.js`)

## Imports
Import the `scss` package into the main `styles.scss` file and add the following global styles (since I clearly have a thing for _dark mode_):
```scss
// styles.scss
@import '~@riapacheco/yutes/main.scss'; // For stripping styles & antialiasing
@import '~@riapacheco/yutes/seasonal.scss'; // To access dark color palette

html, body {
  font-size: 17px;
  background-color: $midnight-dark;
  background-image: linear-gradient(to bottom right, $midnight-dark, $midnight-medium);
  background-attachment: fixed; // The background is fixed relative to the viewport
  color: $steel-regular; // Change text color to an _almost_ white
}
```
Add `NgChartsModule` into `app.module.ts`
```typescript
// app.module.ts
import { NgChartsModule } from 'ng2-charts';

imports: [
  ...
  NgChartsModule
]
```

---

# Create Line Chart Component
Create a `line-chart` component [**Figure 1**] and replace the default content inside your `app.component.html` file with its selector (and some other stuff) [**Figure 2**]:
**Figure 1**
```bash
# terminal
ng g c components/line-chart
```
**Figure 2**
```html
<!--app.component.html-->

<div class="mx-auto-320px pt-3">
  <h6>
    Financial Highlights
  </h6>
  <h1>
    BWX Technologies
  </h1>

  <hr class="mb-2">
  <app-line-chart></app-line-chart>
</div>
```

#### Yutes' Shorthand SCSS Classes
* `mx-auto-320px` sets the width of the div to 320px and centers it horizontally
  (you can replace the `320` value with any # from 1 to 3000)
* `pt-3` adds 3rem of padding to the top of the div
* `mb-2` adds 2rem of margin to the bottom of the `hr` element

Now your locally served app [`ng serve` in your terminal] should look like this (exciting): 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v5kam0wu6ttbn96vhiut.png)

(“Inter” is one of the best fonts of all time)
 
---

# Add a Chart Wrapper
In the `line-chart` component, we're going to create a wrapper that will:

1. Bound the chart to a container that has a restricted width and height
2. Add a colorful background

Add this to the template:
```html
<!-- line-chart.component.html -->
<div class="chart-wrapper">
  <canvas></canvas>
</div>
```

Add the following to its stylesheet:
```scss
// line-chart.component.scss
@import '~@riapacheco/yutes/seasonal.scss'; // get those colors again

$width: 320px;
$height: 250px;

.chart-wrapper {
  width: $width;
  min-width: $width;
  max-width: $width;
  height: $height;
  min-height: $height;
  max-height: $height;
  color: $midnight-dark;
  border-radius: 10px;
  background-image: linear-gradient(to bottom right, $bondi-dark, $bondi-light);
  background-attachment: fixed;
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swxa8lcdokrgn9mczd8j.png)

---

# Add and Bind the Chart
Now we can add the `ng2-chart` element to the app by importing a few types and adding their corresponding properties:
```typescript
// line-chart.component.ts

// ⤵️ import these
import { ChartDataset, ChartOptions } from 'chart.js';
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-line-chart',
  templateUrl: './line-chart.component.html',
  styleUrls: ['./line-chart.component.scss']
})
export class LineChartComponent implements OnInit {
  // ⤵️ add them here
  chartData: ChartDataset[] = [];
  chartLabels: string[] = [];
  chartOptions: ChartOptions = {};
  
  constructor() { }

  ngOnInit(): void {
  }
}
```

And the following to the `line-chart.component.html` file:
```html
<div class="chart-wrapper">
  <canvas baseChart
          [type]="'line'"
    [datasets]="chartData"
    [labels]="chartLabels"
    [options]="chartOptions"
    >
  </canvas>
</div>
```
* `baseChart` and `[type]="'line'"` recognizes the package and specifies the chart type
* The remaining directives (applied to the selector) are how we bind the data from the component. Our component's data being the properties on the right (without `[]`) bound to the properties from the package on the left.

---

# Feed and Strip Default Chart Styles
For our example (which is taken from publicly accessible financials), the chart will display how much revenue BWX Technologies generated each year from 2016 to 2021.

## Add the Data
First, we'll add a label to describe what the chart's values represent (`$ in millions`) followed by a `data` array containing those revenues for each year [6 total].

Add the following to the component:
```typescript
// line-chart.component.ts
// more code
export class LineChartComponent implements OnInit {
  chartData: ChartDataset[] = [
    {
      // ⤵️ Add these
      label: '$ in millions',
      data: [ 1551, 1688, 1800, 1895, 2124, 2124 ]
    }
  ];
  chartLabels: string[] = [];
  chartOptions: ChartOptions = {};
  
  // other code
}
```

The app should look like this:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mduzza03wm9yx4ec9ebl.png)

## Strip the Chart
We'll remove the main label we created and the graph's Y-axis labels (as well as any grid lines making up the chart). Users will be able to find these when hovering over the line graph later.

To remove the above styles, we access the `chartOptions` object and set values for the following properties:

* `responsive` 
  Enables the chart to grow to fill any container it's enclosed in
* `scales`
  Allows us to remove the lines and hidden ticks in the chart
* `plugins`
  To hide the main label we created

Add the following to the `chartOptions` object: 
```typescript
// line-chart.component.ts

// more code

export class LineChartComponent implements OnInit {
  chartData: ChartDataset[] = [
		// code we added earlier
  ];
  chartLabels: string[] = [];
  
  chartOptions: ChartOptions = {
    
    // ⤵️ Fill the wrapper
    responsive: true,
    maintainAspectRatio: false,

    // ⤵️ Remove the grids
    scales: {
      xAxis: {
        display: false,
        grid: {
          drawBorder: false // removes random border at bottom
        }
      },
      yAxis: {
        display: false
      }
    },

    // ⤵️ Remove the main legend
    plugins: {
      legend: {
        display: false
      }
    }
  };
```

Now the chart should look empty like this:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tgzgjjyte3hfb3uacxbv.png)

## Show Data with Labels
To reveal the actual line, add labels like this:
```typescript
// line-chart.component.ts

// more code

export class LineChartComponent implements OnInit {
	// stuff we added earlier
  
  // Add this ⤵️ 
  chartLabels: string[] = [ '2016 Revenue', '2017 Revenue', '2018 Revenue', '2019 Revenue', '2020 Revenue', '2021 Revenue' ];
  
  // more code
}
``` 

Now it should look like this:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mftxrvuus2a03yt59sfk.png)

---

# Style the Chart for Optimized User Interaction
If you hover your cursor over any of the points on the line, it'll reveal a tooltip which includes:

* The year that each point represents
* The main label we removed from the top of the chart earlier; and
* A color label (which isn't really relevant with a single line'd line chart)

![hovering](https://ik.imagekit.io/fuc9k9ckt2b/Blog_Post_Images/Dev_to/hoverBlue_c52aNYZfl.gif?ik-sdk-version=javascript-1.4.3&updatedAt=1656646305136)

Notice how the cursor has to **tightly hover over each point's 1 or 2 pixel radius**. For an improved user experience, we can expand the radius that detects the hover event and increase the width of the targeted point during the event so the user understands *which* data point is in focus.

To do this, add the following to the `chartData` array:
```typescript
// line-chart.component.ts

// more code 

export class LineChartComponent implements OnInit {
  chartData: ChartDataset[] = [
    {
      label: '$ in millions',
      data: [1551, 1688, 1800, 1895, 2124, 2124],

      // ⤵️ Add these
      pointHitRadius: 15, // expands the hover 'detection' area
      pointHoverRadius: 8, // grows the point when hovered
    }
  ];
  
  // other code
}
```

Now it's much easier to navigate and understand:
![bigger hits](https://ik.imagekit.io/fuc9k9ckt2b/Blog_Post_Images/Dev_to/biggerHits_seMENUXXC.gif?ik-sdk-version=javascript-1.4.3&updatedAt=1656646417638)

---

# Make it Pretty
## Line and Point Styling
To configure colors, add the following to the `chartData` array. Read the comments to understand how each value impacts style:
```typescript
// line-chart.component.ts

// more code

export class LineChartComponent implements OnInit {
  chartData: ChartDataset[] = [
    {
      label: '$ in millions',
      data: [1551, 1688, 1800, 1895, 2124, 2124],

      pointHitRadius: 15, // expands the hover 'detection' area
      pointHoverRadius: 8, // grows the point when hovered

      // ⤵️ Add these
      pointRadius: 2,
      borderColor: '#2D2F33', // main line color aka $midnight-medium from @riapacheco/yutes/seasonal.scss
      pointBackgroundColor: '#2D2F33',
      pointHoverBackgroundColor: '#2D2F33',
      borderWidth: 2, // main line width
      hoverBorderWidth: 0, // borders on points
      pointBorderWidth: 0, // removes POINT borders
      tension: 0.3, // makes line more squiggly
    }
  ];
  
  // more code
}
```

## Tooltip Styling
To configure the actual tooltip, add the following to the `chartOptions.plugins` object:
```typescript
// line-chart.component.ts

// more code

export class LineChartComponent implements OnInit {
  
  // more code

  chartOptions: ChartOptions = {
		
    // other code
    
    plugins: {
      legend: {
        display: false
      },

      tooltip: {
        // ⤵️ tooltip main styles
        backgroundColor: 'white',
        displayColors: false, // removes unnecessary legend
        padding: 10,

        // ⤵️ title
        titleColor: '#2D2F33',
        titleFont: {
          size: 18
        },

        // ⤵️ body
        bodyColor: '#2D2F33',
        bodyFont: {
          size: 13
        }
      }
    }
  };
}
```

---

# Result

And here you have it! Though crypto is collapsing, lots of related dashboard UI designs *love* mini top-line indicator charts like this (and still look great despite such poor market performance).
![result](https://ik.imagekit.io/fuc9k9ckt2b/Blog_Post_Images/Dev_to/result_g4F7hak32.gif?ik-sdk-version=javascript-1.4.3&updatedAt=1656646523341)

*** [Full code here](https://github.com/riapacheco/chart-demo) ***