Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect a double-click-drag in Javascript/jQuery

I'd like to detect in a web page when the user selects some text by dragging. However, there's one scenario in Windows which I'm calling a "double-click-drag" (sorry if there's already a better name I don't know) and I can't figure out how to detect it. It goes like this:

  1. press mouse button
  2. quickly release mouse button
  3. quickly press mouse button again
  4. drag with the button held down

This causes the dragging to select whole Words. It's quite a useful technique from the user perspective.

What I'm trying to do is tell the difference between a double-click-drag and a click followed by a separate drag. So when I get to step 2 I will get a click event but I don't want to treat it as a click yet; I want to see if they're about to immediately do step 3.

Presumably Windows detects this on the basis of the timing and how much the mouse has moved between step 2 and 3, but I don't know the parameters it uses so I can't replicate the windows logic. note that even if the mouse doesn't move at all between step 2 and 3, I still get a mousemove event.

I realise that I should be designing interfaces that are touch-friendly and device-neutral, and I have every intention of supporting other devices, but this is an enterprise application aimed at users on windows PCs so I want to optimize this case if I can.

like image 850
Andy Avatar asked Jan 30 '14 13:01

Andy


1 Answers

We've done something similar. Our final solution was to create a click handler that suppressed the default response, and then set a global variable to the current date/time. We then set another function to fire in some 200ms or so that would handle the "click" event. That was our base function.

We then modified it to look at the global variable to determine when the last click occured. If it's been less than 200ms (modify based on your needs) we set a flag that would cause the click handler to fizzle and called a double click handler.

You could extend that approach by having your click and double click handlers manually fire the drag functionality.

I don't have access to the aforementioned code right now, but here is an example of that framework being used to track keyboard clicks to determine if a scanner or user has finished typing in a field:

    var lastKeyPress    = loadTime.getTime();

    // This function fires on each keypress while the cursor is in the field.  It checks the field value for preceding and trailing asterisks, which
    // denote use of a scanner.  If these are found it cleans the input and clicks the add button.  This function also watches for rapid entry of keyup events, which 
    // also would denote a scanner, possibly one that does not use asterisks as control characters.
    function checkForScanKeypress() {
        var iVal = document.getElementById('field_id').value;

        var currentTime = new Date()
        var temp        = currentTime.getTime();
        if (temp - lastKeyPress < 80) {
            scanCountCheck = scanCountCheck + 1;
        } else {
            scanCountCheck = 0;
        }
        lastKeyPress    = currentTime.getTime();
    }


    // The script above tracks how many successive times two keyup events have occurred within 80 milliseconds of one another.  The count is reset
    // if any keypress occurs more than 80 milliseconds after the last (preventing false positives from manual entry).  The script below runs
    // every 200 milliseconds and looks to see if more than 3 keystrokes have occurred in such rapid succession.  If so, it is assumed that a scanner
    // was used for this entry.  It then waits until at least 200 milliseconds after the last event and then triggers the next function.
    // The 200ms buffer after the last keyup event insures the function is not called before the scanner completes part number entry.
    function checkForScan() {
        var currentTime = new Date();
        var temp        = currentTime.getTime();
        if (temp - lastKeyPress > 200 && scanCountCheck > 3) {
            FiredWhenUserStopsTyping();
            scanCountCheck = 0;
        }
        setTimeout(checkForScan, 200);
    }

Here is some code that I just wrote up based upon the above ideas. It's not tested and doesn't contain the actual drag events, but should give you a good starting point:

    var lastClick   = loadTime.getTime();

    function fireOnClickEvent(event) {
        event.preventDefault;

        var currentTime = new Date()
        var temp        = currentTime.getTime();
        if (temp - lastClick < 80) {
            clearTimeout(tf);
            doubleClickHandler();
        } else {
            tf          = setTimeout(singleClickHandler, 100);
        }
        lastClick       = currentTime.getTime();
    }

    function singleClickHandler() {
        // Begin normal drag function
    }

    function doubleClickHandler() {
        // Begin alternate drag function
    }
like image 193
Nicholas Avatar answered Sep 30 '22 15:09

Nicholas