This article targets: TIBCO Spotfire 2.1 and forward
Introduction
The custom visualization framework in TIBCO Spotfire doesn’t really require anything of the developer to enable a visual for the Spotfire Web Player. All it does is to reuse the implementation of the RenderCore method to create a PNG image of your visualization and then displays that on the web. But a static image with no user interaction possibilities is all it gives you. If you want anything beyond that, you’re on your own. However, being on your own with a flexible blank canvas is not that bad of a deal. Especially if you have good skills and great tools to make your job easier.
Now, imagine I told you that you could create amazing looking visualizations for the web with just a few lines of code. To prove it, look at the following visualization. It is made with with a little less than 100 lines of XAML code using the Microsoft Silverlight platform.
Integrating the Silverlight control with Spotfire Web Player
Assume you went about and wrote yourself a Silverlight visualization or licensed a commercial one (oh yes, there are quite a number of great ones out there), here’s how you would get it running with the Spotfire Web Player. I do assume that you are somewhat familiar with the basics of Silverlight and that you have read the STN documentation on how to create a web visualization.
First, in the implementation of the add-in that you drop into the Web Player, make sure to register a VisualControlState and a WebControl.
public sealed class CustomAddIn : AddIn
{
// Override methods in this class to register your extensions.
protected override void RegisterViews(AddIn.ViewRegistrar registrar)
{
base.RegisterViews(registrar);
registrar.Register(
typeof(WebControl),
typeof(VisualControlState<GaugeVisual, object>),
typeof(GaugeWebControl));
registrar.Register(
typeof(CustomControlState),
typeof(GaugeVisual),
typeof(VisualControlState<GaugeVisual, object>));
}
}
Second, your WebControl implementation would have to look something like the following snippet. This code basically generates HTML that tells the end-users' browser to render a Silverlight deployment when a file that contains the GaugeVisual is opened.
public class GaugeWebControl : WebControl
{
private VisualControlState<GaugeVisual, object> state;
public GaugeWebControl(VisualControlState<GaugeVisual, object> state)
: base(HtmlTextWriterTag.Div)
{
this.state = state;
}
protected override void OnLoad(EventArgs e)
{
Page.ClientScript.RegisterClientScriptInclude(
"Gauge.js",
Page.ClientScript.GetWebResourceUrl(typeof(TrafficLightChartWebControl), "SpotfireGaugeWeb.Scripts.Gauge.js"));
base.OnLoad(e);
}
protected override void RenderContents(HtmlTextWriter writer)
{
base.RenderContents(writer);
writer.WriteLine("<object data=\"data:application/x-silverlight,\" id=\"silverlight\" type=\"application/x-silverlight-2\" width=\""
+ this.Width + "%\" height=\""+ this.Height + "\">");
writer.WriteLine("<param name=\"source\" value=\GaugeSilverlight/GaugeSilverlight.xap\"/>");
writer.WriteLine("<param name=\"onload\" value=\"pluginLoaded\" />");
writer.WriteLine("<param name=\"background\" value=\"white\" />");
writer.WriteLine("<a href=\"http://go.microsoft.com/fwlink/?LinkID=115261\" style=\'text-decoration: none;\'>');
writer.WriteLine("<img src=\"http://go.microsoft.com/fwlink/?LinkId=108181\" alt=\"Get Microsoft Silverlight\" style=\'border-style: none\'/>');
writer.WriteLine("</a>");
writer.WriteLine("</object>");
}
}
The GaugeSilverlight.xap that we refer to in the snippet above is the binary package that Visual Studio gives you when building a Silverlight project. You need to drop this package in the Spotfire Web Player Installation folder at the path that you defined in the WebConrol implementation. In our example we used the source path GaugeSilverlight\GaugeSilverlight.xap
At this point, we can technically take the Silverlight sample you played around with in the beginning of this article and have it rendered inside of the Web Player. However, instead of having the gauge react to the slider, we obviously want to use values from the Spotfire data table. To do this, the web visualization framework allows us to register for a callback that is triggered when the analysis has changed (CustomVisualization.onInvalidated). But the framework doesn’t really help us in anyway to obtain the new state. To do so we have to manually make a call from the client-side application to the server. Traditionally, this would have been done in Javascript, but with Silverlight it can all be written in standard C# using classes provided by .NET.
The following snippet shows a little bit of the JavaScript glue that we need to make our Silverlight control react to changes in the open document. Here, we pass the URL of the server to our Silverlight control and also invalidate it when it needs to refresh itself.
CustomVisualization.onInvalidated = function() {
invalidate();
}
function pluginLoaded(sender, args) {
setUrl();
invalidate();
}
function setUrl() {
var sl = document.getElementById("silverlight");
sl.Content.gauge.SetUrl(window.location.href);
}
function invalidate() {
var sl = document.getElementById("silverlight");
sl.Content.gauge.SetUrl(window.location.href);
sl.Content.gauge.Invalidate();
}
Instead of having a JavaScript nightmare, here’s how easy it is to make a call to the server. Plus, you have full support from the C# compiler and a full debugging environment inside of Visual Studio. (Note that this code belongs to the Silverlight control)
public partial class GaugeControl : UserControl
{
...
public void Invalidate()
{
WebClient c = new WebClient();
Uri uri = new Uri(this.serverUrl.ToString() + "&getValue=1");
c.DownloadStringCompleted += ValueRetrieved; // Delegate that updates the UI with the new value
c.DownloadStringAsync(uri);
}
}
So where does the WebClient call in the snippet above end up? Of course in our WebControl implementation. So to be able to server the new Silverlight control, we need to change the RenderContents method a bit:
public class GaugeWebControl : WebControl
{
...
protected override void RenderContents(HtmlTextWriter writer)
{
if (Context.Request.QueryString["getValue"] != null)
{
// Return whatever data the silverlight control needs to
// render itself.
}
else {
// Render the silverlight control (see first snippet)
}
}
...
}
Conclusions
Let’s sum up a little. To display a Silverlight control in the Web Player, all you need to do is to say so in your Web Control implementation, and of course to drop the control into the file structure of the Web Player installation. If you want to update in sync with the analysis, you give the Silverlight control the URL of the server and have it get the data and render it. Again, your WebControl implementation has to be able to serve the Silverlight control.