July 3, 2008

Pages


Search Site


Topics


Useful Links

Blogs I Read


Archives

Spry :: Dynamic Graphing With ColdFusion and Spry

November 27 2006 by Andrew Powell
First of all, I needed to generate the chart and XML. ColdFusion does both very well. The file is broken up into functions to increase readability. You can do all this inline, but having functional units to look at greatly increases comprehension. genXML.cfm: <cfscript>
   function main()
   {
      var fullFile = expandPath("/") & "spryGraph.png";
      remFile(fileName=fullFile);
      
      if(isDefined("url.update"))
      {
         addPlayer(playerName=url.name,playerPosition=url.position);
      }
      createChartFile(chartSource=getPlayerList(),fileName=fullFile);
      return createXMLString();
   }
</cfscript>

<cffunction name="addPlayer" access="public" returntype="boolean" hint="Adds a player to the database">
   <cfargument name="playerName" type="string" required="true"/>
   <cfargument name="playerPosition" type="string" required="true"/>
   
   <cfset var retBool = true/>
   
   <cftry>
      <cfquery datasource="#application.datasource#">
         INSERT INTO players(name,position) values(<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.playerName#">,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.playerPosition#">)
      </cfquery>
      <cfcatch type="any">
         <cfset retBool = false/>
      </cfcatch>
   </cftry>
   
   <cfreturn retBool/>
</cffunction>

<cffunction name="remFile" access="public" returntype="boolean" hint="deletes a given file">
   <cfargument name="fileName" type="string" required="true">
   
   <cfset var retBool = true/>
   
   <cftry>
      <cfif fileExists(arguments.fileName)>
         <cffile action="delete" file="#arguments.fileName#"/>
      </cfif>
      <cfcatch type="any">
         <cfset retBool = false/>
      </cfcatch>
   </cftry>
   <cfreturn retBool/>
</cffunction>

<cffunction name="getPlayerList" access="public" returntype="query" hint="returns a list of players in query object">
   <cfset var retQry = queryNew("")/>
   
   <cfquery datasource="#application.datasource#" name="retQry">
      SELECT position, count(position) as cnt FROM players GROUP BY position
   </cfquery>
   
   <cfreturn retQry/>
</cffunction>

<cffunction name="createChartFile" access="public" returntype="boolean">
   <cfargument name="chartSource" type="query" required="true"/>
   <cfargument name="fileName" type="string" required="true"/>
   
   <cfset var playerList = arguments.chartSource/>
   <cfset var spryGraph = ""/>
   <cfset var retBool = true/>
   
   <cftry>
      <cfchart format="png" name="spryGraph" chartheight="270" chartwidth="480" show3d="true">
         <cfchartseries query="playerList" itemcolumn="position" valuecolumn="cnt" type="bar">
      </cfchart>
      
      <cffile action="write" file="#arguments.fileName#" output="#spryGraph#" charset="ISO-8859-1">
      
      <cfcatch type="any">
         <cfset retBool = false>
      </cfcatch>
   </cftry>
   
   <cfreturn retBool/>
</cffunction>

<cffunction name="createXMLString" access="public" returntype="string">
   <cfset var retStr = "">
   <cfsavecontent variable="retStr">
      <cfoutput>
         <fileInfo>
          <fileData>
          <fileName>Player File</fileName>
          <filePath>spryGraph.png?cb=#round(rand("SHA1PRNG")*second(now()))#</filePath>
          </fileData>
         </fileInfo>
      </cfoutput>
   </cfsavecontent>
   <cfreturn retStr>
</cffunction>


<cfcontent type="text/xml">
   <cfoutput>#main()#</cfoutput>
</cfcontent>
Notice the use of CFSAVECONTENT in lieu of CFXML. This keeps your XML as a string and not a CFXML object. CFXML objects take up more memory than simple strings. In an enterprise application, this can become costly. Also notice that in the XML, a cacheBuster (cb) is being added to the file name. This is to keep the browser from reading the image out of cache. Once the XML is generated, we need to find a way to display it. This is not too much different from the Yahoo! Traffic API example. index.cfm: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
      <title>Spry Example 5 - Dynamic Data With Visualization</title>
      <!-- Begin Spry Includes -->
      <script type="text/javascript" src="/assets/js/spry/xpath.js"></script>
      <script type="text/javascript" src="/assets/js/spry/SpryData.js"></script>
      <script type="text/javascript" src="/assets/js/spry/SpryXML.js"></script>
      <!-- End Spry Includes -->
      
      <script type="text/javascript">
         var dsPlayers = new Spry.Data.XMLDataSet("genXML.cfm", "/fileInfo/fileData", { useCache: false});         
         function updatePlayerData(playerForm,spryGraph)
         {
            var playerName = playerForm.playerName.value;
            var playerPosition = playerForm.playerPosition.value;
            var d = new Date();
            dsPlayers.setURL("genXML.cfm?update=1\&position=" + escape(playerPosition) + "\&name=" + escape(playerName));
            dsPlayers.loadData();   
         }
      </script>
   </head>
   <body>
      
      <form id="playerForm" name="playerForm">
         Player Name: <input type="text" id="playerName" name="playerName" /><br/>
         Position:
         <select name="playerPosition" id="playerPosition">
            <option value="Goalkeeper">Goalkeeper</option>
            <option value="Center Back">Center Back</option>
            <option value="Left Back">Left Back</option>
            <option value="Right Back">Right Back</option>
            <option value="Midfield">Midfield</option>
            <option value="Forward">Forward</option>
            <option value="Striker">Striker</option>
         </select><br/>
         <input type="button" id="playerButton" value="Add Player" name="playerButton" onclick="updatePlayerData(playerForm,spryGraph)"/>
      </form>
      
      <div spry:region="dsPlayers">
         <div spry:state="loading"><img src="/assets/images/ajax-loader.gif"/></div>
         <div spry:state="error">An error occured loading your dataset.</div>
         <div spry:state="ready">   
            <script type="text/javascript">
               
            </script>
            <img id="spryGraph" src="{dsPlayers::filePath}" id="" alt="{dsPlayers::fileName}"/>
         </div>
      </div>
   </body>
</html>
You can see a working example here.

Posted in ColdFusion | Spry | AJAX | 3 comments

3 responses to “Spry :: Dynamic Graphing With ColdFusion and Spry”

  1. Raymond Camden Says:
    <p>Your demo link isn't working.</p>
  2. Andrew Powell Says:
    <p>Demo link fixed, but now the code layout is hosed. Go figure.</p>
  3. rob Says:
    <p>i agree does not work and contact to him goes unanswered.</p>

Leave a Reply