batch clipping
This commit is contained in:
parent
71ba0a3f26
commit
a30e46b756
@ -593,8 +593,9 @@ export const isElementInFrame = (
|
||||
element: ExcalidrawElement,
|
||||
allElements: ExcalidrawElementsIncludingDeleted,
|
||||
appState: StaticCanvasAppState,
|
||||
targetFrame?: ExcalidrawFrameElement,
|
||||
) => {
|
||||
const frame = getTargetFrame(element, appState);
|
||||
const frame = targetFrame ?? getTargetFrame(element, appState);
|
||||
const _element = isTextElement(element)
|
||||
? getContainerElement(element) || element
|
||||
: element;
|
||||
|
@ -357,6 +357,36 @@ const renderLinearElementPointHighlight = (
|
||||
context.restore();
|
||||
};
|
||||
|
||||
const getContiguousElements = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: StaticCanvasAppState,
|
||||
) => {
|
||||
const contiguousElementsArray: ExcalidrawElement[][] = [];
|
||||
|
||||
let previousFrameId: string | null | undefined = null;
|
||||
const contiguousElements: ExcalidrawElement[] = [];
|
||||
for (const element of elements) {
|
||||
const frameId = element.frameId || appState.frameToHighlight?.id;
|
||||
|
||||
if (previousFrameId !== frameId) {
|
||||
if (contiguousElements.length > 0) {
|
||||
contiguousElementsArray.push([...contiguousElements]);
|
||||
contiguousElements.length = 0;
|
||||
}
|
||||
|
||||
previousFrameId = frameId;
|
||||
}
|
||||
|
||||
contiguousElements.push(element);
|
||||
}
|
||||
|
||||
if (contiguousElements.length > 0) {
|
||||
contiguousElementsArray.push([...contiguousElements]);
|
||||
}
|
||||
|
||||
return contiguousElementsArray;
|
||||
};
|
||||
|
||||
const frameClip = (
|
||||
frame: ExcalidrawFrameElement,
|
||||
context: CanvasRenderingContext2D,
|
||||
@ -941,45 +971,25 @@ const _renderStaticScene = ({
|
||||
);
|
||||
}
|
||||
|
||||
// Paint visible elements
|
||||
visibleElements
|
||||
.filter((el) => !isEmbeddableOrLabel(el))
|
||||
.forEach((element) => {
|
||||
// Paint visible elements with embeddables on top
|
||||
const visibleNonEmbeddableOrLabelElements = visibleElements.filter(
|
||||
(el) => !isEmbeddableOrLabel(el),
|
||||
);
|
||||
|
||||
const visibleEmbeddableOrLabelElements = visibleElements.filter((el) =>
|
||||
isEmbeddableOrLabel(el),
|
||||
);
|
||||
|
||||
const contiguousElementsArray = [
|
||||
...getContiguousElements(visibleNonEmbeddableOrLabelElements, appState),
|
||||
...getContiguousElements(visibleEmbeddableOrLabelElements, appState),
|
||||
];
|
||||
|
||||
const renderContiguousElements = (
|
||||
contiguousElements: ExcalidrawElement[],
|
||||
) => {
|
||||
for (const element of contiguousElements) {
|
||||
try {
|
||||
const frameId = element.frameId || appState.frameToHighlight?.id;
|
||||
|
||||
if (
|
||||
frameId &&
|
||||
appState.frameRendering.enabled &&
|
||||
appState.frameRendering.clip
|
||||
) {
|
||||
context.save();
|
||||
|
||||
const frame = getTargetFrame(element, appState);
|
||||
|
||||
// TODO do we need to check isElementInFrame here?
|
||||
if (frame && isElementInFrame(element, elements, appState)) {
|
||||
frameClip(frame, context, renderConfig, appState);
|
||||
}
|
||||
renderElement(element, rc, context, renderConfig, appState);
|
||||
context.restore();
|
||||
} else {
|
||||
renderElement(element, rc, context, renderConfig, appState);
|
||||
}
|
||||
if (!isExporting) {
|
||||
renderLinkIcon(element, context, appState);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
// render embeddables on top
|
||||
visibleElements
|
||||
.filter((el) => isEmbeddableOrLabel(el))
|
||||
.forEach((element) => {
|
||||
try {
|
||||
const render = () => {
|
||||
renderElement(element, rc, context, renderConfig, appState);
|
||||
|
||||
if (
|
||||
@ -991,36 +1001,39 @@ const _renderStaticScene = ({
|
||||
const label = createPlaceholderEmbeddableLabel(element);
|
||||
renderElement(label, rc, context, renderConfig, appState);
|
||||
}
|
||||
|
||||
if (!isExporting) {
|
||||
renderLinkIcon(element, context, appState);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
// - when exporting the whole canvas, we DO NOT apply clipping
|
||||
// - when we are exporting a particular frame, apply clipping
|
||||
// if the containing frame is not selected, apply clipping
|
||||
const frameId = element.frameId || appState.frameToHighlight?.id;
|
||||
|
||||
for (const contiguousElements of contiguousElementsArray) {
|
||||
const firstElement = contiguousElements[0];
|
||||
|
||||
if (firstElement) {
|
||||
context.save();
|
||||
const frameId = firstElement.frameId || appState.frameToHighlight?.id;
|
||||
|
||||
if (
|
||||
frameId &&
|
||||
appState.frameRendering.enabled &&
|
||||
appState.frameRendering.clip
|
||||
) {
|
||||
context.save();
|
||||
const frame = getTargetFrame(firstElement, appState);
|
||||
|
||||
const frame = getTargetFrame(element, appState);
|
||||
|
||||
if (frame && isElementInFrame(element, elements, appState)) {
|
||||
if (frame && isElementInFrame(firstElement, elements, appState)) {
|
||||
frameClip(frame, context, renderConfig, appState);
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
renderContiguousElements(contiguousElements);
|
||||
context.restore();
|
||||
} else {
|
||||
render();
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** throttled to animation framerate */
|
||||
|
Loading…
x
Reference in New Issue
Block a user