Make a path get cut off by a circle - svg

Is there a way to cut off a path when it is outside of a circle?
<svg width="100" height="100">
<circle cx="50" cy="50" r="50" fill="red" />
<path d="M0 0 L100 100" stroke-width="1px" stroke="black" />
</svg>
Is it possible to make that line stay inside the circle (and not be visible off of the circle) without changing the d="M200 175 L696 880" in the path?

You can use a clipPath to prevent things drawing outside another shape.
<svg width="100" height="100">
<clipPath id="clip">
<circle cx="50" cy="50" r="50" fill="red" />
</clipPath>
<circle cx="50" cy="50" r="50" fill="red" />
<path d="M0 0 L100 100" stroke-width="1px" stroke="black" clip-path="url(#clip)"/>
</svg>

Related

Cutting out intersecting lines in SVG files using python

I am attempting to generate svgs where all the stuff in the middle of the outer ring of circles is removed. Ideally I would like this to all be in one path. So far I have tried calculating arcs and merging them with circle paths but that gets kinda messy. Is there a way to go through and collapse this all down to just one path or a clean series of paths.
[1]: https://i.stack.imgur.com/72PoK.png
Edit: Added The code for the svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink" baseProfile="full" fill-rule="evenodd" height="1024" version="1.1" width="1024">
<defs/>
<polyline fill="none" points="512,312 512.0,512.0 668,387 512.0,512.0 707,557 512.0,512.0 599,692 512.0,512.0 425,692 512.0,512.0 317,557 512.0,512.0 356,387 512.0,512.0" stroke="green" stroke-width="1"/>
<polygon fill="none" points="512,312 668,387 707,557 599,692 425,692 317,557 356,387" stroke="green" stroke-linejoin="bevel" stroke-width="1"/>
<circle cx="512.0" cy="512.0" fill="none" r="200" stroke="purple" stroke-width="1"/>
<circle cx="512" cy="312" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="668" cy="387" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="707" cy="557" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="599" cy="692" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="425" cy="692" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="317" cy="557" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
<circle cx="356" cy="387" fill="none" r="66.66666666666667" stroke="purple" stroke-width="1"/>
</svg>
Im using a module called Svgwrite to generate this
Here's a modified version of your SVG, where a mask has been used to blank out the interior of all your small outer circles.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink" baseProfile="full" fill-rule="evenodd" height="1024" version="1.1" width="1024">
<defs>
<mask id="blank-circles">
<rect width="100%" height="100%" fill="white"/>
<!-- Holes where each of the outer circles are. -->
<!-- We are using <use> elements so we don't need to define the circles twice. -->
<use xlink:href="#c1" fill="black"/>
<use xlink:href="#c2" fill="black"/>
<use xlink:href="#c3" fill="black"/>
<use xlink:href="#c4" fill="black"/>
<use xlink:href="#c5" fill="black"/>
<use xlink:href="#c6" fill="black"/>
<use xlink:href="#c7" fill="black"/>
</mask>
</defs>
<!-- Mask is applied to all the elements via a parent <g> element -->
<g mask="url(#blank-circles)">
<polyline fill="none" points="512,312 512.0,512.0 668,387 512.0,512.0 707,557 512.0,512.0 599,692 512.0,512.0 425,692 512.0,512.0 317,557 512.0,512.0 356,387 512.0,512.0" stroke="green" stroke-width="1"/>
<polygon fill="none" points="512,312 668,387 707,557 599,692 425,692 317,557 356,387" stroke="green" stroke-linejoin="bevel" stroke-width="1"/>
<circle cx="512.0" cy="512.0" fill="none" r="200" stroke="purple" stroke-width="1"/>
<g fill="none" stroke="purple" stroke-width="1">
<!-- fill and stroke properties are moved to a parent <g> so that they
aren't applied when referenced from the <mask>. -->
<circle id="c1" cx="512" cy="312" r="66.66666666666667"/>
<circle id="c2" cx="668" cy="387" r="66.66666666666667"/>
<circle id="c3" cx="707" cy="557" r="66.66666666666667"/>
<circle id="c4" cx="599" cy="692" r="66.66666666666667"/>
<circle id="c5" cx="425" cy="692" r="66.66666666666667"/>
<circle id="c6" cx="317" cy="557" r="66.66666666666667"/>
<circle id="c7" cx="356" cy="387" r="66.66666666666667"/>
</g>
</g>
</svg>

