├── .gitignore
├── docs
├── images
│ └── odometer.gif
├── welcome
│ ├── onepage-scroll.css
│ ├── landing-page.coffee
│ ├── landing-page.js
│ ├── landing-page.css
│ ├── onepage-scroll.js
│ └── index.html
├── api
│ └── themes.md
└── intro.md
├── .hsdoc
├── config.rb
├── sass
├── odometer-theme-minimal.sass
├── odometer-theme-default.sass
├── odometer-theme-digital.sass
├── odometer-theme-plaza.sass
├── odometer-theme-train-station.sass
├── odometer-theme-car.sass
├── odometer-theme-slot-machine.sass
└── _mixins.sass
├── README.md
├── component.json
├── test
├── demo.html
└── performance.html
├── package.json
├── bower.json
├── LICENSE
├── Gruntfile.coffee
├── themes
├── odometer-theme-minimal.css
├── odometer-theme-default.css
├── odometer-theme-plaza.css
├── odometer-theme-digital.css
├── odometer-theme-train-station.css
├── odometer-theme-car.css
└── odometer-theme-slot-machine.css
├── odometer.min.js
├── odometer.coffee
└── odometer.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .sass-cache/
--------------------------------------------------------------------------------
/docs/images/odometer.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HubSpot/odometer/HEAD/docs/images/odometer.gif
--------------------------------------------------------------------------------
/.hsdoc:
--------------------------------------------------------------------------------
1 | title: "Odometer"
2 | source: "odometer.coffee"
3 | examples: "**/*.md"
4 | assets: "{docs/welcome/*,odometer.js,themes/*}"
5 |
--------------------------------------------------------------------------------
/config.rb:
--------------------------------------------------------------------------------
1 | preferred_syntax = :sass
2 | css_dir = './themes'
3 | sass_dir = './sass'
4 | output_style = :expanded
5 | environment = :production
--------------------------------------------------------------------------------
/sass/odometer-theme-minimal.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 | @import mixins
3 |
4 | $themeName: "odometer-theme-minimal"
5 |
6 | +spinning-odometer($themeName)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Odometer
2 | ========
3 |
4 | Odometer is a Javascript and CSS library for smoothly transitioning numbers.
5 |
6 | ### [Overview](http://github.hubspot.com/odometer/docs/welcome)
7 | ### [Docs and Demo](http://github.hubspot.com/odometer)
8 |
--------------------------------------------------------------------------------
/sass/odometer-theme-default.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 | @import mixins
3 |
4 | $themeName: "odometer-theme-default"
5 |
6 | +spinning-odometer($themeName)
7 |
8 | .odometer.odometer-auto-theme, .odometer#{"." + $themeName}
9 | font-family: "Helvetica Neue", sans-serif
10 | line-height: 1.1em
11 |
12 | .odometer-value
13 | text-align: center
--------------------------------------------------------------------------------
/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "odometer",
3 | "version": "0.4.8",
4 | "repo": "hubspot/odometer",
5 | "description": "Transition numbers with ease",
6 | "keywords": [
7 | "odometer",
8 | "car",
9 | "number",
10 | "transition",
11 | "animation",
12 | "slot",
13 | "machine",
14 | "turnstile",
15 | "javascript",
16 | "client-side"
17 | ],
18 | "styles": ["themes/odometer-theme-default.css"],
19 | "scripts": [
20 | "odometer.js"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/test/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
13 |
14 |
15 |
16 |
3252
17 |
18 |
23 |
--------------------------------------------------------------------------------
/sass/odometer-theme-digital.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 | @import mixins
3 | @import url("//fonts.googleapis.com/css?family=Wallpoet")
4 |
5 | $themeName: "odometer-theme-digital"
6 | $green: #8bf5a5
7 |
8 | +spinning-odometer($themeName)
9 |
10 | .odometer.odometer-auto-theme, .odometer#{"." + $themeName}
11 | +background-image(radial-gradient(rgba($green, 0.4), #000))
12 | background-color: #000
13 | font-family: "Wallpoet", monospace
14 | padding: 0 .2em
15 | line-height: 1.1em
16 | color: $green
17 |
18 | .odometer-digit + .odometer-digit
19 | margin-left: .1em
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "odometer",
3 | "version": "0.4.8",
4 | "description": "Transition numbers with ease",
5 | "main": "odometer.js",
6 | "authors": [
7 | "Adam Schwartz ",
8 | "Zack Bloom "
9 | ],
10 | "license": "MIT",
11 | "devDependencies": {
12 | "grunt-contrib-coffee": "~0.7.0",
13 | "coffee-script": "~1.6.3",
14 | "grunt-contrib-uglify": "~0.2.4",
15 | "grunt-cli": "~0.1.9",
16 | "grunt": "~0.4.1",
17 | "grunt-contrib-watch": "~0.5.3",
18 | "grunt-contrib-compass": "~0.5.0",
19 | "color": "~0.4.4"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "odometer",
3 | "main": "odometer.js",
4 | "version": "0.4.8",
5 | "homepage": "http://github.hubspot.com/odometer/docs/welcome",
6 | "authors": [
7 | "Zack Bloom ",
8 | "Adam Schwartz "
9 | ],
10 | "description": "Transition numbers with ease",
11 | "keywords": [
12 | "odometer",
13 | "car",
14 | "number",
15 | "transition",
16 | "animation",
17 | "slot",
18 | "machine",
19 | "turnstile",
20 | "javascript",
21 | "client-side"
22 | ],
23 | "license": "MIT",
24 | "ignore": [
25 | "**/.*",
26 | "node_modules",
27 | "bower_components"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/sass/odometer-theme-plaza.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 | @import mixins
3 |
4 | $themeName: "odometer-theme-plaza"
5 | $digitPadding: .03em
6 |
7 | +spinning-odometer($themeName)
8 |
9 | .odometer.odometer-auto-theme, .odometer#{"." + $themeName}
10 | +border-radius(.15em)
11 | background-color: #f0f8ff
12 | font-family: "Helvetica Neue", sans-serif
13 | font-weight: 100
14 | padding: 0 .12em
15 | line-height: 1.2em
16 | font-size: 1.2em
17 | background-size: 16px 16px
18 |
19 | .odometer-digit
20 | +border-radius(.1em)
21 | padding: 0 $digitPadding
22 | color: #648baf
23 |
24 | .odometer-digit-inner
25 | left: $digitPadding
26 |
--------------------------------------------------------------------------------
/sass/odometer-theme-train-station.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 | @import mixins
3 | @import url("//fonts.googleapis.com/css?family=Economica")
4 |
5 | $themeName: "odometer-theme-train-station"
6 | $digitPadding: .15em
7 |
8 | +spinning-odometer($themeName)
9 |
10 | .odometer.odometer-auto-theme, .odometer#{"." + $themeName}
11 | font-family: "Economica", sans-serif
12 |
13 | .odometer-digit
14 | +inline-block
15 | +border-radius(.1em)
16 | +background-image(linear-gradient(top, #111 0%, #111 35%, #333 55%, #111 55%, #111 100%))
17 | background-color: #222
18 | padding: 0 $digitPadding
19 | color: #fff
20 |
21 | + .odometer-digit
22 | margin-left: .1em
23 |
24 | .odometer-digit-inner
25 | left: $digitPadding
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 HubSpot, Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
9 |
--------------------------------------------------------------------------------
/Gruntfile.coffee:
--------------------------------------------------------------------------------
1 | Path = require('path')
2 | fs = require('fs')
3 |
4 | module.exports = (grunt) ->
5 | grunt.initConfig
6 | pkg: grunt.file.readJSON("package.json")
7 |
8 | coffee:
9 | compile:
10 | files:
11 | 'odometer.js': 'odometer.coffee'
12 | 'docs/welcome/landing-page.js': 'docs/welcome/landing-page.coffee'
13 |
14 | watch:
15 | coffee:
16 | files: ['odometer.coffee', 'docs/welcome/landing-page.coffee', 'sass/*']
17 | tasks: ["coffee", "uglify", "compass"]
18 |
19 | uglify:
20 | options:
21 | banner: "/*! <%= pkg.name %> <%= pkg.version %> */\n"
22 |
23 | dist:
24 | src: 'odometer.js'
25 | dest: 'odometer.min.js'
26 |
27 | compass:
28 | dist:
29 | options:
30 | sassDir: 'sass'
31 | cssDir: 'themes'
32 |
33 | grunt.loadNpmTasks 'grunt-contrib-watch'
34 | grunt.loadNpmTasks 'grunt-contrib-uglify'
35 | grunt.loadNpmTasks 'grunt-contrib-coffee'
36 | grunt.loadNpmTasks 'grunt-contrib-compass'
37 |
38 | grunt.registerTask 'default', ['coffee', 'uglify', 'compass']
39 |
--------------------------------------------------------------------------------
/sass/odometer-theme-car.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 | @import mixins
3 | @import url("//fonts.googleapis.com/css?family=Arimo")
4 |
5 | $themeName: "odometer-theme-car"
6 | $padding: .15em
7 | $borderRadius: .2em
8 |
9 | +spinning-odometer($themeName)
10 |
11 | .odometer.odometer-auto-theme, .odometer#{"." + $themeName}
12 | +border-radius(.34em)
13 | font-family: "Arimo", monospace
14 | padding: $padding
15 | background: #000
16 | color: #eee0d3
17 |
18 | .odometer-digit
19 | +box-shadow(inset 0 0 .3em rgba(0, 0, 0, 0.8))
20 | +background-image(linear-gradient(top, #333 0%, #333 40%, #101010 60%, #333 80%, #333 100%))
21 | padding: 0 $padding
22 |
23 | &:first-child
24 | +border-radius($borderRadius 0 0 $borderRadius)
25 |
26 | &:last-child
27 | +border-radius(0 $borderRadius $borderRadius 0)
28 | +background-image(linear-gradient(top, #eee0d3 0%, #eee0d3 40%, #bbaa9a 60%, #eee0d3 80%, #eee0d3 100%))
29 | background-color: #eee0d3
30 | color: #000
31 |
32 | .odometer-digit-inner
33 | left: $padding
34 |
35 | &.odometer-animating-up .odometer-ribbon-inner, &.odometer-animating-down.odometer-animating .odometer-ribbon-inner
36 | -webkit-transition-timing-function: linear
37 | -moz-transition-timing-function: linear
38 | -ms-transition-timing-function: linear
39 | -o-transition-timing-function: linear
40 | transition-timing-function: linear
--------------------------------------------------------------------------------
/sass/odometer-theme-slot-machine.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 | @import mixins
3 | @import url("//fonts.googleapis.com/css?family=Rye")
4 |
5 | $themeName: "odometer-theme-slot-machine"
6 | $spacing: .15em
7 | $borderRadius: .2em
8 |
9 | +spinning-odometer($themeName)
10 |
11 | .odometer.odometer-auto-theme, .odometer#{"." + $themeName}
12 | +border-radius(.34em)
13 | +background-image(linear-gradient(#ff0, #ffa500))
14 | background-color: #fc0
15 | font-family: "Rye", monospace
16 | padding: $spacing
17 | color: #f80000
18 | line-height: 1.35em
19 | border: .03em solid #000
20 | -webkit-text-stroke: .05em #000
21 |
22 | .odometer-digit
23 | +box-shadow(inset 0 0 .1em rgba(0, 0, 0, 0.5), 0 0 0 .03em #fff, 0 0 0 .05em rgba(0, 0, 0, 0.2))
24 | +border-radius(.2em)
25 | +background-image(linear-gradient(top, #ccc 0%, #fff 20%, #fff 80%, #ccc 100%))
26 | border: .03em solid #444
27 | padding: .1em $spacing 0
28 |
29 | &:first-child
30 | +box-shadow(inset .05em 0 .1em rgba(0, 0, 0, 0.5), 0 0 0 .03em #fff, 0 0 0 .05em rgba(0, 0, 0, 0.2))
31 |
32 | &:last-child
33 | +box-shadow(inset -.05em 0 .1em rgba(0, 0, 0, 0.5), 0 0 0 .03em #fff, 0 0 0 .05em rgba(0, 0, 0, 0.2))
34 |
35 | + .odometer-digit
36 | margin-left: $spacing
37 |
38 | .odometer-digit-inner
39 | padding-top: .08em
40 |
41 | .odometer-digit-inner, .odometer-value.odometer-last-value
42 | left: 0
43 | right: 0
44 | text-align: center
--------------------------------------------------------------------------------
/test/performance.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
18 |
19 |
22 |
23 |
32 |
33 |
34 |
35 |
80 |
--------------------------------------------------------------------------------
/docs/welcome/onepage-scroll.css:
--------------------------------------------------------------------------------
1 | body, html {
2 | margin: 0;
3 | overflow: hidden;
4 | -webkit-transition: opacity 400ms;
5 | -moz-transition: opacity 400ms;
6 | transition: opacity 400ms;
7 | }
8 |
9 | body, .onepage-wrapper, html {
10 | display: block;
11 | position: static;
12 | padding: 0;
13 | width: 100%;
14 | height: 100%;
15 | }
16 |
17 | .main {
18 | height: 100%;
19 | }
20 |
21 | .onepage-wrapper {
22 | width: 100%;
23 | height: 100%;
24 | display: block;
25 | position: relative;
26 | padding: 0;
27 | -webkit-transform-style: preserve-3d;
28 | }
29 |
30 | .onepage-wrapper .section {
31 | width: 100%;
32 | height: 100%;
33 | }
34 |
35 | .onepage-pagination {
36 | position: absolute;
37 | margin: auto;
38 | right: 10px;
39 | left: auto;
40 | top: 0;
41 | bottom: 0;
42 | height: 190px;
43 | z-index: 5;
44 | list-style: none;
45 | padding: 0;
46 | }
47 |
48 | .onepage-pagination li {
49 | padding: 0;
50 | text-align: center;
51 | }
52 |
53 | .onepage-pagination li a{
54 | padding: 10px;
55 | width: 4px;
56 | height: 4px;
57 | display: block;
58 |
59 | }
60 | .onepage-pagination li a:before{
61 | content: '';
62 | position: absolute;
63 | width: 4px;
64 | height: 4px;
65 | background: rgba(0,0,0,0.85);
66 | border-radius: 10px;
67 | -webkit-border-radius: 10px;
68 | -moz-border-radius: 10px;
69 | }
70 |
71 | .onepage-pagination li a.active:before{
72 | width: 10px;
73 | height: 10px;
74 | background: none;
75 | border: 1px solid black;
76 | margin-top: -4px;
77 | left: 8px;
78 | }
79 |
80 | body.viewing-page-2 .onepage-pagination li a:before { background-color: #444; }
81 | body.viewing-page-2 .onepage-pagination li a.active:before { border-color: #444; background: none; }
82 |
83 | body.viewing-page-3 .onepage-pagination li a:before { background-color: #333; }
84 | body.viewing-page-3 .onepage-pagination li a.active:before { border-color: #333; background: none; }
85 | body.viewing-page-3 .social-sharing-wrapper { -webkit-filter: grayscale(1) sepia(1) hue-rotate(-47deg); }
86 | body.viewing-page-3 .social-sharing-wrapper:hover { -webkit-filter: none; }
87 |
88 | body.viewing-page-4 .onepage-pagination li a:before { background-color: #8bf5a5; }
89 | body.viewing-page-4 .onepage-pagination li a.active:before { border-color: #8bf5a5; background: none; }
90 | body.viewing-page-4 .social-sharing-wrapper { -webkit-filter: grayscale(1) contrast(1.3) invert(1); }
91 | body.viewing-page-4 .social-sharing-wrapper:hover { -webkit-filter: none; }
--------------------------------------------------------------------------------
/sass/_mixins.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 |
3 | =spinning-odometer($themeName)
4 | .odometer.odometer-auto-theme, .odometer#{"." + $themeName}
5 | +inline-block
6 | position: relative
7 |
8 | .odometer-digit
9 | +inline-block
10 | position: relative
11 |
12 | .odometer-digit-spacer
13 | +inline-block
14 | visibility: hidden
15 |
16 | .odometer-digit-inner
17 | text-align: left
18 | display: block
19 | position: absolute
20 | top: 0
21 | left: 0
22 | right: 0
23 | bottom: 0
24 | overflow: hidden
25 |
26 | .odometer-ribbon
27 | display: block
28 |
29 | .odometer-ribbon-inner
30 | display: block
31 | -webkit-backface-visibility: hidden
32 |
33 | .odometer-value
34 | display: block
35 | -webkit-transform: translateZ(0)
36 |
37 | &.odometer-last-value
38 | position: absolute
39 |
40 | &.odometer-animating-up
41 |
42 | .odometer-ribbon-inner
43 | -webkit-transition: -webkit-transform 2s
44 | -moz-transition: -moz-transform 2s
45 | -ms-transition: -ms-transform 2s
46 | -o-transition: -o-transform 2s
47 | transition: transform 2s
48 |
49 | &.odometer-animating .odometer-ribbon-inner
50 | -webkit-transform: translateY(-100%)
51 | -moz-transform: translateY(-100%)
52 | -ms-transform: translateY(-100%)
53 | -o-transform: translateY(-100%)
54 | transform: translateY(-100%)
55 |
56 | &.odometer-animating-down
57 |
58 | .odometer-ribbon-inner
59 | -webkit-transform: translateY(-100%)
60 | -moz-transform: translateY(-100%)
61 | -ms-transform: translateY(-100%)
62 | -o-transform: translateY(-100%)
63 | transform: translateY(-100%)
64 |
65 | &.odometer-animating .odometer-ribbon-inner
66 | -webkit-transition: -webkit-transform 2s
67 | -moz-transition: -moz-transform 2s
68 | -ms-transition: -ms-transform 2s
69 | -o-transition: -o-transform 2s
70 | transition: transform 2s
71 |
72 | -webkit-transform: translateY(0)
73 | -moz-transform: translateY(0)
74 | -ms-transform: translateY(0)
75 | -o-transform: translateY(0)
76 | transform: translateY(0)
--------------------------------------------------------------------------------
/themes/odometer-theme-minimal.css:
--------------------------------------------------------------------------------
1 | .odometer.odometer-auto-theme, .odometer.odometer-theme-minimal {
2 | display: inline-block;
3 | vertical-align: middle;
4 | *vertical-align: auto;
5 | *zoom: 1;
6 | *display: inline;
7 | position: relative;
8 | }
9 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-minimal .odometer-digit {
10 | display: inline-block;
11 | vertical-align: middle;
12 | *vertical-align: auto;
13 | *zoom: 1;
14 | *display: inline;
15 | position: relative;
16 | }
17 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-minimal .odometer-digit .odometer-digit-spacer {
18 | display: inline-block;
19 | vertical-align: middle;
20 | *vertical-align: auto;
21 | *zoom: 1;
22 | *display: inline;
23 | visibility: hidden;
24 | }
25 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-minimal .odometer-digit .odometer-digit-inner {
26 | text-align: left;
27 | display: block;
28 | position: absolute;
29 | top: 0;
30 | left: 0;
31 | right: 0;
32 | bottom: 0;
33 | overflow: hidden;
34 | }
35 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-minimal .odometer-digit .odometer-ribbon {
36 | display: block;
37 | }
38 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-minimal .odometer-digit .odometer-ribbon-inner {
39 | display: block;
40 | -webkit-backface-visibility: hidden;
41 | }
42 | .odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-minimal .odometer-digit .odometer-value {
43 | display: block;
44 | -webkit-transform: translateZ(0);
45 | }
46 | .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-minimal .odometer-digit .odometer-value.odometer-last-value {
47 | position: absolute;
48 | }
49 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-minimal.odometer-animating-up .odometer-ribbon-inner {
50 | -webkit-transition: -webkit-transform 2s;
51 | -moz-transition: -moz-transform 2s;
52 | -ms-transition: -ms-transform 2s;
53 | -o-transition: -o-transform 2s;
54 | transition: transform 2s;
55 | }
56 | .odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-minimal.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
57 | -webkit-transform: translateY(-100%);
58 | -moz-transform: translateY(-100%);
59 | -ms-transform: translateY(-100%);
60 | -o-transform: translateY(-100%);
61 | transform: translateY(-100%);
62 | }
63 | .odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-minimal.odometer-animating-down .odometer-ribbon-inner {
64 | -webkit-transform: translateY(-100%);
65 | -moz-transform: translateY(-100%);
66 | -ms-transform: translateY(-100%);
67 | -o-transform: translateY(-100%);
68 | transform: translateY(-100%);
69 | }
70 | .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-minimal.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
71 | -webkit-transition: -webkit-transform 2s;
72 | -moz-transition: -moz-transform 2s;
73 | -ms-transition: -ms-transform 2s;
74 | -o-transition: -o-transform 2s;
75 | transition: transform 2s;
76 | -webkit-transform: translateY(0);
77 | -moz-transform: translateY(0);
78 | -ms-transform: translateY(0);
79 | -o-transform: translateY(0);
80 | transform: translateY(0);
81 | }
82 |
--------------------------------------------------------------------------------
/docs/api/themes.md:
--------------------------------------------------------------------------------
1 | ## Themes
2 |
3 | To use a builtin theme, simply include the theme style sheet:
4 |
5 | ```html
6 |
7 | ```
8 |
9 |
25 |
26 | ### Multiple Themes on One Page
27 |
28 | If you need to use multipled Odometer themes on a single page, do the following.
29 |
30 | ```javascript
31 | odometerOptions = { auto: false }; // Disables auto-initialization
32 |
33 | // For each odometer, initialize with the theme passed in:
34 | var odometer = new Odometer({ el: $('.odometer')[0], value: 123, theme: 'car' });
35 | odometer.render();
36 | ```
37 |
38 |
39 |
40 |
41 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
73 |
--------------------------------------------------------------------------------
/themes/odometer-theme-default.css:
--------------------------------------------------------------------------------
1 | .odometer.odometer-auto-theme, .odometer.odometer-theme-default {
2 | display: inline-block;
3 | vertical-align: middle;
4 | *vertical-align: auto;
5 | *zoom: 1;
6 | *display: inline;
7 | position: relative;
8 | }
9 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-default .odometer-digit {
10 | display: inline-block;
11 | vertical-align: middle;
12 | *vertical-align: auto;
13 | *zoom: 1;
14 | *display: inline;
15 | position: relative;
16 | }
17 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-default .odometer-digit .odometer-digit-spacer {
18 | display: inline-block;
19 | vertical-align: middle;
20 | *vertical-align: auto;
21 | *zoom: 1;
22 | *display: inline;
23 | visibility: hidden;
24 | }
25 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-default .odometer-digit .odometer-digit-inner {
26 | text-align: left;
27 | display: block;
28 | position: absolute;
29 | top: 0;
30 | left: 0;
31 | right: 0;
32 | bottom: 0;
33 | overflow: hidden;
34 | }
35 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-default .odometer-digit .odometer-ribbon {
36 | display: block;
37 | }
38 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-default .odometer-digit .odometer-ribbon-inner {
39 | display: block;
40 | -webkit-backface-visibility: hidden;
41 | }
42 | .odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-default .odometer-digit .odometer-value {
43 | display: block;
44 | -webkit-transform: translateZ(0);
45 | }
46 | .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-default .odometer-digit .odometer-value.odometer-last-value {
47 | position: absolute;
48 | }
49 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-up .odometer-ribbon-inner {
50 | -webkit-transition: -webkit-transform 2s;
51 | -moz-transition: -moz-transform 2s;
52 | -ms-transition: -ms-transform 2s;
53 | -o-transition: -o-transform 2s;
54 | transition: transform 2s;
55 | }
56 | .odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
57 | -webkit-transform: translateY(-100%);
58 | -moz-transform: translateY(-100%);
59 | -ms-transform: translateY(-100%);
60 | -o-transform: translateY(-100%);
61 | transform: translateY(-100%);
62 | }
63 | .odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-down .odometer-ribbon-inner {
64 | -webkit-transform: translateY(-100%);
65 | -moz-transform: translateY(-100%);
66 | -ms-transform: translateY(-100%);
67 | -o-transform: translateY(-100%);
68 | transform: translateY(-100%);
69 | }
70 | .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-default.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
71 | -webkit-transition: -webkit-transform 2s;
72 | -moz-transition: -moz-transform 2s;
73 | -ms-transition: -ms-transform 2s;
74 | -o-transition: -o-transform 2s;
75 | transition: transform 2s;
76 | -webkit-transform: translateY(0);
77 | -moz-transform: translateY(0);
78 | -ms-transform: translateY(0);
79 | -o-transform: translateY(0);
80 | transform: translateY(0);
81 | }
82 |
83 | .odometer.odometer-auto-theme, .odometer.odometer-theme-default {
84 | font-family: "Helvetica Neue", sans-serif;
85 | line-height: 1.1em;
86 | }
87 | .odometer.odometer-auto-theme .odometer-value, .odometer.odometer-theme-default .odometer-value {
88 | text-align: center;
89 | }
90 |
--------------------------------------------------------------------------------
/themes/odometer-theme-plaza.css:
--------------------------------------------------------------------------------
1 | .odometer.odometer-auto-theme, .odometer.odometer-theme-plaza {
2 | display: inline-block;
3 | vertical-align: middle;
4 | *vertical-align: auto;
5 | *zoom: 1;
6 | *display: inline;
7 | position: relative;
8 | }
9 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-plaza .odometer-digit {
10 | display: inline-block;
11 | vertical-align: middle;
12 | *vertical-align: auto;
13 | *zoom: 1;
14 | *display: inline;
15 | position: relative;
16 | }
17 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-plaza .odometer-digit .odometer-digit-spacer {
18 | display: inline-block;
19 | vertical-align: middle;
20 | *vertical-align: auto;
21 | *zoom: 1;
22 | *display: inline;
23 | visibility: hidden;
24 | }
25 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-plaza .odometer-digit .odometer-digit-inner {
26 | text-align: left;
27 | display: block;
28 | position: absolute;
29 | top: 0;
30 | left: 0;
31 | right: 0;
32 | bottom: 0;
33 | overflow: hidden;
34 | }
35 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-plaza .odometer-digit .odometer-ribbon {
36 | display: block;
37 | }
38 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-plaza .odometer-digit .odometer-ribbon-inner {
39 | display: block;
40 | -webkit-backface-visibility: hidden;
41 | }
42 | .odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-plaza .odometer-digit .odometer-value {
43 | display: block;
44 | -webkit-transform: translateZ(0);
45 | }
46 | .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-plaza .odometer-digit .odometer-value.odometer-last-value {
47 | position: absolute;
48 | }
49 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-plaza.odometer-animating-up .odometer-ribbon-inner {
50 | -webkit-transition: -webkit-transform 2s;
51 | -moz-transition: -moz-transform 2s;
52 | -ms-transition: -ms-transform 2s;
53 | -o-transition: -o-transform 2s;
54 | transition: transform 2s;
55 | }
56 | .odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-plaza.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
57 | -webkit-transform: translateY(-100%);
58 | -moz-transform: translateY(-100%);
59 | -ms-transform: translateY(-100%);
60 | -o-transform: translateY(-100%);
61 | transform: translateY(-100%);
62 | }
63 | .odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-plaza.odometer-animating-down .odometer-ribbon-inner {
64 | -webkit-transform: translateY(-100%);
65 | -moz-transform: translateY(-100%);
66 | -ms-transform: translateY(-100%);
67 | -o-transform: translateY(-100%);
68 | transform: translateY(-100%);
69 | }
70 | .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-plaza.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
71 | -webkit-transition: -webkit-transform 2s;
72 | -moz-transition: -moz-transform 2s;
73 | -ms-transition: -ms-transform 2s;
74 | -o-transition: -o-transform 2s;
75 | transition: transform 2s;
76 | -webkit-transform: translateY(0);
77 | -moz-transform: translateY(0);
78 | -ms-transform: translateY(0);
79 | -o-transform: translateY(0);
80 | transform: translateY(0);
81 | }
82 |
83 | .odometer.odometer-auto-theme, .odometer.odometer-theme-plaza {
84 | -moz-border-radius: 0.15em;
85 | -webkit-border-radius: 0.15em;
86 | border-radius: 0.15em;
87 | background-color: #f0f8ff;
88 | font-family: "Helvetica Neue", sans-serif;
89 | font-weight: 100;
90 | padding: 0 0.12em;
91 | line-height: 1.2em;
92 | font-size: 1.2em;
93 | background-size: 16px 16px;
94 | }
95 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-plaza .odometer-digit {
96 | -moz-border-radius: 0.1em;
97 | -webkit-border-radius: 0.1em;
98 | border-radius: 0.1em;
99 | padding: 0 0.03em;
100 | color: #648baf;
101 | }
102 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-plaza .odometer-digit .odometer-digit-inner {
103 | left: 0.03em;
104 | }
105 |
--------------------------------------------------------------------------------
/docs/welcome/landing-page.coffee:
--------------------------------------------------------------------------------
1 | THEMES = [{
2 | name: 'minimal'
3 | numbers: [{
4 | number: 10000
5 | description: '= 282 + 962 = 602 + 802 '
6 | detail: 'two sums of two squares'
7 | source: 'http://www.wolframalpha.com/input/?i=10000'
8 | }, {
9 | number: 99999
10 | description: '= 11000011010011111 2 '
11 | detail: '11000011010011111 in base 2'
12 | source: 'http://www.wolframalpha.com/input/?i=99999'
13 | }]
14 | }, {
15 | name: 'car'
16 | odometerOptions:
17 | format: 'd'
18 | numbers: [{
19 | number: 13476
20 | description: 'miles driven'
21 | detail: 'by the average american each year'
22 | source: 'http://www.fhwa.dot.gov/ohim/onh00/bar8.htm'
23 | }, {
24 | number: 25114
25 | description: 'flat tires'
26 | detail: 'occur in america each hour'
27 | source: 'http://excelmathmike.blogspot.com/2011/04/phooey-on-flats-part-i.html'
28 | }]
29 | }, {
30 | name: 'digital'
31 | odometerOptions:
32 | format: 'd'
33 | numbers: [{
34 | number: 87360
35 | description: 'minutes of tv watched'
36 | detail: 'by the average american each year'
37 | source: 'http://www.nationmaster.com/graph/med_tel_vie-media-television-viewing'
38 | }, {
39 | number: 20938
40 | description: 'minutes snoozed'
41 | detail: 'by the average american each year'
42 | source: 'http://jsfiddle.net/adamschwartz/BWgWj/show/light/'
43 | }]
44 | }, {
45 | name: 'slot-machine'
46 | numbers: [{
47 | number: 818
48 | description: ''
49 | detail: ''
50 | source: ''
51 | }, {
52 | number: 777
53 | description: ''
54 | detail: ''
55 | source: ''
56 | }]
57 | }, {
58 | name: 'train-station'
59 | numbers: [{
60 | number: 682
61 | description: 'train cars'
62 | detail: 'on the longest train in the world'
63 | source: 'http://en.wikipedia.org/wiki/Longest_trains'
64 | }, {
65 | number: 853
66 | description: 'people'
67 | detail: 'capacity of the largest commercial airplane'
68 | source: 'http://en.wikipedia.org/wiki/Airbus_A380'
69 | }]
70 | }]
71 |
72 | animateHeader = ->
73 | $('.title-number-section .odometer').addClass 'odometer-animating-up odometer-animating'
74 |
75 | setupOnePageScroll = ->
76 | $ ->
77 | $('.main').onepage_scroll
78 | sectionContainer: '.section'
79 |
80 | $('.down-arrow').click -> $('.main').moveDown()
81 |
82 | $(document).keydown (e) ->
83 | switch e.keyCode
84 | when 40, 34 then $('.main').moveDown()
85 | when 33, 38 then $('.main').moveUp()
86 |
87 | setupNumberSections = ->
88 | $afterSections = $('.after-number-sections')
89 | $numberSectionTemplate = $('.number-section.template')
90 | $numberSectionTemplateClone = $numberSectionTemplate.clone().removeClass('template')
91 |
92 | _.each THEMES, (theme) ->
93 | $section = $numberSectionTemplateClone.clone().addClass('number-section-theme-' + theme.name)
94 |
95 | $afterSections.before $section
96 |
97 | $odometerContainer = $section.find '.odometer-container'
98 | $odometerContainer.append('
')
99 | $odometerContainer = $odometerContainer.find('div')
100 |
101 | currentNumber = 0
102 |
103 | odometerOptions = $.extend(true, {}, theme.odometerOptions or {},
104 | theme: theme.name
105 | value: theme.numbers[1].number
106 | el: $odometerContainer[0]
107 | )
108 |
109 | odometer = new Odometer odometerOptions
110 |
111 | odometer.render()
112 |
113 | next = ->
114 | number = theme.numbers[currentNumber]
115 | odometer.update number.number
116 | $section.find('.number-description').html number.description
117 | $section.find('.number-detail').html number.detail
118 | $section.find('.number-source').attr 'href', number.source
119 | currentNumber = (currentNumber + 1) % theme.numbers.length
120 |
121 | next()
122 |
123 | setInterval ->
124 | next() if $section.hasClass('active')
125 | , 4 * 1000
126 |
127 | $afterSections.remove()
128 | $numberSectionTemplate.remove()
129 |
130 | init = ->
131 | setupNumberSections()
132 | setupOnePageScroll()
133 | setTimeout ->
134 | animateHeader()
135 | , 500
136 |
137 | init()
138 |
--------------------------------------------------------------------------------
/themes/odometer-theme-digital.css:
--------------------------------------------------------------------------------
1 | @import url("//fonts.googleapis.com/css?family=Wallpoet");
2 | .odometer.odometer-auto-theme, .odometer.odometer-theme-digital {
3 | display: inline-block;
4 | vertical-align: middle;
5 | *vertical-align: auto;
6 | *zoom: 1;
7 | *display: inline;
8 | position: relative;
9 | }
10 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-digital .odometer-digit {
11 | display: inline-block;
12 | vertical-align: middle;
13 | *vertical-align: auto;
14 | *zoom: 1;
15 | *display: inline;
16 | position: relative;
17 | }
18 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-digital .odometer-digit .odometer-digit-spacer {
19 | display: inline-block;
20 | vertical-align: middle;
21 | *vertical-align: auto;
22 | *zoom: 1;
23 | *display: inline;
24 | visibility: hidden;
25 | }
26 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-digital .odometer-digit .odometer-digit-inner {
27 | text-align: left;
28 | display: block;
29 | position: absolute;
30 | top: 0;
31 | left: 0;
32 | right: 0;
33 | bottom: 0;
34 | overflow: hidden;
35 | }
36 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-digital .odometer-digit .odometer-ribbon {
37 | display: block;
38 | }
39 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-digital .odometer-digit .odometer-ribbon-inner {
40 | display: block;
41 | -webkit-backface-visibility: hidden;
42 | }
43 | .odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-digital .odometer-digit .odometer-value {
44 | display: block;
45 | -webkit-transform: translateZ(0);
46 | }
47 | .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-digital .odometer-digit .odometer-value.odometer-last-value {
48 | position: absolute;
49 | }
50 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-digital.odometer-animating-up .odometer-ribbon-inner {
51 | -webkit-transition: -webkit-transform 2s;
52 | -moz-transition: -moz-transform 2s;
53 | -ms-transition: -ms-transform 2s;
54 | -o-transition: -o-transform 2s;
55 | transition: transform 2s;
56 | }
57 | .odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-digital.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
58 | -webkit-transform: translateY(-100%);
59 | -moz-transform: translateY(-100%);
60 | -ms-transform: translateY(-100%);
61 | -o-transform: translateY(-100%);
62 | transform: translateY(-100%);
63 | }
64 | .odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-digital.odometer-animating-down .odometer-ribbon-inner {
65 | -webkit-transform: translateY(-100%);
66 | -moz-transform: translateY(-100%);
67 | -ms-transform: translateY(-100%);
68 | -o-transform: translateY(-100%);
69 | transform: translateY(-100%);
70 | }
71 | .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-digital.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
72 | -webkit-transition: -webkit-transform 2s;
73 | -moz-transition: -moz-transform 2s;
74 | -ms-transition: -ms-transform 2s;
75 | -o-transition: -o-transform 2s;
76 | transition: transform 2s;
77 | -webkit-transform: translateY(0);
78 | -moz-transform: translateY(0);
79 | -ms-transform: translateY(0);
80 | -o-transform: translateY(0);
81 | transform: translateY(0);
82 | }
83 |
84 | .odometer.odometer-auto-theme, .odometer.odometer-theme-digital {
85 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHJhZGlhbEdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY3g9IjUwJSIgY3k9IjUwJSIgcj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzhiZjVhNSIgc3RvcC1vcGFjaXR5PSIwLjQiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMDAwMDAiLz48L3JhZGlhbEdyYWRpZW50PjwvZGVmcz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPjwvc3ZnPiA=');
86 | background-size: 100%;
87 | background-image: -moz-radial-gradient(rgba(139, 245, 165, 0.4), #000000);
88 | background-image: -webkit-radial-gradient(rgba(139, 245, 165, 0.4), #000000);
89 | background-image: radial-gradient(rgba(139, 245, 165, 0.4), #000000);
90 | background-color: #000;
91 | font-family: "Wallpoet", monospace;
92 | padding: 0 0.2em;
93 | line-height: 1.1em;
94 | color: #8bf5a5;
95 | }
96 | .odometer.odometer-auto-theme .odometer-digit + .odometer-digit, .odometer.odometer-theme-digital .odometer-digit + .odometer-digit {
97 | margin-left: 0.1em;
98 | }
99 |
--------------------------------------------------------------------------------
/docs/welcome/landing-page.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var THEMES, animateHeader, init, setupNumberSections, setupOnePageScroll;
3 |
4 | THEMES = [
5 | {
6 | name: 'minimal',
7 | numbers: [
8 | {
9 | number: 10000,
10 | description: '= 282 + 962 = 602 + 802 ',
11 | detail: 'two sums of two squares',
12 | source: 'http://www.wolframalpha.com/input/?i=10000'
13 | }, {
14 | number: 99999,
15 | description: '= 11000011010011111 2 ',
16 | detail: '11000011010011111 in base 2',
17 | source: 'http://www.wolframalpha.com/input/?i=99999'
18 | }
19 | ]
20 | }, {
21 | name: 'car',
22 | odometerOptions: {
23 | format: 'd'
24 | },
25 | numbers: [
26 | {
27 | number: 13476,
28 | description: 'miles driven',
29 | detail: 'by the average american each year',
30 | source: 'http://www.fhwa.dot.gov/ohim/onh00/bar8.htm'
31 | }, {
32 | number: 25114,
33 | description: 'flat tires',
34 | detail: 'occur in america each hour',
35 | source: 'http://excelmathmike.blogspot.com/2011/04/phooey-on-flats-part-i.html'
36 | }
37 | ]
38 | }, {
39 | name: 'digital',
40 | odometerOptions: {
41 | format: 'd'
42 | },
43 | numbers: [
44 | {
45 | number: 87360,
46 | description: 'minutes of tv watched',
47 | detail: 'by the average american each year',
48 | source: 'http://www.nationmaster.com/graph/med_tel_vie-media-television-viewing'
49 | }, {
50 | number: 20938,
51 | description: 'minutes snoozed',
52 | detail: 'by the average american each year',
53 | source: 'http://jsfiddle.net/adamschwartz/BWgWj/show/light/'
54 | }
55 | ]
56 | }, {
57 | name: 'slot-machine',
58 | numbers: [
59 | {
60 | number: 818,
61 | description: '',
62 | detail: '',
63 | source: ''
64 | }, {
65 | number: 777,
66 | description: '',
67 | detail: '',
68 | source: ''
69 | }
70 | ]
71 | }, {
72 | name: 'train-station',
73 | numbers: [
74 | {
75 | number: 682,
76 | description: 'train cars',
77 | detail: 'on the longest train in the world',
78 | source: 'http://en.wikipedia.org/wiki/Longest_trains'
79 | }, {
80 | number: 853,
81 | description: 'people',
82 | detail: 'capacity of the largest commercial airplane',
83 | source: 'http://en.wikipedia.org/wiki/Airbus_A380'
84 | }
85 | ]
86 | }
87 | ];
88 |
89 | animateHeader = function() {
90 | return $('.title-number-section .odometer').addClass('odometer-animating-up odometer-animating');
91 | };
92 |
93 | setupOnePageScroll = function() {
94 | return $(function() {
95 | $('.main').onepage_scroll({
96 | sectionContainer: '.section'
97 | });
98 | $('.down-arrow').click(function() {
99 | return $('.main').moveDown();
100 | });
101 | return $(document).keydown(function(e) {
102 | switch (e.keyCode) {
103 | case 40:
104 | case 34:
105 | return $('.main').moveDown();
106 | case 33:
107 | case 38:
108 | return $('.main').moveUp();
109 | }
110 | });
111 | });
112 | };
113 |
114 | setupNumberSections = function() {
115 | var $afterSections, $numberSectionTemplate, $numberSectionTemplateClone;
116 | $afterSections = $('.after-number-sections');
117 | $numberSectionTemplate = $('.number-section.template');
118 | $numberSectionTemplateClone = $numberSectionTemplate.clone().removeClass('template');
119 | _.each(THEMES, function(theme) {
120 | var $odometerContainer, $section, currentNumber, next, odometer, odometerOptions;
121 | $section = $numberSectionTemplateClone.clone().addClass('number-section-theme-' + theme.name);
122 | $afterSections.before($section);
123 | $odometerContainer = $section.find('.odometer-container');
124 | $odometerContainer.append('
');
125 | $odometerContainer = $odometerContainer.find('div');
126 | currentNumber = 0;
127 | odometerOptions = $.extend(true, {}, theme.odometerOptions || {}, {
128 | theme: theme.name,
129 | value: theme.numbers[1].number,
130 | el: $odometerContainer[0]
131 | });
132 | odometer = new Odometer(odometerOptions);
133 | odometer.render();
134 | next = function() {
135 | var number;
136 | number = theme.numbers[currentNumber];
137 | odometer.update(number.number);
138 | $section.find('.number-description').html(number.description);
139 | $section.find('.number-detail').html(number.detail);
140 | $section.find('.number-source').attr('href', number.source);
141 | return currentNumber = (currentNumber + 1) % theme.numbers.length;
142 | };
143 | next();
144 | return setInterval(function() {
145 | if ($section.hasClass('active')) {
146 | return next();
147 | }
148 | }, 4 * 1000);
149 | });
150 | $afterSections.remove();
151 | return $numberSectionTemplate.remove();
152 | };
153 |
154 | init = function() {
155 | setupNumberSections();
156 | setupOnePageScroll();
157 | return setTimeout(function() {
158 | return animateHeader();
159 | }, 500);
160 | };
161 |
162 | init();
163 |
164 | }).call(this);
165 |
--------------------------------------------------------------------------------
/themes/odometer-theme-train-station.css:
--------------------------------------------------------------------------------
1 | @import url("//fonts.googleapis.com/css?family=Economica");
2 | .odometer.odometer-auto-theme, .odometer.odometer-theme-train-station {
3 | display: inline-block;
4 | vertical-align: middle;
5 | *vertical-align: auto;
6 | *zoom: 1;
7 | *display: inline;
8 | position: relative;
9 | }
10 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-train-station .odometer-digit {
11 | display: inline-block;
12 | vertical-align: middle;
13 | *vertical-align: auto;
14 | *zoom: 1;
15 | *display: inline;
16 | position: relative;
17 | }
18 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-train-station .odometer-digit .odometer-digit-spacer {
19 | display: inline-block;
20 | vertical-align: middle;
21 | *vertical-align: auto;
22 | *zoom: 1;
23 | *display: inline;
24 | visibility: hidden;
25 | }
26 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-train-station .odometer-digit .odometer-digit-inner {
27 | text-align: left;
28 | display: block;
29 | position: absolute;
30 | top: 0;
31 | left: 0;
32 | right: 0;
33 | bottom: 0;
34 | overflow: hidden;
35 | }
36 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-train-station .odometer-digit .odometer-ribbon {
37 | display: block;
38 | }
39 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-train-station .odometer-digit .odometer-ribbon-inner {
40 | display: block;
41 | -webkit-backface-visibility: hidden;
42 | }
43 | .odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-train-station .odometer-digit .odometer-value {
44 | display: block;
45 | -webkit-transform: translateZ(0);
46 | }
47 | .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-train-station .odometer-digit .odometer-value.odometer-last-value {
48 | position: absolute;
49 | }
50 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-train-station.odometer-animating-up .odometer-ribbon-inner {
51 | -webkit-transition: -webkit-transform 2s;
52 | -moz-transition: -moz-transform 2s;
53 | -ms-transition: -ms-transform 2s;
54 | -o-transition: -o-transform 2s;
55 | transition: transform 2s;
56 | }
57 | .odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-train-station.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
58 | -webkit-transform: translateY(-100%);
59 | -moz-transform: translateY(-100%);
60 | -ms-transform: translateY(-100%);
61 | -o-transform: translateY(-100%);
62 | transform: translateY(-100%);
63 | }
64 | .odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-train-station.odometer-animating-down .odometer-ribbon-inner {
65 | -webkit-transform: translateY(-100%);
66 | -moz-transform: translateY(-100%);
67 | -ms-transform: translateY(-100%);
68 | -o-transform: translateY(-100%);
69 | transform: translateY(-100%);
70 | }
71 | .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-train-station.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
72 | -webkit-transition: -webkit-transform 2s;
73 | -moz-transition: -moz-transform 2s;
74 | -ms-transition: -ms-transform 2s;
75 | -o-transition: -o-transform 2s;
76 | transition: transform 2s;
77 | -webkit-transform: translateY(0);
78 | -moz-transform: translateY(0);
79 | -ms-transform: translateY(0);
80 | -o-transform: translateY(0);
81 | transform: translateY(0);
82 | }
83 |
84 | .odometer.odometer-auto-theme, .odometer.odometer-theme-train-station {
85 | font-family: "Economica", sans-serif;
86 | }
87 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-train-station .odometer-digit {
88 | display: inline-block;
89 | vertical-align: middle;
90 | *vertical-align: auto;
91 | *zoom: 1;
92 | *display: inline;
93 | -moz-border-radius: 0.1em;
94 | -webkit-border-radius: 0.1em;
95 | border-radius: 0.1em;
96 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzExMTExMSIvPjxzdG9wIG9mZnNldD0iMzUlIiBzdG9wLWNvbG9yPSIjMTExMTExIi8+PHN0b3Agb2Zmc2V0PSI1NSUiIHN0b3AtY29sb3I9IiMzMzMzMzMiLz48c3RvcCBvZmZzZXQ9IjU1JSIgc3RvcC1jb2xvcj0iIzExMTExMSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzExMTExMSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
97 | background-size: 100%;
98 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #111111), color-stop(35%, #111111), color-stop(55%, #333333), color-stop(55%, #111111), color-stop(100%, #111111));
99 | background-image: -moz-linear-gradient(top, #111111 0%, #111111 35%, #333333 55%, #111111 55%, #111111 100%);
100 | background-image: -webkit-linear-gradient(top, #111111 0%, #111111 35%, #333333 55%, #111111 55%, #111111 100%);
101 | background-image: linear-gradient(to bottom, #111111 0%, #111111 35%, #333333 55%, #111111 55%, #111111 100%);
102 | background-color: #222;
103 | padding: 0 0.15em;
104 | color: #fff;
105 | }
106 | .odometer.odometer-auto-theme .odometer-digit + .odometer-digit, .odometer.odometer-theme-train-station .odometer-digit + .odometer-digit {
107 | margin-left: 0.1em;
108 | }
109 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-train-station .odometer-digit .odometer-digit-inner {
110 | left: 0.15em;
111 | }
112 |
--------------------------------------------------------------------------------
/docs/intro.md:
--------------------------------------------------------------------------------
1 | Odometer
2 | ========
3 |
4 |
36 |
37 |
38 |
41 |
42 |
43 |
80 |
81 | GitHub ★ s so far: 0
82 |
83 |
84 | Odometer is a Javascript and CSS library for smoothly transitioning numbers.
85 | See the [demo page](http://github.hubspot.com/odometer/docs/welcome) for some examples.
86 |
87 | Odometer's animations are handled entirely in CSS using transforms making
88 | them extremely performant, with automatic fallback on older browsers.
89 |
90 | The library and largest theme is less than 3kb when minified and compressed.
91 |
92 | All of [the themes](http://github.hubspot.com/odometer/api/themes/) can be resized by setting the `font-size` of the `.odometer` element.
93 |
94 | Usage
95 | -----
96 |
97 | **The simplest possible usage is just including [the javascript](https://raw.github.com/HubSpot/odometer/v0.4.8/odometer.min.js) and a [theme css](http://github.hubspot.com/odometer/api/themes/)
98 | file on your page. Add the `odometer` class to any numbers you'd like to animate on change. You're done.**
99 |
100 | Just set the `innerHTML`, `innerText`, or use jQuery's `.text()` or `.html()` methods to change their contents, and the animation
101 | will happen automatically. Any libraries you're using to update their value, provided they don't update by erasing and rerendering
102 | the `odometer` element, will work just fine.
103 |
104 | On older browsers, it will automatically fallback to a simpler animation which won't tax their fragile javascript runtime.
105 |
106 | Example
107 | -------
108 |
109 | 123
110 |
111 | Play with this simple example on [jsFiddle](http://jsfiddle.net/adamschwartz/rx6BQ/).
112 |
113 | Advanced
114 | --------
115 |
116 | You can set options by creating a `odometerOptions` object:
117 |
118 | ```javascript
119 | window.odometerOptions = {
120 | auto: false, // Don't automatically initialize everything with class 'odometer'
121 | selector: '.my-numbers', // Change the selector used to automatically find things to be animated
122 | format: '(,ddd).dd', // Change how digit groups are formatted, and how many digits are shown after the decimal point
123 | duration: 3000, // Change how long the javascript expects the CSS animation to take
124 | theme: 'car', // Specify the theme (if you have more than one theme css file on the page)
125 | animation: 'count' // Count is a simpler animation method which just increments the value,
126 | // use it when you're looking for something more subtle.
127 | };
128 | ```
129 |
130 | You can manually initialize an odometer with the global `Odometer`:
131 |
132 | ```javascript
133 | var el = document.querySelector('.some-element');
134 |
135 | od = new Odometer({
136 | el: el,
137 | value: 333555,
138 |
139 | // Any option (other than auto and selector) can be passed in here
140 | format: '',
141 | theme: 'digital'
142 | });
143 |
144 | od.update(555)
145 | // or
146 | el.innerHTML = 555
147 | ```
148 |
149 | Format
150 | ------
151 |
152 | The format option allows you to configure how the digit groups are formatted,
153 | and how many digits are shown after the decimal point.
154 |
155 | Format - Example
156 | (,ddd) - 12,345,678
157 | (,ddd).dd - 12,345,678.09
158 | (.ddd),dd - 12.345.678,09
159 | ( ddd),dd - 12 345 678,09
160 | d - 12345678
161 |
162 | Browser Support
163 | ---------------
164 |
165 | Odometer is intended to support IE8+, FF4+, Safari 6+, and Chrome.
166 |
167 | Dependencies
168 | ------------
169 |
170 | None!
171 |
172 | Contributing
173 | ------------
174 |
175 | Odometer is built using Grunt. To setup the build environment you first
176 | must have Node.js installed. Then:
177 |
178 | ```bash
179 | # In the project directory
180 | npm install
181 | ```
182 |
183 | To build the project:
184 | ```bash
185 | grunt
186 | ```
187 |
188 | To have it watch for changes and build automatically:
189 | ```bash
190 | grunt watch
191 | ```
192 |
193 | We welcome pull requests!
194 |
--------------------------------------------------------------------------------
/themes/odometer-theme-car.css:
--------------------------------------------------------------------------------
1 | @import url("//fonts.googleapis.com/css?family=Arimo");
2 | .odometer.odometer-auto-theme, .odometer.odometer-theme-car {
3 | display: inline-block;
4 | vertical-align: middle;
5 | *vertical-align: auto;
6 | *zoom: 1;
7 | *display: inline;
8 | position: relative;
9 | }
10 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-car .odometer-digit {
11 | display: inline-block;
12 | vertical-align: middle;
13 | *vertical-align: auto;
14 | *zoom: 1;
15 | *display: inline;
16 | position: relative;
17 | }
18 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-car .odometer-digit .odometer-digit-spacer {
19 | display: inline-block;
20 | vertical-align: middle;
21 | *vertical-align: auto;
22 | *zoom: 1;
23 | *display: inline;
24 | visibility: hidden;
25 | }
26 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-car .odometer-digit .odometer-digit-inner {
27 | text-align: left;
28 | display: block;
29 | position: absolute;
30 | top: 0;
31 | left: 0;
32 | right: 0;
33 | bottom: 0;
34 | overflow: hidden;
35 | }
36 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-car .odometer-digit .odometer-ribbon {
37 | display: block;
38 | }
39 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-car .odometer-digit .odometer-ribbon-inner {
40 | display: block;
41 | -webkit-backface-visibility: hidden;
42 | }
43 | .odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-car .odometer-digit .odometer-value {
44 | display: block;
45 | -webkit-transform: translateZ(0);
46 | }
47 | .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-car .odometer-digit .odometer-value.odometer-last-value {
48 | position: absolute;
49 | }
50 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-car.odometer-animating-up .odometer-ribbon-inner {
51 | -webkit-transition: -webkit-transform 2s;
52 | -moz-transition: -moz-transform 2s;
53 | -ms-transition: -ms-transform 2s;
54 | -o-transition: -o-transform 2s;
55 | transition: transform 2s;
56 | }
57 | .odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-car.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
58 | -webkit-transform: translateY(-100%);
59 | -moz-transform: translateY(-100%);
60 | -ms-transform: translateY(-100%);
61 | -o-transform: translateY(-100%);
62 | transform: translateY(-100%);
63 | }
64 | .odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-car.odometer-animating-down .odometer-ribbon-inner {
65 | -webkit-transform: translateY(-100%);
66 | -moz-transform: translateY(-100%);
67 | -ms-transform: translateY(-100%);
68 | -o-transform: translateY(-100%);
69 | transform: translateY(-100%);
70 | }
71 | .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-car.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
72 | -webkit-transition: -webkit-transform 2s;
73 | -moz-transition: -moz-transform 2s;
74 | -ms-transition: -ms-transform 2s;
75 | -o-transition: -o-transform 2s;
76 | transition: transform 2s;
77 | -webkit-transform: translateY(0);
78 | -moz-transform: translateY(0);
79 | -ms-transform: translateY(0);
80 | -o-transform: translateY(0);
81 | transform: translateY(0);
82 | }
83 |
84 | .odometer.odometer-auto-theme, .odometer.odometer-theme-car {
85 | -moz-border-radius: 0.34em;
86 | -webkit-border-radius: 0.34em;
87 | border-radius: 0.34em;
88 | font-family: "Arimo", monospace;
89 | padding: 0.15em;
90 | background: #000;
91 | color: #eee0d3;
92 | }
93 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-car .odometer-digit {
94 | -moz-box-shadow: inset 0 0 0.3em rgba(0, 0, 0, 0.8);
95 | -webkit-box-shadow: inset 0 0 0.3em rgba(0, 0, 0, 0.8);
96 | box-shadow: inset 0 0 0.3em rgba(0, 0, 0, 0.8);
97 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzMzMzMzMyIvPjxzdG9wIG9mZnNldD0iNDAlIiBzdG9wLWNvbG9yPSIjMzMzMzMzIi8+PHN0b3Agb2Zmc2V0PSI2MCUiIHN0b3AtY29sb3I9IiMxMDEwMTAiLz48c3RvcCBvZmZzZXQ9IjgwJSIgc3RvcC1jb2xvcj0iIzMzMzMzMyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzMzMzMzMyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
98 | background-size: 100%;
99 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #333333), color-stop(40%, #333333), color-stop(60%, #101010), color-stop(80%, #333333), color-stop(100%, #333333));
100 | background-image: -moz-linear-gradient(top, #333333 0%, #333333 40%, #101010 60%, #333333 80%, #333333 100%);
101 | background-image: -webkit-linear-gradient(top, #333333 0%, #333333 40%, #101010 60%, #333333 80%, #333333 100%);
102 | background-image: linear-gradient(to bottom, #333333 0%, #333333 40%, #101010 60%, #333333 80%, #333333 100%);
103 | padding: 0 0.15em;
104 | }
105 | .odometer.odometer-auto-theme .odometer-digit:first-child, .odometer.odometer-theme-car .odometer-digit:first-child {
106 | -moz-border-radius: 0.2em 0 0 0.2em;
107 | -webkit-border-radius: 0.2em;
108 | border-radius: 0.2em 0 0 0.2em;
109 | }
110 | .odometer.odometer-auto-theme .odometer-digit:last-child, .odometer.odometer-theme-car .odometer-digit:last-child {
111 | -moz-border-radius: 0 0.2em 0.2em 0;
112 | -webkit-border-radius: 0;
113 | border-radius: 0 0.2em 0.2em 0;
114 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VlZTBkMyIvPjxzdG9wIG9mZnNldD0iNDAlIiBzdG9wLWNvbG9yPSIjZWVlMGQzIi8+PHN0b3Agb2Zmc2V0PSI2MCUiIHN0b3AtY29sb3I9IiNiYmFhOWEiLz48c3RvcCBvZmZzZXQ9IjgwJSIgc3RvcC1jb2xvcj0iI2VlZTBkMyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2VlZTBkMyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
115 | background-size: 100%;
116 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eee0d3), color-stop(40%, #eee0d3), color-stop(60%, #bbaa9a), color-stop(80%, #eee0d3), color-stop(100%, #eee0d3));
117 | background-image: -moz-linear-gradient(top, #eee0d3 0%, #eee0d3 40%, #bbaa9a 60%, #eee0d3 80%, #eee0d3 100%);
118 | background-image: -webkit-linear-gradient(top, #eee0d3 0%, #eee0d3 40%, #bbaa9a 60%, #eee0d3 80%, #eee0d3 100%);
119 | background-image: linear-gradient(to bottom, #eee0d3 0%, #eee0d3 40%, #bbaa9a 60%, #eee0d3 80%, #eee0d3 100%);
120 | background-color: #eee0d3;
121 | color: #000;
122 | }
123 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-car .odometer-digit .odometer-digit-inner {
124 | left: 0.15em;
125 | }
126 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-car.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-car.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
127 | -webkit-transition-timing-function: linear;
128 | -moz-transition-timing-function: linear;
129 | -ms-transition-timing-function: linear;
130 | -o-transition-timing-function: linear;
131 | transition-timing-function: linear;
132 | }
133 |
--------------------------------------------------------------------------------
/docs/welcome/landing-page.css:
--------------------------------------------------------------------------------
1 | /* Prism.js */
2 | code[class*="language-"], pre[class*="language-"] {color: black; text-shadow: 0 1px white; font-family: Consolas, Monaco, 'Andale Mono', monospace; direction: ltr; text-align: left; white-space: pre; word-spacing: normal; -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; -webkit-hyphens: none; -moz-hyphens: none; -ms-hyphens: none; hyphens: none; } pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {text-shadow: none; background: #b3d4fc; } pre[class*="language-"]::selection, pre[class*="language-"] ::selection, code[class*="language-"]::selection, code[class*="language-"] ::selection {text-shadow: none; background: #b3d4fc; } @media print {code[class*="language-"], pre[class*="language-"] {text-shadow: none; } } /* Code blocks */ pre[class*="language-"] {padding: 1em; margin: .5em 0; overflow: auto; font-size: .7em; } :not(pre) > code[class*="language-"], pre[class*="language-"] {background: #f5f2f0; } /* Inline code */ :not(pre) > code[class*="language-"] {padding: .1em; border-radius: .3em; } .token.comment, .token.prolog, .token.doctype, .token.cdata {color: slategray; } .token.punctuation {color: #999; } .namespace {opacity: .7; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol {color: #905; } .token.selector, .token.attr-name, .token.string, .token.builtin {color: #690; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string, .token.variable {color: #a67f59; background: hsla(0,0%,100%,.5); } .token.atrule, .token.attr-value, .token.keyword {color: #07a; } .token.regex, .token.important {color: #e90; } .token.important {font-weight: bold; } .token.entity {cursor: help; }
3 |
4 | html, body {
5 | height: 100%;
6 | margin: 0;
7 | }
8 |
9 | html { font-size: 150%; }
10 | @media (max-width: 1200px) { html { font-size: 125%; } }
11 | @media (max-width: 1000px) { html { font-size: 100%; } }
12 | @media (max-width: 767px) { html { font-size: 80%; } }
13 | @media (max-width: 568px) { html { font-size: 50%; } }
14 | @media (max-width: 480px) { html { font-size: 35%; } }
15 | @media (max-width: 320px) { html { font-size: 25%; } }
16 |
17 | body {
18 | font-family: "proxima-nova", "Helvetica Neue", sans-serif;
19 | }
20 |
21 | .template {
22 | display: none;
23 | }
24 |
25 | .section {
26 | height: 100%;
27 | width: 100%;
28 | position: relative;
29 | -webkit-transform: translateZ(0);
30 | }
31 |
32 | .number-container, .about-section {
33 | position: absolute;
34 | margin: auto;
35 | top: 0;
36 | left: 0;
37 | right: 0;
38 | bottom: 0;
39 | width: 100%;
40 | height: 20em;
41 | text-align: center;
42 | -webkit-transform: translateZ(0);
43 | }
44 |
45 | .about-section {
46 | font-size: 1em;
47 | text-align: left;
48 | width: 30em;
49 | height: 22em;
50 | max-width: 80%;
51 | }
52 |
53 | .about-section h1 {
54 | margin-top: 0;
55 | text-align: center;
56 | }
57 |
58 | .about-section a {
59 | color: inherit;
60 | }
61 |
62 | .number-container .odometer-container {
63 | font-size: 6em;
64 | }
65 |
66 | .number-description {
67 | display: inline-block;
68 | text-transform: uppercase;
69 | font-size: 2.5em;
70 | letter-spacing: .08em;
71 | margin: 1em 0 0;
72 | font-weight: bold;
73 | }
74 |
75 | .number-detail {
76 | display: inline-block;
77 | text-transform: uppercase;
78 | font-size: 1.5em;
79 | letter-spacing: .08em;
80 | opacity: 0.5;
81 | }
82 |
83 | .title-number-section .number-container .odometer-container {
84 | font-size: 4em;
85 | }
86 |
87 | .title-number-section .number-description {
88 | font-size: 1.55em;
89 | margin: .5em 0 .25em;
90 | color: #666;
91 | }
92 |
93 | @media (max-width: 767px) {
94 | .title-number-section .number-container .odometer-container {
95 | font-size: 5em;
96 | }
97 |
98 | .title-number-section .number-description {
99 | font-size: 1.8em
100 | }
101 | }
102 |
103 | @media (max-width: 568px) {
104 | .title-number-section .number-container .odometer-container {
105 | font-size: 6em;
106 | }
107 |
108 | .title-number-section .number-description {
109 | font-size: 2.2em;
110 | }
111 | }
112 |
113 | .button {
114 | text-decoration: none;
115 | color: #000;
116 | font-size: 0.7em;
117 | padding: .3em .7em .4em;
118 | cursor: pointer;
119 | margin: 2em auto;
120 | border: .15em solid;
121 | display: inline-block;
122 | line-height: 1.7;
123 | }
124 |
125 | .dark-button {
126 | color: white;
127 | background-color: #222;
128 | }
129 |
130 | .number-source {
131 | text-decoration: none;
132 | color: inherit;
133 | }
134 |
135 | .number-source:hover .number-detail {
136 | border-bottom: 1px dotted;
137 | opacity: 0.8;
138 | }
139 |
140 | .number-section.number-section-theme-minimal {
141 | background: #eee;
142 | color: #444;
143 | }
144 |
145 | .number-section.number-section-theme-minimal .odometer.odometer-theme-minimal .odometer-digit .odometer-digit-inner {
146 | text-align: right;
147 | }
148 |
149 | .number-section.number-section-theme-digital .odometer {
150 | border: .1em solid rgba(139, 245, 165, 0.4);
151 | }
152 |
153 | .number-section.number-section-theme-digital {
154 | background: #000;
155 | color: #8bf5a5;
156 | }
157 |
158 | .number-section.number-section-theme-car {
159 | background: #eee0d3;
160 | color: #333;
161 | }
162 |
163 | .number-section.number-section-theme-train-station {
164 | background: #ccc;
165 | color: #000;
166 | }
167 |
168 | .number-section.number-section-theme-slot-machine {
169 | background-image: -webkit-gradient(linear, 0% 50%, 100% 50%, color-stop(0%, #000000), color-stop(2%, #000000), color-stop(2%, #ffa500), color-stop(50%, #ffe000), color-stop(98%, #ffa500), color-stop(98%, #000000), color-stop(100%, #000000));
170 | background-image: -webkit-linear-gradient(left, #000000 0%, #000000 2%, #ffa500 2%, #ffe000 50%, #ffa500 98%, #000000 98%, #000000 100%);
171 | background-image: -moz-linear-gradient(left, #000000 0%, #000000 2%, #ffa500 2%, #ffe000 50%, #ffa500 98%, #000000 98%, #000000 100%);
172 | background-image: -o-linear-gradient(left, #000000 0%, #000000 2%, #ffa500 2%, #ffe000 50%, #ffa500 98%, #000000 98%, #000000 100%);
173 | background-image: -ms-linear-gradient(left, #000000 0%, #000000 2%, #ffa500 2%, #ffe000 50%, #ffa500 98%, #000000 98%, #000000 100%);
174 | background-image: linear-gradient(left, #000000 0%, #000000 2%, #ffa500 2%, #ffe000 50%, #ffa500 98%, #000000 98%, #000000 100%);
175 | background-size: 31em 100%;
176 | background-repeat: no-repeat;
177 | background-position: center;
178 | color: #000;
179 | }
180 |
181 | .odometer.odometer-theme-odometer {
182 | line-height: 2em;
183 | }
184 |
185 | .odometer-theme-odometer:before {
186 | content: " ";
187 | position: absolute;
188 | left: 0;
189 | top: 0;
190 | width: 100%;
191 | height: .1em;
192 | background: #000;
193 | }
194 |
195 | .odometer-theme-odometer:after {
196 | content: " ";
197 | position: absolute;
198 | left: 0;
199 | bottom: 0;
200 | width: 100%;
201 | height: .1em;
202 | background: #000;
203 | }
204 |
205 | .odometer-theme-odometer .odometer-value {
206 | width: 100%;
207 | text-align: center;
208 | }
209 |
210 | .down-arrow {
211 | position: absolute;
212 | cursor: pointer;
213 | margin: auto;
214 | display: block;
215 | left: 0;
216 | right: 0;
217 | font-size: 2em;
218 | bottom: 1em;
219 | height: 1em;
220 | width: 1em;
221 | text-align: center;
222 | opacity: 0.5;
223 | -webkit-transform: translateZ(0);
224 | }
225 |
226 | .down-arrow:hover {
227 | opacity: 1;
228 | }
229 |
230 | .down-arrow:before {
231 | content: "\2193";
232 | display: block;
233 | }
234 |
235 | /* Social sharing */
236 |
237 | #retweet_button {
238 | position: fixed;
239 | bottom: 30px;
240 | left: 30px;
241 | width: 100px;
242 | z-index: 3;
243 | }
244 |
245 | #github_stars {
246 | position: fixed;
247 | bottom: 30px;
248 | left: 130px;
249 | width: 100px;
250 | z-index: 3;
251 | }
252 |
253 | .social-sharing-wrapper { -webkit-filter: grayscale(1) contrast(1.3); }
254 | .social-sharing-wrapper:hover { -webkit-filter: none; }
255 |
--------------------------------------------------------------------------------
/themes/odometer-theme-slot-machine.css:
--------------------------------------------------------------------------------
1 | @import url("//fonts.googleapis.com/css?family=Rye");
2 | .odometer.odometer-auto-theme, .odometer.odometer-theme-slot-machine {
3 | display: inline-block;
4 | vertical-align: middle;
5 | *vertical-align: auto;
6 | *zoom: 1;
7 | *display: inline;
8 | position: relative;
9 | }
10 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-slot-machine .odometer-digit {
11 | display: inline-block;
12 | vertical-align: middle;
13 | *vertical-align: auto;
14 | *zoom: 1;
15 | *display: inline;
16 | position: relative;
17 | }
18 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-spacer, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-digit-spacer {
19 | display: inline-block;
20 | vertical-align: middle;
21 | *vertical-align: auto;
22 | *zoom: 1;
23 | *display: inline;
24 | visibility: hidden;
25 | }
26 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-digit-inner {
27 | text-align: left;
28 | display: block;
29 | position: absolute;
30 | top: 0;
31 | left: 0;
32 | right: 0;
33 | bottom: 0;
34 | overflow: hidden;
35 | }
36 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-ribbon {
37 | display: block;
38 | }
39 | .odometer.odometer-auto-theme .odometer-digit .odometer-ribbon-inner, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-ribbon-inner {
40 | display: block;
41 | -webkit-backface-visibility: hidden;
42 | }
43 | .odometer.odometer-auto-theme .odometer-digit .odometer-value, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-value {
44 | display: block;
45 | -webkit-transform: translateZ(0);
46 | }
47 | .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-value.odometer-last-value {
48 | position: absolute;
49 | }
50 | .odometer.odometer-auto-theme.odometer-animating-up .odometer-ribbon-inner, .odometer.odometer-theme-slot-machine.odometer-animating-up .odometer-ribbon-inner {
51 | -webkit-transition: -webkit-transform 2s;
52 | -moz-transition: -moz-transform 2s;
53 | -ms-transition: -ms-transform 2s;
54 | -o-transition: -o-transform 2s;
55 | transition: transform 2s;
56 | }
57 | .odometer.odometer-auto-theme.odometer-animating-up.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-slot-machine.odometer-animating-up.odometer-animating .odometer-ribbon-inner {
58 | -webkit-transform: translateY(-100%);
59 | -moz-transform: translateY(-100%);
60 | -ms-transform: translateY(-100%);
61 | -o-transform: translateY(-100%);
62 | transform: translateY(-100%);
63 | }
64 | .odometer.odometer-auto-theme.odometer-animating-down .odometer-ribbon-inner, .odometer.odometer-theme-slot-machine.odometer-animating-down .odometer-ribbon-inner {
65 | -webkit-transform: translateY(-100%);
66 | -moz-transform: translateY(-100%);
67 | -ms-transform: translateY(-100%);
68 | -o-transform: translateY(-100%);
69 | transform: translateY(-100%);
70 | }
71 | .odometer.odometer-auto-theme.odometer-animating-down.odometer-animating .odometer-ribbon-inner, .odometer.odometer-theme-slot-machine.odometer-animating-down.odometer-animating .odometer-ribbon-inner {
72 | -webkit-transition: -webkit-transform 2s;
73 | -moz-transition: -moz-transform 2s;
74 | -ms-transition: -ms-transform 2s;
75 | -o-transition: -o-transform 2s;
76 | transition: transform 2s;
77 | -webkit-transform: translateY(0);
78 | -moz-transform: translateY(0);
79 | -ms-transform: translateY(0);
80 | -o-transform: translateY(0);
81 | transform: translateY(0);
82 | }
83 |
84 | .odometer.odometer-auto-theme, .odometer.odometer-theme-slot-machine {
85 | -moz-border-radius: 0.34em;
86 | -webkit-border-radius: 0.34em;
87 | border-radius: 0.34em;
88 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmYwMCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmYTUwMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
89 | background-size: 100%;
90 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffff00), color-stop(100%, #ffa500));
91 | background-image: -moz-linear-gradient(#ffff00, #ffa500);
92 | background-image: -webkit-linear-gradient(#ffff00, #ffa500);
93 | background-image: linear-gradient(#ffff00, #ffa500);
94 | background-color: #fc0;
95 | font-family: "Rye", monospace;
96 | padding: 0.15em;
97 | color: #f80000;
98 | line-height: 1.35em;
99 | border: 0.03em solid #000;
100 | -webkit-text-stroke: 0.05em #000;
101 | }
102 | .odometer.odometer-auto-theme .odometer-digit, .odometer.odometer-theme-slot-machine .odometer-digit {
103 | -moz-box-shadow: inset 0 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
104 | -webkit-box-shadow: inset 0 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
105 | box-shadow: inset 0 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
106 | -moz-border-radius: 0.2em;
107 | -webkit-border-radius: 0.2em;
108 | border-radius: 0.2em;
109 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2NjY2NjYyIvPjxzdG9wIG9mZnNldD0iMjAlIiBzdG9wLWNvbG9yPSIjZmZmZmZmIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNjY2NjY2MiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPjwvc3ZnPiA=');
110 | background-size: 100%;
111 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #cccccc), color-stop(20%, #ffffff), color-stop(80%, #ffffff), color-stop(100%, #cccccc));
112 | background-image: -moz-linear-gradient(top, #cccccc 0%, #ffffff 20%, #ffffff 80%, #cccccc 100%);
113 | background-image: -webkit-linear-gradient(top, #cccccc 0%, #ffffff 20%, #ffffff 80%, #cccccc 100%);
114 | background-image: linear-gradient(to bottom, #cccccc 0%, #ffffff 20%, #ffffff 80%, #cccccc 100%);
115 | border: 0.03em solid #444;
116 | padding: 0.1em 0.15em 0;
117 | }
118 | .odometer.odometer-auto-theme .odometer-digit:first-child, .odometer.odometer-theme-slot-machine .odometer-digit:first-child {
119 | -moz-box-shadow: inset 0.05em 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
120 | -webkit-box-shadow: inset 0.05em 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
121 | box-shadow: inset 0.05em 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
122 | }
123 | .odometer.odometer-auto-theme .odometer-digit:last-child, .odometer.odometer-theme-slot-machine .odometer-digit:last-child {
124 | -moz-box-shadow: inset -0.05em 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
125 | -webkit-box-shadow: inset -0.05em 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
126 | box-shadow: inset -0.05em 0 0.1em rgba(0, 0, 0, 0.5), 0 0 0 0.03em #fff, 0 0 0 0.05em rgba(0, 0, 0, 0.2);
127 | }
128 | .odometer.odometer-auto-theme .odometer-digit + .odometer-digit, .odometer.odometer-theme-slot-machine .odometer-digit + .odometer-digit {
129 | margin-left: 0.15em;
130 | }
131 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-digit-inner {
132 | padding-top: 0.08em;
133 | }
134 | .odometer.odometer-auto-theme .odometer-digit .odometer-digit-inner, .odometer.odometer-auto-theme .odometer-digit .odometer-value.odometer-last-value, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-digit-inner, .odometer.odometer-theme-slot-machine .odometer-digit .odometer-value.odometer-last-value {
135 | left: 0;
136 | right: 0;
137 | text-align: center;
138 | }
139 |
--------------------------------------------------------------------------------
/odometer.min.js:
--------------------------------------------------------------------------------
1 | /*! odometer 0.4.8 */
2 | (function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G=[].slice;q=' ',n=''+q+" ",d='8 '+n+" ",g=' ',c="(,ddd).dd",h=/^\(?([^)]*)\)?(?:(.)(d+))?$/,i=30,f=2e3,a=20,j=2,e=.5,k=1e3/i,b=1e3/a,o="transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd",y=document.createElement("div").style,p=null!=y.transition||null!=y.webkitTransition||null!=y.mozTransition||null!=y.oTransition,w=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,l=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,s=function(a){var b;return b=document.createElement("div"),b.innerHTML=a,b.children[0]},v=function(a,b){return a.className=a.className.replace(new RegExp("(^| )"+b.split(" ").join("|")+"( |$)","gi")," ")},r=function(a,b){return v(a,b),a.className+=" "+b},z=function(a,b){var c;return null!=document.createEvent?(c=document.createEvent("HTMLEvents"),c.initEvent(b,!0,!0),a.dispatchEvent(c)):void 0},u=function(){var a,b;return null!=(a=null!=(b=window.performance)&&"function"==typeof b.now?b.now():void 0)?a:+new Date},x=function(a,b){return null==b&&(b=0),b?(a*=Math.pow(10,b),a+=.5,a=Math.floor(a),a/=Math.pow(10,b)):Math.round(a)},A=function(a){return 0>a?Math.ceil(a):Math.floor(a)},t=function(a){return a-x(a)},C=!1,(B=function(){var a,b,c,d,e;if(!C&&null!=window.jQuery){for(C=!0,d=["html","text"],e=[],b=0,c=d.length;c>b;b++)a=d[b],e.push(function(a){var b;return b=window.jQuery.fn[a],window.jQuery.fn[a]=function(a){var c;return null==a||null==(null!=(c=this[0])?c.odometer:void 0)?b.apply(this,arguments):this[0].odometer.update(a)}}(a));return e}})(),setTimeout(B,0),m=function(){function a(b){var c,d,e,g,h,i,l,m,n,o,p=this;if(this.options=b,this.el=this.options.el,null!=this.el.odometer)return this.el.odometer;this.el.odometer=this,m=a.options;for(d in m)g=m[d],null==this.options[d]&&(this.options[d]=g);null==(h=this.options).duration&&(h.duration=f),this.MAX_VALUES=this.options.duration/k/j|0,this.resetFormat(),this.value=this.cleanValue(null!=(n=this.options.value)?n:""),this.renderInside(),this.render();try{for(o=["innerHTML","innerText","textContent"],i=0,l=o.length;l>i;i++)e=o[i],null!=this.el[e]&&!function(a){return Object.defineProperty(p.el,a,{get:function(){var b;return"innerHTML"===a?p.inside.outerHTML:null!=(b=p.inside.innerText)?b:p.inside.textContent},set:function(a){return p.update(a)}})}(e)}catch(q){c=q,this.watchForMutations()}}return a.prototype.renderInside=function(){return this.inside=document.createElement("div"),this.inside.className="odometer-inside",this.el.innerHTML="",this.el.appendChild(this.inside)},a.prototype.watchForMutations=function(){var a,b=this;if(null!=l)try{return null==this.observer&&(this.observer=new l(function(a){var c;return c=b.el.innerText,b.renderInside(),b.render(b.value),b.update(c)})),this.watchMutations=!0,this.startWatchingMutations()}catch(c){a=c}},a.prototype.startWatchingMutations=function(){return this.watchMutations?this.observer.observe(this.el,{childList:!0}):void 0},a.prototype.stopWatchingMutations=function(){var a;return null!=(a=this.observer)?a.disconnect():void 0},a.prototype.cleanValue=function(a){var b;return"string"==typeof a&&(a=a.replace(null!=(b=this.format.radix)?b:".",""),a=a.replace(/[.,]/g,""),a=a.replace("","."),a=parseFloat(a,10)||0),x(a,this.format.precision)},a.prototype.bindTransitionEnd=function(){var a,b,c,d,e,f,g=this;if(!this.transitionEndBound){for(this.transitionEndBound=!0,b=!1,e=o.split(" "),f=[],c=0,d=e.length;d>c;c++)a=e[c],f.push(this.el.addEventListener(a,function(){return b?!0:(b=!0,setTimeout(function(){return g.render(),b=!1,z(g.el,"odometerdone")},0),!0)},!1));return f}},a.prototype.resetFormat=function(){var a,b,d,e,f,g,i,j;if(a=null!=(i=this.options.format)?i:c,a||(a="d"),d=h.exec(a),!d)throw new Error("Odometer: Unparsable digit format");return j=d.slice(1,4),g=j[0],f=j[1],b=j[2],e=(null!=b?b.length:void 0)||0,this.format={repeating:g,radix:f,precision:e}},a.prototype.render=function(a){var b,c,d,e,f,g,h;for(null==a&&(a=this.value),this.stopWatchingMutations(),this.resetFormat(),this.inside.innerHTML="",f=this.options.theme,b=this.el.className.split(" "),e=[],g=0,h=b.length;h>g;g++)c=b[g],c.length&&((d=/^odometer-theme-(.+)$/.exec(c))?f=d[1]:/^odometer(-|$)/.test(c)||e.push(c));return e.push("odometer"),p||e.push("odometer-no-transitions"),f?e.push("odometer-theme-"+f):e.push("odometer-auto-theme"),this.el.className=e.join(" "),this.ribbons={},this.formatDigits(a),this.startWatchingMutations()},a.prototype.formatDigits=function(a){var b,c,d,e,f,g,h,i,j,k;if(this.digits=[],this.options.formatFunction)for(d=this.options.formatFunction(a),j=d.split("").reverse(),f=0,h=j.length;h>f;f++)c=j[f],c.match(/0-9/)?(b=this.renderDigit(),b.querySelector(".odometer-value").innerHTML=c,this.digits.push(b),this.insertDigit(b)):this.addSpacer(c);else for(e=!this.format.precision||!t(a)||!1,k=a.toString().split("").reverse(),g=0,i=k.length;i>g;g++)b=k[g],"."===b&&(e=!0),this.addDigit(b,e)},a.prototype.update=function(a){var b,c=this;return a=this.cleanValue(a),(b=a-this.value)?(v(this.el,"odometer-animating-up odometer-animating-down odometer-animating"),b>0?r(this.el,"odometer-animating-up"):r(this.el,"odometer-animating-down"),this.stopWatchingMutations(),this.animate(a),this.startWatchingMutations(),setTimeout(function(){return c.el.offsetHeight,r(c.el,"odometer-animating")},0),this.value=a):void 0},a.prototype.renderDigit=function(){return s(d)},a.prototype.insertDigit=function(a,b){return null!=b?this.inside.insertBefore(a,b):this.inside.children.length?this.inside.insertBefore(a,this.inside.children[0]):this.inside.appendChild(a)},a.prototype.addSpacer=function(a,b,c){var d;return d=s(g),d.innerHTML=a,c&&r(d,c),this.insertDigit(d,b)},a.prototype.addDigit=function(a,b){var c,d,e,f;if(null==b&&(b=!0),"-"===a)return this.addSpacer(a,null,"odometer-negation-mark");if("."===a)return this.addSpacer(null!=(f=this.format.radix)?f:".",null,"odometer-radix-mark");if(b)for(e=!1;;){if(!this.format.repeating.length){if(e)throw new Error("Bad odometer format without digits");this.resetFormat(),e=!0}if(c=this.format.repeating[this.format.repeating.length-1],this.format.repeating=this.format.repeating.substring(0,this.format.repeating.length-1),"d"===c)break;this.addSpacer(c)}return d=this.renderDigit(),d.querySelector(".odometer-value").innerHTML=a,this.digits.push(d),this.insertDigit(d)},a.prototype.animate=function(a){return p&&"count"!==this.options.animation?this.animateSlide(a):this.animateCount(a)},a.prototype.animateCount=function(a){var c,d,e,f,g,h=this;if(d=+a-this.value)return f=e=u(),c=this.value,(g=function(){var i,j,k;return u()-f>h.options.duration?(h.value=a,h.render(),void z(h.el,"odometerdone")):(i=u()-e,i>b&&(e=u(),k=i/h.options.duration,j=d*k,c+=j,h.render(Math.round(c))),null!=w?w(g):setTimeout(g,b))})()},a.prototype.getDigitCount=function(){var a,b,c,d,e,f;for(d=1<=arguments.length?G.call(arguments,0):[],a=e=0,f=d.length;f>e;a=++e)c=d[a],d[a]=Math.abs(c);return b=Math.max.apply(Math,d),Math.ceil(Math.log(b+1)/Math.log(10))},a.prototype.getFractionalDigitCount=function(){var a,b,c,d,e,f,g;for(e=1<=arguments.length?G.call(arguments,0):[],b=/^\-?\d*\.(\d*?)0*$/,a=f=0,g=e.length;g>f;a=++f)d=e[a],e[a]=d.toString(),c=b.exec(e[a]),null==c?e[a]=0:e[a]=c[1].length;return Math.max.apply(Math,e)},a.prototype.resetDigits=function(){return this.digits=[],this.ribbons=[],this.inside.innerHTML="",this.resetFormat()},a.prototype.animateSlide=function(a){var b,c,d,f,g,h,i,j,k,l,m,n,o,p,q,s,t,u,v,w,x,y,z,B,C,D,E;if(s=this.value,j=this.getFractionalDigitCount(s,a),j&&(a*=Math.pow(10,j),s*=Math.pow(10,j)),d=a-s){for(this.bindTransitionEnd(),f=this.getDigitCount(s,a),g=[],b=0,m=v=0;f>=0?f>v:v>f;m=f>=0?++v:--v){if(t=A(s/Math.pow(10,f-m-1)),i=A(a/Math.pow(10,f-m-1)),h=i-t,Math.abs(h)>this.MAX_VALUES){for(l=[],n=h/(this.MAX_VALUES+this.MAX_VALUES*b*e),c=t;h>0&&i>c||0>h&&c>i;)l.push(Math.round(c)),c+=n;l[l.length-1]!==i&&l.push(i),b++}else l=function(){E=[];for(var a=t;i>=t?i>=a:a>=i;i>=t?a++:a--)E.push(a);return E}.apply(this);for(m=w=0,y=l.length;y>w;m=++w)k=l[m],l[m]=Math.abs(k%10);g.push(l)}for(this.resetDigits(),D=g.reverse(),m=x=0,z=D.length;z>x;m=++x)for(l=D[m],this.digits[m]||this.addDigit(" ",m>=j),null==(u=this.ribbons)[m]&&(u[m]=this.digits[m].querySelector(".odometer-ribbon-inner")),this.ribbons[m].innerHTML="",0>d&&(l=l.reverse()),o=C=0,B=l.length;B>C;o=++C)k=l[o],q=document.createElement("div"),q.className="odometer-value",q.innerHTML=k,this.ribbons[m].appendChild(q),o===l.length-1&&r(q,"odometer-last-value"),0===o&&r(q,"odometer-first-value");return 0>t&&this.addDigit("-"),p=this.inside.querySelector(".odometer-radix-mark"),null!=p&&p.parent.removeChild(p),j?this.addSpacer(this.format.radix,this.digits[j-1],"odometer-radix-mark"):void 0}},a}(),m.options=null!=(E=window.odometerOptions)?E:{},setTimeout(function(){var a,b,c,d,e;if(window.odometerOptions){d=window.odometerOptions,e=[];for(a in d)b=d[a],e.push(null!=(c=m.options)[a]?(c=m.options)[a]:c[a]=b);return e}},0),m.init=function(){var a,b,c,d,e,f;if(null!=document.querySelectorAll){for(b=document.querySelectorAll(m.options.selector||".odometer"),f=[],c=0,d=b.length;d>c;c++)a=b[c],f.push(a.odometer=new m({el:a,value:null!=(e=a.innerText)?e:a.textContent}));return f}},null!=(null!=(F=document.documentElement)?F.doScroll:void 0)&&null!=document.createEventObject?(D=document.onreadystatechange,document.onreadystatechange=function(){return"complete"===document.readyState&&m.options.auto!==!1&&m.init(),null!=D?D.apply(this,arguments):void 0}):document.addEventListener("DOMContentLoaded",function(){return m.options.auto!==!1?m.init():void 0},!1),"function"==typeof define&&define.amd?define([],function(){return m}):"undefined"!=typeof exports&&null!==exports?module.exports=m:window.Odometer=m}).call(this);
3 |
--------------------------------------------------------------------------------
/docs/welcome/onepage-scroll.js:
--------------------------------------------------------------------------------
1 | /* ===========================================================
2 | * jquery-onepage-scroll.js v1
3 | * ===========================================================
4 | * Copyright 2013 Pete Rojwongsuriya.
5 | * http://www.thepetedesign.com
6 | *
7 | * Create an Apple-like website that let user scroll
8 | * one page at a time
9 | *
10 | * Credit: Eike Send for the awesome swipe event
11 | * https://github.com/peachananr/onepage-scroll
12 | *
13 | * ========================================================== */
14 |
15 | !function($){
16 |
17 | var defaults = {
18 | sectionContainer: "section",
19 | easing: "ease",
20 | animationTime: 1000,
21 | pagination: true,
22 | updateURL: false
23 | };
24 |
25 | /*------------------------------------------------*/
26 | /* Credit: Eike Send for the awesome swipe event */
27 | /*------------------------------------------------*/
28 |
29 | $.fn.swipeEvents = function() {
30 | return this.each(function() {
31 |
32 | var startX,
33 | startY,
34 | $this = $(this);
35 |
36 | $this.bind('touchstart', touchstart);
37 |
38 | function touchstart(event) {
39 | var touches = event.originalEvent.touches;
40 | if (touches && touches.length) {
41 | startX = touches[0].pageX;
42 | startY = touches[0].pageY;
43 | $this.bind('touchmove', touchmove);
44 | }
45 | event.preventDefault();
46 | }
47 |
48 | function touchmove(event) {
49 | var touches = event.originalEvent.touches;
50 | if (touches && touches.length) {
51 | var deltaX = startX - touches[0].pageX;
52 | var deltaY = startY - touches[0].pageY;
53 |
54 | if (deltaX >= 50) {
55 | $this.trigger("swipeLeft");
56 | }
57 | if (deltaX <= -50) {
58 | $this.trigger("swipeRight");
59 | }
60 | if (deltaY >= 50) {
61 | $this.trigger("swipeUp");
62 | }
63 | if (deltaY <= -50) {
64 | $this.trigger("swipeDown");
65 | }
66 | if (Math.abs(deltaX) >= 50 || Math.abs(deltaY) >= 50) {
67 | $this.unbind('touchmove', touchmove);
68 | }
69 | }
70 | event.preventDefault();
71 | }
72 |
73 | });
74 | };
75 |
76 |
77 | $.fn.onepage_scroll = function(options){
78 | var settings = $.extend({}, defaults, options),
79 | el = $(this),
80 | sections = $(settings.sectionContainer),
81 | total = sections.length,
82 | status = "off",
83 | topPos = 0,
84 | lastAnimation = 0,
85 | quietPeriod = 500,
86 | paginationList = "";
87 |
88 | $.fn.transformPage = function(settings, pos) {
89 | $(this).css({
90 | "-webkit-transform": "translate3d(0, " + pos + "%, 0)",
91 | "-webkit-transition": "all " + settings.animationTime + "ms " + settings.easing,
92 | "-moz-transform": "translate3d(0, " + pos + "%, 0)",
93 | "-moz-transition": "all " + settings.animationTime + "ms " + settings.easing,
94 | "-ms-transform": "translate3d(0, " + pos + "%, 0)",
95 | "-ms-transition": "all " + settings.animationTime + "ms " + settings.easing,
96 | "transform": "translate3d(0, " + pos + "%, 0)",
97 | "transition": "all " + settings.animationTime + "ms " + settings.easing
98 | });
99 | };
100 |
101 | $.fn.moveDown = function() {
102 | var el = $(this);
103 | index = $(settings.sectionContainer +".active").data("index");
104 | if(index < total) {
105 | current = $(settings.sectionContainer + "[data-index='" + index + "']");
106 | next = $(settings.sectionContainer + "[data-index='" + (index + 1) + "']");
107 | if(next) {
108 | current.removeClass("active");
109 | next.addClass("active");
110 | if(settings.pagination === true) {
111 | $(".onepage-pagination li a" + "[data-index='" + index + "']").removeClass("active");
112 | $(".onepage-pagination li a" + "[data-index='" + (index + 1) + "']").addClass("active");
113 | }
114 | $("body")[0].className = $("body")[0].className.replace(/\bviewing-page-\d.*?\b/g, '');
115 | $("body").addClass("viewing-page-"+next.data("index"));
116 |
117 | if (history.replaceState && settings.updateURL === true) {
118 | var href = window.location.href.substr(0,window.location.href.indexOf('#')) + "#" + (index + 1);
119 | history.pushState( {}, document.title, href );
120 | }
121 | }
122 | pos = (index * 100) * -1;
123 | el.transformPage(settings, pos);
124 | }
125 | };
126 |
127 | $.fn.moveUp = function() {
128 | var el = $(this);
129 | index = $(settings.sectionContainer +".active").data("index");
130 | if(index <= total && index > 1) {
131 | current = $(settings.sectionContainer + "[data-index='" + index + "']");
132 | next = $(settings.sectionContainer + "[data-index='" + (index - 1) + "']");
133 |
134 | if(next) {
135 | current.removeClass("active");
136 | next.addClass("active");
137 | if(settings.pagination === true) {
138 | $(".onepage-pagination li a" + "[data-index='" + index + "']").removeClass("active");
139 | $(".onepage-pagination li a" + "[data-index='" + (index - 1) + "']").addClass("active");
140 | }
141 | $("body")[0].className = $("body")[0].className.replace(/\bviewing-page-\d.*?\b/g, '');
142 | $("body").addClass("viewing-page-"+next.data("index"));
143 |
144 | if (history.replaceState && settings.updateURL === true) {
145 | var href = window.location.href.substr(0,window.location.href.indexOf('#')) + "#" + (index - 1);
146 | history.pushState( {}, document.title, href );
147 | }
148 | }
149 | pos = ((next.data("index") - 1) * 100) * -1;
150 | el.transformPage(settings, pos);
151 | }
152 | };
153 |
154 | function init_scroll(event, delta) {
155 | deltaOfInterest = delta;
156 | var timeNow = new Date().getTime();
157 | // Cancel scroll if currently animating or within quiet period
158 | if(timeNow - lastAnimation < quietPeriod + settings.animationTime) {
159 | event.preventDefault();
160 | return;
161 | }
162 |
163 | if (deltaOfInterest < 0) {
164 | el.moveDown();
165 | } else {
166 | el.moveUp();
167 | }
168 | lastAnimation = timeNow;
169 | }
170 |
171 | // Prepare everything before binding wheel scroll
172 |
173 | el.addClass("onepage-wrapper").css("position","relative");
174 | $.each( sections, function(i) {
175 | $(this).css({
176 | position: "absolute",
177 | top: topPos + "%"
178 | }).addClass("section").attr("data-index", i+1);
179 | topPos = topPos + 100;
180 | if(settings.pagination === true) {
181 | paginationList += " ";
182 | }
183 | });
184 |
185 | el.swipeEvents().bind("swipeDown", function(){
186 | el.moveUp();
187 | }).bind("swipeUp", function(){
188 | el.moveDown();
189 | });
190 |
191 | // Create Pagination and Display Them
192 | if(settings.pagination === true) {
193 | $("").prependTo("body");
194 | posTop = (el.find(".onepage-pagination").height() / 2) * -1;
195 | el.find(".onepage-pagination").css("margin-top", posTop);
196 | }
197 |
198 | if(window.location.hash !== "" && window.location.hash !== "#1") {
199 | init_index = window.location.hash.replace("#", "");
200 | $(settings.sectionContainer + "[data-index='" + init_index + "']").addClass("active");
201 | $("body").addClass("viewing-page-"+ init_index);
202 | if(settings.pagination === true) $(".onepage-pagination li a" + "[data-index='" + init_index + "']").addClass("active");
203 |
204 | next = $(settings.sectionContainer + "[data-index='" + (init_index) + "']");
205 | if(next) {
206 | next.addClass("active");
207 | if(settings.pagination === true) $(".onepage-pagination li a" + "[data-index='" + (init_index) + "']").addClass("active");
208 | $("body")[0].className = $("body")[0].className.replace(/\bviewing-page-\d.*?\b/g, '');
209 | $("body").addClass("viewing-page-"+next.data("index"));
210 | if (history.replaceState && settings.updateURL === true) {
211 | var href = window.location.href.substr(0,window.location.href.indexOf('#')) + "#" + (init_index);
212 | history.pushState( {}, document.title, href );
213 | }
214 | }
215 | pos = ((init_index - 1) * 100) * -1;
216 | el.transformPage(settings, pos);
217 |
218 | }else{
219 | $(settings.sectionContainer + "[data-index='1']").addClass("active");
220 | $("body").addClass("viewing-page-1");
221 | if(settings.pagination === true) $(".onepage-pagination li a" + "[data-index='1']").addClass("active");
222 | }
223 | if(settings.pagination === true) {
224 | $(".onepage-pagination li a").click(function (){
225 | var page_index = $(this).data("index");
226 | if (!$(this).hasClass("active")) {
227 | current = $(settings.sectionContainer + ".active");
228 | next = $(settings.sectionContainer + "[data-index='" + (page_index) + "']");
229 | if(next) {
230 | current.removeClass("active");
231 | next.addClass("active");
232 | $(".onepage-pagination li a" + ".active").removeClass("active");
233 | $(".onepage-pagination li a" + "[data-index='" + (page_index) + "']").addClass("active");
234 | $("body")[0].className = $("body")[0].className.replace(/\bviewing-page-\d.*?\b/g, '');
235 | $("body").addClass("viewing-page-"+next.data("index"));
236 | }
237 | pos = ((page_index - 1) * 100) * -1;
238 | el.transformPage(settings, pos);
239 | }
240 | if (settings.updateURL === false) return false;
241 | });
242 | }
243 |
244 |
245 |
246 | $(document).bind('mousewheel DOMMouseScroll', function(event) {
247 | event.preventDefault();
248 | var delta = event.originalEvent.wheelDelta || -event.originalEvent.detail;
249 | init_scroll(event, delta);
250 | });
251 | return false;
252 |
253 | };
254 |
255 | }(window.jQuery);
--------------------------------------------------------------------------------
/docs/welcome/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Odometer — Transition numbers with ease
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | O
35 |
36 | L
37 | M
38 | O
39 |
40 | D
41 |
42 | Z
43 | A
44 | B
45 | C
46 | D
47 |
48 | O
49 |
50 | I
51 | J
52 | K
53 | L
54 | M
55 | O
56 |
57 | M
58 |
59 | G
60 | H
61 | I
62 | J
63 | K
64 | L
65 | M
66 |
67 | E
68 |
69 | Y
70 | Z
71 | A
72 | B
73 | C
74 | D
75 | E
76 |
77 | T
78 |
79 | L
80 | M
81 | N
82 | O
83 | P
84 | Q
85 | R
86 | S
87 | T
88 |
89 | E
90 |
91 | V
92 | W
93 | X
94 | Y
95 | Z
96 | A
97 | B
98 | C
99 | D
100 | E
101 |
102 | R
103 |
104 | G
105 | H
106 | I
107 | J
108 | K
109 | L
110 | M
111 | O
112 | P
113 | Q
114 | R
115 |
116 |
117 |
118 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
How To Use
132 |
Add the js and a theme file to your page:
133 |
< link rel = " stylesheet" href = " odometer-theme-car.css" />
134 | < script src = " odometer.js" > </ script>
135 |
Any element with class name "odometer" will automatically be made into an Odometer! When you want to update the value, simply update it the same way you normally would.
136 |
element. innerHTML = 123 $( '.odometer' ) . html( 123 )
138 |
★ On Github
139 |
140 |
141 |
142 |
149 |
150 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
183 |
184 |
185 |
186 |
187 |
188 |
196 |
197 |
198 |
207 |
208 |
209 |
210 |
211 |
212 |
--------------------------------------------------------------------------------
/odometer.coffee:
--------------------------------------------------------------------------------
1 | VALUE_HTML = ' '
2 | RIBBON_HTML = '' + VALUE_HTML + ' '
3 | DIGIT_HTML = '8 ' + RIBBON_HTML + ' '
4 | FORMAT_MARK_HTML = ' '
5 |
6 | # The bit within the parenthesis will be repeated, so (,ddd) becomes 123,456,789....
7 | #
8 | # If your locale uses spaces to seperate digits, you could consider using a
9 | # Narrow No-Break Space ( ), as it's a bit more correct.
10 | #
11 | # Numbers will be rounded to the number of digits after the radix seperator.
12 | #
13 | # When values are set using `.update` or the `.innerHTML`-type attributes,
14 | # strings are assumed to already be in the locale's format.
15 | #
16 | # This is just the default, it can also be set as options.format.
17 | DIGIT_FORMAT = '(,ddd).dd'
18 |
19 | FORMAT_PARSER = /^\(?([^)]*)\)?(?:(.)(d+))?$/
20 |
21 | # What is our target framerate?
22 | FRAMERATE = 30
23 |
24 | # How long will the animation last?
25 | DURATION = 2000
26 |
27 | # What is the fastest we should update values when we are
28 | # counting up (not using the wheel animation).
29 | COUNT_FRAMERATE = 20
30 |
31 | # What is the minimum number of frames for each value on the wheel?
32 | # We won't render more values than could be reasonably seen
33 | FRAMES_PER_VALUE = 2
34 |
35 | # If more than one digit is hitting the frame limit, they would all get
36 | # capped at that limit and appear to be moving at the same rate. This
37 | # factor adds a boost to subsequent digits to make them appear faster.
38 | DIGIT_SPEEDBOOST = .5
39 |
40 | MS_PER_FRAME = 1000 / FRAMERATE
41 | COUNT_MS_PER_FRAME = 1000 / COUNT_FRAMERATE
42 |
43 | TRANSITION_END_EVENTS = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd'
44 |
45 | transitionCheckStyles = document.createElement('div').style
46 | TRANSITION_SUPPORT = transitionCheckStyles.transition? or transitionCheckStyles.webkitTransition? or
47 | transitionCheckStyles.mozTransition? or transitionCheckStyles.oTransition?
48 |
49 | requestAnimationFrame = window.requestAnimationFrame or window.mozRequestAnimationFrame or
50 | window.webkitRequestAnimationFrame or window.msRequestAnimationFrame
51 |
52 | MutationObserver = window.MutationObserver or window.WebKitMutationObserver or window.MozMutationObserver
53 |
54 | createFromHTML = (html) ->
55 | el = document.createElement('div')
56 | el.innerHTML = html
57 | el.children[0]
58 |
59 | removeClass = (el, name) ->
60 | el.className = el.className.replace new RegExp("(^| )#{ name.split(' ').join('|') }( |$)", 'gi'), ' '
61 |
62 | addClass = (el, name) ->
63 | removeClass el, name
64 | el.className += " #{ name }"
65 |
66 | trigger = (el, name) ->
67 | # Custom DOM events are not supported in IE8
68 | if document.createEvent?
69 | evt = document.createEvent('HTMLEvents')
70 | evt.initEvent(name, true, true)
71 | el.dispatchEvent(evt)
72 |
73 | now = ->
74 | window.performance?.now?() ? +new Date
75 |
76 | round = (val, precision=0) ->
77 | return Math.round(val) unless precision
78 |
79 | val *= Math.pow(10, precision)
80 | val += 0.5
81 | val = Math.floor(val)
82 | val /= Math.pow(10, precision)
83 |
84 | truncate = (val) ->
85 | # | 0 fails on numbers greater than 2^32
86 | if val < 0
87 | Math.ceil(val)
88 | else
89 | Math.floor(val)
90 |
91 | fractionalPart = (val) ->
92 | val - round(val)
93 |
94 | _jQueryWrapped = false
95 | do wrapJQuery = ->
96 | return if _jQueryWrapped
97 |
98 | if window.jQuery?
99 | _jQueryWrapped = true
100 | # We need to wrap jQuery's .html and .text because they don't always
101 | # call .innerHTML/.innerText
102 | for property in ['html', 'text']
103 | do (property) ->
104 | old = window.jQuery.fn[property]
105 | window.jQuery.fn[property] = (val) ->
106 | if not val? or not this[0]?.odometer?
107 | return old.apply this, arguments
108 |
109 | this[0].odometer.update val
110 |
111 | # In case jQuery is brought in after this file
112 | setTimeout wrapJQuery, 0
113 |
114 | class Odometer
115 | constructor: (@options) ->
116 | @el = @options.el
117 | return @el.odometer if @el.odometer?
118 |
119 | @el.odometer = @
120 |
121 | for k, v of Odometer.options
122 | if not @options[k]?
123 | @options[k] = v
124 |
125 | @options.duration ?= DURATION
126 | @MAX_VALUES = ((@options.duration / MS_PER_FRAME) / FRAMES_PER_VALUE) | 0
127 |
128 | @resetFormat()
129 |
130 | @value = @cleanValue(@options.value ? '')
131 |
132 | @renderInside()
133 | @render()
134 |
135 | try
136 | for property in ['innerHTML', 'innerText', 'textContent'] when @el[property]?
137 | do (property) =>
138 | Object.defineProperty @el, property,
139 | get: =>
140 | if property is 'innerHTML'
141 | @inside.outerHTML
142 | else
143 | # It's just a single HTML element, so innerText is the
144 | # same as outerText.
145 | @inside.innerText ? @inside.textContent
146 | set: (val) =>
147 | @update val
148 | catch e
149 | # Safari
150 | @watchForMutations()
151 |
152 | @
153 |
154 | renderInside: ->
155 | @inside = document.createElement 'div'
156 | @inside.className = 'odometer-inside'
157 | @el.innerHTML = ''
158 | @el.appendChild @inside
159 |
160 | watchForMutations: ->
161 | # Safari doesn't allow us to wrap .innerHTML, so we listen for it
162 | # changing.
163 | return unless MutationObserver?
164 |
165 | try
166 | @observer ?= new MutationObserver (mutations) =>
167 | newVal = @el.innerText
168 |
169 | @renderInside()
170 | @render @value
171 | @update newVal
172 |
173 | @watchMutations = true
174 | @startWatchingMutations()
175 | catch e
176 |
177 | startWatchingMutations: ->
178 | if @watchMutations
179 | @observer.observe @el, {childList: true}
180 |
181 | stopWatchingMutations: ->
182 | @observer?.disconnect()
183 |
184 | cleanValue: (val) ->
185 | if typeof val is 'string'
186 | # We need to normalize the format so we can properly turn it into
187 | # a float.
188 | val = val.replace((@format.radix ? '.'), '')
189 | val = val.replace /[.,]/g, ''
190 | val = val.replace '', '.'
191 | val = parseFloat(val, 10) or 0
192 |
193 | round(val, @format.precision)
194 |
195 | bindTransitionEnd: ->
196 | return if @transitionEndBound
197 | @transitionEndBound = true
198 |
199 | # The event will be triggered once for each ribbon, we only
200 | # want one render though
201 | renderEnqueued = false
202 | for event in TRANSITION_END_EVENTS.split(' ')
203 | @el.addEventListener event, =>
204 | return true if renderEnqueued
205 |
206 | renderEnqueued = true
207 |
208 | setTimeout =>
209 | @render()
210 | renderEnqueued = false
211 |
212 | trigger @el, 'odometerdone'
213 | , 0
214 |
215 | true
216 | , false
217 |
218 | resetFormat: ->
219 | format = @options.format ? DIGIT_FORMAT
220 | format or= 'd'
221 |
222 | parsed = FORMAT_PARSER.exec format
223 | if not parsed
224 | throw new Error "Odometer: Unparsable digit format"
225 |
226 | [repeating, radix, fractional] = parsed[1..3]
227 |
228 | precision = fractional?.length or 0
229 |
230 | @format = {repeating, radix, precision}
231 |
232 | render: (value=@value) ->
233 | @stopWatchingMutations()
234 | @resetFormat()
235 |
236 | @inside.innerHTML = ''
237 |
238 | theme = @options.theme
239 |
240 | classes = @el.className.split(' ')
241 | newClasses = []
242 | for cls in classes when cls.length
243 | if match = /^odometer-theme-(.+)$/.exec(cls)
244 | theme = match[1]
245 | continue
246 |
247 | if /^odometer(-|$)/.test(cls)
248 | continue
249 |
250 | newClasses.push cls
251 |
252 | newClasses.push 'odometer'
253 |
254 | unless TRANSITION_SUPPORT
255 | newClasses.push 'odometer-no-transitions'
256 |
257 | if theme
258 | newClasses.push "odometer-theme-#{ theme }"
259 | else
260 | # This class matches all themes, so it should do what you'd expect if only one
261 | # theme css file is brought into the page.
262 | newClasses.push "odometer-auto-theme"
263 |
264 | @el.className = newClasses.join(' ')
265 |
266 | @ribbons = {}
267 |
268 | @formatDigits(value)
269 |
270 | @startWatchingMutations()
271 |
272 | formatDigits: (value) ->
273 | @digits = []
274 |
275 | if @options.formatFunction
276 | valueString = @options.formatFunction(value)
277 | for valueDigit in valueString.split('').reverse()
278 | if valueDigit.match(/0-9/)
279 | digit = @renderDigit()
280 | digit.querySelector('.odometer-value').innerHTML = valueDigit
281 | @digits.push digit
282 | @insertDigit digit
283 | else
284 | @addSpacer valueDigit
285 | else
286 | wholePart = not @format.precision or not fractionalPart(value) or false
287 | for digit in value.toString().split('').reverse()
288 | if digit is '.'
289 | wholePart = true
290 |
291 | @addDigit digit, wholePart
292 |
293 | return
294 |
295 | update: (newValue) ->
296 | newValue = @cleanValue newValue
297 |
298 | return unless diff = newValue - @value
299 |
300 | removeClass @el, 'odometer-animating-up odometer-animating-down odometer-animating'
301 | if diff > 0
302 | addClass @el, 'odometer-animating-up'
303 | else
304 | addClass @el, 'odometer-animating-down'
305 |
306 | @stopWatchingMutations()
307 | @animate newValue
308 | @startWatchingMutations()
309 |
310 | setTimeout =>
311 | # Force a repaint
312 | @el.offsetHeight
313 |
314 | addClass @el, 'odometer-animating'
315 | , 0
316 |
317 | @value = newValue
318 |
319 | renderDigit: ->
320 | createFromHTML DIGIT_HTML
321 |
322 | insertDigit: (digit, before) ->
323 | if before?
324 | @inside.insertBefore digit, before
325 | else if not @inside.children.length
326 | @inside.appendChild digit
327 | else
328 | @inside.insertBefore digit, @inside.children[0]
329 |
330 | addSpacer: (chr, before, extraClasses) ->
331 | spacer = createFromHTML FORMAT_MARK_HTML
332 | spacer.innerHTML = chr
333 | addClass(spacer, extraClasses) if extraClasses
334 | @insertDigit spacer, before
335 |
336 | addDigit: (value, repeating=true) ->
337 | if value is '-'
338 | return @addSpacer value, null, 'odometer-negation-mark'
339 |
340 | if value is '.'
341 | return @addSpacer (@format.radix ? '.'), null, 'odometer-radix-mark'
342 |
343 | if repeating
344 | resetted = false
345 | while true
346 | if not @format.repeating.length
347 | if resetted
348 | throw new Error "Bad odometer format without digits"
349 |
350 | @resetFormat()
351 | resetted = true
352 |
353 | chr = @format.repeating[@format.repeating.length - 1]
354 | @format.repeating = @format.repeating.substring(0, @format.repeating.length - 1)
355 |
356 | break if chr is 'd'
357 |
358 | @addSpacer chr
359 |
360 | digit = @renderDigit()
361 | digit.querySelector('.odometer-value').innerHTML = value
362 | @digits.push digit
363 |
364 | @insertDigit digit
365 |
366 | animate: (newValue) ->
367 | if not TRANSITION_SUPPORT or @options.animation is 'count'
368 | @animateCount newValue
369 | else
370 | @animateSlide newValue
371 |
372 | animateCount: (newValue) ->
373 | return unless diff = +newValue - @value
374 |
375 | start = last = now()
376 |
377 | cur = @value
378 | do tick = =>
379 | if (now() - start) > @options.duration
380 | @value = newValue
381 | @render()
382 | trigger @el, 'odometerdone'
383 | return
384 |
385 | delta = now() - last
386 |
387 | if delta > COUNT_MS_PER_FRAME
388 | last = now()
389 |
390 | fraction = delta / @options.duration
391 | dist = diff * fraction
392 |
393 | cur += dist
394 | @render Math.round cur
395 |
396 | if requestAnimationFrame?
397 | requestAnimationFrame tick
398 | else
399 | setTimeout tick, COUNT_MS_PER_FRAME
400 |
401 | getDigitCount: (values...) ->
402 | for value, i in values
403 | values[i] = Math.abs(value)
404 |
405 | max = Math.max values...
406 |
407 | Math.ceil(Math.log(max + 1) / Math.log(10))
408 |
409 | getFractionalDigitCount: (values...) ->
410 | # This assumes the value has already been rounded to
411 | # @format.precision places
412 | #
413 | parser = /^\-?\d*\.(\d*?)0*$/
414 | for value, i in values
415 | values[i] = value.toString()
416 |
417 | parts = parser.exec values[i]
418 |
419 | if not parts?
420 | values[i] = 0
421 | else
422 | values[i] = parts[1].length
423 |
424 | Math.max values...
425 |
426 | resetDigits: ->
427 | @digits = []
428 | @ribbons = []
429 | @inside.innerHTML = ''
430 | @resetFormat()
431 |
432 | animateSlide: (newValue) ->
433 | oldValue = @value
434 |
435 | fractionalCount = @getFractionalDigitCount oldValue, newValue
436 |
437 | if fractionalCount
438 | newValue = newValue * Math.pow(10, fractionalCount)
439 | oldValue = oldValue * Math.pow(10, fractionalCount)
440 |
441 | return unless diff = newValue - oldValue
442 |
443 | @bindTransitionEnd()
444 |
445 | digitCount = @getDigitCount(oldValue, newValue)
446 |
447 | digits = []
448 | boosted = 0
449 | # We create a array to represent the series of digits which should be
450 | # animated in each column
451 | for i in [0...digitCount]
452 | start = truncate(oldValue / Math.pow(10, (digitCount - i - 1)))
453 | end = truncate(newValue / Math.pow(10, (digitCount - i - 1)))
454 |
455 | dist = end - start
456 |
457 | if Math.abs(dist) > @MAX_VALUES
458 | # We need to subsample
459 | frames = []
460 |
461 | # Subsequent digits need to be faster than previous ones
462 | incr = dist / (@MAX_VALUES + @MAX_VALUES * boosted * DIGIT_SPEEDBOOST)
463 | cur = start
464 |
465 | while (dist > 0 and cur < end) or (dist < 0 and cur > end)
466 | frames.push Math.round cur
467 | cur += incr
468 |
469 | if frames[frames.length - 1] isnt end
470 | frames.push end
471 |
472 | boosted++
473 | else
474 | frames = [start..end]
475 |
476 | # We only care about the last digit
477 | for frame, i in frames
478 | frames[i] = Math.abs(frame % 10)
479 |
480 | digits.push frames
481 |
482 | @resetDigits()
483 |
484 | for frames, i in digits.reverse()
485 | if not @digits[i]
486 | @addDigit ' ', (i >= fractionalCount)
487 |
488 | @ribbons[i] ?= @digits[i].querySelector('.odometer-ribbon-inner')
489 | @ribbons[i].innerHTML = ''
490 |
491 | if diff < 0
492 | frames = frames.reverse()
493 |
494 | for frame, j in frames
495 | numEl = document.createElement('div')
496 | numEl.className = 'odometer-value'
497 | numEl.innerHTML = frame
498 |
499 | @ribbons[i].appendChild numEl
500 |
501 | if j == frames.length - 1
502 | addClass numEl, 'odometer-last-value'
503 | if j == 0
504 | addClass numEl, 'odometer-first-value'
505 |
506 | if start < 0
507 | @addDigit '-'
508 |
509 | mark = @inside.querySelector('.odometer-radix-mark')
510 | mark.parent.removeChild(mark) if mark?
511 |
512 | if fractionalCount
513 | @addSpacer @format.radix, @digits[fractionalCount - 1], 'odometer-radix-mark'
514 |
515 | Odometer.options = window.odometerOptions ? {}
516 |
517 | setTimeout ->
518 | # We do this in a seperate pass to allow people to set
519 | # window.odometerOptions after bringing the file in.
520 | if window.odometerOptions
521 | for k, v of window.odometerOptions
522 | Odometer.options[k] ?= v
523 | , 0
524 |
525 | Odometer.init = ->
526 | if not document.querySelectorAll?
527 | # IE 7 or 8 in Quirksmode
528 | return
529 |
530 | elements = document.querySelectorAll (Odometer.options.selector or '.odometer')
531 |
532 | for el in elements
533 | el.odometer = new Odometer {el, value: (el.innerText ? el.textContent)}
534 |
535 | if document.documentElement?.doScroll? and document.createEventObject?
536 | # IE < 9
537 | _old = document.onreadystatechange
538 | document.onreadystatechange = ->
539 | if document.readyState is 'complete' and Odometer.options.auto isnt false
540 | Odometer.init()
541 |
542 | _old?.apply this, arguments
543 | else
544 | document.addEventListener 'DOMContentLoaded', ->
545 | if Odometer.options.auto isnt false
546 | Odometer.init()
547 | , false
548 |
549 |
550 | if typeof define is 'function' and define.amd
551 | # AMD. Register as an anonymous module.
552 | define [], ->
553 | Odometer
554 | else if exports?
555 | # CommonJS
556 | module.exports = Odometer
557 | else
558 | # Browser globals
559 | window.Odometer = Odometer
560 |
--------------------------------------------------------------------------------
/odometer.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var COUNT_FRAMERATE, COUNT_MS_PER_FRAME, DIGIT_FORMAT, DIGIT_HTML, DIGIT_SPEEDBOOST, DURATION, FORMAT_MARK_HTML, FORMAT_PARSER, FRAMERATE, FRAMES_PER_VALUE, MS_PER_FRAME, MutationObserver, Odometer, RIBBON_HTML, TRANSITION_END_EVENTS, TRANSITION_SUPPORT, VALUE_HTML, addClass, createFromHTML, fractionalPart, now, removeClass, requestAnimationFrame, round, transitionCheckStyles, trigger, truncate, wrapJQuery, _jQueryWrapped, _old, _ref, _ref1,
3 | __slice = [].slice;
4 |
5 | VALUE_HTML = ' ';
6 |
7 | RIBBON_HTML = '' + VALUE_HTML + ' ';
8 |
9 | DIGIT_HTML = '8 ' + RIBBON_HTML + ' ';
10 |
11 | FORMAT_MARK_HTML = ' ';
12 |
13 | DIGIT_FORMAT = '(,ddd).dd';
14 |
15 | FORMAT_PARSER = /^\(?([^)]*)\)?(?:(.)(d+))?$/;
16 |
17 | FRAMERATE = 30;
18 |
19 | DURATION = 2000;
20 |
21 | COUNT_FRAMERATE = 20;
22 |
23 | FRAMES_PER_VALUE = 2;
24 |
25 | DIGIT_SPEEDBOOST = .5;
26 |
27 | MS_PER_FRAME = 1000 / FRAMERATE;
28 |
29 | COUNT_MS_PER_FRAME = 1000 / COUNT_FRAMERATE;
30 |
31 | TRANSITION_END_EVENTS = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd';
32 |
33 | transitionCheckStyles = document.createElement('div').style;
34 |
35 | TRANSITION_SUPPORT = (transitionCheckStyles.transition != null) || (transitionCheckStyles.webkitTransition != null) || (transitionCheckStyles.mozTransition != null) || (transitionCheckStyles.oTransition != null);
36 |
37 | requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
38 |
39 | MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
40 |
41 | createFromHTML = function(html) {
42 | var el;
43 | el = document.createElement('div');
44 | el.innerHTML = html;
45 | return el.children[0];
46 | };
47 |
48 | removeClass = function(el, name) {
49 | return el.className = el.className.replace(new RegExp("(^| )" + (name.split(' ').join('|')) + "( |$)", 'gi'), ' ');
50 | };
51 |
52 | addClass = function(el, name) {
53 | removeClass(el, name);
54 | return el.className += " " + name;
55 | };
56 |
57 | trigger = function(el, name) {
58 | var evt;
59 | if (document.createEvent != null) {
60 | evt = document.createEvent('HTMLEvents');
61 | evt.initEvent(name, true, true);
62 | return el.dispatchEvent(evt);
63 | }
64 | };
65 |
66 | now = function() {
67 | var _ref, _ref1;
68 | return (_ref = (_ref1 = window.performance) != null ? typeof _ref1.now === "function" ? _ref1.now() : void 0 : void 0) != null ? _ref : +(new Date);
69 | };
70 |
71 | round = function(val, precision) {
72 | if (precision == null) {
73 | precision = 0;
74 | }
75 | if (!precision) {
76 | return Math.round(val);
77 | }
78 | val *= Math.pow(10, precision);
79 | val += 0.5;
80 | val = Math.floor(val);
81 | return val /= Math.pow(10, precision);
82 | };
83 |
84 | truncate = function(val) {
85 | if (val < 0) {
86 | return Math.ceil(val);
87 | } else {
88 | return Math.floor(val);
89 | }
90 | };
91 |
92 | fractionalPart = function(val) {
93 | return val - round(val);
94 | };
95 |
96 | _jQueryWrapped = false;
97 |
98 | (wrapJQuery = function() {
99 | var property, _i, _len, _ref, _results;
100 | if (_jQueryWrapped) {
101 | return;
102 | }
103 | if (window.jQuery != null) {
104 | _jQueryWrapped = true;
105 | _ref = ['html', 'text'];
106 | _results = [];
107 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
108 | property = _ref[_i];
109 | _results.push((function(property) {
110 | var old;
111 | old = window.jQuery.fn[property];
112 | return window.jQuery.fn[property] = function(val) {
113 | var _ref1;
114 | if ((val == null) || (((_ref1 = this[0]) != null ? _ref1.odometer : void 0) == null)) {
115 | return old.apply(this, arguments);
116 | }
117 | return this[0].odometer.update(val);
118 | };
119 | })(property));
120 | }
121 | return _results;
122 | }
123 | })();
124 |
125 | setTimeout(wrapJQuery, 0);
126 |
127 | Odometer = (function() {
128 | function Odometer(options) {
129 | var e, k, property, v, _base, _i, _len, _ref, _ref1, _ref2,
130 | _this = this;
131 | this.options = options;
132 | this.el = this.options.el;
133 | if (this.el.odometer != null) {
134 | return this.el.odometer;
135 | }
136 | this.el.odometer = this;
137 | _ref = Odometer.options;
138 | for (k in _ref) {
139 | v = _ref[k];
140 | if (this.options[k] == null) {
141 | this.options[k] = v;
142 | }
143 | }
144 | if ((_base = this.options).duration == null) {
145 | _base.duration = DURATION;
146 | }
147 | this.MAX_VALUES = ((this.options.duration / MS_PER_FRAME) / FRAMES_PER_VALUE) | 0;
148 | this.resetFormat();
149 | this.value = this.cleanValue((_ref1 = this.options.value) != null ? _ref1 : '');
150 | this.renderInside();
151 | this.render();
152 | try {
153 | _ref2 = ['innerHTML', 'innerText', 'textContent'];
154 | for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
155 | property = _ref2[_i];
156 | if (this.el[property] != null) {
157 | (function(property) {
158 | return Object.defineProperty(_this.el, property, {
159 | get: function() {
160 | var _ref3;
161 | if (property === 'innerHTML') {
162 | return _this.inside.outerHTML;
163 | } else {
164 | return (_ref3 = _this.inside.innerText) != null ? _ref3 : _this.inside.textContent;
165 | }
166 | },
167 | set: function(val) {
168 | return _this.update(val);
169 | }
170 | });
171 | })(property);
172 | }
173 | }
174 | } catch (_error) {
175 | e = _error;
176 | this.watchForMutations();
177 | }
178 | this;
179 | }
180 |
181 | Odometer.prototype.renderInside = function() {
182 | this.inside = document.createElement('div');
183 | this.inside.className = 'odometer-inside';
184 | this.el.innerHTML = '';
185 | return this.el.appendChild(this.inside);
186 | };
187 |
188 | Odometer.prototype.watchForMutations = function() {
189 | var e,
190 | _this = this;
191 | if (MutationObserver == null) {
192 | return;
193 | }
194 | try {
195 | if (this.observer == null) {
196 | this.observer = new MutationObserver(function(mutations) {
197 | var newVal;
198 | newVal = _this.el.innerText;
199 | _this.renderInside();
200 | _this.render(_this.value);
201 | return _this.update(newVal);
202 | });
203 | }
204 | this.watchMutations = true;
205 | return this.startWatchingMutations();
206 | } catch (_error) {
207 | e = _error;
208 | }
209 | };
210 |
211 | Odometer.prototype.startWatchingMutations = function() {
212 | if (this.watchMutations) {
213 | return this.observer.observe(this.el, {
214 | childList: true
215 | });
216 | }
217 | };
218 |
219 | Odometer.prototype.stopWatchingMutations = function() {
220 | var _ref;
221 | return (_ref = this.observer) != null ? _ref.disconnect() : void 0;
222 | };
223 |
224 | Odometer.prototype.cleanValue = function(val) {
225 | var _ref;
226 | if (typeof val === 'string') {
227 | val = val.replace((_ref = this.format.radix) != null ? _ref : '.', '');
228 | val = val.replace(/[.,]/g, '');
229 | val = val.replace('', '.');
230 | val = parseFloat(val, 10) || 0;
231 | }
232 | return round(val, this.format.precision);
233 | };
234 |
235 | Odometer.prototype.bindTransitionEnd = function() {
236 | var event, renderEnqueued, _i, _len, _ref, _results,
237 | _this = this;
238 | if (this.transitionEndBound) {
239 | return;
240 | }
241 | this.transitionEndBound = true;
242 | renderEnqueued = false;
243 | _ref = TRANSITION_END_EVENTS.split(' ');
244 | _results = [];
245 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
246 | event = _ref[_i];
247 | _results.push(this.el.addEventListener(event, function() {
248 | if (renderEnqueued) {
249 | return true;
250 | }
251 | renderEnqueued = true;
252 | setTimeout(function() {
253 | _this.render();
254 | renderEnqueued = false;
255 | return trigger(_this.el, 'odometerdone');
256 | }, 0);
257 | return true;
258 | }, false));
259 | }
260 | return _results;
261 | };
262 |
263 | Odometer.prototype.resetFormat = function() {
264 | var format, fractional, parsed, precision, radix, repeating, _ref, _ref1;
265 | format = (_ref = this.options.format) != null ? _ref : DIGIT_FORMAT;
266 | format || (format = 'd');
267 | parsed = FORMAT_PARSER.exec(format);
268 | if (!parsed) {
269 | throw new Error("Odometer: Unparsable digit format");
270 | }
271 | _ref1 = parsed.slice(1, 4), repeating = _ref1[0], radix = _ref1[1], fractional = _ref1[2];
272 | precision = (fractional != null ? fractional.length : void 0) || 0;
273 | return this.format = {
274 | repeating: repeating,
275 | radix: radix,
276 | precision: precision
277 | };
278 | };
279 |
280 | Odometer.prototype.render = function(value) {
281 | var classes, cls, match, newClasses, theme, _i, _len;
282 | if (value == null) {
283 | value = this.value;
284 | }
285 | this.stopWatchingMutations();
286 | this.resetFormat();
287 | this.inside.innerHTML = '';
288 | theme = this.options.theme;
289 | classes = this.el.className.split(' ');
290 | newClasses = [];
291 | for (_i = 0, _len = classes.length; _i < _len; _i++) {
292 | cls = classes[_i];
293 | if (!cls.length) {
294 | continue;
295 | }
296 | if (match = /^odometer-theme-(.+)$/.exec(cls)) {
297 | theme = match[1];
298 | continue;
299 | }
300 | if (/^odometer(-|$)/.test(cls)) {
301 | continue;
302 | }
303 | newClasses.push(cls);
304 | }
305 | newClasses.push('odometer');
306 | if (!TRANSITION_SUPPORT) {
307 | newClasses.push('odometer-no-transitions');
308 | }
309 | if (theme) {
310 | newClasses.push("odometer-theme-" + theme);
311 | } else {
312 | newClasses.push("odometer-auto-theme");
313 | }
314 | this.el.className = newClasses.join(' ');
315 | this.ribbons = {};
316 | this.formatDigits(value);
317 | return this.startWatchingMutations();
318 | };
319 |
320 | Odometer.prototype.formatDigits = function(value) {
321 | var digit, valueDigit, valueString, wholePart, _i, _j, _len, _len1, _ref, _ref1;
322 | this.digits = [];
323 | if (this.options.formatFunction) {
324 | valueString = this.options.formatFunction(value);
325 | _ref = valueString.split('').reverse();
326 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
327 | valueDigit = _ref[_i];
328 | if (valueDigit.match(/0-9/)) {
329 | digit = this.renderDigit();
330 | digit.querySelector('.odometer-value').innerHTML = valueDigit;
331 | this.digits.push(digit);
332 | this.insertDigit(digit);
333 | } else {
334 | this.addSpacer(valueDigit);
335 | }
336 | }
337 | } else {
338 | wholePart = !this.format.precision || !fractionalPart(value) || false;
339 | _ref1 = value.toString().split('').reverse();
340 | for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
341 | digit = _ref1[_j];
342 | if (digit === '.') {
343 | wholePart = true;
344 | }
345 | this.addDigit(digit, wholePart);
346 | }
347 | }
348 | };
349 |
350 | Odometer.prototype.update = function(newValue) {
351 | var diff,
352 | _this = this;
353 | newValue = this.cleanValue(newValue);
354 | if (!(diff = newValue - this.value)) {
355 | return;
356 | }
357 | removeClass(this.el, 'odometer-animating-up odometer-animating-down odometer-animating');
358 | if (diff > 0) {
359 | addClass(this.el, 'odometer-animating-up');
360 | } else {
361 | addClass(this.el, 'odometer-animating-down');
362 | }
363 | this.stopWatchingMutations();
364 | this.animate(newValue);
365 | this.startWatchingMutations();
366 | setTimeout(function() {
367 | _this.el.offsetHeight;
368 | return addClass(_this.el, 'odometer-animating');
369 | }, 0);
370 | return this.value = newValue;
371 | };
372 |
373 | Odometer.prototype.renderDigit = function() {
374 | return createFromHTML(DIGIT_HTML);
375 | };
376 |
377 | Odometer.prototype.insertDigit = function(digit, before) {
378 | if (before != null) {
379 | return this.inside.insertBefore(digit, before);
380 | } else if (!this.inside.children.length) {
381 | return this.inside.appendChild(digit);
382 | } else {
383 | return this.inside.insertBefore(digit, this.inside.children[0]);
384 | }
385 | };
386 |
387 | Odometer.prototype.addSpacer = function(chr, before, extraClasses) {
388 | var spacer;
389 | spacer = createFromHTML(FORMAT_MARK_HTML);
390 | spacer.innerHTML = chr;
391 | if (extraClasses) {
392 | addClass(spacer, extraClasses);
393 | }
394 | return this.insertDigit(spacer, before);
395 | };
396 |
397 | Odometer.prototype.addDigit = function(value, repeating) {
398 | var chr, digit, resetted, _ref;
399 | if (repeating == null) {
400 | repeating = true;
401 | }
402 | if (value === '-') {
403 | return this.addSpacer(value, null, 'odometer-negation-mark');
404 | }
405 | if (value === '.') {
406 | return this.addSpacer((_ref = this.format.radix) != null ? _ref : '.', null, 'odometer-radix-mark');
407 | }
408 | if (repeating) {
409 | resetted = false;
410 | while (true) {
411 | if (!this.format.repeating.length) {
412 | if (resetted) {
413 | throw new Error("Bad odometer format without digits");
414 | }
415 | this.resetFormat();
416 | resetted = true;
417 | }
418 | chr = this.format.repeating[this.format.repeating.length - 1];
419 | this.format.repeating = this.format.repeating.substring(0, this.format.repeating.length - 1);
420 | if (chr === 'd') {
421 | break;
422 | }
423 | this.addSpacer(chr);
424 | }
425 | }
426 | digit = this.renderDigit();
427 | digit.querySelector('.odometer-value').innerHTML = value;
428 | this.digits.push(digit);
429 | return this.insertDigit(digit);
430 | };
431 |
432 | Odometer.prototype.animate = function(newValue) {
433 | if (!TRANSITION_SUPPORT || this.options.animation === 'count') {
434 | return this.animateCount(newValue);
435 | } else {
436 | return this.animateSlide(newValue);
437 | }
438 | };
439 |
440 | Odometer.prototype.animateCount = function(newValue) {
441 | var cur, diff, last, start, tick,
442 | _this = this;
443 | if (!(diff = +newValue - this.value)) {
444 | return;
445 | }
446 | start = last = now();
447 | cur = this.value;
448 | return (tick = function() {
449 | var delta, dist, fraction;
450 | if ((now() - start) > _this.options.duration) {
451 | _this.value = newValue;
452 | _this.render();
453 | trigger(_this.el, 'odometerdone');
454 | return;
455 | }
456 | delta = now() - last;
457 | if (delta > COUNT_MS_PER_FRAME) {
458 | last = now();
459 | fraction = delta / _this.options.duration;
460 | dist = diff * fraction;
461 | cur += dist;
462 | _this.render(Math.round(cur));
463 | }
464 | if (requestAnimationFrame != null) {
465 | return requestAnimationFrame(tick);
466 | } else {
467 | return setTimeout(tick, COUNT_MS_PER_FRAME);
468 | }
469 | })();
470 | };
471 |
472 | Odometer.prototype.getDigitCount = function() {
473 | var i, max, value, values, _i, _len;
474 | values = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
475 | for (i = _i = 0, _len = values.length; _i < _len; i = ++_i) {
476 | value = values[i];
477 | values[i] = Math.abs(value);
478 | }
479 | max = Math.max.apply(Math, values);
480 | return Math.ceil(Math.log(max + 1) / Math.log(10));
481 | };
482 |
483 | Odometer.prototype.getFractionalDigitCount = function() {
484 | var i, parser, parts, value, values, _i, _len;
485 | values = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
486 | parser = /^\-?\d*\.(\d*?)0*$/;
487 | for (i = _i = 0, _len = values.length; _i < _len; i = ++_i) {
488 | value = values[i];
489 | values[i] = value.toString();
490 | parts = parser.exec(values[i]);
491 | if (parts == null) {
492 | values[i] = 0;
493 | } else {
494 | values[i] = parts[1].length;
495 | }
496 | }
497 | return Math.max.apply(Math, values);
498 | };
499 |
500 | Odometer.prototype.resetDigits = function() {
501 | this.digits = [];
502 | this.ribbons = [];
503 | this.inside.innerHTML = '';
504 | return this.resetFormat();
505 | };
506 |
507 | Odometer.prototype.animateSlide = function(newValue) {
508 | var boosted, cur, diff, digitCount, digits, dist, end, fractionalCount, frame, frames, i, incr, j, mark, numEl, oldValue, start, _base, _i, _j, _k, _l, _len, _len1, _len2, _m, _ref, _results;
509 | oldValue = this.value;
510 | fractionalCount = this.getFractionalDigitCount(oldValue, newValue);
511 | if (fractionalCount) {
512 | newValue = newValue * Math.pow(10, fractionalCount);
513 | oldValue = oldValue * Math.pow(10, fractionalCount);
514 | }
515 | if (!(diff = newValue - oldValue)) {
516 | return;
517 | }
518 | this.bindTransitionEnd();
519 | digitCount = this.getDigitCount(oldValue, newValue);
520 | digits = [];
521 | boosted = 0;
522 | for (i = _i = 0; 0 <= digitCount ? _i < digitCount : _i > digitCount; i = 0 <= digitCount ? ++_i : --_i) {
523 | start = truncate(oldValue / Math.pow(10, digitCount - i - 1));
524 | end = truncate(newValue / Math.pow(10, digitCount - i - 1));
525 | dist = end - start;
526 | if (Math.abs(dist) > this.MAX_VALUES) {
527 | frames = [];
528 | incr = dist / (this.MAX_VALUES + this.MAX_VALUES * boosted * DIGIT_SPEEDBOOST);
529 | cur = start;
530 | while ((dist > 0 && cur < end) || (dist < 0 && cur > end)) {
531 | frames.push(Math.round(cur));
532 | cur += incr;
533 | }
534 | if (frames[frames.length - 1] !== end) {
535 | frames.push(end);
536 | }
537 | boosted++;
538 | } else {
539 | frames = (function() {
540 | _results = [];
541 | for (var _j = start; start <= end ? _j <= end : _j >= end; start <= end ? _j++ : _j--){ _results.push(_j); }
542 | return _results;
543 | }).apply(this);
544 | }
545 | for (i = _k = 0, _len = frames.length; _k < _len; i = ++_k) {
546 | frame = frames[i];
547 | frames[i] = Math.abs(frame % 10);
548 | }
549 | digits.push(frames);
550 | }
551 | this.resetDigits();
552 | _ref = digits.reverse();
553 | for (i = _l = 0, _len1 = _ref.length; _l < _len1; i = ++_l) {
554 | frames = _ref[i];
555 | if (!this.digits[i]) {
556 | this.addDigit(' ', i >= fractionalCount);
557 | }
558 | if ((_base = this.ribbons)[i] == null) {
559 | _base[i] = this.digits[i].querySelector('.odometer-ribbon-inner');
560 | }
561 | this.ribbons[i].innerHTML = '';
562 | if (diff < 0) {
563 | frames = frames.reverse();
564 | }
565 | for (j = _m = 0, _len2 = frames.length; _m < _len2; j = ++_m) {
566 | frame = frames[j];
567 | numEl = document.createElement('div');
568 | numEl.className = 'odometer-value';
569 | numEl.innerHTML = frame;
570 | this.ribbons[i].appendChild(numEl);
571 | if (j === frames.length - 1) {
572 | addClass(numEl, 'odometer-last-value');
573 | }
574 | if (j === 0) {
575 | addClass(numEl, 'odometer-first-value');
576 | }
577 | }
578 | }
579 | if (start < 0) {
580 | this.addDigit('-');
581 | }
582 | mark = this.inside.querySelector('.odometer-radix-mark');
583 | if (mark != null) {
584 | mark.parent.removeChild(mark);
585 | }
586 | if (fractionalCount) {
587 | return this.addSpacer(this.format.radix, this.digits[fractionalCount - 1], 'odometer-radix-mark');
588 | }
589 | };
590 |
591 | return Odometer;
592 |
593 | })();
594 |
595 | Odometer.options = (_ref = window.odometerOptions) != null ? _ref : {};
596 |
597 | setTimeout(function() {
598 | var k, v, _base, _ref1, _results;
599 | if (window.odometerOptions) {
600 | _ref1 = window.odometerOptions;
601 | _results = [];
602 | for (k in _ref1) {
603 | v = _ref1[k];
604 | _results.push((_base = Odometer.options)[k] != null ? (_base = Odometer.options)[k] : _base[k] = v);
605 | }
606 | return _results;
607 | }
608 | }, 0);
609 |
610 | Odometer.init = function() {
611 | var el, elements, _i, _len, _ref1, _results;
612 | if (document.querySelectorAll == null) {
613 | return;
614 | }
615 | elements = document.querySelectorAll(Odometer.options.selector || '.odometer');
616 | _results = [];
617 | for (_i = 0, _len = elements.length; _i < _len; _i++) {
618 | el = elements[_i];
619 | _results.push(el.odometer = new Odometer({
620 | el: el,
621 | value: (_ref1 = el.innerText) != null ? _ref1 : el.textContent
622 | }));
623 | }
624 | return _results;
625 | };
626 |
627 | if ((((_ref1 = document.documentElement) != null ? _ref1.doScroll : void 0) != null) && (document.createEventObject != null)) {
628 | _old = document.onreadystatechange;
629 | document.onreadystatechange = function() {
630 | if (document.readyState === 'complete' && Odometer.options.auto !== false) {
631 | Odometer.init();
632 | }
633 | return _old != null ? _old.apply(this, arguments) : void 0;
634 | };
635 | } else {
636 | document.addEventListener('DOMContentLoaded', function() {
637 | if (Odometer.options.auto !== false) {
638 | return Odometer.init();
639 | }
640 | }, false);
641 | }
642 |
643 | if (typeof define === 'function' && define.amd) {
644 | define([], function() {
645 | return Odometer;
646 | });
647 | } else if (typeof exports !== "undefined" && exports !== null) {
648 | module.exports = Odometer;
649 | } else {
650 | window.Odometer = Odometer;
651 | }
652 |
653 | }).call(this);
654 |
--------------------------------------------------------------------------------