<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>CruiseControl</title>
        <link>http://www.ridgway.co.za/category/23.aspx</link>
        <description>Posts related to CruiseControl</description>
        <language>en-ZA</language>
        <copyright>Eden Ridgway</copyright>
        <managingEditor>eden@ridgway.co.za</managingEditor>
        <generator>Subtext Version 1.9.5.176</generator>
        <item>
            <title>Adding Custom Graphs to the CruiseControl.Net Statistics Replacement</title>
            <link>http://ridgway.co.za/archive/2007/05/21/adding-custom-graphs-to-the-cruisecontrol.net-statistics-replacement.aspx</link>
            <description>In version 2.7 of CCNet graphs I made some further improvements to the manner in which graphs are configured.  Now any customisations that need to be done are housed in the &lt;span style="font-weight: bold; color: rgb(0, 0, 255);"&gt;GraphConfiguration.js&lt;/span&gt; file (in the webdashboard\javascript folder).  The logic in the graph generation is now also resilient to problems such as blank or non-numeric data in the custom nodes.&lt;br /&gt;
&lt;br /&gt;
If you want to include custom data in your report you should read the &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/Statistics+Publisher" target="_blank"&gt;Statistics Publisher Wiki page&lt;/a&gt; to get the it included in the report.xml file (which you will find in your artifacts folder for each project).&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Configuration Setup&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
There are 3 areas of configuration, the:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Recent Graphs Tab&lt;/span&gt; - the details of which are stored in the _recentGraphConfigurations array of configuration/option objects.  The datasource of each refers to the _recentStatistics object array, that contains up to the last 20 build statistics.&lt;/li&gt;
    &lt;li&gt;Manner in which &lt;span style="font-weight: bold;"&gt;Summary Data is calculated&lt;/span&gt; - this is stored in the _summaryConfiguration object that contains functions that accept successful and failed build arrays for a day and return an numeric value for each. &lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Historic Builds Tab&lt;/span&gt; - is configured in the same way as the Recent Graphs Tab, except is defined in the _historicGraphConfigurations array and each configuration object uses the _summarisedStatistics datasource.  This datasource contains, the item index, DurationInSeconds, TestsPassed (calculated properties not present in the report.xml file) and the summary data properties defined in _summaryConfiguration. &lt;/li&gt;
