How to make a element follow another element when dragging with jquery? - javascript

I need make a element follow another element when dragging, but with delay in the animation, is similar to "Chat heads of facebook's messenger", you know, the bubbles on Android.
This is my jQuery plugin:
// Draggable plugin
(function($) {
$.fn.drag = function(options) {
options = $.extend({
handle: null,
cursor: 'move',
draggingClass: 'dragging',
heads: null
}, options);
var $handle = this,
$drag = this;
if( options.handle ) {
$handle = $(options.handle);
}
$handle
.css('cursor', options.cursor)
.on("mousedown", function(e) {
var x = $drag.offset().left - e.pageX,
y = $drag.offset().top - e.pageY,
z = $drag.css('z-index');
$drag.css('z-index', 100000);
$(document.documentElement)
.on('mousemove.drag', function(e) {
var chats = $($(options.heads).get().reverse());
chats.each(function(i) {
$(chats[i]).css({ left: $drag.position().left - (10*i)});
$(chats[i]).css({top: $drag.position().top});
});
$drag.offset({
left: x + e.pageX,
top: y + e.pageY
});
})
.one('mouseup', function() {
$(this).off('mousemove.drag');
$drag.css('z-index', z);
var window_width = $(window).width();
var window_height = $(window).height();
var head_wpostion = $(options.heads).position().left;
var head_hposition = $(options.heads).position().top;
if( head_wpostion > (window_width / 2) )
{
$(options.heads).animate({left: (window_width-40)+"px"}, 300 );
$(options.heads).animate({left: (window_width-50)+"px"}, 300 );
}
else
{
$(options.heads).animate({left: "-15px"}, 300 );
$(options.heads).animate({left: "-5px"}, 300 );
}
if( head_hposition > (window_height - 50) )
{
$(options.heads).animate({top: (window_height-75)+"px"}, 200 );
$(options.heads).animate({top: (window_height-65)+"px"}, 200 );
}
if( head_hposition < 0 )
{
$(options.heads).animate({top: "15px"}, 150 );
$(options.heads).animate({top: "5px"}, 150 );
}
});
// disable selection
e.preventDefault();
});
};
})(jQuery);

the only way you can do that is if you position the element you want to to be dragged along relevant to the drag-able element.

Related

Run function for every repeated class on the same page

I've created the following functionality where an image is fixed on the left while scrolling the content and the quote appears for a few pixels.
It's working all right, the only problem is that I'd like to add this many times on the same page and, as it is, it just works with the first image.
The second one is not fixed while scrolling and the quote maintains hidden...
How can I make run this function for every image?
This is a working example
HTML:
<section id="cont_quote" class="maxwidth">
<article class="cont_q hasImage">
<p>Content</p>
<img class="alignleft img_quote" src="/large.jpg" alt="" width="433" height="553" />
<blockquote>
<h3>Why this training plan works</h3>
</blockquote>
<p>Content</p>
</article>
</section>
JS:
// Stick image on scroll
$(window).on('load resize', function () {
if ($(window).width() >= 769) {
var $element = $('#cont_quote');
var $follow = $element.find('.img_quote');
var followHeight = $element.find('.img_quote').outerHeight();
var height = $element.outerHeight() - 300;
var window_height = $(window).height();
$(window).scroll(function () {
var pos = $(window).scrollTop();
var top = $element.offset().top;
// Check if element is above or totally below viewport
if (top + height - followHeight < pos || top > pos + window_height) {
return;
}
var offset = parseInt($(window).scrollTop() - top);
if (offset > 0) {
$follow.css('transform', 'translateY('+ offset +'px)');
}
})
}
});
// Quote show on viewport
function inViewport( element, viewport = { top: 0, bottom: innerHeight } ){
// Get the elements position relative to the viewport
var bb = element.getBoundingClientRect();
// Check if the element is outside the viewport
// Then invert the returned value because you want to know the opposite
return !(bb.top > viewport.bottom || bb.bottom < viewport.top);
}
var myViewport = { top: innerHeight * .5, bottom: innerHeight * .6 };
var myElement = document.querySelector( '#cont_quote blockquote' );
// Listen for the scroll event
document.addEventListener( 'scroll', event => {
// Check the viewport status
if( $(window).width() >= 600 ){
if( inViewport( myElement, myViewport ) && $('.cont_q').hasClass('hasImage') ) {
if( $(window).width() >= 769 ){
myElement.style.opacity = 1;
myElement.style.left = '-25%';
} else {
myElement.style.opacity = 1;
myElement.style.left = '-5%';
}
} else if( inViewport( myElement, myViewport )) {
if( $(window).width() >= 769 ){
myElement.style.opacity = 1;
myElement.style.left = '-15%';
} else {
myElement.style.opacity = 1;
myElement.style.left = '13%';
}
} else {
myElement.style.opacity = 0;
myElement.style.left = '-40%';
}
} else {
myElement.style.opacity = 1;
myElement.style.left = '5%';
}
});

