SVG: fill pattern with overlapping shapes - svg

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

Related

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 mirror paths without changing coordinates

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>

How to include the arrow head in the length of a line in SVG?

In SVG one can define markers and use them as arrow heads. Is there a way to (automatically) include those markers in the length of a line?
Here is an example:
<svg width="600px" height="200px">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" />
</marker>
</defs>
<line x1="50" y1="50" x2="250" y2="50" stroke="#000" stroke-width="5" marker-end="url(#arrow)" />
<line x1="50" y1="100" x2="250" y2="100" stroke="#000" stroke-width="5"/>
</svg>
https://codepen.io/anon/pen/jmZLRM
Here the arrow head gets attached to the end of the line which makes the line including the arrow head longer than the line on its own. I would like to have the line including the arrow head to have the same length as the line without it.
Change the refX attribute (I'm turning the line red, so you can better see where the marker ends):
<svg width="600px" height="200px">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8.7" refY="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" />
</marker>
</defs>
<line x1="50" y1="50" x2="250" y2="50" stroke="red" stroke-width="5" marker-end="url(#arrow)" />
<line x1="50" y1="100" x2="250" y2="100" stroke="#000" stroke-width="5"/>
</svg>

SVG Animation rotate

I've got a very annoying Problem using rotations in my SVG Animation. The problem is: I have an object, which I want to move along a specific path. So far it works well. But if I try to rotate this object at the end of the path it doesn't work. Sometimes my Object disappears because it's outside the viewbox and I have to try many values for the x and y values of the rotate statement until it works. And then it only works if I set the duration to 0.001s so it rotates instant, because actually my object switches to a much higher point in the viewbox and begins to rotate and only the final position is right but you see it rotating down or up around any point so it doesn't really work. I have no idea how to get the x and y values which I need to rotate the object around its own axis. Here is the code example, I hope you know how to solve this problem:
<defs>
<g id="Karte" visibility="hidden">
<!--Karte-->
<rect x="0" y="0" width="980" height="550" style="stroke: none; fill: rgb(189,248,137)" />
<!--Straßen-->
<path id="Straße1" d="M 510 0 L 510 120 0 120 0 150 980 150 980 120 540 120 540 0" style="stroke: none; fill: lightgrey" />
<rect id="Straße2" x="0" y ="320" width="980" height="20" style="stroke:none; fill: lightgrey" />
<rect id="Straße3" x="0" y="500" width="980" height="30" style="stroke:none; fill: lightgrey" />
<rect id="Straße4" x="25" y="340" width="30" height="160" style="stroke:none; fill: lightgrey" />
<rect id="Straße5" x="930" y="340" width="30" height="160" style="stroke:none; fill: lightgrey" />
<path id="campus" d="M 515 150 L 515 170 510 170 510 300 525 300 525 320 650 320 650 300 665 300 665 170 545 170 545 150" style="stroke:none; fill: lightgrey" />
<polyline id="rampe1" points="570,300 570,307 635,317 635,320" style="stroke-width: 1; fill:none" />
<polyline id="rampe2" points="580,300 580,303 645,313 645,320" style="stroke-width: 1; fill:none" />
<g id="Treppe1">
<line x1="515" y1="153" x2="545" y2="153" stroke-width="0.5" />
<line x1="515" y1="157" x2="545" y2="157" stroke-width="0.5" />
<line x1="515" y1="161" x2="545" y2="161" stroke-width="0.5" />
<line x1="515" y1="165" x2="545" y2="165" stroke-width="0.5" />
</g>
<g id="Treppe2">
<line x1="525" y1="303" x2="565" y2="303" stroke-width="0.5" />
<line x1="525" y1="307" x2="565" y2="307" stroke-width="0.5" />
<line x1="525" y1="311" x2="565" y2="311" stroke-width="0.5" />
<line x1="525" y1="315" x2="565" y2="315" stroke-width="0.5" />
</g>
<set attributeName="visibility" to="visible" begin="0s" />
</g>
</defs>
<!--Figuren-->
<defs>
<g id="John" visibility="hidden">
<circle cx="520" cy="100" r="5" />
<line x1="520" y1="104" x2="520" y2="115" stroke-width="2" />
<line x1="520" y1="104" x2="520" y2="117" stroke-width="1" />
<polyline points="520,100 523.5,108 520,112" style="fill:none" />
<polyline points="520,100 514,104 520,108" style="fill:none" />
<set attributeName="visibility" to="visible" begin="0s" />
</g>
</defs>
<!--Animation-->
<use xlink:href="#Karte" />
<use x="420" y="360" transform="rotate(90 910 490)" xlink:href="#John" >
<animateMotion path="M 0 0 L -900 -10" begin="0s" dur="6s" fill="freeze" />
<animateTransform attributeName="transform" type="rotate" from="90 940 490" to="180 940 490" begin="6s" dur="0.001" fill="freeze"/>
<animateMotion path="M-900 -10 L -900 -190" begin="6.01s" dur="3.98s" fill="freeze" />
<animateTransform attributeName="transform" type="rotate" from="180 970 490" to="270 970 490" begin="10s" dur="0.001" fill="freeze"/>
<animateMotion path="M -900 -190 L -450 -190" begin="10.01" dur="4.98" fill="freeze" />
<animateTransform attributeName="transform" type="rotate" from="270 940 490" to="180 940 490" begin="15s" dur="0.001" fill="freeze"/>
<animateMotion path="M -450 -190 L -390 -190" begin="15" dur="1" fill="freeze" />
</use>
</svg>

SVG stroke only in one direction

Currently, I have the following svg:
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" onclick='dispcoord(evt)' viewBox="0 0 80 80">
<g class="background" stroke-width="3" fill="transparent">
<circle cx="40" cy="40" r="39" stroke="black" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(112.5, 40,40)" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(202.5, 40,40)" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(292.5, 40,40)" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(22.5, 40,40)" />
<circle cx="40" cy="40" r="44" stroke="transparent" stroke-width="7" />
</g>
</svg>
http://jsfiddle.net/r5HYK/1/
As you can see, there is the black circle with some "corners" added (dunno how to call that in English). But these "corners" are both outside and inside the circle, but I want to have them only inside. To see how it should look like, you can add the out-commented circle to the svg.
But this solution does not work for me since this svg should be included into a bigger svg file, where the circle to remove the outer "corners" would be visible itself.
So I am searching for something that removes this outer "corners" (maybe a filter?), but does not have any other effect.
Another solution would be a one-sided stroke, since the stroke is expanded to both sides at the moment, but I currently do not know whether this even exists.
Any suggestions?
A clipPath is what you want. You can just clip away everything outside the circle.
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" onclick='dispcoord(evt)' viewBox="0 0 80 80">
<defs>
<clipPath id="clip1">
<circle cx="40" cy="40" r="39" fill="black" />
</clipPath>
</defs>
<g class="background" stroke-width="3" fill="transparent" clip-path="url(#clip1)">
<circle cx="40" cy="40" r="39" stroke="black" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(112.5, 40,40)" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(202.5, 40,40)" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(292.5, 40,40)" />
<path d="M 0,40 A 37,37 0 0,1 12,12" stroke-width="11" stroke="black" transform="rotate(22.5, 40,40)" />
<circle cx="40" cy="40" r="44" stroke="transparent" stroke-width="7" />
</g>
</svg>

Resources