jQuery Draggable Cards (Desktop Only)

A
A
8
♠ ♠ ♠ ♠
♠ ♠ ♠ ♠
8
A
A
8
♣ ♣ ♣ ♣
♣ ♣ ♣ ♣
8
Q
()
\__/
(____)
| |
|__|
|__|
/____\
(______)
(________)
Q

I had an idea yesterday as I was working on custom membership reporting plugin for one of the World’s largest Poker strategy websites.  Wouldn’t it be cool if you could programically create a a UI interface of a deck of cards that you could shift around by clicking and dragging on a desktop or tapping and sliding on your tablet or cell phone?!

Unfortunately you don’t usually get paid to make these fun sort of interfaces so I decided I would create this on my own and share it with the World. Maybe it’s been done before but it’s always more fun to discover things on your own.

How to Make a Digital Version of Dead Man’s Hand A♠ 8♠ A♣ 8♣

No. 10 Saloon Deadwood, SD: Wild Bill Hickok shooting re-enactment with Jack McCall.A little background first. Most people who know me personally know that I love Deadwood, SD. One of my favorite experiences there was in 2010 when I got a chance to sit in on a re-enactment of the shooting of “Wild Bill” Hickok at Saloon No. 10, Main Street Deadwood, SD.

The story of Wild Bill being shot in August, 1876 is legendary, I encourage you to read more about it. The re-enactment is actually across the street in a bar called Saloon No. 10.  I also seem to remember that the original place was torn down and would actually be underground if it was still standing today as the city streets of Deadwood are higher now than it was back in 1876. Please correct me if I’m wrong.

Anyway, the hand Hickok was holding at the time was purportedly black aces and eights and became known as “dead man’s hand”. Since I love this theme, let’s get started!

HTML Playing Cards

The foundation of any good website or web interface is HTML. Properly structured HTML with the proper classes and IDs will allow you to more easily design and manipulate the elements on your page. As with any design, proper planning on how to layout the project pays off later.

The first step was to create a container or a “table” (in this case a div) to encapsulate the interface.  We gave it an id of ‘cardDeck’ and also applied a class of ‘noSelect’ on it so that we could disable highlighting on any child elements.

<div id="cardDeck" class="noSelect"><!--Content will go here--></div>

Each card was constructed with a div then assigned an ID of ‘card’ and a number corresponding to it’s sequence.  Considering that there are three main areas inside a plying card, the number in the top left, number in the bottom right and the main suit icons in the middle of the card, we nested three more divs inside the parent div for that card.  IDs and classes were assigned for general and specific styling.

Here is an example of how we structured the Ace of Spades:

<div id="card1" class="playingCard textBlack">
<div class="cardHeading">
A<br />
&#9824;
</div>
<div id="aceOfSpades" class="playingCardBody">&#9824;</div>
<div class="cardHeadingFlip">
A<br />
&#9824;
</div>
</div>

HTML (ASCII) Icons for Hearts, Diamonds, Clubs and Spades

A few of you may be wondering what the “&#9824;” is all about.  The hearts, diamonds, clubs and spades used above are NOT graphics, they are actually HTML special characters and have a unique number that follows the structure of: the ampersand, a hash tag, 4 digit number and a closing semi-colon. Above, &#9824; corresponds to a spade icon.

Here are the 4 icons used above and their HTML numbers:

&#9824; = ♠
&#9827; = ♣
&#9829; = ♥
&#9830; = ♦

CSS for Playing Cards

Now that the groundwork has been laid out for the cards, it’s time to make this look as realistic as possible.  The UI of interfaces is ALWAYS my favorite part and CSS is directly involved with this!  Granted, if I was going for ultra realism, I would be using PhotoShop to make the graphics for this BUT, it’s amazing what you can do with CSS3 and some attention to detail!

