Home > Back-end >  Random movement of circles created by the script
Random movement of circles created by the script

Time:03-12

I have a function that craeates divs with a circle.

Now they are all created and appear at the beginning of the page and go further in order.

Next, I need each circle to appear in a random place. I did this.

Now I need all of them to move randomly across the entire page, I have difficulties with this.

Here is an example of how everything works for one element that is already on the page.

https://jsfiddle.net/quej8wko/

But when I add this code, all my created circles don't move.

I get an error:

"message": "Uncaught TypeError: Cannot set properties of null (setting 'willChange')",

This is probably due to the fact that initially there are no circles on the page. How can I connect the code so that all created circles move?

//creating circles

var widthHeight = 40; // <-- circle width
var margin = 20; // <-- margin - is it necessary ?
var delta = widthHeight   margin;

function createDiv(id, color) {
  let div = document.createElement('div');
  var currentTop = 0;
  var documentHeight = document.documentElement.clientHeight;
  var documentWidth = document.documentElement.clientWidth;
  div.setAttribute('class', id);
  if (color === undefined) {
    let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
    div.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
  }
  else {
   div.style.backgroundColor = color; 
  }
  div.classList.add("circle");
  div.classList.add("animation");
  
  // Get the random positions minus the delta
  currentTop = Math.floor(Math.random() * documentHeight) - delta;
  currentLeft = Math.floor(Math.random() * documentWidth) - delta;
  
  // Keep the positions between -20px and the current positions
  var limitedTop = Math.max(margin * -1, currentTop);
  var limitedLeft = Math.max(margin * -1, currentLeft);

  div.style.top = limitedTop   "px";
  div.style.left = limitedLeft   "px";
  document.body.appendChild(div);
}
    
let i = 0;

const oneSecond = 1000;

setInterval(() => {
  i  = 1;
  createDiv(`circle${i}`)
}, oneSecond);

//move circles

function RandomObjectMover(obj, container) {
    this.$object = obj;
  this.$container = container;
  this.container_is_window = container === window;
  this.pixels_per_second = 250;
  this.current_position = { x: 0, y: 0 };
  this.is_running = false;
}

// Set the speed of movement in Pixels per Second.
RandomObjectMover.prototype.setSpeed = function(pxPerSec) {
    this.pixels_per_second = pxPerSec;
}

RandomObjectMover.prototype._getContainerDimensions = function() {
   if (this.$container === window) {
       return { 'height' : this.$container.innerHeight, 'width' : this.$container.innerWidth };
   } else {
       return { 'height' : this.$container.clientHeight, 'width' : this.$container.clientWidth };
   }
}

RandomObjectMover.prototype._generateNewPosition = function() {

    // Get container dimensions minus div size
  var containerSize = this._getContainerDimensions();
    var availableHeight = containerSize.height - this.$object.clientHeight;
  var availableWidth = containerSize.width - this.$object.clientHeight;
    
  // Pick a random place in the space
  var y = Math.floor(Math.random() * availableHeight);
  var x = Math.floor(Math.random() * availableWidth);
    
  return { x: x, y: y };    
}

RandomObjectMover.prototype._calcDelta = function(a, b) {
    var dx   = a.x - b.x;         
  var dy   = a.y - b.y;         
  var dist = Math.sqrt( dx*dx   dy*dy ); 
  return dist;
}

RandomObjectMover.prototype._moveOnce = function() {
        // Pick a new spot on the page
    var next = this._generateNewPosition();
    
    // How far do we have to move?
    var delta = this._calcDelta(this.current_position, next);
    
        // Speed of this transition, rounded to 2DP
        var speed = Math.round((delta / this.pixels_per_second) * 100) / 100;
    
    //console.log(this.current_position, next, delta, speed);
          
    this.$object.style.transition='transform ' speed 's linear';
    this.$object.style.transform='translate3d(' next.x 'px, ' next.y 'px, 0)';
    
    // Save this new position ready for the next call.
    this.current_position = next;
  
};

RandomObjectMover.prototype.start = function() {

    if (this.is_running) {
    return;
  }

    // Make sure our object has the right css set
  this.$object.willChange = 'transform';
  this.$object.pointerEvents = 'auto';
    
  this.boundEvent = this._moveOnce.bind(this)
  
  // Bind callback to keep things moving
  this.$object.addEventListener('transitionend', this.boundEvent);
  
  // Start it moving
  this._moveOnce();
  
  this.is_running = true;
}

RandomObjectMover.prototype.stop = function() {

    if (!this.is_running) {
    return;
  }
  
  this.$object.removeEventListener('transitionend', this.boundEvent);
  
    this.is_running = false;
}


// Init it
var x = new RandomObjectMover(document.querySelector(".circle"), window);

// Start it off

x.start();
.circle {
  clip-path: circle(50%);
  height: 40px;
  width: 40px;
  margin: 20px;
  position: absolute;
}

CodePudding user response:

I have modified the snippet which works as you expected.

There was a mistake where you were initializing and creating the object instance only once and none of the div elements that you created inside the setInterval function never got Instantiated.

