Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
3D Flyer Animation
div.stage: ul.flyer
li.flyer__page.flyer__page--6
li.flyer__page.flyer__page--5
li.flyer__page.flyer__page--7
li.flyer__page.flyer__page--4
li.flyer__page.flyer__page--8
li.flyer__page.flyer__page--3
li.flyer__page.flyer__page--1
li.flyer__page.flyer__page--2
let $stage = $('.stage')
let $flyer = $('.flyer')
const BASEPERSPECTIVE = 180
const BASEEASING = 10
const MAXDEGREE = 360
let rotation = { current: 0, final: 0 }
let perspective = { current: BASEPERSPECTIVE, final: BASEPERSPECTIVE }
let zoom = { current: 1, final: 1 }
let easing = BASEEASING
let ease = val => val.current += (val.final - val.current ) / easing
let round = val => Math.round(val * 1000) / 1000
let finished = val => round(val.current) === round(val.final)
let animation = {
_isPlaying: false,
play() {
!this._isPlaying && this._animate()
},
_animate() {
this._isPlaying = true
ease(rotation)
ease(perspective)
ease(zoom)
$flyer.style.transform = `rotateY(-${ rotation.current }deg)`
$stage.style.perspectiveOrigin = `center ${ perspective.current }px`
$stage.style.transform = `scale(${ zoom.current })`
if (finished(rotation)
&& finished(perspective)
&& finished(zoom)) {
this._isPlaying = false
return
}
requestAnimationFrame(this._animate.bind(this))
}
}
document.on('mousemove', e => {
rotation.final = MAXDEGREE * e.clientX / window.innerWidth
perspective.final = (e.clientY - window.innerHeight / 2)
* 2 + BASEPERSPECTIVE
animation.play()
})
document.on('mouseover', () => {
$flyer.classList.add('js-disable-animation')
easing = BASEEASING
animation.play()
})
document.on('mouseleave', () => {
rotation.final = 0
perspective.final = BASEPERSPECTIVE
zoom.final = 1
easing = BASEEASING * 5
animation.play()
})
window.on('mousewheel, DOMMouseScroll', e => {
let wheelDistance = e.detail ? -e.detail / 3 : e.wheelDelta / 120
zoom.final += wheelDistance / 10
zoom.final = Math.min(Math.max(zoom.final, .25), 2)
animation.play()
})
document.on('click', () => {
zoom.final = 1
animation.play()
})
<script src="http://codepen.io/exporia/pen/epaLVO"></script>
body
margin: 0
background: #3c6ea5
overflow: hidden
ul
margin: 0
padding: 0
li
list-style: none
.stage
width: 480px
margin: 100px auto 0 auto
perspective: 800px
perspective-origin: 50% 180px
@keyframes rotate
to
transform: rotateY(360deg)
.flyer
position: relative
transform-style: preserve-3d
transform-origin: 50%
animation: rotate 4s alternate
&__page
$width: 198px
$depth: $width / 2
$deg: 45deg
width: $width
height: round($width * 2.1155)
position: absolute
backface-visibility: hidden
background: url(https://exporia.pl/images/mk/mk.jpg) no-repeat
background-size: 400%
opacity: .95
&--6
background-position: left bottom
transform: rotateY(-$deg) translateZ($depth)
&--5
background-position: right top
transform: rotateY($deg * 3) translateZ(-$depth)
&--7
background-position: -$width bottom
transform: rotateY($deg) translateZ($depth)
&--4
background-position: -$width * 2 top
transform: rotateY(-$deg * 3) translateZ(-$depth)
&--8
background-position: -$width * 2 bottom
transform: rotateY(-$deg) translateZ(-$depth) translateX(100%)
&--3
background-position: -$width top
transform: rotateY($deg * 3) translateZ($depth) translateX(-100%)
&--1
background-position: right bottom
transform: rotateY($deg) translateZ($depth * 3) translateX(100%)
&--2
background-position: left top
transform: rotateY(-$deg * 3) translateZ(-$depth * 3) translateX(-100%)
.js-disable-animation
animation: none
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment