jQuery UI Draggable, Snapping to a Grid - javascript

I have two containers. A thumbnail container, and a "page" container. Both are divs. Thumbnails can be dragged back and forth between the two containers. I have revert on the thumbnails set to 'invalid', so they snap back to one of the two containers if they are dropped outside of either one of them.
The thumbnails must snap to a 20x20 grid inside the "page" container. This is so client the client can put the thumbnails in the "page" container in any place, but still be able to line them up neatly.
The problem is the draggable 'grid' option doesn't seem to work too well for this. It seems the "grid" is determined by the draggables location when you start dragging it, rather than acting as if the page has a real grid that can be snapped to.
Is there a way to fix this so the grid is based off the "page" container, rather than the position of the draggable when you start dragging it?

Check the snapping example on the Jquery UI Site:
http://jqueryui.com/demos/draggable/#snap-to
You can take their same example and specify both a grid and a snap parameter.
Then the snap will be based off of the top left corner of the snap selector.
$( "#draggable5" ).draggable({ snap: ".ui-widget-header", grid: [ 80, 80 ] });
The example on the Jquery site will now let the "80x80" box snap based on the big container.
In your situation it might be easiest to create a div with 100% width and height, then set the snap: selector (using css selectors) to that div, then specifying a grid to snap to...
Good Luck

Maybe you could try to round the starting position to the nearest 20 pixels by using the start event on the draggable.
Something like (untested...):
$('#draggable').draggable(
{snap : grid: [20,20]},
{start : function(event, ui) {
var startPosition = $(ui.draggable).position();
$(ui.draggable).css({
'left' : (Math.round(startPosition.left/20)*20)+'px',
'top' : (Math.round(startPosition.top/20)*20)+'px'});
}
}
);
I'm trying myself to achieve that but I'm cloning the dragged element to another container so that's even more tricky ;-)
I still have to figure out how to set the position of the helper in the start event...
Of course it will only work if the starting position is already absolute (like when dragged).
As a matter of fact, I've nearly achieved it by applying this method to the stop event and removing the grid property.
You don't get any visual feedback when moving the object around because there's no grid per se anymore, but when dropping it, it goes to your own grid:
stop: function(event, ui) {
var stopPosition = $(ui.draggable).position();
$(ui.draggable).css({'left' : (Math.round(stopPosition.left/20)*20)+'px', 'top' : (Math.round(stopPosition.top/20)*20)+'px'});
}
Here's a working example:
http://jsfiddle.net/qNaHE/3/

Related

jQuery Multisortable with CustomScrollBar

I am using the mulisortable jquery plugin (github.com/shvetsgroup/jquery.multisortable) along with mcustomscrollbar plugin (manos.malihu.gr/jquery-custom-content-scroller), and I am having trouble displaying the dragged items "overtop" of the customscrollbar containers.
As an example, I have 4 separate containers that utilize the custom scrollbar, and inside each of these containers I have various lists that are connected by the multisortable plugin. I am able to drag selected items from a list in one container to a list in another container, however since the custom scrollbar adds overflow:hidden to its container, the dragged items go "behind" the lists/containers.
My question is: how do I make the dragged items appear in front of the containers
Things I've Tried:
I have removed the overflow:hidden properties from the scrollbar, which does what I want, but then when scrolling, the scrolled content appears outside of the container, which is not good.
I have tried using the helper:"clone" setting in the multisortable options, but this seems to only clone one item (instead of multiple) and my originating list css does unexpected things.
I have also tried setting the z-index on those items which are selected, however this also doesn't seem to help.
Here is my jsfiddle: http://jsfiddle.net/ML49V/12/
If anyone has come across this before and has any suggestions, I would appreciate it.
Thanks
After doing some searching I found the answer. If you add the lines below to the mulitsortable options, it works as intended.
The working jsfiddle is here: http://jsfiddle.net/ML49V/13/
stop: function (e, ui) {
var elements = ui.item.data('multidrag');
ui.item.after(elements).remove();
},
helper: function (e, item) {
if (!item.hasClass("selected")) {
item.addClass("selected").siblings().removeClass("selected");
}
var elements = item.parent().children(".selected").clone();
item.data('multidrag', elements).siblings(".selected").remove();
var helper = $('<li/>').css('list-style', 'none');
helper.height('auto');
return helper.append(elements);
},

How to restrict containment property of sortable to any div?

The containment property limits the drag of the elements to the edges of the browser window. Which give me scroll bar lengthy with empty space.I have a list within a div drop_down_listnow for making sortable I wrote following code:
$('.drop_down_list').sortable({ // make drop down sortable.
axis: "y",
placeholder: ".drop_down_list_placeholder",
forcePlaceholderSize: true,
containment: ".drop_down_list",
scrollSpeed: 3000
});
but when I am dragging my li element outside the div than scroll bar is still increasing and I am getting white space in my div, after dropping element everything is OK. I want to restrict my scroll bar length within my div, how can I do that ?
jsfiddle link for the problem- http://jsfiddle.net/mqnrD/24/
In the jsfiddle, adding "scroll: false" to the sortable callback should fix this.

