最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Detect CSS Animation Keyframes with Javascript - Stack Overflow

programmeradmin2浏览0评论

So I have a simple CSS animation (a circle that grows, and then shrinks back down). I am able to successfully use Javascript to detect the start and end of the animation, but can't figure out how to detect the individual keyframes of that animation.

So my question is: how can I detect when the 50% keyframe has been reached in my animation?

Demo:

HTML

<div class="center">
    <svg class="center circle-animation" xmlns="/">
        <g>
            <circle cx="65" cy="70" r=60 fill="#96CCFF" stroke-width="3" stroke="#8181F7"></circle>
            <text x="35" y="75" font-size="18" class="output">circle</text>
        </g>
    </svg>
</div>

CSS

svg { width:150px;}

text {color:#000; font-family: sans-serif; font-weight: bold;}

.center{
    margin-top:100px;
    text-align:center;
    padding-bottom:50px;
}  

.circle-animation{
    animation-delay:2s;
    animation-duration: 4s;
    animation-name: circle-animation;
    animation-direction: normal;
    animation-timing-function: linear;
}

@-webkit-keyframes circle-animation {
    0% {transform: scale( 1 );}
    50% {transform: scale( 2.25 );}
    100% {transform: scale( 1 );}
}

JS

window.onload = function() {
    var elm = document.querySelector('.circle-animation');
    var op = document.querySelector('.output');

    elm.addEventListener('animationend', function(e) {
        op.innerHTML = 'ended';
    });

    elm.addEventListener('animationstart', function(e) {
        op.innerHTML = 'started';
    });
}

So I have a simple CSS animation (a circle that grows, and then shrinks back down). I am able to successfully use Javascript to detect the start and end of the animation, but can't figure out how to detect the individual keyframes of that animation.

So my question is: how can I detect when the 50% keyframe has been reached in my animation?

Demo: http://codepen.io/tymichaels/pen/Mprrxw

HTML

<div class="center">
    <svg class="center circle-animation" xmlns="https://www.w3/TR/SVG/">
        <g>
            <circle cx="65" cy="70" r=60 fill="#96CCFF" stroke-width="3" stroke="#8181F7"></circle>
            <text x="35" y="75" font-size="18" class="output">circle</text>
        </g>
    </svg>
</div>

CSS

svg { width:150px;}

text {color:#000; font-family: sans-serif; font-weight: bold;}

.center{
    margin-top:100px;
    text-align:center;
    padding-bottom:50px;
}  

.circle-animation{
    animation-delay:2s;
    animation-duration: 4s;
    animation-name: circle-animation;
    animation-direction: normal;
    animation-timing-function: linear;
}

@-webkit-keyframes circle-animation {
    0% {transform: scale( 1 );}
    50% {transform: scale( 2.25 );}
    100% {transform: scale( 1 );}
}

JS

window.onload = function() {
    var elm = document.querySelector('.circle-animation');
    var op = document.querySelector('.output');

    elm.addEventListener('animationend', function(e) {
        op.innerHTML = 'ended';
    });

    elm.addEventListener('animationstart', function(e) {
        op.innerHTML = 'started';
    });
}
Share asked Mar 18, 2017 at 23:44 Ty RoderickTy Roderick 512 silver badges3 bronze badges 1
  • Possible duplicate: stackoverflow./questions/38653207/… – Waxi Commented Mar 18, 2017 at 23:48
Add a ment  | 

2 Answers 2

Reset to default 4

You can dispatch a custom event on animationstart with setInterval and clear the interval on animationend.

window.onload = function() {
    var elm = document.querySelector('.circle-animation');
    var op = document.querySelector('.output');
    var eventOnAnimate = new Event('onanimate');
    var time = 0;

    elm.addEventListener('animationend', function(e) {
        op.innerHTML = 'ended';
        clearInterval(elm.interval);
        time = 0;
    });

    elm.addEventListener('animationstart', function(e) {
        op.innerHTML = 'started';
        time = 0;
        elm.interval = setInterval(function(){
          eventOnAnimate.data = {sampleData: ++time};
          elm.dispatchEvent(eventOnAnimate);
        });
    });
    
    elm.addEventListener('onanimate', function(e) {
        op.innerHTML = e.data.sampleData + 'ms';
    });
}
svg { width:150px;}

text {color:#000; font-family: sans-serif; font-weight: bold;}

.center{
    margin-top:30px;
    text-align:center;
    padding-bottom:50px;
}  

.circle-animation{
    animation-delay:2s;
    animation-duration: 4s;
    animation-name: circle-animation;
    animation-direction: normal;
    animation-timing-function: linear;
}

@-webkit-keyframes circle-animation {
    0% {transform: scale( 1 );}
    50% {transform: scale( 2.25 );}
    100% {transform: scale( 1 );}
}
<div class="center">
    <svg class="center circle-animation" xmlns="https://www.w3/TR/SVG/">
        <g>
            <circle cx="65" cy="70" r=60 fill="#96CCFF" stroke-width="3" stroke="#8181F7"></circle>
            <text x="35" y="75" font-size="18" class="output">circle</text>
        </g>
    </svg>
</div>

There is no native event support for listening keyframe-by-keyframe, but you can create a workaround with setTimeout and window.getComputedStyle (to get the animation-duration property).

Below is an onKeyframes utility which can be used to listen for an arbitrary number of keyframe events using a more intuitive percentage-based syntax:

onKeyframes(elm, {
  0: function() {
    op.textContent = 'started'
  },
  50: function() {
    op.textContent = 'midpoint'
  },
  100: function() {
    op.textContent = 'ended'
  }
})


Demo Snippet:

function onKeyframes(element, handlers) {
  var from = handlers[0] || handlers.from
  var to = handlers[100] || handlers.to
  delete handlers.from
  delete handlers[0]
  delete handlers.to
  delete handlers[100]

  handlers = Object.keys(handlers).map(function(k) {
    return [k, this[k]]
  }, handlers)

  element.addEventListener('animationstart', function() {
    from && from.apply(this, arguments)
    if (handlers.length) {
      var match = /(\d+)(m?)s/.exec(window.getComputedStyle(element).animationDuration)
      var duration = (match[2] ? 1 : 1e3) * match[1]
      handlers.forEach(function(pair) {
        setTimeout(pair[1], pair[0] / 100 * duration)
      })
    }
  })
  to && element.addEventListener('animationend', to)
}

window.onload = function() {
  var elm = document.querySelector('.circle-animation')
  var op = document.querySelector('.output')

  onKeyframes(elm, {
    0: function() {
      op.textContent = 'started'
    },
    50: function() {
      op.textContent = 'midpoint'
    },
    100: function() {
      op.textContent = 'ended'
    }
  })
}
svg {
  width: 150px;
}

text {
  color: #000;
  font-family: sans-serif;
  font-weight: bold;
}

.center {
  margin-top: 100px;
  text-align: center;
  padding-bottom: 50px;
}

.circle-animation {
  animation-delay: 2s;
  animation-duration: 4s;
  animation-name: circle-animation;
  animation-direction: normal;
  animation-timing-function: linear;
}

@-webkit-keyframes circle-animation {
  0% {
    transform: scale( 1);
  }
  50% {
    transform: scale( 2.25);
  }
  100% {
    transform: scale( 1);
  }
}
<div class="center">
  <svg class="center circle-animation" xmlns="https://www.w3/TR/SVG/">
        <g>
            <circle cx="65" cy="70" r=60 fill="#96CCFF" stroke-width="3" stroke="#8181F7"></circle>
            <text x="35" y="75" font-size="18" class="output">circle</text>
        </g>
    </svg>
</div>

发布评论

评论列表(0)

  1. 暂无评论