Improve multiple setInterval() lag in javascript matrix effect - javascript

I am using multiple setInterval() e.g. to create, move, delete the strings that fall on the screen
Problem is that the MODE 1 interval causes a lag for the interval1
I've also tried to switch to the MODE 2 STUFF but the lag still occurs...
How can this be improved?
function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
var chinese = [`電`,`買`,`開`,`東`,`車`,`紅`,`馬`,`無`,`鳥`,`熱`,`時`,`佛`,`德`,`拜`,`黑`,`冰`,`兔`,`妒`,`壤`,`每`,`步`,`聽`,`實`,`證`,`龍`,`賣`,`龜`,`藝`,`戰`,`繩`,`關`,`鐵`,`圖`,`團`,`轉`,`廣`,`惡`,`豐`,`腦`,`雜`,`壓`,`雞`,`價`,`樂`,`氣`,`廳`,`發`,`勞`,`劍`,`歲`,`權`,`燒`,`贊`,`兩`,`譯`,`觀`,`營`,`處`,`學`,`體`,`點`,`麥`,`蟲`,`舊`,`會`,`萬`,`盜`,`寶`,`國`,`醫`,`雙`,`觸`,`參`];
var japanese = ['が','ぎ','ぐ','げ','ご','ゃ','ゅ','ょ','ざ','じ','ず','ぜ','ぞ','だ','づ','で','ど','ぢ','ば','ぶ','べ','ぼ','ぱ','ぴ', 'ぷ','ぺ','ぽ','あ','い','う','え','お','か','き','く','け','こ','き','さ','し','す','せ','そ','し','た','ち','つ','て','と','ち','な','に','ぬ','ね','の','に','は','ふ','へ','ほ','ひ','ま','み','む','め','も','や','ゆ','よ','ら','る','れ','ろ','り','わ','ゐ','ゑ','を'];
var characters = japanese;
var speedL = [60,80,90,100,120,140,160,180,200,220,240,280,300,400,500,600,700,800,810,820,830,840,850];
var speedDown = [4,5,6,7,8,9,10];
// MODE 2 STUFF
/*var timeStmpSleepMs = 480;
var timeStmp = Date.now();*/
function do_string(){
var string = document.createElement('section');
var sd = speedDown[Math.floor(Math.random()*speedDown.length)];
string.style.left = Math.floor(Math.random() * (document.documentElement.clientWidth-80)) + 'px';
var t = -2200;
string.style.top = t+'px';
var interval1 = setInterval(function(){
// MODE 2 STUFF
/*var newTimeStmp = Date.now();
if((newTimeStmp - timeStmp) > 480){
timeStmp = newTimeStmp;
//console.log('timeStmpSleepMs fired');
do_string();
}*/
if(parseInt(string.style.top) >= (document.documentElement.clientHeight-100)){
clearInterval(interval1);
string.remove();
return false;
}
string.style.top = (t += sd) + 'px';
}, 16);
function letter(){
var letter = document.createElement('div');
letter.innerHTML = characters[Math.floor(Math.random()*characters.length)];
string.appendChild(letter);
// CHANGING LETTER & DELETING LETTER
/*var interval2 = setInterval(function(){
if(parseInt(string.style.top) >= (document.documentElement.clientHeight-200)){
clearInterval(interval2);
letter.remove();
return false;
}
letter.innerHTML = characters[Math.floor(Math.random()*characters.length)];
}, speedL[Math.floor(Math.random()*speedL.length)]);*/
}
for(var i=0; i<getRandomInt(1, 180); i++){
letter();
document.body.appendChild(string);
}
}
do_string();
// MODE 1 STUFF
setInterval(function(){
do_string();
}, 480);
body {
font-size: 16px;
background: black;
color: #25ff00;
font-weight: bold;
font-family: monospace;
line-height: 20px;
}
section {
position: fixed;
}

Hey setInterval uses the same event loop to run, for better performance use requestAnimationFrame which runs on a separate event loop leaving the current one open for other things, see the code below
function doString(){
// Do your string stuff
var rid = requestAnimationFrame(doString);
}
doString();
If you want to control the FPS see this post

Related

How to create a screensaver in javascript

