Strange behaviour of "position: relative" when zooming. What's happening? - javascript

The Fiddle: http://jsfiddle.net/4WFrJ/
My Problem:
I can't wrap my head around the behaviour of this setup.
When I zoom in, the images tend to move faster, but when I zoom out, they don't move at all. Sometimes they just stop at 9.xxxxxx, even though I told them to move only by one pixel. Can you explain this?
My browser is Chrome.
My Aim: achieve a fluid motion with the images disappearing when out of bounds of the parent element, whatever the magnification percentage.
I am in search of the basic rules, that govern these strange processes, from which I hope to learn new things.
The Code:
HTML:
<div id = "presentation">
<ul>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image1.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image2.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image3.jpg"> </li>
<li class = "pres-item"> <img class = "pres-image" src = "../img/presentation/image4.jpg"> </li>
</ul>
</div>
CSS:
html, body {
margin: 0;
}
#presentation {
padding: 10px;
width: 900px;
margin: 50px auto;
overflow: hidden;
}
#presentation ul {
list-style-type: none;
margin: 0;
}
#presentation ul li {
display: inline-block;
}
.pres-item {
height: 150px;
width: auto;
position: relative;
left: 0;
}
.pres-image {
width: inherit;
height: inherit;
}
JS (with jQuery):
$(document).ready(function(){
var presentation = $('#presentation');
var interval = setInterval(function() {
console.log('intervaling');
$('.pres-item').css('left', '+=1');
}, 60);
});
The Image:
The Thanks:
THANKS PEOPLE (in advance)

<script>
// too much code, but it explains..
// do this in ur interval...
var getCurrent_left = $('.pres-item').css('left');
var newCurrent_left = getCurrent_left.split['px'];
var newCurrent_left = parseInt(newCurrent_left[0]) + 1;
var newCurrent_left = parseInt(newCurrent_left);
$('.pres-item').css({"left", newCurrent_left});
// you can use parseFloat(var, 2) for decimal
</script>

My Problem:
When I zoom in, the images tend to move faster, but when I zoom out, they don't move at all.
I'm not sure this is actually a problem. They appear to move slower when zoomed out because they travel fewer screen pixels for each viewport pixel.
Sometimes they just stop at 9.xxxxxx, even though I told them to move only by one pixel. Can you explain this?
Apparently Chrome does not always return that CSS property as an integer. You can see the same effect in this code:
var presentation = document.getElementById('presentation');
var items = presentation.getElementsByClassName('pres-item');
var interval = setInterval(function () {
[].forEach.call(items, function (x) {
var lastLeft = getComputedStyle(x, null).getPropertyValue('left');
console.log(lastLeft);
x.style.left = (parseFloat(lastLeft) + 1) + 'px';
})
}, 60);
I'm not sure if this is a problem or not. You could easily avoid it by keeping track of the offset in a separate variable and incrementing it during your loop instead of computing it from the element's current style.
var presentation = $('#presentation');
var left = 0;
var interval = setInterval(function() {
++left;
$('.pres-item').css('left', left + 'px');
}, 60);

Related

Infinite moving text with scrolling

