How to create a dashboard UI using Anychart.js?

JavascriptProgramming ScriptsWeb Development

AnyChart.js is a JavaScript library that is used when we want to create charts, UI components, and much more. In this tutorial, we will take an example to show how you can create a dashboard UI using Anychart. This dashboard will represent the sales done by a company based on regions, devices and attributes with three bar graphs and a single chart with lines.

Since the code might be too overwhelming for some, I will split the code into different sections and will explain those sections in detail before moving on to the final example.

Generating the Data for the Dashboard

The first step is to create a simple "index.html" file in a directory in which we will write our code. Once we do that, the next step is to start generating the data that is required for the dashboard.

generateData()

Consider the function named generateData() shown below in which we are creating the necessary data that is required by the dashboard.

function generateData() {
   let data = [];
   let dates = [
      Date.UTC(2021, 0, 1), Date.UTC(2021, 1, 1),
      Date.UTC(2021, 2, 1), Date.UTC(2021, 3, 1),
      Date.UTC(2021, 4, 1), Date.UTC(2021, 5, 1),
      Date.UTC(2021, 6, 1), Date.UTC(2021, 7, 1),
      Date.UTC(2021, 8, 1), Date.UTC(2021, 9, 1),
      Date.UTC(2021, 10, 1), Date.UTC(2021, 11, 1) ];
   let territories = ['Europe','Asia Pacific','USA and Canada','Australia'];
   let platforms = ['iPhone', 'iPad', 'Macbooks'];
   let categories = ['Games', 'Social Networking', 'Photo & Video', 'Coding'];
   let monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
   
   for (let d = 0, datesCount = dates.length; d < datesCount; d++) {
      for ( let t=0 , territoriesCount=t erritories.length; t < territoriesCount; t++ ) {
         for ( let p=0 , platformsCount=p latforms.length; p < platformsCount; p++ ) {
            for ( let c=0 , categoriesCount=c ategories.length; c < categoriesCount; c++ ) {
               let date=n ew Date(dates[d]);
               data.push({
                  x: monthNames[date.getMonth()],
                  value: Math.floor(Math.random() * 100 + 1),
                  region: territories[t],
                  device: platforms[p],
                  category: categories[c] });
               }
            }
         }
      }
      return data;
   }  
}

Updating the Data

Now that we have generated the data it's time to use it. We will be iterating over the generated data inside a function called updateData().

updateData()

Consider the updateData() function shown below.

function updateData() {
   let hoverBarsSeriesColor = '#ffd54f';
   let unitMap = {};
   let territoryMap = {};
   let platformMap = {};
   let categoryMap = {};
   
   if (!(regionFilter || deviceFilter || categoryFilter)) {
      titleFilter = 'to filter click on bar charts below';
   } else {
      titleFilter = '';
      if (regionFilter) titleFilter = 'in ' + regionFilter + ' ';
      if (deviceFilter) {
         titleFilter = titleFilter + 'on ' + deviceFilter + ' ';
      }
      if (categoryFilter) {
         titleFilter = titleFilter + 'in category "' + categoryFilter + '"';
      }
   }
   unitsTitle.text('Income per Month<br><span style="color:#929292; font-size:12px;">(' + titleFilter +')</span>');
      for (let i = 0, count = rawData.length; i < count; i++) {
         let dataItem = rawData[i];
         let fitTerritoryFilter = !regionFilter || (regionFilter && regionFilter === dataItem.region);
         let fitPlatformFilter = !deviceFilter || (deviceFilter && deviceFilter === dataItem.device);
         let fitCategoryFilter = !categoryFilter ||
         (categoryFilter && categoryFilter === dataItem.category);
         if (fitTerritoryFilter && fitPlatformFilter && fitCategoryFilter) {
            let unitsMapItem = unitMap[dataItem.x];
            if (unitsMapItem) {
               unitMap[dataItem.x] = [
                  dataItem.x,
                  unitsMapItem[1] + dataItem.value
               ];
            } else {
               unitMap[dataItem.x] = [dataItem.x, dataItem.value];
            }
         }
         if (fitPlatformFilter && fitCategoryFilter) {
            let territoryMapItem = territoryMap[dataItem.region];
            if (territoryMapItem) {
               territoryMapItem.value += dataItem.value;
            } else {
               territoryMapItem = {
                  x: dataItem.region,
                  value: dataItem.value
               };
               territoryMap[dataItem.region] = territoryMapItem;
            }
            territoryMapItem.fill =
               territoryMapItem.x === regionFilter ?
               hoverBarsSeriesColor :
               undefined;
            territoryMapItem.stroke =
               territoryMapItem.x === regionFilter ?
               anychart.color.darken(hoverBarsSeriesColor) :
               undefined;
         }
         if (fitTerritoryFilter && fitCategoryFilter) {
            let platformMapItem = platformMap[dataItem.device];
            if (platformMapItem) {
               platformMapItem.value += dataItem.value;
            } else {
               platformMapItem = {
                  x: dataItem.device,
                  value: dataItem.value
            };
            platformMap[dataItem.device] = platformMapItem;
         }
         platformMapItem.fill =
            platformMapItem.x === deviceFilter ?
            hoverBarsSeriesColor :
            undefined;
         platformMapItem.stroke =
            platformMapItem.x === deviceFilter ?
            anychart.color.darken(hoverBarsSeriesColor) :
            undefined;
      }
      if (fitTerritoryFilter && fitPlatformFilter) {
         let categoryMapItem = categoryMap[dataItem.category];
         if (categoryMapItem) {
            categoryMapItem += dataItem.value;
         } else {
         categoryMapItem = {
            x: dataItem.category,
            value: dataItem.value
         };
         categoryMap[dataItem.category] = categoryMapItem;
      }
      categoryMapItem.fill =
         categoryMapItem.x === categoryFilter ?
         hoverBarsSeriesColor :
         undefined;
      categoryMapItem.stroke =
         categoryMapItem.x === categoryFilter ?
         anychart.color.darken(hoverBarsSeriesColor) :
         undefined;
      }
   }
   let territoryData = getValues(territoryMap);
   let platformData = getValues(platformMap);
   let categoryData = getValues(categoryMap);
   let unitData = getValues(unitMap);
   regionSeries.data(territoryData);
   deviceSeries.data(platformData);
   categorySeries.data(categoryData);
   unitSeries.data(unitData);
}

