Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Real Time Animations and Maximum FPS Limiter #366

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
16e0c32
++FPS Limiter, fixing common complaint
caldempsey Feb 20, 2018
d28b4fe
++FPS Limit added
caldempsey Feb 20, 2018
80b6e6e
Update package.json
caldempsey Feb 20, 2018
2647389
Consistent formatting with original
caldempsey Feb 20, 2018
5c25d65
Consistent formatting with original
caldempsey Feb 20, 2018
66d0038
Update README.md
caldempsey Feb 20, 2018
eec12b4
Update package.json
caldempsey Feb 20, 2018
2b9321f
Update package.json
caldempsey Feb 20, 2018
df6c857
Update package.json
caldempsey Feb 20, 2018
949cf69
Consistency with your code
caldempsey Feb 20, 2018
2397140
Update particles.js
caldempsey Feb 20, 2018
bfafa84
Update particles.js
caldempsey Feb 20, 2018
1b2d33f
Consistency with README
caldempsey Feb 20, 2018
cb9eed3
Removed newline
caldempsey Feb 20, 2018
17b927a
Update particles.json
caldempsey Feb 20, 2018
7ef9796
Update particles.json
caldempsey Feb 20, 2018
0d1c2df
Update particles.json
caldempsey Feb 20, 2018
f00eca0
Update particles.json
caldempsey Feb 20, 2018
b2a0e35
Update package.json
caldempsey Feb 20, 2018
3b552b6
++FPS Limiter, fixing common complaint
caldempsey Feb 20, 2018
5119154
Merge remote-tracking branch 'origin/master'
caldempsey Feb 20, 2018
98dd36b
++FPS Limiter, fixing common complaint
caldempsey Feb 20, 2018
6c454f0
++FPS Limiter, fixing common complaint
caldempsey Feb 20, 2018
029285e
++FPS Limiter, fixing common complaint
caldempsey Feb 20, 2018
625de2b
++FPS Limiter, fixing common complaint
caldempsey Feb 20, 2018
a67285e
Update README.md
caldempsey Feb 20, 2018
6f3e03e
Update README.md
caldempsey Feb 20, 2018
e194cb9
Update README.md
caldempsey Feb 20, 2018
704ae40
Update README.md
caldempsey Feb 20, 2018
c174558
Update README.md
caldempsey Feb 20, 2018
2fde687
Update README.md
caldempsey May 21, 2018
c7b09df
Minor bug fx
dgiangrave Jan 21, 2019
a7cf07a
Real Time Animations
dgiangrave Jan 23, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ particlesJS.load('particles-js', 'assets/particles.json', function() {
**particles.json**
```javascript
{
"fps_limit": 60,
"particles": {
"number": {
"value": 80,
Expand Down Expand Up @@ -153,6 +154,7 @@ particlesJS.load('particles-js', 'assets/particles.json', function() {

key | option type / notes | example
----|---------|------
`.fps_limit` | Limits the fps of the animation redraw, set to 0 for no limit | `30`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`.fps_limit` | Limits the fps of the animation redraw, set to 0 for no limit | `30`
`.fps_limit` | Limits the fps of the animation redraw, set to 0 for no limit | `60`

Should this be 60?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be merged is what it should be!

`particles.number.value` | number | `40`
`particles.number.density.enable` | boolean | `true` / `false`
`particles.number.density.value_area` | number | `800`
Expand Down
1 change: 1 addition & 0 deletions demo/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ particlesJS.load('particles-js', 'particles.json', function() {
particlesJS('particles-js',

{
"fps_limit": 60,
"particles": {
"number": {
"value": 80,
Expand Down
3 changes: 2 additions & 1 deletion demo/particles.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"fps_limit": 60,
"particles": {
"number": {
"value": 80,
Expand Down Expand Up @@ -54,7 +55,7 @@
},
"move": {
"enable": true,
"speed": 6,
"speed": 2,
"direction": "none",
"random": false,
"straight": false,
Expand Down
114 changes: 72 additions & 42 deletions particles.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
var pJS = function(tag_id, params){

var canvas_el = document.querySelector('#'+tag_id+' > .particles-js-canvas-el');
var lastFrameTime = 0;
var pageHidden = false;

/* particles.js variables with default values */
this.pJS = {
this.pJS = {
// Default FPS limit implementation (see line 1314 for codified change).
fps_limit: 60,
canvas: {
el: canvas_el,
w: canvas_el.offsetWidth,
Expand Down Expand Up @@ -213,7 +217,7 @@ var pJS = function(tag_id, params){
if(!pJS.particles.move.enable){
pJS.fn.particlesEmpty();
pJS.fn.particlesCreate();
pJS.fn.particlesDraw();
pJS.fn.particlesDraw(0);
pJS.fn.vendors.densityAutoParticles();
}

Expand Down Expand Up @@ -503,7 +507,7 @@ var pJS = function(tag_id, params){
}
};

pJS.fn.particlesUpdate = function(){
pJS.fn.particlesUpdate = function(delta){

for(var i = 0; i < pJS.particles.array.length; i++){

Expand All @@ -520,9 +524,9 @@ var pJS = function(tag_id, params){

/* move the particle */
if(pJS.particles.move.enable){
var ms = pJS.particles.move.speed/2;
p.x += p.vx * ms;
p.y += p.vy * ms;
var ms = pJS.particles.move.speed/10;
p.x += p.vx * ms * delta;
p.y += p.vy * ms * delta;
}

/* change opacity status */
Expand Down Expand Up @@ -634,13 +638,13 @@ var pJS = function(tag_id, params){

};

pJS.fn.particlesDraw = function(){
pJS.fn.particlesDraw = function(delta){

/* clear canvas */
pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);

/* update each particles param */
pJS.fn.particlesUpdate();
pJS.fn.particlesUpdate(delta);

/* draw each particle */
for(var i = 0; i < pJS.particles.array.length; i++){
Expand Down Expand Up @@ -767,7 +771,7 @@ var pJS = function(tag_id, params){
)
if(i == nb-1){
if(!pJS.particles.move.enable){
pJS.fn.particlesDraw();
pJS.fn.particlesDraw(0);
}
pJS.tmp.pushing = false;
}
Expand All @@ -780,7 +784,7 @@ var pJS = function(tag_id, params){

pJS.particles.array.splice(0, nb);
if(!pJS.particles.move.enable){
pJS.fn.particlesDraw();
pJS.fn.particlesDraw(0);
}

};
Expand Down Expand Up @@ -1309,42 +1313,50 @@ var pJS = function(tag_id, params){
};


pJS.fn.vendors.draw = function(){
pJS.fn.vendors.draw = function (timestamp) {

if(pJS.particles.shape.type == 'image'){

if(pJS.tmp.img_type == 'svg'){

if(pJS.tmp.count_svg >= pJS.particles.number.value){
pJS.fn.particlesDraw();
if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
}else{
//console.log('still loading...');
if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
}

}else{
//if (pageHidden) {
// return;
//}

if(pJS.tmp.img_obj != undefined){
pJS.fn.particlesDraw();
if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
}else{
if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
}

}

}else{
pJS.fn.particlesDraw();
if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
// FPS limit logic
// If we are too fast, just draw without updating
var fps_limit = pJS.fps_limit;
if(timestamp < lastFrameTime + (1000 / fps_limit)) {
requestAnimFrame(pJS.fn.vendors.draw);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be wrong but I think requestAnimationFrame MUST be called on each loop but you can then check if the function is not suppose to run and just return.

So basically but the requestAnimFrame(...) before the if statement.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the code below it's called the function, it's handled by other if/else because the animation stops if the particles.move.enable flag is disabled (and it shouldn't IMO). Thisif is used because it's needed to check the delta between the previous frame to see if a new draw is needed, if it's not needed the values are not updated so the next rAF call could be the right one to update everything. For example, if you want 30FPS instead of 60, you need to skip one frame, because rAF is called the fastest possible depending on the monitor refresh rate (60 Hz - 60 fps).

The issue solved by this PR is that this library doesn't handle well different frequencies, on my MBP 2021 when I use Chrome I have 120FPS I see faster animations than Safari, limited to 60FPS. Every speed is doubled on Chrome, and this is a bad behavior.

return;
}

delta = timestamp - lastFrameTime;
lastFrameTime = timestamp;

if (pJS.particles.shape.type == 'image') {
if (pJS.tmp.img_type == 'svg') {
if (pJS.tmp.count_svg >= pJS.particles.number.value) {
pJS.fn.particlesDraw(delta);
if (!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
} else {
//console.log('still loading...');
if (!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
}
} else {
if (pJS.tmp.img_obj != undefined) {
pJS.fn.particlesDraw(delta);
if (!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
} else {
if (!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
}
}
} else {
pJS.fn.particlesDraw(delta);
if (!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
}
};



pJS.fn.vendors.checkBeforeDraw = function(){

// if shape is image
Expand All @@ -1364,7 +1376,7 @@ var pJS = function(tag_id, params){

}else{
pJS.fn.vendors.init();
pJS.fn.vendors.draw();
pJS.fn.vendors.draw(0);
}

};
Expand Down Expand Up @@ -1408,6 +1420,22 @@ var pJS = function(tag_id, params){
pJS.fn.vendors.start();


/* Cancel animation if page is not in focus
Browsers will do this anyway, however the
Delta time must also be reset, so canceling
the old frame and starting a new one is necessary */
function handleVisibilityChange() {
if (document.hidden) {
pageHidden = true;
cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
} else {
pageHidden = false;
lastFrameTime = performance.now();
pJS.fn.vendors.draw(0);
}
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);

};

Expand Down Expand Up @@ -1435,6 +1463,7 @@ window.requestAnimFrame = (function(){
function(callback){
window.setTimeout(callback, 1000 / 60);
};

})();

window.cancelRequestAnimFrame = ( function() {
Expand Down Expand Up @@ -1538,4 +1567,5 @@ window.particlesJS.load = function(tag_id, path_config_json, callback){
};
xhr.send();

};
};

Loading