I am trying to animate the width of a svg rect with the following code.
window.onload = function() {
var viewBoxWidth = document.querySelector('svg').viewBox.baseVal.width;
var rect1 = document.getElementById('r1');
var rect1Width = rect1.getBBox().width;
var pct = (rect1Width / viewBoxWidth) * 100;
rect1.style.setProperty('--w1', pct + '%');
}
.r1 {
animation-name: moveWidth;
animation-delay: 2s;
animation-duration: 2s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-direction: normal;
animation-fill-mode: forwards;
}
#keyframes moveWidth {
0% {
width: 0%;
}
100% {
width: var(--w1);
}
}
<!DOCTYPE html>
<html>
<body>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r1" id="r1" x="10" y="10" width="200" height="20" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="10" y="30" width="200" height="20" stroke="none" fill="green"></rect>
</svg>
</body>
</html>
The animation is taking place but how can I hide the width of r1 till the animation kicks in at the 2s, (till the delay).
window.onload = function() {
var viewBoxWidth = document.querySelector('svg').viewBox.baseVal.width;
var rect1 = document.getElementById('r1');
var rect1Width = rect1.getBBox().width;
var pct = (rect1Width / viewBoxWidth) * 100;
rect1.style.setProperty('--w1', pct + '%');
}
.r1 {
visibility:hidden;/*hide default*/
animation-name: moveWidth;
animation-delay: 2s;
animation-duration: 2s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-direction: normal;
animation-fill-mode: forwards;
}
#keyframes moveWidth {
0% {
visibility:visible;/*show again*/
width: 0%;
}
100% {
visibility:visible;/*Edit-2 maintains visibility after animation overs*/
width: var(--w1);
}
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r1" id="r1" x="10" y="10" width="200" height="20" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="10" y="30" width="200" height="20" stroke="none" fill="green"></rect>
</svg>
use css visibility
Edit-2: maintains visibility after animation overs)
Simple and easy solution change animation-fill-mode: forwards; to animation-fill-mode: both; and width into px or %
.r1 {
animation-name: moveWidth;
animation-delay: 2s;
animation-duration: 2s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-direction: normal;
animation-fill-mode: both;
}
#keyframes moveWidth {
0% {
width: 0%;
}
100% {
width: 200px;
}
}
<!DOCTYPE html>
<html>
<body>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r1" id="r1" x="10" y="10" width="200" height="20" stroke="none" fill="orange"></rect>
<rect class="r2" id="r2" x="10" y="30" width="200" height="20" stroke="none" fill="green"></rect>
</svg>
</body>
</html>
Related
I'm trying to set an opacity of 1 to the lines that I have in a gauge component, here's a link to the code: https://codepen.io/SergiuT/pen/RwgmOqw
Here's the code:
<svg width="244" height="126" viewBox="0 0 244 126" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="0" width="236" height="122">
<rect x="4.97656" width="234.175" height="122" fill="url(#paint0_linear)" />
</mask>
<g mask="url(#mask0)">
<circle cx="122" cy="125.5" r="115" fill="url(#paint1_radial)" />
</g>
<path id="line1" opacity="0.5" d="M22.5763 57.2082C10.2411 75.2339 2.76131 96.7911 2 120.032" stroke="#75FCC6" stroke-width="4"
stroke-linecap="round" />
<path id="line2" opacity="0.5" d="M81.134 11.9933C59.6579 19.7007 41.0318 33.3096 27.248 50.8443" stroke="#75FCC6"
stroke-width="4" stroke-linecap="round" />
<path id="line3" opacity="0.5" d="M88.6836 9.56243C99.262 6.53918 110.44 4.91934 122 4.91934C133.56 4.91934 144.738 6.53919 155.317 9.56245"
stroke="#979797" stroke-width="4" stroke-linecap="round" />
<path id="line4" opacity="0.5" d="M162.867 11.9933C184.343 19.7007 202.969 33.3096 216.753 50.8443" stroke="#FBE850"
stroke-width="4" stroke-linecap="round" />
<path id="line5" opacity="0.5" d="M221.424 57.2082C233.759 75.2339 241.239 96.791 242 120.032" stroke="#FBE850" stroke-width="4"
stroke-linecap="round" />
<defs>
<linearGradient id="paint0_linear" x1="122.064" y1="58.5794" x2="122.064" y2="122"
gradientUnits="userSpaceOnUse">
<stop />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="translate(122 125.5) rotate(90) scale(115)">
<stop offset="0.765625" stop-color="#75FCC6" stop-opacity="0" />
<stop offset="1" stop-color="#75FCC6" stop-opacity="0.33" />
</radialGradient>
</defs>
</svg>
<div class="indicator">
<div class="wrapper">
<div class="line"></div>
</div>
</div>
.indicator {
width: 100%;
height: 100%;
display: flex;
align-items: center;
position: absolute;
top: 45%;
margin: 0 10px;
#keyframes go {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(150deg);
}
}
.wrapper {
width: 100px;
position: absolute;
left: 1%;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards !important ;
transform-origin: bottom right;
animation: go 2s ease-in;
.line {
display: inline-block;
width: 85px;
border-radius: 2px;
border: 1px solid white;
height: 0;
}
}
}
Edit: The lines shine based on the value of the rotate() from .wrapper
Example: I can pass in 150deg to rotate, or 30deg, or 80deg. So I'm not going to pass all the lines everytime
Put an id="svg" to your svg. Then find the animations shine 1 to 5.
body {
background: black
}
.indicator {
width: 100%;
height: 100%;
display: flex;
align-items: center;
position: absolute;
top: 45%;
margin: 0 10px;
}
#keyframes go {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(150deg);
}
}
.wrapper {
width: 100px;
position: absolute;
left: 1%;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards !important ;
transform-origin: bottom right;
animation: go 2s ease-in;
}
.wrapper .line {
display: inline-block;
width: 85px;
border-radius: 2px;
border: 1px solid white;
height: 0;
}
#svg #line1{
animation: shine1 2s ease-in;
}
#keyframes shine1 {
0% {
opacity: 1
}
20% {
opacity: 1
}
40% {
opacity: 0.5
}
60% {
opacity: 0.5
}
80% {
opacity: 0.5
}
100% {
opacity: 0.5
}
}
#svg #line2{
animation: shine2 2s ease-in;
}
#keyframes shine2 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 1
}
60% {
opacity: 1
}
80% {
opacity: 0.5
}
100% {
opacity: 0.5
}
}
#svg #line3{
animation: shine3 2s ease-in;
}
#keyframes shine3 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 0.5
}
60% {
opacity: 1
}
80% {
opacity: 1
}
100% {
opacity: 0.5
}
}
#svg #line4{
animation: shine4 2s ease-in;
}
#keyframes shine4 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 0.5
}
60% {
opacity: 0.5
}
80% {
opacity: 1
}
100% {
opacity: 1
}
}
#svg #line5{
animation: shine5 2s ease-in;
}
#keyframes shine5 {
0% {
opacity: 0.5
}
20% {
opacity: 0.5
}
40% {
opacity: 0.5
}
60% {
opacity: 0.5
}
80% {
opacity: 0.5
}
100% {
opacity: 1
}
}
<svg id="svg" width="244" height="126" viewBox="0 0 244 126" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="0" width="236" height="122">
<rect x="4.97656" width="234.175" height="122" fill="url(#paint0_linear)" />
</mask>
<g mask="url(#mask0)">
<circle cx="122" cy="125.5" r="115" fill="url(#paint1_radial)" />
</g>
<path id="line1" opacity="0.5" d="M22.5763 57.2082C10.2411 75.2339 2.76131 96.7911 2 120.032" stroke="#75FCC6" stroke-width="4"
stroke-linecap="round" />
<path id="line2" opacity="0.5" d="M81.134 11.9933C59.6579 19.7007 41.0318 33.3096 27.248 50.8443" stroke="#75FCC6"
stroke-width="4" stroke-linecap="round" />
<path id="line3" opacity="0.5" d="M88.6836 9.56243C99.262 6.53918 110.44 4.91934 122 4.91934C133.56 4.91934 144.738 6.53919 155.317 9.56245"
stroke="#979797" stroke-width="4" stroke-linecap="round" />
<path id="line4" opacity="0.5" d="M162.867 11.9933C184.343 19.7007 202.969 33.3096 216.753 50.8443" stroke="#FBE850"
stroke-width="4" stroke-linecap="round" />
<path id="line5" opacity="0.5" d="M221.424 57.2082C233.759 75.2339 241.239 96.791 242 120.032" stroke="#FBE850" stroke-width="4"
stroke-linecap="round" />
<defs>
<linearGradient id="paint0_linear" x1="122.064" y1="58.5794" x2="122.064" y2="122"
gradientUnits="userSpaceOnUse">
<stop />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="translate(122 125.5) rotate(90) scale(115)">
<stop offset="0.765625" stop-color="#75FCC6" stop-opacity="0" />
<stop offset="1" stop-color="#75FCC6" stop-opacity="0.33" />
</radialGradient>
</defs>
</svg>
<div class="indicator">
<div class="wrapper">
<div class="line"></div>
</div>
</div>
I have a html page which animates three svg paths all at once.
#keyframes draw {
100% {
stroke-dashoffset: 1;
}
}
.path {
stroke-dasharray: 555;
stroke-dashoffset: 555;
-webkit-animation: draw 19s normal linear forwards;
-moz-animation-name: draw 3s normal linear forwards;
-o-animation-name: draw 3s normal linear forwards;
animation-name: draw 3s normal linear forwards;
}
<svg class="multipath" version="1.1" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="150px" height="150px" viewBox="0 0 200 200" xml:space="preserve">
<path class="path" fill="none" stroke="#000000" stroke-width="6" stroke-miterlimit="10" d="m 21.079449,129.62288 c 33.842653,-15.80707 -32.075893,-17.10715 0,0"/>
<path class="path" fill="none" stroke="#000000" stroke-width="6" stroke-miterlimit="10" d="M 29.259532,121.44279 C 61.098099,135.68206 62.642648,115.18396 41.844279,94.385593 36.3407,88.882014 10.779265,91.868643 18.5625,91.868643 c 18.104688,0 27.15088,-5.255721 37.754236,-15.101694"/>
<path class="path" fill="none" stroke="#000000" stroke-width="6" stroke-miterlimit="10" d="m 55.058262,119.55508 c 19.137979,21.06152 26.855914,6.64597 25.169494,-22.023302"/>
</svg>
How can i sequence the animation i,e animating second path after completion of first path, third after second.
You can use animation-delay to get the sequence of animation
Stack Snippet
#keyframes draw {
100% {
stroke-dashoffset: 1;
}
}
.path {
stroke-dasharray: 555;
stroke-dashoffset: 555;
animation: draw 3s linear forwards;
}
.path:nth-child(2) {
animation-delay: 1s;
}
.path:nth-child(3) {
animation-delay: 2s;
}
<svg class="multipath" version="1.1" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="150px" height="150px" viewBox="0 0 200 200" xml:space="preserve">
<path class="path" fill="none" stroke="#000000" stroke-width="6" stroke-miterlimit="10" d="m 21.079449,129.62288 c 33.842653,-15.80707 -32.075893,-17.10715 0,0"/>
<path class="path" fill="none" stroke="#000000" stroke-width="6" stroke-miterlimit="10" d="M 29.259532,121.44279 C 61.098099,135.68206 62.642648,115.18396 41.844279,94.385593 36.3407,88.882014 10.779265,91.868643 18.5625,91.868643 c 18.104688,0 27.15088,-5.255721 37.754236,-15.101694"/>
<path class="path" fill="none" stroke="#000000" stroke-width="6" stroke-miterlimit="10" d="m 55.058262,119.55508 c 19.137979,21.06152 26.855914,6.64597 25.169494,-22.023302"/>
</svg>
In HTML with SVG you can create a rect with fading color:
<svg>
<rect width="100%" height="100%">
<animate attributeName="fill" values="red;blue;red" dur="10s" repeatCount="indefinite" />
</rect>
</svg>
Now in my code I have a path like that:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="247pt" height="543pt" viewBox="0.00 0.00 246.86 543.19">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 539.1859)">
<!-- c->e -->
<g id="a1124" class="edge">
<title>c->e</title>
<path fill="none" stroke="#ff0000" stroke-width="3" d="M208.109,-297.8625C205.1217,-279.2357 200.2512,-248.8658 195.5911,-219.8076" />
<polygon fill="#ff0000" stroke="#ff0000" stroke-width="3" points="198.9943,-218.9251 193.9549,-209.6055 192.0827,-220.0336 198.9943,-218.9251" />
</g>
</g>
</svg>
I am looking for a way to fade the color of the path along the path so that it illustrates some kind of data flow. Is there a way to accomplish that? (via CSS or Javascript).
Try this
#keyframes fade {
0% {
stroke: red;
fill: red;
}
50% {
stroke: blue;
fill: blue;
}
100% {
stroke: red;
fill: red;
}
}
#fade {
animation-name: fade;
animation-duration: 10s;
animation-iteration-count: infinite;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="247pt" height="543pt" viewBox="0.00 0.00 246.86 543.19">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 539.1859)">
<!-- c->e -->
<g id="a1124" class="edge">
<title>c->e</title>
<path id="fade" stroke="#ff0000" stroke-width="3" d="M208.109,-297.8625C205.1217,-279.2357 200.2512,-248.8658 195.5911,-219.8076" />
<polygon id="fade" stroke-width="3" points="198.9943,-218.9251 193.9549,-209.6055 192.0827,-220.0336 198.9943,-218.9251" />
</g>
</g>
</svg>
I'm working to create an SVG circle progress indicator in react... Here is my output:
CODEPEN
The problem is I need the red stroke to start at the top, not at the current 90% angle... Is there some CSS I can add to reposition the red stroke to start at the top?
FYI, I'm using the following component in react to render this HTML: https://github.com/wmartins/react-circular-progress/blob/gh-pages/src/js/components/CircularProgress.jsx.js
codepen source below
html
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
css
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0 50%);
}
You could use transform, add transform="rotate(-90 25 25)" and it will start at the top
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0 50%);
}
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle transform="rotate(-90 25 25)" class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-startOffest: 50%;stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
If to use CSS, you can rotate the svg element instead of the circle (which might or might not be possible based on its shape)
.CircularProgress {
transform: rotate(-90deg);
}
.CircularProgress-Bg,
.CircularProgress-Fg {
fill: none;
}
.CircularProgress-Bg {
stroke: #CCC;
}
.CircularProgress-Fg {
transition: stroke-dashoffset .5s ease-in-out;
stroke: red;
}
.CircularProgress-Text {
font-size: 15px;
font-weight: 600;
fill: rgba(255,255,255,0.9);
transform: translate(0, 50%);
}
<svg class="CircularProgress" width="50" height="50" viewBox="0 0 50 50">
<circle class="CircularProgress-Bg" cx="25" cy="25" r="24" stroke-width="2px"></circle>
<circle class="CircularProgress-Fg" cx="25" cy="25" r="24" stroke-width="2px" style="stroke-dasharray: 150.796; stroke-dashoffset: 125.161;"></circle>
<text class="CircularProgress-Text" x="25" y="25" dy=".4em" text-anchor="middle">17%</text>
</svg>
I've designed a 3-bar icon using pure SVG code in HTML. I'm using CSS3 transforms to rotate the top & bottom bars into an X shape. The problem is that they rotate around their own center, but I need them rotating around the icon's center. To get around this I've adjusted their X/Y coordinates.
This causes a LOT of buggy issues with Internet Explorer, Firefox, & Safari. Chrome seems to be alright but obviously I'd like to code this the "right" way so it'll work in all browsers.
Here's my live CodePen
HTML
<svg id="burgericon" xmlns="http://www.w3.org/2000/svg" width="90" height="80">
<g class="icon">
<rect class="frstbar" x="10" y="10" width="70" height="12" rx="7" ry="7" fill="#414141"/>
<rect class="scndbar" x="10" y="35" width="70" height="12" rx="7" ry="7" fill="#414141"/>
<rect class="thrdbar" x="10" y="60" width="70" height="12" rx="7" ry="7" fill="#414141"/>
</g>
</svg>
CSS
.hamburger { display:block; text-align:center; }
svg { cursor:pointer; }
.frstbar, .scndbar, .thrdbar {
-webkit-transition: all 0.35s linear;
-moz-transition: all 0.35s linear;
-o-transition: all 0.35s linear;
transition: all 0.35s linear;
}
#burgericon.open .frstbar {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
#burgericon.open .thrdbar {
-webkit-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
#burgericon.open .scndbar { width: 0; opacity: 0; }
JS
$('#burgericon').on('click', function(e) {
if($(this).attr('class') != "open") {
$(this).attr('class','open');
$('.frstbar').attr('x','25').attr('y','-5');
$('.thrdbar').attr('x','-35').attr('y','55');
}
else {
$(this).attr('class','default');
$('.frstbar').attr('x','10').attr('y','10');
$('.thrdbar').attr('x','10').attr('y','60');
}
});
I also think changing the X/Y coords is causing a blurry effect. I've added a screenshot below. First you'll see the completed X icon and then you'll see how it looks when animated back to default.
The bars aren't perfectly straight but instead they look crooked for some reason.
Screenshot here
I'm still new to SVG manipulation so I'm not sure how to properly rotate <rect> elements with CSS3/JS. Any help or tips in the right direction would be more than appreciated.
You can remove the JS positioning by using the CSS transform-origin property. You can set it on the left of the first and second bars with transform-origin: 0 50%;.
This way they will cross each other when they are rotated :
document.getElementById('burgericon').addEventListener('click', function (e) {
this.classList.toggle('open');
});
.hamburger {
display: block;
text-align: center;
}
svg {
cursor: pointer;
}
.frstbar,.scndbar,.thrdbar {
transition: all 0.35s linear;
transform: rotate(0deg);
transform-origin: 0% 50%;
}
#burgericon.open .frstbar {
transform: rotate(45deg);
}
#burgericon.open .thrdbar {
transform: rotate(-45deg);
}
#burgericon.open .scndbar {
width: 0;
opacity: 0;
}
<nav class="hamburger">
<svg id="burgericon" xmlns="http://www.w3.org/2000/svg" width="90" height="80">
<g class="icon">
<rect class="frstbar" x="10" y="10" width="70" height="12" rx="7" ry="7" fill="#414141" />
<rect class="scndbar" x="10" y="35" width="70" height="12" rx="7" ry="7" fill="#414141" />
<rect class="thrdbar" x="10" y="60" width="70" height="12" rx="7" ry="7" fill="#414141" />
</g>
</svg>
</nav>
<div>
</div>
Credits to David Thomas for the JS
Note that the transform-origin property needs the same vendor prefixes as the transform property. I have omited them for both in the above snippet
CSS
Using css transform: rotate() I rotated the elements so they form the X
Using css opacity and transitions; made the object gradually go transparent.
.icon {
stroke: none;
fill: #777;
}
.icon .frstbar {
transform-origin: 10% 50%;
transition: transform 1s;
}
.icon:hover .frstbar {
transform: rotate(45deg);
}
.icon .thrdbar {
transform-origin: 10% 50%;
transition: transform 1s;
}
.icon:hover .thrdbar {
transform: rotate(-45deg);
}
.scndbar {
opacity: 1;
transition: opacity 1s;
}
.icon:hover .scndbar {
opacity: 0;
}
<svg id="burgericon" xmlns="http://www.w3.org/2000/svg" width="90" height="90" viewBox="0 0 100 100">
<g class="icon">
<rect class="frstbar" x="10" y="10" width="90" height="12" rx="7" ry="7" />
<rect class="scndbar" x="10" y="35" width="90" height="12" rx="7" ry="7" />
<rect class="thrdbar" x="10" y="60" width="90" height="12" rx="7" ry="7" />
</g>
</svg>