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:
parent
58861e87e5
commit
a7da8901d8
33
.github/workflows/build-packages.yml
vendored
Normal file
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
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
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,
|
||||
});
|
||||
};
|
9
src/packages/utils/CHANGELOG.md
Normal file
9
src/packages/utils/CHANGELOG.md
Normal file
@ -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))
|
92
src/packages/utils/README.md
Normal file
92
src/packages/utils/README.md
Normal file
@ -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));
|
||||
})();
|
||||
```
|
1
src/packages/utils/index.js
Normal file
1
src/packages/utils/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { exportToBlob, exportToSvg } from "../utils.ts";
|
5920
src/packages/utils/package-lock.json
generated
Normal file
5920
src/packages/utils/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
55
src/packages/utils/package.json
Normal file
55
src/packages/utils/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
40
src/packages/utils/webpack.prod.config.js
Normal file
40
src/packages/utils/webpack.prod.config.js
Normal file
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user