Attempting to scale a mouse based image, but my math is a bit off

I am working on full-screen image viewing, I will temporarily open the developer url:

http://www.jungledragon.org/apps/jd3/image/704/great_grey_owl.html/zoom

This viewer responds and scales to the width and height of your browser. One of its key features is the ability to zoom in and out with the mouse wheel. Instead of center-based scaling, the idea is to scale by origin, which means the coordinates of your mouse, which allows you to zoom in on certain areas of the image.

How to reproduce the problem

If you open the above URL and play quickly with the mouse wheel, it may be working correctly. However, the math I'm using is a bit off. Here is how you can reproduce the problem:

  • Open the above URL
  • Hover over the owl’s left eye
  • Zoom in on one step with the mouse wheel, it must scale precisely in the eye.
  • Position your mouse on the owl's beak.
  • Zoom in one more step with the mouse wheel.

Now you should notice that the second step of the buzzer did not hit exactly the owl’s cranberries; it seems to be slightly off, both horizontally and vertically. I think this is the result of bad math.

How it works

Here is the javascript that handles all this:

http://www.jungledragon.org/apps/jd3/js/jd3-slideshow.js

I collect the wheel event. Based on its direction, I increase or decrease the zoom level. Actual scaling is nothing more than applying a CSS class that scales an image using CSS3 transform:

&.grow1 { @include jd-scale(1); } &.grow2 { @include jd-scale(1.5); } &.grow3 { @include jd-scale(2.0); } &.grow4 { @include jd-scale(2.5); } &.grow5 { @include jd-scale(3.0); } 

Note. . The above call for SASS mixin, which translates into the right provider prefixes for transform: scale.

The above provides basic scaling without problems. However, in order to scale based on the beginning, there are a few more steps to follow. After actually scaling, I first set the origin of the increase in javascript using transform-origin. Here is my helper function to install it:

 function zoomOrigin(selector, originStr) { selector.css({'-webkit-transform-origin': originStr}); selector.css({'-moz-transform-origin': originStr}); selector.css({'-ms-transform-origin': originStr}); selector.css({'-o-transform-origin': originStr}); selector.css({'transform-origin': originStr}); } 

The basis of this issue is the calculation of the correct origin. To calculate this value, two things are worth mentioning:

  • Absolute coordinates (which means that X and Y) refer to the image, not to the page
  • The source calculation should take into account that the image has grown / shrunk based on the current zoom state.

Calculation of origin occurs in real time based on the mousemove event. Here is a method that does this, with unnecessary parts being removed:

 $("#image-container img").mousemove(function(e) { // user has moved their mouse. in case of zooming or panning, this means that the // origin (center point) of those interactions need to be recalculated // calculate the mouse offset within the zoomable object (which is different than the page-level offset) // this relies on the parent of the element having position:relative set var parentOffset = $(this).offset(); zoomOriginX = e.pageX - parentOffset.left; zoomOriginY = e.pageY - parentOffset.top; // recalculate the width and height of the image given the current zoom level width = $(this).outerWidth() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerWidth()); height = $(this).outerHeight() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerHeight()); // calculate origin percentages based on zoomed width and height // the zoom methods rely on these variables to be set zoomOriginPercX = (zoomOriginX / width * 100); zoomOriginPercY = (zoomOriginY / height * 100); }); 

The main goal of this method is to correctly set the global variables zoomOriginPercX and zoomOriginPercY, which are used to set the start (percent) before scaling.

From a mathematical point of view, my idea was to simply calculate the increased width of the image and use the X and Y offsets to get a percentage of reliable origin. As the statement of the problem shows, I'm pretty close to the correct calculation, but something does not work.

Although scaling currently works well, I want it to be perfect. This would make for a fairly powerful image viewer that is really easy to implement, as well as for others.

+4
source share
1 answer

Desired effect

To begin to answer your question, I think that you first need to clarify the desired effect. In fact, you are looking for the same effect that you get if you are rooted to enlarge the image on the iPhone - the “origin” of the pinch remains unchanged, and everything around it stretches. You can imagine that fasten some elastic fabric at the origin and pull the corners.

Problem

This works great for you if you don't move the mouse between zooms, but if you do, the origin will move. The cause of the problem is precisely that you change the origin of the transformation every time you move the mouse. Of course, you need to do this, but you calculate the origin based on the original (100% enlarged) position of the image. The actual origin should be somewhere between the beginning of the first increase and the new position of the mouse.

In other words, CSS just does one conversion. If you set the start value to x, y, and then zoom in to increase level 2, it will give the same result as if you set the origin to x2, y2, scale to level 1, then move to x, y and go to level 2.

Solutions

I assume that you could solve the problem in several ways:

  • Calculate the scaling factor for the "new" source for each scaling
    • this is most likely a function of the zoom level, mouse position, and previous source.
  • Calculate and apply translation for each movement of the source
    • will again depend on the current source, zoom level and mouse position.
  • Find another way to convert “stop” on top of each other.
    • One way to do this could be to dynamically generate a new one containing a div every time you apply a scale transformation similar to the decision made in this matter .

Unfortunately, I do not have time to go beyond this, but I hope he points you in the right direction?

+1
source

Source: https://habr.com/ru/post/1481725/


All Articles