### i made the big number move

go check it out. if it isn't going up auto-magically, watch it longer. skip the blog post and read the code in a gist.

### the hard part was easy

all i had to do was sign up for Pusher, include the Pusher gem (this is a Rails app), and push data to pusher at the end of the contribution flow. I chose to do this after the email receipt was sent. Nothing critical happens after this point, and this was happening in the background, so great. Send receipt, send "cha-ching" message to pusher.

that was so easy i took a moment to feel the future rays from the future sun hit me in the future face in the future. and i knew the gladness of living in the future.

### the easy part was hard!

so now with this little bit we can subscribe to the magic future beams of data from pusher.

new Pusher(pusherKey).subscribe("actblue_production").bind('new_contribution', BigNumber.update);

still easy. now, we need to animate the number as contributions roll in.

### problem 1: racing contributions

we could get 2 contributions in quick succession, so that the second comes before the first has finished animating.

my strategy: store the target display total in the jQuery 'data' of the element. animate to that stored number, instead of animating according to the number received in the push.

BigNumber.update: function(data) { var storedAmount = BigNumber.element.data('amount'); var total = storedAmount + data.amount; BigNumber.element.data('amount', total); return BigNumber.startAnimation(); };

### problem 2: the really busy day vs. looking good

if the rate of animation isn't high enough, there would exist a rate of cash flowing in so that the animating "Big Number" would never catch up.

**solution 1**: just make the rate really really fast. this idea sucks, it looks like crap as just renders a meaningless blur of numbers as contributions come in. it also means that, aside from short bursts, the big number is seldom moving. it would be nicer if it looked like the number was always moving!

**solution 2**: increase the rate as the displayed number falls further and further behind reality. this got complicated!

BigNumber.animate: function() { if (BigNumber.displayedAmount() >= BigNumber.currentAmount()) { BigNumber.stopAnimation(); } else { var tick, interval, skew = BigNumber.skew(); if(skew < BigNumber.tau / BigNumber.maxInterval) { tick = BigNumber.minTick; interval = BigNumber.maxInterval; } else if(skew < BigNumber.tau / BigNumber.minInterval) { tick = BigNumber.minTick; interval = Math.ceil(BigNumber.tau / skew); } else { interval = BigNumber.minInterval; tick = Math.ceil(skew * BigNumber.minInterval / BigNumber.tau); } BigNumber.adjustAnimation(interval); var newTotal = BigNumber.displayedAmount() + tick; BigNumber.element.text(BigNumber.commify(newTotal)); } };

### problem 3: i don't trust this at all

what if pusher hiccups? i'm afraid you out there are staring at our number and checking our math. solution: just send the whole total with every push to pusher. why not? it's free. so that update function from above, i was a bit insincere, it actually looks like this:

BigNumber.update: function(data) { var total, storedAmount = BigNumber.element.data('amount'); if(data.total > storedAmount) { total = data.total + data.amount; } else { total = storedAmount + data.amount; } BigNumber.element.data('amount', total); return BigNumber.startAnimation(); },

and to stop and start the animation i use good old setInterval and clearInterval:

BigNumber.startAnimation: function() { if(!BigNumber.defined(BigNumber.intervalId) || BigNumber.intervalId == null) { BigNumber.intervalId = setInterval(BigNumber.animate, BigNumber.currentInterval); } return BigNumber; }; BigNumber.stopAnimation: function() { clearInterval(BigNumber.intervalId); BigNumber.intervalId = null; return BigNumber; };

someday I'll even restyle it. check out the gist here: https://gist.github.com/1570978

## Comments