1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2024-11-02 03:25:53 +01:00

Excalidraw export (#2246)

This commit is contained in:
Guillaume Grossetie 2020-11-02 20:14:20 +01:00 committed by GitHub
parent 58861e87e5
commit a7da8901d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 6250 additions and 10 deletions

33
.github/workflows/build-packages.yml vendored Normal file

@ -0,0 +1,33 @@
name: Build packages
on:
push:
branches:
- master
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Install dependencies
run: |
npm ci
npm ci --prefix src/packages/excalidraw
npm ci --prefix src/packages/utils
- name: Build @excalidraw/excalidraw
run: |
npm run pack --prefix src/packages/excalidraw
- name: Build @excalidraw/utils
run: |
npm run pack --prefix src/packages/utils

1
.gitignore vendored

@ -15,3 +15,4 @@ yarn.lock
.idea
dist/
.eslintcache
*.tgz

@ -2,7 +2,7 @@ import React, { useState, useLayoutEffect, useEffect } from "react";
import { LoadingMessage } from "../components/LoadingMessage";
import { TopErrorBoundary } from "../components/TopErrorBoundary";
import Excalidraw from "../excalidraw-embed/index";
import Excalidraw from "../packages/excalidraw/index";
import {
importFromLocalStorage,

@ -1,13 +1,13 @@
import React, { useEffect, forwardRef } from "react";
import { InitializeApp } from "../components/InitializeApp";
import App, { ExcalidrawImperativeAPI } from "../components/App";
import { InitializeApp } from "../../components/InitializeApp";
import App, { ExcalidrawImperativeAPI } from "../../components/App";
import "../css/app.scss";
import "../css/styles.scss";
import "../../css/app.scss";
import "../../css/styles.scss";
import { ExcalidrawProps } from "../types";
import { IsMobileProvider } from "../is-mobile";
import { ExcalidrawProps } from "../../types";
import { IsMobileProvider } from "../../is-mobile";
const Excalidraw = (props: ExcalidrawProps) => {
const {

@ -9,7 +9,7 @@ module.exports = {
mode: "production",
entry: {
"excalidraw.min": "./index.tsx",
"fonts.min": "../../public/fonts.css",
"fonts.min": "../../../public/fonts.css",
},
output: {
path: path.resolve(__dirname, "dist"),
@ -40,7 +40,7 @@ module.exports = {
loader: "ts-loader",
options: {
transpileOnly: true,
configFile: path.resolve(__dirname, "tsconfig.prod.json"),
configFile: path.resolve(__dirname, "../tsconfig.prod.json"),
},
},
{

89
src/packages/utils.ts Normal file

@ -0,0 +1,89 @@
import {
exportToCanvas as _exportToCanvas,
exportToSvg as _exportToSvg,
} from "../scene/export";
import { getDefaultAppState } from "../appState";
import { AppState } from "../types";
import { ExcalidrawElement } from "../element/types";
import { getNonDeletedElements } from "../element";
type ExportOpts = {
elements: readonly ExcalidrawElement[];
appState?: Omit<AppState, "offsetTop" | "offsetLeft">;
getDimensions: (
width: number,
height: number,
) => { width: number; height: number; scale: number };
};
const exportToCanvas = ({
elements,
appState = getDefaultAppState(),
getDimensions = (width, height) => ({ width, height, scale: 1 }),
}: ExportOpts) => {
return _exportToCanvas(
getNonDeletedElements(elements),
{ ...appState, offsetTop: 0, offsetLeft: 0 },
{
exportBackground: appState.exportBackground ?? true,
viewBackgroundColor: appState.viewBackgroundColor ?? "#FFF",
shouldAddWatermark: appState.shouldAddWatermark ?? false,
},
(width: number, height: number) => {
const canvas = document.createElement("canvas");
const ret = getDimensions(width, height);
canvas.width = ret.width;
canvas.height = ret.height;
return canvas;
},
);
};
export const exportToBlob = (
opts: ExportOpts & {
mimeType?: string;
quality?: number;
},
): Promise<Blob | null> => {
const canvas = exportToCanvas(opts);
let { mimeType = "image/png", quality } = opts;
if (mimeType === "image/png" && typeof quality === "number") {
console.warn(`"quality" will be ignored for "image/png" mimeType`);
}
if (mimeType === "image/jpg") {
mimeType = "image/jpeg";
}
quality = quality ? quality : /image\/jpe?g/.test(mimeType) ? 0.92 : 0.8;
return new Promise((resolve) => {
canvas.toBlob(
(blob: Blob | null) => {
resolve(blob);
},
mimeType,
quality,
);
});
};
export const exportToSvg = ({
elements,
appState = getDefaultAppState(),
exportPadding,
metadata,
}: ExportOpts & {
exportPadding?: number;
metadata?: string;
}): SVGSVGElement => {
return _exportToSvg(getNonDeletedElements(elements), {
...appState,
exportPadding,
metadata,
});
};

@ -0,0 +1,9 @@
# Changelog
## [Unreleased]
First release of `@excalidraw/utils` to provide utilities functions.
- Added `exportToBlob` and `exportToSvg` to export an Excalidraw diagram definition, respectively,
to a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and
to a [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement) ([#2246](https://github.com/excalidraw/excalidraw/pull/2246))

@ -0,0 +1,92 @@
# @excalidraw/utils
## Install
npm i @excalidraw/utils
If you prefer Yarn over npm, use this command to install the Excalidraw utils package:
yarn add @excalidraw/utils
## API
### `exportToBlob` (async)
Export an Excalidraw diagram to a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
### `exportToSvg`
Export an Excalidraw diagram to a [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement).
## Usage
Excalidraw utils is published as a UMD (Universal Module Definition).
If you are using a Web bundler (for instance, Webpack), you can import it as an ES6 module:
```js
import { exportToSvg, exportToBlob } from "@excalidraw/utils";
```
To use it in a browser directly:
```html
<script src="https://unpkg.com/@excalidraw/utils@0.1.0/dist/excalidraw.min.js"></script>
<script>
// ExcalidrawUtils is a global variable defined by excalidraw.min.js
const { exportToSvg, exportToBlob } = ExcalidrawUtils;
</script>
```
Here's the `exportToBlob` and `exportToSvg` functions in action:
```js
const excalidrawDiagram = {
type: "excalidraw",
version: 2,
source: "https://excalidraw.com",
elements: [
{
id: "vWrqOAfkind2qcm7LDAGZ",
type: "ellipse",
x: 414,
y: 237,
width: 214,
height: 214,
angle: 0,
strokeColor: "#000000",
backgroundColor: "#15aabf",
fillStyle: "hachure",
strokeWidth: 1,
strokeStyle: "solid",
roughness: 1,
opacity: 100,
groupIds: [],
strokeSharpness: "sharp",
seed: 1041657908,
version: 120,
versionNonce: 1188004276,
isDeleted: false,
boundElementIds: null,
},
],
appState: {
viewBackgroundColor: "#ffffff",
gridSize: null,
},
};
// Export the Excalidraw diagram as SVG string
const svg = exportToSvg(excalidrawDiagram);
console.log(svg.outerHTML);
// Export the Excalidraw diagram as PNG Blob URL
(async () => {
const blob = await exportToBlob({
...excalidrawDiagram,
mimeType: "image/png",
});
const urlCreator = window.URL || window.webkitURL;
console.log(urlCreator.createObjectURL(blob));
})();
```

@ -0,0 +1 @@
export { exportToBlob, exportToSvg } from "../utils.ts";

5920
src/packages/utils/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

@ -0,0 +1,55 @@
{
"name": "@excalidraw/utils",
"version": "0.1.0",
"main": "dist/excalidraw-utils.min.js",
"files": [
"dist/*"
],
"description": "Excalidraw utilities functions",
"license": "MIT",
"keywords": [
"excalidraw",
"excalidraw-utils"
],
"browserslist": {
"production": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all",
"not safari < 12",
"not kaios <= 2.5",
"not edge < 79",
"not chrome < 70",
"not and_uc < 13",
"not samsung < 10"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@babel/core": "7.9.0",
"@babel/plugin-transform-arrow-functions": "7.8.3",
"@babel/plugin-transform-async-to-generator": "7.8.3",
"@babel/plugin-transform-runtime": "^7.12.1",
"@babel/plugin-transform-typescript": "7.9.4",
"@babel/preset-env": "7.9.5",
"@babel/preset-typescript": "7.9.0",
"babel-loader": "8.1.0",
"babel-plugin-transform-class-properties": "6.24.1",
"cross-env": "7.0.2",
"file-loader": "6.0.0",
"ts-loader": "7.0.0",
"webpack": "4.42.0",
"webpack-cli": "3.3.11"
},
"bugs": "https://github.com/excalidraw/excalidraw/issues",
"repository": "https://github.com/excalidraw/excalidraw",
"scripts": {
"build:umd": "cross-env NODE_ENV=production webpack --config webpack.prod.config.js",
"pack": "npm run build:umd && npm pack"
}
}

@ -0,0 +1,40 @@
const webpack = require("webpack");
const path = require("path");
module.exports = {
mode: "production",
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
optimization: {
runtimeChunk: false,
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "excalidraw-utils.min.js",
library: "ExcalidrawUtils",
libraryTarget: "umd",
},
entry: "./index.js",
module: {
rules: [
{
test: /\.(ts|tsx|js)$/,
use: [
{
loader: "ts-loader",
options: {
transpileOnly: true,
configFile: path.resolve(__dirname, "../tsconfig.prod.json"),
},
},
],
},
],
},
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
],
};

@ -128,7 +128,7 @@ export const exportToSvg = (
</defs>
`;
// render backgroiund rect
// render background rect
if (exportBackground && viewBackgroundColor) {
const rect = svgRoot.ownerDocument!.createElementNS(SVG_NS, "rect");
rect.setAttribute("x", "0");