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.
Which is like how drawing a rectangle works on this website: https://awwapp.com/
You'll see that my code just appends the new div
when dragging was detected. The user then has to go back and resize.
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?
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.