Selectable on non-list elements - javascript

I have example where I drag-drop elements to drop area. Basically all elements inside this area are cloned. I also want to implement selectable in this area, but there is a problem - how to select elements which are not part of the list?
I want to implement selectable on non-list elements. I've set
$(".ui-layout-center").selectable();
in droppable div and when I try to select area with mouse, I see lasso, like in this image:
How to select those elements? They are not part of the list, they are dropped clones.
I have example here
Code:
function setDraggable(el) {
el.draggable({
helper: 'original',
revert: false,
cursor: 'move'
});
}
function setResizable(el){
el.resizable({
});
}
$(function() {
$(".ui-layout-center").selectable();
$(".component").draggable({
helper: function() {
$clone = $(this).clone();
$clone.appendTo('body').css({'zIndex': 5});
return $clone;
},
cursor: 'copy',
containment: "document"
});
$('.ui-layout-center').droppable({
activeClass: 'ui-state-hover',
accept: '.component',
drop: function(event, ui) {
if (!ui.draggable.hasClass("dropped"))
var clone= $(ui.draggable).clone().addClass("dropped").draggable();
if(clone){
clone.css('left',ui.position.left);
clone.css('top',ui.position.top);
$(this).append(clone);
setDraggable(clone);
setResizable(clone);
}
}
});
});
CSS:
.ui-layout-center {
width: 800px;
height: 800px;
border: 1px solid black;
}
.ui-state-hover {
background-color: #f9ffff;
}
.ui-layout-center .component {
position:absolute !important;
}
.component{
width: 50px;
height: 50px;
background-color: yellow;
border: 1px solid black;
margin: 3px;
}
HTML:

Related

Set position of jquery draggable element while dragging

