How to Build a Responsive Dashboard Application in Angular — Part 2
Tags: webdev, javascript, angular, tutorial
Published: 2022-06-03 19:44:09

---
canonical_url: https://www.grapecity.com/blogs/how-to-build-responsive-dashboard-application-in-angular-part-2
description: In this second part of a new blog series, learn how to build a responsive dashboard application in Angular. See more from Wijmo today.
---

In [Part 1](https://www.grapecity.com/blogs/how-to-build-responsive-dashboard-application-in-angular) of this series, we talked about why dashboards are helpful, went over the type of dashboard that we'll be building, and set up our dashboard application. In this blog, we'll be implementing our information cards at the top of our dashboard and FlexCharts and Gauges that will display information on the number of people visiting our site and how they access it.

### Information Cards and Wijmo Tooltip

Many dashboards display essential information in cards at the top of the page; for sales dashboards, this would typically be information such as deals in the pipeline, conversion percentage, total sales, remaining revenue until the goal, etc. Since our dashboard will be monitoring statistics for users visiting our site, we want to display the number of active sessions, site load time, APDEX score, and bounce rate. Since we're working in Angular, we'll generate a new component in which we'll display our information cards. To do so, run the following command:


```
 ng g c current-info
```

Now that we have our **current-info **component, we can go ahead and add some HTML to the **current-info.component.html **file:

```
    <div class="info-grid">
        <div class="info">
            <div class="info-session-header">ACTIVE SESSIONS (NOW) <i class="bi bi-question-circle" [wjTooltip]="activeSessionTooltip" [wjTooltipPosition]="6"></i></div>
            <div class="info-session-count">{{ activeSession.current }}</div>
            <div class="info-session previous-day">
                <div class="previous-day-count">
                    <div>30 DAYS AGO</div>
                    <div class="previous-day-value">{{ activeSession.previous }}</div>
                </div>
                <div class="previous-day-change">
                    <div class="change-right">CHANGE</div><br>
                    <div class="change-right negative"><i class="bi bi-caret-down-fill"></i>{{ activeSession.change }}</div>
                </div>
            </div>
        </div>
    </div>
```

This will be the code for our **Active Sessions **card. Like with our **app.component.html **file, we're going to organize our four cards using a grid; that will allow us to reorder our cards based on the screen's width, allowing our application to continue to be responsive.

We're implementing many classes here, which I'll touch on some now, but we'll be going over a little further down when we get into the **current-info.component.css **file; the important thing to know is that this will handle the layout of the card. The **info-grid **class will take care of the layout of our cards, the **info **class handles the core styling that we want to be applied to all of the cards, and classes such as **info-session-header **will be used across all of the cards to style each section of the card.

Before we incorporate the rest of our HTML, there's one more thing to point out here; the use of Bootstrap Icons and Wijmo's Tooltip class. If you look at our **<i>** tags, you'll see that we're using a handful of classes on these elements: **bi, bi-question-circle, and bi-caret-down-fill**. The **bi **class is Bootstrap Icons' base class, with **bi-question-circle **and **bi-caret-down-fill **being the actual icons we want to display.

On the same **<i> **element that we're adding the question mark icon, we're also adding a Wijmo Tooltip. The tooltip will serve to display more information on the card when the user hovers the icon. We set the text that we want to display by assigning the variable **activeSessionTooltip **to the **wjTooltip **property and the tooltip's position by setting a numeric value to the **wjTooltipPosition **property. You can see the enum values that you can use to set the property [here](https://www.grapecity.com/wijmo/api/enums/wijmo.popupposition.html).

We're also binding some values that we want to display throughout the card, and this information is stored in the **current-info.component.ts** file. Typically with values like this, you'll be reading them in from a server, but for the purposes of this dashboard, we're simply setting these values within the TypeScript file.

With that said, if you take a look below, you'll see the complete HTML for our **current-info **component, which includes cards for site load time, APDEX score, and bounce rate:

   

```
 <div class="info-grid">
        <div class="info">
            <div class="info-session-header">ACTIVE SESSIONS (NOW) <i class="bi bi-question-circle" [wjTooltip]="activeSessionTooltip" [wjTooltipPosition]="6"></i></div>
            <div class="info-session-count">{{ activeSession.current }}</div>
            <div class="info-session previous-day">
                <div class="previous-day-count">
                    <div>30 DAYS AGO</div>
                    <div class="previous-day-value">{{ activeSession.previous }}</div>
                </div>
                <div class="previous-day-change">
                    <div class="change-right">CHANGE</div><br>
                    <div class="change-right negative"><i class="bi bi-caret-down-fill"></i>{{ activeSession.change }}</div>
                </div>
            </div>
        </div>
        <div class="info">
            <div class="info-session-header">LOAD TIME (NOW) <i class="bi bi-question-circle" [wjTooltip]="loadTimeTooltip" [wjTooltipPosition]="6"></i></div>
            <div class="info-session-count">{{ loadTime.current }}</div>
            <div class="info-session previous-day">
                <div class="previous-day-count">
                    <div>30 DAYS AGO</div>
                    <div class="previous-day-value">{{ loadTime.previous }}</div>
                </div>
                <div class="previous-day-change">
                    <div class="change-right">CHANGE</div><br>
                    <div class="change-right positive"><i class="bi bi-caret-up-fill"></i>{{ loadTime.change }}</div>
                </div>
            </div>
        </div>
        <div class="info">
            <div class="info-session-header">APDEX SCORE (NOW) <i class="bi bi-question-circle" [wjTooltip]="apdexTooltip" [wjTooltipPosition]="6"></i></div>
            <div class="info-session-count">{{ apdexScore.current }}</div>
            <div class="info-session previous-day">
                <div class="previous-day-count">
                    <div>30 DAYS AGO</div>
                    <div class="previous-day-value">{{ apdexScore.previous }}</div>
                </div>
                <div class="previous-day-change">
                    <div class="change-right">CHANGE</div><br>
                    <div class="change-right positive"><i class="bi bi-caret-up-fill"></i>{{ apdexScore.change }}</div>
                </div>
            </div>
        </div>
        <div class="info">
            <div class="info-session-header">BOUNCE RATE (NOW) <i class="bi bi-question-circle" [wjTooltip]="bounceRateTooltip" [wjTooltipPosition]="6"></i></div>
            <div class="info-session-count">{{ bounceRate.current }}</div>
            <div class="info-session previous-day">
                <div class="previous-day-count">
                    <div>30 DAYS AGO</div>
                    <div class="previous-day-value">{{ bounceRate.previous }}</div>
                </div>
                <div class="previous-day-change">
                    <div class="change-right">CHANGE</div><br>
                    <div class="change-right negative"><i class="bi bi-caret-down-fill"></i>{{ bounceRate.change }}</div>
                </div>
            </div>
        </div>
    </div>

```

Next, we'll jump over to the **current-info.component.css **file to go over how we're laying these cards out:

   

```
 .info-grid {
        display: grid;
        grid-auto-columns: 1fr;
        grid-template-areas:
            'one'
            'two'
            'three'
            'four';
        width: 100%;
        margin-inline: auto;
        box-shadow: 2px 2px 2px 2px hsl(0, 0%, 70%);
        background-color: white;
    }

    .info {
        padding: 1rem;
    }

    .info:nth-child(1) {
        grid-area: one;
    }

    .info:nth-child(2) {
        grid-area: two;
    }

    .info:nth-child(3) {
        grid-area: three;
    }

    .info:nth-child(4) {
        grid-area: four;
    }

    .info-session-header {
        font-size: 1.05em;
        color: gray;
    }

    .info-session-count {
        font-size: 2.5em;
        font-weight: 200;
    }

    .previous-day {
        display: grid;
        grid-auto-columns: 1fr;
        grid-template-areas: 'one two';
        color: gray;
    }

    .previous-day-value {
        color: black;
        font-weight: bold;
    }

    .change-right {
        float: right;
    }

    .caret {
        width: 0;
        height: 0;
        display: inline-block;
        border: 9px solid transparent;
    }

    .positive {
        color: green;
    }

    .negative {
        color: red;
    }

    @media (max-width: 799px) {
        .info:nth-child(1) {
            border-bottom: 1px lightgray solid;
        }

        .info:nth-child(2) {
            border-bottom: 1px lightgray solid;
        }

        .info:nth-child(3) {
            border-bottom: 1px lightgray solid;
        }
    }

    @media (min-width: 800px) {
        .info-grid {
            grid-template-areas:
                'one two'
                'three four';
        }

        .info:nth-child(1) {
            border-bottom: 1px lightgray solid;
            border-right: 1px lightgray solid;
        }

        .info:nth-child(2) {
            border-bottom: 1px lightgray solid;
        }

        .info:nth-child(3) {
            border-right: 1px lightgray solid;
        }
    }

    @media (min-width: 1200px) {
        .info-grid {
            grid-template-areas:
                'one two three four';
        }

        .info:nth-child(1) {
            border-right: 1px lightgray solid;
        }

        .info:nth-child(2) {
            border-right: 1px lightgray solid;
        }

        .info:nth-child(3) {
            border-right: 1px lightgray solid;
        }
    }
```

As you may notice, a lot of this CSS looks very similar to the CSS that handles the dashboard layout; the cards are getting laid out using a grid, and we're assigning each card a **grid-area** value that we can use to position them within the grid. We're also defining some width parameters that will handle the card layout based on the size of the screen.

The last thing to touch on with the CSS is that at the bottom of the cards, we're showing the statistics of each card from 30 days ago, using CSS to color the stats red if we've seen a drop over the last month, and green if we've seen an increase. The previous-day and previous-day-value class handle this.

Before we run the app, we'll hop over to the **current-info.component.ts **file to take a look at the data that we're loading into the component:

 

```
   import { Component, OnInit } from '@angular/core';

    @Component({
      selector: 'app-current-info',
      templateUrl: './current-info.component.html',
      styleUrls: ['./current-info.component.css']
    })
    export class CurrentInfoComponent implements OnInit {
      activeSessionTooltip = 'Number of current active sessions.';
      loadTimeTooltip = 'Current average loadtime of the site.';
      apdexTooltip = 'Ratio of tolerating requests to total requests made.';
      bounceRateTooltip = 'Percentage of visitors who enter and then leave the site.';

      activeSession = { current: 112, previous: 148, change: '24.32%' };
      loadTime = { current: '2.08s', previous: '1.7s', change: '18.30%' };
      apdexScore = { current: '1.00', previous: '0.96', change: '4.17%' };
      bounceRate = { current: '10.2%', previous: '16.4%', change: '37.8%' }

      constructor() { }

      ngOnInit(): void {
      }

    }

```

This is very standard TypeScript; we're merely creating some data that we want to display in each card and defining the text we want to display in each of the tooltips.

When we run the application, we'll see the following:

![Info Cards](https://files.grapecity.com/gc-website-media/bomkymjo/01-infocards.jpg?width=500&height=73.35448057097541)

And if a user hovers over one of the question mark icons, they'll see a Wijmo Tooltip displaying some more information on the card:

![Info Card Tip](https://files.grapecity.com/gc-website-media/mc3dzqeg/02-infocardtip.jpg?width=403&height=187)

### Session Statistics and FlexChart

The following section that we will cover is incorporating FlexChart into our dashboard to show users' session statistics. To do so, we're going to create three new components, using the following commands:

```
    ng g c session-info
    ng g c top-platform-info
    ng g c top-browser
```

The **session-info **component will display information about the number of total sessions, **top-platform-info **will give us information based on what types of devices our users are using to visit our site, and the **top-browser **will display information based on the different browsers that our users are using to access the site. The first component that we'll be going over is the **session-info **component:

  

```
  <div class="sessions-container">
        <div class="sessions-info">
            <div class="session-header">SESSIONS <i class="bi bi-question-circle" [wjTooltip]="sessionTooltip" [wjTooltipPosition]="6"></i></div>
        </div>
        <div class="sessions-info">
            <div class="session-total">
                <div class="session-total-value">
                    {{ totalSessions }}
                </div>
                <div class="session-total-annotation">
                    IN TOTAL
                </div>
            </div>
            <wj-flex-pie class="session-chart" [itemsSource]="data" [bindingName]="'sessions'" [binding]="'number'" [innerRadius]="0.85" [palette]="['rgba(50, 50, 255, 1)', 'rgb(0, 200, 200, 1)']" style="margin-left: auto; margin-right: auto;">
                <wj-flex-chart-legend [position]="'None'"></wj-flex-chart-legend>
            </wj-flex-pie>
        </div>
        <div class="sessions-info sessions-breakdown">
            <div style="display: flex; justify-content: space-between">
                <div>NEW</div><div>RETURNING</div>
            </div>
            <div style="display: flex; justify-content: space-between">
                <div class="session-value-bg">{{data[0].number}}</div><div class="session-value-bg">{{ data[1].number }}</div>
            </div>
            <hr>
            <div>AVERAGE PAGEVIEWS/SESSION</div>
            <div style="display: flex; justify-content: space-between">
                <div class="session-value-bg">{{ pageViews.value }}</div><div class="session-value-sm"><i class="bi bi-caret-up-fill positive"></i>{{ pageViews.change }}</div>
            </div>
            <hr>
            <div>AVERAGE SESSION DURATION</div>
            <div style="display: flex; justify-content: space-between">
                <div class="session-value-bg">{{ sessions.value }}</div><div class="session-value-sm"><i class="bi bi-caret-up-fill positive"></i>{{ sessions.change }}</div>
            </div>
        </div>
    </div>
```

The HTML for this component is straightforward: We've got our card header, the Bootstrap Icon with the Wijmo Tooltip attached, and the base of the card we're displaying the statistics and formatting it with flexboxes. However, the portion of this component that we want to focus on is the Wijmo FlexPie that we're incorporating.

Wijmo's FlexPie is a very powerful component that we can implement with just a few lines of HTML. At its core, all we need to pass to it for it to function is a data source (which we tie to the **itemsSource **property), a binding value which we tie to the **binding **property, and a name-value which we tie to the **bindingName** property. To add a little bit more style to the control, we're setting an inner radius for the FlexPie chart so that we can display some more information in the center, as well as setting a custom palette (for this chart, we're using cyan and royal blue as our two palette colors). The last thing that we'll do is center the control horizontally in the control so that everything lines up nicely.

Before we jump to the CSS, we'll take a look at the **session-info.component.ts **file to get a look at our data:

  

```
  import { Component, OnInit } from '@angular/core';
    import { DataService } from '../data.service';

    @Component({
      selector: 'app-session-info',
      templateUrl: './session-info.component.html',
      styleUrls: ['./session-info.component.css']
    })
    export class SessionInfoComponent implements OnInit {
      data: any[];
      sessionTooltip = 'User sessions breakdown.';
      pageViews = { value: 3.54, change: '12.26%' };
      sessions = { value: '4m 41s', change: '9.38%' };
      totalSessions = '111.9k';

      constructor(private dataService: DataService) {
        this.data = dataService.getSessionData();
      }

      ngOnInit(): void {
      }

    }
```

Here, we're just creating some mock data to display in the card, and we're also calling a data service to get the data for our FlexPie control. If we hop over to our **data.service.ts **file and take a look at the **getSessionData()** method, we'll see the data that we're sending over:  

```
 sessionData = [
        { sessions: 'New Users', number: 49120 },
        { sessions: 'Returning Users', number: 62780 }
    ];

    getSessionData() {
        return this.sessionData;
    }
```

We're simply returning an array of objects, and we'll use this to populate our control. For simplicity's sake, our application is just creating some mock data; in your dashboard, you'll more than likely be calling an API to get data from a server.

Now that we have our HTML and we've seen the data that we'll be using, we'll hop over to the **session-info.component.css **file to look at the little bit of styling that we're doing:

 

```
   .sessions-container {
        padding: 1rem;
    }

    .session-header {
        font-size: 1.05em;
        color: gray;
    }

    .sessions-info {
        position: relative;
    }

    .session-chart {
        border: none;
        height: 200px;
        width: 200px;
    }

    .session-total {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        text-align: center;
    }

    .session-total-value {
        font-size: 2em;
    }

    .session-total-annotation {
        font-size: 1em;
        font-weight: 600;
        color: gray;
    }

    .sessions-breakdown {
        color: gray;
    }

    .session-value-bg {
        color: black;
        font-weight: 500;
        font-size: 1.75rem;
    }

    .session-value-sm {
        padding-top: 0.75em;
    }

    .positive {
        color: green;
    }
```

Here, we're only setting some padding on the different divs so that everything is spaced out correctly, using some positioning to center some of our statistics in the center of our FlexPie control, and adding some coloring so that the numbers in the component stand out. When we run our application, the **sessions-info **component will look like this:

![Sessions](https://files.grapecity.com/gc-website-media/gi3boqx4/03-sessions.png?width=400.76335877862596&height=500)

Now that the sessions section of the dashboard is finished, we'll implement our "Top Platforms" and "Top Browsers" cards; these dashboard cards will both function identically but display different data.

First, we'll go over the "Top Platforms" card:

```
    <div class="platforms-container">
        <div class="platforms-header">TOP PLATFORMS <i class="bi bi-question-circle" [wjTooltip]="platformTooltip" [wjTooltipPosition]="6"></i></div>
        <div class="platforms-info">
            <wj-flex-chart [header]="'Average Load Time'" [bindingX]="'platform'" [selectionMode]="'Point'" [itemsSource]="loadTimeData" [palette]="palette">
                <wj-flex-chart-legend [position]="'None'"></wj-flex-chart-legend>
                <wj-flex-chart-series [name]="'Previous Month'" [binding]="'prevMonth'"></wj-flex-chart-series>
                <wj-flex-chart-series [name]="'Current Month'" [binding]="'curMonth'"></wj-flex-chart-series>
            </wj-flex-chart>
            <wj-flex-pie [header]="'Sessions by Platform'" [bindingName]="'platform'" [binding]="'sessions'" [itemsSource]="sessionData" [palette]="palette"></wj-flex-pie>
        </div>
    </div>
```

You’ll notice here is that we have significantly less HTML than any of the other cards that we've built so far. That speaks to how easy it is to use not just Wijmo's FlexChart controls but all of Wijmo's controls. We're incorporating another Wijmo Tooltip in the card's header, and we're also implementing 2 FlexCharts in this card: FlexChart's bar chart and a FlexPie chart.

As you can see, all we have to do is set a handful of properties. For the FlexPie, we're setting the same properties, sans innerRadius, as we did in our "Sessions" card. We're setting the itemsSource property, the palette property, and our x-axis binding with the bindingX property for the bar chart. We're also adding a legend to the chart and the different series that we want to show. In the case of this bar chart, we want to display information on both the current month and the previous month.

Now that we have the HTML implemented, we'll jump over to our **top-platform-info.component.ts **file and the **data.service.ts **file to see the data that we're binding:

 

```
   import { Component, OnInit } from '@angular/core';
    import { DataService } from '../data.service';

    import * as wjChart from '@grapecity/wijmo.chart';

    @Component({
      selector: 'app-top-platform-info',
      templateUrl: './top-platform-info.component.html',
      styleUrls: ['./top-platform-info.component.css']
    })
    export class TopPlatformInfoComponent implements OnInit {
      loadTimeData: any[];
      sessionData: any[];
      platformTooltip = 'Breakdown of sessions by platform.';
      palette = wjChart.Palettes.darkly;

      constructor(private dataService: DataService) {
        this.loadTimeData = dataService.getPlatformLoadTimeData();
        this.sessionData = dataService.getPlatformSessionData();
      }

      ngOnInit(): void {
      }

    }

```

In this file, we're setting the tooltip text that we want to display, setting our palette, and calling our data service to get the data for our two charts:

  

```
  platformLoadTimeData = [
        { platform: 'Desktop', prevMonth: 1.58, curMonth: 1.49 },
        { platform: 'Phone', prevMonth: 2.01, curMonth: 1.96 },
        { platform: 'Tablet', prevMonth: 2.16, curMonth: 2.41 },
        { platform: 'Other', prevMonth: 2.53, curMonth: 2.65 }
    ];

    platformSessionData = [
        { platform: 'Desktop', sessions: 68379 },
        { platform: 'Phone', sessions: 21478 },
        { platform: 'Tablet', sessions: 14523 },
        { platform: 'Other', sessions: 7520 }
    ];

    getPlatformLoadTimeData() {
        return this.platformLoadTimeData;
    }

    getPlatformSessionData() {
        return this.platformSessionData;
    }

```

Like the last time we referenced pulling data from the data service, we're using mock data in our dashboard, but you'll most likely be calling an API to get data from a database. In our dashboard, we're displaying the load time for each platform (desktop, phone, tablet, and other) and the number of sessions by each platform.

Finally, we need to implement our CSS:

 

```
   .platforms-container {
        padding: 1rem;
    }

    .platforms-header {
        font-size: 1.05em;
        color: gray;
    }

    .platforms-info {
        display: flex;
        flex-direction: row;
        justify-content: space-evenly;
    }

    .wj-flexchart {
        height: 300px;
        border: none;
        width: 50%;
    }

    @media (max-width: 799px) {
        .platforms-info {
            flex-direction: column;
        }

        .wj-flexchart {
            width: 100%;
        }
    }
```

The CSS for this component handles the padding that we use around the edge of the card and how we display the data based on the screen width. When the screen gets smaller, we switch from a horizontal layout of the two charts we're displaying to a vertical layout.

When we run the application, you'll see the following:

![Chart Sample](https://files.grapecity.com/gc-website-media/dhpfa03s/04-chartssample.png?width=500&height=189.51612903225805)

If you hover over any parts of these two charts, the chart will then display a popup that shows the data that is being visually represented:

![Chart Tooltip](https://files.grapecity.com/gc-website-media/w3qmyfhv/05-charttooltip.png?width=500&height=197.0217640320733)

Moving on to the **top-browser **component, this component functions essentially identically to the **top-platform-info **component. The controls and CSS layout are the same; the only different thing is the data that will be passed to the control. You can see the code for all of the different files down below:

**top-browser.component.html**

```
    <div class="browsers-container">
        <div class="browsers-header">TOP BROWSERS <i class="bi bi-question-circle" [wjTooltip]="browserTooltip" [wjTooltipPosition]="6"></i></div>
        <div class="browsers-info">
            <wj-flex-chart [header]="'Average Load Time'" [bindingX]="'browser'" [selectionMode]="'Point'" [itemsSource]="loadTimeData" [palette]="palette">
                <wj-flex-chart-legend [position]="'None'"></wj-flex-chart-legend>
                <wj-flex-chart-series [name]="'Previous Month'" [binding]="'prevMonth'"></wj-flex-chart-series>
                <wj-flex-chart-series [name]="'Current Month'" [binding]="'curMonth'"></wj-flex-chart-series>
            </wj-flex-chart>
            <wj-flex-pie [header]="'Sessions by Browser'" [bindingName]="'browser'" [binding]="'sessions'" [itemsSource]="sessionData" [palette]="palette"></wj-flex-pie>
        </div>
    </div>
```

**top-browser.component.ts**

  

```
  import { Component, OnInit } from '@angular/core';
    import { DataService } from '../data.service';

    import * as wjChart from '@grapecity/wijmo.chart';

    @Component({
      selector: 'app-top-browser',
      templateUrl: './top-browser.component.html',
      styleUrls: ['./top-browser.component.css']
    })
    export class TopBrowserComponent implements OnInit {
      loadTimeData: any[];
      sessionData: any[];
      browserTooltip = 'Breakdown of sessions by browser.';
      palette = wjChart.Palettes.darkly;

      constructor(private dataService: DataService) {
        this.loadTimeData = dataService.getBrowserLoadTimeData();
        this.sessionData = dataService.getBrowserSessionData();
      }

      ngOnInit(): void {
      }
    }
```

**top-browser.component.css**

 

```
   .browsers-container {
        padding: 1rem;
    }

    .browsers-header {
        font-size: 1.05em;
        color: gray;
    }

    .browsers-info {
        display: flex;
        flex-direction: row;
        justify-content: space-evenly;
    }

    .wj-flexchart {
        height: 300px;
        border: none;
        width: 50%;
    }

    @media (max-width: 799px) {
        .browsers-info {
            flex-direction: column;
        }

        .wj-flexchart {
            width: 100%;
        }
    }
```

**data.service.ts**

 

```
   browserLoadTimeData = [
        { browser: 'Chrome', prevMonth: 1.68, curMonth: 1.52 },
        { browser: 'Firefox', prevMonth: 1.93, curMonth: 1.71 },
        { browser: 'Edge', prevMonth: 2.25, curMonth: 2.38 },
        { browser: 'Safari', prevMonth: 2.11, curMonth: 2.03 },
        { browser: 'Other', prevMonth: 2.56, curMonth: 2.49 }
    ];

    browserSessionData = [
        { browser: 'Chrome', sessions: 34520 },
        { browser: 'Firefox', sessions: 29586 },
        { browser: 'Edge', sessions: 13793 },
        { browser: 'Safari', sessions: 22136 },
        { browser: 'Other', sessions: 11865 }
    ];

    getBrowserLoadTimeData() {
        return this.browserLoadTimeData;
    }

    getBrowserSessionData() {
        return this.browserSessionData;
    }
```

When you run the application, you'll now see the card with data populated for browser session data:

![Browser Chart](https://files.grapecity.com/gc-website-media/0rsdpu2d/06-browserchart.png?width=500&height=195.1501154734411)

### Country Sessions and Linear Gauge

The final piece of the dashboard that we'll be building in this article will be the card that displays the top countries by session, taking advantage of Wijmo's Linear Gauge control. The first thing that we'll need to do is generate the component that displays the card, along with the data that goes along with it: 

```
   ng g c top-country-info
```

Now, we'll jump into our **top-country-info.component.html **file to implement our HTML:

```
    <div class="top-countries">
        <div class="countries">
            <div class="countries-header">TOP COUNTRIES BY SESSION <i class="bi bi-question-circle" [wjTooltip]="countrySessionTooltip" [wjTooltipPosition]="6"></i></div>
        </div>
        <div class="countries countries-list">
            <div *ngFor="let country of countryData" class="country-item">
                <div><b>{{ country.name }}</b></div>
                <div>Total Visits: {{ country.visits }}k</div>
                <div>Percentage: {{ country.percentage }}%</div>
                <div class="country-subtotal-gauge">
                    <wj-linear-gauge #theGauge [isReadOnly]="true" [min]="0" [max]="maxVisits" [value]="country.visits" [showRanges]="false">
                    </wj-linear-gauge>
                </div>
            </div>
        </div>
    </div>
```

Like with all our other cards, at the top, we'll create a header, use Bootstrap Icon to add our tooltip icon and tie a Wijmo Tooltip to the icon. We'll also iterate through the top 10 countries based on views, displaying the total number of visitors, the percentage of visitors in relation to the total number of visitors to our site, and Wijmo's Linear Gauge to give a visual representation of the percentage.

As you can see, Wijmo's Linear Gauge is simply a single line of markup, where we set the control to read-only using the **isReadOnly **properties, setting a **min **and **max **value (where the max value is the number of visitors from the most-visited country), and the value of visitors for that country.

We'll now jump over to the **top-country-info.component.ts **file so we can see the data that we're getting for the Linear Gauge control:

 

```
   import { Component, OnInit } from '@angular/core';

    @Component({
      selector: 'app-top-country-info',
      templateUrl: './top-country-info.component.html',
      styleUrls: ['./top-country-info.component.css']
    })
    export class TopCountryInfoComponent implements OnInit {
      countryData = [
        { name: 'United States', visits: 21.9, percentage: 19.7 },
        { name: 'Japan', visits: 13.8, percentage: 12.4 },
        { name: 'Canada', visits: 12.7, percentage: 11.4 },
        { name: 'China', visits: 11.3, percentage: 10.2 },
        { name: 'United Kingdom', visits: 7.9, percentage: 7.1 },
        { name: 'Russia', visits: 5.9, percentage: 5.3 },
        { name: 'Germany', visits: 5.9, percentage: 5.3 },
        { name: 'Mexico', visits: 4.2, percentage: 3.8 },
        { name: 'France', visits: 3.4, percentage: 3.1 },
        { name: 'Ukraine', visits: 3.1, percentage: 2.8 }
      ];
      maxVisits = 21.9;
      countrySessionTooltip = 'Displays the top 10 countries by # of sessions.';

      constructor() { }

      ngOnInit(): void {
      }
    }
```

In this file, we're just creating some mock data to pass into the HTML file. We're also setting the **maxVisits **variable to the same number as the country with the most visits to help the controls look clean and have a better visual representation of the number of visitors of each country. We're also setting the tooltip text in the file.

Finally, we'll look at the **top-country-info.component.css **file to see how we're laying out the card:

 

```
   .top-countries {
        width: 100%;
        margin-inline: auto;
        box-shadow: 2px 2px 2px 2px hsl(0, 0%, 70%);
        background-color: white;
        padding: 1rem;
        height: 550px;
    }

    .countries-header {
        font-size: 1.05em;
        color: gray;
    }

    .countries-list {
        height: 95%;
        max-height: 95%;
        overflow-y: scroll;
        padding-right: 10px;
    }

    .country-item {
        margin-top: 1em;
    }

```

Here, we’re setting some style for the card (the same as the other cards in our dashboard) and some padding around the controls and text that we're displaying.

Now, when you run the application, you'll see the following card being displayed:

![Gauge](https://files.grapecity.com/gc-website-media/mcahv13l/07-gauge.jpg?width=389&height=431)

Now that we've got all the cards that we've been working on in this article implemented, we need to add all of the components to our **app.component.html **file:

```
    <main class="livemap-grid">
      <div class="livemap load-info">
        <app-current-info></app-current-info>
      </div>
      <div class="livemap map">
      </div>
      <div class="livemap user-info">
      </div>
      <div class="livemap sessions">
        <app-session-info></app-session-info>
      </div>
      <div class="livemap issue-info">
      </div>
      <div class="livemap top-countries">
        <app-top-country-info></app-top-country-info>
      </div>
      <div class="livemap top-platforms">
        <app-top-platform-info></app-top-platform-info>
      </div>
      <div class="livemap browsers">
        <app-top-browser></app-top-browser>
      </div>
    </main>
```

When we run our application, and we zoom out and take a look at the entire dashboard, here's what we see:

![Wijmo Map Live](https://files.grapecity.com/gc-website-media/cvpkjosi/08-wijmolivemap.png?width=395.6340956340956&height=500)

The dashboard is coming along nicely! In the next article, we'll be covering the implementation of Wijmo's FlexMap control, Wijmo's FlexGrid control, and how we can tie both together to create an interactive and responsive map/grid combination. See you there!