ウィンドウサイズに応じて動的にいろいろ動かすってところまで対応するのはめんどくさそうだったので、レイアウトを組み立てるところまでのまとめ。
前提条件
- 並べる時は絶対配置で並べる (本家Pinterestも絶対配置)
- ウィンドウサイズをリサイズしてもカラム数は変わらない
参考サイト
レイアウトを組み立てる考え方
基本的には参考サイトに書いてあるとおり。
- 配列を一つ用意し、カラム数分の要素を作る。
- 配列の中の要素は各カラムの高さ(endY)の数値を持つ。
- 新たに要素を並べる時には、配列の中から高さ(endY)が一番小さいカラムに対して並べる。
- 配列の中の要素を、新たに並べたカラムの高さ(endY)に更新する。
※3と4を繰り返す
実装してみる
function PinterestListView(listId) {
var COLUMN = 4, // カラム数
MARGIN = 15, // アイテムの上下マージン
WIDTH = 100, // アイテムのwidth
columns = [], // カラムごとの現在のendY値を格納する配列
list = document.getElementById(listId); // アイテムを並べるbox
/**
* 次に追加するUnitのXY座標を返す
*/
function getPosition() {
var len = columns.length;
if (len < COLUMN) {
return {
x: len * WIDTH + (len * 2 * MARGIN),
y: 0
}
}
var minIndex = columns.indexOf(Math.min.apply(null, columns));
return {
x: minIndex * WIDTH + (minIndex * 2 * MARGIN),
y: columns[minIndex]
}
}
/**
* 高さの最大値を取得
*/
function getMaxHeight() {
return Math.max.apply(null, columns);
}
/**
* 追加したアイテムのendY値を上書きする
*/
function pushUnit(height) {
var len = columns.length;
if (len < COLUMN) {
return columns.push(height + (MARGIN * 2));
}
var minIndex = columns.indexOf(Math.min.apply(null, columns));
return columns[minIndex] += height + (MARGIN * 2);
}
/**
* アイテムを並べる
*/
function layout(items) {
for (var i = 0; i < items.length; ++i) {
var item = items[i],
position = getPosition();
// 位置をセット
item.style.top = position.y + 'px';
item.style.left = position.x + 'px';
// アイテムをHTMLに追加
list.appendChild(item);
// 追加したアイテムのendY値を配列に反映
pushUnit(item.offsetHeight);
// 現在のリストのheightをセット
list.style.height = getMaxHeight() + 'px';
}
return list;
}
/*-------------------------------------------
EXPORT
-------------------------------------------*/
return {
layout: layout
};
}
実際に動かしているサンプルはこちら。
http://jsdo.it/tanihiro/b5kyw
注意点
一箇所、indexOfを使用している箇所があるので、IEだとエラーが出てしまう。