110

I was wondering how we can make a HTML element like <div> or <p> tag element resizable when clicked using pure JavaScript, not the jQuery library or any other library.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
monk
  • 4,727
  • 13
  • 45
  • 67
  • What do you mean 'resizeable'? If you want window resizable, you can set the width of the element in %. – Sagar Patil Jan 22 '12 at 09:39
  • Here is how I resize a div element: https://stackoverflow.com/questions/43411103/resize-div-vertical-or-horizontal/46552497#46552497 – sfanjoy Oct 03 '17 at 20:09
  • 1
    Highly related: https://stackoverflow.com/questions/12194469/best-way-to-do-a-split-pane-in-html – Andrew Jul 09 '20 at 10:56

13 Answers13

143

I really recommend using some sort of library, but you asked for it, you get it:

var p = document.querySelector('p'); // element to make resizable

p.addEventListener('click', function init() {
    p.removeEventListener('click', init, false);
    p.className = p.className + ' resizable';
    var resizer = document.createElement('div');
    resizer.className = 'resizer';
    p.appendChild(resizer);
    resizer.addEventListener('mousedown', initDrag, false);
}, false);

var startX, startY, startWidth, startHeight;

function initDrag(e) {
   startX = e.clientX;
   startY = e.clientY;
   startWidth = parseInt(document.defaultView.getComputedStyle(p).width, 10);
   startHeight = parseInt(document.defaultView.getComputedStyle(p).height, 10);
   document.documentElement.addEventListener('mousemove', doDrag, false);
   document.documentElement.addEventListener('mouseup', stopDrag, false);
}

function doDrag(e) {
   p.style.width = (startWidth + e.clientX - startX) + 'px';
   p.style.height = (startHeight + e.clientY - startY) + 'px';
}

function stopDrag(e) {
    document.documentElement.removeEventListener('mousemove', doDrag, false);
    document.documentElement.removeEventListener('mouseup', stopDrag, false);
}

Demo

Remember that this may not run in all browsers (tested only in Firefox, definitely not working in IE <9).

user123444555621
  • 148,182
  • 27
  • 114
  • 126
  • one question, what does this value of '10' does in the code parseInt(document.defaultView.getComputedStyle(p).width, 10); – monk Jan 22 '12 at 10:10
  • It's an argument to [`parseInt()`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt) which makes sure it processes decimal numbers. – user123444555621 Jan 22 '12 at 10:13
  • 1
    i found a bug in the script, if you try to make multiple p tag element resizable when there is more than one p tag element then the code doesn't work, is there any solution for that? – monk Jan 22 '12 at 14:15
  • 3
    You're not actually gonna use this in production, are you? The code above is obviously a quick hack, and has several other issues. It's just to show how things work on low level. – user123444555621 Jan 22 '12 at 14:40
  • 5
    +1 I know it's low-level, but it's very useful when you can't use a 3rd party library for any reason. I've tested it on Chrome, Firefox, Opera and Safari. – Jan Vorcak Sep 14 '14 at 08:35
  • 1
    With the proper treatment and validation rules, this principle can be used in production. I'm using something like this on an Angular application in which I couldn't use jQuery for performance issues. – Marcos Lima Dec 16 '15 at 18:38
  • @DustinPoissant The whole internet community is like this now. Unfortunately people are not so friendly like they were some 6-7 years ago. – Andrei Surdu Nov 07 '17 at 11:19
  • 4
    I fixed up the jsfiddle. This should be working and achieve the same effect. http://jsfiddle.net/MissoulaLorenzo/gfn6ob3j/ – Lorenzo Gangi Jul 25 '18 at 21:04
118

what about a pure css3 solution?

div {
    resize: both;
    overflow: auto;
} 

MDN Web Docs

W3Schools example

Browser support

Pikamander2
  • 7,332
  • 3
  • 48
  • 69
Alex
  • 1,312
  • 1
  • 8
  • 6
36

Is simple:

Example:https://jsfiddle.net/RainStudios/mw786v1w/

var element = document.getElementById('element');
//create box in bottom-left
var resizer = document.createElement('div');
resizer.style.width = '10px';
resizer.style.height = '10px';
resizer.style.background = 'red';
resizer.style.position = 'absolute';
resizer.style.right = 0;
resizer.style.bottom = 0;
resizer.style.cursor = 'se-resize';
//Append Child to Element
element.appendChild(resizer);
//box function onmousemove
resizer.addEventListener('mousedown', initResize, false);

//Window funtion mousemove & mouseup
function initResize(e) {
   window.addEventListener('mousemove', Resize, false);
   window.addEventListener('mouseup', stopResize, false);
}
//resize the element
function Resize(e) {
   element.style.width = (e.clientX - element.offsetLeft) + 'px';
   element.style.height = (e.clientY - element.offsetTop) + 'px';
}
//on mouseup remove windows functions mousemove & mouseup
function stopResize(e) {
    window.removeEventListener('mousemove', Resize, false);
    window.removeEventListener('mouseup', stopResize, false);
}
Lazaro
  • 369
  • 3
  • 4
20

