feat: make appState.selectedElementIds
more stable (#6745)
This commit is contained in:
parent
3ddcc48e4c
commit
49e4289878
@ -31,6 +31,7 @@ import {
|
|||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import { getSelectedElements } from "../scene";
|
import { getSelectedElements } from "../scene";
|
||||||
import { AppState } from "../types";
|
import { AppState } from "../types";
|
||||||
|
import { Mutable } from "../utility-types";
|
||||||
import { getFontString } from "../utils";
|
import { getFontString } from "../utils";
|
||||||
import { register } from "./register";
|
import { register } from "./register";
|
||||||
|
|
||||||
@ -211,7 +212,7 @@ export const actionWrapTextInContainer = register({
|
|||||||
appState,
|
appState,
|
||||||
);
|
);
|
||||||
let updatedElements: readonly ExcalidrawElement[] = elements.slice();
|
let updatedElements: readonly ExcalidrawElement[] = elements.slice();
|
||||||
const containerIds: AppState["selectedElementIds"] = {};
|
const containerIds: Mutable<AppState["selectedElementIds"]> = {};
|
||||||
|
|
||||||
for (const textElement of selectedElements) {
|
for (const textElement of selectedElements) {
|
||||||
if (isTextElement(textElement)) {
|
if (isTextElement(textElement)) {
|
||||||
|
@ -274,6 +274,7 @@ const duplicateElements = (
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
getNonDeletedElements(finalElements),
|
getNonDeletedElements(finalElements),
|
||||||
|
appState,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -125,13 +125,6 @@ export const actionFinalize = register({
|
|||||||
{ x, y },
|
{ x, y },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
!appState.activeTool.locked &&
|
|
||||||
appState.activeTool.type !== "freedraw"
|
|
||||||
) {
|
|
||||||
appState.selectedElementIds[multiPointElement.id] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -218,6 +218,7 @@ export const actionUngroup = register({
|
|||||||
const updateAppState = selectGroupsForSelectedElements(
|
const updateAppState = selectGroupsForSelectedElements(
|
||||||
{ ...appState, selectedGroupIds: {} },
|
{ ...appState, selectedGroupIds: {} },
|
||||||
getNonDeletedElements(nextElements),
|
getNonDeletedElements(nextElements),
|
||||||
|
appState,
|
||||||
);
|
);
|
||||||
|
|
||||||
frames.forEach((frame) => {
|
frames.forEach((frame) => {
|
||||||
@ -232,9 +233,18 @@ export const actionUngroup = register({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// remove binded text elements from selection
|
// remove binded text elements from selection
|
||||||
boundTextElementIds.forEach(
|
updateAppState.selectedElementIds = Object.entries(
|
||||||
(id) => (updateAppState.selectedElementIds[id] = false),
|
updateAppState.selectedElementIds,
|
||||||
|
).reduce(
|
||||||
|
(acc: { [key: ExcalidrawElement["id"]]: true }, [id, selected]) => {
|
||||||
|
if (selected && !boundTextElementIds.includes(id)) {
|
||||||
|
acc[id] = true;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appState: updateAppState,
|
appState: updateAppState,
|
||||||
elements: nextElements,
|
elements: nextElements,
|
||||||
|
@ -41,6 +41,7 @@ export const actionSelectAll = register({
|
|||||||
selectedElementIds,
|
selectedElementIds,
|
||||||
},
|
},
|
||||||
getNonDeletedElements(elements),
|
getNonDeletedElements(elements),
|
||||||
|
appState,
|
||||||
),
|
),
|
||||||
commitToHistory: true,
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
|
@ -315,7 +315,10 @@ import {
|
|||||||
updateFrameMembershipOfSelectedElements,
|
updateFrameMembershipOfSelectedElements,
|
||||||
isElementInFrame,
|
isElementInFrame,
|
||||||
} from "../frame";
|
} from "../frame";
|
||||||
import { excludeElementsInFramesFromSelection } from "../scene/selection";
|
import {
|
||||||
|
excludeElementsInFramesFromSelection,
|
||||||
|
makeNextSelectedElementIds,
|
||||||
|
} from "../scene/selection";
|
||||||
import { actionPaste } from "../actions/actionClipboard";
|
import { actionPaste } from "../actions/actionClipboard";
|
||||||
import {
|
import {
|
||||||
actionRemoveAllElementsFromFrame,
|
actionRemoveAllElementsFromFrame,
|
||||||
@ -1353,6 +1356,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scene.destroy();
|
this.scene.destroy();
|
||||||
this.library.destroy();
|
this.library.destroy();
|
||||||
clearTimeout(touchTimeout);
|
clearTimeout(touchTimeout);
|
||||||
|
isSomeElementSelected.clearCache();
|
||||||
touchTimeout = 0;
|
touchTimeout = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1825,7 +1829,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
if (event.touches.length === 2) {
|
if (event.touches.length === 2) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1835,7 +1839,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (event.touches.length > 0) {
|
if (event.touches.length > 0) {
|
||||||
this.setState({
|
this.setState({
|
||||||
previousSelectedElementIds: {},
|
previousSelectedElementIds: {},
|
||||||
selectedElementIds: this.state.previousSelectedElementIds,
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
this.state.previousSelectedElementIds,
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
gesture.pointers.clear();
|
gesture.pointers.clear();
|
||||||
@ -1895,7 +1902,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
const imageElement = this.createImageElement({ sceneX, sceneY });
|
const imageElement = this.createImageElement({ sceneX, sceneY });
|
||||||
this.insertImageElement(imageElement, file);
|
this.insertImageElement(imageElement, file);
|
||||||
this.initializeImageDimensions(imageElement);
|
this.initializeImageDimensions(imageElement);
|
||||||
this.setState({ selectedElementIds: { [imageElement.id]: true } });
|
this.setState({
|
||||||
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
{
|
||||||
|
[imageElement.id]: true,
|
||||||
|
},
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2032,6 +2046,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.state,
|
||||||
),
|
),
|
||||||
() => {
|
() => {
|
||||||
if (opts.files) {
|
if (opts.files) {
|
||||||
@ -2130,8 +2145,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: Object.fromEntries(
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
textElements.map((el) => [el.id, true]),
|
Object.fromEntries(textElements.map((el) => [el.id, true])),
|
||||||
|
this.state,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2749,7 +2765,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
} else {
|
} else {
|
||||||
setCursorForShape(this.canvas, this.state);
|
setCursorForShape(this.canvas, this.state);
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
});
|
});
|
||||||
@ -2794,7 +2810,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (nextActiveTool.type !== "selection") {
|
if (nextActiveTool.type !== "selection") {
|
||||||
this.setState({
|
this.setState({
|
||||||
activeTool: nextActiveTool,
|
activeTool: nextActiveTool,
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
});
|
});
|
||||||
@ -2831,7 +2847,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// elements by mistake while zooming
|
// elements by mistake while zooming
|
||||||
if (this.isTouchScreenMultiTouchGesture()) {
|
if (this.isTouchScreenMultiTouchGesture()) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
gesture.initialScale = this.state.zoom.value;
|
gesture.initialScale = this.state.zoom.value;
|
||||||
@ -2876,7 +2892,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (this.isTouchScreenMultiTouchGesture()) {
|
if (this.isTouchScreenMultiTouchGesture()) {
|
||||||
this.setState({
|
this.setState({
|
||||||
previousSelectedElementIds: {},
|
previousSelectedElementIds: {},
|
||||||
selectedElementIds: this.state.previousSelectedElementIds,
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
this.state.previousSelectedElementIds,
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
gesture.initialScale = null;
|
gesture.initialScale = null;
|
||||||
@ -2941,10 +2960,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
? element.containerId
|
? element.containerId
|
||||||
: element.id;
|
: element.id;
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
selectedElementIds: {
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
...prevState.selectedElementIds,
|
{
|
||||||
[elementIdToSelect]: true,
|
...prevState.selectedElementIds,
|
||||||
},
|
[elementIdToSelect]: true,
|
||||||
|
},
|
||||||
|
prevState,
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (isDeleted) {
|
if (isDeleted) {
|
||||||
@ -2980,7 +3002,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
private deselectElements() {
|
private deselectElements() {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
});
|
});
|
||||||
@ -3291,6 +3313,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@ -3998,12 +4021,15 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
editingElement: null,
|
editingElement: null,
|
||||||
startBoundElement: null,
|
startBoundElement: null,
|
||||||
suggestedBindings: [],
|
suggestedBindings: [],
|
||||||
selectedElementIds: Object.keys(this.state.selectedElementIds)
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
.filter((key) => key !== element.id)
|
Object.keys(this.state.selectedElementIds)
|
||||||
.reduce((obj: { [id: string]: boolean }, key) => {
|
.filter((key) => key !== element.id)
|
||||||
obj[key] = this.state.selectedElementIds[key];
|
.reduce((obj: { [id: string]: true }, key) => {
|
||||||
return obj;
|
obj[key] = this.state.selectedElementIds[key];
|
||||||
}, {}),
|
return obj;
|
||||||
|
}, {}),
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@ -4472,7 +4498,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
private clearSelectionIfNotUsingSelection = (): void => {
|
private clearSelectionIfNotUsingSelection = (): void => {
|
||||||
if (this.state.activeTool.type !== "selection") {
|
if (this.state.activeTool.type !== "selection") {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
});
|
});
|
||||||
@ -4604,9 +4630,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
if (this.state.editingLinearElement) {
|
if (this.state.editingLinearElement) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
[this.state.editingLinearElement.elementId]: true,
|
{
|
||||||
},
|
[this.state.editingLinearElement.elementId]: true,
|
||||||
|
},
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
// If we click on something
|
// If we click on something
|
||||||
} else if (hitElement != null) {
|
} else if (hitElement != null) {
|
||||||
@ -4634,7 +4663,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
!isElementInGroup(hitElement, this.state.editingGroupId)
|
!isElementInGroup(hitElement, this.state.editingGroupId)
|
||||||
) {
|
) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
});
|
});
|
||||||
@ -4650,7 +4679,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
!pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements
|
!pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements
|
||||||
) {
|
) {
|
||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
const nextSelectedElementIds = {
|
const nextSelectedElementIds: { [id: string]: true } = {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
[hitElement.id]: true,
|
[hitElement.id]: true,
|
||||||
};
|
};
|
||||||
@ -4668,13 +4697,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
previouslySelectedElements,
|
previouslySelectedElements,
|
||||||
hitElement.id,
|
hitElement.id,
|
||||||
).forEach((element) => {
|
).forEach((element) => {
|
||||||
nextSelectedElementIds[element.id] = false;
|
delete nextSelectedElementIds[element.id];
|
||||||
});
|
});
|
||||||
} else if (hitElement.frameId) {
|
} else if (hitElement.frameId) {
|
||||||
// if hitElement is in a frame and its frame has been selected
|
// if hitElement is in a frame and its frame has been selected
|
||||||
// disable selection for the given element
|
// disable selection for the given element
|
||||||
if (nextSelectedElementIds[hitElement.frameId]) {
|
if (nextSelectedElementIds[hitElement.frameId]) {
|
||||||
nextSelectedElementIds[hitElement.id] = false;
|
delete nextSelectedElementIds[hitElement.id];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// hitElement is neither a frame nor an element in a frame
|
// hitElement is neither a frame nor an element in a frame
|
||||||
@ -4704,7 +4733,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
framesInGroups.has(element.frameId)
|
framesInGroups.has(element.frameId)
|
||||||
) {
|
) {
|
||||||
// deselect element and groups containing the element
|
// deselect element and groups containing the element
|
||||||
nextSelectedElementIds[element.id] = false;
|
delete nextSelectedElementIds[element.id];
|
||||||
element.groupIds
|
element.groupIds
|
||||||
.flatMap((gid) =>
|
.flatMap((gid) =>
|
||||||
getElementsInGroup(
|
getElementsInGroup(
|
||||||
@ -4712,10 +4741,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
gid,
|
gid,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.forEach(
|
.forEach((element) => {
|
||||||
(element) =>
|
delete nextSelectedElementIds[element.id];
|
||||||
(nextSelectedElementIds[element.id] = false),
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -4728,6 +4756,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
showHyperlinkPopup: hitElement.link ? "info" : false,
|
showHyperlinkPopup: hitElement.link ? "info" : false,
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
pointerDownState.hit.wasAddedToSelection = true;
|
pointerDownState.hit.wasAddedToSelection = true;
|
||||||
@ -4844,12 +4873,18 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
frameId: topLayerFrame ? topLayerFrame.id : null,
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => {
|
||||||
selectedElementIds: {
|
const nextSelectedElementIds = {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
[element.id]: false,
|
};
|
||||||
},
|
delete nextSelectedElementIds[element.id];
|
||||||
}));
|
return {
|
||||||
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
nextSelectedElementIds,
|
||||||
|
prevState,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const pressures = element.simulatePressure
|
const pressures = element.simulatePressure
|
||||||
? element.pressures
|
? element.pressures
|
||||||
@ -4945,10 +4980,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
selectedElementIds: {
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
...prevState.selectedElementIds,
|
{
|
||||||
[multiElement.id]: true,
|
...prevState.selectedElementIds,
|
||||||
},
|
[multiElement.id]: true,
|
||||||
|
},
|
||||||
|
prevState,
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
// clicking outside commit zone → update reference for last committed
|
// clicking outside commit zone → update reference for last committed
|
||||||
// point
|
// point
|
||||||
@ -4999,12 +5037,18 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
locked: false,
|
locked: false,
|
||||||
frameId: topLayerFrame ? topLayerFrame.id : null,
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
||||||
});
|
});
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => {
|
||||||
selectedElementIds: {
|
const nextSelectedElementIds = {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
[element.id]: false,
|
};
|
||||||
},
|
delete nextSelectedElementIds[element.id];
|
||||||
}));
|
return {
|
||||||
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
nextSelectedElementIds,
|
||||||
|
prevState,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
mutateElement(element, {
|
mutateElement(element, {
|
||||||
points: [...element.points, [0, 0]],
|
points: [...element.points, [0, 0]],
|
||||||
});
|
});
|
||||||
@ -5378,15 +5422,16 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
const oldIdToDuplicatedId = new Map();
|
const oldIdToDuplicatedId = new Map();
|
||||||
const hitElement = pointerDownState.hit.element;
|
const hitElement = pointerDownState.hit.element;
|
||||||
const elements = this.scene.getElementsIncludingDeleted();
|
const elements = this.scene.getElementsIncludingDeleted();
|
||||||
const selectedElementIds: Array<ExcalidrawElement["id"]> =
|
const selectedElementIds = new Set(
|
||||||
getSelectedElements(elements, this.state, {
|
getSelectedElements(elements, this.state, {
|
||||||
includeBoundTextElement: true,
|
includeBoundTextElement: true,
|
||||||
includeElementsInFrames: true,
|
includeElementsInFrames: true,
|
||||||
}).map((element) => element.id);
|
}).map((element) => element.id),
|
||||||
|
);
|
||||||
|
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
if (
|
if (
|
||||||
selectedElementIds.includes(element.id) ||
|
selectedElementIds.has(element.id) ||
|
||||||
// case: the state.selectedElementIds might not have been
|
// case: the state.selectedElementIds might not have been
|
||||||
// updated yet by the time this mousemove event is fired
|
// updated yet by the time this mousemove event is fired
|
||||||
(element.id === hitElement?.id &&
|
(element.id === hitElement?.id &&
|
||||||
@ -5524,14 +5569,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
selectedElementIds: {},
|
|
||||||
selectedGroupIds: {},
|
|
||||||
editingGroupId: null,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// box-select line editor points
|
// box-select line editor points
|
||||||
@ -5547,28 +5587,29 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
elements,
|
elements,
|
||||||
draggingElement,
|
draggingElement,
|
||||||
);
|
);
|
||||||
this.setState((prevState) =>
|
this.setState((prevState) => {
|
||||||
selectGroupsForSelectedElements(
|
const nextSelectedElementIds = elementsWithinSelection.reduce(
|
||||||
|
(acc: Record<ExcalidrawElement["id"], true>, element) => {
|
||||||
|
acc[element.id] = true;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pointerDownState.hit.element) {
|
||||||
|
// if using ctrl/cmd, select the hitElement only if we
|
||||||
|
// haven't box-selected anything else
|
||||||
|
if (!elementsWithinSelection.length) {
|
||||||
|
nextSelectedElementIds[pointerDownState.hit.element.id] = true;
|
||||||
|
} else {
|
||||||
|
delete nextSelectedElementIds[pointerDownState.hit.element.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectGroupsForSelectedElements(
|
||||||
{
|
{
|
||||||
...prevState,
|
...prevState,
|
||||||
selectedElementIds: {
|
selectedElementIds: nextSelectedElementIds,
|
||||||
...prevState.selectedElementIds,
|
|
||||||
...elementsWithinSelection.reduce(
|
|
||||||
(acc: Record<ExcalidrawElement["id"], true>, element) => {
|
|
||||||
acc[element.id] = true;
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
...(pointerDownState.hit.element
|
|
||||||
? {
|
|
||||||
// if using ctrl/cmd, select the hitElement only if we
|
|
||||||
// haven't box-selected anything else
|
|
||||||
[pointerDownState.hit.element.id]:
|
|
||||||
!elementsWithinSelection.length,
|
|
||||||
}
|
|
||||||
: null),
|
|
||||||
},
|
|
||||||
showHyperlinkPopup:
|
showHyperlinkPopup:
|
||||||
elementsWithinSelection.length === 1 &&
|
elementsWithinSelection.length === 1 &&
|
||||||
elementsWithinSelection[0].link
|
elementsWithinSelection[0].link
|
||||||
@ -5585,8 +5626,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
: null,
|
: null,
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
),
|
prevState,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -5780,7 +5822,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
try {
|
try {
|
||||||
this.initializeImageDimensions(imageElement);
|
this.initializeImageDimensions(imageElement);
|
||||||
this.setState(
|
this.setState(
|
||||||
{ selectedElementIds: { [imageElement.id]: true } },
|
{
|
||||||
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
{ [imageElement.id]: true },
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
|
},
|
||||||
() => {
|
() => {
|
||||||
this.actionManager.executeAction(actionFinalize);
|
this.actionManager.executeAction(actionFinalize);
|
||||||
},
|
},
|
||||||
@ -5844,10 +5891,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
activeTool: updateActiveTool(this.state, {
|
activeTool: updateActiveTool(this.state, {
|
||||||
type: "selection",
|
type: "selection",
|
||||||
}),
|
}),
|
||||||
selectedElementIds: {
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
...prevState.selectedElementIds,
|
{
|
||||||
[draggingElement.id]: true,
|
...prevState.selectedElementIds,
|
||||||
},
|
[draggingElement.id]: true,
|
||||||
|
},
|
||||||
|
prevState,
|
||||||
|
),
|
||||||
selectedLinearElement: new LinearElementEditor(
|
selectedLinearElement: new LinearElementEditor(
|
||||||
draggingElement,
|
draggingElement,
|
||||||
this.scene,
|
this.scene,
|
||||||
@ -6141,31 +6191,37 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (childEvent.shiftKey && !this.state.editingLinearElement) {
|
if (childEvent.shiftKey && !this.state.editingLinearElement) {
|
||||||
if (this.state.selectedElementIds[hitElement.id]) {
|
if (this.state.selectedElementIds[hitElement.id]) {
|
||||||
if (isSelectedViaGroup(this.state, hitElement)) {
|
if (isSelectedViaGroup(this.state, hitElement)) {
|
||||||
// We want to unselect all groups hitElement is part of
|
this.setState((_prevState) => {
|
||||||
// as well as all elements that are part of the groups
|
const nextSelectedElementIds = {
|
||||||
// hitElement is part of
|
..._prevState.selectedElementIds,
|
||||||
const idsOfSelectedElementsThatAreInGroups = hitElement.groupIds
|
};
|
||||||
.flatMap((groupId) =>
|
|
||||||
getElementsInGroup(
|
|
||||||
this.scene.getNonDeletedElements(),
|
|
||||||
groupId,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map((element) => ({ [element.id]: false }))
|
|
||||||
.reduce((prevId, acc) => ({ ...prevId, ...acc }), {});
|
|
||||||
|
|
||||||
this.setState((_prevState) => ({
|
// We want to unselect all groups hitElement is part of
|
||||||
selectedGroupIds: {
|
// as well as all elements that are part of the groups
|
||||||
..._prevState.selectedElementIds,
|
// hitElement is part of
|
||||||
...hitElement.groupIds
|
for (const groupedElement of hitElement.groupIds.flatMap(
|
||||||
.map((gId) => ({ [gId]: false }))
|
(groupId) =>
|
||||||
.reduce((prev, acc) => ({ ...prev, ...acc }), {}),
|
getElementsInGroup(
|
||||||
},
|
this.scene.getNonDeletedElements(),
|
||||||
selectedElementIds: {
|
groupId,
|
||||||
..._prevState.selectedElementIds,
|
),
|
||||||
...idsOfSelectedElementsThatAreInGroups,
|
)) {
|
||||||
},
|
delete nextSelectedElementIds[groupedElement.id];
|
||||||
}));
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectedGroupIds: {
|
||||||
|
..._prevState.selectedElementIds,
|
||||||
|
...hitElement.groupIds
|
||||||
|
.map((gId) => ({ [gId]: false }))
|
||||||
|
.reduce((prev, acc) => ({ ...prev, ...acc }), {}),
|
||||||
|
},
|
||||||
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
nextSelectedElementIds,
|
||||||
|
_prevState,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
// if not gragging a linear element point (outside editor)
|
// if not gragging a linear element point (outside editor)
|
||||||
} else if (!this.state.selectedLinearElement?.isDragging) {
|
} else if (!this.state.selectedLinearElement?.isDragging) {
|
||||||
// remove element from selection while
|
// remove element from selection while
|
||||||
@ -6174,8 +6230,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
const newSelectedElementIds = {
|
const newSelectedElementIds = {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
[hitElement!.id]: false,
|
|
||||||
};
|
};
|
||||||
|
delete newSelectedElementIds[hitElement!.id];
|
||||||
const newSelectedElements = getSelectedElements(
|
const newSelectedElements = getSelectedElements(
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
{ ...prevState, selectedElementIds: newSelectedElementIds },
|
{ ...prevState, selectedElementIds: newSelectedElementIds },
|
||||||
@ -6196,6 +6252,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
: prevState.selectedLinearElement,
|
: prevState.selectedLinearElement,
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -6206,21 +6263,23 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
// when hitElement is part of a selected frame, deselect the frame
|
// when hitElement is part of a selected frame, deselect the frame
|
||||||
// to avoid frame and containing elements selected simultaneously
|
// to avoid frame and containing elements selected simultaneously
|
||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
const nextSelectedElementIds = {
|
const nextSelectedElementIds: {
|
||||||
|
[id: string]: true;
|
||||||
|
} = {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
[hitElement.id]: true,
|
[hitElement.id]: true,
|
||||||
// deselect the frame
|
|
||||||
[hitElement.frameId!]: false,
|
|
||||||
};
|
};
|
||||||
|
// deselect the frame
|
||||||
|
delete nextSelectedElementIds[hitElement.frameId!];
|
||||||
|
|
||||||
// deselect groups containing the frame
|
// deselect groups containing the frame
|
||||||
(this.scene.getElement(hitElement.frameId!)?.groupIds ?? [])
|
(this.scene.getElement(hitElement.frameId!)?.groupIds ?? [])
|
||||||
.flatMap((gid) =>
|
.flatMap((gid) =>
|
||||||
getElementsInGroup(this.scene.getNonDeletedElements(), gid),
|
getElementsInGroup(this.scene.getNonDeletedElements(), gid),
|
||||||
)
|
)
|
||||||
.forEach(
|
.forEach((element) => {
|
||||||
(element) => (nextSelectedElementIds[element.id] = false),
|
delete nextSelectedElementIds[element.id];
|
||||||
);
|
});
|
||||||
|
|
||||||
return selectGroupsForSelectedElements(
|
return selectGroupsForSelectedElements(
|
||||||
{
|
{
|
||||||
@ -6229,15 +6288,19 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
showHyperlinkPopup: hitElement.link ? "info" : false,
|
showHyperlinkPopup: hitElement.link ? "info" : false,
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// add element to selection while keeping prev elements selected
|
// add element to selection while keeping prev elements selected
|
||||||
this.setState((_prevState) => ({
|
this.setState((_prevState) => ({
|
||||||
selectedElementIds: {
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
..._prevState.selectedElementIds,
|
{
|
||||||
[hitElement!.id]: true,
|
..._prevState.selectedElementIds,
|
||||||
},
|
[hitElement!.id]: true,
|
||||||
|
},
|
||||||
|
_prevState,
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -6255,6 +6318,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
: prevState.selectedLinearElement,
|
: prevState.selectedLinearElement,
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
prevState,
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -6279,7 +6343,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
} else {
|
} else {
|
||||||
// Deselect selected elements
|
// Deselect selected elements
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
editingGroupId: null,
|
editingGroupId: null,
|
||||||
});
|
});
|
||||||
@ -6290,13 +6354,17 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (
|
if (
|
||||||
!activeTool.locked &&
|
!activeTool.locked &&
|
||||||
activeTool.type !== "freedraw" &&
|
activeTool.type !== "freedraw" &&
|
||||||
draggingElement
|
draggingElement &&
|
||||||
|
draggingElement.type !== "selection"
|
||||||
) {
|
) {
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
selectedElementIds: {
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
...prevState.selectedElementIds,
|
{
|
||||||
[draggingElement.id]: true,
|
...prevState.selectedElementIds,
|
||||||
},
|
[draggingElement.id]: true,
|
||||||
|
},
|
||||||
|
prevState,
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6610,7 +6678,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.initializeImageDimensions(imageElement);
|
this.initializeImageDimensions(imageElement);
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
selectedElementIds: { [imageElement.id]: true },
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
{ [imageElement.id]: true },
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.actionManager.executeAction(actionFinalize);
|
this.actionManager.executeAction(actionFinalize);
|
||||||
@ -6837,7 +6908,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
private clearSelection(hitElement: ExcalidrawElement | null): void {
|
private clearSelection(hitElement: ExcalidrawElement | null): void {
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, prevState),
|
||||||
selectedGroupIds: {},
|
selectedGroupIds: {},
|
||||||
// Continue editing the same group if the user selected a different
|
// Continue editing the same group if the user selected a different
|
||||||
// element from it
|
// element from it
|
||||||
@ -6849,7 +6920,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
: null,
|
: null,
|
||||||
}));
|
}));
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedElementIds: {},
|
selectedElementIds: makeNextSelectedElementIds({}, this.state),
|
||||||
previousSelectedElementIds: this.state.selectedElementIds,
|
previousSelectedElementIds: this.state.selectedElementIds,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -6918,7 +6989,12 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
const imageElement = this.createImageElement({ sceneX, sceneY });
|
const imageElement = this.createImageElement({ sceneX, sceneY });
|
||||||
this.insertImageElement(imageElement, file);
|
this.insertImageElement(imageElement, file);
|
||||||
this.initializeImageDimensions(imageElement);
|
this.initializeImageDimensions(imageElement);
|
||||||
this.setState({ selectedElementIds: { [imageElement.id]: true } });
|
this.setState({
|
||||||
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
{ [imageElement.id]: true },
|
||||||
|
this.state,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -7043,6 +7119,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
: null,
|
: null,
|
||||||
},
|
},
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
|
this.state,
|
||||||
)
|
)
|
||||||
: this.state),
|
: this.state),
|
||||||
showHyperlinkPopup: false,
|
showHyperlinkPopup: false,
|
||||||
|
135
src/excalidraw-app/debug.ts
Normal file
135
src/excalidraw-app/debug.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
debug: typeof Debug;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const lessPrecise = (num: number, precision = 5) =>
|
||||||
|
parseFloat(num.toPrecision(precision));
|
||||||
|
|
||||||
|
const getAvgFrameTime = (times: number[]) =>
|
||||||
|
lessPrecise(times.reduce((a, b) => a + b) / times.length);
|
||||||
|
|
||||||
|
const getFps = (frametime: number) => lessPrecise(1000 / frametime);
|
||||||
|
|
||||||
|
export class Debug {
|
||||||
|
public static DEBUG_LOG_TIMES = true;
|
||||||
|
|
||||||
|
private static TIMES_AGGR: Record<string, { t: number; times: number[] }> =
|
||||||
|
{};
|
||||||
|
private static TIMES_AVG: Record<
|
||||||
|
string,
|
||||||
|
{ t: number; times: number[]; avg: number | null }
|
||||||
|
> = {};
|
||||||
|
private static LAST_DEBUG_LOG_CALL = 0;
|
||||||
|
private static DEBUG_LOG_INTERVAL_ID: null | number = null;
|
||||||
|
|
||||||
|
private static setupInterval = () => {
|
||||||
|
if (Debug.DEBUG_LOG_INTERVAL_ID === null) {
|
||||||
|
console.info("%c(starting perf recording)", "color: lime");
|
||||||
|
Debug.DEBUG_LOG_INTERVAL_ID = window.setInterval(Debug.debugLogger, 1000);
|
||||||
|
}
|
||||||
|
Debug.LAST_DEBUG_LOG_CALL = Date.now();
|
||||||
|
};
|
||||||
|
|
||||||
|
private static debugLogger = () => {
|
||||||
|
if (
|
||||||
|
Date.now() - Debug.LAST_DEBUG_LOG_CALL > 600 &&
|
||||||
|
Debug.DEBUG_LOG_INTERVAL_ID !== null
|
||||||
|
) {
|
||||||
|
window.clearInterval(Debug.DEBUG_LOG_INTERVAL_ID);
|
||||||
|
Debug.DEBUG_LOG_INTERVAL_ID = null;
|
||||||
|
for (const [name, { avg }] of Object.entries(Debug.TIMES_AVG)) {
|
||||||
|
if (avg != null) {
|
||||||
|
console.info(
|
||||||
|
`%c${name} run avg: ${avg}ms (${getFps(avg)} fps)`,
|
||||||
|
"color: blue",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.info("%c(stopping perf recording)", "color: red");
|
||||||
|
Debug.TIMES_AGGR = {};
|
||||||
|
Debug.TIMES_AVG = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Debug.DEBUG_LOG_TIMES) {
|
||||||
|
for (const [name, { t, times }] of Object.entries(Debug.TIMES_AGGR)) {
|
||||||
|
if (times.length) {
|
||||||
|
console.info(
|
||||||
|
name,
|
||||||
|
lessPrecise(times.reduce((a, b) => a + b)),
|
||||||
|
times.sort((a, b) => a - b).map((x) => lessPrecise(x)),
|
||||||
|
);
|
||||||
|
Debug.TIMES_AGGR[name] = { t, times: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const [name, { t, times, avg }] of Object.entries(Debug.TIMES_AVG)) {
|
||||||
|
if (times.length) {
|
||||||
|
const avgFrameTime = getAvgFrameTime(times);
|
||||||
|
console.info(name, `${avgFrameTime}ms (${getFps(avgFrameTime)} fps)`);
|
||||||
|
Debug.TIMES_AVG[name] = {
|
||||||
|
t,
|
||||||
|
times: [],
|
||||||
|
avg:
|
||||||
|
avg != null ? getAvgFrameTime([avg, avgFrameTime]) : avgFrameTime,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static logTime = (time?: number, name = "default") => {
|
||||||
|
Debug.setupInterval();
|
||||||
|
const now = performance.now();
|
||||||
|
const { t, times } = (Debug.TIMES_AGGR[name] = Debug.TIMES_AGGR[name] || {
|
||||||
|
t: 0,
|
||||||
|
times: [],
|
||||||
|
});
|
||||||
|
if (t) {
|
||||||
|
times.push(time != null ? time : now - t);
|
||||||
|
}
|
||||||
|
Debug.TIMES_AGGR[name].t = now;
|
||||||
|
};
|
||||||
|
public static logTimeAverage = (time?: number, name = "default") => {
|
||||||
|
Debug.setupInterval();
|
||||||
|
const now = performance.now();
|
||||||
|
const { t, times } = (Debug.TIMES_AVG[name] = Debug.TIMES_AVG[name] || {
|
||||||
|
t: 0,
|
||||||
|
times: [],
|
||||||
|
});
|
||||||
|
if (t) {
|
||||||
|
times.push(time != null ? time : now - t);
|
||||||
|
}
|
||||||
|
Debug.TIMES_AVG[name].t = now;
|
||||||
|
};
|
||||||
|
|
||||||
|
private static logWrapper =
|
||||||
|
(type: "logTime" | "logTimeAverage") =>
|
||||||
|
<T extends any[], R>(fn: (...args: T) => R, name = "default") => {
|
||||||
|
return (...args: T) => {
|
||||||
|
const t0 = performance.now();
|
||||||
|
const ret = fn(...args);
|
||||||
|
Debug.logTime(performance.now() - t0, name);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
public static logTimeWrap = Debug.logWrapper("logTime");
|
||||||
|
public static logTimeAverageWrap = Debug.logWrapper("logTimeAverage");
|
||||||
|
|
||||||
|
public static perfWrap = <T extends any[], R>(
|
||||||
|
fn: (...args: T) => R,
|
||||||
|
name = "default",
|
||||||
|
) => {
|
||||||
|
return (...args: T) => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.time(name);
|
||||||
|
const ret = fn(...args);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.timeEnd(name);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
window.debug = Debug;
|
@ -2,6 +2,7 @@ import { GroupId, ExcalidrawElement, NonDeleted } from "./element/types";
|
|||||||
import { AppState } from "./types";
|
import { AppState } from "./types";
|
||||||
import { getSelectedElements } from "./scene";
|
import { getSelectedElements } from "./scene";
|
||||||
import { getBoundTextElement } from "./element/textElement";
|
import { getBoundTextElement } from "./element/textElement";
|
||||||
|
import { makeNextSelectedElementIds } from "./scene/selection";
|
||||||
|
|
||||||
export const selectGroup = (
|
export const selectGroup = (
|
||||||
groupId: GroupId,
|
groupId: GroupId,
|
||||||
@ -67,13 +68,21 @@ export const getSelectedGroupIds = (appState: AppState): GroupId[] =>
|
|||||||
export const selectGroupsForSelectedElements = (
|
export const selectGroupsForSelectedElements = (
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
elements: readonly NonDeleted<ExcalidrawElement>[],
|
elements: readonly NonDeleted<ExcalidrawElement>[],
|
||||||
|
prevAppState: AppState,
|
||||||
): AppState => {
|
): AppState => {
|
||||||
let nextAppState: AppState = { ...appState, selectedGroupIds: {} };
|
let nextAppState: AppState = { ...appState, selectedGroupIds: {} };
|
||||||
|
|
||||||
const selectedElements = getSelectedElements(elements, appState);
|
const selectedElements = getSelectedElements(elements, appState);
|
||||||
|
|
||||||
if (!selectedElements.length) {
|
if (!selectedElements.length) {
|
||||||
return { ...nextAppState, editingGroupId: null };
|
return {
|
||||||
|
...nextAppState,
|
||||||
|
editingGroupId: null,
|
||||||
|
selectedElementIds: makeNextSelectedElementIds(
|
||||||
|
nextAppState.selectedElementIds,
|
||||||
|
prevAppState,
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const selectedElement of selectedElements) {
|
for (const selectedElement of selectedElements) {
|
||||||
@ -91,6 +100,11 @@ export const selectGroupsForSelectedElements = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextAppState.selectedElementIds = makeNextSelectedElementIds(
|
||||||
|
nextAppState.selectedElementIds,
|
||||||
|
prevAppState,
|
||||||
|
);
|
||||||
|
|
||||||
return nextAppState;
|
return nextAppState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
35
src/scene/selection.test.ts
Normal file
35
src/scene/selection.test.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { makeNextSelectedElementIds } from "./selection";
|
||||||
|
|
||||||
|
describe("makeNextSelectedElementIds", () => {
|
||||||
|
const _makeNextSelectedElementIds = (
|
||||||
|
selectedElementIds: { [id: string]: true },
|
||||||
|
prevSelectedElementIds: { [id: string]: true },
|
||||||
|
expectUpdated: boolean,
|
||||||
|
) => {
|
||||||
|
const ret = makeNextSelectedElementIds(selectedElementIds, {
|
||||||
|
selectedElementIds: prevSelectedElementIds,
|
||||||
|
});
|
||||||
|
expect(ret === selectedElementIds).toBe(expectUpdated);
|
||||||
|
};
|
||||||
|
it("should return prevState selectedElementIds if no change", () => {
|
||||||
|
_makeNextSelectedElementIds({}, {}, false);
|
||||||
|
_makeNextSelectedElementIds({ 1: true }, { 1: true }, false);
|
||||||
|
_makeNextSelectedElementIds(
|
||||||
|
{ 1: true, 2: true },
|
||||||
|
{ 1: true, 2: true },
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should return new selectedElementIds if changed", () => {
|
||||||
|
// _makeNextSelectedElementIds({ 1: true }, { 1: false }, true);
|
||||||
|
_makeNextSelectedElementIds({ 1: true }, {}, true);
|
||||||
|
_makeNextSelectedElementIds({}, { 1: true }, true);
|
||||||
|
_makeNextSelectedElementIds({ 1: true }, { 2: true }, true);
|
||||||
|
_makeNextSelectedElementIds({ 1: true }, { 1: true, 2: true }, true);
|
||||||
|
_makeNextSelectedElementIds(
|
||||||
|
{ 1: true, 2: true },
|
||||||
|
{ 1: true, 3: true },
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -10,6 +10,7 @@ import {
|
|||||||
getContainingFrame,
|
getContainingFrame,
|
||||||
getFrameElements,
|
getFrameElements,
|
||||||
} from "../frame";
|
} from "../frame";
|
||||||
|
import { isShallowEqual } from "../utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frames and their containing elements are not to be selected at the same time.
|
* Frames and their containing elements are not to be selected at the same time.
|
||||||
@ -88,11 +89,41 @@ export const getElementsWithinSelection = (
|
|||||||
return elementsInSelection;
|
return elementsInSelection;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isSomeElementSelected = (
|
// FIXME move this into the editor instance to keep utility methods stateless
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
export const isSomeElementSelected = (function () {
|
||||||
appState: Pick<AppState, "selectedElementIds">,
|
let lastElements: readonly NonDeletedExcalidrawElement[] | null = null;
|
||||||
): boolean =>
|
let lastSelectedElementIds: AppState["selectedElementIds"] | null = null;
|
||||||
elements.some((element) => appState.selectedElementIds[element.id]);
|
let isSelected: boolean | null = null;
|
||||||
|
|
||||||
|
const ret = (
|
||||||
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
|
appState: Pick<AppState, "selectedElementIds">,
|
||||||
|
): boolean => {
|
||||||
|
if (
|
||||||
|
isSelected != null &&
|
||||||
|
elements === lastElements &&
|
||||||
|
appState.selectedElementIds === lastSelectedElementIds
|
||||||
|
) {
|
||||||
|
return isSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelected = elements.some(
|
||||||
|
(element) => appState.selectedElementIds[element.id],
|
||||||
|
);
|
||||||
|
lastElements = elements;
|
||||||
|
lastSelectedElementIds = appState.selectedElementIds;
|
||||||
|
|
||||||
|
return isSelected;
|
||||||
|
};
|
||||||
|
|
||||||
|
ret.clearCache = () => {
|
||||||
|
lastElements = null;
|
||||||
|
lastSelectedElementIds = null;
|
||||||
|
isSelected = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns common attribute (picked by `getAttribute` callback) of selected
|
* Returns common attribute (picked by `getAttribute` callback) of selected
|
||||||
@ -161,3 +192,18 @@ export const getTargetElements = (
|
|||||||
: getSelectedElements(elements, appState, {
|
: getSelectedElements(elements, appState, {
|
||||||
includeBoundTextElement: true,
|
includeBoundTextElement: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns prevState's selectedElementids if no change from previous, so as to
|
||||||
|
* retain reference identity for memoization
|
||||||
|
*/
|
||||||
|
export const makeNextSelectedElementIds = (
|
||||||
|
nextSelectedElementIds: AppState["selectedElementIds"],
|
||||||
|
prevState: Pick<AppState, "selectedElementIds">,
|
||||||
|
) => {
|
||||||
|
if (isShallowEqual(prevState.selectedElementIds, nextSelectedElementIds)) {
|
||||||
|
return prevState.selectedElementIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextSelectedElementIds;
|
||||||
|
};
|
||||||
|
@ -2179,7 +2179,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
@ -2413,7 +2412,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@ -4171,7 +4169,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -4399,7 +4396,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@ -4479,7 +4475,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -4892,7 +4887,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -4901,8 +4895,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -5469,7 +5461,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -5478,8 +5469,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
@ -5713,8 +5702,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
|
@ -65,9 +65,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id4": true,
|
|
||||||
"id6": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -76,7 +73,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id7": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
@ -443,8 +439,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id5": true,
|
"id5": true,
|
||||||
@ -618,29 +612,20 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id5": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": false,
|
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": false,
|
|
||||||
"id3": true,
|
|
||||||
"id5": true,
|
|
||||||
"id6": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id4": false,
|
"id4": false,
|
||||||
"id5": true,
|
|
||||||
},
|
},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
"selectionElement": null,
|
"selectionElement": null,
|
||||||
@ -1003,7 +988,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
@ -1179,7 +1163,6 @@ Object {
|
|||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id12": true,
|
|
||||||
"id7": true,
|
"id7": true,
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
@ -1448,8 +1431,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
@ -1528,7 +1509,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id5": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -1712,8 +1692,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id7": true,
|
"id7": true,
|
||||||
"id8": true,
|
|
||||||
"id9": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id10": true,
|
"id10": true,
|
||||||
@ -1825,7 +1803,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id11": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -1934,7 +1911,6 @@ Object {
|
|||||||
"editingLinearElement": null,
|
"editingLinearElement": null,
|
||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id12": true,
|
|
||||||
"id7": true,
|
"id7": true,
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -2116,7 +2092,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -2239,7 +2214,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -2347,7 +2321,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -2356,8 +2329,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
@ -2724,8 +2695,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id5": true,
|
"id5": true,
|
||||||
@ -2904,7 +2873,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -3059,7 +3027,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -3394,7 +3361,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -3754,7 +3720,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -4247,7 +4212,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -4370,7 +4334,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -4478,7 +4441,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -4486,8 +4448,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -4610,7 +4570,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -4654,8 +4613,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -4770,7 +4727,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -5069,7 +5025,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -5522,7 +5477,6 @@ Object {
|
|||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -5875,7 +5829,6 @@ Object {
|
|||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -6423,9 +6376,7 @@ Object {
|
|||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id1": true,
|
|
||||||
},
|
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
@ -7157,7 +7108,6 @@ Object {
|
|||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -7166,8 +7116,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -7395,8 +7343,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -7536,9 +7482,7 @@ Object {
|
|||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id7": false,
|
|
||||||
},
|
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
@ -9539,9 +9483,7 @@ Object {
|
|||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
"editingLinearElement": null,
|
||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id7": false,
|
|
||||||
},
|
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
},
|
},
|
||||||
@ -9948,7 +9890,6 @@ Object {
|
|||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -9956,7 +9897,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -10380,7 +10320,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -10389,8 +10328,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -10681,7 +10618,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -10689,7 +10625,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -10801,7 +10736,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -10938,7 +10872,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -10946,8 +10879,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -11059,7 +10990,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -11132,8 +11062,6 @@ Object {
|
|||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -12334,9 +12262,7 @@ Object {
|
|||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id0": false,
|
|
||||||
},
|
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
@ -12435,9 +12361,7 @@ Object {
|
|||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
"editingLinearElement": null,
|
||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id0": false,
|
|
||||||
},
|
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
},
|
},
|
||||||
@ -13439,9 +13363,7 @@ Object {
|
|||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id0": false,
|
|
||||||
},
|
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
@ -13540,9 +13462,7 @@ Object {
|
|||||||
"editingGroupId": null,
|
"editingGroupId": null,
|
||||||
"editingLinearElement": null,
|
"editingLinearElement": null,
|
||||||
"name": "Untitled-201933152653",
|
"name": "Untitled-201933152653",
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id0": false,
|
|
||||||
},
|
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
},
|
},
|
||||||
@ -13864,7 +13784,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -13874,8 +13793,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id5": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
@ -14347,7 +14264,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
@ -14459,8 +14375,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
"id5": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
@ -14727,7 +14641,6 @@ Object {
|
|||||||
"pendingImageElementId": null,
|
"pendingImageElementId": null,
|
||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -14735,7 +14648,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -15029,9 +14941,7 @@ Object {
|
|||||||
"scrollX": -2.916666666666668,
|
"scrollX": -2.916666666666668,
|
||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id0": true,
|
|
||||||
},
|
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
@ -15261,10 +15171,7 @@ Object {
|
|||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
"scrollY": 0,
|
"scrollY": 0,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id0": false,
|
|
||||||
"id1": true,
|
|
||||||
},
|
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
@ -15451,8 +15358,6 @@ Object {
|
|||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -15461,9 +15366,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -15691,9 +15593,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -15832,7 +15731,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -15842,7 +15740,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id5": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -16204,7 +16101,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
@ -16316,7 +16212,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id5": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -16487,7 +16382,6 @@ Object {
|
|||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
|
||||||
},
|
},
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
@ -16728,7 +16622,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id11": true,
|
|
||||||
"id5": true,
|
"id5": true,
|
||||||
"id6": true,
|
"id6": true,
|
||||||
},
|
},
|
||||||
@ -17036,8 +16929,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id4": true,
|
"id4": true,
|
||||||
@ -17356,8 +17247,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id5": true,
|
"id5": true,
|
||||||
"id6": true,
|
"id6": true,
|
||||||
"id7": true,
|
|
||||||
"id8": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id9": true,
|
"id9": true,
|
||||||
@ -18309,7 +18198,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"viewBackgroundColor": "#ffffff",
|
"viewBackgroundColor": "#ffffff",
|
||||||
@ -18418,7 +18306,6 @@ Object {
|
|||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {
|
||||||
"id0": true,
|
"id0": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id4": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id5": true,
|
"id5": true,
|
||||||
@ -18532,7 +18419,6 @@ Object {
|
|||||||
"id0": true,
|
"id0": true,
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id7": true,
|
|
||||||
},
|
},
|
||||||
"selectedGroupIds": Object {
|
"selectedGroupIds": Object {
|
||||||
"id3": true,
|
"id3": true,
|
||||||
@ -18737,7 +18623,6 @@ Object {
|
|||||||
"previousSelectedElementIds": Object {
|
"previousSelectedElementIds": Object {
|
||||||
"id1": true,
|
"id1": true,
|
||||||
"id2": true,
|
"id2": true,
|
||||||
"id3": true,
|
|
||||||
},
|
},
|
||||||
"resizingElement": null,
|
"resizingElement": null,
|
||||||
"scrollX": 0,
|
"scrollX": 0,
|
||||||
@ -19552,9 +19437,7 @@ Object {
|
|||||||
"scrollX": 10,
|
"scrollX": 10,
|
||||||
"scrollY": -10,
|
"scrollY": -10,
|
||||||
"scrolledOutside": false,
|
"scrolledOutside": false,
|
||||||
"selectedElementIds": Object {
|
"selectedElementIds": Object {},
|
||||||
"id0": true,
|
|
||||||
},
|
|
||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": Object {},
|
"selectedGroupIds": Object {},
|
||||||
"selectedLinearElement": null,
|
"selectedLinearElement": null,
|
||||||
|
@ -430,7 +430,10 @@ describe("arrow", () => {
|
|||||||
const expectedAngle = (7 * Math.PI) / 4;
|
const expectedAngle = (7 * Math.PI) / 4;
|
||||||
const line = createLinearElementWithCurveInsideMinMaxPoints("arrow");
|
const line = createLinearElementWithCurveInsideMinMaxPoints("arrow");
|
||||||
h.app.scene.replaceAllElements([line]);
|
h.app.scene.replaceAllElements([line]);
|
||||||
h.app.state.selectedElementIds[line.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[line.id]: true,
|
||||||
|
};
|
||||||
mutateElement(line, {
|
mutateElement(line, {
|
||||||
angle: originalAngle,
|
angle: originalAngle,
|
||||||
});
|
});
|
||||||
@ -446,7 +449,10 @@ describe("arrow", () => {
|
|||||||
const expectedAngle = (7 * Math.PI) / 4;
|
const expectedAngle = (7 * Math.PI) / 4;
|
||||||
const line = createLinearElementWithCurveInsideMinMaxPoints("arrow");
|
const line = createLinearElementWithCurveInsideMinMaxPoints("arrow");
|
||||||
h.app.scene.replaceAllElements([line]);
|
h.app.scene.replaceAllElements([line]);
|
||||||
h.app.state.selectedElementIds[line.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[line.id]: true,
|
||||||
|
};
|
||||||
mutateElement(line, {
|
mutateElement(line, {
|
||||||
angle: originalAngle,
|
angle: originalAngle,
|
||||||
});
|
});
|
||||||
@ -616,7 +622,10 @@ describe("line", () => {
|
|||||||
const expectedAngle = (7 * Math.PI) / 4;
|
const expectedAngle = (7 * Math.PI) / 4;
|
||||||
const line = createLinearElementWithCurveInsideMinMaxPoints("line");
|
const line = createLinearElementWithCurveInsideMinMaxPoints("line");
|
||||||
h.app.scene.replaceAllElements([line]);
|
h.app.scene.replaceAllElements([line]);
|
||||||
h.app.state.selectedElementIds[line.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[line.id]: true,
|
||||||
|
};
|
||||||
mutateElement(line, {
|
mutateElement(line, {
|
||||||
angle: originalAngle,
|
angle: originalAngle,
|
||||||
});
|
});
|
||||||
@ -632,7 +641,10 @@ describe("line", () => {
|
|||||||
const expectedAngle = (7 * Math.PI) / 4;
|
const expectedAngle = (7 * Math.PI) / 4;
|
||||||
const line = createLinearElementWithCurveInsideMinMaxPoints("line");
|
const line = createLinearElementWithCurveInsideMinMaxPoints("line");
|
||||||
h.app.scene.replaceAllElements([line]);
|
h.app.scene.replaceAllElements([line]);
|
||||||
h.app.state.selectedElementIds[line.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[line.id]: true,
|
||||||
|
};
|
||||||
mutateElement(line, {
|
mutateElement(line, {
|
||||||
angle: originalAngle,
|
angle: originalAngle,
|
||||||
});
|
});
|
||||||
@ -659,14 +671,20 @@ describe("freedraw", () => {
|
|||||||
it("flips an unrotated drawing horizontally correctly", async () => {
|
it("flips an unrotated drawing horizontally correctly", async () => {
|
||||||
const draw = createAndReturnOneDraw();
|
const draw = createAndReturnOneDraw();
|
||||||
// select draw, since not done automatically
|
// select draw, since not done automatically
|
||||||
h.state.selectedElementIds[draw.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[draw.id]: true,
|
||||||
|
};
|
||||||
await checkHorizontalFlip();
|
await checkHorizontalFlip();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("flips an unrotated drawing vertically correctly", async () => {
|
it("flips an unrotated drawing vertically correctly", async () => {
|
||||||
const draw = createAndReturnOneDraw();
|
const draw = createAndReturnOneDraw();
|
||||||
// select draw, since not done automatically
|
// select draw, since not done automatically
|
||||||
h.state.selectedElementIds[draw.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[draw.id]: true,
|
||||||
|
};
|
||||||
await checkVerticalFlip();
|
await checkVerticalFlip();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -676,7 +694,10 @@ describe("freedraw", () => {
|
|||||||
|
|
||||||
const draw = createAndReturnOneDraw(originalAngle);
|
const draw = createAndReturnOneDraw(originalAngle);
|
||||||
// select draw, since not done automatically
|
// select draw, since not done automatically
|
||||||
h.state.selectedElementIds[draw.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[draw.id]: true,
|
||||||
|
};
|
||||||
|
|
||||||
await checkRotatedHorizontalFlip(expectedAngle);
|
await checkRotatedHorizontalFlip(expectedAngle);
|
||||||
});
|
});
|
||||||
@ -687,7 +708,10 @@ describe("freedraw", () => {
|
|||||||
|
|
||||||
const draw = createAndReturnOneDraw(originalAngle);
|
const draw = createAndReturnOneDraw(originalAngle);
|
||||||
// select draw, since not done automatically
|
// select draw, since not done automatically
|
||||||
h.state.selectedElementIds[draw.id] = true;
|
h.state.selectedElementIds = {
|
||||||
|
...h.state.selectedElementIds,
|
||||||
|
[draw.id]: true,
|
||||||
|
};
|
||||||
|
|
||||||
await checkRotatedVerticalFlip(expectedAngle);
|
await checkRotatedVerticalFlip(expectedAngle);
|
||||||
});
|
});
|
||||||
|
@ -89,6 +89,7 @@ const populateElements = (
|
|||||||
...selectGroupsForSelectedElements(
|
...selectGroupsForSelectedElements(
|
||||||
{ ...h.state, ...appState, selectedElementIds },
|
{ ...h.state, ...appState, selectedElementIds },
|
||||||
h.elements,
|
h.elements,
|
||||||
|
h.state,
|
||||||
),
|
),
|
||||||
...appState,
|
...appState,
|
||||||
selectedElementIds,
|
selectedElementIds,
|
||||||
|
@ -181,8 +181,8 @@ export type AppState = {
|
|||||||
defaultSidebarDockedPreference: boolean;
|
defaultSidebarDockedPreference: boolean;
|
||||||
|
|
||||||
lastPointerDownWith: PointerType;
|
lastPointerDownWith: PointerType;
|
||||||
selectedElementIds: { [id: string]: boolean };
|
selectedElementIds: Readonly<{ [id: string]: true }>;
|
||||||
previousSelectedElementIds: { [id: string]: boolean };
|
previousSelectedElementIds: { [id: string]: true };
|
||||||
selectedElementsAreBeingDragged: boolean;
|
selectedElementsAreBeingDragged: boolean;
|
||||||
shouldCacheIgnoreZoom: boolean;
|
shouldCacheIgnoreZoom: boolean;
|
||||||
toast: { message: string; closable?: boolean; duration?: number } | null;
|
toast: { message: string; closable?: boolean; duration?: number } | null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user