jQuery - Technics for reduce code in on scroll function - javascript

i have often Code like this and i think there is for sure a way to write it shorter. I would be glad to learn some new technic if there is one =)
please remind it´s inside an on scroll function. Each block is for one layer that is scrolled sideways.
st : is the actuel scrollTop()
cat3 : scrollTop of content before 3*wh in this case
cat4 : scrollTop of content before + width of cat3
cat5 : scrollTop of content before + width of layer1 + width of cat4
...
var w3 = st - (3 * wh);
if (w3 > 0) {
$('#cat3 .inside').css({
"left" : -1 * w3 + "px",
"position" : "fixed"
});
} else if (w3 < 0){
$('#cat3 .inside').css({
"left" : "0",
"position" : "absolute"
});
}
var w4 = st - (3 * wh + fh[3]);
if (w4 > 0) {
$('#cat4 .inside').css({
"left" : -1 * w4 + "px",
"position" : "fixed"
});
} else if (w4 < 0){
$('#cat4 .inside').css({
"left" : "0",
"position" : "absolute"
});
}
var w5 = st - (3 * wh + fh[3] + fh[4]);
if (w5 > 0) {
$('#cat5 .inside').css({
"left" : -1 * w5 + "px",
"position" : "fixed"
});
} else if (w5 < 0){
$('#cat5 .inside').css({
"left" : "0",
"position" : "absolute"
});
}
Thank you for your advices!

Perhaps wrap the repetitive code in a function:
function setScroll(value, selector) {
var element = $(selector + ' .inside');
var left, position;
if (value > 0) {
left = -1 * value + "px";
position = 'fixed';
} else if (value < 0){
left = 0;
position = 'absolute';
}
element.css({left, position});
}
var w3 = st - (3 * wh);
var w4 = st - (3 * wh + fh[3]);
var w5 = st - (3 * wh + fh[3] + fh[4]);
setScroll(w3, '#cat3');
setScroll(w4, '#cat4');
setScroll(w5, '#cat5');
element.css({left, position}); is ES6 syntax, if for whatever reason you can't use ES6, replace this line with:
element.css({
left: left,
position: position
});
The trick is to identify which parts change, and which parts do not. I identified only two things change here: The value you're comparing with 0, and the element you're modifying.

here is my each function. now its total felxible in amount of cats.
f is calculated once outside of the onScroll function. Any suggestions to this? Thanks.
$('.side-scroll').each(function() {
c[n] = st - (f[n]);
setScroll(c[n], '#cat' + n);
n++;
if(n == ss ){n = 0;}
});

Related

on scroll div gradually fadein fadeout

