Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scrolling through jQuery UI Draggables on Touch Devices Triggers Drag

I'm using jQuery UI's draggables and droppables functionality. To make it work on touch devices, I'm using jQuery UI Touch Punch.

I have a list of draggables that don't have much space around them. On touch devices, I found that the only way to scroll through the list was to use the very narrow spaces around the draggables, which isn't user friendly. I thought about adding buttons to scroll up and down, but I think that would likely feel foreign and clunky to users who are used to scrolling with swipes. I ended up with kind of a hacky workaround, but it has two issues:

  1. It takes a while before the swipe starts to scroll, which might give the false impression that the website is lagging.

  2. There is no kinetic aspect to the scrolling, so it's a lot more work to scroll than usual.

My Question

Can my code be improved to fix the above two issues or should I be taking an entirely different approach to fixing this problem?

The Code

jsFiddle demo • full screen result of jsFiddle demo

HTML

<p>Drag the colored squares into the gray area on the right.</p>

<ul>
    <li><span class="red"></span></li>
    <li><span class="orange"></span></li>
    <li><span class="yellow"></span></li>
    <li><span class="green"></span></li>
    <li><span class="blue"></span></li>
    <li><span class="purple"></span></li>
    <li><span class="red"></span></li>
    <li><span class="orange"></span></li>
    <li><span class="yellow"></span></li>
    <li><span class="green"></span></li>
    <li><span class="blue"></span></li>
    <li><span class="purple"></span></li>
    <li><span class="red"></span></li>
    <li><span class="orange"></span></li>
    <li><span class="yellow"></span></li>
    <li><span class="green"></span></li>
    <li><span class="blue"></span></li>
    <li><span class="purple"></span></li>
    <li><span class="red"></span></li>
    <li><span class="orange"></span></li>
    <li><span class="yellow"></span></li>
    <li><span class="green"></span></li>
    <li><span class="blue"></span></li>
    <li><span class="purple"></span></li>
</ul>

<div></div>

CSS

p {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    margin-bottom: 10px;
}

ul, div {
    float: left;
    height: 440px;
    background-color: #ccc;
    border: 1px solid #000;
}

ul {
    width: 127px;
    overflow-y: scroll;
    list-style: none;
}

li span {
    margin: 9px auto;
}

span {
    display: block;
    width: 100px;
    height: 100px;
    border: 5px solid #000;
}

.red {
    background-color: #f00;
}

.orange {
    background-color: #ff8000;
}

.yellow {
    background-color: #ff0;
}

.green {
    background-color: #0f0;
}

.blue {
    background-color: #00f;
}

.purple {
    background-color: #f0f;
}

div {
    width: 330px;
    margin-left: 20px;
}

div span {
    float: left;
}

JavaScript

// BEGIN: My attempt to fix the scrolling issue on touch devices

if ('ontouchstart' in document.documentElement) {
    $('span').on('dragstart', function(e) {
        if ($(this).hasClass('scroll')) {
            e.preventDefault();
        }
    }).on('mousemove', function(e) {
        if ($(this).hasClass('scroll')) {
            $('ul').scrollTop(scroll_top_on_mousedown + mousedown_coords.pageY - e.pageY);
            return false;
        }

        if (typeof(mousedown_coords) == 'object' && Math.max(
                Math.abs(mousedown_coords.pageX - e.pageX),
                Math.abs(mousedown_coords.pageY - e.pageY)
            ) >= 80
        ) {
            if (e.pageX - mousedown_coords.pageX < 70) {
                $(this).addClass('scroll');
            }
        }
    }).on('mousedown', function(e) {
        mousedown_coords = {
            'pageX': e.pageX,
            'pageY': e.pageY,
        };

        scroll_top_on_mousedown = $('ul').scrollTop();
    }).on('touchend', function() {
        $(this).trigger('mouseup'); // Android fix

        delete window.mousedown_coords;
        $('ul .scroll').removeClass('scroll');
    });
}

// END: My attempt to fix the scrolling issue on touch devices

$('span').draggable({
    distance: 90,
    helper: 'clone',
    containment: $('div')
});

$('div').droppable({
    drop: function(event, ui) {
        if ($(this).children('span').length == 12) {
            $(this).empty();
        }

        $(this).append($(ui.draggable).clone());
    }
});
like image 253
Nick Avatar asked Oct 20 '22 16:10

Nick


1 Answers

Unfortunately I think the best answer is to rethink your UI. Forcing a user to scroll over draggable elements is just going to present problems. At first I thought using jQuery's tabhold event would work to delay the draggable event but they don't want to play nice together.

like image 162
Jeff Avatar answered Oct 24 '22 01:10

Jeff