svg circle tapered fading stroke - svg

I am trying to create an svg file with a circle that has a tapered stroke that fades, meaning the stroke width will be the thickest (say 20px) with the original color and will be the thinnest (say 3px) on the opposite side where the color has faded. I was able to create the circle with color fading with the gradient tool, but I am struggling to figure out how to change the stroke width
Here's the code I have so far, which I created in Photoshop and exported to svg.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="500" viewBox="0 0 500 500">
<defs>
<style>
.cls-1 {
fill: none;
stroke-width: 20px;
stroke: url(#a);
}
</style>
<linearGradient id="a" x1="255.5" y1="240" x2="255.5" y2="51" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="rgba(96,0,0,1)"/>
<stop offset="1" stop-color="rgba(96,0,0,.1)"/>
</linearGradient>
</defs>
<circle class="cls-1" cx="255.5" cy="255.5" r="184.5"/>
</svg>
Here's an image of what I am trying to do.
Sorry, one more favor. I am trying to create an icon, so it will have four of these circles with different colors, with one fading to the top as shown, another fading to the bottom, and the other two to each of the sides. I will really appreciate it if you can also show me how to rotate :)
Thank you in advance.
Regards,
Mike

I would draw a bigger circle with a hole inside. In this case I'm using a mask. You can also draw a holloed path. In both cases you are using the gradient as a fill not as a stroke
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="500" viewBox="0 0 500 500">
<defs>
<style>
.cls-1 {
fill: url(#a);
}
</style>
<linearGradient id="a" x1="255.5" y1="240" x2="255.5" y2="51" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="rgba(96,0,0,1)"/>
<stop offset="1" stop-color="rgba(96,0,0,.1)"/>
</linearGradient>
<mask id="m">
<circle id="c1" cx="255.5" cy="255.5" r="184.5" fill="white" />
<circle fill="black" cx="255.5" cy="245.5" r="164.5"/>
</mask>
</defs>
<circle cx="255.5" cy="255.5" r="184.5" class="cls-1" mask="url(#m)" />
</svg>
And this is an example where I'm using a holloed path instead of the masked circle. Please note that in this case I'm centering the path atound the point x=0 y=0.
<svg width="500" height="500" viewBox="-250 -250 500 500">
<defs>
<style>
.cls-1 {
fill: url(#a);
}
</style>
<linearGradient id="a" y1="200" y2="-200" x1="0" x2="0" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="rgba(96,0,0,1)"/>
<stop offset="1" stop-color="rgba(96,0,0,.1)"/>
</linearGradient>
</defs>
<path class="cls-1" d="M184.5,0A184.5,184.5 0 0 1 -184.5,0A184.5,184.5 0 0 1 184.5,0M164.5,-10A164.5,164.5 0 0 0 -164.5,-10A164.5,164.5 0 0 0 164.5,-10"/>
</svg>

I am trying to create an icon, so it will have four of these circles
with different colors, with one fading to the top as shown, another
fading to the bottom, and the other two to each of the sides. I will
really appreciate it if you can also show me how to rotate
The first circle rotates clockwise
<animateTransform
attributeName="transform"
type="rotate"
values="0 150 150;360 150 150"
begin="svg1.click"
dur="10s"
repeatCount="indefinite"
/>
The second circle rotates counterclockwise.
Since the top circle is set to the opacity parameter fill-opacity: 0.5;
then the effect of changing the thickness of the stroke is created
Added gradient animation to both circles:
<animate
attributeName="stop-color"
dur="1.5s"
values="red;yellow;red"
repeatCount="indefinite"
/>
The text Click me has been added for demonstration it can be removed.
Below is the complete code:
.container {
width:50%;
height:50%;
}
svg {
background:black;
}
#path1 {
fill:url(#gradl);
stroke:none;
fill-opacity:1;
}
#path2 {
fill:url(#grad2);
stroke:none;
fill-opacity:0.5;
}
#crc1 {
stroke:none;
fill:black;
}
#txt1 {
fill:url(#grad2);
}
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 300 300" >
<defs>
<linearGradient id="gradl" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="red" stop-opacity="0.9">
<animate
attributeName="stop-color"
dur="1.5s"
values="red;yellow;red"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="yellow">
<animate
attributeName="stop-color"
dur="1.5s"
values="yellow;red;yellow" repeatCount="indefinite"
/>
</stop>
</linearGradient>
<linearGradient id="grad2" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="lime">
<animate
attributeName="stop-color"
dur="1.5s"
values="lime;purple;lime"
repeatCount="indefinite"
/>
</stop>
<stop offset="100%" stop-color="purple">
<animate
attributeName="stop-color"
dur="1.5s"
values="purple;lime;purple" repeatCount="indefinite"
/>
</stop>
</linearGradient>
</defs>
<path id="path1" d="M71.9 78.4C90.8 58.1 122.9 50.7 150.6 51.5c26.2 0.7 54.9 10.5 72.8 29.7 16.9 18.1 22.9 45.8 23.4 70.6 0.5 25.1-3.2 54.4-20.7 72.4-18.5 19.1-49.4 24.5-76 24.3-25.4-0.2-54.4-6.3-72.4-24.3C59.5 205.8 53.9 176.5 53 150.8 52.2 125.9 55 96.7 71.9 78.4Z" >
<animateTransform
attributeName="transform"
type="rotate"
values="0 150 150;360 150 150"
begin="svg1.click"
dur="10s"
repeatCount="indefinite"
/>
</path>
<path id="path2" transform="rotate(45 150 150)"
d="M71.9 78.4C90.8 58.1 122.9 50.7 150.6 51.5c26.2 0.7 54.9 10.5 72.8 29.7 16.9 18.1 22.9 45.8 23.4 70.6 0.5 25.1-3.2 54.4-20.7 72.4-18.5 19.1-49.4 24.5-76 24.3-25.4-0.2-54.4-6.3-72.4-24.3C59.5 205.8 53.9 176.5 53 150.8 52.2 125.9 55 96.7 71.9 78.4Z" >
<animateTransform
attributeName="transform"
type="rotate"
values="360 148 148;0 148 148"
begin="svg1.click"
dur="10s"
repeatCount="indefinite" />
</path>
<circle id="crc1" cx="150" cy="150" r="90" />
<text id="txt1" x="80" y="160" font-size="36" font-weight="700" > Click me </text>
</svg>
</div>

Related

Is it possible to convert a raidal gradient expressed in objectBoundingBox coordinates to userSpaceOnUse coordinates?

I have this radial gradient expressed in objectBoundingBox coordinates.
<svg width="300" height="300">
<defs>
<radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="100"/>
</svg>
Is it possible to convert it to userSpaceOnUse coordinates?
For this question it is same to assume that each radial gradient only applies to one shape, and that we know x, y, width, and height of said shape.
<svg width="300" height="300">
<defs>
<radialGradient id="MyGradient" gradientUnits="userSpaceOnUse"
cx="?" cy="?" r="?" fx="?" fy="?">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="100"/>
</svg>
First I would show how to do it if the rect you fill with the gradient is a square:
svg{border:solid; width:45vw}
<svg viewBox="0 0 300 300">
<defs>
<radialGradient id="MyGradient" gradientUnits="objectBoundingBox"
cx="0.3" cy="0.4" r="0.3" fx="0.1" fy="0.2">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="200"/>
</svg>
<svg viewBox="0 0 300 300">
<defs>
<radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse"
cx="110" cy="180" r="60" fx="70" fy="140" >
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="black" />
</radialGradient>
</defs>
<rect fill="url(#MyGradient1)" stroke="black" stroke-width="5"
x="50" y="100" width="200" height="200"/>
</svg>
In the case of `gradientUnits="userSpaceOnUse":
The bounding box of the rect to fill is:
bb:{x:50, y:100, width:200, height:200}
The calculated attributes for gradientUnits="userSpaceOnUse" are:
cx = bb.x + bb.width *.3 = 50 + 200 * .3 = 110
cy = bb.y + bb.height *.4 100 + 200*.4 = 180
r = bb.width*.3 = 200*.3 = 60
fx = bb.x + bb.width *.1 = 50 + 200 * .1 = 70
fy = bb.y + bb.height *.2 = 100 + 200 * .2 = 140
So you can use
<radialGradient id="MyGradient1" gradientUnits="userSpaceOnUse" cx="110" cy="180" r="60" fx="70" fy="140" >
When using objectBoundingBox the values of the attributes of the radialGradient are taking values between 0 and 1 or 0 and 100% of the filled box.
You can also use objectBoundingBox as a value for clipPathUnits. Please take a look at the folowing example.
There is this clipPath where the clipping path is a circle. If the clipped shape is a square the result is a circle. If the clipped shape is a rectangle the result is an ellipse meaning that the clipping path is stretched according to the aspect ratio of the clipped shape.
<svg viewBox="0 0 120 60">
<defs>
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<circle cx=".5" cy=".5" r=".45" />
</clipPath>
</defs>
<rect id="r" x="5" y="5" width="50" height="50" />
<use xlink:href="#r" fill="gold" clip-path="url(#clip)" />
<rect id="r1" x="60" y="15" width="55" height="30" />
<use xlink:href="#r1" fill="gold" clip-path="url(#clip)" />
</svg>
The same is happening with the gradient. If the radial gradient with gradientUnits="objectBoundingBox" is used to fill a rectangle with a different width and height the result would be an elliptical gradient (as in your example). If you want to translate an elliptical gradient to gradientUnits="userSpaceOnUse" you would need a way to create a gradient with a different rx and ry. Unfortunately this is not posible.

How to reverse animate linearGradient on mouseout with inline SVG only

I want to create a smooth reverse animation on the svg linearGradient on mouseout. Is this possible with inline code only (without js or css)?
I have tried the following code but after the first mouseover animation finished it reverts back to frame 1 which ruins the smooth mouseout effect.
On mouseout I want to reverse the linearGradient smoothly.
https://codepen.io/daneli84/pen/WNejrdd
<svg viewBox="0 0 360 160" width="360" height="160" id="ani">
<defs>
<linearGradient id="lightGradient">
<stop offset="0%" stop-color="red">
<animate attributeName="stop-color" values="red; gold" dur=".5s"
fill="freeze" begin="ani.mouseover" />
</stop>
<stop offset="90%" stop-color="gold">
</stop>
</linearGradient>
</defs>
<circle cx="80" cy="80" r="50" fill="url(#lightGradient)"/>
</svg>
Expected results with using mouseout and a reverse linearGradient for a smooth reverse animation.
How about this. We animate one way on mouseenter and the reverse on mouseleave.
<svg viewBox="0 0 360 160" width="360" height="160" id="ani">
<defs>
<linearGradient id="lightGradient">
<stop offset="0%" stop-color="red">
<animate attributeName="stop-color" values="red; gold" dur=".5s"
fill="freeze" restart = "whenNotActive" begin="ani.mouseenter" />
<animate attributeName="stop-color" values="gold; red" dur=".5s"
fill="freeze" restart = "whenNotActive" begin="ani.mouseleave" />
</stop>
<stop offset="90%" stop-color="gold">
</stop>
</linearGradient>
</defs>
<circle cx="80" cy="80" r="50" fill="url(#lightGradient)"/>
</svg>

Fill SVG from bottom to top

I've got an SVG I'm trying to animate from bottom to top with a fill. I want it to start as color code #ddd and I want it to end as #ccc filling in from the bottom over a 1 second duration. I'm having problems getting this to work correctly as it seems to look a bit strange.
This is what I've got so far.
<svg width="30px" height="30px" viewBox="0 0 30 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Dashboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-color="#ddd"/>
<stop offset="50%" stop-color="#ccc">
<animate attributeName="offset" values="0;1;0" dur="1s" begin="0s"/>
</stop>
<stop offset="100%" stop-opacity="1" stop-color="#ccc">
<animate attributeName="offset" values="0;1;0" dur="1s" begin="0s"/>
</stop>
</linearGradient>
<g transform="translate(-1161.000000, -558.000000)" fill="url(#lg)" id="current-net-wealth">
<g transform="translate(437.000000, 475.000000)">
<g id="houses" transform="translate(340.000000, 83.000000)">
<g id="house" transform="translate(384.000000, 0.000000)">
<polygon id="Path" points="21 6.66002593 21 3 25 3 25 11.1000432 30 16.6500648 25.3846154 16.6500648 25.3846154 30 4.61538462 30 4.62306431 16.6500648 0 16.6500648 15 0"></polygon>
</g>
</g>
</g>
</g>
</g>
</svg>
Do I need to add an additional stop to the linearGradiant animation?
Something like this.
If you want a duration of 1 second then that's what to write
Your values make the fill go up and down again
fill="freeze" makes the animated value remain after its duration is complete
Your colours don't match the ones you say you want
<svg width="30px" height="30px" viewBox="0 0 30 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="Dashboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-color="#ccc"/>
<stop offset="0%" stop-color="#ccc">
<animate attributeName="offset" to="100%" dur="1s" begin="0s" fill="freeze"/>
</stop>
<stop offset="0%" stop-color="#ddd">
<animate attributeName="offset" to="100%" dur="1s" begin="0s" fill="freeze"/> </stop>
</linearGradient>
<g transform="translate(-1161.000000, -558.000000)" fill="url(#lg)" id="current-net-wealth">
<g transform="translate(437.000000, 475.000000)">
<g id="houses" transform="translate(340.000000, 83.000000)">
<g id="house" transform="translate(384.000000, 0.000000)">
<polygon id="Path" points="21 6.66002593 21 3 25 3 25 11.1000432 30 16.6500648 25.3846154 16.6500648 25.3846154 30 4.61538462 30 4.62306431 16.6500648 0 16.6500648 15 0"></polygon>
</g>
</g>
</g>
</g>
</g>
</svg>

SVG styling <use> (fill x% of the content with linearGradient)

I have an icon that I want to use many times on my page.
I want the icon to be filled dynamically (how much of it will be filled) from server data.
what I got so far is this:
<svg version="1.1" id="myWarningId" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 27.8 24" style="enable-background:new 0 0 27.8 24;" xml:space="preserve">
<defs>
<symbol viewBox="0 0 27.8 24" y="0px" x="0px" id="warning" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
#myWarningId .st1{fill:#FFFFFF;}
#myWarningId polygon{fill: inherit;}
</style>
<linearGradient id="half" x2="0%" y2="100%">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="red" />
<stop offset="50%" stop-color="blue" />
<stop offset="100%" stop-color="blue" />
</linearGradient>
<g>
<polygon points="13.9,0 0,24 27.8,24"></polygon>
<g>
<path d="m13.9,16.1l0,0c-1.1,0 -2.1,-0.9 -2.1,-2.1l0,-4.9c0,-1.1 0.9,-2.1 2.1,-2.1l0,0c1.1,0 2.1,0.9 2.1,2.1l0,4.9c-0.1,1.2 -1,2.1 -2.1,2.1z" class="st1"></path>
<circle r="1.7" cy="19.5" cx="13.9" class="st1"></circle>
</g>
</g>
</symbol>
</defs>
<g class="layer">
<!-- this use will be generated multiple times -->
<use x="0" y="0" fill="url(#half)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_2"></use>
</g>
Now, if I want to change where the line is I need to do it in the <def> tag. but this is changing all my <use> elements.
how can I change the % of the fill for each <use> dynamically and individually?
I don't think that making 100 <linearGradient> definitions for each precent and changing the fillUrl would be a good practice...
You should not put the gradient into the symbol if you want to change the percentage of the stop. If you are fine with steps (10%, 20%, 30%), you can implement one gradient for each step. It looks like this:
<svg version="1.1" id="myWarningId" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 27.8 24" style="enable-background:new 0 0 27.8 24;" xml:space="preserve">
<defs>
<linearGradient id="_10" x2="0%" y2="100%">
<stop offset="10%" stop-color="red" />
<stop offset="10%" stop-color="blue" />
</linearGradient>
<linearGradient id="_20" x2="0%" y2="100%">
<stop offset="20%" stop-color="red" />
<stop offset="20%" stop-color="blue" />
</linearGradient>
<linearGradient id="_30" x2="0%" y2="100%">
<stop offset="30%" stop-color="red" />
<stop offset="30%" stop-color="blue" />
</linearGradient>
<symbol viewBox="0 0 27.8 24" y="0px" x="0px" id="warning" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
#myWarningId .st1{fill:#FFFFFF;}
#myWarningId polygon{fill: inherit;}
</style>
<g>
<polygon points="13.9,0 0,24 27.8,24"></polygon>
<g>
<path d="m13.9,16.1l0,0c-1.1,0 -2.1,-0.9 -2.1,-2.1l0,-4.9c0,-1.1 0.9,-2.1 2.1,-2.1l0,0c1.1,0 2.1,0.9 2.1,2.1l0,4.9c-0.1,1.2 -1,2.1 -2.1,2.1z" class="st1"></path>
<circle r="1.7" cy="19.5" cx="13.9" class="st1"></circle>
</g>
</g>
</symbol>
</defs>
<g class="layer">
<!-- this use will be generated multiple times -->
<use x="0" y="0" fill="url(#_10)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_1"></use>
<use x="0" y="32" fill="url(#_20)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_2"></use>
<use x="0" y="64" fill="url(#_30)" transform="matrix(0.20000000298023224,0,0,0.20000000298023224,0,0) " xlink:href="#warning" id="svg_3"></use>
</g>
</svg>

is it possible to make SVG circle fill color from bottom to top based on percentage? [duplicate]

This question already has answers here:
Outlining and partially filling an SVG Shape
(3 answers)
Closed 7 years ago.
<svg viewbox="-20 -20 100 100">
<circle r="15.29563" cx="0" stroke="#7dc4c2" fill="#5ea4a2">
</svg>
How to fill the circle as below based on percentage!!
http://i.stack.imgur.com/gVAN5.png
Thanks in advance.
you could use a gradient with stop-opacity to do this.
you would add two "middle" stops with opacity 0 and 1 respectively an set the offset of both to the percentage you need.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="0" stop-color="royalblue"/>
<stop offset="100%" stop-opacity="0" stop-color="royalblue"/>
</linearGradient>
<circle cx="50" cy="50" r="45" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
</svg>
you could even animate it
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="1" stop-color="royalblue">
<animate attributeName="offset" values="0;1;0" repeatCount="indefinite" dur="10s" begin="0s"/>
</stop>
<stop offset="40%" stop-opacity="0" stop-color="royalblue">
<animate attributeName="offset" values="0;1;0" repeatCount="indefinite" dur="10s" begin="0s"/>
</stop>
<stop offset="100%" stop-opacity="0" stop-color="royalblue"/>
</linearGradient>
<circle cx="50" cy="50" r="45" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
</svg>
the advantage is that this works on any shape and size without changing the gradient
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 300" width="400" height="200">
<linearGradient id="lg" x1="0.5" y1="1" x2="0.5" y2="0">
<stop offset="0%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="1" stop-color="royalblue"/>
<stop offset="40%" stop-opacity="0" stop-color="royalblue"/>
<stop offset="100%" stop-opacity="0" stop-color="royalblue"/>
</linearGradient>
<circle cx="50" cy="50" r="45" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<circle cx="250" cy="150" r="145" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<rect x="400" y="20" width="100" height="100" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<path d="M50 150L95 290 h-90z" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
<path d="M450 205 A45 45 0 0 1 450 295A100 100 0 0 0 450 205z" fill="url(#lg)" stroke="crimson" stroke-width="5"/>
</svg>
The easiest way to do this is to create a mask with a circular hole in it, and then animate a rectangle behind it. For example:
<path fill="#fff" fill-rule="evenodd"
d="M0 0 200 0 200 200 0 200ZM20 100 A80 80 0 0 0 180 100 80 80 0 0 0 20 100Z"/>
The path data here starts with a square box 200 units wide (M0 0 200 0 200 200 0 200Z) and then uses two arcs to draw a circle of diameter 80 units inside it (A80 80 0 0 0 180 100 80 80 0 0 0 20 100Z). The evenodd fill rule ensures that the circle is cut out from the square.
If you want the circle to fill from bottom to top, then you'll have to use a rotate transformation:
<rect transform="rotate(180 100 100)" x="20" y="20" width="160" height="0" fill="#47f" id="fillup"/>
This spins the coordinate system around the middle of the SVG image so that the rect grows upwards when you increase its height. Here, I'm using a CSS transition to change the height of the rect when you hover over it. But you can use Javascript or JQuery to change the height to whatever you want.
Here's a working example:
svg #fillup { height:0px; transition:height 0.5s; }
svg:hover #fillup { height:160px; }
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="10" y="10" width="180" height="180" fill="#eee"/>
<rect transform="rotate(180 100 100)" x="20" y="20"
width="160" height="0" fill="#47f" id="fillup"/>
<path fill="#fff" fill-rule="evenodd"
d="M0 0 200 0 200 200 0 200ZM20 100 A80 80 0 0 0
180 100 80 80 0 0 0 20 100Z"/>
<circle cx="100" cy="100" r="90" fill="none" stroke="#888"
stroke-width="20"/>
<circle cx="100" cy="100" r="99" fill="none" stroke="#333"
stroke-width="1"/>
<circle cx="100" cy="100" r="80" fill="none" stroke="#333"
stroke-width="1"/>
</svg>

Resources