Creating a dynamic animation of multiple dots moving around on an HTML canvas

I am faced with the task of relocating numerous dots within a canvas, requiring me to create multiple arcs with varying radii positioned randomly.

var context = document.getElementById('stage').getContext('2d');
var radian = Math.PI / 180;
var x = 40;
var y = 40;
var r = 20;
var colorPoints = [];
var frames = 50;
var currentFrame = 0;
var toggle = false;
var iconsLoaded = false;
context.beginPath();
context.arc(x,y, r, 0 * radian, 360 * radian, false)
context.fill();


var drawMultipleCurves = function(ctx){
if(!iconsLoaded){
for (let i = 0; i < 600; i++) {
    ctx.beginPath();
  ctx.filter = 'blur(5px)';
  ctx.fillStyle = '#B835FF';
  colorPoints.push({x: Math.floor((Math.random() * 700) + 0), xMove: Math.floor((Math.random() * 2) + 0) , yMove: Math.floor((Math.random() * 2) + 0) , y: Math.floor((Math.random() * 700) + 0), radius: Math.floor((Math.random() * 20) + 5)});
   ctx.arc(colorPoints[colorPoints.length - 1].x, colorPoints[colorPoints.length - 1].y, colorPoints[colorPoints.length - 1].radius, 0 * radian, 360 * radian, false);
   ctx.fill();
   ctx.closePath();
   iconsLoaded = true;
}
}
else{
for(let i =0;i< colorPoints.length; i++){
if(frames === currentFrame ){
    toggle = !toggle;
    currentFrame = 0;
    }
     if(!toggle){
  colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x + 5 : colorPoints[i].x = colorPoints[i].x - 5;
                        colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y + 5 : colorPoints[i].y = colorPoints[i].y - 5;
    }
    else{
   colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x - 5 : colorPoints[i].x = colorPoints[i].x + 5;
                        colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y - 5 : colorPoints[i].y = colorPoints[i].y + 5;
    }
    ctx.beginPath();
    ctx.arc(colorPoints[i].x, colorPoints[i].y, colorPoints[i].radius, 0 * radian, 360 * radian, false);
                context.closePath( );
                ctx.fill();
    currentFrame = currentFrame + 1;
}
}
}

var animate = function(){
  setTimeout(()=>{
    context.clearRect(0,0,400,400);
    context.beginPath();
    drawMultipleCurves(context);
    context.fill();
  requestAnimationFrame(animate)
  }, 1000/30)
}



 requestAnimationFrame(animate) 
<canvas id="stage" width="400" height="400">
    <p>Your browser doesn't support canvas.</p>
</canvas>

The provided code showcases my approach where I initially placed several random dots with diverse sizes. These positions were saved in an array called 'colorPoints'.

Subsequently, by looping through this array and adjusting the dot locations upon each 'requestAnimation,' I achieved a random movement effect. However, due to the high quantity of dots and the repetitive positioning process, the animation appears somewhat choppy.

If there are any recommendations on how I can enhance the smoothness of this animation, they would be greatly appreciated!

Thank you for your assistance :)

Answer №1

Optimize Rendering Process for Better Performance

Your code is experiencing slowdowns due to inefficient use of the fill operation, especially when combined with filters like stroke.

To improve performance, optimize your code by calling fill only once per frame for each object sharing the same style.

Consider revising your code as shown below:

   ctx.beginPath();
   for (const c of circles) { 
      ctx.moveTo(c.x + c.r, c.y);
      ctx.arc(c.x, c.y, c.r, 0, TAU) 
   }
   ctx.fill();

By adding all arcs first and then filling them in one go, you avoid unnecessary resets caused by the fill command during filter application.

Furthermore, utilizing moveTo to close the previous arc is more efficient compared to using closePath(), especially when dealing with a large number of arcs.

Enhance Performance with Efficient Coding

For optimal performance, group objects that share the same color to minimize the number of fill calls necessary.

While it may require additional setup code, segregating objects based on colors can significantly reduce the rendering overhead.

