Search code examples
javascripthtmlcsswebdesign-patterns

How to auto generate divs with javascript?


I made a basic javascript code so you can poke divs with you mouse.

Unfortunately I have to add them manualy but i wanna add so much of them with a pattern. First i decided to use grid but i guessed it wont work because divs (which i call them squares from now on :D) can change their position.

So I was about to ask, how can I create a javascript code that i can spawn them until they fill the screen.

Also i have another question which is realted to this project, How can i make these squares just decors. I mean by decors i dont want them to effect the webside at all, when the blocks goes out of the screen the body starts to expend, is there any way to avoid that?

(Also it will be better if you make the snippet full screen!)

EDIT: I put the refresh-button on the top left on the main div so you can draw squares by clicking it!

let mouse = {
    speedX: 0,
    speedY: 0,
    posX: 0,
    posY: 0,
    movement: 0,
    speed: 0
  }
  
  //on mousemove update the moouse object
  document.onmousemove = function(e) {
    mouse.speedX = e.movementX;
    mouse.speedY = e.movementY
    mouse.posX = e.pageX;
    mouse.posY = e.pageY;
  }
  
  //refresh the mouse movement and speed every 100ms
  setInterval(() => {
    mouse.movement =
      Math.sqrt(Math.pow(mouse.speedX, 2) + Math.pow(mouse.speedY, 2));
    mouse.speed = mouse.movement * 10;
  }, 100);
  
  //add a square div in parent element
  function addSquare(parent) {
    const newDiv = document.createElement("div");
    newDiv.classList.add("square")
    parent.appendChild(newDiv)
    return newDiv;
  }
  
  //add squares in the parent element filling the available size
  //gap is the space between squares, size is the edge of the square
  //if skipbefore is false it will begin to draw the next square also if it won't fit entirely
  function addSquares(parent, gap, size, skipbefore = true) {
  
    const squares = [];
  
    let rect = parent.getBoundingClientRect();
    const availableWidth = rect.width;
    const availableHeight = rect.height;
  
    let top = 100;
    while (top < availableHeight) {
      let left = 0;
      if (skipbefore && top + size > availableHeight)
        break;
      while (left < availableWidth) {
        if (skipbefore && left + size > availableWidth)
          break;
        const square = addSquare(parent);
        square.style.left = `${left}px`;
        square.style.top = `${top}px`;
        squares.push(square);
        left += gap + size;
      }
      top += gap + size;
    }
  
    return squares;
  }
  
  //onmoveover event handler
  const squareOnMouseOver = (event) => {
    const element = event.target;
  
    const y = mouse.speedY;
    const x = mouse.speedX;
  
    const rad = Math.atan2(y, x);
    yAxis = mouse.movement * Math.sin(rad);
    xAxis = mouse.movement * Math.cos(rad);
  
    const rect = element.getBoundingClientRect();
  
    const left = Math.round(rect.x + xAxis * 3);
    const top = Math.round(rect.y + yAxis * 3);
  
    element.style.left = `${left}px`;
    element.style.top = `${top}px`;
    const o = rad * (180 / Math.PI);
    element.style.transform = `rotate(${o}deg)`;
  }
  
  //resets the .target parent and redraw the squares inside it
  function drawSquares() {
  
    const parent = document.querySelector('.target');
    parent.innerHTML = '';
    const squares = addSquares(parent, 25, 75);
  
    const colors = [
      'lightcoral',
      'bisque',
      'aquamarine',
      'cadetblue',
      'greenyellow',
      'yellowgreen'
    ];
  
    squares.forEach(square => {
      const iColor = Math.floor(Math.random() * (colors.length - 1));
      const color = colors[iColor];
      square.style.background = color;
      square.addEventListener('mouseover', squareOnMouseOver);
    });
  }
body{
    margin: 0;
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgb(242, 239, 231);
    color: rgb(10, 10, 9);

}

.square{
    background-color: lightcoral;
    width: 75px;
    height: 75px;
    position: absolute;
    transform: rotate(0deg);

    transition: all ease-out 0.5s;
    
}

.background {
    display: flex;
    align-items: center;
    justify-content: center;

    width: 100%;
    height: 100%;
}

.container .row .col > * {
    display: inline-block;
}
  
.target {
    display: block;
    width: 100%;
    height: 100%;
}

#draw {
    font-size: 20px;
    padding: .2em 1em;
    cursor: pointer;
}

.name{
    font-size: 40px;
}

#main-container{
    position: absolute;
    padding: 35px 45px;

    width: 950px;
    height: 285px;

    box-shadow: 0px 2px 5px 2px rgb(191, 188, 182);

}

.links{
    display: flex;

    justify-content: center;
    align-items: center;
}

.icons{
    width: 55px;
    height: auto;

    margin: 0px 25px;
    padding: 10px;


    border-radius: 5px;
    transition: all ease-in 0.2s;
}

.icons:hover{
    background-color: rgb(144, 144, 144);
}

.refresh{
    position: absolute;
}

.refresh-button{
    width: 25px;
    height: auto;
}

.btn:hover{
    background-color: rgb(144, 144, 144);

}
<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">

    <link rel="stylesheet" href="css.css">

    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
