I have the following JavaScript code to update tiles on a page:
var delayMinimum = 1000;
var delayMaximum = 5000;
function UpdateTiles()
{
var width = 0;
var delay = 0;
var percent = 0;
var divNameLabel = "";
var divNameValue = "";
var divNameProgress = "";
if (Math.floor((Math.random() * 100) + 1) > 30)
{
percent = Math.floor((Math.random() * 100) + 1);
width = Math.floor(80 * percent / 100);
divNameLabel = "DivDashboardTileTemplatesLabel";
divNameValue = "DivDashboardTileTemplatesValue";
divNameProgress = "DivDashboardTileTemplatesProgress";
document.getElementById(divNameValue).innerText = percent.toString() + "%";
$("div#" + divNameProgress).animate({ width: (width.toString() + "px"), }, delayMinimum);
}
if (Math.floor((Math.random() * 100) + 1) > 30)
{
percent = Math.floor((Math.random() * 100) + 1);
width = Math.floor(80 * percent / 100);
divNameLabel = "DivDashboardTileDocumentsLabel";
divNameValue = "DivDashboardTileDocumentsValue";
divNameProgress = "DivDashboardTileDocumentsProgress";
document.getElementById(divNameValue).innerText = percent.toString() + "%";
$("div#" + divNameProgress).animate({ width: (width.toString() + "px"), }, delayMinimum);
}
if (Math.floor((Math.random() * 100) + 1) > 30)
{
percent = Math.floor((Math.random() * 100) + 1);
width = Math.floor(80 * percent / 100);
divNameLabel = "DivDashboardTileFormsLabel";
divNameValue = "DivDashboardTileFormsValue";
divNameProgress = "DivDashboardTileFormsProgress";
document.getElementById(divNameValue).innerText = percent.toString() + "%";
$("div#" + divNameProgress).animate({ width: (width.toString() + "px"), }, delayMinimum);
}
delay = Math.floor((Math.random() * (delayMaximum - delayMinimum)) + delayMinimum);
window.setTimeout(UpdateTiles, delay);
}
$(document).ready(UpdateTiles);
This works but any tiles updated in every iteration are updated all at once. How could I have independent timers with different intervals for each update?
Consider the following JSFiddle as a solution.
I have simplified it by using 1 function for all 3 calls and they now update at different (random) times. The key to recalling the update is the following line.
setTimeout(function () {updateTileSet(label,value,progress)}, delay);
You only have one timer: window.setTimeout(UpdateTiles, delay), add more timers as you need i order to have multiple timers.
Why did you duplicate the code 3 times?
Use functions instead and set the timeout in each one of them.
Related
I have some JavaScript code and it's working (kind of). I'd like to condense it somehow, maybe grab both the CSS selectors at once and iterate through them with a forEach() loop of some kind.
Right now, the top value for both stars gets the same value, eg style="top: 60%". I'd like to have them get different random values for the top, left, right and transform.
I realize the querySelectorAll will return a NodeList, and can be converted to an array, but I cannot figure out how to do this and have it so the .shooting-star-right gets different values using the Math.random section.
I've tried this:
var stars = document.querySelectorAll('.shooting-star, .shooting-star-right');
for (let el of stars) {
shootingStar();
}
I've also tried this:
var stars = document.querySelectorAll('.shooting-star, .shooting-star-right');
stars.forEach(function() {
shootingStar();
});
Here is my working (although quite messy) code => any help is much appreciated :)
init: () => {
let star = document.querySelector('.shooting-star');
let starRight = document.querySelector('.shooting-star-right');
const shootingStar = () => {
setInterval(() => {
let topPos = Math.floor(Math.random() * 80) + 1,
topPosRight = Math.floor(Math.random() * 80) + 1,
leftPos = Math.floor(Math.random() * 20) + 1,
rightPos = Math.floor(Math.random() * 20 + 1),
trans = Math.floor(Math.random() * 180) + 1,
transRight = Math.floor(Math.random() * 220) + 1;
topPos = topPos + '%',
topPosRight = topPosRight + '%',
leftPos = leftPos + '%',
rightPos = rightPos + '%',
trans = trans + 'deg',
transRight = transRight + 'deg';
star.style.top = topPos,
star.style.left = leftPos,
star.style.transform = 'rotate(' + '-' + trans + ')';
starRight.style.top = topPosRight,
starRight.style.right = rightPos,
starRight.style.transform = 'rotate(' + transRight + ')';
}, 9000);
};
shootingStar();
}
The element el has to be used in the forEach or for of loop. For example (not tested):
function setStyles(name, style) {
for (let el of document.getElementsByClassName(name)) el.style = style;
// or document.getElementsByClassName(name).forEach(el => el.style = style);
}
const r = n => Math.random() * n | 0 + 1;
setStyles('shooting-star', `top:${r(80)}%,left:${r(20)}%,transform:rotate(-${r(180)}deg)`);
setStyles('shooting-star-right', `top:${r(80)}%,right:${r(20)},transform:rotate(${r(220)}deg)`);
Well, this is lesser code:
star.style.top = (Math.floor(Math.random() * 80) + 1) +"%";
star.style.left = (Math.floor(Math.random() * 20) + 1) +"%;
etc.
Also, since you already use transform, you might as well use it for positioning. It works much better than setting left and top when used for animation.
let leftPos = Math.floor(Math.random() * 80) + 1
let topPos = Math.floor(Math.random() * 20) + 1
star.style.transform = 'translate('+ leftPos +'px, '+topPos +'px) rotate(' + '-' + trans + ')';
If you guys are interested, I ended up taking both your comments and finding a solution. I think this looks pretty good.
I really appreciate the assistance
const randomNum = (low, high) => {
let r = Math.floor(Math.random() * (high - low + 1)) + low;
return r;
};
const shootingStars = (name) => {
const stars = document.querySelectorAll(name);
const starsArray = [...stars];
setInterval(() => {
starsArray.forEach(el => {
el.style.cssText = 'transform: rotate(' + randomNum(0, 180) + 'deg' + ') translateY(' + randomNum(0, 200) + 'px' + ')';
});
}, 9000);
};
shootingStars('.shooting-star');
shootingStars('.shooting-star-right');
I want to keep updating my image position with HTML5 canvas. I tried the following javascript code to do the work
window.onload = function start() {
update();
}
function update() {
document.getElementById('scoreband').innerHTML = score;
var style = document.getElementById('bug').style;
timmer = window.setInterval(function () {
style.left = ((Math.random() * 100) + 1) + "%";
style.top = ((Math.random() * 100) + 19) + "%";
}, num);
}
But this is not working when it comes to HTML5 canvas. Is there similar way to do the same job in HTML5 canvas?
To change any visual DOM content you should use requestAmimationFrame
Eg
function update(time){
// time is in ms and has a 1/1000000 second accuracy
// code that changes some content, like the canvas
requestAnimationFrame(update); // requests the next frame in 1/60th second
}
And to start it
requestAnimationFrame(update);
As requested
indow.onload = function start() {
requestAnimationFrame(update);
}
function update() {
document.getElementById('scoreband').innerHTML = score;
var style = document.getElementById('bug').style;
style.left = ((Math.random() * 100) + 1) + "%";
style.top = ((Math.random() * 100) + 19) + "%";
requestAnimationFrame(update);
}
Though it’s not as good as requestAnimationFrame, setInterval’s frame rate can be dynamic.
//supposing num is defined lol
var timer = setInterval(update, num);
function update() {
document.getElementById('scoreband').innerHTML = score;
var style = document.getElementById('bug').style;
style.left = ((Math.random() * 100) + 1) + "%";
style.top = ((Math.random() * 100) + 19) + "%";
}
I have a Javascript animation at http://dev17.edreamz3.com/css/
All code works, however, there are performance problems. on Desktop, its good, On mobile things are so slow that it's unusable. I want to optimize the animation so that it runs smoothly on mobile. It can take 20 seconds or more for the animation to render.
Right now the way the code is designed is in js/anim.js there is a render() function that gets executed every time a scroll event happens. The problem is that this routine is not efficient, that's what I think of. Each time render() executes it loops through all the paths and sections of the maze and redraws them, is there any alternative way or a strategy to get it working both on mobile as well as desktop.
var offPathTime = 1000;
window.offSection = -1;
function render() {
// var top = ($window.scrollTop() + (0.4 * $window.height())) / window.scale;
var top = ($('.parent-div').scrollTop() + (0.4 * $('.parent-div').height())) / window.scale;
top -= 660;
top /= mazeSize.h;
if (window.offSection != -1) {
$body.addClass("blockScroll");
$('.parent-div').addClass("blockScroll");
// var wtop = $window.scrollTop() / window.scale;
var wtop = $('.parent-div').scrollTop() / window.scale;
wtop -= 660;
wtop /= mazeSize.h;
var $offSection = $("#offSection" + window.offSection);
var $section = $("#section" + window.offSection);
$(".section").removeClass("sectionActive");
$offSection.addClass("sectionActive");
$section.addClass("sectionActive");
var sTop = 200 -(mazeSize.h * (window.offSections[window.offSection].cy - wtop));
$container.animate({
left: 290 -(mazeSize.w * window.offSections[window.offSection].cx) + "px",
top: sTop + "px"
}, offPathTime);
// Path
var lr = offPaths[window.offSection].x1 > offPaths[window.offSection].x0;
var dx = Math.abs(offPaths[window.offSection].x1 - offPaths[window.offSection].x0);
var dashw = (dx * mazeSize.w) | 0;
$offPaths[window.offSection].css("width", "0px");
$offPaths[window.offSection].show();
if (lr) {
$offPaths[window.offSection].animate({
width: dashw + "px"
}, offPathTime);
} else {
var x0 = offPaths[window.offSection].x0 * mazeSize.w;
var x1 = offPaths[window.offSection].x1 * mazeSize.w;
$offPaths[window.offSection].css("left", x0 + "px");
$offPaths[window.offSection].animate({
width: dashw + "px",
left: x1 + "px"
}, offPathTime);
}
return;
}
$body.removeClass("blockScroll");
$('.parent-div').removeClass("blockScroll");
$(".offPath").hide();
if ($container.css("top") != "0px") {
$container.animate({
left: "-1550px",
top: "0px"
}, 500);
}
var pathIdx = -1;
var path0 = paths[0];
var path1;
var inPath = 0;
var i;
var curTop = 0;
var found = false;
for (i=0; i<paths.length; i++) {
var top0 = (i == 0) ? 0 : paths[i-1].y;
var top1 = paths[i].y;
if (top >= top0 && top < top1) {
pathIdx = i;
path1 = paths[i];
inPath = (top - top0) / (top1 - top0);
found = true;
if (i > 0) {
var dy = paths[i].y - paths[i-1].y;
var dx = paths[i].x - paths[i-1].x;
var vert = dx == 0;
if (vert)
$paths[i-1].css("height", (dy * mazeSize.h * inPath) + "px");
$paths[i-1].show();
}
} else if (top >= top0) {
path0 = paths[i];
var dy = paths[i].y - top0;
var vert = dy != 0;
if (i > 0) {
if (vert)
$paths[i-1].css("height", (dy * mazeSize.h) + "px");
$paths[i-1].show();
}
} else {
if (i > 0) {
$paths[i-1].hide();
}
}
curTop = top1;
}
// Check for an active section
$(".section").removeClass("sectionActive");
var section;
for (i=0; i<sections.length; i++) {
var d = Math.abs(sections[i].cy - (top - 0.05));
if (d < 0.07) {
var $section = $("#section" + i);
$section.addClass("sectionActive");
}
}
}
1) At the very least - assign all DOM objects to variables outside of the function scope. Like this:
var $parentDiv = $('.parent-div');
var $sections = $(".section");
...
function render() {
...
2) Also you should probably stop animation before executing it again, like this:
$container.stop(true).animate({
...
If you are running render() function on scroll - it will run many times per second. stop() helps to prevent it somewhat.
3) If it will not be sufficient - you can switch from jQuery to Zepto(jQuery-like api, but much faster and uses css transitions for animations) or to Velocity(basically drop-in replacement for jQuery $.animate and much faster than original) or even to GSAP - much more work obviously, but it is very fast and featured animation library.
I have the following JavaScript; the intent is that circles will bounce on the screen, off all edges.
I went to a variable storing the window's height and width, because I thought failure to bounce off the bottom of the screen might because the node was progressively expanding, so my original check against jQuery(window).height() was pointless.
However, after having addressed this way of making a window bouncy on the edges, or tried to (it's at http://cats.stornge.com), I have not seen a ball bounce off one edge of the window, and if you watch your scrollbar, you can see that they are going well beyond the original bottom of the window as they fall.
var viewport_height = jQuery(window).height()
var viewport_width = jQuery(window).width();
var available_images = ['red.png', 'orange.png', 'yellow.png',
'green.png', 'blue.png', 'purple.png', 'brown.png', 'black.png',
'grey.png']; //, 'white.png'];
var bodies = [];
for(var i = 0; i < 3; ++i)
{
body = {id: i, velocity_y : Math.random(),
velocity_x: Math.random() * 10 - 5,
position_x: Math.random() * viewport_width - 100,
position_y: Math.random() * viewport_height - 100};
document.write('<img id="' + i + '" src="' + available_images[Math.floor(Math.random() * available_images.length)] + '" style="z-index: ' + i + '" />');
bodies[bodies.length] = body;
}
function iterate()
{
for(var index = 0; index < bodies.length; ++index)
{
bodies[index].velocity_y += .1;
bodies[index].position_x += bodies[index].velocity_x;
bodies[index].position_y += bodies[index].velocity_y;
var position = jQuery('#' + index).position();
if (position.top + 100 > viewport_height)
{
bodies[index].velocity_y = - bodies[index].velocity_y;
bodies[index].position_y = viewport_height - 100;
}
if (position.top < 0)
{
bodies[index].velocity_y = - bodies[index].velocity_y;
bodies[index].position_y = 0;
}
if (position.left > viewport_width - 100)
{
bodies[index].velocity_x = -bodies[index].velocity_x;
bodies[index].position_x = viewport_width - 100;
}
jQuery('#' + index).css('margin-top',
bodies[index].position_y + 'px');
jQuery('#' + index).css('margin-left',
bodies[index].position_x + 'px');
}
}
setInterval(iterate, 30);
I'd love to see how to make this code set bouncy walls at the boundaries of the original viewport.
When changing the margin-top and margin-left, the width and height of the window started to change as well.
I got this to work by changing the css() calls setting margin-top and margin-left to offset(). I also added another if statement to make sure the balls bounced off the left-hand side as well:
var viewport_height = jQuery(window).height()
var viewport_width = jQuery(window).width();
var available_images = ['red.png', 'orange.png', 'yellow.png',
'green.png', 'blue.png', 'purple.png', 'brown.png', 'black.png',
'grey.png']; //, 'white.png'];
var bodies = [];
for(var i = 0; i < 3; ++i)
{
body = {id: i, velocity_y : Math.random(),
velocity_x: Math.random() * 10 - 5,
position_x: Math.random() * viewport_width - 100,
position_y: Math.random() * viewport_height - 100};
document.write('<img id="' + i + '" src="http://cats.stornge.com/' + available_images[Math.floor(Math.random() * available_images.length)] + '" style="z-index: ' + i + '" />');
bodies[bodies.length] = body;
}
function iterate()
{
for(var index = 0; index < bodies.length; ++index)
{
bodies[index].velocity_y += .1;
bodies[index].position_x += bodies[index].velocity_x;
bodies[index].position_y += bodies[index].velocity_y;
var position = jQuery('#' + index).position();
if (position.top + 100 > viewport_height)
{
bodies[index].velocity_y = - bodies[index].velocity_y;
bodies[index].position_y = viewport_height - 100;
}
if (position.top < 0)
{
bodies[index].velocity_y = - bodies[index].velocity_y;
bodies[index].position_y = 0;
}
if (position.left > viewport_width - 100)
{
bodies[index].velocity_x = -bodies[index].velocity_x;
bodies[index].position_x = viewport_width - 100;
}
if (position.left < 0)
{
bodies[index].velocity_x = -bodies[index].velocity_x;
bodies[index].position_x = 0;
}
jQuery('#' + index).offset({top: bodies[index].position_y, left: bodies[index].position_x });
}
}
setInterval(iterate, 30);
I want to make a div that is full width on the page. It's a container. Then I want to fill it in with divs, and width of each div is 50*n, where n is a randomly generated number. Assume I have a container div with width of 1240px. Now I run a JS function that fills it with e.g. 10 divs with different widths. Now if I sum up all inner divs widths, I get 1240px.
This way I always know that when I run filling function, I get a collection of divs that altogether always are 1240px. Number of divs shouldn't be a fixed number, so there can be 4 or 7 divs. The number of divs amount is generated randomly. Then, if there is some space left, for 1240 px this number is 40px I suppose, it is filled with some dummy div that doesn't have to be of 50*n width.
I have created a function but it doesn't always work as supposed to.
function generateItems() {
originalwidth = $(document).width() - 40;
var fullwidth = 0;
var counter = 0;
do{
var randomnumber = 1 + Math.floor(Math.random() * 4);
tempwidth = 50 * randomnumber;
fullwidth += tempwidth;
if (fullwidth > originalwidth) {
$('#questions').append('<div class="question-area" style="width:' + (originalwidth - fullwidth) + 'px;"><strong>' + (originalwidth - fullwidth) + '</strong></div>');
break;
}
width_padding = tempwidth;
$('#questions').append('<div class="question-area" style="width:' + width_padding + 'px;">' + width_padding + '</div>');
counter++;
}
while (true);
}
I am not even sure it's a good way I have chosen to solve such a task. Please share your thoughts on how to better do this.
I've refactored the code from your answer a bit.
See: http://jsfiddle.net/thirtydot/Bk2yw/
function generateItems() {
var slotWidth = 50,
maxSlots = 3,
thisSlotNum, thisWidth;
var remainingSlots = Math.floor($('#questions').width() / slotWidth),
remainingWidth = $('#questions').width() % slotWidth;
while (remainingSlots > 0) {
thisSlotNum = Math.min(remainingSlots, 1 + Math.floor(Math.random() * maxSlots));
remainingSlots -= thisSlotNum;
thisWidth = thisSlotNum * slotWidth;
$('#questions').append('<div class="question-area" style="width:' + thisWidth + 'px;"><strong>' + thisWidth + '</strong></div>');
}
if (remainingWidth) {
$('#questions').append('<div class="question-area" style="width:' + remainingWidth + 'px;"><strong>' + remainingWidth + '</strong></div>');
}
}
I played a little more with the code and it seems I made it work properly, though I am sure there is something to improve.
Here is the code:
function generateItems() {
originalwidth = $(document).width() - 40;
$('#questions').css('width', originalwidth);
var fullwidth = 0;
var counter = 0;
do{
var randomnumber = 1 + Math.floor(Math.random() * 4);
tempwidth = 50 * randomnumber;
fullwidth += tempwidth;
if (fullwidth > originalwidth) {
$('#questions').append('<div class="question-area" style="width:' + (originalwidth + tempwidth - fullwidth) + 'px;"><strong>' + (originalwidth + tempwidth - fullwidth) + '</strong></div>');
break;
}
width_padding = tempwidth;
$('#questions').append('<div class="question-area" style="width:' + width_padding + 'px;">' + width_padding + '</div>');
counter++;
}
while (true);
}
Here is an screenshot of how it works. The bottom row is the result for another width of the page.
A couple of problems:
fullwidth += tempwidth;
if (fullwidth > originalwidth) {
$('#questions').append('<div class="question-area" style="width:' + (originalwidth - fullwidth) + 'px;"><strong>' + (originalwidth - fullwidth) + '</strong></div>');
break;
}
Here you have already "gone over" the original width with the fullwidth variable, so when you do originalwidth - fullwidth it's always negative (by definition because fullwidth > originalwidth).
Another problem is that if the random width is for example 150 pixels and you have 140 pixels of space left, your code considers that as space running out and puts in the dummy div of 140 px. It's not clear from your question but you probably want a 100 px block and the rest filled with a 40 px block.
Here's a working version:
function generateItems() {
var originalwidth = $(document).width() - 40;
var fullwidth = 0;
var counter = 0;
do{
var randomnumber = 1 + Math.floor(Math.random() * 3);
var tempwidth = 50 * randomnumber;
if (fullwidth + tempwidth > originalwidth) {
var diff = originalwidth - fullwidth;
if( originalwidth - fullwidth > 50 ) {
tempwidth = diff - ( diff % 50 );
}
else {
$('#questions').append('<div class="question-area" style="width:' + diff + 'px;"><strong>' + diff + '</strong></div>');
break;
}
}
fullwidth += tempwidth;
$('#questions').append('<div class="question-area" style="width:' + tempwidth + 'px;">' + tempwidth + '</div>');
counter++;
}
while (true);
}