How to resize div dynamically depending on parent position in js

You could use getComputedStyle to get the transform value with regex and apply 1 / scale value to required coordinates. I was able to solve the issue only for the East holder (I'm too dumb for coordinate geometry :P):

let match = getComputedStyle(element)
           .transform.match(/matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/);
let scale = 1; //for .regular folks
if (match && +match[1] != 0)
   scale = 1 / +match[1]; //because we need to unapply the transformation

Sample:

function resizeable() {
  var resizers = document.querySelectorAll('.n, .s, .w, .e, .nw, .ne, .se, .sw');
  const min = 40;
  for (let i = 0; i < resizers.length; i++) {
    const currentResizer = resizers[i];
    const element = currentResizer.parentElement;
    const parent = currentResizer.parentElement.parentElement;
    let p;
    let c;
    let original_w = 0;
    let original_h = 0;
    let parent_x = 0;
    let parent_y = 0;
    let child_x = 0;
    let child_y = 0;
    let mouse_x = 0;
    let mouse_y = 0;
    let scale_x = 0;
    let scale_y = 0;
    let scroll_x = 0;
    let scroll_y = 0;
    // Mouse events
    currentResizer.addEventListener('mousedown', function(e) {
      first(e);
      document.addEventListener('mousemove', resize);
      document.addEventListener('mouseup', stopResize);
      e.preventDefault();
    });
    // Log
    function log(e){
      var str = 'original_w['+original_w+'] original_h['+original_h+'] \n'+
                'parent_x['+parent_x+'] parent_y['+parent_y+'] \n'+
                'scroll_x['+scroll_x+'] scroll_y['+scroll_y+'] \n'+
                'child_x['+child_x+'] child_y['+child_y+'] \n'+
                'scale_x['+scale_x+'] scale_y['+scale_y+'] \n'+
                'mouse_x['+mouse_x+'] mouse_y['+mouse_y+'] \n'+
                'e.pageX['+e.pageX+'] e.pageY['+e.pageY+'] \n'+
                'obj.left['+element.style.left+'] obj.top['+element.style.top+']';
      console.log(str);
      /**/
      str = '<table>'+
          '<tr>'+
            '<th colspan="2">First Locations:</td>'+
          '</tr>'+
          '<tr>'+
            '<td>original_w['+original_w+']</td>'+
            '<td>original_h['+original_h+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>parent_x['+parent_x+']</td>'+
            '<td>parent_y['+parent_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>scroll_x['+scroll_x+']</td>'+
            '<td>scroll_y['+scroll_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>child_x['+child_x+']</td>'+
            '<td>child_y['+child_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>scale_x['+scale_x+']</td>'+
            '<td>scale_y['+scale_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>mouse_x['+mouse_x+']</td>'+
            '<td>mouse_y['+mouse_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>e.pageX['+e.pageX+']</td>'+
            '<td>e.pageY['+e.pageY+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>obj.left['+element.style.left+']</td>'+
            '<td>obj.top['+element.style.top+']</td>'+
          '</tr>'
      '</table>';
      var m = document.getElementById("nfo"); // Debug element
      m.innerHTML = str;
    }
    // First location & width
    function first(e) {
      c = element.getBoundingClientRect();
      child_y = c.top;
      child_x = c.left;
      p = parent.getBoundingClientRect();
      parent_y = p.top;
      parent_x = p.left;
      scroll_y = window.scrollY;
      scroll_x = window.scrollX;
      original_w = parseFloat(c.width).toFixed(2);
      original_h = parseFloat(c.height).toFixed(2);
      scale_y = parseFloat(c.height / element.offsetHeight).toFixed(2);
      scale_x = parseFloat(c.width / element.offsetWidth).toFixed(2);
      mouse_y = e.pageY - scroll_y;
      mouse_x = e.pageX - scroll_x;
      log(e);
    }
    // Resize process
    function resize(e) {
      element.style.position = "absolute";
      if (currentResizer.classList.contains('se')) {
        const width = e.pageX - scroll_x - child_x ;
        const height = e.pageY - scroll_y - child_y ;
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
      }
      else if (currentResizer.classList.contains('sw')) {
        const width = original_w - (e.pageX - scroll_x - child_x);
        const height = e.pageY - scroll_y - child_y;
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
        if (width > min) {
          element.style.left = e.pageX - scroll_x - parent_x + 'px';
          element.style.width = (width / scale_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('ne')) {
        const width = e.pageX - child_x - scroll_x;
        const height = original_h - (e.pageY - mouse_y - scroll_y);
        if (width > min) {
          element.style.width = (width / scale_x)  + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top =  e.pageY - parent_y - scroll_y + 'px';
        }
      }
      else if (currentResizer.classList.contains('nw')) {
        const width = original_w - (e.pageX - scroll_x - child_x);
        const height = original_h - (e.pageY - scroll_y - mouse_y);
        if (width > min) {
          element.style.left = e.pageX - parent_x - scroll_x + 'px';
          element.style.width = (width / scale_x) + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top = e.pageY - parent_y - scroll_y + 'px';
        }
      }
      else if (currentResizer.classList.contains('e')) {
        const width = e.pageX - scroll_x - child_x;
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('s')) {
        const height = e.pageY - scroll_y - child_y;
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
      }
      else if (currentResizer.classList.contains('w')) {
        const width = original_w - (e.pageX - scroll_x - child_x);
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
          element.style.left = (e.pageX - scroll_x - parent_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('n')) {
        const height = original_h - (e.pageY - scroll_y - mouse_y);
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top = e.pageY - scroll_y - parent_y + 'px';
        }
      }
      log(e);
    }
    // When mouse released stop
    function stopResize(e) {
      first(e);
      document.removeEventListener('mousemove', resize);
    }
  }
}
resizeable();
body {
  width: 1200px;
}
.another_element_on_the_top {
  position: relative;
  float: left;
  margin: 10px;
  width: 100px;
  height: 100px;
}
.another_element_on_the_left {
  position: relative;
  float: left;
  clear: left;
  margin: 10px;
  width: 100px;
  height: 100px;
}
#nfo {
  position: relative;
  float: left;
}
div {
  position: absolute;
  background-color: grey;
}
.holder {
  float: left;
  position: relative;
  margin: -470px 20px 20px 20px;
  width: 550px;
  height: 600px;
}
.scaled:hover:before, .regular:hover:before {
  content: '';
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% - 6px);
  height: calc(100% - 6px);
  border: 6px solid #ccc;
}
.regular:nth-child(1){
  top: 5px;
  left: 5px;
  width: 120px;
  height: 120px;
  background-color: red;
}
.regular:nth-child(3){
  top: 270px;
  left: 60px;
  width: 240px;
  height: 180px;
  background-color: blue;
}
.scaled {
  top: 150px;
  left: 25px;
  width: 160px;
  height: 160px;
  transform: scale(0.6) translate(0, 0);
  transform-origin: top left 0px;
  background-color: green;
  overflow: visible;
}
.previewHeader {
  position: absolute;
  top: 10px;
  left: 10px;
  background-color: #eee;
  border: 1px solid #dedede;
}
.n, .s, .w, .e, .nw, .ne, .se, .sw {
  position: absolute;
  width: 18px;
  height: 18px;
  border: 1px solid grey;
  border-radius: 20px;
  background-color: #fff;
}
.n:hover, .s:hover, .w:hover, .e:hover,
.nw:hover, .ne:hover, .se:hover, .sw:hover {
  background-color: red;
}
.nw {
  top: -10px;
  left: -10px;
  cursor: nw-resize;
}
.ne {
  top: -10px;
  left: calc(100% - 10px);
  cursor: ne-resize;
}
.sw {
  top: calc(100% - 10px);
  left: -10px;
  cursor: sw-resize;
}
.se {
  top: calc(100% - 10px);
  left: calc(100% - 10px);
  cursor: se-resize;
}
.n {
  top: -10px;
  left: calc(50% - 10px);
  cursor: n-resize;
}
.w {
  top: calc(50% - 10px);
  left: -10px;
  cursor: w-resize;
}
.e {
  top: calc(50% - 10px);
  left:  calc(100% - 10px);
  cursor: e-resize;
}
.s {
  top: calc(100% - 10px);
  left: calc(50% - 10px);
  cursor: s-resize;
}
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>

<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>

<div class="holder">
  <div class="regular">
      <div class="previewHeader">Resizable</div>
      <div class="nw"></div>
      <div class="ne"></div>
      <div class="sw"></div>
      <div class="se"></div>
      <div class="n"></div>
      <div class="s"></div>
      <div class="w"></div>
      <div class="e"></div>
  </div>
  <div class="scaled">
    <div class="previewHeader">Scaled</div>
    <div class="nw"></div>
    <div class="ne"></div>
    <div class="sw"></div>
    <div class="se"></div>
    <div class="n"></div>
    <div class="s"></div>
    <div class="w"></div>
    <div class="e"></div>
  </div>
  <div class="regular">
    <div class="previewHeader">Resizable</div>
    <div class="nw"></div>
    <div class="ne"></div>
    <div class="sw"></div>
    <div class="se"></div>
    <div class="n"></div>
    <div class="s"></div>
    <div class="w"></div>
    <div class="e"></div>
  </div>
</div>
<div id="nfo"> X & Y</div>

or by using this method in another question.

   var element = document.querySelector('...');
   var scaleX = element.getBoundingClientRect().width / element.offsetWidth;

"This works because getBoundingClientRect returns the actual dimension while offsetWidth/Height is the unscaled size."

Edit: window.scrollX/Y added. Now it is usable in scrolled pages.

For future reference in any part of the page it works solid. Even while object is scaled.


Have you gave a thought about using jquery resizable o.O? That will save you a lot of time and trouble :)

Here you can check, it's easy and simple : https://jsfiddle.net/maehy5tj/1/

This is all you will need to do :)

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Resizable - Default functionality</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <link rel="stylesheet" href="/resources/demos/style.css">
  <style>
  #resizable { width: 150px; height: 150px; padding: 0.5em; }
  #resizable h3 { text-align: center; margin: 0; }
  </style>
  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <script>
  $( function() {
    $( "#resizable" ).resizable();
  } );
  </script>
</head>
<body>

<div id="resizable" class="ui-widget-content">
  <h3 class="ui-widget-header">Resizable</h3>
</div>


</body>
</html>