Real-Time Application Dashboard with Yii2, Node.js, MySQL and Chart.js

bardimin pic

Written by Bardimin

On September 23, 2021
Home » Blogs » Technology » Real-Time Application Dashboard with Yii2, Node.js, MySQL and Chart.js

In this article we will create a that can display 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:

  1. Webserver is installed, see How to Configure Virtual Host XAMPP in Windows 10
    .
  2. Yii2 is installed, see How to Install Yii2 Advanced via Composer
    .
  3. Node.js is already installed, see Create real-time applications with Nodes.js
    .
  4. Chart.js.

Steps to Create a Real Time Application Dashboard with Yii2, Node.js, MySQL and Chart.js

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=utf8;

B. Create a Node server.js

  1. Set up a Node .js as in Creating real-time applications with Nodes.js.
  2. In the “.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.
  3. When the user first opens the 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');
});
  1. 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');
});
  1. Full 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);
    }
});

C. Configuration on Yii2

  1. Create a class “myCurl.php” with the function “CurlToNodejs”, for how to create a function you can see in [Yii2] How to create and use Functions in Yii2 Basic and Advanced Templates
class myCurl extends Component
{
    public function CurlToNodejs($url.$postdata=null)
    {
        $header = ['Content-type: application/json'] ;
        $curl = curl_init();
        curl_setopt ($curl, CURLOPT_URL, $url)
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
        $response = curl_exec($curl);
        return $response;
    }
}
  1. After that, we create a view “myChart.php” to display the from the dashboard. For chart use.js you can see it on www.chartjs.org
<?php
/* @var $this yiiwebView */
$this->title = 'My Chart Application';
$script = < JS
	$(document).ready(function(){
	//Chart.js Configuration
	    const data = {
            datasets: [{
                label: 'My First Dataset',
                borderWidth: 1
            }]
        };
	    
	    const ctx = document.getElementById('myChart');
	    const myChart = new Chart(ctx, {
	        type: 'bar',
	        data: data,  
	    });	    
	   
	   function UpdateChart(chart, label, data) {
            chart.data.labels=label;
            chart.data.datasets.forEach((dataset) => {
                dataset.data=data;
            });
            chart.update();
       }
	   
Socket.io Configuration
	   const socket = io.connect( 'http://localhost:3000');
       var labels = [] ;
       var values = [] ;
       socket.on('initialData', function(data){
           for (let i = 0; i < data.length; i++){
               labels [i] = [i] (.id data);
               values [i] = [i] (.population data);
           }
           UpdateChart(myChart,labels,values);
       });
        socket.on('newData', function(data){
            switch (data.actions){
                case "create":
                    const i = labels.length;
                    labels [i] = data.id;
                    values [i] = data.population;    
                    break;
                case "update":
                    const l = labels.findIndex(label=>label===data.id);
                    values [l] = data.population;
                    break;
                case "delete":
                    const x = labels.findIndex(label=>label===data.id);
                    if (x > -1) {
                        labels.splice(x, 1);
                        values.splice(x, 1);
                    }
                    break;                   
            }
            UpdateChart(myChart,labels,values);
        });
     
});
JS;
$this->registerJs($script);
$this->registerJsFile("https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js",); ['position' => yiiwebView::POS_HEAD]
$this->registerJsFile('https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js', ['position' => yiiwebView::POS_HEAD] );
?><div class="site-index">
    <div class="body-content">
        <div id="container" style="width: 75%;">
            <canvas id="myChart"></canvas>
        </div>
    </div>
</div>

While in “SiteController.php” we add “actionMychart”. In this function, check whether the initial data is available or not. Otherwise, a query will be made to the as the initial data.

    public function actionMychart()
    {
        $response = Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/status');
        if ($response === 'false') {
            $data = commonmodelsCity::find()
                ->asArray()
                ->all();
            $response 1 = Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/initdata', json_encode($data));
        }
        return $this->render('myChart');
    }
  1. Up to this step, we can already display dashboard graphics. However, it has not been able to display data changes. This time we will use “Gii” to make CRUD. For more details, you can see the Generating Code with Gii.
  2. Create a “City” model with a “Gii Generator Model”. From this step will be formed a file “/models/City.php”.
  3. Then make it with “CRUD Generator Gii” from the model. From this stage, the following files will be formed.
nodejs yii2 mysql chartjs 01
  1. The next step is to add a to “CityController.php” that will notify the Node.js of the data changes by using the “myCurl” function that we created earlier.
  2. Change “actionCreate” to this
    public function actionCreate()
    {
        $model = new City();
        if ($this->request->isPost) {
            if ($model->load($this->request->post()) && $model->save()) {
                $post=Yii::$app->request->post('City');
                $data = ["id" => $post['id'] , "population" = > $post ['population'] "actions"=> "create"];
                Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/newData',json_encode($data));
                return $this->redirect; ['view', 'id' => $model->id]
            }
        } else {
            $model->loadDefaultValues();
        }
        return $this->render('create', [
            'model' = > $model,
        ]);
    }
  1. Then change “actionUpdate” to this
    public function actionUpdate($id)
    {
        $model = $this->FindModel($id);
        if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) {
            $post=Yii::$app->request->post('City');
            $data= , ["id" => $post['id'] "population" = > $post ['population'] "actions"=>"update"];
            Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/newData',json_encode($data));
            return $this->redirect; ['view', 'id' => $model->id]
        }
        return $this->render('update', [
            'model' = > $model,
        ]);
    }
  1. And then change “actionDelete” to like this
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();
        $data = ["id" => $id, "population" =>"","actions"=>"delete"] ;
        Yii::$app->myCurl->CurlToNodejs('http://localhost:3000/newData',json_encode($data));
        return $this->redirect; ['index']
    }

D. Running an app

  1. Run the Node server.js with
node server.js
  1. If all the processes are right, you'll see it this way.
nodejs yii2 mysql chartjs

Latest Articles

Basic Computer and Laptop Maintenance Techniques

Basic Computer and Laptop Maintenance Techniques

You may not realize it, but computers and cars have something in common, both requiring regular maintenance. If your car needs regular oil changes, your computer should also regularly update its software, keep its antivirus up to date, and check for spyware....

The desktop version of ChatGPT for Windows, Linux, and Mac

The desktop version of ChatGPT for Windows, Linux, and Mac

Do you know what ChatGPT is? Do you know how to get and install ChatGPT on your device? ChatGPT is fast becoming one of the most important inventions in the world of natural language processing. You can use it to generate human-like responses based on your input. You...

24 Pinout Voltage at ATX Power Supply to the Motherboard

24 Pinout Voltage at ATX Power Supply to the Motherboard

The Power Supply converts alternating current (AC) power into low-voltage controlled direct current (DC). Some Power Supply devices include a choice of manual input voltages, while others automatically adjust. The Power Supply converts the voltage from the power line...

Google Chrome – Open Bookmarks to a New Tab By Default

Google Chrome – Open Bookmarks to a New Tab By Default

Bookmarks are shortcuts to open website pages that you have saved for you to visit again later. Have you ever visited a website page that is quite interesting and you want to visit it again later? Considering the address of a website page is certainly difficult,...