i'm new to svg and am trying to create inner shadow kind of similiar to the attached pic. I've tried the other stack-overflow answers but the shadow doesn't seems to be as strong as the png attached. Can the experts suggest any possible way of achieving the same?
That doesn't look like a normal inset shadow - the opacity is too high near the border. So you'll have to do some fancy filtering to duplicate it. Here's something that will work for any shape:
<svg width="600px" height="600px">
<defs>
<filter id="strong-inner">
<feFlood flood-color="red"/>
<!-- This next operation subtracts the original shape from the red color
field filling the filter region - which will give you a big color border
surrounding the original shape -->
<feComposite operator="out" in2="SourceGraphic" />
<!-- Next we want to expand the red border so it overlaps the space of the
original shape - the radius 4 below will expand it by 4 pixels -->
<feMorphology operator="dilate" radius="4"/>
<feGaussianBlur stdDeviation="5" />
<!-- After blurring it, we want to select just the parts of the blurred,
expanded border that overlap the original shape - which we can do by using
the 'atop' operator -->
<feComposite operator="atop" in2="SourceGraphic"/>
</filter>
</defs>
<rect x="10" y="10" width="500" height="500" fill="rgb(50, 0 , 200)" filter="url(#strong-inner)"/>
</svg>
We can use box-shadow with inset option.
<svg style="background: rgb(51,54,148); width: 439px; height: 419px; box-shadow: 0 0 15px 6px inset rgba(255,0,96,0.8)"></svg>
Related
I have an image in pgn, e.g. chess piece (white king)
Is there a simple way of applying SVG filters with this image to obtain an SVG containing the same shape (sillhouette( outline) and being filled with one color (e.g. red)?
In the case where your image has a white fill and a transparent outside, then yes, you can do this with an SVG filter.
img {
filter: url(#colorise);
}
<svg width="0" height="0" style="position: absolute">
<defs>
<filter id="colorise">
<!-- Fill the filter area with red -->
<feFlood flood-color="red" result="colour"/>
<!-- Trim the red to just what's "in" (inside) the image (ie non-transparent) -->
<feComposite operator="in" in="colour" in2="SourceGraphic"/>
<!-- Multiply the trimmed red shape with the original image. Black parts stay black. White parts become red. -->
<feBlend mode="multiply" in2="SourceGraphic"/>
</filter>
</defs>
</svg>
<img src="https://cdn.jsdelivr.net/gh/oakmac/chessboardjs/website/img/chesspieces/wikipedia/wK.png"/>
Update
How to make the whole thing red, including the black parts.
img {
filter: url(#colorise);
}
<svg width="0" height="0" style="position: absolute">
<defs>
<filter id="colorise">
<!-- Fill the filter area with red -->
<feFlood flood-color="red" result="colour"/>
<!-- Trim the red to just what's "in" (inside) the image (ie non-transparent) -->
<feComposite operator="in" in="colour" in2="SourceAlpha"/>
</filter>
</defs>
</svg>
<img src="https://cdn.jsdelivr.net/gh/oakmac/chessboardjs/website/img/chesspieces/wikipedia/wK.png"/>
How can I combine svg filters to get both:
a "mottled" texture and
a single colour spectrum (e.g. different levels of blue-and-white)?
I'm able to use an feTurbulence filter to get the "mottling" effect. I'm also aware of the feColorMatrix filter to desaturate an image, i.e. "lose" the color and convert the image to grayscale. However, I haven't been able to combine them to do the latter after the former. When I've tried, the "rainbow" colouring effect of feTurbulence filter seems to persist. My (intermediate) desired result is a grayscale image. Beyond that, I then want to convert that grayscale image to a single colour, e.g. convert it from a gray-and-white spectrum to a blue-and-white spectrum. Perhaps those need to be in separate steps or perhaps they can be combined in a single step.
I show code below which applies the feTurbulence filter (in combination with an feComposite filter) to some text and an svg shape. This code works for me in Google Chrome, but I haven't checked it (nor do I currently need it) in other browsers. In case you are reading this question using a browser for which this filter does not work, a screen capture of output is provided here:
I eventually want to convert that to something like the following (which I created using image manipulation software, not web technologies):
I don't really need a universal cross-browser solution; I only need this to work in Chrome.
.filtered{
filter: url(#filter);
font-size: 100px;
}
p {
font-size: 100px;
}
<svg width="0" height="0">
<defs>
<filter id="filter">
<feTurbulence type="fractalNoise" result="TURBULENCE" baseFrequency="0.1" numOctaves="5" seed="2" />
<feComposite operator="in" in="TURBULENCE" in2="SourceAlpha" />
</filter>
</defs>
</svg>
<div class="filtered">
Some Text<br/>
<svg>
<rect x="10" y="10" width="300" height="100" fill="black" />
</svg>
</div>
These slides by Michael Mullany gave me some good pointers for figuring this out, as did the MDN web docs for SVG filters.
I discovered the following solution (although others are also possible). I use the result attribute value of feComposite filter element as the in attribute value for the feColorMatrix filter element which uses a type of "matrix". To understand the values attribute the following slide from Michael Mullany's talk helped me:
I entered a value of 1 for k3, understanding that to mean that I am adding a fixed full-blue offset to all the pixels in the eventual image, multiplying them by a factor of 0.5 from the output of the feComposite filter element's alpha channel (although I could have arbitrarily also put that value of 0.5 into any of the "R->A", "G->A", "B->A" or "A->A" locations).
If you are looking at this answer from a browser that is not capable of showing the code snippet results properly, the output that I get from the code below when using Google Chrome is the following:
.filtered{
filter: url(#filter);
}
p {
margin: 0;
font-size: 100px;
}
<svg width="0" height="0">
<defs>
<filter id="filter">
<feTurbulence type="fractalNoise" result="myTurbulence" baseFrequency="0.1" numOctaves="5" seed="2" />
<feComposite operator="in" in="myTurbulence" in2="SourceAlpha" result="myComposite"/>
<feColorMatrix in="myComposite" type="matrix"
values="0 0 0 0 0
0 0 0 0 0
0 0 0 0 1
0 0 0 0.5 0" />
</filter>
</defs>
</svg>
<div class="filtered">
<p>Some Text</p>
<svg>
<rect x="10" y="10" width="300" height="100" />
</svg>
</div>
I'm looking to have an svg fill a particular space in my layout, so preserveAspectRatio="none" seems like a good first approach.
However, within the svg, there is a mask that I do not want to stretch / warp. Rather, it should occupy 100% the width, with the height scaling according to its ratio. The two images illustrate the mask's behaviour when the parent svg is in either landscape or portrait. (Note: the grey in the image is the rest of the <svg>, which should stretch to fit)
Can the mask have its own aspectRatio settings? Is there a better way to achieve this? Or, is it even possible?
```
<!-- this should scale according to its bounding parent -->
<svg class="fix" viewbox="0 0 2880 1620" preserveAspectRatio="none..?">
<!-- this should scale according to some intrinsic ratio -->
<mask id="mask"
maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse">
<rect fill="white" x="0" y="0" width="2880" height="1620" />
<path fill="black" d="M57.59,60h409c344.17,.... ...."/>
</mask>
<rect mask="url(#mask)" x="0" y="0" width="100%" height="100%" />
</svg>
```
edit: using mask-image instead of just mask seems possible (as it has additional positioning options), but this does not seem to work with svg elements.
You don't need to use preserveAspectRatio="none" to have the rectangle and mask fill the page. Just extend the <rect> and <mask> past the boundaries of the SVG in all directions. Root <svg> elements have overflow: visible by default, so the extended rect will fill SVGs parent container - as long as you extend far enough of course.
<rect mask="url(#mask)" x="-1000%" y="-1000%" width="3000%" height="3000%" />
I've used 1000% here, but you can adjust that if you need more or less (than 10x).
And note that we are just using the standard default SVG preserveAspectRatio. So we still get the automatic centerinng and scaling of the SVG.
body {
margin: 0;
padding: 0;
}
svg {
width: 100vw;
height: 100vh;
}
<svg viewbox="0 0 2880 1620">
<!-- this should scale according to some intrinsic ratio -->
<mask id="mask"
maskUnits="userSpaceOnUse"
maskContentUnits="userSpaceOnUse"
x="-1000%" y="-1000%" width="3000%" height="3000%">
<rect fill="white" x="-1000%" y="-1000%" width="3000%" height="3000%" />
<circle cx="1440" cy="810" r="400" fill="black"/>
</mask>
<rect mask="url(#mask)" x="-1000%" y="-1000%" width="3000%" height="3000%" />
</svg>
Demo in fiddle format
I have an SVG where I'm using filters to blend white shapes on top of black backgrounds using multiply blending. Since I'm using multiply, I would expect the white shape not to show up at all, but this is not the case. In this example I'm drawing a square in its own filter, then a smaller circle (also in its own filter):
http://jsfiddle.net/mugwhump/SwcjL/2/
However, there is a faint, pixel-wide white outline surrounding the circle. The color and opacity of this outline depends on the color and opacity used to draw the circle.
It disappears if I move the circle into the same filter group as the square, but unfortunately that's not an option.
Any idea how to get rid of that outline? This happens in basically all browsers/renderers.
Here's the code for the svg:
<svg contentScriptType="text/ecmascript" width="530"
xmlns:xlink="http://www.w3.org/1999/xlink" zoomAndPan="magnify"
contentStyleType="text/css" viewBox="0 0 530 530" height="530"
preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg"
version="1.1">
<defs id="defs">
<!--Blend using multiply. -->
<filter color-interpolation-filters="sRGB" x="-1.0" y="-1.0" width="3.0"
xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple"
xlink:actuate="onLoad" height="3.0"
xlink:show="other" id="blend-square-multiply">
<feFlood result="blackness" flood-color="black"/>
<feComposite result="blackness clip" in="blackness" in2="SourceGraphic" operator="in"/>
<feColorMatrix in="SourceGraphic" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0" type="matrix" result="color-trans"/>
<feBlend mode="multiply" in="blackness clip" in2="color-trans"/>
</filter>
</defs>
<!-- White square blended with multiply over black feFlood -->
<g filter="url(#blend-square-multiply)">
<g fill="white" >
<rect x="200" width="100" y="200" height="100" />
</g>
</g>
<!-- White circle blended with multiply over black feFlood
Changing stroke width does nothing, but changing fill color changes
the color of the outline (changing stroke-color does not).
The outline disappears when opacity is set to 0. -->
<g filter="url(#blend-square-multiply)">
<g fill="white" opacity="1">
<circle stroke-width="0" cx="250" cy="250" r="50"/>
</g>
</g>
Remember that source graphics are rasterized before they're handed to the filter pipeline and hence shed their vectorish nature when they enter the threshold of filterdom.
You are getting that effect because the circle element has an edge of anti-aliasing aka semi-opaque pixels around its edges. When those are multiplied with black, you get grey.
Use shape-rendering="crispEdges" to avoid this. Or use an feMorphology erode filter to clip the edges of the antialiasing. Or use an feFuncA filter to dial those edges up to full opacity first. On second thought -- that first idea.
<circle shape-rendering="crispEdges" stroke-width="0" cx="250" cy="250" r="50"/>
I think the enable-background attribute may be the answer to your problem.
http://www.w3.org/TR/SVG/filters.html#EnableBackgroundProperty
I have an SVG "g" object that has several components. I'd like to render the whole thing partly transparent (e.g. alpha = 0.5) I'd also like to to be darker if possible. I know individual fill colors can be adjusted, but how about all of them together, possibly in some parameters to the "g" (grouping) structure.
Changing the opacity of the <g> (either by the opacity="..." attribute, or the opacity CSS rule) will cause the contents of the group to first be composited and then the result to be lowered in opacity. Note that this is distinctly different from lowering the opacity on all the elements inside the group (which you can also do via CSS):
Demo: http://jsfiddle.net/HZr7v/12/
Uses this SVG:
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
<defs><filter id="Darker">
<feColorMatrix type="matrix" values="
0.3 0 0 0 0
0 0.3 0 0 0
0 0 0.3 0 0
0 0 0 0.8 0"/>
</filter></defs>
<g id="g1" transform="translate(60,60)"> <!-- top left -->
<circle r="40" /><rect width="80" height="60" />
</g>
<g id="g2" transform="translate(220,60)"><!-- top right -->
<circle r="40" /><rect width="80" height="60" />
</g>
<g id="g3" transform="translate(60,200)"><!-- bottom left -->
<circle r="40" /><rect width="80" height="60" />
</g>
<g id="g4" transform="translate(220,200)"><!-- bottom right -->
<circle r="40" /><rect width="80" height="60" />
</g>
</svg>
…with this CSS:
circle { fill:red }
rect { fill:blue }
#g2 * { opacity:0.5 } /* Change the opacity of each shape */
#g3 { opacity:0.5 } /* Change the opacity of the group */
#g4 { filter:url(#Darker) } /* Darkens and drops opacity for group */
Note in particular the difference in appearance where the circle and square overlap.
The feColorMatrix filter looks daunting. All it does is set the RGB values to each be 30% of the original RGB (i.e. darker), and the alpha to be 80% of the original alpha. Change the values as you see fit.
Oh, and if you want to desaturate also you can throw this into the filter (before or after the darken step):
<feColorMatrix type="saturate" values="0.5"/>
<!-- values="0" will drop all color, leaving grayscale only -->
<!-- values="1" will leave the current saturation color -->
<!-- values="99" will super-saturate the colors -->
You could set opacity on the <g> itself and that would work. If you want it darker you'll need to apply a filter to the <g> something along these lines perhaps
<filter id="Darker" filterUnits="objectBoundingBox" x="0" y="0" width="100%" height="100%">
<feFlood in="SourceGraphic" flood-color="#0f0" flood-opacity="0.5" result="img2"/>
<feBlend in="SourceGraphic" in2="img2" mode="darken"/>
</filter>