简体   繁体   中英

SVG animate path attribute “d” on hover with velocity or snap.svg

First, I'm a complete beginner with svg's and I can't find a good answer to solve my problem on Google. What I've been trying to do, is simply animating an svg path on hover.

I've downloaded and used snap.svg and velocity.js, so if you know an answer using one of this or maybe booth feel free.

My current code and what I tried with velocity:

<div class="g50">
    <svg class="curtain" viewBox="0 0 180 320" preserveAspectRatio="none">
        <path d="M 180,160 0,200 0,0 180,0 z"/>
    </svg>
</div>

<div class="g50">
    <svg class="curtain" viewBox="0 0 180 320" preserveAspectRatio="none">
        <path d="M 180,200 0,160 0,0 180,0 z"/>
    </svg>
</div>

JS:

$('.curtain').on('mouseenter', function(){
    $(this).find('path').velocity({ 'd': "m 180,34.57627 -180,0 L 0,0 180,0 z" });
});

JS Fiddle Demo:

HERE

There are two solutions for this. The first is pretty straightforward, but it will produce unwanted effects if a user quickly enters and exits the SVG element. Essentially, the animation will looping for far too long; however, it works just fine if the user is casually hovering over the element.

Here's a demo with that solution .

The other solution is more robust and accounts for unusually rapid 'hover toggling' from the user. If the user rapidly hovers in and out of the element, this solution just stops and reverses the animation. This is what I use on any hover states with velocity.

You can view that solution here .

Here's the javascript code using JQuery

...

var svg = $('.curtain');
var path = svg.find('path'); // define svg path
path.data({animating:false}); // add data for animation queue purposes

path.hover(function() { // mouse enter

/*
if the path is in the middle of an animation, stop it immediately and reverse the animation. This prevents many unwanted animations if the user hovers in and out quickly
*/

if (path.data('animating') === true){
path.velocity("stop", true).velocity('reverse',{ duration:300});
path.data({animating:false});

} else {  // begin default animation
$(this).velocity({fill: '#ffcc00'},{
  duration:500,
  begin: function(){
    path.data({animating:true});
  },
  complete: function(){
    path.data({animating:false});
  }
});

} // end of conditional statement
}, function() { // mouse exit

/*
if the path is in the middle of an animation, stop it immediately and reverse the animation. This prevents many unwanted animations if the user hovers in and out quickly
*/

if (path.data('animating') === true){
path.velocity("stop", true).velocity('reverse',{ duration:300});
path.data({animating:false});


} else { // begin default animation

$(this).velocity({fill: '#000'},{
  duration:500,
  begin: function(){
    path.data({animating:true});
  },
  complete: function(){
    path.data({animating:false});
  }
});

} // end of conditional statement
}); // end of hover function

...

If you want to animate the path dimensions, I would suggest using Snap.svg. Here's a simple example using snap.svg to animate the paths.

HTML

<!--add hover state data to div-->  
  <div class="g50" data-path-hover="m 180,34.57627 -180,0 L 0,0 180,0 z">
    <svg viewBox="0 0 180 320" preserveAspectRatio="none"><path d="M 180,160 0,218 0,0 180,0 z"/></svg>
</div>

 <!--add hover state data to div-->
<div class="g50" data-path-hover="m 180,34.57627 -180,0 L 0,0 180,0 z">
    <svg viewBox="0 0 180 320" preserveAspectRatio="none"><path d="M 180,160 0,218 0,0 180,0 z"/></svg>
</div>

JS

(function() {

    function init() {
        var speed = 250,
            easing = mina.easeinout;

        [].slice.call ( document.querySelectorAll( '.g50' ) ).forEach( function( el ) {
            var s = Snap( el.querySelector( 'svg' ) ),
            path = s.select( 'path' ),
                pathConfig = {
                    from : path.attr( 'd' ),
                    to : el.getAttribute( 'data-path-hover' )
                };

            el.addEventListener( 'mouseenter', function() {
                path.animate( { 'path' : pathConfig.to }, speed, easing );
        console.log(pathConfig.to);
            } );

            el.addEventListener( 'mouseleave', function() {
                path.animate( { 'path' : pathConfig.from }, speed, easing );
            } );
        } );
    }

    init();

})();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM