improve & granularize ExcalidrawElement types (#991)

* improve & granularize ExcalidrawElement types

* fix incorrectly passing type

* fix tests

* fix more tests

* fix unnecessary spreads & refactor

* add comments
This commit is contained in:
David Luzar 2020-03-17 20:55:40 +01:00 committed by GitHub
parent 1c545c1d47
commit 373d16abe6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 430 additions and 272 deletions

View file

@ -1,25 +1,45 @@
import { randomSeed } from "roughjs/bin/math";
import nanoid from "nanoid";
import { Point } from "../types";
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
import {
ExcalidrawElement,
ExcalidrawTextElement,
ExcalidrawLinearElement,
ExcalidrawGenericElement,
} from "../element/types";
import { measureText } from "../utils";
export function newElement(
type: string,
x: number,
y: number,
strokeColor: string,
backgroundColor: string,
fillStyle: string,
strokeWidth: number,
roughness: number,
opacity: number,
width = 0,
height = 0,
type ElementConstructorOpts = {
x: ExcalidrawGenericElement["x"];
y: ExcalidrawGenericElement["y"];
strokeColor: ExcalidrawGenericElement["strokeColor"];
backgroundColor: ExcalidrawGenericElement["backgroundColor"];
fillStyle: ExcalidrawGenericElement["fillStyle"];
strokeWidth: ExcalidrawGenericElement["strokeWidth"];
roughness: ExcalidrawGenericElement["roughness"];
opacity: ExcalidrawGenericElement["opacity"];
width?: ExcalidrawGenericElement["width"];
height?: ExcalidrawGenericElement["height"];
};
function _newElementBase<T extends ExcalidrawElement>(
type: T["type"],
{
x,
y,
strokeColor,
backgroundColor,
fillStyle,
strokeWidth,
roughness,
opacity,
width = 0,
height = 0,
...rest
}: ElementConstructorOpts & Partial<ExcalidrawGenericElement>,
) {
const element = {
id: nanoid(),
return {
id: rest.id || nanoid(),
type,
x,
y,
@ -31,29 +51,36 @@ export function newElement(
strokeWidth,
roughness,
opacity,
seed: randomSeed(),
points: [] as readonly Point[],
version: 1,
versionNonce: 0,
isDeleted: false,
seed: rest.seed ?? randomSeed(),
version: rest.version || 1,
versionNonce: rest.versionNonce ?? 0,
isDeleted: rest.isDeleted ?? false,
};
return element;
}
export function newElement(
opts: {
type: ExcalidrawGenericElement["type"];
} & ElementConstructorOpts,
): ExcalidrawGenericElement {
return _newElementBase<ExcalidrawGenericElement>(opts.type, opts);
}
export function newTextElement(
element: ExcalidrawElement,
text: string,
font: string,
) {
opts: {
text: string;
font: string;
} & ElementConstructorOpts,
): ExcalidrawTextElement {
const { text, font } = opts;
const metrics = measureText(text, font);
const textElement: ExcalidrawTextElement = {
...element,
type: "text",
const textElement = {
..._newElementBase<ExcalidrawTextElement>("text", opts),
text: text,
font: font,
// Center the text
x: element.x - metrics.width / 2,
y: element.y - metrics.height / 2,
x: opts.x - metrics.width / 2,
y: opts.y - metrics.height / 2,
width: metrics.width,
height: metrics.height,
baseline: metrics.baseline,
@ -62,6 +89,17 @@ export function newTextElement(
return textElement;
}
export function newLinearElement(
opts: {
type: "arrow" | "line";
} & ElementConstructorOpts,
): ExcalidrawLinearElement {
return {
..._newElementBase<ExcalidrawLinearElement>(opts.type, opts),
points: [],
};
}
// Simplified deep clone for the purpose of cloning ExcalidrawElement only
// (doesn't clone Date, RegExp, Map, Set, Typed arrays etc.)
//
@ -100,11 +138,15 @@ function _duplicateElement(val: any, depth: number = 0) {
return val;
}
export function duplicateElement(
element: ReturnType<typeof newElement>,
): ReturnType<typeof newElement> {
const copy = _duplicateElement(element);
export function duplicateElement<TElement extends Mutable<ExcalidrawElement>>(
element: TElement,
overrides?: Partial<TElement>,
): TElement {
let copy: TElement = _duplicateElement(element);
copy.id = nanoid();
copy.seed = randomSeed();
if (overrides) {
copy = Object.assign(copy, overrides);
}
return copy;
}