Skip to content
This repository has been archived by the owner on Jun 15, 2019. It is now read-only.

Commit

Permalink
compute widths/heights
Browse files Browse the repository at this point in the history
  • Loading branch information
jamestalmage committed Dec 15, 2014
1 parent 5ca7432 commit a2e4dbc
Show file tree
Hide file tree
Showing 2 changed files with 275 additions and 3 deletions.
91 changes: 88 additions & 3 deletions src/table-layout.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
var _ = require('lodash');
var Cell = require('./cell');
(function(){

var Cell = require('./cell');

function makeTableLayout(rows){
var cellRows = generateCells(rows);
expandCells(cellRows);
fillInTable(cellRows);
return cellRows;
}

Expand Down Expand Up @@ -82,8 +84,91 @@ function maxWidth(rows){
},0);
}

function iterateColumn(rows,col,fn,ctx){
for(var i = 0; i < rows.length; i++){
fn.call(ctx,rows[i][col],i);
}
}
function getCell(rows,y,x){
return rows[y][x];
}

function getCellPivot(rows,x,y){
return rows[y][x];
}

function iterateRow(rows,row,fn,ctx){
var columns = rows[row];
for(var i = 0; i < columns.length; i++){
fn.call(ctx,columns[i],i);
}
}
function maxHeight(rows){
return rows.length;
}

module.exports = {
makeTableLayout:makeTableLayout,
maxWidth:maxWidth,
fillInTable:fillInTable
};
fillInTable:fillInTable,
computeWidths:makeComputeWidths(iterateColumn,maxWidth,'colSpan','desiredWidth',getCell),
computeHeights:makeComputeWidths(iterateRow,maxHeight,'rowSpan','desiredHeight',getCellPivot)
};

})();

function makeComputeWidths(iterateColumn,maxWidth,colSpan,desiredWidth,getCell){
return function (vals,rows){
var width = maxWidth(rows);
var result = [];
var spanners = [];
for(var columnIndex = 0; columnIndex < width; columnIndex++){
if(!_.isNumber(vals[columnIndex])){
var maxDesired = 0;
iterateColumn(rows,columnIndex,function(cell,rowIndex){
if(cell[colSpan] && cell[colSpan] > 1){
spanners.push({row:rowIndex,column:columnIndex});
}
else {
maxDesired = Math.max(maxDesired,cell[desiredWidth] || 0);
}
});
result[columnIndex] = maxDesired;
}
else {
result[columnIndex] = vals[columnIndex];
iterateColumn(rows,columnIndex,function(cell,rowIndex) {
if (cell[colSpan] && cell[colSpan] > 1) {
spanners.push({row: rowIndex, column: columnIndex});
}
});
}
}
while(spanners.length){
var coords = spanners.pop();
var cell = getCell(rows,coords.row,coords.column);
var span = cell[colSpan];
var existingWidth = result[coords.column];
var editableCols = _.isNumber(vals[coords.column]) ? 0 : 1;
for(var i = 1; i < span; i ++){
existingWidth += 1 + result[coords.column + i];
if(!_.isNumber(vals[coords.column + i])){
editableCols++;
}
}
if(cell[desiredWidth] > existingWidth){
i = 0;
while(editableCols > 0 && cell[desiredWidth] > existingWidth){
if(!_.isNumber(vals[coords.column+i])){
var dif = Math.round( (cell[desiredWidth] - existingWidth) / editableCols );
existingWidth += dif;
result[coords.column + i] += dif;
editableCols--;
}
i++;
}
}
}
_.extend(vals,result);
}
}
187 changes: 187 additions & 0 deletions test/table-layout-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ describe('tableLayout', function () {
var makeTableLayout = tableLayout.makeTableLayout;
var maxWidth = tableLayout.maxWidth;
var fillInTable = tableLayout.fillInTable;
var computeWidths = tableLayout.computeWidths;
var computeHeights = tableLayout.computeHeights;
var chai = require('chai');
var expect = chai.expect;
var _ = require('lodash');
Expand Down Expand Up @@ -159,7 +161,192 @@ describe('tableLayout', function () {
['','b',{spannerFor:[1,2]}]
]);
});
});

