Skip to main content
m1b
Community Expert
Community Expert
January 18, 2022
Answered

Script API for stroke align dashes to path corners?

  • January 18, 2022
  • 5 replies
  • 1239 views

Hi all, does anybody know if, via ExtendScript, we can determine if a stroked path item is "aligning to corners and path ends, adjusting lengths to fit"? I'm talking about this option in the UI:

 

I couldn't find anything in the object model, but might have missed something. If it turns out that this property isn't exposed via the API, I can probably make a hack that analyzes the outlined stroke to check, but I'd rather not have to. Thanks for looking.

- Mark

 

This topic has been closed for replies.
Correct answer m1b

I've written a function that returns true when the item has dashes aligned. Figured I should post it here for anyone who happens along later.

- Mark

 

Edit: now works with compoundPaths.

 

 

 

/*

    Get Stroke Dashes Alignment Style
    For Adobe Illustrator 2022

    by m1b,
    here: https://community.adobe.com/t5/illustrator-discussions/script-api-for-stroke-align-dashes-to-path-corners/td-p/12689425

    This function returns true if the item's stroke
    dash alignment is set to 'aligning to corners
    and path ends, adjusting lengths to fit'.

    At this time there is no API access to this setting
    so this method is quite hacky: it converts a model
    duplicate of the item into outline stroke
    and counts the number of dashes.

    `item` must be a pathItem or compoundPathItem
    and must have a dashed stroke.

*/


alert(strokeDashesAreAligned(app.activeDocument.selection[0]));


function strokeDashesAreAligned(item, keepSelection) {
    if (
        item == undefined || !(item.hasOwnProperty('pathPoints') || item.hasOwnProperty('pathItems'))
    ) return;

    var dashesAreAligned;

    // we only worry about storing the
    // selection because the outline
    // stroke test later destroys it
    keepSelection = keepSelection || true;
    var doc = getParentDocument(item),
        selectedItems = [];
    if (keepSelection) {
        for (var i = 0; i < doc.selection.length; i++) {
            selectedItems.push(doc.selection[i]);
        }
    }

    if (item.typename == 'CompoundPathItem') {

        // COMPOUND PATH ITEM

        if (
            item.pathItems[0].stroked == false
            || item.pathItems[0].strokeDashes.length == 0
        ) return;

        // duplicate
        var dup = item.duplicate();
        doc.selection = null;
        dup.selected = true;
        // uncompound
        app.executeMenuCommand('noCompoundPath');
        // collect the resulting path items
        var pathItemsToDelete = [];
        for (var i = 0; i < doc.selection.length; i++)
            pathItemsToDelete.push(doc.selection[i]);

        // get result on just the first path
        dashesAreAligned = strokeDashesAreAligned(pathItemsToDelete[0], keepSelection);

        // remove uncompounded duplicates
        for (var i = pathItemsToDelete.length - 1; i >= 0; i--)
            pathItemsToDelete[i].remove();

    } else {

        // PATH ITEM

        if (
            item.stroked == false
            || item.strokeDashes.length == 0
        ) return;

        // duplicate item
        var modelPathItem = item.duplicate();

        // standardise model
        var standardPoints = [[0, 0], [3, 0]];
        modelPathItem.filled = false;
        modelPathItem.stroked = true;
        modelPathItem.strokeWidth = 0.1;
        modelPathItem.strokeDashes = [1];
        modelPathItem.closed = false;
        for (var i = modelPathItem.pathPoints.length - 1; i >= 0; i--) {
            if (i >= standardPoints.length) {
                modelPathItem.pathPoints[i].remove();
            } else {
                modelPathItem.pathPoints[i].anchor = standardPoints[i];
                modelPathItem.pathPoints[i].leftDirection = standardPoints[i];
                modelPathItem.pathPoints[i].rightDirection = standardPoints[i];
            }
        }

        // convert to outlined stroke
        // must clear selection to do this
        doc.selection = null;
        modelPathItem.selected = true;
        app.executeMenuCommand('OffsetPath v22');
        modelPathItem = doc.selection[0];

        // the model, once converted to compoundPathItem,
        // will have 2 pathItems if dashes are not aligned,
        // or 3 if dashes are aligned
        var dashesAreAligned = modelPathItem.pathItems.length == 3;

        // remove the model and reselect the original
        modelPathItem.remove();

        // re-instate inital selection
        for (var i = 0; i < selectedItems.length; i++) {
            selectedItems[i].selected = true;
        }
    }

    return dashesAreAligned;
}

function getParentDocument(obj) {
    while (obj.hasOwnProperty('parent') && obj.constructor.name != 'Document')
        obj = obj.parent;
    return obj;
}

 

 

5 replies

m1b
Community Expert
m1bCommunity ExpertAuthorCorrect answer
Community Expert
January 23, 2022

