0

Given a screen which I want to fill up with n buttons of equal size, how would I calculate it such that the screen is optimally filled with the buttons? It is for a mobile app where the user just has to make a quick selection.

In pseudo code what I initially wrote:

ta = w*h; //total area
as = ta/n; //area of each square
ss = sqrt(as); //side square
sh = ceil(w/ss); //squares horizontally
sv = ceil(h/ss); //squares vertically
sw = w/sh; //square width
sh = h/sv; //square height

However there are a couple of problems with this, first of all due to the ceil function I may end up with an entirely empty row at the bottom of the screen, however a round will sometimes make the squares not fit. Additionally in cases where the bottom row contains only a few buttons the width could have been increased such that less space would be left over on the bottom row (though some space will of course be left).

All similar questions discuss solutions for different sizes of rectangles which I could work out using a recursive or similar approach, but this should be far simpler I believe.

David Mulder
  • 26,123
  • 9
  • 51
  • 114
  • your use of the word "square" while referring to rectangles offends me :) –  Feb 12 '14 at 10:57
  • Have a look here: http://stackoverflow.com/questions/1213394/algorithm-needed-for-packing-rectangles-in-a-fairly-optimal-way and here: http://en.wikipedia.org/wiki/Packing_problem#Identical_rectangles_in_a_rectangle – Tariq Feb 12 '14 at 10:57
  • Are these buttons allowed to change size (a bit) or are they fixed? Also what I don't get: If your squares have a fixed size then why not just float them left in the area and let the browser take care of the rest? Would you be able to set up an example at http://jsfiddle.net for this? – Niklas Feb 12 '14 at 11:02
  • Sorry guys, my internet died minutes after posting this question, back again, @ zyklus: I know, started with squares, then realized I was changing them in rectangles at the end, so the question was about rectangles, but the origin was squares @Tariq: The first question is about boxes of different fixed sizes, whereas for me only the number of boxes is fixed and their size is not. @ Niklas: Think that got answered now as well :) Oh well, gonna check thg435's answer now :D – David Mulder Feb 12 '14 at 12:15

1 Answers1

2

Here's a brute force method:

function split(w, h, n) {

    var splits = [];

    for(var rows = Math.min(2,n-1); rows < n; rows++) {
        if(n % rows != 0)
            continue;
        var cols = n / rows;
        splits.push([cols, rows, w % cols, h % rows]);
    }

    splits.sort(function(a, b) {
        return (a[2] + a[3]) - (b[2] + b[3]) || (a[0] - a[1]) - (b[0] - b[1]);
    });

    if(splits.length > 0)
        return splits[0];
    else
        return split(w,h,n+1); //in case of primes
}

It returns four numbers: columns, rows, extra pixels on the last column, extra pixels on the last row. For example:

 split(300, 100, 12) // 3,4,0,0

makes 3 cols and 4 rows, no pixels to add. Col widths will be 300/3 = 100

split(700, 220, 12) // 3,4,1,0

3 cols, add one px to the last col, column widths will be floor(700/3)=233, 233, 234

Instead of making the last col/row wider/taller, you can add some padding to the container.

David Mulder
  • 26,123
  • 9
  • 51
  • 114
georg
  • 211,518
  • 52
  • 313
  • 390
  • Was hoping to use a deterministic approach, but I guess you must be right then that a brute force approach is the only way to go. Had to tweak your function a bit to get it working, but nice job, it ended up working really nicely :D – David Mulder Feb 12 '14 at 12:29
  • @DavidMulder: you're welcome ;] feel free to share your improvements for other's benefit. – georg Feb 12 '14 at 12:34
  • Your code broke in case n was a prime or when n=2, so fixed those two cases. The rest of my code added a recursive minimal size solution, but that seemed to be too much of a good thing :) – David Mulder Feb 12 '14 at 18:01