I am trying to creating fadein fadeout effect with scrolling but not figure out how . it is like http://www.popsci.com/ . There If scroll then background image (div id fixed-image ) get fading. Them code something like. But I cannot figure out yet how to easily apply in my code. Would guys please check it my code .
var opacity = 1;
var img = element.find('img');
// Look for featured stories.
if (element.length > 0) {
// Attach background image element.
$('#page-wrapper').prepend('<div id="fixed-image" style="background-image: url(\'' + img.attr('data-lgsrc') + '\');"></div>');
img.addClass('hidden');
var scrollPercent;
$(window).scroll(function() {
// When User scrolls down, determine percentage from top to bottom of window.
scrollPercent = (($(window).scrollTop() / $(window).height() * 1.9) - 0.9);
if (scrollPercent < 0) {
$('#fixed-image').css({
'-webkit-filter' : 'blur(0px)',
'-moz-filter' : 'blur(0px)',
'-o-filter' : 'blur(0px)',
'-ms-filter' : 'blur(0px)',
'filter' : 'blur(0px)'
});
}
var opacityCount = 1.5 - Math.min(1.5, (scrollPercent + 1));
$('#fixed-image').css('opacity', opacityCount);
if (scrollPercent <= 1) {
$('#fixed-image').css('opacity', opacityCount);
$('#fixed-image').css({
'-webkit-filter' : 'blur(' + scrollPercent * 10 + 'px)',
'-moz-filter' : 'blur(' + scrollPercent * 10 + 'px)',
'-o-filter' : 'blur(' + scrollPercent * 10 + 'px)',
'-ms-filter' : 'blur(' + scrollPercent * 10 + 'px)',
'filter' : 'blur(' + scrollPercent * 10 + 'px)'
});
}
else {
$('.content-wrapper-outer').css('background-color', 'rgba(255,255,255,' + opacity + ')');
my demo is here https://jsfiddle.net/cyber007/6e6dbr6j/1/
i want slider class will be fadeIn and fadeout gradually base on scrolling
UPDATE
$(window).scroll(function(){
$(".slider").css("opacity", 1 - $(window).scrollTop() / 250);
});
https://jsfiddle.net/cyber007/6e6dbr6j/2/ this one work fine. jus one minor think in console i saw that opacity value keep running after 0 even going - value. i don't think after value 0 no need down value more
Here's a function to clip opacity at 0, although according to MDN: "Any value outside the interval [0 to 1], though valid, is clamped to the nearest limit in the range," so it's not strictly necessary.
$(window).scroll(function(){
var opacity = 1 - $(window).scrollTop() / 250;
if (opacity < 0 ) opacity = 0;
$(".slider").css("opacity", opacity);
});
UPDATE
For arbitrary start and end of your transition, use the linear equation , like so:
$(window).scroll(function(){
var start = 200, end = 600;
var opacity = 1 - ($(window).scrollTop() - start) / (end - start);
if (opacity > 1 ) opacity = 1;
if (opacity < 0 ) opacity = 0;
$(".slider").css("opacity", opacity);
});
Here's a JSFiddle.

JavaScript to calculate random position for divs with no collision

I'm trying to draw a bunch of divs inside of a container in such a way that they are randomly positioned every time the page is loaded and that there is no overlapping. I seem to be stuck in an infinite loop and without the sources loading in Chrome before crashing the page, I can't debug properly.
Here's my code:
$(document).ready(function() {
var filledAreas = new Array();
var minX = 50;
var maxX = $("#banner").width() - 150;
var minY = 50;
var maxY = $("#banner").height() - 150;
var loops = 0;
var loopsMax = 100;
for (var i = 0; i < 15; i++) {
var color = '#' + Math.round(0xffffff * Math.random()).toString(16);
$newDiv = $("<div class='bubble-outer'></div>").css({
'width': '100px',
'height': '100px',
'background-color': color,
});
var randX = 0;
var randY = 0;
var area;
do {
randX = Math.floor(Math.random() * (maxX - minX + 1)) + minX;
randY = Math.floor(Math.random() * (maxY - minY + 1)) + minY;
var area = {
'left': randX,
'top': randY,
'right': randX + 100,
'bottom': randY + 100,
};
} while (loops < loopsMax && checkOverlap(area))
filledAreas.push(area)
$newDiv.css({
'position': 'absolute',
'left': randX + 'px',
'top': randY + 'px',
'display': 'none'
}).delay(1000).appendTo("#banner").fadeIn(300);
}
console.log("Loops: " + loops);
function checkOverlap(area) {
for (var i = 0; i < filledAreas.length; i++) {
var check = filledAreas[i];
if (area.right < check.left && area.bottom < check.top &&
check.right < area.left && check.bottom < area.top) {
loops++;
continue;
} else {
return true;
}
return false;
}
}
});
Since you used my algorithm, might as well post it as an answer!
As with many things, it is easier to cheat than to do exactly what you want to do.
Doing it the "proper" way would involve detecting collisions, which gets very tricky very fast.
However, here's a nice way to cheat at it:
Divide the area into a grid. Each grid square must be at least as big as your biggest element for this to work correctly.
For each element, pick a grid square. If that grid square hasn't been taken yet, place your element somewhere inside that grid square at random.
And... that's it! Now you are guaranteed to never have any collisions, and it looks pretty random because it is :)

JQuery animate background positions in multiple divs on scroll

I have multiple divs on my page where I want to animate their background position onScroll, so here is what I have got for now
/* animate background possition on scroll */
$(window).scroll(function() {
var y = $(this).scrollTop();
if(y < $(".page-separator").offset().top && ( $(".page-separator").offset().top ) < ( y + $(window).height() ) ){
$(this).css('background-position', '0% ' + parseInt(-y / 10) + 'px');
}
});
But it doesn't work. I think it is because $(this)is not currently visible $(".page-separator") , can you please help me to fix it?
So I have modified my code here but I am stacked again, I can't pass parameter into .each jquery function
$(window).scroll(function() {
var y = $(window).scrollTop();
$(".page-separator").each(function(y){
//$(".page-separator").css('background-position', '0% ' + parseInt(-y / 10) + 'px');
if( y < $(this).offset().top && ( $(this).offset().top ) < ( y + $(window).height() ) ){
$(this).css('background-position', '0% ' + parseInt(-y / 10) + 'px');
}console.log(y);
});
});
when I see console.log(y) it only shows 0 1 2 nothing more, not the top position
To change the background-position of the visible .page-separator elements, you'd do :
$(window).on('scroll', function() {
var y = $(window).scrollTop();
$(".page-separator").filter(function() {
return $(this).offset().top < (y + $(window).height()) &&
$(this).offset().top + $(this).height() > y;
}).css('background-position', '0px ' + parseInt(-y / 10) + 'px');
});
FIDDLE
$(this) == $(window) in this case. You should add one class (ex: 'animate') for all divs, and use it as selector (ex: $('.animate'))

Refactor JS Function

I have this ugly chunk of code which is responsible for positioning some sub-navigation on a website and I want some opinion on how I could improve it, because even I admit it's ugly as hell :)
Maybe someone has a better structuring idea, because I don't due to the complex logic :
positionSubItems : function() {
var $that = $(this),
$parent = $that.parents().eq(1),
$elements = $parent.find(' > li'),
$activeElements = $parent.find(' > li.active'),
$container = $that.parent().find(".expandedViewContainer"),
highestBoundary = $($elements[0]).offset().top - $($elements[0]).outerHeight(true),
lowestBoundary = $($elements[$elements.length - 1]).offset().top + $($elements[$elements.length - 1]).outerHeight(true),
containerHeight = $container.outerHeight(true),
elementHeight = $that.outerHeight(true),
returnIndex = function(selector) {
return $(selector).parent().index();
};
if($that.data().subItemsPositioned !== true) {
$container.css({
'margin-top' : - ( containerHeight / 2 + (elementHeight / 2) )
});
if((lowestBoundary - highestBoundary) <= containerHeight) {
$container.css({
'margin-top' : - ((elementHeight * 2) + (elementHeight * returnIndex($that)) + ($activeElements.find(" > ul").outerHeight(true) || 0))
});
}
if($container.offset().top < highestBoundary) {
$container.css({
'margin-top' : - ((elementHeight * 2) + (elementHeight * returnIndex($that)))
});
if((lowestBoundary - highestBoundary) < containerHeight) {
$container.css({
'margin-top' : - ((elementHeight * 2) + (elementHeight * returnIndex($that)) + ($activeElements.find(" > ul").outerHeight(true) || 0))
});
}
}
if(($container.offset().top + containerHeight) >= lowestBoundary) {
$container.css({
'margin-top' : - ( containerHeight - (elementHeight * ($elements.length - returnIndex($that))) )
});
if((lowestBoundary - highestBoundary) <= containerHeight) {
$container.css({
'margin-top' : - ((elementHeight * 2) + (elementHeight * returnIndex($that)) + ($activeElements.find(" > ul").outerHeight(true) || 0))
});
}
}
$that.data().subItemsPositioned = true;
}
}
So just let me briefly explain what it does. Let's say we have a left vertical navigation ( a vertical list of li ). In those lis we have a link and another div which also contains another list of items. So what this function need's to do it's position this sub level of lis according to some rules :
there are two boundaries, one upper which corresponds to the most upper 'li' item on the first level plus it's own height, and the other one lower which corresponds to the most low li on the first level plus it's own height
the first condition would be that always position the sub items, which are held by a container and displayed to the right of the parent li, so the parent it's shown in the middle of that container
based on the above rule, if the offset of the resulted positioning of the container exceeds the upper boundary, then reposition the container so the top offset of the container it's now at the same level as the upper boundary
continuing to click on the rest of the items follow the first rule, apply the second one if it's the case, then if this following condition it's meet apply it : when the offset of the bottom of the container exceeds the lowest boundary, reposition it so the bottom of the container it's always at the same level as the lowest boundary
after going through all of the above rules and conditions you also have to check if the height of the container is bigger than the height between the upper and lower boundary, in that case apply the first rule, position the container at the same level as the upper boundary
there is also another scenario encountered, if there are to few parent lis and the height of the container now exceeds the height of the height between boundaries again, so we'll have to apply the just above mentioned rule
and there is another scenario which I won't describe as I'm already to deep into details
So stating the above, I hope someone has a better way of doing all the logic and maybe a more cleaner way too :)
Without testing if the underlying logic makes sense, this is slightly easier to read in my opinion
if(!$that.data().subItemsPositioned) {
var offset=0;
var ulOuterHeight = (elementHeight * 2) + (elementHeight * returnIndex($that)) + ($activeElements.find(" > ul").outerHeight(true) || 0);
switch(true) {
case (lowestBoundary - highestBoundary) <= containerHeight :
offset = ulOuterHeight;
break;
case $container.offset().top < highestBoundary :
if((lowestBoundary - highestBoundary) < containerHeight) {
offset = ulOuterHeight;
}
else offset = (elementHeight * 2) + (elementHeight * returnIndex($that))
break;
case ($container.offset().top + containerHeight) >= lowestBoundary :
if((lowestBoundary - highestBoundary) <= containerHeight) {
offset = ulOuterHeight;
}
else offset = containerHeight - (elementHeight * ($elements.length - returnIndex($that)));
break;
default: offset = containerHeight/2 + (elementHeight/2);
}
$container.css({'margin-top' : - offset });
$that.data().subItemsPositioned = true;
}
here is some kind of example (without exactly reading what your function does, just some refactorings to dry this function a little bit up
this is still some kind of ugly but i hope it helps to push you into the right direction
positionSubItems : function() {
var $that = $(this),
$parent = $that.parents().eq(1),
$elements = $parent.find(' > li'),
$activeElements = $parent.find(' > li.active'),
$container = $that.parent().find(".expandedViewContainer"),
highestBoundary = $($elements[0]).offset().top - $($elements[0]).outerHeight(true),
lowestBoundary = $($elements[$elements.length - 1]).offset().top + $($elements[$elements.length - 1]).outerHeight(true),
containerHeight = $container.outerHeight(true),
elementHeight = $that.outerHeight(true),
returnIndex = function(selector) {
return $(selector).parent().index();
},
containerCSS = function(marginTop) {
$container.css({
'margin-top' : - marginTop
});
},
doTheMarginTop = function() {
containerCSS((elementHeight * 2) + (elementHeight * returnIndex($that)) + ($activeElements.find(" > ul").outerHeight(true) || 0));
};
if($that.data().subItemsPositioned !== true) {
containerCSS(containerHeight / 2 + (elementHeight / 2));
if((lowestBoundary - highestBoundary) <= containerHeight) {
doTheMarginTop();
}
if($container.offset().top < highestBoundary) {
containerCSS(((elementHeight * 2) + (elementHeight * returnIndex($that))));
if((lowestBoundary - highestBoundary) < containerHeight) {
doTheMarginTop();
}
}
if(($container.offset().top + containerHeight) >= lowestBoundary) {
containerCSS( containerHeight - (elementHeight * ($elements.length - returnIndex($that))) );
if((lowestBoundary - highestBoundary) <= containerHeight) { doTheMarginTop(); }
}
$that.data().subItemsPositioned = true;
}
}
this piece of code seems to be always the same, try to put that out of the if conditions (probably into a function):
$container.css({
'margin-top' : - ((elementHeight * 2) + (elementHeight * returnIndex($that)) + ($activeElements.find(" > ul").outerHeight(true) || 0))
});
i think that should be a good point to start. look for lines of code which are duplicate

random position of divs in javascript

I'm trying to make Divs to appear randomly anywhere on a webpage with javascript. So a div appears then disappears, then another div appears somewhere else on the page then disappears, then another div appears again in another random spot on the page then disappears, and so on.
I'm not sure on how to generate random units in pixels or what technique to use to generate random positions.
How do I do that? Here's my code:
var currentDivPosition = myDiv.offset(),
myDivWidth = myDiv.width(),
myDivHeight = myDiv.height(),
var myDiv = $('<div>'),
finalDivPositionTop, finalDivPositionLeft;
myDiv.attr({ id: 'myDivId', class: 'myDivClass' }); // already defined with position: absolute is CSS file.
// Set new position
finalDivPositionTop = currentDivPosition.top + Math.floor( Math.random() * 100 );
finalDivPositionLeft = currentDivPosition.left + Math.floor( Math.random() * 100 );
myDiv.css({ // Set div position
top: finalDivPositionTop,
left: finalDivPositionLeft
});
$('body').append(myDiv);
myDiv.text('My position is: ' + finalDivPositionTop + ', ' + finalDivPositionLeft);
myDiv.fadeIn(500);
setTimeout(function(){
myDiv.fadeOut(500);
myDiv.remove();
}, 3000);
Here's one way to do it. I'm randomly varying the size of the div within a fixed range, then setting the position so the object is always placed within the current window boundaries.
(function makeDiv(){
// vary size for fun
var divsize = ((Math.random()*100) + 50).toFixed();
var color = '#'+ Math.round(0xffffff * Math.random()).toString(16);
$newdiv = $('<div/>').css({
'width':divsize+'px',
'height':divsize+'px',
'background-color': color
});
// make position sensitive to size and document's width
var posx = (Math.random() * ($(document).width() - divsize)).toFixed();
var posy = (Math.random() * ($(document).height() - divsize)).toFixed();
$newdiv.css({
'position':'absolute',
'left':posx+'px',
'top':posy+'px',
'display':'none'
}).appendTo( 'body' ).fadeIn(100).delay(1000).fadeOut(500, function(){
$(this).remove();
makeDiv();
});
})();
Edit: For fun, added a random color.
Edit: Added .remove() so we don't pollute the page with old divs.
Example: http://jsfiddle.net/redler/QcUPk/8/
Let's say you have this HTML:
<div id="test">test div</div>
And this CSS:
#test {
position:absolute;
width:100px;
height:70px;
background-color:#d2fcd9;
}
Using jQuery, if you use this script, whenever you click the div, it will position itself randomly in the document:
$('#test').click(function() {
var docHeight = $(document).height(),
docWidth = $(document).width(),
$div = $('#test'),
divWidth = $div.width(),
divHeight = $div.height(),
heightMax = docHeight - divHeight,
widthMax = docWidth - divWidth;
$div.css({
left: Math.floor( Math.random() * widthMax ),
top: Math.floor( Math.random() * heightMax )
});
});
The way this works is...first you calculate the document width and height, then you calculate the div width and height, and then you subtract the div width from the document width and the div height from the document height and consider that the pixel range you're willing to put the div in (so it doesn't overflow out of the document). If you have padding and border on the div, you'll need to account for those values too. Once you've figured out the range, you can easily multiple that by Math.random() and find the random position of your div.
So once more: first find the dimensions of the container, then find the dimensions of your element, then subtract element dimensions from container dimensions, and THEN use Math.random() on that value.
The basic idea is encapsulated here:
http://jsfiddle.net/5mvKE/
Some bugs:
You missed to position the div absolutely. Otherwise it will not
work.
I think you need to ad 'px' to the numbers.
The map is made of strings
Right in your jQuery css setup:
myDiv.css({
'position' : 'absolute',
'top' : finalDivPositionTop + 'px',
'left' : finalDivPositionLeft + 'px'
});
I changed an existant code by this one for our website, you can see it on tweefox.nc
<script>
function draw() {
$(canvas).attr('width', WIDTH).attr('height',HEIGHT);
con.clearRect(0,0,WIDTH,HEIGHT);
for(var i = 0; i < pxs.length; i++) {
pxs[i].fade();
pxs[i].move();
pxs[i].draw();
}
}
function Circle() {
this.s = {ttl:8000, xmax:10, ymax:4, rmax:10, rt:1, xdef:950, ydef:425, xdrift:4, ydrift: 4, random:true, blink:true};
this.reset = function() {
this.x = (this.s.random ? WIDTH*Math.random() : this.s.xdef);
this.y = (this.s.random ? HEIGHT*Math.random() : this.s.ydef);
this.r = ((this.s.rmax-1)*Math.random()) + 1;
this.dx = (Math.random()*this.s.xmax) * (Math.random() < .5 ? -1 : 1);
this.dy = (Math.random()*this.s.ymax) * (Math.random() < .5 ? -1 : 1);
this.hl = (this.s.ttl/rint)*(this.r/this.s.rmax);
this.rt = Math.random()*this.hl;
this.s.rt = Math.random()+1;
this.stop = Math.random()*.2+.4;
this.s.xdrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
this.s.ydrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
}
this.fade = function() {
this.rt += this.s.rt;
}
this.draw = function() {
if(this.s.blink && (this.rt <= 0 || this.rt >= this.hl)) {
this.s.rt = this.s.rt*-1;
this.dx = (Math.random()*this.s.xmax) * (Math.random() < .5 ? -1 : 1);
this.dy = (Math.random()*this.s.ymax) * (Math.random() < .5 ? -1 : 1);
} else if(this.rt >= this.hl) this.reset();
var newo = 1-(this.rt/this.hl);
con.beginPath();
con.arc(this.x,this.y,this.r,0,Math.PI*2,true);
con.closePath();
var cr = this.r*newo;
g = con.createRadialGradient(this.x,this.y,0,this.x,this.y,(cr <= 0 ? 1 : cr));
g.addColorStop(0.0, 'rgba(255,255,255,'+newo+')');
g.addColorStop(this.stop, 'rgba(255,255,255,'+(newo*.2)+')');
g.addColorStop(1.0, 'rgba(255,255,255,0)');
con.fillStyle = g;
con.fill();
}
this.move = function() {
this.x += (this.rt/this.hl)*this.dx;
this.y += (this.rt/this.hl)*this.dy;
if(this.x > WIDTH || this.x < 0) this.dx *= -1;
if(this.y > HEIGHT || this.y < 0) this.dy *= -1;
}
this.getX = function() { return this.x; }
this.getY = function() { return this.y; }
}
$(document).ready(function(){
// if( /Android|AppleWebKit|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
// } else {
if(document.getElementById('pixie')) {
WIDTH = $(window).width();
HEIGHT = $(window).height();
canvas = document.getElementById('pixie');
$(canvas).attr('width', WIDTH).attr('height',HEIGHT);
con = canvas.getContext('2d');
pxs = new Array();
rint = 60;
for(var i = 0; i < 50; i++) {
pxs[i] = new Circle();
pxs[i].reset();
}
setInterval(draw,rint);
}
// }
});
</script>

Categories