var _ = require('lodash');
var Cell = require('./cell');
var RowSpanCell = Cell.RowSpanCell;
var ColSpanCell = Cell.ColSpanCell;
(function(){
function layoutTable(table){
_.forEach(table,function(row,rowIndex){
_.forEach(row,function(cell,columnIndex){
cell.y = rowIndex;
cell.x = columnIndex;
for(var y = rowIndex; y >= 0; y--){
var row2 = table[y];
var xMax = (y === rowIndex) ? columnIndex : row2.length;
for(var x = 0; x < xMax; x++){
var cell2 = row2[x];
while(cellsConflict(cell,cell2)){
cell.x++;
}
}
}
});
});
}
function maxWidth(table) {
var mw = 0;
_.forEach(table, function (row) {
_.forEach(row, function (cell) {
mw = Math.max(mw,cell.x + (cell.colSpan || 1));
});
});
return mw;
}
function maxHeight(table){
return table.length;
}
function cellsConflict(cell1,cell2){
var yMin1 = cell1.y;
var yMax1 = cell1.y - 1 + (cell1.rowSpan || 1);
var yMin2 = cell2.y;
var yMax2 = cell2.y - 1 + (cell2.rowSpan || 1);
var yConflict = !(yMin1 > yMax2 || yMin2 > yMax1);
var xMin1= cell1.x;
var xMax1 = cell1.x - 1 + (cell1.colSpan || 1);
var xMin2= cell2.x;
var xMax2 = cell2.x - 1 + (cell2.colSpan || 1);
var xConflict = !(xMin1 > xMax2 || xMin2 > xMax1);
return yConflict && xConflict;
}
function conflictExists(rows,x,y){
var i_max = Math.min(rows.length-1,y);
var cell = {x:x,y:y};
for(var i = 0; i <= i_max; i++){
var row = rows[i];
for(var j = 0; j < row.length; j++){
if(cellsConflict(cell,row[j])){
return true;
}
}
}
return false;
}
function allBlank(rows,y,xMin,xMax){
for(var x = xMin; x < xMax; x++){
if(conflictExists(rows,x,y)){
return false;
}
}
return true;
}
function addRowSpanCells(table){
_.forEach(table,function(row,rowIndex){
_.forEach(row,function(cell){
for(var i = 1; i < cell.rowSpan; i++){
var rowSpanCell = new RowSpanCell(cell);
rowSpanCell.x = cell.x;
rowSpanCell.y = cell.y + i;
rowSpanCell.colSpan = cell.colSpan;
insertCell(rowSpanCell,table[rowIndex+i]);
}
});
});
}
function addColSpanCells(cellRows){
for(var rowIndex = cellRows.length-1; rowIndex >= 0; rowIndex--) {
var cellColumns = cellRows[rowIndex];
for (var columnIndex = 0; columnIndex < cellColumns.length; columnIndex++) {
var cell = cellColumns[columnIndex];
for (var k = 1; k < cell.colSpan; k++) {
var colSpanCell = new ColSpanCell();
colSpanCell.x = cell.x + k;
colSpanCell.y = cell.y;
cellColumns.splice(columnIndex + 1, 0, colSpanCell);
}
}
}
}
function insertCell(cell,row){
var x = 0;
while(x < row.length && (row[x].x < cell.x)) {
x++;
}
row.splice(x,0,cell);
}
function fillInTable(table){
var h_max = maxHeight(table);
var w_max = maxWidth(table);
for(var y = 0; y < h_max; y++){
for(var x = 0; x < w_max; x++){
if(!conflictExists(table,x,y)){
var opts = {x:x,y:y,colSpan:1,rowSpan:1};
x++;
while(x < w_max && !conflictExists(table,x,y)){
opts.colSpan++;
x++;
}
var y2 = y + 1;
while(y2 < h_max && allBlank(table,y2,opts.x,opts.x+opts.colSpan)){
opts.rowSpan++;
y2++;
}
var cell = new Cell(opts);
cell.x = opts.x;
cell.y = opts.y;
insertCell(cell,table[y]);
}
}
}
}
function generateCells(rows){
return _.map(rows,function(row){
if(!_.isArray(row)){
var key = Object.keys(row)[0];
row = row[key];
if(_.isArray(row)){
row = row.slice();
row.unshift(key);
}
else {
row = [key,row];
}
}
return _.map(row,function(cell){
return new Cell(cell);
});
});
}
function makeTableLayout(rows){
var cellRows = generateCells(rows);
layoutTable(cellRows);
fillInTable(cellRows);
addRowSpanCells(cellRows);
addColSpanCells(cellRows);
return cellRows;
}
module.exports = {
makeTableLayout: makeTableLayout,
layoutTable: layoutTable,
addRowSpanCells: addRowSpanCells,
maxWidth:maxWidth,
fillInTable:fillInTable,
computeWidths:makeComputeWidths('colSpan','desiredWidth','x',1),
computeHeights:makeComputeWidths('rowSpan','desiredHeight','y',1)
};
})();
function makeComputeWidths(colSpan,desiredWidth,x,forcedMin){
return function(vals,table){
var result = [];
var spanners = [];
_.forEach(table,function(row){
_.forEach(row,function(cell){
if((cell[colSpan] || 1) > 1){
spanners.push(cell);
}
else {
result[cell[x]] = Math.max(result[cell[x]] || 0, cell[desiredWidth] || 0, forcedMin);
}
});
});
_.forEach(vals,function(val,index){
if(_.isNumber(val)){
result[index] = val;
}
});
//_.forEach(spanners,function(cell){
for(var k = spanners.length - 1; k >=0; k--){
var cell = spanners[k];
var span = cell[colSpan];
var col = cell[x];
var existingWidth = result[col];
var editableCols = _.isNumber(vals[col]) ? 0 : 1;
for(var i = 1; i < span; i ++){
existingWidth += 1 + result[col + i];
if(!_.isNumber(vals[col + i])){
editableCols++;
}
}
if(cell[desiredWidth] > existingWidth){
i = 0;
while(editableCols > 0 && cell[desiredWidth] > existingWidth){
if(!_.isNumber(vals[col+i])){
var dif = Math.round( (cell[desiredWidth] - existingWidth) / editableCols );
existingWidth += dif;
result[col + i] += dif;
editableCols--;
}
i++;
}
}
}
_.extend(vals,result);
for(var j = 0; j < vals.length; j++){
vals[j] = Math.max(forcedMin, vals[j] || 0);
}
};
}
|