Silverlight/Javascript Photo Gallery Wall How-To: Written by Jeff Paries
Silverlight/Javascript Photo Gallery Wall How-To: Written by Jeff Paries
Figure 1
Configuration:
If you would like to change the title, images, or text being displayed in the gallery, you can do so
by editing the galleryConfig.js file. The one used for the example has three parts to it.
The first part is a variable for the gallery title. This is the text that displays above and to the left
of the image gallery. If you do not want a title to display, set the variable to a null string ("").
The second part of the gallery configuration file is an array of images to be displayed. All 16
elements of the image array must be filled to ensure that the gallery displays properly. To
change the images being displayed, simply modify the filenames for the array elements.
The preceding information describes the utilization of the gallery viewer. If you’re interested in
how it was built and how it works, the following section describes the scripts and XAML in more
detail.
How it Works:
The initial concept for the gallery was fleshed out with a quick mockup in a 3D program. I had an
idea of how I wanted the gallery to look, but needed to be able to make tweaks to it to finalize
the rough design prior to jumping into Blend to begin creating it. Figure 2 shows the rendered
layout I came up with.
Figure 2
The construction of the gallery app involved a lot of tweaking, so I will not be trying to describe
step by step how it was created. Rather, I will provide a high level overview of the process and
allow you to dissect the included XAML file.
The main idea was to create 4 main containers: left side, left side reflections, right side, right
side reflections. The left side contains the base "wall", 16 drop shadows, 16 images, and a
gradient mask for the lighting effect. The left side reflections container is a copy of the left side
container, scaled to -1 Y, then adjusted as necessary to line up right. In the reflections container,
it was not necessary to include all 16 images, so the 8 that would not be seen in the reflection
were removed (images 0-7). The right side follows the same pattern, and contains the base
"wall", 1 drop shadow, 1 image, the image label text, image label text drop shadow, and a
gradient mask for the lighting effect. Like the left side, the right side reflection was done by
copy/pasting the right side container, and scaling to -1 Y. Both the left and right reflections
containers have an extra gradient over them to "fade" the reflection out.
The biggest hurdle I encountered in creating the gallery was how to make images that looked
like they had a perspective warp applied to them since there is no tool for doing that directly in
Blend. This led me to explore the use of Image Brushes applied to paths. As of this writing,
Blend doesn't give you a tool with which to create an image brush when you're creating a
Javascript application. Or perhaps I should say if there is a tool for image brushes in Javascript, I
was not able to find it. However, image brushes still work if you plug them into the XAML
directly.
I opened the layout image shown in figure 2 in Blend, and locked the layer so I could build over
it. I then began creating the images by building rectangular paths over the red rectangles in the
image. Once that was done, a path might look something like this:
To add the image brush, I removed the closing "/" at the end of the <Path>, and added a
<Path.Fill> for the image brush as well as a new closing tag for the <Path>, resulting in
something like this:
The image brush is now used as a fill for the path. As a side note, while I haven't yet
experimented with it, the same thing works with video brushes.
I had hoped to get a soft edged drop shadow by using an image I created in Photoshop on the
shadow layers, but the way the fill works, the image did not warp specifically to the rectangle.
The shadows still look good; they're just not exactly what I had hoped for.
The only other mystery shape in the XAML is a small white rectangle floating off canvas to the
left. This rectangle has a 10 second animation attached to it that does virtually nothing. It is
used as a timer to determine when the application will switch into a slideshow mode if no images
are clicked.
As I mentioned earlier, it was just a lot of tweaking that really brought the final version together,
making sure corners lined up, shadows looked right, etc. The next section describes the code
behind the application.
Functionality
The basic functionality of the gallery looks something like this:
When the gallery is loaded, display the title, and load the images from the array into the small
image panes on the left.
When the mouse is moved over an image, draw a black stroke around the image. If the image
has a reflection (images 8-15), draw the stroke on the reflection as well.
When the mouse moves off an image, remove the black stroke around the image. If the image
has a reflection (images 8-15), remove the stroke on the reflection as well.
When an image is clicked, display the image, its reflection, and label text (if present) on the
right-hand side.
If no images are clicked for 10 seconds, begin displaying the slides in a slideshow, starting with
the image following the one that is currently displayed, changing images every 10 seconds.
When loaded, the app begins by calling the loadGalleryImages function. This is attached to the
main canvas via the loaded event:
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="1024" Height="768"
Background="#FF000000"
x:Name="rootCanvas"
Loaded="loadGalleryImages">
The loadGalleryImages function begins by loading the images from the image array into the
preview panes, as well as the reflection panes. It then displays image 0 and its reflection, as well
as the gallery title. Next, it grabs the label for image 0, writes it into the label and label drop
shadow, determines the width of the text, and positions both the label and drop shadow
centered beneath the image. The text is also drawn into the reflection pane. The last thing
loadGalleryImages does is to start the timer, and add an event listener to it. If the timer
completes, the doSlideshow function is called.
For mouse over functionality, a function called showOutline is attached to the MouseEnter
event on the image (remember the image is a path with an image brush applied).
For mouse out functionality, a function called hideOutline is attached to the MouseLeave event
on the image.
The hideOutline function sets the stroke thickness to 0. It then determines the image number
that was selected (based on its name), checks to see if it is an image that has a reflection, and if
so, hides the stroke on the reflection as well.
The displayImage function begins by stopping the timer that started when the app was loaded.
Since user input has been received, the app does not need to enter slideshow mode. It then
plays the fadeOutImage animation. An eventlistener is added to the fadeOutImage animation so
that when it is completed, a function called showNextImage is called.
The showNextImage function updates the display image, text, and reflections based on the
image number that was determined in the displayImage function. It then plays the
fadeInImage animation, and restarts the timer on the page.
The displayImage and showNextImage functions do the work when a user clicks on an
image. However, if the timer is ever allowed to complete, a function called doSlideshow is
called.
doSlideshow checks to see which image is currently being displayed, and sets up a variable for
the next image that should display.
It then calls a function called displayImages that plays the fadeOutImage animation, and adds
an event listener to the animation to call a function called nextSlide upon completion.
The nextSlide function does the majority of the work in slideshow mode. It begins by removing
the event listener that was set on the fadeOutImage animation (nextSlide is called when the
animation is completed).
It then does a quick check to see if the next image to display matches the array length (16). If
so, it loops around to the beginning of the array since the last image in the array is at element
15.
It then builds the proper name for the next image to be displayed, changes the text, text
shadow, and text reflection, adjusts the size of all the text elements, and centers them. Finally,
the display image and reflection are updated, and the fadeInImage animation is started.
And that's it! The gallery scripts are fairly small… the wallGallery.js file, which contains the
functionality for the gallery, is about 5.5K. The configuration file is about 1.5K more. Even the
XAML file is relatively light, at about 43K.