Animate element, but keep container centered - javascript

I am currently working on a custom lightbox script and need some assistance. I have the animation for the image resizing working great, but I ran into a small problem. The lightbox is shown in the middle of the user's screen, but as soon as I animate the width and height, it doesn't remain in the center of the screen, and just uses the old left and top values.
Here's the markup for the lightbox itself:
<div id="jqgal_container">
<div id="jqgal_nav_left" class="jqgal_nav"><</div>
<div id="jqgal_main">
<div id="jqgal_main_img"></div>
<div id="jqgal_footer">
<div id="jqgal_main_caption"><p></p></div>
<div id="jqgal_thumbnav_left" class="jqgal_thumbnav"><</div>
<div id="jqgal_thumbs">
<div id="jqgal_thumbs_container">
<ul></ul>
</div>
</div>
<div id="jqgal_thumbnav_right" class="jqgal_thumbnav">></div>
</div>
</div>
<div id="jqapp_nav_right" class="jqgal_nav">></div>
</div>
The image to be displayed is stored within the #jqgal_main_img as an <img /> element. I animate the width and height of #jqgal_main_img, but I also want to keep the whole container (#jqgal_container) centered on the screen.
My question is, how can I animate the width of the child element, yet still animate the top and left positions of the container respectively, so it appears to expand and grow from the centre?
The code to animate the width and height of the image container at the moment looks as follows:
_resizeToFit : function(img_width, img_height, compFunc)
{
// Calculate the width and height needed:
var req_width = img_width;
var req_height = img_height;
this._elements.mainimg.animate({ width: req_width }, {
duration: 'fast',
complete: function() {
$.jqgal._elements.footer.width(req_width);
$.jqgal._elements.mainimg.animate({ height: req_height }, 'fast', function() {
if(compFunc != undefined) { compFunc.call(this); }
});
},
step : function() {
}
});
}

Also animate the margin-left and margin-top:
"margin-left" : ($(window).width() - req_width) / 2
"margin-top" : ($(window).height() - req_height) / 2
If the elements CSS position is 'absolute', change margin-top / margin-left to top and left.
EDIT:
At the end of the whole 'animate' string, add
.parent().animate({
"margin-left" : )($(window).width() - req_width) / 2) + this._elements.mainimg.parent().scrollLeft(),
"margin-top" : (($(window).height() - req_height) / 2 ) + this._elements.mainimg.parent().scrollTop()
}}
Or in the callback function:
$(this).parent().animate({...});
For ease, it might be best to set variables holding the elements too...
$this = this._elements.mainimg;
$parent = $this.parent();
Then the parent animate() data would look like this:
"margin-left" : )($(window).width() - req_width) / 2) + $parent.scrollLeft(),
"margin-top" : (($(window).height() - req_height) / 2 ) + $parent.scrollTop()
}}
Which is a little easier to read!

i think you should Animate too the margin's and left distance.

Related

Sticky sidebar from bottom during scrolling