In my web app, there is a draggable element.
I need to set the left position of this element when the element reaches a certain limit while dragging.
Using jQuery draggable widget, I have access to the position of the element:
function drag(e, ui) {
console.log(ui.position.left);
}
Let say my left attribute is setted to 1100px, I need to set it to 500px and this, without stopping the dragging.
I have three functions: dragStart, drag, and gradEnd.
Currently, I managed to get only one result: when setting ui.position.left = 500; on the drag function (using a condition), the left position is set to 500 but of course, the element is then stuck at 500px. The reason is that every time the drag function is triggered, the left position is setted to 500.
If the code runs only once the line ui.position.left = 500; the position left attribute is set to 500, but directly reset to 1100.
How can I set the left attribute once and for all?
$("#divId").draggable({
drag: drag,
})
function drag(e, ui) {
if (ui.position.top > 50) {
ui.position.left = 100;
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I am not sure how jQuery Draggable handles things under the hood, but even after setting ui.position.left = 100, it does not register in the event until after dragging has stopped - that is why I opted to check the actual CSS property of the element that is being targeted.
I have also provided an example (closure/functional based) which demonstrates how to handle this without having to check CSS..
First example:
$("#divId").draggable({
drag: drag
});
function drag(e, ui) {
if (ui.position.top > 50) {
$("#container").css('padding-left', '100px');
$(this).css('left', '0px');
}
if (ui.position.left < 0) {
ui.position.left = 0
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
width: 300px;
cursor: grab;
}
#container {
height: 100vh;
width: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="container">
<div id="divId">
Bubble
</div>
</div>
Second example, more of a 'closure based functional approach': does not require you to check CSS..
$("#divId").draggable({
drag: drag()
});
function drag(e, ui) {
let TRIGGER = false, TOP_THRESHOLD = 50, LEFT_POSITION = 100;
return function(e, ui) {
if (TRIGGER) {
ui.position.left = LEFT_POSITION;
} else if (ui.position.top > TOP_THRESHOLD) {
TRIGGER = true;
ui.position.left = LEFT_POSITION;
}
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>

I want to drag and drop buttons and images all ui-elements and drag again the element inside canvas

i want to drag the (buttons,divs,images) and drop on to the canvas and then drag again inside the canvas. its not working properly only (divs) i can drag and drop and again start a dragging inside canvas not on buttons and other element
thanks
$(init);
function init() {
var diagram = [];
var canvas = $(".canvas");
$(".tool").draggable({
helper: "clone",
//cursor: "move",
cancel: false,
});
canvas.droppable({
drop: function(event, ui) {
console.log(ui.helper.prop("outerHTML"))
var new_signature = ui.helper.is('.ui-resizable') ?
ui.helper
:
$(ui.helper).clone().removeClass('tool ui-draggable ui-draggable-
handle ui-draggable-dragging');
$(this).append(new_signature);
new_signature.draggable({
helper: false
}).resizable()
}
});
}
this is a link of jsfiddle for further explanation
Some minor corrections you may want to consider.
JavaScript
function init() {
var diagram = [];
var canvas = $(".canvas");
$(".tool").draggable({
helper: "clone",
cancel: false,
});
canvas.droppable({
drop: function(event, ui) {
console.log(ui.helper.prop("outerHTML"));
var new_signature;
if (ui.helper.is('.ui-resizable')) {
new_signature = ui.helper;
} else {
new_signature = ui.helper.clone();
new_signature.removeClass("ui-draggable ui-draggable-handle ui-draggable-dragging");
new_signature.draggable({
helper: false,
containment: "parent"
}).resizable();
}
$(this).append(new_signature);
}
});
}
$(init);
Fiddle: https://jsfiddle.net/Twisty/0gLh2h6o/
Update
Often, it is best to avoid using draggable and resizable on some things, when there are other Click events that will be handled.
I would suggest creating a wrapper, and handle, that can be used to drag the element, and then resize upon the element.
Consider this:
HTML
<div style="width:20%;float:left;border:1px solid; height:400px">
<h6>buttons</h6>
<div>
<div class="fake tool button tool-1">Click</div>
<br/>
<div class="fake tool button tool-2">Click</div>
<hr />
</div>
</div>
<div style="width:78%;height:400px;float:right;border:1px solid;" class="canvas">
<p>
canvas
</p>
</div>
note:i want to drag these button multiple time and once it dopped inside canvas it can be draggable inside canvas and resizable
CSS
.tool-1,
.tool-2 {
width: 60px;
height: 1.5em;
border: 1px red solid;
border-radius: .2em;
text-align: center;
padding: 0.5em;
}
.tool-2 {
border: 1px green solid;
}
.canvas .tool_wrapper {
display: inline-block;
width: auto;
height: auto;
}
.canvas .tool_wrapper .tool_handle {
height: 10px;
line-height: 10px;
padding: 0;
margin: 0;
text-align: right;
}
.canvas .tool_wrapper .tool_handle .ui-icon {
margin-top: -.30em;
}
.canvas .tool_wrapper .ui-resizable-se {
margin-left: -5px;
margin-top: -5px;
}
.canvas .tool_wrapper .button {
width: 60px;
height: 1.5em;
border-radius: .2em;
text-align: center;
padding: 0.5em;
}
JavaScript
function init() {
var diagram = [];
var canvas = $(".canvas");
$(".tool").draggable({
helper: "clone",
cancel: false,
});
canvas.droppable({
drop: function(event, ui) {
console.log(ui.helper.attr("class"));
if (ui.helper.hasClass("fake")) {
var new_signature;
if (ui.helper.hasClass("button")) {
new_signature = $("<div>", {
class: "tool_wrapper ui-widget",
style: ui.helper.attr("style")
});
new_signature.css("top", (parseInt(new_signature.css("top").substr(0, -2)) - 10) + "px")
var handle = $("<div>", {
class: "tool_handle ui-widget-header"
})
.html(" ").appendTo(new_signature);
var close = $("<span>", {
class: "ui-icon ui-icon-close"
}).appendTo(handle).click(function() {
if (confirm("Are you sure you want to remove this Button?")) {
new_signature.remove();
}
});
var tool = $("<div>", {
class: ui.helper.attr("class"),
contenteditable: true
})
.html(ui.helper.html())
.appendTo(new_signature).resizable();
tool.css({
width: "60px",
height: "1.5em",
"line-height": "inherit"
});
tool.removeClass("fake ui-draggable ui-draggable-handle ui-draggable-dragging");
}
new_signature.appendTo($(this));
new_signature.draggable({
handle: ".tool_handle",
helper: false,
containment: "parent"
})
}
}
});
}
$(init);
Here, we create a div wrapper and create a handle, with a close button, to use to move the element around. This becomes our draggable, and we can place a button, div, or img inside it. This allows contenteditable to receive it's own cl;ick event and not interfere with the click event that draggable is expecting, since it will only be looking for that on the handle.
Resizable is then assigned to the element itself to ensure that we change it's size and not just the size of the wrapper.
Actually, it works. Check the background color of the a element in fiddle:
https://jsfiddle.net/jakecigar/wngwsxw2/9/
.ui-resizable {
background: red;
}
The new_signature element has position:static after it is set to draggable. It needs to be absolute.
Use Twisty's version, add this lines:
cancel: false
after containment: "parent",
and
new_signature.css({position: 'absolute'});
just before $(this).append(new_signature);
It worked in my test.

Manipulate connections between elements dropped on canvas

Here I have been able to drop elements onto a canvas and create connections between them. But every time I drag a dropped element within the canvas, the anchors do not move along with the dragged element. Instead when I try to create a connection from the isolated anchor to another element it immediately re-positions itself with its parent element. This is one issue and I would also like to delete the anchors/ connections whenever its parent element is deleted.
<!doctype html>
<html>
<head>
<script src="../lib/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="../lib/jquery-ui.min.js"></script>
<script src="../lib/jquery.jsPlumb-1.6.4-min.js"></script>
<style>
.chevron-toolbox{
position: absolute;
width: 72px;
height: 80px;
background-color: powderblue;
background-image: url("../dist/img/bigdot.png");
border: solid 3px red;
}
#dropArea{
cursor: pointer;
border: solid 1px gray;
width: 800px;
margin-left: 80px;
height: 400px;
position: relative;
overflow-x: scroll;
overflow-y: scroll;
}
.chevron {
position:absolute;
cursor:pointer;
width: 72px;
height: 80px;
background-color: powderblue;
background-image: url("../dist/img/bigdot.png");
}
</style>
</head>
<body>
<div class="chevron-toolbox" id="cId">
</div>
<div id="dropArea">
</div>
<button id="go">Double Click Me</button>
<script>
jsPlumb.ready(function(e)
{
jsPlumb.setContainer($('#dropArea'));
$(".chevron-toolbox").draggable
({
helper : 'clone',
cursor : 'pointer',
tolerance : 'fit',
revert : true
});
$("#dropArea").droppable
({
accept : '.chevron-toolbox',
containment : 'dropArea',
drop : function (e, ui) {
droppedElement = ui.helper.clone();
ui.helper.remove();
$(droppedElement).removeAttr("class");
jsPlumb.repaint(ui.helper);
$(droppedElement).addClass("chevron");
$(droppedElement).draggable({containment: "dropArea"});
$(droppedElement).appendTo('#dropArea');
setId(droppedElement);
var droppedId = $(droppedElement).attr('id');
var common = {
isSource:true,
isTarget:true,
connector: ["Flowchart"],
};
jsPlumb.addEndpoint(droppedId, {
anchors:["Right"]
}, common);
jsPlumb.addEndpoint(droppedId, {
anchors:["Left"]
}, common);
alert(droppedId);
//Delete an element on double click
var dataToPass = {msg: "Confirm deletion of Item"};
$(droppedElement).dblclick(dataToPass, function(event) {
alert(event.data.msg);
$(this).remove();
});
}
});
//Set a unique ID for each dropped Element
var indexer = 0;
function setId(element){
indexer++;
element.attr("id",indexer);
}
});
</script>
</body>
</html>
In order to properly manipulate the connections, you can use the connect method in jsPlumb placing anchors at desired points.
jsPlumb.connect({
source:'window2',
target:'window3',
paintStyle:{lineWidth:8, strokeStyle:'rgb(189,11,11 )'},
anchors:["Bottom", "Top"],
endpoint:"Rectangle"
});
This is merely an example. Following this pattern in your implementation will be useful when it comes to accessing details regarding those connections and deleting the connections alongside the elements

How do I change the placeholder like as the elements replace each other place?

How do I change the placeholder like as the elements replace each other place.
Please see the example
https://jsfiddle.net/98h31o9v/11/
JavaScript
indexOfCell = 0;
add boxes to #div element
$('#add_box').on('click', function() {
var cell = $("<div></div>");
var elementObj = cell.get(0);
$('#div').append(elementObj);
cell.addClass('content-box').attr('id', 'box_' + indexOfCell);
cell.text(indexOfCell);
indexOfCell += 1;
console.log(elementObj);
$(cell).draggable({
helper: 'original',
zIndex: 10001,
start: function(event, ui) {
if ($(this).data('placeholder') === undefined) {
$(this).data('placeholder', createPlaceholder($(this)));
}
setPlaceHolder($(this).data('placeholder'), $(this));
$(this).after($(this).data('placeholder'));
},
stop: function(event, ui) {
$(this).css('left', $(this).data('placeholder').css('left'));
$(this).css('top', $(this).data('placeholder').css('top'));
$(this).data('placeholder').after($(this));
$(this).data('placeholder').detach();
}
});
$(cell).droppable({
tolerance: 'intersect',
greedy: true,
over: function(event, ui) {
replaceTwoItem(ui.draggable.data('placeholder'), $(this));
}
});
create placeholder
function createPlaceholder(that) {
var className = that.attr('class');
var placeholder = $(document.createElement(that.get(0).nodeName))
.addClass(className || className + " ui-sortable-placeholder")
.removeClass("ui-sortable-helper").css({
background: 'yellow',
border: '1px solid grey'
});
return placeholder;
}
set the placeholder to cell
function setPlaceHolder(placeholder, cell) {
placeholder.css('width', cell.width());
placeholder.css('height', cell.height());
placeholder.css("display", 'block');
placeholder.css('position', 'absolute');
placeholder.css('top', cell.css('top'));
placeholder.css('left', cell.css('left'));
}
replace two item when drag
function replaceTwoItem(itemFrom, itemTo) {
var itemToInsert;
var action;
if (itemFrom.index() === 0) {
itemToInsert = itemFrom.parent();
action = "prepend";
} else {
itemToInsert = itemFrom.prev();
action = "after";
}
itemTo.before(itemFrom);
if (itemTo.get(0) != itemToInsert.get(0)) {
if (action == 'prepend') {
itemToInsert.prepend(itemTo);
} else if (action == 'after') {
itemToInsert.after(itemTo);
}
}
}
});
HTML
<button id="add_box">AddBox</button>
<div id="div">
</div>
CSS
.content-box {
width: 100px;
height: 100px;
background: green;
margin: 5px;
float: left;
}
After the brief discussion in the comments about your requirements I think you can get rid of most of the code you're currently using. The example on the jquery
ui website can be tweaked slightly to get what you want.
Fiddle Example
HTML:
<button id="add_box">AddBox</button>
<div id="sortable" class="ui-sortable">
</div>
JQuery:
$('#add_box').on('click', function() {
//Determine the existing child count.
var boxCount = $('#sortable').children().length;
//Create a new "box" and add it to the end of the list.
var newBox = $('<div class="ui-state-default">' + boxCount + '</div>');
$('#sortable').append(newBox);
//Invoke the sortable function to ensure the appropriate events are bound.
$("#sortable").sortable({
placeholder: "ui-state-highlight"
});
});
CSS:
The below can be cleaned up somewhat.
#sortable {
margin: 0;
padding: 0;
}
.ui-state-highlight {
background: yellow;
margin: 0 5px 5px 5px;
color: black;
float: left;
width: 100px;
height: 100px;
}
.ui-state-default {
background: green;
margin: 0 5px 5px 5px;
color: black;
float: left;
width: 100px;
height: 100px;
}
Update .ui-state-default to change the initial colour and update .ui-state-highlight to change the placeholder colour.

How can I create jQuery UI droppables recursively?

I'm using jQuery UI for drop and drag.
When the draggable item is dropped I use the drop function that appends a new HTML element and makes it draggable and droppable. It works in the first instance ( see http://jsfiddle.net/ze5zgfsq/1/ ) but the draggable + droppale features (including the drop functio) don't extend deeper than that.
I want it to work recursively, though, so that if another draggable element is dropped inside the created element (the dropped one) then a new draggable, droppable element is created within that and so on.
Here's the sample code:
$("#draggableObject").disableSelection();
$("#draggableObject").draggable({
revert: "invalid",
helper: "clone",
opacity: 0.7
});
$(".container").droppable({
accept: "#draggableObject, .droppedObject",
activeClass: "stateHighlight",
hoverClass: "stateHover",
greedy: true,
drop: function (event, ui) {
$(this).append('<li class="droppedObject" style="color:black;text-align:center;">Dropped Object</li>');
$(".droppedObject").draggable({
revert: "invalid",
helper: "clone",
opacity: 0.7
}).droppable({
accept: "#draggableObject, .droppedObject",
activeClass: "stateHighlight",
hoverClass: "stateHover",
greedy: true,
drop: function (event, ui) {
$(this).append('<li class="droppedObject" style="color:black;text-align:center;">Dropped Object</li>');
$(".droppedObject").draggable({
revert: "invalid",
helper: "clone",
opacity: 0.7
});
}
});
}
});
And here's the HTML/CSS:
<ul>
<li id="draggableObject">Draggable Object</li>
</ul>
<ul class="container">
<li>Drop Items Here</li>
</ul>
ul {
height: 300pt;
width: 200pt;
border: 1pt solid blue;
border-radius: 2pt;
}
li {
display: block;
min-height: 100pt;
min-width: 100pt;
border: 1pt solid black;
border-radius: 2pt;
margin: 2pt;
cursor: move;
text-align: center;
}
I came across your question while trying to implement something similar. See if this helps:
http://jsfiddle.net/sdqfotqe/1/
The trick I used is to create the options object separately then use it inside itself i.e. $d.droppable(droppableOptions);
It doesn't do exactly what you are trying to do, but should help with the recursive side of things.
HTML:
<div id="divItems">
<div data-fhirq-type="group" class="editor-choice">Group</div>
<div data-fhirq-type="question" class="editor-choice">Question</div>
</div>
<br/><br />
<div id="divQuestionnaire">
<div id="divRootGroup" class="editor-group"></div>
</div>
CSS:
.editor-group {
border: 1px solid #000;
min-height: 50px;
width:100%;
padding:20px;
background: #efefef;
}
.editor-question {
border: 1px solid #000;
min-height: 50px;
width:100%;
padding:20px;
background: #677b92;
}
.editor-choice {
cursor:move;
width: 100px;
height: 75px;
background: #ccc;
display:inline-block;
}
.droppable-hover {
background: #fffa00;
}
.remove-choice {
width:25px;
height:25px;
border: 1px solid #ddd;
}
JavaScript:
$(document).ready(function () {
$('#divGroupOptions').hide();
$('#divQuestionOptions').hide();
var droppableOptions = {
accept: '.editor-choice',
greedy: true, /* only drop the element in one place */
hoverClass: "droppable-hover", /* highlight the current drop zone */
drop: function (event, ui) {
/* clone, because many elements can be added - it's a copy, not a move */
$d = $(ui.draggable).clone();
$d.removeClass('editor-choice');
$d.addClass(($d.attr('data-fhirq-type') == 'group') ? 'editor-group' : 'editor-question');
/* add a button so the element can be removed if no longer necessary */
var $removeBtn = $('<button class="remove-choice">x</button>').click(function () { $(this).parent().remove(); });
$d.append($removeBtn);
/* make the new element droppable i.e. to support groups within groups etc... */
$d.droppable(droppableOptions).sortable();
$(this).append($d);
}
};
$("#divRootGroup").droppable(droppableOptions).sortable();
$(".editor-choice").draggable({
helper: 'clone'
});
});

Categories