<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 (&#x27;,&#x27;)</span>
  decimal?: string; <span class="hljs-comment">// decimal (&#x27;.&#x27;)</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>) =&gt;</span> number;
  formattingFn?: <span class="hljs-function">(<span class="hljs-params">n: number</span>) =&gt;</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">() =&gt;</span> any; <span class="hljs-comment">// gets called when animation completes</span>
  onStartCallback?: <span class="hljs-function">() =&gt;</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">&#x27;targetId&#x27;</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">&#x27;targetId&#x27;</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">&#x27;targetId&#x27;</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">() =&gt;</span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;Complete!&#x27;</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">&#x27;targetId&#x27;</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&#39;s initialized. So if you initialize it before the DOM renders and your target element is in view before any scrolling, you&#39;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&#39;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&#39;ll need to first install the plugin package. Then you can include it and use the plugin option. See each plugin&#39;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">&#x27;targetId&#x27;</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&#39;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">&#x27;./js/countUp.min.js&#x27;</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">&#x27;target&#x27;</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">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;./main.js&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;module&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>To support IE and legacy browsers, use the <code>nomodule</code> script tag to include separate scripts that don&#39;t use the module syntax:</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">nomodule</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;js/countUp.umd.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">nomodule</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;js/main-for-legacy.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>To run module-enabled scripts locally, you&#39;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">&#x27;countup.js&#x27;</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">&#x27;myTarget&#x27;</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&#39;s formatted value. A class instance or object can be passed to the <code>plugin</code> property of CountUpOptions, and the plugin&#39;s render method will be called instead of CountUp&#39;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>