DIVs to randomly fadeIn on page - javascript

Okay, I've seen a few things that sort of * answer my question, but none of them quite do what I want to do / I'd like to understand how to do this myself from start to finish as a learning exercise. I'm a novice at all this, so bear with me!
What I'm Trying to Do:
I have a black page and I'd like 20-30 small, white div boxes to fadeIn at random positions on the page (like stars is sort of the vibe I'm going for).
Ideally, they wouldn't overlap and they would be randomly sized between 5px and 10px, but I recognize that this might be getting a little too complicated.
Here's what I have so far
I've been working off this jsfiddle and well as this one. This is what I've come up with (that doesn't work, they all fade in equally spaced in a line and don't stay confined from to the site)
Here's my jsfiddle, code below
function randomPosition() {
var h = $(window).height()-10;
var w = $(window).width()-10;
var newHeight = Math.floor(Math.random() * h);
var newWidth = Math.floor(Math.random() * w);
return [newHeight, newWidth];
}
$(document).ready(function() {
var newPosition = randomPosition();
$('.star').css( {
'margin-left':newPosition[1]+'px',
'margin-top':newPosition[0]+'px'
}).each(function(index) { $(this).delay(1500*index).fadeIn('slow');
})
});
CSS
body {
background-color: black;
}
.star {
height: 10px;
width: 10px;
background-color: white;
display: none;
}
HTML (is there a way to do this with just a for loop or something similar?)
<div class="star"> </div>
<div class="star"> </div>
<div class="star"> </div>
<div class="star"></div>

The sizing and positioning isn't too hard. The thing is to do it all in the each loop - currently you get 1 position and use it for everything. Also you will want to make them position:absolute so they don't go off the page.
I've updated your fiddle to set the random position and a size between 5 and 10px:
The overlapping is a bit harder. You need to keep track of the sizes and positions you have generated and in the same .each function compare the current generated size+position to the previous ones to check for overlapping.
http://jsfiddle.net/5ocb5aww/3/
function randomPosition() {
var h = $(window).height()-10;
var w = $(window).width()-10;
var newHeight = Math.floor(Math.random() * h);
var newWidth = Math.floor(Math.random() * w);
return [newHeight, newWidth];
}
function randomSize() {
return Math.round(Math.random() * 5) + 5;
}
$(document).ready(function() {
// stores generated star positions
var stars = [];
$('.star').each(function(index) {
var newPosition, newSize;
// check for overlap
var isOverlap = true;
while(isOverlap)
{
newPosition = randomPosition();
newSize = randomSize();
// check previous stars to see if an edge of this one overlaps
isOverlap = $.grep(stars, function(s) {
return (
(newPosition[1] >= s.x1 && newPosition[1] <= s.x2)
|| (newPosition[1]+newSize >= s.x1 && newPosition[1]+newSize <= s.x2)
)
&& (
(newPosition[0] >= s.y1 && newPosition[0] <= s.y2)
|| (newPosition[0]+newSize >= s.y1 && newPosition[0]+newSize <= s.y2)
);
}).length > 0;
}
// store to check later stars against it
stars.push({
x1: newPosition[1],
x2: newPosition[1] + newSize,
y1: newPosition[0],
y2: newPosition[0] + newSize,
size: newSize});
$(this).css({
'margin-left':newPosition[1]+'px',
'margin-top':newPosition[0]+'px',
'width':newSize + 'px',
'height':newSize + 'px'
});
$(this).delay(800*index).fadeIn('slow');
})
});

