Search code examples
javascriptrandompositionsizelogic

Assign multiple elements random size and random placement, while following the sequential div order


Trying to figure out somekind of logic that will let me distribute elements in a sequenced order. What size and position should be randomly generated within a given range (for example, element must be within viewport and the size of the element should be within a defined range such as minimum 10% of viewport, maximum 60%).

I'm not sure what would be the best way to approach something like this, any ideas?
I've attached a sketch below of what it could look like. The layout would be different at each load.

Markup

<div class="container">
   <div class="post">Post 1</div>
   <div class="post">Post 2</div>
   <div class="post">Post 3</div>
   <div class="post">Post 4</div>
   <div class="post">Post 5</div>
   <div class="post">Post 6</div>
   <div class="post">Post 7</div>
   <div class="post">Post 8</div>
   <div class="post">Post 9</div>
   <div class="post">Post 10</div>
   <div class="post">Post 11</div>
   <div class="post">Post 12</div>
   <div class="post">Post 13</div>
   <div class="post">Post 14</div>
   <div class="post">Post 15</div>
</div>

enter image description here


Solution

  • Thanks, this was fun to code. I set some defaults in CSS and then did the logic in JS. Note that the buffer() function is nonlinear; we want most of the buffers to be close to zero and very few of them to be on the larger side, so we use powers of e (2.7⁰/12 = 0.08em to 2.7⁶/12 = 33.62em) for the scale and then multiply them out to get a bigger range of numbers (rather than powers of two divided by 12).

    I assume the elements are already chronologically ordered. If not, that shouldn't be hard to do, just sort posts[] and insert them in order using appendChild() on the container.

    var defaultMax = Math.exp(6) / 12;  // e⁶ / 12 = 33.5em
    
    // random buffer to give for spacing.
    // growth is inverse exponential, so larger is less likely
    function buffer(min=0.1, max=defaultMax, mult=1) {
      return Math.min(max, Math.max(min,
        min / 2 + Math.exp(Math.random() * 6) * Math.random() * mult / 12
      ))+"em";
    }
    function randomize() {
      var posts = document.getElementsByClassName("posts");
      for (var p = 0; p < posts.length; p++) {
        // random buffered margins, ordered: top right bottom left.
        // top is at least 0.1em, right and bottom are at least 0.25em.
        // top and bottom are cut in half to limit lost vertical space.
        posts[p].style.margin = buffer(0.1,  defaultMax, 0.5) + " "
                              + buffer(0.25) + " "
                              + buffer(0.25, defaultMax, 0.5) + " "
                              + buffer();
        // random width and height (with sane minimum size: 8em x 5em)
        posts[p].style.width = buffer(8);
        posts[p].style.height = buffer(5);
      }
    }
    .posts     { float:left; background:#000; color:#fff;
                 padding:0.2em; text-align:center; }
    .container { width:50em; max-width:100%; }
    <body onload="randomize()">
      <div class="container">
        <div class="posts">Post 1</div>
        <div class="posts">Post 2</div>
        <div class="posts">Post 3</div>
        <div class="posts">Post 4</div>
        <div class="posts">Post 5</div>
        <div class="posts">Post 6</div>
        <div class="posts">Post 7</div>
        <div class="posts">Post 8</div>
        <div class="posts">Post 9</div>
        <div class="posts">Post 10</div>
        <div class="posts">Post 11</div>
        <div class="posts">Post 12</div>
        <div class="posts">Post 13</div>
        <div class="posts">Post 14</div>
        <div class="posts">Post 15</div>
      </div>
    </body>