Monday, May 4, 2009

Dashboards in MOSS using VisiFire Charts:

Dashboards: An upcoming face of MOSS Business Intelligence

When we think about some jazzy dashboards for any Business Management Solution or Project Management site, Silverlight turns out to be a maximum hit area. I also entered in this magic world after the quest of some jazzy dashboard solution, and found 'VisiFire' is the name of this arena. VisiFire is an open source self contained charting solution built with Silverlight. If you haven't seen VisiFire before, it's worth checking out, their gallery page shows a number of really slick animated charts that are dead simple to use with XML data (without writing any Silverlight code).

I'm not going to do any great thing here as you may get couple of example to walk you through for implementation point of view. So, why I'm writing this blog? Good question!! Well the answer is I'll be taking a scenario where we can twist the XML of these graph as per our need. So it will make more desirable and with this tweak you can show any information in the form of super jazzy Silverlight charts. Let's kick off

  1. Download the latest version of VisiFire package from here: http://visifire.com/download_silverlight_charts.php
  2. We will use the out of the box Task List, created in the SharePoint Site.
    (Make sure you have some data in this Task List.)
  3. Create a page in SharePoint that will hold a Data View Web Part. You can use SharePoint Designer for this, with a Web Part Zone selected, from the top menu click Data View > Insert Data View. From the Data Source Library in the right hand task pane select your list and click Show Data. Then select both the Title and Status fields and add them to the Data View. After adding the Data View Web Part just make sure you do not have selected any paging option. Select display all items.

  4. Unzip the VisiFire package that you downloaded and grab "Visifire2.js" and "SL.Visifire.Charts.xap" and add them to the same location as the page you just created in your SharePoint site. (In my example I have uploaded them in my Shared Document Library )

  5. Now here it comes where we will be doing the actual stuff. It's now time to Modify the XSLT.

    I always use visual studio for this.  (See here for an important note about intellisense that will help you a lot).

    I create an empty project add two new files (replacing the words "Original" and "New" as appropriate):

  • Original.xslt
  • New.xslt
  1. In Original.xslt, Search and replace the first xsl:template:

    <xsl:template
    match="/">

    <xsl:call-template
    name="dvt_1"/>

    </xsl:template>

    With this XSLT:

<xsl:template
match="/"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:SharePoint="Microsoft.SharePoint.WebControls">

<!-- Load the chart tools -->

<script
type="text/javascript"
src="Visifire2.js"></script>

<!-- Create the JavaScript variable that holds the data to plot. -->

<!-- Note the xsl:for-each statement which loops over all the -->

<!-- list items and creates the necessary DataPoint entries -->

<!-- in the Chart XML. -->


 

<xsl:text
disable-output-escaping="yes"><![CDATA[

<script type="text/javascript">

var xmlString =

' <vc:Chart xmlns:vc="clr-namespace:Visifire.Charts;assembly=SLVisifire.Charts"'

+ ' Width="350" Height="300" Theme="Theme2" View3D="True" BorderBrush="Gray" BorderThickness="0" Watermark="False" >'

+ ' <vc:Chart.Titles><vc:Title Text="Task Status"/></vc:Chart.Titles>'

+ ' <vc:Chart.Series>'

+ ' <vc:DataSeries RenderAs="Pie" LabelLineThickness="0.5" ShowInLegend="True" Bevel="False">'

+ ' <vc:DataSeries.DataPoints>'

]]></xsl:text>


 

<!—Here we will query the Status field -->

<!—and display the consolidated Status values in Pie Chart. -->

<xsl:text
disable-output-escaping="yes">

