SVG not fully animating - javascript

I was trying to use SVGs to animate the logo for my personal website, but it's not working entirely as expected. In my CSS, I used stroke-dasharray and stroke-dashoffset to animate the SVG. But as you can see in the picture below, it's not "completing" the path and finishing outlining the logo.
It may not seem like a big deal but it is really noticeable on mobile devices.
I've checked to make sure that the actual SVG code is fine, which it is, and I've tried playing around with the values for the stroke-dasharray and stroke-dashoffset in the CSS but nothing seems to work.
Here is the code that I took from out of my website (also on JSFiddle at https://jsfiddle.net/jgpixel/ehkum9vx/7/):
class Component {
constructor(props, root) {
this.props = props;
this.root = root;
}
static setAttributes(attributes, element) {
for (const key in attributes) {
element.setAttribute(key, attributes[key]);
}
}
}
class WebsiteLoader extends Component {
constructor(props, root) {
super(props, root);
this.render();
}
render() {
document.body.className = 'no-scroll';
const overlay = document.createElement('div');
overlay.className = 'overlay';
const overlayContent = document.createElement('div');
overlayContent.className = 'overlay-content';
const jgLogo = this.createSVGLogo();
this.root.appendChild(overlay);
overlay.appendChild(overlayContent);
overlayContent.appendChild(jgLogo);
setTimeout(() => {
overlay.classList.add('fade-out-overlay');
document.body.classList.remove('no-scroll');
setTimeout(() => {
overlay.remove();
}, 410);
}, this.props.animationDuration);
}
createSVGLogo() {
const iconSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
Component.setAttributes({
'width': 166,
'height': 73,
'viewBox': '0 0 166 73',
'fill': 'none'
}, iconSVG);
const pixelPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'pixel',
'd': 'M161.63 57.4413L161.649 57.4609L161.669 57.4799C163.25 59.0047 164.01 60.7848 164.01 62.9001C164.01 65.0173 163.248 66.8409 161.649 68.4394C160.129 69.9597 158.344 70.7001 156.21 70.7001C154.084 70.7001 152.261 69.9639 150.671 68.4392C149.146 66.8494 148.41 65.0262 148.41 62.9001C148.41 60.7668 149.151 58.981 150.671 57.4608C152.269 55.8622 154.093 55.1001 156.21 55.1001C158.325 55.1001 160.106 55.86 161.63 57.4413Z',
'stroke': '#FF656F',
'stroke-width': 3
}, pixelPath);
const letterPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'jg',
'd': 'M1.86963 51.4062L14.9914 46.5371C16.3136 50.0457 18.032 52.8129 20.2098 54.7267C22.7214 56.9339 25.8559 58 29.5 58C33.6001 58 37.0432 56.6285 39.6897 53.8308C42.3327 51.0368 43.6 47.4105 43.6 43.1V2.6H57.8V43.6C57.8 49.0361 56.5873 53.7306 54.2102 57.7342L54.2058 57.7417L54.2014 57.7492C51.8783 61.7675 48.6188 64.9065 44.39 67.1787C40.1784 69.4416 35.1976 70.6 29.4 70.6C22.2609 70.6 16.3535 68.8365 11.5886 65.3915C7.20853 62.1181 3.95558 57.4855 1.86963 51.4062ZM121.82 44.1H104.42V32.2H138.92V35.7C138.92 40.7926 138.051 45.4669 136.329 49.7393L136.325 49.7502C134.661 53.9727 132.3 57.6722 129.238 60.8612L129.238 60.8617C126.253 63.9734 122.694 66.3912 118.545 68.1148C114.41 69.8322 109.875 70.7 104.92 70.7C99.8313 70.7 95.1235 69.8316 90.7823 68.1092C86.4218 66.3125 82.5846 63.849 79.2599 60.7186C76.0023 57.5223 73.4496 53.8524 71.5957 49.7013C69.816 45.5012 68.9203 40.9727 68.9203 36.1C68.9203 31.2241 69.8171 26.7293 71.5958 22.5983C73.4543 18.3703 75.9789 14.6988 79.1702 11.5713L79.1704 11.5711C82.4245 8.38083 86.2212 5.92237 90.5739 4.19412L90.5827 4.19063L90.5914 4.18702C94.9328 2.3994 99.6042 1.5 104.62 1.5C110.338 1.5 115.721 2.68692 120.784 5.0584L120.791 5.06171L120.798 5.06496C125.403 7.16338 129.214 9.99044 132.254 13.5424L122.384 22.4334C120.227 19.9485 117.762 18.014 114.985 16.6555C111.829 15.0787 108.366 14.3 104.62 14.3C101.628 14.3 98.8221 14.8705 96.2204 16.0251C93.7149 17.1003 91.4919 18.6071 89.5597 20.5393L89.5497 20.5493L89.5398 20.5595C87.6654 22.5061 86.1973 24.8042 85.1302 27.4364L85.1236 27.4527L85.1174 27.4692C84.1131 30.1234 83.6203 33.0056 83.6203 36.1C83.6203 39.2072 84.1507 42.1289 85.2251 44.8507L85.225 44.8508L85.2302 44.8636C86.3003 47.503 87.804 49.8329 89.7406 51.8412L89.7595 51.8608L89.7791 51.8798C91.7733 53.8028 94.0533 55.3339 96.6111 56.4707L96.6338 56.4808L96.6568 56.4901C99.3159 57.5681 102.175 58.1 105.22 58.1C108.123 58.1 110.791 57.6043 113.199 56.584C115.643 55.5765 117.751 54.163 119.502 52.3388C121.258 50.5105 122.514 48.4099 123.252 46.0474L123.861 44.1H121.82Z',
'stroke': 'white',
'stroke-width': 3
}, letterPath);
iconSVG.appendChild(letterPath);
iconSVG.appendChild(pixelPath);
return iconSVG;
}
}
new WebsiteLoader({
animationDuration: 6500
}, document.getElementById('root'))
:root {
--primary: #0F1F39;
--accent: #FF656F;
--type: #FFFFFF;
}
html,
body {
min-height: 100%;
background-color: var(--primary);
color: var(--type);
margin: 0;
padding: 0;
}
body.no-scroll {
overflow: hidden;
}
.overlay {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
z-index: 9999999;
display: flex;
justify-content: center;
align-items: center;
animation: hideOverlay;
animation-duration: 1s;
animation-fill-mode: forwards;
background-color: var(--primary);
}
.overlay-content {
display: flex;
}
.overlay-content {
font-size: 100px;
font-weight: bold;
}
.fade-out-overlay {
animation: fadeOutOverlay;
animation-duration: 0.4s;
animation-fill-mode: forwards;
}
#keyframes fadeOutOverlay {
to {
opacity: 0;
}
}
.jg {
stroke-dasharray: 395px;
stroke-dashoffset: 395px;
animation: drawLetter 4s forwards,
fillLetter 0.3s 4.5s forwards;
}
.pixel {
stroke-dasharray: 49px;
stroke-dashoffset: 49px;
animation:drawPixel 4s forwards,
fillPixel 0.3s 4.5s forwards;
}
.jg,
.pixel {
fill: transparent;
}
#keyframes drawLetter {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillLetter {
to {
fill: var(--type);
}
}
#keyframes drawPixel {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillPixel {
to {
fill: var(--accent);
}
}
<div id="root"></div>
Also, here is the code for the SVG, which I've given a background color to just for demonstration purposes (so the white is visible):
<svg width="166" height="73" viewBox="0 0 166 73" fill="none" style="background-color: #0F1F39" xmlns="http://www.w3.org/2000/svg">
<path d="M161.63 57.4413L161.649 57.4609L161.669 57.4799C163.25 59.0047 164.01 60.7848 164.01 62.9001C164.01 65.0173 163.248 66.8409 161.649 68.4394C160.129 69.9597 158.344 70.7001 156.21 70.7001C154.084 70.7001 152.261 69.9639 150.671 68.4392C149.146 66.8494 148.41 65.0262 148.41 62.9001C148.41 60.7668 149.151 58.981 150.671 57.4608C152.269 55.8622 154.093 55.1001 156.21 55.1001C158.325 55.1001 160.106 55.86 161.63 57.4413Z" stroke="#FF656F" stroke-width="3"/>
<path d="M1.86963 51.4062L14.9914 46.5371C16.3136 50.0457 18.032 52.8129 20.2098 54.7267C22.7214 56.9339 25.8559 58 29.5 58C33.6001 58 37.0432 56.6285 39.6897 53.8308C42.3327 51.0368 43.6 47.4105 43.6 43.1V2.6H57.8V43.6C57.8 49.0361 56.5873 53.7306 54.2102 57.7342L54.2058 57.7417L54.2014 57.7492C51.8783 61.7675 48.6188 64.9065 44.39 67.1787C40.1784 69.4416 35.1976 70.6 29.4 70.6C22.2609 70.6 16.3535 68.8365 11.5886 65.3915C7.20853 62.1181 3.95558 57.4855 1.86963 51.4062ZM121.82 44.1H104.42V32.2H138.92V35.7C138.92 40.7926 138.051 45.4669 136.329 49.7393L136.325 49.7502C134.661 53.9727 132.3 57.6722 129.238 60.8612L129.238 60.8617C126.253 63.9734 122.694 66.3912 118.545 68.1148C114.41 69.8322 109.875 70.7 104.92 70.7C99.8313 70.7 95.1235 69.8316 90.7823 68.1092C86.4218 66.3125 82.5846 63.849 79.2599 60.7186C76.0023 57.5223 73.4496 53.8524 71.5957 49.7013C69.816 45.5012 68.9203 40.9727 68.9203 36.1C68.9203 31.2241 69.8171 26.7293 71.5958 22.5983C73.4543 18.3703 75.9789 14.6988 79.1702 11.5713L79.1704 11.5711C82.4245 8.38083 86.2212 5.92237 90.5739 4.19412L90.5827 4.19063L90.5914 4.18702C94.9328 2.3994 99.6042 1.5 104.62 1.5C110.338 1.5 115.721 2.68692 120.784 5.0584L120.791 5.06171L120.798 5.06496C125.403 7.16338 129.214 9.99044 132.254 13.5424L122.384 22.4334C120.227 19.9485 117.762 18.014 114.985 16.6555C111.829 15.0787 108.366 14.3 104.62 14.3C101.628 14.3 98.8221 14.8705 96.2204 16.0251C93.7149 17.1003 91.4919 18.6071 89.5597 20.5393L89.5497 20.5493L89.5398 20.5595C87.6654 22.5061 86.1973 24.8042 85.1302 27.4364L85.1236 27.4527L85.1174 27.4692C84.1131 30.1234 83.6203 33.0056 83.6203 36.1C83.6203 39.2072 84.1507 42.1289 85.2251 44.8507L85.225 44.8508L85.2302 44.8636C86.3003 47.503 87.804 49.8329 89.7406 51.8412L89.7595 51.8608L89.7791 51.8798C91.7733 53.8028 94.0533 55.3339 96.6111 56.4707L96.6338 56.4808L96.6568 56.4901C99.3159 57.5681 102.175 58.1 105.22 58.1C108.123 58.1 110.791 57.6043 113.199 56.584C115.643 55.5765 117.751 54.163 119.502 52.3388C121.258 50.5105 122.514 48.4099 123.252 46.0474L123.861 44.1H121.82Z" stroke="white" stroke-width="3"/>
</svg>
Thanks for the help in advance.

Add stroke-linecap: square:
class Component {
constructor(props, root) {
this.props = props;
this.root = root;
}
static setAttributes(attributes, element) {
for (const key in attributes) {
element.setAttribute(key, attributes[key]);
}
}
}
class WebsiteLoader extends Component {
constructor(props, root) {
super(props, root);
this.render();
}
render() {
document.body.className = 'no-scroll';
const overlay = document.createElement('div');
overlay.className = 'overlay';
const overlayContent = document.createElement('div');
overlayContent.className = 'overlay-content';
const jgLogo = this.createSVGLogo();
this.root.appendChild(overlay);
overlay.appendChild(overlayContent);
overlayContent.appendChild(jgLogo);
setTimeout(() => {
overlay.classList.add('fade-out-overlay');
document.body.classList.remove('no-scroll');
setTimeout(() => {
overlay.remove();
}, 410);
}, this.props.animationDuration);
}
createSVGLogo() {
const iconSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
Component.setAttributes({
'width': 166,
'height': 73,
'viewBox': '0 0 166 73',
'fill': 'none'
}, iconSVG);
const pixelPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'pixel',
'd': 'M161.63 57.4413L161.649 57.4609L161.669 57.4799C163.25 59.0047 164.01 60.7848 164.01 62.9001C164.01 65.0173 163.248 66.8409 161.649 68.4394C160.129 69.9597 158.344 70.7001 156.21 70.7001C154.084 70.7001 152.261 69.9639 150.671 68.4392C149.146 66.8494 148.41 65.0262 148.41 62.9001C148.41 60.7668 149.151 58.981 150.671 57.4608C152.269 55.8622 154.093 55.1001 156.21 55.1001C158.325 55.1001 160.106 55.86 161.63 57.4413Z',
'stroke': '#FF656F',
'stroke-width': 3
}, pixelPath);
const letterPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'jg',
'd': 'M1.86963 51.4062L14.9914 46.5371C16.3136 50.0457 18.032 52.8129 20.2098 54.7267C22.7214 56.9339 25.8559 58 29.5 58C33.6001 58 37.0432 56.6285 39.6897 53.8308C42.3327 51.0368 43.6 47.4105 43.6 43.1V2.6H57.8V43.6C57.8 49.0361 56.5873 53.7306 54.2102 57.7342L54.2058 57.7417L54.2014 57.7492C51.8783 61.7675 48.6188 64.9065 44.39 67.1787C40.1784 69.4416 35.1976 70.6 29.4 70.6C22.2609 70.6 16.3535 68.8365 11.5886 65.3915C7.20853 62.1181 3.95558 57.4855 1.86963 51.4062ZM121.82 44.1H104.42V32.2H138.92V35.7C138.92 40.7926 138.051 45.4669 136.329 49.7393L136.325 49.7502C134.661 53.9727 132.3 57.6722 129.238 60.8612L129.238 60.8617C126.253 63.9734 122.694 66.3912 118.545 68.1148C114.41 69.8322 109.875 70.7 104.92 70.7C99.8313 70.7 95.1235 69.8316 90.7823 68.1092C86.4218 66.3125 82.5846 63.849 79.2599 60.7186C76.0023 57.5223 73.4496 53.8524 71.5957 49.7013C69.816 45.5012 68.9203 40.9727 68.9203 36.1C68.9203 31.2241 69.8171 26.7293 71.5958 22.5983C73.4543 18.3703 75.9789 14.6988 79.1702 11.5713L79.1704 11.5711C82.4245 8.38083 86.2212 5.92237 90.5739 4.19412L90.5827 4.19063L90.5914 4.18702C94.9328 2.3994 99.6042 1.5 104.62 1.5C110.338 1.5 115.721 2.68692 120.784 5.0584L120.791 5.06171L120.798 5.06496C125.403 7.16338 129.214 9.99044 132.254 13.5424L122.384 22.4334C120.227 19.9485 117.762 18.014 114.985 16.6555C111.829 15.0787 108.366 14.3 104.62 14.3C101.628 14.3 98.8221 14.8705 96.2204 16.0251C93.7149 17.1003 91.4919 18.6071 89.5597 20.5393L89.5497 20.5493L89.5398 20.5595C87.6654 22.5061 86.1973 24.8042 85.1302 27.4364L85.1236 27.4527L85.1174 27.4692C84.1131 30.1234 83.6203 33.0056 83.6203 36.1C83.6203 39.2072 84.1507 42.1289 85.2251 44.8507L85.225 44.8508L85.2302 44.8636C86.3003 47.503 87.804 49.8329 89.7406 51.8412L89.7595 51.8608L89.7791 51.8798C91.7733 53.8028 94.0533 55.3339 96.6111 56.4707L96.6338 56.4808L96.6568 56.4901C99.3159 57.5681 102.175 58.1 105.22 58.1C108.123 58.1 110.791 57.6043 113.199 56.584C115.643 55.5765 117.751 54.163 119.502 52.3388C121.258 50.5105 122.514 48.4099 123.252 46.0474L123.861 44.1H121.82Z',
'stroke': 'white',
'stroke-width': 3
}, letterPath);
iconSVG.appendChild(letterPath);
iconSVG.appendChild(pixelPath);
return iconSVG;
}
}
new WebsiteLoader({
animationDuration: 6500
}, document.getElementById('root'))
:root {
--primary: #0F1F39;
--accent: #FF656F;
--type: #FFFFFF;
}
html,
body {
min-height: 100%;
background-color: var(--primary);
color: var(--type);
margin: 0;
padding: 0;
}
body.no-scroll {
overflow: hidden;
}
.overlay {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
z-index: 9999999;
display: flex;
justify-content: center;
align-items: center;
animation: hideOverlay;
animation-duration: 1s;
animation-fill-mode: forwards;
background-color: var(--primary);
}
.overlay-content {
display: flex;
}
.overlay-content {
font-size: 100px;
font-weight: bold;
}
.fade-out-overlay {
animation: fadeOutOverlay;
animation-duration: 0.4s;
animation-fill-mode: forwards;
}
#keyframes fadeOutOverlay {
to {
opacity: 0;
}
}
.jg {
stroke-dasharray: 395px;
stroke-dashoffset: 395px;
stroke-linecap: square;
animation: drawLetter 4s forwards,
fillLetter 0.3s 4.5s forwards;
}
.pixel {
stroke-dasharray: 49px;
stroke-dashoffset: 49px;
animation:drawPixel 4s forwards,
fillPixel 0.3s 4.5s forwards;
}
.jg,
.pixel {
fill: transparent;
}
#keyframes drawLetter {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillLetter {
to {
fill: var(--type);
}
}
#keyframes drawPixel {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillPixel {
to {
fill: var(--accent);
}
}
<div id="root"></div>

