Refactor ExcalidrawElement (#874)

* Get rid of isSelected, canvas, canvasZoom, canvasOffsetX and canvasOffsetY on ExcalidrawElement.

* Fix most unit tests. Fix cmd a. Fix alt drag

* Focus on paste

* shift select should include previously selected items

* Fix last test

* Move this.shape out of ExcalidrawElement and into a WeakMap
This commit is contained in:
Pete Hunt 2020-03-08 10:20:55 -07:00 committed by GitHub
parent 8ecb4201db
commit ccbbdb75a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 416 additions and 306 deletions

View file

@ -1,6 +1,7 @@
import { ExcalidrawElement } from "../element/types";
import { getElementAbsoluteCoords, hitTest } from "../element";
import { AppState } from "../types";
export const hasBackground = (type: string) =>
type === "rectangle" || type === "ellipse" || type === "diamond";
@ -16,6 +17,7 @@ export const hasText = (type: string) => type === "text";
export function getElementAtPosition(
elements: readonly ExcalidrawElement[],
appState: AppState,
x: number,
y: number,
zoom: number,
@ -23,7 +25,7 @@ export function getElementAtPosition(
let hitElement = null;
// We need to to hit testing from front (end of the array) to back (beginning of the array)
for (let i = elements.length - 1; i >= 0; --i) {
if (hitTest(elements[i], x, y, zoom)) {
if (hitTest(elements[i], appState, x, y, zoom)) {
hitElement = elements[i];
break;
}

View file

@ -4,9 +4,11 @@ import { getCommonBounds } from "../element/bounds";
import { renderScene, renderSceneToSvg } from "../renderer/renderScene";
import { distance, SVG_NS } from "../utils";
import { normalizeScroll } from "./scroll";
import { AppState } from "../types";
export function exportToCanvas(
elements: readonly ExcalidrawElement[],
appState: AppState,
{
exportBackground,
exportPadding = 10,
@ -38,6 +40,7 @@ export function exportToCanvas(
renderScene(
elements,
appState,
null,
rough.canvas(tempCanvas),
tempCanvas,

View file

@ -1,6 +1,5 @@
export { isOverScrollBars } from "./scrollbars";
export {
clearSelection,
getSelectedIndices,
deleteSelectedElements,
isSomeElementSelected,

View file

@ -1,5 +1,6 @@
import { ExcalidrawElement } from "../element/types";
import { getElementAbsoluteCoords } from "../element";
import { AppState } from "../types";
export function getElementsWithinSelection(
elements: readonly ExcalidrawElement[],
@ -29,26 +30,20 @@ export function getElementsWithinSelection(
});
}
export function clearSelection(elements: readonly ExcalidrawElement[]) {
let someWasSelected = false;
elements.forEach(element => {
if (element.isSelected) {
someWasSelected = true;
element.isSelected = false;
}
});
return someWasSelected ? elements.slice() : elements;
export function deleteSelectedElements(
elements: readonly ExcalidrawElement[],
appState: AppState,
) {
return elements.filter(el => !appState.selectedElementIds[el.id]);
}
export function deleteSelectedElements(elements: readonly ExcalidrawElement[]) {
return elements.filter(el => !el.isSelected);
}
export function getSelectedIndices(elements: readonly ExcalidrawElement[]) {
export function getSelectedIndices(
elements: readonly ExcalidrawElement[],
appState: AppState,
) {
const selectedIndices: number[] = [];
elements.forEach((element, index) => {
if (element.isSelected) {
if (appState.selectedElementIds[element.id]) {
selectedIndices.push(index);
}
});
@ -57,8 +52,9 @@ export function getSelectedIndices(elements: readonly ExcalidrawElement[]) {
export function isSomeElementSelected(
elements: readonly ExcalidrawElement[],
appState: AppState,
): boolean {
return elements.some(element => element.isSelected);
return elements.some(element => appState.selectedElementIds[element.id]);
}
/**
@ -67,11 +63,14 @@ export function isSomeElementSelected(
*/
export function getCommonAttributeOfSelectedElements<T>(
elements: readonly ExcalidrawElement[],
appState: AppState,
getAttribute: (element: ExcalidrawElement) => T,
): T | null {
const attributes = Array.from(
new Set(
getSelectedElements(elements).map(element => getAttribute(element)),
getSelectedElements(elements, appState).map(element =>
getAttribute(element),
),
),
);
return attributes.length === 1 ? attributes[0] : null;
@ -79,13 +78,16 @@ export function getCommonAttributeOfSelectedElements<T>(
export function getSelectedElements(
elements: readonly ExcalidrawElement[],
appState: AppState,
): readonly ExcalidrawElement[] {
return elements.filter(element => element.isSelected);
return elements.filter(element => appState.selectedElementIds[element.id]);
}
export function getTargetElement(
editingElement: ExcalidrawElement | null,
elements: readonly ExcalidrawElement[],
appState: AppState,
) {
return editingElement ? [editingElement] : getSelectedElements(elements);
return appState.editingElement
? [appState.editingElement]
: getSelectedElements(elements, appState);
}