123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- /**
- * Grid()
- * by Bachir Soussi-Chiadmi www.g-u-i.net
- * version 2.0
- */
-
- function Grid(ctx, settings){
-
- var _defaults = {
- children:'', // tell which dom elmt to target, by default $ctx.children();
- cell_w: 20, cell_h: 20,
- cell_padding:{t:5,r:5,b:5,l:5}, // with or without padding cell width and height are the same
- padding:{t:5,r:5,b:5,l:5}, // padding (in cell) inside the grid where not placed element
- gouttiere: 5, // space between cells h and v
- lines: 20, columns: 20,// how much line and columns grid has
- grille: false, // see the grid with cell's free space infos
- groove: 0, // add groove attitude (randomize placement)
- positioning_mode:'random', // positioning_mode play with with the position on items
- max_distance:0, // distance max between prev item and current item. O = no limit
- min_distance:0, // distance min between prev item and current item. O = no limit
- },
- $ctx = ctx,
- _cells = new Array(),
- _positions = new Array(),
- _grid = this;
- this.ctx = $ctx;
- this.settings = $.extend({}, _defaults, settings);
-
-
- // $.log('this.settings', this.settings);
- // set dom grille visualsation context if enabled
- if (this.settings.grille) {
- $ctx.append('<div class="grille"><div>');
- $('.grille', $ctx).css({
- 'width': '100%',
- 'height': '100%',
- 'position': 'relative'
- });
- }
- // create all empty cells
- for (var l = 0; l < this.settings.lines; l++) {
- _cells[l] = new Array();
- for (var c = 0; c < this.settings.columns; c++) {
- _cells[l][c] = new Cell(this, c, l);
- };
- };
-
- function _setPrevCell(){
- // _grid.prev_cell = false;
- switch(_grid.settings.positioning_mode){
- case 'lefttop': // add items from top left to bootm rif-ght
- _grid.prev_cell = _cells[0][0];
- break;
- case 'center': // add items from center of grid to both side randomly
- _grid.prev_cell = _cells[Math.floor(_grid.settings.lines*.5)][Math.floor(_grid.settings.columns*.5)];
- break;
- case 'borders': // add items from center of grid to both side randomly
- var side = Math.floor(Math.random()*4);
- $.log('side = '+side);
- switch(side){
- case 0 :
- _grid.prev_cell = _cells[0][Math.floor(_grid.settings.columns*Math.random())];
- break;
- case 1 :
- _grid.prev_cell = _cells[_grid.settings.lines-1][Math.floor(_grid.settings.columns*Math.random())];
- break;
- case 2 :
- _grid.prev_cell = _cells[Math.floor(_grid.settings.lines*Math.random())][0];
- break;
- case 3 :
- _grid.prev_cell = _cells[Math.floor(_grid.settings.lines*Math.random())][_grid.settings.columns-1];
- break;
- }
- break;
- case 'random': // add items randomly
- default:
- _grid.prev_cell = _cells[Math.floor(_grid.settings.lines*Math.random())][Math.floor(_grid.settings.columns*Math.random())];
- break;
- }
-
- }
- _setPrevCell();
- /**
- * placeTargets()
- */
- function _placeTargets(){
- // parse targets
- var $targets = _grid.settings.children != '' ? $(_grid.settings.children+':not(.grid-placed)', $ctx) : $ctx.children(':not(.grid-placed)');
- $targets.each(function() {
- var $this = $(this),
- // get the width and height ( ! on cell unit ! how much cells it takes ? ) of item to be positioned
- this_cells_w = Math.ceil($this.width() / (_grid.settings.cell_w + _grid.settings.gouttiere)),
- this_cells_h = Math.ceil($this.height() / (_grid.settings.cell_h + _grid.settings.gouttiere)),
- // get free cells function of width and height of item
- free_cells = getFreeCells(this_cells_w, this_cells_h);
- if(free_cells.length > 0){
- // positioning mode, to change this mode uncomment/comment lines after description
- switch(_grid.settings.positioning_mode){
- case 'lefttop': // add items from top left to bootm rif-ght
- var cell_num = 0,
- cell = free_cells[cell_num];
- break;
- default: // add items from center of grid to both side randomly
- // var cell_num = Math.floor((free_cells.length-1)*0.5 + (-2+Math.random()*4));
- // cell_num = cell_num > free_cells.length-1 ? free_cells.length-1 : ( cell_num < 0 ? 0 : cell_num );
- // var cell = free_cells[cell_num];
- var cell_num = Math.round(Math.random() * (free_cells.length - 1)),
- cell = free_cells[cell_num];
- break;
- }
- _grid.prev_cell = cell;
- var line_limit_loop = cell.row() + (this_cells_h),
- column_limit_loop = cell.column() + (this_cells_w);
- for (var l = cell.row(); l < line_limit_loop; l++) {
- for (var c = cell.column(); c < column_limit_loop; c++) {
- var temp_cell = _cells[l][c];
- temp_cell.setFull();
- };
- };
- // get tp and left coordinates
- // should be directly recorded in the cell object
- var top = cell.row() * (_grid.settings.cell_h + _grid.settings.gouttiere),
- left = cell.column() * (_grid.settings.cell_w + _grid.settings.gouttiere),
- groove = _grid.settings.groove;
- // set groove ;)
- top = !groove ? top: top + Math.round(Math.random() * groove - groove / 2);
- left = !groove ? left: left + Math.round(Math.random() * groove - groove / 2);
- // apply ccs position
- top += _grid.settings.cell_padding.t;
- left += _grid.settings.cell_padding.l;
-
- var event = jQuery.Event("grid_positioned");
- event.top = top;
- event.left = left;
-
- $this.css({
- 'top': top,
- 'left': left
- }).addClass('grid-positioned').trigger(event);
- }else{
- $.log('GRID no free cells left');
- // if no free cells exist
- $this.css({
- 'border': '2px solid red',
- 'opacity': 0.2
- }).trigger('grid_removed');//.remove();
- }
- $this.addClass('grid-placed').trigger('grid_placed');
- }); // end children each
-
- }
-
-
- /**
- * getFreeCells()
- *
- * @ width in cells
- * @ height in cells
- *
- * return array of cell objects
- *
- */
- function getFreeCells(this_cells_w, this_cells_h){
-
- var free_cells = new Array(),
- padding = _grid.settings.padding,
- max_dist = _grid.settings.max_distance,
- min_dist = _grid.settings.min_distance,
- prev_cell = _grid.prev_cell;
-
- // $.log()
-
- for (var l = 0; l < _grid.settings.lines; l++) {
- for (var c = 0; c < _grid.settings.columns; c++) {
- var cell = _cells[l][c];
-
- /*
- TODO about the max_dist keep in mind that all element will not always be 1 cell elemnts !!
- */
-
- // here is a big stuff of conditionning
- // we check a lot of things
- // 1 - basicly if the cell is free
- // 2 - if the cell is under the padding limits
- // 3 - if she has enought space arround her
- // 4 - if we got a prev cell
- // 4.1 - if we got a max_dist != 0
- // 4.1.1 - if the cell is under the max limits
- // 4.2 - if we got a min_dist != 0
- // 4.2.1 - if the cell is behind the min limits
-
- if (cell.isFree() // if cell is free
- && (cell.row() > padding.t && cell.row() < _grid.settings.lines - padding.b
- && cell.column() > padding.l && cell.column() < _grid.settings.columns - padding.r
- )
- && (
- (cell.getAround().right + 1) >= this_cells_w // if enought free space on the right
- && (cell.getAround().bottom + 1) >= this_cells_h // if enought free space on the bottom
- )
- && ( !_grid.prev_cell // else if _grid.prev_cell undefined it's true
- || ( // check max_dist AND min_dist
- (!max_dist // if max_distance is 0 return (stop condition) true
- || ( cell.row() < prev_cell.row()+max_dist && cell.row() > prev_cell.row()-max_dist
- && cell.column() < prev_cell.column()+max_dist && cell.column() > prev_cell.column()-max_dist )// if we got max_distance and prev_cell we check the distance
- )
- &&
- (!min_dist // if min_distance is 0 return (stop condition) true
- || ( (cell.row() > prev_cell.row()+min_dist || cell.row() < prev_cell.row()-min_dist)
- || (cell.column() > prev_cell.column()+min_dist || cell.column() < prev_cell.column()-min_dist) )// if we got min_distance and prev_cell we check the distance
- )
- )
- )
- ) { // true of first big stuff if
- var good = true;
- for (var i = 1; i < this_cells_w; i++) { // for each free cells needed on right
- var temp_cell = _cells[l][c + i];
- if ((temp_cell.getAround().bottom + 1) < this_cells_h) { // if enought free space on bottom
- good = false;
- break;
- }
- };
- if (good) free_cells.push(cell);
- }
- };
- };
-
- return free_cells;
- }
- /**
- * Cell()
- */
- function Cell(g, c, r) {
- var _grid = g,
- _column = c,
- _row = r,
- _free = true,
- _free_cell_right = _grid.settings.columns - 1 - c,
- _free_cell_bottom = _grid.settings.lines - 1 - l;
- if (_grid.settings.grille) {
- var _table = '<table>';
- _table += '<tr><td> </td><td> </td><td> </td></tr>';
- // _table += '<tr><td> </td><td class="state">'+_free+'</td><td class="fr">'+_free_cell_right+'</td></tr>';
- _table += '<tr><td> </td><td> </td><td class="fr">' + _free_cell_right + '</td></tr>';
- _table += '<tr><td> </td><td class="fb">' + _free_cell_bottom + '</td><td> </td></tr>';
- _table += '</table>';
- _grid.ctx.find('.grille').append('<div class="cell-' + l + '-' + c + '">' + _table + '<div>');
- var _dom = $('.cell-' + l + '-' + c, _grid.ctx.find('.grille'));
- _dom.css({
- 'position': 'absolute',
- 'top': _row * (_grid.settings.cell_h + _grid.settings.gouttiere) + _grid.settings.cell_padding.t,
- 'left': _column * (_grid.settings.cell_w + _grid.settings.gouttiere) + _grid.settings.cell_padding.l,
- 'width': _grid.settings.cell_w,
- 'height': _grid.settings.cell_h,
- 'backgroundColor': '#00FF00',
- 'opacity': 0.6
- });
- // $('td', _dom).css({
- // 'fontSize': '8px'
- // });
- }
- this.isFree = function() { return _free; };
- this.getPos = function() { return { c: _column, l: _row }; };
- this.column = function() { return _column; };
- this.row = function() { return _row; };
- this.getAround = function() { return { right: _free_cell_right, bottom: _free_cell_bottom }; };
- this.setFull = function() {
- _free = false;
- _free_cell_bottom = -1;
- _free_cell_right = -1;
- if (_grid.settings.grille) {
- _dom.css({
- 'backgroundColor': '#0000FF'
- });
- $('.fb', _dom).html(_free_cell_bottom);
- $('.fr', _dom).html(_free_cell_right);
- }
- _propageFreeCells();
- };
- this.setFreeCellsRight = function(right) {
- if (_free) {
- // $.log('_setFreeCellRigth | _free_cell_right = ' + _free_cell_right + ' | new right = ' + right);
- _free_cell_right = right;
- if (_grid.settings.grille) $('.fr', _dom).html(_free_cell_right);
- _propageFreeCellsLeft();
- }
- };
- this.setFreeCellsBottom = function(bottom) {
- if (_free) {
- // $.log('_setFreeCellsBottom | _free_cell_bottom = ' + _free_cell_bottom + ' | new right = ' + bottom);
- _free_cell_bottom = bottom;
- if (_grid.settings.grille) $('.fb', _dom).html(_free_cell_bottom);
- _propageFreeCellsTop();
- }
- };
- function _propageFreeCells() {
- // $.log('_propageFreeCells');
- _propageFreeCellsLeft();
- _propageFreeCellsTop();
- };
- function _propageFreeCellsLeft() {
- // $.log('_propageFreeCellsLeft | _column = '+_column);
- if (_column > 0) {
- var left_cel = _cells[_row][_column - 1];
- left_cel.setFreeCellsRight(_free_cell_right + 1);
- }
- };
- function _propageFreeCellsTop() {
- // $.log('_propageFreeCellsTop | _row = '+_row);
- if (_row > 0) {
- var top_cel = _cells[_row - 1][_column];
- top_cel.setFreeCellsBottom(_free_cell_bottom + 1);
- }
- };
- if (typeof Cell.initialized == "undefined") {
- Cell.prototype.infos = function() {
- $.log('cell | column = ' + this.column() + ', line = ' + this.row() + ', free = ' + this.isFree() + ', free cell right = ' + this.getAround().right + ', free cell bottom = ' + this.getAround().bottom);
- };
- Cell.initialized = true;
- }
- }; // cell()
-
- if (typeof Node.initialized == "undefined") {
- Grid.prototype.refresh = function() {
- _placeTargets();
- };
- Grid.prototype.resetPrevCell = function() {
- _setPrevCell();
- // this.prev_cell = false;
- };
- Node.initialized = true;
- }
-
-
- };
- (function($) {
- $.fn.grid = function(settings) {
- return this.each(function(index) {
- $(this).data('grid', new Grid(this, settings));
- });
- }
- })(jQuery);
|