In this article we will create a dashboard that can display graphics from data in real-time. The data we use as simulations is the population of a city. If you update your resident data, add or delete it, the graphic will change in real-time without the need to refresh from the page.
Before we begin, we need to prepare:
- Webserver is installed, see How to Configure Virtual Host XAMPP in Windows 10
. - Yii2 is installed, see How to Install Yii2 Advanced via Composer
. - Node.js is already installed, see Create real-time applications with Nodes.js
. - Chart.js.
Steps to Create a Real Time Application Dashboard with Yii2, Node.js, MySQL and Chart.js
Other Interesting Articles
A. Create a table with MySQL
Create tables with the name “city”, and columns with the names “id” and “population”. Or it’s easier to run the following sql scripts.
CREATE TABLE 'city' ( 'id' CHAR(16) NOT NULL PRIMARY KEY, 'population' INT(11) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
B. Create a Node server.js
- Set up a Node server.js as in Creating real-time applications with Nodes.js.
- In the “server.js” file, what we need to create is an “API” that will update the data on the graph we create with the Chart.js after the data is successfully stored by Yii.
- When the user first opens the dashboard page, we check whether the initial data for the dasboard graph is available, if not Yii will send the initial data.
app.post('/status', (req, res) => { res.send(isInitData); }); app.post('/initData', (req, res) => { if(!isInitData){ myData = req.body; isInitData=true; } res.send('success'); });
- Next we will create an “API” that will update the data on crud operations on Yii.
app.post('/newData', (req, res) => { switch (req.body.actions){ case "create": myData.push({id: req.body.id, population: req.body. population}); break; case "update": let i = myData.findIndex(label => label.id === req.body.id); myData [i] ={id: req.body.id, population: req.body. population}; break; case "delete": let l = myData.findIndex(label => label.id === req.body.id); myData.splice(l,1); break; } io.emit('newData', {id: req.body.id, population: req.body. population, actions:req.body.actions}); res.send('success'); });
- Full script of the file server.js
var app = require("express")(); var bodyParser = require('body-parser') var http = require('http'). Server(app); var io = require("socket.io")(http,{cors: {origin:"*"}}); var myData = [] ; var isInitData=false; http.listen(3000, function () { console.log("Listening on 3000"); }); app.use(bodyParser.json({type: 'application/json' })); app.post('/status', (req, res) => { res.send(isInitData); }); app.post('/initData', (req, res) => { if(!isInitData){ myData = req.body; isInitData=true; } res.send('success'); }); app.post('/newData', (req, res) => { switch (req.body.actions){ case "create": myData.push({id: req.body.id, population: req.body. population}); break; case "update": let i = myData.findIndex(label => label.id === req.body.id); myData [i] ={id: req.body.id, population: req.body. population}; break; case "delete": let l = myData.findIndex(label => label.id === req.body.id); myData.splice(l,1); break; } io.emit('newData', {id: req.body.id, population: req.body. population, actions:req.body.actions}); console.log("issuer new data "+req.body.id+" :"+req.body.actions); res.send('success'); }); io.on("connection", (socket) => { console.log("A user is connected"); if(isInitData){ console.log("initial data issuer"); socket.emit('initialData', myData); } });