Skip to main content
Gotta Dance
Inspiring
December 15, 2022
Answered

Expressions: Returning the width Value of a Layer

  • December 15, 2022
  • 3 replies
  • 3908 views

Hi Everybody,

 

I found this script by Dan Ebberts in another community thread:

 

layer = app.project.activeItem.layer(1);

rect = layer.sourceRectAtTime(0,true);

alert(rect.width);

 

So that's straight forward enough...under which transform of my precomp do I place this expression? 

 

I'm trying to create a set of layer comps with different widths evenly spaced in a row, so I need to first figure out how to getWidth(); essentially.  

 

This topic has been closed for replies.
Correct answer Dan Ebberts

I am assuming the anchor points are all in the center. Because the Lef and Top values are always zero with layers, they would have no influence on layer position, but they could be used to compensate for paragraph justification and baseline shift and could also fix shape layer transforms. 

 

The first step is to create a left justified grid with rows no longer than the comp width and all layers the same height. If I change the expression for the second row, I can achieve this by modifying the Y in the else expression value to look at the height of a layer in the first row. I'd love to know how to automate that.

 

Carried to the extreme, the expression, or the script, would create a grid of different-sized layers with the same padding around each layer. For the graphic, I am visualizing, creating a grid of layers with the same height and consistent vertical padding would be sufficient.

 

If all the layers were 3D, you could set up a camera to move through the grid and pick out different layers to focus on. A couple of years ago, I created a similar graphic in Illustrator by hand. In AE, the final comp would look something like this. It's kind of a crude demo. 

 

 


This turned out to be quite the adventure, but I did learn some stuff. To keep things from getting completely out of control, I did have to make a few assumptions. One is that the anchor points are centered. For layers where it isn't centered , you can just apply this anchor point expression (especially handy for text layers):

r = sourceRectAtTime(time,false);
[r.left + r.width/2, r.top + r.height/2]

I also assumed that the layers are all the same height. If they're not (or if you want to specify a different height), you have to define the height with a slider named "Height" on a layer named "Controls" and they need this scale expression:

h = thisComp.layer("Controls").effect("Height")("Slider");
r = sourceRectAtTime(time,false);
s = (h/r.height)*100;
[s,s]

I also assumed that the horizontal and vertical padding are defined by sliders named "H Gap" and "V Gap" on the "Controls" layer. Note that the Controls layer can be anywhere in the layer stack. All the other layers (those participating in the grid) need this position expression:

hGap = thisComp.layer("Controls").effect("H Gap")("Slider");
vGap = thisComp.layer("Controls").effect("V Gap")("Slider");

upperLeft = [hGap, vGap]; // start in upper left corner of comp
for (i = 1; i < index; i++){
  L = thisComp.layer(i);
  if (L.name == "Controls") continue; // skip the controls layer
  r = L.sourceRectAtTime(time,false);
  if (upperLeft[0] + hGap + r.width*L.scale[0]/100 > thisComp.width){
    upperLeft = [hGap, upperLeft[1] + vGap + r.height*L.scale[1]/100];
  }
  upperLeft += [r.width*L.scale[0]/100 + hGap, 0];
}
r = sourceRectAtTime(time,false);
if (upperLeft[0] + hGap + r.width*scale[0]/100 > thisComp.width){
  upperLeft = [hGap, upperLeft[1] + vGap + r.height*scale[1]/100];
}
upperLeft + [r.width*scale[0],r.height*scale[1]]/200

Realistically, to be able to handle layers of different heights, I think you'd to do it with a script, because it would be a lot of processing to do it with expressions. Anyway, I tested this with text, shapes, solids, and precomps and it seems work well.

3 replies

Community Expert
December 17, 2022

This thread and this other thread made me think about and come up with an expression that would automatically place the first layer in a comp in the upper left corner of the comp, then stack each layer to the right with some padding. 

 

This is my expression:

