How to create admin dashboard with charts using Reactjs and D3js

Saurabh Mhatre
CodeClassifiers
Published in
6 min readMar 22, 2017

--

Image Source:Pixabay

In the previous tutorial we covered user registration and login using reactjs, nodejs and mysql database. In this tutorial we are going to create admin dashboard to view data from mysql database and show the data in pie chart using a d3.js(javascript charting library).

So lets start with creating basic apis in nodejs to get all records from mysql database and send it to frontend. We are going to create a new file in routes folder called dbroutes.js. First create a connection to mysql database using mysql npm module.

var mysql      = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'username',
password : 'yourpasswordhere',
database : 'databasename'
});
connection.connect(function(err){
if(!err) {
console.log("Database is connected ... nn");
} else {
console.log("Error connecting database ... nn");
}
});

Next we write a handler function to get all records..

exports.getAllRecords  = function(req,res){
connection.query('SELECT * from tablename', function (error, results, fields) {
if(error){
console.log("error ocurred",error);
res.send({
"code":400,
"failed":"error ocurred"
})
}
else{
// console.log('The solution is: ', results);
res.send({
"code":200,
"result":results
});
}
});
}

Replace tablename with appropriate table in your database.Next we need to modify server.js to handle new api request.

var express    = require("express");
var bodyParser = require('body-parser');
let dbroutes = require('./routes/dbroutes');
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
var router = express.Router();
// test route
router.get('/', function(req, res) {
res.json({ message: 'welcome to our dockerdashboard module apis' });
});
router.get('/getAllRecords',dbroutes.getAllRecords);
app.use('/api', router);
app.listen(5000);

We have imported dbroutes file at line no.4 and created a new api handler at line no.21.You can test your api in postman/browser using following url:

http://localhost:5000/api/getAllRecords

Now lets start frontend development in reactjs. I am going to use materialui for ui development,superagent for ajax requests and react-d3 for charting purposes.

We are going to use create-react-app for setting up the base project which can be installed using following command:-

sudo npm install -g create-react-app

Next run the following command to set up a new react project:

create-react-app admindashboard
cd admindashboard

Here is my package.json with all the modules required for this project:

