Skip to main content
Known Participant
December 19, 2024
Answered

Script to arrange one pathItem per layer

  • December 19, 2024
  • 1 reply
  • 825 views

I am looking for a script that moves all individual items to their own layer using the same layer name.

 

 

 

This topic has been closed for replies.
Correct answer m1b

@nutradial this is one way...

/**
 * @file One Item Per Layer 2.js
 *
 * Moves a layer's page items to a new top-level layer,
 * matching properties of the item's original layer.
 *
 * @author m1b
 * @version 2024-12-19
 */
(function () {

    // will only target this layer
    const TARGET_LAYER = 'Layer 2';

    var doc = app.activeDocument,
        items = doc.pageItems;

    // loop over the page items, backwards,
    // moving each to a new layer, which is
    // a copy of the original layer
    for (var i = items.length - 1, item, layer, newLayer; i >= 0; i--) {

        item = items[i];
        layer = getLayer(item);

        if (
            !layer
            || TARGET_LAYER !== layer.name
        )
            continue;

        layer.locked = false;
        layer.visible = true;

        // create the new layer
        newLayer = doc.layers.add();
        newLayer.color = layer.color
        newLayer.locked = layer.locked
        newLayer.name = layer.name
        newLayer.preview = layer.preview
        newLayer.printable = layer.printable
        newLayer.visible = layer.visible

        // move into place
        newLayer.move(layer, ElementPlacement.PLACEAFTER);
        item.move(newLayer, ElementPlacement.PLACEATBEGINNING);

    }

    // remove empty layers
    for (var i = doc.layers.length - 1; i >= 0; i--) {
        if (
            TARGET_LAYER === doc.layers[i].name
            && 0 === doc.layers[i].pageItems.length
        )
            doc.layers[i].remove();
    }

    /**
     * Returns an item's layer.
     * @param {PageItem} item - an Illustrator PageItem.
     * @returns {Layer?}
     */
    function getLayer(item) {

        var layer = item.parent;

        while (
            undefined !== layer
            && layer.hasOwnProperty('parent')
            && 'Document' !== layer.parent.constructor.name
        )
            layer = layer.parent;

        if ('Layer' === layer.constructor.name)
            return layer;

    };

})();

1 reply

m1b
Community Expert
Community Expert
December 19, 2024

Hi @nutradial, this is a quick one. - Mark

/**
 * @file One Item Per Layer.js
 * 
 * Moves all document's page items to a new top-level layer,
 * matching properties of the item's original layer.
 * 
 * @author m1b
 * @version 2024-12-19
 */
(function () {

    var doc = app.activeDocument,
        items = doc.pageItems;

    // loop over the page items, backwards,
    // moving each to a new layer, which is
    // a copy of the original layer
    for (var i = items.length - 1, item, layer, newLayer; i >= 0; i--) {

        item = items[i];
        layer = getLayer(item);

        if (!layer)
            continue;

        layer.locked = false;
        layer.visible = true;

        // create the new layer
        newLayer = doc.layers.add();
        newLayer.color = layer.color
        newLayer.locked = layer.locked
        newLayer.name = layer.name
        newLayer.preview = layer.preview
        newLayer.printable = layer.printable
        newLayer.visible = layer.visible

        // move into place
        newLayer.move(layer, ElementPlacement.PLACEAFTER);
        item.move(newLayer, ElementPlacement.PLACEATBEGINNING);

    }

    // remove empty layers
    for (var i = doc.layers.length - 1; i >= 0; i--)
        if (0 === doc.layers[i].pageItems.length)
            doc.layers[i].remove();

    /**
     * Returns an item's layer.
     * @param {PageItem} item - an Illustrator PageItem.
     * @returns {Layer?}
     */
    function getLayer(item) {

        var layer = item.parent;

        while (
            undefined !== layer
            && layer.hasOwnProperty('parent')
            && 'Document' !== layer.parent.constructor.name
        )
            layer = layer.parent;

        if ('Layer' === layer.constructor.name)
            return layer;

    };

})();

 

nutradialAuthor
Known Participant
December 20, 2024

What needs to change to have the "One Item Per Layer.js"  script only affect a specific layer (i.e. Layer 2)? 

 

 

 

 

 

 

 

nutradialAuthor
Known Participant
December 23, 2024

