JavaScript Bar Graph Control

By Robbe D. Morris

Printer Friendly Version

Robbe Morris
Robbe & Melisa Morris
Recently, I wrote an article called JavaScript Slider Control that described how to create a custom slider control for a web based research tool accessed by visitors using Internet Explorer 5.5 and above.  This article is a follow up to that one.  Here we'll show you how to create a 100% client side Bar Graph control for IE 5.5/Netscape 6.2 and above which dynamically builds great looking bar graph charts dynamically without having to refresh the page.  Like the Slider Control, this particular Bar Graph control supports two types of math options: Percent Range and Score (1-9) Range.
If you've already read the JavaScript Slider Control article, then you'll notice that I've simply stripped out the unnecessary functions and combined the remaining functions into one file.  If you choose, you can easily combine the JavaScript Slider Control and the JavaScript Bar Graph Control on one page and trigger refreshes of the bar graph when the slider has completed it's work.  While the test values I've used in both the JavaScript Slider Control and JavaScript Bar Graph Control are the same, your implementation will undoubtedly have different values for the bar graph such as ranking or probability scores.
This example was written in large part to work hand in hand with the Slider control mentioned above.  If your requirements are much more simplistic, it would certainly make sense to simplify the array and some of the functions for drawing the chart.  Feel free to take what you need from the sample and manipulate it to fit your needs.
The demonstration below shows both math options.  Simply click the desired link below the slider to view the four test groups I've put together for you.
 


The bar graph control is driven by one JavaScript file: BarGraphDraw.js.  The bar graph works on a relatively simple premise.  Each function is designed to accept an array which contains individual arrays for each bar in the graph.  At a minimum, the arrays will contain a unique key, element name, weight, display boolean, and math option.  If necessary, elements can be added to the array without breaking the existing bar graph code.
BarGraphDraw.js contains the code necessary to redraw the bar graph based on the display boolean value for each bar.  I've included a test JavaScript file called BarGraphTest.js that shows how to change the display boolean value of certain bars dynamically based on user selection.  This test file is not needed in your implementation of the bar graph control.  BarGraphDraw.js requires that the HTML page that holds the slider control contain two DIV tags: BarGraphHiddenElements and BarGraphTableBarGraphHiddenElements contains hidden INPUT tags to store the weights from the bar graph for posting the values back to the web server.  BarGraphTable contains the HTML for the bar graph itself within it's .innerHTML property.
I've included a method called BarGraphSaveElements to save of the values of the chart into hidden form variables.  It is not used in this sample.  It was simply included for your convenience.
As part of the demo, I've also put together Default.htm as a sample HTML page that demonstrates how to build the master Bar GraphArray along with the two required DIV tag references: BarGraphHiddenElements and BarGraphTable.  Take notice of the BODY onLoad event as well as the test links.  They'll show you how to redraw the bar graph based on user selection.
This source code has been made available for your use in both commercial and non-commercial applications free of charge.  However, you are not free to repackage the source code and sell it as an individual user control or part of a package of user controls.
Feel free to download the bar graph source code zip file: Bar Graph Source Code or copy/paste the code below.
 
Default.htm
 
 <HTML>
   <HEAD>
    <META HTTP-EQUIV='Pragma' CONTENT='no-cache'>
    <META HTTP-EQUIV='Expires' CONTENT='0'>
    <META http-equiv='Cache-Control' content='no-cache'>
    <TITLE>NullSkull.com Bar Graph Control By Robbe D. Morris</TITLE>

<script language=JavaScript src=BarGraphDraw.js></script> 
<script language=JavaScript src=BarGraphTest.js></script>


