Merged PR 212: Optimize FindChildrenById from O(n) to O(1)
Optimize FindChildrenById from O(n) to O(1): - Deprecate FindContainerByIdDFS - Container: Replace Children to string[] - Add HashMap to IHistoryState that contains all containers To access a container by id now cost O(1) without any additional cost + Implement CICD for SVGLibs
This commit is contained in:
parent
466ef2b08b
commit
c256a76e01
45 changed files with 775 additions and 450 deletions
|
@ -24,7 +24,8 @@ export function SelectContainer(
|
|||
|
||||
history.push({
|
||||
lastAction: `Select ${containerId}`,
|
||||
mainContainer: structuredClone(current.mainContainer),
|
||||
mainContainer: current.mainContainer,
|
||||
containers: structuredClone(current.containers),
|
||||
selectedContainerId: containerId,
|
||||
typeCounters: Object.assign({}, current.typeCounters),
|
||||
symbols: structuredClone(current.symbols),
|
||||
|
@ -48,8 +49,9 @@ export function DeleteContainer(
|
|||
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
|
||||
const current = history[history.length - 1];
|
||||
|
||||
const mainContainerClone: IContainerModel = structuredClone(current.mainContainer);
|
||||
const container = FindContainerById(mainContainerClone, containerId);
|
||||
const containers = structuredClone(current.containers);
|
||||
const mainContainerClone: IContainerModel | undefined = FindContainerById(containers, current.mainContainer);
|
||||
const container = FindContainerById(containers, containerId);
|
||||
|
||||
if (container === undefined) {
|
||||
throw new Error(`[DeleteContainer] Tried to delete a container that is not present in the main container: ${containerId}`);
|
||||
|
@ -71,21 +73,22 @@ export function DeleteContainer(
|
|||
}
|
||||
|
||||
const newSymbols = structuredClone(current.symbols);
|
||||
UnlinkContainerFromSymbols(newSymbols, container);
|
||||
UnlinkContainerFromSymbols(containers, newSymbols, container);
|
||||
|
||||
const index = container.parent.children.indexOf(container);
|
||||
if (index > -1) {
|
||||
const index = container.parent.children.indexOf(container.properties.id);
|
||||
const success = containers.delete(container.properties.id);
|
||||
if (index > -1 && success) {
|
||||
container.parent.children.splice(index, 1);
|
||||
} else {
|
||||
throw new Error('[DeleteContainer] Could not find container among parent\'s children');
|
||||
}
|
||||
|
||||
ApplyBehaviorsOnSiblings(container, current.symbols);
|
||||
ApplyBehaviorsOnSiblings(containers, container, current.symbols);
|
||||
|
||||
// Select the previous container
|
||||
// or select the one above
|
||||
const selectedContainerId = GetSelectedContainerOnDelete(
|
||||
mainContainerClone,
|
||||
containers,
|
||||
current.selectedContainerId,
|
||||
container.parent,
|
||||
index
|
||||
|
@ -93,7 +96,8 @@ export function DeleteContainer(
|
|||
|
||||
history.push({
|
||||
lastAction: `Delete ${containerId}`,
|
||||
mainContainer: mainContainerClone,
|
||||
mainContainer: current.mainContainer,
|
||||
containers,
|
||||
selectedContainerId,
|
||||
typeCounters: Object.assign({}, current.typeCounters),
|
||||
symbols: newSymbols,
|
||||
|
@ -115,16 +119,15 @@ export function DeleteContainer(
|
|||
* @returns {IContainerModel} Next selected container
|
||||
*/
|
||||
function GetSelectedContainerOnDelete(
|
||||
mainContainerClone: IContainerModel,
|
||||
containers: Map<string, IContainerModel>,
|
||||
selectedContainerId: string,
|
||||
parent: IContainerModel,
|
||||
index: number
|
||||
): string {
|
||||
const newSelectedContainer = FindContainerById(mainContainerClone, selectedContainerId) ??
|
||||
const newSelectedContainerId = FindContainerById(containers, selectedContainerId)?.properties.id ??
|
||||
parent.children.at(index) ??
|
||||
parent.children.at(index - 1) ??
|
||||
parent;
|
||||
const newSelectedContainerId = newSelectedContainer.properties.id;
|
||||
parent.properties.id;
|
||||
return newSelectedContainerId;
|
||||
}
|
||||
|
||||
|
@ -134,8 +137,12 @@ function GetSelectedContainerOnDelete(
|
|||
* @param symbols Symbols to update
|
||||
* @param container Container to unlink
|
||||
*/
|
||||
function UnlinkContainerFromSymbols(symbols: Map<string, ISymbolModel>, container: IContainerModel): void {
|
||||
const it = MakeDFSIterator(container);
|
||||
function UnlinkContainerFromSymbols(
|
||||
containers: Map<string, IContainerModel>,
|
||||
symbols: Map<string, ISymbolModel>,
|
||||
container: IContainerModel
|
||||
): void {
|
||||
const it = MakeDFSIterator(container, containers);
|
||||
for (const child of it) {
|
||||
const symbol = symbols.get(child.properties.linkedSymbolId);
|
||||
if (symbol === undefined) {
|
||||
|
@ -167,18 +174,19 @@ export function OnPropertyChange(
|
|||
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
||||
}
|
||||
|
||||
const mainContainerClone: IContainerModel = structuredClone(current.mainContainer);
|
||||
const container: ContainerModel | undefined = FindContainerById(mainContainerClone, selected.properties.id);
|
||||
const containers = structuredClone(current.containers);
|
||||
const container: ContainerModel | undefined = FindContainerById(containers, selected.properties.id);
|
||||
|
||||
if (container === null || container === undefined) {
|
||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
||||
}
|
||||
|
||||
SetContainer(container, key, value, type, current.symbols);
|
||||
SetContainer(containers, container, key, value, type, current.symbols);
|
||||
|
||||
history.push({
|
||||
lastAction: `Change ${key} of ${container.properties.id}`,
|
||||
mainContainer: mainContainerClone,
|
||||
mainContainer: current.mainContainer,
|
||||
containers,
|
||||
selectedContainerId: container.properties.id,
|
||||
typeCounters: Object.assign({}, current.typeCounters),
|
||||
symbols: structuredClone(current.symbols),
|
||||
|
@ -189,20 +197,30 @@ export function OnPropertyChange(
|
|||
|
||||
/**
|
||||
* Sort the parent children by x
|
||||
* @param parentClone The clone used for the sort
|
||||
* @param parent The clone used for the sort
|
||||
* @returns void
|
||||
*/
|
||||
export function SortChildren(parentClone: IContainerModel | null | undefined): void {
|
||||
if (parentClone === null || parentClone === undefined) {
|
||||
export function SortChildren(
|
||||
containers: Map<string, IContainerModel>,
|
||||
parent: IContainerModel | null | undefined
|
||||
): void {
|
||||
if (parent === null || parent === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isHorizontal = parentClone.properties.orientation === Orientation.Horizontal;
|
||||
const children = parentClone.children;
|
||||
const isHorizontal = parent.properties.orientation === Orientation.Horizontal;
|
||||
const children = parent.children;
|
||||
|
||||
if (!isHorizontal) {
|
||||
parentClone.children.sort(
|
||||
(a, b) => {
|
||||
parent.children.sort(
|
||||
(aId, bId) => {
|
||||
const a = FindContainerById(containers, aId);
|
||||
const b = FindContainerById(containers, bId);
|
||||
|
||||
if (a === undefined || b === undefined) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const yA = TransformY(a.properties.y, a.properties.height, a.properties.positionReference);
|
||||
const yB = TransformY(b.properties.y, b.properties.height, b.properties.positionReference);
|
||||
if (yA < yB) {
|
||||
|
@ -212,16 +230,23 @@ export function SortChildren(parentClone: IContainerModel | null | undefined): v
|
|||
return 1;
|
||||
}
|
||||
// xA = xB
|
||||
const indexA = children.indexOf(a);
|
||||
const indexB = children.indexOf(b);
|
||||
const indexA = children.indexOf(aId);
|
||||
const indexB = children.indexOf(bId);
|
||||
return indexA - indexB;
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
parentClone.children.sort(
|
||||
(a, b) => {
|
||||
parent.children.sort(
|
||||
(aId, bId) => {
|
||||
const a = FindContainerById(containers, aId);
|
||||
const b = FindContainerById(containers, bId);
|
||||
|
||||
if (a === undefined || b === undefined) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const xA = TransformX(a.properties.x, a.properties.width, a.properties.positionReference);
|
||||
const xB = TransformX(b.properties.x, b.properties.width, b.properties.positionReference);
|
||||
if (xA < xB) {
|
||||
|
@ -231,8 +256,8 @@ export function SortChildren(parentClone: IContainerModel | null | undefined): v
|
|||
return 1;
|
||||
}
|
||||
// xA = xB
|
||||
const indexA = children.indexOf(a);
|
||||
const indexB = children.indexOf(b);
|
||||
const indexA = children.indexOf(aId);
|
||||
const indexB = children.indexOf(bId);
|
||||
return indexA - indexB;
|
||||
}
|
||||
);
|
||||
|
@ -247,6 +272,7 @@ export function SortChildren(parentClone: IContainerModel | null | undefined): v
|
|||
* @param symbols Current list of symbols
|
||||
*/
|
||||
function SetContainer(
|
||||
containers: Map<string, IContainerModel>,
|
||||
container: ContainerModel,
|
||||
key: string, value: string | number | boolean | number[],
|
||||
type: PropertyType,
|
||||
|
@ -267,13 +293,13 @@ function SetContainer(
|
|||
);
|
||||
|
||||
// sort the children list by their position
|
||||
SortChildren(container.parent);
|
||||
SortChildren(containers, container.parent);
|
||||
|
||||
// Apply special behaviors: rigid, flex, symbol, anchor
|
||||
ApplyBehaviors(container, symbols);
|
||||
ApplyBehaviors(containers, container, symbols);
|
||||
|
||||
// Apply special behaviors on siblings
|
||||
ApplyBehaviorsOnSiblingsChildren(container, symbols);
|
||||
ApplyBehaviorsOnSiblingsChildren(containers, container, symbols);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue