I wanted to take an opportunity to go over some of the code from the timeline I linked to in my last post. Even though it’s a Silverlight 1.0 app, there’s still some interesting aspects to the code there.

Right out of the gate, one of the things the app does is use two downloaders. The first one happens invisibly - meaning I don’t give any user feedback that I’m doing it - and is used to download the graphics to display the main downloader with the progress bar. I’ve done this with the last couple of apps I’ve built, and it works well. The idea is to make the graphics the downloader will need available before the downloader is used. This avoids graphics that “pop” on screen as soon as they’re done downloading and creates a smoother experience for the user. In this case, the downloading graphic was zipped to a file that’s about 80K. Once it’s on the client, I grab the image out of the zip for the background, and show the progress bar over the top.

The progress bar on the app is also interesting. When the application is loading, it looks like a graphical version of the timeline is building from left to right as the app downloads. The actual animated piece there is the blue bar. The progress bar rectangle was scaled -1 along the X-axis to flip it, and then had its width manipulated programmatically, collapsing the bar from left to right. The code looks like this:

percentage = Math.floor(sender.downloadProgress * 100);
var newWidth = Math.floor(572.282 - (percentage * 5.72282));
sender.findName(”progressBar”).Width = newWidth;

The “newWidth” calculation calculates the width by figuring out how wide the bar should be, and subtracting it from how wide the bar will be when it’s complete - basically creating a progress bar that works in reverse of the usual way - rather than increasing the width, it’s decreasing. Since the bar is flipped along the X-axis, the width decreases to the right instead of the usual left.

The main timeline is made up of 3 layers - the background, the logos, and the photos. Amazingly, each of these layers is over 8100 pixels wide. The background layer contains the background image as well as the year headers and gradients across the top of the timeline.  The logos layer contains the large graphical logos. The photos layer contains all of the text blurbs for the app, as well as the buttons for the video player. This was done so that the layers could move independently of one another, to create a little more of an organic look when you drag the slider. As you drag the slider, the current position of the slider is calculated and pushed to storyboards for each layer, and then the storyboard is triggered with the Begin() method. The storyboards were all similar, except that they have different durations and ease to make them slide at slightly varied speeds. The storyboards look like this:

<Storyboard x:Name=”movePhotos”>
<DoubleAnimationUsingKeyFrames BeginTime=”00:00:00″ Duration=”00:00:01″ Storyboard.TargetName=”photos” Storyboard.TargetProperty=”(Canvas.Left)”>
<SplineDoubleKeyFrame x:Name=”photosValue” KeyTime=”00:00:01″ Value=”0″ KeySpline=”0,0.497,0.504,1″/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

The code to update the storyboard value property looks like this:

sender.findName(”photosValue”)["Value"] = -scaledBackgroundLocation;

“scaledBackgroundLocation” figures out where the various layers should be relative to the viewport - the timeline thumb across the bottom allows you to move across a very large timeline that is not entirely visible. For each pixel the thumb slider moves to the right, the main timeline background and images need to move an appropriate number of pixels to the left. To figure that out, we needed a scaling factor, which was the maximum left offset value the background images would need to move to display the end of the timeline, divided by the size of the preview timeline across the bottom. That code looks like this:

var scalingFactor = 7502 / 580;

The app width was 630px, so the 7502 comes from subtracting the width of the app from the width of the background images. 8132-630 = 7502. When one of the background images is set to -7502x, the last 630 pixels of the timeline will be visible in the viewport.

The video player is a reskinned Encoder template. I needed to instance the video player and start the app at the same time, so I created a function called “createSLObjects” that is called from the install experience if Silverlight is found. The function looks like this:

function createSLObjects() {
createSilverlight();
var player = new StartPlayer_0();
}

The video player has two animations associated with it. One to scale it up and fade it in when a video button is clicked, and one to scale it down and fade it out when the close button on the player is clicked. There is only a single instance of the video player in the application, and the media element source is manipulated by code when a button is clicked. The video URLs were assigned to variables at the top of the script file to make them easily editable during the development process. As an example, when the button for the Al Gore video is clicked, the following code is executed:

sender.findName(”VideoWindow”).Source = goreVideo;

After which a function is called to make the player visible, set the starting scale and opacity, play the “show” storyboard, and start the video:

function showVideoPlayerCanvas(sender)
{
 sender.findName(”videoPlayerCanvas”).Visibility = “Visible”;
 sender.findName(”videoPlayerScale”)["ScaleX"] = 0;
 sender.findName(”videoPlayerScale”)["ScaleY"] = 0;
 sender.findName(”videoPlayerCanvas”).Opacity = 0;
 sender.findName(”showVideoPlayer”).Begin();
}

Some of the videos were external to the app. For those, I just called window.open, and passed the video’s URL - they will open in the client’s default player.

The last step was the install experience graphic. We work hard to ensure that we’re offering a compelling reason for visitors without Silverlight to click the badge and install. Tim Heuer posted a great tip on how to test out the experience in IE without uninstalling Silverlight.

Overall, the entire project from start to finish took just over two days. I was working very closely with the designer to pull all the pieces together and create a look that was similar to the original Flash piece, but also made sure we had an opportunity to update some of the visual elements.

One of the things I’ve wanted to do in Silverlight for a really long time is create a timeline infographic. Not for anything more than the practice really, but I just think that the different ways of presenting information via an interactive timeline are kind of interesting to see.

The majority of my work involves creating Silverlight applications, and I love it. So imagine how happy I was when a timeline project came in. This one was interesting because it was a conversion from a Flash version to an updated Silverlight (1.0) version. The company I work for had created the Flash version, so we still had all the base assets used in the timeline, which was helpful.

The schedule was a little challenging - I didn’t have a lot of time to complete the work in - and the new version lives in a template that was a significantly narrower width than the Flash version, so there were some adjustments to make.

In the end, I was very pleased with the result. Interestingly enough, the overall performance of the Silverlight piece seems smoother than the Flash version. I had expected the Silverlight one to bog down a bit as I added text, due to the antialiasing, but that didn’t happen.

Anyways, for those of you that are interested, here is the original Flash version:
Flash CEO Summit timeline

The updated Silverlight version is here:
Silverlight CEO Summit timeline