diff --git a/src/actions/actionExport.tsx b/src/actions/actionExport.tsx
index 2c2bec08c..67d442ef8 100644
--- a/src/actions/actionExport.tsx
+++ b/src/actions/actionExport.tsx
@@ -89,6 +89,28 @@ export const actionChangeExportScale = register({
},
});
+export const actionChangeExportPadding = register({
+ name: "changeExportPadding",
+ trackEvent: { category: "export", action: "togglePadding" },
+ perform: (_elements, appState, value) => {
+ return {
+ appState: {
+ ...appState,
+ exportPadding: value ? DEFAULT_EXPORT_PADDING : 0,
+ },
+ commitToHistory: false,
+ };
+ },
+ PanelComponent: ({ appState, updateData }) => (
+ updateData(checked)}
+ >
+ {"Padding"}
+
+ ),
+});
+
export const actionChangeExportBackground = register({
name: "changeExportBackground",
trackEvent: { category: "export", action: "toggleBackground" },
diff --git a/src/actions/types.ts b/src/actions/types.ts
index b04cbef78..1a0acc5a0 100644
--- a/src/actions/types.ts
+++ b/src/actions/types.ts
@@ -68,6 +68,7 @@ export type ActionName =
| "finalize"
| "changeProjectName"
| "changeExportBackground"
+ | "changeExportPadding"
| "changeExportEmbedScene"
| "changeExportScale"
| "saveToActiveFile"
diff --git a/src/appState.ts b/src/appState.ts
index b35cd2a2e..abaec057e 100644
--- a/src/appState.ts
+++ b/src/appState.ts
@@ -1,5 +1,6 @@
import oc from "open-color";
import {
+ DEFAULT_EXPORT_PADDING,
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE,
DEFAULT_TEXT_ALIGN,
@@ -55,6 +56,7 @@ export const getDefaultAppState = (): Omit<
exportScale: defaultExportScale,
exportEmbedScene: false,
exportWithDarkMode: false,
+ exportPadding: DEFAULT_EXPORT_PADDING,
fileHandle: null,
gridSize: null,
isBindingEnabled: true,
@@ -145,6 +147,7 @@ const APP_STATE_STORAGE_CONF = (<
exportBackground: { browser: true, export: false, server: false },
exportEmbedScene: { browser: true, export: false, server: false },
exportScale: { browser: true, export: false, server: false },
+ exportPadding: { browser: true, export: false, server: false },
exportWithDarkMode: { browser: true, export: false, server: false },
fileHandle: { browser: false, export: false, server: false },
gridSize: { browser: true, export: true, server: true },
diff --git a/src/components/ImageExportDialog.tsx b/src/components/ImageExportDialog.tsx
index 2a1e05926..7990c4e93 100644
--- a/src/components/ImageExportDialog.tsx
+++ b/src/components/ImageExportDialog.tsx
@@ -79,7 +79,6 @@ const ImageExportModal = ({
elements,
appState,
files,
- exportPadding = DEFAULT_EXPORT_PADDING,
actionManager,
onExportToPng,
onExportToSvg,
@@ -88,7 +87,6 @@ const ImageExportModal = ({
appState: AppState;
elements: readonly NonDeletedExcalidrawElement[];
files: BinaryFiles;
- exportPadding?: number;
actionManager: ActionManager;
onExportToPng: ExportCB;
onExportToSvg: ExportCB;
@@ -116,7 +114,7 @@ const ImageExportModal = ({
exportToCanvas(exportedElements, appState, files, {
exportBackground,
viewBackgroundColor,
- exportPadding,
+ exportPadding: appState.exportPadding,
})
.then((canvas) => {
// if converting to blob fails, there's some problem that will
@@ -134,7 +132,6 @@ const ImageExportModal = ({
files,
exportedElements,
exportBackground,
- exportPadding,
viewBackgroundColor,
]);
@@ -151,8 +148,10 @@ const ImageExportModal = ({
// dunno why this is needed, but when the items wrap it creates
// an overflow
overflow: "hidden",
+ gap: ".6rem",
}}
>
+ {actionManager.renderAction("changeExportPadding")}
{actionManager.renderAction("changeExportBackground")}
{someElementIsSelected && (
["setState"];
elements: readonly NonDeletedExcalidrawElement[];
files: BinaryFiles;
- exportPadding?: number;
actionManager: ActionManager;
onExportToPng: ExportCB;
onExportToSvg: ExportCB;
@@ -249,7 +246,6 @@ export const ImageExportDialog = ({
elements={elements}
appState={appState}
files={files}
- exportPadding={exportPadding}
actionManager={actionManager}
onExportToPng={onExportToPng}
onExportToSvg={onExportToSvg}
diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx
index 2cf20d01b..ba207c0cf 100644
--- a/src/components/LayerUI.tsx
+++ b/src/components/LayerUI.tsx
@@ -144,6 +144,7 @@ const LayerUI = ({
exportBackground: appState.exportBackground,
name: appState.name,
viewBackgroundColor: appState.viewBackgroundColor,
+ exportPadding: appState.exportPadding,
},
)
.catch(muteFSAbortError)
diff --git a/src/element/bounds.ts b/src/element/bounds.ts
index 793f4c50f..44b8a3625 100644
--- a/src/element/bounds.ts
+++ b/src/element/bounds.ts
@@ -492,7 +492,7 @@ export const getElementBounds = (
export const getCommonBounds = (
elements: readonly ExcalidrawElement[],
-): [number, number, number, number] => {
+): [minX: number, minY: number, maxX: number, maxY: number] => {
if (!elements.length) {
return [0, 0, 0, 0];
}
diff --git a/src/scene/export.ts b/src/scene/export.ts
index 6fb070b33..63986ce5b 100644
--- a/src/scene/export.ts
+++ b/src/scene/export.ts
@@ -177,9 +177,16 @@ const getCanvasSize = (
elements: readonly NonDeletedExcalidrawElement[],
exportPadding: number,
): [number, number, number, number] => {
- const [minX, minY, maxX, maxY] = getCommonBounds(elements);
+ const bounds = getCommonBounds(elements);
+
+ const minX = Math.floor(bounds[0]);
+ const minY = Math.floor(bounds[1]);
+ const maxX = Math.ceil(bounds[2]);
+ const maxY = Math.ceil(bounds[3]);
+
const width = distance(minX, maxX) + exportPadding * 2;
- const height = distance(minY, maxY) + exportPadding + exportPadding;
+ const height =
+ Math.ceil(distance(minY, maxY)) + exportPadding + exportPadding;
return [minX, minY, width, height];
};
diff --git a/src/types.ts b/src/types.ts
index 52a84ef3c..fccea453f 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -113,6 +113,7 @@ export type AppState = {
exportEmbedScene: boolean;
exportWithDarkMode: boolean;
exportScale: number;
+ exportPadding: number;
currentItemStrokeColor: string;
currentItemBackgroundColor: string;
currentItemFillStyle: ExcalidrawElement["fillStyle"];