1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2025-02-18 13:29:36 +01:00

Disable UI rendering when history is skipped (#574)

When we are scrolling, resizing, or moving elements, we already disable the history. Since those actions do not change the state of the UI, we can also avoid re-drawing it and save ~10ms per frame.

I had to change all the forceUpdate() to setState({}), otherwise it would bypass shouldComponentUpdate.
This commit is contained in:
Christopher Chedeau 2020-01-26 19:08:46 +00:00 committed by GitHub
parent 263fef4eaa
commit 8ab176b9a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -180,7 +180,7 @@ export class App extends React.Component<any, AppState> {
private syncActionResult = (res: ActionResult) => {
if (res.elements !== undefined) {
elements = res.elements;
this.forceUpdate();
this.setState({});
}
if (res.appState !== undefined) {
@ -199,7 +199,7 @@ export class App extends React.Component<any, AppState> {
),
);
elements = deleteSelectedElements(elements);
this.forceUpdate();
this.setState({});
e.preventDefault();
};
private onCopy = (e: ClipboardEvent) => {
@ -226,6 +226,14 @@ export class App extends React.Component<any, AppState> {
this.saveDebounced.flush();
};
public shouldComponentUpdate() {
if (!history.isRecording()) {
this.componentDidUpdate();
return false;
}
return true;
}
public async componentDidMount() {
document.addEventListener("copy", this.onCopy);
document.addEventListener("paste", this.onPaste);
@ -253,7 +261,7 @@ export class App extends React.Component<any, AppState> {
if (data.appState) {
this.setState(data.appState);
} else {
this.forceUpdate();
this.setState({});
}
}
@ -275,7 +283,7 @@ export class App extends React.Component<any, AppState> {
public state: AppState = getDefaultAppState();
private onResize = () => {
this.forceUpdate();
this.setState({});
};
private updateCurrentCursorPosition = (e: MouseEvent) => {
@ -286,7 +294,7 @@ export class App extends React.Component<any, AppState> {
private onKeyDown = (event: KeyboardEvent) => {
if (event.key === KEYS.ESCAPE && !this.state.draggingElement) {
elements = clearSelection(elements);
this.forceUpdate();
this.setState({});
this.setState({ elementType: "selection" });
if (window.document.activeElement instanceof HTMLElement) {
window.document.activeElement.blur();
@ -320,7 +328,7 @@ export class App extends React.Component<any, AppState> {
}
return el;
});
this.forceUpdate();
this.setState({});
event.preventDefault();
} else if (
shapesShortcutKeys.includes(event.key.toLowerCase()) &&
@ -505,7 +513,7 @@ export class App extends React.Component<any, AppState> {
elements = clearSelection(elements);
document.documentElement.style.cursor =
value === "text" ? CURSOR_TYPE.TEXT : CURSOR_TYPE.CROSSHAIR;
this.forceUpdate();
this.setState({});
}}
></ToolButton>
);
@ -695,7 +703,7 @@ export class App extends React.Component<any, AppState> {
if (!element.isSelected) {
elements = clearSelection(elements);
element.isSelected = true;
this.forceUpdate();
this.setState({});
}
ContextMenu.push({
@ -737,6 +745,8 @@ export class App extends React.Component<any, AppState> {
let deltaY = lastY - e.clientY;
lastX = e.clientX;
lastY = e.clientY;
// We don't want to save history when panning around
history.skipRecording();
this.setState(state => ({
scrollX: state.scrollX - deltaX,
scrollY: state.scrollY - deltaY,
@ -941,6 +951,8 @@ export class App extends React.Component<any, AppState> {
if (isOverHorizontalScrollBar) {
const x = e.clientX - CANVAS_WINDOW_OFFSET_LEFT;
const dx = x - lastX;
// We don't want to save history when scrolling
history.skipRecording();
this.setState(state => ({ scrollX: state.scrollX - dx }));
lastX = x;
return;
@ -949,6 +961,8 @@ export class App extends React.Component<any, AppState> {
if (isOverVerticalScrollBar) {
const y = e.clientY - CANVAS_WINDOW_OFFSET_TOP;
const dy = y - lastY;
// We don't want to save history when scrolling
history.skipRecording();
this.setState(state => ({ scrollY: state.scrollY - dy }));
lastY = y;
return;
@ -1051,7 +1065,7 @@ export class App extends React.Component<any, AppState> {
lastY = y;
// We don't want to save history when resizing an element
history.skipRecording();
this.forceUpdate();
this.setState({});
return;
}
}
@ -1072,7 +1086,7 @@ export class App extends React.Component<any, AppState> {
lastY = y;
// We don't want to save history when dragging an element to initially size it
history.skipRecording();
this.forceUpdate();
this.setState({});
return;
}
}
@ -1127,7 +1141,7 @@ export class App extends React.Component<any, AppState> {
}
// We don't want to save history when moving an element
history.skipRecording();
this.forceUpdate();
this.setState({});
};
const onMouseUp = (e: MouseEvent) => {
@ -1152,12 +1166,11 @@ export class App extends React.Component<any, AppState> {
this.setState({
draggingElement: null,
});
this.forceUpdate();
return;
}
if (normalizeDimensions(draggingElement)) {
this.forceUpdate();
this.setState({});
}
if (resizingElement && isInvisiblySmallElement(resizingElement)) {
@ -1188,7 +1201,7 @@ export class App extends React.Component<any, AppState> {
if (draggingElement === null) {
// if no element is clicked, clear the selection and redraw
elements = clearSelection(elements);
this.forceUpdate();
this.setState({});
return;
}
@ -1208,7 +1221,7 @@ export class App extends React.Component<any, AppState> {
}
history.resumeRecording();
this.forceUpdate();
this.setState({});
};
lastMouseUp = onMouseUp;
@ -1218,7 +1231,7 @@ export class App extends React.Component<any, AppState> {
// We don't want to save history on mouseDown, only on mouseUp when it's fully configured
history.skipRecording();
this.forceUpdate();
this.setState({});
}}
onDoubleClick={e => {
const { x, y } = viewportCoordsToSceneCoords(e, this.state);
@ -1253,7 +1266,7 @@ export class App extends React.Component<any, AppState> {
elements = elements.filter(
element => element.id !== elementAtPosition.id,
);
this.forceUpdate();
this.setState({});
textX =
this.state.scrollX +
@ -1355,6 +1368,8 @@ export class App extends React.Component<any, AppState> {
private handleWheel = (e: WheelEvent) => {
e.preventDefault();
const { deltaX, deltaY } = e;
// We don't want to save history when panning around
history.skipRecording();
this.setState(state => ({
scrollX: state.scrollX - deltaX,
scrollY: state.scrollY - deltaY,
@ -1412,7 +1427,7 @@ export class App extends React.Component<any, AppState> {
return duplicate;
}),
];
this.forceUpdate();
this.setState({});
}
};