See my cross browser compatible resizer.

    <!doctype html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>resizer</title>
        <meta name="author" content="Andrej Hristoliubov anhr@mail.ru">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript" src="https://rawgit.com/anhr/resizer/master/Common.js"></script>
        <script type="text/javascript" src="https://rawgit.com/anhr/resizer/master/resizer.js"></script>
        <style>
            .element {
                border: 1px solid #999999;
                border-radius: 4px;
                margin: 5px;
                padding: 5px;
            }
        </style>
        <script type="text/javascript">
            function onresize() {
                var element1 = document.getElementById("element1");
                var element2 = document.getElementById("element2");
                var element3 = document.getElementById("element3");
                var ResizerY = document.getElementById("resizerY");
                ResizerY.style.top = element3.offsetTop - 15 + "px";
                var topElements = document.getElementById("topElements");
                topElements.style.height = ResizerY.offsetTop - 20 + "px";
                var height = topElements.clientHeight - 32;
                if (height < 0)
                    height = 0;
                height += 'px';
                element1.style.height = height;
                element2.style.height = height;
            }
            function resizeX(x) {
                //consoleLog("mousemove(X = " + e.pageX + ")");
                var element2 = document.getElementById("element2");
                element2.style.width =
                    element2.parentElement.clientWidth
                    + document.getElementById('rezizeArea').offsetLeft
                    - x
                    + 'px';
            }
            function resizeY(y) {
                //consoleLog("mousemove(Y = " + e.pageY + ")");
                var element3 = document.getElementById("element3");
                var height =
                    element3.parentElement.clientHeight
                    + document.getElementById('rezizeArea').offsetTop
                    - y
                ;
                //consoleLog("mousemove(Y = " + e.pageY + ") height = " + height + " element3.parentElement.clientHeight = " + element3.parentElement.clientHeight);
                if ((height + 100) > element3.parentElement.clientHeight)
                    return;//Limit of the height of the elemtnt 3
                element3.style.height = height + 'px';
                onresize();
            }
            var emailSubject = "Resizer example error";
        </script>
    </head>
    <body>
        <div id='Message'></div>
        <h1>Resizer</h1>
        <p>Please see example of resizing of the HTML element by mouse dragging.</p>
        <ul>
            <li>Drag the red rectangle if you want to change the width of the Element 1 and Element 2</li>
            <li>Drag the green rectangle if you want to change the height of the Element 1 Element 2 and Element 3</li>
            <li>Drag the small blue square at the left bottom of the Element 2, if you want to resize of the Element 1 Element 2 and Element 3</li>
        </ul>
        <div id="rezizeArea" style="width:1000px; height:250px; overflow:auto; position: relative;" class="element">
            <div id="topElements" class="element" style="overflow:auto; position:absolute; left: 0; top: 0; right:0;">
                <div id="element2" class="element" style="width: 30%; height:10px; float: right; position: relative;">
                    Element 2
                    <div id="resizerXY" style="width: 10px; height: 10px; background: blue; position:absolute; left: 0; bottom: 0;"></div>
                    <script type="text/javascript">
                        resizerXY("resizerXY", function (e) {
                                resizeX(e.pageX + 10);
                                resizeY(e.pageY + 50);
                            });
                    </script>
                </div>
                <div id="resizerX" style="width: 10px; height:100%; background: red; float: right;"></div>
                <script type="text/javascript">
                    resizerX("resizerX", function (e) {
                        resizeX(e.pageX + 25);
                    });
                </script>
                <div id="element1" class="element" style="height:10px; overflow:auto;">Element 1</div>
            </div>
            <div id="resizerY" style="height:10px; position:absolute; left: 0; right:0; background: green;"></div>
            <script type="text/javascript">
                resizerY("resizerY", function (e) {
                    resizeY(e.pageY + 25);
                });
            </script>
            <div id="element3" class="element" style="height:100px; position:absolute; left: 0; bottom: 0; right:0;">Element 3</div>
        </div>
        <script type="text/javascript">
            onresize();
        </script>
    </body>
    </html>

Also see my example of resizer

Andrej
  • 679
  • 5
  • 14
  • It's noteworthy that when I try your example in Firefox (on Linux), the horizontal and vertical resizing causes the text to blink back and forth between selected and unselected. – Andrew Jul 09 '20 at 10:33
12

here is a example with resizer helpers in all sides and corners

element = document.getElementById("element")
makeResizable(element,10,10)
function makeResizable(element, minW = 100, minH = 100, size = 20)
{
    const top = document.createElement('div');
    top.style.width = '100%';
    top.style.height = size + 'px';
    top.style.backgroundColor = 'transparent';
    top.style.position = 'absolute';
    top.style.top = - (size/2) + 'px';
    top.style.left = '0px';
    top.style.cursor = 'n-resize';

    top.addEventListener('mousedown',resizeYNegative())

    element.appendChild(top);

    const bottom = document.createElement('div');
    bottom.style.width = '100%';
    bottom.style.height = size + 'px';
    bottom.style.backgroundColor = 'transparent';
    bottom.style.position = 'absolute';
    bottom.style.bottom = - (size/2) + 'px';
    bottom.style.left = '0px';
    bottom.style.cursor = 'n-resize';

    bottom.addEventListener('mousedown',resizeYPositive())

    element.appendChild(bottom);

    const left = document.createElement('div');
    left.style.width = size + 'px';
    left.style.height = '100%';
    left.style.backgroundColor = 'transparent';
    left.style.position = 'absolute';
    left.style.top = '0px';
    left.style.left = - (size/2) + 'px';
    left.style.cursor = 'e-resize';

    left.addEventListener('mousedown',resizeXNegative())

    element.appendChild(left);

    const right = document.createElement('div');
    right.style.width = size + 'px';
    right.style.height = '100%';
    right.style.backgroundColor = 'transparent';
    right.style.position = 'absolute';
    right.style.top = '0px';
    right.style.right = - (size/2) + 'px';
    right.style.cursor = 'e-resize';

    right.addEventListener('mousedown',resizeXPositive())

    element.appendChild(right);


    const corner1 = document.createElement('div');
    corner1.style.width = size + 'px';
    corner1.style.height = size + 'px';
    corner1.style.backgroundColor = 'transparent';
    corner1.style.position = 'absolute';
    corner1.style.top = - (size/2) + 'px';
    corner1.style.left = - (size/2) + 'px';
    corner1.style.cursor = 'nw-resize';

    corner1.addEventListener('mousedown',resizeXNegative())
    corner1.addEventListener('mousedown',resizeYNegative())
    
    element.appendChild(corner1);

    const corner2 = document.createElement('div');
    corner2.style.width = size + 'px';
    corner2.style.height = size + 'px';
    corner2.style.backgroundColor = 'transparent';
    corner2.style.position = 'absolute';
    corner2.style.top = - (size/2) + 'px';
    corner2.style.right = - (size/2) + 'px';
    corner2.style.cursor = 'ne-resize';

    corner2.addEventListener('mousedown',resizeXPositive())
    corner2.addEventListener('mousedown',resizeYNegative())

    element.appendChild(corner2);

    const corner3 = document.createElement('div');
    corner3.style.width = size + 'px';
    corner3.style.height = size + 'px';
    corner3.style.backgroundColor = 'transparent';
    corner3.style.position = 'absolute';
    corner3.style.bottom = - (size/2) + 'px';
    corner3.style.left = - (size/2) + 'px';
    corner3.style.cursor = 'sw-resize';

    corner3.addEventListener('mousedown',resizeXNegative())
    corner3.addEventListener('mousedown',resizeYPositive())

    element.appendChild(corner3);

    const corner4 = document.createElement('div');
    corner4.style.width = size + 'px';
    corner4.style.height = size + 'px';
    corner4.style.backgroundColor = 'transparent';
    corner4.style.position = 'absolute';
    corner4.style.bottom = - (size/2) + 'px';
    corner4.style.right = - (size/2) + 'px';
    corner4.style.cursor = 'se-resize';

    corner4.addEventListener('mousedown',resizeXPositive())
    corner4.addEventListener('mousedown',resizeYPositive())

    element.appendChild(corner4);
    
    function get_int_style(key)
    {
        return parseInt(window.getComputedStyle(element).getPropertyValue(key));
    }

    function resizeXPositive()
    {
        let offsetX
        function dragMouseDown(e) {
            if(e.button !== 0) return
            e = e || window.event;
            e.preventDefault();
            const {clientX} = e;
            offsetX = clientX - element.offsetLeft - get_int_style('width');
            document.addEventListener('mouseup', closeDragElement)
            document.addEventListener('mousemove', elementDrag)
          }
        
          function elementDrag(e) {
                const {clientX} = e;
                let x = clientX - element.offsetLeft - offsetX
                if(x < minW) x = minW;
                element.style.width =  x + 'px';
          }
        
          function closeDragElement() {
            document.removeEventListener("mouseup", closeDragElement);  
            document.removeEventListener("mousemove", elementDrag);
          }
        return dragMouseDown
    }

    function resizeYPositive()
    {
        let offsetY
        function dragMouseDown(e) {
            if(e.button !== 0) return
            e = e || window.event;
            e.preventDefault();
            const {clientY} = e;
            offsetY = clientY - element.offsetTop - get_int_style('height');
    
            document.addEventListener('mouseup',closeDragElement)
            document.addEventListener('mousemove',elementDrag)
          }
        
          function elementDrag(e) {
                const {clientY} = e;
                let y =  clientY - element.offsetTop - offsetY;
                if(y < minH) y = minH;
                element.style.height = y + 'px';
          }
        
          function closeDragElement() {
            document.removeEventListener("mouseup", closeDragElement);  
            document.removeEventListener("mousemove", elementDrag);
          }
        return dragMouseDown
    }

    function resizeXNegative()
    {
        let offsetX
        let startX
        let startW
        let maxX
        function dragMouseDown(e) {
            if(e.button !== 0) return
            e = e || window.event;
            e.preventDefault();
            const {clientX} = e;
            startX = get_int_style('left')
            startW = get_int_style('width')
            offsetX = clientX - startX;
            maxX = startX + startW - minW
    
            document.addEventListener('mouseup',closeDragElement)
            document.addEventListener('mousemove',elementDrag)
          }
        
          function elementDrag(e) {
                const {clientX} = e;
                let x = clientX - offsetX
                let w = startW + startX - x
                if(w < minW) w = minW;
                if(x > maxX) x = maxX;
                element.style.left = x + 'px';
                element.style.width = w + 'px';
          }
        
          function closeDragElement() {
            document.removeEventListener("mouseup", closeDragElement);  
            document.removeEventListener("mousemove", elementDrag);
          }
        return dragMouseDown
    }

    function resizeYNegative()
    {
        let offsetY
        let startY
        let startH
        let maxY
        function dragMouseDown(e) {
            if(e.button !== 0) return
            e = e || window.event;
            e.preventDefault();
            const {clientY} = e;
            startY = get_int_style('top')
            startH = get_int_style('height')
            offsetY = clientY - startY;
            maxY = startY + startH - minH 
    
            document.addEventListener('mouseup',closeDragElement,false)
            document.addEventListener('mousemove',elementDrag,false)
          }
        
          function elementDrag(e) {
                const {clientY} = e;
                let y =  clientY - offsetY
                let h = startH + startY - y
                if(h < minH) h = minH;
                if(y > maxY) y = maxY;
                element.style.top = y + 'px';
                element.style.height = h + 'px';
          }
        
          function closeDragElement() {
            document.removeEventListener("mouseup", closeDragElement);  
            document.removeEventListener("mousemove", elementDrag);
          }
        return dragMouseDown
    }
}
 #element {
  position: absolute;
  background-color: #f1f1f1;
  border: 1px solid #d3d3d3;
  left: 40px;
  top:  40px;
  width: 100px;
  height: 100px;
  border-radius: 5px;
}
<div id="element"></div>
Thiago
  • 332
  • 1
  • 3
  • 16
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 20 '22 at 02:23
  • Very verbose due to multi side/corner resize support, however, it just works. Works perfectly (in comparison with other answers in my case). – KeyKi Feb 19 '23 at 06:39
9

just using the mousemove event in vanilla js

steps

  1. add the mousemove to your target

  2. listen to the target move event

  3. get the pointer position, resize your target

codes

    const div = document.querySelector(`div.before`);
    const box = document.querySelector(`div.container`);
    box.addEventListener(`mousemove`, (e) => {
      const {
        offsetX,
        offsetY,
      } = e;
      div.style.width = offsetX + `px`;
    });

live demo

https://codepen.io/xgqfrms/full/wvMQqZL enter image description here

refs

https://developer.mozilla.org/en-US/docs/Web/API/Element/mousemove_event

https://medium.com/the-z/making-a-resizable-div-in-js-is-not-easy-as-you-think-bda19a1bc53d

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
6

I just created a CodePen that shows how this can be done pretty easily using ES6.

http://codepen.io/travist/pen/GWRBQV

Basically, here is the class that does this.

let getPropertyValue = function(style, prop) {
  let value = style.getPropertyValue(prop);
  value = value ? value.replace(/[^0-9.]/g, '') : '0';
  return parseFloat(value);
}

let getElementRect = function(element) {
  let style = window.getComputedStyle(element, null);
  return {
    x: getPropertyValue(style, 'left'),
    y: getPropertyValue(style, 'top'),
    width: getPropertyValue(style, 'width'),
    height: getPropertyValue(style, 'height')
  }
}

class Resizer {
    constructor(wrapper, element, options) {
        this.wrapper = wrapper;
        this.element = element;
        this.options = options;
        this.offsetX = 0;
        this.offsetY = 0;
        this.handle = document.createElement('div');
        this.handle.setAttribute('class', 'drag-resize-handlers');
        this.handle.setAttribute('data-direction', 'br');
        this.wrapper.appendChild(this.handle);
        this.wrapper.style.top = this.element.style.top;
        this.wrapper.style.left = this.element.style.left;
        this.wrapper.style.width = this.element.style.width;
        this.wrapper.style.height = this.element.style.height;
        this.element.style.position = 'relative';
        this.element.style.top = 0;
        this.element.style.left = 0;
        this.onResize = this.resizeHandler.bind(this);
        this.onStop = this.stopResize.bind(this);
        this.handle.addEventListener('mousedown', this.initResize.bind(this));
    }

    initResize(event) {
        this.stopResize(event, true);
        this.handle.addEventListener('mousemove', this.onResize);
        this.handle.addEventListener('mouseup', this.onStop);
    }

    resizeHandler(event) {
        this.offsetX = event.clientX - (this.wrapper.offsetLeft + this.handle.offsetLeft);
        this.offsetY = event.clientY - (this.wrapper.offsetTop + this.handle.offsetTop);
        let wrapperRect = getElementRect(this.wrapper);
        let elementRect = getElementRect(this.element);
        this.wrapper.style.width = (wrapperRect.width + this.offsetX) + 'px';
        this.wrapper.style.height = (wrapperRect.height + this.offsetY) + 'px';
        this.element.style.width = (elementRect.width + this.offsetX) + 'px';
        this.element.style.height = (elementRect.height + this.offsetY) + 'px';
    }

    stopResize(event, nocb) {
        this.handle.removeEventListener('mousemove', this.onResize); 
        this.handle.removeEventListener('mouseup', this.onStop);
    }
}

class Dragger {
    constructor(wrapper, element, options) {
        this.wrapper = wrapper;
        this.options = options;
        this.element = element;
        this.element.draggable = true;
        this.element.setAttribute('draggable', true);
        this.element.addEventListener('dragstart', this.dragStart.bind(this));
    }

    dragStart(event) {
        let wrapperRect = getElementRect(this.wrapper);
        var x = wrapperRect.x - parseFloat(event.clientX);
        var y = wrapperRect.y - parseFloat(event.clientY);
        event.dataTransfer.setData("text/plain", this.element.id + ',' + x + ',' + y);
    }

