Skip to content

Instantly share code, notes, and snippets.

@Frankie-666
Last active May 8, 2016 08:48
Show Gist options
  • Save Frankie-666/9c7b6d53a58963d79ed0ddde2d66e0d4 to your computer and use it in GitHub Desktop.
Save Frankie-666/9c7b6d53a58963d79ed0ddde2d66e0d4 to your computer and use it in GitHub Desktop.
Spinner
const easeInOutQuart = function (t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
return -c/2 * ((t-=2)*t*t*t - 2) + b;
}
class Wheel {
constructor (s) {
this.canvas = document.createElement('canvas')
this.context = this.canvas.getContext('2d')
this.width = s
this.height = s
this.radius = s / 2
this.started = 0
this.elapsed = 0
this.duration = 1500
}
init () {
this.canvas.width = this.width
this.canvas.height = this.height
this.canvas.style.width = this.width
this.canvas.style.height = this.height
this.started = Date.now()
}
update (dt) {
this.elapsed += dt
this.progress = this.elapsed / this.duration
this.progress = (this.progress > 1 && 1) || this.progress
}
render () {
let progress = easeInOutQuart(this.progress, 0, 1, 1)
this.context.clearRect(0, 0, this.width, this.height)
let offsetX = this.width / 2
let offsetY = this.height / 2
let radius = Math.max(0, progress * this.radius)
let angle = progress * Math.PI * 2
let x = Math.cos(angle - Math.PI) * (this.radius - radius) + offsetX
let y = Math.sin(angle - Math.PI) * (this.radius - radius) + offsetY
this.context.fillStyle = '#af3063'
this.context.strokeStyle = '#af3063'
this.context.save()
this.context.beginPath()
this.context.arc(offsetX, offsetY, this.radius, 0, 2 * Math.PI)
this.context.fill()
this.context.globalCompositeOperation = 'source-in'
let x2 = Math.cos(-angle) * radius
let y2 = Math.sin(-angle) * radius
this.context.beginPath()
this.context.arc(offsetX + x2, offsetY - y2, this.radius, angle, angle + Math.PI)
this.context.lineWidth = radius * 2
this.context.stroke()
this.context.restore()
this.context.beginPath()
this.context.arc(x, y, radius, 0, 2 * Math.PI)
this.context.fill()
}
}
class Spinner {
constructor (s) {
this.canvas = document.createElement('canvas')
this.context = this.canvas.getContext('2d')
this.width = s
this.height = s
this.wheels = []
this.update = this.update.bind(this)
document.body.appendChild(this.canvas)
this.time = 0
}
init () {
this.canvas.width = this.width
this.canvas.height = this.height
this.canvas.style.width = this.width
this.canvas.style.height = this.height
this.time = Date.now()
}
start () {
this.tick()
this.update()
}
tick () {
let wheel = new Wheel(this.width)
wheel.init()
this.wheels.push(wheel)
}
update () {
window.requestAnimationFrame(this.update)
let now = Date.now()
let dt = now - this.time
if (this.wheels.slice(-1)[0].progress === 1) {
if (this.wheels.length + 1 > 4) {
this.wheels = []
}
this.tick()
}
for (let i=0, wheel; i<this.wheels.length; i++) {
wheel = this.wheels[i]
wheel.update(dt)
}
this.time = now
this.render()
}
render () {
this.context.clearRect(0, 0, this.width, this.height)
this.context.globalCompositeOperation = 'source-over'
for (let i=0, wheel; i<this.wheels.length; i++) {
wheel = this.wheels[i]
wheel.render()
this.context.save()
if (!!(i % 2)) {
this.context.globalCompositeOperation = 'destination-out'
}
this.context.drawImage(wheel.canvas, 0, 0, this.width, this.height)
this.context.restore()
}
this.context.globalCompositeOperation = 'destination-in'
this.context.beginPath()
this.context.arc(this.width / 2, this.height / 2, this.width / 2 - 3, 0, 2 * Math.PI)
this.context.fill()
}
}
let spinner = new Spinner(160)
spinner.init()
spinner.start()
<script src="http://facebook.github.io/rebound-js/rebound.js"></script>
canvas {
left: 50%;
margin-left: -80px;
margin-top: -80px;
position: fixed;
top: 50%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment