im trying to develop a game using jquery drag and drop and need help on it. The problem i am facing is that there are 4 drop location and about 25 dragable elements. Each drop location can have only one draggable element and if i try to drop another element the location should be swapped and previously dropped element will get the initial location of newly dragged element.
$(".drag").draggable({
containment: ".dropable",
revert: "invalid",
appendTo: '.dropable',
start: function (evt, ui) {
if (!ui.helper.data("originalPosition")) {
ui.helper.data("originalPosition", ui.originalPosition)
}
}
});
$(".debit_option").droppable({
greedy: true,
accept: '.drag',
over: function () {
$(this).removeClass('out').addClass('hoverClass')
},
out: function () {
$(this).removeClass('hoverClass').addClass('out')
},
drop: function (event, ui) {}
});
$(".credit_option").droppable({
over: function () {
$(this).removeClass('out').addClass('hoverClass')
},
out: function () {
$(this).removeClass('hoverClass').addClass('out')
},
drop: function (event, ui) {}
})
});
function revertDraggable($selector) {
$selector.each(function () {
var $this = $(this);
console.log($this.data('originalPosition'));
position = $this.data('originalPosition');
if (position) {
$this.animate({
left: position.left,
top: position.top
}, 500, function () {
$this.data("orignalPosition", null)
})
}
})
}
$(".no_entry a").click(function (e) {
e.preventDefault();
revertDraggable($(".drag"))
});
Related
we trying to integrate multiple drggable and droppable. we are using sortable for ease of clone functionality in this scenario. draggable once dropped need to be draggable again.
how do we limit sortable to receive only one element and revert to original if more than one dropped onto it.
look like out and over functions of sortable are misbehaving in that case.
commented line code is for disabling dropping second element on sortable. which is not working as expected.
Two issues when you enable my commented code:
draggable clone not reverting to original place after moving out of droppable.
draggable element moved from one droppable to another reverting to draggable's original place.
For a demonstration, see this jsfiddle
script:
// jQuery.noConflict();
jQuery( document ).ready(function() { init();});
function init() {
var mouse_button = false;
jQuery('.ui-draggable').live({
mousedown: function () {
mouse_button = true;
},
mouseup: function () {
if (jQuery(this).attr('data-pos') == 'out' && jQuery(this).attr('data-id')) {
var p = jQuery('#' + jQuery(this).attr('data-id'));
var offset = p.offset();
jQuery(this).hide();
jQuery(this).animate({ left: offset.left, top: offset.top, width: jQuery(this).width, height: jQuery(this).height }, 100, function () {
jQuery(this).remove();
$( ".ui-droppable" ).each(function() {
if($(this).children().length == 0) {
$( this ).removeClass("dontDrop");
}
});
//if(p[0].hasAttribute("draggable"))
p.draggable("enable");
// $('.ui-droppable').sortable('option', 'connectWith',$('.ui-droppable').not('.dontDrop'));
// $('.ui-draggable').draggable('option', 'connectToSortable',$('.ui-droppable').not('.dontDrop'));
});
}
mouse_button = false;
},
mouseout: function () {
if (mouse_button) {
mouse_button = false;
}
}
});
jQuery( '.ui-draggable' ).draggable( {
cursor: 'move',
helper: 'clone',
connectToSortable: ".ui-droppable",
revert: function (event, ui) {
}
} );
jQuery(".ui-droppable").sortable({
cursor: "move",
connectWith: ".ui-droppable",
receive: function (event, ui) {
if($(this).children().length >= 1) {
$(this).children().addClass('filled');
$(this).addClass('dontDrop');
$( ".ui-droppable" ).each(function() {
if($(this).children().length == 0) {
$( this ).removeClass("dontDrop");
}
});
// $('.ui-droppable').sortable('option', 'connectWith',$('.ui-droppable').not('.dontDrop'));
// $('.ui-draggable').draggable('option', 'connectToSortable',$('.ui-droppable').not('.dontDrop'));
}else {
$(this).children().removeClass('filled');
}
if (jQuery(this).data().sortable.currentItem) {
jQuery(this).data().sortable.currentItem.attr('data-id', jQuery(ui.item).attr("id"));
// if(jQuery(ui.item)[0].hasAttribute("draggable"))
jQuery(ui.item).draggable("disable");
}
},
out: function (event, ui) { if (ui.helper) { ui.helper.attr('data-pos', 'out'); } },
over: function (event, ui) { ui.helper.attr('data-pos', 'in'); }
});
}
Here's a working example: click here
You can user Jquery's draggable and droppable interactions to achieve what you want. Check the working example.
$(document).ready(function () {
$(".ui-draggable").draggable(draggable_options) //make cards draggable
$(".ui-droppable").droppable({ //handle card drops
greedy: true,
drop: function (event, ui) {
handleDrop(this, event, ui)
},
accept: function () {
return checkIfShouldAcceptTheDraggable(this)
}
})
})
You can do it like this:(Online Demo (fiddle))
var draggable_options = {
helper: 'clone',
cursor: 'move',
revert: 'invalid',
};
$(".ui-draggable").draggable(draggable_options);
$(".ui-droppable").droppable({
drop: function(event, ui) {
var $item = ui.draggable;
$item.draggable(draggable_options)
$item.attr('style', '')
$(this).append($item)
},
accept: function() {
return $(this).find("li").length === 0 // Your condition
}
});
$(".textToImageRightPanel").droppable({
drop: function(event, ui) {
var $item = ui.draggable;
$item.draggable(draggable_options);
$item.attr('style', '');
// Return to older place in list
returnToOlderPlace($item);
}
});
// Return item by drop in older div by data-tabidx
function returnToOlderPlace($item) {
var indexItem = $item.attr('data-tabidx');
var itemList = $(".textToImageRightPanel").find('li').filter(function() {
return $(this).attr('data-tabidx') < indexItem
});
if (itemList.length === 0)
$("#cardPile").find('ul').prepend($item);
else
itemList.last().after($item);
}
Determining when to revert may be best done in .draggable() using revert: function(){}.
Function: A function to determine whether the element should revert to its start position. The function must return true to revert the element.
You can do this:
jQuery('.ui-draggable').draggable({
cursor: 'move',
helper: 'clone',
connectToSortable: ".ui-droppable",
revert: function(item) {
if (!item) {
return true;
} else {
if (item.hasClass("dontDrop")) {
return true;
}
}
return false;
}
});
the revert function is passed false if the draggable item is not accepted. For example, if it is dropped on something that is not a target. If the draggable item is accepted, a jQuery Object is passed back.
See more: jQueryUI sortable,draggable revert event
The logic is a little confusing. If what is passed back is false, we return true to revert letting draggable revert the item to it's position. If what is passed back is not false, then it's an object we can test. If the target is "full", we revert. Otherwise we do not revert.
Sortable still wants add the item for some reason. May need to adjust to update and clear out any items that are not class "filled".
Fiddle: https://jsfiddle.net/Twisty/7mmburcx/32/
Is there a way how to add listener "droppable" to element, which is actually hovered while dragging "draggable" element?
I've tried this, but it does not work.
$("#draggable span.item").draggable({
helper: "clone",
drag: function(event, ui) {
var pos = ui.position;
var element = document.elementFromPoint(pos.left, pos.top);
$(element).droppable({
classes: {
"ui-droppable-hover": "hover"
},
drop: function(event, ui) {
console.log('dropped');
}
});
}
});
I am trying this because I need apply "droppable" to many elements and classic way via jQuery $("#droppable span.item").droppable(); is very slow in this case. So I would like to init "droppable" listener only for elements, which are hovered while dropping.
did you try this
$(document).ready(function() {
var $dragging = null;
$(document.body).on("mousemove", function(e) {
if ($dragging) {
$dragging.offset({
top: e.pageY,
left: e.pageX
});
}
});
$(document.body).on("mousedown", "div", function (e) {
$dragging = $(e.target);
});
$(document.body).on("mouseup", function (e) {
$dragging = null;
});
});
I have number of drop areas $('.drophere') and a storage of draggables $('.dragme').
Each drop area can contain just one dropped item.
You can drop new item over dropped one (replace). You can drag an item from one drop area to other.
If you start drag an item from drop area and decided drop it back to same area - drop event is not fired, thus the dragged item is lost.
Here is simplified code:
var draggedData;
$('.drophere').droppable({
drop: function (event, ui) {
$(this).attr('data-text', draggedData);
$(this).draggable('enable');
}
}).draggable({
disabled: true,
helper: "clone",
start: function (event, ui) {
draggedData = $(this).attr('data-text');
$(this).attr('data-text', "").draggable('disable');
}
});
$('.dragme').draggable({
helper: "clone",
start: function (event, ui) {
draggedData = $(this).attr('data-text');
}
});
Is it some kind of restriction in jQuery UI droppable? Is any way to "forget" the origins of such dragged item? Thank you.
just added: http://jsfiddle.net/gpnpwwbw/
Taking advantage of jQuery Draggables Stop event I came up with the following solution:
var draggedData,
dropLastDragged
startPosData = {};
function checkIntersect(posData){
var left = startPosData.left,
top = startPosData.top,
right = startPosData.left+startPosData.width,
bottom = startPosData.top+startPosData.height,
cornerLeftPos = posData.left,
cornerTopPos = posData.top;
cornerLeftPos += startPosData.width/2;
cornerTopPos += startPosData.height/2;
if((cornerLeftPos > left && cornerLeftPos < right) && (cornerTopPos > top && cornerTopPos < bottom)){
return true;
}
return false;
}
$('.drophere').droppable({
drop: function (event, ui) {
dropLastDragged = false;
$(this).html(draggedData);
$(this).draggable('enable');
}
}).draggable({
disabled: true,
helper: "clone",
start: function (event, ui) {
startPosData.left = ui.offset.left;
startPosData.width = $(this).width();
startPosData.top = ui.offset.top;
startPosData.height = $(this).height();
draggedData = $(this).html();
$(this).html('Drop here').draggable('disable');
dropLastDragged = this;
},
stop: function(event, ui) {
if(dropLastDragged){
if(checkIntersect(ui.offset)){
$(dropLastDragged).html(ui.helper.html());
$(dropLastDragged).draggable('enable');
}
}
}
});
$('.dragme').draggable({
helper: "clone",
start: function (event, ui) {
draggedData = $(this).html();
}
});
Fiddle
I will simplify my explanation so you get what I am doing. I have two div's and I set up portlets as shown here, however I am dynamically injecting my portlets, no big problem there.
<div id="mainallapplicant" class="myrow"></div>
<div id="contingent_right" class="myrow"></div>
Here is the JavaScript
$( ".myrow" ).sortable({
connectWith: ".myrow",
revert: true,
beforeStop: function( event, ui ) {}
});
I am trying to allow a maximum of only one droppable into mainallapplicant. If there is one already there, I will show a confirmation dialog and depending on the answer, I cancel the drop or move out the existing item and replace it with the new item. I tried the following but I am getting nowhere.
$( ".myrow" ).sortable({
connectWith: ".myrow",
revert: true,
start: function(event, ui) {
if ($(this).prev().find(".portlet").length == 1) {
ui.sender.draggable("cancel");
}
},
stop: function(event, ui) {
if ($(this).prev().find(".portlet").length == 1) {
ui.item.remove();
// Show an error...
}
}
});
You can use start to get the current count of portlet elements, then use stop to do the checking
Also notice I added class names to each div to allow only one div to have a maximum of 1 portlet
$(document).ready(function () {
$.count = 0;
$(".myrow").sortable({
connectWith: ".myrow",
revert: true,
start: function () {
$.count = $(".myrow").has(".portlet").length;
console.log("Start " + $.count);
},
stop: function (event, ui) {
if ($(ui.item).parent(".myrow").hasClass("left")) {
if ($.count == 2) {
$(".myrow").sortable("cancel");
}
}
}
});
});
DEMO: http://jsfiddle.net/Ue4dq/
I am adding the draggable functionality to an element on a particular user event(hold event). Drag functionality is not working the first time.
Hammer(element).on("hold",function(event){
console.log("hold");
$(element).draggable({
helper: "clone",
cursorAt: { left: 5, top: -5 },
cursor: "move",
stop: function() {
$(element).draggable("destroy");
}
});
});
In the above code snippet, the hold event triggers the draggable functionality but it only works when I release the hold and try it the next time. How can make the drag initiate on hold itself rather than the next time?
EDIT:
Added a sample code in jsbin.
How about using a delay on the draggable instead of the hold Hammer event?
$(element).draggable({
helper: "clone",
cursorAt: { left: 5, top: -5 },
cursor: "move",
stop: function() {
$(element).draggable("destroy");
},
start: function() {
console.log("start");
},
delay:300
});
This works for me:
$('.pic').draggable({
revert: 'invalid',
start: function(event, ui) {
},
stop: function(event, ui) {
$(this).removeClass('dragging');
}
});
$('body').hammer().on('hold', '.container li', function() {
$('.pic', this).addClass('dragging');
});
$('body').hammer().on('dragstart', '.container li .pic', function(e) {
if (!$(this).hasClass('dragging')) {
e.preventDefault();
}
});