Drag-able div and click to behind element

Viewed 183

What i exactly want ?

make element clickable that is behind movable div.

Here is what i have tried for achieve that but its not working. And i did not found any other solution for this. This will be great help for me.

add style "pointer-events: none;" but after applying this style then that div is no drag-able.

Here is my code :

Red Div is movable but not clickable and Green Div is clickable but not movable.

function make_movable(id) {

  var movable_div = document.getElementById(id);
  movable_div.onmousedown = dragMouseDown;

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
  }


  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    movable_div.style.top = (movable_div.offsetTop - pos2) + "px";
    movable_div.style.left = (movable_div.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    document.onmouseup = null;
    document.onmousemove = null;
  }

}

make_movable("movable_div1");
make_movable("movable_div2");
#movable_div1 {
  cursor: move;
  background: green;
  width: 100px;
  height: 100px;
  position: absolute;
  pointer-events: none;
  opacity: 0.5;
}

#movable_div2 {
  cursor: move;
  background: red;
  width: 100px;
  height: 100px;
  position: absolute;
  opacity: 0.5;
  /*pointer-events: none;*/
}

button {
  width: 100px;
  padding: 10px;
  margin: 10px;
}
<button onClick="alert('Just pressed button 1');">BUTTON 1</button>
<button onClick="alert('Just pressed button 2');">BUTTON 2</button>
<button onClick="alert('Just pressed button 3');">BUTTON 3</button>
<button onClick="alert('Just pressed button 4');">BUTTON 4</button>
<button onClick="alert('Just pressed button 5');">BUTTON 5</button>
<button onClick="alert('Just pressed button 6');">BUTTON 6</button>
<button onClick="alert('Just pressed button 7');">BUTTON 7</button>
<button onClick="alert('Just pressed button 8');">BUTTON 8</button>
<button onClick="alert('Just pressed button 9');">BUTTON 9</button>
<button onClick="alert('Just pressed button 10');">BUTTON 10</button>

<div id="movable_div1" style="top: 40px; left: 40px;"> </div>
<div id="movable_div2" style="top: 160px; left: 40px;"> </div>

2 Answers

This is possible, but a bit messy!

You can check if the user did move the mouse between the mousedown- and mouseup-events. If the mouse did not move, we assume the user did a click. Now we only need to hide the moveable-element for a brief moment and use that to find the element that is at the current mouse-position topmost. Then we create a new MouseEvent-event (click) and dispatch it to the underlying-element before we make the moveable-element visible again.

Example:

function make_movable(id) {
  var movable_div = document.getElementById(id);
  movable_div.onmousedown = dragMouseDown;
  let didDrag = false; // did the user perform a drag (mousemove)

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    didDrag = false;
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    didDrag = true;
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    movable_div.style.top = (movable_div.offsetTop - pos2) + "px";
    movable_div.style.left = (movable_div.offsetLeft - pos1) + "px";
  }

  function closeDragElement(e) {
    e = e || window.event;
    if (!didDrag) {
      // copy display-property of moveable-element
      let displayCopy = movable_div.style.display;
      // hide moveable-element
      movable_div.style.display = 'none';
      // get x- and y-position from current event
      let x = e.clientX,
          y = e.clientY;
      // create click event with position
      let event = new MouseEvent('click', {
        view: window,
        bubbles: true,
        cancelable: true,
        clientX: x,
        clientY: y
      });
      // get underlying-element at mouse-position
      let element = document.elementFromPoint(x, y);
      // restore display-property of moveable-element
      movable_div.style.display = displayCopy;
      // dispatch event for the underlying-element
      element.dispatchEvent(event);
    }
    document.onmouseup = null;
    document.onmousemove = null;
  }
}

make_movable("movable_div1");
make_movable("movable_div2");
make_movable("movable_div3");
#movable_div1 {
  cursor: move;
  background: green;
  width: 100px;
  height: 100px;
  position: absolute;
  pointer-events: none;
  opacity: 0.5;
}

#movable_div2 {
  cursor: move;
  background: red;
  width: 100px;
  height: 100px;
  position: absolute;
  opacity: 0.5;
  /*pointer-events: none;*/
}

#movable_div3 {
  cursor: move;
  background: purple;
  width: 100px;
  height: 100px;
  position: absolute;
  opacity: 0.5;
}