I want to create a screensaver in JavaScript but I don't know how can I set the time between the images,.
I have an Ajax call and I see if the time is, for example, 2s or 90s, but I don't know how to set that time between images, this is my code:
var cont = 0;
var time = 1000
setInterval(function() {
console.log(tiempo);
if(cont == imagenes.length){
return cont = 0;
}else{
var imagen = imagenes[cont].imagen;
$('#imgZona').attr('src', imagen);
var time = imagenes[cont].tiempoVisible;
finalTime = Number(time);
}
cont++;
}, Number(finalTime ));
but the time between images is always the same, 1000, how can I change it for the time that I receive in the Ajax call? Which is imagenes[cont].tiempoVisible
I cannot comment as I don't have enough reputation, but take a look at this fiddle
https://jsfiddle.net/kidino/4mbpR/
var mousetimeout;
var screensaver_active = false;
var idletime = 5;
function show_screensaver(){
$('#screensaver').fadeIn();
screensaver_active = true;
screensaver_animation();
}
function stop_screensaver(){
$('#screensaver').fadeOut();
screensaver_active = false;
}
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
$(document).mousemove(function(){
clearTimeout(mousetimeout);
if (screensaver_active) {
stop_screensaver();
}
mousetimeout = setTimeout(function(){
show_screensaver();
}, 1000 * idletime); // 5 secs
});
function screensaver_animation(){
if (screensaver_active) {
$('#screensaver').animate(
{backgroundColor: getRandomColor()},
400,
screensaver_animation);
}
}
It will change background-color on idle mouse for 5 seconds, you can replace the code to change image, instead of background color.
Control set every timeout on each iteration.
var cont = 0;
var time = 1000
function next () {
console.log(tiempo);
if(cont == imagenes.length){
cont = 0;
}
var imagen = imagenes[cont].imagen;
$('#imgZona').attr('src', imagen);
cont++;
setTimeout(next, Number(imagenes[cont].tiempoVisible));
}
setTimeout(next, Number(initialTime));
Also I fixed a frindge condition.

Adding click event on a specific div with JavaScript

