Formidable Forms – ChartsJS Graphs

Formidable Forms built in charts and graphs are great for displaying basic form data. But what if you need something a bit more complex? In this post we’ll look at using Formidable Forms Pro with Chart.js to create more complex, interactive graphs from your form entries.

A full demo of the types of things you can acomplish can be seen HERE.

Getting Started

This post will cover how to create graphs using ChartJS using data from a form and a view. Before you begin you will need to have a Formidable Forms Pro account, a form and some form data to use within your graphs.

The first step is to get the ChartJs scripts loaded into your site.

If you are going to be using graphs on multiple pages you can load them in to every page of the site by adding them to the header (or footer) using the PHP function below or if you only want charts on a specific page you can just insert the scripts as required.

add_action( 'wp_head', function () { ?>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<?php } );

Once the scripts are loaded you can start to create your first chart.

To do this you will need 2 elements:

  • HTML5 Canvass
  • Javascript to build the chart.

The html canvass can be wrapped in a div to give you move control over it’s styling and responsive sizing like this:

<div class="myClass"><canvas id="myChart" width="400" height="400"></canvas></div>

And the chart javascript can then be added under the canvass element like this:

<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        }
    }
});
</script>

This is all you need to create your first basic chart and display it on your website.

You can read more about how to create different types of charts and all of the options that ChartJS offers in their documentation HERE.

There are also some great examples of different charts in this article by Tobias Ahlin.

Using Formidable Data

Now that you have a graph loading it’s time to start populating the graph with data from your formidable form entries.

There are various ways you can do this but we’ll focus on 2 options; a simple option and a more complex option.

The Simple Option

The simple way to add form data to your chartJS scripts is to use the frm-stats shortcode. In the Chart JS mentioned above we have this line which contains our data:

data: [12, 19, 3, 5, 2, 3],

We can easily make this data come from our forms by swapping the fixed numbers for frm-stats shortcodes like this:

data: [ 
    [ frm-stats id=1 type=count ], 
    [ frm-stats id=2 type=count ], 
    [ frm-stats id=3 type=count ], 
    [ frm-stats id=4 type=count ]
],

You can also use the frm-math shortcode to get even more figures from your form entries and populate your graphs.

The Complex Option

Sometimes you might need to get a lot of data into a chart and using a html table can be a great option. This works well with Formidable as you can use a view to create your html table and then use the table data to populate your graph.

This also works really well if you want to filter the data in the table and therefore update the data in your graph to show different metrics as seen in the demo HERE.

To create a table from a view you can follow the guide in the FF KB HERE.

Once the table is created add an ID to the table element which we’ll use in our JS file.

