0

I have a page whereby in order to create a new resizable/draggble div the user clicks anywhere on a canvas and it appears next to where the click event occurred.

Once the new element has appeared the user can then resize or drag it around.

A better user experience would be to allow the user to mousedown, drag the new div to the desired size and then mouseup to finish creation. E.g.

What I want

Which is like how drawing a rectangle works on this website: https://awwapp.com/

Click and drag to resize

What I have

You'll see that my code just appends the new div when dragging was detected. The user then has to go back and resize.

enter image description here

I haven't found much in general when researching using jQuery to detect dragging, apart from this but even this example is very much click OR drag when I require click AND drag.

My code, condensed for brevity is currently:

function newPlaceholderPosition(posX, posY, X, Y) {
    cssTop = (Y - posY);
    cssLeft = (X - posX);

    var styles = [
        "top: "+ Math.round(cssTop / 10) * 10 +"px;",
        "left: "+ Math.round(cssLeft / 10) * 10 +"px;"
    ].join(' ');

    return styles.toString();
}

function makePlaceholdersFunctional(elements) {
    elements.resizable({
        containment: "parent",
        handles: 'ne, se, sw, nw',
        minWidth: 100,
        minHeight: 40,
        autoHide: true,
    });

    elements.draggable({
        containment: "parent",
        drag: function() {
            $("body").addClass("element-moving");
        },
        stop: function() {
            $("body").removeClass("element-moving");    
        }
    });
}

var isDragging = false;

$(".canvas")
.mousedown(function(e) {
    isDragging = false;
    // Log where the click took place
    clickLocation = newPlaceholderPosition($(this).offset().left, $(this).offset().top, e.pageX, e.pageY);
})
.mousemove(function(e) {
    // If the user is not dragging an existing div
    if(!$('.canvas').hasClass("child-active")) {
        isDragging = true;  
    }
})
.mouseup(function() {
    var wasDragging = isDragging;
    isDragging = false;
    if (!wasDragging) {
        // console.log("You weren't dragging on the canvas")
    } else {
        // console.log("You WERE dragging on the canvas")
        $(".canvas").append('<div class="resizable" data-id="' + parseInt( $(".resizable").length + 1) + '" style="'+ clickLocation +'"></div>');
        makePlaceholdersFunctional($(".resizable:last"));
    }
});

Is something like this possible using jQuery UI? Could someone provide an example?

dom_ahdigital
  • 1,651
  • 18
  • 37
  • What do you mean from _I require click AND drag_? I don't understand your issue exactly. – Ali Soltani Apr 13 '18 at 12:30
  • The new element should appear and be resizable from the bottom right corner whilst the user is holding the mouse click down. It is not enough to just determine that the user was dragging and therefore append a `div`. Go to https://awwapp.com/ and draw a rectangle - this is what I am trying to do. – dom_ahdigital Apr 13 '18 at 13:36
  • @dom_ahdigital do you want to use resizable to draw the `
    ` before it's added to DOM or is the `
    ` created and then you want the user to be able to resize it?
    – Twisty Apr 13 '18 at 15:30
  • @dom_ahdigital not done yet, but here is an alternative https://jsfiddle.net/Twisty/42zeudf6/ – Twisty Apr 14 '18 at 17:12
  • Sorry for the delay. Yes, requirement is to draw the `div` before it's added to the DOM. – dom_ahdigital Apr 16 '18 at 06:49

2 Answers2

1

Based on the limited information provided, you can make this work, just maybe not the way you expected. It is not something that is a feature of jQuery UI, yet you can leverage the various tools to make something.

Using Selectable, you can capture the mouse points at Start and Stop. This can be used to give you 2 points in the rectangle. It does not require any elements in play and then dynamically, you can create the draggable and resizable element.

Example: https://jsfiddle.net/Twisty/42zeudf6/16/

JavaScript

$(function() {
  var toolFunction = null;
  var action = null;

  function calcBoxDim(x1, y1, x2, y2) {
    var dim = {};
    dim.width = x2 - x1;
    dim.height = y2 - y1;
    dim.top = y1;
    dim.left = x1;
    dim.right = x2;
    dim.bottom = y2;
    dim.center = [x1 + (dim.width / 2), y1 + (dim.height / 2)];
    return dim;
  }

  function makeCanvasDrag($o) {
    $o.draggable({
      containment: $(".canvas")
    });
  }

  function makeCanvasResize($o) {
    $o.resizable({
      containment: $(".canvas")
    });
  }

  function makeRect(x1, y1, x2, y2, ev) {
    var box = calcBoxDim(x1, y1, x2, y2);
    var rect = $("<div>", {
      id: "rect-" + ($(".canvas .rectangle").length + 1),
      class: "draw rectangle move resize"
    }).appendTo($(".canvas")).css({
      width: box.width + "px",
      height: box.height + "px",
      top: (box.top - $(".canvas").offset().top) + "px",
      left: (box.left - $(".canvas").offset().left) + "px",
      position: "absolute"
    });
    return rect;
  }
  $(".tools button").button({
    showLabel: false,
    icon: "none"
  });
  $(".rect").button("option", "icon", "far fa-square").click(function() {
    toolFunction = "rect";
    action = "draw";
    $(".canvas").selectable({
      start: function(e) {
        $(".canvas").data("drawRectMouseDown", e);
      },
      stop: function(e) {
        var down = $(".canvas").data("drawRectMouseDown");
        var up = e;
        makeRect(down.pageX, down.pageY, up.pageX, up.pageY, e);
        makeCanvasDrag($(".canvas .move"));
        makeCanvasResize($(".canvas .resize"));
        toolFunction = null;
        action = null;
      }
    });
  });
  $(".select").button("option", "icon", "fas fa-mouse-pointer")
});

This example uses FontAwesome, but you can use jQuery UI Icons or your own graphics.

I suspect you will end up making a lot of functions that are tied to buttons and events. The tool buttons then populate globals that let the user make use of those tools in the work area.

We have a function that calculates the dimensions based on 2 points. We then have another function that makes the rectangle based on those dimensions. I added a lot of dimensions in case you need to use this function for other shapes. I kept it separate from the maker function in case you are storing all the canvas details someplace and have to redraw the canvas later. If you're pulling the dimensions from a DB and not calculating them from user actions, then it makes sense to keep those functions separate. Otherwise you could combine them.

Hope that help.

Twisty
  • 30,304
  • 2
  • 26
  • 45
-3

NO it's not - that is impossible.