I want make a moving infinite text like this text(We are trusted by over 28,000...) in this link . I already tried something but I have not reached exactly what I want. It is close but not infinite.
<h1 class="deneme display-1 " id="movingtext">We are trusted by over 28,000 clients to power stunning websites.We are trusted by over 28,000 clients to power stunning websites.</h1>
window.addEventListener('scroll', () => {
var elemen = document.getElementById("movingtext");
elemen.style = "left:-450px"
var rect = elemen.getBoundingClientRect();
var rect1 = rect.left;
var scrolled = window.scrollY;
var deg = (rect1 + scrolled) / 1.8;
elemen.style = "left:" + deg + "px";
console.log(rect.left, rect.right);
})
As you can see in the following screenshots this is not infinite either:
first row with "We are trusted by over 28,000..."
and second row
It's just that on normal screen you can't reach the end of the element.
You can accomplish something similar by adding an listener on scroll and transforming the element you want to be moved retative to window.pageYOffset value.
Something like:
window.addEventListener('scroll', () => {
const movingtext = document.getElementById("movingtext");
const scrolled = window.pageYOffset;
//feel free to play with this value to change the speed of the transform ( the `* 3` part)
const left = scrolled * 3;
movingtext.style.transform = `translate3d(-${left}px, 0px, 0px)`;
})
.wrapper {
height: 300vh;
padding-top: 100vh;
max-width: 100vw;
overflow: hidden;
}
.infinite-text {
display: inline-block;
overflow: hidden;
white-space: nowrap;
}
<div class="wrapper">
<h1 class="infinite-text" id="movingtext">We are trusted by over 28,000 clients to power stunning websites.We are trusted by over 28,000 clients to power stunning websites.</h1>
</div>
Please note that this is a draft. You might want to play with sizes and speed of transform or other attributes.
Please note that for this example the container has max-width: 100vw; and overflow: hidden (so it won't display a scrollbar for the element that is bigger than the screen), and the element itself has white-space: nowrap;

Image animate down javascript (no jQuery)

I know how to fix the animation that goes down only when the image is showing up in the window with jQuery, but now I want to do that with JavaScript. Struggling with that. The image must be fluently go down (+50px for 1.6 seconds). Have googling around, but most of them are done with jQuery I suggest and that is not what I want. Furtermore the animation should start when the scrollTop is between 600px and 800px.
function scrollFunction() {
var animate = document.getElementById("picture");
var position = 0;
var top = 0;
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if(scrollTop > 600 && scrollTop < 800){
position++;
animate.style.top = position + "50px";
} else {
stop();
}
}
function stop() {
clearTimeout(animate);
}
#picture {
width: 100%;
height: auto;
top: -5px;
position: relative;
display: block;
margin-left: auto;
margin-right: auto;
margin-bottom: 20px;
}
<div class="col-sm-12 col-xs-12">
<h1 class="responsive-h1">Mi<span class="logo-orange"> Pad2</span></h1>
<p class="edition-title above-text-black">Black Edition</p>
<img src="Img/picture.jpg" id="picture"/>
</div>
jsFiddle : https://jsfiddle.net/n1q3fy8w/
Javascript
var imgSlide = document.getElementById('slidedown-image');
var slideDown = setInterval(function() {
var topVal = parseInt(window.getComputedStyle(imgSlide).top, 10);
imgSlide.style.top = (topVal + 1) + "px";
}, 15);
setTimeout(function( ) { clearInterval( slideDown ); }, 1600);
You get the element first, after that you setup a setInterval which will basically move our img downwards, we then also set a setTimeout which after 1600ms remvoes the slideDown interval and the image stops. Your image however may need position: absolute.
The above answer will only work in Chrome, this however should work in all browswers
jsFiddle : https://jsfiddle.net/n1q3fy8w/1/
javascript
var imgSlide = document.getElementById('slidedown-image');
var slideDown = setInterval(function() {
var topVal = parseInt(imgSlide.style.top, 10);
imgSlide.style.top = (topVal + 1) + "px";
}, 15);
setTimeout(function( ) { clearInterval( slideDown ); }, 1600);
Ok so getComputedStyle only works in chrome, so to get this to work on all other browsers, you have to specifically set the css property on the element and not via CSS.
When you use javascript to access an element and change its style like so element.style.bottom = '150px' the .style gets you all of the css values for your inline styles on that element, so any css changes on an element that is done via a .css/.less file you can't access via javascript.
So all the above code does is we set a top: 0 on the element itself and in our code we use imageSlide.style.top instead of chrome's window.getComputedStyle
Have you considered using a CSS transition? if you are changing the value of top you should be able to add transition: top 1.6s in your css (to picture). (Then the vendor prefixed versions when you get it working)

Simulate accumulation of DOM elements

I'm animating several image element children within a div container holder... they will gradually fall from the top to the bottom of the screen
I want to simulate accumulation... Meaning, if an image intersects another, it will lay on top of it and stop moving (picture snow falling and accumulating)
The way I thought to do this is iterate through each child image and animate its location... then loop through each sibling and check if there is an intersection... but of course this double loop provides terrible performance... Any thoughts?
function update () {
var myInterval = null;
clearInterval(myInterval);
myInterval = setInterval(function() {
$("#holder > img").each(function() {
$(this).css({top: $(this).position().top+=3});
var $el = $(this); //bind context
$el.siblings().each(function() {
if ($el.position().top >= $(this).position().top) {
log("INTERSECT");
}
});
});
}, 10);
}
Two things to consider:
It seems you are trying to make the animation yourself, step by step. It might be easier to use jQuery's .animate() instead.
No need to check for intersections when the layout engine can do that for you. Just put the images where they need to be but in a way in which they are not initially visible. For example, position: relative; and bottom: someVeryBigNumber;. Then animate them to their final place.
<div id="container">
<div id="droppableWrapper">
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
<div class="droppable"></div>
</div>
</div>
#container {
position: relative;
}
#droppableWrapper {
position: absolute;
bottom: 0px;
}
.droppable {
position: relative;
bottom: 1000px; /* Enough to be out of the screen */
}
var stack = new Array();
$(".droppable").each(function(){
// Note that the order of the stack
// is the inverse of the visual "stack" effect.
stack.push(new Droppable($(this)));
});
startDropping();
function startDropping(){
dropNext();
}
function dropNext(){
var droppable = stack.pop();
if(droppable){
droppable.drop().done(dropNext);
}
}
function Droppable(domElem) {
function drop(){
return domElem.animate({
bottom :"0px"
},{
duration: 1000
}).promise();
}
this.drop = drop;
}
Here's a fiddle: fiddle
And a fancier one, using jQuery UI, in case this is what you're looking for: fiddle

