Why is event.clientX incorrectly showing as 0 in firefox for dragend event?
Asked Answered
M

7

34

The alert from dragend is showing mouseX as zero no matter where it is currently. This works fine in Chrome so not sure what I'm doing wrong.

function move(e,obj,but){
    if(typeof(obj) === 'string'){
        obj = document.getElementById(obj) ;
    }
    
    if(typeof(but) === 'string'){
        but = document.getElementById(but) ;
    }

    //elementCoord(but) ;//get the current coords of the button &
    elementCoord(obj) ;//the container
    
    e = e || window.event ;
    var mouseX = e.clientX ;
    var mouseY = e.clientY ;
            
    //alert('mouseX='+mouseX+', but.XCoord '+but.XCoord) ;
    var diffX = Math.abs(obj.XCoord - mouseX) ;
    var diffY = Math.abs(obj.YCoord - mouseY) ;
    
    but.addEventListener("dragend",function(evt){
        evt = evt || window.event ;
        mouseX = evt.clientX ;
        mouseY = evt.clientY ;
        obj.style.left = mouseX - diffX + 'px';
        obj.style.top = mouseY - diffY + 'px';
        alert('mouseX='+mouseX+' diffX='+diffX) ;
        }
    ,false) ;
    
}

Forgot to mention, elementCoord just gets the offset of an object adding it as a property. It works fine in all browsers.

Mudlark answered 25/7, 2012 at 18:16 Comment(6)
dragend event applies to the source element, which is the one being dragged. Use drop event's clientX and clientY to get the coordinate of the target element instead of using dragend.Eulalia
FWIW, here is the Bug: bugzilla.mozilla.org/show_bug.cgi?id=505521Monarda
Browser differences: In IE10 clientX is the same in "dragstart", "dragend", "drop" but in Chrome/Firefox "dragend" is relative to the drag source (drag right and clientX is negative).Georg
Just a note to remine folks to also prefer clientX and clientY over` x` and y in the drag part if you're trying to record where in the element the click was to start the drag...Coincide
I'm getting this issue even for drag eventsEstrellaestrellita
I know it's been 8 years since you asked this question, and 11 years since it was reported to FF, but I finally came up with a solution with working demo, hope this helps!Librarianship
L
12

This is officially an issue with Firefox -- Bugzilla: Bug #505521, Set screen coordinates during HTML5 drag event. I'll quote jbmj to summarize, and I will bold the original developer they are quoting...

I can't believe that this comment
"Note though that it doesn't specify what the properties should be set to, just that they should be set and we currently set them to 0."
from 11years ago is still state of the art.

I was inspired by Jay's comment, to use the "drop" event. But that was only a comment, so let me thresh it out into an answer.

Our problem: dragend event has e.clientY and e.clientX set to 0.

How we will solve it: document's drop event also fires at the same exact time as the element we are dragging's dragend event. And: drop will have the correct values for e.clientY and e.clientX.

Two working demos, 100% JavaScript-Only Solution: SO Code Snippet and JSBin. The SO Code Snippet console sometimes gobbles up the dragged element in the console, and JSBin gave me more consistent results.

var startx = 0;
var starty = 0;
dragStartHandler = function(e) {
  startx = e.clientX;
  starty = e.clientY;
}

dragOverHandler = function(e) {
  e.preventDefault();
  return false;
}

dragEndHandler = function(e) {
  if(!startx || !starty) {
    return false;
  }
  
  var diffx = e.clientX - startx;
  var diffy = e.clientY - starty;
  
  var rect = e.target.getBoundingClientRect();

var offset = { 
                top: rect.top + window.scrollY, 
                left: rect.left + window.scrollX, 
            };
  
  var newleft = offset.left + diffx;
  var newtop = offset.top + diffy;
  
  e.target.style.position = 'absolute';
  e.target.style.left = newleft + 'px';
  e.target.style.top = newtop + 'px';
  
  startx = 0;
  starty = 0;
}

document.getElementsByClassName("draggable")[0].addEventListener('dragstart', dragStartHandler);

