• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Fit Table using Frame To Content

Participant ,
Feb 10, 2023 Feb 10, 2023

Copy link to clipboard

Copied

Hi,

 

I intended to fit the table to the pages in the InDesign document. In spite of this, it exceeds that particular page. I have attached the same document and the script I used to fit the table.  

 

https://drive.google.com/drive/folders/166t-M93Jjm4Dpmp3IWo8Zc6u1kKDiXPN?usp=sharing

-Monisha
TOPICS
How to , Scripting

Views

625

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 10, 2023 Feb 10, 2023

Copy link to clipboard

Copied

Hi @MonishaRajendran, I had a look at your sample file and script. What exactly are you trying to do to the table? Scale it down to fit margins width? Adjust every column width to fit margins width?

 

When you are asking for help with a script it is often helpful for you to post a screenshot of your desired result, also. That way we don't have to guess what you mean.

- Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 10, 2023 Feb 10, 2023

Copy link to clipboard

Copied

Hi, 

My first goal is to fit the table into the frame. Currently, I am unable to fit the table inside the frame. I have attached the screenshot that I wanted to achieve using my script.

 

MonishaRajendran_0-1676024567278.png

 

-Monisha

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 11, 2023 Feb 11, 2023

Copy link to clipboard

Copied

Hi @MonishaRajendran, I had a look at your script, but I didn't quite understand your approach. Instead I have written a script to do an "autofit" type of operation on the table, which I think might be what you want.

Here is your sample document:

Screenshot-2023-02-11-at-20.56.24.gif

Note that I put line breaks in a couple of the header cells to match your desired result screenshot. Do this before running the script. Also make sure that the table isn't overset (ie. make sure the end of the table is visible in a text frame).

- Mark

 

The script:

 

/**
 * Auto-fit Selected Table
 * @author m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/fit-table-using-frame-to-content/m-p/13569385
 */
function main() {

    app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

    var selectedTable = getTable(app.selection[0]);

    if (
        selectedTable == undefined
        || !selectedTable.isValid
    ) {
        alert('Please select a table or inside a table and run script again.');
        return;
    }

    autoFitTable(selectedTable);

}


app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Auto-fit Table');


/**
 * Auto-fits the table: attempts to minimize
 * the width of each column, without changing
 * existing line breaks, similar to Microsoft
 * Excel's auto-fit function.
 * @author m1b
 * @version 2023-02-12
 * @param {Table} table - an Indesign Table.
 * @param {Number} [minimumWidth] - the minimum desired table width, in pts (default: 0).
 */
function autoFitTable(table, minimumWidth) {

    minimumWidth = minimumWidth || 0;

    var bounds = getCellBounds(table.cells[0], 'geometricBounds'),
        tableWidth = 0,
        columnData = [];

    // in this loop we collect all the
    // measurements we'll need later on
    columnsLoop:
    for (var c = 0, left = bounds[1]; c < table.columns.length; c++) {

        var column = table.columns[c],
            columnCells = column.cells,
            columnWidth = Number(table.columns[c].width);

        columnData[c] = {
            left: left,
            leftInset: Math.max.apply(null, columnCells.everyItem().textLeftInset),
            right: left + columnWidth,
            rightInset: Math.max.apply(null, columnCells.everyItem().textRightInset),
            maxLineMeasure: -Infinity,
            maxLineIndex: undefined,
            maxLineCellID: undefined,
            maxLineContents: undefined,
            width: columnWidth,
        };

        cellsLoop:
        for (var i = 0; i < columnCells.length; i++) {

            linesLoop:
            for (var j = 0; j < columnCells[i].lines.length; j++) {

                var cell = columnCells[i];

                if (cell.texts[0].parentTextFrames.length == 0) {
                    alert('Some rows of this table appear to be overset. Please fix and try again.');
                    return;
                }

                var line = cell.lines[j],
                    start = line.insertionPoints[0].horizontalOffset,
                    end = start;

                if (line.insertionPoints.length == 1)
                    end = line.insertionPoints[-1].horizontalOffset;
                else
                    end = Math.max(line.insertionPoints[-1].horizontalOffset, line.insertionPoints[-2].horizontalOffset);

                var lineMeasure = end - start;

                if (lineMeasure > columnData[c].maxLineMeasure) {
                    columnData[c].maxLineMeasure = lineMeasure;
                    columnData[c].maxLineIndex = j;
                    columnData[c].maxLineCellID = cell.id;
                    columnData[c].maxLineContents = line.contents;
                }

            }

        }

        // set the column width
        columnData[c].width = (columnData[c].maxLineMeasure + columnData[c].leftInset + columnData[c].rightInset);

        // advance for the next column
        left += columnWidth;

    }

    // this loop is to actually change the column widths
    for (var c = table.columns.length - 1; c >= 0; c--) {

        table.columns[c].width = columnData[c].width;

        // If the longest line's contents no longer matches,
        // gradually open up the column again until it matches.
        // This is mostly to fix hyphenated words no longer
        // being hyphenated at the new width.

        var cell = table.cells.itemByID(columnData[c].maxLineCellID),
            line = cell.lines[columnData[c].maxLineIndex],
            counter = 100; // count down for safety

        while (
            line.contents !== columnData[c].maxLineContents
            && counter--
        ) {
            table.columns[c].width += 0.5;
            line = cell.lines[columnData[c].maxLineIndex];
        }

        // update the column data, in case the width changes
        columnData[c].width = Number(table.columns[c].width);

        // update the table width
        tableWidth += columnData[c].width;

    }

    if (minimumWidth > tableWidth) {

        // take the edge strokes into account so that
        // a minimum width means the table will fit exactly
        // in a textframe of that size.
        var leftEdgeStrokeWeight = Math.max.apply(null, (table.columns.item(0).cells.everyItem().leftEdgeStrokeWeight)),
            rightEdgeStrokeWeight = Math.max.apply(null, (table.columns.item(-1).cells.everyItem().rightEdgeStrokeWeight));
        minimumWidth -= (leftEdgeStrokeWeight / 2) + (rightEdgeStrokeWeight / 2);

        // the amount to add to each column
        var adjustment = (minimumWidth - tableWidth) / table.columns.length;

        // make the adjustment
        for (var c = table.columns.length - 1; c >= 0; c--)
            table.columns[c].width += adjustment;

    }

};


/**
 * Returns the geometricBounds of the cell;
 * @author m1b
 * @version 2023-02-06
 * @param {Cell} cell - an Indesign Table Cell.
 * @param {String} [boundsType] - can be 'geometricBounds' or 'visibleBounds' (default: 'geometricBounds').
 * @returns {Array<Number>}
 */
function getCellBounds(cell, boundsType) {

    app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

    boundsType = boundsType || 'geometricBounds';

    if (!cell.hasOwnProperty('index'))
        throw Error('getCellBounds failed: bad cell parameter.');

    var table = cell.parent;

    while (
        // table.hasOwnProperty('parent')
        table.constructor.name != 'Table'
    )
        table = table.parent;

    var cellIndex = cell.index,
        tableIndex = indexOf(table, table.storyOffset.parentTextFrames[0].tables),

        // duplicate the textframe because we are going to convert the cell
        dupTextFrame = table.storyOffset.parentTextFrames[0].duplicate(),
        dupCell = dupTextFrame.tables[tableIndex].cells[cellIndex];

    // convert cell to graphic, so we can get the bounds
    dupCell.convertCellType(CellTypeEnum.GRAPHIC_TYPE_CELL);
    var bounds = dupCell.rectangles[0].geometricBounds;

    // clean up
    dupTextFrame.remove();

    // add strokeWidths
    if (boundsType === 'visibleBounds') {
        bounds[0] -= cell.topEdgeStrokeWeight;
        bounds[1] -= cell.leftEdgeStrokeWeight;
        bounds[2] += cell.bottomEdgeStrokeWeight;
        bounds[3] += cell.rightEdgeStrokeWeight;
    }
    else if (boundsType === 'geometricBounds') {
        bounds[0] -= cell.topEdgeStrokeWeight / 2;
        bounds[1] -= cell.leftEdgeStrokeWeight / 2;
        bounds[2] += cell.bottomEdgeStrokeWeight / 2;
        bounds[3] += cell.rightEdgeStrokeWeight / 2;
    }

    return bounds;

};


/**
 * Returns index of obj in arr.
 * Returns -1 if not found.
 * @param {any} obj
 * @param {Array} arr
 * @returns {Number}
 */
function indexOf(obj, arr) {
    for (var i = 0; i < arr.length; i++)
        if (arr[i] === obj)
            return i;
    return -1;
};


/**
 * Attempts to return a Cell, given an object.
 * @author m1b
 * @version 2023-02-06
 * @param {InsertionPoint|Text|Cells|Table} obj - an object related to a Cell.
 * @returns {Cell}
 */
function getTable(obj) {

    if (obj == undefined)
        return;

    if (obj.constructor.name == 'Cell')
        return obj.parent;

    if (obj.parent.constructor.name == 'Cell')
        return obj.parent.parent;

    if (
        obj.hasOwnProperty('cells')
        && obj.cells.length > 0
    )
        return obj.cells[0].parent;

};

 

Edit 2023-02-12: I've added a "minimumWidth" parameter. If you use this, then the script will first auto-fit, so there is no wasted space, then will extend every column by the same amount so that the table matches the minimumWidth amount.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 15, 2023 Feb 15, 2023

Copy link to clipboard

Copied

Hi,

I need to fit the table to the page but as of now I can't able to fit the table using the script I have used.

 

 

-Monisha

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 15, 2023 Feb 15, 2023

Copy link to clipboard

Copied

LATEST

Hi @MonishaRajendran, I'm afraid your script is too complicated for me to debug. I suggest you either create a simple version that just has the section that you want to ask about, or look at my script and see how I did it. Or maybe I am not understanding your needs at all, in which case my apologies, and please try to be much more specific with your question.

- Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines