Set background color in a smooth way - javascript

I've got the following JS code:
// utility function to convert r,g,b to html color
function RGB2HTML(red, green, blue) {
var decColor =0x1000000+ blue + 0x100 * green + 0x10000 *red ;
return '#'+decColor.toString(16).substr(1);
}
// recursive utility function to animate color
// elNames an array of Ids (these are mainly TDs)
// curCnt is current animation step
// totSteps is total steps
function pulseBGMany(elNames, curCnt, totSteps) {
for(var i=0; i < elNames.length; ++i) {
var curEl = document.getElementById(elNames[i]);
var curColor = RGB2HTML(255, 255*(curCnt/totSteps), 255*(curCnt/totSteps));
curEl.style.backgroundColor = curColor;
}
if(curCnt < totSteps) {
setTimeout( function(){ pulseBGMany(elNames, curCnt+1, totSteps); }, 40);
}
}
// eventually in another piece of code, it all gets triggered
...
// schedule ui update here!
// use a closure
(function(names){ setTimeout( function(){ pulseBGMany(names, 0, 25); }, 40)})(diffRes);
...
The code above works, but unfortunately the animation is very chopped and I'm not able to see a smooth gradient from red to white; it seems like all major browsers are losing frames (tested on Firefox and Chromium on Ubuntu).
The array of TDs varies from 1 to even 80 elements, but the effect is always the same.
What am I doing wrong?
As requested, JSFiddle link: http://jsfiddle.net/PsvCP/2/ (You have to set No wrap in body)
Thanks,
Ema

Try doubling the amount of steps, 25fps is somewhat choppy.
Doubling the steps should put you at 50fps which should be fine.
Also make the elmntlist a array of dom elements and not a array of element id's,
Dom lookups are really slow and probaply causing most of your problems.

Think I've gotten around it. Apparently the setTimeout API is particularly slow in both Chrom(ium) and Firefox. Scheduling all the gradient function calls in advance is much more efficient for current browsers and does the trick:
// non-recursive utility function to animate color
function pulseBGMany(elNames, curCnt, totSteps) {
var curColor = RGB2HTML(255, 255*(curCnt/totSteps), 255*(curCnt/totSteps));
for(var i=0; i < elNames.length; ++i) {
elNames[i].style.backgroundColor = curColor;
}
}
...
// schedule ui update here!
// use a closure
var numFade = 15;
for(var i=0; i < numFade; ++i) {
(function(names, iter, tot){ setTimeout( function(){ pulseBGMany(names, iter+1, numFade); }, 50*iter)})(diffRes, i, numFade);
}
...
and as expected this works a lot faster.

Related

Adding delay to function during drawing objects

i placed setInterval into the code but this obviously delaying all the lasers by 1 second.
I want it to be working in the following sequence:
- at start laser1 and laser2 are fired.
- 1 second break and fire another set of lasers etc.
Also if someone could teach me how to move all block of code by four spaces on forum, that would be amazing, as none of the ways i found in google solve this ridiculous problem.
Code shortcut:
let laser1;
let lasers1 = [];
let laser2;
let lasers2 = [];
function createLaser() {
laser1 = new Laser(bossOne.x, bossOne.y + bossOne.sizeY, 10, 50, 5);
lasers1.push(laser1);
laser2 = new Laser(bossOne.x + bossOne.sizeX - 10, bossOne.y +
bossOne.sizeY, 10, 50, 5);
lasers2.push(laser2);
}
function draw() {
requestAnimationFrame(draw);
setInterval(createLaser, 1000);
for (i = 0; i < lasers1.length; i++) {
lasers1[i].show();
lasers1[i].move();
}
for (i = 0; i < lasers2.length; i++) {
lasers2[i].show();
lasers2[i].move();
}
}
requestAnimationFrame(draw);
Remote host for full code if needed:
https://stacho163.000webhostapp.com/
lasers are red
I think i should work with booleans, but can't handle to set it there.
Got a similar topic with key activation, but i lost contact with the one who proposed a solution on the basis of booleans (as it didn't work well) so i took the easiest part first without involving the keys.
Any tips are appreciated :)
Try changing setInterval to setTimeout, as it's already looping recursively - just add a delay to it. Also move the requestAnimationFrame call to the bottom of draw, not the top:
function draw()
setTimeout(createLasers, 1000);
//Loops
requestAnimationFrame(draw);
}

