Selaa lähdekoodia

Revert 400 and 420 (#422)

* revert #400 font file

* Revert "Revert "Set scale for export images (#416)" (#420)"

This reverts commit d603921234b9ae1483f9f0e0f79fb1c3d0878370.
David Luzar 5 vuotta sitten
vanhempi
commit
6892348c3d

BIN
public/FG_Virgil.ttf


+ 1 - 1
public/index.html

@@ -53,7 +53,7 @@
     <link rel="icon" href="%PUBLIC_URL%/logo.png" />
     <link
       rel="preload"
-      href="https://uploads.codesandbox.io/uploads/user/f7fdc300-3c43-44c1-9a59-4338a82a9954/xhjR-FG_Virgil.ttf"
+      href="https://uploads.codesandbox.io/uploads/user/f7fdc300-3c43-44c1-9a59-4338a82a9954/_oPE-FG_Virgil.ttf"
       as="font"
       type="font/ttf"
       crossorigin="anonymous"

+ 6 - 0
src/components/ExportDialog.css

@@ -44,3 +44,9 @@
   justify-content: space-between;
   flex-wrap: wrap;
 }
+
+.ExportDialog__scales {
+  display: flex;
+  align-items: baseline;
+  justify-content: flex-end;
+}

+ 31 - 6
src/components/ExportDialog.tsx

@@ -18,6 +18,11 @@ const probablySupportsClipboard =
   "write" in navigator.clipboard &&
   "ClipboardItem" in window;
 
+const scales = [1, 2, 3];
+const defaultScale = scales.includes(devicePixelRatio) ? devicePixelRatio : 1;
+
+type ExportCB = (elements: readonly ExcalidrawElement[], scale: number) => void;
+
 export function ExportDialog({
   elements,
   appState,
@@ -32,11 +37,12 @@ export function ExportDialog({
   exportPadding?: number;
   actionManager: ActionsManagerInterface;
   syncActionResult: UpdaterFn;
-  onExportToPng(elements: readonly ExcalidrawElement[]): void;
-  onExportToClipboard(elements: readonly ExcalidrawElement[]): void;
+  onExportToPng: ExportCB;
+  onExportToClipboard: ExportCB;
 }) {
   const someElementIsSelected = elements.some(element => element.isSelected);
   const [modalIsShown, setModalIsShown] = useState(false);
+  const [scale, setScale] = useState(defaultScale);
   const [exportSelected, setExportSelected] = useState(someElementIsSelected);
   const previeRef = useRef<HTMLDivElement>(null);
   const { exportBackground, viewBackgroundColor } = appState;
@@ -54,7 +60,8 @@ export function ExportDialog({
     const canvas = getExportCanvasPreview(exportedElements, {
       exportBackground,
       viewBackgroundColor,
-      exportPadding
+      exportPadding,
+      scale
     });
     previewNode?.appendChild(canvas);
     return () => {
@@ -65,7 +72,8 @@ export function ExportDialog({
     exportedElements,
     exportBackground,
     exportPadding,
-    viewBackgroundColor
+    viewBackgroundColor,
+    scale
   ]);
 
   function handleClose() {
@@ -98,7 +106,7 @@ export function ExportDialog({
                     icon={downloadFile}
                     title="Export to PNG"
                     aria-label="Export to PNG"
-                    onClick={() => onExportToPng(exportedElements)}
+                    onClick={() => onExportToPng(exportedElements, scale)}
                   />
 
                   {probablySupportsClipboard && (
@@ -107,7 +115,9 @@ export function ExportDialog({
                       icon={clipboard}
                       title="Copy to clipboard"
                       aria-label="Copy to clipboard"
-                      onClick={() => onExportToClipboard(exportedElements)}
+                      onClick={() =>
+                        onExportToClipboard(exportedElements, scale)
+                      }
                     />
                   )}
                 </Stack.Row>
@@ -119,6 +129,21 @@ export function ExportDialog({
                   syncActionResult
                 )}
                 <Stack.Col gap={1}>
+                  <div className="ExportDialog__scales">
+                    <Stack.Row gap={1} align="baseline">
+                      {scales.map(s => (
+                        <ToolIcon
+                          size="s"
+                          type="radio"
+                          icon={"x" + s}
+                          name="export-canvas-scale"
+                          id="export-canvas-scale"
+                          checked={scale === s}
+                          onChange={() => setScale(s)}
+                        />
+                      ))}
+                    </Stack.Row>
+                  </div>
                   {actionManager.renderAction(
                     "changeExportBackground",
                     elements,

+ 1 - 1
src/components/Stack.tsx

@@ -5,7 +5,7 @@ import React from "react";
 type StackProps = {
   children: React.ReactNode;
   gap?: number;
-  align?: "start" | "center" | "end";
+  align?: "start" | "center" | "end" | "baseline";
 };
 
 function RowStack({ children, gap, align }: StackProps) {

+ 6 - 0
src/components/ToolIcon.scss

@@ -20,6 +20,12 @@
   }
 }
 
+.ToolIcon_size_s .ToolIcon__icon {
+  width: 25px;
+  height: 25px;
+  font-size: 0.8em;
+}
+
 .ToolIcon_type_button {
   padding: 0;
   border: none;

+ 10 - 2
src/components/ToolIcon.tsx

@@ -2,6 +2,8 @@ import "./ToolIcon.scss";
 
 import React from "react";
 
+type ToolIconSize = "s" | "m";
+
 type ToolIconProps =
   | {
       type: "button";
@@ -11,6 +13,7 @@ type ToolIconProps =
       name?: string;
       id?: string;
       onClick?(): void;
+      size?: ToolIconSize;
     }
   | {
       type: "radio";
@@ -20,12 +23,17 @@ type ToolIconProps =
       id?: string;
       checked: boolean;
       onChange?(): void;
+      size?: ToolIconSize;
     };
 
+const DEFAULT_SIZE: ToolIconSize = "m";
+
 export function ToolIcon(props: ToolIconProps) {
+  const sizeCn = `ToolIcon_size_${props.size || DEFAULT_SIZE}`;
+
   if (props.type === "button")
     return (
-      <label className="ToolIcon" title={props.title}>
+      <label className={`ToolIcon ${sizeCn}`} title={props.title}>
         <button
           className="ToolIcon_type_button"
           aria-label={props["aria-label"]}
@@ -38,7 +46,7 @@ export function ToolIcon(props: ToolIconProps) {
     );
 
   return (
-    <label className="ToolIcon" title={props.title}>
+    <label className={`ToolIcon ${sizeCn}`} title={props.title}>
       <input
         className="ToolIcon_type_radio"
         type="radio"

+ 14 - 9
src/index.tsx

@@ -478,18 +478,23 @@ export class App extends React.Component<{}, AppState> {
             appState={this.state}
             actionManager={this.actionManager}
             syncActionResult={this.syncActionResult}
-            onExportToPng={exportedElements => {
+            onExportToPng={(exportedElements, scale) => {
               if (this.canvas)
-                exportCanvas("png", exportedElements, this.canvas, this.state);
+                exportCanvas("png", exportedElements, this.canvas, {
+                  exportBackground: this.state.exportBackground,
+                  name: this.state.name,
+                  viewBackgroundColor: this.state.viewBackgroundColor,
+                  scale
+                });
             }}
-            onExportToClipboard={exportedElements => {
+            onExportToClipboard={(exportedElements, scale) => {
               if (this.canvas)
-                exportCanvas(
-                  "clipboard",
-                  exportedElements,
-                  this.canvas,
-                  this.state
-                );
+                exportCanvas("clipboard", exportedElements, this.canvas, {
+                  exportBackground: this.state.exportBackground,
+                  name: this.state.name,
+                  viewBackgroundColor: this.state.viewBackgroundColor,
+                  scale
+                });
             }}
           />
           {this.actionManager.renderAction(

+ 18 - 42
src/scene/data.ts

@@ -174,10 +174,12 @@ export function getExportCanvasPreview(
   {
     exportBackground,
     exportPadding = 10,
-    viewBackgroundColor
+    viewBackgroundColor,
+    scale = 1
   }: {
     exportBackground: boolean;
     exportPadding?: number;
+    scale?: number;
     viewBackgroundColor: string;
   }
 ) {
@@ -200,8 +202,13 @@ export function getExportCanvasPreview(
   }
 
   const tempCanvas = document.createElement("canvas");
-  tempCanvas.width = distance(subCanvasX1, subCanvasX2) + exportPadding * 2;
-  tempCanvas.height = distance(subCanvasY1, subCanvasY2) + exportPadding * 2;
+  const width = distance(subCanvasX1, subCanvasX2) + exportPadding * 2;
+  const height = distance(subCanvasY1, subCanvasY2) + exportPadding * 2;
+  tempCanvas.style.width = width + "px";
+  tempCanvas.style.height = height + "px";
+  tempCanvas.width = width * scale;
+  tempCanvas.height = height * scale;
+  tempCanvas.getContext("2d")?.scale(scale, scale);
 
   renderScene(
     elements,
@@ -230,58 +237,27 @@ export async function exportCanvas(
     exportBackground,
     exportPadding = 10,
     viewBackgroundColor,
-    name
+    name,
+    scale = 1
   }: {
     exportBackground: boolean;
     exportPadding?: number;
     viewBackgroundColor: string;
-    scrollX: number;
-    scrollY: number;
     name: string;
+    scale?: number;
   }
 ) {
   if (!elements.length) return window.alert("Cannot export empty canvas.");
   // calculate smallest area to fit the contents in
 
-  let subCanvasX1 = Infinity;
-  let subCanvasX2 = 0;
-  let subCanvasY1 = Infinity;
-  let subCanvasY2 = 0;
-
-  elements.forEach(element => {
-    const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
-    subCanvasX1 = Math.min(subCanvasX1, x1);
-    subCanvasY1 = Math.min(subCanvasY1, y1);
-    subCanvasX2 = Math.max(subCanvasX2, x2);
-    subCanvasY2 = Math.max(subCanvasY2, y2);
+  const tempCanvas = getExportCanvasPreview(elements, {
+    exportBackground,
+    viewBackgroundColor,
+    exportPadding,
+    scale
   });
-
-  function distance(x: number, y: number) {
-    return Math.abs(x > y ? x - y : y - x);
-  }
-
-  const tempCanvas = document.createElement("canvas");
   tempCanvas.style.display = "none";
   document.body.appendChild(tempCanvas);
-  tempCanvas.width = distance(subCanvasX1, subCanvasX2) + exportPadding * 2;
-  tempCanvas.height = distance(subCanvasY1, subCanvasY2) + exportPadding * 2;
-
-  renderScene(
-    elements,
-    rough.canvas(tempCanvas),
-    tempCanvas,
-    {
-      viewBackgroundColor: exportBackground ? viewBackgroundColor : null,
-      scrollX: 0,
-      scrollY: 0
-    },
-    {
-      offsetX: -subCanvasX1 + exportPadding,
-      offsetY: -subCanvasY1 + exportPadding,
-      renderScrollbars: false,
-      renderSelection: false
-    }
-  );
 
   if (type === "png") {
     const fileName = `${name}.png`;

+ 1 - 1
src/styles.scss

@@ -3,7 +3,7 @@
 /* http://www.eaglefonts.com/fg-virgil-ttf-131249.htm */
 @font-face {
   font-family: "Virgil";
-  src: url("https://uploads.codesandbox.io/uploads/user/f7fdc300-3c43-44c1-9a59-4338a82a9954/xhjR-FG_Virgil.ttf");
+  src: url("https://uploads.codesandbox.io/uploads/user/f7fdc300-3c43-44c1-9a59-4338a82a9954/_oPE-FG_Virgil.ttf");
   font-display: swap;
 }