Skip to content

Instantly share code, notes, and snippets.

@NickHatBoecker
Last active May 5, 2021 19:36
Show Gist options
  • Save NickHatBoecker/a25278e0ef9bf0279a439f2432a3e65b to your computer and use it in GitHub Desktop.
Save NickHatBoecker/a25278e0ef9bf0279a439f2432a3e65b to your computer and use it in GitHub Desktop.
Newsticker in VueJS
<template>
<div :ref="elementWrapperId" class="newsticker" @click="toggleAnimation">
<div :ref="elementId" class="newsticker__text">{{ text }}</div>
</div>
</template>
<script>
export default {
props: {
text: { type: String, required: true },
},
data: () => ({
elementId: 'newsticker',
elementWrapperId: 'newstickerWrapper',
animationFrame: null,
startPosition: 0,
resetPosition: null,
lastUpdate: null,
position: 0,
pixelPerUpdate: 2,
timeout: 20,
paused: false,
}),
mounted () {
this.startAnimation()
},
destroyed () {
this.stopAnimation()
},
methods: {
toggleAnimation () {
if (this.paused) {
this.startAnimation()
} else {
this.stopAnimation()
}
this.paused = !this.paused
},
startAnimation () {
this.animationFrame = window.requestAnimationFrame(this.update)
},
stopAnimation () {
window.cancelAnimationFrame(this.animationFrame)
},
update () {
if (this.paused) return
const now = Date.now()
if (this.lastUpdate && (now - this.lastUpdate) < this.timeout) {
this.startAnimation()
return
}
this.calculateStartAndResetPositions()
this.updatePosition()
this.lastUpdate = now
// Repeat
this.startAnimation()
},
/**
* Update box and text width in order to calculate the position
* where the text will be repeated
*/
calculateStartAndResetPositions () {
this.startPosition = this.$refs[this.elementWrapperId].offsetWidth
const textWidth = this.$refs[this.elementId].clientWidth
this.resetPosition = 0 - textWidth
},
updatePosition () {
const currentPosition = this.getCurrentPosition()
let newPosition = `${currentPosition - this.pixelPerUpdate}px`
if (currentPosition <= this.resetPosition) {
// If text reaches reset position, reset text
newPosition = `${this.startPosition}px`
}
this.$refs[this.elementId].style.left = newPosition
},
getCurrentPosition () {
let currentPosition = this.$refs[this.elementId].style.left
currentPosition = parseInt(currentPosition.replace('px', ''), 10)
if (!currentPosition) {
// Text runs from rtl, so set start position to right box end
currentPosition = this.startPosition
}
return currentPosition
},
},
}
</script>
<style lang="scss" scoped>
.newsticker {
height: 100px;
overflow: hidden;
position: relative;
&__text {
white-space: nowrap;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment