Search code examples
javascripthtmlcssresize

How to make resizable div, resizable from sides?


I have this code from codepen, It makes a resizable div that resizes from corners:

<div class='resizable'>
  <div class='resizers'>
    <div class='resizer top-left'></div>
    <div class='resizer top-right'></div>
    <div class='resizer bottom-left'></div>
    <div class='resizer bottom-right'></div>
  </div>
</div>

body,
html {
  background: black;
}
.resizable {
  background: white;
  width: 100px;
  height: 100px;
  position: absolute;
  top: 100px;
  left: 100px;
}

.resizable .resizers{
  width: 100%;
  height: 100%;
  border: 3px solid #4286f4;
  box-sizing: border-box;
}

.resizable .resizers .resizer{
  width: 10px;
  height: 10px;
  border-radius: 50%; /*magic to turn square into circle*/
  background: white;
  border: 3px solid #4286f4;
  position: absolute;
}

.resizable .resizers .resizer.top-left {
  left: -5px;
  top: -5px;
  cursor: nwse-resize; /*resizer cursor*/
}
.resizable .resizers .resizer.top-right {
  right: -5px;
  top: -5px;
  cursor: nesw-resize;
}
.resizable .resizers .resizer.bottom-left {
  left: -5px;
  bottom: -5px;
  cursor: nesw-resize;
}
.resizable .resizers .resizer.bottom-right {
  right: -5px;
  bottom: -5px;
  cursor: nwse-resize;
}

function makeResizableDiv(div) {
  const element = document.querySelector(div);
  const resizers = document.querySelectorAll(div + ' .resizer')
  const minimum_size = 20;
  let original_width = 0;
  let original_height = 0;
  let original_x = 0;
  let original_y = 0;
  let original_mouse_x = 0;
  let original_mouse_y = 0;
  for (let i = 0;i < resizers.length; i++) {
    const currentResizer = resizers[i];
    currentResizer.addEventListener('mousedown', function(e) {
      e.preventDefault()
      original_width = parseFloat(getComputedStyle(element, null).getPropertyValue('width').replace('px', ''));
      original_height = parseFloat(getComputedStyle(element, null).getPropertyValue('height').replace('px', ''));
      original_x = element.getBoundingClientRect().left;
      original_y = element.getBoundingClientRect().top;
      original_mouse_x = e.pageX;
      original_mouse_y = e.pageY;
      window.addEventListener('mousemove', resize)
      window.addEventListener('mouseup', stopResize)
    })

    function resize(e) {
      if (currentResizer.classList.contains('bottom-right')) {
        const width = original_width + (e.pageX - original_mouse_x);
        const height = original_height + (e.pageY - original_mouse_y)
        if (width > minimum_size) {
          element.style.width = width + 'px'
        }
        if (height > minimum_size) {
          element.style.height = height + 'px'
        }
      }
      else if (currentResizer.classList.contains('bottom-left')) {
        const height = original_height + (e.pageY - original_mouse_y)
        const width = original_width - (e.pageX - original_mouse_x)
        if (height > minimum_size) {
          element.style.height = height + 'px'
        }
        if (width > minimum_size) {
          element.style.width = width + 'px'
          element.style.left = original_x + (e.pageX - original_mouse_x) + 'px'
        }
      }
      else if (currentResizer.classList.contains('top-right')) {
        const width = original_width + (e.pageX - original_mouse_x)
        const height = original_height - (e.pageY - original_mouse_y)
        if (width > minimum_size) {
          element.style.width = width + 'px'
        }
        if (height > minimum_size) {
          element.style.height = height + 'px'
          element.style.top = original_y + (e.pageY - original_mouse_y) + 'px'
        }
      }
      else {
        const width = original_width - (e.pageX - original_mouse_x)
        const height = original_height - (e.pageY - original_mouse_y)
        if (width > minimum_size) {
          element.style.width = width + 'px'
          element.style.left = original_x + (e.pageX - original_mouse_x) + 'px'
        }
        if (height > minimum_size) {
          element.style.height = height + 'px'
          element.style.top = original_y + (e.pageY - original_mouse_y) + 'px'
        }
      }
    }

    function stopResize() {
      window.removeEventListener('mousemove', resize)
    }
  }
}

