Implement a Ken Burns Slideshow in Umbraco using jQuery and XSLT


Update: Read the following post by all means as it contains useful information but there’s a bug in the randomEffect function and this post provides the correct code.

While talking to a former colleague and extolling the virtues of Umbraco, he asked me if it would be possible to implement an image gallery with the Ken Burns effect e.g. the one here.

My initial reaction was yes with Umbraco it should be possible. So I decided to put implement one such gallery in Umbraco using the following set up:

Overview

What I wanted to achieve was something very close the Bedford Street Gallery image slideshow as per link above. Rather than re-inventing the wheel, I decided to use jQuery and the cross slide script which would give me a quick platform to replicate the desired functionality on Umbraco.

After investigating the cross slide script, I decided that I wanted to have random effects of the cross slide even though I know I’d have to do some research to introduce that random effect. In addition, I made up my mind to implement the functionality using XSLT rather than .NET user controls simply because I wanted to enhance my experience of the former.

Another requirement was to allow the user to simply have all the images in the gallery section of the site and display them in the slideshow on the homepage and have the images automatically resized to fit in the slideshow window. The fact is I want things to be as painless as possible for users who usually are not tech savvy and who might not know how to resize images accordingly.

Issues

Before delving into code, the issues I faced here were:

  1. Learn about the cross slide script and use it with Umbraco
  2. Implementing random effects
  3. Learning and implementing XSLT
  4. Learning and using ImageGen

Implementation

As I  like learning about new concepts by reducing problems to their simplest component, I decided that I would first try to hard code the following (with my images of course):

$('#test1').crossSlide({
  speed: 45,
  fade: 1
}, [
  { src: 'lib/sand-castle.jpeg', dir: 'up'   },
  { src: 'lib/sunflower.jpeg',   dir: 'down' },
  { src: 'lib/flip-flops.jpeg',  dir: 'up'   },
  { src: 'lib/rubber-ring.jpeg', dir: 'down' }
]);

However, I found out that this particular effect of the script requires that the images are more or less the same size i.e. you’ll encounter problems if you mix and match portrait and landscape images.

In fact as it turned out, it would have been easiest to implement the Ken Burns effect image gallery first so that my XSLT would produce something akin to:

$('#test3').crossSlide({
  fade: 1
}, [
  {
    src:  'lib/sand-castle.jpeg',
    href: 'http://flickr.com/photos/spacetrucker/94209642/',
    from: '100% 80% 1x',
    to:   '100% 0% 1.7x',
    time: 3
  }, {
    src:  'lib/sunflower.jpeg',
    href: 'http://flickr.com/photos/hichako/1125341449/',
    from: 'top left',
    to:   'bottom right 1.5x',
    time: 2
  }, {
    src:  'lib/flip-flops.jpeg',
    href: 'http://flickr.com/photos/jayniebell/1125216143/',
    from: '100% 80% 1.5x',
    to:   '80% 0% 1.1x',
    time: 2
  }, {
    src:  'lib/rubber-ring.jpeg',
    href: 'http://flickr.com/photos/ruminatrix/1125292682/',
    from: '100% 50%',
    to:   '30% 50% 1.5x',
    time: 2
  }
]);

Implementing random effects

I wasn’t sure how to tackle this task but after some research, I came across this piece of documentation on the Umbraco site. As a result I produced the following code:

$('#test3').crossSlide({
  fade: 1
}, [
  {
    src:  'lib/sand-castle.jpeg',
    href: 'http://flickr.com/photos/spacetrucker/94209642/',
    from: '100% 80% 1x',
    to:   '100% 0% 1.7x',
    time: 3
  }, {
    src:  'lib/sunflower.jpeg',
    href: 'http://flickr.com/photos/hichako/1125341449/',
    from: 'top left',
    to:   'bottom right 1.5x',
    time: 2
  }, {
    src:  'lib/flip-flops.jpeg',
    href: 'http://flickr.com/photos/jayniebell/1125216143/',
    from: '100% 80% 1.5x',
    to:   '80% 0% 1.1x',
    time: 2
  }, {
    src:  'lib/rubber-ring.jpeg',
    href: 'http://flickr.com/photos/ruminatrix/1125292682/',
    from: '100% 50%',
    to:   '30% 50% 1.5x',
    time: 2
  }
]);

I eventually came up with this:

