Есть ли способ настроить таргетинг на первый и последний элемент в каждой строке, используя изотоп jQuery?

У меня есть изотопная сетка каменной кладки, которая имеет n строк с двумя размерами столбцов: 160 пикселей на 160 пикселей и 320 пикселей на 320 пикселей, и я хотел бы назначить разные стили для первого и последнего элемента каждой строки. В моих строках может быть от 4 до 7 элементов. Я немного боролся с этим и задавался вопросом, возможно ли это.

HTML

<div id="grid" style="position: relative; overflow: hidden; height: 960px;"
class="isotope">
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="two_by_two">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_two">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="two_by_two">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_two">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="two_by_two">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_two">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
    <div class="one_by_one">
        <img class="thumb" src="https://s3.amazonaws.com/stitch-images/products/gucci.png"
        />
    </div>
</div>

CSS

#grid {
    margin:auto;
    margin-top:55px;
    margin-bottom:200px;
    width:1140px
}
#grid .thumb {
    width:97%;
    height:97%
}
#grid .one_by_one {
    width:160px;
    height:160px;
    background:url(https://s3.amazonaws.com/stitch-images/assets/cell_1x1.png);
    cursor:pointer
}
#grid .one_by_two {
    width:160px;
    height:320px;
    background:url(https://s3.amazonaws.com/stitch-images/assets/cell_1x2.png);
    cursor:pointer
}
#grid .two_by_two {
    width:320px;
    height:320px;
    background:url(https://s3.amazonaws.com/stitch-images/assets/cell_2x2.png);
    cursor:pointer
}

JS

$("#grid").isotope masonry: layoutMode: 'fitRows'

Просмотреть мой Jsfiddle http://jsfiddle.net/TDma4/


person mike    schedule 27.01.2013    source источник
comment
Пожалуйста, включите образец HTML, чтобы уточнить ваш вопрос   -  person thaJeztah    schedule 28.01.2013
comment
Я добавил код и jsfiddle   -  person mike    schedule 28.01.2013
comment
Спасибо. Я не думаю, что у меня есть готовый ответ для вас, но добавление примера кода делает ваш вопрос намного яснее :). Отвечу, если найду ответ   -  person thaJeztah    schedule 28.01.2013
comment
Удачи с предложенными решениями?   -  person JSuar    schedule 06.02.2013


Ответы (5)


Вот один из подходов к проблеме.

Рабочее решение: http://jsbin.com/ufuleb/21/

CSS

.first, .last {
  border:2px dashed blue;
  opacity:.75;
}

JavaScript

$("#grid").isotope(
    { layoutMode : 'fitRows' });

// Last div element
$("#grid div:last-child").addClass("last");

var maxWidth = 0;

// Use max to handle last div
$("#grid div").each(function (i) {  
  matrix = matrixToArray($(this).css("-transform"));

  // identify first elements
  if ( parseInt(matrix[4],10) == 0 ) {
    $(this).addClass("first");
  }

  // identify last elements
  if ( parseInt(matrix[4],10) > parseInt(maxWidth,10) ) { 
    maxWidth = matrix[4];
  } else {      
    $(this).prev().addClass("last");
    maxWidth = 0;
  } 
});

// Util function for parsing -webkit-transform
function matrixToArray(matrix) {    
    return matrix.substr(7, matrix.length-8).split(', ');
}

Переберите каждый div и отследите текущее значение xT (CSS -webkit -трансформировать). Всякий раз, когда передается максимальное значение, просто обновите предыдущее значение, которое должно быть последним элементом каждой строки. Самый последний элемент обрабатывается с помощью :last-child. Обратите внимание, что это решение также обрабатывает общее изменение ширины #grid.

Пример вывода

Пример вывода

Это, вероятно, может быть дополнительно оптимизировано, но, по крайней мере, обеспечивает отправную точку.

Мне помог этот ответ: https://stackoverflow.com/a/5968313/1085891

Для справки:

person JSuar    schedule 31.01.2013
comment
Если вы измените -webkit-transform на transform, это должно работать в других браузерах (например, Firefox). Кроме того, гарантируется ли последний дочерний элемент (в порядке DOM) последним элементом в последней строке? - person Jeffery To; 06.02.2013
comment
Обновил мой код. Кроме того, я не смог найти тестовый пример, в котором последний дочерний элемент не был элементом в последней строке с layoutMode: 'fitRows'. - person JSuar; 06.02.2013

В Isotope есть опция itemPositionDataEnabled, которая показывает положение каждого элемента. Используя это вместе с обработчиком onLayout, вы можете вычислить первый и последний элементы каждой строки (демонстрация):

