export.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import rough from "roughjs/bin/rough";
  2. import { ExcalidrawElement } from "../element/types";
  3. import { getCommonBounds } from "../element/bounds";
  4. import { renderScene, renderSceneToSvg } from "../renderer/renderScene";
  5. import { distance, SVG_NS } from "../utils";
  6. import { normalizeScroll } from "./scroll";
  7. import { AppState } from "../types";
  8. export function exportToCanvas(
  9. elements: readonly ExcalidrawElement[],
  10. appState: AppState,
  11. {
  12. exportBackground,
  13. exportPadding = 10,
  14. viewBackgroundColor,
  15. scale = 1,
  16. }: {
  17. exportBackground: boolean;
  18. exportPadding?: number;
  19. scale?: number;
  20. viewBackgroundColor: string;
  21. },
  22. createCanvas: (width: number, height: number) => any = function(
  23. width,
  24. height,
  25. ) {
  26. const tempCanvas = document.createElement("canvas");
  27. tempCanvas.width = width * scale;
  28. tempCanvas.height = height * scale;
  29. return tempCanvas;
  30. },
  31. ) {
  32. // calculate smallest area to fit the contents in
  33. const [minX, minY, maxX, maxY] = getCommonBounds(elements);
  34. const width = distance(minX, maxX) + exportPadding * 2;
  35. const height = distance(minY, maxY) + exportPadding * 2;
  36. const tempCanvas: any = createCanvas(width, height);
  37. renderScene(
  38. elements,
  39. appState,
  40. null,
  41. scale,
  42. rough.canvas(tempCanvas),
  43. tempCanvas,
  44. {
  45. viewBackgroundColor: exportBackground ? viewBackgroundColor : null,
  46. scrollX: normalizeScroll(-minX + exportPadding),
  47. scrollY: normalizeScroll(-minY + exportPadding),
  48. zoom: 1,
  49. remotePointerViewportCoords: {},
  50. },
  51. {
  52. renderScrollbars: false,
  53. renderSelection: false,
  54. renderOptimizations: false,
  55. },
  56. );
  57. return tempCanvas;
  58. }
  59. export function exportToSvg(
  60. elements: readonly ExcalidrawElement[],
  61. {
  62. exportBackground,
  63. exportPadding = 10,
  64. viewBackgroundColor,
  65. }: {
  66. exportBackground: boolean;
  67. exportPadding?: number;
  68. viewBackgroundColor: string;
  69. },
  70. ): SVGSVGElement {
  71. // calculate canvas dimensions
  72. const [minX, minY, maxX, maxY] = getCommonBounds(elements);
  73. const width = distance(minX, maxX) + exportPadding * 2;
  74. const height = distance(minY, maxY) + exportPadding * 2;
  75. // initialze SVG root
  76. const svgRoot = document.createElementNS(SVG_NS, "svg");
  77. svgRoot.setAttribute("version", "1.1");
  78. svgRoot.setAttribute("xmlns", SVG_NS);
  79. svgRoot.setAttribute("viewBox", `0 0 ${width} ${height}`);
  80. svgRoot.innerHTML = `
  81. <defs>
  82. <style>
  83. @font-face {
  84. font-family: "Virgil";
  85. src: url("https://excalidraw.com/FG_Virgil.ttf");
  86. }
  87. @font-face {
  88. font-family: "Cascadia";
  89. src: url("https://excalidraw.com/Cascadia.ttf");
  90. }
  91. </style>
  92. </defs>
  93. `;
  94. // render backgroiund rect
  95. if (exportBackground && viewBackgroundColor) {
  96. const rect = svgRoot.ownerDocument!.createElementNS(SVG_NS, "rect");
  97. rect.setAttribute("x", "0");
  98. rect.setAttribute("y", "0");
  99. rect.setAttribute("width", `${width}`);
  100. rect.setAttribute("height", `${height}`);
  101. rect.setAttribute("fill", viewBackgroundColor);
  102. svgRoot.appendChild(rect);
  103. }
  104. const rsvg = rough.svg(svgRoot);
  105. renderSceneToSvg(elements, rsvg, svgRoot, {
  106. offsetX: -minX + exportPadding,
  107. offsetY: -minY + exportPadding,
  108. });
  109. return svgRoot;
  110. }