CSS3/JS get position of element during animation - javascript

I need to get position of element like (with jQuery)
$(".mydiv").position().left;
However I need to do it during css3 translate animation. This animation translate of div position is included in position() data.
Is it possible to get position of element during animation, but position without any translations (just like there would be no animation)?

Edit
"I'm not using .animate for simple animations since css3. – Kluska000"
Should still be able to utilize jquery's animate() start, step, progress callback functions - even though actual animation done at css. e.g., could utilize .animate() at target element - without actually animating the element - only to utilize start, step, progress callback functions; with duration synced to css animations duration . Also, appear that jquery .animate() does not actually require that a target be a DOM element; could be 2 js objects.
See also window.requestAnimationFrame()
https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
Try (see console at jsfiddle, linked below)
$(function() {
$(".mydiv").animate({
left :"0px"
}, {
duration : 1234,
start : function (promise) {
console.log($(".mydiv").position().left);
},
step : function (now, tween) {
console.log($(".mydiv").position().left);
},
progress : function (promise) {
console.log($(".mydiv").position().left);
},
complete : function () {
$(this).animate({left:"0px"}, 1234)
}
});
});
jsfiddle http://jsfiddle.net/guest271314/xwL7v/
See http://api.jquery.com/animate/ at start , step , progress

well, regardless of how you create your animation, i think the best way would be to create an animation class and attach it as soon as dom loads, but only after recording the position for later use.
basically it would give you the same effect as if you set the animation right away, but you will have a record of all the details for later use:
Live Demo: Fiddle
ps: i made the demo for chrome, just change/remove the -webkit- for other browsers as needed:
-webkit-: chrome, safari
-moz-: firefox
-ms- : internet explorer
-o-: opera
without prefix: default
html:
<div id="status_div"> </div>
<div id="slider"></div>
css:
* {
margin:0;
padding:0;
}
#slider {
width:100px;
height:100px;
display:block;
background:red;
}
.SliderAnim {
-webkit-animation:some_animation 2000ms linear forwards;
}
#status_div {
position:relative;
left:0;
top:0;
width:100%;
height:auto;
border:2px solid navy;
color:black;
}
#-webkit-keyframes some_animation {
from {
-webkit-transform:translateX(-100px);
}
to {
-webkit-transform:translateX(100px);
}
}
js:
$(function () {
// those are the position and offset before animation was attached
var pX = $("#slider").position().left;
var pY = $("#slider").position().top;
var oX = $("#slider").offset().left;
var oY = $("#slider").offset().top;
// those are declarations for vars which will store the position and offset
// of the element right after attaching the animation, and will result in the values
// of the first fram of the animation
var npX = 0;
var npY = 0;
var noX = 0;
var noY = 0;
// this is a timer function to write the details on the status bar
setInterval(function () {
// those are the position and offset of the element during the animation
var apX = $("#slider").position().left;
var apY = $("#slider").position().top;
var aoX = $("#slider").offset().left;
var aoY = $("#slider").offset().top;
//print status bar info
$("#status_div").html("BEFORE ATTACHING ANIMATION position: " + pX + "," + pY + " offset: " + oX + "," + oY + " <br/> AFTER ATTACHING ANIMATION position: " + npX + "," + npY + " offset: " + noX + "," + noY + "<br/> DURING ANIMATION position: " + apX + "," + apY + " offset: " + aoX + "," + aoY);
}, 100);
//attach the animation class to the slider div
$("#slider").addClass("SliderAnim");
//record the changed (will result in the first animation frame)
npX = $("#slider").position().left;
npY = $("#slider").position().top;
noX = $("#slider").offset().left;
noY = $("#slider").offset().top;
});

Related

Parallax background image for top-bottom and not right-left

