This week's @keyframers episode featured David Khourshid giving a short talk and live coding demonstration at CodePen Houston on Reactive Animations with RxJS followed by a Q&A.
Created
April 20, 2018 19:11
-
-
Save shshaw/e3991c94f8a0be9a124ca4c5f5c72017 to your computer and use it in GitHub Desktop.
@keyframers 1.2.0 | Reactive Animations with RxJS | CodePen Houston
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<a href="https://youtu.be/H7FEK6geguM" target="_blank" data-keyframers-credit style="color: #000"></a> | |
<script src="https://codepen.io/shshaw/pen/QmZYMG.js"></script> | |
<h1 id="heading">@davidkpiano<span id="pos"></span></h1> | |
<h2 style="text-align: center"><a href="http://reactivex.io/rxjs">reactivex.io/rxjs</a><br/> | |
</h2> | |
<div id="card"> | |
<div id="title"></div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
console.clear(); | |
const { body } = document; | |
const { clientWidth, clientHeight } = body; | |
const pos = document.querySelector('#pos'); | |
const cardElm = document.querySelector('#card'); | |
const mouseMove$ = Rx.Observable | |
.fromEvent(body, 'mousemove') | |
.map(event => ({ | |
x: event.clientX, | |
y: event.clientY | |
})); | |
const touchMove$ = Rx.Observable | |
.fromEvent(body, 'touchmove') | |
.map(event => ({ | |
x: event.touches[0].clientX, | |
y: event.touches[0].clientY | |
})); | |
const move$ = Rx.Observable | |
.merge(mouseMove$, touchMove$); | |
const animationFrame$ = Rx.Observable | |
.interval(0, Rx.Scheduler.animationFrame); | |
const smoothMove$ = animationFrame$ | |
.withLatestFrom(move$, (tick, move) => move) | |
.scan((fullValue, move) => { | |
return lerp(fullValue, move); | |
}); | |
function lerp(start, end) { | |
const dx = end.x - start.x; | |
const dy = end.y - start.y; | |
const rate = 0.05; | |
return { | |
x: start.x + dx * rate, | |
y: start.y + dy * rate | |
}; | |
} | |
smoothMove$.subscribe(pos => { | |
const rotX = (pos.y / clientHeight * -50) + 25; | |
const rotY = (pos.x / clientWidth * 50) - 25; | |
cardElm.style.cssText = ` | |
transform: rotateX(${rotX}deg) rotateY(${rotY}deg) | |
`; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://unpkg.com/@reactivex/rxjs@latest/dist/global/Rx.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#heading { | |
margin: 0; | |
} | |
a { | |
color: #888; | |
} | |
#card { | |
height: 50vmin; | |
width: 90vmin; | |
background-color: white; | |
background-image: url(https://images.unsplash.com/photo-1521916396286-3f65e9f0eddc?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=4eb92aa01a62d3c6bb783370514dcb7a&auto=format&fit=crop&w=1050&q=80); background-size: cover; | |
// background-image: url(http://reactivex.io/rxjs/img/withLatestFrom.png); background-size: contain; | |
background-repeat: no-repeat; | |
background-position: center center; | |
box-shadow: 0 1rem 3rem rgba(black, 0.2); | |
transform-style: preserve-3d; | |
&:before, &:after { | |
content: ''; | |
position: absolute; | |
display: block; | |
height: 2px; | |
width: 2px; | |
border-radius: 50%; | |
background: rgba(white, 0.2); | |
filter: blur(1px); | |
} | |
&:before { | |
transform: translateZ(1rem); | |
$shadows: (); | |
@for $i from 1 through 50 { | |
$shadows: append($shadows, random(90) * 1vmin random(50) * 1vmin 0 white, comma); | |
} | |
box-shadow: $shadows; | |
} | |
&:after { | |
height: 3px; | |
width: 3px; | |
transform: translateZ(2rem); | |
$shadows: (); | |
@for $i from 1 through 50 { | |
$shadows: append($shadows, random(90) * 1vmin random(50) * 1vmin 0 white, comma); | |
} | |
box-shadow: $shadows; | |
} | |
} | |
body { | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
transform-style: preserve-3d; | |
perspective: 1000px; | |
} | |
html, body { | |
width: 100%; | |
height: 100%; | |
margin: 0; | |
padding: 0; | |
} | |
html { | |
background: linear-gradient(to bottom, #dbe6ed, #cfdde5); | |
} | |
*, *:before, *:after { | |
box-sizing: border-box; | |
position: relative; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment