Using jQuery Draggable with grid and multiple draggable elements - javascript

I'm trying to find an better solution to drag multiple elements at once, all elements snapping to a grid, with jQuery UI draggable.
I found a working solution there for the multiple drag part. I adapted it to be able to use the grid with a "round to multiple" function :
function roundM(number, multiple) {
return Math.round(number / multiple) * multiple;
}
and saving the previous offset. You can see full code in this fiddle.
As you can see, it's working when you drag elements at a normal speed, but when dragging quickly, the other elements do not follow correctly the dragged element.
For now I can keep my solution, but if someone has a better one, I will be glad to test it :)
Thanks

Have a look at: https://jqueryui.com/draggable/#visual-feedback
Create a helper function resulting in Html representing your selected items and use it as 'visual feedback' when setting up your draggable.

Related

jquery animate/scrollTop to multiple anchors inside divs

I'm having a problem implementing relatively complicated auto-scroll functionality on my page. This displays the issue in my code...
http://codepen.io/d3wannabe/pen/XXxdQq
I have multiple divs on my page (blue,red,green in my example) that I not only want to be able to scroll to (which the top 3 buttons in my example achieve perfectly), but I want to be able to scroll WITHIN (which the bottom 3 buttons represent my best attempt at).
The thing I can't figure out, is why the scroll within function works well on my first div ("scrollTo3rdBlueItem" button), but then less accurately with the other divs ("scrollTo3rdRedItem" and "scrollTo3rdGreenItem" buttons). In my full web application (which obviously has more data to scroll through), I basically see that the lower down the page the parent div is positioned, the less accurately I'm able to scroll within it.
I'm struggling to identify much of a pattern though so can't simply try tweaking the offset values. Any ideas what I might be doing wrong here would be hugely appreciated!!
...since I wasn't allowed to post this without quoting code - here's the jquery function you can see in my codepen!
function scrollToParent(parentID){
$('html,body').animate({scrollTop: $('#'+parentID).offset().top}, 500);
}
function scrollToChild(parentID, childID){
//first focus on the parent
scrollToParent(parentID);
$('#'+parentID).animate(
{scrollTop: $('#'+ childID).offset().top - 100}
, 500);
}
UPDATE
Answer here was COMPLETETLY wrong. Left here to preserve the comments.
UPDATE 2
Got IT! You need to take in to account the offset of the parent div. Update your scrollToChild function to the below;
$('#'+parentID).animate(
{
scrollTop: $('#'+ childID).offset().top - $('#'+parentID).offset().top
}, 500);

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);
},

jQuery UI draggable can't be placed at first position in sortable

I have a draggable element that I want to drag into a sortable. However, I can't drag the draggable onto the first position in the sortable list directly. It's only possible when I move beyond the first element and then go back upwards to the position before the first element.
Have a look at this Fiddle: http://jsfiddle.net/Nh75P/53/
Please try to move the draggable directly (in one move) to the position above 'Sortable 1'.
Thanks for your help.
This is an issue with sortable. Apparently on enter the offset of the entry is not accounted for. Submit a bug about this here.
Thank 'Nick Melville' on https://forum.jquery.com/topic/jquery-ui-1-8rc1-sortable-list-doesn-t-allow-drop-at-first-and-last-position-depending-where-the-mouse-gets-clicked-to-drag-on for his answer:
Since this is still a high search result page... Changing the
tolerance to 'pointer' should resolve this issue for you:
http://api.jqueryui.com/sortable/#option-tolerance

JScrollPane Dynamic Height

