I am having a problem with setting up shadow for a svg with mask applied to it. This is the code and jsfiddle: http://jsfiddle.net/3kxnmhfL/
.watch-video-svg {
width: 50px;
height: 50px;
}
<div class="watch-video-svg">
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" height="100%" width="100%" viewBox="0 0 100 100">
<defs>
<filter id="shadow">
<feDropShadow dx="4" dy="8" stdDeviation="4"/>
</filter>
<mask id="cut-off-bottom">
<circle cx="50%" cy="50%" r="50%" fill="white"/>
<polygon points="31,20, 31,77, 80,50" fill="black"/>
<!-- <rect x="0" y="0" width="200" height="200" fill="url(#Gradient)" /> -->
</mask>
</defs>
<circle cx="50%" cy="50%" r="50%" fill="red" mask="url(#cut-off-bottom)" filter="url(#shadow)" />
</svg>
</div>
I'd like the shadow to appear only around svg circle and not containing div.
What could be the reason for shadow not showing up?
SVG filters have a "filter region". The filter region defines the area of pixels that the browser uses to store the result of the filters. The default filter region is the bounds of the element (that the filter is applied to) plus a margin around it to allow for filter elements that have results larger than the original element.
By default, that margin is 10% of the width and height, applied to all four sides. However in your case, a stdDeviation of "4" causes the blur to extend further than that 10% margin allowance. The result is a clipped blur, even though the viewBox has been enlarged enough to cater for the full blur.
To fix, this, you just need to bump up the filter region size. An allowance of 20% seems to work okay:
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
In addition, I've simplified the SVG by getting rid of the unnecessary mask. I also tweaked the viewBox to include the part of the blur that extends to the left.
.watch-video-svg {
width: 500px;
height: 500px;
background: linen;
}
<div class="watch-video-svg">
<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="-5 0 120 120">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="4" dy="8" stdDeviation="4"/>
</filter>
</defs>
<circle cx="50" cy="50" r="50" fill="red" filter=url(#shadow) />
<polygon points="31,20, 31,77, 80,50" fill="white"/>
</svg>
</div>
You need to adjust your mask. Since your element is already a circle you don't need a circle in the mask, a rect to fill all the width/height is enough.
You need to also adjust the viewBox to leave some space for the shadow:
.watch-video-svg {
width: 50px;
height: 50px;
}
<div class="watch-video-svg">
<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 120 120">
<defs>
<filter id="shadow">
<feDropShadow dx="4" dy="8" stdDeviation="4"/>
</filter>
<mask id="cut-off-bottom">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<polygon points="31,20, 31,77, 80,50" fill="black"/>
</mask>
</defs>
<circle cx="50" cy="50" r="50" fill="red" mask="url(#cut-off-bottom)" filter=url(#shadow) />
</svg>
</div>
Related
I have a SVG that needs to have a fixed height so its not super big when the width is 2000+ pixels (widescreens...)
The clipping mask should always be visible and the background image should be sliced and not be stretchend, i tried several things but nothing seems to work.
This is what i have now:
https://codepen.io/bucky208/pen/OEqbPp
div {
width: 100%;
}
<div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1024 1381.5" preserveAspectRatio="none" style="display: block; position: absolute; width: 100%;height: 400px;">
<g id="clipgroup">
<defs>
<polygon id="mask" points="0,572.1 0,1381.3 1024,1040.5 1024,337.6 0,0"/>
</defs>
<clipPath id="mask_1_">
<use xlink:href="#mask" style="overflow:visible;"/>
</clipPath>
<g style="clip-path:url(#mask_1_);">
<image style="overflow:visible;" width="331" height="444" id="theimage" xlink:href="https://image.ibb.co/ipbNkJ/56_E0406_E5_C8_EF897.jpg" transform="matrix(3.1119 0 0 3.1111 -3.0528 -2.604167e-04)"></image>
</g>
</g>
</svg>
</div>
Do i need another wrapper around everything? How do i restore the image ratio?
Kind regards and a big thank you for everyone trying to help.
In order to get image fills to fill their container but preserve the original aspect ratio, a filter combined with objectBoundingBox sizing and preserveAspectRatio is your friend. The following code does what I think you want:
svg {
background: red;
}
#svgcont {
position: absolute;
width: 100%;
}
<div id="svgcont">
<svg x="0" y="0" width="100%" height="800px">
<defs>
<filter id="image-fill-nostretch" primitiveUnits="objectBoundingBox">
<feImage x="0" y="0" width="1" height="1" id="theimage" xlink:href="https://image.ibb.co/ipbNkJ/56_E0406_E5_C8_EF897.jpg" preserveAspectRatio="xMidYMid slice"/>
<feComposite operator="in" x1="SourceGraphic"/>
</filter>
<clipPath id="mask_1_" clipPathUnits="objectBoundingBox">
<polygon id="mask" points="0,0.5 0,1 1,0.75 1,0.25 0,0"/>
</clipPath>
</defs>
<g clip-path="url(#mask_1_)">
<rect width="100%"height="100%" x="0%" y="0%" filter="url(#image-fill-nostretch)"/>
</g>
</svg>
</div>
Is it possible to offset the pattern in an svg element by a certain amount?
The example below uses a pattern of circles that is embedded in a <g> element that has an x="70" offset. Unfortunately the offset only 'cuts' away a part of the element without moving the fill pattern.
html, body, svg {
margin: 0;
width: 100%;
height: 100%;
}
<svg class="gFlow" id="main" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern height="64" id="grid" patternunits="userSpaceOnUse" width="64">
<circle cx="32" cy="32" fill="orange" r="5"></circle>
</pattern>
</defs>
<rect fill="url(#grid)" height="100%" width="100%" x="70"></rect>
</svg>
Don't offset the rectangle, offset the pattern. You can specify the origin (offset) of a pattern using the x and y attributes. It doesn't matter if the offset is positive or negative, the pattern will still fill the element completely.
html, body, svg {
margin: 0;
width: 100%;
height: 100%;
}
svg {
border: solid 1px black;
}
<!-- Pattern with no offset -->
<svg class="gFlow" id="main" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern height="64" id="grid" patternUnits="userSpaceOnUse" width="64">
<circle cx="32" cy="32" fill="orange" r="5"></circle>
</pattern>
</defs>
<rect fill="url(#grid)" height="100%" width="100%"></rect>
</svg>
<!-- Pattern moved right by half the pattern width (32) -->
<svg class="gFlow" id="main" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern height="64" id="grid" patternUnits="userSpaceOnUse" width="64"
x="32" y="0">
<circle cx="32" cy="32" fill="orange" r="5"></circle>
</pattern>
</defs>
<rect fill="url(#grid)" height="100%" width="100%"></rect>
</svg>
Note: SVG attributes are technically case sensitive. That's changing, but you should use the correct case for backwards compatibility. patternunits should be patternUnits.
Is it possible to have a multiple different views into single SVG, or even just simulate that sort of effect with some clever use of groups? I wish to show different parts of a potentially very large SVG, but I'd rather avoid rendering it multiple times. Is there some sort of simple way of doing this?
for standalone SVGs there is the <view/> element which you can use to show only portions of your graphics. try this in a standalone file.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" width="100" height="100">
<view id="circleView" viewBox="0 0 100 100"/>
<view id="rectView" viewBox="100 0 100 100"/>
<a xlink:href="#rectView">
<circle cx="50" cy="50" r="45" fill="blue"/>
</a>
<a xlink:href="#rectView">
<rect x="105" y="5" width="90" height="90" fill="royalblue" stroke="#53c"></rect>
</a>
</svg>
just click on the cirlce to see the rect and on the rect to see the circle.
this also works if you reference your svg via <img>
<img src="your.svg#circleView"/>
<img src="your.svg#rectView"/>
i found this to be not working for inlined SVG. Here you can use a similar aproach. You can just change the viewBox of your SVG. In contrast to the above, viewBoxes can even be animated!
<svg viewBox="0 0 460 360" width="200" height="200">
<polygon id="triangle" points="100,10,450,350,10,350" fill="#52c" />
<circle id="circle" cx="50" cy="50" r="45" fill="#c52" />
<rect id="rect" x="255" y="155" width="200" height="200" fill="#5c2" />
<animate attributeName="viewBox" to="250 150 210 210" dur="0.5s" begin="circle.click" fill="freeze" />
<animate attributeName="viewBox" to="0 0 100 100" dur="0.5s" begin="triangle.click" fill="freeze" />
<animate attributeName="viewBox" to="0 0 460 360" dur="0.5s" begin="rect.click" fill="freeze" />
</svg>
<br/>click on any of he shapes!
of course you can also just set the viewBox by script...
if you want to reference different parts of your SVG, you might use the <use> - Element as suggested in the other answers.
It's pretty simple to do. You just use the <use> element as Robert suggests. Here is a working example.
svg {
border: solid 1px black;
}
svg#original {
width: 450px;
}
<svg viewBox="0 0 450 300" id="original">
<circle cx="225" cy="150" r="150" fill="orange"/>
<circle cx="175" cy="110" r="25" fill="black"/>
<circle cx="275" cy="110" r="25" fill="black"/>
<circle cx="225" cy="70" r="150" fill="none" stroke="black" stroke-width="20" stroke-dasharray="0 145 180 1000"/>
</svg>
<br/>
<!-- part of the original at the same scale -->
<svg width="150" height="150">
<use xlink:href="#original" x="-50" y="0" width="450" height="300"/>
</svg>
<!-- part of the original at 0.5x scale -->
<svg width="150" height="150">
<use xlink:href="#original" x="0" y="0" width="450" height="300" transform="scale(0.5)"/>
</svg>
<!-- part of the original at 3x scale (and using a different method to achieve the scaling) -->
<svg width="150" height="150">
<use xlink:href="#original" x="-450" y="-255" width="1350" height="900"/>
</svg>
I have a SVG canvas which user can select and resize some <image> elements inside. And I use preserveAspectRatio="xMidYMid meet" attribute value to keep the original aspect ratio. The original image sources are mostly 256x256px size. On Firefox and IE-11, when I resize <image> elements to a smaller size than their original size, they look very pixelated. On Chrome they look pretty smooth. I wonder if there are any css or svg features which could help me to make them look smoother on Firefox and IE too.
Thank you.
EDIT: Adding sample..
https://jsfiddle.net/p8km6nhc/7/
<svg viewBox="-170 -87 1678 869" style="width: 100%; height: 100%; overflow: hidden; left: 0px; top: -0.800003px;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<filter id="varlikItemShadow1">
<feGaussianBlur stdDeviation="3" in="SourceGraphic"></feGaussianBlur>
<feOffset dy="1" dx="1"></feOffset>
<feMerge>
<feMergeNode></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g>
<g transform="matrix(1,0,0,1,0,0)">
<g transform="matrix(1,0,0,1,158,256)">
<g title="" data-original-title="" data-rounded="yes">
<text style="font:0px arial;" x="0" y="1" stroke="none" transform="matrix(1,0,0,1,0,0)" fill="#ffffff" fill-opacity="0.111111">[[VarlikId=3999]]</text>
<rect filter="url(#varlikItemShadow1" stroke="#2b5987" stroke-width="2" fill-opacity="0.9" fill="#ffe8f6" ry="10" rx="10" y="0" x="0" height="140" width="1270"></rect>
<path d="M0 0 L 1268 0 1268 138 0 138Z" stroke="none" stroke-width="0" fill="none" fill-opacity="0" transform="matrix(1,0,0,1,0,0)"></path>
<image image-rendering="optimizeQuality" preserveAspectRatio="xMidYMid meet" x="14" y="14" width="1242px" height="66px" xlink:href="https://deviantshare.azurewebsites.net/img/test.png"></image>
<text style="font:32px arial;" x="0" y="30" stroke="none" transform="matrix(1,0,0,1,591,94)" fill="#2b5987">3. Kat</text>
</g>
</g>
</g>
</g>
</svg>
RESULT :
As it clearly looks like an issue with Firefox and IE rendering, thought of trying a workaround to come over this.
Instead of using <image> element of SVG, tried using <img> tag of HTML and embedded it using <foreignObject> element of SVG.
Instead of :
<image image-rendering="optimizeQuality" preserveAspectRatio="xMidYMid meet"
x="14" y="14" width="1242px" height="66px"
xlink:href="https://deviantshare.azurewebsites.net/img/test.png"></image>
Used:
<foreignObject x="600" y="14" width="100" height="100">
<body>
<img src="https://deviantshare.azurewebsites.net/img/test.png"
type="image/svg+xml" width="66px" height="66px">
</body>
</foreignObject>
But one pending issue is IE doesn't support foreignObject yet!
Codepen.io working example
Is this possible? The following is what I tried but it completely fills the circle with black.
<svg id='vizMenu' width="700" height="660">
<defs>
<filter id="dropshadow" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
<feOffset dx="0.5" dy="0.8" result="offsetblur"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<circle id='top' filter="url(#dropshadow)" cx="180" cy="120" r="80" stroke="#2E2E2E" stroke-width="2" fill="url('images/word-cloud.png')"/>
<circle id='bottom' filter="url(#dropshadow)" cx="500" cy="300" r="80" stroke="#2E2E2E" stroke-width="2" fill="url('images/word-cloud.png')"/>
<circle id='extra' filter="url(#dropshadow)" cx="180" cy="560" r="80" stroke="#2E2E2E" stroke-width="2" fill="#ffffff"/>
</svg>
An image fill for an svg element is achieved through SVG Patterns...
<svg width="700" height="660">
<defs>
<pattern id="image" x="0" y="0" patternUnits="userSpaceOnUse" height="1" width="1">
<image x="0" y="0" xlink:href="url.png"></image>
</pattern>
</defs>
<circle id='top' cx="180" cy="120" r="80" fill="url(#image)"/>
</svg>
Well, I couldn't make it work with the accepted answer. This is how I ended up doing it:
<svg width="100" height="100">
<defs>
<pattern id="image" patternUnits="userSpaceOnUse" height="100" width="100">
<image x="0" y="0" height="100" width="100" xlink:href="http://i.imgur.com/7Nlcay7.jpg"></image>
</pattern>
</defs>
<circle id='top' cx="50" cy="50" r="50" fill="url(#image)"/>
</svg>
If you want to customize the size, use this as a scale reference:
x = yourPreferredSize
<svg width=">2x" height=">2x">
<defs>
<pattern id="image" patternUnits="userSpaceOnUse" height=">2x" width=">2x">
<image x="0" y="0" height="2x" width="2x" xlink:href="http://i.imgur.com/7Nlcay7.jpg"></image>
</pattern>
</defs>
<circle id='top' cx="x" cy="x" r="x" fill="url(#image)"/>
</svg>
(This scale works for squared images)
Image repetition problem solved with proper explanation (Thanks to AmeliaBR)
TL;DR: The concept of objectBoundingBox and preserveAspectRatio are used!
<svg height = "10%" width = "10%">
<defs>
<pattern id = "attachedImage" height = "100%" width = "100%"
patternContentUnits = "objectBoundingBox">
<image xlink:href = "url.png" preserveAspectRatio = "none"
width = "1" height = "1"/>
</pattern>
</defs>
<circle cx = "50%" cy = "50%" r = "35%" fill = "url(#attachedImage)"/>
</svg>
I know this is an old question, but I used a filter to overlay the image. The above solution didn't work for me because of scaling and it seemed like the images was tiled. I used this instead, I hope it will help others as well.
<svg width="700" height="660">
<filter id="this_image" x="0%" y="0%" width="100%" height="100%">
<feImage xlink:href="test_image.png"/>
</filter>
<circle filter="url(#this_image)" cx="180" cy="120" r="80" />
</svg>
This is my solution, the differences are that this doesn't use the patternUnits="userSpaceOnUse" and that you specify the desired width and height of the image element.
<defs>
<pattern id="{some name}" x="0" y="0" width="1" height="1">
<image href="{image url}" x="0" y="0" width="{desired width}" height="{desired height}"></image>
</pattern>
</defs>