<h1 id="id-countupjs">CountUp.js</h1> <p>CountUp.js is a dependency-free, lightweight Javascript class that can be used to quickly create animations that display numerical data in a more interesting way.</p> <p>Despite its name, CountUp can count in either direction, depending on the start and end values that you pass.</p> <p>CountUp.js supports all browsers. MIT license.</p> <h2 id="id-try-the-demo"><a href="https://inorganik.github.io/countUp.js">Try the demo</a></h2> <p>Or tinker with CountUp in <a href="https://stackblitz.com/edit/countup-typescript">Stackblitz</a></p> <h2 id="id-jump-to">Jump to:</h2> <ul> <li><strong><a href="#usage">Usage</a></strong></li> <li><strong><a href="#including-countup">Including CountUp</a></strong></li> <li><strong><a href="#contributing">Contributing</a></strong></li> <li><strong><a href="#creating-animation-plugins">Creating Animation Plugins</a></strong></li> </ul> <h2 id="id-features">Features</h2> <ul> <li><strong>Animate when element scrolls into view.</strong> Use option <code>enableScrollSpy</code>.</li> <li><strong>Highly customizeable</strong> with a large range of options, you can even substitute numerals.</li> <li><strong>Smart easing</strong>: CountUp intelligently defers easing until it gets close enough to the end value for easing to be visually noticeable. Configureable in the <a href="#options">options</a>.</li> <li><strong>Plugins</strong> allow for alternate animations like the <a href="https://www.npmjs.com/package/odometer_countup">Odometer plugin</a></li> </ul> <p><img src="./demo/images/odometer_plugin.gif" alt="Odomoeter plugin"></p> <h2 id="id-usage">Usage:</h2> <p><strong>Use CountUp with:</strong></p> <ul> <li><a href="https://github.com/inorganik/ngx-countUp">Angular 2+</a></li> <li><a href="https://github.com/inorganik/countUp.js-angular1">Angular 1.x</a></li> <li><a href="https://gist.github.com/inorganik/2cf776865a4c65c12857027870e9898e">React</a></li> <li><a href="https://gist.github.com/inorganik/85a66941ab88cc10c5fa5b26aead5f2a">Svelte</a></li> <li><a href="https://github.com/xlsdg/vue-countup-v2">Vue</a></li> <li><a href="https://wordpress.org/plugins/countup-js/">WordPress</a></li> <li><a href="https://gist.github.com/inorganik/b63dbe5b3810ff2c0175aee4670a4732">jQuery</a></li> <li><a href="https://github.com/lekoala/formidable-elements/blob/master/docs/count-up.md">custom element</a></li> </ul> <p><strong>Use CountUp directly:</strong></p> <p>On npm as <code>countup.js</code>. You can import as a module, or include the UMD script and access CountUp as a global. See <a href="#including-countup">detailed instructions</a> on including CountUp.</p> <p><strong>Params</strong>:</p> <ul> <li><code>target: string | HTMLElement | HTMLInputElement</code> - id of html element, input, svg text element, or DOM element reference where counting occurs.</li> <li><code>endVal: number | null</code> - the value you want to arrive at. Leave null to use the number in the target element.</li> <li><code>options?: CountUpOptions</code> - optional configuration object for fine-grain control</li> </ul> <p><strong>Options</strong> (defaults in parentheses): <a name="options"></a></p> <pre><code class="hljs language-ts">interface <span class="hljs-title class_">CountUpOptions</span> { startVal?: number; <span class="hljs-comment">// number to start at (0)</span> decimalPlaces?: number; <span class="hljs-comment">// number of decimal places (0)</span> duration?: number; <span class="hljs-comment">// animation duration in seconds (2)</span> useGrouping?: boolean; <span class="hljs-comment">// example: 1,000 vs 1000 (true)</span> useIndianSeparators?: boolean; <span class="hljs-comment">// example: 1,00,000 vs 100,000 (false)</span> useEasing?: boolean; <span class="hljs-comment">// ease animation (true)</span> smartEasingThreshold?: number; <span class="hljs-comment">// smooth easing for large numbers above this if useEasing (999)</span> smartEasingAmount?: number; <span class="hljs-comment">// amount to be eased for numbers above threshold (333)</span> separator?: string; <span class="hljs-comment">// grouping separator (',')</span> decimal?: string; <span class="hljs-comment">// decimal ('.')</span> <span class="hljs-comment">// easingFn: easing function for animation (easeOutExpo)</span> easingFn?: <span class="hljs-function">(<span class="hljs-params">t: number, b: number, c: number, d: number</span>) =></span> number; formattingFn?: <span class="hljs-function">(<span class="hljs-params">n: number</span>) =></span> string; <span class="hljs-comment">// this function formats result</span> prefix?: string; <span class="hljs-comment">// text prepended to result</span> suffix?: string; <span class="hljs-comment">// text appended to result</span> numerals?: string[]; <span class="hljs-comment">// numeral glyph substitution</span> enableScrollSpy?: boolean; <span class="hljs-comment">// start animation when target is in view</span> scrollSpyDelay?: number; <span class="hljs-comment">// delay (ms) after target comes into view</span> scrollSpyOnce?: boolean; <span class="hljs-comment">// run only once</span> onCompleteCallback?: <span class="hljs-function">() =></span> any; <span class="hljs-comment">// gets called when animation completes</span> onStartCallback?: <span class="hljs-function">() =></span> any; <span class="hljs-comment">// gets called when animation starts</span> plugin?: <span class="hljs-title class_">CountUpPlugin</span>; <span class="hljs-comment">// for alternate animations</span> } </code></pre> <p><strong>Example usage</strong>: <a name="example"></a></p> <pre><code class="hljs language-js"><span class="hljs-keyword">const</span> countUp = <span class="hljs-keyword">new</span> <span class="hljs-title class_">CountUp</span>(<span class="hljs-string">'targetId'</span>, <span class="hljs-number">5234</span>); <span class="hljs-keyword">if</span> (!countUp.<span class="hljs-property">error</span>) { countUp.<span class="hljs-title function_">start</span>(); } <span class="hljs-keyword">else</span> { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(countUp.<span class="hljs-property">error</span>); } </code></pre> <p>Pass options:</p> <pre><code class="hljs language-js"><span class="hljs-keyword">const</span> countUp = <span class="hljs-keyword">new</span> <span class="hljs-title class_">CountUp</span>(<span class="hljs-string">'targetId'</span>, <span class="hljs-number">5234</span>, options); </code></pre> <p>with optional complete callback:</p> <pre><code class="hljs language-js"><span class="hljs-keyword">const</span> countUp = <span class="hljs-keyword">new</span> <span class="hljs-title class_">CountUp</span>(<span class="hljs-string">'targetId'</span>, <span class="hljs-number">5234</span>, { <span class="hljs-attr">onCompleteCallback</span>: someMethod }); <span class="hljs-comment">// or (passing fn to start will override options.onCompleteCallback)</span> countUp.<span class="hljs-title function_">start</span>(someMethod); <span class="hljs-comment">// or</span> countUp.<span class="hljs-title function_">start</span>(<span class="hljs-function">() =></span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Complete!'</span>)); </code></pre> <p><strong>Other methods</strong>:</p> <p>Toggle pause/resume:</p> <pre><code class="hljs language-js">countUp.pauseResume(); </code></pre> <p>Reset the animation:</p> <pre><code class="hljs language-js">countUp.reset(); </code></pre> <p>Update the end value and animate:</p> <pre><code class="hljs language-js">countUp.update(989); </code></pre> <hr> <h3 id="id-animate-when-the-element-is-scrolled-into-view"><strong>Animate when the element is scrolled into view</strong></h3> <p>Use the scroll spy option to animate when the element is scrolled into view. When using scroll spy, just initialize CountUp but do not call start();</p> <pre><code class="hljs language-js"><span class="hljs-keyword">const</span> countUp = <span class="hljs-keyword">new</span> <span class="hljs-title class_">CountUp</span>(<span class="hljs-string">'targetId'</span>, <span class="hljs-number">989</span>, { <span class="hljs-attr">enableScrollSpy</span>: <span class="hljs-literal">true</span> }); </code></pre> <p><strong>Troubleshooting scroll spy</strong></p> <p>CountUp checks the scroll position as soon as it's initialized. So if you initialize it before the DOM renders and your target element is in view before any scrolling, you'll need to re-check the scroll position after the page renders:</p> <pre><code class="hljs language-js"><span class="hljs-comment">// after DOM has rendered</span> countUp.<span class="hljs-title function_">handleScroll</span>(); </code></pre> <hr> <h3 id="id-alternate-animations-with-plugins"><strong>Alternate animations with plugins</strong></h3> <p>Currently there's just one plugin, the <strong><a href="https://github.com/msoler75/odometer_countup.js">Odometer Plugin</a></strong>.</p> <p>To use a plugin, you'll need to first install the plugin package. Then you can include it and use the plugin option. See each plugin's docs for more detailed info.</p> <pre><code class="hljs language-js"><span class="hljs-keyword">const</span> countUp = <span class="hljs-keyword">new</span> <span class="hljs-title class_">CountUp</span>(<span class="hljs-string">'targetId'</span>, <span class="hljs-number">5234</span>, { <span class="hljs-attr">plugin</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Odometer</span>({ <span class="hljs-attr">duration</span>: <span class="hljs-number">2.3</span>, <span class="hljs-attr">lastDigitDelay</span>: <span class="hljs-number">0</span> }), <span class="hljs-attr">duration</span>: <span class="hljs-number">3.0</span> }); </code></pre> <p>If you'd like to make your own plugin, see <a href="#creating-animation-plugins">the docs</a> below!</p> <hr> <h2 id="id-including-countup">Including CountUp</h2> <p>CountUp is distributed as an ES6 module because it is the most standardized and most widely compatible module for browsers, though a UMD module is <a href="#umd-module">also included</a>, along with a separate requestAnimationFrame polyfill (see below).</p> <p>For the examples below, first install CountUp. This will give you the latest:</p> <pre><code>npm i countup.js </code></pre> <h3 id="id-example-with-vanilla-js">Example with vanilla js</h3> <p>This is what I used in the demo. Checkout index.html and demo.js.</p> <p>main.js:</p> <pre><code class="hljs language-js"><span class="hljs-keyword">import</span> { <span class="hljs-title class_">CountUp</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'./js/countUp.min.js'</span>; <span class="hljs-variable language_">window</span>.<span class="hljs-property">onload</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">var</span> countUp = <span class="hljs-keyword">new</span> <span class="hljs-title class_">CountUp</span>(<span class="hljs-string">'target'</span>, <span class="hljs-number">2000</span>); countUp.<span class="hljs-title function_">start</span>(); } </code></pre> <p>Include in your html. Notice the <code>type</code> attribute:</p> <pre><code class="hljs language-html"><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./main.js"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span> </code></pre> <p>To support IE and legacy browsers, use the <code>nomodule</code> script tag to include separate scripts that don't use the module syntax:</p> <pre><code class="hljs language-html"><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">nomodule</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"js/countUp.umd.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span> <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">nomodule</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"js/main-for-legacy.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span> </code></pre> <p>To run module-enabled scripts locally, you'll need a simple local server setup like <a href="https://www.npmjs.com/package/http-server">this</a> (test the demo locally by running <code>npm run serve</code>) because otherwise you may see a CORS error when your browser tries to load the script as a module.</p> <h3 id="id-for-webpack-and-other-build-systems">For Webpack and other build systems</h3> <p>Import from the package, instead of the file location:</p> <pre><code class="hljs language-js"><span class="hljs-keyword">import</span> { <span class="hljs-title class_">CountUp</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'countup.js'</span>; </code></pre> <h3 id="id-umd-module">UMD module</h3> <p>CountUp is also wrapped as a UMD module in <code>./dist/countUp.umd.js</code> and it exposes CountUp as a global variable on the window scope. To use it, include <code>countUp.umd.js</code> in a script tag, and invoke it like so:</p> <pre><code class="hljs language-js"><span class="hljs-keyword">var</span> numAnim = <span class="hljs-keyword">new</span> countUp.<span class="hljs-title class_">CountUp</span>(<span class="hljs-string">'myTarget'</span>, <span class="hljs-number">2000</span>); numAnim.<span class="hljs-title function_">start</span>() </code></pre> <h3 id="id-requestanimationframe-polyfill">requestAnimationFrame polyfill</h3> <p>You can include <code>dist/requestAnimationFrame.polyfill.js</code> if you want to support IE9 and older, and Opera mini.</p> <hr> <h2 id="id-contributing">Contributing</h2> <p>Before you make a pull request, please be sure to follow these instructions:</p> <ol> <li>Do your work on <code>src/countUp.ts</code></li> <li>Lint: <code>npm run lint</code></li> <li>Run tests: <code>npm t</code></li> <li>Build and serve the demo by running <code>npm start</code> then check the demo to make sure it counts.</li> </ol> <!-- PUBLISHING 1. bump version in package.json and countUp.ts 2. npm run build 3. commit changes 4. npm publish --> <hr> <h2 id="id-creating-animation-plugins">Creating Animation Plugins</h2> <p>CountUp supports plugins as of v2.6.0. Plugins implement their own render method to display each frame's formatted value. A class instance or object can be passed to the <code>plugin</code> property of CountUpOptions, and the plugin's render method will be called instead of CountUp's.</p> <pre><code class="hljs language-ts"><span class="hljs-keyword">export</span> declare interface <span class="hljs-title class_">CountUpPlugin</span> { <span class="hljs-title function_">render</span>(<span class="hljs-attr">elem</span>: <span class="hljs-title class_">HTMLElement</span>, <span class="hljs-attr">formatted</span>: string): <span class="hljs-keyword">void</span>; } </code></pre> <p>An example of a plugin:</p> <pre><code class="hljs language-ts"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SomePlugin</span> implements <span class="hljs-title class_">CountUpPlugin</span> { <span class="hljs-comment">// ...some properties here</span> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">options: SomePluginOptions</span>) { <span class="hljs-comment">// ...setup code here if you need it</span> } <span class="hljs-title function_">render</span>(<span class="hljs-attr">elem</span>: <span class="hljs-title class_">HTMLElement</span>, <span class="hljs-attr">formatted</span>: string): <span class="hljs-keyword">void</span> { <span class="hljs-comment">// render DOM here</span> } } </code></pre> <p>If you make a plugin, be sure to create a PR to add it to this README!</p>