issue with offset calculation of zoomed element based on screen - javascript

I'm trying to calculate the coordinates of a zoomed in image based on the pageX and pageY coordinates given to me by a PanResponder. I figured I would just have to add the offset of the X and Y to the coordinates given back to me but I seem to have misjudge what would have to happen.
The coordinates of the device screen regardless of scale seem to correlate to the same location on the zoomed element. So if I place something in the top left of the device screen it goes to that location on the zoomed in element.
I get my offset by measuring the zoomed element with RCTUIManager and it seems to give back the correct values for the X and Y offset based on other calculations I have tested.
This is the most recent iteration of the code I have attempted to use:
let {measureData} = this.state;
let offsetX = measureData.x;
let offsetY = measureData.y
let x = (e.nativeEvent.pageX) - offsetX;
let y = (e.nativeEvent.pageY) - offsetY;
I'm subtracting because the values I receive are negative, I also will allow them to pan this later so I had hoped it would work correctly if they moved it so the value was positive to subtract it.
measureData contains the values from the RCTUIManager which gets updated every time a zoom event occurs.
How I update measureData
setMeasureData = () => {
RCTUIManager.measure(ReactNative.findNodeHandle(this.refs['wrap']), (x, y, width, height, pageX, pageY) => {
this.setState({
measureData: {x, y, width, height, pageX, pageY}
})
});
}
This is called in a callback function after the zoom is changed.
The elements I'm trying to add are added using another component I feed the X Y values into, this component uses Animated.ValueXY() with the calculated coordinates to place the image in the correct starting location for them to be able to drag it after.
The current calculation makes anything placed go down and right of the touch event. I'm not sure where my logic or calculations are wrong with this. I'm hoping someone may have some insight into where my calculation or thought process is wrong.

Ok so my logic was correct and wrong all at the same time. The problem was when they zoom in the X Y values stay the same so I am looking at "less" pixels within the viewport meaning I had to divide the X Y coordinates from the native event by the scale then add the offset in order for me to get the correct x and y values.

Related

Find a point old position after zoom using java script

