fix zindex to account for group boundaries (#2065)

This commit is contained in:
David Luzar 2020-09-11 17:06:07 +02:00 committed by GitHub
parent ea020f2c50
commit d07099aadd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1287 additions and 416 deletions

View file

@ -10,7 +10,11 @@ import { t } from "../i18n";
import { getShortcutKey } from "../utils";
import { LinearElementEditor } from "../element/linearElementEditor";
import { mutateElement } from "../element/mutateElement";
import { selectGroupsForSelectedElements } from "../groups";
import {
selectGroupsForSelectedElements,
getSelectedGroupForElement,
getElementsInGroup,
} from "../groups";
import { AppState } from "../types";
import { fixBindingsAfterDuplication } from "../element/binding";
import { ActionResult } from "./types";
@ -82,28 +86,53 @@ const duplicateElements = (
const newElements: ExcalidrawElement[] = [];
const oldElements: ExcalidrawElement[] = [];
const oldIdToDuplicatedId = new Map();
const finalElements = elements.reduce(
(acc: Array<ExcalidrawElement>, element: ExcalidrawElement) => {
if (appState.selectedElementIds[element.id]) {
const newElement = duplicateElement(
appState.editingGroupId,
groupIdMap,
element,
{
x: element.x + 10,
y: element.y + 10,
},
);
oldIdToDuplicatedId.set(element.id, newElement.id);
oldElements.push(element);
newElements.push(newElement);
return acc.concat([element, newElement]);
const duplicateAndOffsetElement = (element: ExcalidrawElement) => {
const newElement = duplicateElement(
appState.editingGroupId,
groupIdMap,
element,
{
x: element.x + 10,
y: element.y + 10,
},
);
oldIdToDuplicatedId.set(element.id, newElement.id);
oldElements.push(element);
newElements.push(newElement);
return newElement;
};
const finalElements: ExcalidrawElement[] = [];
let i = 0;
while (i < elements.length) {
const element = elements[i];
if (appState.selectedElementIds[element.id]) {
if (element.groupIds.length) {
const groupId = getSelectedGroupForElement(appState, element);
// if group selected, duplicate it atomically
if (groupId) {
const groupElements = getElementsInGroup(elements, groupId);
finalElements.push(
...groupElements,
...groupElements.map((element) =>
duplicateAndOffsetElement(element),
),
);
i = i + groupElements.length;
continue;
}
}
return acc.concat(element);
},
[],
);
finalElements.push(element, duplicateAndOffsetElement(element));
} else {
finalElements.push(element);
}
i++;
}
fixBindingsAfterDuplication(finalElements, oldElements, oldIdToDuplicatedId);
return {
elements: finalElements,
appState: selectGroupsForSelectedElements(

View file

@ -15,69 +15,12 @@ import {
SendToBackIcon,
BringForwardIcon,
} from "../components/icons";
import { ExcalidrawElement } from "../element/types";
import { AppState } from "../types";
const getElementIndices = (
direction: "left" | "right",
elements: readonly ExcalidrawElement[],
appState: AppState,
) => {
const selectedIndices: number[] = [];
let deletedIndicesCache: number[] = [];
const cb = (element: ExcalidrawElement, index: number) => {
if (element.isDeleted) {
// we want to build an array of deleted elements that are preceeding
// a selected element so that we move them together
deletedIndicesCache.push(index);
} else {
if (appState.selectedElementIds[element.id]) {
selectedIndices.push(...deletedIndicesCache, index);
}
// always empty cache of deleted elements after either pushing a group
// of selected/deleted elements, of after encountering non-deleted elem
deletedIndicesCache = [];
}
};
// sending back → select contiguous deleted elements that are to the left of
// selected element(s)
if (direction === "left") {
let i = -1;
const len = elements.length;
while (++i < len) {
cb(elements[i], i);
}
// moving to front → loop from right to left so that we don't need to
// backtrack when gathering deleted elements
} else {
let i = elements.length;
while (--i > -1) {
cb(elements[i], i);
}
}
// sort in case we were gathering indexes from right to left
return selectedIndices.sort();
};
const moveElements = (
func: typeof moveOneLeft,
elements: readonly ExcalidrawElement[],
appState: AppState,
) => {
const _elements = elements.slice();
const direction =
func === moveOneLeft || func === moveAllLeft ? "left" : "right";
const indices = getElementIndices(direction, _elements, appState);
return func(_elements, indices);
};
export const actionSendBackward = register({
name: "sendBackward",
perform: (elements, appState) => {
return {
elements: moveElements(moveOneLeft, elements, appState),
elements: moveOneLeft(elements, appState),
appState,
commitToHistory: true,
};
@ -102,7 +45,7 @@ export const actionBringForward = register({
name: "bringForward",
perform: (elements, appState) => {
return {
elements: moveElements(moveOneRight, elements, appState),
elements: moveOneRight(elements, appState),
appState,
commitToHistory: true,
};
@ -127,7 +70,7 @@ export const actionSendToBack = register({
name: "sendToBack",
perform: (elements, appState) => {
return {
elements: moveElements(moveAllLeft, elements, appState),
elements: moveAllLeft(elements, appState),
appState,
commitToHistory: true,
};
@ -160,7 +103,7 @@ export const actionBringToFront = register({
name: "bringToFront",
perform: (elements, appState) => {
return {
elements: moveElements(moveAllRight, elements, appState),
elements: moveAllRight(elements, appState),
appState,
commitToHistory: true,
};