diff --git a/docs/Behaviors.md b/docs/Behaviors.md index 125b5a9..57b5905 100644 --- a/docs/Behaviors.md +++ b/docs/Behaviors.md @@ -1,25 +1,27 @@ -# Container behaviors +# Comportements des conteneurs -This document is about the special and unique behaviors that a container can have. +Ce document traite des comportements spéciaux et uniques qu'un conteneur peut avoir. -Each behavior is documented into a section with 3 subsections : -- Rules +Chaque comportement est documenté dans une section avec 3 sous-sections : +- Règles - Applications -- Code reference and algorithms +- Références de code et algorithmes -# Default behavior +# Comportement par défaut -The default behavior is the floating panel. It can move and resize itself but not its siblings. +Le comportement par défaut est le panneau flottant. Il peut se déplacer et se redimensionner mais pas ses frères et soeurs. -## Rules +## Règles -The default behavior does not have any particular rules that applies to itself. +Le comportement par défaut n'a pas de règles particulières qui s'appliquent à lui-même. -However it does have a common rule for any behavior that applies to its children. +Cependant, il a une règle commune pour tout comportement qui s'applique à ses enfants. -Which is to apply the specials behaviors of its children (rigid or anchor). +Il s'agit d'appliquer les comportements spéciaux de ses enfants (rigide ou ancré). + +Traduit avec www.DeepL.com/Translator (version gratuite) ## Applications @@ -32,72 +34,73 @@ Allowing freedom of movement can help for better precision if not the same as th An example would be trying to overlap an element in order to use it as a layer. -## Code references and algorithms -In the module `PropertiesOperations.ts` in the following functions: +## Références de code et algorithmes + +Dans le module `PropertiesOperations.ts` dans les fonctions suivantes : - `OnPropertyChange()` - `OnPropertiesSubmit()` -and in `ContainerOperation.ts` in `AddContainer()`, +et dans le module `ContainerOperation.ts` dans `AddContainer()`, -it uses the `ApplyBehaviors` function of the `Behaviors.ts` module to apply the specials behaviors of its children. +il utilise la fonction `ApplyBehaviors` du module `Behaviors.ts` pour appliquer les comportements spéciaux de ses enfants. -# Rigid body behavior +# Comportement du corps rigide -The rigid body behavior is a special behavior -that allows a container to be restricted into a space. +Le comportement de corps rigide est un comportement spécial +qui permet de restreindre un conteneur dans un espace donné. -## Rules +## Règles -The main rules are : -- The rigid container must be kept inside its parent container -- The rigid container must be inside an unallocated space of its parent. Meaning, that it cannot overlap with another sibling. +Les principales règles sont : +- Le conteneur rigide doit être maintenu à l'intérieur de son conteneur parent. +- Le conteneur rigide doit se trouver à l'intérieur d'un espace non alloué de son parent. C'est-à-dire qu'il ne peut pas se superposer à un autre frère ou sœur. ## Applications -This behavior has many applications to it. Mainly about recalculations. +Ce comportement a de nombreuses applications. Principalement sur les recalculs. -You may want to resize/move quickly and be certain that it does not overflow its parent. +Vous pouvez vouloir redimensionner/déplacer rapidement et être certain qu'il ne déborde pas de son parent. -You may want to resize its parent and makes its resize its children. +Vous pouvez vouloir redimensionner son parent et faire en sorte qu'il redimensionne ses enfants. -You may want siblings to interact with each other. +Vous pouvez vouloir que les frères et sœurs interagissent les uns avec les autres. -## Code references and algorithms +## Références de code et algorithmes -Its algorithm can be a little complicated due to the numerous uses cases. +Son algorithme peut être un peu compliqué en raison des nombreux cas d'utilisation. -### First rule +### Première règle -Lets start with the first rule : *The rigid container must be kept inside its parent container* +Commençons par la première règle : *Le conteneur rigide doit être maintenu à l'intérieur de son conteneur parent*. -Inside the `RigidBodyBehaviors.ts`, see `constraintBodyInsideParent()` and `constraintBodyInsideSpace()`. +Dans le fichier `RigidBodyBehaviors.ts`, voyez `constraintBodyInsideParent()` et `constraintBodyInsideSpace()`. -As you can see `constraintBodyInsideParent()` is just a wrapper for `constraintBodyInsideSpace()`, so lets just study the last function. +Comme vous pouvez le voir, `constraintBodyInsideParent()` n'est qu'une enveloppe pour `constraintBodyInsideSpace()`, donc étudions juste cette dernière fonction. -This is a simple problem of two rectangle. +C'est un problème simple de deux rectangles. -In order to restrict the child to its parent, -we need to know firstly, if the children is not bigger than its parent. +Afin de restreindre l'enfant à son parent, +nous devons d'abord savoir si l'enfant n'est pas plus grand que son parent. -If it is, we just need to set the child at the beginning and makes it takes the full size of its parent. +Si c'est le cas, il suffit de placer l'enfant au début et de lui faire prendre la taille complète de son parent. -If it is not, we need to check if the children is out of bound (outside its parent). And if it is out of bound, we need to move it back inside. +Si ce n'est pas le cas, nous devons vérifier si l'enfant est hors limites (en dehors de son parent). Et si c'est le cas, nous devons le ramener à l'intérieur. -To check if it bigger than its parent we just need to compare their sizes : `childWidth > parentWidth` and vertically `childHeight > parentHeight`. +Pour vérifier s'il est plus grand que son parent, il suffit de comparer leurs tailles : `childWidth > parentWidth` et verticalement `childHeight > parentHeight`. -If false we need to check out of bound, check for x (and y): `child.x < parent.x` for the left side or `child.x + child.width > parent.x + parent.width` for the right side. We don't want the overlap either which is why we uses `child.width`. +Si c'est faux, nous devons vérifier la sortie de l'objet, vérifier pour x (et y) : `child.x < parent.x` pour le côté gauche ou `child.x + child.width > parent.x + parent.width` pour le côté droit. Nous ne voulons pas non plus de chevauchement, c'est pourquoi nous utilisons `child.width`. -The condition is also equivalent to `child.x > parent.x + parent.width - child.width` which could makes more sense as the required space must be smaller because of the child size. +La condition est également équivalente à `child.x > parent.x + parent.width - child.width` qui pourrait être plus logique puisque l'espace requis doit être plus petit à cause de la taille de l'enfant. -In my algorithm, I decided to put them near the edge where they went out of bound : +Dans mon algorithme, j'ai décidé de les placer près du bord où ils sont sortis de la limite : ``` left oob: child.x = parent.x @@ -137,78 +140,78 @@ constraintBodyInsideSpace(child, parent) { ``` -### Second rule +### Deuxième règle -The second rule is the most important and complicated as it must interact with its siblings. +La deuxième règle est la plus importante et la plus compliquée car elle doit interagir avec ses frères et sœurs. -*The rigid container must be inside an unallocated space of its parent. Meaning, that it cannot overlap with another sibling.* +*Le conteneur rigide doit se trouver dans un espace non alloué de son parent. Ce qui signifie qu'il ne peut pas chevaucher un autre frère ou une autre soeur. -Let's first define what is a *space* : a *space* is the width of a container. Which consequently means that the rule only applies on the horizontal view. To simply the matter that also means that we only need to work on one dimension. +Définissons d'abord ce qu'est un *espace* : un *espace* est la largeur d'un conteneur. Ce qui signifie donc que la règle ne s'applique que sur la vue horizontale. Pour simplifier la chose, cela signifie également que nous ne devons travailler que sur une seule dimension. -To solve this problem, like the parent, we could use collision detection between its siblings. However this could be very slow as the worst case scenario is a cartesian product: O(n2). Because for each container we need to search for other container that collide with use. When it collide we need to move it and search again. +Pour résoudre ce problème, comme pour le parent, nous pourrions utiliser la détection de collision entre ses frères et sœurs. Cependant, cela pourrait être très lent car le pire scénario est un produit cartésien : O(n2). En effet, pour chaque conteneur, nous devons rechercher les autres conteneurs qui entrent en collision avec lui. Lorsqu'il entre en collision, nous devons le déplacer et recommencer la recherche. -Remember, this rule is applied every time you change a property of container, this is *lag*. We cannot afford to inefficient loops. +Rappelez-vous, cette règle est appliquée chaque fois que vous changez une propriété du conteneur, c'est le *lag*. Nous ne pouvons pas nous permettre des boucles inefficaces. -Let us use a "system of space" that has "containers" that cannot "overlap". +Utilisons un "système d'espace" qui a des "conteneurs" qui ne peuvent pas "se chevaucher". -Memory. +La mémoire. -Memory, RAM, Hard drive space, handles their space through a system of adresses and chunks of spaces (words, bytes...). In our case we don't have chunk of spaces but floating numbers (which can be a pain the work with because of the edge cases). +La mémoire, la RAM, l'espace du disque dur, gèrent leur espace par un système d'adresses et de morceaux d'espaces (mots, octets...). Dans notre cas, nous n'avons pas de morceaux d'espaces, mais des nombres flottants (qui peuvent être un casse-tête à cause des cas limites). -This system is particularly useful as it remember the space used after every iteration of allocation, meaning that we can know exactly when there is no more space inside parent and when a container must resized itself in order to fit inside. +Ce système est particulièrement utile car il se souvient de l'espace utilisé après chaque itération d'allocation, ce qui signifie que nous pouvons savoir exactement quand il n'y a plus d'espace à l'intérieur du parent et quand un conteneur doit se redimensionner afin de tenir à l'intérieur. -Alright let us start the algorithm. See `constraintBodyInsideUnallocatedWidth()`, `getAvailableWidths()` and `getAvailableWidthsTwoLines()` in `RigidBodyBehaviors.ts` for implementation reference. +Bien, commençons l'algorithme. Voir `constraintBodyInsideUnallocatedWidth()`, `getAvailableWidths()` et `getAvailableWidthsTwoLines()` dans `RigidBodyBehaviors.ts` pour les références de l'implémentation. -We have initially the whole space available: let `space` be this available space in the parent. +Nous avons initialement tout l'espace disponible : laissez `space` être cet espace disponible dans le parent. -`space` is a pointer, thus at the beginning it has `0` to its pointer address and `parent.width` as it space. +`space` est un pointeur, donc au début il a `0` à son adresse de pointeur et `parent.width` comme espace. -To simplify the algorithm when adding a container, let us compare it to eating a bûche de Noël (yule log). +Pour simplifier l'algorithme lors de l'ajout d'un conteneur, comparons cela à manger une bûche de Noël. ![buche](./assets/yule-log-cake.jpg) -Like eating the cake, we need to cut it and take a part. +Comme pour le gâteau, il faut le couper et en prendre une part. -There is 5 possible way to cut it : -- Not eating the cake (maybe we prefer to eat a different cake/part) -- Eating the whole cake -- Cutting the cake at the left side -- Cutting the cake at the right right -- Cutting the cake in the middle +Il y a 5 façons possibles de le couper : +- Ne pas manger le gâteau (on préfère peut-être manger un autre gâteau/une autre part) +- Manger le gâteau entier +- Couper le gâteau à gauche +- Couper le gâteau sur le côté droit +- Couper le gâteau au milieu -Not cutting the cake means returning the whole cake as is. +Ne pas couper le gâteau signifie rendre le gâteau entier tel quel. -Eating the whole cake is to not returns anything. +Manger le gâteau entier, c'est ne rien rendre. -Cutting at the left or the right side means leave 1 part. +Couper à gauche ou à droite signifie laisser une partie. -Cutting the middle means leaving two part. +Couper au milieu signifie laisser deux parts. -After cutting the cake, *while* there is still some left, we can continue the operation. (it is a *for* loop in the code though for syntax reasons) +Après avoir coupé le gâteau, *pendant* qu'il en reste encore, on peut continuer l'opération. (c'est une boucle *pour* dans le code cependant pour des raisons de syntaxe) -However after serving for the siblings we *may* notice that there is no more left for us. We get angry, we *throw* a tantrum. +Cependant, après avoir servi les frères et sœurs, nous pouvons remarquer qu'il n'en reste plus pour nous. Nous nous mettons en colère, nous *jetons* une crise de colère. ```c -// if you did not understood the joke +// si vous n'avez pas compris la blague if (there no more cake) { throw tantrum } ``` -Wait, there is actually cake! +Attends, il y a vraiment du gâteau ! -But it is left in multiple parts, we will just takes the *closest* one that *fits* our hunger. +Mais il est laissé en plusieurs morceaux, nous allons juste prendre le plus proche qui correspond à notre faim. -If there is one that fits our hunger let's take it! +S'il y en a un qui correspond à notre faim, prenons-le ! -Yet! There is cake but none fits our hunger. But we do have a *minimum* acceptance, let us be humble, we will still take the small bit. By the way, taking multiple part would look bad for us. Nonetheless, if my *minimum* acceptance were to be higher than what is left, I would *throw* a *warning* for next time. +Pourtant ! Il y a des gâteaux mais aucun ne correspond à notre faim. Mais nous avons une acceptation *minimale*, soyons humbles, nous prendrons quand même la petite part. D'ailleurs, prendre plusieurs parts serait mauvais pour nous. Néanmoins, si mon acceptation *minimale* devait être supérieure à ce qui reste, je lancerais un *avertissement* pour la prochaine fois. -Alright lets translate this in pseudo-code. +Traduisons cela en pseudo-code. -Let us start with getting the available spaces : +Commençons par obtenir les espaces disponibles : -```c# +```typescript getAvailableSpaces(parent, me) { spaces = [{ x: 0, size: parent.width }] @@ -236,9 +239,9 @@ getAvailableSpaces(parent, me) { } ``` -To allocate: +Pour allouer : -```c# +```typescript allocate(sibling, space) { if (sibling is not overlapping the space) { return [space] @@ -258,7 +261,7 @@ allocate(sibling, space) { if (sibling overlap at the right side) { return [{ x: left side of space - size: leftSide of sibling - leftSide of space + size: leftSide of sibling - leftSide of space }] } @@ -276,9 +279,9 @@ allocate(sibling, space) { } ``` -Finally the top part: +Enfin pour l'appelant : -```c# +```typescript constraintBodyInsideUnallocatedWidth(parent, container) { spaces = getAvailableSpaces(parent, container) if (there is no more spaces) { @@ -306,49 +309,49 @@ constraintBodyInsideUnallocatedWidth(parent, container) { } ``` -This algorithm is great but, some problems remains: -- Finding the closest takes O(nlogn) with n being the number of spaces. This is usually not bad since the objective of the rigid body is to **fill** space. But it still does have a very bad worst case. -- There is 2 searches for space, same problem but the previous sort helps to make it faster for the best cases +Cet algorithme est génial, mais certains problèmes subsistent : +- Trouver le plus proche prend O(nlogn), n étant le nombre d'espaces. Ce n'est généralement pas mauvais puisque l'objectif du corps rigide est de **remplir** l'espace. Mais il y a toujours un très mauvais cas de figure. +- Il y a 2 recherches pour l'espace, même problème mais le tri précédent aide à le rendre plus rapide pour les meilleurs cas. -# Anchor behavior +# Comportement d'ancrage -The anchor behavior allows a container to gain priority over its siblings. +Le comportement d'ancrage permet à un conteneur d'être prioritaire sur ses frères et sœurs. -## Rules +## Règles -It has the following rules: - - The container cannot be moved by other rigid siblings container - - The container cannot be resized by any other siblings container - - The container cannot overlap any other siblings rigid container : - - overlapping containers are shifted to the nearest available space/width - - or resized when there is no available space left other than theirs - - or lose their rigid body properties when there is absolutely no available space left (not even theirs) +Il a les règles suivantes : + - Le conteneur ne peut pas être déplacé par un autre conteneur frère ou sœur rigide. + - Le conteneur ne peut pas être redimensionné par un autre conteneur de la même famille. + - Le conteneur ne peut pas chevaucher un autre conteneur rigide de la même famille : + - les conteneurs qui se chevauchent sont déplacés vers l'espace/largeur disponible le plus proche + - ou redimensionnés lorsqu'il n'y a plus d'autre espace disponible que le leur + - ou perdent leurs propriétés de corps rigide lorsqu'il n'y a absolument plus d'espace disponible (même pas le leur). ## Applications -Gaining priority can helps makes sure that a rigid object won't move no matter what and will absolutly move no matter what is under it. +Le gain de priorité permet de s'assurer qu'un objet rigide ne bougera pas, quoi qu'il arrive, et qu'il bougera absolument, peu importe ce qui se trouve sous lui. -## Code references and algorithms +## Références de code et algorithmes -While there is a more rules applied to this behavior, most of them are just conditions. +Bien qu'il y ait plusieurs règles appliquées à ce comportement, la plupart d'entre elles ne sont que des conditions. -These three rules: - - The container cannot be moved by other rigid siblings container - - The container cannot be resized by any other siblings container - - It cannot overlap any other siblings rigid container +Ces trois règles : + - Le conteneur ne peut pas être déplacé par d'autres conteneurs frères et sœurs rigides. + - Le conteneur ne peut pas être redimensionné par un autre conteneur de la même famille. + - Il ne peut pas chevaucher un autre conteneur rigide de la même famille. -Can be translate into a single one: "The container is an allocated space so any container is in contact will move or be resized" +Il peut être traduit en un seul : "Le conteneur est un espace alloué, donc tout conteneur en contact se déplacera ou sera redimensionné". -Meaning that applying the rigid body properties of the sibling will also apply this rule. The difference with the default behavior and the anchor behavior is that the anchor container will be taken into account during the calculation of available space. +Ce qui signifie que l'application des propriétés du corps rigide du frère ou de la sœur appliquera également cette règle. La différence entre le comportement par défaut et le comportement d'ancrage est que le conteneur d'ancrage sera pris en compte lors du calcul de l'espace disponible. -You can think of the default container as a floating panel and the anchor container as a wall. You can go under the floating panel but cannot go over the wall. +Vous pouvez considérer le conteneur par défaut comme un panneau flottant et le conteneur d'ancrage comme un mur. Vous pouvez passer sous le panneau flottant mais pas par-dessus le mur. -To optimize the algorithm, we just need to find the overlapping siblings since the anchor is not applied to those who are not in collision. +Pour optimiser l'algorithme, il suffit de trouver les frères et sœurs qui se chevauchent puisque l'ancre n'est pas appliquée à ceux qui ne sont pas en collision. Pseudo-code : @@ -363,6 +366,76 @@ ImposePosition(container) { } ``` -Also, modify `getAvailableSpaces()` so it takes into account anchor containers. +De plus, nous devons modifier `getAvailableSpaces()` pour qu'il prenne en compte les conteneurs d'ancrage. -That's it. \ No newline at end of file + +# Le comportement Flex + +Le comportement flex est un comportement qui modifie à la fois la position et la taille d'un conteneur tout en interagissant avec ses frères et sœurs. + + +## Application + +Le comportement flex est utile pour le redimensionnement automatique d'un conteneur en fonction de son parent et de ses frères et sœurs. + + +## Références de code et algorithmes + +Tout d'abord, nous devons déterminer ce qu'est un espace flexible. Un espace flexible est la zone située entre deux objets d'ancrage, un objet d'ancrage pouvant être un conteneur ancré ou les bords du conteneur parent. + +L'algorithme pour trouver un espace flexible est d'itérer sur les conteneurs et de créer un groupe à chaque fois qu'une ancre est trouvée (voir `GetFlexibleGroups`). + +Ensuite, pour appliquer le flex dans ces groupes, il y a trois scénarios principaux : +- Il n'y a pas assez d'espace même si l'on comprime tous les conteneurs à leur largeur minimale. +- Il y a suffisamment d'espace pour que tous les conteneurs aient la même taille. +- Il n'y a pas assez d'espace pour que tous les conteneurs aient la même taille, mais nous pouvons les comprimer. + +Dans le premier scénario, il suffit de renvoyer une erreur. + +Dans le second scénario, nous devons changer la taille de chaque conteneur pour qu'ils aient la même largeur. Ainsi, `wantedWidth = sum(space_width) / n`. La position sera alors `containerIndex * wantedWidth`. + +Enfin, dans le troisième scénario, il existe plusieurs façons de procéder. Nous pourrions simplement appliquer le comportement de poussée tout en redimensionnant un par un chaque conteneur jusqu'à ce qu'ils s'adaptent, mais cela peut ne pas avoir de solution et coûtera un total de O(n2) de complexité. + +L'autre moyen est d'utiliser la programmation linéaire puisque nous pouvons traduire ce problème comme un programme linéaire : la fonction objectif serait de maximiser la largeur de tous les conteneurs sans déborder du conteneur parent `max sum(width_i) <= wantedWidth`. Les inéquations supplémentaires sont les contraintes de largeur minimale et maximale. + +L'algorithme que nous allons utiliser est l'algorithme du simplexe. Il s'agit d'un algorithme populaire dans le domaine de l'optimisation mathématique. + + + +# Comportement de poussée + +Lorsqu'on a un conteneur à droite et qu'on en ajoute un nouveau à sa droite, on pousse ce conteneur à gauche s'il y a assez de place. + + +## Application + +Permet d'ajouter un nouveau conteneur sans empiéter sur les conteneurs existants lorsqu'il y a suffisamment d'espace à leur gauche. + + +## Références de code et algorithmes + +Afin de pousser, nous devons trouver les trous à la gauche du nouveau conteneur. Lorsque nous trouvons un trou, nous devons pousser le conteneur à la droite du trou jusqu'à ce qu'il n'y ait plus de place. + +Pour trouver un trou, nous devons itérer par paire (deux par deux) de la droite vers la gauche. + +Pour pousser le conteneur de droite, nous pouvons simplement soustraire sa position de la taille du trou. + +Lorsque l'espace restant est égal à 0, nous pouvons arrêter de pousser. + +Comme vous pouvez le constater, cet algorithme est très lent et peut coûter jusqu'à O(n2). Et comme les calculs se chevauchent, il est également possible qu'en raison de la précision de la virgule flottante, il reste un espace minuscule. + + +# Comportement de swap + +Lorsque deux conteneurs sont en collision, la position des deux conteneurs est permutée. + + +## Application + +Lorsqu'il n'y a plus de place et que le corps rigide est activé, pour déplacer un conteneur dans la ligne, nous pouvons permuter deux conteneurs en augmentant x. + + +## Références de code et algorithmes + +Le code pour ce comportement est très simple : +- Lorsque deux conteneurs se chevauchent, on permute leur position. \ No newline at end of file diff --git a/docs/CICD.md b/docs/CICD.md index 7c3543f..4aee2bf 100644 --- a/docs/CICD.md +++ b/docs/CICD.md @@ -7,6 +7,7 @@ Its `azure-pipelines.yml` configuration file can be found at the root project fo # Drone.io -Due to the limitations of Azure Pipelines (limited free usage, no parallel, no dockerhub...), it might be more useful to use Drone.io. +Due to the limitations of Azure Pipelines (limited free usage, no parallel, no dockerhub...), it might be more useful to use Drone.io. +However `pnpm` will not be as useful as in Azure Pipelines since we cannot cache on the parent machine. Its config file can be found in `.drone.yml`. \ No newline at end of file diff --git a/docs/Hardcoded.md b/docs/Hardcoded.md deleted file mode 100644 index 75cf025..0000000 --- a/docs/Hardcoded.md +++ /dev/null @@ -1,14 +0,0 @@ -> Here you will find the documentation of desastrous stuff that I made - -# XPositionReference - -XPositionReference is used as a fake horizontal offset indicator. - -The truth is that the svg will always take the left for its transformations and the best for us is to do the same. - -That's why everything that is shown to the user about XPositionReference is an illusion. Like for example: -- The inputs, see `PropertiesOperations.ts`, `StaticForm`, `DynamicForm`. -- Child dimensions, see `Container.ts`. - - -Look for use of `transformX()` and `restoreX()`.