Sunday, January 4, 2009

Silverlight 2 : Using Magnifier to Zoom contents on Canvas

First of all wish all my blog readers very Happy New Year ! , Thanks for your continuous feedback and support all the time. Some people given me feedback in 2008 that I wrote some article too basic and not to the level which they expect, frankly speaking , I wrote here what comes to my mind, what I see and what I feel difficult to understand to others, so I always try my best to keep things simple and quick.But I will do follow your feedback so be with me in year 2009 since lots new on this blog going to be there in coming few months !

There are several post on usage of Magnifier in Silverlight 1.1 as well as in 2.0, Some have done with Images and some with Videos. I am re-making this code snippet which is already published by Jeff Prosise’s blog and code snippet which I am going to share here is already available on one of the PDC 2008 snippet at : http://www.wintellect.com/Downloads/PDC_2008_Demos.zip

Idea of doing this again re-work and twick the already written source code is to create awareness about the Magnifier which can be use efficiently for zooming part of image or video.

Step 1 : Create a Layout which will hold 3 Canvas.

<Grid x:Name="LayoutRoot" Background="Black" MouseLeftButtonDown="OnMouseLeftButtonDown" MouseMove="OnMouseMove" MouseLeftButtonUp="OnMouseLeftButtonUp">

Note that, for Zooming particular portion of Canvas, we are suppose to handle mouse events on all over base canvas which you can see from above events.

<Canvas x:Name="CoreCanvas" Width="800" Height="530">
            <!-- Base canvas -->
            <Canvas x:Name="BaseCanvas" Canvas.Left="0" Canvas.Top="0" Width="800" Height="400" Background="Black">
                <Canvas Canvas.Left="90" Canvas.Top="30" Width="620" Height="470">
                    <Rectangle Canvas.Left="0" Canvas.Top="0" Width="620" Height="470" Fill="White" />
                    <MediaElement Canvas.Left="10" Canvas.Top="10" Width="600" Height="450" Source="Bear.wmv" />
                </Canvas>
            </Canvas>

Above is the Canvas which will hold Video / Image file on which we will put magnifier for zooming.

<!-- Magnify canvas -->
<Canvas x:Name="MagnifyCanvas" Canvas.Left="0" Canvas.Top="0" Width="800" Height="400" Background="Black" Visibility="Collapsed">
                <Canvas.RenderTransform>
                    <ScaleTransform CenterX="0" CenterY="0" ScaleX="4" ScaleY="4"/>
                </Canvas.RenderTransform>
                <Canvas.Clip>
                    <EllipseGeometry x:Name="Lens" Center="0,0" RadiusX="40" RadiusY="40" />
                </Canvas.Clip>
                <Canvas Canvas.Left="90" Canvas.Top="30" Width="620" Height="470">
                    <Rectangle Canvas.Left="0" Canvas.Top="0" Width="620" Height="470" Fill="White" />
                    <MediaElement Canvas.Left="10" Canvas.Top="10" Width="600" Height="450" Source="Bear.wmv" />
                </Canvas>
                <Path Canvas.Left="0" Canvas.Top="0" StrokeThickness="0">
                    <Path.Data>
                         <EllipseGeometry x:Name="LensBorder" Center="0,0" RadiusX="40" RadiusY="40" />
                    </Path.Data>
                </Path>
            </Canvas>
        </Canvas>
      </Grid>

Above code will add another Canvas with Ellipse which is our circular magnifier for zooming, you can try out with RectangleGeometry.

Step 2 : Create a general method as AdjustLens() for maitaining the Magnifier value and position.

Variables declare for drag and scale which keep tracks whether drag by mouse for Magnification or not.

private bool drag = false;
private const double scale = 4.0;

private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
            double x = e.GetPosition(CoreCanvas).X;
            double y = e.GetPosition(CoreCanvas).Y;
            AdjustLens(x, y);

            MagnifyCanvas.Visibility = Visibility.Visible;
            ((FrameworkElement)sender).CaptureMouse();
            drag = true;
}

OnMouseLeftButtonDown basically pass the position of CoreCanvas to AdjustLens() which keep tracks of all the movements on Canvas.Same for rest of the events.

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (drag)
            {
                double x = e.GetPosition(BaseCanvas).X;
                double y = e.GetPosition(BaseCanvas).Y;
                AdjustLens(x, y);
            }
        }

        private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (drag)
            {
                MagnifyCanvas.Visibility = Visibility.Collapsed;
                ((FrameworkElement)sender).ReleaseMouseCapture();
                drag = false;
            }
        }

AdjustLens() helps to position Magnifier as per mouse movements and position of Canvas.

private void AdjustLens(double x, double y)
        {
            Lens.Center = LensBorder.Center = new Point(x, y);
            MagnifyCanvas.SetValue(Canvas.LeftProperty, (1 - scale) * x);
            MagnifyCanvas.SetValue(Canvas.TopProperty, (1 - scale) * y);
        }
  So build the project, you will get output as follows.

mag1

After applying Magnifier by dragging mouse, it will look like..

mag3

If you notice, you can see a Big Ellipse on right corner of the screen which shows a Bird is zoomed up, you can implement Magnifier while Video is in Run mode and it will not disturb the execution of video neither it will break any frame, It will run as smooth as it runs normally.

Hope this post will give you idea about implementation of Magnifier in Silverlight application and inspire you to implement it like I inspired and remake it from Jeff’s blog.

Vikram. 

3 comments:

Swapnil said...

Hi Vikram........

Nice Article....It helped me a lot..

Keep the good work going.

Thank You....
Swapnil P.Patil.

Vikram Pendse said...

Thanks Swapnil.

Unknown said...

Hi Vikram,
I am from an MNC in Pune and currently we have some projects going on in Microsoft .NET technologies with SilverLight 2.0.

We need some technical assistance in SilverLight 2.0 and was wondering if we could get some time from you for the same. I'd really appreciate if you could kindly let me know a suitable time when I can give you a call and discuss a few things. My email id is - makoojo@gmail.com.

Thanks & regards


Manoj Joshi