chunyenHuang / hummusRecipe

A powerful PDF tool for NodeJS based on HummusJS.
https://hummus-recipe.s3.amazonaws.com/docs/Recipe.html
MIT License
339 stars 91 forks source link

Table header specification as array of objects #190

Closed phynweb closed 4 years ago

phynweb commented 4 years ago

Currently, the header option when setting up a table accepts an object or boolean. When we use an object, its settings apply to all column headers, but i'm facing a use case where i'd like to align different column headers differently. I have text in a column that i'd like to alight left (horizontally), and numbers in other columns that i'd like to be aligned right.

Unless i'm missing something that allows doing this, would it be possible to either specify different header settings as an array of objects, or directly specify header options on the column?

shaehn commented 4 years ago

Currently, there is no way to decide how the text in an individual header cell is to be positioned. They are all either left, centered or right aligned.

The subsequent question is how to modify the code to get the behavior that is desired? The header alignment could get tied to the data column alignment, but I am not sure if that is sufficient. Someone may want to left justify the header text and use something else for the data in the column.

Suggestions, ideas, examples welcome.

phynweb commented 4 years ago

The header alignment could get tied to the data column alignment, but I am not sure if that is sufficient. Someone may want to left justify the header text and use something else for the data in the column.

What if things remain the way they are now and we add an attribute (e.g. "alignHeaderToData") to the data column that indicates the data column alignment should override the header default setting? If this attribute is falsy everything works just the same. Something like the lines commented in the code block below from table.js?

I haven't tested it yet, and i'm just guessing colOptions and cellOptions map to header object and data column object respectively.

   if (firstTime && options.header) {
        // Display table header
        for (const column of this._layouts['_table_']) {
            let colOptions = clone(column.options.header);
            if (typeof options.header === 'object') {
                const cellOptions = getCellOptions(options.header);
                colOptions = this._merge(colOptions, clone(cellOptions));
            }
            colOptions = this._merge(colOptions, { textBox: { minHeight: headerHeight, width: column.width } });
            // Something like this? 
            // if(cellOptions.alignHeaderToData){ colOptions.cell.textAlign = cellOptions.cell.textAlign }
            this.text(column.text, column.x, currentY, colOptions);
        }
        currentY += headerHeight;
        tableHeight += headerHeight;
        rowLines.push(y + tableHeight);
    }
shaehn commented 4 years ago

Ok, I have pondered this for awhile now. I will add the suggested attribute, but will call it 'alignToData'. I am also going to add an 'hcell' attribute to the data columns so that it can be used to override the 'alignToData' attribute in the header object.

For example, if alignToData is set to 'true', the following hcell object will override it.

{
            text: 'Occupation',
            name: 'job',
            width: 100,
            color: 'red',
            size: 10,
            cell: {textAlign:'right bottom'},
            hcell: {textAlign:'center center'}
}
phynweb commented 4 years ago

Sounds good to me. You approach also has the advantage of potentially allowing other data column attributes (other than textAlign) to be applied the header if a reasonable need arises in the future.

I'll keep an eye out for the release of this feature. Thanks