<script language=JavaScript>

         //  Element array constants used to identify positions in the array

        
         var idxBarGraphDisplayKey=0;
         var idxBarGraphDisplayName=1;
         var idxBarGraphDisplay=2;
         var idxBarGraphDisplayWeight=3;
         var idxBarGraphMathType=4
      

         var BarGraphArrays = new Array();

               BarGraphArrays[0] = new Array ('1000','Element 0',false,'15.7',BarGraphMathTypePercent); 
               BarGraphArrays[1] = new Array ('1001','Element 1',false,'20.0',BarGraphMathTypePercent);                        
               BarGraphArrays[2] = new Array ('1002','Element 2',false,'19.4',BarGraphMathTypePercent); 
               BarGraphArrays[3] = new Array ('1003','Element 3',false,'5.2',BarGraphMathTypePercent); 
               BarGraphArrays[4] = new Array ('1004','Element 4',false,'20.5',BarGraphMathTypePercent); 
               BarGraphArrays[5] = new Array ('1005','Element 5',false,'8.7',BarGraphMathTypePercent); 
               BarGraphArrays[6] = new Array ('1006','Element 6',false,'10.2',BarGraphMathTypePercent); 
               BarGraphArrays[7] = new Array ('1007','Element 7',false,'4.0',BarGraphMathTypeScore); 
               BarGraphArrays[8] = new Array ('1008','Element 8',false,'7.0',BarGraphMathTypeScore); 
               BarGraphArrays[9] = new Array ('1009','Element 9',false,'5.0',BarGraphMathTypeScore); 
               BarGraphArrays[10] = new Array ('1010','Element 10',false,'3.4',BarGraphMathTypeScore); 
               BarGraphArrays[11] = new Array ('1011','Element 11',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[12] = new Array ('1012','Element 12',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[13] = new Array ('1013','Element 13',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[14] = new Array ('1014','Element 14',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[15] = new Array ('1015','Element 15',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[16] = new Array ('1016','Element 16',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[17] = new Array ('1017','Element 17',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[18] = new Array ('1018','Element 18',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[19] = new Array ('1019','Element 19',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[20] = new Array ('1020','Element 20',false,'10.0',BarGraphMathTypePercent); 
               BarGraphArrays[21] = new Array ('1021','Element 21',false,'2.5',BarGraphMathTypeScore); 
               BarGraphArrays[22] = new Array ('1022','Element 22',false,'8.5',BarGraphMathTypeScore); 
               BarGraphArrays[23] = new Array ('1023','Element 23',false,'7.5',BarGraphMathTypeScore); 
               BarGraphArrays[24] = new Array ('1024','Element 24',false,'6.5',BarGraphMathTypeScore); 
               BarGraphArrays[25] = new Array ('1025','Element 25',false,'2.5',BarGraphMathTypeScore); 
               BarGraphArrays[26] = new Array ('1026','Element 26',false,'9.0',BarGraphMathTypeScore); 
               BarGraphArrays[27] = new Array ('1027','Element 27',false,'2.5',BarGraphMathTypeScore); 
               BarGraphArrays[28] = new Array ('1028','Element 28',false,'4.5',BarGraphMathTypeScore); 
               BarGraphArrays[29] = new Array ('1029','Element 29',false,'5.75',BarGraphMathTypeScore); 
               BarGraphArrays[30] = new Array ('1030','Element 30',false,'2.5',BarGraphMathTypeScore); 

</script>
   
<style>
.BodyHeader {	font-family:verdana,arial,helvetica;sans-serif; color:#000000;	font-size:16px; 	
                           font-weight:normal; 	text-decoration:none; 	font-style:normal; }
.BodyHeader2 {	font-family:verdana,arial,helvetica;sans-serif; color:#000000;	font-size:10px; 
                            	font-weight:normal; 	text-decoration:none; 	font-style:normal; }
.BodyLink {	font-family:verdana,arial,helvetica;sans-serif; color:#5D7BBA;	font-size:10px; 
                     	font-weight:normal; 	text-decoration:underline; 	font-style:normal; }
</style>

  </HEAD>

<BODY onload="BarGraphWriteInputs(BarGraphArrays);BarGraphTest(BarGraphArrays,1);" >
 
 <table border="0" align="center">
   <tr><td align="center" class=BodyHeader>NullSkull.com Bar Graph Demo</td></tr>
   <tr><td align="center" class=BodyHeader2>By Robbe D. Morris</td></tr>
   <tr><td align="center"> </td></tr>
   
   <tr><td><div id=BarGraphTable name=BarGraphTable > </div> </td></tr>
   <tr><td align="center"><Br></td></tr>
   <tr><td align="center"><a href=javascript:BarGraphTest(BarGraphArrays,1); class=BodyLink>Percentage Example 1</a>
       <a href=javascript:BarGraphTest(BarGraphArrays,2); class=BodyLink>Score Example 1</a></td></tr>
 <tr><td align="center"><a href=javascript:BarGraphTest(BarGraphArrays,3); class=BodyLink >Percentage Example 2</a>
     <a href=javascript:BarGraphTest(BarGraphArrays,4); class=BodyLink>Score Example 2</a></td></tr>
 </table>
   
 <div id=BarGraphHiddenElements name=BarGraphHiddenElements ></div>
</BODY>
</HTML>


BarGraphTest.js
 
 
 function BarGraphTest(GraphArrays,nTest)
  {

            var oBarGraphRow;
            var lArrayLength=0;
            var lLoop=0;
            var lFoundCnt=0;
 
       try
		  {

             lArrayLength = GraphArrays.length;
 
    	     if (lArrayLength < 1) { return false; }
 
             for (lLoop=0; lLoop=0) && (lLoop <=6))                                                
                                         { oBarGraphRow[idxBarGraphDisplay] = true;  }

                                        break;

                         case 2 :

   
                                         if ((lLoop >6) && (lLoop <=10))                                             
                                         { 	oBarGraphRow[idxBarGraphDisplay] = true;  }
                                        
                                        break;

						case 3 :

   
                                        if ((lLoop >10) && (lLoop <=20))                                      
                                         { 	oBarGraphRow[idxBarGraphDisplay] = true;  }
                                        
                                        break;

						case 4 :

   
                                       if ((lLoop >20) && (lLoop <=30))                                    
                                         { 	oBarGraphRow[idxBarGraphDisplay] = true;  }
                                        
                                        break;
         
                 }

               GraphArrays[lLoop] = oBarGraphRow;

            }

		  }
		   catch (exception) 
	     	{ 
			   if (exception.description == null) { alert("Test Error: " + exception.message); }  
		       else {  alert("Test Error: " + exception.description); }
             }
	 
        BarGraphDrawTable(GraphArrays);
      }
  
BarGraphDraw.js
 
 var BarGraphBarColor = '#330066';
 var BarGraphBarBorder = '2';
 var BarGraphMaxWidth=200; 
 var BarGraphMathOption=1;
 var BarGraphTableWidth=430;
 var BarGraphTableTDWidth=230;
 var BarGraphMathTypePercent=1;
 var BarGraphMathTypeScore=2;


 function BarGraphDrawTable(GraphArrays)
  {

      
      var sBarGraphName='';
      var sBarGraphWgt='';
      var sH='';
      var Idx=0;
      var lArrayLength=0;
      var lLoop=0;
      var lFoundCnt=0;
      var oBarGraphRow;
      var nWidth=0;
      var nWeight=0;
      var sBarGraphBarBorder='BORDER-RIGHT: ' + BarGraphBarBorder + 'px outset ' + BarGraphBarColor + '; ';
            sBarGraphBarBorder+='BORDER-LEFT: ' + BarGraphBarBorder + 'px outset ' + BarGraphBarColor + ';';
            sBarGraphBarBorder+=' BORDER-TOP: ' + BarGraphBarBorder + 'px outset ' + BarGraphBarColor + ';';
            sBarGraphBarBorder+=' BORDER-BOTTOM: ' + BarGraphBarBorder + 'px outset ' + BarGraphBarColor;
      var sBarGraphWeightStyle='font-family:verdana,arial,helvetica;sans-serif color:#000000; font-size:12px;align="right"; '
            sBarGraphWeightStyle +='BORDER-RIGHT: 0px outset #5D7BBA; BORDER-LEFT: 0px outset #5D7BBA; ';
            sBarGraphWeightStyle +=' BORDER-TOP: 0px outset #5D7BBA; BORDER-BOTTOM: 0px outset #5D7BBA;';
            sBarGraphWeightStyle +=' text-align: RIGHT;BACKGROUND-COLOR:#FFFFFF;height:20px;';
      var sBarGraphNameStyle ='font-family:verdana,arial,helvetica;sans-serif color:#000000; font-size:12px;'
            sBarGraphNameStyle +=' text-decoration:none; font-style:bold; background-color:#FFFFFF; ';
      var sBarGraphInsStyle='font-family:verdana,arial,helvetica;sans-serif color:#000000; font-size:10px;';
            sBarGraphInsStyle +=' text-decoration:none; font-style:bold; background-color:#FFFFFF; ';
      var oBarGraph = document.getElementById('BarGraphTable');
      var oBarGraphDIV;
 
   try
	  {

 
        lArrayLength = GraphArrays.length;

    	if (lArrayLength < 1) { return false; }
 
        sH += '<table border="0" align="left" width=' + BarGraphTableWidth + ' cellpadding=0 cellspacing="2" >';
 
 
        for (lLoop=0; lLoop<lArrayLength; lLoop++)
       {
		  
           oBarGraphRow = GraphArrays[lLoop];
           Idx = lLoop;
  
           if (oBarGraphRow[idxBarGraphDisplay] == true)
            {
       
               lFoundCnt +=1;

               sBarGraphName = 'id=divBarGraph_' + Idx + ' name=divBarGraph_' + Idx;
               sBarGraphWgt = 'id=txtBarGraphWeight_' + Idx + ' name=txtBarGraphWeight_' + Idx;
           
   
              sH += '<tr>';
              sH += '<td align="left" valign=middle nowrap width=125 style="' + sBarGraphNameStyle + '">' 
              sH += oBarGraphRow[idxBarGraphDisplayName] + ' </td>';
              sH += '<td align="left" valign="top"  width=' + BarGraphTableTDWidth + ' height=20 ';
              sH += ' id=tblBarGraph1 name=tblBarGraph1 nowrap>';
              sH += '<div ' + sBarGraphName + ' style="' + sBarGraphBarBorder + ';position:relative;left:0px;top:0px;height:20;'
              sH += 'width:0;valign:top;BACKGROUND-COLOR:' + BarGraphBarColor + ';"></div></td>';
              sH += '<td align="right"><input ' + sBarGraphWgt + ' type=text value="0.00" READONLY size=6 maxlength=30 ';
              sH += ' style="' + sBarGraphWeightStyle + '" ></td>';
              sH += '</tr>';
 
              BarGraphMathOption = oBarGraphRow[idxBarGraphMathType];

            }
          }

             sH += '<tr><td align="center" colspan="2"> </td><td align="center" style="' + sBarGraphInsStyle + '">';
	         sH += '</td><td> </td></tr>';
             sH += '</table>';
      
             oBarGraph.innerHTML=sH;

	         for (lLoop=0; lLoop<lArrayLength; lLoop++)
            {
		  
               oBarGraphRow = BarGraphArrays[lLoop];
               Idx = lLoop;
           
               if (oBarGraphRow[idxBarGraphDisplay] == true)
               {
       
                  lFoundCnt +=1;
                  oBarGraphDIV = document.getElementById('divBarGraph_' + Idx);

                  nWidth = BarGraphConvertWeightToWidth(oBarGraphRow[idxBarGraphDisplayWeight]); 
			               
		  if ((nWidth > BarGraphMaxWidth) || (nWidth < 0)) 
		   { 
		     nWidth = 0; 
		     nWeight = BarGraphConvertWidthToWeight(nWidth);
					   }
                  else { nWeight = oBarGraphRow[idxBarGraphDisplayWeight]; }
                
          
	          oBarGraphDIV.style.width=nWidth;
			  
		  document.getElementById("txtBarGraphWeight_" + Idx).value = BarGraphRoundNumber(nWeight,"1");
              
                 }
	        }
             BarGraphSaveElements(GraphArrays);
	      }
	       catch (exception) 
		  { 
		     if (exception.description == null) { alert("BarGraph Draw Error: " + exception.message); }  
		     else {  alert("BarGraph Draw Error: " + exception.description); }
		  }
  }


   function BarGraphWriteInputs(GraphArrays)
  {

      var sBarGraphName='';
      var lArrayLength=0;
      var lLoop=0;
      var sH='';
      var oBarGraphRow;
 
     try
	  {

      var oBarGraph = document.getElementById('BarGraphHiddenElements');
  
        lArrayLength = GraphArrays.length;

    	if (lArrayLength < 1) { return false; }
 
        for (lLoop=0; lLoop<lArrayLength; lLoop++)
       {
		  
           oBarGraphRow = GraphArrays[lLoop]; 
           
           sBarGraphName = 'id=savBarGraph_' + oBarGraphRow[idxBarGraphDisplayKey]  + ' name=savBarGraph_' ;
           sBarGraphName += oBarGraphRow[idxBarGraphDisplayKey] ;  

           sH += '<input ' + sBarGraphName + ' type=hidden value="' + oBarGraphRow[idxBarGraphDisplayWeight] + '"';
           sH += ' size=10 maxlength=30 size=10>'; 
	 
        }
         
        oBarGraph.innerHTML=sH;
	 
  } 
    catch (exception) 
    { 
      if (exception.description == null) { alert("BarGraph Hidden Elements: " + exception.message); }  
      else {  alert("BarGraph Hidden Elements: " + exception.description); }
    }
  }



 function BarGraphSaveElements(GraphArrays)
   {

      var lArrayLength=0;
      var lLoop=0;
      var oBarGraphRow;
	  var sKey;
 
   
      try
	  {

        lArrayLength = GraphArrays.length;

    	if (lArrayLength < 1) { return false; }
 
        for (lLoop=0; lLoop<lArrayLength; lLoop++)
       {
		  
           oBarGraphRow = GraphArrays[lLoop];
    
           if (oBarGraphRow[idxBarGraphDisplay] == true)
            {
               oBarGraphRow[idxBarGraphDisplayWeight] = document.getElementById("txtBarGraphWeight_" + lLoop).value;
               document.getElementById("savBarGraph_" + oBarGraphRow[idxBarGraphDisplayKey]).value = oBarGraphRow[idxBarGraphDisplayWeight];
			}
        }
	  }
	  catch (e) {}
   }


  

	function BarGraphConvertWidthToWeight(nWidth)
	{
         var nRet=0;
         var nMax=0;
         var nWeight=0;

         nMax = parseFloat(BarGraphMaxWidth);
         nWidth = parseFloat(nWidth);
 
         switch (BarGraphMathOption)
		{

              case 1:
 
                     nWeight = (nWidth / nMax) * 100;	   
                     nRet =  nWeight;
                     break;

              case 2:
 
                     nWeight = (nWidth / nMax) * 9;	
                     if (nWeight <1) { nWeight=1; }
                     nRet =  nWeight;
	             break;

		}

		 return nRet;
		  
	}

	function BarGraphConvertWeightToWidth(nWeight)
	{
         var nRet=0;
         var nMax=0;
         var nWidthPercent=0;
		  
         nMax = parseFloat(BarGraphMaxWidth);
         nWeight = parseFloat(nWeight);
 
         switch (BarGraphMathOption)
		{

              case 1:

                      nWeight = nWeight * 2;						   
                      nRet = BarGraphRoundNumber(nWeight,"1");
                      break;

              case 2:

                      if ((nWeight<1) || (nWeight >9)) { nWeight=1;}
                      nWidthPercent = nWeight / 9;
                      nRet = BarGraphRoundNumber(nMax * nWidthPercent,"1");
                      break;

		}

		 return nRet;
		  
	}


  function BarGraphRoundNumber(number,X)
  {
	  
    var number2;
    var TmpNum;

    X=(!X ? 1:X);
	
    number2 = Math.round(number*Math.pow(10,X))/Math.pow(10,X);
    TmpNum = "" + number2;
    var TmpArray = TmpNum.split(".");
    if (TmpArray.length <2) { number2 = number2 + ".0"; }
	 
    return number2;
  }
 

 

Robbe has been a Microsoft MVP in C# since 2004.  He is also the co-founder of NullSkull.com which provides .NET articles, book reviews, software reviews, and software download and purchase advice.