Search code examples
javascripthtmlcssdrag-and-dropinteract.js

Pop-up message does not appear next to cloned objects


I have a panel with 3 draggable objects and a background image. My JavaScript script (based on interact.js) allows dragging and dropping objects on top of a background image. All draggable objects are also cloneable. It means that each time I drag an original object from the panel, it gets cloned.

Now I want to add a pop-up functionality: when I click on an object, a pop-up message should appear. The problem is that the pop-up message appears next to the original object, but not the cloned one. I what that a pop-up message appears next to an object that I click on (excluding original ones). How can I do it? This is the piece of JavaScript code related to pop-ups:

function myFunction() {
    var popup = document.getElementById("myPopup");
    popup.classList.toggle("show");
}

The whole code:

HTML (an example of a circle object that belongs to a class drag-base):

<div id="drag-base" class="popup draggable" onclick="myFunction()">
   <span class="popuptext" id="myPopup">A Simple Popup!</span>
</div>

CSS:

#drag-base {
      background: #d9534f;
      color: #000000;
      width: 35px;
      height: 35px;
      border-radius: 50%;
      text-align: center;
      -webkit-transform: translate(0px, 0px);
              transform: translate(0px, 0px);
    } 

.dropzone {
      background-color: #e9ebed;
      padding: 10px;
      width: 100%;
      height: 600px;
      overflow-y: scroll;
      border: dashed 4px transparent;
      float:left;
    }

    .drop-active {
      border-color: #aaa;
    }

    .drop-target {
      background-color: #3f5265;
      color: #FFF;
      border-color: #fff;
      border-style: solid;
    }

    /* Popup container - can be anything you want */
    .popup {
        position: relative;
        display: inline-block;
        cursor: pointer;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }

    /* The actual popup */
    .popup .popuptext {
        visibility: hidden;
        width: 160px;
        background-color: #555;
        color: #fff;
        text-align: center;
        border-radius: 6px;
        padding: 8px 0;
        position: absolute;
        z-index: 1;
        bottom: 125%;
        left: 50%;
        margin-left: -80px;
    }

    /* Popup arrow */
    .popup .popuptext::after {
        content: "";
        position: absolute;
        top: 100%;
        left: 50%;
        margin-left: -5px;
        border-width: 5px;
        border-style: solid;
        border-color: #555 transparent transparent transparent;
    }

    /* Toggle this class - hide and show the popup */
    .popup .show {
        visibility: visible;
        -webkit-animation: fadeIn 1s;
        animation: fadeIn 1s;
    }

    /* Add animation (fade in the popup) */
    @-webkit-keyframes fadeIn {
        from {opacity: 0;} 
        to {opacity: 1;}
    }

    @keyframes fadeIn {
        from {opacity: 0;}
        to {opacity:1 ;}
    }

JavaScript:

<script type="text/javascript">
    // target elements with the "draggable" class
    interact('.draggable').draggable({
        inertia: true,
        restrict: {
          restriction: ".dropzone",
          drag: document.getElementById('dropzone'),
          endOnly: true,
          elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
        },
        autoScroll: true,
        onmove: function (event) {
          var target = event.target;   
          var x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
          var y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

          target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';

          target.setAttribute('data-x', x);
          target.setAttribute('data-y', y);
        },
        onend: function(event) {
            console.log(event);
        }
    })
    .on('move', function (event) {
    var interaction = event.interaction;
    if (interaction.pointerIsDown && !interaction.interacting() && event.currentTarget.getAttribute('clonable') != 'false') {
      var original = event.currentTarget;
      var clone = event.currentTarget.cloneNode(true);
      var x = clone.offsetLeft;
      var y = clone.offsetTop;
      clone.setAttribute('clonable','false');
      clone.style.position = "absolute";
      clone.style.left = original.offsetLeft+"px";
      clone.style.top = original.offsetTop+"px";
      original.parentElement.appendChild(clone);
      interaction.start({ name: 'drag' },event.interactable,clone);
    }
    })
    .resizable({
        edges: { left: true, right: true, bottom: true, top: true }
    })
    .on('resizemove', function (event) {
        var target = event.target;
            x = (parseFloat(target.getAttribute('data-x')) || 0),
            y = (parseFloat(target.getAttribute('data-y')) || 0);

        // update the element's style
        target.style.width  = event.rect.width + 'px';
        target.style.height = event.rect.height + 'px';

        // translate when resizing from top or left edges
        x += event.deltaRect.left;
        y += event.deltaRect.top;

        target.style.webkitTransform = target.style.transform =
            'translate(' + x + 'px,' + y + 'px)';

        target.setAttribute('data-x', x);
        target.setAttribute('data-y', y);
        //target.textContent = event.rect.width + '×' + event.rect.height;
      });

    // enable draggables to be dropped into this
    interact('.dropzone').dropzone({  
      // Require a 50% element overlap for a drop to be possible
      overlap: 0.50,

      // listen for drop related events:

      ondropactivate: function (event) {
        // add active dropzone feedback
        event.target.classList.add('drop-active');
      },
      ondragenter: function (event) {
        var draggableElement = event.relatedTarget,
            dropzoneElement = event.target;

        // feedback the possibility of a drop
        dropzoneElement.classList.add('drop-target');
      },
      ondragleave: function (event) {
        // remove the drop feedback style
        event.target.classList.remove('drop-target');
      },
      ondrop: function (event) {
        //event.relatedTarget.textContent = 'Dropped';
      },
      ondropdeactivate: function (event) {
        // remove active dropzone feedback
        event.target.classList.remove('drop-active');
        event.target.classList.remove('drop-target');
      }
    });

    $(".dropzone").html("<img src='https://s-media-cache-ak0.pinimg.com/originals/fb/d5/55/fbd5556e0e364b31166bebfce433c14e.jpg'>");

    // When the user clicks on div, open the popup
    function myFunction() {
        var popup = document.getElementById("myPopup");
        popup.classList.toggle("show");
    }

</script>

Solution

  • Use the class instead of the ID, and use DOM traversal to find the popup inside the element that was clicked. Pass the clicked element to the function:

    <div id="drag-base" class="popup draggable" onclick="myFunction(this)">
       <span class="popuptext" id="myPopup">A Simple Popup!</span>
    </div>
    

    and then use that in the function:

    function myFunction(div) {
        div.querySelector(".popuptext").classList.toggle("show");
    }