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"];