jQuery Draggable: Image Flicker - javascript

I've been developing an Image panning tool, and after a kind member directed me to the draggable plugin for jQuery, I have most of it completed. Right now if the user drags the image (contained inside a div of about 300px by 300px), the image will first flicker, then pan. This problems seems to occur after a mouse down event, on the mouse move event. The image will shift into one of the four corners on mouse move, and moving to certain areas will cause another shift. I haven't been able to find anything through google, and I'm relatively new to jQuery still.
I've uploaded the code here, in case my description is too vague:
http://www.studentgroups.ucla.edu/csa/test/zoom.htm
Any ideas or advice is greatly appreciated!

For one, you've made the image draggable both via the jQuery plugin, and your own code. Your code is changing the background-position of the div, and the jQuery plugin is changing the div's actual position. That's bound to cause some problems.
Also, Draggable's containment parameter seems to be designed for draggable items who are smaller than their parent container, not ones who are bigger, like you're trying to do.
Anyways, here's the working code:
$(document).ready(function() {
$(".draggable").draggable().bind('dragstop', function(e, ui) {
if (ui.position.top > 0) {
$(this).css('top', 0);
}
if (ui.position.left > 0) {
$(this).css('left', 0);
}
var bottom = -($(this).height() - $(this).parent().height()),
right = -($(this).width() - $(this).parent().width());
if (ui.position.top < bottom) {
$(this).css('top', bottom);
}
if (ui.position.left < right) {
$(this).css('left', right);
}
});
});
If you don't need edge-snapping, you can get rid of the .bind() function, and just call .draggable().
$(document).ready(function() {
$(".draggable").draggable();
});

Related

jQuery UI draggable has jerky transition on drop

