Abstract away or eliminate most of the mutation of the Elements array (#955)

This commit is contained in:
Pete Hunt 2020-03-14 21:48:51 -07:00 committed by GitHub
parent 05af9f04ed
commit e1e2249f57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 293 additions and 272 deletions

View file

@ -1,7 +1,7 @@
import { ExcalidrawElement } from "./types";
import { rotate } from "../math";
import { Drawable } from "roughjs/bin/core";
import { Point } from "roughjs/bin/geometry";
import { Point } from "../types";
import { getShapeForElement } from "../renderer/renderElement";
// If the element is created from right to left, the width is going to be negative
@ -68,7 +68,7 @@ export function getLinearElementAbsoluteBounds(element: ExcalidrawElement) {
// move, bcurveTo, lineTo, and curveTo
if (op === "move") {
// change starting point
currentP = data as Point;
currentP = (data as unknown) as Point;
// move operation does not draw anything; so, it always
// returns false
} else if (op === "bcurveTo") {
@ -133,7 +133,7 @@ export function getArrowPoints(element: ExcalidrawElement, shape: Drawable[]) {
const prevOp = ops[ops.length - 2];
let p0: Point = [0, 0];
if (prevOp.op === "move") {
p0 = prevOp.data as Point;
p0 = (prevOp.data as unknown) as Point;
} else if (prevOp.op === "bcurveTo") {
p0 = [prevOp.data[4], prevOp.data[5]];
}

View file

@ -7,7 +7,7 @@ import {
getElementAbsoluteCoords,
getLinearElementAbsoluteBounds,
} from "./bounds";
import { Point } from "roughjs/bin/geometry";
import { Point } from "../types";
import { Drawable, OpSet } from "roughjs/bin/core";
import { AppState } from "../types";
import { getShapeForElement } from "../renderer/renderElement";
@ -231,7 +231,7 @@ const hitTestRoughShape = (opSet: OpSet[], x: number, y: number) => {
// move, bcurveTo, lineTo, and curveTo
if (op === "move") {
// change starting point
currentP = data as Point;
currentP = (data as unknown) as Point;
// move operation does not draw anything; so, it always
// returns false
} else if (op === "bcurveTo") {

View file

@ -1,5 +1,6 @@
import { ExcalidrawElement, ExcalidrawTextElement } from "./types";
import { ExcalidrawElement } from "./types";
import { randomSeed } from "roughjs/bin/math";
import { invalidateShapeForElement } from "../renderer/renderElement";
type ElementUpdate<TElement extends ExcalidrawElement> = Omit<
Partial<TElement>,
@ -9,45 +10,35 @@ type ElementUpdate<TElement extends ExcalidrawElement> = Omit<
// This function tracks updates of text elements for the purposes for collaboration.
// The version is used to compare updates when more than one user is working in
// the same drawing.
export function mutateElement(
element: ExcalidrawElement,
updates?: ElementUpdate<ExcalidrawElement>,
export function mutateElement<TElement extends ExcalidrawElement>(
element: TElement,
updates: ElementUpdate<TElement>,
) {
if (updates) {
Object.assign(element, updates);
const mutableElement = element as any;
for (const key in updates) {
const value = (updates as any)[key];
if (typeof value !== "undefined") {
mutableElement[key] = value;
}
}
(element as any).version++;
(element as any).versionNonce = randomSeed();
if (
typeof updates.height !== "undefined" ||
typeof updates.width !== "undefined" ||
typeof updates.points !== "undefined"
) {
invalidateShapeForElement(element);
}
mutableElement.version++;
mutableElement.versionNonce = randomSeed();
}
export function newElementWith(
element: ExcalidrawElement,
updates: ElementUpdate<ExcalidrawElement>,
): ExcalidrawElement {
return {
...element,
...updates,
version: element.version + 1,
versionNonce: randomSeed(),
};
}
// This function tracks updates of text elements for the purposes for collaboration.
// The version is used to compare updates when more than one user is working in
// the same document.
export function mutateTextElement(
element: ExcalidrawTextElement,
updates: ElementUpdate<ExcalidrawTextElement>,
): void {
Object.assign(element, updates);
(element as any).version++;
(element as any).versionNonce = randomSeed();
}
export function newTextElementWith(
element: ExcalidrawTextElement,
updates: ElementUpdate<ExcalidrawTextElement>,
): ExcalidrawTextElement {
export function newElementWith<TElement extends ExcalidrawElement>(
element: TElement,
updates: ElementUpdate<TElement>,
): TElement {
return {
...element,
...updates,

View file

@ -1,6 +1,6 @@
import { randomSeed } from "roughjs/bin/math";
import nanoid from "nanoid";
import { Point } from "roughjs/bin/geometry";
import { Point } from "../types";
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
import { measureText } from "../utils";
@ -32,7 +32,7 @@ export function newElement(
roughness,
opacity,
seed: randomSeed(),
points: [] as Point[],
points: [] as readonly Point[],
version: 1,
versionNonce: 0,
isDeleted: false,

View file

@ -1,5 +1,4 @@
import { ExcalidrawElement } from "./types";
import { invalidateShapeForElement } from "../renderer/renderElement";
import { mutateElement } from "./mutateElement";
export function isInvisiblySmallElement(element: ExcalidrawElement): boolean {
@ -101,7 +100,5 @@ export function normalizeDimensions(
});
}
invalidateShapeForElement(element);
return true;
}

View file

@ -1,10 +1,10 @@
import { measureText } from "../utils";
import { ExcalidrawTextElement } from "./types";
import { mutateTextElement } from "./mutateElement";
import { mutateElement } from "./mutateElement";
export const redrawTextBoundingBox = (element: ExcalidrawTextElement) => {
const metrics = measureText(element.text, element.font);
mutateTextElement(element, {
mutateElement(element, {
width: metrics.width,
height: metrics.height,
baseline: metrics.baseline,