$('#grid').isotope({
    itemPositionDataEnabled: true,
    onLayout: function (elems, instance) {
        var items, rows, numRows, row, prev, i;

        // gather info for each element
        items = elems.map(function () {
            var el = $(this), pos = el.data('isotope-item-position');
            return {
                x: pos.x,
                y: pos.y,
                w: el.width(),
                h: el.height(),
                el: el
            };
        });

        // first pass to find the first and last items of each row
        rows = [];
        i = {};
        items.each(function () {
            var y = this.y, r = i[y];
            if (!r) {
                r = {
                    y: y,
                    first: null,
                    last: null
                };
                rows.push(r);
                i[y] = r;
            }
            if (!r.first || this.x < r.first.x) {
                r.first = this;
            }
            if (!r.last || this.x > r.last.x) {
                r.last = this;
            }
        });
        rows.sort(function (a, b) { return a.y - b.y; });
        numRows = rows.length;

        // compare items for each row against the previous row
        for (prev = rows[0], i = 1; i < numRows; prev = row, i++) {
            row = rows[i];
            if (prev.first.x < row.first.x &&
                    prev.first.y + prev.first.h > row.y) {
                row.first = prev.first;
            }
            if (prev.last.x + prev.last.w > row.last.x + row.last.w &&
                    prev.last.y + prev.last.h > row.y) {
                row.last = prev.last;
            }
        }

        // assign classes to first and last elements
        elems.removeClass('first last');
        $.each(rows, function () {
            this.first.el.addClass('first');
            this.last.el.addClass('last');
        });
    }
});

Обновление: исправлен алгоритм на основе отзывов JSuar.

Обновление 2. Исправлена ​​ошибка, из-за которой элементы были выше двух рядов.

person Jeffery To    schedule 04.02.2013
comment
@JSuar, можешь привести пример? Обработчик onLayout вызывается каждый раз, когда Isotope размещает элементы - person Jeffery To; 05.02.2013
comment
Это крайний случай, но если вы установите width:520px;, один из больших элементов не будет перехватываться как последний элемент. - person JSuar; 05.02.2013

Майк, если вы чувствуете себя авантюрно, вы можете расширить Isotop, чтобы сделать это. Я вытащил следующее из http://isotope.metafizzy.co/docs/extending-isotope.html

Любые дополнительные свойства, которые вы хотите сделать, вы можете сделать в блоке .each.

_fitRowsLayout : function( $elems ) {
  var instance = this,
      containerWidth = this.element.width(),
      props = this.fitRows;

  $elems.each( function() {
    var $this = $(this),
        atomW = $this.outerWidth(true),
        atomH = $this.outerHeight(true);

    if ( props.x !== 0 && atomW + props.x > containerWidth ) {
      // if this element cannot fit in the current row
      props.x = 0;
      props.y = props.height;
    } 

    // position the atom
    instance._pushPosition( $this, props.x, props.y );

    props.height = Math.max( props.y + atomH, props.height );
    props.x += atomW;

  });
},
person zmanc    schedule 31.01.2013

используйте это: http://jsfiddle.net/86WVw/1/

Изменить: isotope теперь использует translate3d, отредактировано для использования как translate, так и translate3d http://jsfiddle.net/86WVw/3/

дополнительный css:

[style*="translate(0px"], [style*="translate3d(0px"], .border { // .border is class for end of row item, you can change it to whatever you want
    border: 3px dotted #f00;
}

дополнительный js:

gw = $('#grid').width(); // get grid width
w = $('#grid').width(); // to find smallest width, take a big number first
$('#grid>div').each(function(){ // iterate through tiles
    if ($(this).width()<w) // if width smaller then assumed smallest width
        w = $(this).width(); // change smallest width
});

var x;
for (x = w; x < gw; x += w) // iterate translated tiles from smallest width to grid width
{
    var elms = $('[style*="translate3d('+x+'px"], [style*="translate('+x+'px"]');
    $(elms).each(function(){
        if ((x+$(this).width())>(gw-w)) // if tiles left + tile width reach end of grid
        $(this).addClass('border'); // apply class
    });
}
person am05mhz    schedule 02.02.2013

Вопрос гораздо проще, чем кажется.
Размер поля кратен обычной матрице.

Это мой подход.

var columnsWidth = 100; // the base matrix width
var columns = 8; // the number of columns available (container.width / columnsWidth)

$.each(box, function() {
    var box = $(this) // the current box
    var boxSize = [2,2] // obtained subdividing size by matrix
    var maximumXChord = (columns - boxSize[0]) * columnsWidth // the maximum X available

    if (box.x == maximumXChord) { // check if the current X Chords is equal to the maximum
        console.log('the box is the last of this row!')
    } else if (box.x == 0) { // check if the the X is 0
        console.log('the box is the first of this row!') 
    }
})

Это все!

person Lorenzo Migliorero    schedule 28.01.2014