How can I ignore deceleration from event.acceleration in JS?

I'm trying to have an event occur when the phone first starts moving. This triggers just fine. However, I am running into a problem: deceleration is measured similarly to acceleration. When I stop moving the device, I see another spike. Any suggestions on how to ignore that second spike?
The following code gives me "huzzah!" when I first move the phone and when I stop moving it. I only want the trigger on the first movement. I got the pertinent functions and most of the variables defined here. Not the full extent of the script, but all the parts of this functionality.
var elmt = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var acceleration = eventData.acceleration;
var speed = 0;
speed = round(acceleration.y);
elmt.splice(0,1);
elmt.push(speed);
speedSmoothed=elmt.average();
//Rounding function
function round(val) {
var amt = 10;
return Math.round(val * amt) / amt;
}
//Averaging function for the array
Array.prototype.average=function(){
var sum=0;
var j=0;
for(var i=0;i<this.length;i++){
if(isFinite(this[i])){
sum=sum+parseFloat(this[i]);
j++;
}
}
if(j===0){
return 0;
}else{
return sum/j;
}
}
//trigger
if (speedSmoothed>1.5){
console.log("Huzzah!");
}
a few hours of thinking later, I got a little crafty. Enough to reliably behave like I want it to anyway.
if (speedSmoothed>1.5 && elmt[0]>elmt[4]){
console.log("Huzzah!");
}

Loop animation with svg.js

I have a very simple animation with svg.js that I would like to run on a loop as long as the page is open. I haven't been able to find any thing while looking through either the github, documentation, or stack overflow pages. A working version of the animation without looping can be found here. The important js is:
//create the svg element and the array of circles
var draw = SVG('canvas').size(300, 50);
var circ = [];
for (var i = 0; i < 5; i++) {
//draw the circles
circ[i] = draw.circle(12.5).attr({
fill: '#fff'
}).cx(i * 37.5 + 12.5).cy(20);
//first fade the circles out, then fade them back in with a callback
circ[i].animate(1000, '<>', 1000 + 100 * i).attr({
opacity: 0
}).after(function () {
this.animate(1000, '<>', 250).attr({
opacity: 1
});
});
}
I know this would be pretty easy to do without a js library, but I'm looking at this as just a first step into using svg.js. Later I plan on using it for much more robust animations. Thanks for any advice or pointers.
From version 0.38 of svg.js on the loop() method is built in:
https://github.com/wout/svg.js#loop
I'm also planning on creating a reverse() method in one of the upcoming releases. Right now the loop() method restarts the animation from the beginning.
I'm not sure if its possible just with svg.js attributes, as its not clear from svg.js if its creating typical svg animation elements or not. Whatever, it could be done with a loop though. So...
function anim( obj,i ) {
obj.animate(1000, '<>', 1000 + 100 * i).attr({
opacity: 0
}).after(function () {
obj.animate(1000, '<>', 250).attr({
opacity: 1
});
});
};
function startAnims() {
for( var i = 0; i< 5; i++ ) {
anim( circ[i],i );
}
setTimeout( startAnims, 5000 ); // Or possibly setInterval may be better
};
jsfiddle here http://jsfiddle.net/8bMBZ/7/ As its not clear if its adding elements each time behind the scenes (you may want to store the animation and just start that if so). There are other libs that tie in differently to SVG if you need like Raphael, snap, d3, Pablo.js that you could try as alternatives if you need to look at animation from a slightly different way.
I used after to call a function that start the animation recursively. This way I was able to achieve both infinite looping and reversing. Of course you can count to avoid infinite looping but the general idea is as follows:
//custom animation function whose context is the element animated
function myCustomAnimation(pos, morph, from, to) {
var currentVal = morph(from, to); //do morphing and your custom math
this.attr({ 'some prop': currentVal });
}
var animationStart = 0; //just extra values for my custom animation function
var animationEnd = 1; //animation values start at 0 and ends at 1
line.attr({ 'stroke-width': 2, stroke: 'red' });
animateMeRepeatedly.apply(line);
function animateMeRepeatedly()
{
this.animate(1500)
.during(function (pos, morph) {
myCustomAnimation.apply(this, [pos, morph, animationStart, animationEnd]);
})
.after(function () {
this.animate(1500).during(function (pos, morph) {
myCustomAnimation.apply(this, [pos, morph, animationEnd, animationStart]);
}).after(animateMeRepeatedly);
});
}