Draggable limited in movement

I would like to create a big draggable element and put it into a smaller container that limits its movement, so 2 of the draggable sides must touch the container/container's sides.
I also want that the draggable object will be draggable from anywhere in the frame, and not only while clicking on the object itself.
I saw that jQuery provides a nice draggable object:
http://docs.jquery.com/UI/Draggable
Here is an example I made of what is allowed and what is not:
You should set the containment to that object like following:
$(".selector")
.draggable({
containment: "parent"
});
Here is doco

jQuery UI Sortable: Scroll entire page as well as container

I have two lists of elements, and I have enabled jQuery UI sortable on both of them. I used the connectWith option to enable me to drag between the two lists.
One list has a lot of elements in it, so I added overflow-y: scroll to it, but when I try to grab an element from that list and drag it to the other, it only scrolls the list, not the entire page.
I made a jsFiddle demo (http://jsfiddle.net/MCcuc/). Scroll down, and try to move Item Q (drag it by the gray bar on top of the box) from the red list into the green list. You'll see the red list scrolls, but the page does not. How can I scroll the whole page as well as the list?
I'm just enabling sortable without many options:
$('.sort').sortable({
connectWith: '.sort',
handle: '.handle'
});
That's indeed a conflict with scrollable overflow. The draggable helper element is constrained to its parent in that case, probably because trying to "get outside" the parent only results in enlarging its scrollable region.
A workaround is to pass a helper function that clones the dragged element and reparents it under the page body. This way, the draggable helper element will be outside of its original parent from the start, and therefore will scroll the entire page:
$(".sort").sortable({
connectWith: ".sort",
handle: ".handle",
helper: function(event, element) {
return element.clone().appendTo("body");
}
});
You will find an updated fiddle demonstrating this here.

Javascript element dragging with jQuery UI

I have a <div> that displays a graph inside. Sometimes this graph gets too big for the <div>, so I need a way for users to grab the graph with their mouse and move it around. I found the jQuery UI Draggable interaction and thought this is what I need. It was easy enough to get the basics to work, however, I'm having trouble getting this right.
Ideally, the graph can only be dragged to reveal otherwise hidden parts. For example, if there's more graph hidden to the right, then you can drag it to the left and see that hidden part. But then you can't drag it to the left anymore once everything to the right is visible. How do I implement something like this with jQuery UI Draggable? Is it possible? Is jQuery UI the right tool for this?
Less than ideal, but still ok, is that you can drag the graph wherever you want even if the graph is small enough to fit in the parent <div> and nothing is hidden. I can't even get this to work right. What happens is I can just choose not to specify the containment option. Then the graph isn't constrained.. The problem now is the graph's <div> is only a certain size (100% width and height of parent <div>). The nodes are placed with absolute positioning outside this size. Then when you go to drag the graph to reveal those hidden nodes, you can no longer drag the graph... because you're now clicking outside the graph's <div>.
I can maybe have a graph container <div> that I mess with to get things right and dynamically resize that container div as nodes are added or removed.. Or I can implement this without jQuery UI, just using the mousemove event.. What's the best approach? Is there another good library for this?
I think this is what you are looking for - Your container should be overflow:hidden, your graph would be contained in some thing with a width and height, and beyond that you just need to calculate a "constraint" box, which is going to be the .offset() of the container, adding the "extra space" by the calculating "overflowed" portion I.E. only allow dragging the thing from offset.left + container.innerWidth() - draggable.width() -> offset.left
Now, if either of these contraints already "fits" you'll need to make sure to "zero" it to the offset, and if they both fit, skip adding draggable... Put it all together and you get:
var contain = $("#container"),
big = $("#bigthing"),
offset = contain.offset(),
// calculate the "constraints"
constraints = [
offset.left + contain.innerWidth() - big.width(),
offset.top + contain.innerHeight() - big.height(),
offset.left,
offset.top
],
// it "fits" if our left/top constraint is higher or equal to the right/bottom
fitsX = constraints[0] >= constraints[2],
fitsY = constraints[1] >= constraints[3];
if (!(fitsX && fitsY)) {
if (fitsX) {
constraints[0] = constraints[2];
}
if (fitsY) {
constraints[1] = constraints[3];
}
big.draggable({
containment: constraints
});
}
Fiddled: http://jsfiddle.net/gnarf/jqy2b/1/
If you need to dynamically resize the draggable thing, just recalculate the containment option!

Categories