I've written a function that returns true when the item has dashes aligned. Figured I should post it here for anyone who happens along later.

- Mark

 

Edit: now works with compoundPaths.

 

 

 

/*

    Get Stroke Dashes Alignment Style
    For Adobe Illustrator 2022

    by m1b,
    here: https://community.adobe.com/t5/illustrator-discussions/script-api-for-stroke-align-dashes-to-path-corners/td-p/12689425

    This function returns true if the item's stroke
    dash alignment is set to 'aligning to corners
    and path ends, adjusting lengths to fit'.

    At this time there is no API access to this setting
    so this method is quite hacky: it converts a model
    duplicate of the item into outline stroke
    and counts the number of dashes.

    `item` must be a pathItem or compoundPathItem
    and must have a dashed stroke.

*/


alert(strokeDashesAreAligned(app.activeDocument.selection[0]));


function strokeDashesAreAligned(item, keepSelection) {
    if (
        item == undefined || !(item.hasOwnProperty('pathPoints') || item.hasOwnProperty('pathItems'))
    ) return;

    var dashesAreAligned;

    // we only worry about storing the
    // selection because the outline
    // stroke test later destroys it
    keepSelection = keepSelection || true;
    var doc = getParentDocument(item),
        selectedItems = [];
    if (keepSelection) {
        for (var i = 0; i < doc.selection.length; i++) {
            selectedItems.push(doc.selection[i]);
        }
    }

    if (item.typename == 'CompoundPathItem') {

        // COMPOUND PATH ITEM

        if (
            item.pathItems[0].stroked == false
            || item.pathItems[0].strokeDashes.length == 0
        ) return;

        // duplicate
        var dup = item.duplicate();
        doc.selection = null;
        dup.selected = true;
        // uncompound
        app.executeMenuCommand('noCompoundPath');
        // collect the resulting path items
        var pathItemsToDelete = [];
        for (var i = 0; i < doc.selection.length; i++)
            pathItemsToDelete.push(doc.selection[i]);

        // get result on just the first path
        dashesAreAligned = strokeDashesAreAligned(pathItemsToDelete[0], keepSelection);

        // remove uncompounded duplicates
        for (var i = pathItemsToDelete.length - 1; i >= 0; i--)
            pathItemsToDelete[i].remove();

    } else {

        // PATH ITEM

        if (
            item.stroked == false
            || item.strokeDashes.length == 0
        ) return;

        // duplicate item
        var modelPathItem = item.duplicate();

        // standardise model
        var standardPoints = [[0, 0], [3, 0]];
        modelPathItem.filled = false;
        modelPathItem.stroked = true;
        modelPathItem.strokeWidth = 0.1;
        modelPathItem.strokeDashes = [1];
        modelPathItem.closed = false;
        for (var i = modelPathItem.pathPoints.length - 1; i >= 0; i--) {
            if (i >= standardPoints.length) {
                modelPathItem.pathPoints[i].remove();
            } else {
                modelPathItem.pathPoints[i].anchor = standardPoints[i];
                modelPathItem.pathPoints[i].leftDirection = standardPoints[i];
                modelPathItem.pathPoints[i].rightDirection = standardPoints[i];
            }
        }

        // convert to outlined stroke
        // must clear selection to do this
        doc.selection = null;
        modelPathItem.selected = true;
        app.executeMenuCommand('OffsetPath v22');
        modelPathItem = doc.selection[0];

        // the model, once converted to compoundPathItem,
        // will have 2 pathItems if dashes are not aligned,
        // or 3 if dashes are aligned
        var dashesAreAligned = modelPathItem.pathItems.length == 3;

        // remove the model and reselect the original
        modelPathItem.remove();

        // re-instate inital selection
        for (var i = 0; i < selectedItems.length; i++) {
            selectedItems[i].selected = true;
        }
    }

    return dashesAreAligned;
}

function getParentDocument(obj) {
    while (obj.hasOwnProperty('parent') && obj.constructor.name != 'Document')
        obj = obj.parent;
    return obj;
}

 

 

femkeblanco
Legend
January 19, 2022

Hi @m1b.  Is this part of your attempt so solve this problem?  If so, I would be interested in what your general approach is.  I ask because I gave it some thought at the time, but got nowhere. 

m1b
Community Expert
m1bCommunity ExpertAuthor
Community Expert
January 19, 2022

Yes exactly @femkeblanco! I'm still chipping away at it, bit by bit. I think I'll have a solution soon, depending on how much time I get to work on it this week. It really sent me down a rabbit hole! I will post on the original thread when I get somewhere.

- Mark

femkeblanco
Legend
January 19, 2022

Good luck!

m1b
Community Expert
m1bCommunity ExpertAuthor
Community Expert
January 18, 2022

Oh, just found this post, asking same question. Sorry for repeat.

- Mark