├── img ├── bg-tile.png ├── digits.png ├── digits.psd ├── digits-min.png └── time-placeholder.png ├── css └── media.css ├── index.html ├── README.md └── js ├── jquery.countdown.min.js └── jquery.countdown.js /img/bg-tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/download/jquery-countdown/master/img/bg-tile.png -------------------------------------------------------------------------------- /img/digits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/download/jquery-countdown/master/img/digits.png -------------------------------------------------------------------------------- /img/digits.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/download/jquery-countdown/master/img/digits.psd -------------------------------------------------------------------------------- /img/digits-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/download/jquery-countdown/master/img/digits-min.png -------------------------------------------------------------------------------- /img/time-placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/download/jquery-countdown/master/img/time-placeholder.png -------------------------------------------------------------------------------- /css/media.css: -------------------------------------------------------------------------------- 1 | html, body, .wrapper { 2 | height: 100%; 3 | width: 100%; 4 | } 5 | body { background: url(../img/bg-tile.png) repeat; } 6 | 7 | .wrapper { display: table; } 8 | 9 | .cell { 10 | display: table-cell; 11 | margin: 0; 12 | padding: 0; 13 | text-align: center; 14 | vertical-align: middle; 15 | } 16 | 17 | #holder { 18 | width: 603px; 19 | height: 383px; 20 | margin: auto; 21 | } 22 | 23 | .cntSeparator { display: none; } 24 | 25 | .cntDigit { 26 | margin-top: 148px !important; 27 | } 28 | 29 | .cntDigit#cnt_0 { margin-left: 52px; } 30 | .cntDigit#cnt_2 { margin-left: 7px; } 31 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jquery-countdown plugin test 5 | 6 | 7 | 8 | 17 | 18 | 19 | Fork me on GitHub 20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery Countdown 2 | 3 | jQuery Countdown is a countdown library with an amazing animation. Take a look 4 | at the [demonstration](http://reflejo.github.com/jquery-countdown/) 5 | 6 | Now you can download the PSD file 7 | [here](https://github.com/Reflejo/jquery-countdown/blob/master/img/digits.psd). 8 | 9 | ### Basic usage: 10 | 11 | ```javascript 12 | $('#counter').countdown({startTime: "01:12:32:55"}); 13 | ``` 14 | 15 | ### Complete usage: 16 | 17 | ```javascript 18 | $('#counter').countdown({ 19 | stepTime: 60, 20 | format: 'hh:mm:ss', 21 | startTime: "12:32:55", 22 | digitImages: 6, 23 | digitWidth: 53, 24 | digitHeight: 77, 25 | timerEnd: function() { alert('end!!'); }, 26 | image: "digits.png" 27 | }); 28 | ``` 29 | 30 | ### Added continuous countdown 31 | 32 | ```javascript 33 | $('#counter').countdown({ 34 | format: 'sss', 35 | startTime: "120", 36 | continuous: true, 37 | timerEnd: function() { alert('end!!'); }, 38 | image: "digits.png" 39 | }); 40 | ``` 41 | 42 | ### Countdown to a Date 43 | 44 | Relative to current hour: 45 | 46 | ```javascript 47 | $('#counter').countdown({ 48 | image: "digits.png", 49 | format: "mm:ss", 50 | endTime: '50:00' 51 | }); 52 | ``` 53 | 54 | An absolute date: 55 | 56 | 57 | ```javascript 58 | $('#counter').countdown({ 59 | image: "digits.png", 60 | format: "mm:ss", 61 | endTime: new Date('07/16/13 05:00:00') 62 | }); 63 | ``` 64 | 65 | Start manually the counter: 66 | 67 | ```javascript 68 | $('#counter').countdown({ 69 | image: "digits.png", 70 | format: "mm:ss", 71 | endTime: new Date('07/16/13 05:00:00'), 72 | start: false 73 | }); 74 | $("#startButton").click(function (e) { 75 | $('#counter').start(); 76 | }); 77 | ``` 78 | 79 | Did I mention that js code weighs just **4.0 KB**? 80 | 81 | ### Developers 82 | 83 | - Martín Conte Mac Donell - - [@fz](https://twitter.com/fz) 84 | - [Matt Neary](http://mattneary.com) - 85 | 86 | ### Demo 87 | 88 | Look at the [demo](http://reflejo.github.com/jquery-countdown/). 89 | 90 | -------------------------------------------------------------------------------- /js/jquery.countdown.min.js: -------------------------------------------------------------------------------- 1 | var createDigits=function(t,e){var i,n,r=0;digits=[],intervals=[];for(var a=0;a=0){if(elem=$('
').css({height:e.digitHeight,"float":"left",background:"url('"+e.image+"')",width:e.digitWidth}),elem.current=parseInt(e.startTime[a]),digits.push(elem),margin(r,-elem.current*e.digitHeight*e.digitImages),e.continuous===!0)digits[r]._max=function(){return 9};else switch(e.format[a]){case"h":digits[r]._max=function(t,e){return t%2==0?2:e?3:9};break;case"d":digits[r]._max=function(){return 9};break;case"m":digits[r]._max=function(t){return i||(i=t),t==i?9:5};break;case"s":digits[r]._max=function(t){return n||(n=t),t==n?9:5}}r+=1}else elem=$('
').css({"float":"left"}).text(e.startTime[a]);t.append(elem)}},makeMovement=function(t,e,i,n){intervals[t]&&window.clearInterval(intervals[t]);var r=-(n.digitHeight*n.digitImages*digits[t].current);margin(t,r),digits[t].current=digits[t].current+(i?e:-e);var a=0;intervals[t]=setInterval(function(){if(a++===n.digitImages*e)return window.clearInterval(intervals[t]),void delete intervals[t];var s=i?-n.digitHeight:n.digitHeight;margin(t,r+a*s)},n.stepTime/e)},margin=function(t,e){return void 0!==e?(digits[t].margin=e,digits[t].css({backgroundPosition:"0 "+e+"px"})):digits[t].margin||0},moveDigit=function(t,e){if(0!=digits[t].current)makeMovement(t,1,!1,e);else if(t>0){var i=0==digits[t-1].current;makeMovement(t,digits[t]._max(t,i),!0,e),moveDigit(t-1,e)}else{for(var n=0;n 5 | * Dual licensed under the MIT and GPL licenses. 6 | * http://docs.jquery.com/License 7 | * 8 | */ 9 | 10 | // Draw digits in given container 11 | var createDigits = function(where, options) { 12 | var counter = 0; 13 | // Iterate each startTime digit, if it is not a digit 14 | // we'll asume that it's a separator 15 | var mFirstPos, sFirstPos; 16 | // reset digits and intervals array. 17 | digits = []; 18 | intervals = []; 19 | 20 | for (var i = 0; i < options.startTime.length; i++) { 21 | if (parseInt(options.startTime[i]) >= 0) { 22 | elem = $('
').css({ 23 | height: options.digitHeight, 24 | float: 'left', 25 | background: 'url(\'' + options.image + '\')', 26 | width: options.digitWidth 27 | }); 28 | 29 | elem.current = parseInt(options.startTime[i]); 30 | digits.push(elem); 31 | 32 | margin(counter, -elem.current * options.digitHeight * options.digitImages); 33 | 34 | if (options.continuous === true) { 35 | digits[counter]._max = function() { return 9; }; 36 | } else { 37 | // Add max digits, for example, first digit of minutes (mm) has 38 | // a max of 5. Conditional max is used when the left digit has reach 39 | // the max. For example second "hours" digit has a conditional max of 4 40 | switch (options.format[i]) { 41 | case 'h': 42 | digits[counter]._max = function(pos, isStart) { 43 | if (pos % 2 == 0) 44 | return 2; 45 | else 46 | return (isStart) ? 3: 9; 47 | }; 48 | break; 49 | case 'd': 50 | digits[counter]._max = function() { return 9; }; 51 | break; 52 | case 'm': 53 | digits[counter]._max = function(pos) { 54 | if(!mFirstPos) { mFirstPos = pos; } 55 | return pos == mFirstPos ? 9 : 5; 56 | }; 57 | break; 58 | case 's': 59 | digits[counter]._max = function(pos) { 60 | if(!sFirstPos) { sFirstPos = pos; } 61 | return pos == sFirstPos ? 9 : 5; 62 | }; 63 | } 64 | } 65 | 66 | counter += 1; 67 | } else { 68 | elem = $('
').css({float: 'left'}) 69 | .text(options.startTime[i]); 70 | } 71 | where.append(elem) 72 | } 73 | }; 74 | 75 | var makeMovement = function(elem, steps, isForward, options) { 76 | // Stop any other movement over the same digit. 77 | if (intervals[elem]) 78 | window.clearInterval(intervals[elem]); 79 | 80 | // Move to the initial position (We force that because in chrome 81 | // there are some scenarios where digits lost sync) 82 | var initialPos = -(options.digitHeight * options.digitImages * 83 | digits[elem].current); 84 | margin(elem, initialPos); 85 | digits[elem].current = digits[elem].current + ((isForward) ? steps: -steps); 86 | 87 | var x = 0; 88 | intervals[elem] = setInterval(function() { 89 | if (x++ === options.digitImages * steps) { 90 | window.clearInterval(intervals[elem]); 91 | delete intervals[elem]; 92 | return; 93 | } 94 | 95 | var diff = isForward ? -options.digitHeight: options.digitHeight; 96 | margin(elem, initialPos + (x * diff)); 97 | }, options.stepTime / steps); 98 | }; 99 | 100 | // Set or get element margin 101 | var margin = function(elem, val) { 102 | if (val !== undefined) { 103 | digits[elem].margin = val; 104 | return digits[elem].css({'backgroundPosition': '0 ' + val + 'px'}); 105 | } 106 | 107 | return digits[elem].margin || 0; 108 | }; 109 | 110 | 111 | // Makes the movement. This is done by "digitImages" steps. 112 | var moveDigit = function(elem, options) { 113 | if (digits[elem].current == 0) { 114 | // Is there still time left? 115 | if (elem > 0) { 116 | var isStart = (digits[elem - 1].current == 0); 117 | 118 | makeMovement(elem, digits[elem]._max(elem, isStart), true, options); 119 | moveDigit(elem - 1, options); 120 | } else { // That condition means that we reach the end! 00:00. 121 | for (var i = 0; i < digits.length; i++) { 122 | clearInterval(intervals[i]); 123 | clearInterval(intervals.main); 124 | margin(i, 0); 125 | } 126 | options.timerEnd(); 127 | } 128 | return; 129 | } 130 | makeMovement(elem, 1, false, options); 131 | }; 132 | 133 | 134 | 135 | // parses a date of the form hh:mm:ss, for example, where 136 | // ... precision is the same as the format. 137 | var parseRelativeDate = function(form, options) { 138 | // give the date the values of now by default 139 | var now = new Date(); 140 | var d = now.getDate(); 141 | var m = now.getMonth() + 1; 142 | var y = now.getFullYear(); 143 | var h = now.getHours(), mm, s; 144 | 145 | // read in components and render based on format 146 | var format = options.format; 147 | var parts = form.split(':'); 148 | if( format.indexOf('dd') == 0 ) { 149 | d = parts[0]; 150 | parts = parts.slice(1); 151 | format = format.substr(3); 152 | } 153 | if( format.indexOf('hh') == 0 ) { 154 | h = parts[0]; 155 | parts = parts.slice(1); 156 | format = format.substr(3); 157 | } 158 | if( format.indexOf('mm') == 0 ) { 159 | mm = parts[0]; 160 | parts = parts.slice(1); 161 | format = format.substr(3); 162 | } 163 | if( format.indexOf('ss') == 0 ) { 164 | s = parts[0]; 165 | parts = parts.slice(1); 166 | format = format.substr(3); 167 | } 168 | // return our constructed date object 169 | return new Date([m, d, y].join('/') + ' ' + [h, mm, s].map(pad).join(':') + ' GMT-0900'); 170 | }; 171 | 172 | 173 | // convert a date object to the format specified 174 | var formatCompute = function(d, options) { 175 | var format = options.format; 176 | var parse = { 177 | d: Math.floor( ( d - new Date( d.getFullYear(), 0, 1 ) ) / ( 1000 * 60 * 60 * 24 ) ), 178 | h: d.getUTCHours(), 179 | m: d.getUTCMinutes(), 180 | s: d.getUTCSeconds() 181 | }; 182 | return format.replace(/(dd|hh|mm|ss)/g, function($0, form) { 183 | return pad(parse[form[0]]); 184 | }); 185 | }; 186 | 187 | // add leading zeros 188 | var pad = function(x){return (1e15+""+x).slice(-2)}; 189 | 190 | var start = function (element) { 191 | if (element.attr('started') != 'true') { 192 | element.attr('started', true) 193 | intervals.main = setInterval(function () { 194 | moveDigit(digits.length - 1, element.data('options')); 195 | }, 196 | 1000); 197 | } 198 | }; 199 | 200 | var digits = []; 201 | var intervals = []; 202 | jQuery.fn.countdown = function(userOptions) { 203 | // Default options 204 | var options = { 205 | stepTime: 60, 206 | // startTime and format MUST follow the same format. 207 | // also you cannot specify a format unordered (e.g. hh:ss:mm is wrong) 208 | format: "dd:hh:mm:ss", 209 | startTime: "01:12:32:55", 210 | digitImages: 6, 211 | digitWidth: 67, 212 | digitHeight: 90, 213 | timerEnd: function(){}, 214 | image: "digits.png", 215 | continuous: false, 216 | start: true 217 | }; 218 | $.extend(options, userOptions); 219 | 220 | // if an endTime is provided... 221 | if( userOptions.endTime ) { 222 | // calculate the difference between endTime and present time 223 | var endDate = userOptions.endTime instanceof Date ? userOptions.endTime : parseRelativeDate(userOptions.endTime, options); 224 | var diff = endDate.getTime() - (new Date()).getTime(); 225 | // and set that as the startTime 226 | userOptions.startTime = formatCompute(new Date(diff), options); 227 | delete userOptions.endTime; 228 | } 229 | $.extend(options, userOptions); 230 | if (this.length) { 231 | clearInterval(intervals.main); 232 | createDigits(this, options); 233 | this.data('options', options); 234 | if (options.start === true) { 235 | start(this); 236 | } 237 | } 238 | }; 239 | 240 | // start the counter 241 | jQuery.fn.start = function () { 242 | start(this); 243 | }; 244 | --------------------------------------------------------------------------------