We recently released v.10.3 of NetAdvantage for Silverlight Data Visualization, which includes the high speed XamDataChart. You can browse to the online samples to get full picture of the controls that part of this set. However the XamDataChart is on focus for this article. We’ve introduced a new property, TransitionDuration, on Series class (base class for all series). TransitionDuration is a dependency property of type System.TimeSpan. If set, it indicates the duration of the current series’ morph. I don’t know how many of the readers have noticed this property but it exists since v.10.2 of the product. The idea behind this property is to provide smooth transition of a data point from one value to another. Please note, and do not confuse – the morph (smooth transition) is only applied when a value within single data point is changed. No transition happens when you add a new data point to the underlying data source, or when you remove data points. The transition is only applied to a single (or many) data point when a value of bound property is changed.
We certainly can identify many scenarios for real-world usage of Motion Framework, but this article focuses on the realization of Stats Distribution part of World Maps showcase application. The Stats Distribution part shows 4-dimentional data. Two of the dimensions are obvious – the X axis shows cumulative hits for the given site, the Y axis shows the share (in percent) for given browser (or region) for that site. Now we apply Time as 3rd dimension, Time – so the X and Y values change over time and you can clearly see this change when hit the Play button. The 4th dimension, change of hits over time is represented by the radius (size) of a bubble. Increase of bubble size shows there are more hits for the current time period (day) relative to the previous one:
Using this part of the MyWorldMaps application you can see how data changes over time.
While you can easily accomplish the task with 3 dimensions – X, Y and Time, adding size of bubble requires some advanced techniques. The full solution consists of a DispatcherTimer which ticks at regular time intervals (adjustable by the “Change Animation Speed” slider). On a timer tick we simply update all related data points in the Chart’s data source. In order to see different browsers (or regions) as separate Legend Items, and respective bubbles in different colors, we need to create separate series instance for every browser (or region) we have data for. We use ScatterSeries to show bubbles, as shown here. Although XamDataChart supports BubbleSeries out of the box (as CTP) in v.10.3, we still cannot animate the bubble radius change with the BubbleSeries. That’s why we are using the approach with custom MarkerTemplate for a ScatterSeries.
Because we are going to use one and the same MarkerTemplate multiple times, we have created a separate Silverlight User Control that facilitates the job of displaying and animating bubble. It has three important properties:
· IsAnimated – Boolean property to indicate whether or not the size of the bubble should be animated upon change;
· AnimDuration – TimeSpan property to set the duration of animation, when animated;
· LocalRadius –Double value property indicating the size of the bubble. When this property is changed, if IsAnimated is True, the bubble size changes with smooth animation;
To animate bubble size we use a utility class SizeAnimation, which can be found under MotionFramework folder of Silverlight Application in the provided solution. This class creates DoubleAnimationUsingKeyFrames to animate change in Width and Height properties of our custom control used as MarkerTemplate. We also have created custom extensions to easily apply animations to a FrameworkElement.
To box all functionality into a single, reusable routine we have created the CoreMF class. It implements all required functionality around instantiating DispatcherTimer, handling Tick event and changing the data points in data source accordingly. Important properties and methods of CoreMF that you need to know are:
· DataChart – XamDataChart instance to perform motion framework actions on;
· Legend – Legend which will show Chart data sources (Series);
· DataSource – Dictionary<int,IList>. This is the core united data source for animations. If you, for example have data for 3 browser versions, each browser data will be a separate IList and you have to combine all the sources into one single Dictionary. The core framework will automatically pick up the appropriate item from each IList to update the current data point;
· XAxisName – string, representing the Name property of XAxis within the DataChart that data will be bound to;
· YAxisName – string, representing the Name property of YAxis within the DataChart that data will be bound to;
· PropertyNameX – string, the name of the property of underlying business object that will be bound to the X Axis;
· PropertyNameY – string, the name of the property of underlying business object that will be bound to the Y Axis;
· PropertyNameR – string, the name of the property of underlying business object that will be bound to the bubble radius;
· MarkerTemplate – DataTemplate. You can define your own template to serve as DataTemplate. Of course you can use the provided BubbleMarker user control, but can also create your own DataTemplate, which can be in different shape and may or may not animate the size
· LegendItemTemplate – DataTemplate. You can define your own DataTemplate for the LegendItem, so you can customize your legend
Finally, once you have your data ready and you have just inserted XamDataChart on your page, you have created an instance of CoreMF and set its properties like that:
this._coreMF = new CoreMF();
this._coreMF.DataChart = this.dcMotion;
this._coreMF.MarkerTemplate = this.Resources["MarkerTemplate"] as DataTemplate;
this._coreMF.DataSource = DemoModel.GetDictionaryData(5, 25);
this._coreMF.PropertyNameR = "ValueR";
this._coreMF.PropertyNameX = "ValueX";
this._coreMF.PropertyNameY = "ValueY";
this._coreMF.XAxisName = "axisX";
this._coreMF.YAxisName = "axisY";
this._coreMF.ChartLegend = this.mainLegend;
Then, you just decide when to trigger the animation by invoking the Play method on the CoreMF instance:
If you want to get deeper just download the code and look into the CoreMF class, where all the logic is handled.