I'm planning to recreate the Medium.com like sidebar. This is what I have now but it's far from over.
Open the JSFiddle below to understand better; I am looking to do the following:
When you scroll down, it suddenly sticks to the bottom. How do I make it stick gradually as you scroll?
Because it uses position: fixed, it moves towards the right side without respecting the layout. How do I fix this?
When you scroll up and there's less space, it overlaps with the header as shown in the screenshot. Again, most likely because position: fixed is used.
How do I fix this? I know there's sticky-kit that does the work but I can't use any plugin.
HTML:
<div class="container">
<div class="row">
<div class="col-xs-12">
Header and Menu is placed here.
<hr />
</div>
<div class="col-xs-8">
<p>This is the main body which the user would be scrolling infinitely as more data gets loaded on scroll.</p>
</div>
<div class="col-xs-4">
<div id="sidebar">
<p>
This is the sidebar which I want to stop when it reaches the bottom like the one shown in medium dot com
</p>
</div>
</div>
</div>
</div>
Javascript:
function scrollCheck() {
var $right = $('#sidebar'),
scrollTop = $(window).scrollTop(),
windowHeight = $(window).height(),
docHeight = $(document).height(),
rightHeight = $right.height(),
distanceToTop = rightHeight - windowHeight,
distanceToBottom = scrollTop + windowHeight - docHeight;
if (scrollTop > distanceToTop) {
$right.css({
'position': 'fixed',
'bottom': (scrollTop + windowHeight > docHeight ? distanceToBottom + 'px' : '0px')
});
}
else {
$right.css({
'position': 'relative',
'bottom': 'auto'
});
}
}
$(window).bind('scroll', scrollCheck);
JSFIDDLE
I'll answer what questions of yours I could. Here is the edited Fiddle first.
As for your questions:
The sudden sticking to the bottom is caused because the element isn't the full length of the page so sticking it to the bottom with a fixed position will cause it to jump there. Whereas with the change I made so it sticks to the top there won't have this jump, as the element is at the top of the screen when scrolling so it can be discreetly fixed there.
This was because the element didn't have a fixed width and setting position: fixed; means that the elements width is no longer set by the parent, but the view port. So it expands to fill all the width in the view port it can.
This was happening because the position: fixed; was never removed when scrolling back above the elements original position, the updated if statement in the Js now removes the class with position: fixed; when scrolling above its original location.
A more detailed look into what I changed.
I added a CSS class so .toggleClass could be used to make the function cleaner.
.docked-sidebar {
position: fixed;
top: 0;
}
I also changed the conditions for the if statement so that they worked. Using .offset().top; to get the distance between the sidebar and the top of the page, while removing most of the other variables as they weren't needed. Finally I created bool variable(isDocked) so that the same condition isn't triggered multiple times.
var $right = $('#sidebar'),
isDocked = false,
initOffsetTop = $right.offset().top;
function scrollCheck() {
var scrollTop = $(window).scrollTop(),
offsetTop = $right.offset().top;
if (!isDocked && ((offsetTop - scrollTop) < 0)) {
$right.toggleClass("docked-sidebar");
isDocked = true;
} else if (isDocked && scrollTop <= initOffsetTop) {
$right.toggleClass("docked-sidebar");
isDocked = false;
}
}
For sticking to the bottom and then to the top exactly like the example website I recommend checking this question.

How to use jQuery scroll to change the height of an element?

I have a HTML class navigation with the initial height of 100px and min-height is 40px. I want to change the height of the class, based on the scroll (if scroll down than size will decrease and if scroll up than size will increase). I use the following code and it's working perfectly.
$(window).scroll( function() {
if( $('.navigation').offset().top > 50 )
{
$('.navigation').css({
'height' : '40px',
'background' : 'rgba(37, 37, 37, 0.9)'
});
} else {
$('.navigation').css({
'height' : '100px',
'background' : '#b24926'
});
}
});
If I press the keyboard down arrow key two times than navigation class moved from original height to minimum height and if the up arrow key press two times than navigation class moved from minimum height to original height.
But I want to make the scroll more smooth (like 4-5 up or down key presses to reach from one height to another).
For example: initial height is: 100px and minimum height is 30px. Now:
if down arrow key is pressed/mouse wheel is move down one time than height will be 85px, if again down arrow is pressed height will be 70px and so on. That means for each down arrow key is pressed/mouse wheel is move down than height will decrease by 15-20px and for each up arrow key is pressed/mouse wheel is move up, height will increase by 15-20px.
Can anyone tell me how can I do that (without using third party api).
Thanks
You can use simple percent calculation to update height
var limitForMinimalHeight = 400; //after this distance navigation will be minimal height
var maxHeight = 100;
var minHeight = 40;
$(window).scroll( function() {
var screenTop = $(document).scrollTop();
var achievedDistancePercent = Math.min(screenTop*100/limitForMinimalHeight, 100);
var amounToAdd = ((maxHeight - minHeight) * (100 - achievedDistancePercent))/100;
var newHeight = minHeight + amounToAdd;
$('.navigation').height(newHeight);
});
You can test it on JSFiddle
$(document).scroll(function() {
if($(this).scrollTop()>100) {
$('.selector').addClass('scrolled');
}
if($(this).scrollTop()<40) {
$('.selector').removeClass('scrolled');
}
});

Hover direction according to container size