Here is my approach to your exercise ... the overlapping position would require a little bit more effort ... I'll leave you that to sort for yourself (may require restructuring the code I'm handing here)
jsFiddle Demo
JS
function starDust(wdt, hgt, tSt, tAp){
var timer = tAp * 1000;
var defInt = tSt,
starInt = setInterval(function(){
var posX = Math.floor((Math.random() * wdt) + 1),
posY = Math.floor((Math.random() * hgt) + 1),
size = Math.floor((Math.random() * 10) + 1);
$('body').append('<div class="star"></div>');
$('.star:last').css({'width':size,'height':size,'left':posX,'top':posY}).hide().fadeIn('slow');
var totalStars = $('.star').length;
if(totalStars == defInt){
clearInterval(starInt);
}
}, timer);
}
$(function(){
// Function arguments: starDust(max X position in px, max Y position in px, total number of stars, time in seconds between stars show);
starDust(600,300,25,1);
});
CSS
body{
background-color:#000;
}
.star{
position: absolute;
background-color:#fff;
min-width:5px;
min-height:5px;
}

Related

Animations in Javascript

I'm working on my Javascript project.
In this project I have to create some animations.
In this specific case, I have to make a ball bounce up and down.
The code below works great just from the top to the bottom, but not viceversa.
var div = document.getElementById('container-ball');
function createBall(event)
{
var x = event.clientX;
var y = event.clientY;
var newBall = document.createElement('div');
newBall.style.position = "absolute"
newBall.style.width = '15px';
newBall.style.height = '15px';
var bx = newBall.style.left = x + 'px';
var by = newBall.style.top = y + 'px';
newBall.style.borderRadius = '10px';
newBall.style.backgroundColor = 'white';
var incrementPos = 0;
var id = setInterval(bounce, 5);
function bounce()
{
incrementPos++;
by = newBall.style.top = incrementPos + y + "px";
if(by == 650 + "px")
{
clearInterval(id)
var id2 = setInterval(function bounceUp()
{
incrementPosYMax -= 650
by = newBall.style.bottom = by + "px" - incrementPosYMax
}, 5)
}`/*Function that make the ball bounce down and up(but when it came at 650 px it stopped )*/ì
} /*End of the set interval */`
div.appendChild(newBall);
}
div.addEventListener("click", createBall);
This down below is the HTML CODE
<html>
<head>
<link rel= "stylesheet" href="style/style.css">
</head>
<body>
<div id ="container-ball">
</div>
<script src="js/main.js"></script>
</body>
Working example (comments see below):
const areaHeight = 150; // it is 650px in the original question
var div = document.getElementById('container-ball');
function createBall(event) {
var x = event.clientX;
var y = event.clientY;
var newBall = document.createElement('div');
newBall.className = 'ball';
var bx = newBall.style.left = x + 'px';
var by = newBall.style.top = y + 'px';
var incrementPos = 0;
var id = setInterval(bounce, 5);
let direction = 1; // 1 = down, -1 = up
function bounce() {
incrementPos += direction;
by = newBall.style.top = incrementPos + y + "px";
if (by == areaHeight + "px" || by == y + 'px') {
direction = -direction;
}
}
div.appendChild(newBall);
}
#container-ball {
width: 300px;
height: 157px;
background: gray;
}
#container-ball .ball {
position: absolute;
width: 15px;
height: 15px;
border-radius: 10px;
background-color: white;
border: 1px solid #333;
box-sizing: border-box;
}
<div id="container-ball" onclick="createBall(event)"></div>
Click on the grey box
Now, the explanation.
I've moved ball's styles to CSS - this is easier to control in the future. So when I have a class for ball, I can write in my code: newBall.className = 'ball';
I removed incrementPosYMax because I do not really understand if you need it
I understand your 'bounce' as bounce, so my ball just fall to the floor and then return to the original position. I do not really understand if you mean that (please, comment if it is wrong).
Your program is quite small, so I do not see the need for another setInterval, so all the animation in my example is inside only one setInterval
I've added new variable direction to control the direction for the ball (1 = down, -1 = up)
I do not like the parts with by == areaHeight + "px", but I keep them for you, because you use it in your code.
This code have some bugs, that you (or me if you ask) can fix. I just need to understand that my approach is correct
How the direction works:
Take a look at this line by = newBall.style.top = incrementPos + y + "px"; here you set new "y" coordinate for the ball as sum of 'original' "y" coordinate (in y) and offset (the distance that ball moved over the time) in incrementPos. So, if you increase incrementPos, then the ball's position will be lower (because "zero" in browser is at the top left corner, bigger "y" means lower the element).
Before my change, in your code you changed the offset with this line: incrementPos++; (means you increase incrementPos by 1 on every bounce step).
To move to another direction, you need to subtract 1 on every bounce step.
To reflect the "direction" of that move, I've added direction variable (so 1 means move down, and -1 means move up)
Now the offset is changed by: incrementPos += direction; (so I add this direction, not always 1)
Sometimes we need to change the "direction" with this code: direction = -direction;
The "levels" where we need to change direction is checked by this code: if (by == areaHeight + "px" || by == y + 'px') - here we check bottom (areaHeight) and top (y - it is where user clicks the mouse)

