Real-time Chart in JavaScript with ChartJS and Hamoni Sync
Tags: realtime, javascript, chart, socketio
Published: 2018-04-13 07:52:05

---
title: Real-time Chart in JavaScript with ChartJS and Hamoni Sync
published: true
description: how to build real-time chart in javascript using Hamoni Sync
tags: #realtime #javascript #chart #socketio
---

Real-time data is data that is presented as it is acquired. It is often used in tracking or monitoring systems like traffic GPS system, auction/bidding applications and stock trading applications. Charts help with a graphical representation of this data and help the viewer make a decision easily. 

In this post, I’ll show you how to make real-time chart in JavaScript. We’ll be building a basic voting web application with a page for voting, and another page with a real-time chart showing the voting result as it happens. Here’s a peek at what we’ll be building


![](https://d2mxuefqeaa7sj.cloudfront.net/s_271D2C4415082D830A5E129B885A0502958EA9373BF02DC765D6BC3010DA0C13_1523603994116_hamoni-chartjs.gif)


I’ll be using [Chart.js](http://www.chartjs.org/) and [Hamoni Sync](https://www.hamoni.tech/) to build it. Chart.js is a simple JavaScript charting library. Hamoni Sync is a real-time state synchronisation service which enables you to synchronise your application state in real-time. The vote result is the state we want show users in real-time. Hamoni Sync makes this easier by allowing you to define state for your application, while you avoid designing complex state logic around publish/subscribe systems. 

# Setup the code

We will be using a project template which already has the HTML pages and node app to serve the static files. Follow the instruction below to set it up


1. Clone the repo from GitHub by running `git clone https://github.com/pmbanugo/realtime-chartjs-hamoni-starter.git` in the command line. If you’re not using git, you can download it [here](https://github.com/pmbanugo/realtime-chartjs-hamoni-starter).
2. Switch to the project directory `cd realtime-chartjs-hamoni-starter`
3. Install the dependencies by running `npm install`. This will install [express](https://expressjs.com/) and Hamoni Sync node modules.
# Backend

The **server.js** file contains code to server HTML pages in the **public** folder. Lines 9 - 14 defines a default state for the voting application. It contains 4 candidates with their vote count as 0.  

```javascript

    let voteData = [
      { candidate: "Peter Mbanugo", vote: 0 },
      { candidate: "Angela Daniels", vote: 0 },
      { candidate: "Rose Philly", vote: 0 },
      { candidate: "James Crump", vote: 0 }
    ];
```

 
 It also defines a REST endpoint for voting defined from lines 18 to 30. When a vote comes in, we may want to save that data to a database and then update the chart with an up-to-date result of the vote. The chart state will be communicated in real-time using Hamoni Sync. On line 40 I have declared a statement to initialise Hamoni but we need an account ID and app ID. 


## Create Hamoni Account and App 

Login to the Hamoni [dashboard](https://dashboard.hamoni.tech/) (or Signup if you don’t already have an account). When logged in you can click the `Show Account ID` button to see your account ID. We need a Hamoni App ID, hence we need to create an app from the dashboard. An app is a container that can hold application state. You’d typically want to have a separate Hamoni app for each of your application. 

Under the “Create Application” header, enter an application name and click the create button. Within a few seconds, you should see it created and displayed in the application list section. 


![Hamoni dashboard](https://d2mxuefqeaa7sj.cloudfront.net/s_271D2C4415082D830A5E129B885A0502958EA9373BF02DC765D6BC3010DA0C13_1523552120862_Screen+Shot+2018-04-12+at+17.54.22.png)


Copy the app and account ID and replace them with the string value on line 40 in **server.js**

## Create application state in Hamoni

Now we need to create state in Hamoni Sync. To do that we need to use a sync primitive. Sync primitives are what you use to define and manipulate state. They’re basically a way to categorise or differentiate kinds of data to be stored. There are 3 sync primitives:


1. **Value Primitive:** This kind of state holds simple information represented with datatypes like string, boolean or numbers. It is best suited for cases such as unread message count, toggles, etc.
2. **Object Primitive****:** Object state represents states that can be modelled as a JavaScript object. An example usage could be storing the score of a game.
3. **List Primitive:** This holds a list of state objects. A state object is a JavaScript object. You can update an item based on its index in the list.

 
I’ll be using an object primitive for this post. 

Add the following function in **server.js** 


```javascript
    function createState() {
      hamoni
        .createObject("election", voteData)
        .then(statePrimitive => {
          console.log("election state created");
          state = statePrimitive;
        })
        .catch(console.log);
    }
```

This creates a state with the name of `election` and state value using the variable `voteData`. Then we need to connect to the Hamoni Sync server. We do this by calling `hamoni.connect()`. Add the following code below the function `createState()`

```javascript

    hamoni.connect().then(() => createState()).catch(console.log);
```

If it connects successfully to the server, we call the `createState()` function to create the state for our chart.

## Update application state

We want to update the state when a new vote comes in. The object primitive which holds our state has an `update()` method which can be used to update the state. We will update the *election* state when the user calls `/vote` endpoint of our API. Below lines 27, add the following code to update the state


```javascript
    app.post("/vote", function(req, res) {
      ....
      state.update(voteData);
      ....
    });
```

This will update the state and broadcast the update to connected clients.

# Frontend

Our backend is ready to accept votes and update the state. Now we need to build the frontend to send in votes and display realtime chart. 

The starter template we cloned at the beginning has the files **public/vote.html** and **public/js/vote.js.** These files already contain code to display a form in the web page and javascript to post to the server. I skipped writing that code here because it’s a basic HTML form and JavaScript to send form data to the server. Do leave a comment if anything there is confusing. 

The chart will be displayed in **index.html** inside the public folder. **index.html** already contains script tags for Chart.js and Hamoni Sync (see lines 17 and 18)

```html

    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
    <script src="https://unpkg.com/hamoni-sync@0.2.0/hamoni.dev.js"></script>
```


## Render the chart

Open the file **public/index.js.** Add the function below to render a chart in the web page.

```javascript

    function renderChart(state) {
      var ctx = document.getElementById("myChart").getContext("2d");
      var chart = new Chart(ctx, {
        // The type of chart we want to create
        type: "bar",
        // The data for our dataset
        data: {
          labels: state.map(s => s.candidate),
          datasets: [
            {
              label: "Elections 2018",
              backgroundColor: "rgb(255, 99, 132)",
              borderColor: "rgb(255, 99, 132)",
              data: state.map(s => s.vote)
            }
          ]
        },
        // Configuration options go here
        options: {
          scales: {
            xAxes: [
              {
                time: {
                  unit: "Vote"
                },
                gridLines: {
                  display: false
                },
                ticks: {
                  maxTicksLimit: 6
                }
              }
            ],
            yAxes: [
              {
                ticks: {
                  min: 0,
                  max: 30,
                  maxTicksLimit: 10
                },
                gridLines: {
                  display: true
                }
              }
            ]
          },
          legend: {
            display: true
          }
        }
      });
    }
```

This function takes a parameter that represents our chart state. The type options specify the type of chart we want to render, in this case, a bar chart. The data option defines properties used to display data for the chart. There are two important properties that I want to bring to your attention. First is the label property on line 8, `labels: state.map(s => s.candidate)`
It gets its value from the state. The chart state is an array of each electoral candidate and their vote. With that code, we’re setting the candidate’s name as labels for the chart. The second is `data: state.map( s => s.vote)` on line 14. It sets the data for the chart. 

Now we need to retrieve chart state and render the chart.

## Get state and state updates

To retrieve the chart state, we need to connect to Hamoni Sync. Add the following code to get state and state updates, then render the chart based on that:



    let hamoni = new Hamoni("Account_ID", "APP_ID");
    hamoni
      .connect()
      .then(response => {
        hamoni
          .get("election")
          .then(statePrimitive => {
            renderChart(statePrimitive.get());
            
            statePrimitive.onUpdated(state => renderChart(state));
          })
          .catch(console.log);
      })
      .catch(error => console.log(error));
      


If the client successfully connects to Hamoni Sync, we call `hamoni.get("election")` to get our election state. If it succeeds, we call `renderCharts()` with the value for the state. 

To be notified of state updates, we call `onUpdated()` on the state primitive with a callback that should be executed each time there’s an update. 

Now we can test our code to see it working. Open the command line and run `npm start`, then open your browser and navigate to [localhost:5000](http://localhost:5000). 


![](https://d2mxuefqeaa7sj.cloudfront.net/s_271D2C4415082D830A5E129B885A0502958EA9373BF02DC765D6BC3010DA0C13_1523604009149_hamoni-chartjs.gif)


Voila!! 🚀 

Real-time chart state made with less hassle. Chart.js is easy to use. Hamoni Sync reduces the development time and effort in designing complex state logic around publish/subscribe systems because it embraces the concept of state.  

You can get the finished source code on [GitHub](https://github.com/pmbanugo/realtime-chartjs-hamoni). 


# Links


- [Hamoni Sync](https://www.hamoni.tech/)
- [Chart.js](http://www.chartjs.org/docs/latest/)
- [Express](http://expressjs.com/)