| (function (factory) { |
| if (typeof define === 'function' && define.amd) { |
| // AMD |
| define(['jquery'], factory); |
| } else if (typeof exports === 'object') { |
| // CommonJS |
| factory(require('jquery')); |
| } else { |
| // Browser globals |
| factory(jQuery); |
| } |
| }(function ($) { |
| var CountTo = function (element, options) { |
| this.$element = $(element); |
| this.options = $.extend({}, CountTo.DEFAULTS, this.dataOptions(), options); |
| this.init(); |
| }; |
| |
| CountTo.DEFAULTS = { |
| from: 0, // the number the element should start at |
| to: 0, // the number the element should end at |
| speed: 1000, // how long it should take to count between the target numbers |
| refreshInterval: 100, // how often the element should be updated |
| decimals: 0, // the number of decimal places to show |
| formatter: formatter, // handler for formatting the value before rendering |
| onUpdate: null, // callback method for every time the element is updated |
| onComplete: null // callback method for when the element finishes updating |
| }; |
| |
| CountTo.prototype.init = function () { |
| this.value = this.options.from; |
| this.loops = Math.ceil(this.options.speed / this.options.refreshInterval); |
| this.loopCount = 0; |
| this.increment = (this.options.to - this.options.from) / this.loops; |
| }; |
| |
| CountTo.prototype.dataOptions = function () { |
| var options = { |
| from: this.$element.data('from'), |
| to: this.$element.data('to'), |
| speed: this.$element.data('speed'), |
| refreshInterval: this.$element.data('refresh-interval'), |
| decimals: this.$element.data('decimals') |
| }; |
| |
| var keys = Object.keys(options); |
| |
| for (var i in keys) { |
| var key = keys[i]; |
| |
| if (typeof(options[key]) === 'undefined') { |
| delete options[key]; |
| } |
| } |
| |
| return options; |
| }; |
| |
| CountTo.prototype.update = function () { |
| this.value += this.increment; |
| this.loopCount++; |
| |
| this.render(); |
| |
| if (typeof(this.options.onUpdate) == 'function') { |
| this.options.onUpdate.call(this.$element, this.value); |
| } |
| |
| if (this.loopCount >= this.loops) { |
| clearInterval(this.interval); |
| this.value = this.options.to; |
| |
| if (typeof(this.options.onComplete) == 'function') { |
| this.options.onComplete.call(this.$element, this.value); |
| } |
| } |
| }; |
| |
| CountTo.prototype.render = function () { |
| var formattedValue = this.options.formatter.call(this.$element, this.value, this.options); |
| this.$element.text(formattedValue); |
| }; |
| |
| CountTo.prototype.restart = function () { |
| this.stop(); |
| this.init(); |
| this.start(); |
| }; |
| |
| CountTo.prototype.start = function () { |
| this.stop(); |
| this.render(); |
| this.interval = setInterval(this.update.bind(this), this.options.refreshInterval); |
| }; |
| |
| CountTo.prototype.stop = function () { |
| if (this.interval) { |
| clearInterval(this.interval); |
| } |
| }; |
| |
| CountTo.prototype.toggle = function () { |
| if (this.interval) { |
| this.stop(); |
| } else { |
| this.start(); |
| } |
| }; |
| |
| function formatter(value, options) { |
| return value.toFixed(options.decimals); |
| } |
| |
| $.fn.countTo = function (option) { |
| return this.each(function () { |
| var $this = $(this); |
| var data = $this.data('countTo'); |
| var init = !data || typeof(option) === 'object'; |
| var options = typeof(option) === 'object' ? option : {}; |
| var method = typeof(option) === 'string' ? option : 'start'; |
| |
| if (init) { |
| if (data) data.stop(); |
| $this.data('countTo', data = new CountTo(this, options)); |
| } |
| |
| data[method].call(data); |
| }); |
| }; |
| })); |