Skip to content

Commit eb5788b

Browse files
committed
Adds 3D card flip
1 parent bcfb0fa commit eb5788b

File tree

7 files changed

+957
-0
lines changed

7 files changed

+957
-0
lines changed

3d-card-flip/card-flip.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
*
3+
* Copyright 2016 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
'use strict';
19+
20+
class SCFlipCard extends HTMLElement {
21+
22+
static get SIDES () {
23+
return {
24+
FRONT: 1,
25+
BACK: 2
26+
};
27+
}
28+
29+
flip () {
30+
if (this._locked) {
31+
return;
32+
}
33+
34+
this._locked = true;
35+
36+
const scale = (500 + 200) / 500;
37+
38+
const sideOne = [
39+
{transform: `translateZ(-200px) rotate${this._axis}(0deg) scale(${scale})`},
40+
{transform: `translateZ(-100px) rotate${this._axis}(0deg) scale(${scale})`, offset: 0.15},
41+
{transform: `translateZ(-100px) rotate${this._axis}(180deg) scale(${scale})`, offset: 0.65},
42+
{transform: `translateZ(-200px) rotate${this._axis}(180deg) scale(${scale})`}
43+
];
44+
45+
const sideTwo = [
46+
{transform: `translateZ(-200px) rotate${this._axis}(180deg) scale(${scale})`},
47+
{transform: `translateZ(-100px) rotate${this._axis}(180deg) scale(${scale})`, offset: 0.15},
48+
{transform: `translateZ(-100px) rotate${this._axis}(360deg) scale(${scale})`, offset: 0.65},
49+
{transform: `translateZ(-200px) rotate${this._axis}(360deg) scale(${scale})`}
50+
];
51+
52+
const umbra = [
53+
{opacity: 0.3, transform: `translateY(2px) rotate${this._axis}(0deg)`},
54+
{opacity: 0.0, transform: `translateY(62px) rotate${this._axis}(0deg)`, offset: 0.15},
55+
{opacity: 0.0, transform: `translateY(62px) rotate${this._axis}(180deg)`, offset: 0.65},
56+
{opacity: 0.3, transform: `translateY(2px) rotate${this._axis}(180deg)`}
57+
];
58+
59+
const penumbra = [
60+
{opacity: 0.0, transform: `translateY(2px) rotate${this._axis}(0deg)`},
61+
{opacity: 0.5, transform: `translateY(62px) rotate${this._axis}(0deg)`, offset: 0.15},
62+
{opacity: 0.5, transform: `translateY(62px) rotate${this._axis}(180deg)`, offset: 0.65},
63+
{opacity: 0.0, transform: `translateY(2px) rotate${this._axis}(180deg)`}
64+
];
65+
66+
const timing = {
67+
duration: this._duration,
68+
iterations: 1,
69+
easing: 'ease-in-out',
70+
fill: 'forwards'
71+
};
72+
73+
switch (this._side) {
74+
case SCFlipCard.SIDES.FRONT:
75+
this._front.animate(sideOne, timing);
76+
this._back.animate(sideTwo, timing);
77+
78+
this._back.focus();
79+
this._front.inert = true;
80+
this._back.inert = false;
81+
break;
82+
83+
case SCFlipCard.SIDES.BACK:
84+
this._front.animate(sideTwo, timing);
85+
this._back.animate(sideOne, timing);
86+
87+
this._front.focus();
88+
this._front.inert = false;
89+
this._back.inert = true;
90+
break;
91+
92+
default:
93+
throw new Error('Unknown side');
94+
}
95+
96+
this._umbra.animate(umbra, timing);
97+
this._penumbra.animate(penumbra, timing)
98+
.onfinish = _ => {
99+
this._locked = false;
100+
this._side = (this._side === SCFlipCard.SIDES.FRONT) ?
101+
SCFlipCard.SIDES.BACK :
102+
SCFlipCard.SIDES.FRONT;
103+
};
104+
}
105+
106+
createdCallback () {
107+
this._locked = false;
108+
this._side = SCFlipCard.SIDES.FRONT;
109+
this._front = this.querySelector('.front');
110+
this._back = this.querySelector('.back');
111+
this._buttons = this.querySelectorAll('button');
112+
this._umbra = this.querySelector('.umbra');
113+
this._penumbra = this.querySelector('.penumbra');
114+
115+
this._front.inert = false;
116+
this._back.inert = true;
117+
118+
this._duration = parseInt(this.getAttribute('duration'), 10);
119+
if (isNaN(this._duration)) {
120+
this._duration = 800;
121+
}
122+
123+
this._axis = this.getAttribute('axis') || 'X';
124+
if (this._axis.toUpperCase() === 'RANDOM') {
125+
this._axis = (Math.random() > 0.5 ? 'Y' : 'X');
126+
}
127+
}
128+
129+
attachedCallback () {
130+
Array.from(this._buttons)
131+
.forEach(b => {
132+
b.addEventListener('click', _ => this.flip());
133+
});
134+
}
135+
136+
detachedCallback () {
137+
138+
}
139+
}
140+
141+
document.registerElement('sc-card', SCFlipCard);

3d-card-flip/images/penumbra.svg

Lines changed: 8 additions & 0 deletions
Loading

3d-card-flip/images/supercharged.jpg

30 KB
Loading

3d-card-flip/images/umbra.svg

Lines changed: 8 additions & 0 deletions
Loading

3d-card-flip/index.html

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!--
2+
Copyright 2016 Google Inc. All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
-->
13+
<!doctype html>
14+
<head>
15+
<meta charset="utf-8">
16+
<meta name="author" content="Paul Lewis" />
17+
<meta name="viewport" content="width=device-width">
18+
<title>3D Card Flip</title>
19+
<link rel="stylesheet" href="styles.css">
20+
</head>
21+
<body>
22+
<sc-card axis="random" duration="3000">
23+
<div class="umbra"></div>
24+
<div class="penumbra"></div>
25+
26+
<div class="front" tabindex="-1">
27+
<h1>Supercharged</h1>
28+
<button>Flip card</button>
29+
</div>
30+
31+
<div class="back" tabindex="-1">
32+
<button>Flip card</button>
33+
</div>
34+
35+
</sc-card>
36+
37+
<script src="inert.js"></script>
38+
<script src="card-flip.js"></script>
39+
</body>
40+
</html>

0 commit comments

Comments
 (0)