fix: disable render throttling by default & during resize (#5451)
This commit is contained in:
parent
df14c69977
commit
5bc40402a6
@ -166,7 +166,7 @@ import {
|
||||
isAndroid,
|
||||
} from "../keys";
|
||||
import { distance2d, getGridPoint, isPathALoop } from "../math";
|
||||
import { renderSceneThrottled } from "../renderer/renderScene";
|
||||
import { renderScene } from "../renderer/renderScene";
|
||||
import { invalidateShapeForElement } from "../renderer/renderElement";
|
||||
import {
|
||||
calculateScrollCenter,
|
||||
@ -286,6 +286,10 @@ let currentScrollBars: ScrollBars = { horizontal: null, vertical: null };
|
||||
let touchTimeout = 0;
|
||||
let invalidateContextMenu = false;
|
||||
|
||||
// remove this hack when we can sync render & resizeObserver (state update)
|
||||
// to rAF. See #5439
|
||||
let THROTTLE_NEXT_RENDER = true;
|
||||
|
||||
let lastPointerUp: ((event: any) => void) | null = null;
|
||||
const gesture: Gesture = {
|
||||
pointers: new Map(),
|
||||
@ -858,6 +862,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
if ("ResizeObserver" in window && this.excalidrawContainerRef?.current) {
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
THROTTLE_NEXT_RENDER = false;
|
||||
// recompute device dimensions state
|
||||
// ---------------------------------------------------------------------
|
||||
this.refreshDeviceState(this.excalidrawContainerRef.current!);
|
||||
@ -1221,7 +1226,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
);
|
||||
});
|
||||
|
||||
renderSceneThrottled(
|
||||
renderScene(
|
||||
renderingElements,
|
||||
this.state,
|
||||
this.state.selectionElement,
|
||||
@ -1259,8 +1264,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
this.scheduleImageRefresh();
|
||||
},
|
||||
THROTTLE_NEXT_RENDER && window.EXCALIDRAW_THROTTLE_RENDER === true,
|
||||
);
|
||||
|
||||
if (!THROTTLE_NEXT_RENDER) {
|
||||
THROTTLE_NEXT_RENDER = true;
|
||||
}
|
||||
|
||||
this.history.record(this.state, this.scene.getElementsIncludingDeleted());
|
||||
|
||||
// Do not notify consumers if we're still loading the scene. Among other
|
||||
|
@ -83,6 +83,8 @@ import { jotaiStore, useAtomWithInitialValue } from "../jotai";
|
||||
import { reconcileElements } from "./collab/reconciliation";
|
||||
import { parseLibraryTokensFromUrl, useHandleLibrary } from "../data/library";
|
||||
|
||||
window.EXCALIDRAW_THROTTLE_RENDER = true;
|
||||
|
||||
const isExcalidrawPlusSignedUser = document.cookie.includes(
|
||||
COOKIES.AUTH_STATE_COOKIE,
|
||||
);
|
||||
|
1
src/global.d.ts
vendored
1
src/global.d.ts
vendored
@ -14,6 +14,7 @@ interface Window {
|
||||
__EXCALIDRAW_SHA__: string | undefined;
|
||||
EXCALIDRAW_ASSET_PATH: string | undefined;
|
||||
EXCALIDRAW_EXPORT_SOURCE: string;
|
||||
EXCALIDRAW_THROTTLE_RENDER: boolean | undefined;
|
||||
gtag: Function;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ const renderLinearPointHandles = (
|
||||
context.restore();
|
||||
};
|
||||
|
||||
export const renderScene = (
|
||||
export const _renderScene = (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
appState: AppState,
|
||||
selectionElement: NonDeletedExcalidrawElement | null,
|
||||
@ -572,8 +572,7 @@ export const renderScene = (
|
||||
return { atLeastOneVisibleElement: visibleElements.length > 0, scrollBars };
|
||||
};
|
||||
|
||||
/** renderScene throttled to animation framerate */
|
||||
export const renderSceneThrottled = throttleRAF(
|
||||
const renderSceneThrottled = throttleRAF(
|
||||
(
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
appState: AppState,
|
||||
@ -582,9 +581,9 @@ export const renderSceneThrottled = throttleRAF(
|
||||
rc: RoughCanvas,
|
||||
canvas: HTMLCanvasElement,
|
||||
renderConfig: RenderConfig,
|
||||
callback?: (data: ReturnType<typeof renderScene>) => void,
|
||||
callback?: (data: ReturnType<typeof _renderScene>) => void,
|
||||
) => {
|
||||
const ret = renderScene(
|
||||
const ret = _renderScene(
|
||||
elements,
|
||||
appState,
|
||||
selectionElement,
|
||||
@ -598,6 +597,46 @@ export const renderSceneThrottled = throttleRAF(
|
||||
{ trailing: true },
|
||||
);
|
||||
|
||||
/** renderScene throttled to animation framerate */
|
||||
export const renderScene = <T extends boolean = false>(
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
appState: AppState,
|
||||
selectionElement: NonDeletedExcalidrawElement | null,
|
||||
scale: number,
|
||||
rc: RoughCanvas,
|
||||
canvas: HTMLCanvasElement,
|
||||
renderConfig: RenderConfig,
|
||||
callback?: (data: ReturnType<typeof _renderScene>) => void,
|
||||
/** Whether to throttle rendering. Defaults to false.
|
||||
* When throttling, no value is returned. Use the callback instead. */
|
||||
throttle?: T,
|
||||
): T extends true ? void : ReturnType<typeof _renderScene> => {
|
||||
if (throttle) {
|
||||
renderSceneThrottled(
|
||||
elements,
|
||||
appState,
|
||||
selectionElement,
|
||||
scale,
|
||||
rc,
|
||||
canvas,
|
||||
renderConfig,
|
||||
callback,
|
||||
);
|
||||
return undefined as T extends true ? void : ReturnType<typeof _renderScene>;
|
||||
}
|
||||
const ret = _renderScene(
|
||||
elements,
|
||||
appState,
|
||||
selectionElement,
|
||||
scale,
|
||||
rc,
|
||||
canvas,
|
||||
renderConfig,
|
||||
);
|
||||
callback?.(ret);
|
||||
return ret as T extends true ? void : ReturnType<typeof _renderScene>;
|
||||
};
|
||||
|
||||
const renderTransformHandles = (
|
||||
context: CanvasRenderingContext2D,
|
||||
renderConfig: RenderConfig,
|
||||
|
@ -39,7 +39,7 @@ const mouse = new Pointer("mouse");
|
||||
// Unmount ReactDOM from root
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderSceneThrottled");
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
renderScene.mockClear();
|
||||
|
@ -14,7 +14,7 @@ import { reseed } from "../random";
|
||||
// Unmount ReactDOM from root
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderSceneThrottled");
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
renderScene.mockClear();
|
||||
|
@ -16,7 +16,7 @@ import { KEYS } from "../keys";
|
||||
// Unmount ReactDOM from root
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderSceneThrottled");
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
renderScene.mockClear();
|
||||
|
@ -14,7 +14,7 @@ import { reseed } from "../random";
|
||||
// Unmount ReactDOM from root
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderSceneThrottled");
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
renderScene.mockClear();
|
||||
|
@ -20,7 +20,7 @@ import { t } from "../i18n";
|
||||
|
||||
const { h } = window;
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderSceneThrottled");
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
|
||||
const mouse = new Pointer("mouse");
|
||||
const finger1 = new Pointer("touch", 1);
|
||||
|
@ -18,7 +18,7 @@ const mouse = new Pointer("mouse");
|
||||
// Unmount ReactDOM from root
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderSceneThrottled");
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
renderScene.mockClear();
|
||||
|
@ -16,7 +16,7 @@ import { Keyboard, Pointer } from "./helpers/ui";
|
||||
// Unmount ReactDOM from root
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderSceneThrottled");
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
renderScene.mockClear();
|
||||
|
Loading…
x
Reference in New Issue
Block a user