<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src='https://cdn.jsdelivr.net/npm/scarletsframe@0.34.0/dist/scarletsframe.min.js'></script>
<script type="text/javascript">
// Polyfill the PointerEvent
(function(){function z(a){document.write('<script src="'+a+'"><\/script>')}
if(window.PointerEvent === void 0)
z('https://code.jquery.com/pep/0.4.3/pep.js');
})();
</script>
</head>
<body>
<sf-m name="cards" id="root">
<div sf-each="x in list" style="transform: translate3d({{x.x}}px, {{x.y}}px, {{x.z}}px);">
<div
@mousedown="mouseDown"
style="
pointer-events: {{ x.throwed ? 'none' : 'all' }};
background-image: url({{ x.background }});
transform: perspective({{ x.perspective }}px)
rotateX({{ x.rotateX }}deg)
rotateY({{ x.rotateY }}deg)
rotateZ({{ x.rotateZ }}deg)
scale({{ x.scale }});">
</div>
</div>
</sf-m>
</body>
</html>
<!-- Inspired by: https://codesandbox.io/embed/j0y0vpz59 -->
* {
box-sizing: border-box;
}
html,
body {
overscroll-behavior-y: contain;
margin: 0;
padding: 0;
height: 100%;
width: 100%;
user-select: none;
font-family: system, BlinkMacSystemFont, avenir next, avenir, helvetica neue, helvetica, ubuntu, roboto, noto, segoe ui, arial,
sans-serif;
position: fixed;
overflow: hidden;
}
sf-m{
display: block;
}
#root {
background: lightblue;
position: fixed;
overflow: hidden;
width: 100%;
height: 100%;
}
#root > div {
position: absolute;
width: 100vw;
height: 100vh;
will-change: transform;
display: flex;
align-items: center;
justify-content: center;
transition: 0.7s transform ease-out;
}
#root > div > div {
background-color: white;
background-size: auto 85%;
background-repeat: no-repeat;
background-position: center center;
width: 45vh;
max-width: 300px;
height: 85vh;
max-height: 570px;
will-change: transform;
transition: 0.2s transform ease-in-out;
border-radius: 10px;
box-shadow: 0 12.5px 100px -10px rgba(50, 50, 73, 0.4), 0 10px 10px -10px rgba(50, 50, 73, 0.3);
}
#root > div.dragging {
transition: 50ms transform linear;
}
var $ = sf.$;
var test;
sf.model('cards', function(My){
// For you to play around on the console :)
test = My;
My.list = [
'https://upload.wikimedia.org/wikipedia/en/f/f5/RWS_Tarot_08_Strength.jpg',
'https://upload.wikimedia.org/wikipedia/en/5/53/RWS_Tarot_16_Tower.jpg',
'https://upload.wikimedia.org/wikipedia/en/9/9b/RWS_Tarot_07_Chariot.jpg',
'https://upload.wikimedia.org/wikipedia/en/d/db/RWS_Tarot_06_Lovers.jpg',
'https://upload.wikimedia.org/wikipedia/en/thumb/8/88/RWS_Tarot_02_High_Priestess.jpg/690px-RWS_Tarot_02_High_Priestess.jpg',
'https://upload.wikimedia.org/wikipedia/en/d/de/RWS_Tarot_01_Magician.jpg'
];
// Lets convert above list into array of object
for(var i=0; i < My.list.length; i++){
My.list[i] = {
background:My.list[i],
perspective: 1500,
rotateX:30,
rotateY:0,
rotateZ:Math.ceil(Math.random()*20) - 10,
scale:1,
x:0,
y:i * -4,
z:0,
throwed:false // true = disable interaction on card
};
}
// Mouse click start
My.mouseDown = function(ev, item){
item.scale = 1.15;
item.rotateZ = 0;
// Save reference of clicked item
clicked = item;
// Add event listener after user clicking the card
$(document)
.on('mousemove', My.mouseMove)
.once('mouseup', My.mouseUp);
// Add dragging class into the clicked item
$(My.list.getElement(item)).addClass('dragging');
}
// Return every card back after some delay
function collectCard(){
for(let i=0; i < My.list.length; i++){
setTimeout(function(){
var item = My.list[i];
item.x = 0;
item.throwed = false;
item.rotateZ = Math.ceil(Math.random()*20) - 10;
}, i * 200);
}
}
// Throw current clicked card on a direction
function throwCard(isLeft){
clicked.x = isLeft ? -750 : 750;
clicked.throwed = true;
// Collect cards back if this the last card
if(clicked === My.list[0])
setTimeout(collectCard, 1000);
}
// Mouse click ended
My.mouseUp = function(ev){
clicked.scale = 1;
// Throw if user move little fast
if(Math.abs(speedX) >= 3)
throwCard(speedX < 0 ? true : false);
// Reset card position if not throwed
else clicked.x = 0;
// Remove event listener and the dragging class
$(document).off('mousemove', My.mouseMove);
$(My.list.getElement(clicked)).removeClass('dragging');
// Reset mouse speed detection and remove reference of clicked item
speedX = 0;
clicked = null;
}
var speedX = 0;
My.mouseMove = function(ev){
// Move card with this
clicked.x += ev.movementX;
speedX = ev.movementX;
}
});
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |