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

scale & position expression - macOS dock effect

Community Beginner ,
Apr 11, 2023 Apr 11, 2023

I'm using some expressions to create a similar effect to the macOS dock. When I independently scale the layers they adjust their position automatically. vid1.gif

 

I want to add this 'cursor' when it's near is going to scale, and needs to change its position as well

vid2.gif

 

But when I activate the expression doesn't change

vid3.gif

it also offsets the shape a bit

 

shape.png

 

TOPICS
Expressions
1.4K
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 ,
Apr 11, 2023 Apr 11, 2023

You need to provide the actual code so people can tell you what to change or add. Those screenshots and partially visible expressions don't tell us everything and are kinda useless.

 

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
Community Beginner ,
Apr 11, 2023 Apr 11, 2023

yeah you're right, here is the code I'm using

 

This is the expression for placing the layer beside the previous layer, adding a spacing between them

var spaceBetween = thisComp.layer("control").effect("padding")("Slider");

//previousLayerValues
var previousLayerHalfWidth = thisComp.layer(thisLayer, 1).sourceRectAtTime().width / 2;
var previousLayerScale =  thisComp.layer(thisLayer, 1).transform.scale[0] / 100;
var previousLayerPosition = thisComp.layer(thisLayer, 1).transform.xPosition.valueAtTime(time);


//thisLayerValues
var thisLayerHalfWidth = thisLayer.sourceRectAtTime().width / 2;
var thisLayerScale = transform.scale[0] / 100;
var thisLayerFinalScale = thisLayerHalfWidth * thisLayerScale;


previousLayerPosition + spaceBetween + (Math.round(previousLayerHalfWidth*previousLayerScale)) + thisLayerFinalScale

 

This is the expression I'm using to scale depending on the 'cursor' position

 

var position1 = thisComp.layer("cursor").transform.xPosition;
var position2 = transform.xPosition;
var theLenght = length(position1,position2);
linear(theLenght, 100,10, [20,20], [5,5])

 

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
Community Expert ,
Apr 11, 2023 Apr 11, 2023

I don't have time to write the expressions for you now but the workflow involves using sourctRectAtTime and multiply the size by the scale change and use that to adjust the position by sliding the shape layer (or individual shape if all of your rectangles are on the same shape layer when the cursor layer gets close.

 

The spacing for all layers would be controlled by referring to the first layer in the chain and using sratTime to offset each layer to the right. As long as you reference the other layer's scale, everything should stay lined up. 

 

If I get some time this evening, I'll try and post the solution. If you share your problem project file, it will be a lot easier for me to dig into your code and solve the problem. You'll basically need to throw a multiply by .01 using the X scale value to make the position react to the scale changes and control the way the layers move by shifting the shape layer rectangle/transform rectangle/Anchor point to the left edge of the rectangle. I hope that makes a little sense. 

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
Community Beginner ,
Apr 11, 2023 Apr 11, 2023

I attached the source file, I was making it this way because I'd like to use compositions or images instead of shape layers.
thanks a lot!

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 ,
Apr 12, 2023 Apr 12, 2023

You cannot simply use linear equations. of course this will never work because neither layer ever knows that there is more than one other layer. You have to pack the stuff into a for() loop and iterate through all layers every time to see what their actual positions and scales are.

 

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
Community Expert ,
Apr 12, 2023 Apr 12, 2023

I think I have solved this for you. You will need a Null as a Null Controller layer, four Layer Control Sliders, A Cursor layer (I make an arrow shape layer with the anchor point at the tip of the arrow, and standard shape layers with one rectangle to keep it simple, or regular layers (footage, solids, images) or text layers and the following expressions. Here's the explanations.

 

Start by setting the layer Anchor Point X value to zero or use this expression for Anchor Point:

[0, height/2]

 If you are using a shape layer rectangle, and the rectangle is normalized (Rectangle1/Transform Rectangle 1/Position = 0, 0] so it is in the center of the layer, you add this expression to the Shape Layer's anchor point:

x = - content("Rectangle 1").content("Rectangle Path 1").size[0]/2;
y = 0;
[x, y]

Then you add a bunch of controllers to a Conntroller Null layer and add this expression to every layer's scale:

ls = thisComp.layer("Controller Null").effect("Layeer Size")("Slider");
sG = thisComp.layer("Controller Null").effect("Grow Ratio")("Slider")/100;
prox = thisComp.layer("Controller Null").effect("Proximity")("Slider");
cP = thisComp.layer("Cursor").position;
box = sourceRectAtTime();
w = box.width;
h = box.height;
g = sG;
cP = thisComp.layer("Cursor").position;
t = length(cP + [- w, 0], position);
x = thisComp.width / w * ls;
yR = thisComp.height / h;
t = length(cP + [- 200, 0], position);
ofst = ease(t, 0, prox, x * sG, 0);

[x + ofst, yR * ls]

 The sliders are listed, and the expression will give you a bunch of layers that are the same ratio as the comp and a percentage of the comp size

 

Add this expression to Position every layer below the first layer in the stack, and every new layer will line up to the left of the top layer in the stack and be centered. 

ref = thisComp.layer(index-1);
refP = ref.position;
refS = ref.scale * .01;
refBox = ref.sourceRectAtTime();
ls = thisComp.layer("Controller Null").effect("Layeer Size")("Slider");
sG = thisComp.layer("Controller Null").effect("Grow Ratio")("Slider");
prox = thisComp.layer("Controller Null").effect("Proximity")("Slider");
pad = thisComp.layer("Controller Null").effect("Pad")("Slider");
cP = thisComp.layer("Cursor").position;box = sourceRectAtTime();
t = length(position, cP);
ofst = ease(t, 0, prox, sG, 0);
w = box.width;
h = box.height;
xR = thisComp.width / w;
yR = thisComp.height / h;

[refP[0] + ((refBox.width + ofst) * refS[0]) + pad, refP[1]]

The expression will also work with Left Justified Text layers. I could add some more code to take care of center and right justified text.

 

Here's the result:

RickGerard_0-1681335988452.gif

I need a little more work on the text layers to get the growth consistent, but if you had all text layers, everything should work. 

 

You could modify the scale expression to use two sliders for height and width ratios or just take the layer size if you wanted to simplify things. 

 

This should get you started.

 

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 ,
Apr 12, 2023 Apr 12, 2023
LATEST

Doesn't really solve the problem for the non-sequential change illustrated in the original images. if that's required you can't avoid using a loop.

 

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