{"version":3,"sources":["webpack://@srexi/purecounterjs/./purecounter.js","webpack://@srexi/purecounterjs/./js/purecounter.js"],"names":["options","this","defaults","start","end","duration","delay","once","decimals","legacy","currency","currencysymbol","separator","separatorsymbol","selector","configOptions","Object","assign","registerEventListeners","elements","document","querySelectorAll","intersectionListenerSupported","intersectObserver","IntersectionObserver","animateElements","bind","forEach","element","observe","window","addEventListener","animateLegacy","e","parseConfig","elementIsInView","observer","elm","target","elementConfig","innerHTML","formatNumber","intersectionRatio","value","setTimeout","startCounter","config","incrementsPerStep","countMode","currentCount","parseValue","setAttribute","counterWorker","setInterval","nextNum","nextNumber","clearInterval","baseConfig","configValues","filter","call","attributes","attr","test","name","replace","toLowerCase","parseInt","number","steps","mode","parseFloat","symbol","limit","Math","abs","Number","toFixed","RegExp","strConfig","minimumFractionDigits","maximumFractionDigits","convertToCurrencySystem","applySeparator","toLocaleString","undefined","data","top","offsetTop","left","offsetLeft","width","offsetWidth","height","offsetHeight","offsetParent","pageYOffset","pageXOffset","innerHeight","innerWidth","IntersectionObserverEntry","prototype"],"mappings":"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","file":"/dist/purecounter.js","sourcesContent":["import PureCounter from './js/purecounter';\n\nconst pure = new PureCounter;","export default class PureCounter {\n\tconstructor(options) {\n\t\tthis.defaults = {\n\t\t start: 0,\n\t\t end: 100,\n\t\t duration: 2000,\n\t\t delay: 10,\n\t\t once: true,\n\t\t decimals: 0,\n\t\t legacy: true,\n\t\t currency: false,\n\t\t currencysymbol: false,\n\t\t separator: false,\n\t\t separatorsymbol: ',',\n\t\t selector: '.purecounter'\n\t\t}\n\t\tthis.configOptions = Object.assign({}, this.defaults, options || {});\n\t\tthis.registerEventListeners();\n\t}\n\n\t/** Initial function */\n\tregisterEventListeners() {\n\t\t/** Get all elements with class 'purecounter' */\n\t\tvar elements = document.querySelectorAll(this.configOptions.selector);\n\t\t/** Get browser Intersection Listener Support */\n\t\tvar intersectionSupported = this.intersectionListenerSupported();\n\n\t\t/** Run animateElements base on Intersection Support */\n\t\tif (intersectionSupported) {\n\t\t\tvar intersectObserver = new IntersectionObserver(this.animateElements.bind(this), {\n\t\t\t\t\"root\": null,\n\t\t\t\t\"rootMargin\": '20px',\n\t\t\t\t\"threshold\": 0.5\n\t\t\t});\n\n\t\t\telements.forEach(element => {intersectObserver.observe(element);})\n\t\t} else {\n\t\t\tif (window.addEventListener) {\n\t\t\t\tthis.animateLegacy(elements);\n\n\t\t\t\twindow.addEventListener('scroll', function (e) {\n\t\t\t\t\tthis.animateLegacy(elements);\n\t\t\t\t}, { \"passive\": true });\n\t\t\t}\n\t\t}\n\t}\n\n\t/** This legacy to make Purecounter use very lightweight & fast */\n\tanimateLegacy(elements) {\n\t\telements.forEach(element => {\n\t\t\tvar config = this.parseConfig(element);\n\t\t\tif(config.legacy === true && this.elementIsInView(element)) {\n\t\t\t\tthis.animateElements([element]);\n\t\t\t}\n\t\t})\n\t}\n\n\t/** Main Element Count Animation */\n\tanimateElements(elements, observer) {\n\t\telements.forEach(element => {\n\t\t\tvar elm = element.target || element; // Just make sure which element will be used\n\t\t\tvar elementConfig = this.parseConfig(elm); // Get config value on that element\n\n\t\t\t// If duration is less than or equal zero, just format the 'end' value\n\t\t\tif (elementConfig.duration <= 0) {\n\t\t\t\treturn elm.innerHTML = this.formatNumber(elementConfig.end, elementConfig);\n\t\t\t}\n\n\t\t\tif ((!observer && !this.elementIsInView(element)) || (observer && element.intersectionRatio < 0.5)) {\n\t\t\t\tvar value = elementConfig.start > elementConfig.end ? elementConfig.end : elementConfig.start;\n\t\t\t\treturn elm.innerHTML = this.formatNumber(value, elementConfig);\n\t\t\t}\n\n\t\t\t// If duration is more than 0, then start the counter\n\t\t\tsetTimeout(() => {\n\t\t\t\treturn this.startCounter(elm, elementConfig);\n\t\t\t}, elementConfig.delay);\n\t\t});\n\t}\n\n\t/** This is the the counter method */\n\tstartCounter(element, config) {\n\t\t// First, get the increments step\n\t\tvar incrementsPerStep = (config.end - config.start) / (config.duration / config.delay);\n\t\t// Next, set the counter mode (Increment or Decrement)\n\t\tvar countMode = 'inc';\n\n\t\t// Set mode to 'decrement' and 'increment step' to minus if start is larger than end\n\t\tif (config.start > config.end) {\n\t\t\tcountMode = 'dec';\n\t\t\tincrementsPerStep *= -1;\n\t\t}\n\n\t\t// Next, determine the starting value\n\t\tvar currentCount = this.parseValue(config.start);\n\t\t// And then print it's value to the page\n\t\telement.innerHTML = this.formatNumber(currentCount, config);\n\n\t\t// If the config 'once' is true, then set the 'duration' to 0\n\t\tif(config.once === true){\n\t\t\telement.setAttribute('data-purecounter-duration', 0);\n\t\t}\n\n\t\t// Now, start counting with counterWorker using Interval method based on delay\n\t\tvar counterWorker = setInterval(() => {\n\t\t\t// First, determine the next value base on current value, increment value, and count mode\n\t\t\tvar nextNum = this.nextNumber(currentCount, incrementsPerStep, countMode);\n\t\t\t// Next, print that value to the page\n\t\t\telement.innerHTML = this.formatNumber(nextNum, config);\n\t\t\t// Now set that value to the current value, because it's already printed\n\t\t\tcurrentCount = nextNum;\n\n\t\t\t// If the value is larger or less than the 'end' (base on mode), then print the end value and stop the Interval\n\t\t\tif ((currentCount >= config.end && countMode == 'inc') || (currentCount <= config.end && countMode == 'dec')) {\n\t\t\t\telement.innerHTML = this.formatNumber(config.end, config);\n\t\t\t\tclearInterval(counterWorker);\n\t\t\t}\n\t\t}, config.delay);\n\t}\n\n\t/** This function is to generate the element Config */\n\tparseConfig(element) {\n\t\t// First, we need to declare the base Config\n\t\t// This config will be used if the element doesn't have config\n\t\tvar baseConfig = {...this.configOptions};\n\n\t\t// Next, get all 'data-precounter' attributes value. Store to array\n\t\tvar configValues = [].filter.call(element.attributes, function(attr) {\n\t\t\treturn /^data-purecounter-/.test(attr.name);\n\t\t});\n\n\t\t// Now, we create element config as an empty object\n\t\tvar elementConfig = {};\n\n\t\t// And then, fill the element config based on config values\n\t\tconfigValues.forEach(e => {\n\t\t\tvar name = e.name.replace('data-purecounter-', '').toLowerCase();\n\t\t\tvar value = name == 'duration' ? parseInt(this.parseValue(e.value) * 1000) : this.parseValue(e.value);\n\t\t\telementConfig[name] = value; // We will get an object\n\t\t})\n\n\t\t// Last marge base config with element config and return it as an object\n\t\treturn Object.assign(baseConfig, elementConfig);\n\t}\n\n\t/** This function is to get the next number */\n\tnextNumber(number, steps, mode = 'inc') {\n\t\t// First, get the exact value from the number and step (int or float)\n\t\tnumber = this.parseValue(number);\n\t\tsteps = this.parseValue(steps);\n\n\t\t// Last, get the next number based on current number, increment step, and count mode\n\t\t// Always return it as float\n\t\treturn parseFloat(mode === 'inc' ? (number + steps) : (number - steps));\n\t}\n\n\t/** This function is to convert number into currency format */\n\tconvertToCurrencySystem (number, config) {\n\t\tvar symbol = config.currencysymbol || \"\", // Set the Currency Symbol (if any)\n\t\t\tlimit = config.decimals || 1, // Set the decimal limit (default is 1)\n\t\t\tnumber = Math.abs(Number(number)); // Get the absolute value of number\n\n\t\t// Set the value\n\t\tvar value = number >= 1.0e+12 ? `${(number / 1.0e+12).toFixed(limit)} T` // Twelve zeros for Trillions\n\t\t\t: number >= 1.0e+9 ? `${(number / 1.0e+9).toFixed(limit)} B` // Nine zeros for Billions\n\t\t\t: number >= 1.0e+6 ? `${(number / 1.0e+6).toFixed(limit)} M` // Six zeros for Millions\n\t\t\t: number >= 1.0e+3 ? `${(number / 1.0e+12).toFixed(limit)} K` // Three zeros for Thousands\n\t\t\t: number.toFixed(limit); // If less than 1000, print it's value\n\n\t\t// Apply symbol before the value and return it as string\n\t\treturn symbol + value;\n\t}\n\n\t/** This function is to get the last formated number */\n\tapplySeparator(value, config){\n\t\t// If config separator is false, delete all separator\n\t\tif (!config.separator) {\n\t\t\treturn value.replace(new RegExp(/,/gi, 'gi'), '')\n\t\t}\n\n\t\t// If config separator is true, then create separator\n\t\treturn value.replace(/(\\d)(?=(\\d{3})+(?!\\d))/g, \"$1,\")\n\t\t\t.replace(new RegExp(/,/gi, 'gi'), config.separatorsymbol)\n\t}\n\n\t/** This function is to get formated number to be printed in the page */\n\tformatNumber(number, config) {\n\t\t// This is the configuration for 'toLocaleString' method\n\t\tvar strConfig = {minimumFractionDigits: config.decimals, maximumFractionDigits: config.decimals};\n\t\t// Set the number if it using currency, then convert. If doesn't, just parse it as float\n\t\tnumber = config.currency ? this.convertToCurrencySystem(number, config) : parseFloat(number);\n\n\t\t// Last, apply the number separator using number as string\n\t\treturn this.applySeparator(number.toLocaleString(undefined, strConfig), config);\n\t}\n\n\t/** This function is to get the parsed value */\n\tparseValue(data) {\n\t\t// If number with dot (.), will be parsed as float\n\t\tif (/^[0-9]+\\.[0-9]+$/.test(data)) {\n\t\t\treturn parseFloat(data);\n\t\t}\n\t\t// If just number, will be parsed as integer\n\t\tif (/^[0-9]+$/.test(data)) {\n\t\t\treturn parseInt(data);\n\t\t}\n\t\t// If it's boolean string, will be parsed as boolean\n\t\tif (/^true|false/i.test(data)) {\n\t\t\treturn /^true/i.test(data);\n\t\t}\n\t\t// Return it's value as default\n\t\treturn data;\n\t}\n\n\t/** This function is to detect the element is in view or not. */\n\telementIsInView(element) {\n\t\tvar top = element.offsetTop;\n\t\tvar left = element.offsetLeft;\n\t\tvar width = element.offsetWidth;\n\t\tvar height = element.offsetHeight;\n\n\t\twhile (element.offsetParent) {\n\t\t\telement = element.offsetParent;\n\t\t\ttop += element.offsetTop;\n\t\t\tleft += element.offsetLeft;\n\t\t}\n\n\t\treturn (\n\t\t\ttop >= window.pageYOffset &&\n\t\t\tleft >= window.pageXOffset &&\n\t\t\t(top + height) <= (window.pageYOffset + window.innerHeight) &&\n\t\t\t(left + width) <= (window.pageXOffset + window.innerWidth)\n\t\t);\n\t}\n\n\t/** Just some condition to check browser Intersection Support */\n\tintersectionListenerSupported() {\n\t\treturn ('IntersectionObserver' in window) &&\n\t\t\t('IntersectionObserverEntry' in window) &&\n\t\t\t('intersectionRatio' in window.IntersectionObserverEntry.prototype);\n\t}\n}\n"],"sourceRoot":""}