1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- import { ExcalidrawElement } from "./element/types";
- import { newElementWith } from "./element/mutateElement";
- import { getCommonBounds } from "./element";
- interface Box {
- minX: number;
- minY: number;
- maxX: number;
- maxY: number;
- }
- export interface Alignment {
- position: "start" | "center" | "end";
- axis: "x" | "y";
- }
- export const alignElements = (
- selectedElements: ExcalidrawElement[],
- alignment: Alignment,
- ): ExcalidrawElement[] => {
- const groups: ExcalidrawElement[][] = getMaximumGroups(selectedElements);
- const selectionBoundingBox = getCommonBoundingBox(selectedElements);
- return groups.flatMap((group) => {
- const translation = calculateTranslation(
- group,
- selectionBoundingBox,
- alignment,
- );
- return group.map((element) =>
- newElementWith(element, {
- x: element.x + translation.x,
- y: element.y + translation.y,
- }),
- );
- });
- };
- export const getMaximumGroups = (
- elements: ExcalidrawElement[],
- ): ExcalidrawElement[][] => {
- const groups: Map<String, ExcalidrawElement[]> = new Map<
- String,
- ExcalidrawElement[]
- >();
- elements.forEach((element: ExcalidrawElement) => {
- const groupId =
- element.groupIds.length === 0
- ? element.id
- : element.groupIds[element.groupIds.length - 1];
- const currentGroupMembers = groups.get(groupId) || [];
- groups.set(groupId, [...currentGroupMembers, element]);
- });
- return Array.from(groups.values());
- };
- const calculateTranslation = (
- group: ExcalidrawElement[],
- selectionBoundingBox: Box,
- { axis, position }: Alignment,
- ): { x: number; y: number } => {
- const groupBoundingBox = getCommonBoundingBox(group);
- const [min, max]: ["minX" | "minY", "maxX" | "maxY"] =
- axis === "x" ? ["minX", "maxX"] : ["minY", "maxY"];
- const noTranslation = { x: 0, y: 0 };
- if (position === "start") {
- return {
- ...noTranslation,
- [axis]: selectionBoundingBox[min] - groupBoundingBox[min],
- };
- } else if (position === "end") {
- return {
- ...noTranslation,
- [axis]: selectionBoundingBox[max] - groupBoundingBox[max],
- };
- } // else if (position === "center") {
- return {
- ...noTranslation,
- [axis]:
- (selectionBoundingBox[min] + selectionBoundingBox[max]) / 2 -
- (groupBoundingBox[min] + groupBoundingBox[max]) / 2,
- };
- };
- const getCommonBoundingBox = (elements: ExcalidrawElement[]): Box => {
- const [minX, minY, maxX, maxY] = getCommonBounds(elements);
- return { minX, minY, maxX, maxY };
- };
|