I am working on this "simple" problem for hours with no success, although I tried many ways to solve it using all kind of solutions suggested in SO.
My problem is as follows:
I have a point on a canvas, which when I click on it my app does something, after identifying the point by comparing the mouse click coordinates to the stored position of the point.
After zooming into the point, using the mouse wheel, I click on the point again but the mouse coordinates no longer fits the stored position of the point.
I need to either transform the mouse coordinates to it's coordinates before the zoom, so I will be able to compare to the stored position, or to transform the stored position to the new canvas so it can be compare to the coordinates of the mouse. Any of the solution is fine by me.
I know the following data:
The "scale" value,
The size of the canvas (top, left, width, height),
The new origin of the canvas (top, left)
I would like a solution using java script.
Finally figured it out and it is quite simple, once I understood the concept.
Save the new canvas origin after doing the zoom (in JS it is calling ctx.translate() and ctx.scale(), where ctx is the canvas context.
When need to calculate the mouse position in the old coordinate system, one has to add back the moved origin of the canvas, and multiply by the scale factor.
seat.x = (-new_org.x + pos.x) / scale;
seat.y = (-new_org.y + pos.y) / scale;
where pos is the calculated mouse pointer
pos.x = event.clientX - .getBoundingClientRect().left;
pos.y = event.clientY - .getBoundingClientRect().top;

Pinch zoom on touch devices

I have a graph rendered within the HTML5 canvas. The working is good till this point. Now I need to implement pinch zoom on the graph for touch devices. The logic is as the two finger stretches apart the graph zooms in and as the finger moves together the graph zooms out. In this case we need to constantly update the axis value. The problem here is how do we get the individual X and Y axis value of both the fingers and then calculate the amount of zoom to be done. As for example, for zooming using mouse we can get the start X and Y value on mouse down and on mouse up we get the end X and Y axis value. Using this start and end value of X and Y axis the graph can be zoomed accordingly. The canvas should not zoom in/out. The zoom in can be infinite but the zoom out will be till the default plotting of the graph. Any idea or help would be really appreciable. I am not getting the proper calculation.
I have implemented it in the following way. Any suggestions are welcome.
First I have taken the screen co-ordinates of the two fingers touch on start and converted it to its corresponding view co-ordinates by calculating its distance from the topmost and leftmost position. After that I have calculated the scale and new co-ordinates for X-axis in the following way.
Let
d1 and d2 be the dataspace coordinates of the initial/starting touches.
newx1 and newx2 are the x positions of the new touches.
screenW is the current screen width (i.e. width of plot in screen space).
Then
scale = (d2 - d1) / (newx2 - newx1)
If we use newd1, newd2 to denote the new datarange min and max values that we're trying to compute:
newd1 = d1 - newx1 * scale
newd2 = newd1 + screenW * scale
Similarly, we can do the calculation for new datarange min and max values of Y-axis.
Variant A:
Take a JavaScript library like Hammer.js which abstracts away all then event handling and gives you an event in case of a pinch. This should look like this:
var element = document.getElementById('test_el');
var hammertime = Hammer(element).on("pinchout", function(event) {
console.log("Zoom out!!");
// event.scale should contain the scaling factor for the zoom
});
Variant B:
Read about the touch events and how to identify if it is a multitouch. Figure out when it is a pinch and if how far the fingers have moved. There is nice write up here.

Javascript comparing mouse click to xy to that of button

I am trying to get the x and y of an html button to that of a mouseclick by the user, I am doing this as follows:
function buttonPressed(event, id){
var mainEvent = event ? event : window.event;
var mousex=event.clientX;
var mousey=mainEvent.screenY;
var y= $('#'+id).position();
var x= document.getElementById(id).offsetLeft;
console.log(y);
console.log(mousey);
This shows 2 different ways to get these value of both the button and the mouse (event.clientX,mainEvent.screenY,$('#'+id).position()(uses jquery),and offsetLeft).
However none of these techniques seem to work as I would like them to as the values do not line up ie when I click on the top left of the button the values are not the same or even similar. Additionally it seems like the difference changes, for example: if I have a button top left and one top right on the top left the values may differ by 100, whereas the bottom they will differ by -100. How can I acheive what I am wanting (to be able to compare the mousex and the button x)?
client X/Y Mouse pointer X/Y coordinate relative to window
offset X/Y Mouse pointer X/Y coordinate relative to element that fired the event
screen X/Y Relative to the top left of the physical screen/monitor
Thats why you are getting difference here
var mousex=event.clientX;
var mousey=mainEvent.screenY;
Use clientX for both

How to get the correct mouse position in relation to a div that has has a scale transform applied

I am using CSS transform scale to create a smooth zoom on a div. The problem is that I want to be able to get the correct mouse position in relation to div even when scaled up, but I can seem figure out the correct algorithm to get this data. I am retrieving the current scale factor from:
var transform = new WebKitCSSMatrix(window.getComputedStyle($("#zoom_div")[0]).webkitTransform);
scale = transform.a;
When I read the position of the div at various scale settings it seems to report the correct position, i.e. when I scale the div until is is larger the the screen the position left and top values are negative and appear to be correct, as does the returned scale value:
$("#zoom_div").position().left
$("#zoom_div").position().top
To get the current mouse position I am reading the x and y position from the click event and taking away the offset. This works correctly at a scale value of 1 (no scale) but not when the div is scaled up. Here is my basic code:
$("#zoom_div").on("click", function(e){
var org = e.originalEvent;
var pos = $("#zoom_div").position();
var offset = {
x:org.changedTouches[0].pageX - pos.left,
y:org.changedTouches[0].pageY - pos.top
}
var rel_x_pos = org.changedTouches[0].pageX - offset.x;
var rel_y_pos = org.changedTouches[0].pageY - offset.y;
var rel_pos = [rel_x_pos, rel_y_pos];
return rel_pos;
});
I have made several attempts at multiplying dividing adding and subtracting the scale factor to/from from the pageX / Y but without any luck. Can anyone help me figure out how to get the correct value.
(I have simplified my code from the original to hopefully make my question clearer, any errors you may find in the above code is due to that editing down. My original code with the exception for the mouse position issue).
To illustrate what I am talking about I have made a quick jsfiddle example that allows the dragging of a div using translate3d. When the scale is normal (1) the div is dragged at the point where it is clicked. When the div is scales up (2) it no longer drags correctly from the point clicked.
http://jsfiddle.net/6EsYG/12/
You need to set the webkit transform origin. Basically, when you scale up it will originate from the center. This means the offset will be wrong. 0,0 will start in the center of the square. However, if you set the origin to the top left corner, it will keep the correct coordinates when scaling it. This is how you set the origin:
#zoom_div{
-webkit-transform-origin: 0 0;
}
This combined with multiplying the offset by the scale worked for me:
offset = {
"x" : x * scale,
"y" : y * scale
}
View jsFiddle Demo
dont use event.pageX - pos.left, but event.offsetX (or for some browser: event.originalEvent.layerX
div.on('click',function(e) {
var x = (e.offsetX != null) ? e.offsetX : e.originalEvent.layerX;
var y = (e.offsetY != null) ? e.offsetY : e.originalEvent.layerY;
});
see my jsFiddle exemple: http://jsfiddle.net/Yukulele/LdLZg/
You may embed the scaled content within an iframe. Scale outside the iframe to enable scaled mouse events within the iframe as mouse events are document scope.

How to get the coordinates clicked on an HTML5 canvas?

I need to get the x and y coordinates of where I clicked on an HTML5 canvas element. I did the following for the y coordinate:
$("#my_canvas").click(function(event) {
alert(Math.floor(event.clientY-$(this).offset().top));
});
This gives me what appears to be the correct y coordinate. The problem is if you scroll down, clientY gets smaller because it seems to be measuring the y coordinate on the screen, disregarding the scrolling. So the above gives a negative number.
What is the proper way to get the x and y coordinate?
Use pageY instead of clientY, so that both the coordinates you compare are relative to the document :
event.pageY-$(this).offset().top

Categories