Answer №2

Using the blur filter on the CanvasRenderingContext2D can be resource-intensive, especially when applied to a canvas with 600 circles. This requires redrawing all 600 circles and then applying the blur filter on each screen update.

An alternative approach involves creating a master texture initially with a blurred circle. This textured circle can then be reused and drawn onto the canvas using the drawImage() method. To adjust the size of the circles, instead of using a radius, we utilize a scale property.

For instance:

var context = document.getElementById('stage').getContext('2d');
var radian = Math.PI / 180;
var x = 40;
var y = 40;
var r = 20;
var colorPoints = [];
var frames = 50;
var currentFrame = 0;
var toggle = false;
var iconsLoaded = false;
var texture = document.createElement("canvas");
var textureContext = texture.getContext("2d");
texture.width = 80;
texture.height = 80;
textureContext.filter = 'blur(5px)';
textureContext.fillStyle = '#B835FF';
textureContext.arc(texture.width / 2, texture.height / 2, 25, 0 * radian, 360 * radian, false);
textureContext.fill();
textureContext.closePath();

var drawMultipleCurves = function(ctx) {
    if (!iconsLoaded) {
        for (let i = 0; i < 600; i++) {
            colorPoints.push({
                x: Math.floor((Math.random() * 700) + 0),
                xMove: Math.floor((Math.random() * 2) + 0),
                yMove: Math.floor((Math.random() * 2) + 0),
                y: Math.floor((Math.random() * 700) + 0),
                scale: 0.2 + Math.random() * 0.8
            });

            iconsLoaded = true;
        }
    } else {
        for (let i = 0; i < colorPoints.length; i++) {
            if (frames === currentFrame) {
                toggle = !toggle;
                currentFrame = 0;
            }
            if (!toggle) {
                colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x + 5 : colorPoints[i].x = colorPoints[i].x - 5;
                colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y + 5 : colorPoints[i].y = colorPoints[i].y - 5;
            } else {
                colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x - 5 : colorPoints[i].x = colorPoints[i].x + 5;
                colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y - 5 : colorPoints[i].y = colorPoints[i].y + 5;
            }
            ctx.drawImage(texture, colorPoints[i].x, colorPoints[i].y, texture.width * colorPoints[i].scale, texture.height * colorPoints[i].scale);

            currentFrame = currentFrame + 1;
        }
    }
}

var animate = function() {
    setTimeout(() => {
        context.clearRect(0, 0, 400, 400);
        context.beginPath();
        drawMultipleCurves(context);
        context.fill();
        requestAnimationFrame(animate)
    })
}

requestAnimationFrame(animate)
<canvas id="stage" width="400" height="400">
<p>Your browser doesn't support canvas.</p>
</canvas>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for tackling drag and drop functionality with only HTML, CSS, and JavaScript

Currently, I am faced with a challenge involving drag and drop TEST. Observing the image provided below, you will notice 3 columns each containing 3 small boxes of varying colors. These boxes are draggable, meaning they can be moved between columns follow ...

How can I trigger a function by clicking on a link that was generated dynamically with jQuery?

I am dynamically creating multiple <a href="#"></a> elements with dynamically assigned id attributes like <a href="#" id='delete"+id+"'></a>. The IDs generated will be like delete01, delete02, .... I want to trigger a func ...

Image of sprite is not displayed

Having trouble displaying a sprite. Here is the HTML file : <head> <script src="https://github.com/photonstorm/phaser-ce/releases/download/v2.7.5/phaser.min.js"></script> </head> <body> <div id="game"></div& ...

Not successfully aligning all buttons except for the initial one

HTML code snippet <div class="breadcrumbs row"> <button><a href="#">One</a></button> <button><a href="#">Two</a></button> <h1><button><a href="#">Three</a></button>& ...

Establish the focus when the TinyMCE editor loads

After clicking the edit button, the tinymce text editor is displayed but there's an issue where the focus is not set on the first load of the editor. However, it works fine from the second load onwards. Here's what I have attempted: HTML <h ...

