Skip to content

Commit

Permalink
Merge pull request #230 from excalidraw/master
Browse files Browse the repository at this point in the history
merge upstream
  • Loading branch information
zsviczian authored Jul 1, 2024
2 parents 4053873 + 1d5b41d commit 7467358
Show file tree
Hide file tree
Showing 20 changed files with 643 additions and 332 deletions.
7 changes: 6 additions & 1 deletion packages/excalidraw/actions/actionFinalize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ export const actionFinalize = register({
-1,
arrayToMap(elements),
);
maybeBindLinearElement(multiPointElement, appState, { x, y }, app);
maybeBindLinearElement(
multiPointElement,
appState,
{ x, y },
elementsMap,
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/excalidraw/actions/actionFlip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const flipElements = (

bindOrUnbindLinearElements(
selectedElements.filter(isLinearElement),
app,
elementsMap,
isBindingEnabled(appState),
[],
);
Expand Down
142 changes: 51 additions & 91 deletions packages/excalidraw/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,9 @@ import type {
ScrollBars,
} from "../scene/types";
import { getStateForZoom } from "../scene/zoom";
import { findShapeByKey } from "../shapes";
import { findShapeByKey, getElementShape } from "../shapes";
import type { GeometricShape } from "../../utils/geometry/shape";
import {
getClosedCurveShape,
getCurveShape,
getEllipseShape,
getFreedrawShape,
getPolygonShape,
getSelectionBoxShape,
} from "../../utils/geometry/shape";
import { getSelectionBoxShape } from "../../utils/geometry/shape";
import { isPointInShape } from "../../utils/collision";
import type {
AppClassProperties,
Expand Down Expand Up @@ -436,7 +429,6 @@ import {
hitElementBoundText,
hitElementBoundingBoxOnly,
hitElementItself,
shouldTestInside,
} from "../element/collision";
import { textWysiwyg } from "../element/textWysiwyg";
import { isOverScrollBars } from "../scene/scrollbars";
Expand Down Expand Up @@ -2942,7 +2934,7 @@ class App extends React.Component<AppProps, AppState> {
nonDeletedElementsMap,
),
),
this,
this.scene.getNonDeletedElementsMap(),
);
}

Expand Down Expand Up @@ -4321,7 +4313,7 @@ class App extends React.Component<AppProps, AppState> {
this.setState({
suggestedBindings: getSuggestedBindingsForArrows(
selectedElements,
this,
this.scene.getNonDeletedElementsMap(),
),
});

Expand Down Expand Up @@ -4487,7 +4479,7 @@ class App extends React.Component<AppProps, AppState> {
if (isArrowKey(event.key)) {
bindOrUnbindLinearElements(
this.scene.getSelectedElements(this.state).filter(isLinearElement),
this,
this.scene.getNonDeletedElementsMap(),
isBindingEnabled(this.state),
this.state.selectedLinearElement?.selectedPointsIndices ?? [],
);
Expand Down Expand Up @@ -4866,59 +4858,6 @@ class App extends React.Component<AppProps, AppState> {
return null;
}

/**
* get the pure geometric shape of an excalidraw element
* which is then used for hit detection
*/
public getElementShape(element: ExcalidrawElement): GeometricShape {
switch (element.type) {
case "rectangle":
case "diamond":
case "frame":
case "magicframe":
case "embeddable":
case "image":
case "iframe":
case "text":
case "selection":
return getPolygonShape(element);
case "arrow":
case "line": {
const roughShape =
ShapeCache.get(element)?.[0] ??
ShapeCache.generateElementShape(element, null)[0];
const [, , , , cx, cy] = getElementAbsoluteCoords(
element,
this.scene.getNonDeletedElementsMap(),
);

return shouldTestInside(element)
? getClosedCurveShape(
element,
roughShape,
[element.x, element.y],
element.angle,
[cx, cy],
)
: getCurveShape(roughShape, [element.x, element.y], element.angle, [
cx,
cy,
]);
}

case "ellipse":
return getEllipseShape(element);

case "freedraw": {
const [, , , , cx, cy] = getElementAbsoluteCoords(
element,
this.scene.getNonDeletedElementsMap(),
);
return getFreedrawShape(element, [cx, cy], shouldTestInside(element));
}
}
}

private getBoundTextShape(element: ExcalidrawElement): GeometricShape | null {
const boundTextElement = getBoundTextElement(
element,
Expand All @@ -4927,18 +4866,24 @@ class App extends React.Component<AppProps, AppState> {

if (boundTextElement) {
if (element.type === "arrow") {
return this.getElementShape({
...boundTextElement,
// arrow's bound text accurate position is not stored in the element's property
// but rather calculated and returned from the following static method
...LinearElementEditor.getBoundTextElementPosition(
element,
boundTextElement,
this.scene.getNonDeletedElementsMap(),
),
});
return getElementShape(
{
...boundTextElement,
// arrow's bound text accurate position is not stored in the element's property
// but rather calculated and returned from the following static method
...LinearElementEditor.getBoundTextElementPosition(
element,
boundTextElement,
this.scene.getNonDeletedElementsMap(),
),
},
this.scene.getNonDeletedElementsMap(),
);
}
return this.getElementShape(boundTextElement);
return getElementShape(
boundTextElement,
this.scene.getNonDeletedElementsMap(),
);
}

return null;
Expand Down Expand Up @@ -4977,7 +4922,10 @@ class App extends React.Component<AppProps, AppState> {
x,
y,
element: elementWithHighestZIndex,
shape: this.getElementShape(elementWithHighestZIndex),
shape: getElementShape(
elementWithHighestZIndex,
this.scene.getNonDeletedElementsMap(),
),
// when overlapping, we would like to be more precise
// this also avoids the need to update past tests
threshold: this.getElementHitThreshold() / 2,
Expand Down Expand Up @@ -5082,7 +5030,7 @@ class App extends React.Component<AppProps, AppState> {
x,
y,
element,
shape: this.getElementShape(element),
shape: getElementShape(element, this.scene.getNonDeletedElementsMap()),
threshold: this.getElementHitThreshold(),
frameNameBound: isFrameLikeElement(element)
? this.frameNameBoundsCache.get(element)
Expand Down Expand Up @@ -5114,7 +5062,10 @@ class App extends React.Component<AppProps, AppState> {
x,
y,
element: elements[index],
shape: this.getElementShape(elements[index]),
shape: getElementShape(
elements[index],
this.scene.getNonDeletedElementsMap(),
),
threshold: this.getElementHitThreshold(),
})
) {
Expand Down Expand Up @@ -5402,7 +5353,10 @@ class App extends React.Component<AppProps, AppState> {
x: sceneX,
y: sceneY,
element: container,
shape: this.getElementShape(container),
shape: getElementShape(
container,
this.scene.getNonDeletedElementsMap(),
),
threshold: this.getElementHitThreshold(),
})
) {
Expand Down Expand Up @@ -6103,7 +6057,10 @@ class App extends React.Component<AppProps, AppState> {
x: scenePointerX,
y: scenePointerY,
element,
shape: this.getElementShape(element),
shape: getElementShape(
element,
this.scene.getNonDeletedElementsMap(),
),
})
) {
hoverPointIndex = LinearElementEditor.getPointIndexUnderCursor(
Expand Down Expand Up @@ -7239,7 +7196,7 @@ class App extends React.Component<AppProps, AppState> {

const boundElement = getHoveredElementForBinding(
pointerDownState.origin,
this,
this.scene.getNonDeletedElementsMap(),
);
if (strokeOptions?.highlighter) {
//zsviczian
Expand Down Expand Up @@ -7510,7 +7467,7 @@ class App extends React.Component<AppProps, AppState> {
});
const boundElement = getHoveredElementForBinding(
pointerDownState.origin,
this,
this.scene.getNonDeletedElementsMap(),
);

this.scene.insertElement(element);
Expand Down Expand Up @@ -7993,7 +7950,7 @@ class App extends React.Component<AppProps, AppState> {
this.setState({
suggestedBindings: getSuggestedBindingsForArrows(
selectedElements,
this,
this.scene.getNonDeletedElementsMap(),
),
});

Expand Down Expand Up @@ -8519,7 +8476,7 @@ class App extends React.Component<AppProps, AppState> {
draggingElement,
this.state,
pointerCoords,
this,
this.scene.getNonDeletedElementsMap(),
);
}
this.setState({ suggestedBindings: [], startBoundElement: null });
Expand Down Expand Up @@ -9009,7 +8966,10 @@ class App extends React.Component<AppProps, AppState> {
x: pointerDownState.origin.x,
y: pointerDownState.origin.y,
element: hitElement,
shape: this.getElementShape(hitElement),
shape: getElementShape(
hitElement,
this.scene.getNonDeletedElementsMap(),
),
threshold: this.getElementHitThreshold(),
frameNameBound: isFrameLikeElement(hitElement)
? this.frameNameBoundsCache.get(hitElement)
Expand Down Expand Up @@ -9077,7 +9037,7 @@ class App extends React.Component<AppProps, AppState> {

bindOrUnbindLinearElements(
linearElements,
this,
this.scene.getNonDeletedElementsMap(),
isBindingEnabled(this.state),
this.state.selectedLinearElement?.selectedPointsIndices ?? [],
);
Expand Down Expand Up @@ -9565,7 +9525,7 @@ class App extends React.Component<AppProps, AppState> {
}): void => {
const hoveredBindableElement = getHoveredElementForBinding(
pointerCoords,
this,
this.scene.getNonDeletedElementsMap(),
);
this.setState({
suggestedBindings:
Expand All @@ -9592,7 +9552,7 @@ class App extends React.Component<AppProps, AppState> {
(acc: NonDeleted<ExcalidrawBindableElement>[], coords) => {
const hoveredBindableElement = getHoveredElementForBinding(
coords,
this,
this.scene.getNonDeletedElementsMap(),
);
if (
hoveredBindableElement != null &&
Expand Down Expand Up @@ -10160,7 +10120,7 @@ class App extends React.Component<AppProps, AppState> {
) {
const suggestedBindings = getSuggestedBindingsForArrows(
selectedElements,
this,
this.scene.getNonDeletedElementsMap(),
);

const elementsToHighlight = new Set<ExcalidrawElement>();
Expand Down
5 changes: 4 additions & 1 deletion packages/excalidraw/components/Stats/Angle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { degreeToRadian, radianToDegree } from "../../math";
import { angleIcon } from "../icons";
import DragInput from "./DragInput";
import type { DragInputCallbackType } from "./DragInput";
import { getStepSizedValue, isPropertyEditable } from "./utils";
import { getStepSizedValue, isPropertyEditable, updateBindings } from "./utils";
import type Scene from "../../scene/Scene";
import type { AppState } from "../../types";

Expand All @@ -33,11 +33,13 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
if (!latestElement) {
return;
}

if (nextValue !== undefined) {
const nextAngle = degreeToRadian(nextValue);
mutateElement(latestElement, {
angle: nextAngle,
});
updateBindings(latestElement, elementsMap);

const boundTextElement = getBoundTextElement(latestElement, elementsMap);
if (boundTextElement && !isArrowElement(latestElement)) {
Expand All @@ -63,6 +65,7 @@ const handleDegreeChange: DragInputCallbackType<AngleProps["property"]> = ({
mutateElement(latestElement, {
angle: nextAngle,
});
updateBindings(latestElement, elementsMap);

const boundTextElement = getBoundTextElement(latestElement, elementsMap);
if (boundTextElement && !isArrowElement(latestElement)) {
Expand Down
Loading

0 comments on commit 7467358

Please sign in to comment.