├── Makefile ├── README.md ├── demo.html ├── jquery.spincrement.js └── jquery.spincrement.min.js /Makefile: -------------------------------------------------------------------------------- 1 | jquery.spincrement.min.js: jquery.spincrement.js 2 | uglifyjs jquery.spincrement.js --compress --mangle --output jquery.spincrement.min.js 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spincrement 2 | 3 | A jQuery plugin for incrementing up to a certain number, for effect. 4 | 5 | See it in action [here](https://rawgit.com/johnjcamilleri/jquery-spincrement/master/demo.html). 6 | 7 | ## Usage 8 | 9 | ``` 10 | $('#selector').spincrement(options) 11 | ``` 12 | 13 | ## Options 14 | 15 | ### HTML Attributes 16 | 17 | Some things can be set at HTML attributes. 18 | These take precedence over the JavaScript options. 19 | 20 | | Attribute | Description | 21 | |:----------|:-----------------------| 22 | | data-from | Start from this number | 23 | | data-to | Count to this number | 24 | | data-dp | Decimal places | 25 | 26 | ### JavaScript options 27 | 28 | | Name | Default | Description | 29 | |:------------------|:--------------------|:------------------------------------------------------------------------| 30 | | from | 0 | Start from this number | 31 | | to | null | Count to this number. When null, use contents of element. | 32 | | decimalPlaces | null | How many decimal places. When null, determine from contents of element. | 33 | | decimalPoint | '.' | | 34 | | thousandSeparator | ',' | | 35 | | duration | 1000 | Total length of animation (ms) | 36 | | leeway | 50 | Amount to which duration may randomly vary (percent) | 37 | | easing | 'spincrementEasing' | Function ... | 38 | | fade | true | Use fade effect | 39 | | complete | null | Callback function called when animation is done | 40 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | jquery-spincrement demo 4 | 5 | 6 | 13 | 14 | 15 |

jquery-spincrement demo

16 |
17 | 18 |
19 |
20 | Simple: 95
21 | Thousands, override decimals: 16,060,606
22 | Inferred decimal places, from non-zero: 1.56
23 | Negative, with callback: -2.35
24 | HTML attributes: ...
25 |
26 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /jquery.spincrement.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery Spincrement plugin 3 | * 4 | * Plugin structure based on: http://blog.jeremymartin.name/2008/02/building-your-first-jquery-plugin-that.html 5 | * Leveraging of jQuery animate() based on: http://www.bennadel.com/blog/2007-Using-jQuery-s-animate-Method-To-Power-Easing-Based-Iteration.htm 6 | * Easing function from jQuery Easing plugin: http://gsgd.co.uk/sandbox/jquery/easing/ 7 | * Thousands separator code: http://www.webmasterworld.com/forum91/8.htm 8 | * 9 | * @author John J. Camilleri 10 | * @version 1.2 11 | */ 12 | 13 | /* global jQuery */ 14 | 15 | (function ($) { 16 | // Custom easing function 17 | $.extend($.easing, { 18 | // This is ripped directly from the jQuery easing plugin (easeOutExpo), from: http://gsgd.co.uk/sandbox/jquery/easing/ 19 | spincrementEasing: function (x, t, b, c, d) { 20 | return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b 21 | } 22 | }) 23 | 24 | // Spincrement function 25 | $.fn.spincrement = function (opts) { 26 | // Default values 27 | var defaults = { 28 | from: 0, 29 | to: null, 30 | decimalPlaces: null, 31 | decimalPoint: '.', 32 | thousandSeparator: ',', 33 | duration: 1000, // ms; TOTAL length animation 34 | leeway: 50, // percent of duraion 35 | easing: 'spincrementEasing', 36 | fade: true, 37 | complete: null 38 | } 39 | var options = $.extend(defaults, opts) 40 | 41 | // Function for formatting number 42 | var re_thouSep = new RegExp(/^(-?[0-9]+)([0-9]{3})/) 43 | function format (num, dp) { 44 | num = num.toFixed(dp) // converts to string! 45 | 46 | // Non "." decimal point 47 | if ((dp > 0) && (options.decimalPoint !== '.')) { 48 | num = num.replace('.', options.decimalPoint) 49 | } 50 | 51 | // Thousands separator 52 | if (options.thousandSeparator) { 53 | while (re_thouSep.test(num)) { 54 | num = num.replace(re_thouSep, '$1' + options.thousandSeparator + '$2') 55 | } 56 | } 57 | return num 58 | } 59 | 60 | // Apply to each matching item 61 | return this.each(function () { 62 | // Get handle on current obj 63 | var obj = $(this) 64 | 65 | // Set params FOR THIS ELEM 66 | var from = options.from 67 | if (obj.attr('data-from')) { 68 | from = parseFloat(obj.attr('data-from')) 69 | } 70 | 71 | var to 72 | if (obj.attr('data-to')) { 73 | to = parseFloat(obj.attr('data-to')) 74 | } else if (options.to !== null) { 75 | to = options.to 76 | } else { 77 | var ts = $.inArray(options.thousandSeparator, ['\\', '^', '$', '*', '+', '?', '.']) > -1 ? '\\' + options.thousandSeparator : options.thousandSeparator 78 | var re = new RegExp(ts, 'g') 79 | to = parseFloat(obj.text().replace(re, '')) 80 | } 81 | 82 | var duration = options.duration 83 | if (options.leeway) { 84 | // If leeway is set, randomise duration a little 85 | duration += Math.round(options.duration * ((Math.random() * 2) - 1) * options.leeway / 100) 86 | } 87 | 88 | var dp 89 | if (obj.attr('data-dp')) { 90 | dp = parseInt(obj.attr('data-dp'), 10) 91 | } else if (options.decimalPlaces !== null) { 92 | dp = options.decimalPlaces 93 | } else { 94 | var ix = obj.text().indexOf(options.decimalPoint) 95 | dp = (ix > -1) ? obj.text().length - (ix + 1) : 0 96 | } 97 | 98 | // Start 99 | obj.css('counter', from) 100 | if (options.fade) obj.css('opacity', 0) 101 | obj.animate( 102 | { 103 | counter: to, 104 | opacity: 1 105 | }, 106 | { 107 | easing: options.easing, 108 | duration: duration, 109 | 110 | // Invoke the callback for each step. 111 | step: function (progress) { 112 | obj.html(format(progress * to, dp)) 113 | }, 114 | complete: function () { 115 | // Cleanup 116 | obj.css('counter', null) 117 | obj.html(format(to, dp)) 118 | 119 | // user's callback 120 | if (options.complete) { 121 | options.complete(obj) 122 | } 123 | } 124 | } 125 | ) 126 | }) 127 | } 128 | })(jQuery) 129 | -------------------------------------------------------------------------------- /jquery.spincrement.min.js: -------------------------------------------------------------------------------- 1 | !function(t){t.extend(t.easing,{spincrementEasing:function(t,a,e,n,r){return a===r?e+n:n*(-Math.pow(2,-10*a/r)+1)+e}}),t.fn.spincrement=function(a){function e(t,a){if(t=t.toFixed(a),a>0&&"."!==r.decimalPoint&&(t=t.replace(".",r.decimalPoint)),r.thousandSeparator)for(;o.test(t);)t=t.replace(o,"$1"+r.thousandSeparator+"$2");return t}var n={from:0,to:null,decimalPlaces:null,decimalPoint:".",thousandSeparator:",",duration:1e3,leeway:50,easing:"spincrementEasing",fade:!0,complete:null},r=t.extend(n,a),o=new RegExp(/^(-?[0-9]+)([0-9]{3})/);return this.each(function(){var a=t(this),n=r.from;a.attr("data-from")&&(n=parseFloat(a.attr("data-from")));var o;if(a.attr("data-to"))o=parseFloat(a.attr("data-to"));else if(null!==r.to)o=r.to;else{var i=t.inArray(r.thousandSeparator,["\\","^","$","*","+","?","."])>-1?"\\"+r.thousandSeparator:r.thousandSeparator,l=new RegExp(i,"g");o=parseFloat(a.text().replace(l,""))}var c=r.duration;r.leeway&&(c+=Math.round(r.duration*(2*Math.random()-1)*r.leeway/100));var s;if(a.attr("data-dp"))s=parseInt(a.attr("data-dp"),10);else if(null!==r.decimalPlaces)s=r.decimalPlaces;else{var d=a.text().indexOf(r.decimalPoint);s=d>-1?a.text().length-(d+1):0}a.css("counter",n),r.fade&&a.css("opacity",0),a.animate({counter:o,opacity:1},{easing:r.easing,duration:c,step:function(t){a.html(e(t*o,s))},complete:function(){a.css("counter",null),a.html(e(o,s)),r.complete&&r.complete(a)}})})}}(jQuery); --------------------------------------------------------------------------------