svg mirror paths without changing coordinates - svg

i have an svg graphic but wanted to mirror it without changing the coordinates of the line/stroke but swap the position of the arrowhead and circle… is there a more efficient way of doing this? one thing that i thought about is changing the angle of each arrowhead and circle but is tedious to do. another suggestion is using transform matrix. does anybody know how to do this? thanks in advance.
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="2000" height="2000" xmlns="http://www.w3.org/2000/svg">
<g>
<path fill="none" stroke="#4caf50" stroke-width="2" stroke-miterlimit="10" d="M195.2,75.3c28-11.5,60.9-18.1,96-18.1 c78.4,0,145.6,32.9,173.1,79.4" />
<g fill="#4caf50" id="test">
<polygon class="one" points="201.6,79 202.1,77.7 195.7,75.1 198.8,68.9 197.5,68.3 193.8,75.9"/>
<path class="two" d="M461.6,138.1c0.8,1.4,2.7,1.9,4.1,1.1s1.9-2.7,1.1-4.1c-0.8-1.4-2.7-1.9-4.1-1.1 C461.3,134.8,460.8,136.6,461.6,138.1z"/>
</g>
</g>
</svg>

This can be solved with the help of SVG markers. MDN and W3C
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="2000" height="2000" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="arrow1" viewBox="0 0 20 20" refX="0" refY="10"
markerUnits="userSpaceOnUse" orient="auto"
markerWidth="20" markerHeight="20">
<polyline id="markerPoly1" points="0,0 20,10 0,20 2,10" fill="#4caf50" />
</marker>
<marker id="circle1" viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="userSpaceOnUse"
markerWidth="10" markerHeight="10">
<circle cx="5" cy="5" r="5" fill="#4caf50"" />
</marker>
</defs
<g>
<path fill="none" stroke="#4caf50" stroke-width="2" stroke-miterlimit="10" d="M195.2,75.3c28-11.5,60.9-18.1,96-18.1 c78.4,0,145.6,32.9,173.1,79.4" style=" marker-start: url(#circle1); marker-end: url(#arrow1);
fill:none; stroke:green; stroke-width:2; " />
</svg>
Update
The angle of the marker can be changed using the attribute orient = ("180").
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="2000" height="2000" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="arrowLeft" viewBox="0 0 20 20" refX="0" refY="10"
markerUnits="userSpaceOnUse" orient="170"
markerWidth="20" markerHeight="20">
<polyline id="markerPoly1" points="0,0 20,10 0,20 2,10" fill="#4caf50" />
</marker>
<marker id="arrowRight" viewBox="0 0 20 20" refX="0" refY="10"
markerUnits="userSpaceOnUse" orient="auto"
markerWidth="20" markerHeight="20">
<polyline id="markerPoly1" points="0,0 20,10 0,20 2,10" fill="#4caf50" />
</marker>
<marker id="circle1" viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="userSpaceOnUse" orient="auto"
markerWidth="10" markerHeight="10">
<circle cx="5" cy="5" r="5" fill="#4caf50" />
</marker>
</defs>
<path id="path1" fill="none" stroke="#4caf50" stroke-width="2" stroke-miterlimit="10" d="M195.2,75.3c28-11.5,60.9-18.1,96-18.1 c78.4,0,145.6,32.9,173.1,79.4" style=" marker-end: url(#arrowRight); marker-start: url(#circle1);
fill:none; stroke:green; stroke-width:2; " />
<g transform="translate(0 100)" >
<path id="path1" fill="none" stroke="#4caf50" stroke-width="2" stroke-miterlimit="10" d="M195.2,75.3c28-11.5,60.9-18.1,96-18.1 c78.4,0,145.6,32.9,173.1,79.4" style=" marker-end: url(#circle1); marker-start: url(#arrowLeft);
fill:none; stroke:green; stroke-width:2; " />
</g>
</svg>

Related

SVG path co-ordinates different from circle

Must be something very trivial, but I'm unable to figure out why the line is not being drawn between the two points (represented by circles).
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="-10 -10 80 90"
width="400" height="400" version="1.1">
<path d="M 0 31.5 V 0,72" fill="none" id="bust" stroke="black"/>
<circle cx="0" cy="31.5" r="5"/>
<circle cx="0" cy="72" r="5"/>
</svg>
Output in Firefox
As Robert Longson points out, I only need single value after V.
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="-10 -10 80 90"
width="400" height="400" version="1.1">
<path d="M 0 31.5 V 72" fill="none" id="bust" stroke="black"/>
<circle cx="0" cy="31.5" r="5"/>
<circle cx="0" cy="72" r="5"/>
</svg>