Set top of page to 340px from top with jQuery

Currently I have a script which starts a progress bar the moment a user starts scrolling.
Is it possible to change this to when the user gets to 340px from the top of the page?
Here is a demo of my site: http://pixsols.com/test/wordpress/reading-progress/
Here is my current code:
(function ( $ ) {
$.fn.progressScroll = function(options) {
var settings = $.extend({
fontSize : 20,
color : '#009ACF',
height : '5px',
textArea : 'dark',
}, options);
// element state info
var docOffset = $(this).offset().top,
elmHeight = $(this).height(),
winHeight = $(window).height();
// listen for scroll changes
$(window).on('scroll', function() {
var docScroll = $(window).scrollTop(),
windowOffset = docOffset - docScroll,
viewedPortion = winHeight + docScroll - docOffset;
if($(window).scrollTop() > 0) {
if($('.scrollWrapper').hasClass('hidden')) {
$('.scrollWrapper').removeClass('hidden').hide();
$('.scrollWrapper').slideDown('slow');
}
} else {
$('.scrollWrapper').slideUp('slow');
$('.scrollWrapper').addClass('hidden');
}
if(viewedPortion < 0) { viewedPortion = 0; }
if(viewedPortion > elmHeight) { viewedPortion = elmHeight; }
// calculate viewed percentage
var viewedPercentage = viewedPortion / elmHeight;
// set percent in progress element
$('.scroll-bar').css('width', (viewedPercentage*100)+'%' );
});
var self = this;
$(window).on('resize', function() {
docOffset = $(self).offset().top;
elmHeight = $(self).height();
winHeight = $(window).height();
$(window).trigger('scroll');
});
$(window).trigger('scroll');
var $el = $('.scroll-bar').css(settings);
return $el;
};
}( jQuery ));
My guess would be to manipulate this:
windowOffset = docOffset - docScroll,
Probably you should add or subtract 320px from windowOffset. So for example"
windowOffset = docOffset - docScroll + 320,

jQuery addClass only affecting current item

I use this code to make a slider function.
$(function() {
$(".slider").draggable({
axis: 'x',
containment: 'parent',
drag: function(event, ui) {
if (ui.position.left > 200) {
$(".well").fadeOut(500, function(){
$( ".well" ).delay(1000).addClass( "disappear" );
$( ".showup" ).delay(500).removeClass( "disappear" );
});
} else {
// $("h2 span").css("opacity", 100 - (ui.position.left / 5))
}
},
stop: function(event, ui) {
if (ui.position.left < 201) {
$(this).animate({
left: 0
})
}
}
});
$('.slider')[0].addEventListener('touchmove', function(event) {
event.preventDefault();
var el = event.target;
var touch = event.touches[0];
curX = touch.pageX - this.offsetLeft - 40;
if(curX <= 0) return;
if(curX > 200){
$('.well').fadeOut();
$(".well").addClass( "disappear" );
$('.well').add('<h2>Erbjudandet använt</h2>');
}
el.style.webkitTransform = 'translateX(' + curX + 'px)';
}, false);
$('.slider')[0].addEventListener('touchend', function(event) {
this.style.webkitTransition = '-webkit-transform 0.3s ease-in';
this.addEventListener( 'webkitTransitionEnd', function( event ) { this.style.webkitTransition = 'none'; }, false );
this.style.webkitTransform = 'translateX(0px)';
}, false);
});
Here is my HTML for displaying the slider:
return "<link rel='stylesheet' href='http://www.infid.se/wp-content/themes/simplemarket/anvandstyle.css'>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'></script>
<script src='http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js'></script>
<script src='http://www.infid.se/wp-content/themes/simplemarket/slidetounlock.js'></script>
<div id='page-wrap'>
<div class='showup disappear'><h2>Erbjudande använt</h2></div>
<div class='well'>
<h2><strong class='slider'></strong> <span>Använd erbjudande</span></h2>
</div>
</div>";
The problem here is that I have about 100 of these sliders, and when slider is activated(The "disappear" class makes it disappear, and the h2 is added on), all of them disappears. Is there a way to make the "disappear" class only affect the current item?
You need to select the element relative to the current slider so change.
$('.well').fadeOut();
$(".well").addClass( "disappear" );
$('.well').add('<h2>Erbjudandet använt</h2>');
to
$well = $(this).closest('.well'); //Select only the respective well element.
$well.fadeOut();
$well.addClass( "disappear" );
$well.add('<h2>Erbjudandet använt</h2>');
.....
$well.prev(".showup").delay(500).removeClass( "disappear" );
Similarly you can change this in other events as applicable.
$(".slider").draggable({
axis: 'x',
containment: 'parent',
drag: function(event, ui) {
if (ui.position.left > 200) {
var $well = $(this).closest('.well');
$well.fadeOut(500, function(){
$well.delay(1000).addClass( "disappear" );
$well.prev(".showup").delay(500).removeClass( "disappear" );
});
} else {
// $("h2 span").css("opacity", 100 - (ui.position.left / 5))
}
},
stop: function(event, ui) {
if (ui.position.left < 201) {
$(this).animate({
left: 0
})
}
}
});
$('.slider')[0].addEventListener('touchmove', function(event) {
event.preventDefault();
var el = event.target;
var touch = event.touches[0];
curX = touch.pageX - this.offsetLeft - 40;
if(curX <= 0) return;
if(curX > 200){
var $well = $(this).closest('.well');
$well.fadeOut();
$well.addClass( "disappear" );
$well.add('<h2>Erbjudandet använt</h2>');
}
el.style.webkitTransform = 'translateX(' + curX + 'px)';
}, false);
Fiddle