Basically I started with the table (#cardDeck), made the width 100%, height reasonable, styled the background green and rounded the corners; good enough.  The card body had a “playingCard” class assigned with a fixed width and height, white background and rounded edges.  There was a second class assigned for the suit color as well. The DIVs in the corners were assigned a “cardHeading” and “cardHeadingFlip” class respectively and were assigned their position as “absolute”.

NOTE: A lot of CSS beginners fail to get absolute positioning to work for them the way they like because of a simple mistake.  The parent tag HAS to have the position assigned as relative or you will find your absolute positioned element going to the extreme edge of the page.  Although, by default, elements are relative, that relative position HAS to be strictly assigned to the parent element.

Here is a slightly minified version of the CSS used in the HTML Card Interface above:

/* Card Styles */
#cardDeck{position:relative;width:100%;height:350px;padding:50px;border:1px solid #fcb040;background-color:#073;-moz-border-radius: 100px / 50%;-webkit-border-radius: 100px / 50%;border-radius: 100px / 50%;}
.playingCard{position:relative;float:left;margin:0 0 -20px -40px;background-color:#fff;width:140px;height:200px;text-align:center;border:1px solid #999;border-radius: 10px 10px 10px 10px;-moz-border-radius: 10px 10px 10px 10px;-webkit-border-radius: 10px 10px 10px 10px;border: 0px solid #000000;-webkit-box-shadow: -1px 2px 5px 0px rgba(0,0,0,0.3);-moz-box-shadow: -1px 2px 5px 0px rgba(0,0,0,0.3);box-shadow: -1px 2px 5px 0px rgba(0,0,0,0.3);cursor:pinter;}
.cardHeading{position:absolute; top:4px; left:10px; text-align:left;padding:0;margin:0;line-height:.95;font-family: "Times New Roman", Times, serif;}
.cardHeading p{text-align:left;padding:0;margin:0;}
.cardHeadingFlip{position:absolute; bottom:4px; right:10px; text-align:left;padding:0;margin:0;line-height:.95;font-family: "Times New Roman", Times, serif;-webkit-transform: rotate(180deg); -moz-transform: rotate(180deg); -o-transform: rotate(180deg); -ms-transform: rotate(180deg); transform: rotate(180deg);}
.cardHeadingFlip p{text-align:left;padding:0;margin:0;}
.textBlack{color:#202020;}
.textRed{color:#fc4052;}
#card1{margin:0;-ms-transform:rotate(-2deg);-webkit-transform: rotate(-2deg);transform: rotate(-2deg);}
#card2{margin:20px 0 0 -40px;-ms-transform:rotate(1deg);-webkit-transform: rotate(1deg);transform: rotate(1deg);}
#card3{margin:60px 0 0 -50px;-ms-transform:rotate(3deg);-webkit-transform: rotate(3deg);transform: rotate(3deg);}
#card4{margin:24px 0 0 -20px;-ms-transform:rotate(-1deg);-webkit-transform: rotate(-1deg);transform: rotate(-1deg);}
#card5{margin:70px 0 0 70px;-ms-transform: rotate(20deg);-webkit-transform: rotate(20deg);transform: rotate(20deg);}
#aceOfSpades{font-size:450%;padding-top:30px;}
#eightOfSpades{font-size:200%;padding:4px 18px;line-height:1.14;}
#aceOfClubs{font-size:450%;padding-top:30px;}
#eightOfClubs{font-size:200%;padding:4px 18px;line-height:1.14;}
#queenOfHearts{font-size:60%;padding-top:24px;}
.suitFlip180{-ms-transform: rotate(180deg);-webkit-transform: rotate(180deg);transform: rotate(180deg);padding-bottom:10px;}
/* END Card Styles */

Fun, huh?! Now lets get these cards interactive and apply some jQuery to it!

jQuery for Playing Cards, Click and Drag and Z-Index Manipulation

jQuery provides a easy and well supported way to create animations to your web experiences.  In this case, we just want to be able to pick the cards up and move them while making it look as realistic as possible.  I may look at this again in the future to add even more functionality.

Doing a typical Document Ready Function will allow us to target the cards. When I first started doing this, however, each individual element in the cards was draggable too.  I solved that by using the closest() function that targets the nearest parent div named with a class of “playingCard”.

jQuery TIP:

If you’re having problems using jQuery where your page is targeting the child elements instead of the parent, try using the closest() function.

The basic idea of clicking an dragging items using jQuery is simple.  If, when the mouse is moving, and a variable ($dragCard) is set as your targeted element, that card gets placed where the mouse is in relation to the body.

I put a couple of other hacks in place to make sure the experience is a little more “realistic” too. Using jQuery, I set the z-index for the element that is clicked to +1 the last clicked card so the card in use always appears above the others.  I also changed the cursor to “default” so the user doesn’t see weird mouse cursors when clicking and dragging.

Here is the jQuery that I placed at the bottom of the body tag:

<script type="text/javascript">
// <![CDATA[
jQuery(document).ready(function($) {
var $dragCard = null; var $cardZ = 1;
var $playingCardObject = $(document.body).on("mousemove", function(e) {
if ($dragCard) {
$dragCard.offset({
top: e.pageY,
left: e.pageX
});
}
$(document.body).on("mousedown", "div#cardDeck div", function (e) {
$dragCard = $(e.target).closest( "div.playingCard" );
$cardZ++;
$(e.target).closest( "div.playingCard" ).css('z-index', $cardZ);
$('html,body').css('cursor','default');
});
$(document.body).on("mouseup", function (e) {
$dragCard = null; }); $('#aceOfSpades').click(false);
$('html,body').css('cursor','default');
});
});
// ]]>
</script>

Summary

There’s obviously more that goes into something like this and it definitely takes more than five minutes to do. Long articles get boring so I’m ending it here and will get more specific in new articles.  If you have any questions, feel free to place a comment and we can discuss!

Thank you for reading and happy coding!

Leave a Comment