The DataPlanet Silverlight Sample Application

David Carron / Tuesday, January 17, 2012

In the research department, we often use cut-down or lightweight versions of the release controls to allow us to develop concepts and ideas without getting tied up in all the details which make an industrial-strength control. Like an automobile manufacturer's concept car, these aren't yet road-worthy, but they're a great way to show-case where we're going in the future, and by using them within working applications we get a chance to refine the APIs and exported API "concepts" before locking them in to a released product.

Designing controls and their APIs isn't just a question of getting optimal functionality and interactions for each control. Whilst developing an API for a control, we build small sample applications which use the control along with other existing controls. This allows us to verify not only that the control allows us to do what's needed, but that things which should be easy actually are easy, and that things which should work the same way on multiple controls actually do work the same way.

The purpose of building these applications isn't only to test the APIs, it's also to try to break them: finding the limits of our APIs before they're released allows us to push the limits back, making sure that by the time the control reaches you we can be sure that it will do everything you want it to. All this definition, test and redefinition ends up being a lot of work for us of course, but the results are worth it.

The application we're looking at here runs off the USGS real-time earthquake RSS feed with each earthquake is stored in an object which looks more-or-less like this:

public class Earthquake
    public double Magnitude { get; private set; }
    public string Location { get; private set; }
    public string FullLocation { get; private set; }
    public DateTimeOffset Date { get; private set; }
    public List<Earthquake> CloseTo { get; private set; }
    public GeoRSSItem GeoRSS { get; private set; }


The GeoRSSItem field references the fairly generic class:

public class GeoRSSItem : SyndicationItem
    public Point Point { get; set; }
    public IEnumerable<Point> Line { get; set; }
    public IEnumerable<Point> Polygon { get; set; }


The full definitions of Earthquake and GeoRSSItem include some extra code which I haven't shown here since they also take part in the download and parsing of the RSS feed. The individual earthquakes are store in single ObservableCollection which also manages a list of "selected" items.

All of the interactive controls used in the sample application generate mouse events, and these are all hooked up to the same event listener in the backing code: 

private void Bubble_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    Earthquakes earthquakes = DataContext as Earthquakes;

    earthquakes.SelectedItem = (DataContext)((FrameworkElement)sender).DataContext).Item;
    e.Handled = true;


And that's about it for the C# code: all of the applications interactions and animations are configured directly in the page XAML by binding either to the earthquakes list, the selected earthquakes list or to properties on other controls.


DataMap Control

The map control used in the DataPlanet showcase is being used to explore a API options for mapping controls. The behavior we've been looking into here is to extend the integrated motion framework and to allow the map's longitude to "wrap around" when the map is showing the relevant portion of the map.

This simple requirement places some unexpectedly strong requirements on the control and its API.

<controls:DataMap TransitionDuration="0:0:1" 
WindowCenter="{Binding SelectedItem.GeoRSS.Point}"
WindowZoom="0.25" >
<controls:SymbolSeries ItemsSource="{Binding}"
                    ValueScale="{StaticResource MagnitudeScale}"
MarkerTemplate="{StaticResource BubbleTemplate}" />
            ItemsSource="{Binding SelectedItems}"
MarkerTemplate="{StaticResource LabelTemplate}"
MarkerHorizontalAlignment="Center" MarkerVerticalAlignment="Top"
LongitudeMemberPath="GeoRSS.Point.X" LatitudeMemberPath="GeoRSS.Point.Y" />


Motion framework has been extended to animate panning and zooming which are both controlled by the familiar TransitionDuration and Transition properties that you've probably already seen for other motion framework enabled controls. Panning the map to follow the selection is implemented without any page code by binding the map's WindowCenter to the selected earthquake's position: whenever the selection changes the automatically recenters and, since motion framework is enabled, the map will pan smoothly. Since the control is displaying inherently geographic data, panning follows a geographic "great circle" path instead of a simple linear interpolation. You don't need to worry about the details of any of this though: we've done a lot of work to make this all completely transparent for the page designer and natural to the end-user.