How to load an initial set of images, then animate between them randomly without jQuery

On my page I have a gallery (just a div) with several images on it. I want to show the first 9 images immediately, then load more images and use CSS transitions to animate between the existing images.
Loading the initial images is easy but I do not know the best way to load the next set of images and then start animating (using the CSS Transform property). So far this is what I have:
HTML (abbreviated):
<div id="mainContainer">
<div class="imageHolder"><img class="homeImages" src="test.png"></div>
<div class="imageHolder"><img class="homeImages" src="test1.png"></div>
<div class="imageHolder"><img class="homeImages" src="test3.png"></div>
</div>
CSS (abbreviated):
img {
display: inline;
position: relative;
margin: 0;
padding: 0;
width: 30%;
}
.changed.opaque {
opacity: 0;
border: 2px solid red;
}
I am looking to do a variety of effects, the most simple one would be to change the opacity and fade one image over the other. To load the next set of images I have this:
Javascript:
var imageArray = [
'test2.png',
'test3.png',
'test4.png',
'test5.png',
'test6.png',
];
var imageNodeArray = [];
for(var i = imageArray.length - 1; i >= 0; i -= 1) {
var img = new Image();
img.onload = function() {
imageNodeArray.push(this);
};
img.src = imageArray[i];
}
document.onclick = function() {
imageNodeArray[0].setAttribute('class', 'changed.opaque');
divs[0].appendChild(imageNodeArray[0])
}
This does add an image to my mainContainer however, even though I can tell from devTools that it has the changed.opaque class applied to it, no opacity is shown on the added image.
I am curious about this. I would also like to know the best way to "stack" images to have a bunch to animate through. I am not sure that appending child is right.... Thank you
function animate() {
var index = Math.floor((Math.random() * document.querySelectorAll('#mainContainer > .imageHolder').length + 1));
var current = document.querySelector('.top');
var next = document.querySelector('.imageHolder:nth-of-type(' + index + ')');
current.className = "imageHolder";
next.className += "top";
}
Should be able to handle and switch between any dynamically inserted images.
Currently using:
.imageHolder {
display: none;
}
.top {
display: inherit;
}
to switch the image is just a simple implementation.
Here's the working fiddle: http://jsfiddle.net/e9dxN/1/
Alternative implementation: http://jsfiddle.net/e9dxN/6/

jquery infinite slider images