Related

React Native Wave Animation: Convert CSS style to JS style

I am trying to achieve something like this for my React Native project.
I have tried using css-to-react-native-transform library to convert CSS to JS but it's been unsuccessful so far.
So any help regarding this issue would be greatly appreciated as I am fairly new with this.
Here is the CSS code:
<style>
.waves {
position: absolute;
bottom: 4.5vh;
width: 100%;
height:15vh;
margin-bottom:-7px; Fix for safari gap
min-height:130px;
max-height:180px;
}
/* Animation */
.parallax > use {
animation: move-forever 25s cubic-bezier(.55,.5,.45,.5) infinite;
}
.parallax > use:nth-child(1) {
animation-delay: -2s;
animation-duration: 7s;
}
.parallax > use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
}
.parallax > use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
}
.parallax > use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
}
#keyframes move-forever {
0% {
transform: translate3d(-90px,0,0);
}
100% {
transform: translate3d(85px,0,0);
}
}
/Shrinking for mobile/
#media (max-width: 768px) {
.waves {
height:70px;
min-height:70px;
}
}
</style>
<!--Waves Container-->
<div>
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto">
<defs>
<path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
</defs>
<g class="parallax">
<use xlink:href="#gentle-wave" x="48" y="0" fill="rgba(255,255,255,0.7" />
<use xlink:href="#gentle-wave" x="48" y="3" fill="#89c2ee" />
<use xlink:href="#gentle-wave" x="48" y="5" fill="#0379ff" />
<use xlink:href="#gentle-wave" x="48" y="7" fill="#fff" />
</g>
</svg>
</div>
<!--Waves end-->
Here is what I have tried so far on my React Native:
import React from 'react';
import { View, Image, StyleSheet, ImageBackground, Text } from 'react-native';
import { useTheme } from 'react-native-paper';
import { SCREEN_INFO } from './constants';
import transform from "css-to-react-native-transform";
const color = transform(`
.waves {
position: absolute;
bottom: 4.5vh;
width: 100%;
height:15vh;
margin-bottom:-7px;
min-height:130px;
max-height:180px;
}
.parallax > use {
animation: move-forever 25s cubic-bezier(.55,.5,.45,.5) infinite;
}
.parallax > use:nth-child(1) {
animation-delay: -2s;
animation-duration: 7s;
}
.parallax > use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
}
.parallax > use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
}
.parallax > use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
}
#keyframes move-forever {
0% {
transform: translate3d(-90px,0,0);
}
100% {
transform: translate3d(85px,0,0);
}
}
#media (max-width: 768px) {
.waves {
height:70px;
min-height:70px;
}
}
`);
export default function Welcome({ navigation, route }) {
const { colors } = useTheme();
return (
<View
style={styles.flex}
>
<View style={{borderWidth: 2, borderColor: 'red'}}>
<View style={[styles.waves]}/>
<View style={styles.parallax}/>
<Text style={{fontSize: 20, color:'black'}}>Hello</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
flex: {
flex: 1,
},
center: {
justifyContent: 'center',
alignItems: 'center',
flex: 1,
}
});

