Last active
March 4, 2024 19:04
-
-
Save stuartlangridge/2ec64a7d7793d5b9d24be0cf18550ff6 to your computer and use it in GitHub Desktop.
Exporting an SVG from Figma and identifying which SVG elements in the exported file correspond to which objects in Figma
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const getSvgNamesForNodes = () => { | |
// this is guesswork. When Figma has two nodes with the same name (say, "Union"), | |
// it serialises them into SVG with names "Union" and "Union_2", but it's not | |
// clear which one becomes "Union" and which "Union_2". It is theorised that this | |
// is done in the same order that .findAll returns, so we make use of that. | |
// Figma might decide to change this at any time, of course. It would be much | |
// nicer if there were an SVG export option which also serialised getPluginData() | |
// data as data-* attributes in the output SVG, but there isn't, yet. | |
let names = {}; | |
let nameIndices = {}; | |
window.figma.currentPage.findAll().forEach(o => { | |
let index = ""; | |
if (nameIndices[o.name]) { | |
index = "_" + (nameIndices[o.name] + 1); | |
nameIndices[o.name] += 1 | |
} else { | |
nameIndices[o.name] = 1; | |
} | |
names[o.name + index] = o; | |
}); | |
return names; | |
} | |
// grab the current page as an SVG | |
const im = await figma.currentPage.exportAsync({format:"SVG", svgIdAttribute: true}); | |
const svgtext = new TextDecoder("utf-8").decode(im); | |
// parse it into a DOM | |
const parser = new DOMParser(); | |
const doc = parser.parseFromString(svgtext, "image/svg+xml"); | |
// get the calculated names for each Figma node | |
const mapping = getSvgNamesForNodes(); | |
// use the names to pair each SVG element with its corresponding Figma node, and copy some info across | |
for (let calculated_svgname in mapping) { | |
let svgel = doc.getElementById(calculated_svgname); | |
if (!svgel) { continue; } | |
svgel.setAttribute("data-figma-nodeid", mapping[calculated_svgname].id); | |
} | |
// there should now be no SVG elements with an ID but without a nodeid: check, for paranoia | |
const unmatched = doc.querySelectorAll("[id]:not([data-figma-nodeid])"); | |
if (unmatched.length > 0) { | |
console.warn("Failed to match up the following nodes:", unmatched); | |
} | |
// serialise the DOM back into svg text | |
const finaltext = new XMLSerializer().serializeToString(doc); | |
console.log(finaltext); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment