I'm trying to animate a counter that I've made with Vue.js.
The value is being animated by Tween.js and then formatted with Numeral js but I'm having an issue.
I'd like to increment by a random amount, and when I increment, animate the number from whatever it is currently showing to the new total.
I have num
which holds the final value of the counter, and displayNum
which holds the animating value.
The issue is that my current code (if you hammer the increment button) sometimes starts animating the number from 0, rather than the current total. Especially when you get to over 1,000.
How can I stop this behaviour?
At present, whenever you click increment it takes the currently displayed number and starts a new tween to the target number.
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
var v = new Vue({
'el' : '#app',
'data' : {
num : 0,
displayNum : 0,
tween : false
},
methods:{
increment(){
var vm = this;
// select a random number and add it to our target
vm.num += Math.round(Math.random() * 300);
// create an object that we can use tween.js to animate
var anim = { num: vm.displayNum };
// if we are already animating, stop the animation
if( vm.tween ){
vm.tween.stop();
}
// create a new animation from the current number
vm.tween = new TWEEN.Tween(anim)
// to our new target
.to({ num : vm.num }, 3000)
.easing(TWEEN.Easing.Quadratic.Out)
.onUpdate(function() {
// Failed attempt to debug
if( anim.num < vm.displayNum ){
console.log("Something isn't right");
}
// on update, replace the display number with a rounded, formatted
// version of the animating number
vm.displayNum = numeral(Math.round(anim.num)).format('0,0');
})
// if the tween ever stops, set the vm's current tween to
// false
.onStop(function(){
vm.tween = false;
})
.start();
}
}
})
html, body{
height:100%;
}
body{
display:flex;
align-items:center;
justify-content:center;
}
.window{
width:200px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/r14/Tween.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<div class="window has-text-centered">
<div class="is-size-1">
<span v-html="displayNum"></span>
</div>
<div>
<button class="button" @click="increment">Increment</button>
</div>
<div class="is-size-7">
<span v-html="num"></span>
</div>
</div>
</div>
The problem is you are mixing strings and integers up. First, make sure displayNum is a string on the model and then when you initialize the animation make sure to parseInt it while removing the comma that shows up when you go over 999.
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
var v = new Vue({
'el' : '#app',
'data' : {
num : 0,
displayNum : "0",
tween : false
},
methods:{
increment(){
var vm = this;
// select a random number and add it to our target
vm.num += Math.round(Math.random() * 300);
// create an object that we can use tween.js to animate
var anim = { num: parseInt(vm.displayNum.replace(",","")) };
// if we are already animating, stop the animation
if( vm.tween ){
vm.tween.stop();
}
// create a new animation from the current number
vm.tween = new TWEEN.Tween(anim)
// to our new target
.to({ num : vm.num }, 3000)
.easing(TWEEN.Easing.Quadratic.Out)
.onUpdate(function() {
// Failed attempt to debug
//if( anim.num < vm.displayNum ){
// console.log("Something isn't right", anim, vm.displayNum);
//}
// on update, replace the display number with a rounded, formatted
// version of the animating number
vm.displayNum = numeral(Math.round(anim.num)).format('0,0');
})
// if the tween ever stops, set the vm's current tween to
// false
.onStop(function(){
vm.tween = false;
})
.start();
}
}
})
html, body{
height:100%;
}
body{
display:flex;
align-items:center;
justify-content:center;
}
.window{
width:200px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/r14/Tween.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<div class="window has-text-centered">
<div class="is-size-1">
<span v-html="displayNum"></span>
</div>
<div>
<button class="button" @click="increment">Increment</button>
</div>
<div class="is-size-7">
<span v-html="num"></span>
</div>
</div>
</div>