UNPKG

tm-odometer

Version:

TmOdometer: Lightweight JavaScript library for animated numeric counters with smooth transitions and precise decimal handling.

4 lines (3 loc) 9.8 kB
/*! tm-odometer-lib v2.0.0 | MIT License */ const t=/^\(?([^)]*)\)?(?:(.)(d+))?$/,e=1e3/30,i=document.createElement("div").style,n=null!=i.transition||null!=i.webkitTransition||null!=i.mozTransition||null!=i.oTransition,o=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,s=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;let r=!1;const a=()=>{if(!r&&window.jQuery){r=!0;for(const t of["html","text"]){const e=window.jQuery.fn[t];window.jQuery.fn[t]=function(t){var i;return null==t||null==(null===(i=this[0])||void 0===i?void 0:i.odometer)?e.apply(this,arguments):this[0].odometer.update(t)}}}},d=t=>{const e=document.createElement("div");if(e.innerHTML=t,!e.children[0])throw new Error("Invalid HTML: No valid root element found.");return e.children[0]},h=(t,e)=>t.className=t.className.replace(new RegExp(`(^| )${e.split(" ").join("|")}( |$)`,"gi")," "),l=(t,e)=>(h(t,e),t.className+=` ${e}`),u=(t,e)=>{if("function"==typeof CustomEvent){const i=new CustomEvent(e,{bubbles:!0,cancelable:!0});t.dispatchEvent(i)}else if(document.createEvent){const i=document.createEvent("HTMLEvents");i.initEvent(e,!0,!0),t.dispatchEvent(i)}},c=()=>{var t,e;const i=null===(e=null===(t=window.performance)||void 0===t?void 0:t.now)||void 0===e?void 0:e.call(t);return null!=i?i:+new Date},m=t=>t<0?Math.ceil(t):Math.floor(t);var p,f;class v{constructor(t){var i,n,o,s,r;if(this.value=0,this.watchMutations=!1,this.transitionEndBound=!1,this.format={repeating:"",precision:0},this.digits=[],this.ribbons={},this.options=t,this.el=this.options.el,this.el.odometer)return this.el.odometer;this.el.odometer=this;for(const t in v.options){const e=v.options[t];null!==(i=(s=this.options)[t])&&void 0!==i||(s[t]=e)}null!==(n=(r=this.options).duration)&&void 0!==n||(r.duration=2e3),this.MAX_VALUES=this.options.duration/e/2|0,this.resetFormat(),this.value=this.cleanValue(null!==(o=this.options.value)&&void 0!==o?o:""),this.renderInside(),this.render();try{for(const t of["innerHTML","innerText","textContent"])this.el[t]&&Object.defineProperty(this.el,t,{get:()=>{var e,i;return"innerHTML"===t?this.inside.outerHTML:null!==(i=null!==(e=this.inside.innerText)&&void 0!==e?e:this.inside.textContent)&&void 0!==i?i:""},set:t=>this.update(t)})}catch(t){this.watchForMutations()}}renderInside(){this.inside=document.createElement("div"),this.inside.className="odometer-inside",this.el.innerHTML="",this.el.appendChild(this.inside)}watchForMutations(){var t;if(s)try{null!==(t=this.observer)&&void 0!==t||(this.observer=new s((t=>{const e=this.el.innerText||"";this.renderInside(),this.render(this.value),this.update(e)}))),this.watchMutations=!0,this.startWatchingMutations()}catch(t){}}startWatchingMutations(){var t;this.watchMutations&&(null===(t=this.observer)||void 0===t||t.observe(this.el,{childList:!0}))}stopWatchingMutations(){var t;null===(t=this.observer)||void 0===t||t.disconnect()}cleanValue(t){var e;return"string"==typeof t&&(t=(t=(t=t.replace(null!==(e=this.format.radix)&&void 0!==e?e:".","<radix>")).replace(/[.,]/g,"")).replace("<radix>","."),t=parseFloat(t)||0),((t,e)=>(null!=e||(e=0),e?(t*=Math.pow(10,e),t+=.5,(t=Math.floor(t))/Math.pow(10,e)):Math.round(t)))(t,this.format.precision)}bindTransitionEnd(){if(this.transitionEndBound)return;this.transitionEndBound=!0;let t=!1;const e="transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd".split(" ");for(const i of e)this.el.addEventListener(i,(()=>(t||(t=!0,setTimeout((()=>{this.render(),t=!1,u(this.el,"odometerdone")}),0)),!0)),!1)}resetFormat(){var e;let i=null!==(e=this.options.format)&&void 0!==e?e:"(,ddd).dd";i=i||"d";const n=t.exec(i);if(!n)throw new Error("TmOdometer: Unparsable digit format");const[o,s,r,a]=n,d=(null==a?void 0:a.length)||0;this.format={repeating:s,radix:r,precision:d}}render(t){null!=t||(t=this.value),this.stopWatchingMutations(),this.resetFormat(),this.inside.innerHTML="";let{theme:e}=this.options;const i=this.el.className.split(" "),o=[];for(const t of i)if(t.length){const i=/^odometer-theme-(.+)$/.exec(t);if(i){e=i[1];continue}if(/^odometer(-|$)/.test(t))continue;o.push(t)}o.push("odometer"),n||o.push("odometer-no-transitions"),e?o.push(`odometer-theme-${e}`):o.push("odometer-auto-theme"),this.el.className=o.join(" "),this.ribbons={},this.formatDigits(t),this.startWatchingMutations()}formatDigits(t){if(this.digits=[],this.options.formatFunction){const e=this.options.formatFunction(t);for(const t of e.split("").reverse())if(t.match(/0-9/)){const e=this.renderDigit();e.querySelector(".odometer-value").innerHTML=t,this.digits.push(e),this.insertDigit(e)}else this.addSpacer(t)}else{const e=this.preservePrecision(t);let i=!this.format.precision;for(const t of e.split("").reverse())"."===t&&(i=!0),this.addDigit(t,i)}}preservePrecision(t){let e=t.toString();if(this.format.precision){const t=e.split(".");1===t.length&&(e+=".",t[1]="");for(let i=0;i<this.format.precision;i++)t[1][i]||(e+="0")}return e}update(t){const e=(t=this.cleanValue(t))-this.value;return e?(h(this.el,"odometer-animating-up odometer-animating-down odometer-animating"),l(this.el,e>0?"odometer-animating-up":"odometer-animating-down"),this.stopWatchingMutations(),this.animate(t),this.startWatchingMutations(),setTimeout((()=>{this.el.offsetHeight,l(this.el,"odometer-animating")}),0),this.value=t,this.value):this.value}renderDigit(){return d('<span class="odometer-digit"><span class="odometer-digit-spacer">8</span><span class="odometer-digit-inner"><span class="odometer-ribbon"><span class="odometer-ribbon-inner"><span class="odometer-value"></span></span></span></span></span>')}insertDigit(t,e){return e?this.inside.insertBefore(t,e):this.inside.children.length?this.inside.insertBefore(t,this.inside.children[0]):this.inside.appendChild(t)}addSpacer(t,e,i){const n=d('<span class="odometer-formatting-mark"></span>');return n.innerHTML=t,i&&l(n,i),this.insertDigit(n,e)}addDigit(t,e){var i;if(null!=e||(e=!0),"-"===t)return this.addSpacer(t,null,"odometer-negation-mark");if("."===t)return this.addSpacer(null!==(i=this.format.radix)&&void 0!==i?i:".",null,"odometer-radix-mark");if(e){let t=!1;for(;;){if(!this.format.repeating.length){if(t)throw new Error("Bad odometer format without digits");this.resetFormat(),t=!0}const e=this.format.repeating[this.format.repeating.length-1];if(this.format.repeating=this.format.repeating.substring(0,this.format.repeating.length-1),"d"===e)break;this.addSpacer(e)}}const n=this.renderDigit();return n.querySelector(".odometer-value").innerHTML=t,this.digits.push(n),this.insertDigit(n)}animate(t){n&&"count"!==this.options.animation?this.animateSlide(t):this.animateCount(t)}animateCount(t){const e=t-this.value;if(!e)return;const i=c();let n=i,s=this.value,r=()=>{if(c()-i>(this.options.duration||0))return this.value=t,this.render(),void u(this.el,"odometerdone");const a=c()-n;if(a>50){n=c();const t=a/(this.options.duration||0);s+=e*t,this.render(Math.round(s))}o?o(r):setTimeout(r,50)};r()}getDigitCount(...t){for(let e=0;e<t.length;e++)t[e]=Math.abs(t[e]);const e=Math.max(...t);return Math.ceil(Math.log(e+1)/Math.log(10))}getFractionalDigitCount(...t){const e=/^\-?\d*\.(\d*?)0*$/;for(let i=0;i<t.length;i++){const n=t[i].toString(),o=e.exec(n);t[i]=o?o[1].length:0}return Math.max(...t)}resetDigits(){this.digits=[],this.ribbons={},this.inside.innerHTML="",this.resetFormat()}createRange(t,e,i){const n=t<e,o=Math.abs(e-t)+(i?1:0);return Array.from({length:o},((e,i)=>n?t+i:t-i))}animateSlide(t){var e;let i=this.value;const n=this.format.precision;n&&(t*=Math.pow(10,n),i*=Math.pow(10,n));const o=t-i;if(!o)return;this.bindTransitionEnd();const s=[],r=this.getDigitCount(i,t);let a=0,d=i;for(let e=0;e<r;e++){d=m(i/Math.pow(10,r-e-1));const n=m(t/Math.pow(10,r-e-1)),o=n-d;let h;if(Math.abs(o)>this.MAX_VALUES){h=[];const t=o/(this.MAX_VALUES+this.MAX_VALUES*a*.5);let e=d;for(;o>0&&e<n||o<0&&e>n;)h.push(Math.round(e)),e+=t;h[h.length-1]!==n&&h.push(n),a++}else h=this.createRange(d,n,!0);for(let t=0;t<h.length;t++)h[t]=Math.abs(h[t]%10);s.push(h)}this.resetDigits();const h=s.reverse();for(let t=0;t<h.length;t++){let e=h[t];this.digits[t]||this.addDigit(" ",t>=n),void 0===this.ribbons[t]&&(this.ribbons[t]=this.digits[t].querySelector(".odometer-ribbon-inner")),this.ribbons[t].innerHTML="",o<0&&(e=e.reverse());for(let i=0;i<e.length;i++){const n=e[i],o=document.createElement("div");o.className="odometer-value",o.innerHTML=n.toString(),this.ribbons[t].appendChild(o),i===e.length-1&&l(o,"odometer-last-value"),0===i&&l(o,"odometer-first-value")}}d<0&&this.addDigit("-");const u=this.inside.querySelector(".odometer-radix-mark");u&&u.parentNode.removeChild(u),n&&this.addSpacer(null!==(e=this.format.radix)&&void 0!==e?e:".",this.digits[n-1],"odometer-radix-mark")}static init(){if(!document.querySelectorAll)return[];const t=document.querySelectorAll(v.options.selector||".odometer");return Array.from(t,(t=>{var e;return t.odometer=new v({el:t,value:null!==(e=t.innerText)&&void 0!==e?e:t.textContent})}))}}v.options=null!==(p=window.odometerOptions)&&void 0!==p?p:{},f=v,setTimeout((()=>{var t,e;if(window.odometerOptions)for(const i in window.odometerOptions)null!==(t=(e=f.options)[i])&&void 0!==t||(e[i]=window.odometerOptions[i])}),0),(t=>{var e;if((null===(e=document.documentElement)||void 0===e?void 0:e.doScroll)&&document.createEventObject){const e=document.onreadystatechange;document.onreadystatechange=function(){"complete"===document.readyState&&!1!==t.options.auto&&t.init(),e&&(null==e||e.apply(this,arguments))}}else document.addEventListener("DOMContentLoaded",(function(){!1!==t.options.auto&&t.init()}),!1)})(v),a(),setTimeout(a,0);export{v as default}; //# sourceMappingURL=tm-odometer.min.js.map