Using Chart.js to Display Poll Data in a Cool Way
Tags: javascript, tutorial, webdev
Published: 2020-10-12 14:28:35

It’s voting time. Get ready to see a million graphs showing poll results of all the various groups — how many left-handed cellists voted green party, how many fiscally liberal vampires want to defund global warming, how many otters have the public opinion that eating is best while lying on your back.

I used Chart.js to build a bar graph that displays poll results between three counters. In this blog, I’ll show you how I did it.

![demo gif](https://dev-to-uploads.s3.amazonaws.com/i/7yjbyu91p79tyakrslvh.gif)

> [the code on GitHub](https://github.com/cooljasonmelton/poll-machine)

# Tutorial
### Table of Contents
* Preliminary Junk
* HTML & CSS
* JavaScript for Vote Buttons and Results Text
* Applying Chart.js
* Conclusion

### Preliminary Junk
To start, I set up a file for my HTML, CSS, and JavaScript. Then, I installed Chart.js with npm:
```
npm install chart.js --save
```

I ended up with a file structure (minus the demo) like this:
![file structure](https://dev-to-uploads.s3.amazonaws.com/i/1qunzb9nnfty0mct286h.png)

### HTML & CSS
I set up the bones for this project in `index.html`.

```html
   <div class="c-container"> 
        <!-- chart.js attaches to canvas element -->
        <canvas id="r-chart"></canvas>           
    </div>

    <div class="o-container">
      <!-- Vote Buttons -->
        <h3 class="r-header">Vote:</h3>
        <button id="a-btn" class="option">A</button>
        <button id="b-btn" class="option">B</button>
        <button id="c-btn" class="option">C</button>
      <!-- Results Text -->
        <h3 class="r-header">Results:</h3>
        <p id='a-text' class="results">0</p>
        <p id='b-text' class="results">0</p>
        <p id='c-text' class="results">0</p>
    </div>
```

And, I connected my stylesheet, JavaScript file and the Chart.js node module.
```html
  <head>
    <link rel="stylesheet" href="styles.css">
    <title>Poll Machine</title>
  </head>
...
...
    <!-- chart.js library -->
    <script src="node_modules/chart.js/dist/Chart.js" defer></script>
    
    <script src="index.js" defer></script>
```

I added CSS to make the buttons and text look nice. I added some color, margins, padding, and put everything in a grid. I’m not going to go into severe detail, but you can find the CSS [here](https://github.com/cooljasonmelton/poll-machine/blob/main/styles.css).

### JavaScript for Vote Buttons and Results Text
With the counter buttons’ HTML and CSS looking decent, I went to work on their functionality.

First, I grabbed all the buttons and text nodes by their classnames.

```javascript
    // VOTE BTN ARR
    const btnArr = [...document.getElementsByClassName('option')];
    // RESULT TEXT ARR
    const txtArr = [...document.getElementsByClassName('results')];

```
> Using `.getElementsByClassName()` returns an `HTMLCollection` type. These are similar to an `array`, but you cannot use array methods like `map()` with them. I used the spread operator ( `...` ) to copy the `HTMLCollection` into a new `array`.

I set up an initial vote count for each button:
```javascript
    // INITIAL VOTE COUNT
    let resultA = 0
    let resultB = 0
    let resultC = 0
```

With my buttons in an array, I map over them and give each an event listener. Whenever, a button is clicked it will the function `updateVote()`.


```javascript
    // ADD CLICK LISTENER TO BTNS
    const clickableBtns = () => {
        return btnArr.map(btn => {
            return btn.addEventListener('click', () => updateVote(btn.id.charAt(0)))
        })
    }
```

`updateVote()` does all the work. It takes a parameter of the first character ( `charAt(0)` ) of the button id. This will be `'a'`, `'b'`, or `'c'`. Then, it adds one to the correlated result variable.

Next, I map over my results text. These are an array of paragraph elements I have stored in txtArr. I map this array to display the proper result for each element.

Finally, I update the chart. I will cover this in the next section.

```javascript

    const updateVote = (choice) => {
        // ADD ONE TO CHOICE
        if (choice === 'a') resultA++
        if (choice === 'b') resultB++
        if (choice === 'c') resultC++

        // UPDATE RESULT TEXT
        txtArr.map(txt=> {
            let ch = txt.id.charAt(0)
            if (ch === 'a') return txt.innerHTML = resultA
            if (ch === 'b') return txt.innerHTML = resultB
            if (ch === 'c') return txt.innerHTML = resultC
        })

        // UPDATE CHART DATA
        newChart.data.datasets[0].data = [resultA]
        newChart.data.datasets[1].data = [resultB]
        newChart.data.datasets[2].data = [resultC]
        newChart.update()
    }
```

### Applying Chart.js
Chart.js must be applied to a canvas element. I grab the canvas element I set up in the HTML.

```javascript
    // CHART CANVAS
    let chartCvs = document.getElementById('r-chart')
```

Next, I make a chart by calling new Chart.

```javascript
    // CHART SPECS
    const newChart = new Chart(chartCvs, {
        type: 'bar',
        data: {
            datasets: [{
                maxBarThickness: 70,
                label: 'A',
                data: [resultA],
                backgroundColor: ['#56A3A6'],
                borderColor: ['gray'],
                borderWidth: 1
            },
            {
                maxBarThickness: 70,
                label: 'B',
                data: [resultB],
                backgroundColor: ['#DB504A'],
                borderColor: ['gray'],
                borderWidth: 1
            },
            {
                maxBarThickness: 70,
                label: 'C',
                data: [resultC],
                backgroundColor: ['#E3B505'],
                borderColor: ['gray'],
                borderWidth: 1
            }
        ]},
        options: {
            title: {
                display: true,
                text: ["Results"]
            },
            // TURN OFF ANNOYING HOVER POPUP
            tooltips: { enabled: false },
            scales: {
                yAxes: [{
                    ticks: {
                        display: true,
                        beginAtZero: true
                    }
                }]
            }
        }
    });
```

`new Chart` takes a canvas element, `chartCvs`, for its first argument. For its second argument, it takes an object that holds all the chart specifications.

The three main keys of the object are `type`, `data`, and `options`.

`type` controls the type of graph. Chart.js gives a lot of good options. For this, I went with a simple bar graph by providing the value `'bar’`.

The `data` takes one or multiple datasets depending on the type of graph you are making. For each bar, I give information about the color and style of the bar and the data and labels correlating to each letter — A, B, or C.

Finally, for `options`, I create a title, turn off tooltips (a hover box I didn’t like), and give labels and ticks to the scales on the y-axis.

### Conclusion
The graphs of Chart.js display really nicely with detail and smooth transitions. There was a bit of a learning curve for me to get everything working. For this reason, I hard-coded a lot of the project. If I were to redo this, I would abstract a lot of this and explore more of what Chart.js offers. There’s a lot more customization that you can apply to a chart.

Message me if you have any feedback. I would love any suggestions or ideas to improve this blog or the ‘poll machine’. Please comment or feel free to email me at `jason.melton2@gmail.com`.

Best, Jason