Search code examples
delphianimationdelphi-xe2easingeasing-functions

Implementing EaseIn, EaseOut functions in Delphi


I am trying to implement fluid movement of tabs in TChromeTabs. I can see the easing formulas here, but I am no mathematician and have no idea how to translate this into code. My attempts so far have got me nowhere.

Are there Delphi implementations of the Easing functions available?


Solution

  • I found several useful examples online and used the algorithms to write my own Delphi Easing functions. Here they are:

    ...
    
    type
      TChromeTabsEaseType = (
        ttlinearTween,
        tteaseInQuad,
        tteaseOutQuad,
        tteaseInOutQuad,
        tteaseInCubic,
        tteaseOutCubic,
        tteaseInOutCubic,
        tteaseInQuart,
        tteaseOutQuart,
        tteaseInOutQuart,
        tteaseInQuint,
        tteaseOutQuint,
        tteaseInOutQuint,
        tteaseInSine,
        tteaseOutSine,
        tteaseInOutSine,
        tteaseInExpo,
        tteaseOutExpo,
        tteaseInOutExpo,
        tteaseInCirc,
        tteaseOutCirc,
        tteaseInOutCirc
      );
    
        function CalculateEase(CurrentTime, StartValue, ChangeInValue, Duration: Real; EaseType: TChromeTabsEaseType): Real; overload;
        function CalculateEase(StartPos, EndPos, PositionPct: Real; EaseType: TChromeTabsEaseType): Real; overload;
    
    implementation
    
        function CalculateEase(CurrentTime, StartValue, ChangeInValue, Duration: Real; EaseType: TChromeTabsEaseType): Real;
        begin
          case EaseType of
            ttLinearTween:
              begin
                Result := ChangeInValue * CurrentTime / Duration + StartValue;
              end;
    
            ttEaseInQuad:
              begin
                CurrentTime := CurrentTime / Duration;
    
                  Result := ChangeInValue * CurrentTime * CurrentTime + StartValue;
              end;
    
            ttEaseOutQuad:
              begin
                CurrentTime := CurrentTime / Duration;
    
                  Result := -ChangeInValue * CurrentTime * (CurrentTime-2) + StartValue;
              end;
    
            ttEaseInOutQuad:
              begin
                CurrentTime := CurrentTime / (Duration / 2);
    
                if CurrentTime < 1 then
                  Result := ChangeInValue / 2 * CurrentTime * CurrentTime + StartValue
                else
                begin
                  CurrentTime := CurrentTime - 1;
                  Result := -ChangeInValue / 2 * (CurrentTime * (CurrentTime - 2) - 1) + StartValue;
                end;
              end;
    
            ttEaseInCubic:
              begin
                CurrentTime := CurrentTime / Duration;
    
                Result := ChangeInValue * CurrentTime * CurrentTime * CurrentTime + StartValue;
              end;
    
            ttEaseOutCubic:
              begin
                CurrentTime := (CurrentTime / Duration) - 1;
    
                Result := ChangeInValue * ( CurrentTime * CurrentTime * CurrentTime + 1) + StartValue;
              end;
    
            ttEaseInOutCubic:
              begin
                CurrentTime := CurrentTime / (Duration/2);
    
                if CurrentTime < 1 then
                  Result := ChangeInValue / 2 * CurrentTime * CurrentTime * CurrentTime + StartValue
                else
                begin
                  CurrentTime := CurrentTime - 2;
    
                  Result := ChangeInValue / 2 * (CurrentTime * CurrentTime * CurrentTime + 2) + StartValue;
                end;
              end;
    
            ttEaseInQuart:
              begin
                CurrentTime := CurrentTime / Duration;
    
                Result := ChangeInValue * CurrentTime * CurrentTime * CurrentTime * CurrentTime + StartValue;
              end;
    
            ttEaseOutQuart:
              begin
                CurrentTime := (CurrentTime / Duration) - 1;
    
                Result := -ChangeInValue * (CurrentTime * CurrentTime * CurrentTime * CurrentTime - 1) + StartValue;
              end;
    
            ttEaseInOutQuart:
              begin
                  CurrentTime := CurrentTime / (Duration / 2);
    
                if CurrentTime < 1 then
                  Result := ChangeInValue / 2 * CurrentTime * CurrentTime * CurrentTime * CurrentTime + StartValue
                else
                begin
                  CurrentTime := CurrentTime - 2;
    
                  Result := -ChangeInValue / 2 * (CurrentTime * CurrentTime * CurrentTime * CurrentTime - 2) + StartValue;
                end;
              end;
    
            ttEaseInQuint:
              begin
                CurrentTime := CurrentTime / Duration;
    
                Result := ChangeInValue * CurrentTime * CurrentTime * CurrentTime * CurrentTime * CurrentTime + StartValue;
              end;
    
            ttEaseOutQuint:
              begin
                CurrentTime := (CurrentTime / Duration) - 1;
    
                  Result := ChangeInValue * (CurrentTime * CurrentTime * CurrentTime * CurrentTime * CurrentTime + 1) + StartValue;
              end;
    
            ttEaseInOutQuint:
              begin
                CurrentTime := CurrentTime / (Duration / 2);
                if CurrentTime < 1 then
                  Result := ChangeInValue / 2 * CurrentTime * CurrentTime * CurrentTime * CurrentTime * CurrentTime + StartValue
                else
                begin
                  CurrentTime := CurrentTime - 2;
    
                  Result := ChangeInValue / 2 * (CurrentTime * CurrentTime * CurrentTime * CurrentTime * CurrentTime + 2) + StartValue;
                end;
              end;
    
            ttEaseInSine:
              begin
                  Result := -ChangeInValue * Cos(CurrentTime / Duration * (PI / 2)) + ChangeInValue + StartValue;
              end;
    
            ttEaseOutSine:
              begin
                  Result := ChangeInValue * Sin(CurrentTime / Duration * (PI / 2)) + StartValue;
              end;
    
            ttEaseInOutSine:
              begin
                Result := -ChangeInValue / 2 * (Cos(PI * CurrentTime / Duration) - 1) + StartValue;
              end;
    
            ttEaseInExpo:
              begin
                Result := ChangeInValue * Power(2, 10 * (CurrentTime/Duration - 1) ) + StartValue;
              end;
    
            ttEaseOutExpo:
              begin
                Result := ChangeInValue * (-Power(2, -10 * CurrentTime / Duration ) + 1 ) + StartValue;
              end;
    
            ttEaseInOutExpo:
              begin
                CurrentTime := CurrentTime / (Duration/2);
    
                if CurrentTime < 1 then
                  Result := ChangeInValue / 2 * Power(2, 10 * (CurrentTime - 1) ) + StartValue
                else
                 begin
                   CurrentTime := CurrentTime - 1;
    
                     Result := ChangeInValue / 2 * (-Power(2, -10 * CurrentTime) + 2 ) + StartValue;
                 end;
              end;
    
            ttEaseInCirc:
              begin
                CurrentTime := CurrentTime / Duration;
    
                  Result := -ChangeInValue * (Sqrt(1 - CurrentTime * CurrentTime) - 1) + StartValue;
              end;
    
            ttEaseOutCirc:
              begin
                CurrentTime := (CurrentTime / Duration) - 1;
    
                Result := ChangeInValue * Sqrt(1 - CurrentTime * CurrentTime) + StartValue;
              end;
    
            ttEaseInOutCirc:
              begin
                CurrentTime := CurrentTime / (Duration / 2);
    
                if CurrentTime < 1 then
                  Result := -ChangeInValue / 2 * (Sqrt(1 - CurrentTime * CurrentTime) - 1) + StartValue
                else
                begin
                    CurrentTime := CurrentTime - 2;
    
                    Result := ChangeInValue / 2 * (Sqrt(1 - CurrentTime * CurrentTime) + 1) + StartValue;
                end;
              end;
          end;
        end;
    
        function CalculateEase(StartPos, EndPos, PositionPct: Real; EaseType: TChromeTabsEaseType): Real;
        var
          t, b, c, d: Real;
        begin
          c := EndPos - StartPos;
          d := 100;
          t := PositionPct;
          b := StartPos;
    
          Result := CalculateEase(t, b, c, d, EaseType);
        end;
    
        ...