2

https://jsfiddle.net/f8L300ug/3/

I'm trying to make a simple drag-to-resize function. See the example above.

If the mouse is released outside the <body>, the mouseup event won't be triggered, in contrast to what this post implies: Responding to the onmousemove event outside of the browser window in IE

jsFiddle's drag handler does a good job in this. If the mouse is released outside the element, then unbind the mousemove event; If the mouse is not released outside the element and moves back in, then keep the mousemove event. How can I achieve this?

Here's my code. jsFiddle's resize functionality is not perfect after well. After playing it for a while, I triggered a bug and my CSS panel is gone, so I can't post my CSS code here...

JS:

var initialX;
var leftPanel = document.getElementById("left");
var rightPanel = document.getElementById("right");
var resizePanels = function(e){
    var deltaX = e.clientX - initialX;
    var bodyWidth = parseInt(window.getComputedStyle(leftPanel).width);
    initialX = e.clientX;
    var newWidth = bodyWidth + deltaX;
    leftPanel.style.width = newWidth + "px";
    rightPanel.style.width =     (parseInt(window.getComputedStyle(document.body).width) - newWidth)*0.9 + "px";
}

var bodyUnbindResize = function(){
    document.body.removeEventListener("mousemove", resizePanels)
    document.body.style.cursor = "default";
}

document.getElementById("dragger").addEventListener("mousedown", function(){
    document.body.addEventListener("mousemove", resizePanels)
    document.body.addEventListener("mouseup", bodyUnbindResize)
    document.body.style.cursor = "col-resize";
});

HTML:

<div id="left" class="grid">
</div>
<div id="dragger" class="grid"></div>
<div id="right" class="grid">
</div>

And please improve my code if you have a better way. This is the first time I use vanilla JS to do this, so this might not be the best way. Thanks!

1 Answer 1

5

It doesn't seem to work when you attach the listener to document.body, but it does work if you attach it to window. If the mouse isn't released, even when you go out of the bounds of the window, then the browser will still detect the mouse move event, which means it is also able to detect when the mouse is released. This also means that when you go out of the window's bounds, you'll get a negative value. You can easily fix that.

https://jsfiddle.net/f8L300ug/8/

var initialX;
var leftPanel = document.getElementById("left");
var rightPanel = document.getElementById("right");
var resizePanels = function (e) {
    // If the mouse is still down when dragging outside,
    // to the left of the window, e.clientX will be negative
    // and undesired behavior happens. 
    // To fix this, simply give it a value of 0 when it is below 0 (out of the window)
    var clientX = e.clientX < 0 ? 0 : e.clientX;
    var deltaX = clientX - initialX;
    var bodyWidth = parseInt(window.getComputedStyle(leftPanel).width, 10); // < It's a good idea to always
    var newWidth = bodyWidth + deltaX;                                      // specify a radix for parseInt
    initialX = clientX;
    leftPanel.style.width = newWidth + "px";
    rightPanel.style.width = (parseInt(window.getComputedStyle(document.body).width, 10) - newWidth) * 0.9 + "px";
}; // < It's a good idea to always close your `var` statements with a `;`

var bodyUnbindResize = function () {
    window.removeEventListener("mousemove", resizePanels);
    document.body.style.cursor = "default";
};

document.getElementById("dragger").addEventListener("mousedown", function () {
    // Attach the mouse listeners to the window
    window.addEventListener("mousemove", resizePanels);
    window.addEventListener("mouseup", bodyUnbindResize);
    document.body.style.cursor = "col-resize";
});
.grid{
    height: 200px;
    user-select:none;
    webkit-touch-callout: none;
    -webkit-user-select: none;
}

#left{
    width: 50px;
    border-right: 1px solid #ccc;
    float:left;
    background: black;
}

#dragger{
    width: 5px;
    float:left;
    background-color:#eee;
    cursor: col-resize;
}

#right{
    width: 100px;
    border-left: 1px solid #ccc;
    overflow:hidden;
    background: blue;
}
<div id="left" class="grid">
</div>
<div id="dragger" class="grid"></div>
<div id="right" class="grid">
</div>

You can also set a maximum width for your elements, so that they don't overflow the body. window.innerWidth gives you the current maximum width of the window.

Sign up to request clarification or add additional context in comments.

2 Comments

I was adding mouse move/up listeners to my "knob" which made the knob stop when moving outside the div. I used the pattern above: "knob" mousedown adds "window" mouse move/up. Now works awesomely. Thanks. (I almost forgot to remove the listeners. My "window" mouseup now removes "window" mouse move/up listeners.)
Can we apply this to a simple carousel? Adding the listener when mousedown executed then removing the mousemove and mousedown event listener when mouseup activated. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.