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

Extendscript: loop a function with an array as it's argument

Explorer ,
Dec 03, 2019 Dec 03, 2019

I hope this title makes sense. Essentially, I want to have a function loop and output different strings depending on some variables in its argument.

 

The following code is supposed to add an "offset path" to shape layer groups. This offset path should then get receive an expression, in which it references the stroke width of each group. It almost works, but I can't get it to consider the different shape layer groups. 

 

The test-scenario is the following: We have a Shape layer with two shape layer groups inside of it (for example "Shape 1" and "Shape 2"). "Shape 1" has a property "Stroke 1" with a Stroke Width of 10 and "Shape 2" has a property "Stroke 1" with a Stroke Width of 20.

 

I already was able to create the two variables "shapeList" and "strokeList", which hold an array of all shape group names as well as all stroke names. For the purpose of our example:

shapeList = [Shape 1, Shape 2];

strokeList = [Stroke 1, Stroke 1];

 

I created these variables to be able to create the expression to reference each stroke width value, which I think would look like the following: 

('content' + '("' + shapeList[?] + '")' + '.content' + '("' + strokeList[?] + '")' + '.strokeWidth')

 

I attempted to create a for loop in line 83, which is supposed to fill the "[?]"s with the right array number, which unfortunately does not work. Hardcoding the "[?]"s with something [1] like creates a working expression link, so at least I got it to that point but I would like it to be flexible and can't wrap my head around it anymore at this point.

Any help would be gladly appreciated.

 

Thank you so much in advance

 

Michael

 

 

try{
    
var myComp = app.project.activeItem;
var myLayer = myComp.selectedLayers;
var strokeList = [];
var shapeList = [];
var exprString = [];

//Panel + Functionality
{
    function myScript(thisObj){
        function myScript_buildUI(thisObj){
            var myPanel = (thisObj instanceof Panel) ? thisObj : new Window("palette", "Dockable Script", undefined, {resizable: true, closeButton:true});
            
        res = "group{orientation:'column',\
        groupOne: Group{orientation:'row',\
        ButtonOne: Button{text:'Try Me'},\
            },\
        groupTwo: Group{orientation:'row',\
        ButtonTwo: Button{text:'not_assigned'},\
        },\
        groupThree: Group{orientation:'row',\
        ButtonThree: Button{text:'not_assigned'},\
        },\
            }";
            
            myPanel.grp = myPanel.add(res);
            
            // Defaults / Functionality
            
            //Button 1
            
            myPanel.grp.groupOne.ButtonOne.onClick = function buttonOneClick() {
            app.beginUndoGroup("Action One");
            //Main Function: Adds or modifies the offset stroke
                function main(a) {
                    for(i = 0; i < myLayer.length; i++){
                    //Check if selection is a shape layer
                        if (myLayer[i] instanceof ShapeLayer) {
                            //If so, check if it has a stroke
                                if(hasStroke()) {
                                    //If so, allow action
                                    if(hasOffsetPath()) {
                                        changeOffsetValue(a)
                                    } else {
                                        addOffsetPath(a)
                                    }
                                } else {
                                    ("This shape doesn't have a stroke yet")
                                }
                            } else { alert("This is not a shape layer") }
                        }
                    }
                    
                    //Loop that outputs strokeList Array
                     for (var i=0;i<myLayer.length;i++){
                        //Variable to access shape layer props
                        var contents = myLayer[i].property("ADBE Root Vectors Group");
                                    for(s = 1; s <= contents.numProperties; s++){
                                            //Variable to acccess shape groups
                                            var shape = contents.property(s).property("Contents");
                                                for(p=1; p<= shape.numProperties; p++){
                                                    //Variable to check if property is a Stroke, which itself has 9 Properties (or Gradient Stroke which has 14)
                                                    var includesStroke = shape.property(p).numProperties == 9 || shape.property(p).numProperties == 14;
                                                        if(includesStroke) {
                                                            strokeList[strokeList.length] = shape.property(p).name;
                                                        }
                                                }
                                        }
                                    }
                                    
                    //Loop that outputs shapeList Array
                     for (var i=0;i<myLayer.length;i++){
                            //Variable to access shape layer props
                            var contents = myLayer[i].property("ADBE Root Vectors Group");
                                    for(s = 1; s <= contents.numProperties; s++){
                                            //Variable to acccess shape names
                                            shapeList[shapeList.length] = contents.property(s).name;
                                        } 
                                    }
                    
            //Prepare expression
            for(var x = 1; x <= shapeList.length; x++){
                var shapeName = shapeList[x];
                    for(var y = 1; y <= strokeList.length; y++){
                        var strokeName = strokeList[y];
                        main('content' + '("' + shapeName + '")' + '.content' + '("' + strokeName + '")' + ".strokeWidth");            
                            }
                    }
            app.endUndoGroup();
            };
            
            //Button 2
            myPanel.grp.groupTwo.ButtonTwo.onClick = function buttonTwoClick() {
                main(getStrokeWidth()/(-2));
            };
            
            //Button 3
            myPanel.grp.groupThree.ButtonThree.onClick = function buttonThreeClick() {
                main(0)
            };
            
            myPanel.layout.layout(true);
            
            return myPanel;
        }
        
        var myScriptPal = myScript_buildUI(thisObj);
        
        if(myScriptPal != null && myScriptPal instanceof Window) {
            myScriptPal.center();
            myScriptPal.show();
        }
    }
    myScript(this);
}

//Make sure at least one layer is selected
    if (myLayer.length == 0) {
        alert("Select a shape layer") 
        }
    
//Checks if shape layer has an enabled stroke
function hasStroke(){

    for (var i=0;i<myLayer.length;i++){
        
    //Variable to access shape layer props
    var contents = myLayer[i].property("ADBE Root Vectors Group");

    //
    for(s = 1; s <= contents.numProperties; s++){
            var shape = contents.property(s).property("Contents");
                    if(shape.property("ADBE Vector Graphic - Stroke").active == true){
                        return true
                    }else{
                        return false
                }
        }
    }
}

//Adds an offset Path
function addOffsetPath(a){

    for (var i=0;i<myLayer.length;i++){
        
    //Variable to access shape layer props
    var contents = myLayer[i].property("ADBE Root Vectors Group");
        for(s = 1; s <= contents.numProperties; s++){
            var shape = contents.property(s).property("Contents");
            var myOffset = shape.addProperty("ADBE Vector Filter - Offset").property(1);
            myOffset.expression = a;
                
        }
    }
}

//Checks if current shape layer already has an offset path     
function hasOffsetPath(){

    for (var i=0;i<myLayer.length;i++){
        
    //Variable to access shape layer props
    var contents = myLayer[i].property("ADBE Root Vectors Group");
        for(s = 1; s <= contents.numProperties; s++){
            var myFilter = "ADBE Vector Filter - Offset"
            var shape = contents.property(s).property("Contents");
                if(myFilter in shape){
                    return true
                }else{
                    return false
            }
        }
    }
}

//changes the offset Path value in case it is already applied
function changeOffsetValue(a){    
    if (hasOffsetPath()) {
        for (var i=0;i<myLayer.length;i++){
            
            //Variable to access shape layer props
            var contents = myLayer[i].property("ADBE Root Vectors Group");
        
            //
            for(s = 1; s <= contents.numProperties; s++){
                var myFilter = "ADBE Vector Filter - Offset";
                var shape = contents.property(s).property("Contents").property(myFilter);
                        var offset = shape.property(1);
                         offset.expression = a;
                
            }
        }
    }
}




}catch(err){
    alert("Error at line # " + err.line.toString() + "\r" + err.toString());
    
}

 

 

TOPICS
Expressions , Scripting , SDK
3.5K
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 ,
Dec 03, 2019 Dec 03, 2019

Your functions don't do anything and will always hold the last variable in the loop. You are not controlling the flow of the loops with break() and continue() to escape when you actually have hit the right combos. It will simply go on forever and everything else in your code therefore becomes meaningless.

 

Mylenium

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
Explorer ,
Dec 04, 2019 Dec 04, 2019

I understand the principle of break and continue, but I don't know how it applies in this case to help me. Which functions exactly don't do anything? How can I tell the machine it has hit a right combo without hardcoding?

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
Contributor ,
Dec 04, 2019 Dec 04, 2019

There are several ways to tell how far your script is getting. You can disperse alerts or $.writeln() throughout to see how far the script makes it before freezing or erroring, or you can add breakpoints and use the Data Browser in ExtendScript to see if all the variables are being populated. I tried this on your script and found one glaring problem.

 

When you declare "var includesStroke", I would not recommend using the number of properties something has to define if it is a certain type of effect. There may be hidden properties, or different numbers of them in different versions of AE. I'm pretty sure this is causing the error, because you script never makes it to the "Loop that outputs shapeList Array", and thus never runs any meaningful code that can be visualised in AE.

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
Explorer ,
Dec 05, 2019 Dec 05, 2019
LATEST

I can imagine that using the number of properties as something to define a certain type is not the best way but it's the only way I found to make it work as I was unable to find out the type of this property. Actually, as unsexy as it may look, this line works just fine and both of the array variables spit out the correct arrays. I'm pretty sure the problem is, as Mylenium mentioned, that the code overwrites itself. What is not working properly is line 83 - 87. It overwrites itself because it currently has no way to see whether or not the property has an expression applied already. I added a function that checks this condition but I couldn't find a way to utilize it yet without after effects crashing.

 

 

//Checks if the offset path has an expression applied to it
function offsetHasExpression(){

    for (var i=0;i<myLayer.length;i++){
        
    //Variable to access shape layer props
    var contents = myLayer[i].property("ADBE Root Vectors Group");
        for(s = 1; s <= contents.numProperties; s++){
            var myFilter = "ADBE Vector Filter - Offset"
            var shape = contents.property(s).property("Contents").property(myFilter);
            var offset = shape.property(1);
                if(offset.expressionEnabled == true){
                    return true
                }else{
                    return false
            }
        }
    }
}

 

 

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