JavaScript zoom image and center viewable area - javascript

I'm trying to create a zoom able image upon click of a button, however the image should be zoomed centered on the view able area, as the image may be bigger than the container.
I've created a fiddle here to illustrate what I want, I'd obviously usually hide the image outside the container, I'm not bothered about that part just now, also put in a border overlay to show the bounds of the container.
I've done the zoom part based on the image ratio, I just need to work out the new top and left css values and apply it to the image after the zoom. Also the image is draggable, so once you move the image it must take into account the position of the image.
Basically, the centrol point of the image within the red container must remain the same after the zoom, so you are effectly zooming in on whatever is at the middle of the container.
http://jsfiddle.net/wFaFg/1/
why do you we need code to link to jsfiddle?
Thanks
edit:
http://jsfiddle.net/FU55w/
getting close with the above fiddle, but still not zooming completely on central point

So I found the solution,
It is slightly more complex than just finding out how much the image increased in size.
I work out the x & y value of the center point of the image within the container, by taking the left and top value, turning it positive then adding half the container width and height.
var x = Math.abs(image.position().left) + container.width() / 2
var y = Math.abs(image.position().top) + container.height() / 2
I work out the ratio of the image scale by dividing the new width by the old width, then I can multiply the x & y value by the ratio.
Then take the difference between the new x and y away from the current left and top.
image.position().left - (newX - x)
image.position().top - (newY - y)
Complete fiddle:
http://jsfiddle.net/fbd2mk5q/

Try the new fiddle based on your comment:
http://jsfiddle.net/wFaFg/6/
$("#zoom").on("click", function(e)
{
var container = $("#container");
var image = $("#container img");
var curLeft = image.position().left;
var curTop = image.position().top;
var ratio = image.height() / image.width();
image.css({
height: image.height() + (20 * ratio),
width: image.width() + (20 * ratio),
left: curLeft - ((20 * ratio)/2),
top: curTop - ((20 * ratio)/2)
});
});

Related

Zoom to cursor without canvas in javascript

I have an <img> that is zoomed upon mousewheel scrolling, by adjusting transform: scale(). I want the zooming to be like in Google Maps, where you zoom to where the mouse cursor is, not to the center of the image. I'd like to not use canvas though, just for the learning experience (that's also why the other questions I found did not really help).
I set up a JSFiddle to demonstrate the problem. My thought process was as follows: when zooming in by 10%, the image expands in all directions, from the center of the image, by 10%. That means that e.g., the left and right edge will travel 5% of the original width in each direction. I therefore tried to solve the problem like so:
Calculate mouse offset from image center
Calculate new image offset (top and left) by multiplying mouse offset with zoom factor and divide by two
Apply offset and watch it all blow up it my face with the power of a million burning suns
It seems that I just can't find a formula or algorithm that fits.
Eventually I figured it out myself, although only by looking at existing solutions. Here is the JSFiddle that contains only the essentials.
The idea is to first set transform-origin: 0 0. This makes sure that, upon zooming, the image expands down and right, instead of distributing the increase in width over all four sides. Note that it does not reposition the image, it just changes the origin for all transformations.
Additionally, this JSFiddle assumes that the top and left margins of the image are aligned with the top and left margins of the container element. If the image should be repositioned before zooming occurs, this should be done through transform: translate() and the translateX and translateY values need to be updated accordingly.
The heart of the logic is this:
// Track the percentage change between the old
// and the new scale of the image
const ratio = 1 - nextScale / currentScale
// get the current mouse offset
const {
clientX,
clientY
} = event
// The += here is extremely important!
// The new 2D translation values are derived from the difference
// between mouse cursor position and current (!) 2D translation.
// So where is the mouse cursor relative to the translated image
// This difference is then adjusted by the % change of the scaling
translateX += (clientX - translateX) * ratio
translateY += (clientY - translateY) * ratio
/*
This would work for the first wheel scroll. But afterwards, the
image will not be translated enough to offset the zooming because
we're not taking into account the existing translation
translateX += (clientX - translateX) * ratio
translateY += (clientY - translateY) * ratio
*/
So to summarize the required steps:
Calculate the next scale
Calculate the current mouse offset relative to the translated image
Adjust the mouse offset for the change in scaling, e.g., const percentChange = 1 - nextScale / currentScale
Add the adjusted mouse offset to the existing values for translate()
Apply the transformation (scaling and the translation)
The linked JSFiddle also includes Lodash and transition: transform 330ms ease-in-out; to make the scrolling a little smoother and not affect browser performance too much.
You could use transform-origin : <position of your mouse pointer> :
transform-origin : 0% 0% points on the top left corner.
transform-origin : 100% 100% points on the bottom right corner.
Here's an example I made : https://jsfiddle.net/zez538L8/4/
The javaScript :
var currentzoom = 1;
function zoom(delta, e) {
var img = document.getElementById("test");
var width = img.offsetWidth; //calculating the size of the img (in px)
var height = img.offsetHeight;
var x = event.offsetX; //calculating the position of the mouse pointer on the picture (in px)
var y = event.offsetY;
var xpercent = x*100/width; //calculating the position of the mouse pointer on the picture (in %)
var ypercent = y*100/height;
img.style.transform = "scale("+currentzoom+")"; //scaling the picture
img.style.transformOrigin = xpercent + "% "+ ypercent +"%"; //transform-origin
currentzoom += delta;
}

Get x and y co-ordinate of image on mouse over

I am trying to get x and y co-ordinate on mouse move event of image
Now there are 2 scenarios which i think is utmost important for getting exact co-ordinates
Note : also i need to put zoomer on image hover
If you want to apply zoomer then image must be displayed in less
height and width div than original width and height
In first scenario, i will display the image as it is without any height and width limitations
But in this scenario i won't be able to apply zoomer as per mentioned in above note
Suppose i have image of pixel 2000x1500 then below code works very smoothly
var mouseMove = function(e) {
var X = Math.round((e.pageX - img.offset().left);
var Y = Math.round((e.pageY - img.offset().top));
};
In second scenario, i will display image in fix width and height div which will be smaller than image width and height
Suppose div width and height is 850x750 and you are displaying image of dimension 2000x1500 in that div
Now to get exact x and y co-ordinate code is
$(document).ready(function() {
$('#competition').on('load', function(e) {
naturalWidth = e.target.naturalWidth;
});
});
var mouseMove = function(e) {
var img = $('#competition'); // div in which image is loaded
// naturalWidth is origional width of image
// img.width() is width of div
ratio = (naturalWidth / img.width());
var X = Math.round((e.pageX - img.offset().left) * ratio);
var Y = Math.round((e.pageY - img.offset().top) * ratio);
};
Now what happens in second scenario is, when i move mouse horizontally, it gives 3 pixel difference after each mouse move event for x co-ordinate like 1 4 7 10 13
But i want to catch every single pixel of image
Any help would be greatly accepted...

Saving and loading div locations - Zoom and save alters div location on load

So I have a bunch of divs that are absolute to an overlay. The user creates a square div by dragging on the overlay. If you were to create a div and then zoom in and out, the div stays positioned in the same spot since it is absolute to the overlay as mentioned before.
However here's where the problem is. You are able to save the div location (top, left, height, width) to a .json and load the .json to show all of your previously saved divs. This works fine.... if you save and load on the same browser zoom percentage.
If you were to draw divs on 150% zoom, for example, and try to load the div's position on 100% zoom, the position is altered (as to make up for the zoom I presume).
I tried forcing the window zoom to 100% on save, but that didn't work, and I am kind of stuck now. Does anyone have any suggestions?
Following Alex's advice to use percentages, I was able to come up with a solution that works perfectly.
In the method that sets the top and left of the div - I changed that from pixels relative to the parent to percentage relative to the parent.
So this
{
width = endX - startX;
left = startX;
height = endY - startY;
top = startY;
}
Became this
{
width = endX - startX;
var percentageLeft = startX / parent.offsetWidth * 100;
left = percentageLeft;
height = endY - startY;
var percentageTop = startY / parent.offsetHeight * 100;
top = percentageTop;
}
and then by changing the saving/loading to look for percentages instead of pixels, I was able to make this work!

Calculate new (x, y) coordinates after transform & transform-origin?

I've got this simple fiddle to demonstrate what I'm trying to accomplish: http://jsfiddle.net/eUSep/
As you can see, I'm scaling up my test1 div and specifying a new origin. How can I calculate the new position (top, left) of test2 after the transformation? It must be calculated off of the origin and the scale, but I haven't been able to get it right.
At first I thought I could do it by calculating the height and width change (based on the current scale and previous scale), and subtracting half of that from the current left, then adding the other half onto the width (pseudo code):
var left = current_left - (width_change / 2);
var top = current_top - (height_change / 2 );
var right = current_left + width + (width_change / 2);
var bottom = current_top + height + (height_change / 2);
But that doesn't take the origin into account, and I think this would only work if the origin was in the exact center each time. Does anyone know how I can accomplish this?
It actually appears that Jquery Position will do the work for me.
Updated fiddle: http://jsfiddle.net/eUSep/1/
I can get the position before and after the transformation to see the change:
var pos = $('#test2').position();

Scaling text relative to position in browser window.

I'm currently stuck on a little bit of math for my project. I'm trying to scale a div in my page based on how close it is to the center of the browser window, so when it is in the center of the window it is full size, but as you scroll down or up it scales down as if to disappear. I'm just struggling on how to calculate this value.
Thanks in advanced,
Harry.
let x and y be the position of your div relative to the browser window
window.innerHeight and window.innerWidth will give you the current visible window height and width.
var w = window.innerWidth;
var h = window.innerHeight;
The center would be
var center = (w/2, h/2);
the distance from the center is:
var distance = Math.sqrt((w/2 - x)*(w/2 - x), (h/2 - y)*(h/2 - y));
Now you want to scale the div so that it's maximum size when its distance from the center is 0 and smaller when it's further away.
The simplest thing to do is to use a width of w - distance and a height of h - distance. That will give you a linear scale, you can use other scaling functions as well, but I'll leave that to you to play with for now. :)

Categories

Resources