Playmorph

by Felis Catus

HTML

<div class="button">
    <svg id="playpause" width="50" height="50" viewBox="0,0 50,50">
        <g id="morph">
            <path d="M 19.5,18 30,25 19.5,32 19.5,32 Z"/>
            <path d="M 19.5,18 22.5,25 22.5,25 19.5,32 Z"/>
        </g>
    </svg>
</div>
<div class="test">
</div>
<img src='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIgdmlld0JveD0iMCAwIDUwIDUwIj48dXNlIHhsaW5rOmhyZWY9IiNtb3JwaCIgeD0iMSIgeT0iMSIgLz48L3N2Zz4='>
    <svg xmlns="http://www.w3.org/2000/svg" height="50" width="50" viewBox="0 0 50 50"><use xlink:href="#morph" x="1" y="1" /></svg>

CSS

div.button>svg{
    position:absolute;
    top:0;
    left:0;
}
svg#playpause>g>path {
    stroke-linejoin:round;
    stroke-width:3;
    fill:white;
    stroke:white;
}
div.button{
    position:absolute;
    width:50px;
    height:50px;
}
div.test{
    position:absolute;
    width:50px;
    height:50px;
    left:100px;
    background:rgba(255,0,0,0.5);
}
div.button:before{
    display:block;
    position:absolute;
    background:rgba(0,0,0,.5);
    width:100%;
    height:100%;
    top:0;
    left:0;
    content:"";
    border-radius:5px;
}
div.test:before{
    display:block;
    position:absolute;
    width:100%;
    height:100%;
    top:0;
    left:0;
    content:"";
    border-radius:5px;
    background:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNTAiIHdpZHRoPSI1MCIgdmlld0JveD0iMCAwIDUwIDUwIj48dXNlIHhsaW5rOmhyZWY9IiNtb3JwaCIgeD0iMSIgeT0iMSIgLz48L3N2Zz4=') center no-repeat;
}
div.button>svg, div.button:before{
    transition:transform 50ms ease;
}
div.button:active>svg, div.button:active:before{
    transform:scale(0.9);   
}
img{
    left: 125px;
    position: absolute;
    top: 5px;
}
body{
    background:blue;
}
body>svg{
    position:absolute;
    top:50px;
}

JavaScript

(function setEvents(){
    function mkTransition(from,to,steps){
        return (function mkClosure(){
            var start=parseFloat(from);
            var delta=(parseFloat(to)-parseFloat(from))/parseFloat(steps);
            return (function doStep(){
                return start+=delta;
            });
        }());            
    }
    function mkTransform(fromPath,toPath,steps){//return path gen
        var path1pts=fromPath.split(' ').slice(1,-1);//remove MZ
        var path2pts=toPath.split(' ').slice(1,-1);
        return (function mkClosure(){
            var pathgen=path1pts.map(
                function projectFromTo(coord,index){
                    return coord.split(',').map(function(fld,idx){
                        return mkTransition(fld,path2pts[index].split(',')[idx],steps)
                    })
                });
            return (function mkPath(){
                return pathgen.reduce(function c2p(prev,curr){
                    return prev+' '+curr.reduce(function f2c(prv,crr){
                        return prv()+','+crr();
                    });
                },'M')+' Z';
            });
        }());
    }
    var playing=0;
    var intv=0;
    var stepcnt=0,stepcnt1=0,stagger=3,steptotal=5;
    var play1="M 19.5,18 30,25 19.5,32 19.5,32 Z";
    var play2="M 19.5,18 22.5,18 22.5,32 19.5,32 Z";
    var pause1="M 19.5,18 22.5,25 22.5,25 19.5,32 Z";
    var pause2="M 27.5,18 30.5,18 30.5,32 27.5,32 Z";
    var bars=document.querySelectorAll("#playpause>g>path");
    document.getElementsByClassName("button")[0].onclick=function(){
        playing=1-playing;
        if(intv)clearInterval(intv);
        stepcnt=0;
        if(playing){     
            var mkPath1=mkTransform(play1,play2,steptotal);
            var mkPath2=mkTransform(pause1,pause2,steptotal);
            intv=setInterval(function toPause(){
                if(stepcnt<steptotal)
                  bars[0].setAttribute("d",mkPath1());
               ...