document.addEventListener('dragover', dragOverHandler);
document.addEventListener('drop', dragEndHandler);
.draggable {
  border: 1px solid black;
  cursor: move;
  width:250px;
};
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  
  <BR><BR><BR>

  <div id="draggable1" class="draggable" draggable="true">
    Hey, try to drag this element!
  </div>
  
</body>
</html>

Explanation:

  • dragStartHandler() : This is bound to the draggable element. Here, all we do is record the current x/y coordinates at start.
  • dragOverHandler() : This is bound to the document, so that we can override the default dragover behavior. This is needed to do any type of drag & dropping.
  • dragEndHandler() : This is bound to the document's drop. Normally, we would want this to bind to the element's dragend, but since clientY and clientX are missing, we bind it to the document. This just does exactly what you'd want to happen when dragend is called, except you have x/y coordinates.
Librarianship answered 11/8, 2020 at 20:22 Comment(0)
S
10

There is an old bug with firefox about drag events not being provided with user pointer information

I have found that almost all drag related events in firefox now do publish user pointer information:

  • "dragstart"
  • "dragenter"
  • "dragleave"
  • "dragover"
  • "drop"
  • "dragend"
  • "drag"

Tested in firefox version 99

So to answer the original question: event.clientX will no longer always be 0 in dragend in firefox 🎉


If you need to get pointer information during a drag (ie what "drag" would usually give you) then you can do the following:

  1. Add an event listener to a fairly high EventTarget (eg window) and listen for "dragover" events.
  • dragover fires whenever you are over a potential drop target, which is every Element
  • By adding an event listener to a high EventTarget (eg window) you can leverage event bubbling to capture all the dragover events for all Elements in the document
  1. Profit 💰: effectively get a drag event by repurposing dragover
window.addEventListener('dragover', (event) => {
  // event.clientX and friends are correctly set!
});
Supervene answered 20/4, 2022 at 6:0 Comment(1)
i thought i was crazy but when i looked it up it really is the truth, thanks. They have a bug for 14 years that they can't fix, very nice firefox good jobGreenfinch
C
5

As it appears this bug may remain core to Firefox for some time longer, here's a 99% drop-in patch:

if(/Firefox\/\d+[\d\.]*/.test(navigator.userAgent)
        && typeof window.DragEvent === 'function'
        && typeof window.addEventListener === 'function') (function(){
    // patch for Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=505521
    var cx, cy, px, py, ox, oy, sx, sy, lx, ly;
    function update(e) {
        cx = e.clientX; cy = e.clientY;
        px = e.pageX;   py = e.pageY;
        ox = e.offsetX; oy = e.offsetY;
        sx = e.screenX; sy = e.screenY;
        lx = e.layerX;  ly = e.layerY;
    }
    function assign(e) {
        e._ffix_cx = cx; e._ffix_cy = cy;
        e._ffix_px = px; e._ffix_py = py;
        e._ffix_ox = ox; e._ffix_oy = oy;
        e._ffix_sx = sx; e._ffix_sy = sy;
        e._ffix_lx = lx; e._ffix_ly = ly;
    }
    window.addEventListener('mousemove', update, true);
    window.addEventListener('dragover', update, true);
    // bug #505521 identifies these three listeners as problematic:
    // (although tests show 'dragstart' seems to work now, keep to be compatible)
    window.addEventListener('dragstart', assign, true);
    window.addEventListener('drag', assign, true);
    window.addEventListener('dragend', assign, true);

    var me = Object.getOwnPropertyDescriptors(window.MouseEvent.prototype),
        ue = Object.getOwnPropertyDescriptors(window.UIEvent.prototype);
    function getter(prop,repl) {
        return function() {return me[prop] && me[prop].get.call(this) || Number(this[repl]) || 0};
    }
    function layerGetter(prop,repl) {
        return function() {return this.type === 'dragover' && ue[prop] ? ue[prop].get.call(this) : (Number(this[repl]) || 0)};
    }
    Object.defineProperties(window.DragEvent.prototype,{
        clientX: {get: getter('clientX', '_ffix_cx')},
        clientY: {get: getter('clientY', '_ffix_cy')},
        pageX:   {get: getter('pageX', '_ffix_px')},
        pageY:   {get: getter('pageY', '_ffix_py')},
        offsetX: {get: getter('offsetX', '_ffix_ox')},
        offsetY: {get: getter('offsetY', '_ffix_oy')},
        screenX: {get: getter('screenX', '_ffix_sx')},
        screenY: {get: getter('screenY', '_ffix_sy')},
        x:       {get: getter('x', '_ffix_cx')},
        y:       {get: getter('y', '_ffix_cy')},
        layerX:  {get: layerGetter('layerX', '_ffix_lx')},
        layerY:  {get: layerGetter('layerY', '_ffix_ly')}
    });
})();

