Bug in the default Deep Zoom code and some extras

I found this bug today in the default code outputted from the Deep Zoom Composer code. It doesn’t take into account the aspect ratio when panning so you need to divided the width by this ratio or else or vertical panning will be strange.

newOrigin.X = currentPosition.X - (((e.GetPosition(msi).X - dragOffset.X)/msi.ActualWidth)*msi.ViewportWidth);
        newOrigin.Y = currentPosition.Y - (((e.GetPosition(msi).Y - dragOffset.Y) / msi.ActualHeight) * msi.ViewportWidth / msi.AspectRatio);

I also don’t like the way you can pan your image out of view and get lost so added a little helper really quickly (sure someone can improve on this)

MouseMove += delegate(object sender, MouseEventArgs e)
        {
        if (mouseIsDragging)
        {
        var newOrigin = new Point();
        newOrigin.X = currentPosition.X - (((e.GetPosition(msi).X - dragOffset.X)/msi.ActualWidth)*msi.ViewportWidth);
        newOrigin.Y = currentPosition.Y - (((e.GetPosition(msi).Y - dragOffset.Y) / msi.ActualHeight) * msi.ViewportWidth / msi.AspectRatio);

        msi.ViewportOrigin = ensureinView(newOrigin);
        }
        };

 

private Point ensureinView(Point newOrigin)
        {
        double width = GetMSIWidth(msi);
        double height = width/msi.AspectRatio;
        Point Offset = GetMSIOffset(newOrigin, width);
        if (Offset.X < 0)
        {
        Offset.X = 0;
        }
        if (Offset.X - width > -msi.ActualWidth)
        {
        Offset.X = width - msi.ActualWidth;
        }
        if (Offset.Y < 0)
        {
        Offset.Y = 0;
        }
        if (Offset.Y - height > -msi.ActualHeight)
        {
        Offset.Y = height - msi.ActualHeight;
        }
        return new Point((Offset.X/msi.ActualWidth)*msi.ViewportWidth, (Offset.Y/msi.ActualHeight)*msi.ViewportWidth/msi.AspectRatio);
        }

        private static double GetMSIWidth(MultiScaleImage msi)
        {
        //ViewportWidth is the ratio of the image to the control size, eg when it occupies half ratio is 2, occupies half (half is out of view) it is 0.5
        return msi.ActualWidth/msi.ViewportWidth;
        }

        private static Point GetMSIOffset(Point viewportOrigin, double currentMapWidthInPixels)
        {
        //ViewportOrigin is the distance from the top left measured as a ratio of its width, eg when it is 256px and is 128px away it is 0.5
        return new Point {X = (currentMapWidthInPixels*viewportOrigin.X), Y = (currentMapWidthInPixels*viewportOrigin.Y)};
        }

I also in the little sample i did today really didn’t want to zoom out to far so added a little check on the zoom method:

public void Zoom(double zoom, Point pointToZoom)
        {
        if (zoom >= 1 || msi.ViewportWidth < 1)
        {
        Point logicalPoint = msi.ElementToLogicalPoint(pointToZoom);
        msi.ZoomAboutLogicalPoint(zoom, logicalPoint.X, logicalPoint.Y);
        }
        }

This means you can zoom too far beyond the overall width of the image. One side effect of this is the image will snap to the bottom right of the control when smaller then the control. Be a simple improvement to allow for it to be moved within the bounds.

Anyway I hope this helps someone out.