├── 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);
--------------------------------------------------------------------------------