I have a simple drag and drop functionality that I'm attempting to get working. I have cards that are draggable and can be dropped on top of other cards to swap positions with the other card. Here's a fiddle with the functionality in place: https://jsfiddle.net/vj0a9gp8/1/
The drag and drop code is pretty simple:
$(function() {
$(".card"). draggable({
revert: true
}). droppable({
hoverClass: "card-hover",
drop: function(event, ui) {
swapNodes($(this).get(0), $(ui.draggable).get(0));
}
});
});
function swapNodes(a, b) {
var aparent = a.parentNode;
var asibling = a.nextSibling === b ? a : a.nextSibling;
b.parentNode.insertBefore(a, b);
aparent.insertBefore(b, asibling);
}
Basically when a card is dragged and then dropped onto another, the swapNodes function traverses up the dom and places them where they belong. This all works great. The issue, which you can see in the fiddle, is that when the drop occurs the dropped card kind of jerks off screen before animating in to place and it looks poorly overall. I've tried playing around with draggable.position to address and fix this functionality but all I've managed to do is make it worse. Any ideas?
When you drag your element, it changes the left and top position. When you drop it, you change its position in the DOM, but you never specify a new top and left, so it still keeps the one set when dragging it. The animation is there because you have a revert to true, which puts back the original position and animates it.
Easy solution would be to set revert to 'invalid' (so only if there's no drop) and set the left and top in your swap function. Like this
revert: 'invalid'
...
b.style.left = '';
b.style.top = '';
https://jsfiddle.net/huw2Lkgb/1/

Vertical scroll on mobile - hammer.js element in page

There are a million similar questions but I can't find an answer that works for me.
Here is the situation:
I have an HTML page, and within that page is an element that I am using hammer.js on.
Need to be able to scroll like this:
--->
While also being able to pinch-to-zoom (and subsequently pan on that zoomed element) on the seating chart element above.
The element itself works perfectly. I'm using doubletap, pinch, pinchend, pan, and panend on it.
Now, in the event that the element is totally zoomed out (I'm keeping track of the scale for this reason), I would like the entire page to scroll when using it on a mobile browser (aka the finger will be dragging the page up).
I have tried almost everything under the sun at this point. I can't seem to get it to manually scroll to a specific position (I have tried setting window.scrollTop and using window.scrollTo() with no results).
If someone could point me in the right direction, I'll worship you and your family for the next...say....13 days. Heck, maybe even 14.
TL;DR
- Have we pinch zoomed on the element? If so, handle panning around that element with glee!
- Are we fully zoomed out / pinched out on the element? If so, mobile users should be able to scroll the page like normal!
Thanks
Chris
You may try window.scrollTo to "simulate" normal scroll. Like so:
var currentScroll = 0;
var currentScale = 1; //"fully zoomed out" state
hammer.on("panstart", function (ev) {
currentScroll = window.scrollY;
});
hammer.on("pan", function(ev) {
if (currentScale == 1) {
//abort pan and scroll window instead
window.scrollTo(0, currentScroll + ev.deltaY * -1);
return;
}
//do stuff with pan here...
});

jQuery - how to animate draggable div towards moving cursor during drag event

I am using jquery UI draggable and want to have a draggable div animate during a drag event. Imagine that when stationary, the square div in the example is attached to a magnet. Wen you click on it and start dragging, it will not drag until a certain distance threshold is reached (distance = distance between center of div and current mouse position). After that threshold is reached, the div will animate toward the mouse and should then proceed to a normal drag event.
My problem is that when the mouse is dragged past the distance threshold at a fast enough speed, the div will start flashing because it is switching between showing the animated div and the one that is being dragged. Another problem that occurs is that if you drag the mouse fast enough and then stop, the div animates to the last recorded mouse position, but by the time the calculation is made, the mouse might already be at a different position, so the mouse is at one spot and the div is at another. Any ideas on how to make the div animate towards the mouse and then continue the drag event in one smooth transition? (also, i want the animation do be long enough so that you can see the div moving. if duration is set to 1, it works fine but I want it to be more visually appealing and smooth) Here is a demo: http://jsfiddle.net/b84wn2nf/
Here is some of the code found in the demo:
$(".dragSquare").draggable({
drag: function (event, ui) {
if($(this).hasClass("stuck")){
var mx = event.pageX;
var my = event.pageY;
ui.position.left = $(this).position().left;
ui.position.top = $(this).position().top;
var d = Math.floor(Math.sqrt(Math.pow(mx - ($(this).offset().left + ($(this).width() / 2)), 2) + Math.pow(my - ($(this).offset().top + ($(this).height() / 2)), 2)));
console.log(d)
if (d > 200) {
var animateToX = event.pageX - $(this).width() / 2;
var animateToY = event.pageY - $(this).height() / 2;
$(this).stop(true, true).animate({
left: animateToX + 'px',
top: animateToY + 'px'
}, {
/*easing: 'easeOutBounce,'*/
duration: 500,
start: function () {},
complete: function () {
$(this).removeClass("stuck");
}
});
}
}
} });
Okay, So I know I posted this a long time ago, and since then, I started to use the Snap.js SVG library instead of jQuery, which makes it much easier to cancel a drag, but before the switch, I solved the problem the only way I could: by modifying the source code.
In jquery-ui.js, locate the jQuery UI Draggable section, and then scroll down to _mouseDrag method.
What you need to do in your own code is set a global variable to tell jQuery if you want the drag behavior to be overridden. I used 'cancelDrag' as the variable name. So when its set to false, dragging behaves normally.
In _mouseDrag, you will see the following code:
this.helper[0].style.left = this.position.left + "px";
this.helper[0].style.top = this.position.top + "px";
What you need to do is wrap it in a conditional statement that depends on your boolean variable, so it looks like this:
if(!cancelDrag){
this.helper[0].style.left = this.position.left + "px";
this.helper[0].style.top = this.position.top + "px";
}
Basically, if cancelDrag is set to true, jQuery drag handler will not change the position of your element. Its not ideal, and should probably not be used, but it works. Make sure that if you modify this file, you are not using the minified source.

On stop scrolling auto position column

i'm working on a split scrolling site with two columns. And it's working great, but there is one problem i can't seem to solve. It's when i stop scrolling and the columns are positioned like this:
They need to automatically position themselves next to each other, so the user gets to see the full nicely aligned image. Now i've tried using Jquery Inview:
$('.content:nth-child(2)').one('inview', function (event, visible) { // i know the selector is wrong just for example purposes
if (visible == true) {
$('col.left').css( "top", "0" );
} else {
// element has gone out of viewport
}
});
But that doesn't seem to do the trick.. Using inview is probably the wrong way to go anyway. Now i have tried googling a solution but i can't seem to be able to find anything that does the trick. Does anyone know a plugin that does this for me? Or if someone can point me in the right direction that would be awesome.
JSFIDDLE
Thanks in advance
You could call a function to align the left and right after the user has completed scrolling. This example assumes the left and right columns are the same (as in your example).
...
$(window).scroll(function () {
$('.right').css('top', (top + $(window).scrollTop()) + 'px');
clearTimeout(t);
t = setTimeout(function(){scrollend();},200);
});
function scrollend(){
//console.log("scrollend");
clearTimeout(t);
$('.right').css('top', (0 - $(window).scrollTop()) + 'px');
}
...
E.G: http://jsfiddle.net/u9apC/4/

How to make a sliding thingamajig between photos?

See the effect in the photos in the article here:
http://www.popsci.com/science/article/2012-11/and-after-images-show-hurricane-sandys-devastation
Does anyone have any idea how that's done? I suppose I could make two frames with adjustable width within a fixed frame, but what about the handle? And the way the frame line and handle brighten and enlarge when you mouse over? Hover event, to be sure, but what kind of hover event?
It is very simple. You have 2 DIVs with the 2 different images (as background-image in css) overlapping eachother (In e.g absolute positioning.) (Perhaps the "Before" picture above)
Then you have a slider and when dragged it decreases the overlapping DIV's width, making the underlaying DIV show!
This functionallity can be found in a jQuery plugin called "Before/After"
Link: jQuery BEFORE / AFTER
You could of course just write your own that isn't dependant on jQuery UI.
;(function($){
$.fn.slidingThingamajig = function () {
return this.each(function(){
var $this = $(this);
$this.find('.handle')
.css({cursor:'ew-resize'}) // Here's your fancy cursor with directional arrows
.on('mousedown', function(e) {
$this.addClass('resizable');
$this.parents().on('mousemove', function (e) {
$('.resizable').css({width:e.pageX - $('.resizable').offset().left});
}).on('mouseup', function(e) {
$('.resizable').removeClass('resizable');
});
e.preventDefault();
});
});
}
})(jQuery);
You would probably need to tweak this a little, but it's mostly all there.

Categories