generate animation as if it were a marquee

I do not know much about css, but I think this code could help me generate a marquee. basically I want the animation that is done with the boxes, be done with the texts.
My main problem occurs with the animation, it is not very fluid, I want it to be more fluid and it starts from the end of the container to the left. How can I do it? I would be very grateful.
http://jsfiddle.net/joof5dhx/
<div id="horizontalScroller">
<div>it is a message a little more of 100 characteres</div>
<div>it is a message a little more of 110 characteres</div>
<div>it is a message a little more of 120 characteres</div>
<div>it is a message a little more of 130 characteres</div>
</div>
window.horizontalScroller = function($elem) {
var left = parseInt($elem.css("left"));
var temp = -1 * $('#horizontalScroller > div').height();
if(left < temp) {
left = $('#horizontalScroller').height()
$elem.css("left", left);
}
$elem.animate({ left: (parseInt(left)-60) }, 900, function () {
window.horizontalScroller($(this))
});
}
$(document).ready(function() {
var i = 0;
$("#horizontalScroller > div").each(function () {
$(this).css("left", i);
i += 60;
window.horizontalScroller($(this));
});
});
http://jsfiddle.net/hhcbtyyg/
You could just:
window.horizontalScroller = function($elem)
{
var left = parseInt($elem.css("left"));
$elem.animate({ left: (parseInt(left)-60) }, 900, function ()
{
// get the current left of the element
var currentLeft = parseInt($(this).css("left"));
// get the width of the element
var width = $(this).width();
// get the container
var container = $(this).parent("#horizontalScroller");
// get the width of the container
var containerWidth = $(container).width();
// check if the element goes out of the view item X + item w < 0
if ((currentLeft + width) <= 0)
{
// put it on the opposite side: simply container w + item w
$(this).css("left", (containerWidth + width) + "px");
}
window.horizontalScroller($(this))
});
}
I just don't understand why you use height in your code above. If there is something I don't know let me know.
UPDATED:
To make the items appear on the leftmost by default:
$(document).ready(function() {
var container = $("#horizontalScroller");
var children = $(container).children();
var containerW = $(container).width();
// Loop through each item of container
for (var i = 0; i < children.length; i++)
{
var item = children[i];
var itemW = $(item).width();
// this is simply the space between them, remove if you don't need it
var padding = 10 * (i + 1);
// simply: padding + Container Width + (Item Width * (i + 1))
// (Item Width * (i + 1)) because you need to position each element beside each other.
$(item).css("left", (padding + containerW + itemW * (i + 1)) + "px");
window.horizontalScroller($(item));
}
});
your updated fiddle
hope that helps
Hi checked this version of your jsfiddle, i did some modificaitons, since your animation starts from whatever the value of height is your div had. check this I tried to match the height of your css and width in your css, i just noticed that the "left" var in your js gets the height of your element.
CSS:
#horizontalScroller {
position: absolute;
width:300px;
height: 300px;
border: 1px solid red;
overflow: hidden;
}
Maybe you can get some tips how to accomplish it in responsive way.
JSFIDDLE