<table class="table" id="dataTable">
   <thead>
      <tr>
         <th>Year</th>
         <th>Jan</th>
         <th>Feb</th>
         <th>Mar</th>
         <th>Apr</th>
         <th>May</th>
         <th>Jun</th>
         <th>Jul</th>
         <th>Aug</th>
         <th>Sep</th>
         <th>Oct</th>
         <th>Nov</th>
         <th>Dec</th>
         <th>Total</th>
      </tr>
   </thead>
   <tbody>
      <tr class="color1">
         <th>2015</th>
         <td class="field_1522">33,065</td>
         <td class="field_1522">37,336</td>
         <td class="field_1522">42,315</td>
         <td class="field_1522">45,109</td>
         <td class="field_1522">38,924</td>
         <td class="field_1522">50,995</td>
         <td class="field_1522">44,470</td>
         <td class="field_1522">36,073</td>
         <td class="field_1522">47,177</td>
         <td class="field_1522">38,066</td>
         <td class="field_1522">46,954</td>
         <td class="field_1522">34,082</td>
         <th class="field_1522">494,566</th>
      </tr>
      <tr class="color2">
         <th>2016</th>
         <td class="field_1522">42,040</td>
         <td class="field_1522">39,316</td>
         <td class="field_1522">56,807</td>
         <td class="field_1522">42,491</td>
         <td class="field_1522">35,733</td>
         <td class="field_1522">35,733</td>
         <td class="field_1522">47,308</td>
         <td class="field_1522">40,568</td>
         <td class="field_1522">43,592</td>
         <td class="field_1522">47,049</td>
         <td class="field_1522">40,687</td>
         <td class="field_1522">32,360</td>
         <th class="field_1522">503,684</th>
      </tr>
      <tr class="color3">
         <th>2017</th>
         <td class="field_1522">52,748</td>
         <td class="field_1522">49,735</td>
         <td class="field_1522">93,008</td>
         <td class="field_1522">86,093</td>
         <td class="field_1522">129,698</td>
         <td class="field_1522">104,697</td>
         <td class="field_1522">109,352</td>
         <td class="field_1522">112,593</td>
         <td class="field_1522">127,415</td>
         <td class="field_1522">169,435</td>
         <td class="field_1522">149,345</td>
         <td class="field_1522">106,577</td>
         <th class="field_1522">1,290,696</th>
      </tr>
      <tr class="color4">
         <th>2018</th>
         <td class="field_1522">192,178</td>
         <td class="field_1522">144,774</td>
         <td class="field_1522">176,033</td>
         <td class="field_1522">179,468</td>
         <td class="field_1522">190,112</td>
         <td class="field_1522">170,225</td>
         <td class="field_1522">156,544</td>
         <td class="field_1522">156,302</td>
         <td class="field_1522">161,413</td>
         <td class="field_1522">194,819</td>
         <td class="field_1522">159,978</td>
         <td class="field_1522">133,378</td>
         <th class="field_1522">2,015,224</th>
      </tr>
      <tr class="color5">
         <th>2019</th>
         <td class="field_1522">215,648</td>
         <td class="field_1522">165,316</td>
         <td class="field_1522">189,860</td>
         <td class="field_1522">200,208</td>
         <td class="field_1522">198,685</td>
         <td class="field_1522">154,718</td>
         <td class="field_1522">221,578</td>
         <td class="field_1522">198,596</td>
         <td class="field_1522">208,853</td>
         <td class="field_1522">283,768</td>
         <td class="field_1522">269,358</td>
         <td class="field_1522">182,090</td>
         <th class="field_1522">2,488,678</th>
      </tr>
      <tr class="color6">
         <th>2020</th>
         <td class="field_1522">216,394</td>
         <td class="field_1522">180,863</td>
         <td class="field_1522">273,389</td>
         <td class="field_1522">355,957</td>
         <td class="field_1522">303,761</td>
         <td class="field_1522">319,998</td>
         <td class="field_1522">429,280</td>
         <td class="field_1522">0</td>
         <td class="field_1522">0</td>
         <td class="field_1522">0</td>
         <td class="field_1522">0</td>
         <td class="field_1522">0</td>
         <th class="field_1522">2,079,642</th>
      </tr>
   </tbody>
</table>

Once we have the table created we can then use the following JS to capture the data from the table and store it our browsers console log as an array. The array data can then be used to populate our graph which we’ll also include as part of the same JS file.

TIP: It’s useful to put this script in it’s own JS file (E.g myChart1.js) and store in it’s own folder on your web server. You can then link to this from the view or the webpage to load it in.

