How can I avoid a “jump” when scaling on the canvas, when the center of scaling changes due to pinching (zooming) or other subway style gesture

How can I avoid the “transition” when scaling to the canvas object, when the center of scaling changes due to pinching (zooming) or other metropolis-style gesture.

The behavior I'm trying to archive is similar to the scaling behavior of the preinstalled win8 maps application. If you perform a pinch gesture (increase or decrease), the center of zoom is set halfway between the fingers. If you lift one of your fingers, place it on another point, you can immediately perform another zoom operation, the center of zoom will change correctly, without any jumps (moving from the coordinates of the user interface of objects on the canvas).

I am trying to implement similar behavior on a large Canvas object (in a C # WinRT application) using a compound transform. I want to enable translation and scaling, without rotation (for now, maybe I'll add this later):

I initialize this by placing the center of scale at the center of the screen:

this.compositeTransform = new CompositeTransform(); this.compositeTransform.CenterX = this.mainPage.Width / 2.0; this.compositeTransform.CenterY = this.mainPage.Height / 2.0; this.innerCanvas.RenderTransform = compositeTransform; 

Then I will use the delta event to process the input

 private void InnerCanvas_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { this.compositeTransform.ScaleX *= e.Delta.Scale; this.compositeTransform.ScaleY *= e.Delta.Scale; this.compositeTransform.CenterX = e.Position.X; this.compositeTransform.CenterY = e.Position.Y; this.compositeTransform.TranslateX += e.Delta.Translation.X; this.compositeTransform.TranslateY += e.Delta.Translation.Y; } 

This works correctly if I perform the same gesture. The new center is calculated correctly when I perform tough gestures. However, a change in the center of zoom leads to a sudden jump, for example, when one of the fingers is lifted after a gesture. Of course, I can only change the center for gestures, but the problem of jumping remains. This, of course, is logical, since scaling works with the new center of scaling. I did not understand how to avoid the jump. Since the scale value itself remains constant, it should be possible to have the same form (unchanged coordinates) with a changed center.

My current reasoning is that I have to somehow change the coordinates of TranslateX and TranslateYY in order to balance the new center point so that the current screen coordinates of the ui elements remain unchanged. Something like this (scaleTransform is a ScaleTransform that only gets scale data) ...

 Point reverseScaleTransform = this.scaleTransform.Inverse.TransformPoint(new Point(e.Position.X,e.Position.Y)); this.compositeTransform.TranslateX += reverseScaleTransform.X - e.Position.X; this.compositeTransform.TranslateY += reverseScaleTransform.Y - e.Position.Y; 

But that doesn't work either. All this seems like a standard problem on the tablet, but I did not find a solution, despite the excessive search, maybe I'm using the wrong keywords.

+4
source share
3 answers

I finally figured out how to solve the problem using manual transformations without using ScrollViewer.

  TranslateTransform tmpTranslate = new TranslateTransform(); private void InnerCanvas_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { //Transform world space into local space (origin: Scale center from the last manipulation event) this.tmpTranslate.X = this.compositeTransform.CenterX; this.tmpTranslate.Y = this.compositeTransform.CenterY; Point center = this.compositeTransform.Inverse.TransformPoint(e.Position); Point localPoint = tmpTranslate.Inverse.TransformPoint(center); //Now scale the point in local space localPoint.X *= this.compositeTransform.ScaleX; localPoint.Y *= this.compositeTransform.ScaleY; //Transform local space into world space again Point worldPoint = tmpTranslate.TransformPoint(localPoint); //Take the actual scaling... Point distance = new Point( worldPoint.X - center.X, worldPoint.Y - center.Y); //...amd balance the jump of the changed scaling origin by changing the translation this.compositeTransform.TranslateX += distance.X; this.compositeTransform.TranslateY += distance.Y; //Also set the scaling values themselves, especially set the new scale center... this.compositeTransform.ScaleX *= e.Delta.Scale; this.compositeTransform.ScaleY *= e.Delta.Scale; this.compositeTransform.CenterX = center.X; this.compositeTransform.CenterY = center.Y; //And consider a translational shift this.compositeTransform.TranslateX += e.Delta.Translation.X; this.compositeTransform.TranslateY += e.Delta.Translation.Y; } 
+2
source

I would suggest looking at a sample window of the 8 scroll, pan, and zoom XAML run .

Scaling is already implemented for you, just use the scroll viewer with zooming enabled. Does this fit your requirements?

0
source

If we just add

 distance.x = (currentcenter.x - previouscenter.x) * (scalefactortillnow - 1) 

similarly

 distance.y = (currentcenter.y - previouscenter.y) * (scalefactortillnow - 1) 

and

 composite.translatex += distance.x; composite.translatey += distance.y; 

it would be enough to compensate for the jumps due to a change in the center. I personally ran into a problem and found that it works.

0
source

All Articles