Thursday, February 07, 2008

Using Yahoo UI Charts With ADO.NET (Astoria) Data Services

Recently I've been working on a time tracking application for my wife so that she can track time and generate invoices for her fledgling consulting business.

*Shameless plug: If you need any UI design help, she's awesome, really.  Her designs are sharp and professional, and she'll even build it out in HTML for you.  You can contact me at jfiorato at gmail dot com if you're interested in her services.*

One of the things I wanted to add to this application, is some charts that display some interesting metrics.  I'd had some mild exposure to YUI's charts, and found the flash rendering of charts preferable to the image generation that you get with Google's recently released chart API.

To connect ADO.NET Data Services with the Yahoo Chart API, I'm going to do the following:

  1. Create my simple ADO.NET Data Service.
  2. Add a reference to the ADO.NET Data Services client side library.
  3. Add references to the Yahoo UI Chart API.
  4. Make a service call to ADO.NET through Javascript.
  5. Pipe the results to a Yahoo DataSource
  6. Provide the DataSource to the Yahoo Chart API

So, first thing I'm going to do is create my data service.  This involves creating a Linq to Sql class and making it available as a service.  You can follow the most of the instructions from my post about creating a simple REST service with ASP.NET Data Services.

Next I'll add my references to the ADO.NET Data Services Client Side UI Library to the ScriptManager:

<asp:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <asp:ScriptReference Name="MicrosoftAjaxDataService.js" />
    </Scripts>
</asp:ScriptManager>

Then I'll do as the Yahoo Charts API documentation tells me, and add my div tag for the chart, then after that, a reference to all the Yahoo Javascript libraries.

<div id="myContainer" />
<!-- Dependencies -->
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/element/element-beta-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/datasource/datasource-beta-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/json/json-beta-min.js"></script>
<!-- OPTIONAL: Connection (enables XHR) -->
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/connection/connection-min.js"></script>
<!-- Source files -->
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/charts/charts-experimental-min.js"></script>

Once these are all put together, then I'll make my call to the ADO.NET Data Service through Javascript, then loop through the results, add them to a Yahoo DataSource object, then send the object to the Chart object.

<script type="text/javascript">
 
    var myAstoriaService = new Sys.Data.DataService("Services/TimeTrackerDataService.svc");
    myAstoriaService.query("/TimeEntries?$orderby=Date", ServiceCall_Success, ServiceCall_Error);
 
    function ServiceCall_Success(result, context, operation)
    {
        Sys.Debug.clearTrace();
        Sys.Debug.trace(result.length);
        var dataSet = new Array();
        for(i=0;i<result.length;i++)
        {
            dataSet[i] = { Date: YAHOO.util.Date.format(result[i].Date, "DD/MM/YYYY"), Duration: result[i].Duration.toString() };
        }
 
        YAHOO.widget.Chart.SWFURL = "http://yui.yahooapis.com/2.4.0/build/charts/assets/charts.swf";
 
        var myDataSource = new YAHOO.util.DataSource(dataSet);
        myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
        myDataSource.responseSchema =
        {
            fields: [ "Date","Duration" ]
        };
 
        var myChart = new YAHOO.widget.ColumnChart( "myContainer", myDataSource,
        {
            xField: "Date",
            yField: "Duration"
        });
    }
 
    function ServiceCall_Error(error, context, operation)
    {
        alert(error);
    }
</script>

Now, the only bummer about this is that I have to use the ADO.NET Data Services Client Libraries.  The Yahoo Datasource is perfectly capable of taking a URL that returns either XML or JSON and populating itself.  However, it appears that the JSON that ADO.NET Data Services generates isn't exactly valid JSON, according to www.json.org and the Yahoo JSON parser.

I guess there isn't a whole lot of code here anyway.  So it's not too bad.  Another limitation, is that when you're building charts you usually need to do some grouping and sorting of those groups to get interesting chart data.  From what limited documentation there is on this right now, I can't find a way to do any grouping of the data through the URL Addressing Scheme.