SVG using non-repetitive pattern as fill

I'm trying to use different SVG elements with a pattern as a fill, but the pattern doesn't get repeated for every element. I'm not sure if there's the possibility to repeat the pattern, but right now it looks as if there's a pattern and three circles create a mask over the pattern. What I want to achieve is the three circles clearly looking differently because each pattern resets for each circle and then it doesn't look 'cut out'.
I suppose a last-resort solution would be to create multiple patterns with different names for every element I use, then it'll work, but I'm hoping there's a less cumbersome way.
I tried:
Wrapping each element in a different SVG container
Appending ids to the elements and then in css target every id separately with the fill being the url
I made a codesandbox which shows my problem:
https://codesandbox.io/s/busy-ives-hv3rr?file=/index.html
The solution #herrstrietzel posted is one way to go.
Another solution is to create variants of your original pattern, but with a different origin. You specify the origin using the x and y attributes.
<svg id="patternId" width="100%" height="100%">
<defs>
<pattern id="a" patternUnits="userSpaceOnUse" width="65" height="65" patternTransform="scale(2) rotate(0)">
<rect x="0" y="0" width="100%" height="100%" fill="hsla(0,0%,100%,1)"/>
<path d="M.5.5v12h12V.5H.5zm13 13v12h12v-12h-12zm-13 13v12h12v-12H.5zm26 13v12h12v-12h-12zm13 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(258.5,59.4%,59.4%,1)"/>
<path d="M26.5.5v12h12V.5h-12zm0 13v12h12v-12h-12zm13 13v12h12v-12h-12zm-39 13v12h12v-12H.5zm0 13v12h12v-12H.5z"
stroke-width="1" stroke="none" fill="hsla(339.6,82.2%,51.6%,1)"/>
<path d="M13.5.5v12h12V.5h-12zm39 13v12h12v-12h-12zm-39 13v12h12v-12h-12zm39 0v12h12v-12h-12zm-26 26v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(198.7,97.6%,48.4%,1)"/>
<path d="M52.5.5v12h12V.5h-12zm-13 13v12h12v-12h-12zm0 26v12h12v-12h-12zm13 0v12h12v-12h-12zm-39 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(33, 90%, 65%, 1)"/>
</pattern>
<pattern id="a2" href="#a" x="20" y="20"/>
<pattern id="a3" href="#a" x="45" y="50"/>
</defs>
<svg height="200" width="200">
<circle cx="50" cy="50" r="40" fill="url(#a)" />
</svg>
<svg height="200" width="200">
<circle cx="100" cy="50" r="40" fill="url(#a2)" />
</svg>
<svg height="200" width="200">
<circle cx="50" cy="100" r="40" fill="url(#a3)" />
</svg>
</svg>
Another alternative is to switch to objectBoundingBox units. So that the pattern is relative the the object it is applied to.
<svg id="patternId" width="100%" height="100%">
<defs>
<pattern id="a" patternUnits="objectBoundingBox" width="65" height="65">
<g transform="scale(2)">
<rect x="0" y="0" width="100%" height="100%" fill="hsla(0,0%,100%,1)"/>
<path d="M.5.5v12h12V.5H.5zm13 13v12h12v-12h-12zm-13 13v12h12v-12H.5zm26 13v12h12v-12h-12zm13 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(258.5,59.4%,59.4%,1)"/>
<path d="M26.5.5v12h12V.5h-12zm0 13v12h12v-12h-12zm13 13v12h12v-12h-12zm-39 13v12h12v-12H.5zm0 13v12h12v-12H.5z"
stroke-width="1" stroke="none" fill="hsla(339.6,82.2%,51.6%,1)"/>
<path d="M13.5.5v12h12V.5h-12zm39 13v12h12v-12h-12zm-39 13v12h12v-12h-12zm39 0v12h12v-12h-12zm-26 26v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(198.7,97.6%,48.4%,1)"/>
<path d="M52.5.5v12h12V.5h-12zm-13 13v12h12v-12h-12zm0 26v12h12v-12h-12zm13 0v12h12v-12h-12zm-39 13v12h12v-12h-12z"
stroke-width="1" stroke="none" fill="hsla(33, 90%, 65%, 1)"/>
</g>
</pattern>
<pattern id="a2" href="#a" x="20" y="20"/>
<pattern id="a3" href="#a" x="45" y="50"/>
</defs>
<svg height="200" width="200">
<circle cx="50" cy="50" r="40" fill="url(#a)" />
</svg>
<svg height="200" width="200">
<circle cx="100" cy="50" r="40" fill="url(#a)" />
</svg>
<svg height="200" width="200">
<circle cx="50" cy="100" r="40" fill="url(#a)" />
</svg>
</svg>
Applying transforms like transform="translate(50 50)" (instead of fixed x/y positioning would do the trick.
<svg id="patternId" width="100%" height="100%">
<defs>
<pattern id="pattern-0" patternUnits="userSpaceOnUse" width="65" height="65" patternTransform="scale(2) rotate(0)" >
<g id="patternInner">
<rect x="0" y="0" width="100%" height="100%" fill="hsla(0,0%,100%,1)" />
<path d="M.5.5v12h12V.5H.5zm13 13v12h12v-12h-12zm-13 13v12h12v-12H.5zm26 13v12h12v-12h-12zm13 13v12h12v-12h-12z" stroke-width="1" stroke="none" fill="hsla(258.5,59.4%,59.4%,1)" />
<path d="M26.5.5v12h12V.5h-12zm0 13v12h12v-12h-12zm13 13v12h12v-12h-12zm-39 13v12h12v-12H.5zm0 13v12h12v-12H.5z" stroke-width="1" stroke="none" fill="hsla(339.6,82.2%,51.6%,1)" />
<path d="M13.5.5v12h12V.5h-12zm39 13v12h12v-12h-12zm-39 13v12h12v-12h-12zm39 0v12h12v-12h-12zm-26 26v12h12v-12h-12z" stroke-width="1" stroke="none" fill="hsla(198.7,97.6%,48.4%,1)" />
<path d="M52.5.5v12h12V.5h-12zm-13 13v12h12v-12h-12zm0 26v12h12v-12h-12zm13 0v12h12v-12h-12zm-39 13v12h12v-12h-12z" stroke-width="1" stroke="none" fill="hsla(33, 90%, 65%, 1)" />
</g>
</pattern>
<pattern id="pattern-1" href="#pattern-0" x="80" y="80" patternTransform="scale(2) rotate(45)" />
</defs>
<circle cx="50" cy="50" r="40" fill="url(#pattern-0)" />
<circle cx="50" cy="50" r="50" fill="url(#pattern-0)" transform="translate(50 33)" />
<circle cx="50" cy="50" r="50" fill="url(#pattern-1)" transform="translate(50 33)" />
<rect x="0" y="0" width="50" height="50" stroke="#fff" stroke-width="1" transform="translate(10 60)" fill="url(#pattern-0)" />
</svg>
Worth noting: duplicating patterns for slightly modified usage is pretty straight forward, since the <pattern> element supports referencing/reusing previously defined patterns via href attribute (similar to <use>):
<pattern id="pattern-1" href="#pattern-0" x="80" y="80" patternTransform="scale(2) rotate(45)" />
Would result in a rotated pattern sharing all properties of the initially defined pattern.

How to draw circles in SVG like if they were a single shape?

I need to draw an indeterminate number of circles in SVG like if they were a single shape. Making all circles have the same fill color does not work because I need those circles to have a filter applied in them, like in the picture, and as you can see the overlapping areas are in a different color.
<pattern
id="diagonalHatch"
patternUnits="userSpaceOnUse"
width="1"
height="3"
patternTransform="rotate(-45 2 2)">
<path
d="M -1,2 l 6,0"
[attr.stroke]="'#' + color"
stroke-width=".5"
/>
</pattern>
<ng-container *ngFor="let cone of cones, index as i">
<svg:circle
fill="url(#diagonalHatch)"
[attr.cx]="scaleX * (offset + cone.cX)"
[attr.cy]="cone.cY"
[attr.r]="scaleX * radius"
/>
</ng-container>
Result I am getting
Result I need
I suppose that what you have right now is something like this where due to the semitransparency of the pattern you can see the overlapped parts as darker:
<svg viewBox="0 0 100 50" width="400">
<pattern
id="diagonalHatch"
patternUnits="userSpaceOnUse"
width="1"
height="3"
patternTransform="rotate(-45 2 2)">
<path
d="M -1,2 l 6,0"
stroke="rgba(0, 100, 100, .3)"
stroke-width="0.5"
/>
</pattern>
<g>
<circle fill="url(#diagonalHatch)" r="20" cx="25" cy="25"/>
<circle fill="url(#diagonalHatch)" r="20" cx="50" cy="25"/>
<circle fill="url(#diagonalHatch)" r="20" cx="75" cy="25"/>
</g>
</svg>
As a possible solution you could use the circles as a clipping path and clip a rectangle the size of the svg canvas like so:
<svg viewBox="0 0 100 50" width="400">
<pattern
id="diagonalHatch"
patternUnits="userSpaceOnUse"
width="1"
height="3"
patternTransform="rotate(-45 2 2)">
<path
d="M -1,2 l 6,0"
stroke="rgba(0, 100, 100, .3)"
stroke-width="0.5"
/>
</pattern>
<clipPath id="c">
<circle r="20" cx="25" cy="25"/>
<circle r="20" cx="50" cy="25"/>
<circle r="20" cx="75" cy="25"/>
</clipPath>
<rect fill="url(#diagonalHatch)" width="100" height="50" clip-path="url(#c)"/>
</svg>

Add a stroke to a clipped path

I'd like to display a stroke around the intersection of two circles.
Here's my code:
<clipPath id="clip">
<circle cx="100" cy="100" r="50" />
</clipPath>
<circle cx="150" cy="100" r="50" fill="red" clip-path="url(#clip)" stroke="black" />
The stroke of the clipped circle is getting clipped by the clipPath as well, but I'd like it to wrap around the intersection of both circles.
Just add half the stroke width to the radius of the clipping circle.
For instance, we have circles of radius 50 and stroke width 10. So we make the clipping circle have a radius of (50 + 5) = 55.
<svg>
<clipPath id="clip1">
<circle cx="100" cy="100" r="55" stroke="black" fill="none" stroke-width="5"/>
</clipPath>
<clipPath id="clip2">
<circle cx="150" cy="100" r="55" stroke="black" fill="red" stroke-width="5"/>
</clipPath>
<circle cx="150" cy="100" r="50" stroke="black" fill="red" stroke-width="10" clip-path="url(#clip1)" />
<circle cx="100" cy="100" r="50" stroke="black" fill="none" stroke-width="10" clip-path="url(#clip2)" />
</svg>
One option would be to have both circles act both as clip paths and as stroked circles.
<clipPath id="clip1">
<circle cx="100" cy="100" r="50" id="circle1" stroke="black" fill="none"/>
</clipPath>
<clipPath id="clip2">
<circle cx="150" cy="100" r="50" id="circle2" stroke="black" fill="red"/>
</clipPath>
<use xlink:href="#circle2" clip-path="url(#clip1)"/>
<use xlink:href="#circle1" clip-path="url(#clip2)"/>
Make sure the second <use> element is not filled because it would cover half of the stroke of the first <use> element.

How to Exclude Area inside of clippath in Svg

I want to hide anything that outside a rectangle. (this i have achieved with clipping successfully). but another condition is that, 'also hide anything that comes inside the black big circle'. Now how i can achieve that?
in below example, 'yellow circle' must be eliminated'.
see below images for detail
Original:-
Desired:-
Below is my Svg code:-
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
</clipPath>
</svg>
Erik Dahlström is right, your clip can include the entire rectangle and the cutout for the circle. This way, anything you associate with #clip1 as the clip-path will not be visible inside your circle area. Here is what it looks like for your example:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<path d="M 50,50 l200 0 l0 200 l-200 0z M150,150 a30,30 1 0,0 60,0z M210,150 a30,30 1 0,0 -60,0z"/>
</clipPath>

Resources