Add a stroke to a clipped path - svg

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.

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>

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>

How to color a region i.e the intersection of two object?

I want to color an intersection of two object, let's say a circle and a rectangle.
What I have tried so far is to defined a path bounding that region then add the fill attribute, but it seems too complicated.
Is there any other ways to do so?
Let me elabotare more one the problem:
<svg width="352" height="57" xmlns="http://www.w3.org/2000/svg">
<line y2="0.75" x2="103.95" y1="43.15" x1="42.35" stroke-width="1.5" stroke="#000" fill="none"/>
<line y2="50.35" x2="201.55" y1="0.75" x1="103.95" stroke-width="1.5" stroke="#000" fill="none"/>
<line y2="19.15" x2="239.95" y1="49.55" x1="201.55" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="none"/>
<line y2="55.95" x2="282.35" y1="18.35" x1="240.75" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="none"/>
<line y2="37.55" x2="351.15" y1="31.95" x1="0.75" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="none"/>
</svg>
I have a set of lines which the end of one is another end of the other.
I have another line intersecing these line.
How could I color the region i.e the triangles formed by these line?
You can use <clipPath> to clip the rect with the circle like so:
svg{width:100vh;}
<svg viewBox="50 50 200 100">
<clipPath id="clip">
<use xlink:href="#c" />
</clipPath>
<g fill="none" stroke="black" >
<circle id="c" cx="100" cy="100" r="30" />
<rect id="r" x="90" y="80" width="80" height="60" />
</g>
<use xlink:href="#r" clip-path="url(#clip)" fill="gold" />
</svg>
You could work with opacity to let the color of an overlapped element shine through like shown here:
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg">
<g style="stroke:#000; stroke-width:1">
<circle cx="50" cy="50" r="50" opacity="0.5" style="fill:red" />
<circle cx="100" cy="50" r="50" opacity="0.5" style="fill:yellow" />
<rect x="0" y="70" width="150" height="50" fill-opacity="0.5" style="fill:blue" />
</g>
</svg>
You can also specify the opacity levels separately for stroke and fill by using stroke-opacity and fill-opacity.
Edit:
Looking at your edited question again: when you are dealing with a succession of lines (and curves) you should use <path> elements instead of individual <line> elements. One of its advantages is that it comes with a fill behaviour that is almost exactly as you want it to be. However, to suit the requirements of your example you would need to find the positions where the straight line enters and leaves the zig-zag shape. These positions then define the points used for your filled path. The "original" (non-filled) path is then plotted over the filled path:
<svg width="352" height="57" xmlns="http://www.w3.org/2000/svg">
<path d="M56,33 103.95,0.75 201.55,50.35 239.95,19.15 260,36z
M0.75,31.95 351.15,37.55" style="fill:yellow" />
<path d="M42.35,43.15 103.95,0.75 201.55,50.35 239.95,19.15 282.35,55.95
M0.75,31.95 351.15,37.55" style="stroke:black;fill:none"/>
</svg>

changing the start point in svg circle

I want to use the below SVG but the the fill starts from 3 O clock.
I want the fill to start from 12 O clock.
Please give suggestions on how to achieve that.
<svg id="svg" width="200" height="200" viewPort="0 0 100 100" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48"
stroke-dashoffset="0"></circle>
<text id="percentile" x="50%" y="50%" text-anchor="middle" stroke="#191919"
stroke-width="1px" font-size="35" dy="0.3em">{{pct}}</text>
<!--<text id="percentile" x="50%" y="50%" text-anchor="middle" stroke="#191919"
stroke-width="1px" font-size="20" dy="-0.3em">Percentile</text>-->
<circle id="bar" r="90" cx="100" cy="100" fill="transparent"
stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
</svg>
I presume you are using the image to show some kind of progress, i.e. it starts at completely gray, then gradually fills up with yellow starting from 3 o'clock as the proportion goes from 0 to 1 (or 0% to 100%), and the image shows what it looks like at 50%. You want to shift the start from 3 o'clock to 12 o'clock.
Update: The original solution I posted here suggested that you could solve this problem by using stroke-dashoffset. However, that solution was incorrect: it only works for small percentages of the circle, and breaks down once you try to fill larger proportions of the circle. The updated solution below shows an implementation of the suggestion in the comments below the original question. It involves rotating the circle. The demo code below also addresses one of the concerns you expressed for this solution in your comments, i.e. the demo code shows that if the rotation is applied only to the circle, it should not affect text that is placed within the circle.
<svg id="svg" width="500" height="200">
<g transform="">
<circle r="90" cx="100" cy="100" fill="none" stroke="gray" stroke-width="20"></circle>
<circle id="bar" r="90" cx="100" cy="100" fill="none" stroke="orange" stroke-width="20" stroke-dasharray="70.69 494.80" transform="rotate(0, 100, 100)"></circle>
<text x="35" y="100" font-family="Verdana" font-size="15">Text inside circle</text>
</g>
<g transform="translate(250)">
<circle r="90" cx="100" cy="100" fill="none" stroke="gray" stroke-width="20"></circle>
<circle id="bar" r="90" cx="100" cy="100" fill="none" stroke="orange" stroke-width="20" stroke-dasharray="70.69 494.80" transform="rotate(-90, 100, 100)"></circle>
<text x="35" y="100" font-family="Verdana" font-size="15">Text inside circle</text>
</g>
</svg>

Make a path get cut off by a circle

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>

Resources