Making an element draggable without jquery ui? - javascript

I'm trying to build an image cropper similar to Twitters - http://jsfiddle.net/yarKr/1/. What I'm stuck on is the ability to drag the image. What is the best way to do this without resorting to jquery ui?
<div class="canvas">
<span class="window"></span>
<img src="http://www.dailystab.com/blog/wp-content/uploads/2009/03/katy-perry-esquire-4.jpg" class="draggable" />
</div>
I want to be able to move drag the image around inside the .canvas div.

Something like this will work: jsFiddle
var TheDraggable = null;
$(document).ready(function () {
$('.draggable').on({
mousedown: function () { TheDraggable = $(this); },
mouseup: function () { TheDraggable = null; }
});
$(document).mousemove(function (e) {
if (TheDraggable) {
TheDraggable.css({'top': e.pageY, 'left': e.pageX});
}
});
});
And then for the CSS you add this: .draggable { position:absolute; }
You could rewrite this and add some form of easing on the repositioning, change the cursor or add a more precise starting point based on where the initial click happened on the picture but overall, that should get you started.

How about, while dragging, making the position absolute and setting it to or near the position of the mouse?

This is mine.
http://jsfiddle.net/pd1vojsL/
3 draggable buttons in a div, dragging constrained by div.
<div id="parent" class="parent">
<button id="button1" class="button">Drag me</button>
<button id="button2" class="button">Drag me</button>
<button id="button3" class="button">Drag me</button>
</div>
<div id="log1"></div>
<div id="log2"></div>
Requires JQuery (only):
$(function() {
$('.button').mousedown(function(e) {
if(e.which===1) {
var button = $(this);
var parent_height = button.parent().innerHeight();
var top = parseInt(button.css('top')); //current top position
var original_ypos = button.css('top','').position().top; //original ypos (without top)
button.css({top:top+'px'}); //restore top pos
var drag_min_ypos = 0-original_ypos;
var drag_max_ypos = parent_height-original_ypos-button.outerHeight();
var drag_start_ypos = e.clientY;
$('#log1').text('mousedown top: '+top+', original_ypos: '+original_ypos);
$(window).on('mousemove',function(e) {
//Drag started
button.addClass('drag');
var new_top = top+(e.clientY-drag_start_ypos);
button.css({top:new_top+'px'});
if(new_top<drag_min_ypos) { button.css({top:drag_min_ypos+'px'}); }
if(new_top>drag_max_ypos) { button.css({top:drag_max_ypos+'px'}); }
$('#log2').text('mousemove min: '+drag_min_ypos+', max: '+drag_max_ypos+', new_top: '+new_top);
//Outdated code below (reason: drag contrains too early)
/*if(new_top>=drag_min_ypos&&new_top<=drag_max_ypos) {
button.css({top:new_top+'px'});
}*/
});
$(window).on('mouseup',function(e) {
if(e.which===1) {
//Drag finished
$('.button').removeClass('drag');
$(window).off('mouseup mousemove');
$('#log1').text('mouseup');
$('#log2').text('');
}
});
}
});
});

Drag icon - less jumping
Borrowing from frenchie's answer I have to create a movable popup on the fly. Have to add dragability to the object after it's created. This not flawless - any faster than a slow drag and the cursor leaves the behind until you let go, at which point the <div> then snaps and sticks to the cursor movements until you click again.
<!-- language: lang-html -->
<input type="button" value="pop" onclick="pop('NN')" id="btnNN"><!-- NN is the query rownumber -->
<b style="display:none;" id="protoContent">
<div id="divdrag~">
<img style="float:left;" id="drag~">
my form <input id="inp1_~">...
</div>
</b>
<!-- language: lang-js -->
var TheDraggable = null;
$(document).ready(function () {
$(document).mousemove(function (e) {
if (TheDraggable) {
TheDraggable.css({'top': e.pageY-15, 'left': e.pageX-15});
}//"-15" gets the cursor back on img inside the <div>
});
});
var gOpenPop="";
function pop(NN){
if(gOpenPop!=""){
document.getElementById("divdrag"+gOpenPop).style.display="none";//hide opened
if(gOpenPop==NN){
gOpenPop="";
return;
}
}
gOpenPop=NN;
//add div after the button
$("#btn"+NN).after(
//get div w/ form, replace of any "~"s with argument NN
$("#protoContent").html().replace(/~/g,NN)
);
//ojb created, now bind click for dragability to the img
$('#drag'+NN).on(
{mousedown: function () {TheDraggable = $("#divdrag"+NN); },//
mouseup: function () { TheDraggable = null; }
});
...
}

