Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Masonry sort order left to right rather than top to bottom?

Using Masonry on a catalog site. By default, the items displayed sort by date, then by part number. My images are varying height. The problem is, and correct me if I'm wrong, Masonry sets row 2, item 1 below the shortest item in row 1 rather than on the left of the page. So in other words, when my database returns a certain order, Masonry places those items ordered top to bottom (when varying heights), rather than left to right.

I don't find anything in documentation to control this. Is there a way to force Masonry to keep items in order left to right and just float vertically based on height?

I attempted to post an illustration, but apparently I'm not qualified to do so. Here's a link to the illustration:

enter image description here

like image 755
Justin Graber Avatar asked Jul 08 '13 20:07

Justin Graber


2 Answers

inspired by Billy's answer (and therefor by skobaljic's answer :) ) I just changed the initialisation of shortColIndex and minimumY to achieve this behaviour. Might be a little easier plus - using the colGroup's size - responsive layouts with different column counts still work.

Here is the complete code for v3.3.2:

Masonry.prototype._getItemLayoutPosition = function( item ) {
  item.getSize();
  // how many columns does this brick span
  var remainder = item.size.outerWidth % this.columnWidth;
  var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
  // round if off by 1 pixel, otherwise use ceil
  var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
  colSpan = Math.min( colSpan, this.cols );

  var colGroup = this._getColGroup( colSpan );
  // ### HACK: sort by natural order, not by min col height
  // get the minimum Y value from the columns
  // var minimumY = Math.min.apply( Math, colGroup );
  // var shortColIndex = utils.indexOf( colGroup, minimumY );
  var shortColIndex = jQuery(item.element).index() % colGroup.length;
  var minimumY = colGroup[shortColIndex];

  // position the brick
  var position = {
    x: this.columnWidth * shortColIndex,
    y: minimumY
  };

  // apply setHeight to necessary columns
  var setHeight = minimumY + item.size.outerHeight;
  var setSpan = this.cols + 1 - colGroup.length;
  for ( var i = 0; i < setSpan; i++ ) {
    this.colYs[ shortColIndex + i ] = setHeight;
  }

  return position;
};
like image 181
Christoph Avatar answered Oct 05 '22 12:10

Christoph


There is no option in Masonry to sort items, because it is a simple plugin that places bricks one by one. Choosing new brick position is simple: place it higher as you can.

But what one can do in this case is to change the script by adding one two lines that define sorting, assuming all bricks are same width (for example, always 5 in row).

To demonstrate this, I used jQuery Masonry (was compressed) and you can check it out in this Fiddle.

JS

$.Mason.prototype._placeBrick = function(e) {
    var n = $(e),
        r, i, s, o, u;
    r = Math.ceil(n.outerWidth(!0) / this.columnWidth), r = Math.min(r, this.cols);
    if (r === 1) s = this.colYs;
    else {
        i = this.cols + 1 - r, s = [];
        for (u = 0; u < i; u++) o = this.colYs.slice(u, u + r), s[u] = Math.max.apply(Math, o)
    }
    var a = Math.min.apply(Math, s),
        f = 0;
    for (var l = 0, c = s.length; l < c; l++)
        if (s[l] === a) {
            f = l;
            break
        }
    /* Add new calculation, what column next brick is in: */
    f = $(e).index() % this.cols; /* Get col index f: Just divide with element's index */
    a = s[f]; /* This is current height for f-th column */
    /* END of customizing */
    var h = {
        top: a + this.offset.y
    };
    h[this.horizontalDirection] = this.columnWidth * f + this.offset.x, this.styleQueue.push({
        $el: n,
        style: h
    });
    var p = a + n.outerHeight(!0),
        d = this.cols + 1 - c;
    for (l = 0; l < d; l++) this.colYs[f + l] = p;
};
like image 27
skobaljic Avatar answered Oct 05 '22 11:10

skobaljic