[Feature] Pathway SVG Export (#102)

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#102
This commit is contained in:
2025-09-10 18:44:18 +12:00
parent e82fe7e87e
commit 31783306e2
7 changed files with 125 additions and 19 deletions

View File

@ -384,12 +384,31 @@ function draw(pathway, elem) {
.style("fill", "#e8e8e8");
// Add image only for non pseudo nodes
node.filter(d => !d.pseudo).append("image")
.attr("xlink:href", d => d.image)
.attr("x", -nodeRadius)
.attr("y", -nodeRadius)
.attr("width", nodeRadius * 2)
.attr("height", nodeRadius * 2);
node.filter(d => !d.pseudo).each(function (d) {
const g = d3.select(this).append("g");
// Parse the SVG string
const parser = new DOMParser();
const svgDoc = parser.parseFromString(d.image_svg, "image/svg+xml");
const svgContent = svgDoc.documentElement;
// Remove width/height so scaling works
svgContent.removeAttribute("width");
svgContent.removeAttribute("height");
// Move all children of the parsed SVG into our <g>
while (svgContent.firstChild) {
g.node().appendChild(svgContent.firstChild);
}
// Get viewBox dimensions for scaling
const vb = svgContent.viewBox.baseVal;
const svgWidth = vb.width || 40;
const svgHeight = vb.height || 40;
// Center and scale
g.attr("transform", `translate(${-svgWidth/2},${-svgHeight/2}) scale(${(nodeRadius*2)/svgWidth})`);
});
// add element to nodes array
node.each(function (d) {
@ -397,4 +416,38 @@ function draw(pathway, elem) {
});
pop_add(node, "Compound", node_popup);
}
}
function serializeSVG(svgElement) {
svgElement.querySelectorAll("line.link").forEach(line => {
const style = getComputedStyle(line);
line.setAttribute("stroke", style.stroke);
line.setAttribute("stroke-width", style.strokeWidth);
line.setAttribute("fill", style.fill);
});
const serializer = new XMLSerializer();
let svgString = serializer.serializeToString(svgElement);
// Add namespace if missing
if (!svgString.includes('xmlns="http://www.w3.org/2000/svg"')) {
svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"');
}
return svgString;
}
function downloadSVG(svgElement, filename = 'chart.svg') {
const svgString = serializeSVG(svgElement);
const blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}