【问题标题】:CSS: Pause animation on timerCSS:定时器暂停动画
【发布时间】:2021-07-11 11:14:21
【问题描述】:

我正在实现一个计时器。

目标是用户可以启动计时器,当他觉得需要时,他可以暂停或继续计时器。

我遇到的困难是暂停 SVG 动画。

我关注了这个article,但是它不起作用。

有什么建议吗?

代码

(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>

代码

根据answer 的建议更改代码。

现在的问题是动画在中间变快,在开始和结束时变慢,所以它不会在“时钟”上打对点

(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>

【问题讨论】:

    标签: javascript html css svg css-animations


    【解决方案1】:

    我还没有测试过;只是挖掘旧知识。

    使用animation: fill 1s; 速记表示法
    你也在搞乱animation-play-state 设置。

    尝试使用所有单独的属性:https://developer.mozilla.org/en-US/docs/Web/CSS/animation

    和一个animation-play-state: running(或暂停)开始

    更新

    如果我将您的 CSS 更改为:

        xanimation: fill 1s;
        animation-name: fill;
        animation-duration:60s;
        animation-play-state:paused;
    

    您的切换开关有某事

    所以播放状态切换有效

    现在你必须让你的 CSS 和 SVG 做你想做的事

    【讨论】:

    • 感谢您的回答。我试着按照你说的做,但是没有用:/
    • 查看更新,我无法一键将您的代码复制到答案中
    • 是的,这就是我所做的,但它不起作用:/ 我有这个 codepen,如果你想看的话 - codepen.io/saomartinho/pen/oNYrbRe
    • 所以应用我所做的更改并从那里获取它。您正在混合 animationtransition 并为您的第一个“初始化”倒计时使用填充动画......把它拆开
    • 好的,成功了,你。但现在又出现了另一个问题。切换过渡到动画时长时,动画开始和结束时较慢,中间较快。这会导致点不能正确地击中“时钟”。我用您建议的更改更新了问题,因此您可以看到差异。
    猜你喜欢
    • 1970-01-01
    • 2016-03-28
    • 2013-11-25
    • 2015-03-17
    • 2012-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    相关资源
    最近更新 更多