この質問への回答を得ることができませんでしたが、Neptiloからの同様の質問に対する適切な実装を見つけました。ただし、長方形では機能せず、正方形のみでした。そこで、マッキードのアイデアを適用して長方形を正規化し、次に正方形のアルゴリズムに従いました。
その結果がfitToContainer()
関数です。フィットする四角形の数n
とcontainerWidth
とcontainerHeight
元のitemWidth
と を指定しitemHeight
ます。アイテムに元の幅と高さがない場合は、 と を使用itemWidth
しitemHeight
て、アイテムの目的の比率を指定します。
たとえば、480 x 270 (ピクセル、または単位が何であれ) の 4 つの列と 3 つの行になりますfitToContainer(10, 1920, 1080, 16, 9)
。{nrows: 4, ncols: 3, itemWidth: 480, itemHeight: 270}
fitToContainer(10, 1920, 1080, 1, 1)
そして、1920x1080 の同じ例の領域に 10 個の正方形を収めるには、次のように呼び出すことができます{nrows: 2, ncols: 5, itemWidth: 384, itemHeight: 384}
。
function fitToContainer(n, containerWidth, containerHeight, itemWidth, itemHeight) {
// We're not necessarily dealing with squares but rectangles (itemWidth x itemHeight),
// temporarily compensate the containerWidth to handle as rectangles
containerWidth = containerWidth * itemHeight / itemWidth;
// Compute number of rows and columns, and cell size
var ratio = containerWidth / containerHeight;
var ncols_float = Math.sqrt(n * ratio);
var nrows_float = n / ncols_float;
// Find best option filling the whole height
var nrows1 = Math.ceil(nrows_float);
var ncols1 = Math.ceil(n / nrows1);
while (nrows1 * ratio < ncols1) {
nrows1++;
ncols1 = Math.ceil(n / nrows1);
}
var cell_size1 = containerHeight / nrows1;
// Find best option filling the whole width
var ncols2 = Math.ceil(ncols_float);
var nrows2 = Math.ceil(n / ncols2);
while (ncols2 < nrows2 * ratio) {
ncols2++;
nrows2 = Math.ceil(n / ncols2);
}
var cell_size2 = containerWidth / ncols2;
// Find the best values
var nrows, ncols, cell_size;
if (cell_size1 < cell_size2) {
nrows = nrows2;
ncols = ncols2;
cell_size = cell_size2;
} else {
nrows = nrows1;
ncols = ncols1;
cell_size = cell_size1;
}
// Undo compensation on width, to make squares into desired ratio
itemWidth = cell_size * itemWidth / itemHeight;
itemHeight = cell_size;
return { nrows: nrows, ncols: ncols, itemWidth: itemWidth, itemHeight: itemHeight }
}