jQuery draggable bug (element not in line with cursor) - javascript

EDIT: JSFIDDLE: http://jsfiddle.net/h9yzsqfr/
--
Code:
elem.editor.find("div.ui-widget").draggable(
{
handle:"div.content",
containment:elem.editor,
snap:"*",
start: function(e,ui)
{
$(ui.helper).addClass("dragging");
},
drag: function(e,ui)
{
checkTop(ui);
if($(ui.helper).parents("div.lo-content").length > 0)
{
$(ui.helper).appendTo(elem.editor);
ui.position = { 'top': e.pageY, 'left': e.pageX };
}
},
stop: function(e,ui)
{
oldWidget.saveState($(ui.helper),1);
setTimeout(function() {
$(ui.helper).removeClass("dragging");
}, 300);
}
});
I have some draggable objects within a container defined by elem.editor; however I have some other draggable objects inside div.lo-content which is also inside elem.editor.
Whenever an object inside div.lo-content is dragged, it should reattach to the elem.editor container which is working fine; however as demonstrated in the following GIF (below), it is not setting the position of the draggable object to where the mouse cursor is.
What is a workaround for this problem?

The problem is your width: 100% and the containment option. As soon as its appended to body it stays 100%, but of the body, then it gets smaller but the containment has already been calculated.
One way to solve it is to reset containment. There are probably different ways to do it, one way could be like this:
start: function (e, ui) {
if ($(this).parents(".inner").length > 0) {
$(ui.helper).addClass("dragging");
ui.helper.css({
'width': '100px',
'left': '0px',
'top': '0px'
});
ui.helper.data()['ui-draggable'].containment = [0,0,$('body').width(), $('body').height()]
ui.helper.appendTo("body");
}
},
http://jsfiddle.net/puurqx8r/6/

connectToSortable 
It's a  Selector that Allows the draggable to be dropped onto the specified sortables. If this option is used, a draggable can be dropped onto a sortable list and then becomes part of it. Note: The helper option must be set to "clone" in order to work flawlessly. Requires the jQuery UI Sortable plugin to be included.
Code examples:
Initialize the draggable with the connectToSortableoption specified:
$( ".selector" ).draggable({
connectToSortable: "#my-sortable"
cursorAt:{top: 5, left: t}
});

Use cursorAt: top:, left: and appendTo: 'body'
See my answer with example here.
jQuery draggable shows helper in wrong place after page scrolled

I had the same problem. This is caused by the use of margins to center elements. Try using position absolute!

I removed position:absolute on dragable object

Related

jQuery UI Droppable - How to allow only 1 element per drop zone, instead of stacking

My current script: https://jsfiddle.net/uoyp37bj/11/
The issue is that currently it's possible to "stack" droppable elements by dragging them on-top of each other. I'm trying to make it so that only the latest dropped element stays there, and any previous elements are removed.
I originally just "hid" the additional items using CSS, but as I'm using an input box to keep track of which items exist in the drop zones, this is no longer possible. Any help would be really appreciated, hoping it's something relatively simple within the jQuery UI API, but currently nothing has worked for me.
$(".social-msl-link-label").draggable({
connectToSortable: ".social-msl-group-list",
revert: "invalid",
helper: "clone"
});
var orderMSLids = [];
var droppableOptions = {
accept: ".social-msl-link-label",
tolerance: 'pointer',
greedy: true,
hoverClass: 'highlight',
drop: function(ev, ui) {
orderMSLids = [];
$(ui.draggable).clone(true).detach().css({
position: 'relative',
top: 'auto',
left: 'auto'
}).appendTo(this);
orderMSLids.push($(this).find('.social-msl-link-label').attr('id'));
$(this).siblings().filter(function() {
return $(this).text().trim() === $(ui.draggable).text().trim();
}).empty();
str = [];
$(".social-msl-links-order li").each(function(index) {
var res = $(this).children().attr('id');
if (res) {
str.push(res);
}
});
var string = str.join(",");
$('#msl-order').val(string);
}
};
$(".social-msl-links-order li.social-msl-drop").droppable(droppableOptions);
$('.social-msl-add').click(function() {
var $droppable = $('<li class="social-msl-drop"></li>').droppable(droppableOptions);
$droppable.insertBefore('.social-msl-add');
});
$('#msl-order').prop('value').split(',').forEach(function(id) {
var $droppable = $('.social-msl-drop.ui-droppable:empty').first();
if (id) {
$('.draggable #' + id).clone(true).appendTo($droppable);
}
});
Just had a thought, but haven't progressed - may be possible to iterate over all of the elements inside the "drop" call, and remove any duplicates. Within this loop, could also check if any drop zones have 2 elements and remove all except 1. Not sure how to script that, but the initial logic makes sense to me.
Instead of appending the draggable to droppable, just replace it's entire content with the draggable like this:
$(this).html(ui.draggable.clone(true).css({
position: 'relative',
top: 'auto',
left: 'auto'
}));
Instead of:
$(ui.draggable).clone(true).detach().css({
position: 'relative',
top: 'auto',
left: 'auto'
}).appendTo(this);

