Home > database >  How to use vanilla script to bounce elements from each other
How to use vanilla script to bounce elements from each other

Time:12-26

I've tried adding the top and left changes, and margin (with different positioning changes too) changes to each element if one approaches another but only the margin change works once. Is there a way to make them work more consistently?

This is where I've used a function to add the event listeners:

var three = document.getElementById('three');
var test = document.getElementById('test');
var two = document.getElementById('two');
var obj = null;

function testmovea(object, event) {
    obj = document.getElementById(object.id);
    document.addEventListener("mousemove", move);
}

function move(event) {
    obj.innerText = event.clientX   ' '   event.clientY;
    obj.style.position = 'absolute';
    obj.style.left = event.clientX   "px";
    obj.style.top = event.clientY   "px";
    three.addEventListener('mouseover', borders);
    three.addEventListener('mouseleave', bordersOff);
    two.addEventListener('mouseenter', bTwo);
    test.addEventListener('mouseenter', bTest);
    two.addEventListener('mouseleave', bTwoReset);
    test.addEventListener('mouseleave', bTestReset);
    document.addEventListener("mouseup", stopMove);
}
    function bTwo() {
        two.style.margin = "10%";
    }
    
    function bTwoReset() {
        two.style.margin = "0%";

    }
    
    function bTest() {
        test.style.margin = "10%";
    }
    
    function bTestReset() {
        test.style.margin = "0%"
    }

This is the mouse stop event I use:

    function stopMove() {
        document.removeEventListener('mousemove', move);
        test.removeEventListener('mouseover', bTest);
        two.removeEventListener('mouseover', bTwo);
        test.removeEventListener('mouseleave', bTestReset);
        two.removeEventListener('mouseleave', bTwoReset);
    }

the testmovea function relies on a onmousedown property defined for a DOM element of the page

Update: I've managed to get it to partially work:

 function collide(el1, el2) {
    if(twoBoundX >= threeBoundY || threeBoundY >= twoBoundX) {
        two.style.margin =   event.clientX   "px";
        two.style.margin =   event.clientY   "px";
    }
 }

where twoBoundX and threeBoundY are getBoundingClientRect() of the respective elements

Here's the full code snippet:

<html>
    <head>

    <style type="text/css">
    #two {
        border: 1px solid black;
        padding: 1%;
        margin: 1%;
        margin-top: 10%;
        width: 10%;
    }
    #three {
        border: 1px solid black;
        padding: 1%;
        margin-top: 2%;
    }
    </style>
    </head>
    <body>
    <div id="two" onm ousedown="testmovea(this, event)" onclick="currentTwoPos()">
    stop movement 
    </div>
    <div id="three" onm ousedown="testmovea(this)">Expand div</div>
    <div style="height: 30%" id="two" contenteditable="true">
    some contenteditable</div>
    </body>
        <script>
 var three = document.getElementById('three');
 var two = document.getElementById('two');
 const twoBound = two.getBoundingClientRect();
 const threeBound = three.getBoundingClientRect();
 var threeBoundX = threeBound.x;
 var threeBoundY = threeBound.y;
 var twoBoundX = twoBound.x;
 var twoBoundY = twoBound.y;
 var twoBoundBottom = null;
 var twoBoundTop = null;
 var obj = null;
 
  function collide(el1, el2) {
    if(twoBoundX >= threeBoundY || threeBoundY >= twoBoundX) {
        two.style.left = event.clientX   "px";
        two.style.top = event.clientY   "px";
        three.style.left = event.clientX   "px";
        three.style.top = event.clientY   "px";
    }
 }
 
    function testmovea(object, event) {
    obj = document.getElementById(object.id);
    document.addEventListener("mousemove", move);
    }
  
