Jelajahi Sumber

feat: Support Links in Exported SVG (#4791)

Jesse Jurman 3 tahun lalu
induk
melakukan
46e43baad1

+ 18 - 6
src/renderer/renderElement.ts

@@ -836,6 +836,18 @@ export const renderElementToSvg = (
   const cy = (y2 - y1) / 2 - (element.y - y1);
   const degree = (180 * element.angle) / Math.PI;
   const generator = rsvg.generator;
+
+  // element to append node to, most of the time svgRoot
+  let root = svgRoot;
+
+  // if the element has a link, create an anchor tag and make that the new root
+  if (element.link) {
+    const anchorTag = svgRoot.ownerDocument!.createElementNS(SVG_NS, "a");
+    anchorTag.setAttribute("href", element.link);
+    root.appendChild(anchorTag);
+    root = anchorTag;
+  }
+
   switch (element.type) {
     case "selection": {
       // Since this is used only during editing experience, which is canvas based,
@@ -863,7 +875,7 @@ export const renderElementToSvg = (
           offsetY || 0
         }) rotate(${degree} ${cx} ${cy})`,
       );
-      svgRoot.appendChild(node);
+      root.appendChild(node);
       break;
     }
     case "line":
@@ -898,7 +910,7 @@ export const renderElementToSvg = (
         }
         group.appendChild(node);
       });
-      svgRoot.appendChild(group);
+      root.appendChild(group);
       break;
     }
     case "freedraw": {
@@ -923,7 +935,7 @@ export const renderElementToSvg = (
       path.setAttribute("fill", element.strokeColor);
       path.setAttribute("d", getFreeDrawSvgPath(element));
       node.appendChild(path);
-      svgRoot.appendChild(node);
+      root.appendChild(node);
       break;
     }
     case "image": {
@@ -944,7 +956,7 @@ export const renderElementToSvg = (
 
           symbol.appendChild(image);
 
-          svgRoot.prepend(symbol);
+          root.prepend(symbol);
         }
 
         const use = svgRoot.ownerDocument!.createElementNS(SVG_NS, "use");
@@ -965,7 +977,7 @@ export const renderElementToSvg = (
           }) rotate(${degree} ${cx} ${cy})`,
         );
 
-        svgRoot.appendChild(use);
+        root.appendChild(use);
       }
       break;
     }
@@ -1012,7 +1024,7 @@ export const renderElementToSvg = (
           text.setAttribute("direction", direction);
           node.appendChild(text);
         }
-        svgRoot.appendChild(node);
+        root.appendChild(node);
       } else {
         // @ts-ignore
         throw new Error(`Unimplemented type ${element.type}`);

+ 5 - 0
src/tests/fixtures/elementFixture.ts

@@ -37,3 +37,8 @@ export const diamondFixture: ExcalidrawElement = {
   ...elementBase,
   type: "diamond",
 };
+export const rectangleWithLinkFixture: ExcalidrawElement = {
+  ...elementBase,
+  type: "rectangle",
+  link: "excalidraw.com",
+};

File diff ditekan karena terlalu besar
+ 16 - 0
src/tests/scene/__snapshots__/export.test.ts.snap


+ 14 - 1
src/tests/scene/export.test.ts

@@ -1,6 +1,10 @@
 import { NonDeletedExcalidrawElement } from "../../element/types";
 import * as exportUtils from "../../scene/export";
-import { diamondFixture, ellipseFixture } from "../fixtures/elementFixture";
+import {
+  diamondFixture,
+  ellipseFixture,
+  rectangleWithLinkFixture,
+} from "../fixtures/elementFixture";
 
 describe("exportToSvg", () => {
   const ELEMENT_HEIGHT = 100;
@@ -112,4 +116,13 @@ describe("exportToSvg", () => {
     );
     expect(svgElement.innerHTML).toMatchSnapshot();
   });
+
+  it("with elements that have a link", async () => {
+    const svgElement = await exportUtils.exportToSvg(
+      [rectangleWithLinkFixture],
+      DEFAULT_OPTIONS,
+      null,
+    );
+    expect(svgElement.innerHTML).toMatchSnapshot();
+  });
 });

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini