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

Angular text inside textframe

Enthusiast ,
Jan 12, 2025 Jan 12, 2025

Copy link to clipboard

Copied

Hi

I have a complicated textframe scenario.

I know there is a way to do angular text in Indesign. I have done simple versions. I forgot the method. It was something to do with direct selection tool and skewing.

 

How can I achieve this layout. For some reason it is not working for me.

I have marked the required textframe output with red color.

Thanks

TOPICS
How to , Scripting

Views

325

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

correct answers 2 Correct answers

Community Expert , Jan 12, 2025 Jan 12, 2025

And here is a "one liner":

 

// (c) id-tasker.com
// CopyPath.jsx
app.selection[0].paths[0].entirePath=app.selection[1].paths[0].entirePath;

 

 

Duplicate and rotate original TextFrame - or skew it or both(*) - then select it and then select "source" TextFrame - selection order is very important - then run this script:

 

RobertatIDTasker_1-1736714731159.png

 

RobertatIDTasker_0-1736714897855.png

 

And just in case:

https://creativepro.com/how-to-install-scripts-in-indesign/

 

(*) if you skew it - text will get deformed:

RobertatIDTasker_1-1736715057805.png

 

It's a "quick and dirty" solution - copies

...

Votes

Translate

Translate
Community Expert , Jan 13, 2025 Jan 13, 2025

Hi @Bedazzled532, you've already got good answers here, but I know that you are a scripter, so I wanted to turn this idea into a script for you to try. It is an extension of Robert's idea. Select textframe(s) and run script, and enter the rotation amount.

demo.gif

- Mark

 

 

 

/**
 * @file Rotate Text In Frame.js
 *
 * Rotates the text in the selected text frame(s)
 * without rotating the frame(s).
 *
 * @author m1b
 * @version 2025-01-15
 * @discussion https://community.adobe.com/t5/indesign-discussion
...

Votes

Translate

Translate
Community Expert ,
Jan 12, 2025 Jan 12, 2025

Copy link to clipboard

Copied

I don't think there's any way to achieve this except rotating the text frame. For a layout like you show, a combination of an outline frame and then one or more text frames, rotated and positioned within that outline, is the only simple solution.

 

To go "around the corner" you could use two text frames or one shaped into an L.

 

Skewing is only orthogonal — left-right. It won't tilt content.


┋┊ InDesign to Kindle (& EPUB): A Professional Guide, v3.1 ┊ (Amazon) ┊┋

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 ,
Jan 12, 2025 Jan 12, 2025

Copy link to clipboard

Copied

I vaguely recall that it's somewhat easier to do in Illustrator, but I don't recall the details. Another solution that achieves this effect in InDesign, at the cost of a fair number of clicks, would be something like this:

 

  • Draw one line at the correct angle with the Line tool
  • Convert it to Text on Path 
  • Use Edit -> Step & Repeat to make lots of angled Text-on-Paths with appropriate spacing
  • Arrange them in your L-shape
  • Thread them all manually (that's the above-cited "fair number of clicks")
  • Fill with your text
  • Select all the text, right-click and choose Text on Path Options
  • Add a bit of skew from the Text on Path Options (if your design needs to match that JPEG sample, I'm fairly certain that at least some skew was applied in that sample)

 

I've attached a minimal example in IDML for demonstration purposes.

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 ,
Jan 12, 2025 Jan 12, 2025

Copy link to clipboard

Copied

@Bedazzled532 

 

Rotate TextFrame - then move points:

RobertatIDTasker_0-1736711994857.png

 

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 ,
Jan 12, 2025 Jan 12, 2025

Copy link to clipboard

Copied

And here is a "one liner":

 

// (c) id-tasker.com
// CopyPath.jsx
app.selection[0].paths[0].entirePath=app.selection[1].paths[0].entirePath;

 

 

Duplicate and rotate original TextFrame - or skew it or both(*) - then select it and then select "source" TextFrame - selection order is very important - then run this script:

 

RobertatIDTasker_1-1736714731159.png

 

RobertatIDTasker_0-1736714897855.png

 

And just in case:

https://creativepro.com/how-to-install-scripts-in-indesign/

 

(*) if you skew it - text will get deformed:

RobertatIDTasker_1-1736715057805.png

 

It's a "quick and dirty" solution - copies ONLY FIRST Path - but can be easily modified to copy all Paths.

 

And will work with graphic frames:

RobertatIDTasker_2-1736715321562.png

 

But with those - it's quicker to just select image insde and rotate:

 

RobertatIDTasker_3-1736715369781.png

 

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 ,
Jan 13, 2025 Jan 13, 2025

Copy link to clipboard

Copied

  1. Draw the final form without the text.
  2. Draw a small rectangle, a text frame and turn it to  the angle you want it at the end.
  3. Select both, Object > Pathfinder > add
  4. Fill it with the text.

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
Enthusiast ,
Jan 13, 2025 Jan 13, 2025

Copy link to clipboard

Copied

@Robert at ID-Tasker @Willi Adelberger @Joel Cherney @James Gifford—NitroPress Thanks to all of you. All your instructuions helped. 

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 ,
Jan 13, 2025 Jan 13, 2025

Copy link to clipboard

Copied

Hi @Bedazzled532, you've already got good answers here, but I know that you are a scripter, so I wanted to turn this idea into a script for you to try. It is an extension of Robert's idea. Select textframe(s) and run script, and enter the rotation amount.

demo.gif

- Mark

 

 

 

/**
 * @file Rotate Text In Frame.js
 *
 * Rotates the text in the selected text frame(s)
 * without rotating the frame(s).
 *
 * @author m1b
 * @version 2025-01-15
 * @discussion https://community.adobe.com/t5/indesign-discussions/angular-text-inside-textframe/m-p/15085031
 */