xPad=20;
yPad = 20;
s = scale * .01;
i = index;
tLyr = sourceRectAtTime();
w = s[0] * tLyr.width/2;
h = s[1] * tLyr.height/2;

if (i == 1){
	[w + xPad/2, h + yPad/2];
}
else{
	lW = s[0] * tLyr.width/2;
	lH = tLyr.height/2;
	ref = thisComp.layer(i - 1);
	rScl = ref.scale * .01;
	refBox = ref.sourceRectAtTime();
	refW = rScl[0] * refBox.width / 2;
	refH = refBox.height / 2;
	x = refW + xPad;
	y = refH + yPad;
	ref.position + [x + lW, 0];
}

The comp uses sourceRectAtTime() instead of just width. I also added in scale compensation. My goal is to make it work with shape layers, text layers, footage or solid layers, and even nested comps.

 

So far, the expression works perfectly. The next thing I would like to do is look at the position of the first layer that moves outside the composition frame to the right and shift that layer and all layers that follow below the top row created by the if/else section of my expression. When the next row is filled, I'd like the layers to drop down once again.

 

I'm kind of lost. Adding an if (current layer x position is greater than comp width) (move down below the first row}. If anyone knows how to write code that creates multiple rows, it is Dan Ebberts. I would appreciate any pointers. I'd appreciate the feedback. When I get a little more time to fiddle with this, I'll start a new thread specifically dealing with automatically creating multiple layers of rows. 

 

Dan Ebberts
Community Expert
December 17, 2022

When putting something like this together, you have to first define all your assumptions. Are you assuming that all layers have their anchor points centered? Are all the layers the same height? If not, is a row's height determined by its tallest layer? Or do you have a scale expression that makes them all the same height? I think, for the OP's video wall, you could assume constant height, but not width. Also, is the last layer in a row the last one that fits fully within the comp, or the last one that's at least partly visible in the comp?

Community Expert
December 17, 2022

I am assuming the anchor points are all in the center. Because the Lef and Top values are always zero with layers, they would have no influence on layer position, but they could be used to compensate for paragraph justification and baseline shift and could also fix shape layer transforms. 

 

The first step is to create a left justified grid with rows no longer than the comp width and all layers the same height. If I change the expression for the second row, I can achieve this by modifying the Y in the else expression value to look at the height of a layer in the first row. I'd love to know how to automate that.

 

Carried to the extreme, the expression, or the script, would create a grid of different-sized layers with the same padding around each layer. For the graphic, I am visualizing, creating a grid of layers with the same height and consistent vertical padding would be sufficient.

 

If all the layers were 3D, you could set up a camera to move through the grid and pick out different layers to focus on. A couple of years ago, I created a similar graphic in Illustrator by hand. In AE, the final comp would look something like this. It's kind of a crude demo. 

 

 

Gotta Dance
Inspiring
December 15, 2022

Nevermind, I found a tutorial that covers sourceRectAtTime(). Thanks!

 

https://www.youtube.com/watch?v=CVliDoNgoCg

Gotta Dance
Inspiring
December 15, 2022

Actually none of this has actually answered my question.

 

My question is where to I put this snippet, code, etc. for precomps?

 

There's no variables for precomps that denote width.

 

There's just anchor position, scale (%, not size), rotation, and opacity.

 

Do I have the wrong idea just putting this basic script?

 

Dan Ebberts
Community Expert
December 15, 2022

Precomps do have a width attribute:

So using something like this will give you the width:

thisComp.layer("Precomp 1").width

or, if the precomp layer has been scaled, something like this:

L = thisComp.layer("Precomp 1");
L.width * L.scale[0]/100

 

 

Mylenium
Brainiac
December 15, 2022

This is not an expression, it's a script snippet. If you just want to plot the width you apply something like this to the source text property of a text layer:

 

thisComp.layer("XYZ").sourceRectAtTime()[0]

 

Mylenium