2025-03-12 15:23:31 +01:00
|
|
|
import { isInvisiblySmallElement } from "./sizeHelpers";
|
|
|
|
import { isLinearElementType } from "./typeChecks";
|
|
|
|
|
2024-05-08 14:21:50 +05:30
|
|
|
import type {
|
2020-04-11 17:10:56 +01:00
|
|
|
ExcalidrawElement,
|
|
|
|
NonDeletedExcalidrawElement,
|
|
|
|
NonDeleted,
|
|
|
|
} from "./types";
|
2020-03-14 20:46:57 -07:00
|
|
|
|
2024-03-08 22:29:19 +01:00
|
|
|
/**
|
|
|
|
* @deprecated unsafe, use hashElementsVersion instead
|
|
|
|
*/
|
2020-10-04 11:12:47 -07:00
|
|
|
export const getSceneVersion = (elements: readonly ExcalidrawElement[]) =>
|
2020-05-20 16:21:37 +03:00
|
|
|
elements.reduce((acc, el) => acc + el.version, 0);
|
2020-03-14 20:46:57 -07:00
|
|
|
|
2024-03-08 22:29:19 +01:00
|
|
|
/**
|
|
|
|
* Hashes elements' versionNonce (using djb2 algo). Order of elements matters.
|
|
|
|
*/
|
|
|
|
export const hashElementsVersion = (
|
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
|
): number => {
|
|
|
|
let hash = 5381;
|
|
|
|
for (let i = 0; i < elements.length; i++) {
|
|
|
|
hash = (hash << 5) + hash + elements[i].versionNonce;
|
|
|
|
}
|
|
|
|
return hash >>> 0; // Ensure unsigned 32-bit integer
|
|
|
|
};
|
|
|
|
|
|
|
|
// string hash function (using djb2). Not cryptographically secure, use only
|
|
|
|
// for versioning and such.
|
|
|
|
export const hashString = (s: string): number => {
|
|
|
|
let hash: number = 5381;
|
|
|
|
for (let i = 0; i < s.length; i++) {
|
|
|
|
const char: number = s.charCodeAt(i);
|
|
|
|
hash = (hash << 5) + hash + char;
|
|
|
|
}
|
|
|
|
return hash >>> 0; // Ensure unsigned 32-bit integer
|
|
|
|
};
|
|
|
|
|
2021-04-19 17:29:13 +02:00
|
|
|
export const getVisibleElements = (elements: readonly ExcalidrawElement[]) =>
|
|
|
|
elements.filter(
|
|
|
|
(el) => !el.isDeleted && !isInvisiblySmallElement(el),
|
|
|
|
) as readonly NonDeletedExcalidrawElement[];
|
|
|
|
|
2023-11-23 23:07:53 +01:00
|
|
|
export const getNonDeletedElements = <T extends ExcalidrawElement>(
|
|
|
|
elements: readonly T[],
|
2023-06-15 00:42:01 +08:00
|
|
|
) =>
|
2023-11-23 23:07:53 +01:00
|
|
|
elements.filter((element) => !element.isDeleted) as readonly NonDeleted<T>[];
|
2023-06-15 00:42:01 +08:00
|
|
|
|
2020-05-20 16:21:37 +03:00
|
|
|
export const isNonDeletedElement = <T extends ExcalidrawElement>(
|
2020-04-11 17:10:56 +01:00
|
|
|
element: T,
|
2020-05-20 16:21:37 +03:00
|
|
|
): element is NonDeleted<T> => !element.isDeleted;
|
2020-11-11 15:55:22 +01:00
|
|
|
|
|
|
|
const _clearElements = (
|
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
|
): ExcalidrawElement[] =>
|
|
|
|
getNonDeletedElements(elements).map((element) =>
|
|
|
|
isLinearElementType(element.type)
|
|
|
|
? { ...element, lastCommittedPoint: null }
|
|
|
|
: element,
|
|
|
|
);
|
|
|
|
|
2021-10-21 22:05:48 +02:00
|
|
|
export const clearElementsForDatabase = (
|
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
|
) => _clearElements(elements);
|
|
|
|
|
2020-11-11 15:55:22 +01:00
|
|
|
export const clearElementsForExport = (
|
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
|
) => _clearElements(elements);
|
|
|
|
|
|
|
|
export const clearElementsForLocalStorage = (
|
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
|
) => _clearElements(elements);
|