Stop div scrolling past set position

I adapted this code to create a large div which scrolls horizontally inside a smaller div, depending on the position of the mouse.
You can see my example here.. http://thetally.efinancialnews.com/tallyassets/20years/index.html
What I am trying to achieve is for the inner (yellow) div to stop at a maximum of left:0px, in other words the far left of the yellow div will become stuck to the far left of the outer div if you go that far.
I tried to implement this with an 'if else' statement, however as this piece of code gets run every 30th of a second it creates a strange result, which I can't find a solution for. I'm sure its very simple but its stumped me
You can see my code here...
var x=0,
rate=0,
maxspeed=10;
var backdrop = $('.container');
var years = $('.events');
$('.direction', backdrop).mousemove(function(e){
var $this = $(this);
var left = $this.is('.left');
if (left){
var w = $this.width();
rate = (w - e.pageX - $(this).offset().left + 1)/w;
} else {
var w = $this.width();
rate = -(e.pageX - $(this).offset().left + 1)/w;
}
});
backdrop.hover(function(){
var scroller = setInterval( moveBackdrop, 30 );
$(this).data('scroller', scroller);
},
function(){
var scroller = $(this).data('scroller');
clearInterval( scroller );
});
function moveBackdrop(){
if ( parseInt(years.css("left"), 10) <= 0 ) {
x += maxspeed * rate;
var newpos = x+'px';
years.css('left',newpos);
} else {
years.css('left','0');
}
}
The code in question is right here at the end^
Is this what you were trying to do?
function moveBackdrop(){
if ( parseInt(years.css("left"), 10) <= 0 && rate < 0 ) {
// Means that the element is already at left: 0 or less,
// and we are trying to move it even more left with rate being negative.
// So keep the element at left: 0
years.css('left','0');
} else {
x += maxspeed * rate;
var newpos = x+'px';
years.css('left',newpos);
}
}
Extra note for future: parseInt uses base 10 by default :) so parseInt("20px") will equal 20
Final Edit: Ah there is an even better way to do it.
function moveBackdrop(){
x += maxspeed * rate;
if( x < 0 ) x = 0; // If left less than 0, fix it at 0
var newpos = x+'px';
years.css('left',newpos);
}

jQuery animated background with many elements

I'm trying to create a background with many circles moving around and it really pushes the browser a bit too hard.
Is there any way I can do this without being too resource-intensive?
Here's the current code I have:
http://jsfiddle.net/2MGAE/2/
$( document ).ready(function() {
// Create all our glorious bubbles
for (var i = 1; i <= 150; i++) {
$('#bubbles').append('<span class="bubble' + i + '"></span>');
}
// Get random number
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Function to move bubbles randomly
function moveRandom(obj) {
var positionTop = getRandomInt(-350,1000);
var positionLeft = getRandomInt(-700,1600);
var positionTopNew = positionTop + getRandomInt(-50,50);
var positionLeftNew = positionLeft + getRandomInt(-50,50);
var size = getRandomInt(30,60);
function animation() {
obj.animate({
top: positionTop + 'px',
left: positionLeft + 'px',
width: size,
height: size
}, 6000
);
obj.animate({
top: positionTopNew + 'px',
left: positionLeftNew + 'px'
}, 6000, function() {
animation();
});
}
animation();
}
// Activate bubble movement
$('#bubbles span').each(function() {
moveRandom($(this));
})
});
Or is it just too many elements animated that it will always be a resource hog?
Pretty neat! You may want to use the HTML 5 canvas element to do this. It will utilize the GPU and doesn't require 3rd party js libraries.
REF:
http://updates.html5rocks.com/2012/07/Taking-advantage-of-GPU-acceleration-in-the-2D-canvas
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial
There are 2 things that come to mind.
You could look up how to use the <canvas> tag with really cool examples at Createjs.com
or
you could gopro and learn webgl and three.js which uses the gpu for cool fast 3d effects!