button {
  width: 100px;
  padding: 10px;
  margin: 10px;
}
<button onClick="alert('Just pressed button 1');">BUTTON 1</button>
<button onClick="alert('Just pressed button 2');">BUTTON 2</button>
<button onClick="alert('Just pressed button 3');">BUTTON 3</button>
<button onClick="alert('Just pressed button 4');">BUTTON 4</button>
<button onClick="alert('Just pressed button 5');">BUTTON 5</button>
<button onClick="alert('Just pressed button 6');">BUTTON 6</button>
<button onClick="alert('Just pressed button 7');">BUTTON 7</button>
<button onClick="alert('Just pressed button 8');">BUTTON 8</button>
<button onClick="alert('Just pressed button 9');">BUTTON 9</button>
<button onClick="alert('Just pressed button 10');">BUTTON 10</button>

<div id="movable_div1" style="top: 40px; left: 40px;"> </div>
<div id="movable_div2" style="top: 160px; left: 40px;"> </div>
<div id="movable_div3" style="top: 40px; left: 160px;"> </div>

Tested with Firefox 67 (macOS).

You can use setTimeout to check if a user is clicking or dragging.

timer = setTimeout(() => {
  document.onmousemove = elementDrag;
  isDragging = true;
}, 400);

If onmousedown event is triggered more than 400ms and onmouseup event is not being triggered yet, we can assume that the user is trying to drag the element. And if onmouseup event is triggered in 400ms, we can assume that the user is trying to click the element or the button behind it.

function tryClick(e) {
  var { clientX, clientY } = e;
  var element = document.elementFromPoint(clientX, clientY);
  if (element.classList.contains("clickable")) {
    element.hidden = true;
    tryClick(e);
    element.hidden = false;
  } else if (element.tagName == "BUTTON") {
    element.click();
  }
}

The tryClick function is a recursive function that checks if the element that the mouse is currently pointed is clickable. If it is, hide it and check the element behind it and so on. If it's not, check if the element is a BUTTON and trigger click if it is.

function make_movable(id) {

  var movable_div = document.getElementById(id);
  movable_div.onmousedown = dragMouseDown;

  var timer = null,
      isDragging = false;

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;

    // check if the element is movable
    if (!movable_div.classList.contains("movable")) return;

    timer = setTimeout(() => {
      document.onmousemove = elementDrag;
      isDragging = true;
    }, 400);
  }


  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    movable_div.style.top = (movable_div.offsetTop - pos2) + "px";
    movable_div.style.left = (movable_div.offsetLeft - pos1) + "px";
  }

  function closeDragElement(e) {
    clearTimeout(timer);
    timer = null;
    if (!isDragging) {
      tryClick(e);
    } else {
      isDragging = false;
    }
    document.onmouseup = null;
    document.onmousemove = null;
  }

  function tryClick(e) {
    var { clientX, clientY } = e;
    var element = document.elementFromPoint(clientX, clientY);
    if (element.classList.contains("clickable")) {
      element.hidden = true;
      tryClick(e);
      element.hidden = false;
    } else if (element.tagName == "BUTTON") {
      element.click();
    }
  }
}

make_movable("movable_div1");
make_movable("movable_div2");
make_movable("movable_div3");
#movable_div1 {
  cursor: move;
  background: green;
  width: 100px;
  height: 100px;
  position: absolute;
  pointer-events: none;
  opacity: 0.5;
}

#movable_div2 {
  cursor: move;
  background: red;
  width: 100px;
  height: 100px;
  position: absolute;
  opacity: 0.5;
  /*pointer-events: none;*/
}

#movable_div3 {
  cursor: move;
  background: lightblue;
  width: 100px;
  height: 100px;
  position: absolute;
  opacity: 0.5;
  /*pointer-events: none;*/
}

button {
  width: 100px;
  padding: 10px;
  margin: 10px;
}
<button onClick="alert('Just pressed button 1');">BUTTON 1</button>
<button onClick="alert('Just pressed button 2');">BUTTON 2</button>
<button onClick="alert('Just pressed button 3');">BUTTON 3</button>
<button onClick="alert('Just pressed button 4');">BUTTON 4</button>
<button onClick="alert('Just pressed button 5');">BUTTON 5</button>
<button onClick="alert('Just pressed button 6');">BUTTON 6</button>
<button onClick="alert('Just pressed button 7');">BUTTON 7</button>
<button onClick="alert('Just pressed button 8');">BUTTON 8</button>
<button onClick="alert('Just pressed button 9');">BUTTON 9</button>
<button onClick="alert('Just pressed button 10');">BUTTON 10</button>

<div id="movable_div1" class="clickable" style="top: 40px; left: 40px;"> </div>
<div id="movable_div2" class="movable" style="top: 160px; left: 40px;"> </div>
<div id="movable_div3" class="movable clickable" style="top: 40px; left: 160px;"> </div>

Related