Note, although the OP's question was specific to just 'dragend', this is a fix for all affected events.

It grabs the last accurate coordinates of the mouse from the 'mousemove' and 'dragover' events, and implants them into the affected 'dragstart', 'drag', and 'dragend' events.

Please note, it isn't an exact fix. x / y coordinates might be slightly off. Since 'drag' event occurs before 'dragover', it executes with the coordinates from the previous event frame.

Condemn answered 17/9, 2021 at 20:20 Comment(1)
This solved my problem. Thank you dear sir! I hope Mozzilla will fix this issue soon.Crutchfield
U
2

Update March 2022: The bug has finally been assigned to the same person who has been blocking it for 13 years. This was mid October 2021. So after 13 years, a solution is on its way.

Undecagon answered 10/3, 2022 at 7:52 Comment(2)
Have anyone checked that he is still alive? No change on this for another year...Canfield
And still broken in May 2024. :-(Latin
B
0

I ran into the same issue with Firefox the other day.

I managed to find a work around although it depends on using a global variable for storing the mouse before and after positions.

The bit that seemed to get things working was to get the pageX and pageY values from the ondrop event instead of the ondragend event.

The only problem is that the ondrop doesn't store the dragged element or the original mouse positions (hence the need for the global variable).

var dragDetails = {
   target: null,
   orgMouseX: 0,
   orgMouseY: 0,
   desMouseX: 0,
   desMouseY: 0
}

$("targetElement").on("dragstart", function(event) {
   dragDetails.target = this;
   dragDetails.orgMouseX = event.originalEvent.pageX;
   dragDetails.orgMouseY = event.originalEvent.pageY;
});

$("html").on("drop", function(event) {
   dragDetails.desMouseX = event.originalEvent.pageX;
   dragDetails.desMouseY = event.originalEvent.pageY;
   handleDrag();
});

Here is an example in a fiddle : https://jsfiddle.net/L1b6uz2d/2/

It seems to work on the latest versions of Chrome, Firefox, Edge and Internet Explorer (the accuracy isn't as good on Internet Explorer though) and it works on Android Chrome. Haven't tested any others yet and I'm sure the code can be improved.

I did manage to get it working without the need for a global variable but I had to use the ondrop and then pass the target, pageX and pageY as parameters to the ondragend event (I didn't include a fiddle because the code was very ugly)

Brimmer answered 19/2, 2019 at 15:6 Comment(0)
E
0
document.addEventListener("dragover", function( event ) {
      event.preventDefault();
      console.log(event.pageX)
  }, false);

add console.log (event.pageX) in dragover Listener http://jsfiddle.net/zfnj5rv4/

Ectoblast answered 14/8, 2019 at 13:19 Comment(1)
The OP is asking how to solve the problem of event.pageX in dragend. dragover occurs when a completely different element is dragging over this. How is that supposed to be used to solve event.pageX missing in dragend?Librarianship
P
-2

Don't use e.clientX or e.clientY

Use e.pageX and e.pageY or e.targetTouches[0].pageX e.targetTouches[0].pageY (for Touchscreens) instead.

pageX is referring to the document, clientX to the viewport. See also:

https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientX

Perdition answered 31/10, 2018 at 11:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.