1<!-- Scatter v0.1 | (c) Peter Boughton | License: LGPLv3 | https://www.sorcerersisle.com/software/scatter -->
2<!doctype html><meta charset=utf-8 />
3<title>Cards Scatter Demo</title>
4
5<h1>Cards Scatter Demo</h1>
6<p>A full deck of playing cards strewn across a table.
7<p>Uses random mode plus <em>not</em> setting overflow:hidden style on the container to allow cards to overlap the edge.
8<p>Click to flip a card - uses custom handler for click event to modify the CSS transform.
9<p>Each individual card uses Scatter too - pre-defined pip coordinates are passed to a fixed mode Scatter instance with click events disabled.
10
11<p><i>(View source to see markup, script and CSS used.)</i>
12<script src="../scatter.js"></script>
13
14
15<style>
16 body
17 {
18 font-family:sans-serif;
19 background:#CCC;
20 }
21
22 #Table
23 {
24 display:block;
25 background:#484;
26 border: solid 1px black;
27 width:960px;
28 margin:auto;
29 height:480px;
30 margin-top:4em;
31 }
32
33 #Table>*
34 {
35 transition: 0.3s;
36 }
37
38 .card
39 {
40 position:relative;
41 display: inline-block;
42 background: white;
43 border: solid 2px white;
44 border-radius: 9px;
45 height: 342px; /* 3.5in ~ 346px */
46 width: 236px; /* 2.5in ~ 240px */
47 box-shadow: 0 0 2px rgba(0,0,0,0.2);
48
49 font-family: serif;
50 text-align:center;
51 }
52 .card.hearts,.card.diams { color: red; }
53 .card.spades,.card.clubs { color: black; }
54
55 .card .inv{ transform: rotate(180deg); }
56
57 .card .corner
58 {
59 width: 30px;
60 font-size: 34px;
61 line-height: 1;
62 position: absolute;
63 }
64 .card .corner:not(.inv){left:0;top:0;}
65 .card .corner.inv{right:0;bottom:0;}
66
67 .card .body
68 {
69 width:100%;
70 height:100%;
71 font-size:80px;
72 }
73
74 /* Larger pip for Ace of Spades */
75 .card.spades.v1 .body
76 {
77 font-size: 160px;
78 margin-top:-20px;
79 }
80
81
82 .card .body.picture
83 {
84 margin: 22px auto;
85 padding: 4px 0;
86 width:176px;
87 height:282px;
88 border:solid 1px navy;
89 background:#FFE;
90 }
91
92 .card.facedown
93 {
94 background-color: white;
95 background-image: radial-gradient(circle,white,navy 6px,white 12px,white);
96 background-size: 18px 20px;
97 }
98 .card.facedown>*
99 {
100 display:none;
101 }
102</style>
103
104
105<div id="Table"></div>
106
107
108<script>
109 var Suits = ['spades','hearts','clubs','diams'];
110 var Labels = { 1:'A' , 11:'J' , 12:'Q' , 13:'K' , 10:'1<span style="margin-left:-0.4ch;">0</span>' };
111
112 var Ends = 126;
113 var Sides = 54;
114 var Corners = [[-Sides,-Ends],[Sides,-Ends],[-Sides,Ends,180],[Sides,Ends,180]];
115 var MidRow = [[-Sides,0],[Sides,0]];
116 var NineTen = [[-Sides,-48],[Sides,-48],[-Sides,48,180],[Sides,48,180]];
117 var Pictures = [[-Sides,-Ends],[Sides,Ends,180],[0,-Ends+30],[0,Ends-30,180],[0,-Ends+60],[0,Ends-60,180]];
118
119 var Hats = {11:'♗',12:'♕',13:'♚'};
120
121 var PipPositions =
122 { 1: [[0,0]]
123 , 2: [[0,-Ends],[0,Ends,180]]
124 , 3: [[0,0],[0,-Ends],[0,Ends,180]]
125 , 4: Corners
126 , 5: Corners.concat([[0,0]])
127 , 6: Corners.concat(MidRow)
128 , 7: Corners.concat(MidRow).concat([[0,-68]])
129 , 8: Corners.concat(MidRow).concat([[0,-68],[0,68,180]])
130 , 9: Corners.concat(NineTen).concat([[0,0]])
131 , 10: Corners.concat(NineTen).concat([[0,-87],[0,87,180]])
132 , 11: Pictures
133 , 12: Pictures
134 , 13: Pictures
135 };
136
137
138 function renderCard(Value,Suit)
139 {
140 var SuitHtml = '&'+Suit+';';
141
142 var Label = Labels[Value] || Value;
143
144 var CardHtml = '<div class="card '+Suit+' v'+Value+'">'
145 +'<div class="corner"><div class="value">'+Label+'</div><div class="suit">'+SuitHtml+'</div></div>'
146 ;
147
148 if ( Value > 10 )
149 {
150 CardHtml += '<div class="body picture">'
151 + '<div class="pip">'+SuitHtml+'</div><div class="pip">'+SuitHtml+'</div>'
152 + '<div class="hat">'+Hats[Value]+'</div><div class="hat">'+Hats[Value]+'</div>'
153 + '<div class="head">☺</div><div class="head">☺</div>'
154 + '</div>'
155 ;
156 }
157 else
158 {
159 CardHtml += '<div class="body">';
160 for ( var i = 1 ; i <= Value ; ++i )
161 CardHtml += '<div class="pip">'+SuitHtml+'</div>';
162 CardHtml += '</div>';
163 }
164
165 CardHtml += '<div class="corner inv"><div class="value">'+Label+'</div><div class="suit">'+SuitHtml+'</div></div>'
166 +'</div>';
167
168 return CardHtml;
169 }
170
171 /*
172 render each card and positions pips using
173 */
174 var Table = document.getElementById('Table');
175 for ( var i=0 ; i<Suits.length ; ++i )
176 {
177 for ( var Value = 1 ; Value <= 13 ; ++Value )
178 {
179 Table.innerHTML += renderCard(Value,Suits[i]);
180
181 var CardOptions =
182 { InitialMode : 'fixed'
183 , FixedRelativeTo : 'center'
184 , FixedPositions : PipPositions[Value]
185 , ChildEvents : {'click':void 0}
186 , ContainerEvents : {'click':void 0}
187 };
188
189 new Scatter('.card.v'+Value+'.'+Suits[i]+' .body',CardOptions );
190 }
191 }
192
193 function flipCard(event)
194 {
195 event.stopPropagation();
196 event.currentTarget.classList.toggle('facedown');
197
198 if ( event.currentTarget.style.transform.indexOf('rotate3d') !== -1 )
199 {
200 event.currentTarget.style.transform = event.currentTarget.style.transform.replace(/rotate3d\([^)]+\)/,'');
201 }
202 else
203 {
204 // non-zero z rotation overcomes animation glitch when card has clockwise 2d rotation.
205 event.currentTarget.style.transform += ' rotate3d(0,1,0.001,180deg)';
206 }
207 }
208
209 var CardOptions =
210 { Mode : 'random'
211 , InitialMode : 'random'
212 , Scale : 0.3
213 , MaxRotation : 45
214 , Shuffle : true
215 , ChildEvents : {click:flipCard}
216 };
217 var CardScatter = new Scatter(document.getElementById('Table'),CardOptions);
218
219</script>