How to speed up this moving algorithm? In Javascript

I have an Array of 16 billiard balls in JS and want to move each ball smoothly with its direction and speed.
For that I set up a timer, calling UpdateThis() every 42ms (for 24 fps).
The problem is that UpdateThis() takes 53ms as firebug states.
Now UpdateThis iterates over every ball and calls UpdateBall(ball).
I assume that the problem lies there.UpdateBall looks like this:
function UpdateBall(ball)
{
if(ball.direction.x != 0 && ball.direction.y != 0) {
//ball moving!
for(var i = 0; i < balls.length; i++) {
//CheckCollision(ball, balls[i]); //even without this it takes 53 ms!
}
var ps = VAdd(ball.position, VMul(ball.direction, ball.speed)); //Multiply Direction with speed and add to position!
if(ps.x < Bx || ps.y < By || ps.x > Bw || ps.y > Bh) { //Bounce off the wall!
ball.direction = VMul(ball.direction, -1); //Invert direction
ball.speed *= 1;
ps = VAdd(ball.position, VMul(ball.direction, ball.speed)); //Calc new position!
}
ball.position = ps;
ball.MoveTo(); //See explanation at the bottom.
ball.speed *= GRK; //Gravity
if(ball.speed < 0.05) {
ball.speed = 0;
}
}
}
it seems that the most time is spent in ball.MoveTo() which looks like this:
function()
{
this.image.style.left = this.position.x + "px";
this.image.style.top = this.position.y + "px";
}
-- UPDATE --
function UpdateThis() {
for(var i = 0; i < balls.length; i++) {
var cur = balls[i];
UpdateBall(cur);
balls[i] = cur;
}
}
and onload looks like
nx = setInterval(function() { UpdateThis(); }, 42);
Does somebody have any ideas on how to speed this up?
-- UPDATE 2 --
You can download the folder with the HTML file here (the password is password)
What about separating the position updates from the drawing? So have something like this (untested code):
function DrawBall(ball)
{
ball.MoveTo(); //Take this line out of UpdateBall
}
-
function UpdateThis() {
for(var i = 0; i < balls.length; i++) {
var cur = balls[i];
UpdateBall(cur);
balls[i] = cur;
}
}
-
function DrawThis() {
for(var i = 0; i < balls.length; i++) {
DrawBall(balls[i]);
}
setTimeout(function() { DrawThis(); }, 42);
}
-
nx = setInterval(function() { UpdateThis(); }, 42);
setTimeout(function() { DrawThis(); }, 42);
If indeed it's the moving of the position that's slow, this way the logic update still happens at 42ms, and the framerate is no faster than 42ms but it can skip frames. (I haven't actually tried this, so this is all theoretical and you may need to tweak some stuff)
Why moving may be (and most probably is) slow?
Move functionality could be slow, because it has more things to do than simple variable assignment. It has to actually render some element to some other place. You could test this if you run this on IE9. I anticipate it should run faster since it uses hardware video acceleration.
As for the other routine I hope others will dissect it. :)
Questions for you
Can you please describe how do balls move? Sporadically? How do you call UpdateBall() for each ball? Do you queue those calls?
Provide VMul and VAdd functionality
Have you played with styling? Maybe relative positioning of balls' immediate parent may speed up rendering. And setting overflow:hidden on it as well. I don't know. Depends on how you've done it. Hence a JSFiddle would be very helpful.
A suggestion
Instead of using setInterval to call your function you should maybe just queue them and let them execute as fast as it gets. And just for the sake of it, provide a central setInterval with some watcher that they don't run too fast.
But I guess that it still utilizes your processor to 100% which isn't good anyway.
Very important note: Don't run you app while Firebug's enabled because it's a well known fact that Javascript executes much slower when Firebug is running.
That's tough, if MoveTo() is in fact your bottleneck, since there is not a whole lot going on there. About the only things I can think of, right off hand, are
1) Cache the style property of the image and position for faster lookups. Everytime you see a dot in the object chain it's requires stepping through the scope chain. Ideally you can cache this property at the time the parent of MoveTo() is constructed.
2) Are the 'px' strings required? It may result in an invalid CSS specification, but it may still work. I have a hard time believing 2 string concats would really change all that much though.
The main problem here is likely the fact that anytime you change the DOM, the browsers re-flows the entire page. Your only other option may be to refactor such that instead of changing the styles, you actually remove the previous contents, and replace it with the a document fragment describing the new state. This would result in only 2 re-flows for the entire step (1 for removal, 1 for addition), instead of 2 for each ball.
EDIT: Regarding #1 above, when I say cache, I don't mean just locally in the function call. But perhaps as a closure in the parent object. For example:
var Ball = function(img){
var style = img.style;
var posX;
var posY;
function MoveTo(){
style.left = posX + "px";
style.right = posY + "px";
}
};

