Compare commits
32 Commits
master
...
zsviczian-
Author | SHA1 | Date | |
---|---|---|---|
|
b82a0749b1 | ||
|
a772362599 | ||
|
3f11ca0a44 | ||
|
808e4711f9 | ||
|
a26e8bade8 | ||
|
fc7135c5d1 | ||
|
f017a60101 | ||
|
17f9f64eda | ||
|
619e4061f5 | ||
|
028ad1ee81 | ||
|
09a05a4a1c | ||
|
c4738b31fb | ||
|
87e6638e9e | ||
|
0a6d41ecf9 | ||
|
11109fcc62 | ||
|
c7346e3a77 | ||
|
fd030de669 | ||
|
f77975cee5 | ||
|
f994e5d71d | ||
|
77028f4d08 | ||
|
fb29bb4816 | ||
|
23fcddb2a3 | ||
|
b314b939b2 | ||
|
bc687fea1b | ||
|
e15f313fe7 | ||
|
9f02922c91 | ||
|
2b6819eb2d | ||
|
c0e9b8d7bc | ||
|
c8c683c025 | ||
|
2117fbbc57 | ||
|
3b9953f57f | ||
|
7d1efb7f8b |
@ -1361,6 +1361,10 @@ class App extends React.Component<AppProps, AppState> {
|
||||
document.querySelector(".excalidraw")!,
|
||||
).getPropertyValue("--color-selection");
|
||||
|
||||
//const now = Date.now();
|
||||
//if (!this.state.shouldCacheIgnoreZoom) {
|
||||
// console.log(`renderScene`, now);
|
||||
//}
|
||||
renderScene(
|
||||
{
|
||||
elements: renderingElements,
|
||||
@ -1397,11 +1401,14 @@ class App extends React.Component<AppProps, AppState> {
|
||||
if (this.state.scrolledOutside !== scrolledOutside) {
|
||||
this.setState({ scrolledOutside });
|
||||
}
|
||||
|
||||
this.scheduleImageRefresh();
|
||||
//if (!this.state.shouldCacheIgnoreZoom) {
|
||||
// setTimeout(() => console.log(`after renderScene`, now));
|
||||
//}
|
||||
},
|
||||
},
|
||||
THROTTLE_NEXT_RENDER && window.EXCALIDRAW_THROTTLE_RENDER === true,
|
||||
true ||
|
||||
(THROTTLE_NEXT_RENDER && window.EXCALIDRAW_THROTTLE_RENDER === true),
|
||||
);
|
||||
|
||||
if (!THROTTLE_NEXT_RENDER) {
|
||||
|
@ -30,7 +30,7 @@ import { RenderConfig } from "../scene/types";
|
||||
import { distance, getFontString, getFontFamilyString, isRTL } from "../utils";
|
||||
import { getCornerRadius, isPathALoop, isRightAngle } from "../math";
|
||||
import rough from "roughjs/bin/rough";
|
||||
import { AppState, BinaryFiles, Zoom } from "../types";
|
||||
import { AppState, BinaryFiles, NormalizedZoomValue, Zoom } from "../types";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import {
|
||||
BOUND_TEXT_PADDING,
|
||||
@ -93,6 +93,50 @@ export interface ExcalidrawElementWithCanvas {
|
||||
boundTextElementVersion: number | null;
|
||||
}
|
||||
|
||||
export const cappedElementCanvasSize = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
zoom: Zoom,
|
||||
): {
|
||||
width: number;
|
||||
height: number;
|
||||
zoomValue: NormalizedZoomValue;
|
||||
} => {
|
||||
const sizelimit = 16777216; // 2^24
|
||||
const padding = getCanvasPadding(element);
|
||||
let zoomValue = zoom.value;
|
||||
|
||||
if (isLinearElement(element) || isFreeDrawElement(element)) {
|
||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||
|
||||
let width = distance(x1, x2) * window.devicePixelRatio + padding * 2;
|
||||
let height = distance(y1, y2) * window.devicePixelRatio + padding * 2;
|
||||
|
||||
const size = width * height * zoomValue * zoomValue;
|
||||
if (size > sizelimit) {
|
||||
zoomValue = Math.sqrt(
|
||||
sizelimit / (width * height),
|
||||
) as NormalizedZoomValue;
|
||||
width = distance(x1, x2) * window.devicePixelRatio + padding * 2;
|
||||
height = distance(y1, y2) * window.devicePixelRatio + padding * 2;
|
||||
}
|
||||
width *= zoomValue;
|
||||
height *= zoomValue;
|
||||
return { width, height, zoomValue };
|
||||
}
|
||||
let width = element.width * window.devicePixelRatio + padding * 2;
|
||||
let height = element.height * window.devicePixelRatio + padding * 2;
|
||||
|
||||
const size = width * height * zoomValue * zoomValue;
|
||||
if (size > sizelimit) {
|
||||
zoomValue = Math.sqrt(sizelimit / (width * height)) as NormalizedZoomValue;
|
||||
width = element.width * window.devicePixelRatio + padding * 2;
|
||||
height = element.height * window.devicePixelRatio + padding * 2;
|
||||
}
|
||||
width *= zoomValue;
|
||||
height *= zoomValue;
|
||||
return { width, height, zoomValue };
|
||||
};
|
||||
|
||||
const generateElementCanvas = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
zoom: Zoom,
|
||||
@ -102,44 +146,35 @@ const generateElementCanvas = (
|
||||
const context = canvas.getContext("2d")!;
|
||||
const padding = getCanvasPadding(element);
|
||||
|
||||
const { width, height, zoomValue } = cappedElementCanvasSize(element, zoom);
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
let canvasOffsetX = 0;
|
||||
let canvasOffsetY = 0;
|
||||
|
||||
if (isLinearElement(element) || isFreeDrawElement(element)) {
|
||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||
|
||||
canvas.width =
|
||||
distance(x1, x2) * window.devicePixelRatio * zoom.value +
|
||||
padding * zoom.value * 2;
|
||||
canvas.height =
|
||||
distance(y1, y2) * window.devicePixelRatio * zoom.value +
|
||||
padding * zoom.value * 2;
|
||||
const [x1, y1] = getElementAbsoluteCoords(element);
|
||||
|
||||
canvasOffsetX =
|
||||
element.x > x1
|
||||
? distance(element.x, x1) * window.devicePixelRatio * zoom.value
|
||||
? distance(element.x, x1) * window.devicePixelRatio * zoomValue
|
||||
: 0;
|
||||
|
||||
canvasOffsetY =
|
||||
element.y > y1
|
||||
? distance(element.y, y1) * window.devicePixelRatio * zoom.value
|
||||
? distance(element.y, y1) * window.devicePixelRatio * zoomValue
|
||||
: 0;
|
||||
|
||||
context.translate(canvasOffsetX, canvasOffsetY);
|
||||
} else {
|
||||
canvas.width =
|
||||
element.width * window.devicePixelRatio * zoom.value +
|
||||
padding * zoom.value * 2;
|
||||
canvas.height =
|
||||
element.height * window.devicePixelRatio * zoom.value +
|
||||
padding * zoom.value * 2;
|
||||
}
|
||||
|
||||
context.save();
|
||||
context.translate(padding * zoom.value, padding * zoom.value);
|
||||
context.translate(padding * zoomValue, padding * zoomValue);
|
||||
context.scale(
|
||||
window.devicePixelRatio * zoom.value,
|
||||
window.devicePixelRatio * zoom.value,
|
||||
window.devicePixelRatio * zoomValue,
|
||||
window.devicePixelRatio * zoomValue,
|
||||
);
|
||||
|
||||
const rc = rough.canvas(canvas);
|
||||
@ -156,7 +191,7 @@ const generateElementCanvas = (
|
||||
element,
|
||||
canvas,
|
||||
theme: renderConfig.theme,
|
||||
canvasZoom: zoom.value,
|
||||
canvasZoom: zoomValue,
|
||||
canvasOffsetX,
|
||||
canvasOffsetY,
|
||||
boundTextElementVersion: getBoundTextElement(element)?.version || null,
|
||||
@ -422,6 +457,11 @@ const generateElementShape = (
|
||||
// `null` indicates no rc shape applicable for this element type
|
||||
// (= do not generate anything)
|
||||
if (shape === undefined) {
|
||||
const prevElementWithCanvas = elementWithCanvasCache.get(element);
|
||||
if (prevElementWithCanvas?.canvas) {
|
||||
prevElementWithCanvas.canvas.width = 0;
|
||||
prevElementWithCanvas.canvas.height = 0;
|
||||
}
|
||||
elementWithCanvasCache.delete(element);
|
||||
|
||||
switch (element.type) {
|
||||
@ -685,7 +725,10 @@ const generateElementWithCanvas = (
|
||||
zoom,
|
||||
renderConfig,
|
||||
);
|
||||
|
||||
if (prevElementWithCanvas?.canvas) {
|
||||
prevElementWithCanvas.canvas.width = 0;
|
||||
prevElementWithCanvas.canvas.height = 0;
|
||||
}
|
||||
elementWithCanvasCache.set(element, elementWithCanvas);
|
||||
|
||||
return elementWithCanvas;
|
||||
|
@ -29,7 +29,11 @@ import {
|
||||
} from "../scene/scrollbars";
|
||||
import { getSelectedElements } from "../scene/selection";
|
||||
|
||||
import { renderElement, renderElementToSvg } from "./renderElement";
|
||||
import {
|
||||
cappedElementCanvasSize,
|
||||
renderElement,
|
||||
renderElementToSvg,
|
||||
} from "./renderElement";
|
||||
import { getClientColors } from "../clients";
|
||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||
import {
|
||||
@ -407,6 +411,21 @@ export const _renderScene = ({
|
||||
|
||||
let editingLinearElement: NonDeleted<ExcalidrawLinearElement> | undefined =
|
||||
undefined;
|
||||
const start = Date.now();
|
||||
const showDebug = false; //!appState.shouldCacheIgnoreZoom && (appState.zoom.value < 0.5);
|
||||
if (showDebug) {
|
||||
console.log("start: renderElements");
|
||||
}
|
||||
console.log(
|
||||
visibleElements.length,
|
||||
appState.zoom.value,
|
||||
Math.round(
|
||||
visibleElements.reduce((acc, el) => {
|
||||
const { width, height } = cappedElementCanvasSize(el, appState.zoom);
|
||||
return acc + width * height;
|
||||
}, 0),
|
||||
),
|
||||
);
|
||||
visibleElements.forEach((element) => {
|
||||
try {
|
||||
renderElement(element, rc, context, renderConfig, appState);
|
||||
@ -426,7 +445,9 @@ export const _renderScene = ({
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
if (showDebug) {
|
||||
console.log(`finish: renderElements ${Date.now() - start}`);
|
||||
}
|
||||
if (editingLinearElement) {
|
||||
renderLinearPointHandles(
|
||||
context,
|
||||
@ -636,10 +657,8 @@ export const _renderScene = ({
|
||||
}
|
||||
context.restore();
|
||||
}
|
||||
|
||||
// Reset zoom
|
||||
context.restore();
|
||||
|
||||
// Paint remote pointers
|
||||
for (const clientId in renderConfig.remotePointerViewportCoords) {
|
||||
let { x, y } = renderConfig.remotePointerViewportCoords[clientId];
|
||||
@ -787,7 +806,6 @@ export const _renderScene = ({
|
||||
});
|
||||
context.restore();
|
||||
}
|
||||
|
||||
context.restore();
|
||||
return { atLeastOneVisibleElement: visibleElements.length > 0, scrollBars };
|
||||
};
|
||||
|
21
src/utils.ts
21
src/utils.ts
@ -135,17 +135,24 @@ export const throttleRAF = <T extends any[]>(
|
||||
let timerId: number | null = null;
|
||||
let lastArgs: T | null = null;
|
||||
let lastArgsTrailing: T | null = null;
|
||||
let watchdog: number | null = null;
|
||||
|
||||
const scheduleFunc = (args: T) => {
|
||||
timerId = window.requestAnimationFrame(() => {
|
||||
timerId = null;
|
||||
//console.log("start render in animation frame");
|
||||
fn(...args);
|
||||
//console.log("render done in animation frame");
|
||||
lastArgs = null;
|
||||
if (lastArgsTrailing) {
|
||||
//console.log("last args trailing", lastArgsTrailing);
|
||||
lastArgs = lastArgsTrailing;
|
||||
lastArgsTrailing = null;
|
||||
scheduleFunc(lastArgs);
|
||||
}
|
||||
if (watchdog) {
|
||||
clearTimeout(watchdog);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -165,6 +172,9 @@ export const throttleRAF = <T extends any[]>(
|
||||
if (timerId !== null) {
|
||||
cancelAnimationFrame(timerId);
|
||||
timerId = null;
|
||||
if (watchdog) {
|
||||
clearTimeout(watchdog);
|
||||
}
|
||||
}
|
||||
if (lastArgs) {
|
||||
fn(...(lastArgsTrailing || lastArgs));
|
||||
@ -176,8 +186,19 @@ export const throttleRAF = <T extends any[]>(
|
||||
if (timerId !== null) {
|
||||
cancelAnimationFrame(timerId);
|
||||
timerId = null;
|
||||
if (watchdog) {
|
||||
clearTimeout(watchdog);
|
||||
watchdog = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
watchdog = window.setTimeout(() => {
|
||||
console.log("watchdog", timerId);
|
||||
if (timerId !== null) {
|
||||
cancelAnimationFrame(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
}, 1000);
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user