简体   繁体   中英

Contain a draggable element in a div without overflowing

sorry, I don't know if this is an easy question or a difficult one and I'm just a newbie in JS, but I have a problem: I have a draggable element inside a div, it can be dragged freely. The thing is whenever I drag the element to the edges of the containing div the element's parts get hidden because of "overflow: hidden" (I purposely did that) but is there a way to make it like the edges of the element just bumps to the edges of the containing div instead of overflowing?

<div id="topDiv">
   parent div
  <div id="insideDiv">
    <br> draggable content
    <br>
  </div>
</div>
html, body {
  height: 100%;
  margin: 0;
}

#topDiv {
  background-color: lightblue;
  max-height: 70%;
  padding: 10px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

#insideDiv {
  background-color: pink;
  overflow-y: auto;
}
var container = document.querySelector("#topDiv");
var activeItem = null;
var active = false;

container.addEventListener("touchstart", dragStart, false);
container.addEventListener("touchend", dragEnd, false);
container.addEventListener("touchmove", drag, false);
container.addEventListener("mousedown", dragStart, false);
container.addEventListener("mouseup", dragEnd, false);
container.addEventListener("mousemove", drag, false);

function dragStart(e) {
    if (e.target !== e.currentTarget) {
        active = true;
        activeItem = e.target; // this is the item we are interacting with
        if (activeItem !== null) {
            if (!activeItem.xOffset) {
                activeItem.xOffset = 0;
            }
            if (!activeItem.yOffset) {
                activeItem.yOffset = 0;
            }
            if (e.type === "touchstart") {
                activeItem.initialX = e.touches[0].clientX - activeItem.xOffset;
                activeItem.initialY = e.touches[0].clientY - activeItem.yOffset;
            } else {
                console.log("doing something!");
                activeItem.initialX = e.clientX - activeItem.xOffset;
                activeItem.initialY = e.clientY - activeItem.yOffset;
            }
        }
    }
}

function dragEnd(e) {
    if (activeItem !== null) {
        activeItem.initialX = activeItem.currentX;
        activeItem.initialY = activeItem.currentY;
    }
    active = false;
    activeItem = null;
}

function drag(e) {
    if (active) {
        if (e.type === "touchmove") {
            e.preventDefault();

            activeItem.currentX = e.touches[0].clientX - activeItem.initialX;
            activeItem.currentY = e.touches[0].clientY - activeItem.initialY;
        } else {
            activeItem.currentX = e.clientX - activeItem.initialX;
            activeItem.currentY = e.clientY - activeItem.initialY;
        }
        activeItem.xOffset = activeItem.currentX;
        activeItem.yOffset = activeItem.currentY;
        setTranslate(activeItem.currentX, activeItem.currentY, activeItem);
    }
}

function setTranslate(xPos, yPos, el) {
    currentPosX = xPos;
    currentPosY = yPos;
    el.style.transform = "translate(" + xPos + "px, " + yPos + "px)";
}

Here's my example: https://jsfiddle.net/ezmatto0911/r38he9no/13/

UPDATE: I've been able to get along with the getBoundingClientRect() as mentioned by @N3R4ZZuRR0 but I still run into some problems:

  1. It's shaky when I drag the inner div to the top and left edges of the parent div.
  2. I can't get the proper location to 'throw' the inner div back into, once i drag it to the bottom and right edges of the parent div.

here's my updated code:

 html, body {
        height: 100%;
        margin: 0;
      }

      #topDiv {
        background-color: lightblue;
        max-height: 50%;
        padding: 10px;
        box-sizing: border-box;
        display: flex;
        flex-direction: column;
        overflow: hidden;
      }

      #insideDiv {
        background-color: pink;
        width: 30%;
        overflow-y: auto;
      }
<div id="topDiv">
      <div>
        Parent Div
      </div>
      <div id="insideDiv">
        <br> element
        <br>
      </div>
    </div>
var container = document.getElementById('topDiv');
var activeItem = null;
var active = false;

container.addEventListener("touchstart", dragStart, false);
container.addEventListener("touchend", dragEnd, false);
container.addEventListener("touchmove", drag, false);
container.addEventListener("mousedown", dragStart, false);
container.addEventListener("mouseup", dragEnd, false);
container.addEventListener("mousemove", drag, false);

function dragStart(e) {
    if (e.target !== e.currentTarget) {
        active = true;
        activeItem = e.target; // this is the item we are interacting with
        if (activeItem !== null) {
            if (!activeItem.xOffset) {
                activeItem.xOffset = 0;
            }
            if (!activeItem.yOffset) {
                activeItem.yOffset = 0;
            }
            if (e.type === "touchstart") {
                activeItem.initialX = e.touches[0].clientX - activeItem.xOffset;
                activeItem.initialY = e.touches[0].clientY - activeItem.yOffset;
            } else {
                console.log("doing something!");
                activeItem.initialX = e.clientX - activeItem.xOffset;
                activeItem.initialY = e.clientY - activeItem.yOffset;
            }
        }
    }
}

function dragEnd(e) {
    if (activeItem !== null) {
        activeItem.initialX = activeItem.currentX;
        activeItem.initialY = activeItem.currentY;
    }
    active = false;
    activeItem = null;
}

function drag(e) {
    if (active) {
        if (e.type === "touchmove") {
            e.preventDefault();

            activeItem.currentX = e.touches[0].clientX - activeItem.initialX;
            activeItem.currentY = e.touches[0].clientY - activeItem.initialY;
        } else {
            activeItem.currentX = e.clientX - activeItem.initialX;
            activeItem.currentY = e.clientY - activeItem.initialY;
        }

        var div = document.getElementById("topDiv");
        var rect = div.getBoundingClientRect();
        x = rect.left;
        y = rect.top;
        r = rect.right;
        b = rect.bottom;

        var elementToCheck = document.getElementById(activeItem.id);
        var rect2 = elementToCheck.getBoundingClientRect();
        x2 = rect2.left;
        y2 = rect2.top;
        r2 = rect2.right;
        b2 = rect2.bottom;

        console.log('x: ' + x + ', y: ' + y + ', r: ' + r + ', b: ' + b);
        console.log('x2: ' + x2 + ', y2: ' + y2 + ', r2: ' + r2 + ', b2: ' + b2);

        if (x2 > x && y2 > y && r2 < r && b2 < b) {
          activeItem.xOffset = activeItem.currentX;
          activeItem.yOffset = activeItem.currentY;
          setTranslate(activeItem.currentX, activeItem.currentY, activeItem);
        }else if (x2 <= x || y2 <= y || r2 >= r || b2 >= b){
          if (x2 <= x) {
            console.log('LEFT BOUND');
            activeItem.xOffset = x + 2;
          }

          if (y2 <= y) {
            console.log('TOP BOUND');
            activeItem.yOffset = y + 2;
          }

          if (r2 >= r) {
            console.log('RIGHT BOUND');
            activeItem.xOffset = r - 2;
          }

          if (b2 >= b) {
            console.log('BOTTOM BOUND');
            activeItem.yOffset = b - 2;
          }
          setTranslate(activeItem.xOffset, activeItem.yOffset, activeItem);
        }
    }
}

function setTranslate(xPos, yPos, el) {
    currentPosX = xPos;
    currentPosY = yPos;
    el.style.transform = "translate(" + xPos + "px, " + yPos + "px)";
}

here's my fiddle of this sample: https://jsfiddle.net/ezmatto0911/jowb584a/1/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM