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

Angular text inside textframe

Enthusiast ,
Jan 12, 2025 Jan 12, 2025

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
637
Translate
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

LEGEND , 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.pngexpand image

 

RobertatIDTasker_0-1736714897855.pngexpand image

 

And just in case:

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

 

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

RobertatIDTasker_1-1736715057805.pngexpand image

 

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

...
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.gifexpand image

- 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
...
Translate
Community Expert ,
Jan 12, 2025 Jan 12, 2025

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.

Translate
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

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.

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

@Bedazzled532 

 

Rotate TextFrame - then move points:

RobertatIDTasker_0-1736711994857.pngexpand image

 

Translate
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
LEGEND ,
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.pngexpand image

 

RobertatIDTasker_0-1736714897855.pngexpand image

 

And just in case:

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

 

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

RobertatIDTasker_1-1736715057805.pngexpand image

 

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.pngexpand image

 

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

 

RobertatIDTasker_3-1736715369781.pngexpand image

 

Translate
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
  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.
Translate
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

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

Translate
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

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.gifexpand image

- 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.gifexpand image

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

.

Translate
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

@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!).

Translate
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

@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

Translate
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
LATEST

Glad to hear it helped! 🙂

Translate
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