How to optimize this js (now CPU is over 40% when the page is opened)

I have this piece of JavaScript on my page and it loads the CPU considerably. Is there any way to optimize the code? ( I'm using jQuery, so jQuery solutions will be fine )
function Particle() {
this.particleContainerWidth = $('#particle-container').width() - 100;
this.particleContainerHeight = $('#particle-container').height() - 100;
this.path = 'img/';
this.images = ['particle1.png', 'particle2.png', 'particle3.png', 'particle4.png'];
// Randomly Pick a Particle Model
this.image = this.images[randomInt(this.images.length)];
this.file = this.path + this.image;
// Create a Particle DOM
this.element = document.createElement('img');
this.speed().newPoint().display().newPoint().fly();
};
// Generate Random Speed
Particle.prototype.speed = function() {
this.duration = (randomInt(10) + 5) * 1100;
return this;
};
// Generate a Random Position
Particle.prototype.newPoint = function() {
this.pointX = randomInt(this.particleContainerWidth);
this.pointY = randomInt(this.particleContainerHeight);
return this;
};
// Display the Particle
Particle.prototype.display = function() {
$(this.element)
.attr('src', this.file)
.css('position', 'absolute')
.css('top', this.pointY)
.css('left', this.pointX);
$('#particle-container').append(this.element);
return this;
};
// Animate Particle Movements
Particle.prototype.fly = function() {
var self = this;
$(this.element).animate({
"top": this.pointY,
"left": this.pointX
}, this.duration, 'linear', function(){
self.speed().newPoint().fly();
});
};
function randomInt(max) {
// Generate a random integer (0 <= randomInt < max)
return Math.floor(Math.random() * max);
}
$(function(){
$('body').append('<div id="particle-container"></div>');
var total = 8;
var particles = [];
for (i = 0; i < total; i++){
particles[i] = new Particle();
}
});
You cannot make JavaScript consume less of your CPU. That is governed by the priority of the executing application in the OS kernel. The best you can hope for is to reduce execution time.
To improve your execution efficiency limit your usage of prototype and stop assigning values to properties. This method of coding has become popular because it is extremely clean and easy to read, but it horribly backwards to execute.
If you are capable of coding using only variables for assignment, if statements for decisions, and for loops for looping your code execution will be far faster. That will require you to write more code, however, and it will not be so pretty.
To improve output performance write all output segments each into an index of an array and use only a single join method when all output is created and a single innerHTML method to output this text to the page. This will reduce output execution by up to 4 times.
Have you thought about implementing this with a <canvas> version? It won't work in IE directly, of course, and off-hand I'm not sure whether it'd be faster or slower. You could also try it with Processing.
This would need a lot of changing and rewriting, but You can create a new easing function for jquery and post it to animate. Then every particle You have would just be once issued with animate() with Your easing function and the function has to be based on those:
random
current time (new Date()) modulo some number
a singleton holding individual directions
ideas:
Assuming You don't want to change Your code You can try setting the particle to fly with some random timeout when first running fly(). It could change the way it's all executed. No idea if it helps or makes it slower though ;)
Second thing is quality. jquery animate does it too smoothly. You can move Your particles instead of animating and just chande the distance to lower and increase speed and use setTimeout to make it move the same pace as now.

Categories