{
"name": "admindashboard",
"version": "0.1.0",
"private": true,
"devDependencies": {
"react-scripts": "0.9.5"
},
"dependencies": {
"material-ui": "^0.17.1",
"react": "^15.4.2",
"react-bash": "^1.5.3",
"react-d3-basic": "^1.6.11",
"react-d3-tooltip": "^1.4.14",
"react-dom": "^15.4.2",
"react-router": "^4.0.0",
"react-router-dom": "^4.0.0",
"react-tap-event-plugin": "^2.0.1",
"superagent": "^3.5.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}

Copy the dependencies json into your project package file and run npm/yarn install to all the required dependencies.Here is the complete file structure of the project.

├── public
│ ├── css
│ │ ├── material.css
│ │ └── materialicons.woff2
│ ├── favicon.ico
│ └── index.html
├── README.md
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── components
│ │ ├── Dashboard.js
│ │ ├── MysqlMonitoring.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ └── routes
│ └── mainroutes.js
└── yarn.lock

We have a routes folder to store all react-router routes,components which contain individual app screens within src folder. We are going to concentrate on MysqlMonitoring component in this tutorial:

import React, { Component } from 'react';
import {Tabs, Tab} from 'material-ui/Tabs';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
export default class MysqlMonitoring extends Component {
constructor(props){
super(props);
this.state={
mysqlTables:[],
toolTip:[]
}
}
render(){
// console.log(this.state.mysqlTables);
return(
<div>
<MuiThemeProvider>
<Tabs>
<Tab label="MysqlMonitoring" >
{this.state.mysqlTables}
{this.state.toolTip}
</Tab>
</Tabs>
</MuiThemeProvider>
</div>
)
}
}

We have setup page with tabbar at the top and two empty state variables in between.Next step is to fetch data from node server in componentDidMount by sending XMLHttprequest using superagent module:

...
import request from'superagent';
const apiBaseUrl="http://localhost:5000/api/";
export default class MysqlMonitoring extends Component {
...
componentDidMount(){
var self=this;
request
.get(apiBaseUrl+'getAllRecords')
.set('Accept', 'application/json')
.end((err, res)=>{
// Calling the end function will send the request
if(err){
console.log("error occured");
}
else{
//call setState and populate data here
}
});
}

Here is a sample response from server which comes in res variable above to keep things in perspective:

{"code":200,
"result":[
{"id":1,"first_name":"asdf","last_name":"asdf","userid":"asdf","password":"asdf","role":"student","created":"2017-03-05T16:17:14.000Z","modified":"2017-03-05T16:17:14.000Z"},
{"id":2,"first_name":"tea","last_name":"tea","userid":"tea","password":"tea","role":"teacher","created":"2017-03-05T16:18:54.000Z","modified":"2017-03-05T16:18:54.000Z"}
]}

Next we are going to populate mysqlTables array using Tables provided by material-ui:

import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';
export default class MysqlMonitoring extends Component {
...
componentDidMount(){
request
...
.end((err, res)=>{
// Calling the end function will send the request
if(err){
console.log("error occured");
}
else{
// console.log("res",JSON.stringify(res.body.result));
let mysqlTables=[],tableHeader=[],tableHeaderColumn=[];
let tableBody=[],tableRow=[],tableRowColumn=[]
var mysqlResults = res.body.result;
var teachersCount=0,studentCount=0;
mysqlResults.map((item,index)=>{
tableRowColumn=[];
// console.log("items",item,index)
if(index==0){
for(var key in item){
if(item.hasOwnProperty(key)){
// console.log(key)
tableHeaderColumn.push(
<TableHeaderColumn>
{key}
</TableHeaderColumn>
)
}
}
}
for(var key in item){
if(item.hasOwnProperty(key)){
// console.log(key)
if(key=="role" && item[key]=="student"){
studentCount++;
}
else if(key=="role" && item[key]=="teacher"){
teachersCount++;
}
tableRowColumn.push(
<TableRowColumn>
{item[key]}
</TableRowColumn>
)
}
}
tableRow.push(
<TableRow>
{tableRowColumn}
</TableRow>
)
return item;
})
tableBody.push(
<TableBody>
{tableRow}
</TableBody>
)
tableHeader.push(
<TableHeader>
<TableRow>
{tableHeaderColumn}
</TableRow>
</TableHeader>
)
mysqlTables.push(
<Table>
{tableHeader}
{tableBody}
</Table>
)
this.setState({mysqlTables})
}
});
}

}

The code might seem a bit long but it is quite easy to understand.We run a map function to iterate through every json item in results, then check if index is 0 and push all keys of json from first jsonarray item and populate table header.Next we iterate through values of json keys and populate table columns.If this all seems to confusing simply keep in mind that we are simply trying to populate table head and body using multiple JSON array iterations.The end result is this:

MYSQLTABLE

Next we are going to create a simple pie chart using react-d3 by modifying componentDidMount:

var PieTooltip = require('react-d3-tooltip').PieTooltip;
export default class MysqlMonitoring extends Component {
...
componentDidMount(){
request
...
.end((err, res)=>{
if(err){
console.log("error occured");
}
else{
...
var toolTip=[];

console.log("counts",studentCount,teachersCount)
let data = [{
name:"teacher",
count:teachersCount
},{
name:"student",
count:studentCount
}]
let value = function(d){
console.log("value",d);
return d.count;
}
let fieldname = function(d){
return d.name
}
let chartSeries = [
{
"field": "teacher",
"name": "Teachers"
},
{
"field":"student",
"name":"Students"
}
]
toolTip.push(
<div>
<PieTooltip
title={"Teacher Student Ratio"}
data={data}
width={1000}
name={fieldname}
value={value}
height={400}
chartSeries={chartSeries}
/>
</div>
)
this.setState({mysqlTables,toolTip})
}
})
}
}

Piechart takes following data points as parameters:

  • data: source json to generate chart
  • name: json key to take as input parameter to show category names
  • value: json key to takee input values
  • chartSeries: Custom names for each name in name variable defined above(#nameception :p)

Here is what the final chart looks like:

mysqlpiechart

Before proceeding further I think it would be better if you go through sample implementation of piechart on reactd3 website here.

Since piechart requires data as name value json pairs, I had to create custom data json as follows:

let data = [{
name:"teacher",
count:teachersCount
},{
name:"student",
count:studentCount
}]

Where piechart will pickup name field as to display pie categories and count to calculate ratio between different categories based on the values.In my case there were only two entries so teachersCount and studentCount is 1 due to which both categories occupy 50% of the pie chart.

That concludes today’s tutorial. This component is a part of larger project and you can find the complete source code on github here.

Bonus Tips:

The purpose of this tutorial was to make reader get acquainted with basics of d3js so I have kept the code simple and used basic chart.You can extend the dashboard according to your needs and used more charts/ui elements like grids to make it more immersive and useful.

The table population code in componentDidMount method was written in bit of hurry and can be optimized further.

Connect Deeper:

In the next tutorial I am planning to show you how to create terminal emulator in browser similar to the ones found in cloud based ide’s like c9,koding in react and run the commands on remote server using nodejs so follow our facebook page here: Technoetics

--

--