I am implementing a time counter.
The objective is that user can start the timer, and when he feels like it, he can pause or continue the timer.
The difficulty I encountered was pausing the SVG animation.
I followed this article, however it does not work.
Any suggestions?
CODE
(function() {
const start = document.querySelector( '.start' ),
togglePause = document.querySelector( '.pause' ),
seconds = 60;
function format( seconds ) {
var sec = Math.floor( seconds % 60 ),
min = Math.floor( seconds / 60 );
secdisp = sec;
mindisp = min;
if( min === 0 && sec === 0 ) {
clearInterval( countdown );
} else if ( secdisp === 0 ) {
min--;
sec = 0;
}
return mindisp + ':' + ( secdisp < 10 ? '0' + secdisp : secdisp );
}
function tickdown( seconds ) {
var mod = Math.floor( seconds % 60 ),
min = Math.floor( seconds / 60 ) - ( mod === 0 ? 1 : 0 ),
sec = ( mod ? 60 - mod : 0 );
var tick = () => {
seconds--;
document.getElementById('time').innerHTML = format( seconds );
};
tick();
countdown = setInterval( tick, 1000 );
}
document.getElementById('time').innerHTML = format( seconds );
start.addEventListener('click', () => {
var gauge = document.querySelector( '.timer-gauge' ),
frame = document.querySelector( 'html' );
tickdown( seconds );
gauge.style.transitionDuration = seconds + 's';
gauge.classList.add('ticking');
});
togglePause.addEventListener( 'click', () => {
var gauge = document.querySelector( '.timer-gauge' );
const running = gauge.style.animationPlayState === 'running';
gauge.style.animationPlayState = running ? 'paused' : 'running';
});
}());
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html {
background: linear-gradient(125deg, #5967c3 0%,#76b8d6 100%);
height: 100vh;
width: 100vw;
max-height: 100vh;
max-width: 100vw;
}
html:after {
content: " ";
position: absolute;
height: 100%;
left: 0;
top: 0;
opacity: 0;
transition: opacity .1s linear;
width: 100%;
z-index: 1;
pointer-events: none;
}
html.started:after {
background: linear-gradient(125deg, #52b670 0%,#84c86d 100%);
opacity: 1;
}
body {
margin: 0;
}
svg {
position: absolute;
width: 100%;
height: 100%;
padding: 2%;
pointer-events: none;
z-index: 2;
}
.main {
max-width: 100%;
}
.chart-gauge {
font-size: 1.5rem;
text-anchor: middle;
dominant-baseline: central;
alignment-baseline: middle;
stroke-linecap: round;
}
.timer-time {
fill: rgba(255,255,255,.6);
}
.timer-backdrop {
transform: rotate(-90deg);
transform-origin: center;
fill: none;
stroke: rgba(255,255,255,.2);
stroke-width: 5;
}
.timer-gauge {
transform: rotate(-270deg) scaleX(-1);
transform-origin: center;
fill: none;
stroke: rgba(255,255,255,.75);
stroke-width: 5;
animation: fill 1s;
animation-iteration-count: 1;
stroke-dashoffset: 0;
}
.ticking {
stroke-dashoffset: 360;
transition-timing-function: linear;
}
@keyframes fill {
0% { stroke-dashoffset: 360; }
100% { stroke-dashoffset: 0; }
}
<div class="main">
<svg viewBox="0 0 120 120" class="chart-gauge" fill="none" stroke-width="2">
<circle class="timer-backdrop" stroke-dasharray="360" r="57.32" cx="60" cy="60"></circle>
<circle class="timer-gauge" stroke-dasharray="360" r="57.32" cx="60" cy="60"></circle>
<text y="50%" x="50%" id="time" class="timer-time">1:00</text>
</svg>
<button class="start">Start</button>
</div>
<button class="pause">Toggle Pause</button>
CODE
Code change with the suggestion of this answer.
The problem now is that the animation got faster in the middle and slower at the beginning and at the end, so it will not hit the right spots on the "clock"
(function() {
const start = document.querySelector( '.start' ),
togglePause = document.querySelector( '.pause' ),
seconds = 60;
function format( seconds ) {
var sec = Math.floor( seconds % 60 ),
min = Math.floor( seconds / 60 );
secdisp = sec;
mindisp = min;
if( min === 0 && sec === 0 ) {
clearInterval( countdown );
} else if ( secdisp === 0 ) {
min--;
sec = 0;
}
return mindisp + ':' + ( secdisp < 10 ? '0' + secdisp : secdisp );
}
function tickdown( seconds ) {
var mod = Math.floor( seconds % 60 ),
min = Math.floor( seconds / 60 ) - ( mod === 0 ? 1 : 0 ),
sec = ( mod ? 60 - mod : 0 );
var tick = () => {
seconds--;
document.getElementById('time').innerHTML = format( seconds );
};
tick();
countdown = setInterval( tick, 1000 );
}
document.getElementById('time').innerHTML = format( seconds );
start.addEventListener('click', () => {
var gauge = document.querySelector( '.timer-gauge' ),
frame = document.querySelector( 'html' );
tickdown( seconds );
gauge.style.animationDuration = seconds + 's';
gauge.classList.add('ticking');
});
togglePause.addEventListener( 'click', () => {
var gauge = document.querySelector( '.timer-gauge' );
const running = gauge.style.animationPlayState === 'running';
gauge.style.animationPlayState = running ? 'paused' : 'running';
});
}());
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html {
background: linear-gradient(125deg, #5967c3 0%,#76b8d6 100%);
height: 100vh;
width: 100vw;
max-height: 100vh;
max-width: 100vw;
}
html:after {
content: " ";
position: absolute;
height: 100%;
left: 0;
top: 0;
opacity: 0;
transition: opacity .1s linear;
width: 100%;
z-index: 1;
pointer-events: none;
}
html.started:after {
background: linear-gradient(125deg, #52b670 0%,#84c86d 100%);
opacity: 1;
}
body {
margin: 0;
}
svg {
position: absolute;
width: 100%;
height: 100%;
padding: 2%;
pointer-events: none;
z-index: 2;
}
.main {
max-width: 100%;
}
.chart-gauge {
font-size: 1.5rem;
text-anchor: middle;
dominant-baseline: central;
alignment-baseline: middle;
stroke-linecap: round;
}
.timer-time {
fill: rgba(255,255,255,.6);
}
.timer-backdrop {
transform: rotate(-90deg);
transform-origin: center;
fill: none;
stroke: rgba(255,255,255,.2);
stroke-width: 5;
}
.timer-gauge {
transform: rotate(-270deg) scaleX(-1);
transform-origin: center;
fill: none;
stroke: rgba(255,255,255,.75);
stroke-width: 5;
animation-name: initial-fill;
animation-duration: 1s;
animation-iteration-count: 1;
stroke-dashoffset: 0;
}
.ticking {
animation-name: fill;
stroke-dashoffset: 360;
transition-timing-function: linear;
}
@keyframes initial-fill {
0% { stroke-dashoffset: 360; }
100% { stroke-dashoffset: 0; }
}
@keyframes fill {
0% { stroke-dashoffset: 0; }
100% { stroke-dashoffset: 360; }
}
<div class="main">
<svg viewBox="0 0 120 120" class="chart-gauge" fill="none" stroke-width="2">
<circle class="timer-backdrop" stroke-dasharray="360" r="57.32" cx="60" cy="60"></circle>
<circle class="timer-gauge" stroke-dasharray="360" r="57.32" cx="60" cy="60"></circle>
<text y="50%" x="50%" id="time" class="timer-time">1:00</text>
</svg>
<button class="start">Start</button>
</div>
<button class="pause">Toggle Pause</button>
</div>