Algorithm for placing dashboard panels in unoccupied space

I'm working on a portal/dashboard type interface which has panels/widgets that can be freely dragged around the dashboard space as long as they don't overlay any other panels. New panels can be added to the dashboard via a menu containing all available panels, and when a menu item is clicked, the panel is placed into the dashboard. The panels currently occupying the dashboard space are all represented in an object like this:
{
'panel_1': { top: 0, left: 0, width: 300, height: 350 },
'panel_2': { top: 0, left: 370, width: 200, height: 275 },
'panel_3': { top: 370, left: 0, width: 275, height: 400 },
...
}
My question is, what is a valid algorithm that would, when the user clicks one in the menu, correctly place a new panel (of a given width and height) in unoccupied space that is closest to a left and top (x and y) value of 0, 0, without overlapping any of the existing panels?
I think, simple bruteforce algorithm will fit you. As I remember, fit rectangle solve another problem
Iterate over your dashboard axis to find out, whether you can place your rectangle, until X < rectangle.widh + dashboard.width, same for Y.
Foreach X,Y on dashboard iterate over every panel to find whether they overlap. You can apply some optimization, to decrease amount of iteration. If panel overlap rectangle, you can increase X or Y(which is in nested loop) not by 1, but by width or height of panel.
In most cases, you will not make dashboard.width*dashboard.height*panel.count iteration. With some optimization, it will find best fit rather quick
I know this is an old question but if anyone wants a proof of concept then it looks like this:
function findSpace(width, height) {
var $ul = $('.snap-layout>ul');
var widthOfContainer = $ul.width();
var heightOfContainer = $ul.height();
var $lis = $ul.children('.setup-widget'); // The li is on the page and we dont want it to collide with itself
for (var y = 0; y < heightOfContainer - height + 1; y++) {
var heightOfShortestInRow = 1;
for (var x = 0; x < widthOfContainer - width + 1; x++) {
//console.log(x + '/' + y);
var pos = { 'left': x, 'top': y };
var $collider = $(isOverlapping($lis, pos, width, height));
if ($collider.length == 0) {
// Found a space
return pos;
}
var colliderPos = $collider.position();
// We have collided with something, there is no point testing the points within this widget so lets skip them
var newX = colliderPos.left + $collider.width() - 1; // -1 to account for the ++ in the for loop
x = newX > x ? newX : x; // Make sure that we are not some how going backwards and looping forever
var colliderBottom = colliderPos.top + $collider.height();
if (heightOfShortestInRow == 1 || colliderBottom - y < heightOfShortestInRow) {
heightOfShortestInRow = colliderBottom - y; // This isn't actually the height its just the distance from y to the bottom of the widget, y is normally at the top of the widget tho
}
}
y += heightOfShortestInRow - 1;
}
//TODO: Add the widget to the bottom
}
function isOverlapping($obsticles, tAxis, width, height) {
var t_x, t_y;
if (typeof (width) == 'undefined') {
// Existing element passed in
var $target = $(tAxis);
tAxis = $target.position();
t_x = [tAxis.left, tAxis.left + $target.outerWidth()];
t_y = [tAxis.top, tAxis.top + $target.outerHeight()];
} else {
// Coordinates and dimensions passed in
t_x = [tAxis.left, tAxis.left + width];
t_y = [tAxis.top, tAxis.top + height];
}
var overlap = false;
$obsticles.each(function () {
var $this = $(this);
var thisPos = $this.position();
var i_x = [thisPos.left, thisPos.left + $this.outerWidth()]
var i_y = [thisPos.top, thisPos.top + $this.outerHeight()];
if (t_x[0] < i_x[1] && t_x[1] > i_x[0] &&
t_y[0] < i_y[1] && t_y[1] > i_y[0]) {
overlap = this;
return false;
}
});
return overlap;
}

Categories