Animation flickers with Firefox 18.0.1 (due to RequestAnimationFrame?)

i used this http://www.netmagazine.com/tutorials/create-interactive-street-view-jquery tutorial to create an intro for one of our customers:
http://f-bilandia.de/kunstmann/bronski/
It used to work really good on all browsers. When I updated to the newest stable version of Firefox (FF 18.0.1) however, there is heavy flickering while changing the images.
When reading the release notes of the newest version, i saw that ff has a new Javascript engine and has improved image quality with a new HTML scaling algorithm. Maybe it's because of that? Other possible solutions?
Below you can see the code i've used:
$(document).ready(function(){
var $doc = $(document);
var $win = $(window);
// dimensions - we want to cache them on window resize
var windowHeight, windowWidth;
var fullHeight, scrollHeight;
var streetImgWidth = 1024, streetImgHeight = 640;
calculateDimensions();
var currentPosition = -1, targetPosition = 0;
var $videoContainer = $('.street-view');
var video = $('.street-view > img')[0];
var $hotspotElements = $('[data-position]');
// handling resize and scroll events
function calculateDimensions() {
windowWidth = $win.width();
windowHeight = $win.height();
fullHeight = $('#main').height();
scrollHeight = fullHeight - windowHeight;
}
function handleResize() {
calculateDimensions();
resizeBackgroundImage();
handleScroll();
}
function handleScroll() {
targetPosition = $win.scrollTop() / scrollHeight;
}
// main render loop
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
function animloop(){
if ( Math.floor(currentPosition*5000) != Math.floor(targetPosition*5000) ) {
currentPosition += (targetPosition - currentPosition) / 5;
render(currentPosition);
}
requestAnimFrame(animloop);
}
// rendering
function render( position ) {
// position the elements
var minY = -windowHeight, maxY = windowHeight;
$.each($hotspotElements,function(index,element){
var $hotspot = $(element);
var elemPosition = Number( $hotspot.attr('data-position') );
var elemSpeed = Number( $hotspot.attr('data-speed') );
var elemY = windowHeight/2 + elemSpeed * (elemPosition-position) * scrollHeight;
if ( elemY < minY || elemY > maxY ) {
$hotspot.css({'visiblity':'none', top: '-1000px','webkitTransform':'none'});
} else {
$hotspot.css({'visiblity':'visible', top: elemY, position: 'fixed'});
}
});
renderVideo( position );
}
function resizeBackgroundImage(){
// get image container size
var scale = Math.max( windowHeight/streetImgHeight , windowWidth/streetImgWidth );
var width = scale * streetImgWidth , height = scale * streetImgHeight;
var left = (windowWidth-width)/2, top = (windowHeight-height)/2;
$videoContainer
.width(width).height(height)
.css('position','fixed')
.css('left',left+'px')
.css('top',top+'px');
}
// video handling
var imageSeqLoader = new ProgressiveImageSequence( "street/vid-{index}.jpg" , 387 , {
indexSize: 4,
initialStep: 16,
onProgress: handleLoadProgress,
onComplete: handleLoadComplete,
stopAt: 1
} );
// there seems to be a problem with ie
// calling the callback several times
var loadCounterForIE = 0;
imageSeqLoader.loadPosition(currentPosition,function(){
loadCounterForIE++;
if ( loadCounterForIE == 1 ) {
renderVideo(currentPosition);
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
}
});
var currentSrc, currentIndex;
function renderVideo(position) {
var index = Math.round( currentPosition * (imageSeqLoader.length-1) );
var img = imageSeqLoader.getNearest( index );
var nearestIndex = imageSeqLoader.nearestIndex;
if ( nearestIndex < 0 ) nearestIndex = 0;
var $img = $(img);
var src;
if ( !!img ) {
src = img.src;
if ( src != currentSrc ) {
video.src = src;
currentSrc = src;
}
}
}
$('body').append('<div id="loading-bar" style="">Loading...</div>');
function handleLoadProgress() {
var progress = imageSeqLoader.getLoadProgress() * 100;
$('#loading-bar').css({width:progress+'%',opacity:1});
}
function handleLoadComplete() {
$('#loading-bar').css({width:'100%',opacity:0,display: "none"});
$("html, body").css("overflow", "auto");
$("html, body").css("overflow-x", "hidden");
$("nav").css("display", "block");
$("#preloader").fadeOut("slow");
$("#scroll-hint").css("display", "block");
}
$win.resize( handleResize );
$win.scroll( handleScroll );
handleResize();
animloop();
});
Inside your "render( position )" function the following lines seem like they should be refactored.
if ( elemY < minY || elemY > maxY ) {
$hotspot.css({'visiblity':'none', top: '-1000px','webkitTransform':'none'});
} else {
$hotspot.css({'visiblity':'visible', top: elemY, position: 'fixed'});
}
For one visibility is spelled wrong and there is no "none" value for it (it would be "hidden"). Just use "display" with "none" and "" values.
The "top", "webkitTransform", and "position" keys seem unnecessary. If the element is not visible there's no need to set the top, and why wouldn't the element always be fixed position?