function move(event) {
    obj.innerText = event.clientX   ' '   event.clientY;
    obj.style.position = 'absolute';
    obj.style.left = event.clientX   "px";
    obj.style.top = event.clientY   "px";
    two.addEventListener('mouseover', collide);
    three.addEventListener('mouseover', collide);
    document.addEventListener("mouseup", stopMove);
} 

    function stopMove() {
    mousemove = false;
        document.removeEventListener('mousemove', move);
        three.removeEventListener('mouseover', collide);
        two.removeEventListener('mouseover', collide);
    }
    </script>
</html>  

CodePudding user response:

collision detection

You need to define a function that checks whether two of your shapes collide. If you only have rectangles whose vertex are parallel with the OX and OY vertexes, it would look like this:

function areColliding(r1, r2) {
    return !(
           (r1.x > r2.x   r2.w) ||
           (r1.x   r1.w < r2.x) ||
           (r1.y > r2.y   r2.h) ||
           (r1.y   r1.h < r2.y)
           );
}

Of course, if some rotation or even other shapes are involved into your problem, then you need to extend/adjust the collision detector accordingly.

a shared function

You need to create a function that would receive the current status of the elements and the move that happens. It would look like this:

function handleMove(currentPositions, proposedPositions) {
    while (!validPositions(proposedPositions)) {
        proposedPositions = generateNewPositions(currentPositions, handleCollisions(proposedPositions));
    }
    refreshUI(proposedPositions);
}
  • currentPositions is the set of positions your elements currently have
  • proposedPositions is the set of positions your elements are going to have if there are no collisions
  • validPositions checks for any pair of shapes that would collide and returns true if none of those pair collide and false if at least one such pair collides
  • proposedPositions is being refreshed while there are still collisions
  • generateNewPositions is your handler for collision-based changes
  • handleCollisions effectuates changes to avoid collision
  • refreshUI refreshes the UI

event handling

your mouse events should handle change updates by loading all the positions of your elements and calling this shared functionality.

Note: If you have further problems, then you might need to create a reproducible example so we could see your exact structure, styling and code as well.

<html>
    <head>

    <style type="text/css">
    #two {
        border: 1px solid black;
        width: 10%;
        padding: 1%;
        margin: 1%;
        margin-top: 10%;
    }
    #three {
        border: 1px solid black;
        padding: 1%;
        margin-top: 2%;
    }
    </style>
    </head>
    <body>
    <div id="two" onm ousedown="testmovea(this, event)" style="position: relative;">
    stop movement 
    </div>
    <div id="three" onm ousedown="testmovea(this)" style="position: relative;">Expand div</div>
    <!--<div style="height: 30%; position: relative;" id="two" contenteditable="true">
    some contenteditable</div>-->
    </body>
        <script>
 var three = document.getElementById('three');
 var two = document.getElementById('two');
 let moveStarted = false;
 
  function collide() {
    const first = two.getBoundingClientRect();
    const second = three.getBoundingClientRect();
    if (!(
        (first.x   first.width < second.x) ||
        (second.x   second.width < first.x) ||
        (first.y   first.height < second.y) ||
        (second.y   second.height < first.y)
    )) {
        two.style.left = event.clientX   "px";
        two.style.top = event.clientY   "px";
        three.style.left = event.clientX   "px";
        three.style.top = event.clientY   "px";
    }
 }
 
    function testmovea(object, event) {
    obj = document.getElementById(object.id);
    if (!moveStarted) {
        document.addEventListener("mousemove", move);
        moveStarted = true;
    }
    }
  
function move(event) {
    //obj.innerText = event.clientX   ' '   event.clientY;
    obj.style.left = event.clientX   "px";
    obj.style.top = event.clientY   "px";
    if (!obj.classList.contains("dragged")) obj.classList.add("dragged");
    collide(obj);
} 

    function stopMove() {
    mousemove = false;
    if (moveStarted) {
        document.removeEventListener('mousemove', move);
        moveStarted = false;
    }
    }
    document.addEventListener("mouseup", stopMove);
    </script>
</html>  

  • Related