    dragStop(event, prevX, prevY) {
        var posX = parseFloat(event.clientX) + prevX;
        var posY = parseFloat(event.clientY) + prevY;
        this.wrapper.style.left = posX + 'px';
        this.wrapper.style.top = posY + 'px';
    }
}

class DragResize {
    constructor(element, options) {
        options = options || {};
        this.wrapper = document.createElement('div');
        this.wrapper.setAttribute('class', 'tooltip drag-resize');
        if (element.parentNode) {
          element.parentNode.insertBefore(this.wrapper, element);
        }
        this.wrapper.appendChild(element);
        element.resizer = new Resizer(this.wrapper, element, options);
        element.dragger = new Dragger(this.wrapper, element, options);
    }
}

document.body.addEventListener('dragover', function (event) {
    event.preventDefault();
    return false;
});

document.body.addEventListener('drop', function (event) {
    event.preventDefault();
    var dropData = event.dataTransfer.getData("text/plain").split(',');
    var element = document.getElementById(dropData[0]);
    element.dragger.dragStop(event, parseFloat(dropData[1]), parseFloat(dropData[2]));
    return false;
});
Travis Tidwell
  • 5,360
  • 1
  • 14
  • 9
  • 2
    "pretty easily": lol - Also, this is breaking for me; it seems it's having trouble with selection and deselection of text. – Andrew Jul 09 '20 at 10:34
5

I have created a function that recieve an id of an html element and adds a border to it's right side the function is general and just recieves an id so you can copy it as it is and it will work

var myoffset;
function resizeE(elem){
    var borderDiv = document.createElement("div");
    borderDiv.className = "border";
    borderDiv.addEventListener("mousedown",myresize = function myrsize(e) {
     myoffset = e.clientX - (document.getElementById(elem).offsetLeft + parseInt(window.getComputedStyle(document.getElementById(elem)).getPropertyValue("width")));
     window.addEventListener("mouseup",mouseUp);
     document.addEventListener("mousemove",mouseMove = function mousMove(e) {
      document.getElementById(elem).style.width = `${e.clientX -  myoffset - document.getElementById(elem).offsetLeft}px`;
  });
 });
    document.getElementById(elem).appendChild(borderDiv);
}

function mouseUp() {
    document.removeEventListener("mousemove", mouseMove);
    window.removeEventListener("mouseup",mouseUp);
}

function load() 
{
 resizeE("resizeableDiv");
 resizeE("anotherresizeableDiv");
  resizeE("anotherresizeableDiv1");
}
.border {

  position: absolute;
  cursor: e-resize;
  width: 9px;
  right: -5px;
  top: 0;
  height: 100%;
}

#resizeableDiv {
  width: 30vw;
  height: 30vh;
  background-color: #84f4c6;
  position: relative;
}
#anotherresizeableDiv {
  width: 30vw;
  height: 30vh;
  background-color: #9394f4;
  position: relative;
}
#anotherresizeableDiv1 {
  width: 30vw;
  height: 30vh;
  background-color: #43f4f4;
  position: relative;
}
#anotherresizeableDiv1 .border{
  background-color: black;
}
#anotherresizeableDiv .border{
  width: 30px;
  right: -200px;
  background-color: green;
}
<body onload="load()">

  <div id="resizeableDiv">change my size with the east border</div>
  <div id="anotherresizeableDiv1">with visible border</div>
</body>
  <div id="anotherresizeableDiv">with editted outside border</div>
</body>
resizeE("resizeableDiv"); //this calls a function that does the magic to the id inserted
coder
  • 700
  • 8
  • 12
4

There are very good examples here to start trying with, but all of them are based on adding some extra or external element like a "div" as a reference element to drag it, and calculate the new dimensions or position of the original element.

Here's an example that doesn't use any extra elements. We could add borders, padding or margin without affecting its operation. In this example we have not added color, nor any visual reference to the borders nor to the lower right corner as a clue where you can enlarge or reduce dimensions, but using the cursor around the resizable elements the clues appears!

let resizerForCenter = new Resizer('center')  
resizerForCenter.initResizer()

See it in action with CodeSandbox:

In this example we use ES6, and a module that exports a class called Resizer. An example is worth a thousand words:

Edit boring-snow-qz1sd

Or with the code snippet:

const html = document.querySelector('html')

class Resizer {
 constructor(elemId) {
  this._elem = document.getElementById(elemId)
  /**
   * Stored binded context handlers for method passed to eventListeners!
   * 
   * See: https://stackoverflow.com/questions/9720927/removing-event-listeners-as-class-prototype-functions
   */
  this._checkBorderHandler = this._checkBorder.bind(this)
  this._doResizeHandler  = this._doResize.bind(this)
  this._initResizerHandler = this.initResizer.bind(this)
  this._onResizeHandler  = this._onResize.bind(this)
 }

 initResizer() {
  this.stopResizer()
  this._beginResizer()
 }

 _beginResizer() {
  this._elem.addEventListener('mousemove', this._checkBorderHandler, false)
 }

 stopResizer() {
  html.style.cursor = 'default'
  this._elem.style.cursor = 'default'
  
  window.removeEventListener('mousemove', this._doResizeHandler, false)
  window.removeEventListener('mouseup', this._initResizerHandler, false)

  this._elem.removeEventListener('mousedown', this._onResizeHandler, false)
  this._elem.removeEventListener('mousemove', this._checkBorderHandler, false)
 }

 _doResize(e) {
  let elem = this._elem

  let boxSizing = getComputedStyle(elem).boxSizing
  let borderRight = 0
  let borderLeft = 0
  let borderTop = 0
  let borderBottom = 0

  let paddingRight = 0
  let paddingLeft = 0
  let paddingTop = 0
  let paddingBottom = 0

  switch (boxSizing) {
   case 'content-box':
     paddingRight = parseInt(getComputedStyle(elem).paddingRight)
     paddingLeft = parseInt(getComputedStyle(elem).paddingLeft)
     paddingTop = parseInt(getComputedStyle(elem).paddingTop)
     paddingBottom = parseInt(getComputedStyle(elem).paddingBottom)
    break
   case 'border-box':
     borderRight = parseInt(getComputedStyle(elem).borderRight)
     borderLeft = parseInt(getComputedStyle(elem).borderLeft)
     borderTop = parseInt(getComputedStyle(elem).borderTop)
     borderBottom = parseInt(getComputedStyle(elem).borderBottom)
    break
   default: break
  }

  let horizontalAdjustment = (paddingRight + paddingLeft) - (borderRight + borderLeft)
  let verticalAdjustment  = (paddingTop + paddingBottom) - (borderTop + borderBottom)

  let newWidth = elem.clientWidth  + e.movementX - horizontalAdjustment + 'px'
  let newHeight = elem.clientHeight + e.movementY - verticalAdjustment   + 'px'
  
  let cursorType = getComputedStyle(elem).cursor
  switch (cursorType) {
   case 'all-scroll':
     elem.style.width = newWidth
     elem.style.height = newHeight
    break
   case 'col-resize':
     elem.style.width = newWidth
    break
   case 'row-resize':
     elem.style.height = newHeight
    break
   default: break
  }
 }

