chovy
chovy

Reputation: 75864

How to restrict dragging div to parent container

I want to restrict the pink boxes to not be draggable outside the parent container:

<!doctype html>
<html lang="en">
    <head>
        <title>arrows</title>
    <style>
    * {
        box-sizing: border-box;
    }

    #draw {
        position: relative;
        width: 800px;
        height: 800px;
        border: 1px solid black;
    }

    #draw > div {
        width: 10rem;
        height: 10rem;
        border: 1px solid black;
        background-color: violet;
    }



    #box1 {
        position: absolute;
        top: 100px;
        left: 100px;
    }

    #box2 {
        position: absolute;
        top: 400px;
        left: 400px;
    }
    </style>
        <script type="module">
            import { getArrow, getBoxToBoxArrow } from "https://cdn.esm.sh/v58/[email protected]/es2021/curved-arrows.js";
            const el1 = document.getElementById('box1');
            const el2 = document.getElementById('box2');


            function Arrow() {
                const pos1 = { x: el1.offsetLeft, y: el1.offsetTop, w: el1.clientWidth, h: el1.clientHeight };
                const pos2 = { x: el2.offsetLeft, y: el2.offsetTop, w: el2.clientWidth, h: el2.clientHeight };
                console.log(pos1);
                const p1 = { x: pos1.x, y: pos1.y, w: pos1.w, h: pos1.h };
                const p2 = { x: pos2.x, y: pos2.y, w: pos2.w, h: pos2.h };
                const arrowHeadSize = 10;
                const color = 'black';
                //const [sx, sy, c1x, c1y, c2x, c2y, ex, ey, ae] = getArrow(p1.x, p1.y, p2.x, p2.y, {
                const [sx, sy, c1x, c1y, c2x, c2y, ex, ey, ae] = getBoxToBoxArrow(p1.x, p1.y, p1.w, p1.h, p2.x, p2.y, p2.w, p2.h, {
                    padEnd: arrowHeadSize,
                });

                return `
                    <svg
                        width="100%"
                        height="100%"
                        xmlns="http://www.w3.org/2000/svg">
                        <path
                            d=${`"M ${sx} ${sy} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${ex} ${ey}"`}
                            stroke="${color}"
                            strokeWidth="${(arrowHeadSize / 2) || 1}"
                            fill="none"
                        />
                        <polygon
                            points="${`0,${-arrowHeadSize} ${arrowHeadSize *
                                2},0, 0,${arrowHeadSize}`}"
                            transform="${`translate(${ex}, ${ey}) rotate(${ae})`}"
                            fill="${color}"
                        />
                    </svg>
                `;
            } 

            function draggable(el) {
                el.addEventListener('mousedown', function(e) {
                    var offsetX = e.clientX - parseInt(window.getComputedStyle(this).left);
                    var offsetY = e.clientY - parseInt(window.getComputedStyle(this).top);
                    
                    function mouseMoveHandler(e) {
                        el.style.top = (e.clientY - offsetY) + 'px';
                        el.style.left = (e.clientX - offsetX) + 'px';
                        
                        const arrow = Arrow();
                        const draw = document.getElementById('draw');
                        const svg = draw.querySelector('svg');

                        draw.insertAdjacentHTML('afterbegin', arrow);
                        (svg && svg.remove());
                    }

                    function reset() {
                        window.removeEventListener('mousemove', mouseMoveHandler);
                        window.removeEventListener('mouseup', reset);
                    }

                    window.addEventListener('mousemove', mouseMoveHandler);
                    window.addEventListener('mouseup', reset);
                });
            }

            function moveBox(el) {
            }

            function onLoad() {
                const arrow = Arrow();
                const draw = document.getElementById('draw');
                draw.insertAdjacentHTML('afterbegin', arrow);

                draggable(el1);
                draggable(el2);
            }

            window.addEventListener('load', onLoad);
        </script>
    </head>
    <body>
        <div id="draw">
            <div id="box1"></div>
            <div id="box2"></div>
        </div>
    </body>
</html>

Demo: https://playground-snowy.vercel.app/arrows

https://codepen.io/chovy/pen/WNZZBJe

Upvotes: 1

Views: 1275

Answers (2)

skara9
skara9

Reputation: 4194

When setting the position of the element, if the position is out of bounds on any side, set it to the max value of that side.

If the top value is less than the min of 0, set it to zero.

If the top value is more than the max of (container height - element height), set it to the max.

And so on...

function mouseMoveHandler(e) {
    const draw = document.getElementById('draw');

    let top = e.clientY - offsetY;
    let left = e.clientX - offsetX;

    if (top < 0) top = 0;
    if (left < 0) left = 0;
    if (top > draw.clientHeight - el.clientHeight) top = draw.clientHeight - el.clientHeight;
    if (left > draw.clientWidth - el.clientWidth) left = draw.clientWidth - el.clientWidth;

    el.style.top = top + 'px';
    el.style.left = left + 'px';
    
    const arrow = Arrow();
    const svg = draw.querySelector('svg');

    draw.insertAdjacentHTML('afterbegin', arrow);
    (svg && svg.remove());
}

Upvotes: 2

Semih Ozturk
Semih Ozturk

Reputation: 57

You can update inside of mouseMoverHandler function like this.

let newTop = (e.clientY - offsetY);
if (newTop < 0) {
    newTop = 0;
}

if (newTop + 160 > 800) {
    newTop = newTop - (newTop + 160 - 800);
}

let newLeft = (e.clientX - offsetX);
if (newLeft < 0) {
    newLeft = 0;
}

if (newLeft + 160 > 800) {
    newLeft = newLeft - (newLeft + 160 - 800);
}

el.style.top = newTop + 'px';
el.style.left = newLeft + 'px';

Upvotes: 1

Related Questions