L'interface de l'application de test
Maintenant que nous avons fait le tour des fonctions d'easing nécessaires, il est temps de proposer une application de test : nous allons enfin voir ces fonctions à l’œuvre ! L'objectif de l'application sera simple : des boutons feront l'aller et retour d'une zone de déplacement selon la fonction d'easing qui leur sera affectée.
Pour un aperçu efficace des courbes d'easing, nous allons créer une application sans prétention dont l'interface ressemblera à ceci :
447705
Nous reconnaissons :
- trois zones délimitées par des panneaux TPanel (un pour les contrôles de types Out ou In, un pour les contrôles de types InOut ou OutIn et un pour un composant TTrackbar afin d'ajuster la vitesse de l'animation ;
- une séparation ajustable TSplitter entre les deux panneaux supérieurs afin de moduler les distances à parcourir par les contrôles animés (elle est à deviner ;) ) ;
- des boutons TButton qui serviront d'objets animés (21 dans chaque panneau : 1 pour un repère linéaire et 10 pour chaque type).
Voici le fichier LFM correspondant :
object MainForm: TMainForm
Left = 304
Height = 623
Top = 197
Width = 953
Caption = 'Test des interpolations - © G. Vasseur 2019'
ClientHeight = 623
ClientWidth = 953
OnCreate = FormCreate
LCLVersion = '1.8.2.0'
object pnlMain: TPanel
Left = 10
Height = 553
Top = 10
Width = 933
Align = alClient
BorderSpacing.Around = 10
ClientHeight = 553
ClientWidth = 933
TabOrder = 0
OnClick = btnLinear2Click
object pnlLeft: TPanel
Left = 1
Height = 551
Top = 1
Width = 474
Align = alLeft
ClientHeight = 551
ClientWidth = 474
TabOrder = 0
OnClick = btnLinear2Click
object btnEaseOutBounce: TButton
Left = 0
Height = 25
Top = 256
Width = 120
Caption = 'EaseOutBounce'
OnClick = btnEaseOutQuadClick
TabOrder = 0
end
object btnEaseOutBack: TButton
Left = 0
Height = 25
Top = 232
Width = 120
Caption = 'EaseOutBack'
OnClick = btnEaseOutQuadClick
TabOrder = 1
end
object btnEaseOutElastic: TButton
Left = 0
Height = 25
Top = 208
Width = 120
Caption = 'EaseOutElastic'
OnClick = btnEaseOutQuadClick
TabOrder = 2
end
object btnEaseOutCirc: TButton
Left = 0
Height = 25
Top = 184
Width = 120
Caption = 'EaseOutCirc'
OnClick = btnEaseOutQuadClick
TabOrder = 3
end
object btnEaseOutSine: TButton
Left = 0
Height = 25
Top = 136
Width = 120
Caption = 'EaseOutSine'
OnClick = btnEaseOutQuadClick
TabOrder = 4
end
object btnEaseOutQuint: TButton
Left = 0
Height = 25
Top = 112
Width = 120
Caption = 'EaseOutQuint'
OnClick = btnEaseOutQuadClick
TabOrder = 5
end
object btnEaseOutQuad: TButton
Left = 0
Height = 25
Top = 40
Width = 120
Caption = 'EaseOutQuad'
OnClick = btnEaseOutQuadClick
TabOrder = 6
end
object btnEaseOutCubic: TButton
Left = 0
Height = 25
Top = 64
Width = 120
Caption = 'EaseOutCubic'
OnClick = btnEaseOutQuadClick
TabOrder = 7
end
object btnEaseOutQuart: TButton
Left = 0
Height = 25
Top = 88
Width = 120
Caption = 'EaseOutQuart'
OnClick = btnEaseOutQuadClick
TabOrder = 8
end
object btnEaseOutExpo: TButton
Left = 0
Height = 25
Top = 160
Width = 120
Caption = 'EaseOutExpo'
OnClick = btnEaseOutQuadClick
TabOrder = 9
end
object btnEaseInQuad: TButton
Left = 1
Height = 25
Top = 296
Width = 120
Caption = 'EaseInQuad'
OnClick = btnEaseInQuadClick
TabOrder = 10
end
object btnEaseInCubic: TButton
Left = 1
Height = 25
Top = 320
Width = 120
Caption = 'EaseInCubic'
OnClick = btnEaseInQuadClick
TabOrder = 11
end
object btnEaseInQuart: TButton
Left = 1
Height = 25
Top = 344
Width = 120
Caption = 'EaseInQuart'
OnClick = btnEaseInQuadClick
TabOrder = 12
end
object btnEaseInQuint: TButton
Left = 1
Height = 25
Top = 368
Width = 120
Caption = 'EaseInQuint'
OnClick = btnEaseInQuadClick
TabOrder = 13
end
object btnEaseInSine: TButton
Left = 1
Height = 25
Top = 392
Width = 120
Caption = 'EaseInSine'
OnClick = btnEaseInQuadClick
TabOrder = 14
end
object btnEaseInExpo: TButton
Left = 1
Height = 25
Top = 416
Width = 120
Caption = 'EaseInExpo'
OnClick = btnEaseInQuadClick
TabOrder = 15
end
object btnEaseInCirc: TButton
Left = 1
Height = 25
Top = 440
Width = 120
Caption = 'EaseInCirc'
OnClick = btnEaseInQuadClick
TabOrder = 16
end
object btnEaseInElastic: TButton
Left = 1
Height = 25
Top = 464
Width = 120
Caption = 'EaseInElastic'
OnClick = btnEaseInQuadClick
TabOrder = 17
end
object btnEaseInBack: TButton
Left = 1
Height = 25
Top = 488
Width = 120
Caption = 'EaseInBack'
OnClick = btnEaseInQuadClick
TabOrder = 18
end
object btnEaseInBounce: TButton
Left = 1
Height = 25
Top = 512
Width = 120
Caption = 'EaseInBounce'
OnClick = btnEaseInQuadClick
TabOrder = 19
end
object btnLinear: TButton
Left = 0
Height = 25
Top = 8
Width = 120
Caption = 'Linear'
Font.Style =
OnClick = btnLinear2Click
ParentFont = False
TabOrder = 20
end
end
object pnlRight: TPanel
Left = 480
Height = 551
Top = 1
Width = 452
Align = alClient
ClientHeight = 551
ClientWidth = 452
TabOrder = 1
OnClick = btnLinear2Click
object btnLinear2: TButton
Left = 0
Height = 25
Top = 8
Width = 120
Caption = 'Linear'
Font.Style =
OnClick = btnLinear2Click
ParentFont = False
TabOrder = 0
end
object btnEaseInOutCubic: TButton
Left = 0
Height = 25
Top = 320
Width = 120
Caption = 'EaseInOutCubic'
OnClick = btnEaseInOutQuadClick
TabOrder = 1
end
object btnEaseInOutQuart: TButton
Left = 0
Height = 25
Top = 344
Width = 120
Caption = 'EaseInOutQuart'
OnClick = btnEaseInOutQuadClick
TabOrder = 2
end
object btnEaseOutInQuart: TButton
Left = 0
Height = 25
Top = 88
Width = 120
Caption = 'EaseOutInQuart'
OnClick = btnEaseOutInQuadClick
TabOrder = 3
end
object btnEaseOutInCubic: TButton
Left = 0
Height = 25
Top = 64
Width = 120
Caption = 'EaseOutInCubic'
OnClick = btnEaseOutInQuadClick
TabOrder = 4
end
object btnEaseOutInQuint: TButton
Left = 0
Height = 25
Top = 112
Width = 120
Caption = 'EaseOutInQuint'
OnClick = btnEaseOutInQuadClick
TabOrder = 5
end
object btnEaseInOutQuint: TButton
Left = 0
Height = 25
Top = 368
Width = 120
Caption = 'EaseInOutQuint'
OnClick = btnEaseInOutQuadClick
TabOrder = 6
end
object btnEaseOutInSine: TButton
Left = 0
Height = 25
Top = 136
Width = 120
Caption = 'EaseOutInSine'
OnClick = btnEaseOutInQuadClick
TabOrder = 7
end
object btnEaseInOutQuad: TButton
Left = 0
Height = 25
Top = 296
Width = 120
Caption = 'EaseInOutQuad'
OnClick = btnEaseInOutQuadClick
TabOrder = 8
end
object btnEaseOutInQuad: TButton
Left = 0
Height = 25
Top = 40
Width = 120
Caption = 'EaseOutInQuad'
OnClick = btnEaseOutInQuadClick
TabOrder = 9
end
object btnEaseInOutSine: TButton
Left = 0
Height = 25
Top = 392
Width = 120
Caption = 'EaseInOutSine'
OnClick = btnEaseInOutQuadClick
TabOrder = 10
end
object btnEaseOutInCirc: TButton
Left = 0
Height = 25
Top = 184
Width = 120
Caption = 'EaseOutInCirc'
OnClick = btnEaseOutInQuadClick
TabOrder = 11
end
object btnEaseOutInElastic: TButton
Left = 0
Height = 25
Top = 208
Width = 120
Caption = 'EaseOutInElastic'
OnClick = btnEaseOutInQuadClick
TabOrder = 12
end
object btnEaseOutInBack: TButton
Left = 0
Height = 25
Top = 232
Width = 120
Caption = 'EaseOutInBack'
OnClick = btnEaseOutInQuadClick
TabOrder = 13
end
object btnEaseOutInBounce: TButton
Left = 0
Height = 25
Top = 256
Width = 120
Caption = 'EaseOutInBounce'
OnClick = btnEaseOutInQuadClick
TabOrder = 14
end
object btnEaseOutInExpo: TButton
Left = 0
Height = 25
Top = 160
Width = 120
Caption = 'EaseOutInExpo'
OnClick = btnEaseOutInQuadClick
TabOrder = 15
end
object btnEaseInOutExpo: TButton
Left = 0
Height = 25
Top = 416
Width = 120
Caption = 'EaseInOutExpo'
OnClick = btnEaseInOutQuadClick
TabOrder = 16
end
object btnEaseInOutCirc: TButton
Left = 0
Height = 25
Top = 440
Width = 120
Caption = 'EaseInOutCirc'
OnClick = btnEaseInOutQuadClick
TabOrder = 17
end
object btnEaseInOutElastic: TButton
Left = 0
Height = 25
Top = 464
Width = 120
Caption = 'EaseInOutElastic'
OnClick = btnEaseInOutQuadClick
TabOrder = 18
end
object btnEaseInOutBack: TButton
Left = 0
Height = 25
Top = 488
Width = 120
Caption = 'EaseInOutBack'
OnClick = btnEaseInOutQuadClick
TabOrder = 19
end
object btnEaseInOutBounce: TButton
Left = 0
Height = 25
Top = 512
Width = 120
Caption = 'EaseInOutBounce'
OnClick = btnEaseInOutQuadClick
TabOrder = 20
end
end
object Splitter1: TSplitter
Left = 475
Height = 551
Top = 1
Width = 5
end
end
object pnlBottom: TPanel
Left = 0
Height = 50
Top = 573
Width = 953
Align = alBottom
BorderSpacing.InnerBorder = 10
ClientHeight = 50
ClientWidth = 953
TabOrder = 1
object tbarWait: TTrackBar
Left = 11
Height = 28
Top = 11
Width = 301
Max = 100
OnChange = tbarWaitChange
Position = 0
Align = alLeft
BorderSpacing.Around = 10
TabOrder = 0
end
end
end
Ce long listing ne doit pas effrayer : en fait, il indique où sont placés les composants (ce qui peut varier selon vos goûts), leur intitulé (qui correspond pour les boutons à la fonction représentée), leur taille (les boutons ont tous une largeur de 120, mais cette valeur est indicative) ainsi que le gestionnaire d'événement OnClick associé (les boutons sont regroupés par catégories comme le montrera le code). De toute façon, le code source complet de l'unité est fourni à la fin de billet.
Comme annoncé, vous noterez la présence d'un TTrackbar qui déterminera la vitesse (de manière très grossière pour le moment) d'exécution des interpolations, ainsi que d'un TSplitter dont la fonction sera de modifier à volonté la largeur des zones de déplacement afin de voir comment se comportent les fonctions sur des trajets plus ou moins longs.
:arrow: Aucune action n'est nécessaire pour le TSplitter qui saura dimensionner les panneaux suivant le choix de l'utilisateur final.
Le code associé à l'application
Le code reprend celui décrit dans les billets précédents, mais il ajoute la gestion des clics sur les boutons. Sachant que les coordonnées des boutons sont des entiers, on a simplement introduit une variante à valeur entière des différentes interpolations qui utilisaient des nombres flottants Single.
Une fois toutes les fonctions solidement définies, le reste de l'application ne met en œuvre que des techniques habituelles.
Nous déclarons des constantes pour la valeur de fin à atteindre et la durée par défaut ainsi qu'une énumération afin de différencier les interpolations :
const
C_DefaultDuration = 100;
C_End = 200;
type
TInterpolation = (intLinear,
intEaseInQuad, intEaseOutQuad, intEaseInOutQuad, intEaseOutInQuad,
intEaseInCubic, intEaseOutCubic, intEaseInOutCubic, intEaseOutInCubic,
intEaseInQuart, intEaseOutQuart, intEaseInOutQuart, intEaseOutInQuart,
intEaseInQuint, intEaseOutQuint, intEaseInOutQuint, intEaseOutInQuint,
intEaseInSine, intEaseOutSine, intEaseInOutSine, intEaseOutInSine,
intEaseInExpo, intEaseOutExpo, intEaseInOutExpo, intEaseOutInExpo,
intEaseInCirc, intEaseOutCirc, intEaseInOutCirc, intEaseOutInCirc,
intEaseInElastic, intEaseOutElastic, intEaseInOutElastic, intEaseOutInElastic,
intEaseInBack, intEaseOutBack, intEaseInOutBack, intEaseOutInBack,
intEaseInBounce, intEaseOutBounce, intEaseInOutBounce, intEaseOutInBounce
);
Les clics ont été modulés ainsi : un clic sur un des boutons de référence (btnLinear et btnLinear2), c'est-à-dire suivant un parcours linéaire, provoque le déplacement des tous les boutons. En revanche, un clic sur un autre bouton provoque seulement le déplacement de son groupe (Out, In, OutIn ou InOut).
Voici le code associé aux premiers boutons dits de référence :
procedure TMainForm.btnLinear2Click(Sender: TObject);
// *** lancement des animations ***
var
Li, LWidth, LWidth2: Integer;
LBack: Boolean;
begin
tbarWait.Enabled := False;
LWidth := pnlLeft.Width - btnLinear2.Width;
LWidth2 := pnlRight.Width - btnLinear.Width;
for LBack := False to True do
for Li := 1 to fDuration do
begin
btnLinear.Left := ComputeInterpolationInt(0, LWidth, Li, intLinear, LBack);
btnLinear2.Left := ComputeInterpolationInt(0, LWidth2, Li, intLinear, LBack);
btnEaseInQuad.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuad, LBack);
btnEaseOutQuad.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuad, LBack);
btnEaseInOutQuad.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuad, LBack);
btnEaseOutInQuad.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuad, LBack);
btnEaseInCubic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCubic, LBack);
btnEaseOutCubic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutCubic, LBack);
btnEaseInOutCubic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutCubic, LBack);
btnEaseOutInCubic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInCubic, LBack);
btnEaseInQuart.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuart, LBack);
btnEaseOutQuart.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuart, LBack);
btnEaseInOutQuart.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuart, LBack);
btnEaseOutInQuart.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuart, LBack);
btnEaseInQuint.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuint, LBack);
btnEaseOutQuint.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuint, LBack);
btnEaseInOutQuint.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuint, LBack);
btnEaseOutInQuint.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuint, LBack);
btnEaseInSine.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInSine, LBack);
btnEaseOutSine.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutSine, LBack);
btnEaseInOutSine.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutSine, LBack);
btnEaseOutInSine.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInSine, LBack);
btnEaseInExpo.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInExpo, LBack);
btnEaseOutExpo.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutExpo, LBack);
btnEaseInOutExpo.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutExpo, LBack);
btnEaseOutInExpo.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInExpo, LBack);
btnEaseInCirc.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCirc, LBack);
btnEaseOutCirc.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutCirc, LBack);
btnEaseInOutCirc.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutCirc, LBack);
btnEaseOutInCirc.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInCirc, LBack);
btnEaseInElastic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInElastic, LBack);
btnEaseOutElastic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutElastic, LBack);
btnEaseInOutElastic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutElastic, LBack);
btnEaseOutInElastic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInElastic, LBack);
btnEaseInBack.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBack, LBack);
btnEaseOutBack.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutBack, LBack);
btnEaseInOutBack.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutBack, LBack);
btnEaseOutInBack.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInBack, LBack);
btnEaseInBounce.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBounce, LBack);
btnEaseOutBounce.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutBounce, LBack);
btnEaseInOutBounce.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutBounce, LBack);
btnEaseOutInBounce.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInBounce, LBack);
sleep(10);
Repaint;
Application.ProcessMessages;
end;
tbarWait.Enabled := True;
end;
Dans deux boucles imbriquées qui prennent en compte le sens du déplacement (booléen Back) et la portion de durée effectuée (Li pour fDuration), les boutons sont tous déplacés grâce à la modification de leur propriété Left.
C'est le résultat entier de la fonction ComputeInterpolationInt qui est affecté à cette propriété Left de chaque bouton. La fonction calcule la valeur à retourner en fonction du point de départ, du point d'arrivée, du type d'interpolation et du sens de déplacement.
Après le déplacement, un temps d'arrêt est donné via sleep pour éviter une exécution trop rapide, la zone d'affichage est repeinte avec Repaint pour prendre en compte les changements et un appel est fait à Application.ProcessMessages pour répondre aux éventuels messages non traités (comme l'arrêt de l'application par exemple).
Vous remarquerez que le TTrackBar est désactivé pendant les mouvements afin de garantir l'homogénéité des données durant le processus d'interpolation.
De la même manière, voici le code correspondant aux clics sur les boutons de type In :
procedure TMainForm.btnEaseInQuadClick(Sender: TObject);
// *** fonctions IN ***
var
Li, LWidth: Integer;
LBack: Boolean;
begin
tbarWait.Enabled := False;
LWidth := pnlLeft.Width - btnLinear2.Width;
for LBack := False to True do
for Li := 1 to fDuration do
begin
btnLinear.Left := ComputeInterpolationInt(0, LWidth, Li, intLinear, LBack);
btnEaseInQuad.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuad, LBack);
btnEaseInCubic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCubic, LBack);
btnEaseInQuart.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuart, LBack);
btnEaseInQuint.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuint, LBack);
btnEaseInSine.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInSine, LBack);
btnEaseInExpo.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInExpo, LBack);
btnEaseInCirc.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCirc, LBack);
btnEaseInElastic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInElastic, LBack);
btnEaseInBack.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBack, LBack);
btnEaseInBounce.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBounce, LBack);
sleep(10);
pnlLeft.Repaint;
Application.ProcessMessages;
end;
tbarWait.Enabled := True;
end;
Le code est similaire au précédent sinon que seuls sont affectés les boutons visés et que la méthode Repaint n'affecte que le panneau modifié. Nous renvoyons au code fourni à la fin de ce billet pour les autres types de fonction : il est évidemment construit sur le même modèle.
Reste à gérer la durée qui est une propriété nommée Duration qui elle-même fait référence à un champ privé fDuration à travers un setter :
property Duration: Cardinal read fDuration write SetDuration default C_DefaultDuration;
Le setter peut sembler superflu, mais il prépare une meilleure gestion de la durée qui n'est pour le moment qu'une suite linéaire de valeurs entières.
Les méthodes associées sont simples et en relation avec le composant TTrackbar qui fournit la valeur brute de la durée :
procedure TMainForm.tbarWaitChange(Sender: TObject);
// *** changement de la vitesse ***
begin
Duration := tbarWait.Position;
end;
procedure TMainForm.SetDuration(AValue: Cardinal);
// *** détermination de la durée d'interpolation ***
begin
if fDuration = C_End - AValue then
Exit;
fDuration := C_End - AValue;
end;
Il ne reste que la création de la fiche à compléter pour obtenir une application fonctionnelle :
procedure TMainForm.FormCreate(Sender: TObject);
// *** création de la fiche ***
begin
Duration := C_DefaultDuration;
tbarWait.Max := C_End;
tbarWait.Position := fDuration;
end;
Nous devons en effet renseigner la valeur de la durée par défaut et ajuster correctement les propriétés du composant TTrackbar.
La méthode ComputeInterpolationInt renvoie à une méthode ComputeInterpolation calquée sur les fonctions que nous avions déjà produites :
function TMainForm.ComputeInterpolationInt(AStart, AEnd: Integer;
AStep: Integer; AInter: TInterpolation; ABack: Boolean): Integer;
// *** interpolation entière ***
begin
Result := Round(ComputeInterpolation(AStart, AEnd, AStep, AInter, ABack));
end;
Voici le code de cette méthode ComputeInterpolation :
function TMainForm.ComputeInterpolation(AStart, AEnd, AStep: Single;
AInter: TInterpolation; ABack: Boolean): Single;
// *** calcul des interpolations ***
begin
case AInter of
// linéaire
intLinear: Result := EaseNone(AStart, AEnd, AStep);
// quadratique
intEaseInQuad: Result := EaseInQuad(AStart, AEnd, AStep);
intEaseOutQuad: Result := EaseOutQuad(AStart, AEnd, AStep);
intEaseInOutQuad: Result := EaseInOutQuad(AStart, AEnd, AStep);
intEaseOutInQuad: Result := EaseOutInQuad(AStart, AEnd, AStep);
// cubique
intEaseInCubic: Result := EaseInCubic(AStart, AEnd, AStep);
intEaseOutCubic: Result := EaseOutCubic(AStart, AEnd, AStep);
intEaseInOutCubic: Result := EaseInOutCubic(AStart, AEnd, AStep);
intEaseOutInCubic: Result := EaseOutInCubic(AStart, AEnd, AStep);
// quartique
intEaseInQuart: Result := EaseInQuart(AStart, AEnd, AStep);
intEaseOutQuart: Result := EaseOutQuart(AStart, AEnd, AStep);
intEaseInOutQuart: Result := EaseInOutQuart(AStart, AEnd, AStep);
intEaseOutInQuart: Result := EaseOutInQuart(AStart, AEnd, AStep);
// quintique
intEaseInQuint: Result := EaseInQuint(AStart, AEnd, AStep);
intEaseOutQuint: Result := EaseOutQuint(AStart, AEnd, AStep);
intEaseInOutQuint: Result := EaseInOutQuint(AStart, AEnd, AStep);
intEaseOutInQuint: Result := EaseOutInQuint(AStart, AEnd, AStep);
// sinus
intEaseInSine: Result := EaseInSine(AStart, AEnd, AStep);
intEaseOutSine: Result := EaseOutSine(AStart, AEnd, AStep);
intEaseInOutSine: Result := EaseInOutSine(AStart, AEnd, AStep);
intEaseOutInSine: Result := EaseOutInSine(AStart, AEnd, AStep);
// exponentielle
intEaseInExpo: Result := EaseInExpo(AStart, AEnd, AStep);
intEaseOutExpo: Result := EaseOutExpo(AStart, AEnd, AStep);
intEaseInOutExpo: Result := EaseInOutExpo(AStart, AEnd, AStep);
intEaseOutInExpo: Result := EaseOutInExpo(AStart, AEnd, AStep);
// cercle
intEaseInCirc: Result := EaseInCirc(AStart, AEnd, AStep);
intEaseOutCirc: Result := EaseOutCirc(AStart, AEnd, AStep);
intEaseInOutCirc: Result := EaseInOutCirc(AStart, AEnd, AStep);
intEaseOutInCirc: Result := EaseOutInCirc(AStart, AEnd, AStep);
// élastique
intEaseInElastic: Result := EaseInElastic(AStart, AEnd, AStep);
intEaseOutElastic: Result := EaseOutElastic(AStart, AEnd, AStep);
intEaseInOutElastic: Result := EaseInOutElastic(AStart, AEnd, AStep);
intEaseOutInElastic: Result := EaseOutInElastic(AStart, AEnd, AStep);
// retour
intEaseInBack: Result := EaseInBack(AStart, AEnd, AStep);
intEaseOutBack: Result := EaseOutBack(AStart, AEnd, AStep);
intEaseInOutBack: Result := EaseInOutBack(AStart, AEnd, AStep);
intEaseOutInBack: Result := EaseOutInBack(AStart, AEnd, AStep);
// rebond
intEaseInBounce: Result := EaseInBounce(AStart, AEnd, AStep);
intEaseOutBounce: Result := EaseOutBounce(AStart, AEnd, AStep);
intEaseInOutBounce: Result := EaseInOutBounce(AStart, AEnd, AStep);
intEaseOutInBounce: Result := EaseOutInBounce(AStart, AEnd, AStep);
end;
if ABack then
Result := AEnd - Result;
end;
Comme attendu, elle fonctionne à la manière d'une gare de triage selon la fonction d'easing voulue.
Finalement, l'unité complète donnera :
{¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤@
@ @
@ Nom du produit : GVTransitions - interpolations 02 @
@ Nom du fichier : main.pas @
@ Copyright : G. Vasseur 2019 @
@ Contact : gillesvasseur58@gmail.com @
@ Date/Heure : 05/02/2019 12:20:05 @
@ Version : 1.0.0.14 @
@ @
@¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤}
{ Transitions entre deux images - interpolations
Copyright (C) 05/02/2019 12:20:05 G. Vasseur 2018 gillesvasseur58@gmail.com
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
StdCtrls, ComCtrls;
const
C_DefaultDuration = 100;
C_End = 200;
type
TInterpolation = (intLinear,
intEaseInQuad, intEaseOutQuad, intEaseInOutQuad, intEaseOutInQuad,
intEaseInCubic, intEaseOutCubic, intEaseInOutCubic, intEaseOutInCubic,
intEaseInQuart, intEaseOutQuart, intEaseInOutQuart, intEaseOutInQuart,
intEaseInQuint, intEaseOutQuint, intEaseInOutQuint, intEaseOutInQuint,
intEaseInSine, intEaseOutSine, intEaseInOutSine, intEaseOutInSine,
intEaseInExpo, intEaseOutExpo, intEaseInOutExpo, intEaseOutInExpo,
intEaseInCirc, intEaseOutCirc, intEaseInOutCirc, intEaseOutInCirc,
intEaseInElastic, intEaseOutElastic, intEaseInOutElastic, intEaseOutInElastic,
intEaseInBack, intEaseOutBack, intEaseInOutBack, intEaseOutInBack,
intEaseInBounce, intEaseOutBounce, intEaseInOutBounce, intEaseOutInBounce
);
{ TMainForm }
TMainForm = class(TForm)
btnEaseOutInQuart: TButton;
btnLinear2: TButton;
btnEaseInQuad: TButton;
btnEaseOutCubic: TButton;
btnEaseInCubic: TButton;
btnEaseOutQuad: TButton;
btnEaseInOutCubic: TButton;
btnEaseInOutQuart: TButton;
btnEaseOutInCubic: TButton;
btnEaseInQuart: TButton;
btnEaseOutQuart: TButton;
btnEaseInQuint: TButton;
btnEaseOutQuint: TButton;
btnEaseOutInQuint: TButton;
btnEaseInOutQuint: TButton;
btnEaseInSine: TButton;
btnEaseOutSine: TButton;
btnEaseInOutSine: TButton;
btnEaseOutInSine: TButton;
btnEaseInOutQuad: TButton;
btnEaseOutInQuad: TButton;
btnEaseInExpo: TButton;
btnEaseInCirc: TButton;
btnEaseInElastic: TButton;
btnEaseInBack: TButton;
btnEaseInBounce: TButton;
btnEaseOutCirc: TButton;
btnEaseOutElastic: TButton;
btnEaseOutBack: TButton;
btnEaseOutBounce: TButton;
btnEaseOutExpo: TButton;
btnLinear: TButton;
btnEaseOutInCirc: TButton;
btnEaseOutInElastic: TButton;
btnEaseOutInBack: TButton;
btnEaseOutInBounce: TButton;
btnEaseInOutExpo: TButton;
btnEaseInOutCirc: TButton;
btnEaseInOutElastic: TButton;
btnEaseInOutBack: TButton;
btnEaseOutInExpo: TButton;
btnEaseInOutBounce: TButton;
pnlRight: TPanel;
pnlLeft: TPanel;
pnlBottom: TPanel;
pnlMain: TPanel;
Splitter1: TSplitter;
tbarWait: TTrackBar;
procedure btnEaseInOutQuadClick(Sender: TObject);
procedure btnEaseInQuadClick(Sender: TObject);
procedure btnEaseOutInQuadClick(Sender: TObject);
procedure btnEaseOutQuadClick(Sender: TObject);
procedure btnLinear2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure tbarWaitChange(Sender: TObject);
private
fDuration: Cardinal;
procedure SetDuration(AValue: Cardinal);
function InPower(AStart, AChange, AStep: Single; APower: Integer): Single;
function OutPower(AStart, AChange, AStep: Single; APower: Integer): Single;
function InOutPower(AStart, AChange, AStep: Single; APower: Integer): Single;
protected
function EaseNone(AStart, AChange, AStep: Single): Single;
function EaseInQuad(AStart, AChange, AStep: Single): Single;
function EaseOutQuad(AStart, AChange, AStep: Single): Single;
function EaseInOutQuad(AStart, AChange, AStep: Single): Single;
function EaseOutInQuad(AStart, AChange, AStep: Single): Single;
function EaseInCubic(AStart, AChange, AStep: Single): Single;
function EaseOutCubic(AStart, AChange, AStep: Single): Single;
function EaseInOutCubic(AStart, AChange, AStep: Single): Single;
function EaseOutInCubic(AStart, AChange, AStep: Single): Single;
function EaseInQuart(AStart, AChange, AStep: Single): Single;
function EaseOutQuart(AStart, AChange, AStep: Single): Single;
function EaseInOutQuart(AStart, AChange, AStep: Single): Single;
function EaseOutInQuart(AStart, AChange, AStep: Single): Single;
function EaseInQuint(AStart, AChange, AStep: Single): Single;
function EaseOutQuint(AStart, AChange, AStep: Single): Single;
function EaseInOutQuint(AStart, AChange, AStep: Single): Single;
function EaseOutInQuint(AStart, AChange, AStep: Single): Single;
function EaseInSine(AStart, AChange, AStep: Single): Single;
function EaseOutSine(AStart, AChange, AStep: Single): Single;
function EaseInOutSine(AStart, AChange, AStep: Single): Single;
function EaseOutInSine(AStart, AChange, AStep: Single): Single;
function EaseInExpo(AStart, AChange, AStep: Single): Single;
function EaseOutExpo(AStart, AChange, AStep: Single): Single;
function EaseInOutExpo(AStart, AChange, AStep: Single): Single;
function EaseOutInExpo(AStart, AChange, AStep: Single): Single;
function EaseInCirc(AStart, AChange, AStep: Single): Single;
function EaseOutCirc(AStart, AChange, AStep: Single): Single;
function EaseInOutCirc(AStart, AChange, AStep: Single): Single;
function EaseOutInCirc(AStart, AChange, AStep: Single): Single;
function EaseInElastic(AStart, AChange, AStep: Single): Single;
function EaseOutElastic(AStart, AChange, AStep: Single): Single;
function EaseInOutElastic(AStart, AChange, AStep: Single): Single;
function EaseOutInElastic(AStart, AChange, AStep: Single): Single;
function EaseInBack(AStart, AChange, AStep: Single): Single;
function EaseOutBack(AStart, AChange, AStep: Single): Single;
function EaseInOutBack(AStart, AChange, AStep: Single): Single;
function EaseOutInBack(AStart, AChange, AStep: Single): Single;
function EaseInOutBounce(AStart, AChange, AStep: Single): Single;
function EaseOutInBounce(AStart, AChange, AStep: Single): Single;
function EaseInBounce(AStart, AChange, AStep: Single): Single;
function EaseOutBounce(AStart, AChange, AStep: Single): Single;
public
property Duration: Cardinal read fDuration write SetDuration default C_DefaultDuration;
function ComputeInterpolation(AStart, AEnd, AStep: Single; AInter: TInterpolation;
ABack: Boolean = False): Single;
function ComputeInterpolationInt(AStart, AEnd: Integer; AStep: Integer; AInter: TInterpolation;
ABack: Boolean = False): Integer;
end;
var
MainForm: TMainForm;
implementation
uses
math;
{$R *.lfm}
{ TMainForm }
procedure TMainForm.btnLinear2Click(Sender: TObject);
// *** lancement des animations ***
var
Li, LWidth, LWidth2: Integer;
LBack: Boolean;
begin
tbarWait.Enabled := False;
LWidth := pnlLeft.Width - btnLinear2.Width;
LWidth2 := pnlRight.Width - btnLinear.Width;
for LBack := False to True do
for Li := 1 to fDuration do
begin
btnLinear.Left := ComputeInterpolationInt(0, LWidth, Li, intLinear, LBack);
btnLinear2.Left := ComputeInterpolationInt(0, LWidth2, Li, intLinear, LBack);
btnEaseInQuad.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuad, LBack);
btnEaseOutQuad.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuad, LBack);
btnEaseInOutQuad.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuad, LBack);
btnEaseOutInQuad.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuad, LBack);
btnEaseInCubic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCubic, LBack);
btnEaseOutCubic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutCubic, LBack);
btnEaseInOutCubic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutCubic, LBack);
btnEaseOutInCubic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInCubic, LBack);
btnEaseInQuart.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuart, LBack);
btnEaseOutQuart.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuart, LBack);
btnEaseInOutQuart.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuart, LBack);
btnEaseOutInQuart.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuart, LBack);
btnEaseInQuint.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuint, LBack);
btnEaseOutQuint.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuint, LBack);
btnEaseInOutQuint.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuint, LBack);
btnEaseOutInQuint.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuint, LBack);
btnEaseInSine.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInSine, LBack);
btnEaseOutSine.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutSine, LBack);
btnEaseInOutSine.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutSine, LBack);
btnEaseOutInSine.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInSine, LBack);
btnEaseInExpo.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInExpo, LBack);
btnEaseOutExpo.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutExpo, LBack);
btnEaseInOutExpo.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutExpo, LBack);
btnEaseOutInExpo.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInExpo, LBack);
btnEaseInCirc.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCirc, LBack);
btnEaseOutCirc.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutCirc, LBack);
btnEaseInOutCirc.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutCirc, LBack);
btnEaseOutInCirc.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInCirc, LBack);
btnEaseInElastic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInElastic, LBack);
btnEaseOutElastic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutElastic, LBack);
btnEaseInOutElastic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutElastic, LBack);
btnEaseOutInElastic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInElastic, LBack);
btnEaseInBack.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBack, LBack);
btnEaseOutBack.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutBack, LBack);
btnEaseInOutBack.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutBack, LBack);
btnEaseOutInBack.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInBack, LBack);
btnEaseInBounce.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBounce, LBack);
btnEaseOutBounce.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutBounce, LBack);
btnEaseInOutBounce.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutBounce, LBack);
btnEaseOutInBounce.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInBounce, LBack);
sleep(10);
Repaint;
Application.ProcessMessages;
end;
tbarWait.Enabled := True;
end;
procedure TMainForm.btnEaseInQuadClick(Sender: TObject);
// *** fonctions IN ***
var
Li, LWidth: Integer;
LBack: Boolean;
begin
tbarWait.Enabled := False;
LWidth := pnlLeft.Width - btnLinear2.Width;
for LBack := False to True do
for Li := 1 to fDuration do
begin
btnLinear.Left := ComputeInterpolationInt(0, LWidth, Li, intLinear, LBack);
btnEaseInQuad.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuad, LBack);
btnEaseInCubic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCubic, LBack);
btnEaseInQuart.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuart, LBack);
btnEaseInQuint.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInQuint, LBack);
btnEaseInSine.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInSine, LBack);
btnEaseInExpo.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInExpo, LBack);
btnEaseInCirc.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInCirc, LBack);
btnEaseInElastic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInElastic, LBack);
btnEaseInBack.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBack, LBack);
btnEaseInBounce.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseInBounce, LBack);
sleep(10);
pnlLeft.Repaint;
Application.ProcessMessages;
end;
tbarWait.Enabled := True;
end;
procedure TMainForm.btnEaseInOutQuadClick(Sender: TObject);
// *** fonctions INOUT ***
var
Li, LWidth2: Integer;
LBack: Boolean;
begin
tbarWait.Enabled := False;
LWidth2 := pnlRight.Width - btnLinear.Width;
for LBack := False to True do
for Li := 1 to fDuration do
begin
btnLinear2.Left := ComputeInterpolationInt(0, LWidth2, Li, intLinear, LBack);
btnEaseInOutQuad.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuad, LBack);
btnEaseInOutCubic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutCubic, LBack);
btnEaseInOutQuart.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuart, LBack);
btnEaseInOutQuint.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutQuint, LBack);
btnEaseInOutSine.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutSine, LBack);
btnEaseInOutExpo.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutExpo, LBack);
btnEaseInOutCirc.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutCirc, LBack);
btnEaseInOutElastic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutElastic, LBack);
btnEaseInOutBack.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutBack, LBack);
btnEaseInOutBounce.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseInOutBounce, LBack);
sleep(10);
pnlRight.Repaint;
Application.ProcessMessages;
end;
tbarWait.Enabled := True;
end;
procedure TMainForm.btnEaseOutInQuadClick(Sender: TObject);
// *** fonctions OUTIN ***
var
Li, LWidth2: Integer;
LBack: Boolean;
begin
tbarWait.Enabled := False;
LWidth2 := pnlRight.Width - btnLinear.Width;
for LBack := False to True do
for Li := 1 to fDuration do
begin
btnLinear2.Left := ComputeInterpolationInt(0, LWidth2, Li, intLinear, LBack);
btnEaseOutInQuad.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuad, LBack);
btnEaseOutInCubic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInCubic, LBack);
btnEaseOutInQuart.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuart, LBack);
btnEaseOutInQuint.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInQuint, LBack);
btnEaseOutInSine.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInSine, LBack);
btnEaseOutInExpo.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInExpo, LBack);
btnEaseOutInCirc.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInCirc, LBack);
btnEaseOutInElastic.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInElastic, LBack);
btnEaseOutInBack.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInBack, LBack);
btnEaseOutInBounce.Left := ComputeInterpolationInt(0, LWidth2, Li, intEaseOutInBounce, LBack);
sleep(10);
pnlRight.Repaint;
Application.ProcessMessages;
end;
tbarWait.Enabled := True;
end;
procedure TMainForm.btnEaseOutQuadClick(Sender: TObject);
// *** fonctions OUT ***
var
Li, LWidth: Integer;
LBack: Boolean;
begin
tbarWait.Enabled := False;
LWidth := pnlLeft.Width - btnLinear2.Width;
for LBack := False to True do
for Li := 1 to fDuration do
begin
btnLinear.Left := ComputeInterpolationInt(0, LWidth, Li, intLinear, LBack);
btnEaseOutQuad.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuad, LBack);
btnEaseOutCubic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutCubic, LBack);
btnEaseOutQuart.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuart, LBack);
btnEaseOutQuint.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutQuint, LBack);
btnEaseOutSine.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutSine, LBack);
btnEaseOutExpo.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutExpo, LBack);
btnEaseOutCirc.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutCirc, LBack);
btnEaseOutElastic.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutElastic, LBack);
btnEaseOutBack.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutBack, LBack);
btnEaseOutBounce.Left := ComputeInterpolationInt(0, LWidth, Li, intEaseOutBounce, LBack);
sleep(10);
pnlLeft.Repaint;
Application.ProcessMessages;
end;
tbarWait.Enabled := True;
end;
procedure TMainForm.FormCreate(Sender: TObject);
// *** création de la fiche ***
begin
Duration := C_DefaultDuration;
tbarWait.Max := C_End;
tbarWait.Position := fDuration;
end;
procedure TMainForm.tbarWaitChange(Sender: TObject);
// *** changement de la vitesse ***
begin
Duration := tbarWait.Position;
end;
procedure TMainForm.SetDuration(AValue: Cardinal);
// *** détermination de la durée d'interpolation ***
begin
if fDuration =AValue then
Exit;
fDuration := AValue;
end;
function TMainForm.InPower(AStart, AChange, AStep: Single; APower: Integer
): Single;
// *** calcul d'une interpolation de type IN pour les puissances ***
begin
Result := AChange * Power(AStep / fDuration, APower) + AStart;
end;
function TMainForm.OutPower(AStart, AChange, AStep: Single; APower: Integer
): Single;
// *** calcul d'une interpolation de type OUT pour les puissances ***
var
LSign: Integer;
begin
LSign := ifthen(Odd(APower), 1, -1);
Result := LSign * AChange * (Power(AStep / fDuration - 1, APower) + LSign) + AStart;
end;
function TMainForm.InOutPower(AStart, AChange, AStep: Single; APower: Integer
): Single;
// *** calcul d'une interpolation de type INOUT pour les puissances ***
var
LSign: Integer;
begin
LSign := ifthen(Odd(APower), 1, -1);
AStep := AStep / fDuration * 2;
if AStep < 1 then
Result := AChange / 2 * Power(AStep, APower) + AStart
else
Result := LSign * AChange / 2 * (Power(AStep - 2, APower) + LSign * 2) + AStart;
end;
function TMainForm.EaseNone(AStart, AChange, AStep: Single): Single;
// *** pas de fonction ease ***
begin
Result := AChange * AStep / fDuration + AStart;
end;
function TMainForm.EaseInQuad(AStart, AChange, AStep: Single): Single;
// *** INQUAD ***
begin
Result := InPower(AStart, AChange, AStep, 2);
end;
function TMainForm.EaseOutQuad(AStart, AChange, AStep: Single): Single;
// *** OUTQUAD ***
begin
Result := OutPower(AStart, AChange, AStep, 2);
end;
function TMainForm.EaseInOutQuad(AStart, AChange, AStep: Single): Single;
// *** INOUTQUAD ***
begin
Result := InOutPower(AStart, AChange, AStep, 2);
end;
function TMainForm.EaseOutInQuad(AStart, AChange, AStep: Single): Single;
// *** OUTINQUAD ***
begin
if AStep < fDuration / 2 then
Result := EaseOutQuad(AStart, AChange / 2, AStep * 2)
else
Result := EaseInQuad(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInCubic(AStart, AChange, AStep: Single): Single;
// *** INCUBIC ***
begin
Result := InPower(AStart, AChange, AStep, 3);
end;
function TMainForm.EaseOutCubic(AStart, AChange, AStep: Single): Single;
// *** OUTCUBIC ***
begin
Result := OutPower(AStart, AChange, AStep, 3);
end;
function TMainForm.EaseInOutCubic(AStart, AChange, AStep: Single): Single;
// *** INOUTCUBIC ***
begin
Result := InOutPower(AStart, AChange, AStep, 3);
end;
function TMainForm.EaseOutInCubic(AStart, AChange, AStep: Single): Single;
// *** OUTINCUBIC ***
begin
if AStep < fDuration / 2 then
Result := EaseOutCubic(AStart, AChange / 2, AStep * 2)
else
Result := EaseInCubic(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInQuart(AStart, AChange, AStep: Single): Single;
// *** INQUART ***
begin
Result := InPower(AStart, AChange, AStep, 4);
end;
function TMainForm.EaseOutQuart(AStart, AChange, AStep: Single): Single;
// *** OUTQUART ***
begin
Result := OutPower(AStart, AChange, AStep, 4);
end;
function TMainForm.EaseInOutQuart(AStart, AChange, AStep: Single): Single;
// *** INOUTQUART ***
begin
Result := InOutPower(AStart, AChange, AStep, 4);
end;
function TMainForm.EaseOutInQuart(AStart, AChange, AStep: Single): Single;
// *** OUTINQUART ***
begin
if AStep < fDuration / 2 then
Result := EaseOutQuart(AStart, AChange / 2, AStep * 2)
else
Result := EaseInQuart(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInQuint(AStart, AChange, AStep: Single): Single;
// *** INQUINT ***
begin
Result := InPower(AStart, AChange, AStep, 5);
end;
function TMainForm.EaseOutQuint(AStart, AChange, AStep: Single): Single;
// *** OUTQUINT ***
begin
Result := OutPower(AStart, AChange, AStep, 5);
end;
function TMainForm.EaseInOutQuint(AStart, AChange, AStep: Single): Single;
// *** INOUTQUINT ***
begin
Result := InOutPower(AStart, AChange, AStep, 5);
end;
function TMainForm.EaseOutInQuint(AStart, AChange, AStep: Single): Single;
// *** OUTINQUINT ***
begin
if AStep < fDuration / 2 then
Result := EaseOutQuint(AStart, AChange / 2, AStep * 2)
else
Result := EaseInQuint(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInSine(AStart, AChange, AStep: Single): Single;
// *** INSINE ***
begin
Result := - AChange * cos(AStep / fDuration * Pi / 2) + AChange + AStart;
end;
function TMainForm.EaseOutSine(AStart, AChange, AStep: Single): Single;
// *** OUTSINE ***
begin
Result := AChange * sin(AStep / fDuration * Pi / 2) + AStart;
end;
function TMainForm.EaseInOutSine(AStart, AChange, AStep: Single): Single;
// *** INOUTSINE ***
begin
Result := - AChange / 2 * (cos(AStep / fDuration * Pi) - 1) + AStart;
end;
function TMainForm.EaseOutInSine(AStart, AChange, AStep: Single): Single;
// *** OUTINSINE ***
begin
if AStep < fDuration / 2 then
Result := EaseOutSine(AStart, AChange / 2, AStep * 2)
else
Result := EaseInSine(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInExpo(AStart, AChange, AStep: Single): Single;
// *** INEXPO ***
begin
Result := ifthen(AStep = 0, AStart,
AChange * Power(2, 10 * (AStep / fDuration - 1)) + AStart);
end;
function TMainForm.EaseOutExpo(AStart, AChange, AStep: Single): Single;
// *** OUTEXPO ***
begin
Result := ifthen(AStep = fDuration, AChange + AStart,
AChange * (- Power(2, -10 * AStep / fDuration) + 1) + AStart);
end;
function TMainForm.EaseInOutExpo(AStart, AChange, AStep: Single): Single;
// *** INOUTEXPO ***
begin
if AStep = 0 then
Result := AStart
else
if AStep = fDuration then
Result := AChange + AStart
else
begin
AStep := AStep / fDuration * 2;
if AStep < 1 then
Result := AChange / 2 * Power(2, 10 * (AStep - 1)) + AStart
else
Result := AChange / 2 * (- Power(2, - 10 * (AStep - 1)) + 2) + AStart;
end;
end;
function TMainForm.EaseOutInExpo(AStart, AChange, AStep: Single): Single;
// *** OUTINEXPO ***
begin
if AStep < fDuration / 2 then
Result := EaseOutExpo(AStart, AChange / 2, AStep * 2)
else
Result := EaseInExpo(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInCirc(AStart, AChange, AStep: Single): Single;
// *** INCIRC ***
begin
Result := - AChange * (Sqrt(1 - Power(AStep / fDuration, 2)) - 1) + AStart;
end;
function TMainForm.EaseOutCirc(AStart, AChange, AStep: Single): Single;
// *** OUTCIRC ***
begin
Result := AChange * Sqrt(1 - Power(AStep / fDuration - 1, 2)) + AStart;
end;
function TMainForm.EaseInOutCirc(AStart, AChange, AStep: Single): Single;
// *** INOUTCIRC ***
begin
AStep := AStep / fDuration * 2;
if AStep < 1 then
Result := - AChange / 2 * (Sqrt(1 - Power(AStep, 2)) - 1) + AStart
else
Result := AChange / 2 * (Sqrt(1 - Power(AStep - 2, 2)) + 1) + AStart;
end;
function TMainForm.EaseOutInCirc(AStart, AChange, AStep: Single): Single;
// *** OUTINCIRC ***
begin
if AStep < fDuration / 2 then
Result := EaseOutCirc(AStart, AChange / 2, AStep * 2)
else
Result := EaseInCirc(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInElastic(AStart, AChange, AStep: Single): Single;
// *** INELASTIC ***
begin
if AStep = 0 then
Result := AStart
else
begin
AStep := AStep / fDuration;
if AStep = 1 then
Result := AChange + AStart
else
begin
AStep := AStep - 1;
Result := - (AChange * Power(2, 10 * AStep) * sin((AStep * fDuration
- (fDuration * 0.3 / 4)) * 2 * Pi / (fDuration * 0.3))) + AStart;
end;
end;
end;
function TMainForm.EaseOutElastic(AStart, AChange, AStep: Single): Single;
// *** OUTELASTIC ***
begin
if AStep = 0 then
Result := AStart
else
begin
AStep := AStep / fDuration;
if AStep = 1 then
Result := AChange + AStart
else
Result := AChange * Power(2, - 10 * AStep) * sin((AStep * fDuration -
(fDuration * 0.3 / 4)) * 2 * Pi / (fDuration * 0.3)) + AChange + AStart;
end;
end;
function TMainForm.EaseInOutElastic(AStart, AChange, AStep: Single): Single;
// *** INOUTELASTIC ***
begin
if AStep = 0 then
Result := AStart
else
begin
AStep := AStep / fDuration * 2;
if AStep = 2 then
Result := AChange + AStart
else
begin
// 0.45 = 0.3*1.5 0.1125 = 0.45 / 4
if AStep < 1 then
begin
AStep := AStep - 1;
Result := - (AChange * Power(2, 10 * AStep) * sin((AStep * fDuration -
fDuration * 0.1125) * 2 * Pi / (fDuration * 0.45))) / 2 + AStart;
end
else
begin
AStep := AStep - 1;
Result := AChange * Power(2, - 10 * AStep) * sin((AStep * fDuration -
fDuration * 0.1125) * 2 * Pi / (fDuration * 0.45)) / 2 + AChange + AStart;
end;
end;
end;
end;
function TMainForm.EaseOutInElastic(AStart, AChange, AStep: Single): Single;
// *** OUTINELASTIC ***
begin
if AStep < fDuration / 2 then
Result := EaseOutElastic(AStart, AChange / 2, AStep * 2)
else
Result := EaseInElastic(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInBack(AStart, AChange, AStep: Single): Single;
// *** INBACK ***
begin
// 1.70158 = 10% 2.592389 = 20% 3.394051 = 30% 4.15574465 = 40%
Result := AChange * Power(AStep / fDuration, 2) * (2.70158 *
AStep / fDuration - 1.70158) + AStart;
end;
function TMainForm.EaseOutBack(AStart, AChange, AStep: Single): Single;
// *** OUTBACK ***
begin
Result := AChange * (Power(AStep / fDuration - 1, 2) *
(2.70158 * (AStep / fDuration - 1) + 1.70158) + 1) + AStart;
end;
function TMainForm.EaseInOutBack(AStart, AChange, AStep: Single): Single;
// *** INOUTBACK ***
begin
// 2.5949095 = 1.70158 * 1.525
AStep := AStep / fDuration * 2;
if AStep < 1 then
Result := AChange / 2 * Power(AStep, 2) * (3.594905 * AStep - 2.594905)
+ AStart
else
Result := AChange / 2 * (Power(AStep - 2, 2) * (3.594905 * (AStep - 2)
+ 2.594905) + 2) + AStart;
end;
function TMainForm.EaseOutInBack(AStart, AChange, AStep: Single): Single;
// *** OUTINBACK ***
begin
if AStep < fDuration / 2 then
Result := EaseOutBack(AStart, AChange / 2, AStep * 2)
else
Result := EaseInBack(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInOutBounce(AStart, AChange, AStep: Single): Single;
// *** INOUTBOUNCE ***
begin
if AStep < fDuration / 2 then
Result := EaseInBounce(0, AChange, AStep * 2) / 2 + AStart
else
Result := EaseOutBounce(0, AChange, AStep * 2 - fDuration) / 2 + AChange / 2
+ AStart;
end;
function TMainForm.EaseOutInBounce(AStart, AChange, AStep: Single): Single;
// *** OUTINBOUNCE ***
begin
if AStep < fDuration / 2 then
Result := EaseOutBounce(AStart, AChange / 2, AStep * 2)
else
Result := EaseInBounce(AStart + AChange / 2, AChange / 2, AStep * 2 - fDuration);
end;
function TMainForm.EaseInBounce(AStart, AChange, AStep: Single): Single;
// *** INBOUNCE ***
begin
Result := AChange - EaseOutBounce(0, AChange, fDuration - AStep) + AStart;
end;
function TMainForm.EaseOutBounce(AStart, AChange, AStep: Single): Single;
// *** OUTBOUNCE ***
begin
AStep := AStep / fDuration;
if AStep < 1 / 2.75 then
Result := AChange * 7.5625 * Power(AStep, 2) + AStart
else
if AStep < 2 / 2.75 then
begin
AStep := AStep - 1.5 / 2.75;
Result := AChange * (7.5625 * Power(AStep, 2) + 0.75) + AStart;
end
else
if AStep < 2.5 / 2.75 then
begin
AStep := AStep - 2.25 / 2.75;
Result := AChange * (7.5625 * Power(AStep, 2) + 0.9375) + AStart;
end
else
begin
AStep := AStep - 2.625 / 2.75;
Result := AChange * (7.5625 * Power(AStep, 2) + 0.984375) + AStart;
end;
end;
function TMainForm.ComputeInterpolation(AStart, AEnd, AStep: Single;
AInter: TInterpolation; ABack: Boolean): Single;
// *** calcul des interpolations ***
begin
case AInter of
// linéaire
intLinear: Result := EaseNone(AStart, AEnd, AStep);
// quadratique
intEaseInQuad: Result := EaseInQuad(AStart, AEnd, AStep);
intEaseOutQuad: Result := EaseOutQuad(AStart, AEnd, AStep);
intEaseInOutQuad: Result := EaseInOutQuad(AStart, AEnd, AStep);
intEaseOutInQuad: Result := EaseOutInQuad(AStart, AEnd, AStep);
// cubique
intEaseInCubic: Result := EaseInCubic(AStart, AEnd, AStep);
intEaseOutCubic: Result := EaseOutCubic(AStart, AEnd, AStep);
intEaseInOutCubic: Result := EaseInOutCubic(AStart, AEnd, AStep);
intEaseOutInCubic: Result := EaseOutInCubic(AStart, AEnd, AStep);
// quartique
intEaseInQuart: Result := EaseInQuart(AStart, AEnd, AStep);
intEaseOutQuart: Result := EaseOutQuart(AStart, AEnd, AStep);
intEaseInOutQuart: Result := EaseInOutQuart(AStart, AEnd, AStep);
intEaseOutInQuart: Result := EaseOutInQuart(AStart, AEnd, AStep);
// quintique
intEaseInQuint: Result := EaseInQuint(AStart, AEnd, AStep);
intEaseOutQuint: Result := EaseOutQuint(AStart, AEnd, AStep);
intEaseInOutQuint: Result := EaseInOutQuint(AStart, AEnd, AStep);
intEaseOutInQuint: Result := EaseOutInQuint(AStart, AEnd, AStep);
// sinus
intEaseInSine: Result := EaseInSine(AStart, AEnd, AStep);
intEaseOutSine: Result := EaseOutSine(AStart, AEnd, AStep);
intEaseInOutSine: Result := EaseInOutSine(AStart, AEnd, AStep);
intEaseOutInSine: Result := EaseOutInSine(AStart, AEnd, AStep);
// exponentielle
intEaseInExpo: Result := EaseInExpo(AStart, AEnd, AStep);
intEaseOutExpo: Result := EaseOutExpo(AStart, AEnd, AStep);
intEaseInOutExpo: Result := EaseInOutExpo(AStart, AEnd, AStep);
intEaseOutInExpo: Result := EaseOutInExpo(AStart, AEnd, AStep);
// cercle
intEaseInCirc: Result := EaseInCirc(AStart, AEnd, AStep);
intEaseOutCirc: Result := EaseOutCirc(AStart, AEnd, AStep);
intEaseInOutCirc: Result := EaseInOutCirc(AStart, AEnd, AStep);
intEaseOutInCirc: Result := EaseOutInCirc(AStart, AEnd, AStep);
// élastique
intEaseInElastic: Result := EaseInElastic(AStart, AEnd, AStep);
intEaseOutElastic: Result := EaseOutElastic(AStart, AEnd, AStep);
intEaseInOutElastic: Result := EaseInOutElastic(AStart, AEnd, AStep);
intEaseOutInElastic: Result := EaseOutInElastic(AStart, AEnd, AStep);
// retour
intEaseInBack: Result := EaseInBack(AStart, AEnd, AStep);
intEaseOutBack: Result := EaseOutBack(AStart, AEnd, AStep);
intEaseInOutBack: Result := EaseInOutBack(AStart, AEnd, AStep);
intEaseOutInBack: Result := EaseOutInBack(AStart, AEnd, AStep);
// rebond
intEaseInBounce: Result := EaseInBounce(AStart, AEnd, AStep);
intEaseOutBounce: Result := EaseOutBounce(AStart, AEnd, AStep);
intEaseInOutBounce: Result := EaseInOutBounce(AStart, AEnd, AStep);
intEaseOutInBounce: Result := EaseOutInBounce(AStart, AEnd, AStep);
end;
if ABack then
Result := AEnd - Result;
end;
function TMainForm.ComputeInterpolationInt(AStart, AEnd: Integer;
AStep: Integer; AInter: TInterpolation; ABack: Boolean): Integer;
// *** interpolation entière ***
begin
Result := Round(ComputeInterpolation(AStart, AEnd, AStep, AInter, ABack));
end;
end.
Voici une vidéo qui montre l'application en action :
https://youtu.be/4611zBvmA6Q
Vous voici parvenus au bout de votre première exploration des interpolations, et plus spécifiquement des courbes d'easing. L'épisode suivant va formaliser ce travail préparatoire en proposant une série de classes à réutiliser dans vos projets à venir.
Le code source de l'application est ici : 447733.
Vous avez lu gratuitement 4 782 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.