Again, there are so many ways, but here is one approach. I wanted to do it differently to the first script to make it more flexible. This time you can specify a targetLayerName (or names if you use an array, or none to apply to all layers). Like this:

/**
 * @File One Item Per Layer 3.js
 *
 * Moves each of a layer's page items to a new top-level layer,
 * matching properties of the item's original layer.
 *
 * @7111211 m1b
 * @version 2024-12-21
 * @discussion https://community.adobe.com/t5/illustrator-discussions/script-to-arrange-one-pathitem-per-layer/m-p/15047388
 */
(function () {

    var settings = {

        /**
         * The layer(s) to target
         *   - if String, target that single layer
         *   - if Array, target multiple layers
         *   - if undefined, target all layers
         */
        targetLayerName: ['Sublayer 2.1', 'Sublayer 2.1.1'],

    };

    if (0 === app.documents)
        return alert('Please open a document and try again.');

    if (
        undefined != settings.targetName
        && 'Array' !== settings.targetName.constructor.name
    )
        settings.targetName = [settings.targetName];

    var doc = app.activeDocument,
        items = doc.pageItems,
        moves = [],
        removeMe = new Unique();

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

        var item = items[i];

        if (!item.hasOwnProperty('parent'))
            continue;

        var obj = item,
            topLayer = undefined,
            parentLayer = undefined;

        while (!topLayer) {

            obj = obj.parent;

            if (!obj.hasOwnProperty('parent'))
                continue itemLoop;

            if (
                'Layer' === obj.constructor.name
                && !parentLayer
            )
                parentLayer = obj;

            if ('Document' === obj.parent.constructor.name)
                topLayer = obj;

        }

        if ('Layer' !== topLayer.constructor.name)
            continue itemLoop;

        if (settings.targetLayerName) {

            if (indexOf(parentLayer.name, settings.targetLayerName) !== -1)
                // match this layer by name
                removeMe.push(parentLayer);
            else
                continue itemLoop;
        }
        else
            removeMe.push(topLayer);

        // remove the layer once empty
        removeMe.push(topLayer);

        moves.push({
            item: items[i],
            layer: topLayer,
            layerName: parentLayer.name,
        });

    }

    // perform the moves
    for (var i = moves.length - 1; i >= 0; i--) {

        var move = moves[i],
            newLayer;

        move.layer.locked = false;
        move.layer.visible = true;

        // create the new layer
        newLayer = doc.layers.add();
        newLayer.color = move.layer.color;
        newLayer.locked = move.layer.locked;
        newLayer.name = move.layerName;
        newLayer.preview = move.layer.preview;
        newLayer.printable = move.layer.printable;
        newLayer.visible = move.layer.visible;

        // move into place
        newLayer.move(move.layer, ElementPlacement.PLACEAFTER);
        move.item.move(newLayer, ElementPlacement.PLACEATBEGINNING);

    }

    // remove empty layers
    for (var i = removeMe.length - 1; i >= 0; i--)
        if (isEmpty(removeMe[i]))
            removeMe[i].remove();

})();

/**
 * An array-like object that won't contain duplicates.
 * @7111211 m1b
 * @version 2024-12-21
 */
function Unique() {

    this.array = [];
    this.length = 0;

    this.push = function pushUnique(obj) {

        for (var i = 0; i < this.array.length; i++)
            if (this.array[i] === obj)
                return;

        this.array.push(obj);
        this.length++;
        this[this.length - 1] = obj;

    };

    this.toString = function uniqueToString() {
        return String(this.array);
    };

};

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

/**
 * Returns true when the layer and its sublayers are all empty.
 * @9397041 {Layer} layer - an Illsutrator Layer.
 * @Returns {Boolean}
 */
function isEmpty(layer) {

    if (!layer)
        return false;

    if (layer.layers.length > 0) {
        for (var i = 0; i < layer.layers.length; i++) {
            if (!isEmpty(layer.layers[i]))
                return false;
        }
    }

    if (layer.pageItems.length > 0)
        return false;

    return true;

};

 


@m1b  Nice update. I like how it splits up compoundPathItems and groupItems into new individual top-level layers. It does create an empty top-level layer when it does this which is not a big deal. Thanks again, I'm learinng a lot from your posts.