function main() {

    var settings = {
        // rotation amount in degrees (negative is clockwise)
        rotationAngle: 30,

        // whether to rotate the columns gutters, or split columns
        // into multiple frames before rotating text
        rotateColumnGutters: false,

        showUI: true,

    };

    var doc = app.activeDocument,
        items = getTextFrames(doc.selection);

    if (0 === items.length)
        return alert('Please select one or more text frames and try again.');

    // handle ui
    if (settings.showUI) {

        var result = ui(settings);

        if (
            2 === result
            || isNaN(settings.rotationAngle)
        )
            // user cancelled
            return;

    }

    // rotate each item
    for (var i = 0; i < items.length; i++) {

        if (
            !settings.rotateColumnGutters
            && items[i].textFramePreferences.textColumnCount > 1
        ) {
            // add the columns as separate frames
            items.splice.apply(items, [i, 1].concat(separateTextColumns(items[i])));
        };

        rotateTextInFrame(items[i], settings.rotationAngle);

    }

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Rotate Text In Frame');

/**
 * Rotates a text frame, but keeps it's path points in place.
 * @author m1b
 * @version 2025-01-13
 * @param {TextFrame} frame - the text frame to rotate.
 * @param {Number} angle - the counter-clockwise angle of rotation, in degrees.
 */
function rotateTextInFrame(frame, angle) {

    if ('function' !== typeof frame.transform)
        // not right kind of object
        return;

    // store paths and pathpoints' properties
    var dupPaths = [];

    for (var i = 0; i < frame.paths.length; i++) {

        dupPaths[i] = [];
        var dupPath = dupPaths[i];

        for (var j = 0; j < frame.paths[i].pathPoints.length; j++)
            dupPath[j] = frame.paths[i].pathPoints[j].properties;

    }

    // rotate the frame
    frame.transform(
        CoordinateSpaces.PARENT_COORDINATES,
        [[0, 0], BoundingBoxLimits.GEOMETRIC_PATH_BOUNDS, CoordinateSpaces.INNER_COORDINATES],
        app.transformationMatrices.add(undefined, undefined, undefined, angle)
    );

    // re-assign the original path points properties
    for (var i = 0; i < frame.paths.length; i++)
        for (var j = 0; j < frame.paths[i].pathPoints.length; j++)
            frame.paths[i].pathPoints[j].properties = dupPaths[i][j];

};

/**
 * Returns an array of text frames
 * derived from the items supplied.
 * @param {Array<DOM Item>} items - the items.
 * @returns {Array<TextFrame>}
 */
function getTextFrames(items) {

    if (!items.length)
        return [];

    var textFrames = [];

    for (var i = 0; i < items.length; i++) {

        var item = items[i];

        if ('TextFrame' === item.constructor.name)
            textFrames.push(item);

        else if (
            item.hasOwnProperty('parentTextFrames')
            && item.parentTextFrames.length > 0
        )
            textFrames.push(item.parentTextFrames[0]);

        else if (
            item.hasOwnProperty('textFrames')
            && item.textFrames.length > 0
        )
            textFrames.push(item.textFrames.everyItem().getElements());

    }

    return textFrames;

};

/**
 * Splits a multi-column text frame
 * into separate text frames.
 * @author m1b
 * @version 2023-08-21
 * @param {TextFrame} textFrame - the text frame to split.
 */
function separateTextColumns(textFrame) {

    if (
        textFrame == undefined
        || textFrame.constructor.name != 'TextFrame'
        || textFrame.textFramePreferences.textColumnCount < 2
    )
        return;

    app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

    var columnCount = textFrame.textFramePreferences.textColumnCount,
        columnGutter = textFrame.textFramePreferences.textColumnGutter,
        b = textFrame.geometricBounds,
        frameWidth = b[3] - b[1],
        inset = textFrame.textFramePreferences.insetSpacing,
        frames = [textFrame];

    // calculate the column width
    var columnWidth = (frameWidth - inset[1] - inset[3] - (columnGutter * (columnCount - 1))) / columnCount;

    // adjust the textFrame to the width of one column
    // also remove inset spacing, if any
    textFrame.textFramePreferences.textColumnCount = 1;
    textFrame.textFramePreferences.insetSpacing = [inset[0], 0, inset[2], 0];
    textFrame.geometricBounds = [b[0], b[1] + inset[1], b[2], b[1] + inset[1] + columnWidth];

    // now add the other column frames and thread them
    for (var i = 1; i < columnCount; i++) {

        var frame = frames[i - 1].duplicate(undefined, [(columnWidth + columnGutter), 0]);

        frame.parentStory.contents = '';
        frames[i - 1].nextTextFrame = frame;
        frames.push(frame);

    }

    return frames;

};

/**
 * UI for Rotate Text In Frame script.
 * @author m1b
 * @version 2025-01-13
 * @param {Object} settings
 * @param {Array<String>} settings.before - the before array of strings.
 * @param {Array<String>} [settings.description] - a short description of what's going to happen (default: none).
 * @returns {1|2} - ScriptUI result code (1 = good, 2 = user cancelled).
 */
function ui(settings) {

    var w = new Window("dialog", 'Rotate Text In Frame'),

        content = w.add("group {orientation:'column', margins:[10,10,10,0] }"),
        group = content.add("group {orientation:'row', alignment:['left','top'], alignChildren:['left','top'], margins:[0,0,0,0] }"),
        label = group.add("statictext {text:'Rotation Angle', justify: 'left', alignment:['left','center']}"),
        rotationField = group.add('edittext {preferredSize: [60,-1], text:"' + settings.rotationAngle + '"}'),
        label = group.add('statictext {text:"\u00B0", justify: "left"}'),
        note = content.add('statictext {text:"Negative angles are clockwise.", justify: "left", alignment:["left","top"]}'),

        extraControls = content.add("group {orientation:'column', alignChildren: ['left','center'] alignment:['left','top'], margins:[0,25,0,0] }"),
        rotateGuttersCheckBox = extraControls.add("CheckBox { text: 'Rotate Column Gutters', alignment: ['left','top'] }"),

        bottomUI = w.add("group {orientation:'row', alignment:['fill','top'], margins: [0,20,0,0] }"),
        buttons = bottomUI.add("group {orientation:'row', alignment:['right','top'], alignChildren:'right' }"),
        cancelButton = buttons.add('button', undefined, 'Cancel', { name: 'cancel' }),
        okButton = buttons.add('button', undefined, 'Rotate', { name: 'ok' });

    // update UI
    rotationField.text = settings.rotationAngle || 30;
    rotateGuttersCheckBox.value = false !== settings.rotateColumnGutters;

    okButton.onClick = function () {

        var rotationAngle = Number(rotationField.text);

        if (isNaN(rotationAngle))
            return;

        // update settings
        settings.rotationAngle = rotationAngle;
        settings.rotateColumnGutters = rotateGuttersCheckBox.value;

        w.close(1);

    };

    w.center();
    return w.show();

};

 

 

Edit 2025-01-14: added Robert's suggestion to use `entirePath` property and also to handle compound paths.

 

Edit 2025-01-15: minor issue, but I changed the pathpoint assignment again, because `entirePath` can't capture the `pointType` property, which may be important for some paths. Also I added a feature to choose what to do with multiple columns: rotate the gutter(s), or not. It gives you this choice:

demo2.gif

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 ,
Jan 13, 2025 Jan 13, 2025

Copy link to clipboard

Copied

.

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 ,
Jan 13, 2025 Jan 13, 2025

Copy link to clipboard

Copied

@Robert at ID-Tasker thanks, I was able to use `entirePath` (I didn't use it originally because I didn't think this would work on bezier curves but it does!) and your suggestion of handling multiple paths was also sensible (I was being lazy!).

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
Enthusiast ,
Jan 13, 2025 Jan 13, 2025

Copy link to clipboard

Copied

@m1b Thank you so much Mark. It really helped.  Really appreciate the help. It will save me time.

I have one more upcoming post with some weird kind of requirement and seems like scripting will help.

Thanks

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 06, 2025 Feb 06, 2025

Copy link to clipboard

Copied

LATEST

Glad to hear it helped! 🙂

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