Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing / altering a jQuery UI drag event

I'd like users to be able to drag a horizontal menu bar left and right. I realize there are lots of carousel and slider libraries which have this behavior– but none of them fit the situation.

When users drag an LI, can it pass the new x-offset information to the left margin of the first LI?

I took a stab at it here: http://jsfiddle.net/n92ng9uz/

The main problem with the above fiddle, is that the offset is still applied to the individual LI, and if I prevent the event from bubbling up the dragging is no longer smooth.

like image 822
rob-gordon Avatar asked Sep 08 '15 10:09

rob-gordon


2 Answers

Since you specified in the comments that it's a requirement to use margin-left on the first li element, and not modify the position of the ul, I am pretty sure that it can't be easily done using jQuery UI draggable. If we were to make the li draggable, we wouldn't catch mouse events on the other lis, and if we were to make the ul draggable, we couldn't easily make it affect only the margin-left of the first li and not the position of the ul.

Here is a live demo of a solution that uses mouse events directly instead of using jQuery UI:

var firstLI = $('li:first-child');

var initx = 0;
var dragstartx = 0;
var dragging = false;

$("ul").mousedown(function(e) {
    dragging = true;
    dragstartx = e.pageX;
    initx = parseInt(firstLI.css("marginLeft"), 10);
});

$("ul").mousemove(function(e) {
    if (dragging) {
        firstLI.css("marginLeft", (initx + e.pageX - dragstartx) + "px");
    }
});

$("ul").mouseleave(function(e) {
    dragging = false;
});

$("ul").mouseup(function(e) {
    dragging = false;
});
ul {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

ul > li {
    display: inline-block;
    padding: 10px;
}

ul > li:nth-child(odd) {
    background: orangered;
}

ul > li:nth-child(even) {
    background: gold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
    <li>Link 1</li>
    <li>Link 2</li>
    <li>Link 3</li>
    <li>Link 4</li>
    <li>Link 5</li>
    <li>Link 6</li>
    <li>Link 7</li>
    <li>Link 8</li>
    <li>Link 9</li>
    <li>Link 10</li>
</ul>

JSFiddle Version: https://jsfiddle.net/n92ng9uz/2/

like image 195
Maximillian Laumeister Avatar answered Nov 17 '22 19:11

Maximillian Laumeister


EDIT: Nevermind... figured it out... You need to move each item left by the position difference. I think this is what you are after: http://jsfiddle.net/xwesf1Lt/. Tell me if I'm wrong. Note that I changed the diff variable to just the left position.

Also, instead of altering the margin, we alter the left attribute.

var firstLI = $('ul:first-child')[0];
firstLI.style.marginLeft = 0;

$('li').draggable({
    axis: 'x',
    drag: function(e, ui) {
        var diff = ui.position.left;
        console.log(diff);
        var currentLeft = parseInt(firstLI.style.marginLeft, 10);
        var offset = currentLeft + diff + 'px';
        //firstLI.style.marginLeft = diff;
        //  to drag all of them:

        $("li").each(function(index) {
            $(this).css("left", offset);
        });

        // with this enabled, can only be moved 1px at a time..?
        // e.preventDefault();
    }
});
like image 20
IAMZERG Avatar answered Nov 17 '22 20:11

IAMZERG