I write a userscript for a website, and the script includes a jQuery UI draggable. Greatly simplified, the site has two rows, and each row has two divs placed horizontally.
The site layout previously used two columns with inner divs instead of rows. The draggable was constrained to the right column's parent, which is exactly what we wanted. Now, however, there's no way to constrain to the right "column" because that column no longer exists in the DOM.
Is there a way to fluidly contain the draggable div to the right column of divs without the old parent element? I can add elements to the DOM (or do whatever) if needed, we have the full power of jQuery and jQuery UI available. I know it would be possible to use a droppable on the top right div, but from what I understand that would cause the draggable to snap between the two. If that's the only option then I'll do that, but if there's another method I would love to see it.
FIDDLE
<div id="outercontainer">
<div id="toprow">
<div id="topleft"></div>
<div id="topright"></div>
</div>
<div id="bottomrow">
<div id="bottomleft"></div>
<div id="bottomright"></div>
</div>
</div>
<div id="dragme"></div>
The actual containment value used in constraining position is an array of coordinates that's being calculated based on the object you set in the options themselves. But you can access this containment property on the draggable instance and modify them as you wish. The only restriction is that it needs to be a rectangle, you cannot mix shapes.
In your case, you can simply work out the coordinates from the elements.
$("#dragme").draggable({
// You still need to set a value for containment
// else it won't be checked when evaluating the position
containment: 'document',
start: function(e, ui) {
// You simply set a left, top, right, bottom coordinates.
// You need to set it on start so if the elements have been
// resized, the containment follows.
var cont = [
$('#topleft').offset().left + $('#topleft').outerWidth(),
$('#toprow').offset().top,
$('#toprow').offset().left + $('#toprow').outerWidth() - ui.helper.width(),
$('#bottomrow').offset().top + $('#bottomrow').outerHeight() - ui.helper.height(),
]
$(this).draggable('instance').containment = cont;
}
});
https://jsfiddle.net/nxxbh8eL/
Related
I'm trying to get widgets in a grid to get removed when a widget is dragged into a separate Div, but I can't seem to get it working using 'removable' in the grid's options.
I've been through the docs (https://github.com/gridstack/gridstack.js/tree/develop/doc) and tried different options that are on there as well as tried to replicate one of the demos that has the functionality working (http://gridstackjs.com/demo/two.html) I've looked for other people who've had these issues too but can't find any posts that were able to help with this problem.
The First Div is where I want to drag the widgets to, and the second is where I'll be dragging them from.
<div class = 'trash ui-droppable'>
<h1 class = 'text-center pt-4'><?= FontAwesome::light('trash'); ?>
</h1>
</div>
<div class = 'grid-stack mt-3 ui-droppable'>
<!-- Widgets set here -->
</div>
Here's the JQuery which sets the grid's options, the option that I think should be allowing widgets to be dropped into is removeable and set it to the first Div's class name of ".trash".
var options = {
cellHeight: 100,
verticalMargin: 10,
removable: '.trash'
};
$('.grid-stack').gridstack(options);
What should be happening is I drag a widget over to the top Div, and the widget should be removed from the grid entirely but instead when dragged out and released acts like it's been dragged out the grid and places it back to where it was.
I had the same problem, which was fixed by giving the trash div a minimum height (like 75px).
I'm using gridstack with acceptWidgets to drag-and-drop widgets from a left side panel to the main panel, kind of similar to http://gridstackjs.com/demo/two.html
In my case, I want to set height, width and other item attributes to my "grid-stack-item". However, setting up those attributes won't affect when the item is dropped in the gridstack.
Here is a JSFiddle: https://jsfiddle.net/trevisan/wt7bg6s1/8/
Note that the "Drag me" element has data-gs-width="6" which I expected to make it stretch as my gridstack has 6 columns.
<div class="grid-stack-item" data-gs-width="6">
<div class="grid-stack-item-content">Drag me</div>
</div>
I have tried to call makeWidget method but then I end up having two widgets on my gridstack.
Does anyone have an idea how to figure that out?
Notice that Drag me element is not in gridstack even it has class name "grid-stack-item",
#grid element and #grid2 element has initialized by gridstack but sidebar element(Drag me element) didn't:
$('#grid1').gridstack(options);
$('#grid2').gridstack(_.defaults({
float: true
}, options));
So the data-gs-width attribute means nothing to Drag me element.
Say I have two block level elements in the same container. I want to increase the height of the first (closer to top of page) one, and use a transition on that height. How do I get the resulting offsetTop of the second div, before the transition ends?
I don't want to know how to do it for this example. I want to know how to do it for a generic case. Many other elements may be going through transitions at the same time, not just the element directly above the one I am interested in.
The only way I can think of doing it is to force the transitions to end, check the position, and then restart all the transitions. ...but means I have to do it as the transitions start. ...and it causes a flicker when the page is repainted with the temporarily finished transitions.
Demo: http://jsbin.com/AyAfEXu/2
One approach would be to clone all your elements once you have added the classes that trigger the CSS transitions, then you can get the resulting properties from the cloned elements which will immediately hold the new values.
I suggest the use of a container element:
<div id="container">
<div id="one"></div>
<div id="two">
<div id="curr">current offsetTop of P:</div>
</div>
</div>
And with jQuery you would do:
$(function () {
//Kick off animations
$('#one').addClass('loaded');
//Clone container and position it outside of view
var $cloneContainer = $('#container').clone().css({
position: 'absolute',
left: '-99999px'
}).prependTo('body');
//Get offset from cloned element
var newOffset = $cloneContainer.find('#two').offset().top;
console.log(newOffset);
//Remove clone
$cloneContainer.remove();
});
Here's a working demo of this approach
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!
I have two fixed hight divs each containing a sortable list which are connected to each other. Is there a way to hide the overflow while still having the lists connected? E.g. if the overflow is set to hidden then the li doesn't show when it is dragged outside of the div.
I know a possible solution would be to calculate the maximum number of li that the div can contain and dynamically add/remove elements based on the number of visible elements, but I was wondering if there was a better solution?
You should be able to fix this by using the appendTo option, which will tell it where to attach the helper object to in the DOM. The default is to use parent which means the helper that's being dragged is inside your overflow: hidden div. Changing it to, for example, body should fix it for you. I.e:
$( ".selector" ).sortable({ appendTo: 'body' });
Have a look at containment. It defines a bounding box that the sortable items are constrained to while dragging.
http://api.jqueryui.com/sortable/#option-containment