feat: Support Links in Exported SVG (#4791)
This commit is contained in:
parent
bd35b682fa
commit
46e43baad1
@ -836,6 +836,18 @@ export const renderElementToSvg = (
|
|||||||
const cy = (y2 - y1) / 2 - (element.y - y1);
|
const cy = (y2 - y1) / 2 - (element.y - y1);
|
||||||
const degree = (180 * element.angle) / Math.PI;
|
const degree = (180 * element.angle) / Math.PI;
|
||||||
const generator = rsvg.generator;
|
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) {
|
switch (element.type) {
|
||||||
case "selection": {
|
case "selection": {
|
||||||
// Since this is used only during editing experience, which is canvas based,
|
// Since this is used only during editing experience, which is canvas based,
|
||||||
@ -863,7 +875,7 @@ export const renderElementToSvg = (
|
|||||||
offsetY || 0
|
offsetY || 0
|
||||||
}) rotate(${degree} ${cx} ${cy})`,
|
}) rotate(${degree} ${cx} ${cy})`,
|
||||||
);
|
);
|
||||||
svgRoot.appendChild(node);
|
root.appendChild(node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "line":
|
case "line":
|
||||||
@ -898,7 +910,7 @@ export const renderElementToSvg = (
|
|||||||
}
|
}
|
||||||
group.appendChild(node);
|
group.appendChild(node);
|
||||||
});
|
});
|
||||||
svgRoot.appendChild(group);
|
root.appendChild(group);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "freedraw": {
|
case "freedraw": {
|
||||||
@ -923,7 +935,7 @@ export const renderElementToSvg = (
|
|||||||
path.setAttribute("fill", element.strokeColor);
|
path.setAttribute("fill", element.strokeColor);
|
||||||
path.setAttribute("d", getFreeDrawSvgPath(element));
|
path.setAttribute("d", getFreeDrawSvgPath(element));
|
||||||
node.appendChild(path);
|
node.appendChild(path);
|
||||||
svgRoot.appendChild(node);
|
root.appendChild(node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "image": {
|
case "image": {
|
||||||
@ -944,7 +956,7 @@ export const renderElementToSvg = (
|
|||||||
|
|
||||||
symbol.appendChild(image);
|
symbol.appendChild(image);
|
||||||
|
|
||||||
svgRoot.prepend(symbol);
|
root.prepend(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
const use = svgRoot.ownerDocument!.createElementNS(SVG_NS, "use");
|
const use = svgRoot.ownerDocument!.createElementNS(SVG_NS, "use");
|
||||||
@ -965,7 +977,7 @@ export const renderElementToSvg = (
|
|||||||
}) rotate(${degree} ${cx} ${cy})`,
|
}) rotate(${degree} ${cx} ${cy})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
svgRoot.appendChild(use);
|
root.appendChild(use);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1012,7 +1024,7 @@ export const renderElementToSvg = (
|
|||||||
text.setAttribute("direction", direction);
|
text.setAttribute("direction", direction);
|
||||||
node.appendChild(text);
|
node.appendChild(text);
|
||||||
}
|
}
|
||||||
svgRoot.appendChild(node);
|
root.appendChild(node);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
throw new Error(`Unimplemented type ${element.type}`);
|
throw new Error(`Unimplemented type ${element.type}`);
|
||||||
|
5
src/tests/fixtures/elementFixture.ts
vendored
5
src/tests/fixtures/elementFixture.ts
vendored
@ -37,3 +37,8 @@ export const diamondFixture: ExcalidrawElement = {
|
|||||||
...elementBase,
|
...elementBase,
|
||||||
type: "diamond",
|
type: "diamond",
|
||||||
};
|
};
|
||||||
|
export const rectangleWithLinkFixture: ExcalidrawElement = {
|
||||||
|
...elementBase,
|
||||||
|
type: "rectangle",
|
||||||
|
link: "excalidraw.com",
|
||||||
|
};
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,10 @@
|
|||||||
import { NonDeletedExcalidrawElement } from "../../element/types";
|
import { NonDeletedExcalidrawElement } from "../../element/types";
|
||||||
import * as exportUtils from "../../scene/export";
|
import * as exportUtils from "../../scene/export";
|
||||||
import { diamondFixture, ellipseFixture } from "../fixtures/elementFixture";
|
import {
|
||||||
|
diamondFixture,
|
||||||
|
ellipseFixture,
|
||||||
|
rectangleWithLinkFixture,
|
||||||
|
} from "../fixtures/elementFixture";
|
||||||
|
|
||||||
describe("exportToSvg", () => {
|
describe("exportToSvg", () => {
|
||||||
const ELEMENT_HEIGHT = 100;
|
const ELEMENT_HEIGHT = 100;
|
||||||
@ -112,4 +116,13 @@ describe("exportToSvg", () => {
|
|||||||
);
|
);
|
||||||
expect(svgElement.innerHTML).toMatchSnapshot();
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user