I wrote a script that changes the BG position as you scroll down, its works good for left and right positions but i cant seem to reach the syntax that will allow me to parallax the background-position top or bottom - instead of right and left.
here is my code:
function parallax(){
var scrolled = $(window).scrollTop();
$('section.intro .custombg').css('background-position',(scrolled * -0.2) + 'px');}
$(window).scroll(function(e){
parallax();
});
}
The css attribute background-position has two values, #horizontal #vertical.
See: http://www.w3.org/wiki/CSS/Properties/background-position
Consider something like:
function parallax(){
var scrolledTop = $(window).scrollTop();
var scrolledLeft = $(window).scrollLeft();
$('section.intro .custombg').css('background-position',(scrolledLeft * -0.2) + 'px ' + (scrolledTop * -0.2) + 'px');}
$(window).scroll(function(e){
parallax();
});
}
Also, this seems like it will add the scroll event every time the parallax method is called. To correct this, you could try:
function parallax(top, left) {
$('section.intro .custombg').css('background-position',(left * -0.2) + 'px ' + (top * -0.2) + 'px');}
} // end function
$(document).ready(function() {
$(window).scroll(function(e) {
parallax($(window).scrollTop(), $(window).scrollLeft()); // call the method
});
});
This is all wrong, you are setting up an event handler each time you use $(window).scroll(). You only need to do that once. Try this.
var scrolledTop,
scrolledLeft,
background_position,
$custom_bg;
function parallax(){
scrolledTop = window.scrollY,
scrolledLeft = window.scrollX,
background_position = (scrolledLeft * -0.2) + 'px ' + (scrolledTop * -0.2) + 'px');
console.log('background_position', background_position);
$custom_bg.css('background-position', background_position);
}
$(function() {
$custom_bg = $('section.intro .custombg');
$(window).on('scroll', parallax);
});
try
function parallax(){
var scrolled = $(window).scrollTop();
$('section.intro .custombg').css('background-position','center ' + (scrolled * -0.2) + 'px');}
$(window).scroll(function(e){
parallax();
});
}
If you're looking to do more with parallax and change other properties as, I'd highly recommend the Skrollr library (https://github.com/Prinzhorn/skrollr).
You can vary almost any CSS property as you scroll, giving you more options than just background position or something else. It might be more than you're looking for, but it's pretty lightweight and has mobile support, too (which you could have trouble accounting for without a well-developed library). Hope it helps!
For example, if you wanted to shift the background-position of a background image, you could simply do the following:
initialize skrollr (in this case without options, but there are parameters you can set)
<script type="text/javascript">
var s = skrollr.init();
</script>
Then, you're able to use simple data-tags to tell Skrollr which elements you want to make fancy and which you don't. In your case, you could do something vaguely like the following:
(whatever element you want to use parallax on)
<div data-0="background-color:rgb(0,0,255);transform[bounce]:rotate(0deg);" data-500="background-color:rgb(255,0,0);transform[bounce]:rotate(360deg);">
WOOOT
</div>
However, you'd swap background-color out for background-position
<div data-0="background-position: 0px 0px" data-700="background-position: 0px 100px"> </div>
or
<div data-0="background-position: top center" data-700="background-position: bottom center"> </div>
You can use any of the accepted CSS background-position keywords.
Useful:
https://github.com/Prinzhorn/skrollr

Matching div height to combined height of other divs

I'm trying to match the height of background div to the combined height of divs in front. I used simple jQuery height function and it kind of worked:
var originalHeight = $("#topbg").height() + $("#menurowbg").height() + $("#headerbg").height() + $("#contentareabg").height() + $("#footerbg").height();
$("#wrapper").height(originalHeight);
The problem is, the height needs to change dynamically if one of those divs is resized to keep matching. I tried to put the setTimeout function, but failed. I'm obviously missing something but can't figure it out. Please help this jQuery rookie. Here's my current code:
var originalHeight = $("#topbg").height() + $("#menurowbg").height() + $("#headerbg").height() + $("#contentareabg").height() + $("#footerbg").height();
setTimeout function checkHeight() {
if(originalHeight < ($("#topbg").height() + $("#menurowbg").height() + $("#headerbg").height() + $("#contentareabg").height() + $("#footerbg").height()))
{
originalHeight = $("#topbg").height() + $("#menurowbg").height() + $("#headerbg").height() + $ ("#contentareabg").height() + $("#footerbg").height();
}
}, 500);
$("#wrapper").height(originalHeight);
There are three scenarios:
1) Use setInterval() rather than setTimeout() to execute code ever X amount of milliseconds:
setInterval(function() {
setContainerSize();
}, 1000);
Example: http://jsfiddle.net/XWmdL/3/
2) The containing div is the parent of the divs being resized. In that case, You don't have to add all the heights together and reset the container's height. You can just set the container's width and height attributes to auto:
#container {
width: auto;
height: auto;
}
Example: http://jsfiddle.net/XWmdL/1/
3) If your child divs are being resized when the window size changes, you need to use the $(window).resize() event. Change the viewing window size in the following example and you'll see the red background size change as the yellow div changes.
Example: http://jsfiddle.net/XWmdL/2/
Hope this helps!
First the condition is wrong
setTimeout function checkHeight() {
if(originalHeight < (jQuery("#topbg").height() + jQuery("#menurowbg").height() + jQuery("#headerbg").height() + jQuery("#contentareabg").height() + jQuery("#footerbg").height())) {
originalHeight = jQuery("#topbg").height() + jQuery("#menurowbg").height() + jQuery("#headerbg").height() + jQuery("#contentareabg").height()+jQuery("#footerbg").height();
jQuery("#wrapper").height(originalHeight);
}, 500);

