Adding ability to copy to clipboard as SVG (#1250)

This commit is contained in:
Roxana Chiorean 2020-04-05 16:13:17 -07:00 committed by GitHub
parent 2de4fe29ad
commit d5366db341
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 7 deletions

View File

@ -97,6 +97,14 @@ export async function copyCanvasToClipboardAsPng(canvas: HTMLCanvasElement) {
}); });
} }
export async function copyCanvasToClipboardAsSvg(svgroot: SVGSVGElement) {
try {
await navigator.clipboard.writeText(svgroot.outerHTML);
} catch (error) {
console.error(error);
}
}
export async function copyTextToSystemClipboard(text: string | null) { export async function copyTextToSystemClipboard(text: string | null) {
let copied = false; let copied = false;
if (probablySupportsClipboardWriteText) { if (probablySupportsClipboardWriteText) {

View File

@ -88,6 +88,7 @@ import {
copyToAppClipboard, copyToAppClipboard,
getClipboardContent, getClipboardContent,
probablySupportsClipboardBlob, probablySupportsClipboardBlob,
probablySupportsClipboardWriteText,
} from "../clipboard"; } from "../clipboard";
import { normalizeScroll } from "../scene"; import { normalizeScroll } from "../scene";
import { getCenter, getDistance } from "../gesture"; import { getCenter, getDistance } from "../gesture";
@ -565,6 +566,22 @@ export class App extends React.Component<any, AppState> {
); );
}; };
private copyToClipboardAsSvg = () => {
const selectedElements = getSelectedElements(
globalSceneState.getAllElements(),
this.state,
);
exportCanvas(
"clipboard-svg",
selectedElements.length
? selectedElements
: globalSceneState.getAllElements(),
this.state,
this.canvas!,
this.state,
);
};
private onTapStart = (event: TouchEvent) => { private onTapStart = (event: TouchEvent) => {
if (!didTapTwice) { if (!didTapTwice) {
didTapTwice = true; didTapTwice = true;
@ -2661,6 +2678,11 @@ export class App extends React.Component<any, AppState> {
label: t("labels.copyAsPng"), label: t("labels.copyAsPng"),
action: this.copyToClipboardAsPng, action: this.copyToClipboardAsPng,
}, },
probablySupportsClipboardWriteText &&
hasNonDeletedElements(globalSceneState.getAllElements()) && {
label: t("labels.copyAsSvg"),
action: this.copyToClipboardAsSvg,
},
...this.actionManager.getContextMenuItems((action) => ...this.actionManager.getContextMenuItems((action) =>
this.canvasOnlyActions.includes(action.name), this.canvasOnlyActions.includes(action.name),
), ),
@ -2689,6 +2711,10 @@ export class App extends React.Component<any, AppState> {
label: t("labels.copyAsPng"), label: t("labels.copyAsPng"),
action: this.copyToClipboardAsPng, action: this.copyToClipboardAsPng,
}, },
probablySupportsClipboardWriteText && {
label: t("labels.copyAsSvg"),
action: this.copyToClipboardAsSvg,
},
...this.actionManager.getContextMenuItems( ...this.actionManager.getContextMenuItems(
(action) => !this.canvasOnlyActions.includes(action.name), (action) => !this.canvasOnlyActions.includes(action.name),
), ),

View File

@ -7,7 +7,10 @@ import { exportToCanvas, exportToSvg } from "../scene/export";
import { fileSave } from "browser-nativefs"; import { fileSave } from "browser-nativefs";
import { t } from "../i18n"; import { t } from "../i18n";
import { copyCanvasToClipboardAsPng } from "../clipboard"; import {
copyCanvasToClipboardAsPng,
copyCanvasToClipboardAsSvg,
} from "../clipboard";
import { serializeAsJSON } from "./json"; import { serializeAsJSON } from "./json";
import { ExportType } from "../scene/types"; import { ExportType } from "../scene/types";
@ -299,16 +302,21 @@ export async function exportCanvas(
if (!hasNonDeletedElements(elements)) { if (!hasNonDeletedElements(elements)) {
return window.alert(t("alerts.cannotExportEmptyCanvas")); return window.alert(t("alerts.cannotExportEmptyCanvas"));
} }
if (type === "svg") { if (type === "svg" || type === "clipboard-svg") {
const tempSvg = exportToSvg(elements, { const tempSvg = exportToSvg(elements, {
exportBackground, exportBackground,
viewBackgroundColor, viewBackgroundColor,
exportPadding, exportPadding,
}); });
await fileSave(new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }), { if (type === "svg") {
fileName: `${name}.svg`, await fileSave(new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }), {
}); fileName: `${name}.svg`,
return; });
return;
} else if (type === "clipboard-svg") {
copyCanvasToClipboardAsSvg(tempSvg);
return;
}
} }
const tempCanvas = exportToCanvas(elements, appState, { const tempCanvas = exportToCanvas(elements, appState, {

View File

@ -4,6 +4,7 @@
"selectAll": "Select All", "selectAll": "Select All",
"copy": "Copy", "copy": "Copy",
"copyAsPng": "Copy to clipboard as PNG", "copyAsPng": "Copy to clipboard as PNG",
"copyAsSvg": "Copy to clipboard as SVG",
"bringForward": "Bring Forward", "bringForward": "Bring Forward",
"sendToBack": "Send To Back", "sendToBack": "Send To Back",
"bringToFront": "Bring To Front", "bringToFront": "Bring To Front",

View File

@ -22,7 +22,12 @@ export interface Scene {
elements: ExcalidrawTextElement[]; elements: ExcalidrawTextElement[];
} }
export type ExportType = "png" | "clipboard" | "backend" | "svg"; export type ExportType =
| "png"
| "clipboard"
| "clipboard-svg"
| "backend"
| "svg";
export type ScrollBars = { export type ScrollBars = {
horizontal: { horizontal: {