The demo page referenced can be found here.
I'm trying to determine a way that on the click of a parent category (ex: Stone Tiles, Stone Sinks), that the JScrollPane would re-determine the current height and adjust as needed. Unfortunately, my attempts to do so have not worked yet.
I referenced the example here which provided the following function (to do a refresh)...
api.reinitialise();
I've tried to setup this function to be triggered by the category parents like so...
var pane = $('.menuwrap')
pane.jScrollPane();
var api = pane.data('jsp');
var i = 1;
$("li.expandable.parent").click(function() {
api.reinitialise();
});
Unfortunately, while I was able to verify the click is being rendered, the function (api.reinitialize) doesn't appear to be working. I'm hoping that a fresh pair of eyes could point me in the right direction. :-)
Thanks!
The problem is that api.reinitialise executes immediately after the click, and the li element will not have expanded yet so when jscroll pane goes to to recalculate the height it gets it wrong. You can try adding a delay but the best solution would be to bind api.reinitialise() to an event that's triggered once the your list has finished expanding. I'm not sure how you're expanding the div within the li but if for instance it's using .animate, you could bind the api.reinitialise to the animation complete event.
Also noted that not all the parent li's have the class parent associated it to them. I would expect you would want the pane to reinitialize on the expansion and collapsing of all the main li elements.
Hope that helps !
Cheers :)
What you can do is have your inner divs expanded by default, and then close them with jquery, rather than in the CSS directly.
So instead of doing this:
.mydiv.closed {display:none}
do this in your jquery after the elements are drawn to the page:
$('.mydiv.closed').hide();
This will load the jscrollpane at the necessary height, and then collapse what you want to be initially hidden.

Getting DIV id based on x & y position

The problem I'm trying to solve is "What's at this position?"
It's fairly trivial to get the x/y position (offset) of a DIV, but what about the reverse? How do I get the id of a DIV (or any element) given an x/y position?
Unfortunately, triggering a manufactured/simulated mouse event won't work, since when you dispatch it, you have to provide a target element. Since that element is the one you're trying to figure out, all you could do is dispatch it on the body, as if it had already bubbled.
You really are left to do it on your own, that is manually walk through the elements you're interested in, and compare their position/size/zIndex to your x/y point and see if they overlap. Except in IE and more recently FF3, where you can use
var el = document.elementFromPoint(x, y);
See
http://developer.mozilla.org/En/DOM:document.elementFromPoint
http://msdn.microsoft.com/en-us/library/ms536417(VS.85).aspx
function getDivByXY(x,y) {
var alldivs = document.getElementsByTagName('div');
for(var d = 0; d < alldivs.length; d++) {
if((alldivs[d].offsetLeft == x) && (alldivs[d].offsetTop == y)) {
return alldivs[d];
}
}
return false;
}
Use a JQuery selector to filter the list of all DIVs for one that matches your position criteria?
Create a mouse event listener, then trigger a mouse event at that location. This should give you the entire stack of elements at that location.
Or, look at the source of Firebug.
If all you have is the X and Y position, (and you can't track mouse movement like you mentioned) then you will have to traverse the DOM, looping through every DIV. For each DIV you will need to compare its X and Y coordinates against those you have. This is an expensive operation, but it is the only way. I suggest you might be better off rethinking your problem instead of coming up with a solution for it.
One option is to build an array of "div-dimension" objects. (Not to be confused with the divs themselves... IE7 perf is frustrating when you read dimensions off of object.)
These objects consist of a pointer to the div, their dimensions (four points... say top, left, bottom, and right), and possibly a dirty bit. (Dirty bit is only really needed if the sizes change.
You could then iterate through the array and check dimensions. It requires O(n) to do that on each mouse move. You might be able to do slightly better with a binary search style approach... maybe.
If you do a binary search style approach, one way is to store 4 arrays. Each with a single point of the dimension, and then binary search on all four. O(4logn) = O(logn).
I'm not saying I recommend any of these, but they MIGHT work.
I think what John is saying is that you can use document.createEvent() to simulate a mousemove at the location you want. If you capture that event, by adding an eventlistener to the body, you can look at the event.target and see what element was at that position. I'm unsure as to what degree IE supports this method, maybe someone else knows?
http://developer.mozilla.org/en/DOM/document.createEvent
Update:
Here's a jquery plugin that simulates events:
http://jquery-ui.googlecode.com/svn/trunk/tests/simulate/jquery.simulate.js
this might be a little too processor intensive but going over the whole list of div elements on a page, finding their positions and sizes then testing if they're under the mouse. i don't think i'd want to do that to a browser though.
You might find it's more efficient to traverse the DOM tree once when the page is loaded, get all elements' positions and sizes, and store them in an array/hash/etc. If you design the data structure well, you should be able to find an element at the given coordinates fairly quickly when you need it later.
Consider how often you will need to detect an element, and compare that to how often the elements on the page will change. You would be balancing the number of times you have to re-compute all the element locations (an expensive computation) against the number of times you'd actually use the computed information (relatively cheap, I hope).

Categories