Skip to main content
Participating Frequently
November 5, 2015
Answered

How to align items (groupItem) with clipping masks?

  • November 5, 2015
  • 3 replies
  • 2385 views

I have a script that aligns an groupItemToBeAligned on one layer to another referenceGroupItem on another layer, so far so good. Problem comes when the groupItemToBeAligned consists of items that have clipping masks, simply using

groupItemToBeAligned.position = referenceGroupItem.position;

Doesn't work, it's taking the position of everything, what's the best method to align what's actually visible ? I tried using:

var vBounds = referenceGroupItem.visibleBounds;

x1 = vBounds[0];

y1 = vBounds[1];

x2 = vBounds[2];

y2 = vBounds[3];

groupItemToBeAligned.position = [x1, y1];

Produces the same results unfortunately.

This topic has been closed for replies.
Correct answer Disposition_Dev

Huzzah, yet again! I can't express how much it helps to have the actual file you're working with. This version aligns perfectly on all artboards. Let me know if you have any other issues. =)

function align(){ 

    var myDoc = app.activeDocument; 

    var aB = myDoc.artboards; 

    var layers = myDoc.layers;

   

 

 

    for(var a=0;a<aB.length;a++){

        var masks = [];

        myDoc.selection = null;

        aB.setActiveArtboardIndex(a); 

        myDoc.selectObjectsOnActiveArtboard(); 

 

 

        var reference; // this is the object we wan to align to.. AKA Key object 

        var obj; // this is the object we want to align.

        var items = myDoc.selection; 

 

 

        var topLayer = layers[0]; 

        var botLayer = layers[1]; 

       

       

 

 

 

        if(topLayer =! null || botLayer =! null){ 

            for(var b=0;b<2;b++){ 

                if(items.layer == botLayer){ 

                    reference = items

                } 

                else if(items.layer = topLayer){ 

                    obj = items;

                } 

            } 

 

 

            //recursive function digs into groupItems to find all

            //clipping masks present on the current artboard.

            //pushes all clipping masks to 'masks' array. 

            function findClips(thisGroup){ 

                var item; 

                for(var b=0;b<thisGroup.pageItems.length;b++){ 

                    item = thisGroup.pageItems

                    if(item.clipping){ 

                        masks.push(item);

                    } 

                } 

                if(thisGroup.groupItems.length>0){ 

                    for(var b=0;b<thisGroup.groupItems.length;b++){ 

                        var inGroup = thisGroup.groupItems

                        findClips(inGroup); 

                    } 

                }

            } 

            //searches masks array for the clipping mask with highest top value

            function findTop(masks){

                var topMost;

                for(var b=0;b<masks.length;b++){

                    if(b==0){

                        topMost = masks;

                    }

                    else if(masks.top > topMost.top){

                        topMost = masks;

                    }

                }

                return topMost.top;

            }

            //searches masks array for clipping mask with farthest left value

            function findLeft(masks){

                var leftMost;

                for(var b=0;b<masks.length;b++){

                    if(b==0){

                        leftMost = masks;

                    }

                    else if(masks.left < leftMost.left){

                        leftMost = masks;

                    }

                }

                return leftMost.left;

            }

 

 

            //populate masks array

            findClips(obj);

            //find highest and farthest left clipping mask coordinates

            var clipLeft = findLeft(masks);

            var clipTop = findTop(masks);

            

 

 

            //determines the extraneous, invisible, extra art 

            //on the left side and top of the objects so that 

            //that measurement can be ignored during placement 

            var objExtraLeft = clipLeft - obj.left; 

            var objExtraTop = obj.top - clipTop;

 

 

            //determine top and left coordinates for object 

            //to be aligned. 

            var left = reference.left - objExtraLeft; 

            var top = reference.top + objExtraTop;

 

 

            //move object to be aligned into position 

            obj.left = left; 

            obj.top = top; 

 

        } 

        else{ 

            alert("You're missing a layer!"); 

        } 

    } 

align(); 

3 replies

Disposition_Dev
Disposition_DevCorrect answer
Legend
November 18, 2015

Huzzah, yet again! I can't express how much it helps to have the actual file you're working with. This version aligns perfectly on all artboards. Let me know if you have any other issues. =)

