Compare commits

..
Author SHA1 Message Date
zsviczian b82a0749b1 fixed maxZoom 2023-04-04 19:14:59 +02:00
zsviczian a772362599 more detailed debug 2023-04-04 18:55:40 +02:00
zsviczian 3f11ca0a44 debug 2023-04-04 18:47:35 +02:00
zsviczian 808e4711f9 debug total render size 2023-04-04 18:42:34 +02:00
zsviczianandGitHub a26e8bade8 Update renderElement.ts 2023-04-04 16:50:48 +02:00
zsviczianandGitHub fc7135c5d1 Update renderElement.ts 2023-04-04 16:38:26 +02:00
zsviczianandGitHub f017a60101 Update renderElement.ts 2023-04-04 16:17:08 +02:00
zsviczianandGitHub 17f9f64eda Update renderElement.ts 2023-04-04 16:12:05 +02:00
zsviczianandGitHub 619e4061f5 cappedElementCanvasSize 2023-04-04 16:01:47 +02:00
zsviczianandGitHub 028ad1ee81 Update utils.ts 2023-04-04 13:26:53 +02:00
zsviczianandGitHub 09a05a4a1c Update utils.ts 2023-04-04 13:20:11 +02:00
zsviczianandGitHub c4738b31fb Update utils.ts 2023-04-04 13:18:51 +02:00
zsviczianandGitHub 87e6638e9e Update utils.ts 2023-04-04 13:16:24 +02:00
zsviczianandGitHub 0a6d41ecf9 watchdog 2023-04-04 13:15:35 +02:00
zsviczianandGitHub 11109fcc62 Update renderScene.ts 2023-04-04 10:49:48 +02:00
zsviczian c7346e3a77 always throttle render 2023-04-03 22:24:18 +02:00
zsviczian fd030de669 debug 2023-04-03 21:45:38 +02:00
zsviczian f77975cee5 debug 2023-04-03 21:41:48 +02:00
zsviczian f994e5d71d debug 2023-04-03 21:36:01 +02:00
zsviczian 77028f4d08 debug 2023-04-03 21:31:35 +02:00
zsviczian fb29bb4816 debug 2023-04-03 21:26:53 +02:00
zsviczian 23fcddb2a3 debug 2023-04-03 21:22:33 +02:00
zsviczian b314b939b2 checkpoints 2023-04-03 21:14:31 +02:00
zsviczian bc687fea1b log renderScene 2023-04-03 21:08:18 +02:00
zsviczian e15f313fe7 debug 2023-04-03 20:59:37 +02:00
zsviczian 9f02922c91 attempt at catching the point before freeze 2023-04-03 20:52:21 +02:00
zsviczian 2b6819eb2d fix canvas too large 2023-04-03 20:19:13 +02:00
zsviczianandGitHub c0e9b8d7bc Update renderElement.ts 2023-04-03 19:35:28 +02:00
zsviczianandGitHub c8c683c025 Update renderElement.ts 2023-04-03 19:28:53 +02:00
zsviczianandGitHub 2117fbbc57 Update renderElement.ts 2023-04-03 19:26:25 +02:00
zsviczianandGitHub 3b9953f57f link 2023-04-03 12:15:11 +02:00
zsviczianandGitHub 7d1efb7f8b Attempt at implementing #4036 2023-04-03 12:05:19 +02:00
15 changed files with 212 additions and 196 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
An open source virtual hand-drawn style whiteboard. </br>
Collaborative and end-to-end encrypted. </br>
<br />
</h2>
</h3>
</div>
<br />
-1
View File
@@ -20,7 +20,6 @@
},
"dependencies": {
"@dwelle/tunnel-rat": "0.1.1",
"@excalidraw/roughjs": "4.5.3",
"@sentry/browser": "6.2.5",
"@sentry/integrations": "6.2.5",
"@testing-library/jest-dom": "5.16.2",
+1 -1
View File
@@ -94,7 +94,7 @@
// if its present redirect
document.cookie.includes("excplus-autoredirect=true")
) {
// window.location.href = "https://app.excalidraw.com";
window.location.href = "https://app.excalidraw.com";
}
</script>
+86 -90
View File
@@ -23,7 +23,6 @@ import {
ExcalidrawTextElement,
} from "../element/types";
import { getSelectedElements } from "../scene";
import { AppState } from "../types";
import { getFontString } from "../utils";
import { register } from "./register";
@@ -186,110 +185,107 @@ export const actionCreateContainerFromText = register({
trackEvent: { category: "element" },
predicate: (elements, appState) => {
const selectedElements = getSelectedElements(elements, appState);
const areTextElements = selectedElements.every((el) => isTextElement(el));
return selectedElements.length > 0 && areTextElements;
return selectedElements.length === 1 && isTextElement(selectedElements[0]);
},
perform: (elements, appState) => {
const selectedElements = getSelectedElements(
getNonDeletedElements(elements),
appState,
);
let updatedElements: readonly ExcalidrawElement[] = elements.slice();
const containerIds: AppState["selectedElementIds"] = {};
const updatedElements = elements.slice();
if (selectedElements.length === 1 && isTextElement(selectedElements[0])) {
const textElement = selectedElements[0];
const container = newElement({
type: "rectangle",
backgroundColor: appState.currentItemBackgroundColor,
boundElements: [
...(textElement.boundElements || []),
{ id: textElement.id, type: "text" },
],
angle: textElement.angle,
fillStyle: appState.currentItemFillStyle,
strokeColor: appState.currentItemStrokeColor,
roughness: appState.currentItemRoughness,
strokeWidth: appState.currentItemStrokeWidth,
strokeStyle: appState.currentItemStrokeStyle,
roundness:
appState.currentItemRoundness === "round"
? {
type: isUsingAdaptiveRadius("rectangle")
? ROUNDNESS.ADAPTIVE_RADIUS
: ROUNDNESS.PROPORTIONAL_RADIUS,
}
: null,
opacity: 100,
locked: false,
x: textElement.x - BOUND_TEXT_PADDING,
y: textElement.y - BOUND_TEXT_PADDING,
width: computeContainerDimensionForBoundText(
textElement.width,
"rectangle",
),
height: computeContainerDimensionForBoundText(
textElement.height,
"rectangle",
),
groupIds: textElement.groupIds,
});
for (const textElement of selectedElements) {
if (isTextElement(textElement)) {
const container = newElement({
type: "rectangle",
backgroundColor: appState.currentItemBackgroundColor,
boundElements: [
...(textElement.boundElements || []),
{ id: textElement.id, type: "text" },
],
angle: textElement.angle,
fillStyle: appState.currentItemFillStyle,
strokeColor: appState.currentItemStrokeColor,
roughness: appState.currentItemRoughness,
strokeWidth: appState.currentItemStrokeWidth,
strokeStyle: appState.currentItemStrokeStyle,
roundness:
appState.currentItemRoundness === "round"
? {
type: isUsingAdaptiveRadius("rectangle")
? ROUNDNESS.ADAPTIVE_RADIUS
: ROUNDNESS.PROPORTIONAL_RADIUS,
}
: null,
opacity: 100,
locked: false,
x: textElement.x - BOUND_TEXT_PADDING,
y: textElement.y - BOUND_TEXT_PADDING,
width: computeContainerDimensionForBoundText(
textElement.width,
"rectangle",
),
height: computeContainerDimensionForBoundText(
textElement.height,
"rectangle",
),
groupIds: textElement.groupIds,
// update bindings
if (textElement.boundElements?.length) {
const linearElementIds = textElement.boundElements
.filter((ele) => ele.type === "arrow")
.map((el) => el.id);
const linearElements = updatedElements.filter((ele) =>
linearElementIds.includes(ele.id),
) as ExcalidrawLinearElement[];
linearElements.forEach((ele) => {
let startBinding = ele.startBinding;
let endBinding = ele.endBinding;
if (startBinding?.elementId === textElement.id) {
startBinding = {
...startBinding,
elementId: container.id,
};
}
if (endBinding?.elementId === textElement.id) {
endBinding = { ...endBinding, elementId: container.id };
}
if (startBinding || endBinding) {
mutateElement(ele, { startBinding, endBinding });
}
});
}
// update bindings
if (textElement.boundElements?.length) {
const linearElementIds = textElement.boundElements
.filter((ele) => ele.type === "arrow")
.map((el) => el.id);
const linearElements = updatedElements.filter((ele) =>
linearElementIds.includes(ele.id),
) as ExcalidrawLinearElement[];
linearElements.forEach((ele) => {
let startBinding = ele.startBinding;
let endBinding = ele.endBinding;
mutateElement(textElement, {
containerId: container.id,
verticalAlign: VERTICAL_ALIGN.MIDDLE,
boundElements: null,
});
redrawTextBoundingBox(textElement, container);
if (startBinding?.elementId === textElement.id) {
startBinding = {
...startBinding,
elementId: container.id,
};
}
if (endBinding?.elementId === textElement.id) {
endBinding = { ...endBinding, elementId: container.id };
}
if (startBinding || endBinding) {
mutateElement(ele, { startBinding, endBinding }, false);
}
});
}
mutateElement(
textElement,
{
containerId: container.id,
verticalAlign: VERTICAL_ALIGN.MIDDLE,
boundElements: null,
},
false,
);
redrawTextBoundingBox(textElement, container);
updatedElements = pushContainerBelowText(
[...updatedElements, container],
return {
elements: pushContainerBelowText(
[...elements, container],
container,
textElement,
);
containerIds[container.id] = true;
}
),
appState: {
...appState,
selectedElementIds: {
[container.id]: true,
[textElement.id]: false,
},
},
commitToHistory: true,
};
}
return {
elements: updatedElements,
appState: {
...appState,
selectedElementIds: containerIds,
},
appState,
commitToHistory: true,
};
},
+11 -4
View File
@@ -1,8 +1,8 @@
import React, { useContext } from "react";
import { flushSync } from "react-dom";
import { RoughCanvas } from "@excalidraw/roughjs/bin/canvas";
import rough from "@excalidraw/roughjs/bin/rough";
import { RoughCanvas } from "roughjs/bin/canvas";
import rough from "roughjs/bin/rough";
import clsx from "clsx";
import { nanoid } from "nanoid";
@@ -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) {
+2 -2
View File
@@ -7,8 +7,8 @@ import {
ExcalidrawTextElementWithContainer,
} from "./types";
import { distance2d, rotate } from "../math";
import rough from "@excalidraw/roughjs/bin/rough";
import { Drawable, Op } from "@excalidraw/roughjs/bin/core";
import rough from "roughjs/bin/rough";
import { Drawable, Op } from "roughjs/bin/core";
import { Point } from "../types";
import {
getShapeForElement,
+1 -1
View File
@@ -30,7 +30,7 @@ import {
import { getElementAbsoluteCoords, getCurvePathOps, Bounds } from "./bounds";
import { Point } from "../types";
import { Drawable } from "@excalidraw/roughjs/bin/core";
import { Drawable } from "roughjs/bin/core";
import { AppState } from "../types";
import { getShapeForElement } from "../renderer/renderElement";
import { hasBoundTextElement, isImageElement } from "./typeChecks";
-1
View File
@@ -297,7 +297,6 @@ export const textWysiwyg = ({
filter: "var(--theme-filter)",
maxHeight: `${editorMaxHeight}px`,
});
editable.scrollTop = 0;
// For some reason updating font attribute doesn't set font family
// hence updating font family explicitly for test environment
if (isTestEnv()) {
+1 -1
View File
@@ -1,4 +1,4 @@
import { Random } from "@excalidraw/roughjs/bin/math";
import { Random } from "roughjs/bin/math";
import { nanoid } from "nanoid";
import { isTestEnv } from "./utils";
+61 -76
View File
@@ -21,16 +21,16 @@ import {
getElementAbsoluteCoords,
getArrowheadPoints,
} from "../element/bounds";
import { RoughCanvas } from "@excalidraw/roughjs/bin/canvas";
import { Drawable, Options } from "@excalidraw/roughjs/bin/core";
import { RoughSVG } from "@excalidraw/roughjs/bin/svg";
import { RoughGenerator } from "@excalidraw/roughjs/bin/generator";
import { RoughCanvas } from "roughjs/bin/canvas";
import { Drawable, Options } from "roughjs/bin/core";
import { RoughSVG } from "roughjs/bin/svg";
import { RoughGenerator } from "roughjs/bin/generator";
import { RenderConfig } from "../scene/types";
import { distance, getFontString, getFontFamilyString, isRTL } from "../utils";
import { getCornerRadius, isPathALoop, isRightAngle } from "../math";
import rough from "@excalidraw/roughjs/bin/rough";
import { AppState, BinaryFiles, Zoom } from "../types";
import rough from "roughjs/bin/rough";
import { AppState, BinaryFiles, NormalizedZoomValue, Zoom } from "../types";
import { getDefaultAppState } from "../appState";
import {
BOUND_TEXT_PADDING,
@@ -87,64 +87,54 @@ export interface ExcalidrawElementWithCanvas {
element: ExcalidrawElement | ExcalidrawTextElement;
canvas: HTMLCanvasElement;
theme: RenderConfig["theme"];
scale: number;
canvasZoom: Zoom["value"];
canvasOffsetX: number;
canvasOffsetY: number;
boundTextElementVersion: number | null;
}
const cappedElementCanvasSize = (
export const cappedElementCanvasSize = (
element: NonDeletedExcalidrawElement,
zoom: Zoom,
): {
width: number;
height: number;
scale: number;
zoomValue: NormalizedZoomValue;
} => {
// these limits are ballpark, they depend on specific browsers and device.
// We've chosen lower limits to be safe. We might want to change these limits
// based on browser/device type, if we get reports of low quality rendering
// on zoom.
//
// ~ safari mobile canvas area limit
const AREA_LIMIT = 16777216;
// ~ safari width/height limit based on developer.mozilla.org.
const WIDTH_HEIGHT_LIMIT = 32767;
const sizelimit = 16777216; // 2^24
const padding = getCanvasPadding(element);
let zoomValue = zoom.value;
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const elementWidth =
isLinearElement(element) || isFreeDrawElement(element)
? distance(x1, x2)
: element.width;
const elementHeight =
isLinearElement(element) || isFreeDrawElement(element)
? distance(y1, y2)
: element.height;
if (isLinearElement(element) || isFreeDrawElement(element)) {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
let width = elementWidth * window.devicePixelRatio + padding * 2;
let height = elementHeight * window.devicePixelRatio + padding * 2;
let width = distance(x1, x2) * window.devicePixelRatio + padding * 2;
let height = distance(y1, y2) * window.devicePixelRatio + padding * 2;
let scale: number = zoom.value;
// rescale to ensure width and height is within limits
if (
width * scale > WIDTH_HEIGHT_LIMIT ||
height * scale > WIDTH_HEIGHT_LIMIT
) {
scale = Math.min(WIDTH_HEIGHT_LIMIT / width, WIDTH_HEIGHT_LIMIT / height);
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;
// rescale to ensure canvas area is within limits
if (width * height * scale * scale > AREA_LIMIT) {
scale = Math.sqrt(AREA_LIMIT / (width * height));
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 = Math.floor(width * scale);
height = Math.floor(height * scale);
return { width, height, scale };
width *= zoomValue;
height *= zoomValue;
return { width, height, zoomValue };
};
const generateElementCanvas = (
@@ -156,7 +146,7 @@ const generateElementCanvas = (
const context = canvas.getContext("2d")!;
const padding = getCanvasPadding(element);
const { width, height, scale } = cappedElementCanvasSize(element, zoom);
const { width, height, zoomValue } = cappedElementCanvasSize(element, zoom);
canvas.width = width;
canvas.height = height;
@@ -169,22 +159,22 @@ const generateElementCanvas = (
canvasOffsetX =
element.x > x1
? distance(element.x, x1) * window.devicePixelRatio * scale
? distance(element.x, x1) * window.devicePixelRatio * zoomValue
: 0;
canvasOffsetY =
element.y > y1
? distance(element.y, y1) * window.devicePixelRatio * scale
? distance(element.y, y1) * window.devicePixelRatio * zoomValue
: 0;
context.translate(canvasOffsetX, canvasOffsetY);
}
context.save();
context.translate(padding * scale, padding * scale);
context.translate(padding * zoomValue, padding * zoomValue);
context.scale(
window.devicePixelRatio * scale,
window.devicePixelRatio * scale,
window.devicePixelRatio * zoomValue,
window.devicePixelRatio * zoomValue,
);
const rc = rough.canvas(canvas);
@@ -201,7 +191,7 @@ const generateElementCanvas = (
element,
canvas,
theme: renderConfig.theme,
scale,
canvasZoom: zoomValue,
canvasOffsetX,
canvasOffsetY,
boundTextElementVersion: getBoundTextElement(element)?.version || null,
@@ -389,16 +379,6 @@ export const setShapeForElement = <T extends ExcalidrawElement>(
export const invalidateShapeForElement = (element: ExcalidrawElement) =>
shapeCache.delete(element);
function adjustRoughness(size: number, roughness: number): number {
if (size >= 50) {
return roughness;
}
const factor = 2 + (50 - size) / 10;
// console.log({ ret: roughness / factor, roughness, factor, size });
return roughness / factor;
}
export const generateRoughOptions = (
element: ExcalidrawElement,
continuousPath = false,
@@ -425,10 +405,7 @@ export const generateRoughOptions = (
// calculate them (and we don't want the fills to be modified)
fillWeight: element.strokeWidth / 2,
hachureGap: element.strokeWidth * 4,
roughness: adjustRoughness(
Math.min(element.width, element.height),
element.roughness,
),
roughness: element.roughness,
stroke: element.strokeColor,
preserveVertices: continuousPath,
};
@@ -480,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) {
@@ -728,7 +710,7 @@ const generateElementWithCanvas = (
const prevElementWithCanvas = elementWithCanvasCache.get(element);
const shouldRegenerateBecauseZoom =
prevElementWithCanvas &&
prevElementWithCanvas.scale !== zoom.value &&
prevElementWithCanvas.canvasZoom !== zoom.value &&
!renderConfig?.shouldCacheIgnoreZoom;
const boundTextElementVersion = getBoundTextElement(element)?.version || null;
@@ -743,7 +725,10 @@ const generateElementWithCanvas = (
zoom,
renderConfig,
);
if (prevElementWithCanvas?.canvas) {
prevElementWithCanvas.canvas.width = 0;
prevElementWithCanvas.canvas.height = 0;
}
elementWithCanvasCache.set(element, elementWithCanvas);
return elementWithCanvas;
@@ -759,7 +744,7 @@ const drawElementFromCanvas = (
) => {
const element = elementWithCanvas.element;
const padding = getCanvasPadding(element);
const zoom = elementWithCanvas.scale;
const zoom = elementWithCanvas.canvasZoom;
let [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
// Free draw elements will otherwise "shuffle" as the min x and y change
@@ -786,10 +771,10 @@ const drawElementFromCanvas = (
const maxDim = Math.max(distance(x1, x2), distance(y1, y2));
tempCanvas.width =
maxDim * window.devicePixelRatio * zoom +
padding * elementWithCanvas.scale * 10;
padding * elementWithCanvas.canvasZoom * 10;
tempCanvas.height =
maxDim * window.devicePixelRatio * zoom +
padding * elementWithCanvas.scale * 10;
padding * elementWithCanvas.canvasZoom * 10;
const offsetX = (tempCanvas.width - elementWithCanvas.canvas!.width) / 2;
const offsetY = (tempCanvas.height - elementWithCanvas.canvas!.height) / 2;
@@ -870,11 +855,11 @@ const drawElementFromCanvas = (
context.drawImage(
elementWithCanvas.canvas!,
(x1 + renderConfig.scrollX) * window.devicePixelRatio -
(padding * elementWithCanvas.scale) / elementWithCanvas.scale,
(padding * elementWithCanvas.canvasZoom) / elementWithCanvas.canvasZoom,
(y1 + renderConfig.scrollY) * window.devicePixelRatio -
(padding * elementWithCanvas.scale) / elementWithCanvas.scale,
elementWithCanvas.canvas!.width / elementWithCanvas.scale,
elementWithCanvas.canvas!.height / elementWithCanvas.scale,
(padding * elementWithCanvas.canvasZoom) / elementWithCanvas.canvasZoom,
elementWithCanvas.canvas!.width / elementWithCanvas.canvasZoom,
elementWithCanvas.canvas!.height / elementWithCanvas.canvasZoom,
);
if (
+25 -7
View File
@@ -1,5 +1,5 @@
import { RoughCanvas } from "@excalidraw/roughjs/bin/canvas";
import { RoughSVG } from "@excalidraw/roughjs/bin/svg";
import { RoughCanvas } from "roughjs/bin/canvas";
import { RoughSVG } from "roughjs/bin/svg";
import oc from "open-color";
import { AppState, BinaryFiles, Point, Zoom } from "../types";
@@ -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 };
};
+1 -1
View File
@@ -1,4 +1,4 @@
import rough from "@excalidraw/roughjs/bin/rough";
import rough from "roughjs/bin/rough";
import { NonDeletedExcalidrawElement } from "../element/types";
import { getCommonBounds } from "../element/bounds";
import { renderScene, renderSceneToSvg } from "../renderer/renderScene";
+1 -1
View File
@@ -16,7 +16,7 @@ import {
StrokeRoundness,
} from "./element/types";
import { SHAPES } from "./shapes";
import { Point as RoughPoint } from "@excalidraw/roughjs/bin/geometry";
import { Point as RoughPoint } from "roughjs/bin/geometry";
import { LinearElementEditor } from "./element/linearElementEditor";
import { SuggestedBinding } from "./element/binding";
import { ImportedDataState } from "./data/types";
+21
View File
@@ -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;
};
-9
View File
@@ -1484,15 +1484,6 @@
resolved "https://registry.yarnpkg.com/@excalidraw/prettier-config/-/prettier-config-1.0.2.tgz#b7c061c99cee2f78b9ca470ea1fbd602683bba65"
integrity sha512-rFIq8+A8WvkEzBsF++Rw6gzxE+hU3ZNkdg8foI+Upz2y/rOC/gUpWJaggPbCkoH3nlREVU59axQjZ1+F6ePRGg==
"@excalidraw/roughjs@4.5.3":
version "4.5.3"
resolved "https://registry.yarnpkg.com/@excalidraw/roughjs/-/roughjs-4.5.3.tgz#7d91897bfd1aaeb19a48d5272bd4776cb19f015b"
integrity sha512-X9HPfNjPLNHt+gN7t1LN7nN4h4o8M2EWuN/Y4YgG0ODsDZn51gRBeIPuhSo2hsDgLeTQHnkrmpPTm4XeeQVtoA==
dependencies:
path-data-parser "^0.1.0"
points-on-curve "^0.2.0"
points-on-path "^0.2.1"
"@firebase/analytics-types@0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.4.0.tgz#d6716f9fa36a6e340bc0ecfe68af325aa6f60508"