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?
I have the following SVG document:
<svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 21 484" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="dropShadow">
<feDropShadow dx="4" dy="0" stdDeviation="4"></feDropShadow>
</filter>
</defs>
<g id="Artboard" stroke-width="5" stroke="#FF0000" fill="#000000" stroke-linecap="round">
<path style="filter: url(#dropShadow)" d="M7.5,8.5 L7.5,471.5" id="path-1"></path>
</g>
</svg>
In Firefox, when I open the SVG document, it simply shows a very thin (not 5 wide) vertical line. In Chrome, it doesn't show anything (nor does it in codepen, here: https://codepen.io/jwir3/pen/BJBqEK ).
I'm not quite sure what I'm doing incorrectly here, but it has something to do with the filter, because, if I remove the filter: url(#dropShadow) from the path definition, the line shows up as expected.
You can't use objectBoundingBox units if your shape has no height or width.
Keyword objectBoundingBox should not be used when the geometry of the applicable element has no width or no height, such as the case of a horizontal or vertical line, even when the line has actual thickness when viewed due to having a non-zero stroke width since stroke width is ignored for bounding box calculations. When the geometry of the applicable element has no width or height and objectBoundingBox is specified, then the given effect (e.g., a gradient or a filter) will be ignored.
The default for filterUnits is objectBoundingBox units so you need to change that to userSpaceOnUse i.e.
<svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 21 484" xmlns="http://www.w3.org/2000/svg">
<title>Line Drop Shadow</title>
<description>A red line with 5px width thickness and round caps, having a drop-shadow. This highlights the regression documented in PURP-1017.</description>
<defs>
<filter id="dropShadow" filterUnits="userSpaceOnUse">
<feDropShadow dx="4" dy="0" stdDeviation="4"></feDropShadow>
</filter>
</defs>
<g id="Artboard" stroke-width="5" stroke="#FF0000" fill="#000000" stroke-linecap="round">
<path style="filter: url(#dropShadow)" d="M7.5,8.5 L7.5,471.5" id="path-1"></path>
</g>
</svg>
When processing filters, different browsers process in different stroke.
Chrome considers stroke as a value with a zero pixel, so it does not include it in the filter region.
Therefore, to make the result look the same in different browsers, it is better to replace path with stroke-width ="5", a rectangle with a width of 5px withoutstroke (stroke="none")
In addition, the default values for the filter area are: x =" - 10% "" y = "- 10%" `` width = "120%" `` height = "120%"- large blur sizes are usually truncated .
By default, filterUnits = "objectBoundingBox" and therefore the values are specified in percentages.
To make it easier to calculate the size of the filter region action, specify the value offilterUnits = "userSpaceOnUse" and then you can specify all dimensions for thefilter region` in pixels.
<svg preserveAspectRatio="xMinYMin meet" width="100%" height="100%" viewBox="0 0 21 484" xmlns="http://www.w3.org/2000/svg" >
<defs>
<filter id="dropShadow" filterUnits = "userSpaceOnUse" x="4" y="0" width="12" height="472">
<feDropShadow dx="6" dy="4" stdDeviation="3"></feDropShadow>
</filter>
</defs>
<g id="Artboard" fill="#FF0000" filter="url(#dropShadow)" >
<!-- <path style="filter: url(#dropShadow)" d="M7.5,8.5 L7.5,471.5" id="path-1" stroke-width="5" ></path>-->
<rect x="5" y="5" width="5" stroke="none" height="463" />
</g>
</svg>
Swapping to userSpaceOnUse is the correct answer in most circumstances but has the following limitations:
The filter effects region will apply from -10% to 120% of the canvas, rather than the bounding box of the element (using more memory and processing time)
For large dynamic SVGs (such as created by d3) it can be hard to calculate the required filter x/y/width/height to ensure the filter applies to all elements.
An alternate (less elegant) solution is to apply the filter to a <g> and use a hidden node within this to give the group the correct width or height:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="dropShadow" width="20">
<feDropShadow dx="4" dy="0" stdDeviation="4"></feDropShadow>
</filter>
</defs>
<g id="Artboard" style="filter: url(#dropShadow)">
<circle r="5" cx="0" cy="0" visibility="hidden"></circle>
<path d="M10,10 L10,100" stroke-width="5" stroke="#FF0000" fill="#000000" stroke-linecap="round"></path>
</g>
</svg>
I have a pin that needs to be shown inside a circle in Svg.
My current code is the following:
<svg viewBox="0 0 20 20" preserveAspectRatio="xMinYMin meet">
<circle cx="50%" cy="1.5" r="1.5" style="fill: green;"></circle>
<svg x="47.5%" y="5%" viewBox="0 0 10000 10000" fill="#fff" preserveAspectRatio="none">
<g>
<path d="M250,124.3c-35,0-63.4,28.8-63.4,64.1c0,35.3,28.5,64,63.4,64s63.4-28.8,63.4-64.1C313.4,153,285,124.3,250,124.3z
M250,222c-18.3,0-33.2-15.1-33.2-33.7s14.9-33.7,33.2-33.7s33.2,15.1,33.2,33.7S268.3,222,250,222z">
</path>
<path d="M250,50.9c-74.9,0-135.8,61.6-135.8,137.4c0,31.3,22.5,84.4,66.9,157.7c32.9,54.4,66.2,100.3,66.6,100.7l2.4,3.3l2.4-3.3
c0.3-0.5,33.7-46.3,66.6-100.7c44.4-73.3,66.9-126.4,66.9-157.7C385.8,112.5,324.9,50.9,250,50.9z M250,397.6
c-16.5-24.3-45.5-68.4-69.9-114c-23.5-44-35.9-77-35.9-95.4c0-59,47.4-107,105.8-107s105.8,48,105.8,107
c0,18.4-12.4,51.4-35.9,95.4C295.4,329.3,266.5,373.4,250,397.6z">
</path>
</g>
</svg>
</svg>
which works somewhat but seems inelegant, and perhaps also buggy. What I would like is a better way to center the group 'inside' the circle without using JavaScript
It would be nice if I could get rid of the extra SVG element in the middle with its really big viewBox that I'm using to place the pin. So if you can show me how to do it with just a g and make a scaling function that would be good.
If you want to use coordinates that contain percentage values, you need an element that has x and y attributes. <use> is such an element, <g> is not.
Your live will be easier if you draw your pin centered on the origin of the coordinate system: translate(-250 -230).
After that, you can easily scale it to the size you need: scale(0.0025) (remember: multiple transform commands are processed right-to-left.)
Finally, you use the pin template with the same x and y coordinates as your circle.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 20 20" preserveAspectRatio="xMinYMin meet">
<defs>
<!--center the pin around the origin and scale it to final size-->
<g id="pin" transform="scale(0.0025) translate(-250 -230)">
<path d="M250,124.3c-35,0-63.4,28.8-63.4,64.1c0,35.3,28.5,64,63.4,64s63.4-28.8,63.4-64.1C313.4,153,285,124.3,250,124.3z
M250,222c-18.3,0-33.2-15.1-33.2-33.7s14.9-33.7,33.2-33.7s33.2,15.1,33.2,33.7S268.3,222,250,222z" />
<path d="M250,50.9c-74.9,0-135.8,61.6-135.8,137.4c0,31.3,22.5,84.4,66.9,157.7c32.9,54.4,66.2,100.3,66.6,100.7l2.4,3.3l2.4-3.3
c0.3-0.5,33.7-46.3,66.6-100.7c44.4-73.3,66.9-126.4,66.9-157.7C385.8,112.5,324.9,50.9,250,50.9z M250,397.6
c-16.5-24.3-45.5-68.4-69.9-114c-23.5-44-35.9-77-35.9-95.4c0-59,47.4-107,105.8-107s105.8,48,105.8,107
c0,18.4-12.4,51.4-35.9,95.4C295.4,329.3,266.5,373.4,250,397.6z" />
</g>
</defs>
<!--use the same coordinates for the center of the circle and the pin-->
<circle cx="50%" cy="1.5" r="1.5" fill="green" />
<use xlink:href="#pin" x="50%" y="1.5" fill="white" />
</svg>
I need to draw red cirle with two curved string inside like that:
upper string always be 3 chars length
lower string can be from 1 to 20 chars length
UPDATE1:
I try to use textpath and circle tags, but I think I need to change some coordinates:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="40" cy="40" r="24" style="stroke:#006600; fill:none"/>
<defs>
<path id="myTextPath"
d="M75,20
a1,1 0 0,0 150,0"
/>
</defs>
<text x="5" y="50" style="stroke: #000000;">
<textPath xlink:href="#myTextPath" >
string
</textPath>
</text>
</svg>
Also I didnt clear understand <path> 'd' atrribute , but I found out that I can change starting point to M10,20 but how I can change text curve orientation?
d="M10,20 a1,1 0 0,0 150,0"
To have text that "hangs" from a line nicely, the best way right now is to use a path with a smaller radius. There is an attribute to adjust the text's baseline, but that doesn't work reliably.
So you need two arcs. One for the bottom half of the circle, and one with a smaller radius for the top half. They also need to both start from the left. That means one will go clockwise, and the other will go anti-clockwise. You control that with the arc command's "sweep" flag.
We need to also use startOffset="50%" and text-anchor="middle" to centre the text on the paths.
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 80 80">
<defs>
<path id="tophalf" d="M26,40 a14,14 0 0,1 28,0" />
<path id="lowerhalf" d="M16,40 a24,24 0 0,0 48,0" />
</defs>
<circle cx="40" cy="40" r="24" style="stroke:#006600; fill:none"/>
<path d="M16,40 a24,24 0 0,0 48,0" style="stroke:#600; fill:none"/>
<text x="5" y="50" style="stroke: #000000;"
text-anchor="middle">
<textPath xlink:href="#tophalf" startOffset="50%">str</textPath>
</text>
<text x="5" y="50" style="stroke: #000000;"
text-anchor="middle">
<textPath xlink:href="#lowerhalf" startOffset="50%">second st</textPath>
</text>
</svg>
This works fine in FF, but unfortunately, it seems there are bugs in Chrome and IE right now that is causing the text to not be centred properly on those browsers.
I need to get text with desired height and width.
I tried to find something in documentation of svg but found only font-size and also I tried to use scale in such manner:
<text xmlns="http://www.w3.org/2000/svg" id="10996080909940" name="-1"
x="1782.9351809218" y="-751.796133712862" width="1" height="1" style="font:Arial;text-
anchor:start;stroke:#000000" transform="rotate(0) scale(2 2)"> SOME TEXT </text>
But I get too big size of text and in place not where I need.
If you mean you want the text to exactly fill an arbitrary width and height, then there isn't really an easy way to do it in SVG. You can't specifiy a width and height on the <text> element. At least not in the current SVG spec (1.1).
However there are several ways to achieve this effect with a bit of trickery.
One way is by using a transform, as you suggested:
<svg>
<text font-size="10px" font-family="Verdana" transform="translate(99,400) scale(3.5,13.7)">SQUASHED TEXT</text>
<rect x="100" y="300" width="300" height="100" fill="none" stroke="red" />
</svg>
A second way is by using an inner <svg> element and setting the viewBox to match the bounds of the text. You then set preserveAspectRatio="none".
<svg>
<svg x="100" y="100" width="300" height="100" viewBox="0.2 -7.3 86 7.3" preserveAspectRatio="none" overflow="visible">
<text font-size="10px" font-family="Verdana">SQUASHED TEXT</text>
</svg>
<rect x="100" y="100" width="300" height="100" fill="none" stroke="red" />
</svg>
This way is more verbose, but it has the advantage that once you have found the correct viewBox for a piece of text, you can make it fit any sized rectangle very easily. Just set the x,y,width and height of the inner <svg> to the size of the rectangle.
Demo here: http://jsfiddle.net/ZRgEF/3/