I would like to alter the hover direction based on the container size, if there's not enough space on the container to show the hover to the right, it should then show on the left.
See fiddle for details:
http://jsfiddle.net/jHgkp/3/
I use hoverIntent, but FULL details are on the Fiddle above:
$(document).ready(function(){
$(".discover").hoverIntent({
over: makeVisible,
out: makeInvisible,
timeout: 200
});
}); // close document.ready
function makeVisible() {
$(this).find('ul').fadeIn(100);}
function makeInvisible() {
$(this).find('ul').fadeOut(300);}
There are a few approches.
1) You can style the tooltip on the third element to show on the left side (not dynamic)
2) You can take the element offest().left + element.width + the tooltip width and compare it with the holder width. (dynamic)
3) Yo can the the tooltip offest + width and directly compare it to the holder width. (dynamic)
It depends what exactly you want...
This is the only JS added.
var holderWidth = $('.container').outerWidth();
and
//where 260 is left 150 + width 110
var pos = $(this).offset().left + 260
if(holderWidth < pos){
$(this).addClass('leftPos');
}else{
$(this).removeClass('leftPos');
}
and 1 line of css:
.leftPos ul { left: auto; right: 150px; }
Demo

element.height returns visible height - I want total?

So apparently this is only happening to me - and I can't think why but if it works, I'm happy :)
I have a full screen slideshow and I have created a function that will vertically center any images that are too large.
function fixImages(){
maxheight = $('.index-slide-container').height();
$('.index-slide-container img').each( function(index, ele){
if (ele.height > maxheight){
offset = ( maxheight - ele.height ) / 2;
$(ele).css('top', offset + 'px');
}
});
}
fixImages();
However, ele.height returns the height of the visible part of the image (the height of it's container, as it has overflow:hidden, even though when I console.log(ele) and expand the element, 'height' is clearly the correct value.
I have also tried $(ele).height(), $(ele).css('height'), $(ele).outerHeight() and ele.clientHeight; all of which return the same.
Thanks
I made some tests, and $('img').height(); is giving me the right height of the picture.
If you wish to center the picture vertically why don't you use the absolute positioning with css like this for example :
.index-slide-container img {
position:absolute;
top:50%;
}
And than, you could set the negative margin programmatically with jQuery :
$('.index-slide-container img').each( function(i, e){
var height = $(e).height() / 2;
$(e).css({'margin-top':'-'+height});
});

jQuery: Animate Margins to Auto?

I'm trying to animate an image so that it centers itself. Here's the code I'd like to use:
$('#myImage').animate({'margin-right': 'auto'});
But when I do that, it's ignored and doesn't change the margin.
Is there a way to animate a margin to auto, or otherwise center an image?
Thanks!
As 'auto' isn't a number, jQuery cannot animate it.
If you are okay with taking the image out of the flow of the document, you can set position to absolute or fixed and try:
$('#myImage').animate({'left': '50%', 'margin-left': -$('#myImage').width()/2 });
You cannot animate an auto property. To properly animate the element to the center of the screen you will need to position it absolutely (or other) and then calculate the screen size, element size, and scroll position. Here is a another SO answer on something similar. Here is the Fiddle
jQuery.fn.center = function () {
this.css("position","absolute");
var top = ( $(window).height() - this.height() ) / 2+$(window).scrollTop() + "px",
left = ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px";
this.animate({top: top, left: left});
return this;
}
Alternatively if you only want the horizontal alignment you can remove the top from the animate function. And if you really want to get creative you can remove the position:absolute, and reposition margin:auto after the animation in case of screen resizing. See another fiddle.
jQuery.fn.center = function () {
this.css("position","absolute");
var left = ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px";
this.animate({left: left}, function(){
$(this).css({position: 'static', margin: '0 auto'});
});
return this;
}
$('#selector').center();
Expanding on Josiah Ruddell's answer. If you guys need your image to keep its flow in the document, use this modified version of Josiah's answer. My image was originally positioned at margin: 0 -1000px, and slides in to the calculated margin left and right. While keeping its flow in the dom the whole time
jQuery.fn.center = function () {
var margin = ( $(window).width() - this.width() ) / 2;
this.animate({
marginLeft: margin,
marginRight: margin
}, function(){
$(this).css({margin: '0 auto'});
});
return this;
}

Categories

Resources