SVG pathLength on circle not defining circle's circumference?

According to https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle, the pathLength attribute is supposed to define the "total length for the circle's circumference", however, when I use stroke-dasharray, it doesn't seem to line up?
<svg width="100" height="100" viewBox="0 0 1 1">
<circle
cx="0.5"
cy="0.5"
stroke-width="0.5"
r="0.25"
pathLength="360"
stroke-dasharray="180 360"
stroke-dashoffset="0"
stroke="black"
fill="none"
/>
</svg>
According to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength as well, this should be half-filled, thus a semi-circle, however it's slightly less than a semi-circle. If I have stroke-dasharray set to 360 360 instead, it doesn't fully close when, if I understand how the pathLength attribute is supposed to work, it should.
Am I misunderstanding pathLength or stroke-dasharray?
Edit: it seems to work differently across browsers...?
Chromium:
Firefox:
Safari:
Edit 2:
When I get their total lengths, it's different across browsers! Is this intended? Is it possible to solve this issue?
As #enxaneta commented. The smaller the viewBox, the bigger the problem is. In this example it is only the last one (viewBox="0 0 100 100") that looks OK in Chrome.
<svg xmlns="http//www.w3.org/2000/svg" width="130" viewBox="0 0 1 1">
<path d="M0 .5 L1 .5" stroke-width=".01" stroke="gray"/>
<circle cx=".5" cy=".5" r=".4" stroke="black" stroke-width=".2" fill="none" stroke-dasharray="180 360" pathLength="360" />
</svg>
<svg xmlns="http//www.w3.org/2000/svg" width="130" viewBox="0 0 10 10">
<path d="M0 5 L10 5" stroke-width=".1" stroke="gray"/>
<circle cx="5" cy="5" r="4" stroke="black" stroke-width="2" fill="none" stroke-dasharray="180 360" pathLength="360" />
</svg>
<svg xmlns="http//www.w3.org/2000/svg" width="130" viewBox="0 0 50 50">
<path d="M0 25 L50 25" stroke-width=".5" stroke="gray"/>
<circle cx="25" cy="25" r="20" stroke="black" stroke-width="10" fill="none" stroke-dasharray="180 360" pathLength="360" />
</svg>
<svg xmlns="http//www.w3.org/2000/svg" width="130" viewBox="0 0 100 100">
<path d="M0 50 L100 50" stroke-width="1" stroke="gray"/>
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="20" fill="none" stroke-dasharray="180 360" pathLength="360" />
</svg>

SVG: repeating markers through the line/path

I'm trying to build svg-line (or path - doesn't matter) with repeating markers along it's entire length. What is the best way to implement it?
There is a description of marker-pattern property on w3. It looks perfect but for some reason I can't get the correct result in my code.
Furthermore, I don't see any markers, replicating the w3 example:
https://jsfiddle.net/pLaukq8p/
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="200">
<marker id="DoubleDash" markerWidth="8" markerHeight="12" refX="0" refY="0"
viewBox="-4 -6 8 12" markerUnits="userSpaceOnUse" orient="auto">
<rect x="-3" y="-5" width="2" height="10"/>
<rect x="1" y="-5" width="2" height="10"/>
</marker>
<marker id="SingleDash" markerWidth="4" markerHeight="12" refX="0" refY="0"
viewBox="-2 -6 4 12" markerUnits="userSpaceOnUse" orient="auto">
<rect x="-1" y="-5" width="2" height="10"/>
</marker>
<path d="M 50,100 S 100,132 150,86 200,173 250,76 300,81
350,136 400,87 450,166 500,87 550,96"
stroke="deeppink" stroke-width="2" fill="none"
marker-pattern="40 url(#DoubleDash) 40 url(#SingleDash)"/>
</svg>

Smil animations on svg

