I have an HTML5 application which utilizes drag and drop. Essentially the user can drag an image from a "drawer" onto a canvas to create a larger image. I want the elements to drop in the place where they were release. I have this working in all browsers except Firefox.
On the drop event, I am using the following to get the coordinates of the mouse, and calculate the position of the dropped image within the canvas.
var top = evt.originalEvent.offsetX;
var left = evt.originalEvent.offsetY;
The issue is, this property is not available in FF. Is there any other way to get this? Without it, I can't see how to possible drag and move elements within FF.
Note: I am not using the canvas element. I am dropping images to a div. Not sure if that matters.
Try this in firefox..
var X = event.layerX - $(event.target).position().left;
var Y = event.layerY - $(event.target).position().top;
I tried using layerX and layerY but mysteriously they were different from same values in Chrome.
Then I realized that on a Retina display Firefox setDragImage won't take the scale into account.
In other words, calling setDragImage(div, 10, 10) would place the cursor at 5px; 5px point.
Ridiculous, isn't it?
var originalEvent = e.originalEvent,
offsetX = originalEvent.offsetX,
offsetY = originalEvent.offsetY;
if (_.isUndefined(offsetX) || _.isUndefined(offsetY)) {
// Firefox doesn't take scale into account so we need to compensate for it
offsetX = originalEvent.layerX * (window.devicePixelRatio || 1);
offsetY = originalEvent.layerY * (window.devicePixelRatio || 1);
}
originalEvent.dataTransfer.setDragImage(el, offsetX, offsetY);
I tried Kathirvans answer above but it didnt work for me. The magic potion for my page was...
var x = e.originalEvent.pageX - $(this).offset().left;
var y = e.originalEvent.pageY - $(this).offset().top;
Related
I'm trying to find the bounding box of an HTML element using Javascript in screen coordinates so that I can use external tools (such as ffmpeg's x11grab screen recording functionality) to take screenshots/videos of that element by itself.
If there is no CSS zoom present, then I can find the bounding box for element elem like this:
let viewportTop = window.screenY + (window.outerHeight - window.innerHeight);
let viewportLeft = window.screenX;
let rect = elem.getBoundingClientRect();
let width = rect.width;
let height = rect.height;
let left = viewportLeft + rect.left;
let top = viewportTop + rect.top;
I can then use these width, height, left, top coordinates to record the desired box on the browser window.
However, sometimes I want to increase the zoom of the element to make things easier to see:
elem.style.zoom = "2";
Having done this, the bounding box returned by elem.getBoundingClientRect() is now scaled down by a factor of 2. If I use the approach above to calculate my recording bounding box, it no longer lines up with the element.
I've had some success with calling window.getComputedStyle(elem, null).getPropertyValue("zoom"), parsing the zoom number, and using it to correct the bounding box. However, this isn't a perfect solution--what if I want to zoom document.body by some amount and also zoom the target element by some amount?
So, I'm wondering if there's a universal way to convert the coordinates from elem.getBoundingClientRect to screen coords that works even when CSS zoom is applied to various elements.
I considered using the browser's own zoom rather than CSS zoom, but I would rather not since I'm using Selenium to set this stuff up and I've seen dire warnings about adjusting the browser zoom with Selenium here.
I am trying to create a canvas that allows me to draw on it rectangles using mouse events. Very similar to the way selection works in windows, I want to be able to click down anywhere on my page, drag left/right/up/down, then once I release, a rectangle is drawn with the starting coordinates (x1 and y1) on mousedown and the ending coordinates (x2, y2) on mouseup.
I've been trying to create eventListeners bound to my canvas that return the starting and ending coordinates on mousedown and mouseup respectively, but my variables stay undefined.
My canvas spans the entire length of my window so no need to take into account relative positioning. Also the solution has to be implemented using purely Javascript, no JQuery allowed.
Thank you for your help!
UPDATE
Ignore most of what is underneath, re-reading your question, it seems like you have the theory nailed. Your problem is most likely the mousedown and mouseup function parameters are missing. Try the following;
document.getElementsByTagName('canvas')[0].addEventListener('mousedown', function(e){
// I THINK IT'S THE e ON THE LINE ABOVE THIS THAT YOU'RE MISSING.
// YOU CAN THEN ACCESS THE POSITION OF THE MOUSE USING;
mouse.x = e.pageX;
mouse.Y = e.pageY;
})
I won't write the code for you, but I can give you theory.
Store your mouse x & y variables in an object such as mouse = {}.
Add an event listener to the canvas for mouse down (click) and store the e.pageX and e.pageY in mouse.firstX and mouse.firstY. Use something like:
document.getElementsByTagName('canvas')[0].addEventListener('mousedown', function(e){
mouse.firstX = e.pageX;
mouse.firstY = e.pageY;
})
Create a second event listener for the canvas for mouseup and store this set of e.pageX and e.pageY in mouse.secondX and mouse.secondY.
Calculate the difference between firstX and secondX, firstY and secondY to work out big your rectangle sound be.
var width = mouse.firstX + mouse.secondX // rect width
var height = mouse.firstY + mouse.secondY // rect height
Then, using these calculations, draw a rectangle on your canvas using firstX and firstY as the position parameters.
I hope this is relatively clear and helpful for you. If not, this might help;
http://simonsarris.com/blog/140-canvas-moving-selectable-shapes
While my function works on my first monitor like it should on my second monitor all coordinates of event are negative. Like its referent point is still on my primary monitor. Event is triggered on drag and drop from html5.
function endDnD(e) {
var parentOff = $(this).parent().offset();
console.log(e);
console.log(e.pageX, e.pageY, parentOff.left, parentOff.top);
var posX = e.screenX - parentOff.left;
var posY = e.pageY - parentOff.top;
$(this).css('left', posX);
$(this).css('top', posY);
}
I think you need to add this into your equation:
window.screen.availLeft
that returns a 0 value if it's the primary screen (left screen by default) or the width of the primary screen as the starting point of the right screen.
look for information and example here:
https://developer.mozilla.org/en-US/docs/Web/API/Screen/availLeft
Note that while this is information on Mozilla's site it should also work for other popular browsers
To get an X coordinate on the current screen you can use:
e.clientX
instead of e.pageX. That will return a x > 0 value.
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.
I'm moving the mouse over a div and I want to know the mouse coordinates with respect to the div origin. (upper left corner)
I expected the mousemove event to contain the relative (client?) coordinates of the mouse, but apparently it doesn't.
In firefox for instance, none of the event properties* contain relative coordinates
Am I missing something?
*clientX,Y - pageX,Y - screenX, y
You're not missing anything, but you'll need to calculate the relative coordinates yourself.
Something along these lines should do it (substitute jquery with w/e code you want to use to get the position):
var pos = $('div').position();
var relX = event.pageX - pos.left;
var relY = event.pageY - pos.top;
Also see: JS: mouse coordinates relative to an element which covers some of the details on supporting other browsers (though if you're using jquery that may not be needed).