function align(){ 

    var myDoc = app.activeDocument; 

    var aB = myDoc.artboards; 

    var layers = myDoc.layers;

   

 

 

    for(var a=0;a<aB.length;a++){

        var masks = [];

        myDoc.selection = null;

        aB.setActiveArtboardIndex(a); 

        myDoc.selectObjectsOnActiveArtboard(); 

 

 

        var reference; // this is the object we wan to align to.. AKA Key object 

        var obj; // this is the object we want to align.

        var items = myDoc.selection; 

 

 

        var topLayer = layers[0]; 

        var botLayer = layers[1]; 

       

       

 

 

 

        if(topLayer =! null || botLayer =! null){ 

            for(var b=0;b<2;b++){ 

                if(items.layer == botLayer){ 

                    reference = items

                } 

                else if(items.layer = topLayer){ 

                    obj = items;

                } 

            } 

 

 

            //recursive function digs into groupItems to find all

            //clipping masks present on the current artboard.

            //pushes all clipping masks to 'masks' array. 

            function findClips(thisGroup){ 

                var item; 

                for(var b=0;b<thisGroup.pageItems.length;b++){ 

                    item = thisGroup.pageItems

                    if(item.clipping){ 

                        masks.push(item);

                    } 

                } 

                if(thisGroup.groupItems.length>0){ 

                    for(var b=0;b<thisGroup.groupItems.length;b++){ 

                        var inGroup = thisGroup.groupItems

                        findClips(inGroup); 

                    } 

                }

            } 

            //searches masks array for the clipping mask with highest top value

            function findTop(masks){

                var topMost;

                for(var b=0;b<masks.length;b++){

                    if(b==0){

                        topMost = masks;

                    }

                    else if(masks.top > topMost.top){

                        topMost = masks;

                    }

                }

                return topMost.top;

            }

            //searches masks array for clipping mask with farthest left value

            function findLeft(masks){

                var leftMost;

                for(var b=0;b<masks.length;b++){

                    if(b==0){

                        leftMost = masks;

                    }

                    else if(masks.left < leftMost.left){

                        leftMost = masks;

                    }

                }

                return leftMost.left;

            }

 

 

            //populate masks array

            findClips(obj);

            //find highest and farthest left clipping mask coordinates

            var clipLeft = findLeft(masks);

            var clipTop = findTop(masks);

            

 

 

            //determines the extraneous, invisible, extra art 

            //on the left side and top of the objects so that 

            //that measurement can be ignored during placement 

            var objExtraLeft = clipLeft - obj.left; 

            var objExtraTop = obj.top - clipTop;

 

 

            //determine top and left coordinates for object 

            //to be aligned. 

            var left = reference.left - objExtraLeft; 

            var top = reference.top + objExtraTop;

 

 

            //move object to be aligned into position 

            obj.left = left; 

            obj.top = top; 

 

        } 

        else{ 

            alert("You're missing a layer!"); 

        } 

    } 

align(); 

Participating Frequently
November 19, 2015

Genius!!! Thank you so much for your help! Works perfect. This has been a really great learning experience for me too.

Disposition_Dev
Legend
November 18, 2015

Ok, i looked at the file you posted, and i see why my script wasn't working.. but my question i guess is why is the artwork created that way??? why don't you just use a hexagon to clip all of the artwork inside? why do you have a group of different clipping masks that create a shape instead of using a shape to create the clipping mask?

Anyway.. neither here nor there. Not my place.

Upon quick review, based on your comment about not looping through all the clipping paths, i notice that you have an if statement out of place (beginning on line 55).

line 55, that reads "if(thisGroup.groupItems.length>0){" needs to be inside of the for loop above it, like this:

for(var b=0;b<thisGroup.pageItems.length;b++){ 

    item = thisGroup.pageItems

    if(item.clipping){ 

        // return item; 

        lefts.push(item.left); 

        tops.push(item.top); 

        $.writeln("Group Item: ", b, "\n", "L: ", item.left, "\nT: ", item.top); 

    } 

    if(thisGroup.groupItems.length>0){ 

        for(var c=0;c<thisGroup.groupItems.length;c++){  //embarrasing note.. i realize i originally had a nested loop that used the same variable as the parent loop.... fixed that this time..

            var inGroup = thisGroup.groupItems

            return returnPosition(inGroup, lefts, tops); 

        } 

    }

}

in order for the recursion to work, you need to check all of the loose pathItems to see if they're clipping paths first, then loop through all of the groupItems. The way you had it, you were executing the for loop on the pageItems of thisGroup and only checking whether any of those were clipping masks. then after that loop was finished, then you were looking into the groupItems.

Let me dig around in this and see if i can't get it working for the test file you sent. It is a HUGE help to test the script on the actual file rather than some bogus file that i built based on assumptions of what you're trying to do. So thanks. =)