Settings for the Bar Graph

Now we need to write the bar settings for the bar graph. Consider the code snippet shown below that creates the bar settings.

setupBarSeriesSettings()

function setupBarSeriesSettings(series) {
   series.tooltip().titleFormat(function () {
      return this.x;
   });
   series.tooltip().format(function () {
      return '$' + formatMoney(this.value, 0, '.', ',');
   });
   series.listen('pointClick', function (e) {
      let series = e.target;
      let seriesName = series.name();
      let categoryName = e.iterator.get('x');
      switch (seriesName) {
         case 'regions':
            regionFilter =
               regionFilter && regionFilter === categoryName ?
               null :
               categoryName;
            break;
         case 'devices':
            deviceFilter =
               deviceFilter && deviceFilter === categoryName ?
               null :
               categoryName;
            break;
         case 'categories':
            categoryFilter =
               categoryFilter && categoryFilter ===
               categoryName ?
               null :
               categoryName;
            break;
         default:
      }
      updateData();
   });
}

Now some utility functions are left and our Dashboard UI is completed.

Let's Assemble Everything

Let's put the entire code in a single index.html file. Consider the entire code shown below.

Example

index.html

<html> <head> <script src="https://cdn.anychart.com/releases/v8/js/anychart-base.min.js"></script> <script src="https://cdn.anychart.com/releases/v8/js/anychart-ui.min.js"></script> <script src="https://cdn.anychart.com/releases/v8/js/anychart-exports.min.js"></script> <script src="https://cdn.anychart.com/releases/v8/js/anychart-table.min.js"></script> <link href="https://cdn.anychart.com/releases/v8/css/anychart-ui.min.css" type="text/css" rel="stylesheet"> <link href="https://cdn.anychart.com/releases/v8/fonts/css/anychart-font.min.css" type="text/css" rel="stylesheet"> <style type="text/css"> html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="container"></div> <script> // Filters let regionFilter = null; let deviceFilter = null; let categoryFilter = null; // Charting objects let unitsChart = null; let regionChart = null; let deviceChart = null; let categoryChart = null; let unitSeries = null; let regionSeries = null; let deviceSeries = null; let categorySeries = null; let unitsTitle = null; let titleFilter = 'to filter click on bar charts below'; // Raw dashboard data, see data format in the end of the file let rawData = generateData(); anychart.onDocumentReady(function() { function unitsSoldChart() { let chart = anychart.area(); chart.padding(15, 0, 0, 0); // Set chart title text unitsTitle = chart .title() .useHtml(true) .hAlign('center') .enabled(true); unitsTitle.text( 'Income per Month<br><span style="color:#929292; font-size: 12px;">(' + titleFilter + ')</span>' ); // Create xAxis let xAxis = chart.xAxis(); xAxis.title(false); xAxis.staggerMode(false); chart .yAxis() .labels() .format(function() { return formatMoney(parseInt(this.value), 0, '.', ','); }); // Create area series unitSeries = chart.area(); unitSeries.tooltip().titleFormat(function() { return this.x; }); unitSeries.tooltip().format(function() { return '$' + formatMoney(this.value, 0, '.', ','); }); return chart; } // Create Units sold chart, Area unitsChart = unitsSoldChart(); function filterBarChart() { let chart = anychart.bar(); chart.title().enabled(true).fontSize(14); chart.padding(35, 5, 0, 5); chart.yAxis().enabled(false); return chart; } // Create filter bar chart by regions regionChart = filterBarChart(); regionChart.title().text('Sales by Region'); regionSeries = regionChart.bar(); regionSeries.name('regions'); setupBarSeriesSettings(regionSeries); // Create filter bar chart by device type deviceChart = filterBarChart(); deviceChart.title().text('Sales by Device Type'); deviceSeries = deviceChart.bar(); deviceSeries.name('devices'); setupBarSeriesSettings(deviceSeries); // Create filter bar chart by device type categoryChart = filterBarChart(); categoryChart.title().text('Sales by Category'); categorySeries = categoryChart.bar(); categorySeries.name('categories'); setupBarSeriesSettings(categorySeries); updateData(); let layoutTable = anychart.standalones.table(4, 5); layoutTable.cellBorder(null); layoutTable.getCol(0).width('2.5%'); layoutTable.getCol(4).width('2.5%'); layoutTable.getRow(0).height(40); layoutTable.getRow(2).height('35%'); layoutTable.getRow(3).height(20); layoutTable .getCell(0, 1) .colSpan(3) .content('Sales Dashboard') .hAlign('center') .vAlign('bottom') .fontSize(18) .fontColor('#212121'); layoutTable.getCell(1, 1).colSpan(3).content(unitsChart); layoutTable.getCell(2, 1).content(regionChart); layoutTable.getCell(2, 2).content(deviceChart); layoutTable.getCell(2, 3).content(categoryChart); layoutTable.container('container'); layoutTable.draw(); }); function setupBarSeriesSettings(series) { series.tooltip().titleFormat(function() { return this.x; }); series.tooltip().format(function() { return '$' + formatMoney(this.value, 0, '.', ','); }); series.listen('pointClick', function(e) { let series = e.target; let seriesName = series.name(); let categoryName = e.iterator.get('x'); switch (seriesName) { case 'regions': regionFilter = regionFilter && regionFilter === categoryName ? null : categoryName; break; case 'devices': deviceFilter = deviceFilter && deviceFilter === categoryName ? null : categoryName; break; case 'categories': categoryFilter = categoryFilter && categoryFilter === categoryName ? null : categoryName; break; default: } updateData(); }); } function updateData() { let hoverBarsSeriesColor = '#ffd54f'; let unitMap = {}; let territoryMap = {}; let platformMap = {}; let categoryMap = {}; if (!(regionFilter || deviceFilter || categoryFilter)) { titleFilter = 'to filter click on bar charts below'; } else { titleFilter = ''; if (regionFilter) titleFilter = 'in ' + regionFilter + ' '; if (deviceFilter) { titleFilter = titleFilter + 'on ' + deviceFilter + ' '; } if (categoryFilter) { titleFilter = titleFilter + 'in category "' + categoryFilter + '"'; } } unitsTitle.text( 'Income per Month<br><span style="color:#929292; font-size: 12px;">(' + titleFilter + ')</span>' ); for (let i = 0, count = rawData.length; i < count; i++) { let dataItem = rawData[i]; let fitTerritoryFilter = !regionFilter || (regionFilter && regionFilter === dataItem .region); let fitPlatformFilter = !deviceFilter || (deviceFilter && deviceFilter === dataItem .device); let fitCategoryFilter = !categoryFilter || (categoryFilter && categoryFilter === dataItem.category); if (fitTerritoryFilter && fitPlatformFilter && fitCategoryFilter) { let unitsMapItem = unitMap[dataItem.x]; if (unitsMapItem) { unitMap[dataItem.x] = [ dataItem.x, unitsMapItem[1] + dataItem.value ]; } else { unitMap[dataItem.x] = [dataItem.x, dataItem.value]; } } if (fitPlatformFilter && fitCategoryFilter) { let territoryMapItem = territoryMap[dataItem.region]; if (territoryMapItem) { territoryMapItem.value += dataItem.value; } else { territoryMapItem = { x: dataItem.region, value: dataItem.value }; territoryMap[dataItem.region] = territoryMapItem; } territoryMapItem.fill = territoryMapItem.x === regionFilter ? hoverBarsSeriesColor : undefined; territoryMapItem.stroke = territoryMapItem.x === regionFilter ? anychart.color.darken(hoverBarsSeriesColor) : undefined; } if (fitTerritoryFilter && fitCategoryFilter) { let platformMapItem = platformMap[dataItem.device]; if (platformMapItem) { platformMapItem.value += dataItem.value; } else { platformMapItem = { x: dataItem.device, value: dataItem.value }; platformMap[dataItem.device] = platformMapItem; } platformMapItem.fill = platformMapItem.x === deviceFilter ? hoverBarsSeriesColor : undefined; platformMapItem.stroke = platformMapItem.x === deviceFilter ? anychart.color.darken(hoverBarsSeriesColor) : undefined; } if (fitTerritoryFilter && fitPlatformFilter) { let categoryMapItem = categoryMap[dataItem.category]; if (categoryMapItem) { categoryMapItem += dataItem.value; } else { categoryMapItem = { x: dataItem.category, value: dataItem.value }; categoryMap[dataItem.category] = categoryMapItem; } categoryMapItem.fill = categoryMapItem.x === categoryFilter ? hoverBarsSeriesColor : undefined; categoryMapItem.stroke = categoryMapItem.x === categoryFilter ? anychart.color.darken(hoverBarsSeriesColor) : undefined; } } let territoryData = getValues(territoryMap); let platformData = getValues(platformMap); let categoryData = getValues(categoryMap); let unitData = getValues(unitMap); regionSeries.data(territoryData); deviceSeries.data(platformData); categorySeries.data(categoryData); unitSeries.data(unitData); } function generateData() { let data = []; let dates = [ Date.UTC(2021, 0, 1), Date.UTC(2021, 1, 1), Date.UTC(2021, 2, 1), Date.UTC(2021, 3, 1), Date.UTC(2021, 4, 1), Date.UTC(2021, 5, 1), Date.UTC(2021, 6, 1), Date.UTC(2021, 7, 1), Date.UTC(2021, 8, 1), Date.UTC(2021, 9, 1), Date.UTC(2021, 10, 1), Date.UTC(2021, 11, 1) ]; let territories = ['Europe', 'Asia Pacific', 'USA and Canada', 'Australia']; let platforms = ['iPhone', 'iPad', 'Macbooks']; let categories = ['Games', 'Social Networking', 'Photo & Video', 'Coding']; let monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; for (let d = 0, datesCount = dates.length; d < datesCount; d++) { for ( let t = 0, territoriesCount = territories.length; t < territoriesCount; t++ ) { for ( let p = 0, platformsCount = platforms.length; p < platformsCount; p++ ) { for ( let c = 0, categoriesCount = categories.length; c < categoriesCount; c++ ) { let date = new Date(dates[d]); data.push({ x: monthNames[date.getMonth()], value: Math.floor(Math.random() * 100 + 1), region: territories[t], device: platforms[p], category: categories[c] }); } } } } return data; } function getValues(obj) { let res = []; let i = 0; for (let key in obj) { if (obj.hasOwnProperty(key)) { res[i++] = obj[key]; } } return res; } function formatMoney(value, c, d, t) { let n = value; c = isNaN(Math.abs(c)) ? 2 : Math.abs(c); d = d === undefined ? '.' : d; t = t === undefined ? ',' : t; let s = n < 0 ? '-' : ''; let i = parseInt((n = Math.abs(+n || 0).toFixed(c))) + ''; let j = i.length > 3 ? i.length % 3 : 0; return ( s + (j ? i.substr(0, j) + t : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + t) + (c ? d + Math.abs(n - i) .toFixed(c) .slice(2) : '') ); } </script> </body> </html>

You can run this code here itself by clicking the "Edit and Run" button at the top-right corner of the program block. You will get to see a Dashboard as the output with a single graph and three bar graphs.

Conclusion

In this tutorial, we used an example to demonstrate how you can use the features available in AnyChart.js to create a Dashboard UI.

raja
Updated on 11-Oct-2022 13:10:10

Advertisements