21

I'm trying to build a jQuery plugin that allows you to drag and draw a rectangle (or a div with a border) but I'm not sure how to do it. I don't know of any that currently have this ability so I don't know where to look for an example of how to do this.

How can I implement drag and draw in jQuery?

Andrew
  • 227,796
  • 193
  • 515
  • 708

2 Answers2

51

The basics for something like this are quite simple, when you think about it:

  • Listen for mousedown events on some container (possible the entire document);
    • Place an absolutely positioned element at the position of the mouse, using the mouse coordinates from the event object (e.pageX and e.pageY);
    • Start listening to mousemove events to change the width and height object (based on the mouse coordinates);
  • Listen for the mouseup event to detach the mousemove event listener.

The aforementioned absolute placed element is, e.g., a <div> with a border and background: transparent.

Update: here is an example:

$(function() {
    var $container = $('#container');
    var $selection = $('<div>').addClass('selection-box');

    $container.on('mousedown', function(e) {
        var click_y = e.pageY;
        var click_x = e.pageX;

        $selection.css({
          'top':    click_y,
          'left':   click_x,
          'width':  0,
          'height': 0
        });
        $selection.appendTo($container);

        $container.on('mousemove', function(e) {
            var move_x = e.pageX,
                move_y = e.pageY,
                width  = Math.abs(move_x - click_x),
                height = Math.abs(move_y - click_y),
                new_x, new_y;

            new_x = (move_x < click_x) ? (click_x - width) : click_x;
            new_y = (move_y < click_y) ? (click_y - height) : click_y;

            $selection.css({
              'width': width,
              'height': height,
              'top': new_y,
              'left': new_x
            });
        }).on('mouseup', function(e) {
            $container.off('mousemove');
            $selection.remove();
        });
    });
});

Demo: http://jsbin.com/ireqix/226/

  • 5
    For the sake of anyone following along, I updated your answer with the solution to the dragging in different directions. – Andrew Jan 17 '12 at 04:22
  • 2
    And I needed something just like this for a quick html image mapper (rectangles only suited my needs). Incorporates the drag-both-ways change as above, and outputs html image-map source. http://jsbin.com/ireqix/91 – frumbert Oct 16 '12 at 05:46
  • When you moving the selection box around quickly (but still within the document area) the origin position seems to get messed up sometimes, but when you continue moving it seems to pop back to the correct location. For example, if you move back and forth right/left, eventually the origin location gets offset. Any idea why this happens? – chinabuffet Feb 17 '13 at 14:23
  • I think the problem is that the x position (but the same applies to the y coordinate as well) is adjusted left when the mouse moves left of the origin, but is never adjusted back to the right when the mouse moves right again. Putting an else clause that sets the x position back to the original `click_x` seems to resolve this. – chinabuffet Feb 17 '13 at 15:52
  • @chinabuffet You're absolutely right. I rewrote the code slightly to circumvent the issue. Thanks for the heads-up! – Peter-Paul van Gemerden Feb 17 '13 at 17:01
  • This kind of thing (community collaboration) is why I still love SO – mtyson Jan 13 '14 at 20:54
  • jsbin demos not working anymore - getting `ReferenceError: Can't find variable: $` errors in the console. Running locally on my dev machine and local browser works. Note also that `mouseup` events are not removed and pile up so a call to `$container.off('mouseup');` is also needed. [improved jsbin here](https://jsbin.com/hanopen/edit?html,js,console,output) – abulka Jun 12 '20 at 00:51
  • ummm... jsbin is a buggy nightmare - here is the working code on jsfiddle https://jsfiddle.net/tcab/hay4op0t/ note I have extracted the box calculation function so that the box can be reported on the mouseup. Also I untangled the chained handlers into separate functions which I think is clearer to understand. – abulka Jun 12 '20 at 01:09
0
$("#YOUR_ELEMENT_ID").on("mousedown", function (e) {
    var click_x = e.pageX;
    var click_y = e.pageY;

    /* Posição do objeto */
    var x = parseFloat($(this).css("left").replace("px", "")),
        y = parseFloat($(this).css("top").replace("px", ""));
    /* Calcula distância no eixo x */
    var distanc_x = Math.abs(x - click_x);
    var distanc_y = Math.abs(y - click_y);

    $("#YOUR_ELEMENT_ID")
        .on("mousemove", function (e) {

            var new_x = e.pageX - distanc_x;
            var new_y = e.pageY - distanc_y;

            $(this).css({
                top: new_y,
                left: new_x,
            });

        }).on("mouseup", function (e) {
        $(this).off("mousemove");
    });

});
temp
  • 1