Related

passing parameters into function

I am very new to javascript and I hope to get some help simplifying the code.
I have two div box that contains 3 images each. Each div box displays an image by default (no. 1 and 4) and the mouse hover toggle a change in image (independently). See http://jsfiddle.net/hdaq9se5/6/.
The following code works just right but I am hoping to get some help simplifying the code, e.g. modify the animation function such that it takes the class of the div box as input.
$(document).ready(function () {
$("#image_two, #image_three, #image_five, #image_six").hide();
$(".image_rollover").hover(function () {
animation()
});
$(".image_rollover2").hover(function () {
animation2()
});
});
function animation() {
var $curr=$(".image_rollover img:visible");
var $next=$curr.next();
if($next.size()==0) $next=$(".image_rollover img:first");
$next.show();
$curr.hide();
}
function animation2() {
var $curr=$(".image_rollover2 img:visible");
var $next=$curr.next();
if($next.size()==0) $next=$(".image_rollover2 img:first");
$next.show();
$curr.hide();
}
Like this?
Using jquery, this is in most places (almost everywhere) the current Element. Like the Element that dispatched an event, ...
knowing this you don't need to pass any classes into animation, jquery already provides you with all you need.
$(document).ready(function() {
$(".image_box img").not(":first-child").hide();
$(".image_box").hover(animation);
});
function animation() {
var $curr = $("img:visible", this);
var $next = $curr.next();
if ($next.length === 0) {
$next = $("img:first", this);
}
$next.show();
$curr.hide();
}
.image_box {
border: 1px solid #000000;
width: 130px;
height: 80px;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="image_rollover image_box">
<img id="image_one" src="http://placehold.it/130x80&text=1">
<img id="image_two" src="http://placehold.it/130x80&text=2">
<img id="image_three" src="http://placehold.it/130x80&text=3">
</div>
<div class="image_rollover2 image_box">
<img id="image_four" src="http://placehold.it/130x80&text=4">
<img id="image_five" src="http://placehold.it/130x80&text=5">
<img id="image_six" src="http://placehold.it/130x80&text=6">
</div>

Mouse move makes div move inverted smoothly

I'm trying to make my div move smoothly inverted with the "ease" effect.
When I hover over the div, I want the image to smoothly move away from the mouse, just like they did with the image of the two toys in the first section of toyfight.co's site.
I've inspected their code and wasn't able to find my answer.
Could any of you provide it?
I've managed to do having a slightly rough movement of the image with the code down below. Also a link to my project on Codepen. (More minimized here)
Answer
This plugin helped me achieve my goal
http://www.jqueryscript.net/animation/jQuery-Plugin-For-3D-Perspective-Transforms-On-Mousemove-LogosDistort.html
HTML
<div class="section-0">
<div class="phone-container" >
<div class="phone-front" id="layer-one"></div>
</div>
</div>
<section class="section-1 parallax parallax-1">
<div class="container" id="section-1">
<div class="text-block animation-element">
<h1>Gemaakt van het fijnste staal</h1>
<p>"The volks is the rare kind of phone that I can recommend without reservations."<br> — The Verge</p>
</div>
</div>
</section>
JQUERY
$.fn.smoothWheel = function () {
// var args = [].splice.call(arguments, 0);
var options = jQuery.extend({}, arguments[0]);
return this.each(function (index, elm) {
if(!('ontouchstart' in window)){
container = $(this);
container.bind("mousewheel", onWheel);
container.bind("DOMMouseScroll", onWheel);
currentY = targetY = 0;
minScrollTop = container.get(0).clientHeight - container.get(0).scrollHeight;
if(options.onRender){
onRenderCallback = options.onRender;
}
if(options.remove){
log("122","smoothWheel","remove", "");
running=false;
container.unbind("mousewheel", onWheel);
container.unbind("DOMMouseScroll", onWheel);
}else if(!running){
running=true;
animateLoop();
}
}
});
};
Try using .css() instead of .offset() on line 358.
So from:
$(target).offset({ top: y ,left : x });
to:
$(target).css({ top: y ,left : x });
The overall effect is a lot smoother. CodePen here.

jQuery hoverIntent for only one div class when the class is being used multiple times

I am using the jQuery hoverIntent plugin to fade in a div when another div is being hovered over. There are 4 elements that share a class name, and I only want to fade in the children of the element I am hovering over, not every div that shares the class' children. The problem now is if I hover over one dive it fades in all 4 elements children. Where in my code little bit of code have I gone wrong?
Here's the html:
<div id="resources" class="faded">
<div class="resourcesHover"></div>
</div>
<div id="forBuilders" class="faded">
<div class="buildersHover"></div>
</div>
<div id="fam" class="faded">
<div class="famHover"></div>
</div>
<div id="homePlans" class="faded">
<div class="plansHover"></div>
</div>
Here's the jQuery
$(document).ready(function(){
$(".faded").hoverIntent({
over: fadeDivIn,
timeout: 300,
out: fadeDivOut
});
function fadeDivIn() {
var $kids = $('.faded').children();
$($kids, this).fadeIn('slow');
}
function fadeDivOut() {
var $kids = $('.faded').children();
$($kids, this).fadeOut('slow');
}
});
Just in case anyone has a similar issue, I figured out the solution and posted it below.
Change your fadeDivIn and fadeDivOut functions as follows:
function fadeDivIn() {
var $kids = $(this).children();
$($kids).fadeIn('slow');
}
function fadeDivOut() {
var $kids = $(this).children();
$($kids).fadeOut('slow');
}
In your fade in and fade out functions, you need to select this instead of all elements of the class faded
$(document).ready(function(){
$(".faded").on('mouseover', function() {
fadeDivIn(this);
});
$(".faded").on('mouseout', function() {
fadeDivOut(this);
});
function fadeDivIn(hovered_over) {
var $kids = $(hovered_over).children();
$($kids).fadeIn('slow');
}
function fadeDivOut(hovered_over) {
var $kids = $(hovered_over).children();
$($kids).fadeOut('slow');
}
});
Just figured it out. I added a this, to the line that sets the children into a variable, and also removed it from the .fadeIn and .fadeOut lines.
Here's the new jQuery:
$(document).ready(function(){
$(".faded").hoverIntent({
over: fadeDivIn,
timeout: 300,
out: fadeDivOut
});
function fadeDivIn() {
var $kids = $(this,'.faded').children();
$($kids).fadeIn('slow');
}
function fadeDivOut() {
var $kids = $(this,'.faded').children();
$($kids).fadeOut('slow');
}
});

Changing sidebar height when dynamic content is added

I have a 'sticky sidebar nav' that is positioned absolutely relative to the #sidebar div, so it follows the page down on the left hand side and is always available. To make this work I had to add a height to the sidebar, so I used some code to find the height of the container dynamically. This is the code i used:
<script type="text/javascript">
function matchColHeights(col1, col2) {
var col1Height = $(col1).height();
var col2Height = $(col2).height();
if (col1Height > col2Height) {
$(col1).height(col2Height);
} else {
$(col1).height(col2Height);
}
}
$(document).ready(function() {
matchColHeights('#sidebar', 'section#main-container');
})
</script>
Currently the #sidebar div sits inside the section called section#maincontainer. A very simplified version of the html is below.
<body>
<header>Header content</header>
<section id="main-container">
<div id="sidebar">
<ul>
This is the floated ul
<ul>
</div>
<div class="content">
This is where the content of the page sits
</div>
<div class="content2">
This is where the content of the page sits (because of the design there are often more than one divs floated right
<div>Within the content divs are potential expanding divs (accordions and tabs that change size)</div>
</div>
</section>
<footer>Footer content</footer>
</body>
So the problem I have is that there is expandable content (tabs and accordions) in the content area, and when the content expands, the jQuery does not update the height of the sidebar to the new height (this new height could be shorter or longer than the original height). I have tried adding the function to my .click() handler of the accordion (haven't yet tried with the tabs) but here is the code that is used to drop my accordion down:
<!--Content Accordion-->
<script type="text/javascript">
$(document).ready(function() {
$('div.content-accordion> div').hide();
$('div.content-accordion> h4').click(function() {
var $nextDiv = $(this).next();
var $visibleSiblings = $nextDiv.siblings('div:visible');
if ($visibleSiblings.length ) {
$visibleSiblings.slideUp('fast', function() {
$nextDiv.slideToggle('fast');
$matchColHeights('#sidebar', 'section#main-container');
});
} else {
$nextDiv.slideToggle('fast');
$matchColHeights('#sidebar', 'section#main-container');
}
});
});
</script>
As you can see I can add the $matchColHeights('#sidebar', 'section#main-container'); function into the click function and it doesn't refresh to the new height still. I have tried a few other possibilities with no luck.
Just to let everyone know i found a solution...Took alot of messing about but code is below.
I essentially on the click had to set sidebar height back to 0, and create a function that finds the new height of the section#main-container, and then applys that as a css height to the sidebar. This changed the height of the sidebar just fine, but then the sticky sidebar wasnt readjusting to the new height, so i just pasted the code that works my sticky sidebar (the code that starts with $("aside") into the function and it refreshes just fine. Thanks to those that helped.
<!--Content Accordian-->
<script type="text/javascript">
$(document).ready(function() {
$('div.content-accordian> div').hide();
$('div.content-accordian> h4').click(function() {
var $nextDiv = $(this).next();
var $visibleSiblings = $nextDiv.siblings('div:visible');
if ($visibleSiblings.length ) {
$visibleSiblings.slideUp('fast', function() {
$nextDiv.slideToggle('fast', function() {
// START CHANGE SIDEBAR HEIGHT
$("#sidebar").css({ height: 0});
newheight = $("section#main-container").height();
$("#sidebar").css({ height: newheight});
$("aside").stickySidebar({
timer: 500
, easing: "easeInOutQuint"
, constrain: true
});
});
// END CHANGE SIDEBAR HEIGHT
});
} else {
$nextDiv.slideToggle('fast', function() {
// START CHANGE SIDEBAR HEIGHT
$("#sidebar").css({ height: 0});
newheight = $("section#main-container").height();
$("#sidebar").css({ height: newheight});
$("aside").stickySidebar({
timer: 500
, easing: "easeInOutQuint"
, constrain: true
});
});
// END CHANGE SIDEBAR HEIGHT
}
});
});
</script>
I believe you could write
if (col1Height !== col2Height) {
$(col1).height(col2Height);
}
instead of
if (col1Height > col2Height) {
$(col1).height(col2Height);
} else {
$(col1).height(col2Height);
}
But that won't solve your problem.
You probably have to fire that matchColHeights() function from inside a callback like this:
if ($visibleSiblings.length ) {
$visibleSiblings.slideUp('fast', function() {
$nextDiv.slideToggle('fast', function() {
$matchColHeights('#sidebar', 'section#main-container');
});
});
} else {
$nextDiv.slideToggle('fast', function() {
$matchColHeights('#sidebar', 'section#main-container');
});
}
Let me know if it worked.

jQuery Multiple Panel Toggle

I'm working on a portfolio site for an iPhone developer. In this site the iPhone app icons will act as a toggle buttons for panels that describe the application. The panels animate over the main page content. To add to this, if a panel is open and another app icon is clicked the open panels will need to close and the next app will open. Currently the script I have works great for toggling a single panel, see here: http://cncpts.me/dev/
So how can change the current script so it accepts multiple ids or classes, without creating duplicate code?
Here is the jQuery that is driving the functionality for a single toggle action.
$(document).ready(function() {
$("li.panel_button").click(function(){
$("div#panel").animate({
height: "700px"
})
.animate({
height: "600px"
}, "slower");
$("div.panel_button").toggle('zoom'); return false
});
$("div#hide_button").click(function(){
$("div#panel").animate({
height: "0px"
}, "slower"); return false
});
});
Here is the HTML:
<div id="panel">
<div id="panel_contents"></div>
<img src="images/iphone.png" border="0" alt="iPhone Development">
<div class="panel_button" id="hide_button" style="display: none;">
<img src="images/collapse.png" alt="collapse" />
</div>
</div>
give the list items a rel attribute that points to the div you are trying to show/hide.
<li rel='#panel_1' class='panel_button'>
give all the div's a common class such as 'flyaway', do a hide on any div with the same class that is not currently hidden
$('.flyaway').not(':hidden').animate({ height: "0px"}, "slower");
and show the one you want
$("li.panel_button").click(function(){
$($(this).attr('rel')).animate({
height: "700px"
})
.animate({
height: "600px"
}, "slower");
$($(this).attr('rel')+" div.panel_button").toggle('zoom'); return false
});
Here is my solution:
// Plugtrade.com - jQuery Plugin :: Bounce //
// answer for http://stackoverflow.com/questions/5234732/jquery-multiple-panel-toggle
jQuery.fn.bounce = function (el, bounceheight) {
var thisdiv = this;
var owidth = thisdiv.width();
var oheight = thisdiv.height();
var trigger = $(el);
// what we want is to make a parent div and then
// get the child div's dimensions and copy it's position
// display, width and height //
// child then becomes an absolute element nested within the
// parent div.
thisdiv.wrap('<div class="bounceparent"></div>');
// let's make a hidden button
thisdiv.append('<input type=text class="bouncehide" style="display:none" />');
var thishidebtn = thisdiv.last();
var thisparent = thisdiv.parent();
thisparent.width(owidth);
thisparent.height(oheight+bounceheight);
thisparent.css('border', '1px solid #ccc');
thisparent.css('position', thisdiv.css('position'));
thisparent.css('overflow', 'hidden');
thisdiv.css('position', 'relative');
thisdiv.css('top', oheight+bounceheight);
thisdiv.css('height', '0');
var toggle = false;
thishidebtn.click(function() {
if(toggle)
{
toggle = false;
thisdiv.animate({ top: 0, height:oheight+bounceheight }).animate({ top: oheight+bounceheight, height:0 });
}
});
trigger.click(function() {
// some code //
if(!toggle)
{
// show
$('.bouncehide').click();
toggle = true;
thisdiv.animate({ top: 0, height:oheight+bounceheight }).animate({ top: bounceheight, height:oheight });
}
else
{
// hide
toggle = false;
thisdiv.animate({ top: 0, height:oheight+bounceheight }).animate({ top: oheight+bounceheight, height:0 });
}
});
// return original object so it can be chained
return thisdiv;
}; // END -> plugin :: bounce
... and here is how you use it:
$(function(){
$('#boinky').bounce('#toggle', 50);
$('#boinkyb').bounce('#toggleb', 50);
});
jsFiddle example:
http://jsfiddle.net/523NH/14/
hope this helps you.

Categories