trigger event when draggable hit edge of containment

jQuery UI draggable plugin allow you to set contain for draggable like
$('.panel').draggable({
handle: ".head",
containment: "parent",
cursor: "pointer"
}
);
My question is how can I detect if div have reached the edge of its containment?
I want to mimic the Windows effect when you drag a panel to edge it go 50% width and 100% height but I don't know how to detect/trigger an event when div reaches the edge.
Thanks
You can use the drag function to return the position of the draggable element while it's being moved. Compare that against the position of the outer edge of the parent and when the two intersect trigger the resizing action.
This fiddle is a very simplified version of what you're looking for, but it should illustrate the basic concept and get you started in the right direction. Hopefully this helps.
http://jsfiddle.net/98jpC/1/
$(function(){
var draggableRight;
var draggableWidth = $('.draggable').width();
var parentWidth = $('#parent').width();
$('.draggable').draggable({
containment: 'parent',
drag: function(e, ui){
draggableRight = ui.position.left + draggableWidth;
if(draggableRight == parentWidth){
$(document).trigger("mouseup");
$('.draggable').css({
width: '50%',
height: '100%',
top: 0,
left: '50%'
});
}
}
});
});

Allow the draggable content exceed but not within the parent boundary in Jquery?

I am using Jquery ui and it provide a function for me to make draggable content. It has an option 'containment' that force the draggable item move within the box.
However, for my case, the content (image) must exceed the screen , how can I force it not to drag inside the screen?
Thanks
$("#popup").draggable({
addClasses:true,
scrollSpeed: "200",
containment: "parent",
//appendTo: "body",
helper: function(){
// Create an invisible div as the helper. It will move and
// follow the cursor as usual.
return $('<div></div>').css('opacity',0);
},
drag: function(event, ui){
// During dragging, animate the original object to
// follow the invisible helper with custom easing.
var p = ui.helper.position();
$(this).stop().animate({
top: p.top,
left: p.left
},1000,'easeOutCirc');
}
});

jQuery multi-draggable

Edit#1:
Since I asked this problem, I made a script which allows the elements to move together, but with problems. :(
$(this).append(
$('<div class="elem '+classes+'" style="width: 210px; height: 30px" data-modby="'+ui.draggable.attr("data-for")+'"><p>'+text+'</p></div>')
.resizable({
grid: 10,
maxHeight: 120,
maxWidth: 600,
minHeight: 30,
minWidth: 210,
containment: ".box-section"
})
.draggable({
grid: [10,10],
containment: ".box-section",
scroll: false,
helper: "original",
start: function(event, ui) {
posTopArray = [];
posLeftArray = [];
if ($(this).hasClass("r-active")) {
$(".elem.r-active").each(function(i) {
thiscsstop = $(this).css('top');
if (thiscsstop == 'auto') thiscsstop = 0;
thiscssleft = $(this).css('left');
if (thiscssleft == 'auto') thiscssleft = 0;
posTopArray[i] = parseInt(thiscsstop);
posLeftArray[i] = parseInt(thiscssleft);
});
}
begintop = $(this).offset().top;
beginleft = $(this).offset().left;
},
drag: function(event, ui) {
var topdiff = $(this).offset().top - begintop;
var leftdiff = $(this).offset().left - beginleft;
if ($(this).hasClass("r-active")) {
$(".elem.r-active").each(function(i) {
$(this).css('top', posTopArray[i] + topdiff);
$(this).css('left', posLeftArray[i] + leftdiff);
});
}
}
})
);
The actual problem is the moved elements have to stay in the containment box (called .box-section and if I have a single element it works fine. Also if i have two elements has not the same width, if i pick the sorter one and drag, I can pull out the longer of the container.
Also, if I move them fast (like a ninja) they will slip, and they won't be in the same grid they used to be.
30 percent solved since:
I'm going to make a new thingy which can drag and drop items to a box, and resize them.
My problem is that, I can't make them move together. But with some rules.
Rule one: They must move based on a 10x10px grid.
Rule two: They can't move outside their frame.
(Resize is an issue which i simply can't imagine, so I don't care about it, resize will be later)
I made a fiddle for it here: http://jsfiddle.net/9fueY/ you can see this.
In the right side, you can see inputs and a and a checkbox (and on hover a button).
The checkbox is the draggable object, drag it to the image. Now you have some text or a star appeared on the left.
If you type anything to the inputs, it refreshes the text.
OnHover the right boxes you can see a button. By clicking on it, will make a clone of the first element. Drag it inside.
If you click to a right-side box, it will glow blue. Click to two boxes on the right, makes all the two textfields glow blue in the image.
Now this is the case when i want them to move together. :D
What's your opinion, what should I do with this?
Thank you very much. - Répás
There is a plugin i developed for dragging elements together. Please do use it if it makes sense.
https://github.com/someshwara/MultiDraggable

Expand containing div when dragging an item inside it and reaching limits

My page has several items (divs) that are draggable and resizable.
My code for doing this is given below:
part.draggable(
{
containment: 'parent',
drag: function(event, ui){
partIsDragging = true
part.prev().css('top', ui.position.top - 20 ).css('left', ui.position.left )
part.prev().show()
},
stop: function(event, ui) {
partIsDragging = false
}
}).resizable({
containment: 'parent',
handles: 'ne, se, sw, nw,n,w,e,s',
stop: function() {
}
});
The html structure for these is the following:
<body>
<div id="wrapper">
<div class="draggableItem"></div>
<div class="draggableItem"></div>
<div class="draggableItem"></div>
<div class="draggableItem"></div>
</div>
</body>
In my css files i have set body height: 100% and wrapper height: 100%. Width is always fixed for wrapper, width: 950px. I want my div to expand in height when the draggableItem reaches the bottom of the wrapper. Right now when the page is loaded, it has the height as big as the resolution allows it but in case I have more items in the wrapper then everything becomes cluttered and I would like when dragging an item to somehow expand the wrapper in height dynamically. This should happen only if I hit the bottom border.
PS: I am using jQuery and jQuery-ui.
I may have a solution. First off, I replaced part with '.draggableItem' and this where appropriate. Please tell me if that breaks the code in some critical way. In addition, I removed part.prev().css('top', ui.position.top - 20 ).css('left', ui.position.left ) in the code below.
function adjustWrapperHeight(movingObject)
{
var objectBottomPosition = $(movingObject).offset().top+$(movingObject).height()
var wrapperBottomPosition = $("#wrapper").offset().top+$("#wrapper").height()
if(wrapperBottomPosition-objectBottomPosition<distanceBuffer)
{
$("#wrapper").height($("#wrapper").height()+distanceBuffer+1)
}
}
var distanceBuffer = 20;
$('.draggableItem').draggable(
{
containment: 'parent',
drag: function(event, ui)
{
partIsDragging = true
adjustWrapperHeight(this)
},
stop: function(event, ui)
{
partIsDragging = false
}
}).resizable(
{
handles: 'ne, se, sw, nw,n,w,e,s',
resize: function(event, ui)
{
adjustWrapperHeight(this)
var objectRightPosition = $(this).offset().left+$(this).width()
var wrapperRightPosition = $("#wrapper").offset().left+$("#wrapper").width()
if(wrapperRightPosition<=objectRightPosition)
{
$(this).width(ui.originalSize.width)
var containmentLeftPosition = wrapperRightPosition-$(this).width()
$(this).offset({top:$(this).offset().top,left:containmentLeftPosition})
}
}
})
})
The function adjustWrapperHeight(movingObject) adjusts div#wrapper's height depending on a movingObject's bottom position. That is, when movingObject "pushes up" against div#wrapper's borders, it adjusts div#wrapper's height.
I had to use a hack for resizable. The containment: 'parent' for resizable (but not draggable) sets the containment to the container's ORIGINAL height or so it seems. That means as the height of div#wrapper dynamically changes, the constraint set by containment: 'parent' does not dynamically change. To fix this, I removed containment: 'parent' and indeed the entire containment and ensured that div#wrapper's right containment isn't broken within the resize event. Note that you should probably do this with div#wrapper's left containment as well.
Please tell me if this was helpful. Thank you.

Categories