I am drawing an SVG ellipse and I want two gaps, positioned center top and bottom:
<ellipse fill="none" stroke="black" stroke-width cx="15" cy="15" rx="12.55" ry="13.45" stroke-dasharray="19.65 1.5 39.32 1.5"/>
But I want the gap edges to be vertical, like if I a straight line was drawn through the un-gapped ellipse:
<g stroke-width="1.5">
<ellipse stroke="black" fill="none" cx="15" cy="15" rx="12.55" ry="13.45"/>
<path stroke="white" d="M15 35 V30">
</g>
I can't do that, because the line is not transparent. The gaps should look like nothing has been drawn there and not alter or overlay the background.
Further unsuccessful experiments:
stroke-linecap="square" on example #1
stroke="transparent" for the line in ex. #2.
stroke="transparent" stroke-occupacy="1" for the line in ex. #2.
What can I do?
jsfiddle
This is a typical case for using a mask. Everything that coincides with the white parts of the mask is drawn as is, everything that coincides with the black parts becomes transparent.
<svg viewBox="0 0 40 40" height="90vh">
<mask id="mask">
<rect width="100%" height="100%" fill="white" />
<path stroke="black" stroke-width="5" d="M15 35 V0" />
</mask>
<ellipse stroke="black" fill="none" stroke-width="1.5"
mask="url(#mask)"
cx="15" cy="15" rx="12.55" ry="13.45" />
</svg>
Related
This:
<svg width=100 height=100>
<g transform="translate(0.5, 0.5)" stroke=red fill=none>
<line x1=10 y1=10 x2=10 y2=50 />
<path d="M20,10 H20 V50 H20 Z" />
<path d="M30,10 H31 V50 H30 Z" />
<path d="M40,10 H42 V50 H40 Z" />
<path d="M50,10 H52 V50 H50 Z" />
</g>
</svg>
produces image like this in Chrome (zoomed in so it's obvious):
Top part
Bottom part
Note that the edges of the lines and the corners of the rectangles are of a slightly lighter red.
This looks like it's anti-aliasing, but trying shape-rendering="crispEdges" suggestion in this answer did not fully work. The problem is that it then cuts the line by 1px instead:
<svg width=100 height=100>
<g shape-rendering="crispEdges" stroke=red fill=none>
<line x1=10 y1=10 x2=10 y2=50 />
<path d="M20,10 H20 V50 H20 Z" />
<path d="M30,10 H31 V50 H30 Z" />
<path d="M40,10 H42 V50 H40 Z" />
<path d="M50,10 H52 V50 H50 Z" />
</g>
</svg>
Top part
Bottom part
Is there a way to fix this somehow, so I get the same line color across the specified coordinate range?
On Win64 Chrome, I'm only seeing the antialiasing on the first two elements.
The explanation for the line element is simple. Because you are translating down by half a pixel, the two line ends are ending halfway up/down a pixel. Hence you will get antialiasing in that case. Adjust the coords, or add stroke-linecap="square" to fix that.
Illustration:
<svg viewBox="0 0 70 40" width="420">
<g transform="translate(10,10)">
<g fill="none" stroke="#ccc" id="grid">
<rect width="10" height="10"/>
<rect x="10" width="10" height="10"/>
<rect y="10" width="10" height="10"/>
<rect x="10" y="10" width="10" height="10"/>
</g>
<!-- line (as is) -->
<line x1="5" y1="20" x2="5" y2="5" stroke="#00c8" stroke-width="10"/>
<line x1="5" y1="20" x2="5" y2="5" stroke="red" stroke-width="1"/>
</g>
<g transform="translate(40,10)">
<use xlink:href="#grid"/>
<!-- rectamngle corner -->
<path d="M 5,20 L 5,5 L 20,5" fill="none" stroke="#00c8" stroke-width="10"/>
<path d="M 5,20 L 5,5 L 20,5" fill="none" stroke="red" stroke-width="1"/>
</g>
</svg>
As for the zero width rectangle. Not sure what's happening there. It is only slightly lighter. It is likely a rendering bug in Skia. It may only effect the GPU renderer of Skia (I didn't check). The GPU renderer has a few more rendering bugs on these sort of edge cases than the CPU rendering path. If you care, you could file a bug about it.
<svg width=100 height=100>
<g transform="translate(0.5, 0.5)" stroke=red fill=none>
<line x1=10 y1=10 x2=10 y2=50 stroke-linecap="square"/>
<path d="M20,10 H20 V50 H20 Z" />
</g>
</svg>
Here is an example:
<svg width="60" height="30">
<path stroke="red" stroke-width="1" fill="none" d="M0 25 L10 25 L45 5 L55 5"/>
</svg>
I find that the inclined line segment has a thinner stroke-width then the horizontal lines. How do I make the stroke-width consistent across the entire path?
Breaking the path into multiple paths did not help as the line joins are not elegant. The points are generated dynamically so the solution needs to be generic.
<svg width="180" height="120">
<g stroke="red" fill="none">
<g stroke-width="1">
<path id="p" d="M0 25l10 0l35-20l10 0" />
<use href="#p" y="25" shape-rendering="optimizeQuality"/>
<use href="#p" y="50" shape-rendering="crispEdges"/>
</g>
<use href="#p" stroke-width="2" x="60"/>
<use href="#p" stroke-width="3" x="120"/>
</g>
</svg>
I added stroke-width 2 and 3 to your example. The effect is less because more pixels are being used to draw the line.
At 1 pixel your monitor and Browser can't make much of it. Only add (some) anti-aliasing.
screenshot zoomed:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering won't help
because it is still your monitor/browser only having 1 pixel to draw that line
Same for CSS https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering..
it is still 1 pixel
Same for setting style="transform:translateZ(0)"
Maybe in the future with Quantum Dot display technology it will look better. https://en.wikipedia.org/wiki/Next_generation_of_display_technology
I'm trying to create a filter for only the stroke of path in SVG, but the feImage keeps getting clipped to what I assume is that bounding box (see green rectangle below in code as bounding box). I've tried setting the filter's x/y and width/height to all sorts of positions/sizes, as seems to be the prevailing advice, but nothing works. x/y just offset the feImage and width/height of greater than 100% has no effect.
I won't know in advance if the stroke or fill is solid or something else (like linearGradient.
The below demonstrates what I'm looking to do - just get the stroke of a shape (regardless of size or fill) and apply a filter to it for all modern browsers.
Notes: FF doesn't even display the left-hand feImage. Chrome clips the left and top. Edge clips all 4 sides.
<html>
<body>
<svg width="960" height="540" >
<rect width="960" height="540" stroke="#385D8A" fill="white" stroke-width="3"/>
<svg name="BoundingBox1" class="rect" x="100" y="100" overflow="visible" fill="none" stroke="#00ff00" stroke-width="1">
<path d="M0,0L121.68,0L121.68,121.68L0,121.68Z" />
</svg>
<!-- BELOW IS MODIFIED "SPEECH" SHAPE. NEED A FILTER ON THE STROKE ONLY. -->
<svg name="Speech-strokeonly" x="100" y="100" overflow="visible" fill="blue" stroke="orange" stroke-width="12" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M35.541,137.084L30.985,113.988A60.926,60.926 0 1 1 53.043,121.34Z" id="strokeOnly" fill="none"/>
<filter id="effs0sp9" color-interpolation-filters="sRGB" x="0" y="0">
<feImage xlink:href="#strokeOnly" />
</filter>
</defs>
<path d="M35.541,137.084L30.985,113.988A60.926,60.926 0 1 1 53.043,121.34Z" id="effs0sp9" filter="url(#effs0sp9)" overflow="visible" />
<text y="160" stroke="black" stroke-width="0.2">this is the one that has undesirable clipping of</text>
<text y="178" stroke="black" stroke-width="0.2">of stroke in Chrome/Edge. Doesn't appear at all in FF</text>
</svg>
<!-- BELOW IS ORIGINAL WITH BOTH FILL AND STROKE -->
<svg name="BoundingBox2" x="400" y="100" overflow="visible" fill="none" stroke="green" stroke-width="1">
<path d="M0,0L121.68,0L121.68,121.68L0,121.68Z" />
</svg>
<svg name="Speech-original" x="400" y="100" overflow="visible" fill="blue" stroke="orange" stroke-width="12">
<path d="M35.541,137.084L30.985,113.988A60.926,60.926 0 1 1 53.043,121.34Z" id="effs0sp9" />
<text y="-22" stroke="black" stroke-width="0.2">this is the original one</text>
<text y="-6" stroke="black" stroke-width="0.2">that I just want the stroke as feImage from</text>
</svg>
</svg>
</body>
</html>
Is there a way to grab the whole stroke of a shape only and use in a filter?
Suppose I have a SVG circle with a radius r. Now suppose I have an SVG line which starts at the center of the SVG circle. How can I determine the x2 and y2 coordinates of where it crosses the radius of the circle.
<line x1="500" y1="500" x2="300" y2="75" style="stroke:#156217;stroke-width:4" />
<circle cx="500" cy="500" r="100" stroke="black" stroke-width="3" fill="transparent" />
You can clip the line with a clipPath. The use element allows us to point to the circle element we want to reuse for clipping.
<svg viewBox="0 0 1000 1000">
<defs>
<clipPath id="cp">
<use xlink:href="#c"/>
</clipPath>
</defs>
<line x1="500" y1="500" x2="300" y2="75" style="stroke:#156217;stroke-width:4" clip-path="url(#cp)" />
<circle id="c" cx="500" cy="500" r="100" stroke="black" stroke-width="3" fill="none" />
</svg>
I mean after my SVG stops completing the animation I want the animation to start over again and end and then again start over and so on.
I tried:
<svg>
<animate repeatCount="indefinite"/>
</svg>
But it doesn't work.
See example animMotion01 in the w3 SVG spec for a fairly reduced example illustrating SVG animation (including use of repeatCount="indefinite"):
<svg width="5cm" height="3cm" viewBox="0 0 500 300"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<desc>Example animMotion01 - demonstrate motion animation computations</desc>
<rect x="1" y="1" width="498" height="298"
fill="none" stroke="blue" stroke-width="2" />
<!-- Draw the outline of the motion path in blue, along
with three small circles at the start, middle and end. -->
<path id="path1" d="M100,250 C 100,50 400,50 400,250"
fill="none" stroke="blue" stroke-width="7.06" />
<circle cx="100" cy="250" r="17.64" fill="blue" />
<circle cx="250" cy="100" r="17.64" fill="blue" />
<circle cx="400" cy="250" r="17.64" fill="blue" />
<!-- Here is a triangle which will be moved about the motion path.
It is defined with an upright orientation with the base of
the triangle centered horizontally just above the origin. -->
<path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z"
fill="yellow" stroke="red" stroke-width="7.06" >
<!-- Define the motion path animation -->
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto" >
<mpath xlink:href="#path1"/>
</animateMotion>
</path>
</svg>