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

StackOverflow https://stackoverflow.com/questions/23449283

Pergunta

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

Foi útil?

Solução

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>

Outras dicas

So I've used Adams code as a base. So HTML and CSS stay the same:

HTML

<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>

CSS:

.posts { float:left; background:#000; color:#fff; padding:0.2em; text-align:center; }
.container { width:50em; max-width:100%; }

JavaScript

Will change however. Update any of the properties in the options variable to change layout.

var options = {
    width: {
        min: 10,
        max: 60,
        unit: '%'
    },
    height: {
        min: 10,
        max: 30,
        unit: '%'
    },
    margin: {
        min: 5,
        max: 10,
        unit: 'px'
    }

}


function getRandomInt (min, max, unit) {
    return Math.floor(Math.random() * (max - min + 1)) + min + unit;
}
function randomize() {
  var posts = document.getElementsByClassName("posts");
  for (var p = 0; p < posts.length; p++) {
    posts[p].style.margin =  getRandomInt(options.margin.min,options.margin.max, options.margin.unit) + " " + getRandomInt(options.margin.min,options.margin.max, options.margin.unit);
    posts[p].style.width = getRandomInt(options.width.min,options.width.max, options.width.unit);
    posts[p].style.height = getRandomInt(options.height.min,options.height.max, options.height.unit);
  }
}

I've created a fiddle: http://jsfiddle.net/qsUw7/

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top