I have an issue when zooming in on a fractal (webgl) - javascript

When I zoom in too much and I drag the picture using my mouse it just moves too fast. Similarly if I zoom out too much the picture drags very slowly.
This is how it is zooming in (scale) and how it drags the picture around (xPos, yPos)
fPosition.x = fPosition.x * scale + xPos;
fPosition.y = fPosition.y * scale + yPos;
What should I do to fix this?

You need to adjust the movement by the inverse scale. When at 1 to 1 no zoom you move the image 1 pixel for every one pixel you drag.
When you are zoomed in at 2 to 1. One pixel is now 2 pixels wide (you have a scale of 2) you still want to drag the image at the same screen speed so you move it 1/scale pixels for every pixel you drag. 1/2 = 0.5 for every one pixel you move your mouse/pointer/touch thing .
When zoomed out 0.5 to 1, the scale is now 0.5 and the images is half its size you need to move it 1/scale pixels for every pixel you drag. 1/0.5 = 2
So scale is how big a pixel is and movement is the inverse of that scale. 1 divide scale

Related

How do I adjust panning after zoom?

I have a view built in React. Simplified it consists of a workspace which is positioned absolute in relation to the viewport. The viewport is the same size as the browser window. Normally (but not always) the workspace will be larger than the viewport, like in the figure below.
The user can pan the workspace revealing different areas of it in the viewport. The panning sets a negative offset on the workspace in relation to the viewport expressed in pixels (PanX and PanY).
The user can also zoom in and out. Zooming is done in fixed steps, in this example with a factor of 0.25, i.e. +0.25 for zooming in and -0.25 for zooming out. This affects the scale which in turn affects the size of the workspace. In figure 2 below the user has zoomed in one step (scale +0.25).
Every object in the workspace scale proportionally to the workspace. In this example the green triangle represents an object in the workspace. So after zooming in, the triangle will be larger. When the object becomes larger its offset in the viewport will change. In this example it will look like it grows downwards and to the right.
What I want to accomplish is that the center of the viewport should still be centered after the user has zoomed in or out. To accomplish this I need to adjust the PanX and PanY so the viewport remains centered over the point in workspace where it was centered before the zoom.
So my question is: How do I keep the viewport centered over the same point in the workspace when zooming in and out?
The calculation should result in new values that I can set for PanX and PanY for the workspace that centers the viewport. Keep in mind that the viewport can be positioned anywhere as long as none of its edges are outside the workspace (like in the figure below).
Thank you in advance!
If you want to keep whatever is in the center of the screen in the center of the screen, then define:
const centerX = screen.width / 2;
const centerY = screen.height / 2;
Then when you scale by a value scale (e.g. 0.25 or -0.25), you need to adjust PanX and PanY:
PanX -= scale * centerX;
PanY -= scale * centerY;
I wrote a tutorial here, which uses an SVG and a slightly different transformation system, but it is basically the same thing.

Using parallax scrolling, cube has distortion

I am creating a 2d platformer right now, and I decided that I would use parallax scrolling.
So what I did is I had 3 tile maps, one for the background, one for the foreground, and one for on front of the foreground.
Each tile map would display the tiles at a different size.
Background -> 48px
Foreground -> 64px
On front of foreground -> 80px
I got the pixels from looking at other 3d games(such as Minecraft), when cubes are further a way. I wanted each tile to be as if the size of it is a cube.
I used the below code to calculate where each tile goes on the screen, based on its x, y, and size.
x - (cameraX * size / 64) + canvas.width / 2; // 64 is the size of the texture.
y - (cameraY * size / 64) + canvas.height / 2;
Here was the result:
As you can see the tiles in the background are moving slower.
However, when you jump, there would be white space between the tiles:
I understand why this is happening, it is because there should be a top face on the tile (as if it is a cube), but since it is only a square, it shows white space.
So I used this code to make it look as if it is a 3d cube.
var i = (size - size * 0.25);
while (i < size)
{
ctx.drawImage(images[this.type], getProperX(x*(i), i), getProperY(y*i, i), i, i);
// The first argument of getProperX/getProperY is the x/y, the second argument is the size of the tile.
i += 1;
}
This keeps drawing loads of squares, with a size slightly smaller than the last, so that the getProperX/Y function will display it in the right place.
Now they looks like cubes, so the problem is nearly fixed:
The only problem now, is that the length of the cubes are very long when you are looking on top/bottom of it, or to the right/left of it (as if it is distorted).
Why are the cubes/tiles so long, can anyone explain to me?
How would you go about fixing something like this?
Did I do something wrong in my parallax scrolling function getProperX/Y()? because I don't see why there is so much space between the distant tiles and the close ones.
Thanks for all help, very appreciated.

