The SVG I'm working with has a drop shadow via feGaussianBlur filter.
The shadow itself is displayed properly, but gets cut off on top and bottom edges.
Like so:
The SVG in question is:
<?xml version="1.0" standalone="no" ?>
<!DOCTYPE svg
PUBLIC '-//W3C//DTD SVG 1.1//EN'
'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg height="600" version="1.1" width="700" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs/>
<filter id="SVGID_0">
<feGaussianBlur in="SourceGraphic" stdDeviation="6.6"/>
<feOffset dx="0" dy="0"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<path d="M 0 83 Q 0 83 0 83 Q 0 83 6 79.5 Q 12 76 17 71 Q 22 66 30.5 57.5 Q 39 49 54 36 Q 69 23 82.5 16.5 Q 96 10 120 4.5 Q 144 -1 170.5 0 Q 197 1 218 16.5 Q 239 32 253.5 51 Q 268 70 278 83.5 Q 288 97 299 110 Q 310 123 320 129.5 Q 330 136 338 136.5 Q 346 137 355 129.5 L 364 122" stroke-linecap="round" style="stroke: #005e7a; stroke-width: 30; fill: none; filter: url(#SVGID_0);" transform="translate(50 50)" />
</svg>
The cropping seems to happen consistently in Chrome (30), Firefox (25), and Opera (12).
I can see that it's not a viewbox limitation, as it's set to 600x700.
I can also see in devtools inspector the bounding box of <path> element, and it's almost as if that's what cuts off the shadow:
If that's the case:
Why is the shadow only cut off vertically and not horizontally?
How to work around it, so that it's not clipped like this?
If it's not the bounding box, what causes this and how to avoid this clipping?
You need to increase the size of the filter region.
<filter id="SVGID_0" y="-40%" height="180%">
works just fine. The silent defaults for the filter region are: x="-10%" y="-10%" width="120%" height="120%" - large blurs usually get clipped. (Your shadow isn't getting clipped horizontally because your width is about 2.5x your height - so that 10% results in a wider horizontal filter region). Also, the y filter region seems to be calculated as if the path had a zero pixel stroke, so it's ignoring the stroke width. (Different browsers have different behavior wrt whether they consider the stroke to be part of the bounding box for purposes of filter region calculation.)
(Update: Moving up observations from comments)
Please note that if your particular shape is either zero width or zero height (e.g. a horizontal or vertical line), then you must specify filterUnits="userSpaceOnUse" as part of the filter declaration and explicitly specify a filter region (x,y,width height) in userSpaceUnits (usually pixels) that creates enough room to display a shadow.
Add an attribute to the filter shadow svg tag:
filterUnits="userSpaceOnUse"
Final Output:
<filter id="dropshadow" filterUnits="userSpaceOnUse" height="800" width="1600">
Which makes the shadow absolutely positioned and visible outside of its container.
If you're using it inside an HTML, you can simply use CSS properties to fix this issue.
svg {
overflow: visible !important;
}
I haven't checked other browsers, but chrome has the overflow: hidden by default on svg tags.
A bit late, but I hope it's helpful.
Related
I've been trying to figure this one out for a few days, the material icons are a bit too thick, so I downloaded one and have been trying to change the stroke weight / thickness. But just using the stroke-width property doesn't change anything, and if I add a 'stroke' it also adds a border around the element.
For example, here is the 'public' icon from google / material icons
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-.61.08-1.21.21-1.78L8.99 15v1c0 1.1.9 2 2 2v1.93C7.06 19.43 4 16.07 4 12zm13.89 5.4c-.26-.81-1-1.4-1.9-1.4h-1v-3c0-.55-.45-1-1-1h-6v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41C17.92 5.77 20 8.65 20 12c0 2.08-.81 3.98-2.11 5.4z"/>
</svg>
How would I go about making this thinner or thicker? Is there a minimum font weight? ( I want some pretty thin strokes for this)
The design of the icon is your problem
Paste the path in https://yqnn.github.io/svg-path-editor/
If you want more detail you need to edit the (filled) path.
I have two SVGs I want to morph between with Anime.Js, however they need to be the same number of points. So I either need a way to add points to an SVG or a way to convert a circle into a path with a specific number of points.
Here are the SVGs in question:
<svg id="svg1" width="290" height="290" viewBox="0 0 290 290" xmlns="http://www.w3.org/2000/svg">
<path d="M10,145a135,135 0 1,0 270,0a135,135 0 1,0 -270,0" />
</svg>
<svg width="290" height="290" viewBox="0 0 290 290" xmlns="http://www.w3.org/2000/svg">
<path d="M280 145C280 225.081 219.558 290 145 290C10 290 10 225.081 10 145C10 64.9187 70.4416 0 145 0C280 0 280 64.9187 280 145Z" />
</svg>
My assumption is that I might be able to just add points anywhere on the line of the circle's path in something like Figma. If that's the case, it's 22 points I need, correct?
try these values:
var morphing = anime({
targets: 'path',
d: [
{ value: 'M 280 145C 280 219.5 205.5 280 145 280C 70.5 280 10 219.5 10 145C 10 70.5 70.5 10 145 10C 219.5 10 280 70.5 280 145Z' },
{ value: 'M 280 145C 280 225.081 219.558 290 145 290C 10 290 10 225.081 10 145C 10 64.9187 70.4416 0 145 0C 280 0 280 64.9187 280 145Z' }
],
easing: 'easeOutQuad',
duration: 10000,
loop: true
});
It seems to work but I'm unfamiliar with the layout.
I tried substituting code into codepen Anime.js Morphing Paths.
You can see the last two points of both svg data is identical and that's how I think it should be. And obviously creating a circle with cubic beziers as this also translates near to the squished circle / square. I've formatted the string exactly as it is in their example, didn't seem to work otherwise.
Consider the following SVG image code:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<title>Clipped Path Problem Demo</title>
<g id="group:image">
<defs>
<mask id="mask">
<rect id="rectangle:inset" x="250" y="134" width="500" height="732" fill="white"/>
</mask>
</defs>
<g id="group:curves" mask="url('#mask')">
<!-- <rect id="rectangle:filler.shape" width="1" height="1" fill="transparent"/> -->
<path id="path:curves" d="
M 441 327
c -85 88 -85 175 -85 175
c 0 88 85 175 85 175
s 90 103 90 103
c 85 88 85 175 85 175" fill="transparent" stroke="black" stroke-width="73"/>
</g>
</g>
<g id="group:guides">
<rect id="rectangle:guide.area:inset" x="250" y="134" width="500" height="732" fill="transparent" stroke="black" stroke-dasharray="20 10" stroke-width="1"/>
</g>
</svg>
(CodePen: https://codepen.io/patrickdark/full/zPEVVg/. (I added a height="500px" attribute to the pen to make it more likely to fit on screen.))
The left side of the curved path is clipped to a vertical line even though the mask is well over the size needed to contain that portion of the image.
If I insert a shape of any size with non-zero dimensions into the masked g element—such as the 1×1 transparent rectangle in the XML comment—the clipped edge is magically unclipped.
I would think this is a bug except that it’s happening in Chrome (62), Edge (41), and Firefox Developer Edition (58 Beta 4). What I would like to know is why this seemingly nonsensical clipping is occurring.
(Note: Clipping at the bottom of the curved path is intentional.)
Since a mask works on color and alpha channel values (a potentially costly operation), it doesn't stretch to infinity, but rendering is clipped of by default at the object bounding box of the masked element plus 10% in every direction (defined by the attributes x, y, width, height in bounding box units).
The object bounding box although is defined not to include stroke widths. You are surpassing these limits and need to make adjustments at least to the x and width attribute of the mask.
Since this seems to be not intuitive, the general algorithm for applying a mask goes like this:
Identify the region the mask is applied to. This is always the rectangle given by the x, y, width, height attributes of the <mask> element. If, as is the default, the maskUnits attribute is given as objectBoundingBox, the coordinates are determined by the object bounding box of the element the mask is applied to. The contents of the mask are not taken into account. 0 and 1 in that coordinate system are the minimum and maximum of the joined bounding box of the masked element and all its descendants.
Superimpose the content of the mask element with the element it is applied to. As a default, the coordinate system used for placing these elements is given as maskContentUnits="userSpaceOnUse", which means the same coordinate system the masked element is drawn into.
For every point within the region defined above, multiply the opacity of the masked content with the luminance of the masking content to compute a resulting opacity of the masked element.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<title>Clipped Path Problem Resoved</title>
<g id="group:image">
<defs>
<mask id="mask" x="-20%" width="140%">
<rect id="rectangle:inset" x="250" y="134" width="500" height="732" fill="white"/>
</mask>
</defs>
<g id="group:curves"mask="url('#mask')">
<!-- <rect id="rectangle:filler.shape" width="1" height="1" fill="transparent"/> -->
<path id="path:curves" d="
M 441 327
c -85 88 -85 175 -85 175
c 0 88 85 175 85 175
s 90 103 90 103
c 85 88 85 175 85 175" fill="transparent" stroke="black" stroke-width="73"/>
</g>
</g>
<g id="group:guides">
<rect id="rectangle:guide.area:inset" x="250" y="134" width="500" height="732" fill="transparent" stroke="black" stroke-dasharray="20 10" stroke-width="1"/>
</g>
</svg>
This is my svg path. I am trying to achieve trapezium. Left of the rectangle has come out fine. I wanted the same way on the right side. How do I bend it?
<path d="M20 20 H 300 V 70 H 10 Z" fill="transparent" style="stroke:black; stroke-width:2"/>
This is the image reference of the shape I wanted:
http://amsi.org.au/teacher_modules/C3/C3g37.png
If you don't want a vertical line best not to use V as that command draws them. I've replaced the V with an L below.
<svg width="100%" height="100%">
<path d="M20 20 H 300 L 310 70 H 10 Z" fill="transparent" style="stroke:black; stroke-width:2"/>
</svg>
I want to draw a shape in SVG that has the centre hollowed out.
I asked this question for drawing a circle with a circle in the middle here.
I would like to draw any shape in SVG with the middle (of another shape) hollowed out.
Any ideas?
I'm thinking it could be possible using Masks or ClipPaths but I'm not sure if I understand them fully
Create your shape as a path, which consists of two sub-paths. The first subpath describes your outer shape; the second subpath describes the inside shape. Set the fill-rule of the pathto 'evenodd'.
e.g. for a hollowed out rectangle, we make a path consisting of two sub-paths. One for the outside rectangle; one for the inner rectangle:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<path d="M 100 100 L 200 100 L 200 200 L 100 200 z
M 110 110 L 190 110 L 190 190 L 110 190 z"
fill="red"
stroke="black" stroke-width="1"
fill-rule="evenodd"/>
</svg>