mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: support adding multiple library items on canvas (#5116)
This commit is contained in:
parent
cad6097d60
commit
d2cc76e52e
11 changed files with 275 additions and 34 deletions
90
src/distribute.ts
Normal file
90
src/distribute.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { ExcalidrawElement } from "./element/types";
|
||||
import { newElementWith } from "./element/mutateElement";
|
||||
import { getMaximumGroups } from "./groups";
|
||||
import { getCommonBoundingBox } from "./element/bounds";
|
||||
|
||||
export interface Distribution {
|
||||
space: "between";
|
||||
axis: "x" | "y";
|
||||
}
|
||||
|
||||
export const distributeElements = (
|
||||
selectedElements: ExcalidrawElement[],
|
||||
distribution: Distribution,
|
||||
): ExcalidrawElement[] => {
|
||||
const [start, mid, end, extent] =
|
||||
distribution.axis === "x"
|
||||
? (["minX", "midX", "maxX", "width"] as const)
|
||||
: (["minY", "midY", "maxY", "height"] as const);
|
||||
|
||||
const bounds = getCommonBoundingBox(selectedElements);
|
||||
const groups = getMaximumGroups(selectedElements)
|
||||
.map((group) => [group, getCommonBoundingBox(group)] as const)
|
||||
.sort((a, b) => a[1][mid] - b[1][mid]);
|
||||
|
||||
let span = 0;
|
||||
for (const group of groups) {
|
||||
span += group[1][extent];
|
||||
}
|
||||
|
||||
const step = (bounds[extent] - span) / (groups.length - 1);
|
||||
|
||||
if (step < 0) {
|
||||
// If we have a negative step, we'll need to distribute from centers
|
||||
// rather than from gaps. Buckle up, this is a weird one.
|
||||
|
||||
// Get indices of boxes that define start and end of our bounding box
|
||||
const index0 = groups.findIndex((g) => g[1][start] === bounds[start]);
|
||||
const index1 = groups.findIndex((g) => g[1][end] === bounds[end]);
|
||||
|
||||
// Get our step, based on the distance between the center points of our
|
||||
// start and end boxes
|
||||
const step =
|
||||
(groups[index1][1][mid] - groups[index0][1][mid]) / (groups.length - 1);
|
||||
|
||||
let pos = groups[index0][1][mid];
|
||||
|
||||
return groups.flatMap(([group, box], index) => {
|
||||
const translation = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
|
||||
// Don't move our start and end boxes
|
||||
if (index !== index0 && index !== index1) {
|
||||
pos += step;
|
||||
translation[distribution.axis] = pos - box[mid];
|
||||
}
|
||||
|
||||
return group.map((element) =>
|
||||
newElementWith(element, {
|
||||
x: element.x + translation.x,
|
||||
y: element.y + translation.y,
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Distribute from gaps
|
||||
|
||||
let pos = bounds[start];
|
||||
|
||||
return groups.flatMap(([group, box]) => {
|
||||
const translation = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
|
||||
translation[distribution.axis] = pos - box[start];
|
||||
|
||||
pos += step;
|
||||
pos += box[extent];
|
||||
|
||||
return group.map((element) =>
|
||||
newElementWith(element, {
|
||||
x: element.x + translation.x,
|
||||
y: element.y + translation.y,
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue