Support Strict Transformation Between Containers
Transformation depends on three cases:
- Crowded: Transform into a container with siblings more than 1.
- Empty: Transform into a container where there are no siblings.
- Orphan: Transform into a container where there is only one element there.
Calculations are made to:
- Translate object {x,y} => update occupied-translate. These coordinates are relative and related to the connected index. E.g: If the element left its original container and got inserted at the destination container with index-3 then the translation should be based on the insertion index. (Not the same case for the position.)
- Position object {x,y} => update occupied-position. These coordinates are absolute. Calculating position affects the next element's movement. E.g: If element-last-one has to move down it will check the
occupied-position
because can't move based on its own position so this will kill dealing with different heights/widths. So it has to move to a post-defined point. For transformation inside the list itself, it's not a problem. But for migration to a new container then the calculated value should be done before triggering any transformation. It's not a step-by-step regular movement.
Three different phases for execution:
- Calculate and assign position once the destination list/container is defined. Before knowing the insertion index.
- Calculating translation which should be done after detecting the insertion index before triggering the transformer otherwise we will calculate the next position instead of the current one.
- Assigning the translation after the transformer(move-down) is done. Otherwise, the dragged will be
out-position= true
.
Roadmap:
A- Handle the case where transformation between containers happens to the absent bottom (#493)
- [x] Fix undo for draggable when it's inside the position threshold but triggered or shifted slightly. Now it does trigger the undo instead of treating this case as moved out.
- [x] Fix dragged insertion inside the container when the breaking point is not detected. It enforces the dragged to be attached to the bottom right after the first cycle of iteration avoiding unnecessary function calls that led to the same result.
- [x] Avoid unnecessary updating position/translate when appending to the bottom.
- [x] Remove
numberOfElementsTransformed
and updateNumOfElementsTransformed
from dragged and replace the use case with exicting indicators.
- [x] Support transformation when dragged is migrated to the bottom of the destination container.
- [x] Add test cases for transforming back and forth horizontally and vertically.
B- Refactor utils to Core removing #getDiff
(#494)
interface INode extends ICore {
isConnected(): boolean;
isPositionedUnder(elmY: number): boolean;
isPositionedLeft(elmX: number): boolean;
getRectBottom(): number;
getRectRight(): number;
getRectDiff(elm: this, axis: Axis): number;
getDisplacement(elm: this, axis: Axis): number;
getDistance(elm: this, axis: Axis): number;
getOffset(): RectDimensions;
hasSamePosition(elm: this, axis: Axis): boolean;
}
C- Check the layout shift for vertically transforming elements with different heights inside the same container (#496)
-
Outside the container then insert:
a. The dragged is bigger than the targeted element - moving without releasing.
b. The dragged is smaller than the targeted element - moving without releasing.
c. The dragged is smaller than the targeted element - move and release with iteration.
-
Inside the container:
a. The dragged is bigger than the targeted element - moving without releasing.
b. The dragged is bigger than the targeted element - move and release with iteration.
c. The dragged is smaller than the targeted element - moving without releasing.
d. The dragged is smaller than the targeted element - move and release with iteration.
D- Enable transformation for containers orphaned by migration (#497)
In this case, the origin container has two elements.
- One element transformed into another container. It has a solo element now.
- A new element is going to be transformed into it, the container which has one element.
- The insertion margin shouldn't cause any layout shift.
To solve it, when the container is receiving a new element. DFlex restores the preserved last element position and calculates the margin to guarantee the given scenario where there is no shifting in positions.
E- Enable transformation from origin higher than destination
One of the calculations DFlex has is defining a threshold for each layout (#418). Threshold tells the transformers when dragged is in/out its position or the container strict boundaries. This strict definition of threshold helps to improve user experience and the physical sense of elements' interactivity. It also plays role in detecting the active container when an element migrates from one to another. This definition prevents the transformation from a container having bigger height/width into another container having smaller boundaries. When leaving the position and entering a new one the transformer can't tell if the element is inside the less-boundaries container or not. To tackle this issue each depth must have a unified transforming boundary. So when the element is dragged at the same level horizontally or vertically it can be settled into the destination container and attached to the bottom which has the highest weight.
Steps to Solve it:
- [x] Define insertion area threshold for layouts with the same depth to optimize transformation between containers (#500), (#513).
- [x] Use shared utility in DOM-Gen to generate composed keys for layout depth + key (#501)
- [x] Add a unified container dimension for each layout that belongs to the same depth (#503) So when checking where the dragged is located different heights and widths won't be a problem given when dragged is transforming all of them has the same dimensions. Still, this needs to be improved to become more dynamic since heights and widths are constantly changing or supposed to be so.
- [x] Create a shared method for element insertion deals with all directions and is able to restore the positions if any (#508) and (#509)
- [x] Create composed translate and position methods to structure getting insertion offset and margin (#510) and (#511).
F- Dealing with multiple transformations without settling into a new position (#519)
This scenario requires checking all the containers that are affected by the transformation and rollback each last transformation accordingly. This is done by adding a unique id
to the migration instance instead of a central one created for each clickable operation. E.g. The user clicks and transforms then one id
is created for this operation. This allows to roll back each transformation connected to the same id
. But to achieve multiple undo between containers the id is shifted into migration.
interface MigrationPerContainer {
/** Last known index for draggable before transitioning. */
index: number;
/** Transition siblings key. */
SK: string;
/** Transition unique id. */
id: string;
}
G- Enable multiple steps of transformation (#520)
- [x] Translate from origin to destination. The destination is not an orphan, the margin is then calculated based on the space between the last two elements in the destination container.
- [x] Translate from origin to destination. The destination is an orphan the margin is then calculated based on the space between the dragged and the next element in the origin container.
- [x] Translate from one destination to another. The destination is an orphan, same as above.
H- Add the ability to extend the transformation area between containers (#521). This allows accumulating all registered elements in one container.
Source code(tar.gz)
Source code(zip)