Wednesday, 22 December 2010

HTML: How to create bar charts with tables

   


In this post I will explain a very - very! - simple method to create vertical or horizontal bar charts using only HTML. You already know that on the web you can find many different solutions to create charts. In October, I  posted a list of jQuery plugins and I know there are other JavaScript snippets or Flash stuff available to draw graphs. However I've always found hard to apply those solutions to my needs. That is because I wanted to use data from a database, while many of the available snippets get the data from txt or xml files.



What do we need?
In order to create my simple bar chart, we need to gather data from our database. I won't explain how to do it, because that is not the main topic here. It really doesn't matter how you get your data, but, in order to explain the solution, I assume that you have data such as:
JanFebMarAprMayJunJulAugSepOctNovDec
101520253035404550556065

In our example, we will have months as values for the x-axis and numeric data for the y-axis.
Remember that the above table is just an example, applying the html bar charts to other data is very simple, after understanding the logic behind the code.

Create the chart
Now that we have the data, we need to create a table that will represent the frame of our chart. We are going to generate a vertical bar chart.
Our frame will be something like this:
<table width="100%" border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td height="30" valign="bottom"><div align="right">100</div></td>
    <td width="0" rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" >
Please notice that inside the main table, we've created another table. I know it is confusing, but believe me you need to do it in order to keep things working. Inside the second table we are going to put another table which has:
  • an height value equal to the data value for the month from our database. I increased that value (in the example *3) because I needed it to be more visible. Keep that increasing factor constant in your page, if you change it;
  • a border colour and - important! - a background colour. Those attributes will determine the colour of your bar.
Here is the code:
<table width="20" height="<%=CInt(rs.Fields.Item("jan_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table>
Then, we close the containing table and start again with a new column.
            </td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" >
...and so on. We have to repeat the process 12 times (for each month).
The above code will create a table containing all the data. The main table contains other tables each containing the table we actually use to draw the bars. The final result is:
<table width="100%" border="1" cellpadding="0" cellspacing="0">
  <tr>
    <td height="30" valign="bottom"><div align="right">100</div></td>
    <td width="0" rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("jan_v").Value)*3%>" border="0" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("feb_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("mar_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("apr_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("may_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("jun_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("jul_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("aug_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("sep_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("oct_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("nov_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
    <td rowspan="11" valign="bottom"><div align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
          <tr>
            <td width="50%" valign="bottom" ><table width="20" height="<%=CInt(rs.Fields.Item("dec_v").Value)*3%>" border="1" align="center" bordercolor="#FF0000" bgcolor="#CCCCFF">
                <tr>
                  <td></td>
                </tr>
              </table></td>
          </tr>
        </table>
      </div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">90</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">80</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">70</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">60</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">50</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">40</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">30</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">20</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">10</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="right">0</div></td>
  </tr>
  <tr>
    <td height="30" valign="bottom"><div align="center">&nbsp;</div></td>
    <td><div align="center">Jan</div></td>
    <td><div align="center">Feb</div></td>
    <td><div align="center">Mar</div></td>
    <td><div align="center">Apr</div></td>
    <td><div align="center">May</div></td>
    <td><div align="center">Jun</div></td>
    <td><div align="center">Jul</div></td>
    <td><div align="center">Aug</div></td>
    <td><div align="center">Sep</div></td>
    <td><div align="center">Oct</div></td>
    <td><div align="center">Nov</div></td>
    <td><div align="center">Dec</div></td>
  </tr>
</table>
The final effect will be:
100
90
80
70
60
50
40
30
20
10
0
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec

What about horizontal bars?
If you want to create horizontal bar charts, you have to consider the width attribute instead of the height  attribute of your table.
This is the code as an example:
<table width="330" border="0">
  <tr>
    <td colspan="11"><table width="70" border="1" bordercolor="#CCCCFF" bgcolor="#CCCCFF">
        <tr  bgcolor="#CC66FF">
          <td></td>
        </tr>
        <tr>
          <td></td>
        </tr>
        <tr bgcolor="#CC66FF">
          <td></td>
        </tr>
      </table></td>
  </tr>
  <tr>
    <td width="30"><div align="left">|0</div></td>
    <td width="30"><div align="left">|10</div></td>
    <td width="30"><div align="left">|20</div></td>
    <td width="30"><div align="left">|30</div></td>
    <td width="30"><div align="left">|40</div></td>
    <td width="30"><div align="left">|50</div></td>
    <td width="30"><div align="left">|60</div></td>
    <td width="30"><div align="left">|70</div></td>
    <td width="30"><div align="left">|80</div></td>
    <td width="30"><div align="left">|90</div></td>
    <td width="30"><div align="left">|100</div></td>
  </tr>
</table>
And the result will be:
|0
|10
|20
|30
|40
|50
|60
|70
|80
|90
|100

Conclusion
I believe that the above examples can be a good solution for simple bar charts. It is just a starting point. For instance, you can apply jQuery effects to your bars in order to make them fade in or you can use css to create particular background colours for the bars. Your imagination will then be the only limit.

Happy coding, and please add your thoughts to the comment section.

3 comments:

  1. I love it, exactly what I need! Thanks!

    ReplyDelete
  2. This is neat trick. Although in this modern world there are not many places where you would need to use such an approach but it definitely wins where you can use only plan html.

    Good work

    ReplyDelete

Comments are moderated. I apologize if I don't publish comments immediately.

However, I do answer to all the comments.