JSFiddle - React, Tailwind, and code Playground

by frumbert

HTML

<script src="https://cdn.jsdelivr.net/npm/[email protected]/leader-line.min.js"></script>
<script src="plain-draggable"></script>
<script src="https://unpkg.com/[email protected]/plain-draggable.min.js"></script>
<div id="frame">
  <div id="container">
    <div id="terminal-1" class="terminal"></div>
    <div id="terminal-2" class="terminal"></div>
    <div id="terminal-3" class="terminal"></div>
  </div>
  <div id="wrapper"></div>
</div>

CSS

#frame {
  margin: 64px;
  width: 240px;
  height: 240px;
  overflow: scroll;
}

#container {
  width: 480px;
  height: 480px;
  position: relative;
  background-color: beige;
}

.terminal {
  width: 32px;
  height: 32px;
  position: absolute;
  background-color: blue;
}

#terminal-1 {
  left: 32px;
  top: 32px;
  background-color: red;
}

#terminal-2 {
  left: 416px;
  top: 320px;
}

#terminal-3 {
  left: 64px;
  top: 180px;
}

#wrapper {
  width: 0;
  height: 0;
  position: relative; /* Origin of coordinates for lines, and scrolled content (i.e. not `absolute`) */
}

JavaScript

var elmWrapper = document.getElementById('wrapper'),
  rectWrapper = elmWrapper.getBoundingClientRect(),
  handle1 = document.getElementById('terminal-1'),
  handle2 = document.getElementById('terminal-2'),
  line1 = new LeaderLine(handle1,
    document.getElementById('terminal-2')),
  elmLine1 = document.querySelector('.leader-line:last-of-type'),
  lineEnd = document.getElementById('terminal-3'),
  line2 = new LeaderLine(lineEnd, line1.end),
  elmLine2 = document.querySelector('.leader-line:last-of-type');

// Move to the origin of coordinates as the document
elmWrapper.style.transform = 'translate(-' +
  (rectWrapper.left + pageXOffset) + 'px, -' +
  (rectWrapper.top + pageYOffset) + 'px)';

elmWrapper.appendChild(elmLine1);
elmWrapper.appendChild(elmLine2);

const topLeft = new PlainDraggable(handle1, {
        onMove: function () {
            line1.position();
            line2.position();
        },
        onMoveStart: function () { line1.dash = { animation: true }; },
        onDragEnd: function () { line1.dash = false; },
        autoScroll: elmWrapper
});


const bottomRight = new PlainDraggable(handle2, {
        onMove: function () {
            line1.position();
            line2.position();
        },
        onMoveStart: function () { line1.dash = { animation: true }; },
        onDragEnd: function () { line1.dash = false; },
        autoScroll: elmWrapper
});