fix: No more debounced refresh() for subtypes.

This commit is contained in:
Daniel J. Geiger 2023-04-28 09:47:03 -05:00
parent 91fe07d9c5
commit ab3467973f
6 changed files with 31 additions and 71 deletions

View File

@ -361,7 +361,6 @@ export const useExcalidrawSetAppState = () =>
export const useExcalidrawActionManager = () => export const useExcalidrawActionManager = () =>
useContext(ExcalidrawActionManagerContext); useContext(ExcalidrawActionManagerContext);
let refreshTimer = 0;
let didTapTwice: boolean = false; let didTapTwice: boolean = false;
let tappedTwiceTimer = 0; let tappedTwiceTimer = 0;
let cursorX = 0; let cursorX = 0;
@ -1388,20 +1387,6 @@ class App extends React.Component<AppProps, AppState> {
cursorButton[socketId] = user.button; cursorButton[socketId] = user.button;
}); });
const refresh = () => {
// If a scene refresh is cued, restart the countdown.
// This way we are not calling this.setState({}) once per
// ExcalidrawElement. The countdown improves performance
// when there are large numbers of ExcalidrawElements
// executing this refresh() callback.
if (refreshTimer !== 0) {
window.clearTimeout(refreshTimer);
}
refreshTimer = window.setTimeout(() => {
this.refresh();
window.clearTimeout(refreshTimer);
}, 50);
};
const renderingElements = this.scene const renderingElements = this.scene
.getNonDeletedElements() .getNonDeletedElements()
.filter((element) => { .filter((element) => {
@ -1449,7 +1434,6 @@ class App extends React.Component<AppProps, AppState> {
imageCache: this.imageCache, imageCache: this.imageCache,
isExporting: false, isExporting: false,
renderScrollbars: !this.device.isMobile, renderScrollbars: !this.device.isMobile,
renderCb: refresh,
}, },
callback: ({ atLeastOneVisibleElement, scrollBars }) => { callback: ({ atLeastOneVisibleElement, scrollBars }) => {
if (scrollBars) { if (scrollBars) {

View File

@ -22,6 +22,7 @@ import {
} from "../../../../element/types"; } from "../../../../element/types";
import { newElementWith } from "../../../../element/mutateElement"; import { newElementWith } from "../../../../element/mutateElement";
import { getElementAbsoluteCoords } from "../../../../element/bounds"; import { getElementAbsoluteCoords } from "../../../../element/bounds";
import Scene from "../../../../scene/Scene";
// Imports for actions // Imports for actions
import { t, registerAuxLangData } from "../../../../i18n"; import { t, registerAuxLangData } from "../../../../i18n";
@ -908,7 +909,7 @@ const measureMathElement = function (element, next) {
return metrics; return metrics;
} as SubtypeMethods["measureText"]; } as SubtypeMethods["measureText"];
const renderMathElement = function (element, context, renderCb) { const renderMathElement = function (element, context) {
ensureMathElement(element); ensureMathElement(element);
const isMathJaxLoaded = mathJaxLoaded; const isMathJaxLoaded = mathJaxLoaded;
const _element = element as NonDeleted<ExcalidrawMathElement>; const _element = element as NonDeleted<ExcalidrawMathElement>;
@ -996,9 +997,7 @@ const renderMathElement = function (element, context, renderCb) {
if (isMathJaxLoaded) { if (isMathJaxLoaded) {
imageCache[imgKey] = img; imageCache[imgKey] = img;
} }
if (renderCb) { Scene.getScene(element)?.informMutation();
renderCb();
}
}; };
img.src = reader.result as string; img.src = reader.result as string;
}, },

View File

@ -257,7 +257,7 @@ const drawElementOnCanvas = (
context.globalAlpha = element.opacity / 100; context.globalAlpha = element.opacity / 100;
const map = getSubtypeMethods(element.subtype); const map = getSubtypeMethods(element.subtype);
if (map?.render) { if (map?.render) {
map.render(element, context, renderConfig.renderCb); map.render(element, context);
context.globalAlpha = 1; context.globalAlpha = 1;
return; return;
} }

View File

@ -11,7 +11,6 @@ import {
getInitializedImageElements, getInitializedImageElements,
updateImageCache, updateImageCache,
} from "../element/image"; } from "../element/image";
import { ensureSubtypesLoadedForElements } from "../subtypes";
export const SVG_EXPORT_TAG = `<!-- svg-source:excalidraw -->`; export const SVG_EXPORT_TAG = `<!-- svg-source:excalidraw -->`;
@ -52,48 +51,30 @@ export const exportToCanvas = async (
files, files,
}); });
let refreshTimer = 0; renderScene({
elements,
const renderConfig = { appState,
viewBackgroundColor: exportBackground ? viewBackgroundColor : null, scale,
scrollX: -minX + exportPadding, rc: rough.canvas(canvas),
scrollY: -minY + exportPadding, canvas,
zoom: defaultAppState.zoom, renderConfig: {
remotePointerViewportCoords: {}, viewBackgroundColor: exportBackground ? viewBackgroundColor : null,
remoteSelectedElementIds: {}, scrollX: -minX + exportPadding,
shouldCacheIgnoreZoom: false, scrollY: -minY + exportPadding,
remotePointerUsernames: {}, zoom: defaultAppState.zoom,
remotePointerUserStates: {}, remotePointerViewportCoords: {},
theme: appState.exportWithDarkMode ? "dark" : "light", remoteSelectedElementIds: {},
imageCache, shouldCacheIgnoreZoom: false,
renderScrollbars: false, remotePointerUsernames: {},
renderSelection: false, remotePointerUserStates: {},
renderGrid: false, theme: appState.exportWithDarkMode ? "dark" : "light",
isExporting: true, imageCache,
renderCb: () => { renderScrollbars: false,
if (refreshTimer !== 0) { renderSelection: false,
window.clearTimeout(refreshTimer); renderGrid: false,
} isExporting: true,
refreshTimer = window.setTimeout(() => {
renderConfig.renderCb = () => {};
window.clearTimeout(refreshTimer);
// Here instead of setState({}), call renderScene() again
render();
}, 50);
}, },
}; });
const render = () => {
renderScene({
elements,
appState,
scale,
rc: rough.canvas(canvas),
canvas,
renderConfig,
});
};
render();
return canvas; return canvas;
}; };
@ -187,12 +168,10 @@ export const exportToSvg = async (
} }
const rsvg = rough.svg(svgRoot); const rsvg = rough.svg(svgRoot);
await ensureSubtypesLoadedForElements(elements, () => { renderSceneToSvg(elements, rsvg, svgRoot, files || {}, {
renderSceneToSvg(elements, rsvg, svgRoot, files || {}, { offsetX: -minX + exportPadding,
offsetX: -minX + exportPadding, offsetY: -minY + exportPadding,
offsetY: -minY + exportPadding, exportWithDarkMode: appState.exportWithDarkMode,
exportWithDarkMode: appState.exportWithDarkMode,
});
}); });
return svgRoot; return svgRoot;

View File

@ -24,7 +24,6 @@ export type RenderConfig = {
renderScrollbars?: boolean; renderScrollbars?: boolean;
renderSelection?: boolean; renderSelection?: boolean;
renderGrid?: boolean; renderGrid?: boolean;
renderCb?: () => void;
/** when exporting the behavior is slightly different (e.g. we can't use /** when exporting the behavior is slightly different (e.g. we can't use
CSS filters), and we disable render optimizations for best output */ CSS filters), and we disable render optimizations for best output */
isExporting: boolean; isExporting: boolean;

View File

@ -241,7 +241,6 @@ export type SubtypeMethods = {
render: ( render: (
element: NonDeleted<ExcalidrawElement>, element: NonDeleted<ExcalidrawElement>,
context: CanvasRenderingContext2D, context: CanvasRenderingContext2D,
renderCb?: () => void,
) => void; ) => void;
renderSvg: ( renderSvg: (
svgRoot: SVGElement, svgRoot: SVGElement,