4

I'm trying to build a draggable column based layout in JavaScript and having a bit of hard time with it.

The layout comprises of 3 columns (divs), with two dragable divs splitting each. The idea is that they are positioned absolutely and as you drag the draggers, the columns' respective widths, and left values are updated.

The three columns should always span the full width of the browser (the right most column is 100% width), but the other two should remain static by default when the browser is resized (which is why i'm using px, not %).

My code isn't working as of yet, I'm relatively new to JavaScript (which is why I don't want to use jQuery).

Having said that, there must be a more efficient (and cleaner) way of achieving this with less code that works (without reaching for the $ key).

If anyone with some awesome JS skills can help me out on this I'd be super-appreciative.

Here's the fiddle I'm working on http://jsfiddle.net/ZFwz5/3/

And here's the code:

HTML

<!-- colums -->
<div class="col colA"></div>
<div class="col colB"></div>
<div class="col colC"></div>

<!-- draggers -->
<div class="drag dragA" style="position: absolute; width: 0px; height: 100%; cursor: col-resize; left:100px;"><div></div></div>
<div class="drag dragB" style="position: absolute; width: 0px; height: 100%; cursor: col-resize; left: 300px;"><div></div></div>

CSS:

body {
overflow:hidden;
}
.col {
    position: absolute;
    height:100%;
    left: 0;
    top: 0;
    overflow: hidden;
}
.colA {background:red;width:100px;}
.colB {background:green; width:200px; left:100px;}
.colC {background:blue; width:100%; left:300px;}

.drag > div {
background: 0 0;
position: absolute;
width: 10px;
height: 100%;
cursor: col-resize;
left: -5px;
}

and my terrible JavaScript:

//variabe columns 
var colA = document.querySelector('.colA');
var colB = document.querySelector('.colB');
var colC = document.querySelector('.colC');

//variable draggers
var draggers = document.querySelectorAll('.drag');
var dragA = document.querySelector(".dragA");
var dragB = document.querySelector(".dragB");
var dragging = false;

function drag() {
        var dragLoop;
        var t = this;
        var max;
        var min;
    if (dragging = true) {

        if (this == dragA) {
            min = 0;
            max = dragB.style.left;
        } else {
            min = dragA.style.left;
            max = window.innerWidth;
        }

        dragLoop = setInterval(function () {
            var mouseX = event.clientX;
            var mouseY = event.clientY;
            if (mouseX >= max) {
                mouseX = max;
            }
            if (mouseY <= min) {
                mouseY = min;
            }
            t.style.left = mouseX;
            updateLayout();
        }, 200);
    }
}
function updateLayout() {
        var posA = dragA.style.left;
        var posB = dragB.style.left;
        colB.style.paddingRight = 0;

        colA.style.width = posA;

        colB.style.left = posA;
        colB.style.width = posB - posA;

        colC.style.left = posB;
        colC.style.width = window.innerWidth - posB;
}


for (var i = 0; i < draggers.length; i++) {
    draggers[i].addEventListener('mousedown', function () {
    dragging = true;
    });                                
    draggers[i].addEventListener('mouseup', function () {
        clearInterval(dragLoop);
        dragging = false;
    });
    draggers[i].addEventListener('mouseMove', function () {
        updateLayout();
        drag();
    });
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
user3143218
  • 1,738
  • 5
  • 32
  • 48

2 Answers2

1

I see a couple of things wrong here. First of all, the mousemove event only fires on an element when the mouse is over that element. You might have better luck registering a mousemove listener on the parent of your div.drag elements, then calculating the mouse's position inside that parent whenever a mouse event happens, then using that position to resize your columns and your draggers.

Second, I'm not quite sure what you're trying to do by registering a function with setInterval. You're doing pretty well with registering event listeners; why not continue to use them to change the state of your DOM? Why switch to a polling-based mechanism? (and the function you pass to setInterval won't work anyway - it refers to a variable named event, which in that context is undefined.)

Dan O
  • 6,022
  • 2
  • 32
  • 50
  • Thanks for the comments Dan. Much appreciated. I fond this http://stackoverflow.com/questions/8960193/how-to-make-html-element-resizable-using-pure-javascript which might be helpful as well. – user3143218 May 23 '14 at 17:02
1

This is just a little example... I hope it can help you :)

window.onload = function() {    

var myDiv = document.getElementById('myDiv');

function show_coords(){
var monitor = document.getElementById('monitor');
var x = event.clientX - myDiv.clientWidth / 2;
var y = event.clientY - myDiv.clientWidth / 2;
monitor.innerText = "X: " + x + "\n" + "Y: " + y;
myDiv.style.left = x + "px";
myDiv.style.top = y + "px";
}

document.onmousemove = function(){
    if(myDiv.innerText == "YES"){show_coords();}
}

myDiv.onmousedown = function(){
    myDiv.innerText = "YES";
}
myDiv.onmouseup = function(){
    myDiv.innerText = "NO";
}

}


jsFiddle

neoDev
  • 2,879
  • 3
  • 33
  • 66