Drag and Drop -JQuery - javascript

Im creating myself a drag functions just for my personal use so I can drag elements around. I'm having a problem. At the moment trying to make the drag so one you pick up the element you can drag it but once you drop it, it goes back to the original position. This is not working as you can see here. When I let go of #drag2 or #drag3 then it goes to the position of #drag1.
My Function:
function drag(el) {
var position = $(el).position();
var ptop = position.top;
var pleft = position.left;
var down = false;
$(el).mousedown(function(event) {
down = true;
$(this).css({
cursor: 'crosshair',
});
$(this).mousemove(function(event) {
if (down == true) {
$(this).css({
cursor: 'crosshair',
});
var w = $(this).width();
var h = $(this).height();
var left3 = (w / 2) + 7;
var top3 = (h / 2) + 7;
$(this).css({
cursor: 'crosshair',
left: (event.clientX) + (3 * 3) - left3,
top: (event.clientY) + (3 * 3) - top3
});
}
}).mouseup(function() {
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: ptop,
left: pleft
}, 300);
});
});
}
I have to get the old position:
var position = $(el).position();
var ptop = position.top;
var pleft = position.left;
So should it not get the position of all of them and bring them self back to where they were? Any help will be appreciated.
EDIT: I DO NOT WANT TO USE ANY PLUGIN OR JQUERY UI, THANKS ANYWAYS

The solution is very simple
See this fiddle: http://jsfiddle.net/BggPn/4/
you define 1 var for left and 1 for top. All 3 the elements use the same variables. If you loop through the elements then you make a new scope where each element has it's own vars.
Working code:
$(document).ready(function() {
drag('#drag, #drag2, #drag3')
});
function drag(el) {
$(el).each(function(){
var position = $(this).position();
var ptop = position.top;
var pleft = position.left;
var down = false;
$(this).mousedown(function(event) {
down = true;
$(this).css({
cursor: 'crosshair',
});
$(this).mousemove(function(event) {
if (down == true) {
$(this).css({
cursor: 'crosshair',
});
var w = $(this).width();
var h = $(this).height();
var left3 = (w / 2) + 7;
var top3 = (h / 2) + 7;
$(this).css({
cursor: 'crosshair',
left: (event.clientX) + (3 * 3) - left3,
top: (event.clientY) + (3 * 3) - top3
});
}
}).mouseup(function() {
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: ptop,
left: pleft
}, 300);
});
});
});
}
Make it a plugin:
$.fn.drag = function drag(){
return this.each(function(){
var position = $(this).position();
var ptop = position.top;
var pleft = position.left;
var down = false;
$(this).mousedown(function(event) {
down = true;
$(this).css({
cursor: 'crosshair',
});
$(this).mousemove(function(event) {
if (down == true) {
$(this).css({
cursor: 'crosshair',
});
var w = $(this).width();
var h = $(this).height();
var left3 = (w / 2) + 7;
var top3 = (h / 2) + 7;
$(this).css({
cursor: 'crosshair',
left: (event.clientX) + (3 * 3) - left3,
top: (event.clientY) + (3 * 3) - top3
});
}
}).mouseup(function() {
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: ptop,
left: pleft
}, 300);
});
});
});
}
Now you can call it by:
$("#drag1, #drag2").drag();