I think you are just starting out with JavaScript with this sample project.

Below are few suggestions:

  • Learn to debug the code. You should be using dev tools by making use of debugger statement where it takes you to the source code to analyze the variable scope and stack during the runtime. console.log also helps in few situations.
  • I could see a lot of confusing naming convention (You have named the create div parameter as id but creating a div class using that id)
  • Try using ES6 features (class syntax is really good when writing OOP in JS although it's just a syntactic sugar for prototype)

//creating circles

var widthHeight = 40; // <-- circle width
var margin = 20; // <-- margin - is it necessary ?
var delta = widthHeight   margin;

function createAndInitializeDivObject(id, color) {
  let div = document.createElement('div');
  var currentTop = 0;
  var documentHeight = document.documentElement.clientHeight;
  var documentWidth = document.documentElement.clientWidth;
  div.setAttribute('class', id);
  if (color === undefined) {
    let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
    div.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
  }
  else {
   div.style.backgroundColor = color; 
  }
  div.classList.add("circle");
  div.classList.add("animation");
  
  // Get the random positions minus the delta
  currentTop = Math.floor(Math.random() * documentHeight) - delta;
  currentLeft = Math.floor(Math.random() * documentWidth) - delta;
  
  // Keep the positions between -20px and the current positions
  var limitedTop = Math.max(margin * -1, currentTop);
  var limitedLeft = Math.max(margin * -1, currentLeft);

  div.style.top = limitedTop   "px";
  div.style.left = limitedLeft   "px";
  document.body.appendChild(div);

  var x = new RandomObjectMover(document.querySelector(`.${id}`), window);
  x.start();
}
    
let i = 0;

const oneSecond = 1000;



setInterval(() => {
  i  = 1;
  createAndInitializeDivObject(`circle${i}`)
}, oneSecond);

//move circles

function RandomObjectMover(obj, container) {

    this.$object = obj;
  this.$container = container;
  this.container_is_window = container === window;
  this.pixels_per_second = 250;
  this.current_position = { x: 0, y: 0 };
  this.is_running = false;
}

// Set the speed of movement in Pixels per Second.
RandomObjectMover.prototype.setSpeed = function(pxPerSec) {
    this.pixels_per_second = pxPerSec;
}

RandomObjectMover.prototype._getContainerDimensions = function() {
   if (this.$container === window) {
       return { 'height' : this.$container.innerHeight, 'width' : this.$container.innerWidth };
   } else {
       return { 'height' : this.$container.clientHeight, 'width' : this.$container.clientWidth };
   }
}

RandomObjectMover.prototype._generateNewPosition = function() {

    // Get container dimensions minus div size
  var containerSize = this._getContainerDimensions();
    var availableHeight = containerSize.height - this.$object.clientHeight;
  var availableWidth = containerSize.width - this.$object.clientHeight;
    
  // Pick a random place in the space
  var y = Math.floor(Math.random() * availableHeight);
  var x = Math.floor(Math.random() * availableWidth);
    
  return { x: x, y: y };    
}

RandomObjectMover.prototype._calcDelta = function(a, b) {
    var dx   = a.x - b.x;         
  var dy   = a.y - b.y;         
  var dist = Math.sqrt( dx*dx   dy*dy ); 
  return dist;
}

RandomObjectMover.prototype._moveOnce = function() {
        // Pick a new spot on the page
    var next = this._generateNewPosition();
    
    // How far do we have to move?
    var delta = this._calcDelta(this.current_position, next);
    
        // Speed of this transition, rounded to 2DP
        var speed = Math.round((delta / this.pixels_per_second) * 100) / 100;
    
    //console.log(this.current_position, next, delta, speed);
          
    this.$object.style.transition='transform ' speed 's linear';
    this.$object.style.transform='translate3d(' next.x 'px, ' next.y 'px, 0)';
    
    // Save this new position ready for the next call.
    this.current_position = next;
  
};

RandomObjectMover.prototype.start = function() {

    if (this.is_running) {
    return;
  }

    // Make sure our object has the right css set
  this.$object.willChange = 'transform';
  this.$object.pointerEvents = 'auto';
    
  this.boundEvent = this._moveOnce.bind(this)
  
  // Bind callback to keep things moving
  this.$object.addEventListener('transitionend', this.boundEvent);
  
  // Start it moving
  this._moveOnce();
  
  this.is_running = true;
}

RandomObjectMover.prototype.stop = function() {

    if (!this.is_running) {
    return;
  }
  
  this.$object.removeEventListener('transitionend', this.boundEvent);
  
    this.is_running = false;
}


// Init it
var x = new RandomObjectMover(document.querySelector(".circle"), window);

// Start it off

x.start();
.circle {
    width: 35px;
    height: 35px;
    border-radius: 35px;
    background-color: #ffffff;
    border: 3px solid purple;
    position: absolute;
  }
<!DOCTYPE html>
<html>
    <head>

        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div ></div>
        <script src="app.js"></script>
    </body>
</html>

  • Related