Skip to content

Commit

Permalink
Merge pull request #500 from mynaparrot/improve
Browse files Browse the repository at this point in the history
update reconciliation logic
  • Loading branch information
jibon57 authored Aug 20, 2023
2 parents a1f8d36 + 9a9c302 commit 4d5980b
Showing 1 changed file with 26 additions and 36 deletions.
62 changes: 26 additions & 36 deletions src/components/whiteboard/helpers/reconciliation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export type BroadcastedExcalidrawElement = ExcalidrawElement & {
[PRECEDING_ELEMENT_KEY]?: string;
};

export const arrayToMapWithIndex = <T extends { id: string }>(
elements: readonly T[],
) =>
elements.reduce((acc, element: T, idx) => {
acc.set(element.id, [element, idx]);
return acc;
}, new Map<string, [element: T, index: number]>());

const shouldDiscardRemoteElement = (
localAppState: AppState,
local: ExcalidrawElement | undefined,
Expand All @@ -36,30 +44,13 @@ const shouldDiscardRemoteElement = (
return false;
};

const getElementsMapWithIndex = <T extends ExcalidrawElement>(
elements: readonly T[],
) =>
elements.reduce(
(
acc: {
[key: string]: [element: T, index: number] | undefined;
},
element: T,
idx,
) => {
acc[element.id] = [element, idx];
return acc;
},
{},
);

export const reconcileElements = (
localElements: readonly ExcalidrawElement[],
remoteElements: readonly BroadcastedExcalidrawElement[],
localAppState: AppState,
): ReconciledElements => {
const localElementsData =
getElementsMapWithIndex<ExcalidrawElement>(localElements);
arrayToMapWithIndex<ExcalidrawElement>(localElements);

const reconciledElements: ExcalidrawElement[] = localElements.slice();

Expand All @@ -72,7 +63,7 @@ export const reconcileElements = (
for (const remoteElement of remoteElements) {
remoteElementIdx++;

const local = localElementsData[remoteElement.id];
const local = localElementsData.get(remoteElement.id);

if (shouldDiscardRemoteElement(localAppState, local?.[0], remoteElement)) {
if (remoteElement[PRECEDING_ELEMENT_KEY]) {
Expand All @@ -84,7 +75,7 @@ export const reconcileElements = (

// Mark duplicate for removal as it'll be replaced with the remote element
if (local) {
// Unless the ramote and local elements are the same element in which case
// Unless the remote and local elements are the same element in which case
// we need to keep it as we'd otherwise discard it from the resulting
// array.
if (local[0] === remoteElement) {
Expand All @@ -108,61 +99,60 @@ export const reconcileElements = (
offset++;
if (cursor === 0) {
reconciledElements.unshift(remoteElement);
localElementsData[remoteElement.id] = [
localElementsData.set(remoteElement.id, [
remoteElement,
cursor - offset,
];
]);
} else {
reconciledElements.splice(cursor + 1, 0, remoteElement);
localElementsData[remoteElement.id] = [
localElementsData.set(remoteElement.id, [
remoteElement,
cursor + 1 - offset,
];
]);
cursor++;
}
} else {
let idx = localElementsData[parent]
? //eslint-disable-next-line
localElementsData[parent]![1]
let idx = localElementsData.has(parent)
? localElementsData.get(parent)![1]
: null;
if (idx != null) {
idx += offset;
}
if (idx != null && idx >= cursor) {
reconciledElements.splice(idx + 1, 0, remoteElement);
offset++;
localElementsData[remoteElement.id] = [
localElementsData.set(remoteElement.id, [
remoteElement,
idx + 1 - offset,
];
]);
cursor = idx + 1;
} else if (idx != null) {
reconciledElements.splice(cursor + 1, 0, remoteElement);
offset++;
localElementsData[remoteElement.id] = [
localElementsData.set(remoteElement.id, [
remoteElement,
cursor + 1 - offset,
];
]);
cursor++;
} else {
reconciledElements.push(remoteElement);
localElementsData[remoteElement.id] = [
localElementsData.set(remoteElement.id, [
remoteElement,
reconciledElements.length - 1 - offset,
];
]);
}
}
// no parent z-index information, local element exists → replace in place
} else if (local) {
reconciledElements[local[1]] = remoteElement;
localElementsData[remoteElement.id] = [remoteElement, local[1]];
localElementsData.set(remoteElement.id, [remoteElement, local[1]]);
// otherwise push to the end
} else {
reconciledElements.push(remoteElement);
localElementsData[remoteElement.id] = [
localElementsData.set(remoteElement.id, [
remoteElement,
reconciledElements.length - 1 - offset,
];
]);
}
}

Expand Down

0 comments on commit 4d5980b

Please sign in to comment.