I have a fairly large SVG file of administrative subdivisions that I need to work with in Raphael.JS (it has 600 polygons and weights 1.2 Mb).
Now, I need to convert
Little fix for polygon id, fill and stroke attributes save
var polys = document.querySelectorAll('polygon,polyline');
[].forEach.call(polys,convertPolyToPath);
function convertPolyToPath(poly){
var svgNS = poly.ownerSVGElement.namespaceURI;
var path = document.createElementNS(svgNS,'path');
var points = poly.getAttribute('points').split(/\s+|,/);
var x0=points.shift(), y0=points.shift();
var pathdata = 'M'+x0+','+y0+'L'+points.join(' ');
if (poly.tagName=='polygon') pathdata+='z';
path.setAttribute('id',poly.getAttribute('id'));
path.setAttribute('fill',poly.getAttribute('fill'));
path.setAttribute('stroke',poly.getAttribute('stroke'));
path.setAttribute('d',pathdata);
poly.parentNode.replaceChild(path,poly);
}
A clicky-bunty answer:
Might be not an appropriate answer (because with large files the program needs some time).
Copying everything from the developer tools seems pretty inconvenient. You could use an XSLT to transform polygons and polylines to paths:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="svg"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<!-- Identity transform: Copy everything
(except for polygon/polyline, handled below) -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Turn polygons/polylines into paths,
copy all attributes and content
(except for @points: Will be matched
by template below) -->
<xsl:template match="svg:polygon|svg:polyline">
<path>
<xsl:apply-templates select="@*|node()"/>
</path>
</xsl:template>
<!-- Turn the points attribute into a d attribute -->
<xsl:template match="@points">
<xsl:attribute name="d">
<xsl:value-of select="concat('M',.)"/>
<!-- If we have a polygon, we need to make
this a closed path by appending "z" -->
<xsl:if test="parent::svg:polygon">
<xsl:value-of select="'z'"/>
</xsl:if>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Any attributes of the polygon/polyline elements will be carried over to the path element. This is also suitable for batch processing. You can run this using any XSLT processor (Saxon, Xalan, xsltproc, Altova...) or even in-browser, using the XSLTProcessor
object, like:
var xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(stylesheet);
var transformedSVG = xsltProcessor.transformToFragment(svgDocument).firstChild
(Similar question: Examples of polygons drawn by path vs polygon in SVG)
Run this code:
var polys = document.querySelectorAll('polygon,polyline');
[].forEach.call(polys,convertPolyToPath);
function convertPolyToPath(poly){
var svgNS = poly.ownerSVGElement.namespaceURI;
var path = document.createElementNS(svgNS,'path');
var pathdata = 'M '+poly.getAttribute('points');
if (poly.tagName=='polygon') pathdata+='z';
path.setAttribute('d',pathdata);
poly.parentNode.replaceChild(path,poly);
}
Using the Developer Tools (or Firebug) of the browser, use "Copy as HTML" (or Copy SVG) on the element to get the modified source onto the clipboard.
Paste into a new file and enjoy.
I have a demo of the above method (slightly modified) on my website:
http://phrogz.net/svg/convert_polys_to_paths.svg
There are two methods in use on that page; one (like the above) uses string-based techniques to get and set the points; the other uses the SVG DOM for accessing points and setting path commands.
As noted by @Interactive in the comments, you can do this via text-only transformations by:
<polyline
and <polygon
to <path
points="
to d="M
For any elements that were <polygon>
, you need to add z
as the last character of the d
attribute to connect the last point to the first. For example:
<polygon points="1,2 3,-4 5,6"/>
becomes
<path d="M1,2 3,-4 5,6z"/>
This 'hack' works because the specifications declare that a moveto
command (M
or m
) followed by multiple coordinates is legal, with all coordinates after the first interpreted as lineto
commands.