describe('computeWidths',function() {
function mc(desiredWidth, colSpan) {
return {desiredWidth: desiredWidth, colSpan: colSpan};
}

it('finds the maximum desired width of each column', function () {
var widths = [];
var cells = [
[mc(7), mc(3), mc(5)],
[mc(8), mc(5), mc(2)],
[mc(6), mc(9), mc(1)]
];

computeWidths(widths, cells);

expect(widths).to.eql([8, 9, 5]);
});

it('won\'t touch hard coded values', function () {
var widths = [null, 3];
var cells = [
[mc(7), mc(3), mc(5)],
[mc(8), mc(5), mc(2)],
[mc(6), mc(9), mc(1)]
];

computeWidths(widths, cells);

expect(widths).to.eql([8, 3, 5]);
});

it('assumes undefined desiredWidth is 0', function () {
var widths = [];
var cells = [[{}], [{}], [{}]];
computeWidths(widths, cells);
expect(widths).to.eql([0])
});

it('takes into account colSpan and wont over expand', function () {
var widths = [];
var cells = [
[mc(10, 2), mc(5), mc(5)],
[mc(5), mc(3), mc(2)],
[mc(4), mc(2), mc(1)]
];
computeWidths(widths, cells);
expect(widths).to.eql([5, 5, 5]);
});

it('will expand rows involved in colSpan in a balanced way', function () {
var widths = [];
var cells = [
[mc(13, 2), mc(), mc(5)],
[mc(5), mc(5), mc(2)],
[mc(4), mc(2), mc(1)]
];
computeWidths(widths, cells);
expect(widths).to.eql([6, 6, 5]);
});

it('expands across 3 cols', function () {
var widths = [];
var cells = [
[mc(25, 3), mc(), mc()],
[mc(5), mc(5), mc(2)],
[mc(4), mc(2), mc(1)]
];
computeWidths(widths, cells);
expect(widths).to.eql([9, 9, 5]);
});

it('multiple spans in same table', function () {
var widths = [];
var cells = [
[mc(25, 3), mc(), mc()],
[mc(30, 3), mc(), mc()],
[mc(4), mc(2), mc(1)]
];
computeWidths(widths, cells);
expect(widths).to.eql([11, 9, 8]);
});

it('spans will only edit uneditable tables',function(){
var widths = [null, 3];
var cells = [
[mc(20,3),mc(),mc()],
[mc(4),mc(20),mc(5)]
];
computeWidths(widths, cells);
expect(widths).to.eql([7,3,8])
});

it('spans will only edit uneditable tables - first column uneditable',function(){
var widths = [3];
var cells = [
[mc(20,3),mc(), mc()],
[mc(4), mc(3), mc(5)]
];
computeWidths(widths, cells);
expect(widths).to.eql([3,7,8])
});
});

describe('computeHeights',function(){
function mc(desiredHeight,colSpan){
return {desiredHeight:desiredHeight,rowSpan:colSpan};
}

it('finds the maximum desired height of each row',function(){
var heights = [];
var cells = [
[mc(7), mc(3), mc(5)],
[mc(8), mc(5), mc(2)],
[mc(6), mc(9), mc(1)]
];

computeHeights(heights,cells);

expect(heights).to.eql([7,8,9]);
});

it('won\'t touch hard coded values',function(){
var heights = [null,3];
var cells = [
[mc(7), mc(3), mc(5)],
[mc(8), mc(5), mc(2)],
[mc(6), mc(9), mc(1)]
];

computeHeights(heights,cells);

expect(heights).to.eql([7,3,9]);
});

it('assumes undefined desiredHeight is 0',function(){
var heights = [];
var cells = [[{},{},{}]];
computeHeights(heights,cells);
expect(heights).to.eql([0])
});

it('takes into account rowSpan and wont over expand',function(){
var heights = [];
var cells = [
[mc(10,2), mc(5), mc(5)],
[mc(5), mc(3), mc(2)],
[mc(4), mc(2), mc(1)]
];
computeHeights(heights,cells);
expect(heights).to.eql([5,5,4]);
});

it('will expand rows involved in rowSpan in a balanced way',function(){
var heights = [];
var cells = [
[mc(13,2), mc(), mc(5)],
[mc(5), mc(5), mc(2)],
[mc(4), mc(2), mc(1)]
];
computeHeights(heights,cells);
expect(heights).to.eql([6,6,4]);
});

it('expands across 3 rows',function(){
var heights = [];
var cells = [
[mc(25,3), mc(5), mc(4)],
[mc(), mc(5), mc(2)],
[mc(), mc(2), mc(1)]
];
computeHeights(heights,cells);
expect(heights).to.eql([9,9,5]);
});

it('multiple spans in same table',function(){
var heights = [];
var cells = [
[mc(25,3), mc(30,3), mc(4)],
[mc(), mc(), mc(2)],
[mc(), mc(), mc(1)]
];
computeHeights(heights,cells);
expect(heights).to.eql([11,9,8]);
});
});

/**
Expand Down

0 comments on commit a2e4dbc

Please sign in to comment.