Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pinch-to-zoom on huge images?

I found this Pinch-to-zoom example at http://forums.create.msdn.com

Here is the xaml:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 
            <StackPanel> 
                <TextBlock Text="Tap to center" Style="{StaticResource PhoneTextNormalStyle}"/> 
                <TextBlock Text="Tap and hold to reset" Style="{StaticResource PhoneTextNormalStyle}"/> 
                <TextBlock Text="Touch and move to drag" Style="{StaticResource PhoneTextNormalStyle}"/> 
                <TextBlock Text="Pinch (touch with two fingers) to scale and rotate" Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap"/> 
                <TextBlock Text="Flick (drag and release the touch while still moving) will show flick data on bottom of screen." Style="{StaticResource PhoneTextNormalStyle}" TextWrapping="Wrap"/> 
            </StackPanel> 
            <TextBlock x:Name="flickData" Text="Flick:" Style="{StaticResource PhoneTextNormalStyle}" VerticalAlignment="Bottom"/> 
            <Image x:Name="image" Source="/map.jpg" RenderTransformOrigin="0.5,0.5" CacheMode="BitmapCache"> 
                <Image.RenderTransform> 
                    <CompositeTransform x:Name="transform"/> 
                </Image.RenderTransform> 
                <toolkit:GestureService.GestureListener> 
                    <toolkit:GestureListener  
                        Tap="OnTap" Hold="OnHold" 
                        DragStarted="OnDragStarted" DragDelta="OnDragDelta" DragCompleted="OnDragCompleted" 
                        Flick="OnFlick" 
                        PinchStarted="OnPinchStarted" PinchDelta="OnPinchDelta" PinchCompleted="OnPinchCompleted"/> 
                </toolkit:GestureService.GestureListener> 
            </Image> 
        </Grid> 

And the cs source:

public partial class GestureSample : PhoneApplicationPage 
    { 
        double initialAngle; 
        double initialScale; 

        public GestureSample() 
        { 
            InitializeComponent(); 
        } 

        private void OnTap(object sender, GestureEventArgs e) 
        { 
            transform.TranslateX = transform.TranslateY = 0; 
        } 

        private void OnDoubleTap(object sender, GestureEventArgs e) 
        { 
            transform.ScaleX = transform.ScaleY = 1; 
        } 

        private void OnHold(object sender, GestureEventArgs e) 
        { 
            transform.TranslateX = transform.TranslateY = 0; 
            transform.ScaleX = transform.ScaleY = 1; 
            transform.Rotation = 0; 
        } 

        private void OnDragStarted(object sender, DragStartedGestureEventArgs e) 
        { 
            image.Opacity = 0.3; 
        } 

        private void OnDragDelta(object sender, DragDeltaGestureEventArgs e) 
        { 
            transform.TranslateX += e.HorizontalChange; 
            transform.TranslateY += e.VerticalChange; 
        } 

        private void OnDragCompleted(object sender, DragCompletedGestureEventArgs e) 
        { 
            image.Opacity = 1.0; 
        } 

        private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e) 
        { 
            Point point0 = e.GetPosition(image, 0); 
            Point point1 = e.GetPosition(image, 1); 
            Point midpoint = new Point((point0.X + point1.X) / 2, (point0.Y + point1.Y) / 2); 
            image.RenderTransformOrigin = new Point(midpoint.X / image.ActualWidth, midpoint.Y / image.ActualHeight); 
            initialAngle = transform.Rotation; 
            initialScale = transform.ScaleX; 
            image.Opacity = 0.8; 
        } 

        private void OnPinchDelta(object sender, PinchGestureEventArgs e) 
        { 
            transform.Rotation = initialAngle + e.TotalAngleDelta; 
            transform.ScaleX = transform.ScaleY = initialScale * e.DistanceRatio; 
        } 

        private void OnPinchCompleted(object sender, PinchGestureEventArgs e) 
        { 
            image.Opacity = 1.0; 
        } 

        private void OnFlick(object sender, FlickGestureEventArgs e) 
        { 
            flickData.Text = string.Format("{0} Flick: Angle {1} Velocity {2},{3}", 
                e.Direction, Math.Round(e.Angle), e.HorizontalVelocity, e.VerticalVelocity); 
        } 
    }

It works pretty well for small images (less then 2000x2000 pixels). But in my example, i have this huge metro map (http://www.vasttrafik.se/upload/Linjekartor_hogupplost/Goteborg2010/Linjen%C3%A4tskarta-101212.png or vector http://www.vasttrafik.se/upload/Linjekartor_hogupplost/Goteborg2010/Linjen%C3%A4tskarta-101212.pdf). It would be even nicer if the user could scale a vector image but even importing such a huge vector is a serious performance issue.

Maybe i could split the image up into several "multi-scale images" and use this http://dotnetbyexample.blogspot.com/2010/08/windows-phone-7-multi-touch-panzoom.html, but i don't really know how to use his class :(

Any ideas? How would you guys solve this problem?

Thanks

Richard

like image 743
Richard Avatar asked Feb 03 '11 11:02

Richard


2 Answers

The ideal approach for your solution is to use MultiScaleImage, which is specifically designed to display large image data. However, in order to work with MultiScaleImage you need to get your iamge data prepared int he right format. Basically, you need the image sliced up and rescaled, etc so that the user loads as little information as possible while they zoom in and out of your image.

The DeepZoom documentation describes the process and has links to the DeepZoom Composer tool, which you use to prepare your image data.

Once you've got the MultiScaleImage approach working, you can then look at using Laurent's Multitouch Behavior (if necessary) to provide additional user interactions.

like image 184
Derek Lakin Avatar answered Sep 18 '22 05:09

Derek Lakin


Have you heard of Silverlight Deep-Zoom?

http://msdn.microsoft.com/en-us/library/cc645050(v=vs.95).aspx

like image 29
Vasco Rinaldo Avatar answered Sep 22 '22 05:09

Vasco Rinaldo