Spaces:
Sleeping
Sleeping
| const preservedAttributes = { | |
| ...[ | |
| "viewBox", "transform", "x", "y", "width", "height", "ry", "d", "x1", "y1", "x2", "y2", "color", | |
| "stroke-width", "points", "stroke-dasharray", "font-size", "font-weight", "font-style", "text-anchor", | |
| ].reduce((dict, key) => ({...dict, [key]: key}), {}), | |
| "xlink:href": "href", | |
| }; | |
| const domNodeToElement = node => { | |
| const elem : any = { | |
| type: node.tagName, | |
| }; | |
| for (const key in preservedAttributes) { | |
| const value = node.getAttribute(key); | |
| if (value) | |
| elem[preservedAttributes[key]] = value; | |
| } | |
| switch (node.tagName) { | |
| case "tspan": | |
| elem.text = node.textContent; | |
| break; | |
| case "a": | |
| if (!/:(\d+:\d+:\d+)$/.test(elem.href)) { | |
| //if (!/lilypond/.test(elem.href)) | |
| // console.warn("unexpected a.href:", elem.href); | |
| delete elem.href; | |
| } | |
| else | |
| elem.href = elem.href.match(/:(\d+:\d+:\d+)$/)[1]; | |
| break; | |
| case "path": | |
| //console.log("path:", node.getAttribute("d"), elem); | |
| //if (elem.d) | |
| // elem.d = sha1(elem.d); | |
| break; | |
| case "polygon": | |
| //if (elem.points) | |
| // elem.points = sha1(elem.points); | |
| break; | |
| } | |
| [ | |
| "x", "y", "width", "height", "ry", "x1", "y1", "x2", "y2", "stroke-width", "font-size", "font-weight", "font-style", "text-anchor", | |
| ].forEach(att => { | |
| if (elem[att]) { | |
| const n = Number(elem[att]); | |
| if (Number.isFinite(n)) | |
| elem[att] = n; | |
| } | |
| }); | |
| if (elem.transform) { | |
| let [_, tx, ty, sx, sy] = [null, 0, 0, 1, 1]; | |
| if (/translate\([\d.\-,\s]+\)\s*scale\([\d.\-,\s]+\)/.test(elem.transform)) | |
| [_, tx, ty, sx, sy] = elem.transform.match(/translate\(([\d.-]+),\s*([\d.-]+)\)\s*scale\(([\d.-]+),\s*([\d.-]+)\)/); | |
| else if (/translate\([\d.\-,\s]+\)/.test(elem.transform)) | |
| [_, tx, ty] = elem.transform.match(/translate\(([\d.-]+),\s*([\d.-]+)\)/); | |
| else if (/scale\([\d.\-,\s]+\)/.test(elem.transform)) | |
| [_, sx, sy] = elem.transform.match(/scale\(([\d.-]+),\s*([\d.-]+)\)/); | |
| else if (/^rotate(.*)$/.test(elem.transform)) {} | |
| else | |
| console.warn("unexpected transform:", elem.transform); | |
| elem.transform = { | |
| translate: { | |
| x: Number(tx), | |
| y: Number(ty), | |
| }, | |
| scale: { | |
| x: Number(sx), | |
| y: Number(sy), | |
| }, | |
| }; | |
| } | |
| for (let i = 0; i < node.childNodes.length; ++i) { | |
| const child = node.childNodes[i]; | |
| if (child.nodeType === 1) { | |
| //console.log("child:", child); | |
| elem.children = elem.children || []; | |
| elem.children.push(domNodeToElement(child)); | |
| } | |
| } | |
| switch (elem.type) { | |
| case "text": | |
| if (elem.children) | |
| elem.text = elem.children.filter(e => e.type === "tspan" && e.text).map(e => e.text).join(""); | |
| break; | |
| } | |
| return elem; | |
| }; | |
| const svgToElements = (svgText, {logger = null, DOMParser = null} = {}) => { | |
| const dom = new DOMParser().parseFromString(svgText, "text/xml"); | |
| //console.log("dom:", dom); | |
| if (logger) | |
| logger.append("svgToElements"); | |
| const svg : any = dom.childNodes[0]; | |
| console.assert(svg && svg.tagName === "svg"); | |
| const root = domNodeToElement(svg); | |
| //if (logger) | |
| // logger.append("svgToElements.root", JSON.parse(JSON.stringify(root))); | |
| if (!root.children) { | |
| console.log("invalid svg:", root, svgText); | |
| return null; | |
| } | |
| // remove proxy tags of a & g | |
| while (true) { | |
| const index = root.children.findIndex(c => c.type === "a" && c.children); | |
| if (index >= 0) { | |
| const a = root.children[index]; | |
| a.children.forEach(p => { | |
| p.href = a.href; | |
| p.color = a.color; | |
| }); | |
| root.children.splice(index, 1, ...a.children); | |
| } | |
| else { | |
| const gi = root.children.findIndex(c => c.type === "g" && c.children); | |
| if (gi >= 0) { | |
| const g = root.children[gi]; | |
| for (const child of g.children) { | |
| if (g.transform) { | |
| child.transform = child.transform || { | |
| translate: {x: 0, y: 0}, | |
| scale: {x: 1, y: 1}, | |
| }; | |
| child.transform.translate.x = g.transform.translate.x + child.transform.translate.x * g.transform.scale.x; | |
| child.transform.translate.y = g.transform.translate.y + child.transform.translate.y * g.transform.scale.y; | |
| child.transform.scale.x *= g.transform.scale.x; | |
| child.transform.scale.y *= g.transform.scale.y; | |
| } | |
| if (g.color) | |
| child.color = g.color; | |
| if (g.href) | |
| child.href = g.href; | |
| } | |
| root.children.splice(gi, 1, ...g.children); | |
| } | |
| else | |
| break; | |
| } | |
| }; | |
| return root; | |
| }; | |
| export { | |
| svgToElements, | |
| }; | |