<script>
   // HTML To JSON Script 
   // *Forked* from https://johndyer.name/html-table-to-json/
   var table = document.getElementById('dataTable');
   var json = []; // first row needs to be headers
   
   var headers = [];
       for (var i = 0; i < table.rows[0].cells.length; i++) {
       headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi, '');
   }
   
   // go through cells 
   for (var i = 1; i < table.rows.length; i++) {
       var tableRow = table.rows[i];
       var rowData = {};
   for (var j = 0; j < tableRow.cells.length; j++) {
       rowData[headers[j]] = tableRow.cells[j].innerHTML;
   }
       json.push(rowData);
   }
   
   var total2015 = json[0].total;
   var total2016 = json[1].total;
   var total2017 = json[2].total;
   var total2018 = json[3].total;
   var total2019 = json[4].total;
   var total2020 = json[5].total;
   
   function seriesFigures(idx) {
     return [
       parseFloat(json[idx].jan.replace(/,/g, '')),
       parseFloat(json[idx].feb.replace(/,/g, '')),
       parseFloat(json[idx].mar.replace(/,/g, '')),
       parseFloat(json[idx].apr.replace(/,/g, '')),
       parseFloat(json[idx].may.replace(/,/g, '')),
       parseFloat(json[idx].jun.replace(/,/g, '')),
       parseFloat(json[idx].jul.replace(/,/g, '')),
       parseFloat(json[idx].aug.replace(/,/g, '')),
       parseFloat(json[idx].sep.replace(/,/g, '')),
       parseFloat(json[idx].oct.replace(/,/g, '')),
       parseFloat(json[idx].nov.replace(/,/g, '')),
       parseFloat(json[idx].dec.replace(/,/g, ''))
     ]
   }
   
   var figures2015 = seriesFigures(0);
   var figures2016 = seriesFigures(1);
   var figures2017 = seriesFigures(2);
   var figures2018 = seriesFigures(3);
   var figures2019 = seriesFigures(4);
   var figures2020 = seriesFigures(5);
   
   console.log(json);
   
   console.log("2015", figures2015);
   console.log("2016", figures2016);
   console.log("2017", figures2017);
   console.log("2018", figures2018);
   console.log("2019", figures2019);
   console.log("2020", figures2020);
   
   // Chart JS Script - Year on Year Comparison Bar Chart
   
   var ctxBarChart = document.getElementById("myBarChart").getContext('2d');
   
   var myBarChart = new Chart(ctxBarChart, {
     type: 'bar',
     data: {
       labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // Our labels
         datasets: [{
           label: '2015', // Name the series
           data: figures2015, // Our values
           backgroundColor: 'rgba(52,82,255,0.6)',
           borderColor: 'rgba(52,82,255,1)',
           borderWidth: 1 // Specify bar border width
         },
         {
           label: '2016', // Name the series
           data: figures2016, // Our values
           backgroundColor: 'rgba(159,52,227,0.6)',
           borderColor: 'rgba(159,52,227,1)',
           borderWidth: 1 // Specify bar border width
         },
         {
           label: '2017', // Name the series
           data: figures2017, // Our values
           backgroundColor: 'rgba(210,0,192,0.6)',
           borderColor: 'rgba(210,0,192,1)',
           borderWidth: 1 // Specify bar border width
         },
         {
           label: '2018', // Name the series
           data: figures2018, // Our values
           backgroundColor: 'rgba(239,0,154,0.6)',
           borderColor: 'rgba(239,0,154,1)',
           borderWidth: 1 // Specify bar border width
         },
         {
           label: '2019', // Name the series
           data: figures2019, // Our values
           backgroundColor: 'rgba(253,0,117,0.6)',
           borderColor: 'rgba(253,0,117,1)',
           borderWidth: 1 // Specify bar border width
         },
         {
           label: '2020', // Name the series
           data: figures2020, // Our values
           backgroundColor: 'rgba(255,16,83,0.6)',
           borderColor: 'rgba(255,16,83,1)',
           borderWidth: 1 // Specify bar border width
         }
       ]},
     options: {
       responsive: true, // Instruct chart js to respond nicely.
       maintainAspectRatio: false, // Add to prevent default behaviour of full-width/height
       legend: {
         display: true,
         position: 'top',
         labels: {
           usePointStyle: true,
           padding: 20,
         },
       },
     }
   });
</script>

This script combines our ChartJS script and the HTML Table to JSON script to populate the chart for us with whatever data is in the table. As we mentioned above you can then filter the table using the view and a filter form (if required – see KB article HERE) to make the table and chart data even more dynamic.

You can see this script & table in action HERE.

As you can see from the above options there are almost endless things you can do with ChartJs and Formidable Forms. If you’re not a JS expert then the learning curve for ChartJS may be quite steep to get the data and charts working in the way you require but stick with it as it’s well worth the effort to get your data displaying in beautiful, interactive graphs.

Best of luck.