 _onResize(e) {
  // On resizing state!
  let elem = e.target
  let newCursorType = undefined
  let cursorType = getComputedStyle(elem).cursor
  switch (cursorType) {
   case 'nwse-resize':
    newCursorType = 'all-scroll'
    break
   case 'ew-resize':
    newCursorType = 'col-resize'
    break
   case 'ns-resize':
    newCursorType = 'row-resize'
    break
   default: break
  }
  
  html.style.cursor = newCursorType // Avoid cursor's flickering 
  elem.style.cursor = newCursorType
  
  // Remove what is not necessary, and could have side effects!
  elem.removeEventListener('mousemove', this._checkBorderHandler, false);
  
  // Events on resizing state
  /**
   * We do not apply the mousemove event on the elem to resize it, but to the window to prevent the mousemove from slippe out of the elem to resize. This work bc we calculate things based on the mouse position
   */
  window.addEventListener('mousemove', this._doResizeHandler, false);
  window.addEventListener('mouseup', this._initResizerHandler, false);
 }

 _checkBorder(e) {
  const elem = e.target
  const borderSensitivity = 5
  const coor = getCoordenatesCursor(e)
  const onRightBorder  = ((coor.x + borderSensitivity) > elem.scrollWidth)
  const onBottomBorder = ((coor.y + borderSensitivity) > elem.scrollHeight)
  const onBottomRightCorner = (onRightBorder && onBottomBorder)
  
  if (onBottomRightCorner) {
   elem.style.cursor = 'nwse-resize'
  } else if (onRightBorder) {
   elem.style.cursor = 'ew-resize'
  } else if (onBottomBorder) {
   elem.style.cursor = 'ns-resize'
  } else {
   elem.style.cursor = 'auto'
  }
  
  if (onRightBorder || onBottomBorder) {
   elem.addEventListener('mousedown', this._onResizeHandler, false)
  } else {
   elem.removeEventListener('mousedown', this._onResizeHandler, false)
  }
 }
}

function getCoordenatesCursor(e) {
 let elem = e.target;
 
 // Get the Viewport-relative coordinates of cursor.
 let viewportX = e.clientX
 let viewportY = e.clientY
 
 // Viewport-relative position of the target element.
 let elemRectangle = elem.getBoundingClientRect()
 
 // The  function returns the largest integer less than or equal to a given number.
 let x = Math.floor(viewportX - elemRectangle.left) // - elem.scrollWidth
 let y = Math.floor(viewportY - elemRectangle.top) // - elem.scrollHeight
 
 return {x, y}
}

let resizerForCenter = new Resizer('center')
resizerForCenter.initResizer()

let resizerForLeft = new Resizer('left')
resizerForLeft.initResizer()

setTimeout(handler, 10000, true); // 10s

function handler() {
  resizerForCenter.stopResizer()
}
body {
 background-color: white;
}

#wrapper div {
 /* box-sizing: border-box; */
 position: relative;
 float:left;
 overflow: hidden;
 height: 50px;
 width: 50px;
 padding: 3px;
}

#left {
 background-color: blueviolet;
}
#center {
 background-color:lawngreen ;
}
#right {
 background: blueviolet;
}
#wrapper {
 border: 5px solid hotpink;
 display: inline-block;
 
}
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>Resizer v0.0.1</title>
</head>
  <body>
    <div id="wrapper">
      <div id="left">Left</div>
      <div id="center">Center</div>
      <div id="right">Right</div>
    </div>
  </body>
</html>
fender0ne
  • 281
  • 4
  • 13
2

// import
function get_difference(pre, mou) {
  return {
    x: mou.x - pre.x,
    y: mou.y - pre.y
  };
}

/*
if your panel is in a nested environment, which the parent container's width and height does not equa to document width 
and height, for example, in an element `canvas`, then edit it to

function oMousePos(e) {
  var rc = canvas.getBoundingClientRect();
  return {
    x: e.clientX - rc.left,
    y: e.clientY - rc.top,
  };
}
*/

function oMousePos(e) {
  return {
    x: e.clientX,
    y: e.clientY,
  };
}

function render_element(styles, el) {
  for (const [kk, vv] of Object.entries(styles)) {
    el.style[kk] = vv;
  }
}

class MoveablePanel {

  /*
  prevent an element from moving out of window
  */
  constructor(container, draggable, left, top) {
    this.container = container;
    this.draggable = draggable;
    this.left = left;
    this.top = top;
    let rect = container.getBoundingClientRect();
    this.width = rect.width;
    this.height = rect.height;
    this.status = false;

    // initial position of the panel, should not be changed
    this.original = {
      left: left,
      top: top
    };

    // current left and top postion
    // {this.left, this.top}

    // assign the panel to initial position
    // initalize in registration
    this.default();

    if (!MoveablePanel._instance) {
      MoveablePanel._instance = [];
    }
    MoveablePanel._instance.push(this);
  }

  mousedown(e) {
    this.status = true;
    this.previous = oMousePos(e)
  }

  mousemove(e) {
    if (!this.status) {
      return;
    }
    let pos = oMousePos(e);
    let vleft = this.left + pos.x - this.previous.x;
    let vtop = this.top + pos.y - this.previous.y;
    let kleft, ktop;

    if (vleft < 0) {
      kleft = 0;
    } else if (vleft > window.innerWidth - this.width) {
      kleft = window.innerWidth - this.width;
    } else {
      kleft = vleft;
    }

    if (vtop < 0) {
      ktop = 0;
    } else if (vtop > window.innerHeight - this.height) {
      ktop = window.innerHeight - this.height;
    } else {
      ktop = vtop;
    }
    this.container.style.left = `${kleft}px`;
    this.container.style.top = `${ktop}px`;
  }

  /*
  sometimes user move the cursor too fast which mouseleave is previous than mouseup
  to prevent moving too fast and break the control, mouseleave is handled the same as mouseup
  */

  mouseupleave(e) {
    if (!this.status) {
      return null;
    }
    this.status = false;
    let pos = oMousePos(e);
    let vleft = this.left + pos.x - this.previous.x;
    let vtop = this.top + pos.y - this.previous.y;

    if (vleft < 0) {
      this.left = 0;
    } else if (vleft > window.innerWidth - this.width) {
      this.left = window.innerWidth - this.width;
    } else {
      this.left = vleft;
    }

    if (vtop < 0) {
      this.top = 0;
    } else if (vtop > window.innerHeight - this.height) {
      this.top = window.innerHeight - this.height;
    } else {
      this.top = vtop;
    }

    this.show();
    return true;
  }

  default () {
    this.container.style.left = `${this.original.left}px`;
    this.container.style.top = `${this.original.top}px`;
  }