What is the reason for ng-submit not being prevented by a mandatory select field?

In an HTML5 form, when a select element is required and no option is selected, the appropriate styling for invalidation is applied. However, the ng-submit still allows the form to be submitted. Why does this occur and is there a way to prevent submission ...

``Is there a way to dynamically display an image along with its corresponding title and content

After dynamically inserting a title and content, I found myself struggling to include an image between them. Is there a way to accomplish this? This issue arises in my controller. const postSchema = { title: String, content: String, }; const Post ...

ng namespace not found

I am currently in the process of converting a simple Angular 1.6 project to TypeScript. I have declared all the necessary typings dependencies and they have been compiled and installed successfully. However, I am encountering a compilation error stating "C ...

The term 'TextInput' is not recognized in React Native and cannot be found

I'm currently working on setting up a login screen for a social media app that I am developing. The issue I am facing is that I have a LoginScreen.js and RegisterScreen.js with forms for email and password, but when I try to render them, I encounter a ...

What causes the default date to be displayed on the datePicker in MVC when using Persian dates?

Trying to pass the value of a datePicker input to the action via model always results in receiving the following value: Date = {1/1/0001 12:00:00 AM} Ajax is used to serialize and send the values of inputs to the action. Upon inspection in the console, i ...

The art of positioning Bootstrap popovers

Does anyone know a way to position a bootstrap popover on the "Right Bottom" of a clicked button instead of the "Right Middle"? The positioning should be dynamic. https://i.sstatic.net/OSQln.png To see the standard code, click here: http://jsfiddle.net/V ...

A hyperlink will not float above

I can't seem to get the links in my navbar to change color when I hover over them, even though I've used the :hover selector. Can someone please assist me with this? <header> <nav class="navbar navbar-expand-lg navbar-dark sta ...

How should white space be managed in Bootstrap 4 cards when incorporating responsive column classes - wrap elements inside divs or apply classes directly?

In Bootstrap 4, when applying a responsive column class like "col-sm-8" directly to a "div" with the class "card", whitespace is added between the card border and content. This can be seen in the highlighted yellow area in the image below. https://i.sstat ...

What criteria do browsers follow to determine the specific colors to use for border styles like inset and outset?

When I set border: 1px outset blue; as the style for an element, the browser displays two distinct border colors: one for the top and left borders, and another for the bottom and right borders. li { border: 10px outset #0000FF; color: #FFF; ...

Using Bootstrap to center elements only on specific ones

I am currently working on creating a "navbar/toolbar" with one item positioned on the left side (h3) and three items aligned on the right side (a, a, and select). However, I am facing an issue where only the first item (h3) is vertically centered. Can some ...

Determine if a JavaScript code in my ASP view will be executed based on control from the controller

Working on an ASP.NET MVC4 system, I have a javascript code that displays a performance graph of students when the page loads. Here is the code for the graph: <script> window.onload = function () { var r = Raphael("holder"), ...

Showing the ng-controller contents post executing AJAX request using the "as" method

My goal is to display the contents of ng-repeat after making an AJAX call using $http. <table ng-controller="TableController as tc"> <tr> <th>Date</th> <!-- other headers are here --> ...

Splitting Angular modules into separate projects with identical configurations

My Angular project currently consists of approximately 20 different modules. Whenever there is a code change in one module, the entire project needs to be deployed. I am considering breaking down my modules into separate projects for individual deployment. ...

Establish the dimensions of the element to match the dimensions of a responsive image

Currently, I am working on implementing flippable images on my website. It is important to me that the "back" of these images matches the dimensions of the front image. The challenge I am facing is that I have applied the Bootstrap img-responsive class to ...

What is the best way to create a gap between two Bootstrap buttons?

I'm attempting to create two buttons in the same line in this code, but it's not working as I want. Take a look below: <div class="w3-show-inline-block"> <div class="w3-bar"> <button class="btn btn-s ...