JSFiddle - React, Tailwind, and code Playground

by Lazaro Contreras

HTML

<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
<defs>
  <mask id="hole">
    <rect width="100%" height="100%" fill="white"/>
    <rect class="box" x="28" y="28" width="150" height="150" style="fill:black;stroke:black;stroke-width:2;fill-opacity:1;stroke-opacity:1;stroke-dasharray:10"/>
  </mask>
</defs>
<rect class="box" x="28" y="28" width="150" height="150" style="fill:black;stroke:black;stroke-width:2;fill-opacity:0;stroke-opacity:1;stroke-dasharray:10"/>
<rect width="100%" height="100%" fill="rgba(0,0,0,0.5)" mask="url(#hole)"/>
</svg>

<div class="obj2 draggable"></div>
<div class="obj draggable"></div>

<img height="100%" src="https://cdnb.artstation.com/p/assets/images/images/017/179/293/large/amir-zand-sample.jpg?1554933668">

CSS

.box {
  stroke-dasharray: 100;
  animation: dash 20s linear infinite;
}

@keyframes dash {
  to {
    stroke-dashoffset: -1000;
  }
}

.draggable {
  cursor: grab;
}

.draggable:active {
  cursor: grabbing;
}

:root {
  --white: rgba(0, 0, 0, 0.9);
}

svg {
  position: absolute;
  width: 100%;
  height: 100%;
}

.obj,
.obj2 {
  position: absolute;
  width: 0;
  height: 0;
  border: 10px solid transparent;
  user-select: none;
}

.obj {
  top: 159px;
  left: 159px;
  border-right: 10px solid var(--white);
  border-bottom: 10px solid var(--white);
}

.obj2 {
  top: 27px;
  left: 27px;
  border-left: 10px solid var(--white);
  border-top: 10px solid var(--white);
}

html,
body {
  margin: 0;
  padding: 0;
  background: blue;
}

JavaScript

var boxs = document.querySelectorAll(".box");

var obj = document.querySelector('.obj');

var obj2 = document.querySelector('.obj2');

var mouseY, mouseX, element;

obj.addEventListener('mousedown', function(e) {
  mouseY = e.pageY - obj.offsetTop;
  mouseX = e.pageX - obj.offsetLeft;
  element = e.currentTarget;
  window.addEventListener('mousemove', move);
});

obj2.addEventListener('mousedown', function(e) {
  mouseY = e.pageY - obj2.offsetTop;
  mouseX = e.pageX - obj2.offsetLeft;
  element = e.currentTarget;
  window.addEventListener('mousemove', move);
});


window.addEventListener('mouseup', function() {
  window.removeEventListener('mousemove', move);
});

function move(e) {

  if ((e.pageY - mouseY) > 0) {
    if (element == obj) {

      if (((e.pageY - mouseY) - obj2.offsetTop + 18) > 50) {
        element.style.top = e.pageY - mouseY + 'px';
      }
    } else {
      if ((obj.offsetTop - (e.pageY - mouseY) + 18) > 50) {
        element.style.top = e.pageY - mouseY + 'px';
      }
    }
  }
  
  if ((e.pageX - mouseX) > 0) {
    if (element == obj) {
      if (((e.pageX - mouseX) - obj2.offsetLeft + 18) > 50) {
        element.style.left = e.pageX - mouseX + 'px';
      }
    } else {
      if ((obj.offsetLeft - (e.pageX - mouseX) + 18) > 50) {
        element.style.left = e.pageX - mouseX + 'px';
      }
    }
  }

  boxs.forEach((box) => {
    box.setAttribute("width", obj.offsetLeft - obj2.offsetLeft + 18);
    box.setAttribute("height", obj.offsetTop - obj2.offsetTop + 18);
    box.setAttribute("x", obj2.offsetLeft + 1);
    box.setAttribute("y", obj2.offsetTop + 1);
  });
}