|
@@ -9,6 +9,7 @@ import {
|
|
|
newTextElement,
|
|
|
duplicateElement,
|
|
|
resizeTest,
|
|
|
+ normalizeResizeHandle,
|
|
|
isInvisiblySmallElement,
|
|
|
isTextElement,
|
|
|
textWysiwyg,
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
getCursorForResizingElement,
|
|
|
getPerfectElementSize,
|
|
|
resizePerfectLineForNWHandler,
|
|
|
+ normalizeDimensions,
|
|
|
} from "./element";
|
|
|
import {
|
|
|
clearSelection,
|
|
@@ -38,7 +40,7 @@ import { renderScene } from "./renderer";
|
|
|
import { AppState } from "./types";
|
|
|
import { ExcalidrawElement } from "./element/types";
|
|
|
|
|
|
-import { isInputLike, debounce, capitalizeString } from "./utils";
|
|
|
+import { isInputLike, debounce, capitalizeString, distance } from "./utils";
|
|
|
import { KEYS, isArrowKey } from "./keys";
|
|
|
|
|
|
import { findShapeByKey, shapesShortcutKeys, SHAPES } from "./shapes";
|
|
@@ -776,6 +778,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
|
const { x, y } = viewportCoordsToSceneCoords(e, this.state);
|
|
|
|
|
|
+ const originX = x;
|
|
|
+ const originY = y;
|
|
|
+
|
|
|
let element = newElement(
|
|
|
this.state.elementType,
|
|
|
x,
|
|
@@ -945,16 +950,15 @@ export class App extends React.Component<any, AppState> {
|
|
|
const deltaX = x - lastX;
|
|
|
const deltaY = y - lastY;
|
|
|
const element = selectedElements[0];
|
|
|
+ const isLinear =
|
|
|
+ element.type === "line" || element.type === "arrow";
|
|
|
switch (resizeHandle) {
|
|
|
case "nw":
|
|
|
element.width -= deltaX;
|
|
|
element.x += deltaX;
|
|
|
|
|
|
if (e.shiftKey) {
|
|
|
- if (
|
|
|
- element.type === "arrow" ||
|
|
|
- element.type === "line"
|
|
|
- ) {
|
|
|
+ if (isLinear) {
|
|
|
resizePerfectLineForNWHandler(element, x, y);
|
|
|
} else {
|
|
|
element.y += element.height - element.width;
|
|
@@ -986,10 +990,7 @@ export class App extends React.Component<any, AppState> {
|
|
|
break;
|
|
|
case "se":
|
|
|
if (e.shiftKey) {
|
|
|
- if (
|
|
|
- element.type === "arrow" ||
|
|
|
- element.type === "line"
|
|
|
- ) {
|
|
|
+ if (isLinear) {
|
|
|
const { width, height } = getPerfectElementSize(
|
|
|
element.type,
|
|
|
x - element.x,
|
|
@@ -1022,6 +1023,11 @@ export class App extends React.Component<any, AppState> {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ if (resizeHandle) {
|
|
|
+ resizeHandle = normalizeResizeHandle(element, resizeHandle);
|
|
|
+ }
|
|
|
+ normalizeDimensions(element);
|
|
|
+
|
|
|
document.documentElement.style.cursor = getCursorForResizingElement(
|
|
|
{ element, resizeHandle },
|
|
|
);
|
|
@@ -1064,33 +1070,35 @@ export class App extends React.Component<any, AppState> {
|
|
|
const draggingElement = this.state.draggingElement;
|
|
|
if (!draggingElement) return;
|
|
|
|
|
|
- let width =
|
|
|
- e.clientX -
|
|
|
- CANVAS_WINDOW_OFFSET_LEFT -
|
|
|
- draggingElement.x -
|
|
|
- this.state.scrollX;
|
|
|
- let height =
|
|
|
- e.clientY -
|
|
|
- CANVAS_WINDOW_OFFSET_TOP -
|
|
|
- draggingElement.y -
|
|
|
- this.state.scrollY;
|
|
|
+ const { x, y } = viewportCoordsToSceneCoords(e, this.state);
|
|
|
+
|
|
|
+ let width = distance(originX, x);
|
|
|
+ let height = distance(originY, y);
|
|
|
+
|
|
|
+ const isLinear =
|
|
|
+ this.state.elementType === "line" ||
|
|
|
+ this.state.elementType === "arrow";
|
|
|
+
|
|
|
+ if (isLinear && x < originX) width = -width;
|
|
|
+ if (isLinear && y < originY) height = -height;
|
|
|
|
|
|
if (e.shiftKey) {
|
|
|
- let {
|
|
|
- width: newWidth,
|
|
|
- height: newHeight,
|
|
|
- } = getPerfectElementSize(
|
|
|
+ ({ width, height } = getPerfectElementSize(
|
|
|
this.state.elementType,
|
|
|
width,
|
|
|
- height,
|
|
|
- );
|
|
|
- draggingElement.width = newWidth;
|
|
|
- draggingElement.height = newHeight;
|
|
|
- } else {
|
|
|
- draggingElement.width = width;
|
|
|
- draggingElement.height = height;
|
|
|
+ !isLinear && y < originY ? -height : height,
|
|
|
+ ));
|
|
|
+
|
|
|
+ if (!isLinear && height < 0) height = -height;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isLinear) {
|
|
|
+ draggingElement.x = x < originX ? originX - width : originX;
|
|
|
+ draggingElement.y = y < originY ? originY - height : originY;
|
|
|
}
|
|
|
|
|
|
+ draggingElement.width = width;
|
|
|
+ draggingElement.height = height;
|
|
|
draggingElement.shape = null;
|
|
|
|
|
|
if (this.state.elementType === "selection") {
|
|
@@ -1136,6 +1144,10 @@ export class App extends React.Component<any, AppState> {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ if (normalizeDimensions(draggingElement)) {
|
|
|
+ this.forceUpdate();
|
|
|
+ }
|
|
|
+
|
|
|
if (resizingElement && isInvisiblySmallElement(resizingElement)) {
|
|
|
elements = elements.filter(el => el.id !== resizingElement.id);
|
|
|
}
|
|
@@ -1349,10 +1361,6 @@ export class App extends React.Component<any, AppState> {
|
|
|
const minX = Math.min(...parsedElements.map(element => element.x));
|
|
|
const minY = Math.min(...parsedElements.map(element => element.y));
|
|
|
|
|
|
- const distance = (x: number, y: number) => {
|
|
|
- return Math.abs(x > y ? x - y : y - x);
|
|
|
- };
|
|
|
-
|
|
|
parsedElements.forEach(parsedElement => {
|
|
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(parsedElement);
|
|
|
subCanvasX1 = Math.min(subCanvasX1, x1);
|