11

I've been trying to work out exactly how the TED Talk homepage works. Leaving aside all the animation rubbish, I find the way that the boxes are organised is really fascinating.

At first glance it looks like the jQuery masonry plugin, bu it quickly becomes clear that it tends to create several right angle triangle shapes, but has no fixed number of columns or rows, and the final shape produced is always completely solid (no hollow parts).

My initial assumption was that the boxes (their size is predetermined by some factor on the site) were sorted randomly and then sequentially added to the grid using a few simple rules, however I can't identify what those rules might be, or how they could prevent any hollows in the final shape.

Does anyone have any idea how this works?

hammar
  • 138,522
  • 17
  • 304
  • 385
peterjwest
  • 4,294
  • 2
  • 33
  • 46
  • whats so fascinating about it? each video is placed in a div and the position and sizes of divs are absolute, which makes it easy according to me! try searching for "theAppContainer" div in source – FUD Dec 20 '11 at 17:26
  • Care to elaborate in an answer? – Benjamin Dec 21 '11 at 14:38
  • what i meant was, that you can create a random layout with rectangle and squares like that its not necessarily a fractal patten for which you need to research. And the layout can be created using divs with absolute position and sizes!! – FUD Dec 21 '11 at 18:01
  • also see http://stackoverflow.com/questions/565006/ – sdcvvc Dec 21 '11 at 22:06
  • @ChingPing I'm not talking about the implementation which is trivial, but the algorithm which is interesting. :P – peterjwest Mar 23 '12 at 13:21

3 Answers3

4