I'm trying to create an infinite slider using jquery. My page has some tags, with the width equal to the window width.
I want to slide every image after 10 seconds, and when the last image comes up and it's time for the first image to show, I want it to come still from the right.
Now I created a div with a big width, 10000px to hold my unordered list of images and they have display:none. My question is why when I'm giving margin-left: -1000px for one list item, the images appear to overlap one above the other, instead of appearing one after the other. I tried to take a screenshot but I don't know what is happening with my dropbox.
This is my CSS:
.slider {
position: relative;
height: 498px;
/*display: inline-block;*/
overflow: hidden;
}
.slider-list {
/*display: inline-block;*/
float: left;
padding: 0;
margin: 0;
width: 10000px
/*height: 496px;*/
}
.slider-list li{
display: inline-block;
/*float: left;*/
/*width: 100%;*/
height: 496px;
z-index: 1;
And here is my HTML:
<div class="slider">
<ul class="slider-list">
<li><img class="homepage-img"src="images/homepage.jpg"></li>
<li><img class="homepage-img"src="images/image1.jpg"></li>
<li><img class="homepage-img"src="images/image2.jpg"></li>
<li><img class="homepage-img"src="images/image3.jpg"></li>
<li><img class="homepage-img"src="images/image4.jpg"></li>
</ul>
The div with the class .slider will close after some more elements.
UPDATE:
This is my jQuery code since I written this post:
$(document).ready(function(){
slide();
});
slide = function() {
var img = $('.homepage-img');
var content = $('.slider-content');
var slider = $('.slider-list');
var elements = $('.slider-list li').children();
var auto_slide_speed = 100;//ms
var timer;
var i = 0;
img.width($(window).width());
$("li").width($(window).width());
img.height($('.slider-list').height());
content.height($('.slider-list').height());
var img_width = $('.slider-list li').outerWidth();
console.log($('.slider-list li').length);
console.log(elements);
//calculam margin-left = -latimea unei imagini
// while(1)
// {
var left = parseInt(slider.css('margin-left')) - img_width;
for(i = 0; i <= $('.slider-list li').length; i++)
{
console.log(i);
slider.animate({
"margin-left": "+=" + left},
1500,
function() {
// $('.slider-list li:last').after($('.slider-list li:first'));
// $('slider').css({'margin-left' : '0px'});
});
// left = left + left;
// $('slider li').append($(elements[i]).clone());
}
console.log(i);
}
With this, my slider ony goes as far as my list goes. How do I append the first item after the last item and so on so it can be infinite?
If you are targeting modern browsers that support transitions and transforms i would do it that way..
Demo at http://jsfiddle.net/gaby/dbLu5/
jQuery
var slides = $('.slider-list li'); // cache a reference to the slides
setInterval(function(){
var current = slides.filter('.current'), // find slide in view
next = current.next(); // find next slide
if (!next.length){next = slides.first();} // loop if at last slide
slides.removeClass('off'); // reposition already viewed slides to the right
current.removeClass('current').addClass('off'); // set current slide to animate left
next.removeClass('off').addClass('current'); // set next slide to slide in view
}, 10000); // set the interval
CSS (you need to add vendor prefixes for the transform and transition properties)
.slider-list {
position:relative;
padding: 0;
margin: 0;
overflow:hidden;
height: 496px;
}
.slider-list li {
width:100%;
height: 100%;
display: block;
z-index: 1;
transition:transform 1s;
transform:translateX(100%);
left:0; top:0;
position:absolute;
overflow:hidden;
}
.slider-list li.current{
transform:translateX(0%);
z-index:100;
}
.slider-list li.off{
transform:translateX(-100%);
z-index:100;
}
Here is a FIDDLE that will get you started.
Put all your images in a hidden div
Clone them and put them in the visible div
Animate the image by changing the left margin
You can adjust the time between images by the set interval function
You can adjust the slidein time by the animate time.
Because it's an infinite loop, I put the button in to stop the animation any time you want.
JS
var pictxtnumber = 1;
loadpictxt(pictxtnumber);
var fadeintime = 500;
animatediv();
function animatediv()
{
var number = 0;
var interval = setInterval(function() {
pictxtnumber = pictxtnumber + 1;
if(pictxtnumber > 6)
{
pictxtnumber = 1;
}
loadpictxt(pictxtnumber);
$('#stopanim').on('click', function(){
clearInterval(interval);
});
}, 1000);
}
function loadpictxt(num)
{
$('.picturediv').html('');
$(".hiddenimage img:nth-child(" + num + ") ").clone().appendTo('.picturediv');
$('.picturediv img').css('margin-left', '100px');
$('.picturediv img').animate({marginLeft: "0"}, 100);
}
I've made two simple jquery plugins for that:
https://github.com/lingtalfi/jItemSlider
https://github.com/lingtalfi/jInfiniteSlider
I recommend the item slider because the items are forced to be aligned, and it's simpler in the end.
Now to answer your question: How do I append the first item after the last item and so on so it can be infinite?
You could just display your slider items two times (or more) in a row.
Given your html code:
var jSliderList = $(".slider-list");
var jSliderOriginalItems = $("li", jSliderList); // keep track of this one
function init(){
jSliderList.append(jSliderOriginalItems.clone()); // should work, not tested
}
Then with css, you would narrow the slider to the width of your choice.
Suggestions:
I would suggest that you append a page rather than just one item.
A basic approach would be to encapsulate things into functions, like this:
slideToRight()
appendItemsToTheRight()
removeUnecessaryItemsToTheLeft()
slide()
To perform the slide, you could use css transitions.
In your css, put something like this:
.sliderContainer {
transition: transform 2s ease;
}
And then in your js code, to slide, just use a function such as:
function moveSlider(the_offset) {
jSliderContent.css({
transform: "translate3d(" + the_offset + "px, 0px, 0px)"
});
}
Now to actually append an item, you could use a renderItem function to generate them, instead of cloning things.

Categories

Resources