  /*
  panel with a higher z index will interupt drawing
  therefore if panel is not displaying, set it with a lower z index that canvas

  change index doesn't work, if panel is hiding, then we move it out
  hide: record current position, move panel out
  show: assign to recorded position

  notice this position has nothing to do panel drag movement
  they cannot share the same variable
  */

  hide() {
    // move to the right bottom conner
    this.container.style.left = `${window.screen.width}px`;
    this.container.style.top = `${window.screen.height}px`;
  }

  show() {
    this.container.style.left = `${this.left}px`;
    this.container.style.top = `${this.top}px`;
  }
}
// end of import

class DotButton{
    constructor(
        width_px, 
        styles, // mainly pos, padding and margin, e.g. {top: 0, left: 0, margin: 0},
        color, 
        color_hover,
        border, // boolean
        border_dismiss, // boolean: dismiss border when hover
    ){
        this.width = width_px;
        this.styles = styles;
        this.color = color;
        this.color_hover = color_hover;
        this.border = border;
        this.border_dismiss = border_dismiss;
    }

    create(_styles=null){
        var el = document.createElement('div');
        Object.keys(this.styles).forEach(kk=>{
            el.style[kk] = `${this.styles[kk]}px`;
        });
        if(_styles){
            Object.keys(_styles).forEach(kk=>{
                el.style[kk] = `${this.styles[kk]}px`;
            });
        }
        el.style.width = `${this.width}px`
        el.style.height = `${this.width}px`
        el.style.position = 'absolute';
        el.style.left = `${this.left_px}px`;
        el.style.top = `${this.top_px}px`;
        el.style.background = this.color;
        if(this.border){
            el.style.border = '1px solid'; 
        }
        el.style.borderRadius = `${this.width}px`;

        el.addEventListener('mouseenter', ()=>{
            el.style.background = this.color_hover;
            if(this.border_dismiss){
                el.style.border = `1px solid ${this.color_hover}`; 
            }
        });
        el.addEventListener('mouseleave', ()=>{
            el.style.background = this.color;
            if(this.border_dismiss){
                el.style.border = '1px solid'; 
            }
        });
        return el;
    }
}

function cursor_hover(el, default_cursor, to_cursor){
    el.addEventListener('mouseenter', function(){
        this.style.cursor = to_cursor;
    }.bind(el));


    el.addEventListener('mouseleave', function(){
        this.style.cursor = default_cursor;
    }.bind(el));
}

class FlexPanel extends MoveablePanel{
    constructor(
        parent_el,
        top_px,
        left_px,
        width_px, 
        height_px, 
        background,
        handle_width_px, 
        coner_vmin_ratio, 
        button_width_px, 
        button_margin_px, 
    ){
        super(
            (()=>{
                var el = document.createElement('div');
                render_element(
                    {
                        position: 'fixed', 
                        top: `${top_px}px`,
                        left: `${left_px}px`,
                        width: `${width_px}px`,
                        height: `${height_px}px`,
                        background: background, 
                    }, 
                    el,
                );
                return el;
            })(), // iife returns a container (panel el)
            new DotButton(button_width_px, {top: 0, right: 0, margin: button_margin_px}, 'green', 'lightgreen', false, false).create(), // draggable
            left_px, // left
            top_px, // top
        );

        this.draggable.addEventListener('mousedown', e => {
            e.preventDefault();
            this.mousedown(e);
        });

        this.draggable.addEventListener('mousemove', e => {
            e.preventDefault();
            this.mousemove(e);
        });

        this.draggable.addEventListener('mouseup', e => {
            e.preventDefault();
            this.mouseupleave(e);
        });

        this.draggable.addEventListener('mouseleave', e => {
            e.preventDefault();
            this.mouseupleave(e);
        });

        this.parent_el = parent_el;
        this.background = background;

        // parent
        this.width = width_px;
        this.height = height_px;

        this.handle_width_px = handle_width_px;
        this.coner_vmin_ratio = coner_vmin_ratio;

        this.panel_el = document.createElement('div');

        // styles that won't change 
        this.panel_el.style.position = 'absolute';
        this.panel_el.style.top = `${this.handle_width_px}px`;
        this.panel_el.style.left = `${this.handle_width_px}px`; 
        this.panel_el.style.background = this.background;
    
        this.handles = [
            this.handle_top,
            this.handle_left,
            this.handle_bottom,
            this.handle_right, 

            this.handle_lefttop,
            this.handle_topleft,
            this.handle_topright,
            this.handle_righttop, 
            this.handle_rightbottom, 
            this.handle_bottomright,
            this.handle_bottomleft,
            this.handle_leftbottom, 
        ] = Array.from({length: 12}, i => document.createElement('div'));

        this.handles.forEach(el=>{
            el.style.position = 'absolute';
        });

        this.handle_topleft.style.top = '0';
        this.handle_topleft.style.left = `${this.handle_width_px}px`;

        this.handle_righttop.style.right = '0';
        this.handle_righttop.style.top = `${this.handle_width_px}px`;

        this.handle_bottomright.style.bottom = '0';
        this.handle_bottomright.style.right = `${this.handle_width_px}px`;

        this.handle_leftbottom.style.left = '0';
        this.handle_leftbottom.style.bottom = `${this.handle_width_px}px`;


        this.handle_lefttop.style.left = '0';
        this.handle_lefttop.style.top = '0';

        this.handle_topright.style.top = '0';
        this.handle_topright.style.right = '0';

        this.handle_rightbottom.style.right = '0';
        this.handle_rightbottom.style.bottom = '0';

        this.handle_bottomleft.style.bottom = '0';
        this.handle_bottomleft.style.left = '0';

        this.update_ratio();

        [
            'ns-resize', // |
            'ew-resize', // -
            'ns-resize', // |
            'ew-resize', // -

            'nwse-resize', // \
            'nwse-resize', // \
            'nesw-resize', // /
            'nesw-resize', // /
            'nwse-resize', // \
            'nwse-resize', // \
            'nesw-resize', // /
            'nesw-resize', // /
        ].map((dd, ii)=>{
            cursor_hover(this.handles[ii], 'default', dd);
        });

        this.vtop = this.top;
        this.vleft = this.left;
        this.vwidth = this.width;
        this.vheight = this.height;

        this.update_ratio();

        this.handles.forEach(el=>{
            this.container.appendChild(el);
        });

        cursor_hover(this.draggable, 'default', 'move');

        this.panel_el.appendChild(this.draggable);
        this.container.appendChild(this.panel_el);
        this.parent_el.appendChild(this.container);

        [
            this.edgemousedown, 
            this.verticalmousemove,
            this.horizontalmousemove,
            this.nwsemousemove,
            this.neswmousemove,
            this.edgemouseupleave,
        ] = [
            this.edgemousedown.bind(this),
            this.verticalmousemove.bind(this),
            this.horizontalmousemove.bind(this),
            this.nwsemousemove.bind(this),
            this.neswmousemove.bind(this),
            this.edgemouseupleave.bind(this),
        ];

        this.handle_top.addEventListener('mousedown', e=>{this.edgemousedown(e, 'top')});
        this.handle_left.addEventListener('mousedown', e=>{this.edgemousedown(e, 'left')});
        this.handle_bottom.addEventListener('mousedown', e=>{this.edgemousedown(e, 'bottom')});
        this.handle_right.addEventListener('mousedown', e=>{this.edgemousedown(e, 'right')}); 
        this.handle_lefttop.addEventListener('mousedown', e=>{this.edgemousedown(e, 'lefttop')});
        this.handle_topleft.addEventListener('mousedown', e=>{this.edgemousedown(e, 'topleft')});
        this.handle_topright.addEventListener('mousedown', e=>{this.edgemousedown(e, 'topright')});
        this.handle_righttop.addEventListener('mousedown', e=>{this.edgemousedown(e, 'righttop')}); 
        this.handle_rightbottom.addEventListener('mousedown', e=>{this.edgemousedown(e, 'rightbottom')}); 
        this.handle_bottomright.addEventListener('mousedown', e=>{this.edgemousedown(e, 'bottomright')});
        this.handle_bottomleft.addEventListener('mousedown', e=>{this.edgemousedown(e, 'bottomleft')});
        this.handle_leftbottom.addEventListener('mousedown', e=>{this.edgemousedown(e, 'leftbottom')});

        this.handle_top.addEventListener('mousemove', this.verticalmousemove);
        this.handle_left.addEventListener('mousemove', this.horizontalmousemove);
        this.handle_bottom.addEventListener('mousemove', this.verticalmousemove);
        this.handle_right.addEventListener('mousemove', this.horizontalmousemove); 
        this.handle_lefttop.addEventListener('mousemove', this.nwsemousemove);
        this.handle_topleft.addEventListener('mousemove', this.nwsemousemove);
        this.handle_topright.addEventListener('mousemove', this.neswmousemove);
        this.handle_righttop.addEventListener('mousemove', this.neswmousemove); 
        this.handle_rightbottom.addEventListener('mousemove', this.nwsemousemove); 
        this.handle_bottomright.addEventListener('mousemove', this.nwsemousemove);
        this.handle_bottomleft.addEventListener('mousemove', this.neswmousemove);
        this.handle_leftbottom.addEventListener('mousemove', this.neswmousemove);

        this.handle_top.addEventListener('mouseup', e=>{this.verticalmousemove(e); this.edgemouseupleave()});
        this.handle_left.addEventListener('mouseup', e=>{this.horizontalmousemove(e); this.edgemouseupleave()});
        this.handle_bottom.addEventListener('mouseup', e=>{this.verticalmousemove(e); this.edgemouseupleave()});
        this.handle_right.addEventListener('mouseup', e=>{this.horizontalmousemove(e); this.edgemouseupleave()}); 
        this.handle_lefttop.addEventListener('mouseup', e=>{this.nwsemousemove(e); this.edgemouseupleave()});
        this.handle_topleft.addEventListener('mouseup', e=>{this.nwsemousemove(e); this.edgemouseupleave()});
        this.handle_topright.addEventListener('mouseup', e=>{this.neswmousemove(e); this.edgemouseupleave()});
        this.handle_righttop.addEventListener('mouseup', e=>{this.neswmousemove(e); this.edgemouseupleave()}); 
        this.handle_rightbottom.addEventListener('mouseup', e=>{this.nwsemousemove(e); this.edgemouseupleave()}); 
        this.handle_bottomright.addEventListener('mouseup', e=>{this.nwsemousemove(e); this.edgemouseupleave()});
        this.handle_bottomleft.addEventListener('mouseup', e=>{this.neswmousemove(e); this.edgemouseupleave()});
        this.handle_leftbottom.addEventListener('mouseup', e=>{this.neswmousemove(e); this.edgemouseupleave()});
    
        this.handle_top.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_left.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_bottom.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_right.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_lefttop.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_topleft.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_topright.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_righttop.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_rightbottom.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_bottomright.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_bottomleft.addEventListener('mouseleave', this.edgemouseupleave);
        this.handle_leftbottom.addEventListener('mouseleave', this.edgemouseupleave);
    }

