LOADING...

Preview

Pen ID
Unlock Campus Themeforest adv

 

Code
CSS
html,
body {
  height: 100%;
}

body {
  background: #000;
  cursor: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/836/hearthstone-cursor.png) 10 2, auto;
  overflow: hidden;
}
body:active {
  cursor: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/836/hearthstone-click.png) 10 2, auto;
}
body:after {
  background-color: #000;
  background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/836/hearthstone-battlefield.jpg);
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  bottom: 0;
  content: '';
  -webkit-filter: blur(8px);
          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;
  -webkit-perspective: 400px;
          perspective: 400px;
  position: absolute;
  -webkit-transform-style: preserve-3d;
          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;
}
.card: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;
  -webkit-transform-style: preserve-3d;
          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;
}
JS
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;
Host Instantly Drag and Drop Website Builder

 

Description

In honor of the release of the Whispers of the Old Gods expansion for Hearthstone, I wanted to share this proof of concept. The card drag feature in the game has always been one of my favorite things to play with. It feels like the card is reacting to air resistance as you drag it around.
Term
Mon, 11/27/2017 - 21:56

Related Codes

Pen ID
Pen ID
Pen ID