<div class="background">
    <div class="target"></div>
    <div class="container text-center" id="main-container">
        <div class="">
            <div class="refresh">
                <button class="btn" id="draw" onclick="drawSquares()"><img class="refresh-button" src="SVG/arrow-clockwise.svg"></button>
            </div>

            <div class="name">Berk Efe Keskin</div>
            <br>
            <i>This website is working in progress right now...</i>
            <br>
            <i>Here is some useful links.</i>
            <br>
            <br>
            
            <div class="links">
                <a href="#"><img class="icons" src="SVG/github.svg"></a>
                <a href="#"><img class="icons" src="SVG/linkedin.svg"></a>
                <a href="#"><img class="icons" src="SVG/stack-overflow.svg"></a>
            </div>
            
        </div>
    </div>
    

</div>

    <script type="text/javascript" src = "javascript.js"></script> 

</body>
</html>


Solution

  • You may have a function that given a container will be filled with how many squares can fit inside as long as there is still avaiable width and available height in the target.

    Here in this demo I better factored your code and added a main function called drawSquares that gets called when the button reDRAW is clicked. Each time the squares are redrawn, the target content is emptied.

    I'm using a button to trigger the box drawing because the available space depends on the size of the area when the action is fired. For example you can expand the snippet and decide to redraw the squares to have the whole new area filled again.

    You may decide to call the action on document ready or when the window gets resized.

    let mouse = {
      speedX: 0,
      speedY: 0,
      posX: 0,
      posY: 0,
      movement: 0,
      speed: 0
    }
    
    //on mousemove update the moouse object
    document.onmousemove = function(e) {
      mouse.speedX = e.movementX;
      mouse.speedY = e.movementY
      mouse.posX = e.pageX;
      mouse.posY = e.pageY;
    }
    
    //refresh the mouse movement and speed every 100ms
    setInterval(() => {
      mouse.movement =
        Math.sqrt(Math.pow(mouse.speedX, 2) + Math.pow(mouse.speedY, 2));
      mouse.speed = mouse.movement * 10;
    }, 100);
    
    //add a square div in parent element
    function addSquare(parent) {
      const newDiv = document.createElement("div");
      newDiv.classList.add("square")
      parent.appendChild(newDiv)
      return newDiv;
    }
    
    //add squares in the parent element filling the available size
    //gap is the space between squares, size is the edge of the square
    //if skipbefore is false it will begin to draw the next square also if it won't fit entirely
    function addSquares(parent, gap, size, skipbefore = true) {
    
      const squares = [];
    
      let rect = parent.getBoundingClientRect();
      const availableWidth = rect.width;
      const availableHeight = rect.height;
    
      let top = 100;
      while (top < availableHeight) {
        let left = 0;
        if (skipbefore && top + size > availableHeight)
          break;
        while (left < availableWidth) {
          if (skipbefore && left + size > availableWidth)
            break;
          const square = addSquare(parent);
          square.style.left = `${left}px`;
          square.style.top = `${top}px`;
          squares.push(square);
          left += gap + size;
        }
        top += gap + size;
      }
    
      return squares;
    }
    
    //onmoveover event handler
    const squareOnMouseOver = (event) => {
      const element = event.target;
    
      const y = mouse.speedY;
      const x = mouse.speedX;
    
      const rad = Math.atan2(y, x);
      yAxis = mouse.movement * Math.sin(rad);
      xAxis = mouse.movement * Math.cos(rad);
    
      const rect = element.getBoundingClientRect();
    
      const left = Math.round(rect.x + xAxis * 3);
      const top = Math.round(rect.y + yAxis * 3);
    
      element.style.left = `${left}px`;
      element.style.top = `${top}px`;
      const o = rad * (180 / Math.PI);
      element.style.transform = `rotate(${o}deg)`;
    }
    
    //resets the .target parent and redraw the squares inside it
    function drawSquares() {
    
      const parent = document.querySelector('.target');
      parent.innerHTML = '';
      const squares = addSquares(parent, 25, 75);
    
      const colors = [
        'lightcoral',
        'bisque',
        'aquamarine',
        'cadetblue',
        'greenyellow',
        'yellowgreen'
      ];
    
      squares.forEach(square => {
        const iColor = Math.floor(Math.random() * (colors.length - 1));
        const color = colors[iColor];
        square.style.background = color;
        square.addEventListener('mouseover', squareOnMouseOver);
      });
    }
    body {
      margin: 0;
      width: 100vw;
      height: 100vh;
      display: flex;
    }
    
    .square {
      background-color: lightcoral;
      width: 75px;
      height: 75px;
      position: absolute;
      transform: rotate(0deg);
      transition: all ease-out 0.5s;
    }
    
    #Header {
      font-size: italic;
    }
    
    .background {
      width: 100%;
      height: 100%;
    }
    
    .target {
      position: relative;
      display: block;
      width: 100%;
      height: 100%;
      z-index: -1;
    }
    
    #draw {
      font-size: 20px;
      padding: .2em 1em;
      cursor: pointer;
    }
    
    .container .row .col > * {
      display: inline-block;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <link el="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
    
    <body>
      <div class="background">
    
        <span>Work in progress...</span>
    
        <div class="container text-center">
          <div class="row">
            <div class="col">
              <h1 id="Header">Work in progress...</h1>
              <button id="draw" onclick="drawSquares()">reDRAW</button>
            </div>
          </div>
        </div>
    
        <div class="target"></div>
      </div>
    </body>