    // box size change triggers corner handler size change
    update_ratio(){
        this.container.style.top = `${this.vtop}px`;
        this.container.style.left = `${this.vleft}px`;
        this.container.style.width = `${this.vwidth}px`;
        this.container.style.height = `${this.vheight}px`;

        this.panel_el.style.width = `${this.vwidth - 2 * this.handle_width_px}px`;
        this.panel_el.style.height = `${this.vheight - 2 * this.handle_width_px}px`;

        this.ratio = this.vwidth < this.vheight ? this.coner_vmin_ratio * this.vwidth : this.coner_vmin_ratio * this.vheight;
        [
            this.handle_top,
            this.handle_bottom, 
        ].forEach(el=>{
            el.style.width = `${this.vwidth - 2 * this.ratio}px`;
            el.style.height = `${this.handle_width_px}px`;
        });

        [
            this.handle_left,
            this.handle_right, 
        ].forEach(el=>{
            el.style.height = `${this.vheight - 2 * this.ratio}px`;
            el.style.width = `${this.handle_width_px}px`;
        });

        this.handle_top.style.top = `0`;
        this.handle_top.style.left = `${this.ratio}px`;

        this.handle_left.style.top = `${this.ratio}px`;
        this.handle_left.style.left = `0`;

        this.handle_bottom.style.bottom = `0`;
        this.handle_bottom.style.right = `${this.ratio}px`;

        this.handle_right.style.bottom = `${this.ratio}px`;
        this.handle_right.style.right = `0`;

        [
            this.handle_topright,
            this.handle_bottomleft,
        ].forEach(el=>{
            el.style.width = `${this.ratio}px`;
            el.style.height = `${this.handle_width_px}px`;
        });

        [
            this.handle_lefttop,
            this.handle_rightbottom,
        ].forEach(el=>{
            el.style.width = `${this.handle_width_px}px`;
            el.style.height = `${this.ratio}px`;
        });

        [
            this.handle_topleft,
            this.handle_bottomright,
        ].forEach(el=>{
            el.style.width = `${this.ratio - this.handle_width_px}px`;
            el.style.height = `${this.handle_width_px}px`;
        });

        [
            this.handle_righttop,
            this.handle_leftbottom,
        ].forEach(el=>{
            el.style.height = `${this.handle_width_px}px`;
            el.style.width = `${this.ratio - this.handle_width_px}px`;
        });
    }

    edgemousedown(e, flag){
        this.previous = oMousePos(e);
        this.flag = flag;
        this.drag = true;
    }

    verticalmousemove(e){
        if(this.drag){
            // -
            this.mouse = oMousePos(e);
            var ydif = this.mouse.y - this.previous.y;
            switch(this.flag){
                case 'top':
                    this.vtop = this.top + ydif;
                    this.vheight = this.height - ydif;

                    this.vleft = this.left;
                    this.vwidth = this.width;
                break;

                case 'bottom':
                    this.vheight = this.height + ydif;

                    this.vtop = this.top;
                    this.vleft = this.left;
                    this.vwidth = this.width;
                break;
            }
            this.update_ratio();
        }
    }

