batch clipping
This commit is contained in:
parent
71ba0a3f26
commit
a30e46b756
@ -593,8 +593,9 @@ export const isElementInFrame = (
|
|||||||
element: ExcalidrawElement,
|
element: ExcalidrawElement,
|
||||||
allElements: ExcalidrawElementsIncludingDeleted,
|
allElements: ExcalidrawElementsIncludingDeleted,
|
||||||
appState: StaticCanvasAppState,
|
appState: StaticCanvasAppState,
|
||||||
|
targetFrame?: ExcalidrawFrameElement,
|
||||||
) => {
|
) => {
|
||||||
const frame = getTargetFrame(element, appState);
|
const frame = targetFrame ?? getTargetFrame(element, appState);
|
||||||
const _element = isTextElement(element)
|
const _element = isTextElement(element)
|
||||||
? getContainerElement(element) || element
|
? getContainerElement(element) || element
|
||||||
: element;
|
: element;
|
||||||
|
@ -357,6 +357,36 @@ const renderLinearElementPointHighlight = (
|
|||||||
context.restore();
|
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 = (
|
const frameClip = (
|
||||||
frame: ExcalidrawFrameElement,
|
frame: ExcalidrawFrameElement,
|
||||||
context: CanvasRenderingContext2D,
|
context: CanvasRenderingContext2D,
|
||||||
@ -941,86 +971,69 @@ const _renderStaticScene = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paint visible elements
|
// Paint visible elements with embeddables on top
|
||||||
visibleElements
|
const visibleNonEmbeddableOrLabelElements = visibleElements.filter(
|
||||||
.filter((el) => !isEmbeddableOrLabel(el))
|
(el) => !isEmbeddableOrLabel(el),
|
||||||
.forEach((element) => {
|
);
|
||||||
|
|
||||||
|
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 {
|
try {
|
||||||
const frameId = element.frameId || appState.frameToHighlight?.id;
|
renderElement(element, rc, context, renderConfig, appState);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
frameId &&
|
isEmbeddableElement(element) &&
|
||||||
appState.frameRendering.enabled &&
|
(isExporting || !element.validated) &&
|
||||||
appState.frameRendering.clip
|
element.width &&
|
||||||
|
element.height
|
||||||
) {
|
) {
|
||||||
context.save();
|
const label = createPlaceholderEmbeddableLabel(element);
|
||||||
|
renderElement(label, rc, context, renderConfig, appState);
|
||||||
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) {
|
if (!isExporting) {
|
||||||
renderLinkIcon(element, context, appState);
|
renderLinkIcon(element, context, appState);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// render embeddables on top
|
for (const contiguousElements of contiguousElementsArray) {
|
||||||
visibleElements
|
const firstElement = contiguousElements[0];
|
||||||
.filter((el) => isEmbeddableOrLabel(el))
|
|
||||||
.forEach((element) => {
|
|
||||||
try {
|
|
||||||
const render = () => {
|
|
||||||
renderElement(element, rc, context, renderConfig, appState);
|
|
||||||
|
|
||||||
if (
|
if (firstElement) {
|
||||||
isEmbeddableElement(element) &&
|
context.save();
|
||||||
(isExporting || !element.validated) &&
|
const frameId = firstElement.frameId || appState.frameToHighlight?.id;
|
||||||
element.width &&
|
|
||||||
element.height
|
|
||||||
) {
|
|
||||||
const label = createPlaceholderEmbeddableLabel(element);
|
|
||||||
renderElement(label, rc, context, renderConfig, appState);
|
|
||||||
}
|
|
||||||
if (!isExporting) {
|
|
||||||
renderLinkIcon(element, context, appState);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// - 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;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
frameId &&
|
frameId &&
|
||||||
appState.frameRendering.enabled &&
|
appState.frameRendering.enabled &&
|
||||||
appState.frameRendering.clip
|
appState.frameRendering.clip
|
||||||
) {
|
) {
|
||||||
context.save();
|
const frame = getTargetFrame(firstElement, appState);
|
||||||
|
|
||||||
const frame = getTargetFrame(element, appState);
|
if (frame && isElementInFrame(firstElement, elements, appState)) {
|
||||||
|
frameClip(frame, context, renderConfig, appState);
|
||||||
if (frame && isElementInFrame(element, elements, appState)) {
|
|
||||||
frameClip(frame, context, renderConfig, appState);
|
|
||||||
}
|
|
||||||
render();
|
|
||||||
context.restore();
|
|
||||||
} else {
|
|
||||||
render();
|
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
renderContiguousElements(contiguousElements);
|
||||||
|
context.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** throttled to animation framerate */
|
/** throttled to animation framerate */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user