mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Merge branch 'master' into mrazator/separate-element-into-standalone-package
This commit is contained in:
commit
ffa8da2aa7
6 changed files with 149 additions and 117 deletions
|
@ -491,20 +491,8 @@ export const bindLinearElement = (
|
|||
return;
|
||||
}
|
||||
|
||||
const binding: PointBinding | FixedPointBinding = {
|
||||
let binding: PointBinding | FixedPointBinding = {
|
||||
elementId: hoveredElement.id,
|
||||
...(isElbowArrow(linearElement)
|
||||
? {
|
||||
...calculateFixedPointForElbowArrowBinding(
|
||||
linearElement,
|
||||
hoveredElement,
|
||||
startOrEnd,
|
||||
elementsMap,
|
||||
),
|
||||
focus: 0,
|
||||
gap: 0,
|
||||
}
|
||||
: {
|
||||
...normalizePointBinding(
|
||||
calculateFocusAndGap(
|
||||
linearElement,
|
||||
|
@ -514,9 +502,20 @@ export const bindLinearElement = (
|
|||
),
|
||||
hoveredElement,
|
||||
),
|
||||
}),
|
||||
};
|
||||
|
||||
if (isElbowArrow(linearElement)) {
|
||||
binding = {
|
||||
...binding,
|
||||
...calculateFixedPointForElbowArrowBinding(
|
||||
linearElement,
|
||||
hoveredElement,
|
||||
startOrEnd,
|
||||
elementsMap,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
mutateElement(linearElement, {
|
||||
[startOrEnd === "start" ? "startBinding" : "endBinding"]: binding,
|
||||
});
|
||||
|
@ -1276,13 +1275,16 @@ const updateBoundPoint = (
|
|||
pointDistance(adjacentPoint, edgePointAbsolute) +
|
||||
pointDistance(adjacentPoint, center) +
|
||||
Math.max(bindableElement.width, bindableElement.height) * 2;
|
||||
const intersections = intersectElementWithLineSegment(
|
||||
const intersections = [
|
||||
...intersectElementWithLineSegment(
|
||||
bindableElement,
|
||||
lineSegment<GlobalPoint>(
|
||||
adjacentPoint,
|
||||
pointFromVector(
|
||||
vectorScale(
|
||||
vectorNormalize(vectorFromPoint(focusPointAbsolute, adjacentPoint)),
|
||||
vectorNormalize(
|
||||
vectorFromPoint(focusPointAbsolute, adjacentPoint),
|
||||
),
|
||||
interceptorLength,
|
||||
),
|
||||
adjacentPoint,
|
||||
|
@ -1292,23 +1294,16 @@ const updateBoundPoint = (
|
|||
).sort(
|
||||
(g, h) =>
|
||||
pointDistanceSq(g, adjacentPoint) - pointDistanceSq(h, adjacentPoint),
|
||||
);
|
||||
|
||||
// debugClear();
|
||||
// debugDrawPoint(intersections[0], { color: "red", permanent: true });
|
||||
// debugDrawLine(
|
||||
// lineSegment<GlobalPoint>(
|
||||
// adjacentPoint,
|
||||
// pointFromVector(
|
||||
// vectorScale(
|
||||
// vectorNormalize(vectorFromPoint(focusPointAbsolute, adjacentPoint)),
|
||||
// interceptorLength,
|
||||
// ),
|
||||
// adjacentPoint,
|
||||
// ),
|
||||
// ),
|
||||
// { permanent: true, color: "green" },
|
||||
// );
|
||||
),
|
||||
// Fallback when arrow doesn't point to the shape
|
||||
pointFromVector(
|
||||
vectorScale(
|
||||
vectorNormalize(vectorFromPoint(focusPointAbsolute, adjacentPoint)),
|
||||
pointDistance(adjacentPoint, edgePointAbsolute),
|
||||
),
|
||||
adjacentPoint,
|
||||
),
|
||||
];
|
||||
|
||||
if (intersections.length > 1) {
|
||||
// The adjacent point is outside the shape (+ gap)
|
||||
|
@ -1731,21 +1726,6 @@ const determineFocusDistance = (
|
|||
)
|
||||
.sort((g, h) => Math.abs(g) - Math.abs(h));
|
||||
|
||||
// debugClear();
|
||||
// [
|
||||
// lineSegmentIntersectionPoints(rotatedInterceptor, interceptees[0]),
|
||||
// lineSegmentIntersectionPoints(rotatedInterceptor, interceptees[1]),
|
||||
// ]
|
||||
// .filter((p): p is GlobalPoint => p !== null)
|
||||
// .forEach((p) => debugDrawPoint(p, { color: "black", permanent: true }));
|
||||
// debugDrawPoint(determineFocusPoint(element, ordered[0] ?? 0, rotatedA), {
|
||||
// color: "red",
|
||||
// permanent: true,
|
||||
// });
|
||||
// debugDrawLine(rotatedInterceptor, { color: "green", permanent: true });
|
||||
// debugDrawLine(interceptees[0], { color: "red", permanent: true });
|
||||
// debugDrawLine(interceptees[1], { color: "red", permanent: true });
|
||||
|
||||
const signedDistanceRatio = ordered[0] ?? 0;
|
||||
|
||||
return signedDistanceRatio;
|
||||
|
|
|
@ -13,6 +13,8 @@ import type {
|
|||
|
||||
import type Scene from "@excalidraw/excalidraw/scene/Scene";
|
||||
|
||||
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
||||
|
||||
import { updateBoundElements } from "./binding";
|
||||
import { getCommonBounds } from "./bounds";
|
||||
import { mutateElement } from "./mutateElement";
|
||||
|
@ -28,7 +30,7 @@ import {
|
|||
} from "./typeChecks";
|
||||
|
||||
import type { Bounds } from "./bounds";
|
||||
import type { NonDeletedExcalidrawElement } from "./types";
|
||||
import type { ExcalidrawElement } from "./types";
|
||||
|
||||
export const dragSelectedElements = (
|
||||
pointerDownState: PointerDownState,
|
||||
|
@ -82,13 +84,20 @@ export const dragSelectedElements = (
|
|||
}
|
||||
}
|
||||
|
||||
const commonBounds = getCommonBounds(
|
||||
Array.from(elementsToUpdate).map(
|
||||
(el) => pointerDownState.originalElements.get(el.id) ?? el,
|
||||
),
|
||||
);
|
||||
const origElements: ExcalidrawElement[] = [];
|
||||
|
||||
for (const element of elementsToUpdate) {
|
||||
const origElement = pointerDownState.originalElements.get(element.id);
|
||||
// if original element is not set (e.g. when you duplicate during a drag
|
||||
// operation), exit to avoid undefined behavior
|
||||
if (!origElement) {
|
||||
return;
|
||||
}
|
||||
origElements.push(origElement);
|
||||
}
|
||||
|
||||
const adjustedOffset = calculateOffset(
|
||||
commonBounds,
|
||||
getCommonBounds(origElements),
|
||||
offset,
|
||||
snapOffset,
|
||||
gridSize,
|
||||
|
|
|
@ -1004,23 +1004,32 @@ export const updateElbowArrowPoints = (
|
|||
// 0. During all element replacement in the scene, we just need to renormalize
|
||||
// the arrow
|
||||
// TODO (dwelle,mtolmacs): Remove this once Scene.getScene() is removed
|
||||
const {
|
||||
startBinding: updatedStartBinding,
|
||||
endBinding: updatedEndBinding,
|
||||
...restOfTheUpdates
|
||||
} = updates;
|
||||
const startBinding =
|
||||
typeof updates.startBinding !== "undefined"
|
||||
? updates.startBinding
|
||||
typeof updatedStartBinding !== "undefined"
|
||||
? updatedStartBinding
|
||||
: arrow.startBinding;
|
||||
const endBinding =
|
||||
typeof updates.endBinding !== "undefined"
|
||||
? updates.endBinding
|
||||
typeof updatedEndBinding !== "undefined"
|
||||
? updatedEndBinding
|
||||
: arrow.endBinding;
|
||||
const startElement =
|
||||
startBinding &&
|
||||
getBindableElementForId(startBinding.elementId, elementsMap);
|
||||
const endElement =
|
||||
endBinding && getBindableElementForId(endBinding.elementId, elementsMap);
|
||||
|
||||
if (
|
||||
(startBinding && !startElement) ||
|
||||
(endBinding && !endElement) ||
|
||||
(elementsMap.size === 0 && validateElbowPoints(updatedPoints)) ||
|
||||
startElement?.id !== startBinding?.elementId ||
|
||||
endElement?.id !== endBinding?.elementId
|
||||
(Object.keys(restOfTheUpdates).length === 0 &&
|
||||
(startElement?.id !== startBinding?.elementId ||
|
||||
endElement?.id !== endBinding?.elementId))
|
||||
) {
|
||||
return normalizeArrowElementUpdate(
|
||||
updatedPoints.map((p) =>
|
||||
|
@ -1080,7 +1089,8 @@ export const updateElbowArrowPoints = (
|
|||
p,
|
||||
arrow.points[i] ?? pointFrom<LocalPoint>(Infinity, Infinity),
|
||||
),
|
||||
)
|
||||
) &&
|
||||
validateElbowPoints(updatedPoints)
|
||||
) {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -67,6 +67,10 @@ export const actionDuplicateSelection = register({
|
|||
icon: DuplicateIcon,
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState, formData, app) => {
|
||||
if (appState.selectedElementsAreBeingDragged) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// duplicate selected point(s) if editing a line
|
||||
if (appState.editingLinearElement) {
|
||||
// TODO: Invariants should be checked here instead of duplicateSelectedPoints()
|
||||
|
|
|
@ -55,6 +55,8 @@ import {
|
|||
|
||||
import { hasStrokeColor } from "@excalidraw/element/comparisons";
|
||||
|
||||
import { updateElbowArrowPoints } from "@excalidraw/element/elbowArrow";
|
||||
|
||||
import type { LocalPoint } from "@excalidraw/math";
|
||||
|
||||
import type {
|
||||
|
@ -1582,7 +1584,7 @@ export const actionChangeArrowType = register({
|
|||
if (!isArrowElement(el)) {
|
||||
return el;
|
||||
}
|
||||
const newElement = newElementWith(el, {
|
||||
let newElement = newElementWith(el, {
|
||||
roundness:
|
||||
value === ARROW_TYPE.round
|
||||
? {
|
||||
|
@ -1597,6 +1599,8 @@ export const actionChangeArrowType = register({
|
|||
});
|
||||
|
||||
if (isElbowArrow(newElement)) {
|
||||
newElement.fixedSegments = null;
|
||||
|
||||
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||
|
||||
app.dismissLinearEditor();
|
||||
|
@ -1671,14 +1675,9 @@ export const actionChangeArrowType = register({
|
|||
endHoveredElement &&
|
||||
bindLinearElement(newElement, endHoveredElement, "end", elementsMap);
|
||||
|
||||
mutateElement(newElement, {
|
||||
points: [finalStartPoint, finalEndPoint].map(
|
||||
(p): LocalPoint =>
|
||||
pointFrom(p[0] - newElement.x, p[1] - newElement.y),
|
||||
),
|
||||
...(startElement && newElement.startBinding
|
||||
const startBinding =
|
||||
startElement && newElement.startBinding
|
||||
? {
|
||||
startBinding: {
|
||||
// @ts-ignore TS cannot discern check above
|
||||
...newElement.startBinding!,
|
||||
...calculateFixedPointForElbowArrowBinding(
|
||||
|
@ -1687,12 +1686,11 @@ export const actionChangeArrowType = register({
|
|||
"start",
|
||||
elementsMap,
|
||||
),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(endElement && newElement.endBinding
|
||||
: null;
|
||||
const endBinding =
|
||||
endElement && newElement.endBinding
|
||||
? {
|
||||
endBinding: {
|
||||
// @ts-ignore TS cannot discern check above
|
||||
...newElement.endBinding,
|
||||
...calculateFixedPointForElbowArrowBinding(
|
||||
|
@ -1701,16 +1699,47 @@ export const actionChangeArrowType = register({
|
|||
"end",
|
||||
elementsMap,
|
||||
),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
: null;
|
||||
|
||||
newElement = {
|
||||
...newElement,
|
||||
startBinding,
|
||||
endBinding,
|
||||
...updateElbowArrowPoints(newElement, elementsMap, {
|
||||
points: [finalStartPoint, finalEndPoint].map(
|
||||
(p): LocalPoint =>
|
||||
pointFrom(p[0] - newElement.x, p[1] - newElement.y),
|
||||
),
|
||||
startBinding,
|
||||
endBinding,
|
||||
fixedSegments: null,
|
||||
}),
|
||||
};
|
||||
|
||||
LinearElementEditor.updateEditorMidPointsCache(
|
||||
newElement,
|
||||
elementsMap,
|
||||
app.state,
|
||||
);
|
||||
} else {
|
||||
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||
if (newElement.startBinding) {
|
||||
const startElement = elementsMap.get(
|
||||
newElement.startBinding.elementId,
|
||||
) as ExcalidrawBindableElement;
|
||||
if (startElement) {
|
||||
bindLinearElement(newElement, startElement, "start", elementsMap);
|
||||
}
|
||||
}
|
||||
if (newElement.endBinding) {
|
||||
const endElement = elementsMap.get(
|
||||
newElement.endBinding.elementId,
|
||||
) as ExcalidrawBindableElement;
|
||||
if (endElement) {
|
||||
bindLinearElement(newElement, endElement, "end", elementsMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newElement;
|
||||
|
|
|
@ -818,8 +818,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
|||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 30,
|
||||
"width": 50,
|
||||
"x": 200,
|
||||
"width": 0,
|
||||
"x": "149.29289",
|
||||
"y": 0,
|
||||
}
|
||||
`;
|
||||
|
@ -852,7 +852,7 @@ History {
|
|||
0,
|
||||
],
|
||||
[
|
||||
50,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
|
@ -937,7 +937,7 @@ History {
|
|||
0,
|
||||
],
|
||||
[
|
||||
50,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue