Two people doing their own thing.

Microsoft Certified Partner Soul Solutions
Mar 8

Written by: Soul Solutions
Saturday, 8 March 2008

johnWeeGo.jpgAfter seeing the amazing demo at Mix08 this week I decided I needed to play with this. Checkout my collection of photos from our trip to Thailand last year: http://thailand.soulclients.com

step6.jpg

So what do you need to do to make this?

Visual Studio 2008

Silverlight2 Tools for vs2008

Deep Zoom Composer

Essentially I put together a bunch of code from other people's posts and the Mix08 code and fixed a few bugs. Thanks to Mike, Yasser and Mike for their posts.

Step 1, make the tiles from your set of images.

step1.jpg

This guide is great. Essentially you import your uber resolutions images (Windows Live Photo Gallery stitches awesome panoramas btw) and lay them out how you want it to be displayed. Tip, you can draw a box around a group of images, shift click the primary image (light blue border) and then use the tools to align, match size, shrink and grow and evenly space.

Finally your export either as a single image or as a collection. The later opens up some interesting options I will explore later as each image is exported separately.

When complete open the export folder as you need to copy this into your project.

Step 2, create a new silverlight2 application in vs2008.

Create a new project, under "Silverlight" you will find a "Siverlight Application" template. On the next screen I opted for web project to host the control but you could just use a html page.

step2.jpg

Scott Guthrie explains more here.

Step 3, drop a MultiScaleImage on the canvas, set path to your exported files

The control to use is the "MultiScaleImage". Drop one onto the page.xaml inside the default grid. You need to copy the output from step 1 into a folder in the "clientBin" of the web site. We need to supply this path to the control:


<MULTISCALEIMAGE Source="thai2007/items.bin" x:Name="deepZoomObject" />

If you run this up you get the image but no interactivity.

Step 4, wire up some events

This is pretty much the point where all the examples out there differ. I want to be able to use several key combinations, the mouse to pan and zoom, be nice a smooth and not break if you go off the application.

I choose to use the following:

  • up,down,left,right to pan, i (in) and o (out) to zoom. Plus and minus are not listed - help me out someone?
  • AWSD to pan, c and space to zoom.
  • Mouse click and drag to pan
  • Mouse wheel to zoom in and out on the current mouse position

First up the key events and mouse leave are on the control while the other mouse events are on the MultiScaleImage. I also removed the height and width so the control will fill the whole page:


<UserControl x:Class="SoulSolutions.DeepZoom.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    KeyDown="UserControl_KeyDown" MouseLeave="UserControl_MouseLeave">
    <Grid x:Name="LayoutRoot" Background="Black">
        <MultiScaleImage x:Name="deepZoomObject" Source="thai2007/items.bin" 
        MouseLeftButtonDown="deepZoomObject_MouseLeftButtonDown" 
        MouseLeftButtonUp="deepZoomObject_MouseLeftButtonUp" 
        MouseMove="deepZoomObject_MouseMove"/>
    </Grid>
</UserControl>

In the code behind - page.xaml.cs we can hookup the events like so:
Key press:


private void UserControl_KeyDown(object sender, KeyEventArgs e)
{
    Point p = deepZoomObject.ElementToLogicalPoint(new Point((deepZoomObject.Width / 2),
 	((deepZoomObject.Width / deepZoomObject.AspectRatio) / 2))); 
    switch (e.Key)
    {
        case Key.I:
        case Key.C:
        case Key.Add:
            deepZoomObject.ZoomAboutLogicalPoint(1.1, p.X, p.Y);
            break;
        case Key.O:
        case Key.Space:
        case Key.Subtract:
            deepZoomObject.ZoomAboutLogicalPoint(0.9, p.X, p.Y);
            break;
        case Key.Left:
        case Key.A:
            deepZoomObject.ViewportOrigin = 
                new Point(deepZoomObject.ViewportOrigin.X - 0.1,
                deepZoomObject.ViewportOrigin.Y);
            break;
        case Key.Right:
        case Key.D:
            deepZoomObject.ViewportOrigin = 
                new Point(deepZoomObject.ViewportOrigin.X + 0.1,
                deepZoomObject.ViewportOrigin.Y);
            break;
        case Key.Up:
        case Key.W:
            deepZoomObject.ViewportOrigin = new Point(deepZoomObject.ViewportOrigin.X,
              deepZoomObject.ViewportOrigin.Y - 0.1);
            break;
        case Key.Down:
        case Key.S:
            deepZoomObject.ViewportOrigin = new Point(deepZoomObject.ViewportOrigin.X,
              deepZoomObject.ViewportOrigin.Y + 0.1);
            break;
        default:
            break;
    } 
} 

Mouse drag and drop:


bool dragInProgress = false;
Point dragOffset;
Point currentPosition;

private void deepZoomObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    dragInProgress = true;
    dragOffset = e.GetPosition(this);
    currentPosition = deepZoomObject.ViewportOrigin;
} 

private void deepZoomObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    dragInProgress = false;
} 

private void deepZoomObject_MouseMove(object sender, MouseEventArgs e)
{
    if (dragInProgress)
    {
        Point newOrigin = new Point();
        newOrigin.X = currentPosition.X - 
            (((e.GetPosition(deepZoomObject).X - dragOffset.X) 
		    / deepZoomObject.ActualWidth) * deepZoomObject.ViewportWidth);
        newOrigin.Y = currentPosition.Y - 
            (((e.GetPosition(deepZoomObject).Y - dragOffset.Y) 
		    / deepZoomObject.ActualHeight) * deepZoomObject.ViewportWidth);
        deepZoomObject.ViewportOrigin = newOrigin;
    }
} 

Just ensure we stop our drag and drop when you leave the application otherwise you get that nasty effect of it panning all all mouse movements.


private void UserControl_MouseLeave(object sender, MouseEventArgs e)
{
    dragInProgress = false;
}

Step 5, embed some JavaScript for mouse wheel event

Unfortunately the mouse wheel is not exposed to us so we have to work around this by capturing the event in JavaScript and communicating this back to the control. Mike has a helper class and the necessary javascript, so we simply include the scrollhelper.cs class and the scroller.js file. You must go to the properties of the javascript file and set "Build Action" =  "Embedded Resource".

Then we only need to attach to the event and Zoom about the point of the mouse cursor:


public Page()
{
    InitializeComponent();
    ScrollHelper scroller = new ScrollHelper();
    scroller.ScrollChanged += scroller_ScrollChanged;
} 

void scroller_ScrollChanged(object sender, ScrollEventArgs e)
{
    Point logicalPoint = deepZoomObject.ElementToLogicalPoint(new Point(e.X, e.Y));
    if (e.ScrollDelta < 0)
    {
        deepZoomObject.ZoomAboutLogicalPoint(.66, logicalPoint.X, logicalPoint.Y);
    }
    else
    {
        deepZoomObject.ZoomAboutLogicalPoint(1.33, logicalPoint.X, logicalPoint.Y);
    }
}

Step 6, Deploy

http://thailand.soulclients.com/

step6.jpg

So you can run this and check that it all works but now you really want to put this on the web and share it. Well its pretty simple if you just want the whole page, essentially the web project can simply be copied to your server to run. Your other option is to now use the control in an existing page.

In order to run a Silverlight 2 application on your web server you must set the mime type for ".xap" to "application/x-silverlight".

As this is a .net 3.5 project I also had to install the .net3.5 framework on my server.

You can download the source code, it only missing the images from the deep zoom composer here:

http://thailand.soulclients.com/SoulSolutions.DeepZoom.zip (12KB)

Tags:

10 comments so far...

Re: Silverlight Deep Zoom Sample Code

Thanks for the helpful code! It works great!

By Robert on   Sunday, 9 March 2008

Re: Silverlight Deep Zoom Sample Code

I noticed in the Hard Rock demo, they actually dynamically filtered and animated the tiles.

Do you know how they accomplished this?

By Robert on   Monday, 10 March 2008

Re: Silverlight Deep Zoom Sample Code

When I find out I blog it here first!
They mention a reference to an SDK but there is zero documentation on this. I'm really keen to have some filtering in place and the dynamically looking reshuffle they show.
So far I've spoted you must export as a collection from the deep zoom composer - this makes a folder of tile for each image.
I've seen that the control has a sub items collection but no idea what to do - its not obvious for me.
Will post a full article when i find out with source code.

By John (SoulSolutions) on   Monday, 10 March 2008

Re: Silverlight Deep Zoom Sample Code

Looks like there is now an offically sample with just the mouse bits:
http://blogs.msdn.com/expression/archive/2008/03/09/deep-zoom-sample-with-mousewheel-pan-click-zoom.aspx
Still searching for more....

By John (SoulSolutions) on   Monday, 10 March 2008

Re: Silverlight Deep Zoom Sample Code

I like this !!!!

By WOW Gold on   Thursday, 13 March 2008

Re: Silverlight Deep Zoom Sample Code

it has been explained from the scratch.. too good;)

By nagalakshmi on   Wednesday, 19 March 2008

Re: Silverlight Deep Zoom Sample Code

Can u give me Whole Source
I hv try this bcoz its very intresting.
if u can provide ful ex with images
plz mail me ritesh_niranjan@yahoo.co.in

regard's
Ritesh

By Ritesh on   Wednesday, 19 March 2008

Re: Silverlight Deep Zoom Sample Code

*Update* New code now available:
http://www.soulsolutions.com.au/Blog/tabid/73/EntryID/410/Default.aspx

By John (SoulSolutions) on   Monday, 24 March 2008

Re: Silverlight Deep Zoom Sample Code

Im a designer and I managed to get this working too! Happy days. However I tried doing a real deepzoom like the mix demo, I zoom right down to a spec on an item of clothing and that spec then turns into a new image and so on, however when I export that it gives me loads of files that im not sure what to do with and references Zindex, does your code support this and am I doing something wrong, any help greatly appreciated. Once the smaller image is resized to be tiny, a little pin icon appears on it.

Thanks for the original code it worked great.

By Alex on   Tuesday, 15 April 2008

Your name:
Title:
Comment:
Security Code
Enter the code shown above in the box below
Add Comment    Cancel