Image zoom centered on mouse position

I am writing a script with Fabric.js to zoom an image at the current mouse position. I have made some progress but there is an error somewhere.
Case 1: Keep the mouse at one point and zoom with the mouse wheel.
Result: Works perfectly, image zooms at that particular pixel.
Case 2: Zoom in a little at one position (3-5 times with mouse wheel), then move the mouse to a new position and zoom in there.
Result: Works fine for the first point, but after moving to another point and zooming, the image position is incorrect.
My code is in this fiddle:
https://jsfiddle.net/gauravsoni/y3w0yx2m/1/
I suspect there is something wrong with the image positioning logic:
imgInstance.set({top:imgInstance.getTop()-newMousY,left:imgInstance.getLeft()-newMousX});
What is going wrong?
The key to solving this puzzle is to understand how the image gets enlarged. If we're using a zoom factor of 1.2, the image becomes 20% larger. We assign 1.2 to the variable factor and do the following:
image.setScaleX(image.getScaleX() * factor);
image.setScaleY(image.getScaleY() * factor);
The upper left corner of the image stays in the same place while the picture is enlarged. Now consider the point under the mouse cursor. Every pixel above and to the left of the cursor has become 20% larger. This displaces the point under the cursor by 20% downward and to the right. Meanwhile, the cursor is in the same position.
To compensate for the displacement of the point under the cursor, we move the image so that the point gets back under the cursor. The point moved down and right; we move the image up and left by the same distance.
Note that the image might have been moved in the canvas before the zooming operation, so the cursor's horizontal position in the image is currentMouseX - image.getLeft() before zooming, and likewise for the vertical position.
This is how we calculate the displacement after zooming:
var dx = (currentMouseX - image.getLeft()) * (factor - 1),
dy = (currentMouseY - image.getTop()) * (factor - 1);
Finally, we compensate for the displacement by moving the point back under the cursor:
image.setLeft(image.getLeft() - dx);
image.setTop(image.getTop() - dy);
I integrated this calculation into your demo and made the following fiddle:
https://jsfiddle.net/fgLmyxw4/
I also implemented the zoom-out operation.

Trig / javascript to calculate padding required to accommodate image rotation without clipping

I have a known rect (grey) the outer parent element that contains an image element (orange). It's overflow is hidden.
I want to calculate the padding required to allow the image element(known width and height) to be rotated to a known angle (for this e.g. lets say 30 degrees).
It has proven to be relatively easy to calculate this if i were able to allow the parent(grey) element to expand to accommodate, but i can't.
create list of 4 image edge points p0,p1,p2,p3
rotate them the same way as the image will be rotated
double a=x-x0,b=y-y0,c,s;
c=cos(alfa);
s=sin(alfa);
x=a*c-b*s+x0;
y=a*s+b*c+y0;
x,y is the point
x0,y0 is center of rotation
alfa is the rotation angle
compute min,max of rotated points x,y coordinates this gets you the bounding box
summary
let (x0,y0) be the original image gray box size (X,Y) from your image
let (x1,y1) be the original image size (xa,xb) from your image
let (x2,y2) be the rotated image bounding box size (xmax-xmin,ymax-ymin) from bullet 3
if ((x2<=x0)&&(y2<=y0)) the image fits so stop
let mx=x0/x2 and my=y0/y2 be the needed scales to fit the image
do not zoom:
if (mx>1.0) mx=1.0;
if (my>1.0) my=1.0;
now select the correct scale m
m=mx; if (m>my) m=my;
now the m holds the scale needed to apply on rotated image to fit the gray area
do not forget to center the image ...

Canvas - Reset pixels around

I want to reset pixels to transparent like this:
Consider white as transparent. How to calculate those pixels.
If reset 50% it would be half image, if 100% it would be entire image hidden. On the picture is 35%.
Circle is just for show. It can be any square image.
For each point on the canvas, calculate the angle to your central point. In basic terms:
angle = Math.atan2(y - cy, x - cx);
Where (cx,cy) are the coordinates of your central point, and (x,y) the coordinates of the current pixel being examined.
If this angle is within the range you want to nuke, clear that pixel.
To make this simpler, add Math.PI*3/2, then do % Math.PI*2, and finally multiply by 100/(Math.PI*2) to get a number in the range 0 (up) counter-clockwise to 100.
Now it's a simple case of seeing if that number is less than your target percentage, and if so clear it.

Categories