Skip to content

Text Columns

shaehn edited this page Jan 7, 2020 · 2 revisions

Layout

The layout interface provides the user with the ability to format text in columns. The user provides a layout identifier which can be either a number or string, the page positioning coordinates, and the width and height of the column. The layout identifier allows the user to tie multiple columns together so that a single (or multiple) text calls can can be used to fill/flow text into each of the columns; something like a newspaper or document layout. Following is example code producing such a text layout. Note that there are 3 calls to layout using the same layout identifier. The text will be loaded into the columns in the order of the layout calls.

const HummusRecipe = require('hummus-recipe');
const recipe = new HummusRecipe('new', 'multicolumn.pdf');
const lorem = 'Lorem ipsum dolor sit amet, ...';  // Not all shown here for simplicity.
const numbers = {color:'#781e1b', size:20};

recipe
   .createPage('letter')
    .text('Multiple layouts with auto text fill.', 100, 280,{color:'red'} )
    .arrow(175, 405, {fill:'red', rotation: 90, at:'tail', head:[10,5], shaft:[8,1]})
    .arrow(253, 620, {fill:'red', rotation:-70, at:'tail', head:[10,5], shaft:[325,1]})
    .text('1', 80,  340, numbers)
    .text('2', 80,  530, numbers)
    .text('3', 520, 430, numbers)

    .layout(2, 100, 300, 150, 100 ) // column 1
    .layout(2, 100, 430, 150, 200 ) // column 2
    .layout(2, 370, 300, 140, 280 ) // column 3

    .text(lorem, {
        layout:2,
        flow: false,
        textBox:{
            textAlign: 'justify',  
            style:{width:.5}     // provides frame around text columns
        }})
    .endPage()
    .endPDF();

See that the layout identifier is referenced by the text interface layout option. This is how the text interface is made aware of layout elements. Since text is not providing any positioning, the flow option is set to false so that another text call does not have to be made to 'turn off' text flow (text will not be emitted until flow is turned off). Now look at the picture below. The arrows depict which column is chosen to continue text population. I purposely drew the column text frames to show that the text will continue to flow out of the last column, pretty much like it does in regular text simple text boxes. Don't worry, there is an overflow option which will be discussed later to handle this situation.

If you don't need columns in multiple unique places on a page, there is a simpler way to specify the layout. The layout interface has two options, columns and gap, that can be used to divide up the given layout width and specify the distance between the given columns (gap is optional with default equal to 1/4 inch).

const HummusRecipe = require('hummus-recipe');
const recipe = new HummusRecipe('new', 'singleLayout.pdf');
const lorem = 'Lorem ipsum dolor sit amet, ...';  // Not all shown here for simplicity.

let x = 72;
let y = 52;
let id = 1;

recipe
    .createPage('letter')
    .text('Multiple columns with auto text fill using single "layout".',
       x, y-20,{color:'red'})
    .layout(id, x, y, 500, 200, {columns:3, gap: 10})
    .text(lorem, {
        layout:id,
        flow: false,
        textBox:{
            padding: 2, 
            textAlign: 'justify',  
            style:{width:.5}}})    // show text frame
    .endPage()
    .endPDF();

Text Overflow

To deal with text overflow issues, the text interface has an overflow option which is a property that refers to a user provided callback function, called and overflow notifier. The parameter to this function is called 'self' and is effectively the 'recipe' handle obtained from a 'new HummusRecipe' call. When the given text can no longer fit in the originally defined column layout, the notifier is called. The user can then take various actions depending on their need, say stopping text processing, continue text processing at a new position on the page, or on another page altogether. The following describes the return values the overflow notification program can provide to deal with the text overflow.

So, when the return value of the overflow notifier is the boolean value true, the text processing will stop in its tracks, exiting the text interface. When the return value is an object containing a layout property, it is used to indicate which layout should be used to finish text processing (So the value of layout better be a layout identifier). The return value may also be an object containing a column property, with a numeric value indicating the index of the current layout column to use (0 is column 1, 1 is column 2, etc.), or a two element array indicating a new x,y position for the current layout.

Following are some sample text overflow handlers.

// Halt text processing
const stop = () => { return true; };

// End current page, start new page, use 'page' layout on new page
const nextPage = (self) => {
    self.endPage();
    self.createPage('letter');
    return {layout: 'page'};
};

// Position current column layout to new position on page
let x = 60;
let y = 60;
const nextRow = (self) => { 
    y += 100;
    return {column:[x,y]}
};

Following shows code that uses the overflow option to push text onto a following page.

const HummusRecipe = require('hummus-recipe');
const recipe = new HummusRecipe('new', 'overflow.pdf');
const lorem = 'Lorem ipsum dolor sit amet, ...';  // Not all shown here for simplicity.

// Text overflow handler
const nextPage = (self) => {
    self.endPage();
    self.createPage('letter');
    return {layout: 'newPage'};
};

let x = 72;
let y = 52;

recipe
    .createPage('letter')
    .layout(1, 100, 600, 300, 150, {columns:2, gap:10})
    .layout('newPage', x, y+50, 500, 150, {columns: 3, gap: 10})
    .text('... continuing onto\n   next page...', 420, 710, {color:'red'})
    .text ('Starting on this page with this layout...', 101, 580, {color:'red'})
    .text(lorem, 101, 600, {
        layout:1, 
        flow:false, 
        overflow: nextPage,  // put overflow on following page
        textBox:{padding: 2,
            style:{width:.5}}})
    .text('... finishing here with new layout', x, y, {color:'red'})
    .endPage()
    .endPDF();

Which produces the following:

Clone this wiki locally