Greeting to all,
I recently found myself reading the following article (http://apike.ca/prog_svg_smil.html) and more specifically the "Animation Element - animateMotion".
Is there a way of "telling" the moving "marker" to accelerate or decelerate on specific portions (segments) of the path, or is its speed always defined by the "dur" attribute (in seconds)?
Thanks in advance.
Controlling the animation timing is provided by the calcMode, keyTimes, keySplines and keyPoints attributes of svg animation elements such as animateMotion. Basically you specify points on a normalized timeline and tell svg how to map them onto the progress measured on a normalized timeline as well. you also specify how to interpolate between the support points given. for smooth animations you would chose calcMode="spline".
the relevant references are:
svg(animateMotion)
svg(keyPoints)
smil(CalcModes)
smil(keyTimes)
for demo purposes, have a look at an animated line tracking demo (online here, click on the dark bar; example taken from here, timing control added):
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
width="200" height="200"
viewBox="0 0 200 200" >
<!-- Matthew Bystedt http://apike.ca 2012 -->
<!-- Pattern Definition -->
<defs>
<pattern id="rulerPattern" patternUnits="userSpaceOnUse"
x="0" y="0" width="10" height="10"
viewBox="0 0 10 10" >
<line x1="0" y1="0" x2="10" y2="0" stroke="lightblue" fill="none" stroke-dasharray="2,2" />
<line x1="0" y1="0" x2="0" y2="10" stroke="lightblue" fill="none" stroke-dasharray="2,2" />
</pattern>
<marker id="marker2" viewBox="0 0 10 10" refX="1" refY="5"
markerUnits="strokeWidth" orient="auto"
markerWidth="4" markerHeight="3">
<polyline points="0,0 10,5 0,10 1,5" fill="darkgreen" />
</marker>
</defs>
<!-- Background -->
<rect x="0" y="0" width="100%" height="100%" fill="url(#rulerPattern)" stroke="black" />
<!-- Path Line Example -->
<path id="myAniPath" d="M10,150 A15 15 180 0 1 70 140 A15 25 180 0 0 130 130 A15 55 180 0 1 190 120 A15 10 170 0 1 10 150" stroke="lightgreen" stroke-width="2" fill="none" marker-mid="url(#marker2)" />
<rect x="-10" y="-5" width="20" height="10" fill="none" stroke="black" >
<animateMotion begin="startButton.click" dur="10s" calcMode="spline" keyTimes="0; 1" keySplines=".75 0 .25 1" repeatCount="1" rotate="auto" fill="freeze">
<mpath xlink:href="#myAniPath" />
</animateMotion>
</rect>
<rect id="startButton" x="20" y="20" width="60" height="20" fill="green" />
<line stroke="black" stroke-width="2" x1="20" y1="20" x2="20" y2="40" >
<animate begin="startButton.click" attributeName="x1" from="20" to="80" dur="10s" repeatCount="1" fill="freeze" />
<animate begin="startButton.click" attributeName="x2" from="20" to="80" dur="10s" repeatCount="1" fill="freeze" />
</line>
</svg>

SVG: fill pattern with overlapping shapes

In SVG, how can I fill portions of overlapping shapes, like this example(not drawn with SVG)? If I omit the fill pattern from a shape, I also want the pattern removed from other shapes that it overlaps. After that, yet more shapes may overlap again and re-draw the pattern. I'm generating this SVG from code, and for each shape, I'll know in the code whether it's supposed to add or subtract the fill pattern.
Here's my SVG so far. It draws the shapes, and defines the fill pattern but doesn't use it.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="640" height="480" viewBox="0 0 640 480">
<defs>
<marker id="endArrowGreen" viewBox="0 0 10 10" refX="1" refY="5" markerUnits="strokeWidth" orient="auto" markerWidth="5" markerHeight="4">
<polyline points="0,0 10,5 0,10 1,5" fill="#00CC00" stroke="#00CC00"/>
</marker>
<marker id="startArrowGreen" viewBox="0 0 10 10" refX="1" refY="5" markerUnits="strokeWidth" orient="auto" markerWidth="5" markerHeight="4">
<polyline points="10,0 0,5 10,10 9,5" fill="#00CC00" stroke="#00CC00"/>
</marker>
<marker id="endArrowBlue" viewBox="0 0 10 10" refX="1" refY="5" markerUnits="strokeWidth" orient="auto" markerWidth="5" markerHeight="4">
<polyline points="0,0 10,5 0,10 1,5" fill="#0000CC" stroke="#0000CC"/>
</marker>
<marker id="startArrowBlue" viewBox="0 0 10 10" refX="1" refY="5" markerUnits="strokeWidth" orient="auto" markerWidth="5" markerHeight="4">
<polyline points="10,0 0,5 10,10 9,5" fill="#0000CC" stroke="#0000CC"/>
</marker>
<pattern id="Crosshatch" patternUnits="userSpaceOnUse"
x="0" y="0" width="10" height="10"
viewBox="0 0 10 10" >
<path d="M 0 10 L 10 0" stroke-width="1" stroke="blue" />
</pattern>
</defs>
<g>
<line x1="7.78888" y1="6.08366" x2="319.087" y2="6.08366" stroke-width="1" stroke="#0000CC" />
<polyline points="0,0 -6,-3 -5,0 -6,3" fill="#0000CC" stroke="#0000CC" transform="translate(319.087 6.08366) rotate(0)"/>
<line x1="319.087" y1="6.08366" x2="630.385" y2="6.08366" stroke-width="1" stroke="#0000CC" />
<line x1="630.385" y1="6.08366" x2="630.385" y2="469.354" stroke-width="1" stroke="#0000CC" />
<line x1="630.385" y1="469.354" x2="7.78888" y2="469.354" stroke-width="1" stroke="#0000CC" />
<line x1="7.78888" y1="469.354" x2="7.78888" y2="237.719" stroke-width="1" stroke="#0000CC" />
<line x1="7.78888" y1="6.08366" x2="7.78888" y2="237.719" stroke-width="1" stroke="#0000CC" />
<polyline points="0,0 -6,-3 -5,0 -6,3" fill="#0000CC" stroke="#0000CC" transform="translate(7.78888 237.719) rotate(90)"/>
</g>
<circle cx="298.914" cy="237.087" r="218.732" stroke-width="1" stroke="#0000CC" fill="none"/>
<circle cx="262.395" cy="238.913" r="100" stroke-width="1" stroke="#0000CC" fill="none"/>
<circle cx="438.601" cy="236.175" r="129.523" stroke-width="1" stroke="#0000CC" fill="none"/>
<g>
<line x1="99.913" y1="248.646" x2="302.566" y2="248.646" stroke-width="1" stroke="#0000CC" />
<polyline points="0,0 -6,-3 -5,0 -6,3" fill="#0000CC" stroke="#0000CC" transform="translate(302.566 248.646) rotate(0)"/>
<line x1="302.566" y1="248.646" x2="505.22" y2="248.646" stroke-width="1" stroke="#0000CC" />
<line x1="505.22" y1="248.646" x2="505.22" y2="291.232" stroke-width="1" stroke="#0000CC" />
<line x1="505.22" y1="291.232" x2="99.913" y2="291.232" stroke-width="1" stroke="#0000CC" />
<line x1="99.913" y1="291.232" x2="99.913" y2="269.939" stroke-width="1" stroke="#0000CC" />
<line x1="99.913" y1="248.646" x2="99.913" y2="269.939" stroke-width="1" stroke="#0000CC" />
<polyline points="0,0 -6,-3 -5,0 -6,3" fill="#0000CC" stroke="#0000CC" transform="translate(99.913 269.939) rotate(90)"/>
</g>
<g>
<line x1="114.521" y1="181.118" x2="303.023" y2="181.118" stroke-width="1" stroke="#0000CC" />
<polyline points="0,0 -6,-3 -5,0 -6,3" fill="#0000CC" stroke="#0000CC" transform="translate(303.023 181.118) rotate(0)"/>
<line x1="303.023" y1="181.118" x2="491.525" y2="181.118" stroke-width="1" stroke="#0000CC" />
<line x1="491.525" y1="181.118" x2="491.525" y2="212.753" stroke-width="1" stroke="#0000CC" />
<line x1="491.525" y1="212.753" x2="114.521" y2="212.753" stroke-width="1" stroke="#0000CC" />
<line x1="114.521" y1="212.753" x2="114.521" y2="196.935" stroke-width="1" stroke="#0000CC" />
<line x1="114.521" y1="181.118" x2="114.521" y2="196.935" stroke-width="1" stroke="#0000CC" />
<polyline points="0,0 -6,-3 -5,0 -6,3" fill="#0000CC" stroke="#0000CC" transform="translate(114.521 196.935) rotate(90)"/>
</g>
</svg>
You might want to try the "fill-rule" attribute see http://www.w3.org/TR/SVG/painting.html

Resources