how to set svg path shadow only on outside? - javascript

Is it possible to get a shadow effect only on the outside border?
image

Directly from the docs: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDropShadow#SVG
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2"/>
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.5"
flood-color="cyan"/>
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0"
flood-color="pink" flood-opacity="0.5"/>
</filter>
</defs>
<circle cx="5" cy="50%" r="4"
style="fill:pink; filter:url(#shadow);"/>
<circle cx="15" cy="50%" r="4"
style="fill:pink; filter:url(#shadow2);"/>
<circle cx="25" cy="50%" r="4"
style="fill:pink; filter:url(#shadow3);"/>
</svg>
Output (middle one should be what you need? Just need to change to a path - I will try to do that now):
With Path:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2"/>
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.5"
flood-color="cyan"/>
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0"
flood-color="pink" flood-opacity="0.5"/>
</filter>
</defs>
<circle cx="5" cy="50%" r="4"
style="fill:pink; filter:url(#shadow);"/>
<path d="M11 1, v8, h8, v-8, z"
style="fill:white; filter:url(#shadow2);"/>
<circle cx="25" cy="50%" r="4"
style="fill:pink; filter:url(#shadow3);"/>
Output:
Now I see some issues, as it's not transparent:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2"/>
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.5"
flood-color="cyan" flood-opacity="0.5"/>
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0"
flood-color="pink" flood-opacity="0.7"/>
</filter>
</defs>
<circle cx="5" cy="50%" r="4"
style="fill:pink; filter:url(#shadow);"/>
<circle cx="25" cy="50%" r="4"
style="fill:pink; filter:url(#shadow3);"/>
<mask id="myMask">
<!-- Everything under a white pixel will be visible -->
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<!-- Everything under a black pixel will be invisible -->
<polygon fill="black" points="0.02,0.02 0.98,0.02 0.98,0.98 0.02,0.98 0.02,0.02" />
<!--
<path d="M14 1, v8, h8, v-8, z" fill="black" />
-->
</mask>
<rect x="16" y="1" width="8" height="8"
mask="url(#myMask)"
fill="white"
stroke="black"
stroke-width="0.2"
style="filter:url(#shadow2);"/>
<!--
<path d="M14 1, v8, h8, v-8, z"
style="fill:white; stroke:black; stroke-width: 0.2;
mask=url(#myMask);
filter:url(#shadow2);"/>
-->
<!--
<path d="M14 1, v8, h8, v-8, z"
style="fill:none; stroke:black; stroke-width: 0.2;
clip-path: polygon(0% 0%, 0% 100%, 1% 100%, 1% 1%, 99% 1%, 99% 99%, 1% 99%, 1% 100%, 100% 100%, 100% 0%);
filter:url(#shadow2);"/>
<rect x="14" y="1" width="8" height="8"
style="fill:white; stroke:black; stroke-width: 0.2;
clip-path: polygon(0% 0%, 0% 100%, 1% 100%, 1% 1%, 99% 1%, 99% 99%, 1% 99%, 1% 100%, 100% 100%, 100% 0%);
filter:url(#shadow2);"/>
-->
Output (not yet transparent):
Next try:
I can do it with a rect or a path (the circle is behind the rect/path and you see through) but I don't (yet) know how to do it for an arbitrary path:
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="2"
flood-color="cyan" flood-opacity="0.7"/>
</filter>
</defs>
<mask id="myMask" maskContentUnits="objectBoundingBox">
<rect fill="white" x="-10%" y="-10%" width="120%" height="120%" />
<polygon fill="black" points="0.02,0.02 0.98,0.02 0.98,0.98 0.02,0.98 0.02,0.02" />
</mask>
<!--
Punch a hole in a shape of a square inside the white rect,
revealing the yellow circle underneath
-->
<circle cx="50" cy="50" r="20" fill="yellow" />
<!--
<rect x="25" y="25" height="50" width="50" fill="white"
stroke="black"
stroke-width="2"
mask="url(#myMask)"
style="filter:url(#shadow2);"
/>
-->
<path d="M25,25 v50, h50, v-50, z" fill="white"
stroke="black"
stroke-width="2"
mask="url(#myMask)"
style="filter:url(#shadow2);"
/>
</svg>
Output:
Another example:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="shadow">
<feDropShadow dx="0.2" dy="0.4" stdDeviation="0.2" />
</filter>
<filter id="shadow2">
<feDropShadow dx="0" dy="0" stdDeviation="0.8" flood-color="cyan" flood-opacity="0.7" />
</filter>
<filter id="shadow3">
<feDropShadow dx="-0.8" dy="-0.8" stdDeviation="0" flood-color="pink" flood-opacity="0.7" />
</filter>
</defs>
<mask id="myMask" maskContentUnits="objectBoundingBox">
<rect fill="white" x="-10%" y="-10%" width="120%" height="120%" />
<polygon fill="black" points="0.015,0.015 0.985,0.015 0.985,0.985 0.015,0.985 0.015,0.015" />
</mask>
<!--
Punch a hole in a shape of a square inside the white rect,
revealing the yellow circle underneath
-->
<circle cx="5" cy="50%" r="4" style="fill:pink; filter:url(#shadow);" />
<circle cx="25" cy="50%" r="4" style="fill:pink; filter:url(#shadow3);" />
<path d="M14 1, v8, h8, v-8, z" fill="white" stroke="black" stroke-width="0.2" mask="url(#myMask)" style="filter:url(#shadow2);" />
<!-- <rect x="14" y="1" height="8" width="8" fill="white" stroke="black" stroke-width="0.2" mask="url(#myMask)" style="filter:url(#shadow2);" /> -->
<!-- <circle cx="50" cy="50" r="20" fill="yellow" /> -->
<!-- <rect x="25" y="25" height="50" width="50" fill="white" stroke="black" stroke-width="2" mask="url(#myMask)" style="filter:url(#shadow2);" /> -->
</svg>
Output:

Related

How to transform an svg animation to work on scroll?

I created 4 animations which 2 are squares which moves following the path. And 2 are lines undrawing.
I was wondering if I could transform these animations to be on scroll instead of time duration like bellow ?
I try to find but I don't think that these 4 animations could be on scroll.
Any idea in comment would be helpfull.
// Example class component
class Svg extends React.Component {
render() {
return (
<div>
<svg viewBox="0 0 1200 700" width="100%" height="700" xmlSpace="preserve">
<defs>
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="shadow-filter">
<feOffset dx="0" dy="20" in="SourceAlpha" result="shadowOffsetOuter1" />
<feGaussianBlur stdDeviation="10" in="shadowOffsetOuter1" result="shadowBlurOuter1" />
<feColorMatrix values="0.1 0 0 0 0 0 0.2 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1" />
<feMerge>
<feMergeNode in="shadowMatrixOuter1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g>
<path
d="M544.9,635c-1.2-172.5-2.3-345-3.5-517.5c-0.3-7.8-2.6-21.2-14.1-32.6c-11.7-11.5-28.5-20-57.5-20
c-18.9,0-78.4,0-97.3,0c-64.3,0-138,0-202.4,0h-4.1"
id="Clasque_3"
stroke="rgba(196, 196, 194, .2)" strokeWidth="3" strokeMiterlimit="10" fill="none" strokeDasharray="920.2" strokeDashoffset="0"
> <animate
attributeName="stroke-dashoffset"
values="0;920.2;"
dur="4s"
fill="freeze"
begin="1s"
/>
</path>
<rect x="-35" y="-35" rx="15" ry="15" width="70" height="70" strokeWidth="1" stroke="rgba(196, 196, 194, .1)" fill="#F8F7F5" filter="url(#shadow-filter)" >
<animateMotion
dur="4s"
fill="freeze"
keyPoints="1;0"
keyTimes="0;1"
calcMode="linear"
begin="1s">
<mpath xlinkHref="#Clasque_3"></mpath>
</animateMotion>
</rect>
</g>
<g>
<path
d="M655.4,635c1.2-172.5,2.3-345,3.5-517.5c0.3-7.8,2.6-21.2,14.1-32.6c11.7-11.5,28.5-20,57.5-20
c18.9,0,78.4,0,97.3,0c64.3,0,138,0,202.4,0h4.1"
id="Clasque_6"
stroke="rgba(196, 196, 194, .2)" strokeWidth="3" strokeMiterlimit="10" fill="none" strokeDasharray="920.2" strokeDashoffset="0"
> <animate
attributeName="stroke-dashoffset"
values="0;920.2;"
dur="4s"
fill="freeze"
begin="1s"
/>
</path>
<rect x="-35" y="-35" rx="15" ry="15" width="70" height="70" strokeWidth="1" stroke="rgba(196, 196, 194, .1)" fill="#F8F7F5" filter="url(#shadow-filter)" >
<animateMotion
dur="4s"
fill="freeze"
keyPoints="1;0"
keyTimes="0;1"
calcMode="linear"
begin="1s">
<mpath xlinkHref="#Clasque_6"></mpath>
</animateMotion>
</rect>
</g>
</svg>
</div>
);
}
}
ReactDOM.render(
<Svg />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Register a scroll event listener, assign a value state to your component and assign the corresponding value to your svg
class Svg extends React.Component {
constructor(props) {
super(props);
this.state = {
end: 1
}
this.scroll = this.scroll.bind(this)
window.addEventListener('scroll', this.scroll, true);
}
scroll(event) {
this.setState({
end: window.scrollY > 100? 0 : (1 - window.scrollY / 100)
});
}
componentWillUnmount() {
window.removeEventListener('scroll', this.scroll, true);
}
render() {
return (
<div style={{height: '200vh'}}>
<svg viewBox="0 0 1200 700" width="100%" height="700" xmlSpace="preserve">
<defs>
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="shadow-filter">
<feOffset dx="0" dy="20" in="SourceAlpha" result="shadowOffsetOuter1" />
<feGaussianBlur stdDeviation="10" in="shadowOffsetOuter1" result="shadowBlurOuter1" />
<feColorMatrix values="0.1 0 0 0 0 0 0.2 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1" />
<feMerge>
<feMergeNode in="shadowMatrixOuter1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g>
<path
d="M544.9,635c-1.2-172.5-2.3-345-3.5-517.5c-0.3-7.8-2.6-21.2-14.1-32.6c-11.7-11.5-28.5-20-57.5-20
c-18.9,0-78.4,0-97.3,0c-64.3,0-138,0-202.4,0h-4.1"
id="Clasque_3"
stroke="rgba(196, 196, 194, .2)" strokeWidth="3" strokeMiterlimit="10" fill="none" strokeDasharray="920.2" strokeDashoffset="0"
> <animate
attributeName="stroke-dashoffset"
values={`${(1 - this.state.end) * 920};${(1 - this.state.end) * 920} ;`}
dur="4s"
repeatCount="indefinite"
/>
</path>
<rect className="rect1" x="-35" y="-35" rx="15" ry="15" width="70" height="70" strokeWidth="1" stroke="rgba(196, 196, 194, .1)" fill="#F8F7F5" filter="url(#shadow-filter)" >
<animateMotion
dur="1s"
keyPoints={`${this.state.end};${this.state.end}`}
keyTimes="0;1"
calcMode="linear"
repeatCount="indefinite"
>
<mpath xlinkHref="#Clasque_3"></mpath>
</animateMotion>
</rect>
</g>
<g>
<path
d="M655.4,635c1.2-172.5,2.3-345,3.5-517.5c0.3-7.8,2.6-21.2,14.1-32.6c11.7-11.5,28.5-20,57.5-20
c18.9,0,78.4,0,97.3,0c64.3,0,138,0,202.4,0h4.1"
id="Clasque_6"
stroke="rgba(196, 196, 194, .2)" strokeWidth="3" strokeMiterlimit="10" fill="none" strokeDasharray="920.2" strokeDashoffset="0"
><animate
attributeName="stroke-dashoffset"
values={`${(1 - this.state.end) * 920};${(1 - this.state.end) * 920} ;`}
dur="4s"
repeatCount="indefinite"
/>
</path>
<rect x="-35" y="-35" rx="15" ry="15" width="70" height="70" strokeWidth="1" stroke="rgba(196, 196, 194, .1)" fill="#F8F7F5" filter="url(#shadow-filter)" >
<animateMotion
dur="1s"
keyPoints={`${this.state.end};${this.state.end}`}
keyTimes="0;1"
calcMode="linear"
repeatCount="indefinite"
>
<mpath xlinkHref="#Clasque_6"></mpath>
</animateMotion>
</rect>
</g>
</svg>
</div>
);
}
}

Real group transparency in three.js

Like this question, I want to change opacity of a group. But the accepted answer in that question is not completely correct. Changing opacity of a group is not equal to changing opacity of it's parts. I can show this with this small svg example:
Group opacity (Good):
<svg width="200" viewBox="0 0 50 50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<g>
<rect x="20" y="30" width="10" height="50" fill="brown"/>
<g style="fill: #0b0">
<circle cx="20" cy="30" r="10"/>
<circle cx="30" cy="30" r="10"/>
<circle cx="25" cy="20" r="10"/>
</g>
</g>
</g>
</svg>
Individual opacity (Bad):
<svg width="200" viewBox="0 0 50 50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g>
<g>
<rect x="20" y="30" width="10" height="50" fill="brown" opacity="0.5"/>
<g style="fill: #0b0">
<circle cx="20" cy="30" r="10" opacity="0.5"/>
<circle cx="30" cy="30" r="10" opacity="0.5"/>
<circle cx="25" cy="20" r="10" opacity="0.5"/>
</g>
</g>
</g>
</svg>
How to do something like this in three.js?

Drop shadow hidden outside element svg

Perhaps someone faced this problem. How can this be corrected without making an internal relative bias? I would like to achieve the effect so that the shadow is on all sides smoothly leaving under the item.
I can only describe on the CSS what I mean (on SVG I don't know how yet):
box-shadow: 0 3px 16px 5px rgba(0,0,0,.3);
Problem:
<svg height="0">
<filter id="drop-shadow-path-line" x="0" y="0" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="-20" dy="20" /><feGaussianBlur result="blurOut" in="offOut" stdDeviation="3" /><feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</svg>
<svg height="200" width="200">
<g transform="translate(25 25)">
<rect x="0" y="0" width="100" height="100" fill="orange" filter="url(#drop-shadow-path-line)" />
<g>
<svg>
Need:
#exmaple-svg{
position:relative;
top:25px;
left:25px;
}
.item{
position: absolute;
left: 20px;
top: 20px;
width:100px;
height:100px;
background-color: rgba(255,0,0,.5);
filter:drop-shadow(0 4px 15px #000);
}
<div id="exmaple-svg">
<div class="item"><div>
</div>
PS:Thank You for any help and Your time.
I have seen many solutions and I will write in advance, the shadow need not apply to all items, if You have the same situation and You need to apply a drop shadow to all child elements that it features are done via CSS by adding:filter:drop-shadow(0 3px 15px #000)on the root SVG element
Updated: for #enxaneta (bug with <path />) - shadow is clipped depending on the location of the reference point p2y (Bezier curve). Still looking for a solution... so that it is not circumcised.
<svg viewBox="100 50 250 250">
<path d="M136.8595428466797 123.9515609741211 C 181.78643913269042 123.9515609741211 158.49101142883302 131.44540405273438 203.41790771484375 131.44540405273438" data-id-device-from="Light-X[room-1550230117502][1]" data-name-device-from="Light-X" data-name-chanel-from="as" data-number-chanel-from="8" data-type-list-name-from="input" stroke-width="2" stroke="#000" fill="none" stroke-linecap="round" stroke-linejoin="round" data-type-event-from="analog" data-id-device-to="Light-X[room-1550230117502][0]" data-name-device-to="Light-X" data-name-chanel-to="aos" data-number-chanel-to="0" data-type-list-name-to="output" data-type-event-to="analog" data-color="#b22222" style="stroke: rgb(178, 34, 34);" class="active" filter="url(#drop-shadow-path-line)"></path>
<path d="M136.8595428466797 123.9515609741211 C 179.60736618041992 123.9515609741211 157.44182815551758 124.271484375 200.1896514892578 124.271484375" data-id-device-from="Light-X[room-1550230117502][1]" data-name-device-from="Light-X" data-name-chanel-from="as" data-number-chanel-from="8" data-type-list-name-from="input" stroke-width="2" stroke="#000" fill="none" stroke-linecap="round" stroke-linejoin="round" data-type-event-from="analog" data-id-device-to="Light-X[room-1550230117502][0]" data-name-device-to="Light-X" data-name-chanel-to="aos" data-number-chanel-to="0" data-type-list-name-to="output" data-type-event-to="analog" data-color="#b22222" style="stroke: rgb(178, 34, 34);" class="active" filter="url(#drop-shadow-path-line)"></path>
<path d="M136.8595428466797 123.9515609741211 C 176.21768913269042 123.9515609741211 155.809761428833 53.60844039916992 195.16790771484375 53.60844039916992" data-id-device-from="Light-X[room-1550230117502][1]" data-name-device-from="Light-X" data-name-chanel-from="as" data-number-chanel-from="8" data-type-list-name-from="input" stroke-width="2" stroke="#000" fill="none" stroke-linecap="round" stroke-linejoin="round" data-type-event-from="analog" data-id-device-to="Light-X[room-1550230117502][0]" data-name-device-to="Light-X" data-name-chanel-to="aos" data-number-chanel-to="0" data-type-list-name-to="output" data-type-event-to="analog" data-color="#b22222" style="stroke: rgb(178, 34, 34);" class="active" filter="url(#drop-shadow-path-line)"></path>
<path d="M136.8595428466797 123.9515609741211 C 181.30219955444335 123.9515609741211 158.25785903930665 119.24974060058594 202.7005157470703 119.24974060058594" data-id-device-from="Light-X[room-1550230117502][1]" data-name-device-from="Light-X" data-name-chanel-from="as" data-number-chanel-from="8" data-type-list-name-from="input" stroke-width="2" stroke="#000" fill="none" stroke-linecap="round" stroke-linejoin="round" data-type-event-from="analog" data-id-device-to="Light-X[room-1550230117502][0]" data-name-device-to="Light-X" data-name-chanel-to="aos" data-number-chanel-to="0" data-type-list-name-to="output" data-type-event-to="analog" data-color="#b22222" style="stroke: rgb(178, 34, 34);" class="active" filter="url(#drop-shadow-path-line)"></path>
<path d="M136.8595428466797 123.9515609741211 C 181.30219955444335 123.9515609741211 158.25785903930665 102.39105224609375 202.7005157470703 102.39105224609375" data-id-device-from="Light-X[room-1550230117502][1]" data-name-device-from="Light-X" data-name-chanel-from="as" data-number-chanel-from="8" data-type-list-name-from="input" stroke-width="2" stroke="#000" fill="none" stroke-linecap="round" stroke-linejoin="round" data-type-event-from="analog" data-id-device-to="Light-X[room-1550230117502][0]" data-name-device-to="Light-X" data-name-chanel-to="aos" data-number-chanel-to="0" data-type-list-name-to="output" data-type-event-to="analog" data-color="#b22222" style="stroke: rgb(178, 34, 34);" class="active" filter="url(#drop-shadow-path-line)"></path>
<path d="M133.2725830078125 154.7993927001953 C 181.83128128051757 154.7993927001953 156.6526969909668 170.1845245361328 205.21139526367188 170.1845245361328" data-id-device-from="Light-X[room-1550230117502][1]" data-name-device-from="Light-X" data-name-chanel-from="as" data-number-chanel-from="8" data-type-list-name-from="input" stroke-width="2" stroke="#000" fill="none" stroke-linecap="round" stroke-linejoin="round" data-type-event-from="analog" data-id-device-to="Light-X[room-1550230117502][0]" data-name-device-to="Light-X" data-name-chanel-to="aos" data-number-chanel-to="0" data-type-list-name-to="output" data-type-event-to="analog" data-color="#b22222" style="stroke: rgb(178, 34, 34);" class="active" filter="url(#drop-shadow-path-line)"></path>
<filter id="drop-shadow-path-line" width="200%" height="200%">
<feGaussianBlur result="blurOut" in="SourceAlpha" stdDeviation="3" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</svg>
Redefine the size of your filter and remove the offset (feOffset)
The default value for the x attribute for <filter> is -10%. By setting it 0 you cut off part of the image. Not using the x and y attributes is often a good idea.
<svg height="0">
<filter id="drop-shadow-path-line" width="200%" height="200%">
<feGaussianBlur result="blurOut" in="SourceAlpha" stdDeviation="3" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</svg>
<svg height="200" width="200">
<g transform="translate(25 25)">
<rect x="0" y="0" width="100" height="100" fill="orange" filter="url(#drop-shadow-path-line)" />
<g>
<svg>
I hope this is what you need.
UPDATE
The OP updated their question by adding a new path.
For clarity I've simplified the svg. The solution in this case implies putting all paths in a <g> element and aplying the filter to the group. Also I'm using filterUnits ="userSpaceOnUse" for the filter.
svg {
border: 1px solid;
}
path {
stroke-width: 2;
stroke: rgb(178, 34, 34);
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
g{
filter:url(#drop-shadow-path-line);
}
<svg viewBox="100 50 250 250">
<defs>
<filter id="drop-shadow-path-line" filterUnits ="userSpaceOnUse" >
<feGaussianBlur result="blurOut" in="SourceAlpha" stdDeviation="3" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<g>
<path d="M136.8595428466797 123.9515609741211 C 181.78643913269042 123.9515609741211 158.49101142883302 131.44540405273438 203.41790771484375 131.44540405273438" sclass="active" ></path>
<path d="M136.8595428466797 123.9515609741211 C 179.60736618041992 123.9515609741211 157.44182815551758 124.271484375 200.1896514892578 124.271484375" class="active" ></path>
<path d="M136.8595428466797 123.9515609741211 C 176.21768913269042 123.9515609741211 155.809761428833 53.60844039916992 195.16790771484375 53.60844039916992" class="active" ></path>
<path d="M136.8595428466797 123.9515609741211 C 181.30219955444335 123.9515609741211 158.25785903930665 119.24974060058594 202.7005157470703 119.24974060058594" class="active" ></path>
<path d="M136.8595428466797 123.9515609741211 C 181.30219955444335 123.9515609741211 158.25785903930665 102.39105224609375 202.7005157470703 102.39105224609375" class="active" ></path>
<path d="M133.2725830078125 154.7993927001953 C 181.83128128051757 154.7993927001953 156.6526969909668 170.1845245361328 205.21139526367188 170.1845245361328" class="active" ></path>
</g>
</svg>
I couldn't quite get there and was unable to get the 5px spread specified.
Posting here because it may still be useful.
div { /* just so we can see what the css version would look like */
background:orange;
width:100px;
height:100px;
box-shadow: 0 4px 15px 5px rgba(0,0,0,.3);
}
<svg height="0">
<filter id="dropShadow">
<feGaussianBlur in="SourceAlpha" stdDeviation="15" />
<feOffset dx="0" dy="3" />
<feComponentTransfer>
<feFuncA type="linear" slope="0.4"/>
</feComponentTransfer>
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</svg>
<svg height="200" width="200" filter="url(#dropShadow)">
<g transform="translate(50 50)" >
<rect x="0" y="0" width="100" height="100" fill="orange" />
<g>
<svg>
<div></div>
P.S. You could use this Codepen by Michael Mullany to construct SVG drop shadows.

SVG Animation works in Chrome, but doesn't in Firefox and other browsers

Okay, so I have an SVG that is basically a clock animation. It works as intended in Chrome when I'm testing it, but loses form when I try it in Firefox or Safari.
This is the SVG in question:
<svg id="svg" width="100%" viewBox="-400 -150 800 300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1">
<defs>
<path id="sec" d="M0,-140A140,140 0 0,1 0,140A140,140 0 0,1 0,-140" stroke-dasharray="880" stroke-dashoffset="-880.1"
fill="none">
<animate id="second" attributeName="stroke-dashoffset" dur="1s" repeatCount="60" begin="0s;second.end" additive="sum"
accumulate="sum" calcMode="spline" values="0;-14.66" keyTimes="0;1" keySplines="0.42 0.0 0.58 1.0" />
</path>
<path id="min" d="M0,-130A130,130 0 0,1 0,130A130,130 0 0,1 0,-130" stroke-dasharray="817" stroke-dashoffset="-817.1"
fill="none">
<animate id="minute" attributeName="stroke-dashoffset" dur="60s" repeatCount="60" begin="0s;minute.end" additive="sum"
accumulate="sum" calcMode="spline" values="0;0;-13.613" keyTimes="0;0.9833;1" keySplines="0,0,1,1;0.42 0.0 0.58 1.0" />
</path>
<path id="hr" d="M0,-120A120,120 0 0,1 0,120A120,120 0 0,1 0,-120" stroke-dasharray="754" stroke-dashoffset="-754.1"
fill="none">
<animate id="hour" attributeName="stroke-dashoffset" dur="3600s" repeatCount="12" begin="0s;hour.end" additive="sum"
accumulate="sum" calcMode="spline" values="0;0;-62.83" keyTimes="0;0.9997222;1" keySplines="0,0,1,1;0.42 0.0 0.58 1.0" />
</path>
<mask id="mask" maskUnits="userSpaceOnUse" x="-150" y="-150" width="300" height="300">
<g stroke-width="10" stroke-linecap="round" stroke="white">
<use xlink:href="#sec" x="0" y="0" />
<use xlink:href="#min" x="0" y="0" />
<use xlink:href="#hr" x="0" y="0" />
</g>
</mask>
</defs>
<g stroke-width="7" stroke-linecap="round" mask="url(#mask)">
<g stroke="hsla(0, 95%, 25%, 1)">
<use xlink:href="#sec" />
</g>
<g stroke="hsla(188, 15%, 35%, 1)">
<use xlink:href="#min" />
</g>
<g stroke="hsla(218, 5%, 15%, 1)">
<use xlink:href="#hr" />
</g>
</g>
</svg>
<script>
window.onload = function () {
var now = new Date();
var h = now.getHours(), m = now.getMinutes(), s = now.getSeconds();
var curr = h * 60 * 60 + m * 60 + s;
svg.setCurrentTime(curr);
};
</script>
The second hand moves to the next position all the way from the top instead of animating from the previous place. You can test this yourself. This is the link to the code hosted on codepen.

Calculate SVG.Text Length before drawing [duplicate]

I want to color the background of svg text similar to background-color in css
I was only able to find documentation on fill, which colors the text itself
Is it even possible?
You could use a filter to generate the background.
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" result="bg" />
<feMerge>
<feMergeNode in="bg"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">solid background</text>
</svg>
No this is not possible, SVG elements do not have background-... presentation attributes.
To simulate this effect you could draw a rectangle behind the text attribute with fill="green" or something similar (filters). Using JavaScript you could do the following:
var ctx = document.getElementById("the-svg"),
textElm = ctx.getElementById("the-text"),
SVGRect = textElm.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", SVGRect.x);
rect.setAttribute("y", SVGRect.y);
rect.setAttribute("width", SVGRect.width);
rect.setAttribute("height", SVGRect.height);
rect.setAttribute("fill", "yellow");
ctx.insertBefore(rect, textElm);
The solution I have used is:
<svg>
<line x1="100" y1="100" x2="500" y2="100" style="stroke:black; stroke-width: 2"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.6em">Hello World!</text>
<text x="150" y="105" style="fill:black">Hello World!</text>
</svg>
A duplicate text item is being placed, with stroke and stroke-width attributes. The stroke should match the background colour, and the stroke-width should be just big enough to create a "splodge" on which to write the actual text.
A bit of a hack and there are potential issues, but works for me!
Instead of using a <text> tag, the <foreignObject> tag can be used, which allows for XHTML content with CSS.
No, you can not add background color to SVG elements. You can do it programmatically with d3.
var text = d3.select("text");
var bbox = text.node().getBBox();
var padding = 2;
var rect = self.svg.insert("rect", "text")
.attr("x", bbox.x - padding)
.attr("y", bbox.y - padding)
.attr("width", bbox.width + (padding*2))
.attr("height", bbox.height + (padding*2))
.style("fill", "red");
Answer by Robert Longson (#RobertLongson) with modifications:
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow"/>
<feComposite in="SourceGraphic" operator="xor"/>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50"> solid background </text>
<text x="20" y="50" font-size="50">solid background</text>
</svg>
and we have no bluring and no heavy "getBBox" :)
Padding is provided by white spaces in text-element with filter.
It's worked for me
Going further with #dbarton_uk answer, to avoid duplicating text you can use paint-order=stroke style:
<svg>
<line x1="100" y1="100" x2="350" y2="100" style="stroke:grey; stroke-width: 100"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.5em; fill:black; paint-order:stroke; stroke-linejoin:round">Hello World!</text>
</svg>
Note the stroke-linejoin:round which is needed to avoid seeing spikes for the W sharp angle.
You can combine filter with the text.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>SVG colored patterns via mask</title>
</head>
<body>
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter x="0" y="0" width="1" height="1" id="bg-text">
<feFlood flood-color="white"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<!-- something has already existed -->
<rect fill="red" x="150" y="20" width="100" height="50" />
<circle cx="50" cy="50" r="50" fill="blue"/>
<!-- Text render here -->
<text filter="url(#bg-text)" fill="black" x="20" y="50" font-size="30">text with color</text>
<text fill="black" x="20" y="50" font-size="30">text with color</text>
</svg>
</body>
</html>
For those wondering how to apply padding to a text element when it has a background like in the Robert's answer, do the following:
<svg>
<defs>
<filter x="-0.1" y="-0.1" width="1.2" height="1.2" id="solid">
<feFlood flood-color="#171717"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">Hello</text>
</svg>
In the example above, filter's x and y positions can be used as transform: translate(-10%, -10%) would, and width and height values can be read as 120% and 120%. So we made background 20% bigger, and offsetted it -10%, so background is now 10% bigger on each side of the text.
this is my favorite hack (not sure it should work). It refer an element that is not yet displayed, and it works pretty well
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 620 40" preserveAspectRatio="xMidYMid meet">
<defs>
<filter x="-0.02" y="0" width="1.04" height="1.1" id="removebackground">
<feFlood flood-color="#00ffff"/>
</filter>
</defs>
<!--Draw the text-->
<use xlink:href="#mygroup" filter="url(#removebackground)" />
<g id="mygroup">
<text id="text1" x="9" y="20" style="text-anchor:start;font-size:14px;">custom text with background</text>
<line x1="200" y1="18" x2="200" y2="36" stroke="#000" stroke-width="5"/>
<line x1="120" y1="27" x2="203" y2="27" stroke="#000" stroke-width="5"/>
</g>
</svg>
The previous answers relied on doubling up text and lacked sufficient whitespace.
By using atop and I was able to get the results I wanted.
This example also includes arrows, a common use case for SVG text labels:
<svg viewBox="-105 -40 210 234">
<title>Size Guide</title>
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="white"></feFlood>
<feComposite in="SourceGraphic" operator="atop"></feComposite>
</filter>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z"></path>
</marker>
</defs>
<g id="garment">
<path id="right-body" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 0 l30 0 l0 154 l-30 0"></path>
<path id="right-sleeve" d="M30 0 l35 0 l0 120 l-35 0" fill="none" stroke-linejoin="round" stroke="black" stroke-width="1"></path>
<use id="left-body" href="#right-body" transform="scale(-1,1)"></use>
<use id="left-sleeve" href="#right-sleeve" transform="scale(-1,1)"></use>
<path id="collar-right-top" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 -6.5 l11.75 0 l6.5 6.5"></path>
<use id="collar-left-top" href="#collar-right-top" transform="scale(-1,1)"></use>
<path id="collar-left" fill="white" stroke="black" stroke-width="1" stroke-linejoin="round" d="M-11.75 -6.5 l-6.5 6.5 l30 77 l6.5 -6.5 Z"></path>
<path id="front-right" fill="white" stroke="black" stroke-width="1" d="M18.25 0 L30 0 l0 154 l-41.75 0 l0 -77 Z"></path>
<line x1="0" y1="0" x2="0" y2="154" stroke="black" stroke-width="1" stroke-dasharray="1 3"></line>
<use id="collar-right" href="#collar-left" transform="scale(-1,1)"></use>
</g>
<g id="dimension-labels">
<g id="dimension-sleeve-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="85" y1="0" x2="85" y2="120" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="85" y="60" class="dimension" text-anchor="middle" dominant-baseline="middle"> 120 cm</text>
</g>
<g id="dimension-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-85" y1="0" x2="-85" y2="154" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="-85" y="77" text-anchor="middle" dominant-baseline="middle" class="dimension"> 154 cm</text>
</g>
<g id="dimension-sleeve-to-sleeve">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-65" y1="-20" x2="65" y2="-20" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="-20" text-anchor="middle" dominant-baseline="middle" class="dimension"> 130 cm </text>
</g>
<g title="Back Width" id="dimension-back-width">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-30" y1="174" x2="30" y2="174" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="174" text-anchor="middle" dominant-baseline="middle" class="dimension"> 60 cm </text>
</g>
</g>
</svg>
An obvious workaround to the problem of the blur produced by the filter effect is to render the <text> two times: once for the background (with transparent characters) and once for the characters (without a background filter).
For me, this was the only way to make the text readable in Safari.
<svg width="100%" height="100%">
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" />
</filter>
<g transform="translate(20, 50)" font-size="50">
<text aria-hidden="true" fill="none" filter="url(#solid)">solid background</text>
<text fill="blue">solid background</text>
</g>
</svg>
The aria-hidden="true" attribute is there to prevent screen readers from speaking the text twice, if the user uses a screen reader.
You can add style to your text:
style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
text-shadow: rgb(255, 255, 255) -2px -2px 0px, rgb(255, 255, 255) -2px 2px 0px,
rgb(255, 255, 255) 2px -2px 0px, rgb(255, 255, 255) 2px 2px 0px;"
White, in this example.
Does not work in IE :)

Categories