    horizontalmousemove(e){
        if(this.drag){
            // |
            this.mouse = oMousePos(e);
            var xdif = this.mouse.x - this.previous.x;
            switch(this.flag){
                case 'left':
                    this.vleft = this.left + xdif;
                    this.vwidth = this.width - xdif;

                    this.vtop = this.top;
                    this.vheight = this.height;
                break;

                case 'right':
                    this.vwidth = this.width + xdif;
                
                    this.vtop = this.top;
                    this.vleft = this.left;
                    this.vheight = this.height;
                break;
            }
            this.update_ratio();
        }
    }

    nwsemousemove(e){
        if(this.drag){
            // \
            this.mouse = oMousePos(e);
            var ydif = this.mouse.y - this.previous.y;
            var xdif = this.mouse.x - this.previous.x;
            switch(this.flag){
                case 'topleft':
                    this.vleft = this.left + xdif;
                    this.vtop = this.top + ydif;
                    this.vwidth = this.width - xdif;
                    this.vheight = this.height - ydif;
                break;

                case 'lefttop':
                    this.vleft = this.left + xdif;
                    this.vtop = this.top + ydif;
                    this.vwidth = this.width - xdif;
                    this.vheight = this.height - ydif;
                break;

                case 'bottomright':
                    this.vwidth = this.width + xdif;
                    this.vheight = this.height + ydif;

                    this.vtop = this.top;
                    this.vleft = this.left;
                break;

                case 'rightbottom':
                    this.vwidth = this.width + xdif;
                    this.vheight = this.height + ydif;

                    this.vtop = this.top;
                    this.vleft = this.left;
                break;
            }
            this.update_ratio();
        }
    }

    neswmousemove(e){
        if(this.drag){
            // /
            this.mouse = oMousePos(e);
            var ydif = this.mouse.y - this.previous.y;
            var xdif = this.mouse.x - this.previous.x;
            switch(this.flag){
                case 'topright':
                    this.vtop = this.top + ydif;
                    this.vwidth = this.width + xdif;
                    this.vheight = this.height - ydif;

                    this.vleft = this.left;
                break;

                case 'righttop':
                    this.vtop = this.top + ydif;
                    this.vwidth = this.width + xdif;
                    this.vheight = this.height - ydif;

                    this.vleft = this.left;
                break;

                case 'bottomleft':
                    this.vleft = this.left + xdif;
                    this.vwidth = this.width - xdif;
                    this.vheight = this.height + ydif;

                    this.vtop = this.top;
                break;

                case 'leftbottom':
                    this.vleft = this.left + xdif;
                    this.vwidth = this.width - xdif;
                    this.vheight = this.height + ydif;

                    this.vtop = this.top;
                break;
            }
            this.update_ratio();
        }
    }

    edgemouseupleave(){
        this.drag = false;
        this.top = this.vtop;
        this.left = this.vleft;
        this.width = this.vwidth;
        this.height = this.vheight;
    }

    mouseupleave(e){
        if(super.mouseupleave(e)){
            this.vtop = this.top;
            this.vleft = this.left;         
        }
    }
}


var fp = new FlexPanel(
    document.body, // parent div container
    20, // top margin
    20, // left margin
    200, // width 
    150, // height
    'lightgrey', // background
    20, // handle height when horizontal; handle width when vertical
    0.2, // edge up and left resize bar width : top resize bar width = 1 : 5
    35, // green move button width and height
    2, // button margin
);

/*
this method creates an element for you
which you don't need to pass in a selected element

to manipuate dom element
fp.container -> entire panel
fp.panel_el -> inside panel
*/

Achieving functionalities fully requires a lot of hard coding. Please refer to the documentation, it will show you how to use each class as element.

Weilory
  • 2,621
  • 19
  • 35
2
const onMouseDownEvent=(ev: React.DragEvent)=>{
    let imgElem = (ev.target as HTMLImageElement);
    let childElem = (ev.currentTarget && ev.currentTarget.childNodes && ev.currentTarget.childNodes[0]);
    let original_height = parseFloat(getComputedStyle(imgElem, null).getPropertyValue('height').replace('px', ''));
    let original_width = parseFloat(getComputedStyle(imgElem, null).getPropertyValue('width').replace('px', ''));
    let original_Y =  imgElem.getBoundingClientRect().top;
    let original_X =  imgElem.getBoundingClientRect().right;

    ev.preventDefault();
    var original_mouse_y = ev.pageY;
    var original_mouse_x = ev.pageX;
    document.addEventListener('mousemove', resize);
    document.addEventListener('mouseup', stopResize);

    function resize(mouseMoveEvent) {
        const height = original_height + (mouseMoveEvent.pageY - original_mouse_y); 
        const width = original_width + (mouseMoveEvent.pageX - original_mouse_x); 
        
        imgElem.style.height = height + 'px';
        mouseMoveEvent.target.childNodes[0].innerHTML = imgElem.style.height;

        imgElem.style.width = width + 'px';
        mouseMoveEvent.target.childNodes[0].innerHTML = imgElem.style.width;
    }
    
    function stopResize() {
        document.removeEventListener('mousemove', resize)
    }   
}


<div onMouseDown={onMouseDownEvent} id="imgInCanvas" onDragStart={ onDragStartFromContainer } draggable="true"/>
41 72 6c
  • 1,600
  • 5
  • 19
  • 30
1

I'm not sure if this is what you are looking for, but you can always use CSS resize property and add it to an element using javascript; For example lets say you have a div element with the id myDiv and you want to make it resizable:

document.getElementById("myDiv").style.resize = "both";

here's the related links: Style resize Property CSS resize Property

mo3n
  • 1,522
  • 2
  • 10
  • 34
-1

var resizeHandle = document.getElementById('resizable');
var box = document.getElementById('resize');
resizeHandle.addEventListener('mousedown', initialiseResize, false);

function initialiseResize(e) {
  window.addEventListener('mousemove', startResizing, false);
  window.addEventListener('mouseup', stopResizing, false);
}

function stopResizing(e) {
  window.removeEventListener('mousemove', startResizing, false);
  window.removeEventListener('mouseup', stopResizing, false);
}

function startResizing(e) {
  box.style.width = (e.clientX) + 'px';
  box.style.height = (e.clientY) + 'px';
}

function startResizing(e) {
  box.style.width = (e.clientX - box.offsetLeft) + 'px';
  box.style.height = (e.clientY - box.offsetTop) + 'px';
}
#resize {
  position: relative;
  width: 130px;
  height: 130px;
  border: 2px solid blue;
  color: white;
}

#resizable {
  background-color: white;
  width: 10px;
  height: 10px;
  cursor: se-resize;
  position: absolute;
  right: 0;
  bottom: 0;
}
<div id="resize">

  <div id="resizable">
  </div>
shrys
  • 5,860
  • 2
  • 21
  • 36