Could be wrong but a few observations:

  • Each section has 19 videos
  • There are 4 sizes 1 (#1), 1/4 (#2), 1/16 (#3) and 1/32 (#4)

For a given section, there are always 4(#1). The number of (#2), (#3) and (#4) can be either:

  • 4(#1), 10(#2), 4(#3), 1(#1) = 19
  • 4(#1), 11(#2), 4(#3), 0(#1) = 19
  • 4(#1), 11(#2), 3(#3), 1(#1) = 19
  • 4(#1), 12(#2), 2(#3), 1(#1) = 19
  • 4(#1), 13(#2), 1(#3), 1(#1) = 19

As for the order:

  • The first row always contains 2(#1) and 4(#2)
  • (#4) are always at the bottom of a column
Benjamin
  • 11,560
  • 13
  • 70
  • 119
1

Here is the javascript code which does it (you need a html page with a div#container):

function ted_layout(settings, coordinates_array, num_elements, start_x, start_y, arrangement, remaining_elements, is_child){
    var num_columns = arrangement.length;
    var col = 0;
    var current_x = start_x;
    while( col < num_columns){
        var column_x_scale = 100 / arrangement[col];
        var current_column_arrangement;
        if(is_child){
            if(num_elements > 14){
                if(column_x_scale == 50){
                    current_column_arrangement = random_shuffle([1, 2, 2]);
                } else {
                    current_column_arrangement = random_shuffle([1, 2]);
                }
            } else if(num_elements > 10){
                if(column_x_scale == 50){
                    current_column_arrangement = [1];
                } else {
                    current_column_arrangement = random_shuffle([1, 2]);
                }
            } else{
                    current_column_arrangement = random_shuffle([1, 2]);
            }
        } else {
            if(num_elements > 14){
                if(column_x_scale == 25){
                    current_column_arrangement = [1, 1];
                } else {
                    current_column_arrangement = [1];
                }
            } else if(column_x_scale == 25){
                    current_column_arrangement = [1, 1];
            } else {
                    current_column_arrangement = [1];
            }
        }


        var num_rows = current_column_arrangement.length;
        var current_y = start_y;
        var row = 0;
        while(row < num_rows){

            var numRects = current_column_arrangement[row];
            var current_rectangle = 0;
            var current_rectangle_x = current_x;

            while( current_rectangle < numRects){
                if(remaining_elements == 0){
                   return coordinates_array;
                }
                var currScale = column_x_scale/numRects;
                var height = settings.height * currScale*0.01;
                var width = settings.width * currScale*0.01;
                if(current_rectangle == numRects-1 && row == num_rows-1 && is_child && Math.random() > 0.5){
                    coordinates_array.push({x: current_rectangle_x, y:current_y, w:width/2, h:height/2, scale:currScale/2*0.01*2})
                }
                else{
                    coordinates_array.push({x: current_rectangle_x, y:current_y, w:width, h:height, scale:currScale*0.01*2})
                }
                current_rectangle_x += width;
                remaining_elements--;
                current_rectangle++;
            }
            row++;
            current_y += height;
        }
        current_x = current_rectangle_x;
        col++;
    }
    if( remaining_elements > 0){
        coordinates_array = ted_layout(settings, coordinates_array, num_elements, start_x, current_y, random_shuffle([2, 4, 4, 2]), remaining_elements, true);
    }
    return coordinates_array;
}


function generate_ted_layout(num_elements){
    var settings = {
        width: 640,
        height: 480,
    };
    var coordinates_array=[];
    returned = ted_layout(settings, coordinates_array, num_elements, 0, 0, random_shuffle([2, 4, 4, 2]), num_elements, false);
    console.log("Returned", returned)
    return returned;
}

function random_shuffle(array){
    var temp;
    for(var i = array.length - 1; i >= 1; i--){
        var elem = Math.floor(Math.random() * (i + 1));
        temp = array[elem];
        array[elem] = array[i];
        array[i] = temp;
    }
    return array;
}


function initAndLayout() {
    var items = generate_ted_layout(20);

    var container = $('#container');    // cache jquery object
    console.log(items);
    for (var i = 0; i < items.length; i++)
    {
        var item = items[i];
        console.log(item);
        $('#container').append($('<div class="item"></div>').css({'left': item.x, 'top': item.y, 'width': item.w, 'height': item.h}));
    }
}
mdml
  • 22,442
  • 8
  • 58
  • 66
js_guru
  • 11
  • 1
  • Clearly this is the best answer. This is exactly how the page works. It's just missing the accompanying description. – Benjamin Nov 16 '15 at 03:02
0

I think I've worked it out.

First of all the number of items varies substantially, I'm currently viewing a page with only 13 boxes.

To start I'll name each of the 4 sizes of blocks from largest to smallest as: A,B,C,D

As we know the first 'row' contains two As and two vertical stacks of Bs, for example:

 _______________________
|   A   | B |   A   | B |
|       |___|       |___|
|       | B |       | B |
|_______|___|_______|___|

The arrangement of these appears to be random, but the Bs are always in the same vertical pattern. Looking at this just now I realised that there are only two rows, and the second row works in the same way.

The second row is twice the height of the first, taking up the rest of the page. It is built of horizontally stacked patterns of shapes, which are (at least in part) selected randomly.

I've found 9 of these patterns of shapes, two of which are a single A or B and the rest are:

  _______    _______    _______    ___    ___    _______    ___
 | B | B |  |   A   |  | B | B |  |C|C|  | B |  |   A   |  |C|C|
 |___|___|  |       |  |___|___|  | B |  |___|  |       |
 |   A   |  |       |  | B | B |  |___|  |C|D   |       |
 |       |  |_______|  |___|___|                |_______|
 |       |  | B | B |  |   A   |                | B |    
 |_______|  |___|___|  |       |                |___|    
 |B  |C|    |B  |C|    |       |
 |___|      |___|      |_______|

The next question is how are these selected? There may be some clever searching to find the best configuration: for example if there are X items to be displayed we need to find a configuration with a total of X which does not exceed the width of the row.

This could be done with a metric of pattern density, which would be number of blocks divided by the width of the pattern.

peterjwest
  • 4,294
  • 2
  • 33
  • 46