|
@@ -21,6 +21,7 @@ import {
|
|
getDrawingVersion,
|
|
getDrawingVersion,
|
|
getSyncableElements,
|
|
getSyncableElements,
|
|
hasNonDeletedElements,
|
|
hasNonDeletedElements,
|
|
|
|
+ newLinearElement,
|
|
} from "../element";
|
|
} from "../element";
|
|
import {
|
|
import {
|
|
deleteSelectedElements,
|
|
deleteSelectedElements,
|
|
@@ -47,7 +48,7 @@ import { restore } from "../data/restore";
|
|
|
|
|
|
import { renderScene } from "../renderer";
|
|
import { renderScene } from "../renderer";
|
|
import { AppState, GestureEvent, Gesture } from "../types";
|
|
import { AppState, GestureEvent, Gesture } from "../types";
|
|
-import { ExcalidrawElement } from "../element/types";
|
|
|
|
|
|
+import { ExcalidrawElement, ExcalidrawLinearElement } from "../element/types";
|
|
|
|
|
|
import {
|
|
import {
|
|
isWritableElement,
|
|
isWritableElement,
|
|
@@ -99,6 +100,7 @@ import { mutateElement, newElementWith } from "../element/mutateElement";
|
|
import { invalidateShapeForElement } from "../renderer/renderElement";
|
|
import { invalidateShapeForElement } from "../renderer/renderElement";
|
|
import { unstable_batchedUpdates } from "react-dom";
|
|
import { unstable_batchedUpdates } from "react-dom";
|
|
import { SceneStateCallbackRemover } from "../scene/globalScene";
|
|
import { SceneStateCallbackRemover } from "../scene/globalScene";
|
|
|
|
+import { isLinearElement } from "../element/typeChecks";
|
|
import { rescalePoints } from "../points";
|
|
import { rescalePoints } from "../points";
|
|
|
|
|
|
function withBatchedUpdates<
|
|
function withBatchedUpdates<
|
|
@@ -707,21 +709,18 @@ export class App extends React.Component<any, AppState> {
|
|
window.devicePixelRatio,
|
|
window.devicePixelRatio,
|
|
);
|
|
);
|
|
|
|
|
|
- const element = newTextElement(
|
|
|
|
- newElement(
|
|
|
|
- "text",
|
|
|
|
- x,
|
|
|
|
- y,
|
|
|
|
- this.state.currentItemStrokeColor,
|
|
|
|
- this.state.currentItemBackgroundColor,
|
|
|
|
- this.state.currentItemFillStyle,
|
|
|
|
- this.state.currentItemStrokeWidth,
|
|
|
|
- this.state.currentItemRoughness,
|
|
|
|
- this.state.currentItemOpacity,
|
|
|
|
- ),
|
|
|
|
- data.text,
|
|
|
|
- this.state.currentItemFont,
|
|
|
|
- );
|
|
|
|
|
|
+ const element = newTextElement({
|
|
|
|
+ x: x,
|
|
|
|
+ y: y,
|
|
|
|
+ strokeColor: this.state.currentItemStrokeColor,
|
|
|
|
+ backgroundColor: this.state.currentItemBackgroundColor,
|
|
|
|
+ fillStyle: this.state.currentItemFillStyle,
|
|
|
|
+ strokeWidth: this.state.currentItemStrokeWidth,
|
|
|
|
+ roughness: this.state.currentItemRoughness,
|
|
|
|
+ opacity: this.state.currentItemOpacity,
|
|
|
|
+ text: data.text,
|
|
|
|
+ font: this.state.currentItemFont,
|
|
|
|
+ });
|
|
|
|
|
|
globalSceneState.replaceAllElements([
|
|
globalSceneState.replaceAllElements([
|
|
...globalSceneState.getAllElements(),
|
|
...globalSceneState.getAllElements(),
|
|
@@ -960,21 +959,18 @@ export class App extends React.Component<any, AppState> {
|
|
const element =
|
|
const element =
|
|
elementAtPosition && isTextElement(elementAtPosition)
|
|
elementAtPosition && isTextElement(elementAtPosition)
|
|
? elementAtPosition
|
|
? elementAtPosition
|
|
- : newTextElement(
|
|
|
|
- newElement(
|
|
|
|
- "text",
|
|
|
|
- x,
|
|
|
|
- y,
|
|
|
|
- this.state.currentItemStrokeColor,
|
|
|
|
- this.state.currentItemBackgroundColor,
|
|
|
|
- this.state.currentItemFillStyle,
|
|
|
|
- this.state.currentItemStrokeWidth,
|
|
|
|
- this.state.currentItemRoughness,
|
|
|
|
- this.state.currentItemOpacity,
|
|
|
|
- ),
|
|
|
|
- "", // default text
|
|
|
|
- this.state.currentItemFont, // default font
|
|
|
|
- );
|
|
|
|
|
|
+ : newTextElement({
|
|
|
|
+ x: x,
|
|
|
|
+ y: y,
|
|
|
|
+ strokeColor: this.state.currentItemStrokeColor,
|
|
|
|
+ backgroundColor: this.state.currentItemBackgroundColor,
|
|
|
|
+ fillStyle: this.state.currentItemFillStyle,
|
|
|
|
+ strokeWidth: this.state.currentItemStrokeWidth,
|
|
|
|
+ roughness: this.state.currentItemRoughness,
|
|
|
|
+ opacity: this.state.currentItemOpacity,
|
|
|
|
+ text: "",
|
|
|
|
+ font: this.state.currentItemFont,
|
|
|
|
+ });
|
|
|
|
|
|
this.setState({ editingElement: element });
|
|
this.setState({ editingElement: element });
|
|
|
|
|
|
@@ -1044,11 +1040,8 @@ export class App extends React.Component<any, AppState> {
|
|
if (text) {
|
|
if (text) {
|
|
globalSceneState.replaceAllElements([
|
|
globalSceneState.replaceAllElements([
|
|
...globalSceneState.getAllElements(),
|
|
...globalSceneState.getAllElements(),
|
|
- {
|
|
|
|
- // we need to recreate the element to update dimensions &
|
|
|
|
- // position
|
|
|
|
- ...newTextElement(element, text, element.font),
|
|
|
|
- },
|
|
|
|
|
|
+ // we need to recreate the element to update dimensions & position
|
|
|
|
+ newTextElement({ ...element, text, font: element.font }),
|
|
]);
|
|
]);
|
|
}
|
|
}
|
|
this.setState(prevState => ({
|
|
this.setState(prevState => ({
|
|
@@ -1332,22 +1325,6 @@ export class App extends React.Component<any, AppState> {
|
|
const originX = x;
|
|
const originX = x;
|
|
const originY = y;
|
|
const originY = y;
|
|
|
|
|
|
- let element = newElement(
|
|
|
|
- this.state.elementType,
|
|
|
|
- x,
|
|
|
|
- y,
|
|
|
|
- this.state.currentItemStrokeColor,
|
|
|
|
- this.state.currentItemBackgroundColor,
|
|
|
|
- this.state.currentItemFillStyle,
|
|
|
|
- this.state.currentItemStrokeWidth,
|
|
|
|
- this.state.currentItemRoughness,
|
|
|
|
- this.state.currentItemOpacity,
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- if (isTextElement(element)) {
|
|
|
|
- element = newTextElement(element, "", this.state.currentItemFont);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
type ResizeTestType = ReturnType<typeof resizeTest>;
|
|
type ResizeTestType = ReturnType<typeof resizeTest>;
|
|
let resizeHandle: ResizeTestType = false;
|
|
let resizeHandle: ResizeTestType = false;
|
|
let isResizingElements = false;
|
|
let isResizingElements = false;
|
|
@@ -1437,30 +1414,30 @@ export class App extends React.Component<any, AppState> {
|
|
this.setState({ selectedElementIds: {} });
|
|
this.setState({ selectedElementIds: {} });
|
|
}
|
|
}
|
|
|
|
|
|
- if (isTextElement(element)) {
|
|
|
|
|
|
+ if (this.state.elementType === "text") {
|
|
// if we're currently still editing text, clicking outside
|
|
// if we're currently still editing text, clicking outside
|
|
// should only finalize it, not create another (irrespective
|
|
// should only finalize it, not create another (irrespective
|
|
// of state.elementLocked)
|
|
// of state.elementLocked)
|
|
if (this.state.editingElement?.type === "text") {
|
|
if (this.state.editingElement?.type === "text") {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- if (elementIsAddedToSelection) {
|
|
|
|
- element = hitElement!;
|
|
|
|
- }
|
|
|
|
- let textX = event.clientX;
|
|
|
|
- let textY = event.clientY;
|
|
|
|
- if (!event.altKey) {
|
|
|
|
- const snappedToCenterPosition = this.getTextWysiwygSnappedToCenterPosition(
|
|
|
|
- x,
|
|
|
|
- y,
|
|
|
|
- );
|
|
|
|
- if (snappedToCenterPosition) {
|
|
|
|
- element.x = snappedToCenterPosition.elementCenterX;
|
|
|
|
- element.y = snappedToCenterPosition.elementCenterY;
|
|
|
|
- textX = snappedToCenterPosition.wysiwygX;
|
|
|
|
- textY = snappedToCenterPosition.wysiwygY;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ const snappedToCenterPosition = event.altKey
|
|
|
|
+ ? null
|
|
|
|
+ : this.getTextWysiwygSnappedToCenterPosition(x, y);
|
|
|
|
+
|
|
|
|
+ const element = newTextElement({
|
|
|
|
+ x: snappedToCenterPosition?.elementCenterX ?? x,
|
|
|
|
+ y: snappedToCenterPosition?.elementCenterY ?? y,
|
|
|
|
+ strokeColor: this.state.currentItemStrokeColor,
|
|
|
|
+ backgroundColor: this.state.currentItemBackgroundColor,
|
|
|
|
+ fillStyle: this.state.currentItemFillStyle,
|
|
|
|
+ strokeWidth: this.state.currentItemStrokeWidth,
|
|
|
|
+ roughness: this.state.currentItemRoughness,
|
|
|
|
+ opacity: this.state.currentItemOpacity,
|
|
|
|
+ text: "",
|
|
|
|
+ font: this.state.currentItemFont,
|
|
|
|
+ });
|
|
|
|
|
|
const resetSelection = () => {
|
|
const resetSelection = () => {
|
|
this.setState({
|
|
this.setState({
|
|
@@ -1471,8 +1448,8 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
|
textWysiwyg({
|
|
textWysiwyg({
|
|
initText: "",
|
|
initText: "",
|
|
- x: textX,
|
|
|
|
- y: textY,
|
|
|
|
|
|
+ x: snappedToCenterPosition?.wysiwygX ?? event.clientX,
|
|
|
|
+ y: snappedToCenterPosition?.wysiwygY ?? event.clientY,
|
|
strokeColor: this.state.currentItemStrokeColor,
|
|
strokeColor: this.state.currentItemStrokeColor,
|
|
opacity: this.state.currentItemOpacity,
|
|
opacity: this.state.currentItemOpacity,
|
|
font: this.state.currentItemFont,
|
|
font: this.state.currentItemFont,
|
|
@@ -1481,9 +1458,11 @@ export class App extends React.Component<any, AppState> {
|
|
if (text) {
|
|
if (text) {
|
|
globalSceneState.replaceAllElements([
|
|
globalSceneState.replaceAllElements([
|
|
...globalSceneState.getAllElements(),
|
|
...globalSceneState.getAllElements(),
|
|
- {
|
|
|
|
- ...newTextElement(element, text, this.state.currentItemFont),
|
|
|
|
- },
|
|
|
|
|
|
+ newTextElement({
|
|
|
|
+ ...element,
|
|
|
|
+ text,
|
|
|
|
+ font: this.state.currentItemFont,
|
|
|
|
+ }),
|
|
]);
|
|
]);
|
|
}
|
|
}
|
|
this.setState(prevState => ({
|
|
this.setState(prevState => ({
|
|
@@ -1531,6 +1510,17 @@ export class App extends React.Component<any, AppState> {
|
|
points: [...multiElement.points, [x - rx, y - ry]],
|
|
points: [...multiElement.points, [x - rx, y - ry]],
|
|
});
|
|
});
|
|
} else {
|
|
} else {
|
|
|
|
+ const element = newLinearElement({
|
|
|
|
+ type: this.state.elementType,
|
|
|
|
+ x: x,
|
|
|
|
+ y: y,
|
|
|
|
+ strokeColor: this.state.currentItemStrokeColor,
|
|
|
|
+ backgroundColor: this.state.currentItemBackgroundColor,
|
|
|
|
+ fillStyle: this.state.currentItemFillStyle,
|
|
|
|
+ strokeWidth: this.state.currentItemStrokeWidth,
|
|
|
|
+ roughness: this.state.currentItemRoughness,
|
|
|
|
+ opacity: this.state.currentItemOpacity,
|
|
|
|
+ });
|
|
this.setState(prevState => ({
|
|
this.setState(prevState => ({
|
|
selectedElementIds: {
|
|
selectedElementIds: {
|
|
...prevState.selectedElementIds,
|
|
...prevState.selectedElementIds,
|
|
@@ -1549,26 +1539,40 @@ export class App extends React.Component<any, AppState> {
|
|
editingElement: element,
|
|
editingElement: element,
|
|
});
|
|
});
|
|
}
|
|
}
|
|
- } else if (element.type === "selection") {
|
|
|
|
- this.setState({
|
|
|
|
- selectionElement: element,
|
|
|
|
- draggingElement: element,
|
|
|
|
- });
|
|
|
|
} else {
|
|
} else {
|
|
- globalSceneState.replaceAllElements([
|
|
|
|
- ...globalSceneState.getAllElements(),
|
|
|
|
- element,
|
|
|
|
- ]);
|
|
|
|
- this.setState({
|
|
|
|
- multiElement: null,
|
|
|
|
- draggingElement: element,
|
|
|
|
- editingElement: element,
|
|
|
|
|
|
+ const element = newElement({
|
|
|
|
+ type: this.state.elementType,
|
|
|
|
+ x: x,
|
|
|
|
+ y: y,
|
|
|
|
+ strokeColor: this.state.currentItemStrokeColor,
|
|
|
|
+ backgroundColor: this.state.currentItemBackgroundColor,
|
|
|
|
+ fillStyle: this.state.currentItemFillStyle,
|
|
|
|
+ strokeWidth: this.state.currentItemStrokeWidth,
|
|
|
|
+ roughness: this.state.currentItemRoughness,
|
|
|
|
+ opacity: this.state.currentItemOpacity,
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+ if (element.type === "selection") {
|
|
|
|
+ this.setState({
|
|
|
|
+ selectionElement: element,
|
|
|
|
+ draggingElement: element,
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ globalSceneState.replaceAllElements([
|
|
|
|
+ ...globalSceneState.getAllElements(),
|
|
|
|
+ element,
|
|
|
|
+ ]);
|
|
|
|
+ this.setState({
|
|
|
|
+ multiElement: null,
|
|
|
|
+ draggingElement: element,
|
|
|
|
+ editingElement: element,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
let resizeArrowFn:
|
|
let resizeArrowFn:
|
|
| ((
|
|
| ((
|
|
- element: ExcalidrawElement,
|
|
|
|
|
|
+ element: ExcalidrawLinearElement,
|
|
pointIndex: number,
|
|
pointIndex: number,
|
|
deltaX: number,
|
|
deltaX: number,
|
|
deltaY: number,
|
|
deltaY: number,
|
|
@@ -1579,7 +1583,7 @@ export class App extends React.Component<any, AppState> {
|
|
| null = null;
|
|
| null = null;
|
|
|
|
|
|
const arrowResizeOrigin = (
|
|
const arrowResizeOrigin = (
|
|
- element: ExcalidrawElement,
|
|
|
|
|
|
+ element: ExcalidrawLinearElement,
|
|
pointIndex: number,
|
|
pointIndex: number,
|
|
deltaX: number,
|
|
deltaX: number,
|
|
deltaY: number,
|
|
deltaY: number,
|
|
@@ -1604,7 +1608,9 @@ export class App extends React.Component<any, AppState> {
|
|
x: dx,
|
|
x: dx,
|
|
y: dy,
|
|
y: dy,
|
|
points: element.points.map((point, i) =>
|
|
points: element.points.map((point, i) =>
|
|
- i === pointIndex ? [absPx - element.x, absPy - element.y] : point,
|
|
|
|
|
|
+ i === pointIndex
|
|
|
|
+ ? ([absPx - element.x, absPy - element.y] as const)
|
|
|
|
+ : point,
|
|
),
|
|
),
|
|
});
|
|
});
|
|
} else {
|
|
} else {
|
|
@@ -1612,14 +1618,16 @@ export class App extends React.Component<any, AppState> {
|
|
x: element.x + deltaX,
|
|
x: element.x + deltaX,
|
|
y: element.y + deltaY,
|
|
y: element.y + deltaY,
|
|
points: element.points.map((point, i) =>
|
|
points: element.points.map((point, i) =>
|
|
- i === pointIndex ? [p1[0] - deltaX, p1[1] - deltaY] : point,
|
|
|
|
|
|
+ i === pointIndex
|
|
|
|
+ ? ([p1[0] - deltaX, p1[1] - deltaY] as const)
|
|
|
|
+ : point,
|
|
),
|
|
),
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
const arrowResizeEnd = (
|
|
const arrowResizeEnd = (
|
|
- element: ExcalidrawElement,
|
|
|
|
|
|
+ element: ExcalidrawLinearElement,
|
|
pointIndex: number,
|
|
pointIndex: number,
|
|
deltaX: number,
|
|
deltaX: number,
|
|
deltaY: number,
|
|
deltaY: number,
|
|
@@ -1636,13 +1644,15 @@ export class App extends React.Component<any, AppState> {
|
|
);
|
|
);
|
|
mutateElement(element, {
|
|
mutateElement(element, {
|
|
points: element.points.map((point, i) =>
|
|
points: element.points.map((point, i) =>
|
|
- i === pointIndex ? [width, height] : point,
|
|
|
|
|
|
+ i === pointIndex ? ([width, height] as const) : point,
|
|
),
|
|
),
|
|
});
|
|
});
|
|
} else {
|
|
} else {
|
|
mutateElement(element, {
|
|
mutateElement(element, {
|
|
points: element.points.map((point, i) =>
|
|
points: element.points.map((point, i) =>
|
|
- i === pointIndex ? [p1[0] + deltaX, p1[1] + deltaY] : point,
|
|
|
|
|
|
+ i === pointIndex
|
|
|
|
+ ? ([p1[0] + deltaX, p1[1] + deltaY] as const)
|
|
|
|
+ : point,
|
|
),
|
|
),
|
|
});
|
|
});
|
|
}
|
|
}
|
|
@@ -1711,10 +1721,9 @@ export class App extends React.Component<any, AppState> {
|
|
const deltaX = x - lastX;
|
|
const deltaX = x - lastX;
|
|
const deltaY = y - lastY;
|
|
const deltaY = y - lastY;
|
|
const element = selectedElements[0];
|
|
const element = selectedElements[0];
|
|
- const isLinear = element.type === "line" || element.type === "arrow";
|
|
|
|
switch (resizeHandle) {
|
|
switch (resizeHandle) {
|
|
case "nw":
|
|
case "nw":
|
|
- if (isLinear && element.points.length === 2) {
|
|
|
|
|
|
+ if (isLinearElement(element) && element.points.length === 2) {
|
|
const [, p1] = element.points;
|
|
const [, p1] = element.points;
|
|
|
|
|
|
if (!resizeArrowFn) {
|
|
if (!resizeArrowFn) {
|
|
@@ -1739,7 +1748,7 @@ export class App extends React.Component<any, AppState> {
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case "ne":
|
|
case "ne":
|
|
- if (isLinear && element.points.length === 2) {
|
|
|
|
|
|
+ if (isLinearElement(element) && element.points.length === 2) {
|
|
const [, p1] = element.points;
|
|
const [, p1] = element.points;
|
|
if (!resizeArrowFn) {
|
|
if (!resizeArrowFn) {
|
|
if (p1[0] >= 0) {
|
|
if (p1[0] >= 0) {
|
|
@@ -1761,7 +1770,7 @@ export class App extends React.Component<any, AppState> {
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case "sw":
|
|
case "sw":
|
|
- if (isLinear && element.points.length === 2) {
|
|
|
|
|
|
+ if (isLinearElement(element) && element.points.length === 2) {
|
|
const [, p1] = element.points;
|
|
const [, p1] = element.points;
|
|
if (!resizeArrowFn) {
|
|
if (!resizeArrowFn) {
|
|
if (p1[0] <= 0) {
|
|
if (p1[0] <= 0) {
|
|
@@ -1782,7 +1791,7 @@ export class App extends React.Component<any, AppState> {
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case "se":
|
|
case "se":
|
|
- if (isLinear && element.points.length === 2) {
|
|
|
|
|
|
+ if (isLinearElement(element) && element.points.length === 2) {
|
|
const [, p1] = element.points;
|
|
const [, p1] = element.points;
|
|
if (!resizeArrowFn) {
|
|
if (!resizeArrowFn) {
|
|
if (p1[0] > 0 || p1[1] > 0) {
|
|
if (p1[0] > 0 || p1[1] > 0) {
|
|
@@ -1807,14 +1816,18 @@ export class App extends React.Component<any, AppState> {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- mutateElement(element, {
|
|
|
|
- height,
|
|
|
|
- y: element.y + deltaY,
|
|
|
|
- points:
|
|
|
|
- element.points.length > 0
|
|
|
|
- ? rescalePoints(1, height, element.points)
|
|
|
|
- : undefined,
|
|
|
|
- });
|
|
|
|
|
|
+ if (isLinearElement(element)) {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ height,
|
|
|
|
+ y: element.y + deltaY,
|
|
|
|
+ points: rescalePoints(1, height, element.points),
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ height,
|
|
|
|
+ y: element.y + deltaY,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -1825,15 +1838,18 @@ export class App extends React.Component<any, AppState> {
|
|
// Someday we should implement logic to flip the shape. But for now, just stop.
|
|
// Someday we should implement logic to flip the shape. But for now, just stop.
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
- mutateElement(element, {
|
|
|
|
- width,
|
|
|
|
- x: element.x + deltaX,
|
|
|
|
- points:
|
|
|
|
- element.points.length > 0
|
|
|
|
- ? rescalePoints(0, width, element.points)
|
|
|
|
- : undefined,
|
|
|
|
- });
|
|
|
|
|
|
+ if (isLinearElement(element)) {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ width,
|
|
|
|
+ x: element.x + deltaX,
|
|
|
|
+ points: rescalePoints(0, width, element.points),
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ width,
|
|
|
|
+ x: element.x + deltaX,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case "s": {
|
|
case "s": {
|
|
@@ -1842,14 +1858,16 @@ export class App extends React.Component<any, AppState> {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- mutateElement(element, {
|
|
|
|
- height,
|
|
|
|
- points:
|
|
|
|
- element.points.length > 0
|
|
|
|
- ? rescalePoints(1, height, element.points)
|
|
|
|
- : undefined,
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
|
|
+ if (isLinearElement(element)) {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ height,
|
|
|
|
+ points: rescalePoints(1, height, element.points),
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ height,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case "e": {
|
|
case "e": {
|
|
@@ -1858,13 +1876,16 @@ export class App extends React.Component<any, AppState> {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- mutateElement(element, {
|
|
|
|
- width,
|
|
|
|
- points:
|
|
|
|
- element.points.length > 0
|
|
|
|
- ? rescalePoints(0, width, element.points)
|
|
|
|
- : undefined,
|
|
|
|
- });
|
|
|
|
|
|
+ if (isLinearElement(element)) {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ width,
|
|
|
|
+ points: rescalePoints(0, width, element.points),
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ mutateElement(element, {
|
|
|
|
+ width,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1934,10 +1955,7 @@ export class App extends React.Component<any, AppState> {
|
|
let width = distance(originX, x);
|
|
let width = distance(originX, x);
|
|
let height = distance(originY, y);
|
|
let height = distance(originY, y);
|
|
|
|
|
|
- const isLinear =
|
|
|
|
- this.state.elementType === "line" || this.state.elementType === "arrow";
|
|
|
|
-
|
|
|
|
- if (isLinear) {
|
|
|
|
|
|
+ if (isLinearElement(draggingElement)) {
|
|
draggingOccurred = true;
|
|
draggingOccurred = true;
|
|
const points = draggingElement.points;
|
|
const points = draggingElement.points;
|
|
let dx = x - draggingElement.x;
|
|
let dx = x - draggingElement.x;
|
|
@@ -2023,7 +2041,7 @@ export class App extends React.Component<any, AppState> {
|
|
window.removeEventListener("pointermove", onPointerMove);
|
|
window.removeEventListener("pointermove", onPointerMove);
|
|
window.removeEventListener("pointerup", onPointerUp);
|
|
window.removeEventListener("pointerup", onPointerUp);
|
|
|
|
|
|
- if (elementType === "arrow" || elementType === "line") {
|
|
|
|
|
|
+ if (isLinearElement(draggingElement)) {
|
|
if (draggingElement!.points.length > 1) {
|
|
if (draggingElement!.points.length > 1) {
|
|
history.resumeRecording();
|
|
history.resumeRecording();
|
|
}
|
|
}
|
|
@@ -2041,7 +2059,7 @@ export class App extends React.Component<any, AppState> {
|
|
],
|
|
],
|
|
});
|
|
});
|
|
this.setState({
|
|
this.setState({
|
|
- multiElement: this.state.draggingElement,
|
|
|
|
|
|
+ multiElement: draggingElement,
|
|
editingElement: this.state.draggingElement,
|
|
editingElement: this.state.draggingElement,
|
|
});
|
|
});
|
|
} else if (draggingOccurred && !multiElement) {
|
|
} else if (draggingOccurred && !multiElement) {
|
|
@@ -2215,12 +2233,12 @@ export class App extends React.Component<any, AppState> {
|
|
const dx = x - elementsCenterX;
|
|
const dx = x - elementsCenterX;
|
|
const dy = y - elementsCenterY;
|
|
const dy = y - elementsCenterY;
|
|
|
|
|
|
- const newElements = clipboardElements.map(clipboardElements => {
|
|
|
|
- const duplicate = duplicateElement(clipboardElements);
|
|
|
|
- duplicate.x += dx - minX;
|
|
|
|
- duplicate.y += dy - minY;
|
|
|
|
- return duplicate;
|
|
|
|
- });
|
|
|
|
|
|
+ const newElements = clipboardElements.map(element =>
|
|
|
|
+ duplicateElement(element, {
|
|
|
|
+ x: element.x + dx - minX,
|
|
|
|
+ y: element.y + dy - minY,
|
|
|
|
+ }),
|
|
|
|
+ );
|
|
|
|
|
|
globalSceneState.replaceAllElements([
|
|
globalSceneState.replaceAllElements([
|
|
...globalSceneState.getAllElements(),
|
|
...globalSceneState.getAllElements(),
|