123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- import { ExcalidrawElement } from "./types";
- import { invalidateShapeForElement } from "../renderer/renderElement";
- import Scene from "../scene/Scene";
- import { getSizeFromPoints } from "../points";
- import { randomInteger } from "../random";
- import { Point } from "../types";
- import { getUpdatedTimestamp } from "../utils";
- import { Mutable } from "../utility-types";
- type ElementUpdate<TElement extends ExcalidrawElement> = Omit<
- Partial<TElement>,
- "id" | "version" | "versionNonce"
- >;
- // 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. Note: this will trigger the component to update. Make sure you
- // are calling it either from a React event handler or within unstable_batchedUpdates().
- export const mutateElement = <TElement extends Mutable<ExcalidrawElement>>(
- element: TElement,
- updates: ElementUpdate<TElement>,
- informMutation = true,
- ): TElement => {
- let didChange = false;
- // casting to any because can't use `in` operator
- // (see https://github.com/microsoft/TypeScript/issues/21732)
- const { points, fileId } = updates as any;
- if (typeof points !== "undefined") {
- updates = { ...getSizeFromPoints(points), ...updates };
- }
- for (const key in updates) {
- const value = (updates as any)[key];
- if (typeof value !== "undefined") {
- if (
- (element as any)[key] === value &&
- // if object, always update because its attrs could have changed
- // (except for specific keys we handle below)
- (typeof value !== "object" ||
- value === null ||
- key === "groupIds" ||
- key === "scale")
- ) {
- continue;
- }
- if (key === "scale") {
- const prevScale = (element as any)[key];
- const nextScale = value;
- if (prevScale[0] === nextScale[0] && prevScale[1] === nextScale[1]) {
- continue;
- }
- } else if (key === "points") {
- const prevPoints = (element as any)[key];
- const nextPoints = value;
- if (prevPoints.length === nextPoints.length) {
- let didChangePoints = false;
- let index = prevPoints.length;
- while (--index) {
- const prevPoint: Point = prevPoints[index];
- const nextPoint: Point = nextPoints[index];
- if (
- prevPoint[0] !== nextPoint[0] ||
- prevPoint[1] !== nextPoint[1]
- ) {
- didChangePoints = true;
- break;
- }
- }
- if (!didChangePoints) {
- continue;
- }
- }
- }
- (element as any)[key] = value;
- didChange = true;
- }
- }
- if (!didChange) {
- return element;
- }
- if (
- typeof updates.height !== "undefined" ||
- typeof updates.width !== "undefined" ||
- typeof fileId != "undefined" ||
- typeof points !== "undefined"
- ) {
- invalidateShapeForElement(element);
- }
- element.version++;
- element.versionNonce = randomInteger();
- element.updated = getUpdatedTimestamp();
- if (informMutation) {
- Scene.getScene(element)?.informMutation();
- }
- return element;
- };
- export const newElementWith = <TElement extends ExcalidrawElement>(
- element: TElement,
- updates: ElementUpdate<TElement>,
- ): TElement => {
- let didChange = false;
- for (const key in updates) {
- const value = (updates as any)[key];
- if (typeof value !== "undefined") {
- if (
- (element as any)[key] === value &&
- // if object, always update because its attrs could have changed
- (typeof value !== "object" || value === null)
- ) {
- continue;
- }
- didChange = true;
- }
- }
- if (!didChange) {
- return element;
- }
- return {
- ...element,
- ...updates,
- updated: getUpdatedTimestamp(),
- version: element.version + 1,
- versionNonce: randomInteger(),
- };
- };
- /**
- * Mutates element, bumping `version`, `versionNonce`, and `updated`.
- *
- * NOTE: does not trigger re-render.
- */
- export const bumpVersion = (
- element: Mutable<ExcalidrawElement>,
- version?: ExcalidrawElement["version"],
- ) => {
- element.version = (version ?? element.version) + 1;
- element.versionNonce = randomInteger();
- element.updated = getUpdatedTimestamp();
- return element;
- };
|