excalidraw/src/scene/selection.ts

65 lines
1.9 KiB
TypeScript

import {
ExcalidrawElement,
NonDeletedExcalidrawElement,
} from "../element/types";
import { getElementAbsoluteCoords, getElementBounds } from "../element";
import { AppState } from "../types";
export const getElementsWithinSelection = (
elements: readonly NonDeletedExcalidrawElement[],
selection: NonDeletedExcalidrawElement,
) => {
const [selectionX1, selectionY1, selectionX2, selectionY2] =
getElementAbsoluteCoords(selection);
return elements.filter((element) => {
const [elementX1, elementY1, elementX2, elementY2] =
getElementBounds(element);
return (
element.type !== "selection" &&
selectionX1 <= elementX1 &&
selectionY1 <= elementY1 &&
selectionX2 >= elementX2 &&
selectionY2 >= elementY2
);
});
};
export const isSomeElementSelected = (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
): boolean =>
elements.some((element) => appState.selectedElementIds[element.id]);
/**
* Returns common attribute (picked by `getAttribute` callback) of selected
* elements. If elements don't share the same value, returns `null`.
*/
export const getCommonAttributeOfSelectedElements = <T>(
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
getAttribute: (element: ExcalidrawElement) => T,
): T | null => {
const attributes = Array.from(
new Set(
getSelectedElements(elements, appState).map((element) =>
getAttribute(element),
),
),
);
return attributes.length === 1 ? attributes[0] : null;
};
export const getSelectedElements = (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
) => elements.filter((element) => appState.selectedElementIds[element.id]);
export const getTargetElements = (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
) =>
appState.editingElement
? [appState.editingElement]
: getSelectedElements(elements, appState);