123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- class CountUp {
- constructor(startVal, endVal, decimals, duration, options = {}, page = getCurrentPages()[getCurrentPages().length - 1]) {
- Object.assign(this, {
- page,
- startVal,
- endVal,
- decimals,
- duration,
- options,
- })
- this.__init()
- }
- /**
- * 初始化
- */
- __init() {
- this.setData = this.page.setData.bind(this.page)
- this.lastTime = 0
- // merge options
- this.mergeOptions(this.options)
- this.startVal = Number(this.startVal)
- this.cacheVal = this.startVal
- this.endVal = Number(this.endVal)
- this.countDown = (this.startVal > this.endVal)
- this.frameVal = this.startVal
- this.decimals = Math.max(0, this.decimals || 0)
- this.dec = Math.pow(10, this.decimals)
- this.duration = Number(this.duration) * 1000 || 2000
- // format startVal on initialization
- this.printValue(this.formattingFn(this.startVal))
- }
- /**
- * 默认参数
- */
- setDefaultOptions() {
- return {
- useEasing: true, // toggle easing
- useGrouping: true, // 1,000,000 vs 1000000
- separator: ',', // character to use as a separator
- decimal: '.', // character to use as a decimal
- easingFn: null, // optional custom easing closure function, default is Robert Penner's easeOutExpo
- formattingFn: null, // optional custom formatting function, default is this.formatNumber below
- printValue(value) {}, // printValue
- }
- }
- /**
- * 合并参数
- */
- mergeOptions(options) {
- const defaultOptions = this.setDefaultOptions()
- // extend default options with passed options object
- for (let key in defaultOptions) {
- if (defaultOptions.hasOwnProperty(key)) {
- this.options[key] = typeof options[key] !== 'undefined' ? options[key] : defaultOptions[key]
- if (typeof this.options[key] === 'function') {
- this.options[key] = this.options[key].bind(this)
- }
- }
- }
- if (this.options.separator === '') { this.options.useGrouping = !1 }
- if (!this.options.prefix) this.options.prefix = ''
- if (!this.options.suffix) this.options.suffix = ''
- this.easingFn = this.options.easingFn ? this.options.easingFn : this.easeOutExpo
- this.formattingFn = this.options.formattingFn ? this.options.formattingFn : this.formatNumber
- this.printValue = this.options.printValue ? this.options.printValue : function() {}
- }
- /**
- * 创建定时器
- */
- requestAnimationFrame(callback) {
- let currTime = new Date().getTime()
- let timeToCall = Math.max(0, 16 - (currTime - this.lastTime))
- let timeout = setTimeout(() => {
- callback.bind(this)(currTime + timeToCall)
- }, timeToCall)
- this.lastTime = currTime + timeToCall
- return timeout
- }
- /**
- * 清空定时器
- */
- cancelAnimationFrame(timeout) {
- clearTimeout(timeout)
- }
- /**
- * 格式化数字
- */
- formatNumber(nStr) {
- nStr = nStr.toFixed(this.decimals)
- nStr += ''
- let x, x1, x2, rgx
- x = nStr.split('.')
- x1 = x[0]
- x2 = x.length > 1 ? this.options.decimal + x[1] : ''
- rgx = /(\d+)(\d{3})/
- if (this.options.useGrouping) {
- while (rgx.test(x1)) {
- x1 = x1.replace(rgx, '$1' + this.options.separator + '$2')
- }
- }
- return this.options.prefix + x1 + x2 + this.options.suffix
- }
- /**
- * 过渡效果
- */
- easeOutExpo(t, b, c, d) {
- return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b
- }
- /**
- * 计数函数
- */
- count(timestamp) {
- if (!this.startTime) { this.startTime = timestamp }
- this.timestamp = timestamp
- const progress = timestamp - this.startTime
- this.remaining = this.duration - progress
- // to ease or not to ease
- if (this.options.useEasing) {
- if (this.countDown) {
- this.frameVal = this.startVal - this.easingFn(progress, 0, this.startVal - this.endVal, this.duration)
- } else {
- this.frameVal = this.easingFn(progress, this.startVal, this.endVal - this.startVal, this.duration)
- }
- } else {
- if (this.countDown) {
- this.frameVal = this.startVal - ((this.startVal - this.endVal) * (progress / this.duration))
- } else {
- this.frameVal = this.startVal + (this.endVal - this.startVal) * (progress / this.duration)
- }
- }
- // don't go past endVal since progress can exceed duration in the last frame
- if (this.countDown) {
- this.frameVal = (this.frameVal < this.endVal) ? this.endVal : this.frameVal
- } else {
- this.frameVal = (this.frameVal > this.endVal) ? this.endVal : this.frameVal
- }
- // decimal
- this.frameVal = Math.round(this.frameVal * this.dec) / this.dec
- // format and print value
- this.printValue(this.formattingFn(this.frameVal))
- // whether to continue
- if (progress < this.duration) {
- this.rAF = this.requestAnimationFrame(this.count)
- } else {
- if (this.callback) { this.callback() }
- }
- }
- /**
- * 启动计数器
- */
- start(callback) {
- this.callback = callback
- this.rAF = this.requestAnimationFrame(this.count)
- return !1
- }
- /**
- * 停止计数器
- */
- pauseResume() {
- if (!this.paused) {
- this.paused = !0
- this.cancelAnimationFrame(this.rAF)
- } else {
- this.paused = !1
- delete this.startTime
- this.duration = this.remaining
- this.startVal = this.frameVal
- this.requestAnimationFrame(this.count)
- }
- }
- /**
- * 重置计数器
- */
- reset() {
- this.paused = !1
- delete this.startTime
- this.startVal = this.cacheVal
- this.cancelAnimationFrame(this.rAF)
- this.printValue(this.formattingFn(this.startVal))
- }
- /**
- * 更新计数器
- */
- update(newEndVal) {
- this.cancelAnimationFrame(this.rAF)
- this.paused = !1
- delete this.startTime
- this.startVal = this.frameVal
- this.endVal = Number(newEndVal)
- this.countDown = (this.startVal > this.endVal)
- this.rAF = this.requestAnimationFrame(this.count)
- }
- }
- export default CountUp
|