&lt;/ol&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Example Customisation&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Lets say that one wanted to add a complexity graph to the recent and historic tabs, the changes required would be this:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;One would edit the _recentGraphConfigurations array and add the following (assuming that the xml element node [in the report.xml file] that contains the data is called AverageComplexity):&lt;br /&gt;
    &lt;div class="code"&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;_recentGraphConfigurations &lt;/font&gt;&lt;font color="#0000ff"&gt;=&lt;br /&gt;
        &lt;/font&gt;&lt;font color="#000000"&gt;[&lt;br /&gt;
            &lt;/font&gt;&lt;font color="#006400"&gt;//... Other configuration objects excluded for brevity &lt;br /&gt;
            &lt;/font&gt;&lt;font color="#000000"&gt;{&lt;br /&gt;
                graphName: &lt;/font&gt;&lt;font color="#808080"&gt;"Complexity"&lt;/font&gt;&lt;font color="#000000"&gt;,&lt;br /&gt;
                dataSource: _recentStatistics,&lt;br /&gt;
                numXTicks: _numberRecentGraphXTicks,&lt;br /&gt;
                series: [&lt;br /&gt;
                                { name: &lt;/font&gt;&lt;font color="#808080"&gt;"Average Complexity"&lt;/font&gt;&lt;font color="#000000"&gt;, attributeName: &lt;/font&gt;&lt;font color="#808080"&gt;"AverageComplexity"&lt;/font&gt;&lt;font color="#000000"&gt;, color: &lt;/font&gt;&lt;font color="#808080"&gt;"blue" &lt;/font&gt;&lt;font color="#000000"&gt;}&lt;br /&gt;
                              ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt; &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;Then the manner in which you want to summarise the data on a daily basis needs to be defined in summaryConfiguration.  Note that all the standard summary functions are contained in the QueryFunctions.js file and include methods such as (getLastValue, select, distinct, sum, average, count, min and max).  Say we wanted to display the average complexity value for the day, the configuration would be defined like this: &lt;br /&gt;
    &lt;div class="code"&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;_summaryConfiguration &lt;/font&gt;&lt;font color="#0000ff"&gt;=&lt;br /&gt;
        &lt;/font&gt;&lt;font color="#000000"&gt;{&lt;br /&gt;
            &lt;/font&gt;&lt;font color="#006400"&gt;//Other attributes...&lt;br /&gt;
            &lt;/font&gt;&lt;font color="#000000"&gt;averageComplexity: &lt;/font&gt;&lt;font color="#0000ff"&gt;function&lt;/font&gt;&lt;font color="#000000"&gt;(successfulBuilds, failedBuilds) { &lt;/font&gt;&lt;font color="#0000ff"&gt;return &lt;/font&gt;&lt;font color="#000000"&gt;average(successfulBuilds, &lt;/font&gt;&lt;font color="#808080"&gt;"AverageComplexity"&lt;/font&gt;&lt;font color="#000000"&gt;) }&lt;br /&gt;
        }&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt; &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;Lastly the summarised data collected by the function above for each day must be configured for the history tab, like this:&lt;br /&gt;
    &lt;div class="code"&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;_historicGraphConfigurations &lt;/font&gt;&lt;font color="#0000ff"&gt;=&lt;br /&gt;
        &lt;/font&gt;&lt;font color="#000000"&gt;[&lt;br /&gt;
            &lt;/font&gt;&lt;font color="#006400"&gt;//Other configuration objects...&lt;br /&gt;
            &lt;/font&gt;&lt;font color="#000000"&gt;{&lt;br /&gt;
                graphName: &lt;/font&gt;&lt;font color="#808080"&gt;"Complexity"&lt;/font&gt;&lt;font color="#000000"&gt;,&lt;br /&gt;
                dataSource: _summarisedStatistics,&lt;br /&gt;
                numXTicks: _numberHistoricGraphXTicks,&lt;br /&gt;
                series: [&lt;br /&gt;
                                 { name: &lt;/font&gt;&lt;font color="#808080"&gt;"Average Complexity"&lt;/font&gt;&lt;font color="#000000"&gt;, attributeName: &lt;/font&gt;&lt;font color="#808080"&gt;"averageComplexity"&lt;/font&gt;&lt;font color="#000000"&gt;, color: &lt;/font&gt;&lt;font color="#808080"&gt;"blue" &lt;/font&gt;&lt;font color="#000000"&gt;}&lt;br /&gt;
                              ]&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt; &lt;/div&gt;
    &lt;br /&gt;
    Note how the attribute name here corresponds to the attribute name defined in _summaryConfiguration and not the original statistic configuration element. &lt;/li&gt;
&lt;/ol&gt;
Hopefully the rest is self explanatory. If something does not make sense or I need to explain the configuration approach in more detail, please leave a message on this post.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: rgb(255, 0, 0);"&gt;Update: 7 July 2007 - Clarified some points of confusion around the source of some of the data.&lt;br /&gt;
&lt;/span&gt;&lt;img src="http://ridgway.co.za/aggbug/184.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Eden Ridgway</dc:creator>
            <guid>http://ridgway.co.za/archive/2007/05/21/adding-custom-graphs-to-the-cruisecontrol.net-statistics-replacement.aspx</guid>
            <pubDate>Mon, 21 May 2007 06:01:34 GMT</pubDate>
            <comments>http://ridgway.co.za/archive/2007/05/21/adding-custom-graphs-to-the-cruisecontrol.net-statistics-replacement.aspx#feedback</comments>
            <slash:comments>8</slash:comments>
            <wfw:commentRss>http://ridgway.co.za/comments/commentRss/184.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Dojo Based CruiseControl Statistics Graphs</title>
            <link>http://ridgway.co.za/archive/2007/04/22/dojo-based-cruisecontrol-statistics-graphs.aspx</link>
            <description>I have been making a lot of changes to the CruiseControl Statistics replacement I released a while ago. Most significantly I changed it to use the Dojo charting library and divided the information into tabs. It now looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;table width="100%" align="center"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td valign="top" align="center"&gt;&lt;a target="_blank" href="http://www.flickr.com/photos/47913250@N00/480980818/"&gt;&lt;img width="500" height="251" border="0" alt="CCNetDojoStatisticsBuildReportGraph" src="http://farm1.static.flickr.com/172/480980818_7b8dcb95bb.jpg" /&gt;&lt;/a&gt; &lt;/td&gt;
            &lt;td valign="top" align="center"&gt;&lt;a title="Photo Sharing" target="_blank" href="http://www.flickr.com/photos/47913250@N00/474503297/"&gt;&lt;img width="205" height="240" border="0" alt="DojoHistoricBuildReportGraphs" src="http://farm1.static.flickr.com/219/474503297_e5ffd14a9e_m.jpg" /&gt;&lt;/a&gt; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td colspan="2"&gt;&lt;br /&gt;
            &lt;div style="text-align: center;"&gt;&lt;a target="_blank" href="http://www.flickr.com/photos/47913250@N00/480973085/"&gt;&lt;img width="500" height="172" border="0" alt="CCNetStatisticsBuildTables" src="http://farm1.static.flickr.com/191/480973085_471b68da5b.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Reasons for the Changes&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The reasons for these changes were as follows:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;The display was becoming cluttered with a lot of information that could be nicely separated into tabs. &lt;/li&gt;
    &lt;li&gt;I can now defer the rendering of the tables and historic graphs until the point where the user actually wants to view them. This should dramatically reduce the load time on projects that have a lot of statistics. &lt;/li&gt;
    &lt;li&gt;The dojo charting library is significantly more flexible than PlotKit and will allow for more freedom in future versions. I also expect that others may want graphs that use more than one plotter, like a combination bar and line chart. &lt;/li&gt;
    &lt;li&gt;I will be able to tweak the charting library to do things like rotate the x-axis tick labels so that more of them can be placed on the axis. &lt;/li&gt;
&lt;/ol&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Purpose of the Graphs&lt;/span&gt;&lt;br style="text-decoration: underline;" /&gt;
&lt;br /&gt;
In my previous posts I forgot to explain why I wanted to do all of this in the first place. While having good looking graphs instead of an ugly table is great, what I really wanted to get the following from this, is the following:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;Determine whether or not the development teams were following our development process and making certain their code compiles before checking in. A red flag for me is a project that is frequently broken. I chat to the team and determine the root cause and rectify it. &lt;/li&gt;
    &lt;li&gt;Being able to easily spot projects that are taking long or progressively longer to build and see how I can ensure that it stays at acceptable levels so that the team continue to use CruiseControl effectively. &lt;/li&gt;
    &lt;li&gt;Determine if the teams are fixing their FxCop violations and writing and using unit tests on their projects.&lt;br /&gt;
    &lt;/li&gt;
&lt;/ul&gt;
Other future benefits I would like to get from this are:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;The addition of line counting statistics so I can see how much projects are being worked on and get a sense of code churn. Of course line counting is fraught with problems, but at least it's something. &lt;/li&gt;
    &lt;li&gt;Track project complexity and ensure that we keep it under control. &lt;/li&gt;
&lt;/ul&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Installation&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The &lt;a target="_blank" href="http://www.ridgway.co.za/archive/2007/03/23/180.aspx#InstallationInstructions"&gt;installation instructions&lt;/a&gt; are the same as the previous version.&lt;br /&gt;
&lt;br /&gt;
&lt;table&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;Works well in the following browsers: &lt;/td&gt;
            &lt;td&gt;&lt;img style="width: 32px; height: 32px;" alt="Internet Explorer" src="http://www.ridgway.co.za/Images/ridgway_co_za/InternetExplorerIcon.jpg" /&gt; &lt;img style="width: 32px; height: 32px;" alt="FireFox" src="http://www.ridgway.co.za/Images/ridgway_co_za/FireFoxIcon.jpg" /&gt; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Has some rendering quirks in: &lt;/td&gt;
            &lt;td style="text-align: center;"&gt;&lt;img width="32" height="32" alt="Opera" src="http://www.ridgway.co.za/Images/ridgway_co_za/OperaIcon.jpg" /&gt; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style="vertical-align: middle;"&gt;Have not tested:&lt;/td&gt;
            &lt;td style="vertical-align: middle; text-align: center;"&gt;&lt;img style="width: 32px; height: 32px;" alt="WebKit/Safari" src="http://www.ridgway.co.za/Images/ridgway_co_za/WebKitIcon.jpg" /&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;hr style="width: 100%; height: 2px;" /&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Downloads / Updates&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span style="text-decoration: line-through;"&gt;&lt;/span&gt;Version 2.3 - &lt;/span&gt;&lt;span&gt;27 April 2007] - Changes:&lt;/span&gt;
    &lt;ol&gt;
        &lt;li&gt;Significant restructuring of the graph configuration logic (now lives in a separate file).&lt;span&gt;&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Removed the timeline logic of the graphs.&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Added &lt;span style="font-weight: bold; color: rgb(0, 0, 128);"&gt;coverage graphs&lt;/span&gt; (assumes that the coverage information is stored in the Coverage element). &lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Added tooltips to the graphs (there are problems in IE).&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Graph rendering is now queued with a "Loading..." message in the graph display area. This has helped improve the user experience on the History tab which can be quite slow when displaying a lot of data.&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Miscellaneous other changes in tick generation etc.&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Table cells of greater than 25 characters now wrap. The exception to this is when you have a word without any spaces that exceeds this and is obviously not wrapped. This sometimes happens in the "Build Error Message" column where the path to a file may be very long. I'm considering implementing a solution that splits these up based on a best guess separator (underscore, full stop, or slash).&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;The successful/failed builds are color coded in the detailed table now.&lt;/span&gt; &lt;/li&gt;
    &lt;/ol&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span style="text-decoration: line-through;"&gt;&lt;/span&gt;Version 2.4 - &lt;/span&gt;&lt;span&gt;28 April 2007] - Changes:&lt;/span&gt;
    &lt;ol&gt;
        &lt;li&gt;&lt;span&gt;Fixed a problem that was caused when some statistics had coverage values and others didn't.&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Dramatically improved the performance of the summary logic and it now summarises data on demand. The performance problem here was due to the fact I was using the dojo ArrayList method in the distinct method. On a report with over 1.7MB of data this caused Internet Explorer (it doesn't happen in FF) to display the "A script on this page is causing Internet Explorer to run slowly" message. The performance tweaks have removed this problem, but I'm concerned that it may reappear when processing a much larger file. I created a test case with over 8.5MB of data and I didn't receive the message. However the rendering of the tables on such a report is a bit of a joke. I need to look at further improving the performance of the table rendering functions (I don't believe that doing it in the XSLT is going to render the benefit one would expect due to the amount of HTML the client ends up downloading).&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Split the detailed and summary tables on to separate tabs and now obviously only render them when the user wants to view the respective tab. However this is still too slow.&lt;/span&gt; &lt;/li&gt;
        &lt;li&gt;&lt;span&gt;Increased the time delay between the rendering of the graphs to 150ms.&lt;/span&gt; &lt;/li&gt;
    &lt;/ol&gt;
    &lt;/li&gt;
    &lt;li&gt;[&lt;a href="http://www.ridgway.co.za/demos/CCNetStatisticsGraphs-2.5.zip"&gt;Version 2.5&lt;/a&gt; - 28 April 2007] - Changes:
    &lt;ol&gt;
        &lt;li&gt;Fixed a bug in the tick mark generation that I introduced while making the changes above. Note that now sometimes the last tick mark on the y-axis does not render. I suspect that this is due to the wonders of JavaScript floating point maths (I still need to investigate this fully), but it is a relatively minor issue so I'm not that phased about it. &lt;/li&gt;
        &lt;li&gt;Added the ability to drill down into the detail statistics from the summary table. &lt;/li&gt;
        &lt;li&gt;Now only averages, counts, etc the successful builds (except the for the failed count of course :) ). &lt;/li&gt;
        &lt;li&gt;Various code refactoring. &lt;/li&gt;
    &lt;/ol&gt;
    &lt;/li&gt;
    &lt;li&gt;[&lt;a href="http://www.ridgway.co.za/demos/CCNetStatisticsGraphs-2.6.zip"&gt;Version 2.6&lt;/a&gt; - 18 May 2007] - Changes:
    &lt;ol&gt;
        &lt;li&gt;Fixed a bug caused by unescaped string sequences in the JavaScript statistics object literal definition (i.e. \u was causing a hexidecimal value expected error in IE). Thank you Mo for reporting this. &lt;/li&gt;
    &lt;/ol&gt;
    &lt;/li&gt;
    &lt;li&gt;[&lt;a href="http://www.ridgway.co.za/images/ridgway_co_za/CCNetStatisticsGraphs-2.7.zip"&gt;Version 2.7&lt;/a&gt; - 22 May 2007] - Changes:
    &lt;ol&gt;
        &lt;li&gt;Have improved the manner in which the graphs are configured thereby making it easier for others to add their own custom settings. The details of how this is setup can be found &lt;a href="http://ridgway.co.za/archive/2007/05/21/adding-custom-graphs-to-the-cruisecontrol.net-statistics-replacement.aspx"&gt;here&lt;/a&gt;. &lt;/li&gt;
        &lt;li&gt;Now can jump to the build from the detailed data table.&lt;/li&gt;
        &lt;li&gt;Added pre-configured complexity and sloc graphs. &lt;/li&gt;
    &lt;/ol&gt;
    &lt;/li&gt;
&lt;/ol&gt;
&lt;hr style="width: 100%; height: 2px;" /&gt;
&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;Concerns&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;The Dojo getBorderBox method that the tab control uses is really slow. In some test cases it takes over 5 seconds in total. &lt;/li&gt;
    &lt;li&gt;When switching out of the statistics page Internet Explorer (not FF) struggles and it can take a few seconds just to go back to the listing page. I'm wondering if this is caused by the Dojo framework in some way or by the graphs etc. &lt;/li&gt;
    &lt;li&gt;Internet Explorer is significantly slower than FireFox and Opera. This is inline with the graph rendering performance results at &lt;font face="Arial"&gt;&lt;a href="http://www.ajaxperformance.com/?p=58"&gt;http://www.ajaxperformance.com/?p=58&lt;/a&gt;.&lt;/font&gt;&lt;/li&gt;
    &lt;li&gt;&lt;font face="Arial"&gt;The detailed table rendering performance for projects with lots of builds. A possible solution to this is to introduce paging.&lt;br /&gt;
    &lt;/font&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;&lt;/span&gt;&lt;hr style="width: 100%; height: 2px;" /&gt;
&lt;span style="font-weight: bold; text-decoration: underline;"&gt;To Do&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;Use a frameworks such as &lt;a target="_blank" href="http://www.jsunit.net/"&gt;JsUnit&lt;/a&gt; and &lt;a target="_blank" href="http://jsmock.sourceforge.net/"&gt;JSMock&lt;/a&gt; (maybe even &lt;a href="http://j3unit.sourceforge.net/"&gt;J3Unit&lt;/a&gt;) to properly test the logic. The &lt;a target="_blank" href="http://www.softwareverify.com/javascript/coverage/feature.html"&gt;JavaScript Coverage Validator &lt;/a&gt;may also be of use. &lt;/li&gt;
    &lt;li&gt;Cut down the size of the dojo toolkit distributed with the graphs as it takes quite some time to deploy and there is a lot unnecessary files in the deployment package at the moment.. Basically I need to create a &lt;a target="_blank" href="http://dojotoolkit.org/node/19"&gt;modified build of the Dojo Toolkit&lt;/a&gt; that only includes the pieces that I am using.&lt;/li&gt;
    &lt;li&gt;Find a solution to the single word greater than 25 characters problem in the details table which causes the columns to be very wide. &lt;/li&gt;
    &lt;li&gt;Find a solution to the Internet Explorer tick tooltip problem. At the moment only the ticks for the last series rendered display tooltips. I believe this is because of the way the Graphing library nest each series inside of a div and layer them on top of each other, thereby preventing the data points on the underlying series to receive the events required to display the ticks. &lt;/li&gt;
    &lt;li&gt;Possibly make the ticks a little more informative (requires modifications to the Dojo library). I could use the Dojo tooltip widget to display detailed build information or I could place the information to the right of the graph. &lt;/li&gt;
    &lt;li&gt;Implement filtering in the historic build page that allows graphs to be filtered by date range. I'm a bit concerned about the performance impact of having one master filter that then causes all the graphs to be redrawn.&lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://ridgway.co.za/aggbug/183.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Eden Ridgway</dc:creator>
            <guid>http://ridgway.co.za/archive/2007/04/22/dojo-based-cruisecontrol-statistics-graphs.aspx</guid>
            <pubDate>Sun, 22 Apr 2007 07:00:28 GMT</pubDate>
            <comments>http://ridgway.co.za/archive/2007/04/22/dojo-based-cruisecontrol-statistics-graphs.aspx#feedback</comments>
            <slash:comments>23</slash:comments>
            <wfw:commentRss>http://ridgway.co.za/comments/commentRss/183.aspx</wfw:commentRss>
        </item>
        <item>
            <title>A Simple Dojo Charting Example</title>
            <link>http://ridgway.co.za/archive/2007/04/13/A-Simple-Dojo-Charting-Example.aspx</link>
            <description>&lt;p&gt;When evaluating the &lt;a href="http://dojotoolkit.org/" target="_blank"&gt;Dojo Charting library&lt;/a&gt; as an option for my CruiseControl statistics page replacement it was very evident that the Dojo team hadn't gotten around to providing documentation for this donated library.  If you are unfamiliar with what the features the library offers you should take a look at this &lt;a href="http://ajaxian.com/archives/dojo-charting-engine-released" target="_blank"&gt;Ajaxian post&lt;/a&gt;.  There is also a &lt;a href="http://archive.dojotoolkit.org/nightly/charting/tests/charting/test_engine.html"&gt;test page&lt;/a&gt; for the library which I could have sworn was down a day or two ago.&lt;/p&gt;
&lt;p&gt;In the interest of possibly helping others save some time getting into the chrting library I wanted to post a basic introductory example.  Please be aware that I do not know this library in depth, nor have I worked with the Dojo libraries extensively.&lt;/p&gt;
&lt;p&gt;What is great about the Dojo charting implementation is that it is very versatile.  This however comes at the cost of a slightly more involved structure which makes it somewhat more tedious to use than &lt;a href="http://www.liquidx.net/plotkit/" target="_blank"&gt;PlotKit&lt;/a&gt;.  The composition of the various graphing objects is illustrated in the diagram below.  As you can see from the relationships in the diagram they have allowed for features such as the ability to render multiple different graphs, using different plotters, in one plot area.  They also have different implementations of the Axis, PlotArea and Plotter objects for VML and SVG rendering.&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://www.flickr.com/photos/47913250@N00/457296586/" target="_blank" title="Photo Sharing"&gt;&lt;img width="461" height="391" border="0" src="http://farm1.static.flickr.com/216/457296586_b45eb89c0d_o.gif" alt="Dojo Charting Diargam" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;u&gt;The Example&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So to create a graph one would start off by including a reference to the dojo library and the required namespaces:&lt;/p&gt;
&lt;div class="code"&gt;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;script&lt;/font&gt;&lt;font color="#ff0000"&gt; type&lt;/font&gt;&lt;font color="#0000ff"&gt;="text/javascript"&lt;/font&gt;&lt;font color="#ff0000"&gt; src&lt;/font&gt;&lt;font color="#0000ff"&gt;="dojo/dojo.js"&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;script&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;script&lt;/font&gt;&lt;font color="#ff0000"&gt; type&lt;/font&gt;&lt;font color="#0000ff"&gt;="text/javascript"&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Include the required dojo libraries/namespaces&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;dojo.require(&lt;/font&gt;&lt;font color="#808080"&gt;"dojo.collections.Store"&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;dojo.require(&lt;/font&gt;&lt;font color="#808080"&gt;"dojo.charting.Chart"&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;dojo.require(&lt;/font&gt;&lt;font color="#808080"&gt;'dojo.json'&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;script&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;&lt;font color="#000000"&gt;&lt;/font&gt; &lt;/div&gt;
&lt;p&gt;You then define or retrieve the graph data and store it in the collection store.  This then will be fed into your graph as a series, defined like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;exampleData &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;[&lt;br /&gt;
    { time: &lt;/font&gt;&lt;font color="#800000"&gt;10&lt;/font&gt;&lt;font color="#000000"&gt;, count: &lt;/font&gt;&lt;font color="#800000"&gt;7382 &lt;/font&gt;&lt;font color="#000000"&gt;},&lt;br /&gt;
    { time: &lt;/font&gt;&lt;font color="#800000"&gt;20&lt;/font&gt;&lt;font color="#000000"&gt;, count: &lt;/font&gt;&lt;font color="#800000"&gt;1852 &lt;/font&gt;&lt;font color="#000000"&gt;},&lt;br /&gt;
    { time: &lt;/font&gt;&lt;font color="#800000"&gt;35&lt;/font&gt;&lt;font color="#000000"&gt;, count: &lt;/font&gt;&lt;font color="#800000"&gt;2397 &lt;/font&gt;&lt;font color="#000000"&gt;},&lt;br /&gt;
    { time: &lt;/font&gt;&lt;font color="#800000"&gt;50&lt;/font&gt;&lt;font color="#000000"&gt;, count: &lt;/font&gt;&lt;font color="#800000"&gt;1442 &lt;/font&gt;&lt;font color="#000000"&gt;},&lt;br /&gt;
    { time: &lt;/font&gt;&lt;font color="#800000"&gt;55&lt;/font&gt;&lt;font color="#000000"&gt;, count: &lt;/font&gt;&lt;font color="#800000"&gt;1854 &lt;/font&gt;&lt;font color="#000000"&gt;}&lt;br /&gt;
]&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
var &lt;/font&gt;&lt;font color="#000000"&gt;store &lt;/font&gt;&lt;font color="#0000ff"&gt;= new &lt;/font&gt;&lt;font color="#000000"&gt;dojo.collections.Store()&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;store.setData(exampleData)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
var &lt;/font&gt;&lt;font color="#000000"&gt;timeSeries &lt;/font&gt;&lt;font color="#0000ff"&gt;= new &lt;/font&gt;&lt;font color="#000000"&gt;dojo.charting.Series({&lt;br /&gt;
                                dataSource: store,&lt;br /&gt;
                                bindings: { x: &lt;/font&gt;&lt;font color="#808080"&gt;"time"&lt;/font&gt;&lt;font color="#000000"&gt;, y: &lt;/font&gt;&lt;font color="#808080"&gt;"count" &lt;/font&gt;&lt;font color="#000000"&gt;},&lt;br /&gt;
                                label: &lt;/font&gt;&lt;font color="#808080"&gt;"Example Series"&lt;br /&gt;
                            &lt;/font&gt;&lt;font color="#000000"&gt;})&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt; &lt;/div&gt;
&lt;p&gt;Next come the axis definitions where you can specify the data display range, data source and the tick labels:&lt;/p&gt;
&lt;div class="code"&gt;&lt;font color="#006400"&gt;//Define the x-axis&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;xAxis &lt;/font&gt;&lt;font color="#0000ff"&gt;= new &lt;/font&gt;&lt;font color="#000000"&gt;dojo.charting.Axis()&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Set the upper and lower data range values&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;xAxis.range &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;{ lower: exampleData[&lt;/font&gt;&lt;font color="#800000"&gt;0&lt;/font&gt;&lt;font color="#000000"&gt;].time, upper: exampleData[exampleData.length-&lt;/font&gt;&lt;font color="#800000"&gt;1&lt;/font&gt;&lt;font color="#000000"&gt;].time }&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;xAxis.origin &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#808080"&gt;"max"&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;xAxis.showTicks &lt;/font&gt;&lt;font color="#0000ff"&gt;= true;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;xAxis.label &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#808080"&gt;"Example chart"&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Setup the x tick marks on the chart&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;xAxis.labels &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[ &lt;br /&gt;
                    { label: &lt;/font&gt;&lt;font color="#808080"&gt;'First'&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;20 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                    { label: &lt;/font&gt;&lt;font color="#808080"&gt;'Second'&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;25 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                    { label: &lt;/font&gt;&lt;font color="#808080"&gt;'Third'&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;35 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                    { label: &lt;/font&gt;&lt;font color="#808080"&gt;'Fourth'&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;50 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                    { label: &lt;/font&gt;&lt;font color="#808080"&gt;'Fifth'&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;55 &lt;/font&gt;&lt;font color="#000000"&gt;}&lt;br /&gt;
               ]&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
               &lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Define the y-axis&lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;yAxis &lt;/font&gt;&lt;font color="#0000ff"&gt;= new &lt;/font&gt;&lt;font color="#000000"&gt;dojo.charting.Axis()&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;yAxis.range &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;{ lower: &lt;/font&gt;&lt;font color="#800000"&gt;0&lt;/font&gt;&lt;font color="#000000"&gt;, upper: &lt;/font&gt;&lt;font color="#800000"&gt;5000 &lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;yAxis.showLines &lt;/font&gt;&lt;font color="#0000ff"&gt;= true;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;yAxis.showTicks &lt;/font&gt;&lt;font color="#0000ff"&gt;= true;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;yAxis.label &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#808080"&gt;"Time Taken"&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
   &lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Setup the y tick marks on the chart&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;yAxis.labels &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[ &lt;br /&gt;
                  { label: &lt;/font&gt;&lt;font color="#808080"&gt;"0s"&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;0 &lt;/font&gt;&lt;font color="#000000"&gt;},&lt;br /&gt;
                  { label: &lt;/font&gt;&lt;font color="#808080"&gt;"1s"&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;1000 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                  { label: &lt;/font&gt;&lt;font color="#808080"&gt;"2s"&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;2000 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                  { label: &lt;/font&gt;&lt;font color="#808080"&gt;"3s"&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;3000 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                  { label: &lt;/font&gt;&lt;font color="#808080"&gt;"4s"&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;4000 &lt;/font&gt;&lt;font color="#000000"&gt;}, &lt;br /&gt;
                  { label: &lt;/font&gt;&lt;font color="#808080"&gt;"5s"&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;font color="#000000"&gt;: &lt;/font&gt;&lt;font color="#800000"&gt;5000 &lt;/font&gt;&lt;font color="#000000"&gt;} &lt;br /&gt;
               ]&lt;/font&gt;&lt;font color="#0000ff"&gt;;    &lt;/font&gt; &lt;/div&gt;
&lt;p&gt;You then define how the data will be plotted by defining a Plot and assigning the series with a plotter to render it: &lt;/p&gt;
&lt;div class="code"&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;chartPlot &lt;/font&gt;&lt;font color="#0000ff"&gt;= new &lt;/font&gt;&lt;font color="#000000"&gt;dojo.charting.Plot(xAxis, yAxis)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;chartPlot.addSeries({ &lt;br /&gt;
                data: timeSeries, &lt;br /&gt;
                plotter: dojo.charting.Plotters.CurvedArea &lt;br /&gt;
              })&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt; &lt;/div&gt;
&lt;p&gt;This then needs to be rendered into a specific area, so one defines the PlotArea and adds the Plot to it: &lt;/p&gt;
&lt;div class="code"&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;chartPlotArea &lt;/font&gt;&lt;font color="#0000ff"&gt;= new &lt;/font&gt;&lt;font color="#000000"&gt;dojo.charting.PlotArea()&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;chartPlotArea.size &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;{ width: &lt;/font&gt;&lt;font color="#800000"&gt;380&lt;/font&gt;&lt;font color="#000000"&gt;, height: &lt;/font&gt;&lt;font color="#800000"&gt;170 &lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;chartPlotArea.padding &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;{ top: &lt;/font&gt;&lt;font color="#800000"&gt;20&lt;/font&gt;&lt;font color="#000000"&gt;, right: &lt;/font&gt;&lt;font color="#800000"&gt;20&lt;/font&gt;&lt;font color="#000000"&gt;, bottom: &lt;/font&gt;&lt;font color="#800000"&gt;30&lt;/font&gt;&lt;font color="#000000"&gt;, left: &lt;/font&gt;&lt;font color="#800000"&gt;50 &lt;/font&gt;&lt;font color="#000000"&gt;}&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Add the plot to the area &lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;chartPlotArea.plots.push(chartPlot)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt; &lt;/div&gt;
&lt;p&gt;Finally one needs to create the chart and add the PlotArea to it.  The chart also needs to have a container element, which one assigns to the chart.node.&lt;/p&gt;
&lt;div class="code"&gt;&lt;font color="#0000ff"&gt;var &lt;/font&gt;&lt;font color="#000000"&gt;chart &lt;/font&gt;&lt;font color="#0000ff"&gt;= new &lt;/font&gt;&lt;font color="#000000"&gt;dojo.charting.Chart(&lt;/font&gt;&lt;font color="#0000ff"&gt;null&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#808080"&gt;"Example chart"&lt;/font&gt;&lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#808080"&gt;"This is the example chart description"&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Add the plot area at an offset of 10 pixels from the top left&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;chart.addPlotArea({ x: &lt;/font&gt;&lt;font color="#800000"&gt;10&lt;/font&gt;&lt;font color="#000000"&gt;, y: &lt;/font&gt;&lt;font color="#800000"&gt;10&lt;/font&gt;&lt;font color="#000000"&gt;, plotArea: chartPlotArea })&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;&lt;font color="#006400"&gt;//Setup the chart to be added to the DOM on load&lt;br /&gt;
&lt;/font&gt;&lt;font color="#000000"&gt;dojo.addOnLoad(&lt;/font&gt;&lt;font color="#0000ff"&gt;function&lt;/font&gt;&lt;font color="#000000"&gt;()&lt;br /&gt;
               {&lt;br /&gt;
                   chart.node &lt;/font&gt;&lt;font color="#0000ff"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;dojo.byId(&lt;/font&gt;&lt;font color="#808080"&gt;"GraphContainerArea"&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
                   &lt;/font&gt;&lt;font color="#000000"&gt;chart.render()&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;br /&gt;
               &lt;/font&gt;&lt;font color="#000000"&gt;})&lt;/font&gt;&lt;font color="#0000ff"&gt;;&lt;/font&gt; &lt;/div&gt;
&lt;p&gt;And voila, you have a graph that looks like this:&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://www.flickr.com/photos/47913250@N00/457296570/" target="_blank" title="Photo Sharing"&gt;&lt;img width="409" height="199" border="0" src="http://farm1.static.flickr.com/175/457296570_3c9e315e32_o.jpg" alt="Dojo Graph Example" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To see the graph in action, take a look at this &lt;a href="http://www.ridgway.co.za/demos/DojoChartExample/DemoDojoGraph.html" target="_blank"&gt;demo page&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://ridgway.co.za/aggbug/182.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Eden Ridgway</dc:creator>
            <guid>http://ridgway.co.za/archive/2007/04/13/A-Simple-Dojo-Charting-Example.aspx</guid>
            <pubDate>Fri, 13 Apr 2007 05:14:08 GMT</pubDate>
            <comments>http://ridgway.co.za/archive/2007/04/13/A-Simple-Dojo-Charting-Example.aspx#feedback</comments>
            <slash:comments>9</slash:comments>
            <wfw:commentRss>http://ridgway.co.za/comments/commentRss/182.aspx</wfw:commentRss>
        </item>
        <item>
            <title>CruiseControl.Net Statistics Graphs using PlotKit</title>
            <link>http://ridgway.co.za/archive/2007/03/27/181.aspx</link>
            <description>[&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;: This does not apply to the Dojo Toolkit vesion of the Statistics Plugin.  For information on how to customize that version go to this &lt;a href="http://ridgway.co.za/archive/2007/05/21/adding-custom-graphs-to-the-cruisecontrol.net-statistics-replacement.aspx"&gt;page&lt;/a&gt;.] &lt;br /&gt;
&lt;br /&gt;
As promised in my previous post, &lt;a href="http://ridgway.co.za/archive/2007/03/23/180.aspx"&gt;CruiseControl Statistics Graphs&lt;/a&gt;, here is a high level description of the implementation  that allowed me to display graphs in CruiseControl.Net.  I've also included a quick guide on how to extend the report to include your own custom statistics that you may have published as part of your build.&lt;br /&gt;
&lt;br /&gt;
After I had decided to create a graphical view of the CruiseControl statistics I assessed various options that were available.  My immediate thoughts were to use XSLT to create either SVG or VML graphs.  The problem is that I wanted something that was quick and easy to implement and quite frankly the effort required to do all of this using xslt was just too great.  My attentions then turned to doing the majority of the processing in JavaScript.  The Dojo Charting library was the first solution that sprung to mind, but on further investigation is appeared to be undergoing some restructuring and the documentation is almost non-existent.  It was then that I came across &lt;a href="http://www.liquidx.net/plotkit/"&gt;PlotKit&lt;/a&gt;, a cross browser charting framework built on top of MochiKit.  It was simple and had documentation so it was a clear winner.&lt;br /&gt;
&lt;br /&gt;
So the Statistics Graph solution ended up being structured as follows:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;StatisticsGraphs.xsl - creates JSON representation of the detailed stats data and the general page structure&lt;/li&gt;
    &lt;li&gt;StatisticsGraphs.js - contains the logic to summarise the detailed stats data and to create the plotkit graphs and tables&lt;/li&gt;
    &lt;li&gt;MochiKit_lite_packed.js, PlotKit_Packed.js - packed versions of the libraries that provide the graphing functionality (from PlotKit)&lt;/li&gt;
    &lt;li&gt;excanvas.js - provides canvas emulation for Internet Explorer (from PlotKit)&lt;/li&gt;
&lt;/ol&gt;
If one wanted to create their own custom summary graph of new statistics on the page (for more info on including custom statistics see &lt;a href="http://www.kiwidude.com/blog/2006/10/ccstatistics-for-cruisecontrolnet-11.html"&gt;Grant Drake's blog post&lt;/a&gt;), you would open up StatisticsGraphs.js and do the following:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;Edit the generateDailySummaries function and add your summarised statistic to daySummary&lt;br /&gt;
    &lt;br /&gt;
    &lt;div class="code"&gt; &lt;font color="blue"&gt;var &lt;/font&gt;&lt;font color="black"&gt;daySummary &lt;/font&gt;&lt;font color="blue"&gt;= &lt;br /&gt;
    &lt;/font&gt;&lt;font color="black"&gt;{&lt;br /&gt;
    day : day,&lt;br /&gt;
    successfulBuildCount : count(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"Status"&lt;/font&gt;&lt;font color="black"&gt;, &lt;/font&gt;&lt;font color="blue"&gt;function&lt;/font&gt;&lt;font color="black"&gt;(item) { &lt;/font&gt;&lt;font color="blue"&gt;return &lt;/font&gt;&lt;font color="black"&gt;(item[&lt;/font&gt;&lt;font color="#808080"&gt;"Status"&lt;/font&gt;&lt;font color="black"&gt;] &lt;/font&gt;&lt;font color="blue"&gt;== &lt;/font&gt;&lt;font color="#808080"&gt;"Success"&lt;/font&gt;&lt;font color="black"&gt;)&lt;/font&gt;&lt;font color="blue"&gt;; &lt;/font&gt;&lt;font color="black"&gt;}),&lt;br /&gt;
    failedBuildCount : count(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"Status"&lt;/font&gt;&lt;font color="black"&gt;, &lt;/font&gt;&lt;font color="blue"&gt;function&lt;/font&gt;&lt;font color="black"&gt;(item) { &lt;/font&gt;&lt;font color="blue"&gt;return &lt;/font&gt;&lt;font color="black"&gt;(item[&lt;/font&gt;&lt;font color="#808080"&gt;"Status"&lt;/font&gt;&lt;font color="black"&gt;] &lt;/font&gt;&lt;font color="blue"&gt;== &lt;/font&gt;&lt;font color="#808080"&gt;"Failure"&lt;/font&gt;&lt;font color="black"&gt;)&lt;/font&gt;&lt;font color="blue"&gt;; &lt;/font&gt;&lt;font color="black"&gt;}),&lt;br /&gt;
    lastBuildLabel : getLastValue(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"BuildLabel"&lt;/font&gt;&lt;font color="black"&gt;),&lt;br /&gt;
    testCount : testCount,&lt;br /&gt;
    testsPassed : testCount - testFailures - testsIgnored,&lt;br /&gt;
    testFailures : testFailures,&lt;br /&gt;
    testsIgnored : testsIgnored,&lt;br /&gt;
    fxCopWarnings : average(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"FxCop Warnings"&lt;/font&gt;&lt;font color="black"&gt;),&lt;br /&gt;
    fxCopErrors : average(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"FxCop Errors"&lt;/font&gt;&lt;font color="black"&gt;),&lt;br /&gt;
    averageBuildDuration: average(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"Duration"&lt;/font&gt;&lt;font color="black"&gt;),&lt;br /&gt;
    minBuildDuration: min(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"Duration"&lt;/font&gt;&lt;font color="black"&gt;),&lt;br /&gt;
    maxBuildDuration: max(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"Duration"&lt;/font&gt;&lt;font color="black"&gt;),&lt;br /&gt;
    &lt;br /&gt;
    &lt;/font&gt;&lt;font color="darkgreen"&gt;//Insert new summarised statistics here&lt;br /&gt;
    &lt;/font&gt;&lt;font color="black"&gt;averageCodeCoverage : average(currentStatistics, &lt;/font&gt;&lt;font color="#808080"&gt;"CodeCoverage"&lt;/font&gt;&lt;font color="black"&gt;)&lt;br /&gt;
    }&lt;/font&gt;&lt;font color="blue"&gt;;&lt;/font&gt; 	&lt;/div&gt;
    &lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt; Create a new function to create the graph.  Note that the createGraph function creates the title, graph and legend for you. eg.&lt;br /&gt;
    &lt;br /&gt;
    &lt;div class="code"&gt;&lt;font color="blue"&gt;function &lt;/font&gt;&lt;font color="black"&gt;createCodeCoverageGraph()&lt;br /&gt;
    {&lt;br /&gt;
    createGraph({&lt;br /&gt;
    graphName : &lt;/font&gt;&lt;font color="#808080"&gt;"Average Daily Code Coverage"&lt;/font&gt;&lt;font color="black"&gt;,&lt;br /&gt;
    series : [&lt;br /&gt;
    { &lt;br /&gt;
    name : &lt;/font&gt;&lt;font color="#808080"&gt;"Average Code Coverage"&lt;/font&gt;&lt;font color="black"&gt;, &lt;br /&gt;
    attributeName: &lt;/font&gt;&lt;font color="#808080"&gt;"averageCodeCoverage"&lt;/font&gt;&lt;font color="black"&gt;, &lt;br /&gt;
    color : Color.greenColor() &lt;br /&gt;
    }&lt;br /&gt;
    ]&lt;br /&gt;
    })&lt;br /&gt;
    } &lt;/font&gt; 	&lt;/div&gt;
    &lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt; Then call your new function in the setupGraphs&lt;br /&gt;
    &lt;br /&gt;
    &lt;div class="code"&gt; &lt;font color="blue"&gt;function &lt;/font&gt;&lt;font color="black"&gt;setupGraphs()&lt;br /&gt;
    {&lt;br /&gt;
    createBuildReportGraph()&lt;/font&gt;&lt;font color="blue"&gt;;&lt;br /&gt;
    &lt;/font&gt;&lt;font color="black"&gt;createBuildDurationGraph()&lt;/font&gt;&lt;font color="blue"&gt;;&lt;br /&gt;
    &lt;/font&gt;&lt;font color="black"&gt;createTestGraph()&lt;/font&gt;&lt;font color="blue"&gt;;&lt;br /&gt;
    &lt;/font&gt;&lt;font color="black"&gt;createFxCopGraph()&lt;/font&gt;&lt;font color="blue"&gt;;&lt;br /&gt;
    &lt;br /&gt;
    &lt;/font&gt;&lt;font color="darkgreen"&gt;//Insert calls to functions that create new graphs here&lt;br /&gt;
    &lt;/font&gt;&lt;font color="black"&gt;createCodeCoverageGraph()&lt;/font&gt;&lt;font color="blue"&gt;;&lt;br /&gt;
    &lt;/font&gt;&lt;font color="black"&gt;}&lt;/font&gt;&lt;/div&gt;
    &lt;/li&gt;
&lt;/ol&gt;
So if you are keen to give it a go take a look at my &lt;a href="http://ridgway.co.za/archive/2007/03/27/180.aspx"&gt;previous post&lt;/a&gt; for the download.&lt;img src="http://ridgway.co.za/aggbug/181.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Eden Ridgway</dc:creator>
            <guid>http://ridgway.co.za/archive/2007/03/27/181.aspx</guid>
            <pubDate>Tue, 27 Mar 2007 07:23:42 GMT</pubDate>
            <comments>http://ridgway.co.za/archive/2007/03/27/181.aspx#feedback</comments>
            <wfw:commentRss>http://ridgway.co.za/comments/commentRss/181.aspx</wfw:commentRss>
        </item>
        <item>
            <title>CruiseControl Statistics Graphs</title>
            <link>http://ridgway.co.za/archive/2007/03/23/180.aspx</link>
            <description>&lt;p&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;[&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;Update&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;: &lt;/span&gt;Please note that this approach has been replaced by  a Dojo based solution available from &lt;a href="http://www.ridgway.co.za/archive/2007/04/22/Dojo-Based-CruiseControl-Statistics-Graphs.aspx"&gt;http://www.ridgway.co.za/archive/2007/04/22/Dojo-Based-CruiseControl-Statistics-Graphs.aspx&lt;/a&gt;] &lt;br /&gt;
&lt;/p&gt;
&lt;p&gt; Lets face it, the new CruiseControl Statistics report is damn ugly and is not as useful as it could be.  So I decided to remedy this by replacing the standard statistics xslt transform with one that generates both graphs and tables.  The results are graphs in CruiseControl that look something like the images below.  So what my new CruiseControl Statistics report gives you at the moment is as follows:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Build Report Graph&lt;/span&gt; - the number of failed/successful builds per day and the last build of each day&lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Build Duration Graph&lt;/span&gt; - the average and maximum build duration per day&lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Test Summary Graph&lt;/span&gt; - the average number of tests that passed, failed or were ignored&lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;FxCop Summary Graph&lt;/span&gt; - the average number of warnings and errors per day&lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Build Summary Statistics Table&lt;/span&gt; - a table containing the data that was used to generate the daily stats&lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Build Detailed Statistics Table&lt;/span&gt; - contains the original detailed statistics data as would have been displayed in the old statistics report&lt;/li&gt;
&lt;/ul&gt;
&lt;table width="100%"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td valign="top" align="center"&gt;    &lt;a target="_blank" href="http://www.flickr.com/photos/47913250@N00/453488193/"&gt;&lt;img width="187" height="240" border="0" alt="BuildReportGraphs" src="http://farm1.static.flickr.com/247/453488193_0d4daf9344_m.jpg" /&gt;&lt;/a&gt; &lt;/td&gt;
            &lt;td valign="top" align="center"&gt; &lt;a href="http://www.flickr.com/photos/47913250@N00/431068505/" title="Photo Sharing" target="_blank"&gt;&lt;img width="240" height="99" border="0" src="http://farm1.static.flickr.com/152/431068505_4e1aec6aaf_m.jpg" alt="Build Statics Tables" /&gt;&lt;/a&gt;    &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;a name="InstallationInstructions"&gt;&lt;/a&gt;&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Installation Instructions&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I'll get on to the actual implementation in &lt;a href="http://www.ridgway.co.za/archive/2007/03/23/181.aspx"&gt;another post&lt;/a&gt;, but for now here is how to get it working on your CruiseControl.Net build server:&lt;a href="http://ridgway.co.za/archive/2007/03/23/181.aspx"&gt; &lt;/a&gt;
&lt;ol&gt; &lt;a href="http://ridgway.co.za/archive/2007/03/23/181.aspx"&gt;    &lt;/a&gt;
    &lt;li&gt;Download the latest stable release: &lt;a href="http://www.ridgway.co.za/Demos/CCNetStatisticsGraphs-1.3.zip"&gt;CCNetStatisticsGraphs-1.3.zip&lt;/a&gt;    .  Updates are also present at the end of this post if you feel adventurous.  &lt;span style="font-weight: bold; font-style: italic; color: rgb(255, 0, 0);"&gt;[Note: I have a new version available that uses the Dojo library]&lt;/span&gt;&lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;Unzip the webdashboard folder over the current CruiseControl webdashboard folder (usually found at C:\Program Files\CruiseControl.NET)&lt;/li&gt;
    &lt;li&gt;Open the dashboard.config file in the webdashboard folder and change the the projectStatisticsPlugin setting to point to the new StatisticsGraphs.xsl stylesheet, like this:&lt;br /&gt;
    &lt;br /&gt;
    &lt;div class="code"&gt; &lt;font color="blue"&gt;&amp;lt;&lt;/font&gt;&lt;font color="maroon"&gt;projectStatisticsPlugin&lt;/font&gt;&lt;font color="red"&gt; xslFileName&lt;/font&gt;&lt;font color="blue"&gt;="xsl\StatisticsGraphs.xsl"&lt;/font&gt;&lt;font color="red"&gt; &lt;/font&gt;&lt;font color="blue"&gt;/&amp;gt;&lt;/font&gt; 	&lt;/div&gt;
    &lt;/li&gt;
&lt;/ol&gt;
If it everything is in order you should see the following type of report when viewing your project statics:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;a title="Photo Sharing" target="_blank" href="http://www.flickr.com/photos/47913250@N00/431084927/"&gt;&lt;img width="240" height="124" border="0" alt="Build Report in CruiseControl" src="http://farm1.static.flickr.com/149/431084927_273e0aad54_m.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;
Future improvements to this will largely depend on the interest generated by this post.  If enough people find it useful I'll add new features.  Of course if you extend it, please let me know about it.  Some potential enhancements are:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;The ability to filter the report data&lt;/li&gt;
    &lt;li&gt;Additional reports such as code coverage and complexity reports (based on whether or not the stats are present of course)&lt;/li&gt;
    &lt;li&gt;Static table headers and sorting&lt;/li&gt;
&lt;/ul&gt;
&lt;span&gt;&lt;/span&gt;&lt;hr style="width: 100%; height: 2px;" /&gt;
&lt;br /&gt;
&lt;span&gt;&lt;span style="font-weight: bold; text-decoration: underline; color: rgb(0, 0, 0);"&gt;Notes&lt;/span&gt;&lt;br style="color: rgb(0, 0, 0);" /&gt;
&lt;br style="color: rgb(0, 0, 0);" /&gt;
&lt;span style="color: rgb(0, 0, 0);"&gt;Using PlotKit as the graph rendering engine unfortunately also results in the following issues in the graphs:&lt;/span&gt;&lt;br /&gt;
&lt;/span&gt;
&lt;ol&gt;
    &lt;li&gt;Graphs where you would only expect integer values, display decimals.  There does not seem to be any easy solution to this apart from modifying PlotKit code or ignoring the auto-scaled y-axis figures and writing one's own routine to determine the values and specify the y-axis tick values. [&lt;a style="font-style: italic;" href="#Updates"&gt;Integer y-axis values were implemented in version 1.4&lt;/a&gt;]     &lt;/li&gt;
    &lt;li&gt;There are problems with the labels being truncated on both the vertical and horizontal axis.  One can alleviate the problem somewhat using different margins but at some point you run into trouble.  The space required really needs to be determined dynamically (by the graphing engine).  [&lt;a style="font-style: italic;" href="#Updates"&gt;Problem mostly removed in version 1.5&lt;/a&gt;]&lt;/li&gt;
    &lt;li&gt;With the FxCop report it is difficult to predict whether or not the errors will be greater than warnings and vice-a-versa and hence you cannot use a filled line graph because it may cover up the one set of values.  What would be nice is if you could have the one set of values peek through the other using alpha blending.  Canvas does provide the ability to do this to some degree through the globalCompositeOperation property on the canvas, however this does not work in the IECanvas emulation layer.&lt;/li&gt;
&lt;/ol&gt;
Given the problems mentioned above I may very well switch to using another graphing approach or roll a modified version of Plotkit out.&lt;br /&gt;
&lt;br /&gt;
Some of the suggested enhancements I have received are:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Removal of outliers&lt;/span&gt; - Severe spikes completely mess up the scaling of the graphs.  This one requires some thought because obviously it could also have the affect of making people believe that the graphs are incorrect when in fact the outliers have been removed.&lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Horizontal scaling&lt;/span&gt; - Add in zero values to the graphs for missing days from the start of recorded builds. [&lt;a style="font-style: italic;" href="#Updates"&gt;Implemented in version 1.4&lt;/a&gt;]&lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span style="font-weight: bold;"&gt;Removal of graphs if there no values&lt;/span&gt; - This one I had considered before and since someone else has asked for it, I'm going to implement it it.  It's most obvious when you are not using FxCop and end up with a horrible empty grey block in your report. [&lt;a style="font-style: italic;" href="#Updates"&gt;Implemented in version 1.4&lt;/a&gt;]&lt;/li&gt;
&lt;/ol&gt;
&lt;hr style="width: 100%; height: 2px;" /&gt;
&lt;a name="Updates"&gt;&lt;/a&gt;&lt;strong&gt;&lt;u&gt;Updates&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;span&gt; [Version 1.2 - 8 April 2007] - Fixed an issue caused by apostrophes in the generated statistics (new version 1.2 released) (reported by Grant Drake).&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&lt;a href="http://www.ridgway.co.za/Demos/CCNetStatisticsGraphs-1.3.zip"&gt;Version 1.3&lt;/a&gt; - &lt;/span&gt;&lt;span&gt;8 April 2007] - Fixed an issue in the duration calculation where the duration had an int + string value which of course resulted in a string concatenation :) &lt;/span&gt;&lt;span&gt;(reported by Grant Drake).&lt;/span&gt;&lt;/li&gt;
    &lt;li&gt;&lt;span&gt;[&lt;a href="http://www.ridgway.co.za/Demos/CCNetStatisticsGraphs-1.4.zip"&gt;Version 1.4&lt;/a&gt; - 9 April 2007] - Implemented the following features:&lt;/span&gt;
    &lt;ol&gt;
        &lt;li&gt;&lt;span&gt;Graphs are not displayed when there are no values for them&lt;/span&gt;&lt;/li&gt;
        &lt;li&gt;&lt;span&gt;The x-series values are now a timeline not just all the builds next to each other.  So if there was a build on the 1st of a month and the next build was only on the 4th, zero values are filled in for the 2nd and 3rd of the month.  This has a down side though because at the moment it is displaying weekends for which most projects will have no activity and if a project is worked on sporadically you have large gaps in the graph.  I do believe however there is value in seeing the activity over time in this way and maybe it it worth having some sort of filtering option that allows one to remove weekends and/or days for which there are no statistics.&lt;br /&gt;
        &lt;/span&gt;&lt;/li&gt;
        &lt;li&gt;&lt;span&gt;The y-axis no longer displays values (I manually determined the y-ticks and added them to the graph).&lt;br /&gt;
        &lt;/span&gt;&lt;/li&gt;
    &lt;/ol&gt;
    Only download this release if you are curious about the new functionality.  I will be writing a series of WatiN tests to ensure that everything is working as expected as the mini-project evolves.  My biggest concern for this version is with locales specifically in relation to dates.  To fill in missing days I've used JavaScript date functions and there is an assumption that the browser's locale is the same as that of the server.  Unfortunately this is due to the fact that the CruiseControl month in the statistics xml file is a short name.  Furthermore I cannot use the StartTime value because it is possible that the format of that information is not consistent: one of my example statistics files has StartTime values in both yyyy/MM/dd and dd/MM/yyyy format.&lt;br /&gt;
    &lt;em style="color: rgb(255, 0, 0);"&gt;I found out on the 22 April 2007 that this version suffers from a daylight savings time bug that affected projects that started when daylight savings was in effect.  I have fixed this release.&lt;/em&gt;&lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span&gt;[&lt;a href="http://www.ridgway.co.za/Demos/CCNetStatisticsGraphs-1.5.zip"&gt;Version 1.5&lt;/a&gt; - 10 April 2007] - Modified the PlotKit canvas to allow rendering of HTML labels (i.e. it won't escape your tags) and now draws the graph border and tick marks in the same colour as the axis label colour (I may remove this modification and simply create a new custom canvas).  This has allowed me to reduce the font size of the x-axis labels and put the date on a separate line to the build label.  Unfortunately it has also meant that I'm now distributing the uncompressed version of the PlotKit library (I may use a JavaScript compressor on them later).&lt;/span&gt; &lt;em style="color: rgb(255, 0, 0);"&gt;I found out on the 22 April 2007 that this version suffers from a daylight savings time bug that affected projects that started when daylight savings was in effect.  I have fixed this release.&lt;/em&gt;&lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;span&gt;[Version 2.1] - This is available from &lt;a href="http://www.ridgway.co.za/archive/2007/04/22/Dojo-Based-CruiseControl-Statistics-Graphs.aspx"&gt;this post&lt;/a&gt;.&lt;br /&gt;
    &lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://ridgway.co.za/aggbug/180.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Eden Ridgway</dc:creator>
            <guid>http://ridgway.co.za/archive/2007/03/23/180.aspx</guid>
            <pubDate>Fri, 23 Mar 2007 05:04:17 GMT</pubDate>
            <comments>http://ridgway.co.za/archive/2007/03/23/180.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://ridgway.co.za/comments/commentRss/180.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>