Skip to content

Commit

Permalink
feat(common): ensuring consistent hierarchy of all selected elements …
Browse files Browse the repository at this point in the history
…when add group #WIK-14768 (#824)
  • Loading branch information
huanhuanwa authored Apr 16, 2024
1 parent a69d2db commit ba48c19
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 55 deletions.
6 changes: 6 additions & 0 deletions .changeset/hip-apricots-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@plait/common': patch
'@plait/core': patch
---

ensuring consistent hierarchy of all selected elements when add group
4 changes: 2 additions & 2 deletions packages/common/src/transforms/z-index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PlaitBoard } from '@plait/core';
import { getOneMoveOptions, moveElementsToNewPath, getAllMoveOptions } from '../utils';
import { moveElementsToNewPath, PlaitBoard } from '@plait/core';
import { getOneMoveOptions, getAllMoveOptions } from '../utils';

const moveToTop = (board: PlaitBoard) => {
const moveOptions = getAllMoveOptions(board, 'up');
Expand Down
55 changes: 11 additions & 44 deletions packages/common/src/utils/z-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,19 @@ import {
getGroupByElement,
PlaitGroup,
getElementsInGroup,
Transforms,
Path,
findIndex
findIndex,
getElementsIndices,
MoveNodeOption,
sortElements,
} from '@plait/core';

export interface ZIndexMoveOption {
element: PlaitElement;
newPath: Path;
}

export const moveElementsToNewPath = (board: PlaitBoard, zIndexMoveOption: ZIndexMoveOption[]) => {
zIndexMoveOption
.map(item => {
const path = PlaitBoard.findPath(board, item.element);
const ref = board.pathRef(path);
return () => {
ref.current && Transforms.moveNode(board, ref.current, item.newPath);
ref.unref();
};
})
.forEach(action => {
action();
});
};

export const getOneMoveOptions = (board: PlaitBoard, direction: 'down' | 'up'): ZIndexMoveOption[] => {
export const getOneMoveOptions = (board: PlaitBoard, direction: 'down' | 'up'): MoveNodeOption[] => {
const indicesToMove = getIndicesToMove(board);
let groupedIndices = toContiguousGroups(board, indicesToMove);
if (direction === 'up') {
groupedIndices = groupedIndices.reverse();
}
let moveContents: ZIndexMoveOption[] = [];
let moveContents: MoveNodeOption[] = [];
groupedIndices.forEach((indices, i) => {
const leadingIndex = indices[0];
const trailingIndex = indices[indices.length - 1];
Expand All @@ -65,10 +46,10 @@ export const getOneMoveOptions = (board: PlaitBoard, direction: 'down' | 'up'):
return moveContents;
};

export const getAllMoveOptions = (board: PlaitBoard, direction: 'down' | 'up'): ZIndexMoveOption[] => {
export const getAllMoveOptions = (board: PlaitBoard, direction: 'down' | 'up'): MoveNodeOption[] => {
const indicesToMove = getIndicesToMove(board);
let groupedIndices = toContiguousGroups(board, indicesToMove);
let moveContents: ZIndexMoveOption[] = [];
let moveContents: MoveNodeOption[] = [];
if (direction === 'up') {
groupedIndices = groupedIndices.reverse();
}
Expand All @@ -80,7 +61,7 @@ export const getAllMoveOptions = (board: PlaitBoard, direction: 'down' | 'up'):
const editingGroup = getEditingGroup(board, sourceElement);
let targetIndex = direction === 'down' ? 0 : board.children.length - 1;
if (editingGroup) {
const elementsInGroup = ascendingSortElements(board, getElementsInGroup(board, editingGroup, true, true));
const elementsInGroup = sortElements(board, getElementsInGroup(board, editingGroup, true, true));
targetIndex =
direction === 'down'
? board.children.indexOf(elementsInGroup[0])
Expand Down Expand Up @@ -190,20 +171,6 @@ const getTargetIndex = (board: PlaitBoard, boundaryIndex: number, direction: 'do
};

const getIndicesToMove = (board: PlaitBoard) => {
const selectedElements = [...getSelectedElements(board), ...getSelectedGroups(board)].filter(item => board.canSetZIndex(item));
return selectedElements
.map(item => {
return board.children.indexOf(item);
})
.sort((a, b) => {
return a - b;
});
};

const ascendingSortElements = (board: PlaitBoard, elements: PlaitElement[] = []) => {
return elements.sort((a, b) => {
const indexA = board.children.findIndex(child => child.id === a.id);
const indexB = board.children.findIndex(child => child.id === b.id);
return indexA - indexB;
});
const selectedElements = [...getSelectedElements(board), ...getSelectedGroups(board)];
return getElementsIndices(board, selectedElements);
};
19 changes: 16 additions & 3 deletions packages/core/src/transforms/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {
canAddGroup,
hasSelectedElementsInSameGroup,
canRemoveGroup,
findElements
findElements,
getElementsIndices,
isIndicesContinuous,
getSelectedElements,
getHighestIndexOfElement,
moveElementsToNewPathAfterAddGroup
} from '../utils';
import { NodeTransforms } from './node';

Expand All @@ -20,6 +25,14 @@ export const addGroup = (board: PlaitBoard, elements?: PlaitElement[]) => {
const path = PlaitBoard.findPath(board, item);
NodeTransforms.setNode(board, { groupId: group.id }, path);
});
const selectedElements = getSelectedElements(board);
const highestIndexOfSelectedElement = getHighestIndexOfElement(board, [...selectedElements, ...selectedGroups]);
const indices = getElementsIndices(board, highestSelectedElements);
const isContinuous = isIndicesContinuous(indices);
if (!isContinuous) {
moveElementsToNewPathAfterAddGroup(board, [...selectedElements, ...selectedGroups], [highestIndexOfSelectedElement - 1]);
}
const groupPath = [highestIndexOfSelectedElement + 1];
if (hasSelectedElementsInSameGroup(highestSelectedElements)) {
const newGroupId = selectedIsolatedElements[0].groupId;
NodeTransforms.insertNode(
Expand All @@ -28,10 +41,10 @@ export const addGroup = (board: PlaitBoard, elements?: PlaitElement[]) => {
...group,
groupId: newGroupId
},
[board.children.length]
groupPath
);
} else {
NodeTransforms.insertNode(board, group, [board.children.length]);
NodeTransforms.insertNode(board, group, groupPath);
}
}
};
Expand Down
35 changes: 35 additions & 0 deletions packages/core/src/utils/common.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { Path, PlaitElement } from '../interfaces';
import { PlaitBoard } from '../interfaces/board';
import { Subscription, timer } from 'rxjs';
import { NodeTransforms } from '../transforms/node';
import { sortElements } from './position';

const BOARD_TO_RAF = new WeakMap<PlaitBoard, { [key: string]: number | null }>();

export interface MoveNodeOption {
element: PlaitElement;
newPath: Path;
}

const getTimerId = (board: PlaitBoard, key: string) => {
const state = getRAFState(board);
return state[key] || null;
Expand Down Expand Up @@ -49,3 +57,30 @@ export const debounce = (func: () => void, wait: number, options?: { leading: bo
}
};
};

export const getElementsIndices = (board: PlaitBoard, elements: PlaitElement[]): number[] => {
sortElements(board, elements);
return elements.map(item => {
return board.children.map(item => item.id).indexOf(item.id);
});
};

export const getHighestIndexOfElement = (board: PlaitBoard, elements: PlaitElement[]) => {
const indices = getElementsIndices(board, elements);
return indices[indices.length-1];
};

export const moveElementsToNewPath = (board: PlaitBoard, moveOptions: MoveNodeOption[]) => {
moveOptions
.map(item => {
const path = PlaitBoard.findPath(board, item.element);
const ref = board.pathRef(path);
return () => {
ref.current && NodeTransforms.moveNode(board, ref.current, item.newPath);
ref.unref();
};
})
.forEach(action => {
action();
});
};
21 changes: 18 additions & 3 deletions packages/core/src/utils/group.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ACTIVE_STROKE_WIDTH } from '../constants';
import { PlaitBoard, PlaitElement, PlaitGroup, PlaitGroupElement, RectangleClient, SELECTION_BORDER_COLOR } from '../interfaces';
import { Path, PlaitBoard, PlaitElement, PlaitGroup, PlaitGroupElement, RectangleClient, SELECTION_BORDER_COLOR } from '../interfaces';
import { getSelectionAngle } from './angle';
import { createG, setAngleForG } from './dom';
import { drawRectangle } from './drawing/rectangle';
Expand All @@ -8,6 +8,8 @@ import { idCreator } from './id-creator';
import { getSelectedElements } from './selected-element';
import { isSelectionMoving } from './selection';
import { depthFirstRecursion } from './tree';
import { moveElementsToNewPath } from './common';
import { sortElements } from './position';

export const getElementsInGroup = (board: PlaitBoard, group: PlaitGroup, recursion?: boolean, includeGroup?: boolean) => {
let result: PlaitElement[] = [];
Expand Down Expand Up @@ -234,7 +236,6 @@ export const canRemoveGroup = (board: PlaitBoard, elements?: PlaitElement[]) =>
return selectedElements.length > 0 && selectedGroups.length > 0;
};


export const getEditingGroup = (board: PlaitBoard, element: PlaitElement) => {
const groups = getGroupByElement(board, element, true) as PlaitGroup[];
let editingGroup = null;
Expand All @@ -247,4 +248,18 @@ export const getEditingGroup = (board: PlaitBoard, element: PlaitElement) => {
}
}
return editingGroup;
};
};

export const moveElementsToNewPathAfterAddGroup = (board: PlaitBoard, moveElements: PlaitElement[], newPath: Path) => {
sortElements(board, moveElements);
moveElements.pop();
moveElementsToNewPath(
board,
moveElements.map(element => {
return {
element,
newPath
};
})
);
};
10 changes: 10 additions & 0 deletions packages/core/src/utils/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,13 @@ export const findIndex = <T>(
}
return -1;
};

export const isIndicesContinuous = (indexes: number[]): boolean => {
indexes.sort((a, b) => a - b);
for (let i = 1; i < indexes.length; i++) {
if (indexes[i] !== indexes[i - 1] + 1) {
return false;
}
}
return true;
};
3 changes: 2 additions & 1 deletion packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export * from './group';
export * from './selection';
export * from './angle';
export * from './fragment';
export * from './snap/snap';
export * from './snap/snap';
export * from './position';
4 changes: 2 additions & 2 deletions packages/core/src/utils/position.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { PlaitBoard, PlaitElement } from '../interfaces';

export const sortElements = (board: PlaitBoard, elements: PlaitElement[]) => {
export const sortElements = (board: PlaitBoard, elements: PlaitElement[], ascendingOrder = true) => {
return [...elements].sort((a: PlaitElement, b: PlaitElement) => {
const pathA = PlaitBoard.findPath(board, a);
const pathB = PlaitBoard.findPath(board, b);
return pathA[0] - pathB[0];
return ascendingOrder ? pathA[0] - pathB[0] : pathB[0] - pathA[0];
});
};

0 comments on commit ba48c19

Please sign in to comment.