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)" >