jQuery .Animate Opacity and .FadeOut/In Both Not Working Inside SetInterval

I trying to make what appears to the user to be an image fader. A string of images fade into each other. All the solutions that I found were complex, and normally required an for every image. I've come up with what should be a simple solution. It's working 90% on Firefox/Chrome/IE11 on Windows. On Android Chrome it's having issues.
Basically my idea is, I have two divs, absolutely positioned, one on top of the other. Both start with a background, sized to cover. The top one fades out, revealing the bottom one, and at the end of the animation, the background-image of the top one (current hidden) is changed to image 3. After a pause, it fades back in, and the background-image of the bottom one is changed to image 4. This repeats indefinitely.
HTML:
<div class="slideshow" id="slideshow-top"></div>
<div class="slideshow" id="slideshow-bottom"></div>
CSS:
.slideshow {
display:block;
background-size:cover;
width: 100%;
height: 100%;
position:absolute;
top:0;
left:0;
}
#slideshow-top {
z-index:-5;
background-image:url(http://www.andymercer.net/wp-content/uploads/2013/12/slider-1.jpg);
}
#slideshow-bottom {
z-index:-10;
background-image:url(http://www.andymercer.net/wp-content/uploads/2013/12/slider-2.jpg);
}
Javascript:
var url_array = [
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-1.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-2.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-3.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-4.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-5.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-6.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-7.jpg',
'http://www.walldoze.com/images/full/2013/12/04/wallpapers-desktop-winter-nature-x-wallpaper-backgrounds-natureabstract-designs-interesting-hd-19045.jpg'
];
var count = 1;
setInterval(function() {
if (count%2) { // Fade In
jQuery('#slideshow-top').animate({opacity:0}, '200000', function() {
jQuery('#slideshow-top').css('background-image','url('+url_array[count]+')');
});
}
else { //Fade Out
jQuery('#slideshow-top').animate({opacity:1}, '200', function() {
jQuery('#slideshow-bottom').css('background-image','url('+url_array[count]+')');
});
}
count = (count == url_array.length-1 ? 0 : count + 1);
}, 2000);
http://jsfiddle.net/5eXy9/
As seen in the Fiddle above, this mostly works. However, it seems to ignore the length of the animation. Using .fadeOut has the same effect. I've tried going from 200 to 20000, and there doesn't seem to be a difference.
I'm not sure if this is tied into the other issue, which is that on Android (Galaxy S4, Chrome, Android 4.x), the animation doesn't occur at all. It simply changes images. Any ideas?
EDIT: Jan 10 - Timing problem is fixed, but the main issue (Android) is still unsolved. Any thoughts?
The interval keeps going, so when increasing the animation speed, you have increase the interval speed as well.
The way you've built this, you should always keep the speed of both animations equal to the interval, or if you need a delay, increase the interval compared to the animations so it at least has a higher number than the highest number used in the animations.
The reason changing the speed doesn't work at all for you, is because it should be integers, not strings, so you have to do
jQuery('#slideshow-top').animate({opacity:0}, 200000, function() {...
// ^^ no quotes
I would do something like this
var url_array = [
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-1.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-2.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-3.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-4.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-5.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-6.jpg',
'http://www.andymercer.net/wp-content/uploads/2013/12/slider-7.jpg',
'http://www.walldoze.com/images/full/2013/12/04/wallpapers-desktop-winter-nature-x-wallpaper-backgrounds-natureabstract-designs-interesting-hd-19045.jpg'];
var count = 1;
var speed = 2000,
delay = 1000;
$.each(url_array, function(source) { // preload
var img = new Image();
img.src = source;
});
setInterval(function () {
if (count % 2) { // Fade In
jQuery('#slideshow-top').animate({
opacity: 0
}, speed, function () {
jQuery('#slideshow-top').css('background-image', 'url(' + url_array[count] + ')');
});
} else { //Fade Out
jQuery('#slideshow-top').animate({
opacity: 1
}, speed, function () {
jQuery('#slideshow-bottom').css('background-image', 'url(' + url_array[count] + ')');
});
}
count = (count == url_array.length - 1 ? 0 : count + 1);
}, speed + delay);
FIDDLE

Lightbox moves image to bottom right corner

I'm writing a lightbox image gallery and struggling with the correct image positioning.
When clicking on an image, the lightbox appears. It's a completely new object generated with JS. By setting the margins, I move it to the screen middle (with z-index).
But these actions are performed before the image got time for loading. So JS doesn't have the required information clientWidth and clientHeight and uses 0 instead. This effects that the top left image corner (which is before loading the same as the other corners as well) is in the middle of the screen.
When the image starts loading, it will be extended to the bottom right.
How do I position the image correctly on the screen?
PS: No connection to the lightbox/lightbox2 library.
PPS: relevant code:
JS:
function lightbox(res, dsc) {
// lbimg: Lightbox-Image
var lbimg = document.createElement("img");
lbimg.src = res;
lbimg.id = "lbimg";
document.body.insertBefore(lbimg, document.body.firstChild);
lbimg.style.marginTop = "-" + Math.floor(lbimg.clientHeight/2.) + "px";
lbimg.style.marginLeft = "-" + Math.floor(lbimg.clientWidth/2.) + "px";
}
CSS:
#lbimg {
max-width: 70%;
max-height: 80%;
position: absolute;
left: 50%;
top: 50%;
border: 10px solid #fff;
z-index : 10;
}
HTML (only miniature images are displayed):
<div class="list">
<div><a onclick="lightbox('image.JPG', ''); "><img class="mini" src="image.JPG_MINI.jpg" /></a></div>
<!--other images are defined analogous-->
</div>
function lightbox(res, dsc) {
var lbimg = document.createElement("img");
lbimg.id = "lbimg";
lbimg.onload = function() {
document.body.insertBefore(lbimg, document.body.firstChild);
lbimg.style.marginTop = "-" + Math.floor(lbimg.clientHeight/2) + "px";
lbimg.style.marginLeft = "-" + Math.floor(lbimg.clientWidth/2) + "px";
};
lbimg.src = res;
}
You have to wrap both the DOM insertion and style setting in a load handler (if you wrap only style changes, you will see element "shifting" after insertion). Also set your src after binding the load handler, otherwise it's possible Internet Explorer will miss the handler (when loading images from cache).
Try wrapping your margin calculations inside an onload call:
lbimg.onload = function () {
lbimg.style.marginTop = "-" + Math.floor(lbimg.clientHeight/2.) + "px";
lbimg.style.marginLeft = "-" + Math.floor(lbimg.clientWidth/2.) + "px";
};
This will ensure that the height and width are available to the JS in order that the margins can be calculated correctly.

Animated PNG background with Javascript, but without loop?

I need help with an animated PNG in Javascript.
I found how to animate a PNG background with Javascript here on Stack Overflow. But my problem is that I only need the animation onmouseover and onmouseout. And the animation should play only once, not in a loop, so when the user moves the mouse over a div the the animation in the background should play once and stop at the last frame, but when the user goes off the div, a reverse animation should play once and stop at the last (first) frame. The script I found here is:
The style:
#anim {
width: 240px; height: 60px;
background-image: url(animleft.png);
background-repeat: no-repeat;
}
The HTML:
<div id="anim"></div>
Javascript:
var scrollUp = (function () {
var timerId; // stored timer in case you want to use clearInterval later
return function (height, times, element) {
var i = 0; // a simple counter
timerId = setInterval(function () {
if (i > times) // if the last frame is reached, set counter to zero
i = 0;
element.style.backgroundPosition = "0px -" + i * height + 'px'; //scroll up
i++;
}, 100); // every 100 milliseconds
};
})();
// start animation:
scrollUp(14, 42, document.getElementById('anim'))
I hope anyone can help me, Thank you
To stop the animation after the first set of frames you do want to change the if condition to not reset the counter to zero but instead to clear the interval and stop it from reoccuring.
To only let it play when you enter an element you can attach the animation function as an event listener and play the whole thing in reverse with another function that you plug into your onmouseout event.
Depending on your target browser and since your question is fairly vague I can recommend two alternatives to you:
Use jQuery animate (all browsers, include ref to jquery)
//Animate to x,y where x and y are final positions
$('#anim').mouseenter(function(e) {
$(this).animate({background-position: x + 'px ' + y + 'px'}, 4200);
})
//Do same for mouseleave
Use a css3 animation (using -webkit browser here)
<style>
#-webkit-keyframes resize {
100% {
height: 123px;
}
}
#anim:hover {
-webkit-animation-name: resize;
-webkit-animation-duration: 4s;
}
I would choose option 2 if you are doing mobile development or can choose only css3 capable browsers.

Categories