JSFiddle - React, Tailwind, and code Playground

by Felis Catus

HTML

Click padlock to unlock/relock!
<div class="container">
    <div class="spinner">
        <svg width="100%" height="100%" viewBox="-1 -1 202 202">
            <!--circle id="spinarch" cx="100" cy="100" r="99" style="stroke:red; fill:none; stroke-width:2"/-->
            <path id="spinarch" d="M 1,100" style="fill:none"/>
        </svg>
    </div>
    <div class="lockback">
        <div class="padlock">
            <div class="shackle">
                <div class="inside"></div>
            </div>
            <div class="lock">
            </div>
            <div class="patch">
            </div>
        </div>
    </div>
</div>

CSS

/*colors*/
#spinarch{
    stroke:#3fb1e5; 
    stroke-width:2; 
}
.container{
    background:transparent;
}
.lockback, .shackle>.inside, .patch{
    background:#3fb1e5;
}

.lock{
   border-color:#3fb1e5;
}
.shackle, .lock{
    background:white;
}
/*for example only. container has to be square.*/
body{
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),url("http://www.traipse.com/penrose_tiles/penrose_tiles.gif");
}
.container{
    width:100px;
    height:100px;
    margin:100px 100px;
}

/*structure - don't touch*/
.container{
    position:relative;
    overflow:hidden;
}
.spinner{
    position:absolute;
    background:inherit;
    width:100%;
    height:100%;
    margin:50% 0 0 50%;
    top:-50%;
    left:-50%;
    transform:rotate(0deg);
    -webkit-transform:rotate(0deg);
    border-radius:50%;
}

.lockback{
    position:absolute;
    width:88%;
    height:88%;
    margin:50% 0 0 50%;
    top:-44%;
    left:-44%;
    border-radius:50%;
    overflow:hidden;
    transition:transform 250ms linear;
    -webkit-transition:-webkit-transform 250ms linear;
}
.padlock{
    position:absolute;
    width:36%;
    height:56%;
    margin:50% 0 0 50%;
    top:-28%;
    left:-18%;
}
.shackle{
    border-radius:50% 50% 0% 0%/50% 50% 0% 0%;
    width:76%;
    height:45%;
    left:12%;
    position:relative;
    transform-origin:4% 0;
    -webkit-transform-origin:4% 0;
    transition:transform 250ms linear;
    -webkit-transition:-webkit-transform 500ms linear;
    
}
.lock{
    border-radius:12%/20%;
    width:100%;
    height:45%;
    position:relative;
    border-width:2px;
    border-style:solid;
    left:-2px;
}
.shackle>.inside{
    width:80%;
    height:92%;
    top:10%;
    left:10%;
    position:absolute;
    border-radius:50% 50% 0% 0%/50% 50% 0% 0%;
}
.patch{
    width:90%;
    height:17%;
    position:absolute;
    top:30%;
    left:-81%;
}

JavaScript

(function setEvents(){
    var clicked=0;
    var intId=0;
    var int2Id=0;
    var aperture=0;
    var angle=0;
    var dAperture=10;
    var transformFunc=((/^((?!chrome).)*safari/i.test(navigator.userAgent))?"-webkit-transform":"transform");
    var shackle=document.getElementsByClassName("shackle")[0];
    var arc=document.getElementById("spinarch");
    var spinner=document.getElementsByClassName("spinner")[0];
    
    function setAperture(ang){
        ang%=360;
        var ex=100+Math.round(100*Math.cos(6.28318531*ang/360.0));
        var ey=100+Math.round(100*Math.sin(6.28318531*ang/360.0));
        if(ang<=90){
            arc.setAttribute("d","M 200,100 A 100,100 0 0,1 "+ex+","+ey);
        }else if(ang<=180){
            arc.setAttribute("d","M 200,100 A 100,100 0 0,1 100,200 A 100,100 0 0,1 "+ex+","+ey);
        }else if(ang<=270){
            arc.setAttribute("d","M 200,100 A 100,100 0 0,1 100,200 A 100,100 0 0,1 0,100 A 100,100 0 0,1 "+ex+","+ey);
        }else{
            arc.setAttribute("d","M 200,100 A 100,100 0 0,1 100,200 A 100,100 0 0,1 0,100 A 100,100 0 0,1 100,0 A 100,100 0 0,1 "+ex+","+ey);
        }
    }
document.getElementsByClassName("lockback")[0].onclick=function padlockClick(evt){
    if(clicked){
        clicked=0;
        shackle.style[transformFunc]="";
        clearInterval(intId);
        setAperture(0);
        clearInterval(int2Id);
    }else{
        clicked=1;
        shackle.style[transformFunc]="rotateY(180deg)";
        intId=setInterval(function(){
            if(aperture<=0){
                aperture=0;
                dAperture=-dAperture;
            }else if(aperture>300){
                dAperture=-dAperture;
            }
            setAperture(aperture);
            aperture=(aperture+dAperture)%360;
        },50);
        int2Id=setInterval(function(){
            spinner.style[transformFunc]="rotate("+angle+"deg)";
            angle=(angle+20)%360;
        },50);
    }
}
}());