2 thoughts:
1.) Why don't you use jQuery UI (draggable)?
2.) The idea of giving a selector in stead of an element is wrong, a selector can lead to multiple elements, and that's the first reason why it's failing. If you start with
function drag(selector) {
$(selector).each(function() {
var el = $(this);
//rest of code
}
}
it would be better. But I think you'll run into a few other problems eventually

The problem is whenever you're sending in the list of selectors '#drag, #drag2. #drag3' and your position variable only cares about the first one (try changing the order and you'll see they snap to the first in the list). If you want to go about it this way then you'll want to perform an each iteration over them to get the right values.

get the current position of div after drag and set via this
.mouseup(function() {
var position = $(this).position();
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: position.top,
left: position.left
}, 300);
DEMO
why don't you use drag and drop plugin. see this article
http://viralpatel.net/blogs/2009/05/implement-drag-and-drop-example-jquery-javascript-html.html
or this one
http://plugins.jquery.com/project/dragndrop

Related

javascript global variable good practice

I have a few variables pertaining to the height of elements an want to update them using $(window).on('resize'[...]), as well as calculate them when first loading the page so naturally I would rather make a function for doing that, instead of repeating the code.
Is it bad practice to make these variables global so that I can update them with a function, or is there any other way to do this?
var hSum = 0
for (var i = 0; i < content.length; i++) {
var contentH = $(content[i]).height()
hSum += contentH
}
var windowHeight = $(window).height(),
footerHeight = footer.height(),
heightDocument = windowHeight + hSum + footer.height() - 20;
This is the entirety of the script
function scrollFooter(scrollY, footerHeight) {
if (scrollY >= footerHeight) {
$('footer').css({
'bottom': '0px'
});
} else {
$('footer').css({
'bottom': '-' + footerHeight + 'px'
});
}
}
$(document).ready(function() {
var content = $('.content'),
header = $('header'),
footer = $('footer'),
headerContainer = header.find('.container'),
headerBackground = header.find('.background'),
nav = $('.navbar')
var hSum = 0
for (var i = 0; i < content.length; i++) {
var contentH = $(content[i]).height()
hSum += contentH
}
var windowHeight = $(window).height(),
footerHeight = footer.height(),
documentHeight = windowHeight + hSum + footer.height() - 20;
$('#scroll-animate, #scroll-animate-main').css({
'height': documentHeight + 'px'
})
$('header').css({
'height': windowHeight + 'px'
})
$('.wrapper-parallax').css({
'margin-top': windowHeight + 'px'
})
scrollFooter(window.scrollY, footerHeight);
setTimeout(function fadeHeaderIn() {
headerContainer.css('opacity', '1')
headerBackground.css('transform', 'scale(1.25, 1.25)')
}, 300)
$(window).on('scroll', function() {
scroll = window.scrollY
$('#scroll-animate-main').css({
'top': '-' + scroll + 'px'
});
scrollFooter(scroll, footerHeight);
nav.toggleClass('hidden', scroll < windowHeight)
})
nav.on("mouseenter", function() {
nav.removeClass('minimized')
})
nav.on("mouseleave", function() {
nav.addClass('minimized')
})
$('.navbutton').on('click', function(event) {
if ($(this).attr('href') == "#contact")
$('html, body').stop().animate({ scrollTop: documentHeight }, 300, 'swing')
else $('html, body').stop().animate({ scrollTop: $($(this).attr('href')).offset().top }, 300, 'swing')
event.preventDefault()
})
})
The best thing to do is to create a class to handle all the element functions.
for example, let's assume that you have a div or a canvas that you want to check for it's size.
function divHandler(divID){
this.div = document.getElementById(divID);
//Add all global variables here
this.boundingRect = this.div.getBoundingClientRect()
}
//After that access the variables by other functions
divHandler.prototype.displayData = function(){
console.log(this.boundingRect);
}
const d = new divHandler('someDiv');
d.displayData();
#someDiv{
min-width: 100px;
min-height: 100px;
border: 1px solid black;
}
<div id="someDiv">
</div>
Now you have a class that controls all divs by id and you can use it again and again for all other divs in the code.
Update 1:
You can also add an event listener like this
function divHandler(divID){
this.div = document.getElementById(divID);
//Add all global variables here
this.boundingRect = this.div.getBoundingClientRect()
}
divHandler.prototype.listen = function (event, cb, ...args){
this.div.addEventListener(event,cb.bind(this, ...args));
}
const d = new divHandler('someDiv');
d.listen('click', function(e){
console.log(e.type);
this.div.style.backgroundColor = "blue"
});
#someDiv{
min-width: 100px;
min-height: 100px;
border: 1px solid black;
}
<div id="someDiv"></div>

Scrolling Tabs in Bootstrap 4

