diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index 126d6677..6db858d9 100644 --- a/src/renderer/renderElement.ts +++ b/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}`); diff --git a/src/tests/fixtures/elementFixture.ts b/src/tests/fixtures/elementFixture.ts index 0b84d0af..eca71256 100644 --- a/src/tests/fixtures/elementFixture.ts +++ b/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", +}; diff --git a/src/tests/scene/__snapshots__/export.test.ts.snap b/src/tests/scene/__snapshots__/export.test.ts.snap index c75f2b2f..c0290f75 100644 --- a/src/tests/scene/__snapshots__/export.test.ts.snap +++ b/src/tests/scene/__snapshots__/export.test.ts.snap @@ -71,6 +71,25 @@ exports[`exportToSvg with default arguments 1`] = ` `; +exports[`exportToSvg with elements that have a link 1`] = ` +" + + + + + + " +`; + exports[`exportToSvg with exportEmbedScene 1`] = ` " diff --git a/src/tests/scene/export.test.ts b/src/tests/scene/export.test.ts index 3267c911..1b6f7211 100644 --- a/src/tests/scene/export.test.ts +++ b/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(); + }); });