"Hearthstone Card CSS 3D Click/Drag"
Bootstrap 3.0.0 Snippet by harunpehlivan

<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <!------ Include the above in your HEAD tag ----------> <div class="card"> <img src="http://images.ticiz.com/1992285_w640_h640_original23574925460.jpg" class="card-image" draggable="false"> </div>
html, body { height: 100%; } body { background: #000; cursor: url(https://tebm.files.wordpress.com/2010/02/arge-proje-egitim-esnasc4b1nda-hallerim-1.jpg?w=1000&h=) 10 2, auto; overflow: hidden; &:active { cursor: url(https://tebm.files.wordpress.com/2010/02/arge-proje-egitim-esnasc4b1nda-hallerim-1.jpg?w=1000&h=) 10 2, auto; } &:after { background-color: #000; background-image: url(https://tebm.files.wordpress.com/2010/02/arge-proje-egitim-esnasc4b1nda-hallerim-1.jpg?w=1000&h=); background-position: center center; background-repeat: no-repeat; background-size: cover; bottom: 0; content: ''; filter: blur( 8px ); left: 0; opacity: 0.8; position: absolute; right: 0; top: 0; will-change: transform; z-index: -1; } } .card { left: 0; top: 0; perspective: 400px; position: absolute; transform-style: preserve-3d; will-change: transform; width: 250px; user-drag: none; user-select: none; -moz-user-select: none; -webkit-user-drag: none; -webkit-user-select: none; -ms-user-select: none; &:active { cursor: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/836/hearthstone-grab.png) 10 2, auto; } } .card-image { display: block; pointer-events: none; transform-style: preserve-3d; width: 100%; will-change: transform; user-drag: none; user-select: none; -moz-user-select: none; -webkit-user-drag: none; -webkit-user-select: none; -ms-user-select: none; }
var card, image, cardw, cardh, cardx, cardy, ocardx, ocardy, pinx, piny, pinxperc, pinyperc, targetx, targety, rx, ry, targetrx, targetry, scale, targetscale, ww, wh, md, mx, my, whoosh, whooshvol, whooshvoltarget, majesty, majestyvol, majestyvoltarget, audioloaded; function audioload() { audioloaded++; if( audioloaded == 2 ) { document.body.classList.add( 'loaded' ); majesty.play(); whoosh.play(); bindevents(); loop(); } } function init() { onresize(); card = document.querySelector( '.card' ); image = document.querySelector( '.card-image' ); cardw = image.width; cardh = image.height; cardx = ww / 2 - cardw / 2; cardy = wh / 2 - cardh / 2; ocardx = cardx; ocardy = cardy; pinx = 0; piny = 0; pinxperc = 0; pinyperc = 0; targetx = cardx; targety = cardy; rx = 0; ry = 0; targetrx = 0; targetry = 0; scale = 1; targetscale = scale; md = false; mx = cardx; my = cardy; audioloaded = 0; whooshvol = 0; whooshvoltarget = 0; whoosh = new Audio(); whoosh.addEventListener( 'canplaythrough', audioload ); whoosh.src = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/836/hs-whoosh.ogg'; whoosh.volume = 0; whoosh.loop = true; majestyvol = 0; majestyvoltarget = 0; majesty = new Audio(); majesty.addEventListener( 'canplaythrough', audioload ); majesty.src = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/836/hs-majesty.ogg'; majesty.volume = 0; majesty.loop = true; } function bindevents() { card.addEventListener( 'mousedown', onmousedown ); window.addEventListener( 'mouseup', onmouseup ); window.addEventListener( 'mousemove', onmousemove ); window.addEventListener( 'resize', onresize ); } function onmousedown( e ) { md = true; mx = e.pageX; my = e.pageY; pinx = cardw / 2; // pin to center piny = cardh / 2; // pin to center //pinx = mx - cardx; // pin to click point //piny = my - cardy; // pin to click point pinxperc = 100 - ( pinx / cardw ) * 100; // transform based on the pin position pinyperc = 100 - ( piny / cardh ) * 100; // transform based on the pin position } function onmouseup() { md = false; } function onmousemove( e ) { if( md ) { mx = e.pageX; my = e.pageY; } } function onresize() { ww = window.innerWidth; wh = window.innerHeight; } function loop() { requestAnimationFrame( loop ) // set new target position targetx = mx - cardx - pinx; targety = my - cardy - piny; // lerp to new position cardx += targetx * 0.25; cardy += targety * 0.25; // contain card to window bounds if( cardx < -cardw / 2 ) { cardx = -cardw / 2; } if( cardx > ww - cardw / 2 ) { cardx = ww - cardw / 2; } if( cardy < -cardh / 2 ) { cardy = -cardh / 2; } if( cardy > wh - cardh / 2 ) { cardy = wh - cardh / 2; } // get rotation based on how much card moved targetrx = ( ocardy - cardy - rx ) * 3; targetry = ( cardx - ocardx - ry ) * 3; // lock rotation so things don't get too crazy targetrx = Math.min( targetrx, 90 ); targetrx = Math.max( targetrx, -90 ); targetry = Math.min( targetry, 90 ); targetry = Math.max( targetry, -90 ); // lerp to new rotation rx += targetrx * 0.1; ry += targetry * 0.1; // scale up when the mouse is pressed targetscale = md ? 1.2 - scale : 1 - scale; scale += targetscale * 0.2; // apply the transform card.style[ 'transform' ] = 'translate3d(' + cardx + 'px, ' + cardy + 'px, 0)'; image.style[ 'transform-origin' ] = pinxperc + '% ' + pinyperc + '%'; image.style[ 'transform' ] = 'scale(' + scale + ') rotateY(' + ry + 'deg) rotateX(' + rx + 'deg)'; majestyvoltarget = md ? 0.2 : 0; majestyvol += ( majestyvoltarget - majestyvol ) * 0.1; majesty.volume = majestyvol; whooshvoltarget = ( Math.abs( ( ocardy - cardy ) ) + Math.abs( ( ocardx - cardx ) ) ) * 0.003; whooshvol += ( whooshvoltarget - whooshvol ) * 0.1; whoosh.volume = Math.min( whooshvol, 1 ); // store the old card position ocardx = cardx; ocardy = cardy; } // pull up a chair by the hearth! window.onload = init;

Related: See More


Questions / Comments: