locked
Zoom using manipulation events not working correctly

    Question

  • Hello everyone,

    I'm currently trying to implement zooming and panning on an image control in winRT. Since there's nothing in the internet beside paid frameworks which I cannot afford, I'm trying to implement zooming and panning with manipulation events.

    I'm already making some progress as the zoom works partially as expected. I want to achieve the same behavior as for example in the Windows Phone 8 Photo app, i.e. when I zoom, the point where I started the pinch gesture should be the center of the scaling. My code shows exactly this behavior, however, this is only true when the image was unzoomed first (no zoom yet, so scale is 1). As soon as I completed the first zoom, I'm not able to zoom/unzoom anymore as the image moves to another point and the complete zoom will be misplaced. I assume that I'm running into some problems because the image is already zoomed so I need also to handle the current scaling but I don't know how to handle it.

    Can someone maybe help me in finding out, what's going wrong when I zoomed the image? Here's the code I used for zooming:

    private void Image_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
    {
        manipulationOrigin = e.Position;
     }
    
    private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
    {
        var transform = (sender as Image).RenderTransform as CompositeTransform;
        var scaledOrigin = new Point();
        var vector = new Point();
    
        double scale = e.Delta.Scale;
    
        transform.ScaleX *= scale;
        transform.ScaleY *= scale;
    
         scaledOrigin = new Point(manipulationOrigin.X * e.Cumulative.Scale, manipulationOrigin.Y * e.Cumulative.Scale);
    
        vector = new Point(scaledOrigin.X - manipulationOrigin.X, scaledOrigin.Y - manipulationOrigin.Y);
    
        transform.TranslateX = -vector.X;
        transform.TranslateY = -vector.Y;
     }

    manipulationOrigin is a member of my class, all other variables are locally defined. The image control uses, as stated by the code, a CompositeTransform so I'll be able to pan and zoom.

    I hope my problem is understandable and someone could help me.

    Wednesday, August 13, 2014 12:32 AM

Answers

  • I resolved the issue after I found something on google which gave me the correct direction. Instead of calculating the origin I use the CenterX and CenterY property of the CompositeTransform so the scale is applied using the location where the manipulation started. With this I'm able to zoom around my selected point. All manipulations get stored in a MatrixTransform so the CompositeTransform is always "new" (this means, all values are reset to 0) when a new manipulation occurs (this prevents bugs due to the different center locations)
    • Marked as answer by internetfreak Thursday, August 21, 2014 4:13 AM
    Thursday, August 21, 2014 4:13 AM

All replies

  • I tried to read your links and I think there's surely something which I can use but the main problem is, that I'm using winRT, so some things are not available anymore as they were with silverlight such as the Center property of the Manipulation.

    Thats also the main problem I have when I try to find something in the internet because winRT is different from silverlight so many sites probably contain my answers I need but I cannot use them as I don't know how to replace the missing things

    Wednesday, August 13, 2014 2:39 PM
  • Through a bit experimenting I was able to find a partial solution. Now I also multiply the origin with the current scale factor so the point is correctly scaled when I use it for the calculations. Now I can zoom and unzoom as much as I want as long as the point where the manipulation occurs is still the same (you can use multiple gestures but you may not move your fingers so the system reports the position as almost equal to the last manipulation position) but when I move slightly, the image still jumps a bit because the translation gets too much offset compared to the old value (it should be a relatively small value, i.e 3-5 dip but it is for example 30 dips which is too much)

    Here's the new code I'm using now:

    private void Image_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
            {
                lastScale = ((sender as Image).RenderTransform as CompositeTransform).ScaleX;
                manipulationOrigin = new Point(e.Position.X * lastScale, e.Position.Y * lastScale);
            }
    
            private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
            {
                var transform = (sender as Image).RenderTransform as CompositeTransform;
                var scaledOrigin = new Point();
                var vector = new Point();
    
                double scale = e.Delta.Scale;
    
                transform.ScaleX *= scale;
                transform.ScaleY *= scale;
    
                if (scale != 1)
                {
                    scaledOrigin = new Point(manipulationOrigin.X * e.Cumulative.Scale, manipulationOrigin.Y * e.Cumulative.Scale);
    
                    vector = new Point(scaledOrigin.X - manipulationOrigin.X, scaledOrigin.Y - manipulationOrigin.Y);
    
                    transform.TranslateX = -vector.X;
                    transform.TranslateY = -vector.Y; 
                }
    
            }

    Can someone maybe spot the difference I need to also support gestures on another point? The offset should be relatively small regardless which point I'm using as base point for my manipulation

    Thursday, August 14, 2014 1:30 AM
  • I resolved the issue after I found something on google which gave me the correct direction. Instead of calculating the origin I use the CenterX and CenterY property of the CompositeTransform so the scale is applied using the location where the manipulation started. With this I'm able to zoom around my selected point. All manipulations get stored in a MatrixTransform so the CompositeTransform is always "new" (this means, all values are reset to 0) when a new manipulation occurs (this prevents bugs due to the different center locations)
    • Marked as answer by internetfreak Thursday, August 21, 2014 4:13 AM
    Thursday, August 21, 2014 4:13 AM