Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UWP: Calculate Transformation based on ScrollViewer

Tags:

I have a windows universal app where I am rendering a scene with DirectX. I want to make use of the Scrollviewer and therefore I render my scene behind the Scrollviewer and want to calculate the scene transformation based on the Scrollviewer. It works fine so far, especially the translation and scrolling. But when I zoom in, the scene jumps around in two special situations:

  1. The scene had enough space and was centered and now scrolling is required.
  2. The opposite direction.

More or less I use the following code:

float zoom = scrollViewer.ZoomFactor;  float inverseZoom = 1f / scrollViewer.ZoomFactor;  float scaledContentW = Document.Size.X * scrollViewer.ZoomFactor; float scaledContentH = Document.Size.Y * scrollViewer.ZoomFactor;  float translateX; float translateY;  if (scaledContentW < scrollViewer.ViewportWidth) {     translateX = ((float)scrollViewer.ViewportWidth * inverseZoom - Document.Size.X) * 0.5f; } else {     translateX = -inverseZoom * (float)scrollViewer.HorizontalOffset; }  if (scaledContentH < scrollViewer.ViewportHeight) {     translateY = ((float)scrollViewer.ViewportHeight * inverseZoom - Document.Size.Y) * 0.5f; } else {     translateY = -inverseZoom * (float)scrollViewer.VerticalOffset; }  float visibleX = inverseZoom * (float)scrollViewer.HorizontalOffset; float visibleY = inverseZoom * (float)scrollViewer.VerticalOffset; ;  float visibleW = Math.Min(Document.Size.X, inverseZoom * (float)scrollViewer.ViewportWidth); float visibleH = Math.Min(Document.Size.Y, inverseZoom * (float)scrollViewer.ViewportHeight);  Rect2 visibleRect = new Rect2(visibleX, visibleY, visibleW, visibleH);  transform =     Matrix3x2.CreateTranslation(         translateX,         translateY) *     Matrix3x2.CreateScale(zoom); 

You can get an example here: https://github.com/SebastianStehle/Win2DZoomTest

To be sure that my eyes are not broken I was zooming around and have written the translation and zoom values to a file. You can see it here:

https://www.dropbox.com/s/9ak6ohg4zb1mnxa/Test.png?dl=0

The meaning of the columns is the following:

Column 1: The computed zoom value of the transformation matrix (M11) = ScrollViewer.ZoomFactor Column 2: The computed x offset of the matrix (See above) Column 3: The x value of the result of matrix * vector (500, 500), here: Colum1 * 500 + Column2

You see, that the matrix values look good, but when applying the transformation you get this little jump to the right for some milliseconds. One theory was, that the viewport might change because the scrollbar becomes visible. But this is not the case. I also tried fixed values here, made the scrollbars visible and even created a custom template for the scrollviewer with no scrollbars at all.

Btw: This is a cross post, I also asked the question here: https://github.com/Microsoft/Win2D/issues/125

like image 484
SebastianStehle Avatar asked Aug 07 '15 15:08

SebastianStehle


1 Answers

You see this behavior because when you zoom bigger than the ScrollViewer's size, the zoom center point is moved. To fix this, you just need to subscribe to the ScrollViewer's LayoutUpdated event and inside the handler, manually keep its content in the center.

    private void ScrollViewer_LayoutUpdated(object sender, object e)     {         this.ScrollViewer.ChangeView(this.ScrollViewer.ScrollableWidth / 2, this.ScrollViewer.ScrollableHeight / 2, this.ScrollViewer.ZoomFactor, true);     } 

This should fix the jumpy movement on the two drawed Rectangles from Win2D.


Update

Just to prove my point, the jumpy behavior is most likely due to unusual translate x and/or y value change when the content size goes over the size of the ScrollViewer. So I wrote some code to log these values on the screen as shown below -

... this.Test1.Text += ((float)translateX).ToString() + " "; this.Test2.Text += ((float)translateY).ToString() + " ";  session.Transform =     Matrix3x2.CreateTranslation(         (float)translateX,         (float)translateY) *     Matrix3x2.CreateScale((float)zoom); 

enter image description here

Now look at the numbers on the image above. What I did was I tried zooming in until the jumpy scene occurred. See the highlighted translate y value? It is slightly greater than its previous value, which is against the declining trend.

So to fix this, you will need to be able to skip these unusual values caused by ScrollViewer.

like image 138
Justin XL Avatar answered Nov 07 '22 15:11

Justin XL