I have a snowfall effect in JavaScript, I want the create a click event on the 10th snowflake that falls down. I would also like to add a Class that says "clickable". We want to achieve this, so if user clicks the 10th snowflake only, then they will be redirected to a prize (we also want to add a Class so we can style this nicely via CSS).
I must admit, my JavaScript knowledge isn't as strong as my jQuery, so could someone please help? Here is the codepen that I am using:-
https://codepen.io/scottYg55/pen/GRRzOgO
#snowflakeContainer {
position: absolute;
left: 0px;
top: 0px;
bottom: 0;
right: 0;
background-color: #2c3e50;
}
.snowflake {
padding-left: 15px;
font-family: Cambria, Georgia, serif;
font-size: 14px;
line-height: 24px;
position: fixed;
color: #FFFFFF;
user-select: none;
z-index: 1000;
}
<div id="snowflakeContainer">
<p class="snowflake">*</p>
</div>
JS
// The star of every good animation
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
var transforms = ["transform",
"msTransform",
"webkitTransform",
"mozTransform",
"oTransform"];
var transformProperty = getSupportedPropertyName(transforms);
// Array to store our Snowflake objects
var snowflakes = [];
// Global variables to store our browser's window size
var browserWidth;
var browserHeight;
// Specify the number of snowflakes you want visible
var numberOfSnowflakes = 50;
// Flag to reset the position of the snowflakes
var resetPosition = false;
//
// It all starts here...
//
function setup() {
window.addEventListener("DOMContentLoaded", generateSnowflakes, false);
window.addEventListener("resize", setResetFlag, false);
}
setup();
//
// Vendor prefix management
//
function getSupportedPropertyName(properties) {
for (var i = 0; i < properties.length; i++) {
if (typeof document.body.style[properties[i]] != "undefined") {
return properties[i];
}
}
return null;
}
//
// Constructor for our Snowflake object
//
function Snowflake(element, radius, speed, xPos, yPos) {
// set initial snowflake properties
this.element = element;
this.radius = radius;
this.speed = speed;
this.xPos = xPos;
this.yPos = yPos;
// declare variables used for snowflake's motion
this.counter = 0;
this.sign = Math.random() < 0.5 ? 1 : -1;
// setting an initial opacity and size for our snowflake
this.element.style.opacity = .1 + Math.random();
this.element.style.fontSize = 12 + Math.random() * 50 + "px";
}
//
// The function responsible for actually moving our snowflake
//
Snowflake.prototype.update = function () {
// using some trigonometry to determine our x and y position
this.counter += this.speed / 5000;
this.xPos += this.sign * this.speed * Math.cos(this.counter) / 40;
this.yPos += Math.sin(this.counter) / 40 + this.speed / 30;
// setting our snowflake's position
setTranslate3DTransform(this.element, Math.round(this.xPos), Math.round(this.yPos));
// if snowflake goes below the browser window, move it back to the top
if (this.yPos > browserHeight) {
this.yPos = -50;
}
}
//
// A performant way to set your snowflake's position
//
function setTranslate3DTransform(element, xPosition, yPosition) {
var val = "translate3d(" + xPosition + "px, " + yPosition + "px" + ", 0)";
element.style[transformProperty] = val;
}
//
// The function responsible for creating the snowflake
//
function generateSnowflakes() {
// get our snowflake element from the DOM and store it
var originalSnowflake = document.querySelector(".snowflake");
// access our snowflake element's parent container
var snowflakeContainer = originalSnowflake.parentNode;
// get our browser's size
browserWidth = document.documentElement.clientWidth;
browserHeight = document.documentElement.clientHeight;
// create each individual snowflake
for (var i = 0; i < numberOfSnowflakes; i++) {
// clone our original snowflake and add it to snowflakeContainer
var snowflakeCopy = originalSnowflake.cloneNode(true);
snowflakeContainer.appendChild(snowflakeCopy);
// set our snowflake's initial position and related properties
var initialXPos = getPosition(50, browserWidth);
var initialYPos = getPosition(50, browserHeight);
var speed = 5+Math.random()*40;
var radius = 4+Math.random()*10;
// create our Snowflake object
var snowflakeObject = new Snowflake(snowflakeCopy,
radius,
speed,
initialXPos,
initialYPos);
snowflakes.push(snowflakeObject);
}
// remove the original snowflake because we no longer need it visible
snowflakeContainer.removeChild(originalSnowflake);
// call the moveSnowflakes function every 30 milliseconds
moveSnowflakes();
}
//
// Responsible for moving each snowflake by calling its update function
//
function moveSnowflakes() {
for (var i = 0; i < snowflakes.length; i++) {
var snowflake = snowflakes[i];
snowflake.update();
}
// Reset the position of all the snowflakes to a new value
if (resetPosition) {
browserWidth = document.documentElement.clientWidth;
browserHeight = document.documentElement.clientHeight;
for (var i = 0; i < snowflakes.length; i++) {
var snowflake = snowflakes[i];
snowflake.xPos = getPosition(50, browserWidth);
snowflake.yPos = getPosition(50, browserHeight);
}
resetPosition = false;
}
requestAnimationFrame(moveSnowflakes);
}
//
// This function returns a number between (maximum - offset) and (maximum + offset)
//
function getPosition(offset, size) {
return Math.round(-1*offset + Math.random() * (size+2*offset));
}
//
// Trigger a reset of all the snowflakes' positions
//
function setResetFlag(e) {
resetPosition = true;
}
Thank you in advance for your help!
Greatly appreciated
When generating the snowflakes, try to catch the 10th one and apply what you want
...
function generateSnowflakes() {
...
// create each individual snowflake
for (var i = 0; i < numberOfSnowflakes; i++) {
// clone our original snowflake and add it to snowflakeContainer
var snowflakeCopy = originalSnowflake.cloneNode(true);
snowflakeContainer.appendChild(snowflakeCopy);
// <------------------------------------------>
// catch the tenth snowflake and add your changes here
if (i === 9) {
snowflakeCopy.classList.add("clickable");
snowflakeCopy.addEventListener("click",function (e) {
//the stuff you want to do
//when the 10th snowflake is clicked
// for example :
window.location.replace("URL/OF/PRIZE");
})
}
....
}
...
```

Are there different ways of controlling the font-weight locally or on an uploaded web page?

We have created a typewriter simulator which controls the font weight depending on how fast you type, it is controlled with some javascript, some jQuery and styled with css. Here's the link.https://www.dynamik.systems/typewriter/
Before we uploaded it to the site we coded everything with the program Brackets and the font is something we created with a much wider weight then the usual ones.
But now, when everything is up and running it doesn't work like it did from when we coded it locally. No code is changed and the font-face is the same. We have tried it in Chrome, Safari and Firefox.
This is how it looks locally loaded:
https://imgur.com/yNxaX8B
This is how it looks now:
https://imgur.com/OpoYxpV
This is with another font that shows that the code is working:
https://imgur.com/HKPxMlm
We only have tried different types of font styles (otf, ttf, wow etc.) because that's the only thing we can come up with.
The jquery and js.
(function($) {
let i = 0;
let lastTime = 0;
const $output = $("#output");
const $content = $('#content');
$(window).on("keypress", function(event) {
// Prevent backspace, enter and escape
if(event.which === 13 || event.which === 8 || event.which === 27) { console.log('No output'); return; }
// Keypress counter
$("span2").text(i += 1 );
// Intervall for scrollbar
setInterval(updateScroll,5000);
// Timer for Key llklkLatency
let currTime = new Date();
let ms = lastTime ? currTime - lastTime : 0;
$output.text(ms + "ms");
lastTime = currTime;
// Fontweight
var fontWeight = ms > 900 ? 100 : 900 / ms * 100;
// Typewriter
var key = event.key;
$content.append('<span style="font-weight:' + fontWeight + '">' + key + '</span>');
//Font-Weight
$("span3").text(fontWeight);
});
})( jQuery );
function updateScroll(){
var element = document.getElementById("content");
element.scrollTop = element.scrollHeight;
}
// Timer
const output = document.querySelector('output');
let timeRead = false;
let now = 0;
let interval = null;
function startTimer() {
let elapsedMil = Date.now() - now;
let mil = (elapsedMil).toFixed(0) % 100;
let sec = Math.floor(elapsedMil/1000) % 60;
let min = Math.floor(elapsedMil/60000) % 60;
let hou = Math.floor(elapsedMil/3600000) % 24;
mil = padTime(mil);
sec = padTime(sec);
min = padTime(min);
hou = padTime(hou);
function padTime(num) {
if (num < 10) {
num = "0" + num;
}
return num;
}
output.textContent = hou + ":" + min + ":" + sec + ":" + mil;
}
window.onload = function () {
now = Date.now();
interval = window.setInterval(startTimer, 10);
};
var timer = new Timer();
timer.start();
timer.addEventListener('secondsUpdated', function (e) {
$('#basicUsage').html(timer.getTimeValues().toString());
});
function myFunction() {
document.body.style.backgroundColor = "white";
document.getElementById("info").style.color = "black";
document.getElementById("content").style.color = "black";
}
function myFunction2() {
document.body.style.backgroundColor = "black";
document.getElementById("info").style.color = "white";
document.getElementById("content").style.color = "white";
}
function myFunction3() {
document.body.style.backgroundColor = "#FF3700";
document.getElementById("info").style.color = "black";
document.getElementById("content").style.color = "black";
}
Beginning of the CSS to call for the font:
#font-face {
font-family: "dynamik";
src: url('https://www.dynamik.systems/wp-content/themes/fonts/DynamikGX.eot') format('opentype'),
url('https://www.dynamik.systems/wp-content/themes/fonts/DynamikGX.ttf') format('truetype'),
url('https://www.dynamik.systems/wp-content/themes/fonts/DynamikGX.woff') format('woff');
}
We expect the font-weight to be as the way when we uploaded it locally.

Paperjs bounce animation

Theres some wierd behaviour when playing with Paperjs, i was trying to curve a line up with 7 points separately - which works fine once, but when trying to make the link overshoot and return to 3 different points (to create a bounce effect) doesn't seem to play ball. On the second if statement, the 'counter' variable doesnt seem to increase instead of decrease, '+ steps' instead of '- steps'.
Maybe i'm not using if statements properly in this case, or paperjs has some strange behaviour?
Heres the codepen for it in full, click above the blue line to trigger it off. . Following is one setInterval for one of the points of the segment.
var seg6first = true;
var seg6sec = false;
var seg6thir = false;
setInterval(function() {
if (seg6first == true) {
counter = counter - steps;
if (counter >= 230) {
path.segments[6].point.y = counter;
path.smooth(); }
else {
seg6first = false;
seg6sec = true;
}
}
if (seg6sec == true) {
counter = counter + steps;
if (counter <= 260) {
path.segments[6].point.y = counter;
path.smooth();}
else {
seg6sec = false;
seg6thir = true;
}
}
if (seg6sec == true) {
counter = counter - steps;
if (counter >= 250) {
path.segments[6].point.y = counter;
path.smooth(); }
else {
seg6thir = false;
}
}
}, mintiming);
Thanks!
Rather than manually building your bounce effect, you can use an animation library like GSAP.
It has a lot of features that will make your task easier (see easing documentation).
Here is an example of what you are trying to do (click on the canvas to animate the line).
html,
body {
margin: 0;
overflow: hidden;
height: 100%;
}
canvas[resize] {
width: 100%;
height: 100%;
}
<canvas id="canvas" resize></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.11.8/paper-full.min.js"></script>
<script type="text/paperscript" canvas="canvas">
// user defined constants
var SEGMENTS_COUNT = 6;
var CURVE_HEIGHT = 80;
var ANIMATION_DURATION = 2;
// init path
var path = new Path({
fillColor: 'orange',
selected: true
});
// add points
for (var i = 0; i <= SEGMENTS_COUNT; i++) {
path.add([view.bounds.width * i / SEGMENTS_COUNT, view.center.y]);
}
// on mouse down...
function onMouseDown() {
// ...animate points
for (var i = 0, l = path.segments.length; i < l; i++) {
// get a reference to the point
var point = path.segments[i].point;
// calculate offset using sine function to form a curve
var offset = CURVE_HEIGHT * Math.sin(point.x * Math.PI / view.bounds.width);
// register animation
TweenLite.fromTo(
// target
point,
// duration
ANIMATION_DURATION,
// initial value
{ y: view.center.y },
{
// final value
y: view.center.y - offset,
// easing
ease: Elastic.easeOut.config(1, 0.3),
// on update...
onUpdate: function() {
// ...smooth the path
path.smooth();
}
}
);
}
}
</script>

How to add elements fast but not instantly in javascript?

I would like to fill an element with dots in random order. I have managed to write all the functionality, but I am not satisfied with the execution speed.
If I add all of the points using a while loop, the points just seem to appear all at the same time.
Therefore I add points one by one using a function that I call recursively with a timeout. This, on the other hand, appears too slow. Is there any chance to run a sequence of actions slower than in a loop but faster than setTimeout() can?
var dotCellSize;
var initialOffset;
var slotsHorizontally;
var slotsVertically;
var container;
var redDots;
var dots;
var newDotElement = $('<div class="dot">');
function randomInteger(min,max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function addDots()
{
if (!dots.length)
return;
var dotIndex = randomInteger(0, dots.length - 1);
var dot = dots[dotIndex];
dots.splice(dotIndex, 1);
var column = dot % slotsHorizontally;
var row = Math.floor(dot/slotsHorizontally);
var position = {
left: initialOffset + column*dotCellSize,
top: initialOffset + row*dotCellSize
};
var dotElement = newDotElement.clone().css(position);
if (-1 != redDots.indexOf(dot))
dotElement.addClass('red');
dotElement.appendTo(container);
setTimeout(function() {
addDots();
}, 1);
}
function generateDots(dotContainer, cellSize, numberOfRedDots)
{
container = dotContainer;
dotCellSize = cellSize;
dots = [];
redDots = [];
container.find('div.dot').remove();
numberOfRedDots = typeof numberOfRedDots !== 'undefined' ? numberOfRedDots : 3;
initialOffset = Math.floor(dotCellSize/2);
slotsHorizontally = Math.ceil(container.width()/dotCellSize);
slotsVertically = Math.ceil(container.height()/dotCellSize);
var numberOfSlots = slotsHorizontally*slotsVertically;
while (dots.length < numberOfSlots)
dots.push(dots.length);
while (redDots.length < numberOfRedDots)
{
var newRedDot = randomInteger(0, numberOfSlots - 1);
if (-1 == redDots.indexOf(newRedDot))
redDots.push(newRedDot);
}
addDots();
}
generateDots($('.dot-container'), 18, 15);
.dot {
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #C0E3EA;
position: absolute;
z-index: 1;
}
.dot.red {
background-color: #EF3D48;
}
.dot-container {
width: 420px;
height: 280px;
background-color: #333;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dot-container"></div>
Unfortunately, not really, this is because of how the browser engine decides to repaint the screen. Without the timeout, the browser engine recognizes it's going to do a bunch of updates (adding the dots to the DOM). Because repainting the screen is expensive, it waits to do as much as possible at one time, and, in your case, all of the dots show up at once. With the timeout added, each call to your function gets "deferred" for future execution.
This may or may not happen "right away" and is non-trivial to explain in detail so I would recommend watching this video https://www.youtube.com/watch?v=8aGhZQkoFbQ which explains the JS event loop or read some articles on browser reflow:
Minimizing browser reflow
What is Layout Thrashing?
Without changing much of what you've already done, one solution is to batch a few of the dots to be drawn together. I've added a for loop to your function which will make five dots get drawn together. Adjust this to 10, 20, or higher and you'll see the dots get painted even faster. I hope there is a number that you'll find suitable. I understand you may want to just speed up the drawing of every dot individually, but bear in mind that screens have refresh rates, so the faster you want the routine to finish the more they will appear in batches any way.
var dotCellSize;
var initialOffset;
var slotsHorizontally;
var slotsVertically;
var container;
var redDots;
var dots;
var newDotElement = $('<div class="dot">');
function randomInteger(min,max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function addDots()
{
if (!dots.length)
return;
for (let i = 0; i < 5; i++) {
var dotIndex = randomInteger(0, dots.length - 1);
var dot = dots[dotIndex];
dots.splice(dotIndex, 1);
var column = dot % slotsHorizontally;
var row = Math.floor(dot/slotsHorizontally);
var position = {
left: initialOffset + column*dotCellSize,
top: initialOffset + row*dotCellSize
};
var dotElement = newDotElement.clone().css(position);
if (-1 != redDots.indexOf(dot))
dotElement.addClass('red');
dotElement.appendTo(container);
}
setTimeout(function() {
addDots();
}, 1);
}
function generateDots(dotContainer, cellSize, numberOfRedDots)
{
container = dotContainer;
dotCellSize = cellSize;
dots = [];
redDots = [];
container.find('div.dot').remove();
numberOfRedDots = typeof numberOfRedDots !== 'undefined' ? numberOfRedDots : 3;
initialOffset = Math.floor(dotCellSize/2);
slotsHorizontally = Math.ceil(container.width()/dotCellSize);
slotsVertically = Math.ceil(container.height()/dotCellSize);
var numberOfSlots = slotsHorizontally*slotsVertically;
while (dots.length < numberOfSlots)
dots.push(dots.length);
while (redDots.length < numberOfRedDots)
{
var newRedDot = randomInteger(0, numberOfSlots - 1);
if (-1 == redDots.indexOf(newRedDot))
redDots.push(newRedDot);
}
addDots();
}
generateDots($('.dot-container'), 18, 15);
.dot {
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #C0E3EA;
position: absolute;
z-index: 1;
}
.dot.red {
background-color: #EF3D48;
}
.dot-container {
width: 420px;
height: 280px;
background-color: #333;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dot-container"></div>
Quickly profiling on my i7 3770k revealed that newDotElement.clone().css(position) took about .1 seconds. If you are running at 30 FPS, your frame time is .03 seconds. So you can see that Jquery clone is somewhat of a bottleneck.
However, your initial approach of drawing all the dots at once is sound, if you flag their styles to be "hidden". Then, when all the dots are added to the DOM, but are not visible, retrieve a list of their nodes (forgive the vanilla JS):
Array.from(document.getElementsByClassName("dot-container")[0].childNodes);
Now you can iterate over them and simply change their visibility style from "hidden" to "visible". As skyline3000 points out, the limit with setTimeout (or even requestAnimationFrame) is in the browser, and looping and setting one dot per iteration will take a little over 1 frame, which is actually a little slow. So you can write yourself a little abraction which per call will set a certain number of elements' visibility styles to "visible". By adjusting the quantity of dots you make visible per call, you will speed up or slow down the animation.
function showDots() {
var list = Array.from(document.getElementsByClassName("dot-container")[0].childNodes);
function draw(q) {
var e;
for (var i = 0; i < q; i++) {
if (list.length == 0) {
return;
}
e = list.shift();
e.style.visibility = "visible";
}
}
function callback() {
if (list.length == 0) {
return;
}
draw(4);
setTimeout(callback);
}
callback();
}

Categories

Resources