How to Build a Responsive Dashboard Application in Angular - Part 2

In Part 1 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.

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

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

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

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

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

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

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

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

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!

 

comments powered by Disqus