deck-of-cards
Version:
HTML5 Deck of Cards
256 lines (210 loc) • 6.3 kB
JavaScript
import Deck from './deck'
import animationFrames from './animationFrames'
import createElement from './createElement'
import Ease from './ease'
import translate from './translate'
import prefix from './prefix'
var maxZ = 52
export default function (i) {
var transform = prefix('transform')
// calculate rank/suit, etc..
var rank = i % 13 + 1
var suit = i / 13 | 0
var z = (52 - i) / 4
// create elements
var $el = createElement('div')
var $face = createElement('div')
var $back = createElement('div')
// states
var isDraggable = false
var isFlippable = false
// self = card
var self = {i, rank, suit, pos: i, $el, mount, unmount, setSide}
var modules = Deck.modules
var module
// add classes
$face.classList.add('face')
$back.classList.add('back')
// add default transform
$el.style[transform] = translate(-z + 'px', -z + 'px')
// add default values
self.x = -z
self.y = -z
self.z = z
self.rot = 0
// set default side to back
self.setSide('back')
// add drag/click listeners
addListener($el, 'mousedown', onMousedown)
addListener($el, 'touchstart', onMousedown)
// load modules
for (module in modules) {
addModule(modules[module])
}
self.animateTo = function (params) {
var {delay, duration, x = self.x, y = self.y, rot = self.rot, ease, onStart, onProgress, onComplete} = params
var startX, startY, startRot
var diffX, diffY, diffRot
animationFrames(delay, duration)
.start(function () {
startX = self.x || 0
startY = self.y || 0
startRot = self.rot || 0
onStart && onStart()
})
.progress(function (t) {
var et = Ease[ease || 'cubicInOut'](t)
diffX = x - startX
diffY = y - startY
diffRot = rot - startRot
onProgress && onProgress(t, et)
self.x = startX + diffX * et
self.y = startY + diffY * et
self.rot = startRot + diffRot * et
$el.style[transform] = translate(self.x + 'px', self.y + 'px') + (diffRot ? 'rotate(' + self.rot + 'deg)' : '')
})
.end(function () {
onComplete && onComplete()
})
}
// set rank & suit
self.setRankSuit = function (rank, suit) {
var suitName = SuitName(suit)
$el.setAttribute('class', 'card ' + suitName + ' rank' + rank)
}
self.setRankSuit(rank, suit)
self.enableDragging = function () {
// this activates dragging
if (isDraggable) {
// already is draggable, do nothing
return
}
isDraggable = true
$el.style.cursor = 'move'
}
self.enableFlipping = function () {
if (isFlippable) {
// already is flippable, do nothing
return
}
isFlippable = true
}
self.disableFlipping = function () {
if (!isFlippable) {
// already disabled flipping, do nothing
return
}
isFlippable = false
}
self.disableDragging = function () {
if (!isDraggable) {
// already disabled dragging, do nothing
return
}
isDraggable = false
$el.style.cursor = ''
}
return self
function addModule (module) {
// add card module
module.card && module.card(self)
}
function onMousedown (e) {
var startPos = {}
var pos = {}
var starttime = Date.now()
e.preventDefault()
// get start coordinates and start listening window events
if (e.type === 'mousedown') {
startPos.x = pos.x = e.clientX
startPos.y = pos.y = e.clientY
addListener(window, 'mousemove', onMousemove)
addListener(window, 'mouseup', onMouseup)
} else {
startPos.x = pos.x = e.touches[0].clientX
startPos.y = pos.y = e.touches[0].clientY
addListener(window, 'touchmove', onMousemove)
addListener(window, 'touchend', onMouseup)
}
if (!isDraggable) {
// is not draggable, do nothing
return
}
// move card
$el.style[transform] = translate(self.x + 'px', self.y + 'px') + (self.rot ? ' rotate(' + self.rot + 'deg)' : '')
$el.style.zIndex = maxZ++
function onMousemove (e) {
if (!isDraggable) {
// is not draggable, do nothing
return
}
if (e.type === 'mousemove') {
pos.x = e.clientX
pos.y = e.clientY
} else {
pos.x = e.touches[0].clientX
pos.y = e.touches[0].clientY
}
// move card
$el.style[transform] = translate(Math.round(self.x + pos.x - startPos.x) + 'px', Math.round(self.y + pos.y - startPos.y) + 'px') + (self.rot ? ' rotate(' + self.rot + 'deg)' : '')
}
function onMouseup (e) {
if (isFlippable && Date.now() - starttime < 200) {
// flip sides
self.setSide(self.side === 'front' ? 'back' : 'front')
}
if (e.type === 'mouseup') {
removeListener(window, 'mousemove', onMousemove)
removeListener(window, 'mouseup', onMouseup)
} else {
removeListener(window, 'touchmove', onMousemove)
removeListener(window, 'touchend', onMouseup)
}
if (!isDraggable) {
// is not draggable, do nothing
return
}
// set current position
self.x = self.x + pos.x - startPos.x
self.y = self.y + pos.y - startPos.y
}
}
function mount (target) {
// mount card to target (deck)
target.appendChild($el)
self.$root = target
}
function unmount () {
// unmount from root (deck)
self.$root && self.$root.removeChild($el)
self.$root = null
}
function setSide (newSide) {
// flip sides
if (newSide === 'front') {
if (self.side === 'back') {
$el.removeChild($back)
}
self.side = 'front'
$el.appendChild($face)
self.setRankSuit(self.rank, self.suit)
} else {
if (self.side === 'front') {
$el.removeChild($face)
}
self.side = 'back'
$el.appendChild($back)
$el.setAttribute('class', 'card')
}
}
}
function SuitName (suit) {
// return suit name from suit value
return suit === 0 ? 'spades' : suit === 1 ? 'hearts' : suit === 2 ? 'clubs' : suit === 3 ? 'diamonds' : 'joker'
}
function addListener (target, name, listener) {
target.addEventListener(name, listener)
}
function removeListener (target, name, listener) {
target.removeEventListener(name, listener)
}