I’m trying to fluidify a circle progress bar in a timer. The progress bar represents the progression in the duration of the timer. I made an svg <circle> circle element for the progress bar. Every 10th of second, I change the css attribute stroke-dashoffset of the circle. This works fine but if we choose less than 5 minutes for the time, the movements of the progress bar are not fluid. What can I do to make that fluid ?
class Timer {
constructor(circle, text) {
this.circle = circle
this.text = text
this.text.innerHTML
}
async start(hours, minutes, seconds) {
this.circle.style["stroke-dasharray"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width)
this.circle.style["stroke-dashoffset"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width)
await this.countdown()
this.circle.classList = "progress"
var remaining, interval, duration, end;
duration = parseInt(hours) * 3600000 + parseInt(minutes) * 60000 + (parseInt(seconds) + 1) * 1000
end = Date.now() + duration
interval = setInterval(async () => {
remaining = end - Date.now()
this.circle.style["stroke-dashoffset"] = remaining * parseInt(Math.PI * this.circle.getBoundingClientRect().width) / duration;
if (remaining < 0) {
this.circle.style["stroke-dashoffset"] = 0
clearInterval(interval)
window.location.href = "./"
return true
} else {
this.text.innerHTML = `${("0" + parseInt(remaining / 3600000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 / 60000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 % 60000 / 1000)).slice(-2)}`
}
}, 100)
}
countdown() {
var duration;
duration = 2
this.text.innerHTML = 3
return new Promise(resolve => {
setInterval(async () => {
if (duration <= 0) {
resolve(true)
} else {
this.text.innerHTML = duration
duration -= 1
}
}, 1000)
})
}
}
const timer = new Timer(document.getElementById("progress"), document.getElementById("text"))
const params = new URLSearchParams(window.location.search)
timer.start(0, 0, 10)
:root {
--pi: 3.141592653589793
}
circle.progress {
display: block;
position: absolute;
fill: none;
stroke: url(#circle.progress.color);
stroke-width: 4.5vmin;
stroke-linecap: round;
transform-origin: center;
transform: rotate(-90deg);
}
circle.progress.animation {
animation: circle 3s linear forwards;
}
.progress-container {
left: 50vw;
top: 50vh;
width: 90vmin;
height: 90vmin;
margin-top: -45vmin;
margin-left: -45vmin;
position: absolute;
padding: none;
}
.outer {
margin: none;
width: 100%;
height: 100%;
border-radius: 50%;
box-shadow: 6px 6px 10px -1px rgba(0, 0, 0, 0.15), -6px -6px 10px -1px rgba(255, 255, 255, 0.7);
padding: 2.5%;
}
.inner {
margin: 2.5%;
width: 95%;
height: 95%;
border-radius: 50%;
box-shadow: inset 4px 4px 6px -1px rgba(0, 0, 0, 0.15), inset -4px -4px 6px -1px rgba(255, 255, 255, 0.7);
}
svg {
display: block;
position: absolute;
left: 50vw;
top: 50vh;
width: 90.5vmin;
height: 90.5vmin;
margin-top: -45.25vmin;
margin-left: -45.25vmin;
}
svg text {
font-size: 10vmin;
font-family: 'Roboto', sans-serif;
}
#keyframes circle {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: calc(45.5vmin * var(--pi) * 2);
}
}
<link href="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.2.1/dist/css/materialize.min.css" rel="stylesheet"/>
<div class="progress-container">
<div class="outer center-align">
<div class="inner"></div>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" class="center" version="1.1">
<defs>
<linearGradient id="circle.progress.color">
<stop offset="0%" stop-color="BlueViolet" />
<stop offset="100%" stop-color="MediumVioletRed" />
</linearGradient>
</defs>
<circle id="progress" class="progress animation" cy="45.25vmin" cx="45.25vmin" r="42.75vmin" />
<text id="text" text-anchor="middle" x="50%" y="50%">Temps restant</text>
</svg>
<script src="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.2.1/dist/js/materialize.min.js"></script>
The code here runs the timer for 10 seconds. Normally, you would have to choose the time in another page. To have the time input, go to that page (the page is in french).
I'm not able to explain the issue, so here I have an alternative solution. The function setInterval has issues with the timing (maybe that is actually you issue...). You cannot expect it to be precise. Instead of controlling the progress using setInterval you can use a keyframe animation with the Web Animations API. This is a better alternative to the JavaScript animation where you update an attribute/style, and easier to work with then SVG SMIL animations.
So, I rely on the animation doing its job and then update the time displayed by asking for the currenttime on the animation object.
const progress = document.getElementById('progress');
const text = document.getElementById('text');
document.forms.form01.addEventListener('click', e => {
if(e.target.value){
var progressKeyframes = new KeyframeEffect(
progress,
[
{ strokeDasharray: '0 100' },
{ strokeDasharray: '100 100' }
],
{ duration: parseInt(e.target.value), fill: 'forwards' }
);
var a1 = new Animation(progressKeyframes, document.timeline);
a1.play();
let timer = setInterval(function(){
if(a1.playState == 'running'){
text.textContent = Math.floor(a1.currentTime/1000);
}else if(a1.playState == 'finished'){
text.textContent = Math.round(e.target.value/1000);
clearInterval(timer);
}
}, 100);
}
});
<form name="form01">
<input type="button" value="2000" />
<input type="button" value="5000" />
<input type="button" value="10000" />
</form>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="300">
<defs>
<linearGradient id="circle.progress.color">
<stop offset="0%" stop-color="BlueViolet" />
<stop offset="100%" stop-color="MediumVioletRed" />
</linearGradient>
<filter id="shadow">
<feDropShadow dx=".4" dy=".4" stdDeviation="1" flood-color="gray"/>
</filter>
</defs>
<circle r="40" stroke="white" stroke-width="8" fill="none" transform="translate(50 50)" filter="url(#shadow)"/>
<circle id="progress" r="40" stroke="url(#circle.progress.color)" stroke-width="8" fill="none" pathLength="100" stroke-dasharray="0 100" transform="translate(50 50) rotate(-90)" stroke-linecap="round"/>
<text id="text" dominant-baseline="middle" text-anchor="middle" x="50" y="50">0</text>
</svg>
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>
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
Looking for a resolution for this issue. I set up velocity on wordpress and seem to have run into a wall. When I reference velocity, I get Velocity not defined, and when I reference $.Velocity, I get $ not defined. Jquery 1.11.3 and Velocity are installed but the script that I am running on velocity does not call any Jquery items.
Any help would be much appreciated.
// Velocity.js instead of CSS for performance
var city = document.querySelector('.js-city-1');
var fulllogo = document.querySelector('.cityanimation');
var loading = [animatecity()];
function animatecity() {
// Reset
Velocity(city, {
'stroke-dasharray': 3542,
'stroke-dashoffset': 3542
}, 0);
// Animate
Velocity(city, {
'stroke-dashoffset': 0
}, {
duration: 20000,
complete: function() {
Velocity(city, {
opacity: 0
}, {
duration: 500
}), animatefulllogo();
}
,
});
}
function animatefulllogo() {
// Reset
Velocity(fulllogo, {
opacity: 1
}, 0);
// Animate
Velocity(fulllogo, {
opacity: 0
}, {
duration: 200,
complete: function() {;
}
});
};
Velocity.RunSequence(loading);
#loadscreen{
z-index: 9999;
width: 100%;
height: 100%;
overflow: hidden;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
position: fixed;
background-color: #FFF;
}
#loaderimage{
background-image: url(/wp-content/themes/silicon-city/images/SiliconCity.jpg);
background-position: 50% 50%;
background-repeat: no-repeat;
-webkit-background-size: 100%;
-ms-background-size: 100%;
background-size: 100%;
max-width:1035px;
min-width:360px;
position: fixed;
}
#Layer_1{
margin-top:8px;
}
.cityanimation {
background-color: #FFF;
top:50%;
left:50%;
width:75%;
max-width:1035px;
min-width:360px;
position: fixed;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%); /* IE 9 */
-webkit-transform: translate(-50%, -50%); /* Safari */
}
.st0{
fill:none;
stroke:#28B24B;
stroke-width:.15em;
stroke-linecap:round;
stroke-linejoin:round;
stroke-miterlimit:10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//cdn.jsdelivr.net/velocity/1.2.3/velocity.min.js"></script>
<div id="loadscreen">
<div id="loaderimage">
<div class="cityanimation">
<object>
<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"
viewBox="0 0 1035 393" style="enable-background:new 0 0 1035 393;" xml:space="preserve">
<path class="st0 js-city-1" d="M1.521,213.364h59.398l6.658-0.488v-57.018h15.737v-6.528l10.905-0.134v5.685h17.706l0.122,3.899h1.178h7.636
v23.01l6.009,0.057v-3.574h5.524v4.145h12.426l0.082-4.956h6.822v2.597h5.685V139.75h4.009v-8.015h1.649v-4.713h1.415v-4.716h1.18
v-6.363h1.649v6.363h0.942v4.244h1.887v5.422h11.551v3.065l13.673,13.674v28.289l16.138-0.351v-24.526h2.438v-7.961h32.489v25.018
h4.873v-23.396h13.646v12.35h19.492v18.191h3.574v11.35l16.245,0.027v-35.578h29.727v11.914h10.942l0.268-34.333h19.33v28.102h9.746
l1.625,37.933h8.937v-17.652l42.396-1.598V158.78h13.807l2.763-112.293h2.436v-3.899h5.684v-8.936h-1.136v-2.437h1.623V2.139
L453.054,1l0.49,0.976v29.239h1.786v2.437h-1.299v8.771h5.847v3.899h2.926l2.422,136.264h8.765l0.183-10.971h4.063v-2.762
c0,0,7.389-6.746,13.97,0l1.625-6.498l8.284-5.847l7.637,5.197l2.596,5.196h4.225v-8.932h18.844v23.555h9.096v15.568l23.398-0.359
v-24.518h5.463v-5.809h6.764v-25.592h24.609v36.268h27.301v-17.017h9.902v-7.386h9.695v3.806h16.051v3.136h13.098v3.806h3.158
v-14.778h4.408l1.732-19.33l2.691,19.371h3.584v18.543h4.215v5.15h10.146v14.332h7.527v-12.093h2.74V141.26h2.951v-5.151h12.334
v36.05h3.795v22.393h5.609v-17.914h8.773l2.316-0.006v24.859h14.514h2.529v-15.662h3.939v-13.444h3.775V88.216h2.713v-6.998h4.416
v-6.996h1.988c0.1-0.31,0.209-0.6,0.285-0.898c1.094-4.186,1.883-8.421,1.992-12.759c0.029-1.136,0.055-2.275-0.025-3.406
c-0.072-0.959,0.209-1.709,0.934-2.299c0.225-0.181,0.289-0.365,0.289-0.636c-0.008-4.522,0.037-9.042-0.027-13.56l0.049-0.999
c-0.016,4.854-0.006,9.711-0.014,14.57c0,0.299,0.035,0.49,0.367,0.642c0.652,0.3,1.113,0.844,1.24,1.553
c0.086,0.497,0,1.021,0.004,1.533c0.006,1.682-0.076,3.372,0.059,5.042c0.162,1.95,0.451,3.896,0.809,5.823
c0.336,1.814,0.828,3.597,1.25,5.394c0.055,0.239,0.174,0.334,0.436,0.324c0.541-0.024,1.086-0.007,1.674-0.007v7.019h4.143v6.982
h2.924v84.164h3.479v8.4h4.441l4.865,0.002v-16.695v-12.764h7.533v-3.808h13.012v-9.853h5.395v15.004h9.057v-18.136h17.057v10.075
h12.141v-4.702h4.238v4.477h5.395v-8.507h10.02v9.18h4.049v19.928h7.23v7.611h7.6v-17.018h1.732v-3.58h10.404v43.213h10.994v-86.428
h2.311v-3.357h2.699v-3.582h16.752v4.029h2.508v3.583h1.926v83.945h5.852l-0.031-56.667l0.678-5.362l-1.469-0.789l0.057-0.396h1.525
l0.111-16.925l0.336-1.243l1.297-0.395l0.287-3.723l0.732-1.581c-0.074-1.429-0.574-2.858,0.619-4.289
c0.26-1.902-0.264-4.195,1.355-5.417c0.27-2.018-0.154-4.479,1.639-5.528c0.332-1.789-0.354-3.573,1.07-5.36
c0.236-2.353,0.145-4.705,1.072-7.053l0.336-5.304l0.283-19.241l0.678,18.279l0.678,6.827c0.838,2.051,0.635,4.103,0.789,6.151
c1.395,1.619,0.92,3.236,0.902,4.855c2.518,1.938,1.785,4.069,1.92,6.149c1.561,0.804,1.262,3.283,1.41,5.36
c1.109,1.447,0.959,2.898,0.902,4.344c0.451,1.581,0.695,3.16,0.848,4.74l1.352,1.129l0.451,5.076l0.115,13.262l0.676,0.563
l0.678-0.506l0.395,0.111l-0.057,0.508l-1.354,0.677v5.643l0.508,0.339l0.557,50.658h8.58v-11.014h19.199l-0.006,0.919v34.813
l7.383,1.607l-14.375,0.805l14.375,2.41l-15.15,1.205l15.924,2.412l-14.76,1.607l6.604,1.205v57.908h-15.236h-8.654h-33.711"/>
</svg>
</object>
</div>
</div>
</div>
I also tried the following... thought it might be worth a shot..
jQuery.noConflict();
(function( $ ) {
$(function() {
// Velocity.min.js instead of CSS for performance
var $city = $(".js-city"),
$fulllogo = $(".cityanimation");
var loading = [animatecity()];
function animatecity() {
// Reset
$city
.velocity({
'stroke-dasharray': 3542,
'stroke-dashoffset': 3542
}, 0);
// Animate
$city
.velocity({
'stroke-dashoffset': 0
}, {
duration: 20000,
complete: function() {
$city
.velocity({
opacity: 0
}, {
duration: 500
}), animatefulllogo();
}
,
});
}
function animatefulllogo() {
// Reset
$fulllogo
.velocity({
opacity: 1
}, 0);
// Animate
$fulllogo
.velocity({
opacity: 0
}, {
duration: 200,
complete: function() {;
}
});
};
animatecity();
});
})(jQuery);
Okay... ended up with this.. but looks like Velocity.js doesn't load on window. I did confirm to see if Velocity.js was in the correct directory and it is. The animation still does not work but I am not getting any errors..
(function($) {
// Velocity.min.js instead of CSS for performance
var city = document.querySelector('.js-city');
var fulllogo = document.querySelector('.cityanimation');
function animatecity() {
// Reset
$.Velocity(city, {
'stroke-dasharray': 3542,
'stroke-dashoffset': 3542
}, 0);
// Animate
$.Velocity(city, {
'stroke-dashoffset': 0
}, {
duration: 20000,
complete: function() {
$.Velocity(city, {
opacity: 0
}, {
duration: 500
}), animatefulllogo();
}
,
});
}
function animatefulllogo() {
// Reset
$.Velocity(fulllogo, {
opacity: 1
}, 0);
// Animate
$.Velocity(fulllogo, {
opacity: 0
}, {
duration: 200,
complete: function() {;
}
});
};
animatecity();
})(jQuery);
You need to declare jquery before velocity in your markup scripts
You can see velocity dependence package depends on jquery 1.4 version or more, so it is being dependent on jquery for something.
The reason is that word press actually defines jQuery as jQuery not $. If you run this code:
jquery(document).ready(function () {
var $ = jQuery;
console.log('Now jquery is $', $);
});
So you should have source code jQuery and then asign to $ and finally source code of velocity.