I am working on scrolling tab. Below is my code. I am facing problem that I am not able to click middle tabs. On right button click tabs scrolls move it gradually. What should I do to move tabs gradually? Please help
var hidWidth;
var scrollBarWidths = 40;
var widthOfList = function() {
var itemsWidth = 0;
$('.list a').each(function() {
var itemWidth = $(this).outerWidth();
itemsWidth += itemWidth;
});
return itemsWidth;
};
var widthOfHidden = function() {
return (($('.wrapper').outerWidth()) - widthOfList() - getLeftPosi()) - scrollBarWidths;
};
var getLeftPosi = function() {
return $('.list').position().left;
};
var reAdjust = function() {
if (($('.wrapper').outerWidth()) < widthOfList()) {
$('.scroller-right').show().css('display', 'flex');
} else {
$('.scroller-right').hide();
}
if (getLeftPosi() < 0) {
$('.scroller-left').show().css('display', 'flex');
} else {
$('.item').animate({
left: "-=" + getLeftPosi() + "px"
}, 'slow');
$('.scroller-left').hide();
}
}
reAdjust();
$(window).on('resize', function(e) {
reAdjust();
});
$('.scroller-right').click(function() {
$('.scroller-left').fadeIn('slow');
$('.scroller-right').fadeOut('slow');
$('.list').animate({
left: "+=" + widthOfHidden() + "px"
}, 'slow', function() {
});
});
$('.scroller-left').click(function() {
$('.scroller-right').fadeIn('slow');
$('.scroller-left').fadeOut('slow');
$('.list').animate({
left: "-=" + getLeftPosi() + "px"
}, 'slow', function() {
});
});
Fiddle http://jsfiddle.net/vedankita/2uswn4od/13
Help me to scroll slowly on button click so that I can click on ease tab. Thanks
You should incrementally move the tabs "width of hidden", but no more than wrapper width...
var widthOfHidden = function(){
var ww = 0 - $('.wrapper').outerWidth();
var hw = (($('.wrapper').outerWidth())-widthOfList()-getLeftPosi())-scrollBarWidths;
if (ww>hw) {
return ww;
}
else {
return hw;
}
};
var getLeftPosi = function(){
var ww = 0 - $('.wrapper').outerWidth();
var lp = $('.list').position().left;
if (ww>lp) {
return ww;
}
else {
return lp;
}
};
And then "readjust" after each movement to determine whether or not the scroll arrows still need to show...
$('.scroller-right').click(function() {
$('.scroller-left').fadeIn('slow');
$('.scroller-right').fadeOut('slow');
$('.list').animate({left:"+="+widthOfHidden()+"px"},'slow',function(){
reAdjust();
});
});
$('.scroller-left').click(function() {
$('.scroller-right').fadeIn('slow');
$('.scroller-left').fadeOut('slow');
$('.list').animate({left:"-="+getLeftPosi()+"px"},'slow',function(){
reAdjust();
});
});
Demo: https://www.codeply.com/go/Loo3CqsA7T
Also, you can improve the position of the last tab by making sure it's right position is never less than wrapper width to keep it aligned to the right edge...
var widthOfHidden = function(){
var ww = 0 - $('.wrapper').outerWidth();
var hw = (($('.wrapper').outerWidth())-widthOfList()-getLeftPosi())-scrollBarWidths;
var rp = $(document).width() - ($('.nav-item.nav-link').last().offset().left + $('.nav-item.nav-link').last().outerWidth());
if (ww>hw) {
return (rp>ww?rp:ww);
}
else {
return (rp>hw?rp:hw);
}
};
https://embed.plnkr.co/NcdGqX/
Look at this example. this tabs move gradually. and also you can use bootstrap 4.
I hope it might be helpful.

jQuery animation mouse event

I'm creating a sample application where I need to change the color of a div as soon as user moves cursor away from it.
It's working but accurate, not sure where I'm going wrong.
See my sample application below.
http://jsfiddle.net/manishparab/3q1trzwk/
var cursorX = 0;
var cursorY = 0;
$(document).ready(function() {
$(".a").mouseover(function() {
animateDiv();
setInterval(function() {
isCursorOnSquare('.a')
}, 1);
});
});
$(document).on('mousemove', function(e) {
cursorX = e.pageX;
cursorY = e.pageY;
});
function isCursorOnSquare(elem) {
var pos, width, height;
pos = $(elem).position();
if ((Math.abs(pos.left - cursorX) <= 100 && Math.abs(pos.top - cursorY) <= 100)) {
$(elem).css("background-color", "red");
} else {
$(elem).css("background-color", "yellow");
}
}
function makeNewPosition() {
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh, nw];
}
function animateDiv() {
var newq = makeNewPosition();
var speed = 2000;
$('.a').animate({ top: newq[0], left: newq[1] }, speed, function() {
animateDiv();
});
}
In your code using .abs() the mouse event is also firing when the mouse is -100px to the left or top of the div.
You could also use mouseenter() to accomplish this,
$("div").mouseenter(function(){
$("div").css("background-color", "red");
}).mouseleave(function(){
$("div").css("background-color", "yellow");
});
Use 'mouseenter' and 'mouseout' events it will help.
$('#divID').on('mouseenter', function () {
//your code
});
$('#divID').on('mouseout', function () {
//your code
});

offset not changing after jQuery animation

http://plnkr.co/edit/c6OaitTTvLhltk7b3muf?p=preview
I'm working on a jQuery animation and need to have the animated divs retain their new offset after the animation ends.
The goal of the animation is to be able to click on one of the smaller circles at the bottom and it will swap places/size with the larger circle at the top.
function leadershipToShow(id) {
console.log('leadershipToShow (' + id + ')');
var x = $('.activeLeadership').offset().left;
var y = $('.activeLeadership').offset().top;
var h = $('.activeLeadership').height();
var w = $('.activeLeadership').width();
if($(id).hasClass('activeLeadership')){ console.log('already selected');return false; }
console.log('x ' + x + ', y ' + y);
console.log($(id).offset());
var xi = $(id).offset().left;
var yi = $(id).offset().top;
console.log('xi ' + xi + ', yi ' + yi);
var hi = $(id).height();
var wi = $(id).width();
var xOffset = Math.abs(x - xi);
var yOffset = Math.abs(y - yi);
console.log('xOffset ' + xOffset + ', yOffset ' + yOffset);
$(id).animate({
left: -xOffset + 15,
top: -yOffset,
height: h,
width: w
}, 500, 'linear', function() {console.log('Id Animation Complete');});
var selected = $('.activeLeadership');
console.log(selected.offset());
selected.animate({
left: xOffset + 15,
top: yOffset,
height: hi,
width: wi
}, 500, 'linear',function() {
console.log('selected Animation Complete');
console.log('new active ' + $('.activeLeadership').attr('id'));
console.log('new active position x ' + $('.activeLeadership').offset().left + ', y ' + $('.activeLeadership').offset().top);
console.log('previous active ' + selected.attr('id'));
console.log('previous active position x ' + selected.offset().left + ', y ' + selected.offset().top);}
);
$(id).addClass('activeLeadership');
selected.removeClass('activeLeadership');
}
I got some help with this and figured it out. The solution is that you have to take the offsets of the divs based on their first offset locations. After they've been animated, moving them again is always relative to their starting offset. So to make this work you have to store their starting offset locations in a global variable outside of the function. With an if statement you then associate the id of the div with the variable of the initial offset. Then it is just a matter of taking the difference between the div you want to animate's initial offset and the location you want to move it to.
updated plunker http://plnkr.co/edit/c6OaitTTvLhltk7b3muf?p=preview
var circle0 = { 'left': $('#circle0').offset().left, 'top': $('#circle0').offset().top };
var bigCircle = { 'height': $('.activeLeadership').height(), 'width': $('.activeLeadership').width() };
var circle1 = { 'left': $('#circle1').offset().left, 'top': $('#circle1').offset().top };
var circle2 = { 'left': $('#circle2').offset().left, 'top': $('#circle2').offset().top };
var circle3 = { 'left': $('#circle3').offset().left, 'top': $('#circle3').offset().top };
var circle4 = { 'left': $('#circle4').offset().left, 'top': $('#circle4').offset().top };
var otherCircles = { 'height': $('#circle1').height(), 'width': $('#circle1').width() };
var time = 400;
function leadershipToShow(id) {
var circleToMoveUp = $(id);
if(circleToMoveUp.hasClass('activeLeadership')){ return false; }
var originOfCircleToMoveUp;
if(id === '#circle0'){ originOfCircleToMoveUp = circle0; }
else if(id === '#circle1'){ originOfCircleToMoveUp = circle1; }
else if(id === '#circle2'){ originOfCircleToMoveUp = circle2; }
else if(id === '#circle3'){ originOfCircleToMoveUp = circle3; }
else if(id === '#circle4'){ originOfCircleToMoveUp = circle4; }
var xOffsetUp = circle0.left - originOfCircleToMoveUp.left;
var yOffsetUp = circle0.top - originOfCircleToMoveUp.top;
var circleToMoveDown = $('.activeLeadership');
var originOfCircleToMoveDown;
if(circleToMoveDown.attr('id') === 'circle0'){ originOfCircleToMoveDown = circle0; }
else if(circleToMoveDown.attr('id') === 'circle1'){ originOfCircleToMoveDown = circle1; }
else if(circleToMoveDown.attr('id') === 'circle2'){ originOfCircleToMoveDown = circle2; }
else if(circleToMoveDown.attr('id') === 'circle3'){ originOfCircleToMoveDown = circle3; }
else if(circleToMoveDown.attr('id') === 'circle4'){ originOfCircleToMoveDown = circle4; }
var xOffsetDown = circleToMoveUp.offset().left - originOfCircleToMoveDown.left;
var yOffsetDown = circleToMoveUp.offset().top - originOfCircleToMoveDown.top;
/* SMALL CIRCLE to BIG CIRCLE animation */
circleToMoveUp.animate({
left: xOffsetUp + 15,
top: yOffsetUp,
height: bigCircle.height,
width: bigCircle.width
}, time, 'linear');
/* BIG CIRCLE to SMALL CIRCLE animation */
circleToMoveDown.animate({
left: xOffsetDown + 15,
top: yOffsetDown,
height: otherCircles.height,
width: otherCircles.width
}, time, 'linear');
circleToMoveUp.addClass('activeLeadership');
circleToMoveDown.removeClass('activeLeadership');
}