<![CDATA[ + ' <vc:DataPoint AxisXLabel="Completed]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" YValue="]]></xsl:text>

<xsl:value-of
select="count(/dsQueryResponse/Rows/Row[normalize-space(@Status) = 'Completed'])"/>

<xsl:text
disable-output-escaping="yes"><![CDATA[" LabelText="Completed]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" Exploded="False]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA["/>']]></xsl:text>

<xsl:text
disable-output-escaping="yes">

<![CDATA[ + ' <vc:DataPoint AxisXLabel="Not Started]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" YValue="]]></xsl:text>

<xsl:value-of
select="count(/dsQueryResponse/Rows/Row[normalize-space(@Status) = 'Not Started'])"/>

<xsl:text
disable-output-escaping="yes"><![CDATA[" LabelText="Not Started]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" Exploded="False]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA["/>']]></xsl:text>


 

<xsl:text
disable-output-escaping="yes">

<![CDATA[ + ' <vc:DataPoint AxisXLabel="In Progress]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" YValue="]]></xsl:text>

<xsl:value-of
select="count(/dsQueryResponse/Rows/Row[normalize-space(@Status) = 'In Progress'])"/>

<xsl:text
disable-output-escaping="yes"><![CDATA[" LabelText="In Progress]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" Exploded="False]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA["/>']]></xsl:text>


 

<xsl:text
disable-output-escaping="yes">

<![CDATA[ + ' <vc:DataPoint AxisXLabel="Waiting on someone else]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" YValue="]]></xsl:text>

<xsl:value-of
select="count(/dsQueryResponse/Rows/Row[normalize-space(@Status) = 'Waiting on someone else'])"/>

<xsl:text
disable-output-escaping="yes"><![CDATA[" LabelText="Waiting others]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA[" Exploded="False]]></xsl:text>

<xsl:text
disable-output-escaping="yes"><![CDATA["/>']]></xsl:text>


 

<xsl:text
disable-output-escaping="yes">

<![CDATA[

+ ' </vc:DataSeries.DataPoints>'

+ ' </vc:DataSeries>'

+ ' </vc:Chart.Series>'

+ ' </vc:Chart>';

</script>

]]></xsl:text>

<!-- Create the div to hold the chart and then run -->

<!-- the JavaScript code to actually show the chart. -->

<div
id="TaskPieChart">

<script
language="javascript"
type="text/javascript">

var pTaskChart = new Visifire2(&quot;SL.Visifire.Charts.xap&quot;,350,300);

pTaskChart.setDataXml(xmlString);

pTaskChart.render(&quot;TaskPieChart&quot;);

</script>

</div>

</xsl:template>


  1. Save the file and refresh the page in a browser and you should see a pie chart come to life animated. If you make any mistakes the VisiFire widget is kind enough to give you a line number and position where it blew up, so that can be a help in tracking down typos in the notoriously picky XSLT.

    From here you can check out the other charts and other options via the VisiFire documentation which btw is really easy to read.


Concluding Thoughts:

I love this graphing concept, but I hate the fact that I have to go in and do so much hand-coding.  I've given a little thought to whether it can be generalized and I'm optimistic, but I'm also a little fearful that there may be a brick wall somewhere along the path that won't offer any work-around.  If anyone has some good ideas on this, please make a note in the comments or email me.

Field Name Gotcha's:

There are at least two things to look out for with your field names.

First, a field name with a space has to be escaped in the XSL.  This will probably be an issue here:

        <xsl:variable name="totalCompleted" 
select="count(/dsQueryResponse/Rows/Row[normalize-space(@Status) = 'Completed'])" />

If your "Status" column is actually named "Status Code" then you need to reference it as "Status_x0020_Code":

Second, and I'm a little fuzzy on this, but you also need to be on the alert for field name changes.  If you name your field "Status Code" and then later on, rename it to "AFE Status", the "internal name" does not change.  The internal name will still be "Status Code" and must be referenced as "Status_x0020_Code".

 

6 comments:

  1. Nice walkthrough. It helped me be able to wrap my brain around how to pull list data instead of using static data like in all of Visifire examples.

    Have you tried to do a stacked column chart with a list? I'm not sure how I would loop through the data multiple times to generate the different data points.

    ReplyDelete
  2. Hi Peter, Thanks for the appriciation. Well I havnt tried yet. But I'll definately give it a try and if i'm successfull you will see it in my Blog for sure.

    ReplyDelete
  3. is there any way we can do this without silverlight and without using Visual Studio ?? i.e. show a Pie chart from the Tasks...??

    Regards,
    Kamalnv@gmail.com

    ReplyDelete
  4. kamal, I never tried but have seen a couple of examples where people have used jQuery for generating charts.

    ReplyDelete