Find the place of a cursor in rectangle

I don't know how to find the place part (one of 4 triangles) of a cursor in a rectangle.
This image is more efficient than my explication :s
Im in javascript (so the rectangle is a DIV, 0,0 placed)
I have those varaibles :
var cursor_x = e.clientX + $(document).scrollLeft()
var cursor_y = e.clientY + $(document).scrollTop()
var rect_w = $( rectangle ).width()
var rect_h = $( rectangle ).height()
I just want to know mathematically where is the cursor, in the triangle 1, 2, 3 or 4
What I think is the easiest way is to first normalize y so the computation is the same as for a square and then check for on which side of the diagonals you are...
var ynorm = y * w / h;
var s1 = x > ynorm ? 0 : 1;
var s2 = (w - x) > ynorm ? 0 : 1;
var area = s1*2 + s2;
the final area variable is a number between 0 and 3 telling in which of the four parts you are.
#6502: Thk you, its very helpful.
For more info, im working on an experimental light sortable jquery plugin, that can work with floating placement (top, left, right, bottom)
the code :
simply use $( ..selector.. ).sortable({ items: ..selector.. })
-
$.fn.sortable = function( o ) {
o.self = this;
o.helper = null;
$(document).bind('mouseup.sortable', function(e) {
if( o.sortable ) {
o.sortable.css({ opacity: ''});
if( o.target ) {
if( o.area == 's' ) {
o.sortable.css({ float: '' })
}
else if( o.area == 'n' ) {
o.sortable.css({ float: '' })
o.target.css({ float: '' })
}
else if( o.area == 'w' ) {
o.target.css({ float: 'left' })
o.sortable.css({ float: 'left' })
}
else if( o.area == 'e' ) {
o.target.css({ float: 'left' })
o.sortable.css({ float: 'left' })
}
o.target[ o.area == 's' || o.area == 'e' ? 'before':'after']( o.sortable );
o.target[0].style.setProperty( 'cursor', false , false);
o.target = null;
}
o.helper.remove();
o.sortable = null;
}
}).bind('mousemove.sortable', function(e) {
if( o.sortable ) {
o.ex = e.clientX + $(document).scrollLeft() + 10
o.ey = e.clientY + $(document).scrollTop() - o.sortable[0]._height - 10
o.helper.css({ left: o.ex, top: o.ey });
}
});
return $( this.selector ).delegate( o.items, 'mousemove.sortable', function(e) {
if( o.sortable && o.sortable[0] != this ) {
var self = $(this)
var x = e.clientX + $(document).scrollLeft() - self.offset().left
var y = e.clientY + $(document).scrollTop() - self.offset().top
var w = self.width()
var h = self.height()
var ynorm = y * w / h;
o.area = (w - x) > ynorm ? ( x > ynorm ? 's':'e' ) : ( x > ynorm ? 'w':'n' );
this.style.setProperty( 'cursor', o.area+'-resize', 'important');
o.target = self;
}
}).delegate( o.items, 'mousedown.sortable', function( e ) {
o.sortable = $(this).css({ opacity: 0.4 });
this._width = o.sortable.width();
this._height = o.sortable.height();
o.helper = o.sortable.clone().css({ position: 'absolute', left: -99999, top: 0 })
$('body').append( o.helper )
return false;
});
}

Categories