Jquery ui draggable - auto resize parent containment [duplicate]

This question already has answers here:
JqueryUI Draggable - Auto resize parent container
(2 answers)
Closed 7 years ago.
I am sorry my English is not that great. I would like my container element to resize to always contain its child elements.
Visit jsfiddle.net/datakolay/LakYy/
$(document).ready(function() {
var
$document = $(document),
$parent = $("#parent"),
$container = $(".container", $parent),
offset = $container.offset(),
scrollbarSafety = 15;
$container.height($document.height() - offset.top - scrollbarSafety);
$("#eleman,#eleman2")
.draggable(
{
containment: $container,
drag:
function(event, ui)
{
var
$draggee = $(this),
draggeePosition = $draggee.position(),
shouldHeight = draggeePosition.top + $draggee.height() + 15;
if($parent.height() < shouldHeight)
{
$parent.height(shouldHeight);
}
if($parent.height() > shouldHeight)
{
$parent.height(shouldHeight);
}
}
}
);
});
You can use the following to figure out the shouldHeight - essentially:
use a selector to get all the draggables
Get its height and compare it to what you currently have
Set the height.
Here's the meat of the how to:
var shouldHeight = 0;
$(".ui-draggable").each(function () {
var draggeePosition = $(this).position();
if (shouldHeight < draggeePosition.top + $(this).height() + 15) {
shouldHeight = draggeePosition.top + $(this).height() + 15;
}
});
fiddle: http://jsfiddle.net/LakYy/3/
http://jsfiddle.net/LakYy/5/
$(document).ready(function() {
var
$document = $(document),
$parent = $("#parent"),
$container = $(".container", $parent),
offset = $container.offset(),
scrollbarSafety = 15;
$container.height($document.height() - offset.top - scrollbarSafety);
$("#eleman,#eleman2")
.draggable(
{
containment: $container,
drag:
function(event, ui)
{
var shouldHeight = getdraggablemaxheight();
if($parent.height() < shouldHeight)
{
$parent.height(shouldHeight);
}
if($parent.height() > shouldHeight)
{
$parent.height(shouldHeight);
}
}
}
);
});
function getdraggablemaxheight() {
var $parent = $("#parent"),
$container = $(".container", $parent),
maxheight = 0,
currentheight = 0,
currentposition;
$container.children().each(function(index, element) {
currentposition = $(element).position();
currentheight = currentposition.top + + $(element).height() + 15;
if(currentheight > maxheight)
maxheight = currentheight;
});
return maxheight;
Based on the solution by #caspian you may find this variation scales better with many draggables. Same thing really, but only finds the dom positions once per item:
$(".ui-draggable").each(function () {
var draggeeHeight = $(this).position().top + $(this).height() + 15;
if (shouldHeight < draggeeHeight) {
shouldHeight = draggeeHeight;
};
});
if ($parent.height() != shouldHeight) {
$parent.height(shouldHeight);
}
I needed this as well for a project, here is the fiddle
http://jsfiddle.net/genkilabs/WCw8E/2/
To #coding_idiot, what you are asking about will w the default behavior if you use overflow-x: scroll;

Categories