From 215128ffdf1c546e42563977214f2e1911828c7b Mon Sep 17 00:00:00 2001 From: Andrew Aquino Date: Wed, 7 Oct 2020 06:37:38 -0700 Subject: [PATCH] add titles with width/height to scale buttons in ExportDialog (#2193) --- src/components/ExportDialog.tsx | 42 ++++++++++------ src/locales/en.json | 1 + src/scene/export.ts | 88 +++++++++++++++++++++++---------- 3 files changed, 91 insertions(+), 40 deletions(-) diff --git a/src/components/ExportDialog.tsx b/src/components/ExportDialog.tsx index 36b243f6..384c7cd0 100644 --- a/src/components/ExportDialog.tsx +++ b/src/components/ExportDialog.tsx @@ -6,7 +6,7 @@ import { ToolButton } from "./ToolButton"; import { clipboard, exportFile, link } from "./icons"; import { NonDeletedExcalidrawElement } from "../element/types"; import { AppState } from "../types"; -import { exportToCanvas } from "../scene/export"; +import { exportToCanvas, getExportSize } from "../scene/export"; import { ActionsManagerInterface } from "../actions/types"; import Stack from "./Stack"; import { t } from "../i18n"; @@ -126,19 +126,33 @@ const ExportModal = ({ {actionManager.renderAction("changeProjectName")} - {scales.map((s) => ( - setScale(s)} - /> - ))} + {scales.map((s) => { + const [width, height] = getExportSize( + exportedElements, + exportPadding, + shouldAddWatermark, + s, + ); + + const scaleButtonTitle = `${t( + "buttons.scale", + )} ${s}x (${width}x${height})`; + + return ( + setScale(s)} + /> + ); + })} {actionManager.renderAction("changeExportBackground")} diff --git a/src/locales/en.json b/src/locales/en.json index 21de0393..673eb53e 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -81,6 +81,7 @@ "exportToSvg": "Export to SVG", "copyToClipboard": "Copy to clipboard", "copyPngToClipboard": "Copy PNG to clipboard", + "scale": "Scale", "save": "Save", "saveAs": "Save as", "load": "Load", diff --git a/src/scene/export.ts b/src/scene/export.ts index 30007167..77fdf7a8 100644 --- a/src/scene/export.ts +++ b/src/scene/export.ts @@ -11,6 +11,7 @@ import { t } from "../i18n"; import { DEFAULT_FONT_FAMILY, DEFAULT_VERTICAL_ALIGN } from "../constants"; export const SVG_EXPORT_TAG = ``; +const WATERMARK_HEIGHT = 16; export const exportToCanvas = ( elements: readonly NonDeletedExcalidrawElement[], @@ -35,19 +36,13 @@ export const exportToCanvas = ( return tempCanvas; }, ) => { - let sceneElements = elements; - if (shouldAddWatermark) { - const [, , maxX, maxY] = getCommonBounds(elements); - sceneElements = [...sceneElements, getWatermarkElement(maxX, maxY)]; - } + const sceneElements = getElementsAndWatermark(elements, shouldAddWatermark); - // calculate smallest area to fit the contents in - const [minX, minY, maxX, maxY] = getCommonBounds(sceneElements); - const width = distance(minX, maxX) + exportPadding * 2; - const height = - distance(minY, maxY) + - exportPadding + - (shouldAddWatermark ? 0 : exportPadding); + const [minX, minY, width, height] = getCanvasSize( + sceneElements, + exportPadding, + shouldAddWatermark, + ); const tempCanvas: any = createCanvas(width, height); @@ -93,19 +88,13 @@ export const exportToSvg = ( shouldAddWatermark: boolean; }, ): SVGSVGElement => { - let sceneElements = elements; - if (shouldAddWatermark) { - const [, , maxX, maxY] = getCommonBounds(elements); - sceneElements = [...sceneElements, getWatermarkElement(maxX, maxY)]; - } + const sceneElements = getElementsAndWatermark(elements, shouldAddWatermark); - // calculate canvas dimensions - const [minX, minY, maxX, maxY] = getCommonBounds(sceneElements); - const width = distance(minX, maxX) + exportPadding * 2; - const height = - distance(minY, maxY) + - exportPadding + - (shouldAddWatermark ? 0 : exportPadding); + const [minX, minY, width, height] = getCanvasSize( + sceneElements, + exportPadding, + shouldAddWatermark, + ); // initialze SVG root const svgRoot = document.createElementNS(SVG_NS, "svg"); @@ -149,15 +138,29 @@ export const exportToSvg = ( return svgRoot; }; +const getElementsAndWatermark = ( + elements: readonly NonDeletedExcalidrawElement[], + shouldAddWatermark: boolean, +): readonly NonDeletedExcalidrawElement[] => { + let _elements = [...elements]; + + if (shouldAddWatermark) { + const [, , maxX, maxY] = getCommonBounds(elements); + _elements = [..._elements, getWatermarkElement(maxX, maxY)]; + } + + return _elements; +}; + const getWatermarkElement = (maxX: number, maxY: number) => { return newTextElement({ text: t("labels.madeWithExcalidraw"), - fontSize: 16, + fontSize: WATERMARK_HEIGHT, fontFamily: DEFAULT_FONT_FAMILY, textAlign: "right", verticalAlign: DEFAULT_VERTICAL_ALIGN, x: maxX, - y: maxY + 16, + y: maxY + WATERMARK_HEIGHT, strokeColor: oc.gray[5], backgroundColor: "transparent", fillStyle: "hachure", @@ -168,3 +171,36 @@ const getWatermarkElement = (maxX: number, maxY: number) => { strokeSharpness: "sharp", }); }; + +// calculate smallest area to fit the contents in +const getCanvasSize = ( + elements: readonly NonDeletedExcalidrawElement[], + exportPadding: number, + shouldAddWatermark: boolean, +): [number, number, number, number] => { + const [minX, minY, maxX, maxY] = getCommonBounds(elements); + const width = distance(minX, maxX) + exportPadding * 2; + const height = + distance(minY, maxY) + + exportPadding + + (shouldAddWatermark ? 0 : exportPadding); + + return [minX, minY, width, height]; +}; + +export const getExportSize = ( + elements: readonly NonDeletedExcalidrawElement[], + exportPadding: number, + shouldAddWatermark: boolean, + scale: number, +): [number, number] => { + const sceneElements = getElementsAndWatermark(elements, shouldAddWatermark); + + const [, , width, height] = getCanvasSize( + sceneElements, + exportPadding, + shouldAddWatermark, + ).map((dimension) => Math.trunc(dimension * scale)); + + return [width, height]; +};