Onclick button to pause and run CSS animation with nested nth-child

I have a working css animation. I meant it to loop through each child changing the background color with keyframes.
I'm attempting to create a button to pause and run the animation on click. What I have so far works only for the parent. I can only run and pause the parent. I can't make it work for the nested nth-child.
I've tried document.querySelector('.animation1 animation1:nth-child(16n +1) animation1:nth-child(16n + 2))', document.querySelectorAll() but to no avail.
I've also attempted document.getElementsByClassName('animation1').classList.add("animation-run");.
var button = document.getElementById('button-ani');
var test_ani = document.getElementsByClassName('animation1');
button.onclick = function() {
test_ani[0].classList.toggle('playani');
}
/*document.getElementsByClassName('animation1').classList.add("animation-run"); */
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay) paused;
}
/* animation-run
.animation-run {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
/* Without Paused
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
.playani {
animation-play-state: running;
}
.animation1:hover {
animation: none;
fill: #666;
}
.animation1:nth-child(16n + 1) {
--animation-delay: 0.2s;
}
.animation1:nth-child(16n + 2) {
--animation-delay: 0.3s;
}
.animation1:nth-child(16n + 3) {
--animation-delay: 0.4s;
}
.animation1:nth-child(16n + 4) {
--animation-delay: 0.5s;
}
.animation1:nth-child(16n + 5) {
--animation-delay: 0.5s;
}
#keyframes ani_keyframes {
0% {
fill: #000;
}
40% {
fill: #FF0;
}
80% {
fill: #330;
}
}
<div id="animation1_wrapper">
<button id="button-ani">Toggle Animation Play State</button>
<svg id="animation1" width="100%" height="100%" viewBox="0 0 418 255" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="ani_graphic">
<path class="animation1" d="M263.46 25.3801C257.63 29.2001 252.88 33.7801 249.33 37.8001H263.46V25.3801Z" fill="#000"></path>
<path class="animation1" d="M301.26 37.8001V18.8701C300.92 18.7801 300.58 18.6801 300.24 18.6001C287.1 15.3201 275.8 18.2901 266.73 23.3901V37.8001H301.26Z" fill="#f1f1f1"></path>
<path class="animation1" d="M329.15 37.8001C324.38 30.2101 316.5 23.6801 304.54 19.8201V37.8001H329.15Z" fill="#f1f1f1"></path>
----
----
</g>
</svg>
</div>
You can simply use a forEach loop and querySelectorAll method to do animation on all the classes when you click play OR when you click it again the animation will stop on all svg elements
querySelectorAll method return a node list of same class found in the DOM tree and using forEach we can iterate through it all and apply toggle class on found element with that class name
Live Working Demo:
var button = document.getElementById('button-ani');
var test_ani = document.querySelectorAll('.animation1');
button.onclick = function() {
test_ani.forEach(function(ani) {
ani.classList.toggle('playani');
})
}
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay) paused;
}
/* animation-run
.animation-run {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
/* Without Paused
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
.playani {
animation-play-state: running;
}
.animation1:hover {
animation: none;
fill: #666;
}
.animation1:nth-child(16n + 1) {
--animation-delay: 0.2s;
}
.animation1:nth-child(16n + 2) {
--animation-delay: 0.3s;
}
.animation1:nth-child(16n + 3) {
--animation-delay: 0.4s;
}
.animation1:nth-child(16n + 4) {
--animation-delay: 0.5s;
}
.animation1:nth-child(16n + 5) {
--animation-delay: 0.5s;
}
#keyframes ani_keyframes {
0% {
fill: #000;
}
40% {
fill: #FF0;
}
80% {
fill: #330;
}
}
<div id="animation1_wrapper">
<button id="button-ani">Toggle Animation Play State</button>
<svg id="animation1" width="100%" height="100%" viewBox="0 0 418 255" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="ani_graphic">
<path class="animation1" d="M263.46 25.3801C257.63 29.2001 252.88 33.7801 249.33 37.8001H263.46V25.3801Z" fill="#000"></path>
<path class="animation1" d="M301.26 37.8001V18.8701C300.92 18.7801 300.58 18.6801 300.24 18.6001C287.1 15.3201 275.8 18.2901 266.73 23.3901V37.8001H301.26Z" fill="#f1f1f1"></path>
<path class="animation1" d="M329.15 37.8001C324.38 30.2101 316.5 23.6801 304.54 19.8201V37.8001H329.15Z" fill="#f1f1f1"></path>
----
----
</g>
</svg>
</div>

Javascript Animate Matching CSS Animation

I'm trying to get the Javascript animation to match exactly my css animation. I'm not sure why this is not working? I'm trying to use basic javascript. not jquery. The second div should be matching the animation of the first div
https://jsfiddle.net/JokerMartini/pf2nt4su/
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
let timing = {
duration: 2000,
iterations: Infinity
}
div.animate([
keyframes,
timing
]);
//elements += html;
content.append(div)
body {
background: #808080;
}
.base {
width: 180px;
height: 90px;
background: black;
}
.sample {
animation: play 2s steps(10) infinite;
}
#keyframes play {
0% {
background-color: green;
opacity: 0;
}
100% {
background-color: blue;
opacity: 1;
}
}
<div class='base sample'></div>
<div id="content"></div>
edit: Replace below (notice square brackets)
div.animate([
keyframes,
timing
]);
with:
document.getElementById("content").animate(
keyframes,
timing
);
Here working code snippet: (updated with steps in JS)
<style>
body {
background: #808080;
}
.base {
width: 180px;
height: 90px;
background: black;
}
.sample {
animation: play 2s steps(8) infinite;
}
#keyframes play {
0% {
background-color: green;
opacity: 0;
}
100% {
background-color: blue;
opacity: 1;
}
}
</style>
<div class='base sample'></div> <br>
<div id="content" class="base"></div>
<script>
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
var timing = {
duration: 2000,
easing: 'steps(8)',
iterations: Infinity
}
document.getElementById("content").animate(
keyframes,
timing
);
</script>
Move the content.append(div) before the animate call. Also, remove the [] from the animate.
I forked your JSFiddle. Here is a working version. https://jsfiddle.net/jrgiant/c5z7x2bu/.
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
let timing = {
duration: 2000,
iterations: Infinity
}
content.append(div)
div.animate(
keyframes,
timing
);
//elements += html;
body {
background: #808080;
}
.base {
width: 180px;
height: 90px;
background: black;
}
.sample {
animation: play 2s steps(10) infinite;
}
#keyframes play {
0% {
background-color: green;
opacity: 0;
}
100% {
background-color: blue;
opacity: 1;
}
}
<div class='base sample'></div>
<div id="content"></div>
Your exact problem is that you are applying the animation before appending the div, and passing the keyframes argument as a list of lists instead of a list of objects (as you defined it):
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
content.append(div)
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
let timing = {
duration: 200,
iterations: Infinity
}
div.animate(
keyframes,
timing
);

Circular countdown JavaScript from 10 to Zero

I have been trying to reverse the countdown in this demo from 10 down to zero Without luck.
I have tried reversing the countdown by doing this:
(1*(initialOffset/time))-initialOffset )
It did reverse the animated circle but not the countdown.
Any ideas?
Thanks
var time = 10;
var initialOffset = '440';
var i = 1
/* Need initial run as interval hasn't yet occured... */
$('.circle_animation').css('stroke-dashoffset', initialOffset-(1*(initialOffset/time)));
var interval = setInterval(function() {
$('h2').text(i);
if (i == time) {
clearInterval(interval);
return;
}
$('.circle_animation').css('stroke-dashoffset', initialOffset-((i+1)*(initialOffset/time)));
i++;
}, 1000);
.item {
position: relative;
float: left;
}
.item h2 {
text-align:center;
position: absolute;
line-height: 125px;
width: 100%;
}
svg {
transform: rotate(-90deg);
}
.circle_animation {
stroke-dasharray: 440; /* this value is the pixel circumference of the circle */
stroke-dashoffset: 440;
transition: all 1s linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="item">
<h2>0</h2>
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<circle id="circle" class="circle_animation" r="69.85699" cy="81" cx="81" stroke-width="8" stroke="#6fdb6f" fill="none"/>
</svg>
</div>
Here is also a codepen copy:
https://codepen.io/kaolay/pen/LRVxKd
Try $('h2').text(time - i); instead of $('h2').text(i);
I also added $('h2').text(time); as the 4th line to draw 10 at the beginning
Also, the first part of the circle is not animated in your code, so I changed this line:
$('.circle_animation').css('stroke-dashoffset', initialOffset-(1*(initialOffset/time)));
To this block:
$('.circle_animation').css('stroke-dashoffset', initialOffset);
setTimeout(() => {
$('.circle_animation').css('stroke-dashoffset', initialOffset-(1*(initialOffset/time)));
})
var time = 10;
var initialOffset = '440';
var i = 1;
$('h2').text(time); // adding 10 at the beginning if needed
/* Need initial run as interval hasn't yet occured... */
$('.circle_animation').css('stroke-dashoffset', initialOffset);
setTimeout(() => {
$('.circle_animation').css('stroke-dashoffset', initialOffset-(1*(initialOffset/time)));
})
var interval = setInterval(function() {
$('h2').text(time - i); // here is the clue
if (i == time) {
clearInterval(interval);
return;
}
$('.circle_animation').css('stroke-dashoffset', initialOffset-((i+1)*(initialOffset/time)));
i++;
}, 1000);
.item {
position: relative;
float: left;
}
.item h2 {
text-align:center;
position: absolute;
line-height: 125px;
width: 100%;
}
svg {
transform: rotate(-90deg);
}
.circle_animation {
stroke-dasharray: 440; /* this value is the pixel circumference of the circle */
stroke-dashoffset: 440;
transition: all 1s linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="item">
<h2>0</h2>
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<circle id="circle" class="circle_animation" r="69.85699" cy="81" cx="81" stroke-width="8" stroke="#6fdb6f" fill="none"/>
</svg>
</div>
If you update this line $('h2').text(time - i); then you'll get the numeric countdown. I also initalize i = 0 so that the starting number is 10:
var time = 10;
var initialOffset = '440';
var i = 0
/* Need initial run as interval hasn't yet occured... */
$('.circle_animation').css('stroke-dashoffset', initialOffset-(1*(initialOffset/time)));
var interval = setInterval(function() {
$('h2').text(time - i);
if (i == time) {
clearInterval(interval);
return;
}
$('.circle_animation').css('stroke-dashoffset', initialOffset-((i+1)*(initialOffset/time)));
i++;
}, 1000);
.item {
position: relative;
float: left;
}
.item h2 {
text-align:center;
position: absolute;
line-height: 125px;
width: 100%;
}
svg {
transform: rotate(-90deg);
}
.circle_animation {
stroke-dasharray: 440; /* this value is the pixel circumference of the circle */
stroke-dashoffset: 440;
transition: all 1s linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="item">
<h2>0</h2>
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<circle id="circle" class="circle_animation" r="69.85699" cy="81" cx="81" stroke-width="8" stroke="#6fdb6f" fill="none"/>
</svg>
</div>
What exactly are you asking here?
"It did reverse the animated circle but not the countdown."
you are just trying to countdown?
why not set i = 10 and then do i--
If you want to invert the animation just invert all states of initial values and change i to (time-i). So it goes like this:
<div class="item">
<h2>10</h2>
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<circle id="circle" class="circle_animation" r="69.85699" cy="81" cx="81" stroke-width="8" stroke="#6fdb6f" fill="none"/>
</svg>
</div>
.item {
position: relative;
float: left;
}
.item h2 {
text-align:center;
position: absolute;
line-height: 125px;
width: 100%;
}
svg {
transform: rotate(-90deg);
}
.circle_animation {
stroke-dasharray: 440; /* this value is the pixel circumference of the circle */
stroke-dashoffset: 0;
transition: all 1s linear;
}
var time = 10;
var initialOffset = 440;
var i = 0
/* Need initial run as interval hasn't yet occured... */
$('.circle_animation').css('stroke-dashoffset', 0);
var interval = setInterval(function() {
$('h2').text(time-i);
if (i == time) {
clearInterval(interval);
return;
}
$('.circle_animation').css('stroke-dashoffset', initialOffset*i/time);
i++;
}, 1000);
Code pen:
https://codepen.io/anon/pen/Xybpge

Repeat a function infinite times

How can I repeat the animate function below infinite times? What is the best way to do it?
function animate(count) {
if (count == 0) {
$('.path').css({
'animation': 'draw2 4s'
});
}
if (count == 1) {
$('.path').css({
'animation': 'draw1 4s'
});
}
if (count == 2) {
$('.path').css({
'animation': 'draw3 4s'
});
}
if (count > 0) $('.path:first').one("animationend", function () {
animate(count - 1)
});
}
I think your function can be built in infinitely, Also use switch and cache of jQuery selection:
function animate(count) {
var path = $('.path');
while (true) {
switch (count) {
case 0 :
path.css({
'animation': 'draw2 4s'
});
break;
case 1:
path.css({
'animation': 'draw1 4s'
});
break;
case 2:
path.css({
'animation': 'draw3 4s'
});
break;
default:
path.first().one("animationend", function () {
animate(count - 1)
});
}
}
}
You can do it by using setInterval() function, you need to pass 2 parameters a function and time in Miliseconds to repeat that function,example:
var funcRepeat = animate("something");
var interval = setInterval(funcRepeat,1000);
//This will repeat your function once per second,
// with 500 as value will be twice per second, 250 > 4, etc
If you want to clear the interval, (thats why I stored it in a variable):
clearInterval(interval);
You could also make the funcion inside it:
var interval = setInterval(function(){
// code
},1000);
UPDATE
Looking at your comments, you could simply use recursivity with setTimeout() function:
$(document).ready(function () {
function animate() {
// launch the first animation
$('.path').css({'animation': 'draw2 4s' });
// wait 4s
setTimeout(function(){
// Launch the second animation
$('.path').css({'animation': 'draw1 4s'});
// wait another 4s
setTimeout(function(){
//launch the last one
$('.path').css({'animation': 'draw3 4s'});
// finnaly wait 4s for the last one to complete
// and start again the function using recursivity
setTimeout(animate(),4000);
},4000);
},4000);
}
animate();
});
background-color: #fff;
}
.crosshair {
cursor: crosshair;
}
.bg {
width: 40%;
margin-left: auto;
margin-right: auto;
}
.path {
animation-fill-mode: forwards;
animation-iteration-count: 3;
}
#keyframes draw1 {
0% {
stroke: green;
}
25% {
stroke: green;
}
50% {
stroke: green;
}
75% {
stroke: green;
}
100% {
stroke: green;
fill: none;
stroke-dashoffset: 100;
}
}
#keyframes draw2 {
0% {
stroke: red;
}
25% {
stroke: red;
}
50% {
stroke: red;
}
75% {
stroke: red;
}
100% {
stroke: red;
fill: none;
stroke-dashoffset: 100;
}
}
#keyframes draw3 {
0% {
stroke: blue;
}
25% {
stroke: blue;
}
50% {
stroke: blue;
}
75% {
stroke: blue;
}
100% {
stroke: blue;
fill: none;
stroke-dashoffset: 100;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="612px" height="792px" viewbox="0 0 612 792" enable-background="new 0 0 612 792"
xml:space="preserve">
<path class="path" fill="none" stroke-width="1" stroke-dasharray="550" stroke-dashoffset="550" d="M240,260c0,6.627-5.373,12-12,12h-76c-6.627,0-12-5.373-12-12v-76
c0-6.627,5.373-12,12-12h76c6.627,0,12,5.373,12,12V260z"/>
<path class="path" fill="none" stroke-width="1" stroke-dasharray="550" stroke-dashoffset="550" d="M271,296c0,6.627-5.373,12-12,12h-76c-6.627,0-12-5.373-12-12v-76
c0-6.627,5.373-12,12-12h76c6.627,0,12,5.373,12,12V296z"/>
<path class="path" fill="none" stroke-width="1" stroke-dasharray="550" stroke-dashoffset="550" d="M306,346c0,6.627-5.373,12-12,12h-76c-6.627,0-12-5.373-12-12v-76
c0-6.627,5.373-12,12-12h76c6.627,0,12,5.373,12,12V346z"/>
</svg>
I can do that with an else condition
$('.path:first').one("animationend", function () {
if (count > 0)
animate(count - 1)
else
animate(iterationcount - 1)
})
}

Categories