From 07839f8d20194a348051af648a966a741d4b6b40 Mon Sep 17 00:00:00 2001
From: Preet <833927+pshihn@users.noreply.github.com>
Date: Tue, 11 May 2021 19:35:35 -0700
Subject: [PATCH] perf: Reduce SVG export size by more than half by reducing
precision to 2 decimal places (#3567)
* render svg with a specified precision
* moved precision to a constant
* fix test case to use rounded values
---
package.json | 2 +-
src/constants.ts | 2 ++
src/renderer/renderElement.ts | 29 +++++++++++++++++--
.../scene/__snapshots__/export.test.ts.snap | 8 ++---
yarn.lock | 8 ++---
5 files changed, 38 insertions(+), 11 deletions(-)
diff --git a/package.json b/package.json
index bb8da267..8017d02f 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"react": "17.0.2",
"react-dom": "17.0.2",
"react-scripts": "4.0.3",
- "roughjs": "4.4.0",
+ "roughjs": "4.4.1",
"sass": "1.32.10",
"socket.io-client": "2.3.1",
"typescript": "4.2.4"
diff --git a/src/constants.ts b/src/constants.ts
index 56e0f998..0911d7eb 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -142,3 +142,5 @@ export const DEFAULT_UI_OPTIONS: AppProps["UIOptions"] = {
export const MQ_MAX_WIDTH_PORTRAIT = 730;
export const MQ_MAX_WIDTH_LANDSCAPE = 1000;
export const MQ_MAX_HEIGHT_LANDSCAPE = 500;
+
+export const MAX_DECIMALS_FOR_SVG_EXPORT = 2;
diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts
index 1e55ec5e..cdc95ba0 100644
--- a/src/renderer/renderElement.ts
+++ b/src/renderer/renderElement.ts
@@ -33,6 +33,7 @@ import rough from "roughjs/bin/rough";
import { Zoom } from "../types";
import { getDefaultAppState } from "../appState";
import getFreeDrawShape from "perfect-freehand";
+import { MAX_DECIMALS_FOR_SVG_EXPORT } from "../constants";
const defaultAppState = getDefaultAppState();
@@ -623,6 +624,22 @@ export const renderElement = (
}
};
+const roughSVGDrawWithPrecision = (
+ rsvg: RoughSVG,
+ drawable: Drawable,
+ precision?: number,
+) => {
+ if (typeof precision === "undefined") {
+ return rsvg.draw(drawable);
+ }
+ const pshape: Drawable = {
+ sets: drawable.sets,
+ shape: drawable.shape,
+ options: { ...drawable.options, fixedDecimalPlaceDigits: precision },
+ };
+ return rsvg.draw(pshape);
+};
+
export const renderElementToSvg = (
element: NonDeletedExcalidrawElement,
rsvg: RoughSVG,
@@ -645,7 +662,11 @@ export const renderElementToSvg = (
case "diamond":
case "ellipse": {
generateElementShape(element, generator);
- const node = rsvg.draw(getShapeForElement(element) as Drawable);
+ const node = roughSVGDrawWithPrecision(
+ rsvg,
+ getShapeForElement(element) as Drawable,
+ MAX_DECIMALS_FOR_SVG_EXPORT,
+ );
const opacity = element.opacity / 100;
if (opacity !== 1) {
node.setAttribute("stroke-opacity", `${opacity}`);
@@ -669,7 +690,11 @@ export const renderElementToSvg = (
group.setAttribute("stroke-linecap", "round");
(getShapeForElement(element) as Drawable[]).forEach((shape) => {
- const node = rsvg.draw(shape);
+ const node = roughSVGDrawWithPrecision(
+ rsvg,
+ shape,
+ MAX_DECIMALS_FOR_SVG_EXPORT,
+ );
if (opacity !== 1) {
node.setAttribute("stroke-opacity", `${opacity}`);
node.setAttribute("fill-opacity", `${opacity}`);
diff --git a/src/tests/scene/__snapshots__/export.test.ts.snap b/src/tests/scene/__snapshots__/export.test.ts.snap
index a482bf18..6e683378 100644
--- a/src/tests/scene/__snapshots__/export.test.ts.snap
+++ b/src/tests/scene/__snapshots__/export.test.ts.snap
@@ -39,13 +39,13 @@ exports[`exportToSvg with default arguments 1`] = `
transform="translate(10 10) rotate(0 50 50)"
>