This article will demonstrate how to create charts using Highcharts Library in Angular JS with Web API.
We already know that DotNet Highcharts library is a client-side library for charting and we can create very clean and flexible charts with minimum configuration. Using Highcharts, we can create probably all types of charts which we use in daily life, it could be a line chart, it could be a bar chart or even a column chart.
Charts must be a reusable component in any application so that we can reuse it at different places. That’s why here, we are creating a generic custom directive in AngularJS for charts, which will render different types of charts based on the type of the chart.
In this demonstration, we will use SQL Server for data storage which will be fetched by Web API. At client-side, we are using AngularJS where service fetches the data from API and share with Custom Directive which will responsible to render charts.
This demonstration will cover up three different topics and it seems that if we cover up all topics in single article that will be very long and boring. So, we will divide it in three different parts as following.
- Part 1: Create charts using Highcharts Library and AngularJS custom directive with Web API
- Part 2: Implement Drilldown functionality with charts [Nested charts]
- Part 3: Show loading image/message when rendering the charts
So, let’s move to practical implementation of PART 1 and create charts. To complete this demonstration, there are several tasks which need to be completed.
- TASK 1: Create Database, tables and insert scripts in SQL Server.
- TASK 2: Create Asp.Net MVC application with Web API
- TASK 3: Add Ado.Net Entity Data Model to fetch data from server in API
- TASK 4: Create client side application using Angular JS and implement Highcharts
- TASK 5: Create services and controller to fetch data from API
- TASK 6: Create generic custom directive to render charts
Above is the objective of this article which will be covered step by step as following.
TASK 1 - Create Database tables and insert scripts in SQL Server.
Open SQL Server Management Studio and create a database named “Summit” as well as, two more tables named “Batsmen” and “BatsmenRuns”. These tables will store the data about Top Indian Batsmen’s runs. So, just execute the following scripts to create these two tables and their data.
- CREATE DATABASE Summit
- Go
-
- USE Summit
-
-
-
- CREATE TABLE Batsmen (ID INT PRIMARY KEY IDENTITY(1,1), Name VARCHAR(255) NOT NULL, TotalMatches INT NOT NULL, TotalRuns INT NOT NULL)
-
- INSERT INTO Batsmen (Name,TotalMatches,TotalRuns) VALUES('Sachin Tendulkar',463, 18426);
- INSERT INTO Batsmen (Name,TotalMatches,TotalRuns) VALUES('Yuvraj Singh', 304, 8701 );
- INSERT INTO Batsmen (Name,TotalMatches,TotalRuns) VALUES('M S Dhoni', 306, 9758 );
- INSERT INTO Batsmen (Name,TotalMatches,TotalRuns) VALUES('Rahul Dravid',344, 10889 );
- INSERT INTO Batsmen (Name,TotalMatches,TotalRuns) VALUES('Sourav Ganguly',311, 11363 );
- INSERT INTO Batsmen (Name,TotalMatches,TotalRuns) VALUES('Virender Sehwag',251, 8273);
-
-
-
- CREATE TABLE BatsmenRuns (ID INT PRIMARY KEY IDENTITY(1,1), Name VARCHAR(255) NOT NULL, Year INT NOT NULL, Runs INT NOT NULL)
-
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1989, 0 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1990, 239 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1991, 417 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1992, 704 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1993, 319 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1994, 108 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1995, 444 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1996, 161 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1997, 101 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1998, 189 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',1999, 843 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2000, 132 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2001, 904 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2002, 741 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2003, 114 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2004, 812 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2005, 412 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2006, 628 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2007, 142 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2008, 460 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2009, 972 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2010, 204 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2011, 513 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sachin Tendulkar',2012, 315 );
-
-
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2000,260 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2001,238 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2002,659 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2003,600 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2004,841 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2005,839 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2006,849 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2007,1287)
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2008,893 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2009,783 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2010,349 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2011,453 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2012,2 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2013,276 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Yuvraj Singh',2017,372 );
-
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2004,19 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2005,895 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2006,821 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2007,1103);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2008,1097);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2009,1198);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2010,600 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2011,764 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2012,524 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2013,753 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2014,418 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2015,640 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2016,278 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('M S Dhoni',2017,648 );
-
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',1996,475 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',1997,951 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',1998,283 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',1999,1761);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2000,980 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2001,740 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2002,913 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2003,623 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2004,1025);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2005,1092);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2006,919 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2007,823 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2009,180 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Rahul Dravid',2011,124 );
-
-
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',1992, 3 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',1996, 269 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',1997, 1338);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',1998, 1328);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',1999, 1767);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',2000, 1579);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',2001, 813 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',2002, 1114 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',2003, 756 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',2004, 947 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',2005, 209 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Sourav Ganguly',2007, 1240 );
-
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',1999, 1 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2000, 19 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2001, 439 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2002, 1130);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2003, 871 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2004, 671 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2005, 1017);
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2006, 608 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2007, 475 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2008, 893 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2009, 810 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2010, 446 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2011, 645 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2012, 217 );
- INSERT INTO BatsmenRuns (Name,Year,Runs) VALUES('Virender Sehwag',2013, 31 );
TASK 2 - Create ASP.NET MVC application with Web API
For this demonstration, we are using Visual Studio 2015 but you can use 2013 and 2017 as well. Open Visual Studio 2015 and go to File >> New >> Project. From the installed template, choose Visual C# -> Web -> ASP.NET Web Application. Just add a suitable name and click OK.
The next window will ask to choose the efficient template for the application. So here, we are choosing MVC with Web API with No Authentication.
TASK 3 - Add ADO.NET Entity Data Model to fetch the data from Server in API
Our application is ready, so now, it’s time to implement ADO.NET Entity Data Model for fetching the records from SQL Server from Web API Controller.
From the Solution Explorer, right click on project -> Add -> New Item.
It will open a window as follows. From here, we need to choose ADO.NET Entity Data Model and provide the perfect name and click Add.
Once we click to Add, it will open next window as Wizard where we have to perform several processes to make connection from database. So, from here, just choose EF Designer from Database. Then, click Next.
The next window will ask you to create a new connection with SQL Server. Choose your SQL Server name and database and click Next. It will now give you the list of all tables associated with that database. You have to select both of them which we have created earlier and click Finish.
It will create a data model for tables as below.
Now, we have to create a Web API Controller which will fetch the data. So, to do that, right click on Controllers folder from the solution explorer and Add -> Controller.
We have to choose “Web API 2 Controller – Empty” and click Add. On the next window, just pass the Controller name as “CricketController” and click on "Add" again.
Now, our API Controller is ready. So, you have to add the following code with that Controller.
- using System.Linq;
- using System.Web.Http;
-
- namespace HighchartWithAngularJS.Controllers
- {
- public class CricketController : ApiController
- {
- [Route("Cricket/TopBatsmenInODI")]
- [HttpGet]
- public IHttpActionResult GetTopBatsmenInODI()
- {
- try
- {
- using (var db = new BatsmenEntities())
- {
- var topBatsmenRuns = db.Batsmen.ToList();
- var result = topBatsmenRuns;
- return Ok(result);
- }
- }
- catch (System.Exception)
- {
- throw;
- }
- }
- }
- }
Above, “GetTopBatsmenInODI” action method will get all top Indian batsmen in ODI from the database.
TASK 4 - Create a client-side application using AngularJS and implement Highcharts
Before going to create an AngularJS application, we will install AngularJS and Highcharts from the NuGet Package Manager Console using the following commands.
- Install-Package AngularJS
- Install-Package DotNet.Highcharts
Once you install these client-side libraries with you project, your scripts folder will look like below.
We are done with the data part above and installation also. Now, we have to create a client-side AngularJS application which will implement Highcharts. So, create a folder named as “App” in the same solution and add files as following image shows.
TASK 5 - Create services and controller to fetch data from API
To start with AngularJS application, first, create “app.js” which will create a module for your application. I have given it name as “chartApp”. This name should be defined with ng-app=” chartApp” on _layout.cshtml.
APP.JS
- (function(){
- 'use strict';
-
- var app = angular.module("chartApp", []);
- })();
To get the data from API, we have created ChartSerrvice factory as service which will return the top batsmen's record.
CHARTSERVICE.JS
- (function (app) {
- 'use strict'
-
- app.factory('ChartService', ['$http', ChartService]);
-
- function ChartService($http) {
-
- var getTopBatsmenInODI = function () {
- return $http.get('/Cricket/TopBatsmenInODI');
- };
- return {
- topBatsmenInODI: getTopBatsmenInODI
- }
- };
- })(angular.module("chartApp"));
To fetch the data from service and share with chart, we have to create one “ChartController”. It will get the records and bind with scope variable which will be accessible on UI.
CHARTCONTROLLER.JS
- (function(app){
- 'use strict'
-
- app.controller('ChartController', ['$scope', 'ChartService', ChartController]);
-
- function ChartController($scope, ChartService) {
-
- ChartService.topBatsmenInODI().then(function (response) {
- $scope.TopBatsmenInODIList = response.data;
- });
- };
- })(angular.module("chartApp"));
TASK 6 - Create generic custom directive to render the charts
Before moving to create Chart Custom Directive to render charts, we would like to inform that we are changing the templates dynamically based on type of the chart respectively using the following lines of code.
- templateUrl: function (element, attrs) {
- return "/App/directive/" + attrs.type + 'ChartTemplate.html'
- },
Chart always renders inside the container, so every time, we are changing the container as well.
- chart: {
- type: scope.type,
- renderTo: 'chart_container_' + scope.type
- },
From the UI, we are only passing the type of the chart and data which should be use to populate the series of the charts.
- scope: {
- type: '@',
- data: '='
- },
Following is the whole code to generate charts using Highcharts.
CHARDIRECTIVE.JS
- (function (app) {
- 'use strict'
-
- app.directive('chartDirective', ['$timeout', chartDirective]);
-
- function chartDirective($timeout) {
- return {
- restrict: 'E',
- templateUrl: function (element, attrs) {
- return "/App/directive/" + attrs.type + 'ChartTemplate.html'
- },
- scope: {
- type: '@',
- data: '='
- },
- link: function (scope, element, attribute) {
- scope.chartConfig = new Highcharts.Chart({
- chart: {
- type: scope.type,
- renderTo: 'chart_container_' + scope.type
- },
- title: {
- text: 'Top ODI Batsman in India'
- },
-
- xAxis: {
- type: 'category',
- categories: []
- },
- yAxis: {
- title: {
- text: 'Runs'
- },
- plotLines: [{
- value: 0,
- width: 1,
- color: '#808080'
- }]
- },
- tooltip: {
- valueSuffix: ' Run Scored'
- }
- });
-
- scope.seriesData = [];
- scope.categories = [];
-
- scope.$watch('data', function (newValue) {
- if (newValue != undefined) {
-
- _.forEach(scope.data, function (item) {
- scope.categories.push(item.Name);
- scope.seriesData.push({ name: item.Name, y: item.TotalRuns, drilldown: item.Name });
- });
-
- $timeout(function () {
- scope.chartConfig.addSeries({
- name: 'Top ODI Batsman',
- data: scope.seriesData
- });
-
- }, 2000);
- }
- });
-
- },
- controller: function ($scope, ChartService) {
-
- }
- }
- }
- })(angular.module("chartApp"));
We are using different templates to render charts based on their types. If you would like to add many charts then you will need to create templates as well and also make one entry on Index.cshtml page [Go to below].
LINECAHRTTEMPLATE.HTML
- <div class="col-sm-6">
- <div id="chart_container_line" style="border:5px solid gray;">
- </div>
- </div>
BARCAHRTTEMPLATE.HTML
- <div class="col-sm-6">
- <div id="chart_container_bar" style="border:5px solid gray;">
- </div>
- </div>
COLUMNCAHRTTEMPLATE.HTML
- <div class="col-sm-6">
- <div id="chart_container_column" style="border:5px solid gray;">
- </div>
- </div>
PIECAHRTTEMPLATE.HTML
- <div class="col-sm-6">
- <div id="chart_container_pie" style="border:5px solid gray;">
- </div>
- </div>
The following page renders all the charts. From here, we basically pass its type and data as well. If you are going to add many charts, don’t forget to make entry here.
INDEX.CSHTML
- <div class="jumbotron" align="center">
- <strong>Highcharts with Angular JS and Web API</strong>
- </div>
- <div ng-controller="ChartController">
- <div class="row">
- <chart-directive type="column" data="TopBatsmenInODIList"></chart-directive>
- <chart-directive type="line" data="TopBatsmenInODIList"></chart-directive>
- </div>
- <div class="row">
-
- </div>
- <div class="row">
- <chart-directive type="bar" data="TopBatsmenInODIList"></chart-directive>
- <chart-directive type="pie" data="TopBatsmenInODIList"></chart-directive>
- </div>
- </div>
As we discussed above, _Layout.cshtml file will be used to define your Angular module.
It will also contain all the listed JS files like Service, Controller, App etc.
_LAYOUT.CSHTML
- <!DOCTYPE html>
- <html ng-app="chartApp">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width" />
- <title>@ViewBag.Title</title>
- @Styles.Render("~/Content/css")
- @Scripts.Render("~/bundles/modernizr")
-
- </head>
- <body>
- <div class="navbar navbar-inverse navbar-fixed-top">
- <div class="container">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
- </div>
- <div class="navbar-collapse collapse">
- <ul class="nav navbar-nav">
- <li>@Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)</li>
- <li>@Html.ActionLink("API", "Index", "Help", new { area = "" }, null)</li>
- </ul>
- </div>
- </div>
- </div>
- <div class="container body-content">
- @RenderBody()
- <hr />
- <footer>
- <p>© @DateTime.Now.Year - My ASP.NET Application</p>
- </footer>
- </div>
-
- @Scripts.Render("~/bundles/jquery")
- @Scripts.Render("~/bundles/bootstrap")
- @RenderSection("scripts", required: false)
-
- <script src="~/Scripts/angular.min.js"></script>
-
- <script src="~/Scripts/Highcharts-4.0.1/js/highcharts.js"></script>
- <script src="~/Scripts/Highcharts-4.0.1/js/modules/drilldown.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
-
- <script src="~/App/app.js"></script>
- <script src="~/App/controller/chartController.js"></script>
- <script src="~/App/service/chartService.js"></script>
- <script src="~/App/directive/chartDirective.js"></script>
- </body>
- </html>
Now, everything has been setup, it’s time to run your application. Run and enjoy.
In the next part, we will cover the Highcharts Drilldown functionality.
Conclusion
Today, we have learned how to create charts using Highcharts and AngularJS custom directive and Web API.
I hope this post helps you. Please put your feedback which will help me improve for the next post. If you have any doubts, please ask in the comments section.