<xsl:param name="currentPage"/>

 <xsl:template match="/">
 <xsl:value-of select="umbraco.library:AddJquery()"/>
 <xsl:value-of select="umbraco.library:RegisterJavaScriptFile('crossSlide', '/scripts/jquery.cross-slide.js')"/>
 <xsl:variable name="filePathStart">
 <xsl:text>/umbraco/ImageGen.ashx?image=</xsl:text>
 </xsl:variable>

 <xsl:variable name="fileWidth">
 <xsl:text>&amp;width=350</xsl:text>
 </xsl:variable>
 <script type="text/javascript">
 $('#image-block').crossSlide({
 fade: 1
 }, [
 <xsl:for-each select="$currentPage/descendant::node[@nodeTypeAlias='RunwayGalleryPhoto']">
 { src: '<xsl:value-of select="$filePathStart" disable-output-escaping="yes"/><xsl:value-of select="concat(substring-before(data [@alias='umbracoFile'],'.'), '.jpg')"/><xsl:value-of select="$fileWidth" disable-output-escaping="yes"/>',
 <xsl:value-of select="effects:randomEffect()"/>                }
 <xsl:if test="position() != last()">
 <xsl:text>,</xsl:text>
 </xsl:if>

 </xsl:for-each>
 ]);
 </script>
 </xsl:template>

The code in red is Umbraco’s mechanism to insert the script tags into the head section of the page.The blue section contains part of the query string which will make a call to the ImageGen handler in order to automactically resize the image. The orange section gives the width to which the image should be resized to.

Now you might be asking yourself why I took the trouble to break the querystring call to ImageGen as I have but not doing so causes the slideshow not to work. Upon using Fiddler, for some reason the ampersand was being transmitted as &amp; rather than simply &. I am not sure why this happens but suffices to say that splitting the query string into variables solves that issue.

The green section closes builds the rest of the code. In this particular section, what is important to note is

 <xsl:value-of select="effects:randomEffect()"/>

and if you are not familiar with XSLT and C# it might throw you off. It is possible to extend the XSLT code using C# and in this case I’m using it to introduce the random effect and the randomEffect() function is as follows:

<msxsl:script language="CSharp" implements-prefix="effects">
 <![CDATA[
 public string randomEffect()
 {
 StringBuilder sb = new StringBuilder();

 Random random = new Random();

 switch (random.Next(0,5))
 {
 case 0:
 sb.Append("from: '100% 80% 1x',to: '100% 0% 1.7x',time:7");
 break;
 case 1:
 sb.Append("from: 'top left',to: 'bottom right 1.5x',time: 5");
 break;
 case 2:
 sb.Append("from: '100% 80% 1.5x',to:   '80% 0% 1.1x', time: 5");
 break;
 case 3:
 sb.Append("from: '100% 50%',to:   '30% 50% 1.5x',time: 5");
 break;
 case 4:
 sb.Append("from: '50% 100% 1x',to: '50% 0% 5.7x',time: 6");
 break;

 default:
 sb.Append("from: '100% 80% 1x',to:   '100% 0% 1.7x',time: 5");                                                break;
 }

 return sb.ToString();
 }
 ]]>
 </msxsl:script>

This is now the end of this tutorial/record which I hope you would have found useful.
Advertisements
Tagged with: , , , , , , , ,
Posted in jQuery, Tutorial, Umbraco blogs, XSLT
2 comments on “Implement a Ken Burns Slideshow in Umbraco using jQuery and XSLT
  1. Dave Stringer says:

    Hello, I was trying to get this to work, but the output gets rendered as this:

    $(‘#image-block’).crossSlide({
    fade: 1
    }, [

    ]);

    Even thought there are two images that are decendents of the home page….

    Any ideas where it could be going wrong? I also get a “crossslide must be called on at least 1 element” error… I presume it is because the XSL foreach is not iterating over any children but can’t see where I am going wrong.. Any ideas?

    • DavidS says:

      Hi Dave,

      Without seeing your XSLT and how you’ve laid out your project, it is hard for me to tell what problem is. However, as you’ve pointed out, the most likely culprit is the fact that the XSL foreach isn’t iterating over the elements that you need.

      What you can do is to change the select statement to walk back up the tree to the root and then go back down until you get to the image nodes. That should do it.

      HTH,

      David

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: