i'm trying to build some JQuery UI Selectable demo.
Is it possible to know if the user is selecting from left to right or right to left ?
I have tried this solution but it's not working
var last_selected_id="first";
$( ".selectable" ).selectable({
selecting: function(event, ui) {
if(last_selected_id=="first")
{
//first, do nothing
}
else
{
if(ui.selecting.id>last_selected_id)
{
//left to right
console.log('left to right');
}
else
{
console.log('right to left');
}
last_selected_id = ui.selecting.id;
},....
The ids are sequentially bigger from left to right
You should use the coordinates of mouse pointer provided by JQuery UI event object.
var startX;
var direction;
$( ".selectable" ).selectable({
start: function( event, ui ) {
startX = event.pageX;
direction = "";
},
selecting: function( event, ui ) {
direction = (event.pageX >= startX) ? "right" : "left";
}
});
you're missing 2 statments, one at the beggining saying the ui.selecting.id>0, and the the else if when the ui.selecting.id is lower the the last_element_id this code should work`
if(ui.selecting.id>0)
{
if(last_selected_id=="first")
{
console.log(last_selected_id);
}
else
{
if(ui.selecting.id>last_selected_id)
{
//left to right
direction = "ltr";
}else if(ui.selecting.id<last_selected_id){
//right to left
direction = "rtl";
}
}
if(ui.selecting.id>0){
last_selected_id = ui.selecting.id;
}
}
},
Related
I have 5 carousel on the screen they all are controlled by same navigation buttons.I also need to control them with middle mouse scroll. When i activate mouse wheel control only the carousel which mouse is on top is moving when scrolled. I need to move them all.
I don't know if there is a better solution but i did it this way.
// Wheel Control on Carousels
$( '#body' ).on( 'mousewheel', function ( event ) {
if ( typeof event.originalEvent.wheelDeltaY === 'undefined' ) {
console.log( "could not find mouse deltas" )
}
var deltaY = event.originalEvent.wheelDeltaY;
var scrolledUp = deltaY < 0;
var scrolledDown = deltaY > 0;
if ( scrolledUp ) {
if (swiper_color.activeIndex > 2) {
goTop();
}else{
swiper_color.slidePrev();
swiper_image.slidePrev();
swiper_desc.slidePrev();
swiper_title.slidePrev();
swiper_jar.slidePrev();
}
}
if ( scrolledDown ) {
if (swiper_color.activeIndex < 2) {
swiper_color.slideNext();
swiper_image.slideNext();
swiper_desc.slideNext();
swiper_title.slideNext();
swiper_jar.slideNext();
}else{
checkscroll();
}
}
});
I know the jQuery UI API has snap, snapMethod and snapTolerance built in, but these are not going to work in this case.
Here is the problem I face: when dragging within a container, I want the draggable to snap to the edges of the container when within a certain distance. Calculating distances and triggering this is not an issue. It is getting the draggable to snap which I cannot get to work.
I expected something like: $draggable.position().left = 0; might snap it to the left edge of the parent container but it doesn't make any difference.
Here is a fiddle to demonstrate: https://jsfiddle.net/jwxrevL2/1/
JS:
//set draggable
$('.drag').draggable({
drag: function(){ drag($(this)) },
containment: 'parent',
});
//drag
function drag( $draggable ){
var snap_tolerance = 10;
//Draggable
var d_top = $draggable.position().top;
var d_middle = ($draggable.position().top+($draggable.height()/2));
var d_bottom = ($draggable.position().top+$draggable.height());
var d_left = $draggable.position().left;
var d_center = ($draggable.position().left+($draggable.width()/2));
var d_right = ($draggable.position().left+$draggable.width());
//Wrapper
var $wrapper = $('.wrapper');
var w_top = 0;
var w_bottom = $wrapper.height();
var w_left = 0
var w_right = $wrapper.width();
//snap to left
if( d_left <= (w_left+snap_tolerance )){
console.log('snap left');
$draggable.position().left = w_left;
within_snap = true;
}
//snap to right
if( d_right >= (w_right-snap_tolerance)){
console.log('snap right');
$draggable.position().left = (w_right-$draggable.width());
within_snap = true;
}
//snap to top
if( d_top <= (w_top+snap_tolerance )){
console.log('snap top');
$draggable.position().top = w_top;
within_snap = true;
}
//snap to bottom
if( d_bottom >= (w_bottom-snap_tolerance )){
console.log('snap bottom');
$draggable.position().top = (w_bottom-$draggable.height());
within_snap = true;
}
}//end fn drag
I've have managed to get it working. Although I must say I do not fully understand what is going on. These are the changes I've made (updated fiddle):
//set draggable
$('.drag').draggable({
drag: function(e, ui){ drag($(this), ui) },
containment: 'parent',
});
So on the drag event I pass the ui object as well as the jQuery object (I think, please correct me if I am wrong about the ui object) into the drag function.
//snap to left
if( d_left <= (w_left+snap_tolerance )){
console.log('snap left');
ui.position.left = w_left;
within_snap = true;
}
Then by updating the ui objects position.left property I can snap it into position.
Can anyone explain why it is different using ui rather than the jQuery object?
Here's an example.
You need to specify a grid like so:
<script>
$(function() {
$( "#draggable4" ).draggable({ grid: [ 20, 20 ] });
$( "#draggable5" ).draggable({ grid: [ 80, 80 ] });
});
</script>
https://jsfiddle.net/m3r2xra3/
I am building simple slider with dragging ability. For now, I use pageX to determine the position, like so:
var dragdir = 0,
drag = null;
$('article.small-section').on('mousedown', function(ev) {
drag = 1;
dragdir = ev.pageX;
if(drag) {
$(this).css('cursor','move');
}
}).on('mouseup', function(e){
drag = null
if(!drag) {
$(this).css('cursor','initial');
$(this).css('left','0')
}
});
$('article.small-section').on('mousemove', function(e) {
if(drag) {
if(dragdir > e.pageX) {
//console.log(dragdir+'|'+e.pageX)
if(dragdir > e.pageX+100) {
$(this).parent('section').cycle('prev');
}
$(this).css('right','');
$(this).css('left','-'+(parseInt(e.pageX/10))+'px');
} else {
if(dragdir < e.pageX-100) {
$(this).parent('section').cycle('next');
}
$(this).css('left','');
$(this).css('right','-'+(parseInt(e.pageX/10))+'px');
}
}
});
It works great dragging to the right. To the left - it does, then it backs (or doesn't go at all). I noticed that pageX is going down - that's the problem. How can I fix it?
Working fiddle: http://jsfiddle.net/2jEJH/1/
Hey guys I'm back with another question. I'm using the code below to add a bouncing effect to a div on my site. It works fine right now but the div has to be clicked in order for the effect to start. I would like to modify it so that when the user is scrolling down the page and reaches that section it triggers the effect automatically. How can I modify the code below to trigger the effect when the user scroll's down and reaches that section of the site?
Here is the code I' using
$(".servi-block").click(function () {
doBounce($(this), 2, '10px', 150);
});
function doBounce(element, times, distance, speed) {
for (i = 0; i < times; i++) {
element.animate({
marginTop: '-=' + distance
}, speed)
.animate({
marginTop: '+=' + distance
}, speed);
}
}
$(window).scroll(function(event){
isElementVisible = inViewport($(".servi-block"));
if(isElementVisible)
{
doBounce($(this), 2, '10px', 150);
}
});
function inViewport (el)
{
var r, html;
if ( !el || 1 !== el.nodeType ) { return false; }
html = document.documentElement;
r = el.getBoundingClientRect();
return ( !!r
&& r.bottom >= 0
&& r.right >= 0
&& r.top <= html.clientHeight
&& r.left <= html.clientWidth
);
}
This should help you out: http://api.jquery.com/scroll/
$( "#target" ).scroll(function() {
$( "#log" ).append( "<div>Handler for .scroll() called.</div>" );
});
Also utilize this
$('#target').on("mousewheel", function() {
alert($(document).scrollTop());
});
Those two together should get you the ability to figure out you are scrolling, and when you reach position X, do something.
EDITED
Let's go at it this way -
var targetPos = "500px";
$( document ).scroll(function() {
if ($(document).scrollTop() == targetPos) {
doBounce($(this), 2, '10px', 150);
}
});
You can simply check to see when the element comes into view by taking the element's offset and subtracting that element's parent height and scrollTop value.
Here's an example:
$(document).ready(function() {
$(document).on('scroll', function() {
var offset = $('.element').offset().top,
scroll = $(document).scrollTop(),
height = $(document).height(),
inViewDown = ((offset - scroll - height) <= 0) ? true : false;
if (inViewDown) {
// Do some stuff
}
});
});
Here's a working example: http://jsfiddle.net/ughEe/
I have the following HTML:
<div class="list" id="list">
<div class="item" id="i1">Item 1</div>
<div class="item" id="i2">Item 2</div>
<div class="item" id="i3">Item 3</div>
</div>
<div class="timeline" id="timeline">
</div>
What I want to be able to do, with jQuery, is:
Be able to drag .items from the #list into the #timeline
.items can be dropped into the timeline as many times as required, eg. there could be 4 of item #i1 in the timeline.
.items in the timeline must not overlap each other
.items can be positioned at any place along the timeline so long as they do not overlap any other items on the timeline
So Ive gone for jQueryUI's Draggable and Droppable, and also gone for the jQueryUI Draggable Collision Plugin.
Here is the jQuery I have started with:
$('#list .item').draggable({
helper: 'clone',
revert: 'invalid',
//the following are for the jquery-ui-dragggable-collision plugin
obstacle: '#timeline .item',
preventCollision: true
});
$('#timeline').droppable({
accept: '.item'
});
My problem is that the jQueryUI Draggable Collision Plugin only works when you are dragging the original Div itself, and not dragging a helper. I need helpers so that I can achieve #2 (adding multiple copies of one item). But I need something like the Collision Plugin so I can achieve #3 (items not overlapping).
Does anybody know of a solution to this problem? Is there another plugin that does collision detection on the helper of a draggable object? Is there another approach I can try to get what I want to achieve?
If you prefer a jsfiddle to that uses the jQueryUI Draggable Collision Plugin as you suggested, here is something to play around with: Link to jsfiddle
The approach uses the original helper in order to make use of collision functionality.
The clone is generated in the start event function (and removed again in the stop event in case the dragging did not result in a successful drop):
$(function(){
var draggableSelector = ".list .item:not(.dropped)";
var init = function() {
$(draggableSelector).each(function(i){
$(this)
.draggable({
//helper: 'clone',
revert: 'invalid',
start: function(event,ui) {
var $clone = ui.helper.clone();
$clone
.removeClass("ui-draggable ui-draggable-dragging")
.insertAfter(ui.helper)
;
$(this).data("clone",$clone);
},
stop: function(event,ui) {
if( $(".ui-draggable-dragging.dropped").length == 0) {
$(this).data("clone").remove();
};
},
//the following are for the jquery-ui-draggable-collision plugin
refreshPositions: true,
obstacle: '.item.dropped',
preventCollision: true,
})
.css("left", ( ($(this).width() + 5) * i) + "px")
;
});
$('.timeline').droppable({
accept: '.item'
,drop: function(event,ui) {
ui.draggable
.addClass("dropped")
;
setTimeout(reinit, 500);
}
});
};
var reinit = function() {
$(".list .item.ui-draggable").draggable("destroy");
init();
}
init();
});
Hope that this will be useful.
Here is an example i wrote for this question showing a simple drag and drop plugin with collision detection.
It allows you to drop items onto a timeline as long as there is space for the item to exist without overlapping.
It is by no means a finished product but hopefully will show that code like this is not incredibly complex to write and trying to hack together massive conflicting plugins are not always the best option. Sometimes its best to start from scratch. Its fun, and a really good way to learn.
/*----------ON DOCUMENT READY----------*/
$(document).ready(function() {
$("#timeline").timeline({
items: ".item"
});
});
/*----------THE TIMELINE PLUGIN----------*/
$.fn.timeline = function(options) {
var defaults = {
items: "div"
}
var options = $.extend(defaults, options)
return this.each(function() {
//-----SETUP-----//
//define all the vars we will need later
var el = $(this);
var items = $(options.items);
var mousedown = false;
var dragging = false;
var activeItem = false;
var placedItems = new Array();
//make everything unselectable so it dosne interfere with dragging
$("html").find("*").css({
"user-select": "none",
"-moz-user-select": "none",
"-webkit-user-select": "none",
"-ms-user-select": "none",
"-o-user-select": "none",
}).attr("unselectable", "true").unbind("onselectstart");
//-----EVENTS-----//
//log when the mouse is down anywhere on the doc
$(document).mousedown(function() {
mousedown = true;
});
//when the mouse is released
$(document).mouseup(function(e) {
//if was dragging an item attempt to place it
if (mousedown && dragging) {
placeItem(e);
}
//log that dragging has stopped
mousedown = false;
dragging = false;
});
//log when the mouse is pressed over an item
items.mousedown(function() {
dragging = true;
//clone the active item and hide it ready for dragging
activeItem = $(this).clone().appendTo("body").hide();
});
//when the mouse movers over the doc
$(document).mousemove(function(e) {
//if mouse was pressed over item attempt to drag
if (mousedown && dragging) {
dragItem(e);
}
});
//-----FUNCTIONS-----//
//drag the item around the screen
function dragItem(e) {
//if no active item done do owt
if (!activeItem) {
return false;
}
//work out where the drag anchor is
var x = e.pageX - (activeItem.height() / 2);
var y = e.pageY - (activeItem.width() / 2);
//save the original position in case we cant place the item
if (!activeItem.origPos) {
activeItem.origPos = {
x: x,
y: y
}
}
//drag the item
activeItem.css({
"position": "absolute",
"top": y,
"left": x,
"z-index": "999",
"opacity": 0.6,
"display": "block"
});
}
//attempt to place the item
function placeItem(e) {
//if no active item dont do owt
if (!activeItem) {
return false;
}
//define som vars needed later on
var onTargetY = false;
var onTargetX = false;
var remove = false;
var collision = false;
//check if item is being relesed withing the timeline bounds
if (e.pageY > el.position().top && e.pageY < el.position().top + el.height()) {
onTargetY = true;
}
if (e.pageX > el.position().left && e.pageX < el.position().left + el.width()) {
onTargetX = true;
}
//if on target attempt to drop on timeline
if (onTargetX && onTargetY) {
//snap to the left or right if dropped at the left or right edges
var maxLeft = el.position().left;
var maxRight = el.position().left + el.width() - activeItem.width();
x = e.pageX - (activeItem.width() / 2);
if (x < maxLeft) {
x = maxLeft;
} else if (x > maxRight) {
x = maxRight;
}
//loop the items already on the timeline and check for collisions
$.each(placedItems, function(i, item) {
var itemMin = item.position().left;
var itemMax = item.position().left + item.width();
if (x + activeItem.width() > itemMin && x < itemMax) {
collision = true;
}
});
y = el.position().top;
}
//if there is a collision or the item is dropped outside the timeline
//set x and y back to original position and set removal flag to true
if (collision || !onTargetX || !onTargetY) {
x = activeItem.origPos.x;
y = activeItem.origPos.y;
remove = true;
//if dropped inside the timeline and no collisions add item to the
//array of items inside the timeline
} else {
placedItems.push(activeItem);
}
//finally either animate the item back to where it started then remove it
//or snap it into the timeline in the space found
activeItem.animate({
top: y,
left: x
}, {
duration: 300,
queue: false,
complete: function() {
//if remove flag set remove the item from the dom
if (remove) {
$(this).remove();
}
//some tidying up
activeItem.css("opacity", 1);
activeItem = false;
}
});
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="list" id="list">
<div class="item item1">Item 1</div>
<div class="item item2">Item 2</div>
<div class="item item3">Item 3</div>
</div>
<div class="timeline" id="timeline"></div>
Enjoy :).