<div class="container">
<img src="http://s3-ap-northeast-1.amazonaws.com/nishinoshake/demo/animals/yorkshire.png" class="yorkshire" />
</div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100%;
min-height: 100vh;
padding: 30px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.yorkshire {
width: 200px;
height: auto;
display: block;
will-change: transform;
}
View Compiled
type Easing = (t: number) => number
type TweenOptions = {
from: number
to: number
duration: number
easing: Easing
onUpdate(currentValue: number): void
}
function clamp(num: number, min: number, max: number) {
return Math.min(Math.max(num, min), max)
}
function tween({ from, to, duration, easing, onUpdate }: TweenOptions): Promise<void> {
return new Promise((resolve) => {
const startTime = performance.now()
const tick = () => {
const elapsedTime = performance.now() - startTime
const progress = clamp(elapsedTime / duration, 0, 1)
const currentValue = from + (to - from) * easing(progress)
onUpdate(currentValue)
if (progress === 1) {
resolve()
} else {
requestAnimationFrame(tick)
}
}
onUpdate(from)
requestAnimationFrame(tick)
})
}
const easeOutQuart = (t: number) => 1 - Math.pow(1 - t, 4)
function rotation(el: HTMLElement) {
async function loop() {
await tween({
from: 0,
to: 180,
duration: 960,
easing: easeOutQuart,
onUpdate: val => {
el.style.transform = `rotateY(${val}deg)`
}
})
await tween({
from: 180,
to: 360,
duration: 960,
easing: easeOutQuart,
onUpdate: val => {
el.style.transform = `rotateY(${val}deg)`
}
})
loop()
}
loop()
}
const yorkshire = document.querySelector<HTMLElement>('.yorkshire')
if (yorkshire) {
rotation(yorkshire)
}
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.