Another aspect of geographic data is that it wraps: if you keep on going East, you never hit an edge. Without wrapping, the Pacific Ocean is always split, with the western half drawn to the left of the map and the eastern half to the right. Implementing wrapping within the control presents quite a few technical challenges, but again you don't need to worry about the details: they're all hidden and everything is transparent and natural: enabling wrapping and having the map's markers position themselves and lines interpolate themselves correctly requires no special configuration or work from the page designer.


DataPlanet Control

DataPlanet is the 3D counterpart to the data map, displaying geographic mapping data on an interactive globe. Although DataPlanet displays all of the familiar map series types in 3D, it runs as a native Silverlight 4 or 5 control without any need for 3D APIs or hardware support.  

Since the planet and map are conceptually so similar, we've done a lot of work to make the APIs, style points and interactions the same, too. Although only displaying a marker series in the sample, in principle the data planet control shares all of the familiar map series, as well as the scale objects, tooltips etc.

Here's XAML for the planet as it's used in the sample

<controls:DataPlanet TransitionDuration="0:0:1"
                     WindowCenter="{Binding SelectedItem.GeoRSS.Point}"
Preview="{Binding ElementName=DataMap, Path=ActualWindow}">
<controls:SymbolSeries ItemsSource="{Binding}"
="{StaticResource BubbleTemplate}"
 ValueScale="{StaticResource MagnitudeScale}" />

If you compare that to the map's XAML above, you'll notice that the series definition is actually identical; the same series type is used with the same marker template and the same scaling object; when you use data planet the familiar map series are used in the same way. Although the data planet and map controls are visually quite different, there's almost nothing new to learn when you switch from one to the other.

Panning the planet to follow the selection is implemented in precisely the same, simple way as for the map:  by binding the map's WindowCenter to the selected earthquake's position. The way the control implements this panning is very different to the map, but again, all the details are hidden and the whole thing appears natural and smooth.

The "preview" area on the planet which follows the map's visible region is kept up-to-date without any page code by simply binding the planet's Preview property to the map's ActualWindow. The ability to do this kind of thing is really where all the testing pays off.

The sample application doesn't really stretch the capabilities of the data planet control, and you can expect to be hearing and seeing a lot more about it in the near future.

BubbleChart Control

The bubble chart control is showing the same earthquake data, but this time in a non-geographic way.

The bubble chart acts very much like a list control, but with the addition that each template item has a numerical value which can be used to scale any aspect of the item's brushes and size. As items are added and removed, or existing markers change size, bubble chart works out the best way to pack them.

Looking at the XAML below, you'll see that the same, familiar series, scale and binding concepts used in the data chart and other controls have been reapplied here without modification - again, not only are the APIS identical, but the different controls are actually sharing the same scale object.

<controls:Bubbles ItemsSource="{Binding}"
ValueScale="{StaticResource MagnitudeScale}"
MarkerTemplate="{StaticResource BubbleTemplate}" />


The calculations required to find the optimal placement (and also to maintain it as the control is resized or as items are added and removed) are quite complicated, so to ensure that the application remains responsive, the calculations are performed incrementally with the display updating continuously. This incremental rendering technique has some other applications, which are used in the "bundles" sample.

This bubble control isn't showing the selected item differently, but clicking on any of the items generates triggers the same event listener, updating the selected earthquake and causing both the plane and map to pan.


WipePanel Control

The Wipe Panel control is really the odd-one-out here as it's not at all displaying data graphically.  Instead, the wipe panel control acts as a content presenter with -  for this application - its contents bound to the selected earthquake.

Transitioning between content isn't a new thing, but Silverlight's storyboard and animation system really doesn't allow that many options - once you've made your content fade or pivot, you've pretty much done all that can be done. The WipePanel behaves just like a simple content presenter, with the addition that instead of abruptly switching from one piece of content to the next, it detects changes to its content and applies a shader effect to automatically transition to the new content.  

The wipe panel is all about dynamically switching between content, and we've managed to catch it here in mid-transition. Again, these are configured using the familiar motion framework properties Transition and TransitionDuration. The wipe panel extends this a little bit by adding a TransitionEffect.

<controls:WipePresenter TransitionDuration="0:0:1"
Content="{Binding Path=SelectedItem}"
ContentTemplate="{StaticResource DescriptionTemplate}"/>

 And that's all there is to it.