I have a SVG that contains a single <path>
element that draws a certain shape. The coordinates of this path are contained within the path’s 'd'
attribute’s value. I need this shape flipped horizontally. When I try to accomplish this in Adobe Illustrator, using Reflect tool for example, I get double the size of data in the 'd'
attribute value and therefore double the size of SVG file and that is just too painful to do. I could use transform
and scale
functions to flip the shape without changing the coordinates in 'd'
but then I would increase the rendering time and CPU usage since I added extra work for browser or whichever software renders the SVG.
The logical thing to do is just change the coordinates themselves within the 'd'
to their ‘opposites’ to achieve the flipping of the shape.
I could write a script that does this but alas I do not know the format of how these coordinates are stored and what they actually represent. There are both letters and numbers used.
So, my question is, how would one change the coordinates of a <path>
element’s 'd'
in order to achieve a horizontal flip of the entire shape?
Here is my example SVG for illustration:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px">
<path id="example" class="st0" d="M492 534h-96q-37 0 -53.5 -12.5t-30.5 -50.5q-20 -54 -44 -165q-17 -79 -17 -105q0 -49 38 -58q17 -3 51 -3h67q41 0 56 7.5t23 32.5h27l-24 -106q-10 -42 -27 -58q-18 -15 -50 -19t-139 -4q-89 0 -128 5.5t-63 21.5q-54 35 -54 122q0 53 25 177q31 146 62 218t76 101 t124 29h258l-18 -80q-7 -34 -19 -43.5t-44 -9.5z"/>
</svg>
2
Answers
Here you have an example of how the path can be flipped. I do it in two different functions because
moveElm()
could be useful in other situations. So, first flipping the path over the y-axes and then moving the path back over the y-axes.For both functions the mathematics is not that hard, it is basically just a matter of understanding what the different commands in the d attribute does. The implementation is not complete, but it works for the example given in the question.
The question did not say anything about what programming language you would like to use. The only language specific I used in the example is getBBox(). In Python you can find something similar in the package svgpathtools where you can find the method
path.bbox()
(see, this answer: https://stackoverflow.com/a/76076555/322084). Finding the position and size of the path is necessary for moving (and scaling) the path.Adobe applications prefer cubic béziers
Adobe Illustrator won’t necessarily add additional commands but it converts quadratic béziers (
q
ort
commands) to cubic (c
ors
).This also applies to quite a few graphic applications/vector editors.
This will result in additional coordinate/point data.
Your example graphic probably originates from a font-to-svg conversion based on a truetype font (which natively use quadratic béziers).
Besides, your example seems to be quite optimized – for instance you see "shorthand"
t
commands (reflecting the previous quadratic bézier control point) – a lot of applications or libraries tend to convert them to "longhand" (sot
toq
– adding an explicit control point) equivalents when editing.As suggested by Yuri Khristich: Inkscape can retain these commands better as it is using svg as the object model. However, most editing operations will also convert your quadratic commands to cubics.
Custom JavaScript converters
As illustrated by chrwahl leveraging natively supported JS methods can be incredibly helpful if you need to retain the original data without adding unnecessary overhead – unfortunately most vector editor will add some data (e.g genererator meta data, non optimized pathdata with unnecessarily high floating point accuracy).
Example: flip/mirror graphic
How it works
Its basically quite similar to chrwahl’s script.
d
attribute to a computable array of path data itemsd
attribute stringThe parsing and scaling helpers also cover
a
arcto commands: these commands are an exception as their command values contain a mix of parameters and point coordinates. So we can’t apply the simple x/y scaling we can apply to other commands. Besides, they allow shorthand notations that are rather tedious to parse with too simplistic regex.The parsed path data format/structure follows the W3C draft for the SVGPathData Interface.
To adjust the offset introduced by the flip-transformation we take advantage of relative coordinates. If your path contains only relative commands you can shift the entire path by just changing the first
M
Moveto command coordinates. This concept was also explained by Lea Verou. The includedpathDataToRelative()
does the conversion.In fact the custom flipPathData() function can easily be modified to work as a scaling helper – unless you’re working with the aforementioned
A
arcto commands. Worth noting you don’t even need any kind of normalization – like converting to all absolute commands or converting shorthand commands (which is required for quite a few other path data manipulations).Example 2: Scale pathdata
Web based optimisation
Single path transformations
Single paths can easily be flipped/transformed using these open source web-apps
I’ve been playing around with custom JS converter helpers for similar reasons (AI was constantly bloating my optimized svg code after editing). You may take inspiration from this codepen example. deploying more advanced versions of the above helpers.