makeResizableDiv('.resizable')

How i make it resizes from sides? It should have a circle at the midle of right, left, bottom, right and top side and resize from there. Here is the link from the original pen: Medium: Making a resizable div

Probably there will be need to four new ifs and to four new css classes but im not sure.


Solution

  • I adjusted the positioning and class titles to place the handles on the sides, then removed the scripting from each one that allowed both directions to be adjusted.

    function makeResizableDiv(div) {
      const element = document.querySelector(div);
      const resizers = document.querySelectorAll(div + ' .resizer')
      const minimum_size = 20;
      let original_width = 0;
      let original_height = 0;
      let original_x = 0;
      let original_y = 0;
      let original_mouse_x = 0;
      let original_mouse_y = 0;
      for (let i = 0;i < resizers.length; i++) {
        const currentResizer = resizers[i];
        currentResizer.addEventListener('mousedown', function(e) {
          e.preventDefault()
          original_width = parseFloat(getComputedStyle(element, null).getPropertyValue('width').replace('px', ''));
          original_height = parseFloat(getComputedStyle(element, null).getPropertyValue('height').replace('px', ''));
          original_x = element.getBoundingClientRect().left;
          original_y = element.getBoundingClientRect().top;
          original_mouse_x = e.pageX;
          original_mouse_y = e.pageY;
          window.addEventListener('mousemove', resize)
          window.addEventListener('mouseup', stopResize)
        })
    
        function resize(e) {
          if (currentResizer.classList.contains('right')) {
            const width = original_width + (e.pageX - original_mouse_x);
            
            if (width > minimum_size) {
              element.style.width = width + 'px'
            }
          }
          else if (currentResizer.classList.contains('left')) {
            const width = original_width - (e.pageX - original_mouse_x)
            if (width > minimum_size) {
              element.style.width = width + 'px'
              element.style.left = original_x + (e.pageX - original_mouse_x) + 'px'
            }
          }
          else if (currentResizer.classList.contains('top')) {
            
            const height = original_height - (e.pageY - original_mouse_y)
            if (height > minimum_size) {
              element.style.height = height + 'px'
              element.style.top = original_y + (e.pageY - original_mouse_y) + 'px'
            }
          }
          
          else if (currentResizer.classList.contains('bottom'))       {
            const height = original_height + (e.pageY - original_mouse_y)
            if (height > minimum_size) {
              element.style.height = height + 'px'
            }
            
          }
        }
    
        function stopResize() {
          window.removeEventListener('mousemove', resize)
        }
      }
    }
    
    makeResizableDiv('.resizable')
    body,
    html {
      background: black;
    }
    .resizable {
      background: white;
      width: 100px;
      height: 100px;
      position: absolute;
      top: 100px;
      left: 100px;
    }
    
    .resizable .resizers{
      width: 100%;
      height: 100%;
      border: 3px solid #4286f4;
      box-sizing: border-box;
    }
    
    .resizable .resizers .resizer{
      width: 10px;
      height: 10px;
      border-radius: 50%; /*magic to turn square into circle*/
      background: white;
      border: 3px solid #4286f4;
      position: absolute;
    }
    
    .resizer.top {
      left: 50%;
      top: -5px;
      cursor: ns-resize;
      transform: translate(-7px, 0px);
    }
    
    .resizer.right {
      right: -5px;
      bottom: 50%;
      cursor: ew-resize;
      transform: translate(0px, 5px);
    }
    
    .resizer.bottom {
      left: 50%;
      bottom: -5px;
      cursor: ns-resize;
      transform: translate(-7px, 0px);
    }
    
    .resizer.left {
      left: -5px;
      bottom: 50%;
      cursor: ew-resize;
      transform: translate(0px, 5px);
    }
    <div class='resizable'>
      <div class='resizers'>
        <div class='resizer top'></div>
        <div class='resizer right'></div>
        <div class='resizer bottom'></div>
        <div class='resizer left'></div>
      </div>
    </div>