Vinicius Baptista
Inspiring
November 6, 2015

Hello 212dfcascas

Man, just make sure the object is "Clipped" if "true", use the coordinates of the "pageItems[0]" of him, like this:

Select two objects before perform this script:

if(app.selection[0].clipped){

    var referenceGroupItem = app.activeDocument.selection[0].pageItems[0];

    }else{

        var referenceGroupItem = app.activeDocument.selection[0];

        };

if(app.selection[1].clipped){

    var groupItemToBeAligned = app.activeDocument.selection[1].pageItems[0];

    }else{

        var groupItemToBeAligned = app.activeDocument.selection[1];

        };

   

var groupItemToBeAligned = app.activeDocument.selection[1];

var vBounds = referenceGroupItem.visibleBounds; 

x1 = vBounds[0]; 

y1 = vBounds[1]; 

x2 = vBounds[2]; 

y2 = vBounds[3]; 

groupItemToBeAligned.position = [x1, y1];

to more informations see this post: Re: Get Clipping Path dimensions

I hope helped you.

Enjoy

Participating Frequently
November 7, 2015

Thanks for your help! Unfortunately it still doesn't align, I should clarify, the groupItemToBeAligned is made of many items, some have a clipping mask, others do not, does that matter? Do I need to cycle through each item in a group… or something?

Also doesn't line 14 break line 9 (it's the same as line 11?), I tried with and without the line and still doesn't work btw

This is my script It works if it is a simple case of an object, and another clipped object. The way I use it is I have many artboards and 2 layers. For every artboard, the top layer has a group item, this group item contains several items, some clipped (I think almost all the clipped items are meshes), some are not clipped. I want the group item in the top layer to align to the item in the bottom layer.

var myDoc = app.activeDocument;

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

    var artboard = myDoc.artboards;

    thisArtboard = myDoc.artboards.setActiveArtboardIndex(i);

    // $.writeln(artboard);

    myDoc.selectObjectsOnActiveArtboard();

    var referenceItem = null;

    var itemToBeAligned = null;

    var items = selection;

    // var clippedSelection = null;

    // $.writeln(items);

    if (selection[0].clipped){

        var clippedSelection[0] = selection[0].pageItems[0];

        }else{

            var clippedSelection[0] = selection[0];

    };

    if (selection[1].clipped){

        var clippedSelection[1] = selection[1].pageItems[0];

        }else{

            var clippedSelection[1] = selection[1];

    };

    topLayer = documents[0].layers[1];

    bottomLayer = documents[0].layers[0];

    if ( ( null == topLayer ) || ( null == bottomLayer ) )

    {

        alert("Error");

    }

    else

    {

        for ( x = 0; x != 2; ++x )

        {

            if ( clippsedSelection[ x ].layer == bottomLayer )

            {

                referenceItem = clippsedSelection[ x ];

            }

            else if ( clippsedSelection[ x ].layer == topLayer )

            {

                itemToBeAligned = clippsedSelection[ x ];

            }

        }

        // $.writeln(itemToBeAligned.position);

        // $.writeln(referenceItem.position);

        var vBounds = referenceItem.visibleBounds;

        x1 = vBounds[0];

        y1 = vBounds[1];

        x2 = vBounds[2];

        y2 = vBounds[3];

        // itemToBeAligned.position = referenceItem.position;

        itemToBeAligned.position = [x1,y1];

    }

}

redraw();

Participating Frequently
November 10, 2015

bump!