Skip to content

Instantly share code, notes, and snippets.

@darrenjennings
Created May 30, 2019 22:19
Show Gist options
  • Save darrenjennings/c5e2ac3c7a9efe1917535f77a1ad793a to your computer and use it in GitHub Desktop.
Save darrenjennings/c5e2ac3c7a9efe1917535f77a1ad793a to your computer and use it in GitHub Desktop.
<template>
<div>
<div class="stutterer">
<svg
height="310"
width="310">
<circle
ref="face"
class="clockFace"
cx="155"
cy="155"
r="150"
@click.stop="handleClick"
/>
<g ref="arcGroup">
<path
v-for="i in 10"
:key="i" />
</g>
<path
ref="clockHand"
class="clockHand" />
</svg>
</div>
</div>
</template>
<script>
const SPEED = 0.003 / Math.PI
const FRAMES = 10
export default {
data: () => {
return {
arcs: [],
frame: null,
hitCounter: 0,
t0: Date.now(),
rotation: 0
}
},
mounted () {
this.frame = requestAnimationFrame(this.animate)
if (this.$refs.face) {
this.$refs.face.addEventListener('click', this.handleClick)
}
},
methods: {
handleClick () {
this.hitCounter = 50
},
animate () {
const now = Date.now()
const td = now - this.t0
this.rotation = (this.rotation + SPEED * td) % (2 * Math.PI)
this.t0 = now
this.arcs.push({rotation: this.rotation, td})
let lx, ly, tx, ty
if (this.arcs.length > FRAMES) {
this.arcs.forEach(({rotation, td}, i) => {
lx = tx
ly = ty
const r = 145
tx = 155 + r * Math.cos(rotation)
ty = 155 + r * Math.sin(rotation)
const bigArc = SPEED * td < Math.PI ? '0' : '1'
const path = `M${tx} ${ty}A${r} ${r} 0 ${bigArc} 0 ${lx} ${ly}L155 155`
const hue = 120 - Math.min(120, td / 4)
const colour = `hsl(${hue}, 100%, ${60 - i * (30 / FRAMES)}%)`
if (i !== 0) {
const arcEl = this.$refs.arcGroup.children[i - 1]
arcEl.setAttribute('d', path)
arcEl.setAttribute('fill', colour)
}
})
this.$refs.clockHand.setAttribute('d', `M155 155L${tx} ${ty}`)
this.arcs.shift()
}
if (this.hitCounter > 0) {
this.$refs.face.setAttribute(
'fill',
`hsla(0, 0%, ${this.hitCounter}%, 0.95)`
)
this.hitCounter -= 1
} else {
this.hitCounter = 0
this.$refs.face.setAttribute('fill', 'hsla(0, 0%, 5%, 0.95)')
}
this.frame = requestAnimationFrame(this.animate)
}
},
unmounted () {
this.$refs.face.removeEventListener('click', this.handleClick)
if (this.frame) {
cancelAnimationFrame(this.frame)
}
}
}
</script>
<style scoped>
.clockHand {
stroke: white;
stroke-width: 10px;
stroke-linecap: round;
}
.clockFace {
stroke: white;
stroke-width: 10px;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment