---
title: Spine align
layout: default
category: custom-layout-modes
---

<section id="copy">
  <p><a href="../docs/extending-isotope.html">Custom layout mode</a> that aligns items to the center, placing them either left or right of the spine. <code>gutterWidth</code> option available.</p>

{% highlight javascript %}

$container.isotope({
  layoutMode: 'spineAlign',
  spineAlign: {
    gutterWidth: 20
  },
  // options...
});

{% endhighlight %}

  <p>To use this layout mode, grab the <code>$.Isotope.prototype</code> methods from the script at the bottom of this page's source.</p>

</section>

<section id="options" class="clearfix">

  {% include filter-buttons.html %}

  {% include sort-buttons.html %}

  <h3>Etc</h3>

  <ul id="etc" class="clearfix">
    <li id="toggle-sizes"><a href="#toggle-sizes">Toggle variable sizes</a></li>
    <li id="insert"><a href="#insert">Insert new elements</a></li>
    <li id="append"><a href='#append'>Append new elements</a></li>
    <li id="shuffle"><a href='#shuffle'>Shuffle</a></li>
  </ul>

</section> <!-- #options -->

<div id="container" class="clickable variable-sizes clearfix">
  {% for elem_number in site.best_of_order %}
    {% assign element = site.elements[elem_number] %}
    {% include element-partial.html %}
  {% endfor %}
</div> <!-- #container -->


<script src="../{{ site.jquery_js }}"></script>
<script src="../{{ site.isotope_js }}"></script>
<script src="../js/fake-element.js"></script>
<script>

  // custom layout mode spineAlign
  $.Isotope.prototype._spineAlignReset = function() {
    this.spineAlign = {
      colA: 0,
      colB: 0
    };
  };

  $.Isotope.prototype._spineAlignLayout = function( $elems ) {
    var instance = this,
        props = this.spineAlign,
        gutterWidth = Math.round( this.options.spineAlign && this.options.spineAlign.gutterWidth ) || 0,
        centerX = Math.round(this.element.width() / 2);

    $elems.each(function(){
      var $this = $(this),
          isColA = props.colB > props.colA,
          x = isColA ?
            centerX - ( $this.outerWidth(true) + gutterWidth / 2 ) : // left side
            centerX + gutterWidth / 2, // right side
          y = isColA ? props.colA : props.colB;
      instance._pushPosition( $this, x, y );
      props[( isColA ? 'colA' : 'colB' )] += $this.outerHeight(true);
    });
  };

  $.Isotope.prototype._spineAlignGetContainerSize = function() {
    var size = {};
    size.height = this.spineAlign[( this.spineAlign.colB > this.spineAlign.colA ? 'colB' : 'colA' )];
    return size;
  };

  $.Isotope.prototype._spineAlignResizeChanged = function() {
    return true;
  };


  $(function(){
    
    var $container = $('#container');
    
    {% include random-sizes.js %}
    
    $container.isotope({
      itemSelector : '.element',
      layoutMode: 'spineAlign',
      spineAlign: {
        gutterWidth: 20
      },
      getSortData : {
        symbol : function( $elem ) {
          return $elem.attr('data-symbol');
        },
        category : function( $elem ) {
          return $elem.attr('data-category');
        },
        number : function( $elem ) {
          return parseInt( $elem.find('.number').text(), 10 );
        },
        weight : function( $elem ) {
          return parseFloat( $elem.find('.weight').text().replace( /[\(\)]/g, '') );
        },
        name : function ( $elem ) {
          return $elem.find('.name').text();
        }
      }
    });
      
    {% include option-set-buttons.js %}

    {% include add-buttons.js %}

    {% include change-sizes.js %}

    var $sortBy = $('#sort-by');
    $('#shuffle a').click(function(){
      $container.isotope('shuffle');
      $sortBy.find('.selected').removeClass('selected');
      $sortBy.find('[data-option-value="random"]').addClass('selected');
      return false;
    });
    
  });
</script>